|
|
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 "kms.h" ! 10: ! 11: #define LOG_SND_LEVEL LOG_DEBUG ! 12: #define LOG_VOL_LEVEL LOG_DEBUG ! 13: ! 14: /* Initialize the audio system */ ! 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; ! 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: ! 32: static void sound_uninit(void) { ! 33: if(snd_buffer) ! 34: free(snd_buffer); ! 35: snd_buffer = NULL; ! 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: ! 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: } ! 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 */ ! 100: int snd_send_samples(Uint8* bufffer, int len); ! 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 { ! 112: Log_Printf(LOG_SND_LEVEL, "[Audio] Not starting. Audio output device not initialized."); ! 113: } ! 114: /* Starting sound output loop */ ! 115: if (!sound_output_active) { ! 116: Log_Printf(LOG_SND_LEVEL, "[Sound] Starting output loop."); ! 117: sound_output_active = true; ! 118: CycInt_AddRelativeInterruptCycles(10, INTERRUPT_SND_OUT); ! 119: } else { /* Even re-enable loop if we are already active. This lowers the delay. */ ! 120: Log_Printf(LOG_DEBUG, "[Sound] Restarting output loop."); ! 121: CycInt_AddRelativeInterruptCycles(10, INTERRUPT_SND_OUT); ! 122: } ! 123: } ! 124: ! 125: void snd_stop_output(void) { ! 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); ! 138: } ! 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(); ! 154: } ! 155: ! 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: } ! 165: ! 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; ! 174: ! 175: CycInt_AcknowledgeInterrupt(); ! 176: ! 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); ! 188: ! 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); ! 193: } else { ! 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; ! 265: } ! 266: ! 267: ! 268: /* These functions put samples to a buffer for further processing */ ! 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]; ! 279: } ! 280: } ! 281: ! 282: ! 283: void snd_make_normal_samples(Uint8 *buffer, int len) { ! 284: // do nothing ! 285: } ! 286: ! 287: ! 288: /* This function processes and sends out our samples */ ! 289: int snd_send_samples(Uint8* buffer, int len) { ! 290: switch (sndout_state.mode) { ! 291: case SND_MODE_NORMAL: ! 292: snd_make_normal_samples(buffer, len); ! 293: snd_adjust_volume_and_lowpass(buffer, len); ! 294: Audio_Output_Queue(buffer, len); ! 295: return len; ! 296: case SND_MODE_DBL_RP: ! 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; ! 302: case SND_MODE_DBL_ZF: ! 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; ! 308: default: ! 309: Log_Printf(LOG_WARN, "[Sound] Error: Unknown sound output mode!"); ! 310: return 0; ! 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; ! 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) { ! 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: ! 378: static void snd_access_volume_reg(Uint8 databit) { ! 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: ! 391: static void snd_volume_interface_reset(void) { ! 392: Log_Printf(LOG_VOL_LEVEL, "[Sound] Interface reset."); ! 393: ! 394: bit_num = 0; ! 395: chan_lr = 0; ! 396: tmp_vol = 0; ! 397: } ! 398: ! 399: static void snd_save_volume_reg(void) { ! 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.