cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

Sound_Queue.cpp (4098B)


      1
      2// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
      3
      4#include "Sound_Queue.h"
      5
      6#include <assert.h>
      7#include <string.h>
      8#include <string>
      9
     10/* Copyright (C) 2005 by Shay Green. Permission is hereby granted, free of
     11charge, to any person obtaining a copy of this software module and associated
     12documentation files (the "Software"), to deal in the Software without
     13restriction, including without limitation the rights to use, copy, modify,
     14merge, publish, distribute, sublicense, and/or sell copies of the Software, and
     15to permit persons to whom the Software is furnished to do so, subject to the
     16following conditions: The above copyright notice and this permission notice
     17shall be included in all copies or substantial portions of the Software. THE
     18SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
     19INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
     20PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
     21COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
     22IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     23CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
     24
     25// Return current SDL_GetError() string, or str if SDL didn't have a string
     26static const char* sdl_error( const char* str )
     27{
     28	const char* sdl_str = SDL_GetError();
     29	if ( sdl_str && *sdl_str )
     30		str = sdl_str;
     31	return str;
     32}
     33
     34Sound_Queue::Sound_Queue()
     35{
     36	bufs = NULL;
     37	free_sem = NULL;
     38	sound_open = false;
     39	sync_output = true;
     40
     41	std::string platform = SDL_GetPlatform();
     42	if (platform == "Linux")
     43	{
     44		SDL_InitSubSystem(SDL_INIT_AUDIO);
     45		SDL_AudioInit("alsa");
     46	}
     47	else
     48	{
     49		SDL_Init(SDL_INIT_AUDIO);
     50	}
     51
     52	atexit(SDL_Quit);
     53}
     54
     55Sound_Queue::~Sound_Queue()
     56{
     57	stop();
     58}
     59
     60const char* Sound_Queue::start( long sample_rate, int chan_count )
     61{
     62	assert( !bufs ); // can only be initialized once
     63
     64	write_buf = 0;
     65	write_pos = 0;
     66	read_buf = 0;
     67
     68	bufs = new sample_t [(long) buf_size * buf_count];
     69	if ( !bufs )
     70		return "Out of memory";
     71	currently_playing_ = bufs;
     72
     73	for (long l = 0; l < ((long) buf_size * buf_count); l++)
     74		bufs[0] = 0;
     75
     76	free_sem = SDL_CreateSemaphore( buf_count - 1 );
     77	if ( !free_sem )
     78		return sdl_error( "Couldn't create semaphore" );
     79
     80	SDL_AudioSpec as;
     81	as.freq = (int)sample_rate;
     82	as.format = AUDIO_S16SYS;
     83	as.channels = chan_count;
     84	as.silence = 0;
     85	as.samples = buf_size / chan_count;
     86	as.size = 0;
     87	as.callback = fill_buffer_;
     88	as.userdata = this;
     89	if ( SDL_OpenAudio( &as, NULL ) < 0 )
     90		return sdl_error( "Couldn't open SDL audio" );
     91	SDL_PauseAudio( false );
     92	sound_open = true;
     93
     94	return NULL;
     95}
     96
     97void Sound_Queue::stop()
     98{
     99	if ( sound_open )
    100	{
    101		sound_open = false;
    102		SDL_PauseAudio( true );
    103		SDL_CloseAudio();
    104	}
    105
    106	if ( free_sem )
    107	{
    108		SDL_DestroySemaphore( free_sem );
    109		free_sem = NULL;
    110	}
    111
    112	delete [] bufs;
    113	bufs = NULL;
    114}
    115
    116int Sound_Queue::sample_count() const
    117{
    118	int buf_free = SDL_SemValue( free_sem ) * buf_size + (buf_size - write_pos);
    119	return buf_size * buf_count - buf_free;
    120}
    121
    122inline Sound_Queue::sample_t* Sound_Queue::buf( int index )
    123{
    124	assert( (unsigned) index < buf_count );
    125	return bufs + (long) index * buf_size;
    126}
    127
    128void Sound_Queue::write( const sample_t* in, int count, bool sync )
    129{
    130	sync_output = sync;
    131
    132	while ( count )
    133	{
    134		int n = buf_size - write_pos;
    135		if ( n > count )
    136			n = count;
    137
    138		memcpy( buf( write_buf ) + write_pos, in, n * sizeof (sample_t) );
    139		in += n;
    140		write_pos += n;
    141		count -= n;
    142
    143		if ( write_pos >= buf_size )
    144		{
    145			write_pos = 0;
    146			write_buf = (write_buf + 1) % buf_count;
    147			
    148			if (sync_output)
    149				SDL_SemWait( free_sem );
    150		}
    151	}
    152}
    153
    154void Sound_Queue::fill_buffer( Uint8* out, int count )
    155{
    156	if ((SDL_SemValue( free_sem ) < buf_count - 1 ) || !sync_output)
    157	{
    158		currently_playing_ = buf( read_buf );
    159		memcpy( out, buf( read_buf ), count );
    160		read_buf = (read_buf + 1) % buf_count;
    161
    162		if (sync_output)
    163			SDL_SemPost( free_sem );
    164	}
    165	else
    166	{
    167		memset( out, 0, count );
    168	}
    169}
    170
    171void Sound_Queue::fill_buffer_( void* user_data, Uint8* out, int count )
    172{
    173	((Sound_Queue*) user_data)->fill_buffer( out, count );
    174}