Annotation of previous_trunk/src/snd.c, revision 1.1

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

unix.superglobalmegacorp.com

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