Annotation of previous/src/snd.c, revision 1.1.1.2

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.