|
|
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.