Annotation of hatari/src/audio.c, revision 1.1.1.18

1.1       root        1: /*
1.1.1.5   root        2:   Hatari - audio.c
                      3: 
                      4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
                      6: 
                      7:   This file contains the routines which pass the audio data to the SDL library.
1.1       root        8: */
1.1.1.13  root        9: const char Audio_fileid[] = "Hatari audio.c : " __DATE__ " " __TIME__;
1.1       root       10: 
1.1.1.2   root       11: #include <SDL.h>
                     12: 
1.1       root       13: #include "main.h"
                     14: #include "audio.h"
1.1.1.6   root       15: #include "configuration.h"
1.1.1.9   root       16: #include "log.h"
1.1       root       17: #include "sound.h"
1.1.1.15  root       18: #include "dmaSnd.h"
1.1.1.16  root       19: #include "falcon/crossbar.h"
1.1       root       20: 
1.1.1.18! root       21: #include "screen.h"
        !            22: #include "video.h"     /* FIXME: video.h is dependent on HBL_PALETTE_LINES from screen.h */
        !            23: 
1.1       root       24: 
1.1.1.15  root       25: int nAudioFrequency = 44100;                   /* Sound playback frequency */
                     26: bool bSoundWorking = false;                    /* Is sound OK */
                     27: volatile bool bPlayingBuffer = false;          /* Is playing buffer? */
                     28: int SoundBufferSize = 1024 / 4;                        /* Size of sound buffer (in samples) */
                     29: int CompleteSndBufIdx;                         /* Replay-index into MixBuffer */
                     30: int SdlAudioBufferSize = 0;                    /* in ms (0 = use default) */
1.1.1.18! root       31: int pulse_swallowing_count = 0;                        /* Sound disciplined emulation rate controlled by  */
        !            32:                                                /*  window comparator and pulse swallowing counter */
1.1       root       33: 
1.1.1.2   root       34: /*-----------------------------------------------------------------------*/
1.1.1.11  root       35: /**
                     36:  * SDL audio callback function - copy emulation sound to audio system.
                     37:  */
1.1.1.7   root       38: static void Audio_CallBack(void *userdata, Uint8 *stream, int len)
1.1.1.2   root       39: {
1.1.1.12  root       40:        Sint16 *pBuffer;
1.1.1.18! root       41:        int i, window, nSamplesPerFrame;
1.1.1.7   root       42: 
1.1.1.12  root       43:        pBuffer = (Sint16 *)stream;
                     44:        len = len / 4;  // Use length in samples (16 bit stereo), not in bytes
1.1.1.9   root       45: 
1.1.1.18! root       46:        /* Adjust emulation rate within +/- 0.58% (10 cents) occasionally,
        !            47:         * to synchronize sound. Note that an octave (frequency doubling)
        !            48:         * has 12 semitones (12th root of two for a semitone), and that
        !            49:         * one semitone has 100 cents (1200th root of two for one cent).
        !            50:         * Ten cents are desired, thus, the 120th root of two minus one is
        !            51:         * multiplied by 1,000,000 to convert to microseconds, and divided
        !            52:         * by nScreenRefreshRate=60 to get a 96 microseconds swallow size.
        !            53:         * (2^(10cents/(12semitones*100cents)) - 1) * 10^6 / nScreenRefreshRate
        !            54:         * See: main.c - Main_WaitOnVbl()
        !            55:         */
        !            56: 
        !            57:        pulse_swallowing_count = 0;     /* 0 = Unaltered emulation rate */
        !            58: 
        !            59:        if (ConfigureParams.Sound.bEnableSoundSync)
        !            60:        {
        !            61:                /* Sound synchronized emulation */
        !            62:                nSamplesPerFrame = nAudioFrequency/nScreenRefreshRate;
        !            63:                window = (nSamplesPerFrame > SoundBufferSize) ? nSamplesPerFrame : SoundBufferSize;
        !            64: 
        !            65:                /* Window Comparator for SoundBufferSize */
        !            66:                if (nGeneratedSamples < window + (window >> 1))
        !            67:                /* Increase emulation rate to maintain sound synchronization */
        !            68:                        pulse_swallowing_count = -5793 / nScreenRefreshRate;
        !            69:                else
        !            70:                if (nGeneratedSamples > (window << 1) + (window >> 2))
        !            71:                /* Decrease emulation rate to maintain sound synchronization */
        !            72:                        pulse_swallowing_count = 5793 / nScreenRefreshRate;
        !            73: 
        !            74:                /* Otherwise emulation rate is unaltered. */
        !            75:        }
        !            76: 
1.1.1.9   root       77:        if (nGeneratedSamples >= len)
                     78:        {
1.1.1.10  root       79:                /* Enough samples available: Pass completed buffer to audio system
                     80:                 * by write samples into sound buffer and by converting them from
                     81:                 * 'signed' to 'unsigned' */
                     82:                for (i = 0; i < len; i++)
                     83:                {
1.1.1.12  root       84:                        *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][0];
                     85:                        *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][1];
1.1.1.10  root       86:                }
1.1.1.9   root       87:                CompleteSndBufIdx += len;
                     88:                nGeneratedSamples -= len;
                     89:        }
1.1.1.10  root       90:        else  /* Not enough samples available: */
1.1.1.9   root       91:        {
1.1.1.10  root       92:                for (i = 0; i < nGeneratedSamples; i++)
                     93:                {
1.1.1.12  root       94:                        *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][0];
                     95:                        *pBuffer++ = MixBuffer[(CompleteSndBufIdx + i) % MIXBUFFER_SIZE][1];
1.1.1.10  root       96:                }
                     97:                /* If the buffer is filled more than 50%, mirror sample buffer to fake the
                     98:                 * missing samples */
                     99:                if (nGeneratedSamples >= len/2)
                    100:                {
                    101:                        int remaining = len - nGeneratedSamples;
1.1.1.12  root      102:                        memcpy(pBuffer, stream+(nGeneratedSamples-remaining)*4, remaining*4);
1.1.1.10  root      103:                }
1.1.1.9   root      104:                CompleteSndBufIdx += nGeneratedSamples;
                    105:                nGeneratedSamples = 0;
1.1.1.10  root      106:                
1.1.1.9   root      107:        }
1.1.1.10  root      108: 
1.1.1.9   root      109:        CompleteSndBufIdx = CompleteSndBufIdx % MIXBUFFER_SIZE;
1.1.1.2   root      110: }
                    111: 
1.1       root      112: 
1.1.1.2   root      113: /*-----------------------------------------------------------------------*/
1.1.1.11  root      114: /**
1.1.1.14  root      115:  * Initialize the audio subsystem. Return true if all OK.
1.1.1.11  root      116:  * We use direct access to the sound buffer, set to a unsigned 8-bit mono stream.
                    117:  */
1.1.1.2   root      118: void Audio_Init(void)
1.1       root      119: {
1.1.1.9   root      120:        SDL_AudioSpec desiredAudioSpec;    /* We fill in the desired SDL audio options here */
1.1.1.5   root      121: 
1.1.1.9   root      122:        /* Is enabled? */
                    123:        if (!ConfigureParams.Sound.bEnableSound)
                    124:        {
                    125:                /* Stop any sound access */
                    126:                Log_Printf(LOG_DEBUG, "Sound: Disabled\n");
1.1.1.14  root      127:                bSoundWorking = false;
1.1.1.9   root      128:                return;
                    129:        }
                    130: 
                    131:        /* Init the SDL's audio subsystem: */
                    132:        if (SDL_WasInit(SDL_INIT_AUDIO) == 0)
                    133:        {
                    134:                if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
                    135:                {
                    136:                        fprintf(stderr, "Could not init audio: %s\n", SDL_GetError() );
1.1.1.14  root      137:                        bSoundWorking = false;
1.1.1.9   root      138:                        return;
                    139:                }
                    140:        }
                    141: 
                    142:        /* Set up SDL audio: */
1.1.1.14  root      143:        desiredAudioSpec.freq = nAudioFrequency;
1.1.1.15  root      144:        desiredAudioSpec.format = AUDIO_S16SYS;         /* 16-Bit signed */
                    145:        desiredAudioSpec.channels = 2;                  /* stereo */
1.1.1.9   root      146:        desiredAudioSpec.callback = Audio_CallBack;
                    147:        desiredAudioSpec.userdata = NULL;
                    148: 
1.1.1.15  root      149:        /* In most case, setting samples to 1024 will give an equivalent */
                    150:        /* sdl sound buffer of ~20-30 ms (depending on freq). */
                    151:        /* But setting samples to 1024 for all the freq can cause some faulty */
                    152:        /* OS sound drivers to add an important delay when playing sound at lower freq. */
                    153:        /* In that case we use SdlAudioBufferSize (in ms) to compute a value */
                    154:        /* of samples that matches the corresponding freq and buffer size. */
                    155:        if ( SdlAudioBufferSize == 0 )                  /* don't compute "samples", use default value */
                    156:                desiredAudioSpec.samples = 1024;        /* buffer size in samples */
                    157:        else
                    158:        {
                    159:                int samples = (desiredAudioSpec.freq / 1000) * SdlAudioBufferSize;
                    160:                int power2 = 1;
                    161:                while ( power2 < samples )              /* compute the power of 2 just above samples */
                    162:                         power2 *= 2;
                    163: 
                    164: //fprintf ( stderr , "samples %d power %d\n" , samples , power2 );
                    165:                desiredAudioSpec.samples = power2;      /* number of samples corresponding to the requested SdlAudioBufferSize */
                    166:        }
                    167: 
                    168: 
                    169:        if (SDL_OpenAudio(&desiredAudioSpec, NULL))     /* Open audio device */
1.1.1.9   root      170:        {
                    171:                fprintf(stderr, "Can't use audio: %s\n", SDL_GetError());
1.1.1.14  root      172:                bSoundWorking = false;
                    173:                ConfigureParams.Sound.bEnableSound = false;
1.1.1.9   root      174:                SDL_QuitSubSystem(SDL_INIT_AUDIO);
                    175:                return;
                    176:        }
                    177: 
1.1.1.15  root      178:        SoundBufferSize = desiredAudioSpec.size;        /* May be different than the requested one! */
                    179:        SoundBufferSize /= 4;                           /* bytes -> samples (16 bit signed stereo -> 4 bytes per sample) */
1.1.1.9   root      180:        if (SoundBufferSize > MIXBUFFER_SIZE/2)
                    181:        {
                    182:                fprintf(stderr, "Warning: Soundbuffer size is too big!\n");
                    183:        }
                    184: 
                    185:        /* All OK */
1.1.1.14  root      186:        bSoundWorking = true;
1.1.1.9   root      187:        /* And begin */
1.1.1.14  root      188:        Audio_EnableAudio(true);
1.1       root      189: }
                    190: 
1.1.1.2   root      191: 
                    192: /*-----------------------------------------------------------------------*/
1.1.1.11  root      193: /**
                    194:  * Free audio subsystem
                    195:  */
1.1.1.2   root      196: void Audio_UnInit(void)
1.1       root      197: {
1.1.1.9   root      198:        if (bSoundWorking)
                    199:        {
                    200:                /* Stop */
1.1.1.14  root      201:                Audio_EnableAudio(false);
1.1.1.2   root      202: 
1.1.1.9   root      203:                SDL_CloseAudio();
1.1.1.7   root      204: 
1.1.1.14  root      205:                bSoundWorking = false;
1.1.1.9   root      206:        }
1.1       root      207: }
                    208: 
1.1.1.2   root      209: 
                    210: /*-----------------------------------------------------------------------*/
1.1.1.11  root      211: /**
                    212:  * Lock the audio sub system so that the callback function will not be called.
                    213:  */
1.1.1.5   root      214: void Audio_Lock(void)
1.1       root      215: {
1.1.1.9   root      216:        SDL_LockAudio();
1.1       root      217: }
                    218: 
1.1.1.2   root      219: 
                    220: /*-----------------------------------------------------------------------*/
1.1.1.11  root      221: /**
                    222:  * Unlock the audio sub system so that the callback function will be called again.
                    223:  */
1.1.1.5   root      224: void Audio_Unlock(void)
1.1       root      225: {
1.1.1.9   root      226:        SDL_UnlockAudio();
1.1       root      227: }
                    228: 
1.1.1.2   root      229: 
                    230: /*-----------------------------------------------------------------------*/
1.1.1.11  root      231: /**
                    232:  * Set audio playback frequency variable, pass as PLAYBACK_xxxx
                    233:  */
1.1.1.14  root      234: void Audio_SetOutputAudioFreq(int nNewFrequency)
1.1       root      235: {
1.1.1.9   root      236:        /* Do not reset sound system if nothing has changed! */
1.1.1.14  root      237:        if (nNewFrequency != nAudioFrequency)
1.1.1.9   root      238:        {
1.1.1.14  root      239:                /* Set new frequency */
                    240:                nAudioFrequency = nNewFrequency;
1.1.1.9   root      241: 
1.1.1.17  root      242:                if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
                    243:                {
1.1.1.16  root      244:                        /* Compute Ratio between host computer sound frequency and Hatari's sound frequency. */
                    245:                        Crossbar_Compute_Ratio();
                    246:                }
1.1.1.17  root      247:                else if (ConfigureParams.System.nMachineType != MACHINE_ST)
                    248:                {
1.1.1.16  root      249:                        /* Adapt LMC filters to this new frequency */                   
                    250:                        DmaSnd_Init_Bass_and_Treble_Tables();
                    251:                }
                    252: 
1.1.1.9   root      253:                /* Re-open SDL audio interface if necessary: */
                    254:                if (bSoundWorking)
                    255:                {
                    256:                        Audio_UnInit();
                    257:                        Audio_Init();
                    258:                }
                    259:        }
1.1.1.17  root      260: 
                    261:        if ((ConfigureParams.System.nMachineType == MACHINE_ST) &&
                    262:                (nAudioFrequency == 44100 || nAudioFrequency == 48000))
                    263:        {
                    264:                /* Apply YM2149 C10 filter. */
                    265:                UseLowPassFilter = true;
                    266:        }
                    267:        else
                    268:        {
                    269:                UseLowPassFilter = false;
                    270:        }
1.1       root      271: }
                    272: 
1.1.1.2   root      273: 
                    274: /*-----------------------------------------------------------------------*/
1.1.1.11  root      275: /**
                    276:  * Start/Stop sound buffer
                    277:  */
1.1.1.12  root      278: void Audio_EnableAudio(bool bEnable)
1.1       root      279: {
1.1.1.9   root      280:        if (bEnable && !bPlayingBuffer)
                    281:        {
                    282:                /* Start playing */
1.1.1.14  root      283:                SDL_PauseAudio(false);
                    284:                bPlayingBuffer = true;
1.1.1.9   root      285:        }
                    286:        else if (!bEnable && bPlayingBuffer)
                    287:        {
                    288:                /* Stop from playing */
1.1.1.14  root      289:                SDL_PauseAudio(true);
                    290:                bPlayingBuffer = false;
1.1.1.9   root      291:        }
1.1       root      292: }

unix.superglobalmegacorp.com

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