|
|
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"
9: #include "queue.h"
10:
11: #define LOG_SND_LEVEL LOG_DEBUG
12: #define LOG_VOL_LEVEL LOG_DEBUG
13:
14: /* Note: Buffer limit must not be greather than queue packet size and
15: * must match requested.samples * samplesize (4) from audio.c
16: */
17: #define SND_BUFFER_LIMIT 4096
18:
19:
20: /* queue prototypes */
21: queueADT sndout_q;
22:
23:
24: /* Initialize the audio system */
25: bool sndout_inited;
26: bool sound_output_active = false;
27:
28: void sound_init(void) {
29: snd_buffer.limit=SND_BUFFER_LIMIT;
30: snd_buffer.size=0;
31: if (!sndout_inited && ConfigureParams.Sound.bEnableSound) {
32: Log_Printf(LOG_WARN, "[Audio] Initializing audio device.");
33: Audio_Output_Init();
34: sndout_q = QueueCreate();
35: sndout_inited=true;
36: }
37: }
38:
39: void sound_uninit(void) {
40: if(sndout_inited) {
41: Log_Printf(LOG_WARN, "[Audio] Uninitializing audio device.");
42: sndout_inited=false;
43: Audio_Output_UnInit();
44: QueueDestroy(sndout_q);
45: }
46: }
47:
48: void Sound_Reset(void) {
49: sound_uninit();
50: sound_init();
51: if (sound_output_active && sndout_inited) {
52: Audio_Output_Enable(true);
53: }
54: }
55:
56:
57: /* Start and stop sound output */
58: struct {
59: Uint8 mode;
60: Uint8 mute;
61: Uint8 lowpass;
62: Uint8 volume[2]; /* 0 = left, 1 = right */
63: } sndout_state;
64:
65: /* Maximum volume (really is attenuation) */
66: #define SND_MAX_VOL 43
67:
68: /* Valid modes */
69: #define SND_MODE_NORMAL 0x00
70: #define SND_MODE_DBL_RP 0x10
71: #define SND_MODE_DBL_ZF 0x30
72:
73: /* Function prototypes */
74: void snd_send_samples(void);
75: void snd_make_normal_samples(Uint8 *buf, int len);
76: void snd_make_double_samples(Uint8 *buf, int len, bool repeat);
77: void snd_adjust_volume_and_lowpass(Uint8 *buf, int len);
78: void sndout_queue_put(Uint8 *buf, int len);
79:
80: void snd_start_output(Uint8 mode) {
81: sndout_state.mode = mode;
82: /* Starting SDL Audio */
83: if (sndout_inited) {
84: Audio_Output_Enable(true);
85: } else {
86: Log_Printf(LOG_SND_LEVEL, "[Audio] Not starting. Audio device not initialized.");
87: }
88: /* Starting sound output loop */
89: if (!sound_output_active) {
90: Log_Printf(LOG_SND_LEVEL, "[Sound] Starting loop.");
91: sound_output_active = true;
92: CycInt_AddRelativeInterrupt(100, INT_CPU_CYCLE, INTERRUPT_SND_IO);
93: } else { /* Even re-enable loop if we are already active. This lowers the delay. */
94: Log_Printf(LOG_WARN, "[Sound] Restarting loop.");
95: CycInt_AddRelativeInterrupt(100, INT_CPU_CYCLE, INTERRUPT_SND_IO);
96: }
97: }
98:
99: void snd_stop_output(void) {
100: if (sound_output_active) {
101: sound_output_active=false;
102: }
103: }
104:
105:
106: /* Sound IO loop (reads via DMA from memory to queue) */
107: #define SND_DELAY 100000
108: int old_size;
109: int queue_size;
110:
111: void SND_IO_Handler(void) {
112: CycInt_AcknowledgeInterrupt();
113:
114: old_size = snd_buffer.size;
115: dma_sndout_read_memory();
116:
117: if (!sndout_inited || sndout_state.mute) {
118: snd_buffer.limit = SND_BUFFER_LIMIT;
119: snd_buffer.size = 0;
120: if (!sound_output_active)
121: return;
122: } else {
123: Audio_Output_Lock();
124: queue_size = QueuePeek(sndout_q);
125: Audio_Output_Unlock();
126: if (queue_size<4) {
127: if (snd_buffer.size==SND_BUFFER_LIMIT || snd_buffer.size==old_size) {
128: Log_Printf(LOG_SND_LEVEL, "[Sound] %i samples ready.",snd_buffer.size/4);
129: snd_buffer.limit = snd_buffer.size;
130: snd_send_samples();
131: snd_buffer.limit = SND_BUFFER_LIMIT;
132: snd_buffer.size = 0; /* Must be 0 */
133: }
134:
135: if (!sound_output_active)
136: return;
137: }
138: } /* if queuepeek<4 */
139: CycInt_AddRelativeInterrupt(SND_DELAY, INT_CPU_CYCLE, INTERRUPT_SND_IO);
140: }
141:
142:
143: /* These functions put samples to a buffer for further processing */
144: void snd_make_double_samples(Uint8 *buf, int len, bool repeat) {
145: int i;
146: for (i=0; i<(len*2); i++) {
147: if (snd_buffer.size>0) {
148: buf[i] = snd_buffer.data[snd_buffer.limit-snd_buffer.size];
149: buf[i+4] = repeat ? buf[i] : 0; /* repeat or zero-fill */
150: snd_buffer.size--;
151: } else { /* Fill the rest with silence */
152: buf[i] = buf[i+4] = 0;
153: }
154: if ((i&3)==3) i+=4;
155: }
156: }
157:
158: void snd_make_normal_samples(Uint8 *buf, int len) {
159: int i;
160: for (i=0; i<len; i++) {
161: if (snd_buffer.size>0) {
162: buf[i] = snd_buffer.data[snd_buffer.limit-snd_buffer.size];
163: snd_buffer.size--;
164: } else { /* Fill the rest with silence */
165: buf[i] = 0;
166: }
167: }
168: }
169:
170:
171: /* This function processes and sends out our samples */
172: void snd_send_samples(void) {
173: static Uint8 sndout_buffer[2*SND_BUFFER_LIMIT];
174:
175: switch (sndout_state.mode) {
176: case SND_MODE_NORMAL:
177: snd_make_normal_samples(sndout_buffer, SND_BUFFER_LIMIT);
178: snd_adjust_volume_and_lowpass(sndout_buffer, SND_BUFFER_LIMIT);
179: sndout_queue_put(sndout_buffer, SND_BUFFER_LIMIT);
180: break;
181: case SND_MODE_DBL_RP:
182: snd_make_double_samples(sndout_buffer, SND_BUFFER_LIMIT, true);
183: snd_adjust_volume_and_lowpass(sndout_buffer, 2*SND_BUFFER_LIMIT);
184: sndout_queue_put(sndout_buffer, SND_BUFFER_LIMIT);
185: sndout_queue_put(sndout_buffer+SND_BUFFER_LIMIT, SND_BUFFER_LIMIT);
186: break;
187: case SND_MODE_DBL_ZF:
188: snd_make_double_samples(sndout_buffer, SND_BUFFER_LIMIT, false);
189: snd_adjust_volume_and_lowpass(sndout_buffer, 2*SND_BUFFER_LIMIT);
190: sndout_queue_put(sndout_buffer, SND_BUFFER_LIMIT);
191: sndout_queue_put(sndout_buffer+SND_BUFFER_LIMIT, SND_BUFFER_LIMIT);
192: break;
193:
194: default:
195: Log_Printf(LOG_WARN, "[Sound] Error: Unknown sound output mode!");
196: break;
197: }
198: }
199:
200:
201: /* This function puts data to a queue for the audio system */
202: void sndout_queue_put(Uint8 *buf, int len) {
203: struct queuepacket *p;
204: p=(struct queuepacket *)malloc(sizeof(struct queuepacket));
205: Audio_Output_Lock();
206: p->len=len;
207: memcpy(p->data, buf, p->len);
208: QueueEnter(sndout_q,p);
209: Audio_Output_Unlock();
210: Log_Printf(LOG_SND_LEVEL, "[Sound] Output 1024 samples to queue");
211: }
212:
213:
214: /* This function is called from the audio system to poll data */
215: bool audio_flushed=false;
216:
217: void sndout_queue_poll(Uint8 *buf, int len) {
218: if (QueuePeek(sndout_q)>0) {
219: struct queuepacket *qp;
220: audio_flushed = false;
221: qp=QueueDelete(sndout_q);
222: Log_Printf(LOG_SND_LEVEL, "[Audio] Reading 1024 samples from queue.");
223: memcpy(buf,qp->data,len);
224: free(qp);
225: } else if (!sound_output_active) {
226: /* Last packet received, stop */
227: if (audio_flushed) {
228: Log_Printf(LOG_SND_LEVEL, "[Audio] Done. Stopping.");
229: audio_flushed = false;
230: Audio_Output_Enable(false);
231: } else { /* Flush residual audio from device (required for SDL) */
232: Log_Printf(LOG_SND_LEVEL, "[Audio] Done. Flushing.");
233: audio_flushed = true;
234: memset(buf, 0, len);
235: }
236: } else {
237: Log_Printf(LOG_WARN, "[Audio] Not ready. No data on queue.");
238: memset(buf, 0, len);
239: }
240: }
241:
242: #if 1 /* FIXME: Is this correct? */
243: /* This is a simple lowpass filter */
244: static Sint16 snd_lowpass_filter(Sint16 insample, bool left) {
245: Sint16 outsample;
246: static Sint16 lfiltersample[2] = {0,0};
247: static Sint16 rfiltersample[2] = {0,0};
248:
249: if (left) {
250: outsample = (lfiltersample[0] + (lfiltersample[1]<<1) + insample)>>2;
251: lfiltersample[0] = lfiltersample[1];
252: lfiltersample[1] = insample;
253: } else {
254: outsample = (rfiltersample[0] + (rfiltersample[1]<<1) + insample)>>2;
255: rfiltersample[0] = rfiltersample[1];
256: rfiltersample[1] = insample;
257: }
258: return outsample;
259: }
260: #endif
261:
262: /* This function adjusts sound output volume */
263: void snd_adjust_volume_and_lowpass(Uint8 *buf, int len) {
264: int i;
265: Sint16 ldata, rdata;
266: float ladjust, radjust;
267: if (sndout_state.volume[0] || sndout_state.volume[1] || sndout_state.lowpass) {
268: ladjust = (sndout_state.volume[0]==0)?1:(1-log(sndout_state.volume[0])/log(SND_MAX_VOL));
269: radjust = (sndout_state.volume[1]==0)?1:(1-log(sndout_state.volume[1])/log(SND_MAX_VOL));
270:
271: for (i=0; i<len; i+=4) {
272: ldata = (Sint16)((buf[i]<<8)|buf[i+1]);
273: rdata = (Sint16)((buf[i+2]<<8)|buf[i+3]);
274: #if 1 /* Append lowpass filter */
275: if (sndout_state.lowpass) {
276: ldata = snd_lowpass_filter(ldata, true);
277: rdata = snd_lowpass_filter(rdata, false);
278: }
279: #endif
280: ldata = ldata*ladjust;
281: rdata = rdata*radjust;
282: buf[i] = ldata>>8;
283: buf[i+1] = ldata;
284: buf[i+2] = rdata>>8;
285: buf[i+3] = rdata;
286: }
287: }
288: }
289:
290:
291: /* Internal volume control register access (shifted in left to right)
292: *
293: * xxx ---- ---- unused bits
294: * --- xx-- ---- channel (0x80 = right, 0x40 = left)
295: * --- --xx xxxx volume
296: */
297:
298: Uint8 tmp_vol;
299: Uint8 chan_lr;
300: int bit_num;
301:
302: void snd_access_volume_reg(Uint8 databit) {
303: Log_Printf(LOG_VOL_LEVEL, "[Sound] Interface shift bit %i (%i).",bit_num,databit?1:0);
304:
305: if (bit_num<3) {
306: /* nothing to do */
307: } else if (bit_num<5) {
308: chan_lr = (chan_lr<<1)|(databit?1:0);
309: } else if (bit_num<11) {
310: tmp_vol = (tmp_vol<<1)|(databit?1:0);
311: }
312: bit_num++;
313: }
314:
315: void snd_volume_interface_reset(void) {
316: Log_Printf(LOG_VOL_LEVEL, "[Sound] Interface reset.");
317:
318: bit_num = 0;
319: chan_lr = 0;
320: tmp_vol = 0;
321: }
322:
323: void snd_save_volume_reg(void) {
324: if (bit_num!=11) {
325: Log_Printf(LOG_WARN, "[Sound] Incomplete volume transfer (%i bits).",bit_num);
326: return;
327: }
328: if (tmp_vol>SND_MAX_VOL) {
329: Log_Printf(LOG_WARN, "[Sound] Volume limit exceeded (%i).",tmp_vol);
330: tmp_vol=SND_MAX_VOL;
331: }
332: if (chan_lr&1) {
333: Log_Printf(LOG_WARN, "[Sound] Setting volume of left channel to %i",tmp_vol);
334: sndout_state.volume[0] = tmp_vol;
335: }
336: if (chan_lr&2) {
337: Log_Printf(LOG_WARN, "[Sound] Setting volume of right channel to %i",tmp_vol);
338: sndout_state.volume[1] = tmp_vol;
339: }
340: }
341:
342: /* This function fills the internal volume register */
343: #define SND_SPEAKER_ENABLE 0x10
344: #define SND_LOWPASS_ENABLE 0x08
345:
346: #define SND_INTFC_CLOCK 0x04
347: #define SND_INTFC_DATA 0x02
348: #define SND_INTFC_STROBE 0x01
349:
350: Uint8 old_data;
351:
352: void snd_gpo_access(Uint8 data) {
353: Log_Printf(LOG_VOL_LEVEL, "[Sound] Control logic access: %02X",data);
354:
355: sndout_state.mute = data&SND_SPEAKER_ENABLE;
356: sndout_state.lowpass = data&SND_LOWPASS_ENABLE;
357:
358: if (data&SND_INTFC_STROBE) {
359: snd_save_volume_reg();
360: } else if ((data&SND_INTFC_CLOCK) && !(old_data&SND_INTFC_CLOCK)) {
361: snd_access_volume_reg(data&SND_INTFC_DATA);
362: } else if ((data&SND_INTFC_CLOCK) == (old_data&SND_INTFC_CLOCK)) {
363: snd_volume_interface_reset();
364: }
365: old_data = data;
366: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.