diff options
| author | Louis Burda <quent.burda@gmail.com> | 2022-06-02 15:28:40 +0200 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2022-06-02 15:28:40 +0200 |
| commit | 5bc16063c29aa4d3d287ebd163ccdbcbf54c4f9f (patch) | |
| tree | c131f947a37b3af2d14d41e9eda098bdec2d061c /gearboy/platforms/audio-shared | |
| parent | 78a5f810b22f0d8cafa05f638b0cb2e889824859 (diff) | |
| download | cscg2022-gearboy-master.tar.gz cscg2022-gearboy-master.zip | |
Diffstat (limited to 'gearboy/platforms/audio-shared')
| -rw-r--r-- | gearboy/platforms/audio-shared/Sound_Queue.cpp | 174 | ||||
| -rw-r--r-- | gearboy/platforms/audio-shared/Sound_Queue.h | 51 |
2 files changed, 225 insertions, 0 deletions
diff --git a/gearboy/platforms/audio-shared/Sound_Queue.cpp b/gearboy/platforms/audio-shared/Sound_Queue.cpp new file mode 100644 index 00000000..4dd4fb1b --- /dev/null +++ b/gearboy/platforms/audio-shared/Sound_Queue.cpp @@ -0,0 +1,174 @@ + +// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/ + +#include "Sound_Queue.h" + +#include <assert.h> +#include <string.h> +#include <string> + +/* Copyright (C) 2005 by Shay Green. Permission is hereby granted, free of +charge, to any person obtaining a copy of this software module and associated +documentation files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and +to permit persons to whom the Software is furnished to do so, subject to the +following conditions: The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. THE +SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +// Return current SDL_GetError() string, or str if SDL didn't have a string +static const char* sdl_error( const char* str ) +{ + const char* sdl_str = SDL_GetError(); + if ( sdl_str && *sdl_str ) + str = sdl_str; + return str; +} + +Sound_Queue::Sound_Queue() +{ + bufs = NULL; + free_sem = NULL; + sound_open = false; + sync_output = true; + + std::string platform = SDL_GetPlatform(); + if (platform == "Linux") + { + SDL_InitSubSystem(SDL_INIT_AUDIO); + SDL_AudioInit("alsa"); + } + else + { + SDL_Init(SDL_INIT_AUDIO); + } + + atexit(SDL_Quit); +} + +Sound_Queue::~Sound_Queue() +{ + stop(); +} + +const char* Sound_Queue::start( long sample_rate, int chan_count ) +{ + assert( !bufs ); // can only be initialized once + + write_buf = 0; + write_pos = 0; + read_buf = 0; + + bufs = new sample_t [(long) buf_size * buf_count]; + if ( !bufs ) + return "Out of memory"; + currently_playing_ = bufs; + + for (long l = 0; l < ((long) buf_size * buf_count); l++) + bufs[0] = 0; + + free_sem = SDL_CreateSemaphore( buf_count - 1 ); + if ( !free_sem ) + return sdl_error( "Couldn't create semaphore" ); + + SDL_AudioSpec as; + as.freq = (int)sample_rate; + as.format = AUDIO_S16SYS; + as.channels = chan_count; + as.silence = 0; + as.samples = buf_size / chan_count; + as.size = 0; + as.callback = fill_buffer_; + as.userdata = this; + if ( SDL_OpenAudio( &as, NULL ) < 0 ) + return sdl_error( "Couldn't open SDL audio" ); + SDL_PauseAudio( false ); + sound_open = true; + + return NULL; +} + +void Sound_Queue::stop() +{ + if ( sound_open ) + { + sound_open = false; + SDL_PauseAudio( true ); + SDL_CloseAudio(); + } + + if ( free_sem ) + { + SDL_DestroySemaphore( free_sem ); + free_sem = NULL; + } + + delete [] bufs; + bufs = NULL; +} + +int Sound_Queue::sample_count() const +{ + int buf_free = SDL_SemValue( free_sem ) * buf_size + (buf_size - write_pos); + return buf_size * buf_count - buf_free; +} + +inline Sound_Queue::sample_t* Sound_Queue::buf( int index ) +{ + assert( (unsigned) index < buf_count ); + return bufs + (long) index * buf_size; +} + +void Sound_Queue::write( const sample_t* in, int count, bool sync ) +{ + sync_output = sync; + + while ( count ) + { + int n = buf_size - write_pos; + if ( n > count ) + n = count; + + memcpy( buf( write_buf ) + write_pos, in, n * sizeof (sample_t) ); + in += n; + write_pos += n; + count -= n; + + if ( write_pos >= buf_size ) + { + write_pos = 0; + write_buf = (write_buf + 1) % buf_count; + + if (sync_output) + SDL_SemWait( free_sem ); + } + } +} + +void Sound_Queue::fill_buffer( Uint8* out, int count ) +{ + if ((SDL_SemValue( free_sem ) < buf_count - 1 ) || !sync_output) + { + currently_playing_ = buf( read_buf ); + memcpy( out, buf( read_buf ), count ); + read_buf = (read_buf + 1) % buf_count; + + if (sync_output) + SDL_SemPost( free_sem ); + } + else + { + memset( out, 0, count ); + } +} + +void Sound_Queue::fill_buffer_( void* user_data, Uint8* out, int count ) +{ + ((Sound_Queue*) user_data)->fill_buffer( out, count ); +} diff --git a/gearboy/platforms/audio-shared/Sound_Queue.h b/gearboy/platforms/audio-shared/Sound_Queue.h new file mode 100644 index 00000000..d7c4230a --- /dev/null +++ b/gearboy/platforms/audio-shared/Sound_Queue.h @@ -0,0 +1,51 @@ + +// Simple sound queue for synchronous sound handling in SDL + +// Copyright (C) 2005 Shay Green. MIT license. + +#ifndef SOUND_QUEUE_H +#define SOUND_QUEUE_H + +#include <SDL.h> + +// Simple SDL sound wrapper that has a synchronous interface +class Sound_Queue { +public: + Sound_Queue(); + ~Sound_Queue(); + + // Initialize with specified sample rate and channel count. + // Returns NULL on success, otherwise error string. + const char* start( long sample_rate, int chan_count = 1 ); + + // Number of samples in buffer waiting to be played + int sample_count() const; + + // Write samples to buffer and block until enough space is available + typedef short sample_t; + void write( const sample_t*, int count, bool sync = true ); + + // Pointer to samples currently playing (for showing waveform display) + sample_t const* currently_playing() const { return currently_playing_; } + + // Stop audio output + void stop(); + +private: + enum { buf_size = 2048 }; + enum { buf_count = 3 }; + sample_t* volatile bufs; + SDL_sem* volatile free_sem; + sample_t* volatile currently_playing_; + int volatile read_buf; + int write_buf; + int write_pos; + bool sound_open; + bool sync_output; + + sample_t* buf( int index ); + void fill_buffer( Uint8*, int ); + static void fill_buffer_( void*, Uint8*, int ); +}; + +#endif |
