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

1.1       root        1: /*
1.1.1.5   root        2:   Hatari - audio.c
                      3: 
1.1.1.19  root        4:   This file is distributed under the GNU General Public License, version 2
                      5:   or at your option any later version. Read the file gpl.txt for details.
1.1.1.5   root        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 */
1.1.1.20  root       27: static volatile bool bPlayingBuffer = false;   /* Is playing buffer? */
1.1.1.15  root       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:                }
1.1.1.21  root       97:                /* Clear rest of the buffer to ensure we don't play random bytes instead */
                     98:                /* of missing samples */
                     99:                memset(pBuffer, 0, (len - nGeneratedSamples) * 4);
                    100: 
1.1.1.9   root      101:                CompleteSndBufIdx += nGeneratedSamples;
                    102:                nGeneratedSamples = 0;
1.1.1.10  root      103:                
1.1.1.9   root      104:        }
1.1.1.10  root      105: 
1.1.1.9   root      106:        CompleteSndBufIdx = CompleteSndBufIdx % MIXBUFFER_SIZE;
1.1.1.2   root      107: }
                    108: 
1.1       root      109: 
1.1.1.2   root      110: /*-----------------------------------------------------------------------*/
1.1.1.11  root      111: /**
1.1.1.14  root      112:  * Initialize the audio subsystem. Return true if all OK.
1.1.1.11  root      113:  * We use direct access to the sound buffer, set to a unsigned 8-bit mono stream.
                    114:  */
1.1.1.2   root      115: void Audio_Init(void)
1.1       root      116: {
1.1.1.9   root      117:        SDL_AudioSpec desiredAudioSpec;    /* We fill in the desired SDL audio options here */
1.1.1.5   root      118: 
1.1.1.9   root      119:        /* Is enabled? */
                    120:        if (!ConfigureParams.Sound.bEnableSound)
                    121:        {
                    122:                /* Stop any sound access */
                    123:                Log_Printf(LOG_DEBUG, "Sound: Disabled\n");
1.1.1.14  root      124:                bSoundWorking = false;
1.1.1.9   root      125:                return;
                    126:        }
                    127: 
                    128:        /* Init the SDL's audio subsystem: */
                    129:        if (SDL_WasInit(SDL_INIT_AUDIO) == 0)
                    130:        {
                    131:                if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
                    132:                {
1.1.1.23! root      133:                        Log_Printf(LOG_WARN, "Could not init audio: %s\n", SDL_GetError() );
1.1.1.14  root      134:                        bSoundWorking = false;
1.1.1.9   root      135:                        return;
                    136:                }
                    137:        }
                    138: 
                    139:        /* Set up SDL audio: */
1.1.1.14  root      140:        desiredAudioSpec.freq = nAudioFrequency;
1.1.1.15  root      141:        desiredAudioSpec.format = AUDIO_S16SYS;         /* 16-Bit signed */
                    142:        desiredAudioSpec.channels = 2;                  /* stereo */
1.1.1.9   root      143:        desiredAudioSpec.callback = Audio_CallBack;
                    144:        desiredAudioSpec.userdata = NULL;
                    145: 
1.1.1.15  root      146:        /* In most case, setting samples to 1024 will give an equivalent */
                    147:        /* sdl sound buffer of ~20-30 ms (depending on freq). */
                    148:        /* But setting samples to 1024 for all the freq can cause some faulty */
                    149:        /* OS sound drivers to add an important delay when playing sound at lower freq. */
                    150:        /* In that case we use SdlAudioBufferSize (in ms) to compute a value */
                    151:        /* of samples that matches the corresponding freq and buffer size. */
                    152:        if ( SdlAudioBufferSize == 0 )                  /* don't compute "samples", use default value */
                    153:                desiredAudioSpec.samples = 1024;        /* buffer size in samples */
                    154:        else
                    155:        {
                    156:                int samples = (desiredAudioSpec.freq / 1000) * SdlAudioBufferSize;
                    157:                int power2 = 1;
                    158:                while ( power2 < samples )              /* compute the power of 2 just above samples */
1.1.1.21  root      159:                        power2 *= 2;
1.1.1.15  root      160: 
                    161:                desiredAudioSpec.samples = power2;      /* number of samples corresponding to the requested SdlAudioBufferSize */
                    162:        }
                    163: 
                    164: 
                    165:        if (SDL_OpenAudio(&desiredAudioSpec, NULL))     /* Open audio device */
1.1.1.9   root      166:        {
1.1.1.23! root      167:                Log_Printf(LOG_WARN, "Can't use audio: %s\n", SDL_GetError());
1.1.1.14  root      168:                bSoundWorking = false;
                    169:                ConfigureParams.Sound.bEnableSound = false;
1.1.1.9   root      170:                SDL_QuitSubSystem(SDL_INIT_AUDIO);
                    171:                return;
                    172:        }
                    173: 
1.1.1.21  root      174: #if WITH_SDL2                                          /* SDL2 does not set desiredAudioSpec.size anymore */
                    175:        SoundBufferSize = desiredAudioSpec.samples;
                    176: #else
1.1.1.15  root      177:        SoundBufferSize = desiredAudioSpec.size;        /* May be different than the requested one! */
                    178:        SoundBufferSize /= 4;                           /* bytes -> samples (16 bit signed stereo -> 4 bytes per sample) */
1.1.1.21  root      179: #endif
1.1.1.9   root      180:        if (SoundBufferSize > MIXBUFFER_SIZE/2)
                    181:        {
1.1.1.23! root      182:                Log_Printf(LOG_WARN, "Soundbuffer size is too big (%d > %d)!\n",
        !           183:                           SoundBufferSize, MIXBUFFER_SIZE/2);
1.1.1.9   root      184:        }
                    185: 
                    186:        /* All OK */
1.1.1.14  root      187:        bSoundWorking = true;
1.1.1.9   root      188:        /* And begin */
1.1.1.14  root      189:        Audio_EnableAudio(true);
1.1       root      190: }
                    191: 
1.1.1.2   root      192: 
                    193: /*-----------------------------------------------------------------------*/
1.1.1.11  root      194: /**
                    195:  * Free audio subsystem
                    196:  */
1.1.1.2   root      197: void Audio_UnInit(void)
1.1       root      198: {
1.1.1.9   root      199:        if (bSoundWorking)
                    200:        {
                    201:                /* Stop */
1.1.1.14  root      202:                Audio_EnableAudio(false);
1.1.1.2   root      203: 
1.1.1.9   root      204:                SDL_CloseAudio();
1.1.1.7   root      205: 
1.1.1.14  root      206:                bSoundWorking = false;
1.1.1.9   root      207:        }
1.1       root      208: }
                    209: 
1.1.1.2   root      210: 
                    211: /*-----------------------------------------------------------------------*/
1.1.1.11  root      212: /**
                    213:  * Lock the audio sub system so that the callback function will not be called.
                    214:  */
1.1.1.5   root      215: void Audio_Lock(void)
1.1       root      216: {
1.1.1.9   root      217:        SDL_LockAudio();
1.1       root      218: }
                    219: 
1.1.1.2   root      220: 
                    221: /*-----------------------------------------------------------------------*/
1.1.1.11  root      222: /**
                    223:  * Unlock the audio sub system so that the callback function will be called again.
                    224:  */
1.1.1.5   root      225: void Audio_Unlock(void)
1.1       root      226: {
1.1.1.9   root      227:        SDL_UnlockAudio();
1.1       root      228: }
                    229: 
1.1.1.2   root      230: 
                    231: /*-----------------------------------------------------------------------*/
1.1.1.11  root      232: /**
                    233:  * Set audio playback frequency variable, pass as PLAYBACK_xxxx
                    234:  */
1.1.1.14  root      235: void Audio_SetOutputAudioFreq(int nNewFrequency)
1.1       root      236: {
1.1.1.9   root      237:        /* Do not reset sound system if nothing has changed! */
1.1.1.14  root      238:        if (nNewFrequency != nAudioFrequency)
1.1.1.9   root      239:        {
1.1.1.14  root      240:                /* Set new frequency */
                    241:                nAudioFrequency = nNewFrequency;
1.1.1.9   root      242: 
1.1.1.21  root      243:                if (Config_IsMachineFalcon())
1.1.1.17  root      244:                {
1.1.1.16  root      245:                        /* Compute Ratio between host computer sound frequency and Hatari's sound frequency. */
                    246:                        Crossbar_Compute_Ratio();
                    247:                }
1.1.1.21  root      248:                else if (!Config_IsMachineST())
1.1.1.17  root      249:                {
1.1.1.21  root      250:                        /* Adapt LMC filters to this new frequency */
1.1.1.16  root      251:                        DmaSnd_Init_Bass_and_Treble_Tables();
                    252:                }
                    253: 
1.1.1.9   root      254:                /* Re-open SDL audio interface if necessary: */
                    255:                if (bSoundWorking)
                    256:                {
                    257:                        Audio_UnInit();
                    258:                        Audio_Init();
                    259:                }
                    260:        }
1.1.1.17  root      261: 
1.1.1.22  root      262:        /* Apply YM2149 C10 low pass filter ? (except if forced to NONE) */
                    263:        if ( YM2149_LPF_Filter != YM2149_LPF_FILTER_NONE )
                    264:        {
                    265:                if ( Config_IsMachineST() && nAudioFrequency >= 40000 )
                    266:                        YM2149_LPF_Filter = YM2149_LPF_FILTER_LPF_STF;
                    267:                else
                    268:                        YM2149_LPF_Filter = YM2149_LPF_FILTER_PWM;
                    269:        }
1.1       root      270: }
                    271: 
1.1.1.2   root      272: 
                    273: /*-----------------------------------------------------------------------*/
1.1.1.11  root      274: /**
                    275:  * Start/Stop sound buffer
                    276:  */
1.1.1.12  root      277: void Audio_EnableAudio(bool bEnable)
1.1       root      278: {
1.1.1.9   root      279:        if (bEnable && !bPlayingBuffer)
                    280:        {
                    281:                /* Start playing */
1.1.1.14  root      282:                SDL_PauseAudio(false);
                    283:                bPlayingBuffer = true;
1.1.1.9   root      284:        }
                    285:        else if (!bEnable && bPlayingBuffer)
                    286:        {
                    287:                /* Stop from playing */
1.1.1.14  root      288:                SDL_PauseAudio(true);
                    289:                bPlayingBuffer = false;
1.1.1.9   root      290:        }
1.1       root      291: }

unix.superglobalmegacorp.com

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