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}