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

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:                {
                    133:                        fprintf(stderr, "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:        {
                    167:                fprintf(stderr, "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:        {
                    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.21! root      242:                if (Config_IsMachineFalcon())
1.1.1.17  root      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.21! root      247:                else if (!Config_IsMachineST())
1.1.1.17  root      248:                {
1.1.1.21! root      249:                        /* Adapt LMC filters to this new frequency */
1.1.1.16  root      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: 
1.1.1.21! root      261:        /* Apply YM2149 C10 filter? */
        !           262:        UseLowPassFilter = Config_IsMachineST() && nAudioFrequency >= 40000;
1.1       root      263: }
                    264: 
1.1.1.2   root      265: 
                    266: /*-----------------------------------------------------------------------*/
1.1.1.11  root      267: /**
                    268:  * Start/Stop sound buffer
                    269:  */
1.1.1.12  root      270: void Audio_EnableAudio(bool bEnable)
1.1       root      271: {
1.1.1.9   root      272:        if (bEnable && !bPlayingBuffer)
                    273:        {
                    274:                /* Start playing */
1.1.1.14  root      275:                SDL_PauseAudio(false);
                    276:                bPlayingBuffer = true;
1.1.1.9   root      277:        }
                    278:        else if (!bEnable && bPlayingBuffer)
                    279:        {
                    280:                /* Stop from playing */
1.1.1.14  root      281:                SDL_PauseAudio(true);
                    282:                bPlayingBuffer = false;
1.1.1.9   root      283:        }
1.1       root      284: }

unix.superglobalmegacorp.com

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