cscg22-gearboy

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

Multi_Buffer.cpp (6973B)


      1// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
      2
      3#include "Multi_Buffer.h"
      4
      5/* Copyright (C) 2003-2007 Shay Green. This module is free software; you
      6can redistribute it and/or modify it under the terms of the GNU Lesser
      7General Public License as published by the Free Software Foundation; either
      8version 2.1 of the License, or (at your option) any later version. This
      9module is distributed in the hope that it will be useful, but WITHOUT ANY
     10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
     12details. You should have received a copy of the GNU Lesser General Public
     13License along with this module; if not, write to the Free Software Foundation,
     14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
     15
     16#include "blargg_source.h"
     17
     18#ifdef BLARGG_ENABLE_OPTIMIZER
     19	#include BLARGG_ENABLE_OPTIMIZER
     20#endif
     21
     22Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf )
     23{
     24	length_                 = 0;
     25	sample_rate_            = 0;
     26	channels_changed_count_ = 1;
     27	channel_types_          = 0;
     28	channel_count_          = 0;
     29	immediate_removal_      = true;
     30}
     31
     32Multi_Buffer::channel_t Multi_Buffer::channel( int /*index*/ )
     33{
     34	static channel_t const ch = { 0, 0, 0 };
     35	return ch;
     36}
     37
     38// Silent_Buffer
     39
     40Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse
     41{
     42	// TODO: better to use empty Blip_Buffer so caller never has to check for NULL?
     43	chan.left   = 0;
     44	chan.center = 0;
     45	chan.right  = 0;
     46}
     47
     48// Mono_Buffer
     49
     50Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 )
     51{
     52	chan.center = &buf;
     53	chan.left   = &buf;
     54	chan.right  = &buf;
     55}
     56
     57Mono_Buffer::~Mono_Buffer() { }
     58
     59blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec )
     60{
     61	RETURN_ERR( buf.set_sample_rate( rate, msec ) );
     62	return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() );
     63}
     64
     65
     66// Tracked_Blip_Buffer
     67
     68Tracked_Blip_Buffer::Tracked_Blip_Buffer()
     69{
     70	last_non_silence = 0;
     71}
     72
     73void Tracked_Blip_Buffer::clear()
     74{
     75	last_non_silence = 0;
     76	Blip_Buffer::clear();
     77}
     78
     79void Tracked_Blip_Buffer::end_frame( blip_time_t t )
     80{
     81	Blip_Buffer::end_frame( t );
     82	if ( clear_modified() )
     83		last_non_silence = (int)samples_avail() + blip_buffer_extra_;
     84}
     85
     86blip_ulong Tracked_Blip_Buffer::non_silent() const
     87{
     88	return last_non_silence | unsettled();
     89}
     90
     91inline void Tracked_Blip_Buffer::remove_( long n )
     92{
     93	if ( (last_non_silence -= n) < 0 )
     94		last_non_silence = 0;
     95}
     96
     97void Tracked_Blip_Buffer::remove_silence( long n )
     98{
     99	remove_( n );
    100	Blip_Buffer::remove_silence( n );
    101}
    102
    103void Tracked_Blip_Buffer::remove_samples( long n )
    104{
    105	remove_( n );
    106	Blip_Buffer::remove_samples( n );
    107}
    108
    109void Tracked_Blip_Buffer::remove_all_samples()
    110{
    111	long avail = samples_avail();
    112	if ( !non_silent() )
    113		remove_silence( avail );
    114	else
    115		remove_samples( avail );
    116}
    117
    118long Tracked_Blip_Buffer::read_samples( blip_sample_t* out, long count )
    119{
    120	count = Blip_Buffer::read_samples( out, count );
    121	remove_( count );
    122	return count;
    123}
    124
    125// Stereo_Buffer
    126
    127int const stereo = 2;
    128
    129Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 )
    130{
    131	chan.center = mixer.bufs [2] = &bufs [2];
    132	chan.left   = mixer.bufs [0] = &bufs [0];
    133	chan.right  = mixer.bufs [1] = &bufs [1];
    134	mixer.samples_read = 0;
    135}
    136
    137Stereo_Buffer::~Stereo_Buffer() { }
    138
    139blargg_err_t Stereo_Buffer::set_sample_rate( long rate, int msec )
    140{
    141	mixer.samples_read = 0;
    142	for ( int i = bufs_size; --i >= 0; )
    143		RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) );
    144	return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() );
    145}
    146
    147void Stereo_Buffer::clock_rate( long rate )
    148{
    149	for ( int i = bufs_size; --i >= 0; )
    150		bufs [i].clock_rate( rate );
    151}
    152
    153void Stereo_Buffer::bass_freq( int bass )
    154{
    155	for ( int i = bufs_size; --i >= 0; )
    156		bufs [i].bass_freq( bass );
    157}
    158
    159void Stereo_Buffer::clear()
    160{
    161	mixer.samples_read = 0;
    162	for ( int i = bufs_size; --i >= 0; )
    163		bufs [i].clear();
    164}
    165
    166void Stereo_Buffer::end_frame( blip_time_t time )
    167{
    168	for ( int i = bufs_size; --i >= 0; )
    169		bufs [i].end_frame( time );
    170}
    171
    172long Stereo_Buffer::read_samples( blip_sample_t* out, long out_size )
    173{
    174	require( (out_size & 1) == 0 ); // must read an even number of samples
    175	out_size = min( out_size, samples_avail() );
    176
    177	int pair_count = int (out_size >> 1);
    178	if ( pair_count )
    179	{
    180		mixer.read_pairs( out, pair_count );
    181
    182		if ( samples_avail() <= 0 || immediate_removal() )
    183		{
    184			for ( int i = bufs_size; --i >= 0; )
    185			{
    186				buf_t& b = bufs [i];
    187				// TODO: might miss non-silence settling since it checks END of last read
    188				if ( !b.non_silent() )
    189					b.remove_silence( mixer.samples_read );
    190				else
    191					b.remove_samples( mixer.samples_read );
    192			}
    193			mixer.samples_read = 0;
    194		}
    195	}
    196	return out_size;
    197}
    198
    199
    200// Stereo_Mixer
    201
    202// mixers use a single index value to improve performance on register-challenged processors
    203// offset goes from negative to zero
    204
    205void Stereo_Mixer::read_pairs( blip_sample_t* out, int count )
    206{
    207	// TODO: if caller never marks buffers as modified, uses mono
    208	// except that buffer isn't cleared, so caller can encounter
    209	// subtle problems and not realize the cause.
    210	samples_read += count;
    211	if ( bufs [0]->non_silent() | bufs [1]->non_silent() )
    212		mix_stereo( out, count );
    213	else
    214		mix_mono( out, count );
    215}
    216
    217void Stereo_Mixer::mix_mono( blip_sample_t* out_, int count )
    218{
    219	int const bass = BLIP_READER_BASS( *bufs [2] );
    220	BLIP_READER_BEGIN( center, *bufs [2] );
    221	BLIP_READER_ADJ_( center, samples_read );
    222
    223	typedef blip_sample_t stereo_blip_sample_t [stereo];
    224	stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_ + count;
    225	int offset = -count;
    226	do
    227	{
    228		blargg_long s = BLIP_READER_READ( center );
    229		BLIP_READER_NEXT_IDX_( center, bass, offset );
    230		BLIP_CLAMP( s, s );
    231
    232		out [offset] [0] = (blip_sample_t) s;
    233		out [offset] [1] = (blip_sample_t) s;
    234	}
    235	while ( ++offset );
    236
    237	BLIP_READER_END( center, *bufs [2] );
    238}
    239
    240void Stereo_Mixer::mix_stereo( blip_sample_t* out_, int count )
    241{
    242	blip_sample_t* BLIP_RESTRICT out = out_ + count * stereo;
    243
    244	// do left + center and right + center separately to reduce register load
    245	Tracked_Blip_Buffer* const* buf = &bufs [2];
    246	while ( true ) // loop runs twice
    247	{
    248		--buf;
    249		--out;
    250
    251		int const bass = BLIP_READER_BASS( *bufs [2] );
    252		BLIP_READER_BEGIN( side,   **buf );
    253		BLIP_READER_BEGIN( center, *bufs [2] );
    254
    255		BLIP_READER_ADJ_( side,   samples_read );
    256		BLIP_READER_ADJ_( center, samples_read );
    257
    258		int offset = -count;
    259		do
    260		{
    261			blargg_long s = BLIP_READER_READ_RAW( center ) + BLIP_READER_READ_RAW( side );
    262			s >>= blip_sample_bits - 16;
    263			BLIP_READER_NEXT_IDX_( side,   bass, offset );
    264			BLIP_READER_NEXT_IDX_( center, bass, offset );
    265			BLIP_CLAMP( s, s );
    266
    267			++offset; // before write since out is decremented to slightly before end
    268			out [offset * stereo] = (blip_sample_t) s;
    269		}
    270		while ( offset );
    271
    272		BLIP_READER_END( side,   **buf );
    273
    274		if ( buf != bufs )
    275			continue;
    276
    277		// only end center once
    278		BLIP_READER_END( center, *bufs [2] );
    279		break;
    280	}
    281}