diff options
author | Andree Buschmann <AndreeBuschmann@t-online.de> | 2011-08-31 19:19:49 +0000 |
---|---|---|
committer | Andree Buschmann <AndreeBuschmann@t-online.de> | 2011-08-31 19:19:49 +0000 |
commit | 13cbade08a07296d92e7a7d3e20475de0032cba1 (patch) | |
tree | 731a1a4a99d86632a719ae49e3b3d2a12e764a3a /apps/codecs/libgme/vgm_emu.c | |
parent | d089e104034fdf5562bea125d2cacf4ee486782a (diff) | |
download | rockbox-13cbade08a07296d92e7a7d3e20475de0032cba1.tar.gz rockbox-13cbade08a07296d92e7a7d3e20475de0032cba1.zip |
Update libgme to Blargg's Game_Music_Emu 0.6-pre.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30397 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libgme/vgm_emu.c')
-rw-r--r-- | apps/codecs/libgme/vgm_emu.c | 388 |
1 files changed, 108 insertions, 280 deletions
diff --git a/apps/codecs/libgme/vgm_emu.c b/apps/codecs/libgme/vgm_emu.c index 391bd02d73..4f8a2adbc1 100644 --- a/apps/codecs/libgme/vgm_emu.c +++ b/apps/codecs/libgme/vgm_emu.c | |||
@@ -23,11 +23,6 @@ const char* const gme_wrong_file_type = "Wrong file type for this emulator"; | |||
23 | 23 | ||
24 | int const fm_gain = 3; // FM emulators are internally quieter to avoid 16-bit overflow | 24 | int const fm_gain = 3; // FM emulators are internally quieter to avoid 16-bit overflow |
25 | 25 | ||
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 | // VGM commands (Spec v1.50) | 26 | // VGM commands (Spec v1.50) |
32 | enum { | 27 | enum { |
33 | cmd_gg_stereo = 0x4F, | 28 | cmd_gg_stereo = 0x4F, |
@@ -53,15 +48,8 @@ enum { | |||
53 | 48 | ||
54 | static void clear_track_vars( struct Vgm_Emu* this ) | 49 | static void clear_track_vars( struct Vgm_Emu* this ) |
55 | { | 50 | { |
56 | this->out_time = 0; | 51 | this->current_track = -1; |
57 | this->emu_time = 0; | 52 | track_stop( &this->track_filter ); |
58 | this->emu_track_ended_ = true; | ||
59 | this->track_ended = true; | ||
60 | this->fade_start = INT_MAX / 2 + 1; | ||
61 | this->fade_step = 1; | ||
62 | this->silence_time = 0; | ||
63 | this->silence_count = 0; | ||
64 | this->buf_remain = 0; | ||
65 | } | 53 | } |
66 | 54 | ||
67 | int play_frame( struct Vgm_Emu* this, blip_time_t blip_time, int sample_count, sample_t* buf ); | 55 | int play_frame( struct Vgm_Emu* this, blip_time_t blip_time, int sample_count, sample_t* buf ); |
@@ -77,9 +65,10 @@ void Vgm_init( struct Vgm_Emu* this ) | |||
77 | this->tempo = (int)(FP_ONE_TEMPO); | 65 | this->tempo = (int)(FP_ONE_TEMPO); |
78 | 66 | ||
79 | // defaults | 67 | // defaults |
80 | this->max_initial_silence = 2; | 68 | this->tfilter = *track_get_setup( &this->track_filter ); |
81 | this->silence_lookahead = 1; // tracks should already be trimmed | 69 | this->tfilter.max_initial = 2; |
82 | this->ignore_silence = false; | 70 | this->tfilter.lookahead = 1; |
71 | this->track_filter.silence_ignored_ = false; | ||
83 | 72 | ||
84 | // Disable oversampling by default | 73 | // Disable oversampling by default |
85 | this->disable_oversampling = true; | 74 | this->disable_oversampling = true; |
@@ -88,10 +77,10 @@ void Vgm_init( struct Vgm_Emu* this ) | |||
88 | Sms_apu_init( &this->psg ); | 77 | Sms_apu_init( &this->psg ); |
89 | Synth_init( &this->pcm ); | 78 | Synth_init( &this->pcm ); |
90 | 79 | ||
91 | Buffer_init( &this->buf ); | 80 | Buffer_init( &this->stereo_buf ); |
92 | Blip_init( &this->blip_buf ); | 81 | Blip_init( &this->blip_buf ); |
93 | 82 | ||
94 | // Init fm chips | 83 | // Init fm chips |
95 | Ym2413_init( &this->ym2413 ); | 84 | Ym2413_init( &this->ym2413 ); |
96 | Ym2612_init( &this->ym2612 ); | 85 | Ym2612_init( &this->ym2612 ); |
97 | 86 | ||
@@ -105,7 +94,8 @@ void Vgm_init( struct Vgm_Emu* this ) | |||
105 | 94 | ||
106 | // Unload | 95 | // Unload |
107 | this->voice_count = 0; | 96 | this->voice_count = 0; |
108 | clear_track_vars( this ); | 97 | this->voice_types = 0; |
98 | clear_track_vars( this ); | ||
109 | } | 99 | } |
110 | 100 | ||
111 | // Track info | 101 | // Track info |
@@ -150,13 +140,13 @@ static void parse_gd3( byte const* in, byte const* end, struct track_info_t* out | |||
150 | 140 | ||
151 | int const gd3_header_size = 12; | 141 | int const gd3_header_size = 12; |
152 | 142 | ||
153 | static long check_gd3_header( byte const* h, long remain ) | 143 | static int check_gd3_header( byte const* h, int remain ) |
154 | { | 144 | { |
155 | if ( remain < gd3_header_size ) return 0; | 145 | if ( remain < gd3_header_size ) return 0; |
156 | if ( memcmp( h, "Gd3 ", 4 ) ) return 0; | 146 | if ( memcmp( h, "Gd3 ", 4 ) ) return 0; |
157 | if ( get_le32( h + 4 ) >= 0x200 ) return 0; | 147 | if ( get_le32( h + 4 ) >= 0x200 ) return 0; |
158 | 148 | ||
159 | long gd3_size = get_le32( h + 8 ); | 149 | int gd3_size = get_le32( h + 8 ); |
160 | if ( gd3_size > remain - gd3_header_size ) | 150 | if ( gd3_size > remain - gd3_header_size ) |
161 | gd3_size = remain - gd3_header_size; | 151 | gd3_size = remain - gd3_header_size; |
162 | return gd3_size; | 152 | return gd3_size; |
@@ -167,12 +157,12 @@ static byte const* gd3_data( struct Vgm_Emu* this, int* size ) | |||
167 | if ( size ) | 157 | if ( size ) |
168 | *size = 0; | 158 | *size = 0; |
169 | 159 | ||
170 | long gd3_offset = get_le32( header( this )->gd3_offset ) - 0x2C; | 160 | int gd3_offset = get_le32( header( this )->gd3_offset ) - 0x2C; |
171 | if ( gd3_offset < 0 ) | 161 | if ( gd3_offset < 0 ) |
172 | return 0; | 162 | return 0; |
173 | 163 | ||
174 | byte const* gd3 = this->file_begin + header_size + gd3_offset; | 164 | byte const* gd3 = this->file_begin + header_size + gd3_offset; |
175 | long gd3_size = check_gd3_header( gd3, this->file_end - gd3 ); | 165 | int gd3_size = check_gd3_header( gd3, this->file_end - gd3 ); |
176 | if ( !gd3_size ) | 166 | if ( !gd3_size ) |
177 | return 0; | 167 | return 0; |
178 | 168 | ||
@@ -184,10 +174,10 @@ static byte const* gd3_data( struct Vgm_Emu* this, int* size ) | |||
184 | 174 | ||
185 | static void get_vgm_length( struct header_t const* h, struct track_info_t* out ) | 175 | static void get_vgm_length( struct header_t const* h, struct track_info_t* out ) |
186 | { | 176 | { |
187 | long length = get_le32( h->track_duration ) * 10 / 441; | 177 | int length = get_le32( h->track_duration ) * 10 / 441; |
188 | if ( length > 0 ) | 178 | if ( length > 0 ) |
189 | { | 179 | { |
190 | long loop = get_le32( h->loop_duration ); | 180 | int loop = get_le32( h->loop_duration ); |
191 | if ( loop > 0 && get_le32( h->loop_offset ) ) | 181 | if ( loop > 0 && get_le32( h->loop_offset ) ) |
192 | { | 182 | { |
193 | out->loop_length = loop * 10 / 441; | 183 | out->loop_length = loop * 10 / 441; |
@@ -285,24 +275,25 @@ blargg_err_t Vgm_load_mem( struct Vgm_Emu* this, byte const* new_data, long new_ | |||
285 | Ym2612_enable( &this->ym2612, false ); | 275 | Ym2612_enable( &this->ym2612, false ); |
286 | Ym2413_enable( &this->ym2413, false ); | 276 | Ym2413_enable( &this->ym2413, false ); |
287 | 277 | ||
288 | Sound_set_tempo( this, (int)(FP_ONE_TEMPO) ); | ||
289 | |||
290 | this->voice_count = sms_osc_count; | 278 | this->voice_count = sms_osc_count; |
279 | static int const types [8] = { | ||
280 | wave_type+1, wave_type+2, wave_type+3, noise_type+1, | ||
281 | 0, 0, 0, 0 | ||
282 | }; | ||
283 | this->voice_types = types; | ||
291 | 284 | ||
292 | RETURN_ERR( setup_fm( this ) ); | 285 | RETURN_ERR( setup_fm( this ) ); |
293 | 286 | ||
294 | // do after FM in case output buffer is changed | 287 | // do after FM in case output buffer is changed |
295 | // setup buffer | 288 | // setup buffer |
296 | this->clock_rate_ = this->psg_rate; | 289 | this->clock_rate_ = this->psg_rate; |
297 | Buffer_clock_rate( &this->buf, this->psg_rate ); | 290 | Buffer_clock_rate( &this->stereo_buf, this->psg_rate ); |
298 | 291 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); | |
299 | // Setup bass | 292 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
300 | this->buf_changed_count = Buffer_channels_changed_count( &this->buf ); | ||
301 | 293 | ||
302 | // Post load | 294 | // Post load |
303 | Sound_set_tempo( this, this->tempo ); | 295 | Sound_set_tempo( this, this->tempo ); |
304 | Sound_mute_voices( this, this->mute_mask_ ); | 296 | Sound_mute_voices( this, this->mute_mask_ ); |
305 | |||
306 | return 0; | 297 | return 0; |
307 | } | 298 | } |
308 | 299 | ||
@@ -362,42 +353,56 @@ blargg_err_t setup_fm( struct Vgm_Emu* this ) | |||
362 | // Emulation | 353 | // Emulation |
363 | 354 | ||
364 | blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time ); | 355 | blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time ); |
365 | static blargg_err_t run_clocks( struct Vgm_Emu* this, blip_time_t* time_io, int msec ) | 356 | static blip_time_t run_psg( struct Vgm_Emu* this, int msec ) |
366 | { | 357 | { |
367 | *time_io = run( this, msec * this->vgm_rate / 1000 ); | 358 | blip_time_t t = run( this, msec * this->vgm_rate / 1000 ); |
368 | Sms_apu_end_frame( &this->psg, *time_io ); | 359 | Sms_apu_end_frame( &this->psg, t ); |
369 | return 0; | 360 | return t; |
370 | } | 361 | } |
371 | 362 | ||
363 | static void check_end( struct Vgm_Emu* this ) | ||
364 | { | ||
365 | if( this->pos >= this->file_end ) | ||
366 | track_set_end( &this->track_filter ); | ||
367 | } | ||
372 | 368 | ||
369 | static blargg_err_t run_clocks( struct Vgm_Emu* this, blip_time_t* time_io, int msec ) | ||
370 | { | ||
371 | check_end( this ); | ||
372 | *time_io = run_psg( this, msec ); | ||
373 | return 0; | ||
374 | } | ||
373 | 375 | ||
374 | static blargg_err_t play_( struct Vgm_Emu* this, long count, sample_t* out ) | 376 | blargg_err_t play_( void *emu, int count, sample_t out [] ) |
375 | { | 377 | { |
378 | struct Vgm_Emu* this = (struct Vgm_Emu*) emu; | ||
379 | |||
376 | if ( !uses_fm( this ) ) { | 380 | if ( !uses_fm( this ) ) { |
377 | long remain = count; | 381 | int remain = count; |
378 | while ( remain ) | 382 | while ( remain ) |
379 | { | 383 | { |
380 | remain -= Buffer_read_samples( &this->buf, &out [count - remain], remain ); | 384 | Buffer_disable_immediate_removal( &this->stereo_buf ); |
385 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); | ||
381 | if ( remain ) | 386 | if ( remain ) |
382 | { | 387 | { |
383 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->buf ) ) | 388 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) |
384 | { | 389 | { |
385 | this->buf_changed_count = Buffer_channels_changed_count( &this->buf ); | 390 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
386 | 391 | ||
387 | // Remute voices | 392 | // Remute voices |
388 | Sound_mute_voices( this, this->mute_mask_ ); | 393 | Sound_mute_voices( this, this->mute_mask_ ); |
389 | } | 394 | } |
390 | int msec = Buffer_length( &this->buf ); | 395 | int msec = Buffer_length( &this->stereo_buf ); |
391 | blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000 - 100; | 396 | blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; |
392 | RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); | 397 | RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); |
393 | assert( clocks_emulated ); | 398 | assert( clocks_emulated ); |
394 | Buffer_end_frame( &this->buf, clocks_emulated ); | 399 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); |
395 | } | 400 | } |
396 | } | 401 | } |
397 | 402 | ||
398 | return 0; | 403 | return 0; |
399 | } | 404 | } |
400 | 405 | ||
401 | Resampler_play( &this->resampler, count, out, &this->blip_buf ); | 406 | Resampler_play( &this->resampler, count, out, &this->blip_buf ); |
402 | return 0; | 407 | return 0; |
403 | } | 408 | } |
@@ -414,7 +419,7 @@ static inline int command_len( int command ) | |||
414 | check( len != 1 ); | 419 | check( len != 1 ); |
415 | return len; | 420 | return len; |
416 | } | 421 | } |
417 | 422 | ||
418 | static inline fm_time_t to_fm_time( struct Vgm_Emu* this, vgm_time_t t ) | 423 | static inline fm_time_t to_fm_time( struct Vgm_Emu* this, vgm_time_t t ) |
419 | { | 424 | { |
420 | return (t * this->fm_time_factor + this->fm_time_offset) >> fm_time_bits; | 425 | return (t * this->fm_time_factor + this->fm_time_offset) >> fm_time_bits; |
@@ -443,12 +448,10 @@ blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time ) | |||
443 | { | 448 | { |
444 | vgm_time_t vgm_time = this->vgm_time; | 449 | vgm_time_t vgm_time = this->vgm_time; |
445 | byte const* pos = this->pos; | 450 | byte const* pos = this->pos; |
446 | if ( pos >= this->file_end ) | 451 | /* if ( pos > this->file_end ) |
447 | { | 452 | { |
448 | this->emu_track_ended_ = true; | 453 | warning( "Stream lacked end event" ); |
449 | /* if ( pos > data_end ) | 454 | } */ |
450 | warning( "Stream lacked end event" ); */ | ||
451 | } | ||
452 | 455 | ||
453 | while ( vgm_time < end_time && pos < this->file_end ) | 456 | while ( vgm_time < end_time && pos < this->file_end ) |
454 | { | 457 | { |
@@ -517,7 +520,7 @@ blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time ) | |||
517 | case cmd_data_block: { | 520 | case cmd_data_block: { |
518 | check( *pos == cmd_end ); | 521 | check( *pos == cmd_end ); |
519 | int type = pos [1]; | 522 | int type = pos [1]; |
520 | long size = get_le32( pos + 2 ); | 523 | int size = get_le32( pos + 2 ); |
521 | pos += 6; | 524 | pos += 6; |
522 | if ( type == pcm_block_type ) | 525 | if ( type == pcm_block_type ) |
523 | this->pcm_data = pos; | 526 | this->pcm_data = pos; |
@@ -564,6 +567,8 @@ blip_time_t run( struct Vgm_Emu* this, vgm_time_t end_time ) | |||
564 | 567 | ||
565 | int play_frame( struct Vgm_Emu* this, blip_time_t blip_time, int sample_count, blip_sample_t out [] ) | 568 | int play_frame( struct Vgm_Emu* this, blip_time_t blip_time, int sample_count, blip_sample_t out [] ) |
566 | { | 569 | { |
570 | check_end( this); | ||
571 | |||
567 | // to do: timing is working mostly by luck | 572 | // to do: timing is working mostly by luck |
568 | int min_pairs = (unsigned) sample_count / 2; | 573 | int min_pairs = (unsigned) sample_count / 2; |
569 | int vgm_time = (min_pairs << fm_time_bits) / this->fm_time_factor - 1; | 574 | int vgm_time = (min_pairs << fm_time_bits) / this->fm_time_factor - 1; |
@@ -642,16 +647,18 @@ void update_fm_rates( struct Vgm_Emu* this, int* ym2413_rate, int* ym2612_rate ) | |||
642 | 647 | ||
643 | // Music Emu | 648 | // Music Emu |
644 | 649 | ||
645 | blargg_err_t Vgm_set_sample_rate( struct Vgm_Emu* this, long rate ) | 650 | blargg_err_t Vgm_set_sample_rate( struct Vgm_Emu* this, int rate ) |
646 | { | 651 | { |
647 | require( !this->sample_rate ); // sample rate can't be changed once set | 652 | require( !this->sample_rate ); // sample rate can't be changed once set |
648 | RETURN_ERR( Blip_set_sample_rate( &this->blip_buf, rate, 1000 / 30 ) ); | 653 | RETURN_ERR( Blip_set_sample_rate( &this->blip_buf, rate, 1000 / 30 ) ); |
649 | RETURN_ERR( Buffer_set_sample_rate( &this->buf, rate, 1000 / 20 ) ); | 654 | RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) ); |
650 | 655 | ||
651 | // Set bass frequency | 656 | // Set bass frequency |
652 | Buffer_bass_freq( &this->buf, 80 ); | 657 | Buffer_bass_freq( &this->stereo_buf, 80 ); |
653 | 658 | ||
654 | this->sample_rate = rate; | 659 | this->sample_rate = rate; |
660 | RETURN_ERR( track_init( &this->track_filter, this ) ); | ||
661 | this->tfilter.max_silence = 6 * stereo * this->sample_rate; | ||
655 | return 0; | 662 | return 0; |
656 | } | 663 | } |
657 | 664 | ||
@@ -679,7 +686,7 @@ void Sound_mute_voices( struct Vgm_Emu* this, int mask ) | |||
679 | } | 686 | } |
680 | else | 687 | else |
681 | { | 688 | { |
682 | struct channel_t ch = Buffer_channel( &this->buf ); | 689 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); |
683 | assert( (ch.center && ch.left && ch.right) || | 690 | assert( (ch.center && ch.left && ch.right) || |
684 | (!ch.center && !ch.left && !ch.right) ); // all or nothing | 691 | (!ch.center && !ch.left && !ch.right) ); // all or nothing |
685 | set_voice( this, i, ch.center, ch.left, ch.right ); | 692 | set_voice( this, i, ch.center, ch.left, ch.right ); |
@@ -735,7 +742,6 @@ void Sound_set_tempo( struct Vgm_Emu* this, int t ) | |||
735 | } | 742 | } |
736 | } | 743 | } |
737 | 744 | ||
738 | void fill_buf( struct Vgm_Emu *this ); | ||
739 | blargg_err_t Vgm_start_track( struct Vgm_Emu* this ) | 745 | blargg_err_t Vgm_start_track( struct Vgm_Emu* this ) |
740 | { | 746 | { |
741 | clear_track_vars( this ); | 747 | clear_track_vars( this ); |
@@ -750,7 +756,7 @@ blargg_err_t Vgm_start_track( struct Vgm_Emu* this ) | |||
750 | this->vgm_time = 0; | 756 | this->vgm_time = 0; |
751 | if ( get_le32( header( this )->version ) >= 0x150 ) | 757 | if ( get_le32( header( this )->version ) >= 0x150 ) |
752 | { | 758 | { |
753 | long data_offset = get_le32( header( this )->data_offset ); | 759 | int data_offset = get_le32( header( this )->data_offset ); |
754 | check( data_offset ); | 760 | check( data_offset ); |
755 | if ( data_offset ) | 761 | if ( data_offset ) |
756 | this->pos += data_offset + offsetof (struct header_t,data_offset) - 0x40; | 762 | this->pos += data_offset + offsetof (struct header_t,data_offset) - 0x40; |
@@ -764,266 +770,88 @@ blargg_err_t Vgm_start_track( struct Vgm_Emu* this ) | |||
764 | if ( Ym2612_enabled( &this->ym2612 ) ) | 770 | if ( Ym2612_enabled( &this->ym2612 ) ) |
765 | Ym2612_reset( &this->ym2612 ); | 771 | Ym2612_reset( &this->ym2612 ); |
766 | 772 | ||
767 | Blip_clear( &this->blip_buf, 1 ); | 773 | Blip_clear( &this->blip_buf ); |
768 | Resampler_clear( &this->resampler ); | 774 | Resampler_clear( &this->resampler ); |
769 | } | 775 | } |
770 | 776 | ||
771 | this->fm_time_offset = 0; | 777 | this->fm_time_offset = 0; |
772 | 778 | ||
773 | Buffer_clear( &this->buf ); | 779 | Buffer_clear( &this->stereo_buf ); |
774 | 780 | ||
775 | this->emu_track_ended_ = false; | 781 | // convert filter times to samples |
776 | this->track_ended = false; | 782 | struct setup_t s = this->tfilter; |
783 | s.max_initial *= this->sample_rate * stereo; | ||
784 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD | ||
785 | s.lookahead = 1; | ||
786 | #endif | ||
787 | track_setup( &this->track_filter, &s ); | ||
777 | 788 | ||
778 | if ( !this->ignore_silence ) | 789 | return track_start( &this->track_filter ); |
779 | { | ||
780 | // play until non-silence or end of track | ||
781 | long end; | ||
782 | for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; ) | ||
783 | { | ||
784 | fill_buf( this ); | ||
785 | if ( this->buf_remain | (int) this->emu_track_ended_ ) | ||
786 | break; | ||
787 | } | ||
788 | |||
789 | this->emu_time = this->buf_remain; | ||
790 | this->out_time = 0; | ||
791 | this->silence_time = 0; | ||
792 | this->silence_count = 0; | ||
793 | } | ||
794 | /* return track_ended() ? warning() : 0; */ | ||
795 | return 0; | ||
796 | } | 790 | } |
797 | 791 | ||
798 | // Tell/Seek | 792 | // Tell/Seek |
799 | 793 | ||
800 | static blargg_long msec_to_samples( blargg_long msec, long sample_rate ) | 794 | static int msec_to_samples( int msec, int sample_rate ) |
801 | { | 795 | { |
802 | blargg_long sec = msec / 1000; | 796 | int sec = msec / 1000; |
803 | msec -= sec * 1000; | 797 | msec -= sec * 1000; |
804 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; | 798 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; |
805 | } | 799 | } |
806 | 800 | ||
807 | long Track_tell( struct Vgm_Emu* this ) | 801 | int Track_tell( struct Vgm_Emu* this ) |
808 | { | 802 | { |
809 | blargg_long rate = this->sample_rate * stereo; | 803 | int rate = this->sample_rate * stereo; |
810 | blargg_long sec = this->out_time / rate; | 804 | int sec = track_sample_count( &this->track_filter ) / rate; |
811 | return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate; | 805 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; |
812 | } | 806 | } |
813 | 807 | ||
814 | blargg_err_t Track_seek( struct Vgm_Emu* this, long msec ) | 808 | blargg_err_t Track_seek( struct Vgm_Emu* this, int msec ) |
815 | { | 809 | { |
816 | blargg_long time = msec_to_samples( msec, this->sample_rate ); | 810 | int time = msec_to_samples( msec, this->sample_rate ); |
817 | if ( time < this->out_time ) | 811 | if ( time < track_sample_count( &this->track_filter ) ) |
818 | RETURN_ERR( Vgm_start_track( this ) ); | 812 | RETURN_ERR( Vgm_start_track( this ) ); |
819 | return Track_skip( this, time - this->out_time ); | 813 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); |
820 | } | 814 | } |
821 | 815 | ||
822 | blargg_err_t skip_( struct Vgm_Emu* this, long count ); | 816 | blargg_err_t Track_skip( struct Vgm_Emu* this, int count ) |
823 | blargg_err_t Track_skip( struct Vgm_Emu* this, long count ) | ||
824 | { | 817 | { |
825 | this->out_time += count; | 818 | require( this->current_track >= 0 ); // start_track() must have been called already |
826 | 819 | return track_skip( &this->track_filter, count ); | |
827 | // remove from silence and buf first | ||
828 | { | ||
829 | long n = min( count, this->silence_count ); | ||
830 | this->silence_count -= n; | ||
831 | count -= n; | ||
832 | |||
833 | n = min( count, this->buf_remain ); | ||
834 | this->buf_remain -= n; | ||
835 | count -= n; | ||
836 | } | ||
837 | |||
838 | if ( count && !this->emu_track_ended_ ) | ||
839 | { | ||
840 | this->emu_time += count; | ||
841 | if ( skip_( this, count ) ) | ||
842 | this->emu_track_ended_ = true; | ||
843 | } | ||
844 | |||
845 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
846 | this->track_ended |= this->emu_track_ended_; | ||
847 | |||
848 | return 0; | ||
849 | } | 820 | } |
850 | 821 | ||
851 | blargg_err_t skip_( struct Vgm_Emu* this, long count ) | 822 | blargg_err_t skip_( void* emu, int count ) |
852 | { | 823 | { |
824 | struct Vgm_Emu* this = (struct Vgm_Emu*) emu; | ||
825 | |||
853 | // for long skip, mute sound | 826 | // for long skip, mute sound |
854 | const long threshold = 30000; | 827 | const int threshold = 32768; |
855 | if ( count > threshold ) | 828 | if ( count > threshold ) |
856 | { | 829 | { |
857 | int saved_mute = this->mute_mask_; | 830 | int saved_mute = this->mute_mask_; |
858 | Sound_mute_voices( this, ~0 ); | 831 | Sound_mute_voices( this, ~0 ); |
859 | |||
860 | while ( count > threshold / 2 && !this->emu_track_ended_ ) | ||
861 | { | ||
862 | RETURN_ERR( play_( this, buf_size, this->buf_ ) ); | ||
863 | count -= buf_size; | ||
864 | } | ||
865 | |||
866 | Sound_mute_voices( this, saved_mute ); | ||
867 | } | ||
868 | |||
869 | while ( count && !this->emu_track_ended_ ) | ||
870 | { | ||
871 | long n = buf_size; | ||
872 | if ( n > count ) | ||
873 | n = count; | ||
874 | count -= n; | ||
875 | RETURN_ERR( play_( this, n, this->buf_ ) ); | ||
876 | } | ||
877 | return 0; | ||
878 | } | ||
879 | 832 | ||
880 | // Fading | 833 | int n = count - threshold/2; |
881 | 834 | n &= ~(2048-1); // round to multiple of 2048 | |
882 | void Track_set_fade( struct Vgm_Emu* this, long start_msec, long length_msec ) | 835 | count -= n; |
883 | { | 836 | RETURN_ERR( skippy_( &this->track_filter, n ) ); |
884 | this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo); | ||
885 | this->fade_start = msec_to_samples( start_msec, this->sample_rate ); | ||
886 | } | ||
887 | |||
888 | // unit / pow( 2.0, (double) x / step ) | ||
889 | static int int_log( blargg_long x, int step, int unit ) | ||
890 | { | ||
891 | int shift = x / step; | ||
892 | int fraction = (x - shift * step) * unit / step; | ||
893 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
894 | } | ||
895 | 837 | ||
896 | static void handle_fade( struct Vgm_Emu* this, long out_count, sample_t* out ) | 838 | Sound_mute_voices( this, saved_mute ); |
897 | { | ||
898 | int i; | ||
899 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
900 | { | ||
901 | int const shift = 14; | ||
902 | int const unit = 1 << shift; | ||
903 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
904 | this->fade_step, unit ); | ||
905 | if ( gain < (unit >> fade_shift) ) | ||
906 | this->track_ended = this->emu_track_ended_ = true; | ||
907 | |||
908 | sample_t* io = &out [i]; | ||
909 | int count; | ||
910 | for ( count = min( fade_block_size, out_count - i ); count; --count ) | ||
911 | { | ||
912 | *io = (sample_t) ((*io * gain) >> shift); | ||
913 | ++io; | ||
914 | } | ||
915 | } | 839 | } |
916 | } | ||
917 | 840 | ||
918 | // Silence detection | 841 | return skippy_( &this->track_filter, count ); |
919 | |||
920 | static void emu_play( struct Vgm_Emu* this, long count, sample_t* out ) | ||
921 | { | ||
922 | this->emu_time += count; | ||
923 | if ( !this->emu_track_ended_ ) { | ||
924 | if ( play_( this, count, out ) ) | ||
925 | this->emu_track_ended_ = true; | ||
926 | } | ||
927 | else | ||
928 | memset( out, 0, count * sizeof *out ); | ||
929 | } | 842 | } |
930 | 843 | ||
931 | // number of consecutive silent samples at end | 844 | // Fading |
932 | static long count_silence( sample_t* begin, long size ) | ||
933 | { | ||
934 | sample_t first = *begin; | ||
935 | *begin = silence_threshold; // sentinel | ||
936 | sample_t* p = begin + size; | ||
937 | while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } | ||
938 | *begin = first; | ||
939 | return size - (p - begin); | ||
940 | } | ||
941 | 845 | ||
942 | // fill internal buffer and check it for silence | 846 | void Track_set_fade( struct Vgm_Emu* this, int start_msec, int length_msec ) |
943 | void fill_buf( struct Vgm_Emu* this ) | ||
944 | { | 847 | { |
945 | assert( !this->buf_remain ); | 848 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), |
946 | if ( !this->emu_track_ended_ ) | 849 | length_msec * this->sample_rate / (1000 / stereo) ); |
947 | { | ||
948 | emu_play( this, buf_size, this->buf_ ); | ||
949 | long silence = count_silence( this->buf_, buf_size ); | ||
950 | if ( silence < buf_size ) | ||
951 | { | ||
952 | this->silence_time = this->emu_time - silence; | ||
953 | this->buf_remain = buf_size; | ||
954 | return; | ||
955 | } | ||
956 | } | ||
957 | this->silence_count += buf_size; | ||
958 | } | 850 | } |
959 | 851 | ||
960 | blargg_err_t Vgm_play( struct Vgm_Emu* this, long out_count, sample_t* out ) | 852 | blargg_err_t Vgm_play( struct Vgm_Emu* this, int out_count, sample_t* out ) |
961 | { | 853 | { |
962 | if ( this->track_ended ) | 854 | require( this->current_track >= 0 ); |
963 | { | 855 | require( out_count % stereo == 0 ); |
964 | memset( out, 0, out_count * sizeof *out ); | 856 | return track_play( &this->track_filter, out_count, out ); |
965 | } | ||
966 | else | ||
967 | { | ||
968 | require( out_count % stereo == 0 ); | ||
969 | |||
970 | assert( this->emu_time >= this->out_time ); | ||
971 | |||
972 | // prints nifty graph of how far ahead we are when searching for silence | ||
973 | //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" ); | ||
974 | |||
975 | long pos = 0; | ||
976 | if ( this->silence_count ) | ||
977 | { | ||
978 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
979 | long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time; | ||
980 | while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) | ||
981 | fill_buf( this ); | ||
982 | |||
983 | // fill with silence | ||
984 | pos = min( this->silence_count, out_count ); | ||
985 | memset( out, 0, pos * sizeof *out ); | ||
986 | this->silence_count -= pos; | ||
987 | |||
988 | if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate ) | ||
989 | { | ||
990 | this->track_ended = this->emu_track_ended_ = true; | ||
991 | this->silence_count = 0; | ||
992 | this->buf_remain = 0; | ||
993 | } | ||
994 | } | ||
995 | |||
996 | if ( this->buf_remain ) | ||
997 | { | ||
998 | // empty silence buf | ||
999 | long n = min( this->buf_remain, out_count - pos ); | ||
1000 | memcpy( &out [pos], this->buf_ + (buf_size - this->buf_remain), n * sizeof *out ); | ||
1001 | this->buf_remain -= n; | ||
1002 | pos += n; | ||
1003 | } | ||
1004 | |||
1005 | // generate remaining samples normally | ||
1006 | long remain = out_count - pos; | ||
1007 | if ( remain ) | ||
1008 | { | ||
1009 | emu_play( this, remain, out + pos ); | ||
1010 | this->track_ended |= this->emu_track_ended_; | ||
1011 | |||
1012 | if ( !this->ignore_silence || this->out_time > this->fade_start ) | ||
1013 | { | ||
1014 | // check end for a new run of silence | ||
1015 | long silence = count_silence( out + pos, remain ); | ||
1016 | if ( silence < remain ) | ||
1017 | this->silence_time = this->emu_time - silence; | ||
1018 | |||
1019 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
1020 | fill_buf( this ); // cause silence detection on next play() | ||
1021 | } | ||
1022 | } | ||
1023 | |||
1024 | if ( this->out_time > this->fade_start ) | ||
1025 | handle_fade( this, out_count, out ); | ||
1026 | } | ||
1027 | this->out_time += out_count; | ||
1028 | return 0; | ||
1029 | } | 857 | } |