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