|
|
1.1 root 1: #include "main.h"
2: #include "configuration.h"
3: #include "m68000.h"
4: #include "sysdeps.h"
5: #include "cycInt.h"
6: #include "audio.h"
7: #include "dma.h"
8: #include "snd.h"
1.1.1.2 root 9: #include "kms.h"
1.1 root 10:
11: #define LOG_SND_LEVEL LOG_DEBUG
12: #define LOG_VOL_LEVEL LOG_DEBUG
13:
14: /* Initialize the audio system */
1.1.1.2 root 15: static bool sndout_inited;
16: static bool sound_output_active = false;
17: static bool sndin_inited;
18: static bool sound_input_active = false;
19: static Uint8* snd_buffer = NULL;
20:
21: static void sound_init(void) {
22: if(snd_buffer)
23: free(snd_buffer);
24: snd_buffer = NULL;
1.1 root 25: if (!sndout_inited && ConfigureParams.Sound.bEnableSound) {
26: Log_Printf(LOG_WARN, "[Audio] Initializing audio device.");
27: Audio_Output_Init();
28: sndout_inited=true;
29: }
30: }
31:
1.1.1.2 root 32: static void sound_uninit(void) {
33: if(snd_buffer)
34: free(snd_buffer);
35: snd_buffer = NULL;
1.1 root 36: if(sndout_inited) {
37: Log_Printf(LOG_WARN, "[Audio] Uninitializing audio device.");
38: sndout_inited=false;
39: Audio_Output_UnInit();
40: }
41: }
42:
43: void Sound_Reset(void) {
44: sound_uninit();
45: sound_init();
46: if (sound_output_active && sndout_inited) {
47: Audio_Output_Enable(true);
48: }
49: }
50:
1.1.1.2 root 51: void Sound_Pause(bool pause) {
52: if (pause) {
53: if (sndout_inited) {
54: Log_Printf(LOG_WARN, "[Audio] Uninitializing audio output device (pause).");
55: sndout_inited=false;
56: Audio_Output_UnInit();
57: }
58: if (sndin_inited) {
59: Log_Printf(LOG_WARN, "[Audio] Uninitializing audio input device (pause).");
60: sndin_inited=false;
61: Audio_Input_UnInit();
62: }
63: } else {
64: if (!sndout_inited && ConfigureParams.Sound.bEnableSound) {
65: Log_Printf(LOG_WARN, "[Audio] Initializing audio output device (resume).");
66: Audio_Output_Init();
67: sndout_inited=true;
68: }
69: if (!sndin_inited && sound_input_active && ConfigureParams.Sound.bEnableSound) {
70: Log_Printf(LOG_WARN, "[Audio] Initializing audio input device (resume).");
71: Audio_Input_Init();
72: sndin_inited=true;
73: }
74: if (sound_output_active && sndout_inited) {
75: Audio_Output_Enable(true);
76: }
77: if (sound_input_active && sndin_inited) {
78: Audio_Input_Enable(true);
79: }
80: }
81: }
1.1 root 82:
83: /* Start and stop sound output */
84: struct {
85: Uint8 mode;
86: Uint8 mute;
87: Uint8 lowpass;
88: Uint8 volume[2]; /* 0 = left, 1 = right */
89: } sndout_state;
90:
91: /* Maximum volume (really is attenuation) */
92: #define SND_MAX_VOL 43
93:
94: /* Valid modes */
95: #define SND_MODE_NORMAL 0x00
96: #define SND_MODE_DBL_RP 0x10
97: #define SND_MODE_DBL_ZF 0x30
98:
99: /* Function prototypes */
1.1.1.2 root 100: int snd_send_samples(Uint8* bufffer, int len);
1.1 root 101: void snd_make_normal_samples(Uint8 *buf, int len);
102: void snd_make_double_samples(Uint8 *buf, int len, bool repeat);
103: void snd_adjust_volume_and_lowpass(Uint8 *buf, int len);
104: void sndout_queue_put(Uint8 *buf, int len);
105:
106: void snd_start_output(Uint8 mode) {
107: sndout_state.mode = mode;
108: /* Starting SDL Audio */
109: if (sndout_inited) {
110: Audio_Output_Enable(true);
111: } else {
1.1.1.2 root 112: Log_Printf(LOG_SND_LEVEL, "[Audio] Not starting. Audio output device not initialized.");
1.1 root 113: }
114: /* Starting sound output loop */
115: if (!sound_output_active) {
1.1.1.2 root 116: Log_Printf(LOG_SND_LEVEL, "[Sound] Starting output loop.");
1.1 root 117: sound_output_active = true;
1.1.1.2 root 118: CycInt_AddRelativeInterruptCycles(10, INTERRUPT_SND_OUT);
1.1 root 119: } else { /* Even re-enable loop if we are already active. This lowers the delay. */
1.1.1.2 root 120: Log_Printf(LOG_DEBUG, "[Sound] Restarting output loop.");
121: CycInt_AddRelativeInterruptCycles(10, INTERRUPT_SND_OUT);
1.1 root 122: }
123: }
124:
125: void snd_stop_output(void) {
1.1.1.2 root 126: sound_output_active=false;
127: }
128:
129: void snd_start_input(Uint8 mode) {
130:
131: /* Starting SDL Audio */
132: if (sndin_inited) {
133: Audio_Input_Enable(true);
134: } else if (ConfigureParams.Sound.bEnableSound) {
135: sndin_inited = true;
136: Audio_Input_Init();
137: Audio_Input_Enable(true);
1.1 root 138: }
1.1.1.2 root 139: /* Starting sound output loop */
140: if (!sound_input_active) {
141: Log_Printf(LOG_SND_LEVEL, "[Sound] Starting input loop.");
142: sound_input_active = true;
143: CycInt_AddRelativeInterruptCycles(10, INTERRUPT_SND_IN);
144: } else { /* Even re-enable loop if we are already active. This lowers the delay. */
145: Log_Printf(LOG_DEBUG, "[Sound] Restarting input loop.");
146: CycInt_AddRelativeInterruptCycles(10, INTERRUPT_SND_IN);
147: }
148: }
149:
150: void snd_stop_input(void) {
151: sound_input_active=false;
152: sndin_inited = false;
153: Audio_Input_UnInit();
1.1 root 154: }
155:
1.1.1.2 root 156: /* Sound IO loops */
157:
158: static void do_dma_sndout_intr(void) {
159: if(snd_buffer) {
160: dma_sndout_intr();
161: free(snd_buffer);
162: snd_buffer = NULL;
163: }
164: }
1.1 root 165:
1.1.1.2 root 166: /*
167: At a playback rate of 44.1kHz a sample takes about 23 microseconds.
168: Assuming that the emulation runs at least 1/3 as fast as a real m68k
169: checking the sound queue every 8 microseconds should be ok.
170: */
171: static const int SND_CHECK_DELAY = 8;
172: void SND_Out_Handler(void) {
173: int len;
1.1 root 174:
175: CycInt_AcknowledgeInterrupt();
176:
1.1.1.2 root 177: if (!sound_output_active) {
178: return;
179: }
180:
181: if (sndout_inited && Audio_Output_Queue_Size() > AUDIO_BUFFER_SAMPLES * 2) {
182: CycInt_AddRelativeInterruptUs(SND_CHECK_DELAY * AUDIO_BUFFER_SAMPLES, 0, INTERRUPT_SND_OUT);
183: return;
184: }
185:
186: do_dma_sndout_intr();
187: snd_buffer = dma_sndout_read_memory(&len);
1.1 root 188:
1.1.1.2 root 189: if (len) {
190: len = snd_send_samples(snd_buffer, len);
191: len = (len / 4) + 1;
192: CycInt_AddRelativeInterruptUs(SND_CHECK_DELAY * len, 0, INTERRUPT_SND_OUT);
1.1 root 193: } else {
1.1.1.2 root 194: kms_sndout_underrun();
195: /* Call do_dma_sndout_intr() a little bit later */
196: CycInt_AddRelativeInterruptUs(100, 0, INTERRUPT_SND_OUT);
197: }
198: }
199:
200: bool snd_output_active() {
201: return sound_output_active;
202: }
203:
204: void SND_In_Handler(void) {
205: CycInt_AcknowledgeInterrupt();
206:
207: int dma_done = dma_sndin_write_memory();
208:
209: if (dma_done) {
210: if(snd_input_active()) {
211: kms_sndin_overrun();
212: }
213: } else {
214: CycInt_AddRelativeInterruptUs(10000, 0, INTERRUPT_SND_IN);
215: }
216: }
217:
218: bool snd_input_active() {
219: return sound_input_active;
220: }
221:
222: /* This functions generates 8-bit ulaw samples from 16 bit pcm audio */
223: #define BIAS 0x84 /* define the add-in bias for 16 bit samples */
224: #define CLIP 32635
225:
226: Uint8 snd_make_ulaw(Sint16 sample) {
227: static Sint16 exp_lut[256] = {
228: 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
229: 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
230: 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
231: 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
232: 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
233: 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
234: 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
235: 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
236: 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
237: 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
238: 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
239: 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
240: 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
241: 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
242: 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
243: 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
244: };
245: Sint16 sign, exponent, mantissa;
246: Uint8 ulawbyte;
247:
248: /** get the sample into sign-magnitude **/
249: sign = (sample >> 8) & 0x80; /* set aside the sign */
250: if (sign != 0) {
251: sample = -sample; /* get magnitude */
252: }
253: /* sample can be zero because we can overflow in the inversion,
254: * checking against the unsigned version solves this */
255: if (((Uint16) sample) > CLIP)
256: sample = CLIP; /* clip the magnitude */
257:
258: /** convert from 16 bit linear to ulaw **/
259: sample = sample + BIAS;
260: exponent = exp_lut[(sample >> 7) & 0xFF];
261: mantissa = (sample >> (exponent + 3)) & 0x0F;
262: ulawbyte = ~(sign | (exponent << 4) | mantissa);
263:
264: return ulawbyte;
1.1 root 265: }
266:
267:
268: /* These functions put samples to a buffer for further processing */
1.1.1.2 root 269: void snd_make_double_samples(Uint8 *buffer, int len, bool repeat) {
270: for (int i=len - 4; i >= 0; i -= 4) {
271: buffer[i*2+7] = repeat ? buffer[i+3] : 0; /* repeat or zero-fill */
272: buffer[i*2+6] = repeat ? buffer[i+2] : 0; /* repeat or zero-fill */
273: buffer[i*2+5] = repeat ? buffer[i+1] : 0; /* repeat or zero-fill */
274: buffer[i*2+4] = repeat ? buffer[i+0] : 0; /* repeat or zero-fill */
275: buffer[i*2+3] = buffer[i+3];
276: buffer[i*2+2] = buffer[i+2];
277: buffer[i*2+1] = buffer[i+1];
278: buffer[i*2+0] = buffer[i+0];
1.1 root 279: }
280: }
281:
1.1.1.2 root 282:
283: void snd_make_normal_samples(Uint8 *buffer, int len) {
284: // do nothing
1.1 root 285: }
286:
287:
288: /* This function processes and sends out our samples */
1.1.1.2 root 289: int snd_send_samples(Uint8* buffer, int len) {
1.1 root 290: switch (sndout_state.mode) {
291: case SND_MODE_NORMAL:
1.1.1.2 root 292: snd_make_normal_samples(buffer, len);
293: snd_adjust_volume_and_lowpass(buffer, len);
294: Audio_Output_Queue(buffer, len);
295: return len;
1.1 root 296: case SND_MODE_DBL_RP:
1.1.1.2 root 297: snd_make_double_samples(buffer, len, true);
298: snd_adjust_volume_and_lowpass(buffer, 2*len);
299: Audio_Output_Queue(buffer, len);
300: Audio_Output_Queue(buffer+len, len);
301: return 2*len;
1.1 root 302: case SND_MODE_DBL_ZF:
1.1.1.2 root 303: snd_make_double_samples(buffer, len, false);
304: snd_adjust_volume_and_lowpass(buffer, 2*len);
305: Audio_Output_Queue(buffer, len);
306: Audio_Output_Queue(buffer+len, len);
307: return 2*len;
1.1 root 308: default:
309: Log_Printf(LOG_WARN, "[Sound] Error: Unknown sound output mode!");
1.1.1.2 root 310: return 0;
1.1 root 311: }
312: }
313:
314: #if 1 /* FIXME: Is this correct? */
315: /* This is a simple lowpass filter */
316: static Sint16 snd_lowpass_filter(Sint16 insample, bool left) {
317: Sint16 outsample;
318: static Sint16 lfiltersample[2] = {0,0};
319: static Sint16 rfiltersample[2] = {0,0};
320:
321: if (left) {
322: outsample = (lfiltersample[0] + (lfiltersample[1]<<1) + insample)>>2;
323: lfiltersample[0] = lfiltersample[1];
324: lfiltersample[1] = insample;
325: } else {
326: outsample = (rfiltersample[0] + (rfiltersample[1]<<1) + insample)>>2;
327: rfiltersample[0] = rfiltersample[1];
328: rfiltersample[1] = insample;
329: }
330: return outsample;
331: }
332: #endif
333:
334: /* This function adjusts sound output volume */
335: void snd_adjust_volume_and_lowpass(Uint8 *buf, int len) {
336: int i;
337: Sint16 ldata, rdata;
338: float ladjust, radjust;
1.1.1.2 root 339: if (sndout_state.mute) {
340: for (i=0; i<len; i++) {
341: buf[i] = 0;
342: }
343: } else if (sndout_state.volume[0] || sndout_state.volume[1] || sndout_state.lowpass) {
1.1 root 344: ladjust = (sndout_state.volume[0]==0)?1:(1-log(sndout_state.volume[0])/log(SND_MAX_VOL));
345: radjust = (sndout_state.volume[1]==0)?1:(1-log(sndout_state.volume[1])/log(SND_MAX_VOL));
346:
347: for (i=0; i<len; i+=4) {
348: ldata = (Sint16)((buf[i]<<8)|buf[i+1]);
349: rdata = (Sint16)((buf[i+2]<<8)|buf[i+3]);
350: #if 1 /* Append lowpass filter */
351: if (sndout_state.lowpass) {
352: ldata = snd_lowpass_filter(ldata, true);
353: rdata = snd_lowpass_filter(rdata, false);
354: }
355: #endif
356: ldata = ldata*ladjust;
357: rdata = rdata*radjust;
358: buf[i] = ldata>>8;
359: buf[i+1] = ldata;
360: buf[i+2] = rdata>>8;
361: buf[i+3] = rdata;
362: }
363: }
364: }
365:
366:
367: /* Internal volume control register access (shifted in left to right)
368: *
369: * xxx ---- ---- unused bits
370: * --- xx-- ---- channel (0x80 = right, 0x40 = left)
371: * --- --xx xxxx volume
372: */
373:
374: Uint8 tmp_vol;
375: Uint8 chan_lr;
376: int bit_num;
377:
1.1.1.2 root 378: static void snd_access_volume_reg(Uint8 databit) {
1.1 root 379: Log_Printf(LOG_VOL_LEVEL, "[Sound] Interface shift bit %i (%i).",bit_num,databit?1:0);
380:
381: if (bit_num<3) {
382: /* nothing to do */
383: } else if (bit_num<5) {
384: chan_lr = (chan_lr<<1)|(databit?1:0);
385: } else if (bit_num<11) {
386: tmp_vol = (tmp_vol<<1)|(databit?1:0);
387: }
388: bit_num++;
389: }
390:
1.1.1.2 root 391: static void snd_volume_interface_reset(void) {
1.1 root 392: Log_Printf(LOG_VOL_LEVEL, "[Sound] Interface reset.");
393:
394: bit_num = 0;
395: chan_lr = 0;
396: tmp_vol = 0;
397: }
398:
1.1.1.2 root 399: static void snd_save_volume_reg(void) {
1.1 root 400: if (bit_num!=11) {
401: Log_Printf(LOG_WARN, "[Sound] Incomplete volume transfer (%i bits).",bit_num);
402: return;
403: }
404: if (tmp_vol>SND_MAX_VOL) {
405: Log_Printf(LOG_WARN, "[Sound] Volume limit exceeded (%i).",tmp_vol);
406: tmp_vol=SND_MAX_VOL;
407: }
408: if (chan_lr&1) {
409: Log_Printf(LOG_WARN, "[Sound] Setting volume of left channel to %i",tmp_vol);
410: sndout_state.volume[0] = tmp_vol;
411: }
412: if (chan_lr&2) {
413: Log_Printf(LOG_WARN, "[Sound] Setting volume of right channel to %i",tmp_vol);
414: sndout_state.volume[1] = tmp_vol;
415: }
416: }
417:
418: /* This function fills the internal volume register */
419: #define SND_SPEAKER_ENABLE 0x10
420: #define SND_LOWPASS_ENABLE 0x08
421:
422: #define SND_INTFC_CLOCK 0x04
423: #define SND_INTFC_DATA 0x02
424: #define SND_INTFC_STROBE 0x01
425:
426: Uint8 old_data;
427:
428: void snd_gpo_access(Uint8 data) {
429: Log_Printf(LOG_VOL_LEVEL, "[Sound] Control logic access: %02X",data);
430:
431: sndout_state.mute = data&SND_SPEAKER_ENABLE;
432: sndout_state.lowpass = data&SND_LOWPASS_ENABLE;
433:
434: if (data&SND_INTFC_STROBE) {
435: snd_save_volume_reg();
436: } else if ((data&SND_INTFC_CLOCK) && !(old_data&SND_INTFC_CLOCK)) {
437: snd_access_volume_reg(data&SND_INTFC_DATA);
438: } else if ((data&SND_INTFC_CLOCK) == (old_data&SND_INTFC_CLOCK)) {
439: snd_volume_interface_reset();
440: }
441: old_data = data;
442: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.