Path: blob/a-new-beginning/Cherry/Core/audio/Multi_Buffer.cpp
2 views
// Blip_Buffer 0.4.1. http://www.slack.net/~ant/12#include "Multi_Buffer.h"34/* Copyright (C) 2003-2007 Shay Green. This module is free software; you5can redistribute it and/or modify it under the terms of the GNU Lesser6General Public License as published by the Free Software Foundation; either7version 2.1 of the License, or (at your option) any later version. This8module is distributed in the hope that it will be useful, but WITHOUT ANY9WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS10FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more11details. You should have received a copy of the GNU Lesser General Public12License along with this module; if not, write to the Free Software Foundation,13Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */1415#include "blargg_source.h"1617#ifdef BLARGG_ENABLE_OPTIMIZER18#include BLARGG_ENABLE_OPTIMIZER19#endif2021Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf )22{23length_ = 0;24sample_rate_ = 0;25channels_changed_count_ = 1;26channel_types_ = 0;27channel_count_ = 0;28immediate_removal_ = true;29}3031Multi_Buffer::channel_t Multi_Buffer::channel( int /*index*/ )32{33static channel_t const ch = { 0, 0, 0 };34return ch;35}3637// Silent_Buffer3839Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse40{41// TODO: better to use empty Blip_Buffer so caller never has to check for NULL?42chan.left = 0;43chan.center = 0;44chan.right = 0;45}4647// Mono_Buffer4849Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 )50{51chan.center = &buf;52chan.left = &buf;53chan.right = &buf;54}5556Mono_Buffer::~Mono_Buffer() { }5758blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec )59{60RETURN_ERR( buf.set_sample_rate( rate, msec ) );61return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() );62}636465// Tracked_Blip_Buffer6667Tracked_Blip_Buffer::Tracked_Blip_Buffer()68{69last_non_silence = 0;70}7172void Tracked_Blip_Buffer::clear()73{74last_non_silence = 0;75Blip_Buffer::clear();76}7778void Tracked_Blip_Buffer::end_frame( blip_time_t t )79{80Blip_Buffer::end_frame( t );81if ( clear_modified() )82last_non_silence = (int)samples_avail() + blip_buffer_extra_;83}8485blip_ulong Tracked_Blip_Buffer::non_silent() const86{87return last_non_silence | unsettled();88}8990inline void Tracked_Blip_Buffer::remove_( long n )91{92if ( (last_non_silence -= n) < 0 )93last_non_silence = 0;94}9596void Tracked_Blip_Buffer::remove_silence( long n )97{98remove_( n );99Blip_Buffer::remove_silence( n );100}101102void Tracked_Blip_Buffer::remove_samples( long n )103{104remove_( n );105Blip_Buffer::remove_samples( n );106}107108void Tracked_Blip_Buffer::remove_all_samples()109{110long avail = samples_avail();111if ( !non_silent() )112remove_silence( avail );113else114remove_samples( avail );115}116117long Tracked_Blip_Buffer::read_samples( blip_sample_t* out, long count )118{119count = Blip_Buffer::read_samples( out, count );120remove_( count );121return count;122}123124// Stereo_Buffer125126int const stereo = 2;127128Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 )129{130chan.center = mixer.bufs [2] = &bufs [2];131chan.left = mixer.bufs [0] = &bufs [0];132chan.right = mixer.bufs [1] = &bufs [1];133mixer.samples_read = 0;134}135136Stereo_Buffer::~Stereo_Buffer() { }137138blargg_err_t Stereo_Buffer::set_sample_rate( long rate, int msec )139{140mixer.samples_read = 0;141for ( int i = bufs_size; --i >= 0; )142RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) );143return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() );144}145146void Stereo_Buffer::clock_rate( long rate )147{148for ( int i = bufs_size; --i >= 0; )149bufs [i].clock_rate( rate );150}151152void Stereo_Buffer::bass_freq( int bass )153{154for ( int i = bufs_size; --i >= 0; )155bufs [i].bass_freq( bass );156}157158void Stereo_Buffer::clear()159{160mixer.samples_read = 0;161for ( int i = bufs_size; --i >= 0; )162bufs [i].clear();163}164165void Stereo_Buffer::end_frame( blip_time_t time )166{167for ( int i = bufs_size; --i >= 0; )168bufs [i].end_frame( time );169}170171long Stereo_Buffer::read_samples( blip_sample_t* out, long out_size )172{173require( (out_size & 1) == 0 ); // must read an even number of samples174out_size = min( out_size, samples_avail() );175176int pair_count = int (out_size >> 1);177if ( pair_count )178{179mixer.read_pairs( out, pair_count );180181if ( samples_avail() <= 0 || immediate_removal() )182{183for ( int i = bufs_size; --i >= 0; )184{185buf_t& b = bufs [i];186// TODO: might miss non-silence settling since it checks END of last read187if ( !b.non_silent() )188b.remove_silence( mixer.samples_read );189else190b.remove_samples( mixer.samples_read );191}192mixer.samples_read = 0;193}194}195return out_size;196}197198199// Stereo_Mixer200201// mixers use a single index value to improve performance on register-challenged processors202// offset goes from negative to zero203204void Stereo_Mixer::read_pairs( blip_sample_t* out, int count )205{206// TODO: if caller never marks buffers as modified, uses mono207// except that buffer isn't cleared, so caller can encounter208// subtle problems and not realize the cause.209samples_read += count;210if ( bufs [0]->non_silent() | bufs [1]->non_silent() )211mix_stereo( out, count );212else213mix_mono( out, count );214}215216void Stereo_Mixer::mix_mono( blip_sample_t* out_, int count )217{218int const bass = BLIP_READER_BASS( *bufs [2] );219BLIP_READER_BEGIN( center, *bufs [2] );220BLIP_READER_ADJ_( center, samples_read );221222typedef blip_sample_t stereo_blip_sample_t [stereo];223stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_ + count;224int offset = -count;225do226{227blargg_long s = BLIP_READER_READ( center );228BLIP_READER_NEXT_IDX_( center, bass, offset );229BLIP_CLAMP( s, s );230231out [offset] [0] = (blip_sample_t) s;232out [offset] [1] = (blip_sample_t) s;233}234while ( ++offset );235236BLIP_READER_END( center, *bufs [2] );237}238239void Stereo_Mixer::mix_stereo( blip_sample_t* out_, int count )240{241blip_sample_t* BLIP_RESTRICT out = out_ + count * stereo;242243// do left + center and right + center separately to reduce register load244Tracked_Blip_Buffer* const* buf = &bufs [2];245while ( true ) // loop runs twice246{247--buf;248--out;249250int const bass = BLIP_READER_BASS( *bufs [2] );251BLIP_READER_BEGIN( side, **buf );252BLIP_READER_BEGIN( center, *bufs [2] );253254BLIP_READER_ADJ_( side, samples_read );255BLIP_READER_ADJ_( center, samples_read );256257int offset = -count;258do259{260blargg_long s = BLIP_READER_READ_RAW( center ) + BLIP_READER_READ_RAW( side );261s >>= blip_sample_bits - 16;262BLIP_READER_NEXT_IDX_( side, bass, offset );263BLIP_READER_NEXT_IDX_( center, bass, offset );264BLIP_CLAMP( s, s );265266++offset; // before write since out is decremented to slightly before end267out [offset * stereo] = (blip_sample_t) s;268}269while ( offset );270271BLIP_READER_END( side, **buf );272273if ( buf != bufs )274continue;275276// only end center once277BLIP_READER_END( center, *bufs [2] );278break;279}280}281282283