--- previous/src/audio.c 2018/04/24 19:29:46 1.1 +++ previous/src/audio.c 2018/04/24 19:31:07 1.1.1.2 @@ -6,38 +6,109 @@ #include "audio.h" #include "dma.h" #include "snd.h" +#include "host.h" #include /* Sound emulation SDL interface */ -SDL_AudioDeviceID Audio_Input_Device; -SDL_AudioDeviceID Audio_Output_Device; +static SDL_AudioDeviceID Audio_Input_Device; +static SDL_AudioDeviceID Audio_Output_Device; -int nAudioFrequency = 44100; /* Sound playback frequency */ -bool bSoundOutputWorking = false; /* Is sound output OK */ -bool bSoundInputWorking = false; /* Is sound input OK */ -volatile bool bPlayingBuffer = false; /* Is playing buffer? */ -volatile bool bRecordingBuffer = false; /* Is recording buffer? */ +static bool bSoundOutputWorking = false; /* Is sound output OK */ +static bool bSoundInputWorking = false; /* Is sound input OK */ +static bool bSoundOutAlertShown = false; +static bool bSoundInAlertShown = false; +static bool bPlayingBuffer = false; /* Is playing buffer? */ +static bool bRecordingBuffer = false; /* Is recording buffer? */ +#define REC_BUFFER_SZ 16 /* Recording buffer size in power of two */ +static const Uint32 REC_BUFFER_MASK = (1< 0) { + if (len < chunkSize) chunkSize = len; + SDL_QueueAudio(Audio_Output_Device, data, chunkSize); + data += chunkSize; + len -= chunkSize; + } + } +} +Uint32 Audio_Output_Queue_Size() { + if (bSoundOutputWorking) { + return SDL_GetQueuedAudioSize(Audio_Output_Device) / 4; + } else { + return 0; + } +} /*-----------------------------------------------------------------------*/ /** * SDL audio callback functions - move sound between emulation and audio system. * Note: These functions will run in a separate thread. */ -static void Audio_Output_CallBack(void *userdata, Uint8 *stream, int len) -{ - //printf("AUDIO CALLBACK, size = %i\n",len); - sndout_queue_poll(stream, len); -} -static void Audio_Input_CallBack(void *userdata, Uint8 *stream, int len) -{ - /* FIXME: send data to emulator */ +static void Audio_Input_CallBack(void *userdata, Uint8 *stream, int len) { + Log_Printf(LOG_WARN, "Audio_Input_CallBack %d", len); + if(len == 0) return; + Audio_Input_Lock(); + while(len--) + recBuffer[recBufferWr++&REC_BUFFER_MASK] = *stream++; + recBufferWr &= REC_BUFFER_MASK; + recBufferWr &= ~1; /* Just to be sure */ + Audio_Input_Unlock(); +} + +void Audio_Input_Lock() { + host_lock(&recBufferLock); +} + +/* + * Initialize recording buffer with silence to compensate for time gap + * between Audio_Input_Enable and first call of Audio_Input_CallBack. + */ +#define AUDIO_RECBUF_INIT 0 /* 16000 byte = 1 second */ + +void Audio_Input_InitBuf() { + recBufferRd = 0; + for (recBufferWr = 0; recBufferWr < AUDIO_RECBUF_INIT; recBufferWr++) { + recBuffer[recBufferWr] = 0; + } +} + +int Audio_Input_Read() { + Sint16 sample = 0; + + if (bSoundInputWorking) { + if ((recBufferRd&REC_BUFFER_MASK)==(recBufferWr&REC_BUFFER_MASK)) { + return -1; + } else { + sample = ((recBuffer[recBufferRd&REC_BUFFER_MASK]<<8)|recBuffer[(recBufferRd&REC_BUFFER_MASK)+1]); + recBufferRd += 2; + recBufferRd &= REC_BUFFER_MASK; + return snd_make_ulaw(sample); + } + } else { + return snd_make_ulaw(0); // silence + } +} + +void Audio_Input_Unlock() { + host_unlock(&recBufferLock); +} + +static bool check_audio(int requested, int granted, const char* attribute) { + if(requested != granted) + Log_Printf(LOG_WARN, "[Audio] %s mismatch. Requested:%d, granted:%d", attribute, requested, granted); + return requested == granted; } - /*-----------------------------------------------------------------------*/ /** * Initialize the audio subsystem. Return true if all OK. @@ -48,11 +119,9 @@ void Audio_Output_Init(void) SDL_AudioSpec granted; /* Init the SDL's audio subsystem: */ - if (SDL_WasInit(SDL_INIT_AUDIO) == 0) - { - if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) - { - Log_Printf(LOG_WARN, "Could not init audio output: %s\n", SDL_GetError()); + if (SDL_WasInit(SDL_INIT_AUDIO) == 0) { + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + Log_Printf(LOG_WARN, "[Audio] Could not init audio output: %s\n", SDL_GetError()); DlgAlert_Notice("Error: Can't open SDL audio subsystem."); bSoundOutputWorking = false; return; @@ -60,36 +129,41 @@ void Audio_Output_Init(void) } /* Set up SDL audio: */ - request.freq = 44100; /* 44,1 kHz */ - request.format = AUDIO_S16MSB; /* 16-Bit signed, big endian */ - request.channels = 2; /* stereo */ - request.callback = Audio_Output_CallBack; + request.freq = AUDIO_OUT_FREQUENCY; /* 44,1 kHz */ + request.format = AUDIO_S16MSB; /* 16-Bit signed, big endian */ + request.channels = 2; /* stereo */ + request.callback = NULL; request.userdata = NULL; - request.samples = 1024; /* buffer size in samples (4096 byte) */ + request.samples = AUDIO_BUFFER_SAMPLES; /* buffer size in samples */ Audio_Output_Device = SDL_OpenAudioDevice(NULL, 0, &request, &granted, 0); - if (Audio_Output_Device==0) /* Open audio device */ - { - Log_Printf(LOG_WARN, "Can't use audio: %s\n", SDL_GetError()); - DlgAlert_Notice("Error: Can't open audio output device. No sound output."); + if (Audio_Output_Device==0) /* Open audio device */ { + Log_Printf(LOG_WARN, "[Audio] Can't use audio: %s\n", SDL_GetError()); + if(!bSoundOutAlertShown) { + DlgAlert_Notice("Error: Can't open audio output device. No sound output."); + bSoundOutAlertShown = true; + } bSoundOutputWorking = false; return; } - - /* All OK */ bSoundOutputWorking = true; + bSoundOutputWorking &= check_audio(request.freq, granted.freq, "freq"); + bSoundOutputWorking &= check_audio(request.format, granted.format, "format"); + bSoundOutputWorking &= check_audio(request.channels, granted.channels, "channels"); + bSoundOutputWorking &= check_audio(request.samples, granted.samples, "samples"); + + if(!(bSoundOutputWorking)) { + DlgAlert_Notice("Error: Can't open audio output device. No sound output."); + } } -void Audio_Input_Init(void) -{ +void Audio_Input_Init(void) { SDL_AudioSpec request; /* We fill in the desired SDL audio options here */ SDL_AudioSpec granted; /* Init the SDL's audio subsystem: */ - if (SDL_WasInit(SDL_INIT_AUDIO) == 0) - { - if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) - { + if (SDL_WasInit(SDL_INIT_AUDIO) == 0) { + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { Log_Printf(LOG_WARN, "Could not init audio input: %s\n", SDL_GetError()); DlgAlert_Notice("Error: Can't open SDL audio subsystem."); bSoundInputWorking = false; @@ -98,24 +172,34 @@ void Audio_Input_Init(void) } /* Set up SDL audio: */ - request.freq = 8000; - request.format = AUDIO_S16MSB; /* 16-Bit signed, big endian */ - request.channels = 1; /* mono */ + request.freq = AUDIO_IN_FREQUENCY; /* 8kHz */ + request.format = AUDIO_S16MSB; /* 16-Bit signed, big endian */ + request.channels = 1; /* mono */ request.callback = Audio_Input_CallBack; request.userdata = NULL; - request.samples = 1024; /* buffer size in samples (2048 byte) */ + request.samples = AUDIO_BUFFER_SAMPLES; /* buffer size in samples */ + + Audio_Input_Device = SDL_OpenAudioDevice(NULL, 1, &request, &granted, 0); /* Open audio device */ - Audio_Input_Device = SDL_OpenAudioDevice(NULL, 0, &request, &granted, 0); - if (Audio_Input_Device==0) /* Open audio device */ - { + if (Audio_Input_Device==0){ Log_Printf(LOG_WARN, "Can't use audio: %s\n", SDL_GetError()); - DlgAlert_Notice("Error: Can't open audio input device. No sound recording."); + if(!bSoundInAlertShown) { + DlgAlert_Notice("Error: Can't open audio input device. No sound recording (will record silence instead)."); + bSoundInAlertShown = true; + } bSoundInputWorking = false; return; } - /* All OK */ bSoundInputWorking = true; + bSoundInputWorking &= check_audio(request.freq, granted.freq, "freq"); + bSoundInputWorking &= check_audio(request.format, granted.format, "format"); + bSoundInputWorking &= check_audio(request.channels, granted.channels, "channels"); + bSoundInputWorking &= check_audio(request.samples, granted.samples, "samples"); + + if(!(bSoundInputWorking)) { + DlgAlert_Notice("Error: Can't open audio input device. No sound recording (will record silence instead)."); + } } @@ -123,10 +207,8 @@ void Audio_Input_Init(void) /** * Free audio subsystem */ -void Audio_Output_UnInit(void) -{ - if (bSoundOutputWorking) - { +void Audio_Output_UnInit(void) { + if (bSoundOutputWorking) { /* Stop */ Audio_Output_Enable(false); @@ -136,10 +218,8 @@ void Audio_Output_UnInit(void) } } -void Audio_Input_UnInit(void) -{ - if (bSoundInputWorking) - { +void Audio_Input_UnInit(void) { + if (bSoundInputWorking) { /* Stop */ Audio_Input_Enable(false); @@ -149,92 +229,32 @@ void Audio_Input_UnInit(void) } } - -/*-----------------------------------------------------------------------*/ -/** - * Lock the audio sub system so that the callback function will not be called. - */ -void Audio_Output_Lock(void) -{ - SDL_LockAudioDevice(Audio_Output_Device); -} - -void Audio_Input_Lock(void) -{ - SDL_LockAudioDevice(Audio_Input_Device); -} - - -/*-----------------------------------------------------------------------*/ -/** - * Unlock the audio sub system so that the callback function will be called again. - */ -void Audio_Output_Unlock(void) -{ - SDL_UnlockAudioDevice(Audio_Output_Device); -} - -void Audio_Input_Unlock(void) -{ - SDL_UnlockAudioDevice(Audio_Input_Device); -} - - -/*-----------------------------------------------------------------------*/ -/** - * Set audio playback frequency variable, pass as PLAYBACK_xxxx - */ -void Audio_Output_SetFreq(int nNewFrequency) -{ - /* Do not reset sound system if nothing has changed! */ - if (nNewFrequency != nAudioFrequency) - { - Log_Printf(LOG_WARN, "[SDL Audio] Changing frequency from %i Hz to %i Hz", - nAudioFrequency,nNewFrequency); - /* Set new frequency */ - nAudioFrequency = nNewFrequency; - - /* Re-open SDL audio interface if necessary: */ - if (bSoundOutputWorking) - { - Audio_Output_UnInit(); - Audio_Output_Init(); - } - } -} - - /*-----------------------------------------------------------------------*/ /** * Start/Stop sound buffer */ -void Audio_Output_Enable(bool bEnable) -{ - if (bEnable && !bPlayingBuffer) - { +void Audio_Output_Enable(bool bEnable) { + if (bEnable && !bPlayingBuffer) { /* Start playing */ SDL_PauseAudioDevice(Audio_Output_Device, false); bPlayingBuffer = true; } - else if (!bEnable && bPlayingBuffer) - { + else if (!bEnable && bPlayingBuffer) { /* Stop from playing */ SDL_PauseAudioDevice(Audio_Output_Device, true); bPlayingBuffer = false; } } -void Audio_Input_Enable(bool bEnable) -{ - if (bEnable && !bRecordingBuffer) - { - /* Start playing */ +void Audio_Input_Enable(bool bEnable) { + if (bEnable && !bRecordingBuffer) { + /* Start recording */ + Audio_Input_InitBuf(); SDL_PauseAudioDevice(Audio_Input_Device, false); bRecordingBuffer = true; } - else if (!bEnable && bPlayingBuffer) - { - /* Stop from playing */ + else if (!bEnable && bRecordingBuffer) { + /* Stop recording */ SDL_PauseAudioDevice(Audio_Input_Device, true); bRecordingBuffer = false; }