diff options
Diffstat (limited to 'apps/codecs/libgme/gbs_emu.c')
-rw-r--r-- | apps/codecs/libgme/gbs_emu.c | 355 |
1 files changed, 88 insertions, 267 deletions
diff --git a/apps/codecs/libgme/gbs_emu.c b/apps/codecs/libgme/gbs_emu.c index 640ea43a70..7a6d484673 100644 --- a/apps/codecs/libgme/gbs_emu.c +++ b/apps/codecs/libgme/gbs_emu.c | |||
@@ -3,7 +3,6 @@ | |||
3 | #include "gbs_emu.h" | 3 | #include "gbs_emu.h" |
4 | 4 | ||
5 | #include "blargg_endian.h" | 5 | #include "blargg_endian.h" |
6 | #include "blargg_source.h" | ||
7 | 6 | ||
8 | /* Copyright (C) 2003-2006 Shay Green. this module is free software; you | 7 | /* Copyright (C) 2003-2006 Shay Green. this module is free software; you |
9 | can redistribute it and/or modify it under the terms of the GNU Lesser | 8 | can redistribute it and/or modify it under the terms of the GNU Lesser |
@@ -16,30 +15,17 @@ details. You should have received a copy of the GNU Lesser General Public | |||
16 | License along with this module; if not, write to the Free Software Foundation, | 15 | License along with this module; if not, write to the Free Software Foundation, |
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | 16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
18 | 17 | ||
18 | #include "blargg_source.h" | ||
19 | 19 | ||
20 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; | 20 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; |
21 | 21 | ||
22 | int const idle_addr = 0xF00D; | 22 | int const idle_addr = 0xF00D; |
23 | int const tempo_unit = 16; | 23 | int const tempo_unit = 16; |
24 | 24 | ||
25 | int const stereo = 2; // number of channels for stereo | ||
26 | int const silence_max = 6; // seconds | ||
27 | int const silence_threshold = 0x10; | ||
28 | long const fade_block_size = 512; | ||
29 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
30 | |||
31 | static void clear_track_vars( struct Gbs_Emu* this ) | 25 | static void clear_track_vars( struct Gbs_Emu* this ) |
32 | { | 26 | { |
33 | this->current_track_ = -1; | 27 | this->current_track_ = -1; |
34 | this->out_time = 0; | 28 | track_stop( &this->track_filter ); |
35 | this->emu_time = 0; | ||
36 | this->emu_track_ended_ = true; | ||
37 | this->track_ended = true; | ||
38 | this->fade_start = (blargg_long)(LONG_MAX / 2 + 1); | ||
39 | this->fade_step = 1; | ||
40 | this->silence_time = 0; | ||
41 | this->silence_count = 0; | ||
42 | this->buf_remain = 0; | ||
43 | } | 29 | } |
44 | 30 | ||
45 | void Gbs_init( struct Gbs_Emu* this ) | 31 | void Gbs_init( struct Gbs_Emu* this ) |
@@ -50,11 +36,13 @@ void Gbs_init( struct Gbs_Emu* this ) | |||
50 | 36 | ||
51 | // Unload | 37 | // Unload |
52 | this->header.timer_mode = 0; | 38 | this->header.timer_mode = 0; |
53 | clear_track_vars( this ); | ||
54 | 39 | ||
55 | this->ignore_silence = false; | 40 | // defaults |
56 | this->silence_lookahead = 6; | 41 | this->tfilter = *track_get_setup( &this->track_filter ); |
57 | this->max_initial_silence = 21; | 42 | this->tfilter.max_initial = 21; |
43 | this->tfilter.lookahead = 6; | ||
44 | this->track_filter.silence_ignored_ = false; | ||
45 | |||
58 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); | 46 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); |
59 | 47 | ||
60 | Rom_init( &this->rom, 0x4000 ); | 48 | Rom_init( &this->rom, 0x4000 ); |
@@ -67,6 +55,11 @@ void Gbs_init( struct Gbs_Emu* this ) | |||
67 | 55 | ||
68 | // Reduce apu sound clicks? | 56 | // Reduce apu sound clicks? |
69 | Apu_reduce_clicks( &this->apu, true ); | 57 | Apu_reduce_clicks( &this->apu, true ); |
58 | |||
59 | // clears fields | ||
60 | this->voice_count_ = 0; | ||
61 | this->voice_types_ = 0; | ||
62 | clear_track_vars( this ); | ||
70 | } | 63 | } |
71 | 64 | ||
72 | static blargg_err_t check_gbs_header( void const* header ) | 65 | static blargg_err_t check_gbs_header( void const* header ) |
@@ -78,11 +71,12 @@ static blargg_err_t check_gbs_header( void const* header ) | |||
78 | 71 | ||
79 | // Setup | 72 | // Setup |
80 | 73 | ||
81 | blargg_err_t Gbs_load( struct Gbs_Emu* this, void* data, long size ) | 74 | blargg_err_t Gbs_load_mem( struct Gbs_Emu* this, void* data, long size ) |
82 | { | 75 | { |
83 | // Unload | 76 | // Unload |
84 | this->header.timer_mode = 0; | 77 | this->header.timer_mode = 0; |
85 | this->voice_count_ = 0; | 78 | this->voice_count_ = 0; |
79 | this->track_count = 0; | ||
86 | this->m3u.size = 0; | 80 | this->m3u.size = 0; |
87 | clear_track_vars( this ); | 81 | clear_track_vars( this ); |
88 | 82 | ||
@@ -112,20 +106,24 @@ blargg_err_t Gbs_load( struct Gbs_Emu* this, void* data, long size ) | |||
112 | Rom_set_addr( &this->rom, load_addr ); | 106 | Rom_set_addr( &this->rom, load_addr ); |
113 | 107 | ||
114 | this->voice_count_ = osc_count; | 108 | this->voice_count_ = osc_count; |
109 | static int const types [osc_count] = { | ||
110 | wave_type+1, wave_type+2, wave_type+3, mixed_type+1 | ||
111 | }; | ||
112 | this->voice_types_ = types; | ||
113 | |||
115 | Apu_volume( &this->apu, this->gain_ ); | 114 | Apu_volume( &this->apu, this->gain_ ); |
116 | 115 | ||
117 | // Change clock rate & setup buffer | 116 | // Change clock rate & setup buffer |
118 | this->clock_rate_ = 4194304; | 117 | this->clock_rate_ = 4194304; |
119 | Buffer_clock_rate( &this->stereo_buf, 4194304 ); | 118 | Buffer_clock_rate( &this->stereo_buf, 4194304 ); |
119 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count_, this->voice_types_ ) ); | ||
120 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 120 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
121 | 121 | ||
122 | // Post load | 122 | // Post load |
123 | Sound_set_tempo( this, this->tempo_ ); | 123 | Sound_set_tempo( this, this->tempo_ ); |
124 | |||
125 | // Remute voices | ||
126 | Sound_mute_voices( this, this->mute_mask_ ); | 124 | Sound_mute_voices( this, this->mute_mask_ ); |
127 | 125 | ||
128 | // Reset track count | 126 | // Set track count |
129 | this->track_count = this->header.track_count; | 127 | this->track_count = this->header.track_count; |
130 | return 0; | 128 | return 0; |
131 | } | 129 | } |
@@ -134,7 +132,7 @@ blargg_err_t Gbs_load( struct Gbs_Emu* this, void* data, long size ) | |||
134 | 132 | ||
135 | // see gb_cpu_io.h for read/write functions | 133 | // see gb_cpu_io.h for read/write functions |
136 | 134 | ||
137 | void Set_bank( struct Gbs_Emu* this, int n ) | 135 | void set_bank( struct Gbs_Emu* this, int n ) |
138 | { | 136 | { |
139 | addr_t addr = mask_addr( n * this->rom.bank_size, this->rom.mask ); | 137 | addr_t addr = mask_addr( n * this->rom.bank_size, this->rom.mask ); |
140 | if ( addr == 0 && this->rom.size > this->rom.bank_size ) | 138 | if ( addr == 0 && this->rom.size > this->rom.bank_size ) |
@@ -142,7 +140,7 @@ void Set_bank( struct Gbs_Emu* this, int n ) | |||
142 | Cpu_map_code( &this->cpu, this->rom.bank_size, this->rom.bank_size, Rom_at_addr( &this->rom, addr ) ); | 140 | Cpu_map_code( &this->cpu, this->rom.bank_size, this->rom.bank_size, Rom_at_addr( &this->rom, addr ) ); |
143 | } | 141 | } |
144 | 142 | ||
145 | void Update_timer( struct Gbs_Emu* this ) | 143 | void update_timer( struct Gbs_Emu* this ) |
146 | { | 144 | { |
147 | this->play_period = 70224 / tempo_unit; /// 59.73 Hz | 145 | this->play_period = 70224 / tempo_unit; /// 59.73 Hz |
148 | 146 | ||
@@ -161,21 +159,21 @@ void Update_timer( struct Gbs_Emu* this ) | |||
161 | 159 | ||
162 | // Jumps to routine, given pointer to address in file header. Pushes idle_addr | 160 | // Jumps to routine, given pointer to address in file header. Pushes idle_addr |
163 | // as return address, NOT old PC. | 161 | // as return address, NOT old PC. |
164 | void Jsr_then_stop( struct Gbs_Emu* this, byte const addr [] ) | 162 | void jsr_then_stop( struct Gbs_Emu* this, byte const addr [] ) |
165 | { | 163 | { |
166 | check( this->cpu.r.sp == get_le16( this->header.stack_ptr ) ); | 164 | check( this->cpu.r.sp == get_le16( this->header.stack_ptr ) ); |
167 | this->cpu.r.pc = get_le16( addr ); | 165 | this->cpu.r.pc = get_le16( addr ); |
168 | Write_mem( this, --this->cpu.r.sp, idle_addr >> 8 ); | 166 | write_mem( this, --this->cpu.r.sp, idle_addr >> 8 ); |
169 | Write_mem( this, --this->cpu.r.sp, idle_addr ); | 167 | write_mem( this, --this->cpu.r.sp, idle_addr ); |
170 | } | 168 | } |
171 | 169 | ||
172 | static blargg_err_t Run_until( struct Gbs_Emu* this, int end ) | 170 | static blargg_err_t run_until( struct Gbs_Emu* this, int end ) |
173 | { | 171 | { |
174 | this->end_time = end; | 172 | this->end_time = end; |
175 | Cpu_set_time( &this->cpu, Cpu_time( &this->cpu ) - end ); | 173 | Cpu_set_time( &this->cpu, Cpu_time( &this->cpu ) - end ); |
176 | while ( true ) | 174 | while ( true ) |
177 | { | 175 | { |
178 | Run_cpu( this ); | 176 | run_cpu( this ); |
179 | if ( Cpu_time( &this->cpu ) >= 0 ) | 177 | if ( Cpu_time( &this->cpu ) >= 0 ) |
180 | break; | 178 | break; |
181 | 179 | ||
@@ -190,7 +188,7 @@ static blargg_err_t Run_until( struct Gbs_Emu* this, int end ) | |||
190 | if ( Cpu_time( &this->cpu ) < this->next_play - this->end_time ) | 188 | if ( Cpu_time( &this->cpu ) < this->next_play - this->end_time ) |
191 | Cpu_set_time( &this->cpu, this->next_play - this->end_time ); | 189 | Cpu_set_time( &this->cpu, this->next_play - this->end_time ); |
192 | this->next_play += this->play_period; | 190 | this->next_play += this->play_period; |
193 | Jsr_then_stop( this, this->header.play_addr ); | 191 | jsr_then_stop( this, this->header.play_addr ); |
194 | } | 192 | } |
195 | else if ( this->cpu.r.pc > 0xFFFF ) | 193 | else if ( this->cpu.r.pc > 0xFFFF ) |
196 | { | 194 | { |
@@ -208,9 +206,9 @@ static blargg_err_t Run_until( struct Gbs_Emu* this, int end ) | |||
208 | return 0; | 206 | return 0; |
209 | } | 207 | } |
210 | 208 | ||
211 | static blargg_err_t End_frame( struct Gbs_Emu* this, int end ) | 209 | static blargg_err_t end_frame( struct Gbs_Emu* this, int end ) |
212 | { | 210 | { |
213 | RETURN_ERR( Run_until( this, end ) ); | 211 | RETURN_ERR( run_until( this, end ) ); |
214 | 212 | ||
215 | this->next_play -= end; | 213 | this->next_play -= end; |
216 | if ( this->next_play < 0 ) // happens when play routine takes too long | 214 | if ( this->next_play < 0 ) // happens when play routine takes too long |
@@ -226,16 +224,19 @@ static blargg_err_t End_frame( struct Gbs_Emu* this, int end ) | |||
226 | return 0; | 224 | return 0; |
227 | } | 225 | } |
228 | 226 | ||
229 | blargg_err_t Run_clocks( struct Gbs_Emu* this, blip_time_t duration ) | 227 | blargg_err_t run_clocks( struct Gbs_Emu* this, blip_time_t duration ) |
230 | { | 228 | { |
231 | return End_frame( this, duration ); | 229 | return end_frame( this, duration ); |
232 | } | 230 | } |
233 | 231 | ||
234 | static blargg_err_t play_( struct Gbs_Emu* this, long count, sample_t* out ) | 232 | blargg_err_t play_( void* emu, int count, sample_t* out ) |
235 | { | 233 | { |
236 | long remain = count; | 234 | struct Gbs_Emu* this = (struct Gbs_Emu*) emu; |
235 | |||
236 | int remain = count; | ||
237 | while ( remain ) | 237 | while ( remain ) |
238 | { | 238 | { |
239 | Buffer_disable_immediate_removal( &this->stereo_buf ); | ||
239 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); | 240 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); |
240 | if ( remain ) | 241 | if ( remain ) |
241 | { | 242 | { |
@@ -247,8 +248,8 @@ static blargg_err_t play_( struct Gbs_Emu* this, long count, sample_t* out ) | |||
247 | Sound_mute_voices( this, this->mute_mask_ ); | 248 | Sound_mute_voices( this, this->mute_mask_ ); |
248 | } | 249 | } |
249 | int msec = Buffer_length( &this->stereo_buf ); | 250 | int msec = Buffer_length( &this->stereo_buf ); |
250 | blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000; | 251 | blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; |
251 | RETURN_ERR( Run_clocks( this, clocks_emulated ) ); | 252 | RETURN_ERR( run_clocks( this, clocks_emulated ) ); |
252 | assert( clocks_emulated ); | 253 | assert( clocks_emulated ); |
253 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); | 254 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); |
254 | } | 255 | } |
@@ -256,7 +257,7 @@ static blargg_err_t play_( struct Gbs_Emu* this, long count, sample_t* out ) | |||
256 | return 0; | 257 | return 0; |
257 | } | 258 | } |
258 | 259 | ||
259 | blargg_err_t Gbs_set_sample_rate( struct Gbs_Emu* this, long rate ) | 260 | blargg_err_t Gbs_set_sample_rate( struct Gbs_Emu* this, int rate ) |
260 | { | 261 | { |
261 | require( !this->sample_rate_ ); // sample rate can't be changed once set | 262 | require( !this->sample_rate_ ); // sample rate can't be changed once set |
262 | Buffer_init( &this->stereo_buf ); | 263 | Buffer_init( &this->stereo_buf ); |
@@ -266,6 +267,8 @@ blargg_err_t Gbs_set_sample_rate( struct Gbs_Emu* this, long rate ) | |||
266 | Buffer_bass_freq( &this->stereo_buf, 300 ); | 267 | Buffer_bass_freq( &this->stereo_buf, 300 ); |
267 | 268 | ||
268 | this->sample_rate_ = rate; | 269 | this->sample_rate_ = rate; |
270 | RETURN_ERR( track_init( &this->track_filter, this ) ); | ||
271 | this->tfilter.max_silence = 6 * stereo * this->sample_rate_; | ||
269 | return 0; | 272 | return 0; |
270 | } | 273 | } |
271 | 274 | ||
@@ -296,7 +299,7 @@ void Sound_mute_voices( struct Gbs_Emu* this, int mask ) | |||
296 | } | 299 | } |
297 | else | 300 | else |
298 | { | 301 | { |
299 | struct channel_t ch = Buffer_channel( &this->stereo_buf ); | 302 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); |
300 | assert( (ch.center && ch.left && ch.right) || | 303 | assert( (ch.center && ch.left && ch.right) || |
301 | (!ch.center && !ch.left && !ch.right) ); // all or nothing | 304 | (!ch.center && !ch.left && !ch.right) ); // all or nothing |
302 | Apu_set_output( &this->apu, i, ch.center, ch.left, ch.right ); | 305 | Apu_set_output( &this->apu, i, ch.center, ch.left, ch.right ); |
@@ -315,10 +318,9 @@ void Sound_set_tempo( struct Gbs_Emu* this, int t ) | |||
315 | 318 | ||
316 | this->tempo = (int) ((tempo_unit * FP_ONE_TEMPO) / t); | 319 | this->tempo = (int) ((tempo_unit * FP_ONE_TEMPO) / t); |
317 | Apu_set_tempo( &this->apu, t ); | 320 | Apu_set_tempo( &this->apu, t ); |
318 | Update_timer( this ); | 321 | update_timer( this ); |
319 | } | 322 | } |
320 | 323 | ||
321 | void fill_buf( struct Gbs_Emu* this ); | ||
322 | blargg_err_t Gbs_start_track( struct Gbs_Emu* this, int track ) | 324 | blargg_err_t Gbs_start_track( struct Gbs_Emu* this, int track ) |
323 | { | 325 | { |
324 | clear_track_vars( this ); | 326 | clear_track_vars( this ); |
@@ -330,7 +332,6 @@ blargg_err_t Gbs_start_track( struct Gbs_Emu* this, int track ) | |||
330 | } | 332 | } |
331 | 333 | ||
332 | this->current_track_ = track; | 334 | this->current_track_ = track; |
333 | |||
334 | Buffer_clear( &this->stereo_buf ); | 335 | Buffer_clear( &this->stereo_buf ); |
335 | 336 | ||
336 | // Reset APU to state expected by most rips | 337 | // Reset APU to state expected by most rips |
@@ -364,268 +365,88 @@ blargg_err_t Gbs_start_track( struct Gbs_Emu* this, int track ) | |||
364 | Cpu_reset( &this->cpu, this->rom.unmapped ); | 365 | Cpu_reset( &this->cpu, this->rom.unmapped ); |
365 | Cpu_map_code( &this->cpu, ram_addr, 0x10000 - ram_addr, this->ram ); | 366 | Cpu_map_code( &this->cpu, ram_addr, 0x10000 - ram_addr, this->ram ); |
366 | Cpu_map_code( &this->cpu, 0, this->rom.bank_size, Rom_at_addr( &this->rom, 0 ) ); | 367 | Cpu_map_code( &this->cpu, 0, this->rom.bank_size, Rom_at_addr( &this->rom, 0 ) ); |
367 | Set_bank( this, this->rom.size > this->rom.bank_size ); | 368 | set_bank( this, this->rom.size > this->rom.bank_size ); |
368 | 369 | ||
369 | Update_timer( this ); | 370 | update_timer( this ); |
370 | this->next_play = this->play_period; | 371 | this->next_play = this->play_period; |
371 | this->cpu.r.rp.fa = track; | 372 | this->cpu.r.rp.fa = track; |
372 | this->cpu.r.sp = get_le16( this->header.stack_ptr ); | 373 | this->cpu.r.sp = get_le16( this->header.stack_ptr ); |
373 | this->cpu_time = 0; | 374 | this->cpu_time = 0; |
374 | Jsr_then_stop( this, this->header.init_addr ); | 375 | jsr_then_stop( this, this->header.init_addr ); |
375 | 376 | ||
376 | this->emu_track_ended_ = false; | 377 | // convert filter times to samples |
377 | this->track_ended = false; | 378 | struct setup_t s = this->tfilter; |
379 | s.max_initial *= this->sample_rate_ * stereo; | ||
380 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD | ||
381 | s.lookahead = 1; | ||
382 | #endif | ||
383 | track_setup( &this->track_filter, &s ); | ||
378 | 384 | ||
379 | if ( !this->ignore_silence ) | 385 | return track_start( &this->track_filter ); |
380 | { | ||
381 | // play until non-silence or end of track | ||
382 | long end; | ||
383 | for ( end = this->max_initial_silence * stereo * this->sample_rate_; this->emu_time < end; ) | ||
384 | { | ||
385 | fill_buf( this ); | ||
386 | if ( this->buf_remain | (int) this->emu_track_ended_ ) | ||
387 | break; | ||
388 | } | ||
389 | |||
390 | this->emu_time = this->buf_remain; | ||
391 | this->out_time = 0; | ||
392 | this->silence_time = 0; | ||
393 | this->silence_count = 0; | ||
394 | } | ||
395 | /* return track_ended() ? warning() : 0; */ | ||
396 | return 0; | ||
397 | } | 386 | } |
398 | 387 | ||
399 | 388 | ||
400 | // Track | 389 | // Track |
401 | 390 | ||
402 | static blargg_long msec_to_samples( blargg_long msec, long sample_rate ) | 391 | static int msec_to_samples( int msec, int sample_rate ) |
403 | { | 392 | { |
404 | blargg_long sec = msec / 1000; | 393 | int sec = msec / 1000; |
405 | msec -= sec * 1000; | 394 | msec -= sec * 1000; |
406 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; | 395 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; |
407 | } | 396 | } |
408 | 397 | ||
409 | long Track_tell( struct Gbs_Emu* this ) | 398 | int Track_tell( struct Gbs_Emu* this ) |
410 | { | 399 | { |
411 | blargg_long rate = this->sample_rate_ * stereo; | 400 | int rate = this->sample_rate_ * stereo; |
412 | blargg_long sec = this->out_time / rate; | 401 | int sec = track_sample_count( &this->track_filter ) / rate; |
413 | return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate; | 402 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; |
414 | } | 403 | } |
415 | 404 | ||
416 | blargg_err_t Track_seek( struct Gbs_Emu* this, long msec ) | 405 | blargg_err_t Track_seek( struct Gbs_Emu* this, int msec ) |
417 | { | 406 | { |
418 | blargg_long time = msec_to_samples( msec, this->sample_rate_ ); | 407 | int time = msec_to_samples( msec, this->sample_rate_ ); |
419 | if ( time < this->out_time ) | 408 | if ( time < track_sample_count( &this->track_filter ) ) |
420 | RETURN_ERR( Gbs_start_track( this, this->current_track_ ) ); | 409 | RETURN_ERR( Gbs_start_track( this, this->current_track_ ) ); |
421 | return Track_skip( this, time - this->out_time ); | 410 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); |
422 | } | 411 | } |
423 | 412 | ||
424 | static blargg_err_t skip_( struct Gbs_Emu* this, long count ) | 413 | blargg_err_t skip_( void* emu, int count ) |
425 | { | 414 | { |
415 | struct Gbs_Emu* this = (struct Gbs_Emu*) emu; | ||
416 | |||
426 | // for long skip, mute sound | 417 | // for long skip, mute sound |
427 | const long threshold = 30000; | 418 | const int threshold = 32768; |
428 | if ( count > threshold ) | 419 | if ( count > threshold ) |
429 | { | 420 | { |
430 | int saved_mute = this->mute_mask_; | 421 | int saved_mute = this->mute_mask_; |
431 | Sound_mute_voices( this, ~0 ); | 422 | Sound_mute_voices( this, ~0 ); |
432 | |||
433 | while ( count > threshold / 2 && !this->emu_track_ended_ ) | ||
434 | { | ||
435 | RETURN_ERR( play_( this, buf_size, this->buf ) ); | ||
436 | count -= buf_size; | ||
437 | } | ||
438 | |||
439 | Sound_mute_voices( this, saved_mute ); | ||
440 | } | ||
441 | |||
442 | while ( count && !this->emu_track_ended_ ) | ||
443 | { | ||
444 | long n = buf_size; | ||
445 | if ( n > count ) | ||
446 | n = count; | ||
447 | count -= n; | ||
448 | RETURN_ERR( play_( this, n, this->buf ) ); | ||
449 | } | ||
450 | return 0; | ||
451 | } | ||
452 | 423 | ||
453 | blargg_err_t Track_skip( struct Gbs_Emu* this, long count ) | 424 | int n = count - threshold/2; |
454 | { | 425 | n &= ~(2048-1); // round to multiple of 2048 |
455 | require( this->current_track_ >= 0 ); // start_track() must have been called already | ||
456 | this->out_time += count; | ||
457 | |||
458 | // remove from silence and buf first | ||
459 | { | ||
460 | long n = min( count, this->silence_count ); | ||
461 | this->silence_count -= n; | ||
462 | count -= n; | ||
463 | |||
464 | n = min( count, this->buf_remain ); | ||
465 | this->buf_remain -= n; | ||
466 | count -= n; | 426 | count -= n; |
467 | } | 427 | RETURN_ERR( skippy_( &this->track_filter, n ) ); |
468 | |||
469 | if ( count && !this->emu_track_ended_ ) | ||
470 | { | ||
471 | this->emu_time += count; | ||
472 | // End track if error | ||
473 | if ( skip_( this, count ) ) | ||
474 | this->emu_track_ended_ = true; | ||
475 | } | ||
476 | |||
477 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
478 | this->track_ended |= this->emu_track_ended_; | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | // Fading | ||
484 | 428 | ||
485 | void Track_set_fade( struct Gbs_Emu* this, long start_msec, long length_msec ) | 429 | Sound_mute_voices( this, saved_mute ); |
486 | { | ||
487 | this->fade_step = this->sample_rate_ * length_msec / (fade_block_size * fade_shift * 1000 / stereo); | ||
488 | this->fade_start = msec_to_samples( start_msec, this->sample_rate_ ); | ||
489 | } | ||
490 | |||
491 | // unit / pow( 2.0, (double) x / step ) | ||
492 | static int int_log( blargg_long x, int step, int unit ) | ||
493 | { | ||
494 | int shift = x / step; | ||
495 | int fraction = (x - shift * step) * unit / step; | ||
496 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
497 | } | ||
498 | |||
499 | static void handle_fade( struct Gbs_Emu* this, long out_count, sample_t* out ) | ||
500 | { | ||
501 | int i; | ||
502 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
503 | { | ||
504 | int const shift = 14; | ||
505 | int const unit = 1 << shift; | ||
506 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
507 | this->fade_step, unit ); | ||
508 | if ( gain < (unit >> fade_shift) ) | ||
509 | this->track_ended = this->emu_track_ended_ = true; | ||
510 | |||
511 | sample_t* io = &out [i]; | ||
512 | int count; | ||
513 | for ( count = min( fade_block_size, out_count - i ); count; --count ) | ||
514 | { | ||
515 | *io = (sample_t) ((*io * gain) >> shift); | ||
516 | ++io; | ||
517 | } | ||
518 | } | 430 | } |
519 | } | ||
520 | |||
521 | // Silence detection | ||
522 | 431 | ||
523 | static void emu_play( struct Gbs_Emu* this, long count, sample_t* out ) | 432 | return skippy_( &this->track_filter, count ); |
524 | { | ||
525 | check( current_track_ >= 0 ); | ||
526 | this->emu_time += count; | ||
527 | if ( this->current_track_ >= 0 && !this->emu_track_ended_ ) { | ||
528 | // End track if error | ||
529 | if ( play_( this, count, out ) ) this->emu_track_ended_ = true; | ||
530 | } | ||
531 | else | ||
532 | memset( out, 0, count * sizeof *out ); | ||
533 | } | 433 | } |
534 | 434 | ||
535 | // number of consecutive silent samples at end | 435 | blargg_err_t Track_skip( struct Gbs_Emu* this, int count ) |
536 | static long count_silence( sample_t* begin, long size ) | ||
537 | { | 436 | { |
538 | sample_t first = *begin; | 437 | require( this->current_track_ >= 0 ); // start_track() must have been called already |
539 | *begin = silence_threshold; // sentinel | 438 | return track_skip( &this->track_filter, count ); |
540 | sample_t* p = begin + size; | ||
541 | while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } | ||
542 | *begin = first; | ||
543 | return size - (p - begin); | ||
544 | } | 439 | } |
545 | 440 | ||
546 | // fill internal buffer and check it for silence | 441 | void Track_set_fade( struct Gbs_Emu* this, int start_msec, int length_msec ) |
547 | void fill_buf( struct Gbs_Emu* this ) | ||
548 | { | 442 | { |
549 | assert( !this->buf_remain ); | 443 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate_ ), |
550 | if ( !this->emu_track_ended_ ) | 444 | length_msec * this->sample_rate_ / (1000 / stereo) ); |
551 | { | ||
552 | emu_play( this, buf_size, this->buf ); | ||
553 | long silence = count_silence( this->buf, buf_size ); | ||
554 | if ( silence < buf_size ) | ||
555 | { | ||
556 | this->silence_time = this->emu_time - silence; | ||
557 | this->buf_remain = buf_size; | ||
558 | return; | ||
559 | } | ||
560 | } | ||
561 | this->silence_count += buf_size; | ||
562 | } | 445 | } |
563 | 446 | ||
564 | blargg_err_t Gbs_play( struct Gbs_Emu* this, long out_count, sample_t* out ) | 447 | blargg_err_t Gbs_play( struct Gbs_Emu* this, int out_count, sample_t* out ) |
565 | { | 448 | { |
566 | if ( this->track_ended ) | 449 | require( this->current_track_ >= 0 ); |
567 | { | 450 | require( out_count % stereo == 0 ); |
568 | memset( out, 0, out_count * sizeof *out ); | 451 | return track_play( &this->track_filter, out_count, out ); |
569 | } | ||
570 | else | ||
571 | { | ||
572 | require( this->current_track_ >= 0 ); | ||
573 | require( out_count % stereo == 0 ); | ||
574 | |||
575 | assert( this->emu_time >= this->out_time ); | ||
576 | |||
577 | long pos = 0; | ||
578 | if ( this->silence_count ) | ||
579 | { | ||
580 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
581 | long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time; | ||
582 | while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) | ||
583 | fill_buf( this ); | ||
584 | |||
585 | // fill with silence | ||
586 | pos = min( this->silence_count, out_count ); | ||
587 | memset( out, 0, pos * sizeof *out ); | ||
588 | this->silence_count -= pos; | ||
589 | |||
590 | if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate_ ) | ||
591 | { | ||
592 | this->track_ended = this->emu_track_ended_ = true; | ||
593 | this->silence_count = 0; | ||
594 | this->buf_remain = 0; | ||
595 | } | ||
596 | } | ||
597 | |||
598 | if ( this->buf_remain ) | ||
599 | { | ||
600 | // empty silence buf | ||
601 | long n = min( this->buf_remain, out_count - pos ); | ||
602 | memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out ); | ||
603 | this->buf_remain -= n; | ||
604 | pos += n; | ||
605 | } | ||
606 | |||
607 | // generate remaining samples normally | ||
608 | long remain = out_count - pos; | ||
609 | if ( remain ) | ||
610 | { | ||
611 | emu_play( this, remain, out + pos ); | ||
612 | this->track_ended |= this->emu_track_ended_; | ||
613 | |||
614 | if ( !this->ignore_silence || this->out_time > this->fade_start ) | ||
615 | { | ||
616 | // check end for a new run of silence | ||
617 | long silence = count_silence( out + pos, remain ); | ||
618 | if ( silence < remain ) | ||
619 | this->silence_time = this->emu_time - silence; | ||
620 | |||
621 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
622 | fill_buf( this ); // cause silence detection on next play() | ||
623 | } | ||
624 | } | ||
625 | |||
626 | if ( this->out_time > this->fade_start ) | ||
627 | handle_fade( this, out_count, out ); | ||
628 | } | ||
629 | this->out_time += out_count; | ||
630 | return 0; | ||
631 | } | 452 | } |