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/kss_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/kss_emu.c')
-rw-r--r-- | apps/codecs/libgme/kss_emu.c | 373 |
1 files changed, 102 insertions, 271 deletions
diff --git a/apps/codecs/libgme/kss_emu.c b/apps/codecs/libgme/kss_emu.c index 060a5b74b0..ba80ef613e 100644 --- a/apps/codecs/libgme/kss_emu.c +++ b/apps/codecs/libgme/kss_emu.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // Game_Music_Emu 0.5.5. http://www.slack.net/~ant/ | 1 | // Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ |
2 | 2 | ||
3 | #include "kss_emu.h" | 3 | #include "kss_emu.h" |
4 | 4 | ||
@@ -17,29 +17,14 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | |||
17 | 17 | ||
18 | #include "blargg_source.h" | 18 | #include "blargg_source.h" |
19 | 19 | ||
20 | long const clock_rate = 3579545; | 20 | int const clock_rate = 3579545; |
21 | 21 | ||
22 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; | 22 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; |
23 | 23 | ||
24 | int const stereo = 2; // number of channels for stereo | ||
25 | int const silence_max = 6; // seconds | ||
26 | int const silence_threshold = 0x10; | ||
27 | long const fade_block_size = 512; | ||
28 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
29 | |||
30 | static void clear_track_vars( struct Kss_Emu* this ) | 24 | static void clear_track_vars( struct Kss_Emu* this ) |
31 | { | 25 | { |
32 | this->current_track = -1; | 26 | this->current_track = -1; |
33 | this->out_time = 0; | 27 | track_stop( &this->track_filter ); |
34 | this->emu_time = 0; | ||
35 | this->emu_track_ended_ = true; | ||
36 | this->track_ended = true; | ||
37 | this->fade_start = INT_MAX / 2 + 1; | ||
38 | this->fade_step = 1; | ||
39 | this->silence_time = 0; | ||
40 | this->silence_count = 0; | ||
41 | this->buf_remain = 0; | ||
42 | // warning(); // clear warning | ||
43 | } | 28 | } |
44 | 29 | ||
45 | static blargg_err_t init_opl_apu( enum opl_type_t type, struct Opl_Apu* out ) | 30 | static blargg_err_t init_opl_apu( enum opl_type_t type, struct Opl_Apu* out ) |
@@ -58,17 +43,15 @@ void Kss_init( struct Kss_Emu* this ) | |||
58 | this->chip_flags = 0; | 43 | this->chip_flags = 0; |
59 | 44 | ||
60 | // defaults | 45 | // defaults |
61 | this->max_initial_silence = 2; | 46 | this->tfilter = *track_get_setup( &this->track_filter ); |
62 | this->silence_lookahead = 6; | 47 | this->tfilter.max_initial = 2; |
63 | this->ignore_silence = false; | 48 | this->tfilter.lookahead = 6; |
64 | 49 | this->track_filter.silence_ignored_ = false; | |
65 | this->voice_count = 0; | ||
66 | clear_track_vars( this ); | ||
67 | 50 | ||
68 | memset( this->unmapped_read, 0xFF, sizeof this->unmapped_read ); | 51 | memset( this->unmapped_read, 0xFF, sizeof this->unmapped_read ); |
69 | 52 | ||
70 | // Init all stuff | 53 | // Init all stuff |
71 | Buffer_init( &this->stereo_buffer ); | 54 | Buffer_init( &this->stereo_buf ); |
72 | 55 | ||
73 | Z80_init( &this->cpu ); | 56 | Z80_init( &this->cpu ); |
74 | Rom_init( &this->rom, page_size ); | 57 | Rom_init( &this->rom, page_size ); |
@@ -83,6 +66,10 @@ void Kss_init( struct Kss_Emu* this ) | |||
83 | init_opl_apu( type_msxmusic, &this->msx.music ); | 66 | init_opl_apu( type_msxmusic, &this->msx.music ); |
84 | init_opl_apu( type_msxaudio, &this->msx.audio ); | 67 | init_opl_apu( type_msxaudio, &this->msx.audio ); |
85 | #endif | 68 | #endif |
69 | |||
70 | this->voice_count = 0; | ||
71 | this->voice_types = 0; | ||
72 | clear_track_vars( this ); | ||
86 | } | 73 | } |
87 | 74 | ||
88 | // Track info | 75 | // Track info |
@@ -96,7 +83,7 @@ static blargg_err_t check_kss_header( void const* header ) | |||
96 | 83 | ||
97 | // Setup | 84 | // Setup |
98 | 85 | ||
99 | static void update_gain( struct Kss_Emu* this ) | 86 | static void update_gain_( struct Kss_Emu* this ) |
100 | { | 87 | { |
101 | int g = this->gain; | 88 | int g = this->gain; |
102 | if ( msx_music_enabled( this ) || msx_audio_enabled( this ) | 89 | if ( msx_music_enabled( this ) || msx_audio_enabled( this ) |
@@ -118,6 +105,15 @@ static void update_gain( struct Kss_Emu* this ) | |||
118 | if ( msx_audio_enabled( this ) ) Opl_volume( &this->msx.audio, g ); | 105 | if ( msx_audio_enabled( this ) ) Opl_volume( &this->msx.audio, g ); |
119 | } | 106 | } |
120 | 107 | ||
108 | static void update_gain( struct Kss_Emu* this ) | ||
109 | { | ||
110 | if ( this->scc_accessed ) | ||
111 | { | ||
112 | /* dprintf( "SCC accessed\n" ); */ | ||
113 | update_gain_( this ); | ||
114 | } | ||
115 | } | ||
116 | |||
121 | blargg_err_t Kss_load_mem( struct Kss_Emu* this, const void* data, long size ) | 117 | blargg_err_t Kss_load_mem( struct Kss_Emu* this, const void* data, long size ) |
122 | { | 118 | { |
123 | /* warning( core.warning() ); */ | 119 | /* warning( core.warning() ); */ |
@@ -176,6 +172,10 @@ blargg_err_t Kss_load_mem( struct Kss_Emu* this, const void* data, long size ) | |||
176 | 172 | ||
177 | // sms.psg | 173 | // sms.psg |
178 | this->voice_count = sms_osc_count; | 174 | this->voice_count = sms_osc_count; |
175 | static int const types [sms_osc_count + opl_osc_count] = { | ||
176 | wave_type+1, wave_type+3, wave_type+2, mixed_type+1, wave_type+0 | ||
177 | }; | ||
178 | this->voice_types = types; | ||
179 | this->chip_flags |= sms_psg_flag; | 179 | this->chip_flags |= sms_psg_flag; |
180 | 180 | ||
181 | // sms.fm | 181 | // sms.fm |
@@ -191,6 +191,10 @@ blargg_err_t Kss_load_mem( struct Kss_Emu* this, const void* data, long size ) | |||
191 | 191 | ||
192 | // msx.psg | 192 | // msx.psg |
193 | this->voice_count = ay_osc_count; | 193 | this->voice_count = ay_osc_count; |
194 | static int const types [ay_osc_count + opl_osc_count] = { | ||
195 | wave_type+1, wave_type+3, wave_type+2, wave_type+0 | ||
196 | }; | ||
197 | this->voice_types = types; | ||
194 | this->chip_flags |= msx_psg_flag; | 198 | this->chip_flags |= msx_psg_flag; |
195 | 199 | ||
196 | /* if ( this->header.device_flags & 0x10 ) | 200 | /* if ( this->header.device_flags & 0x10 ) |
@@ -220,21 +224,27 @@ blargg_err_t Kss_load_mem( struct Kss_Emu* this, const void* data, long size ) | |||
220 | // msx.scc | 224 | // msx.scc |
221 | this->chip_flags |= msx_scc_flag; | 225 | this->chip_flags |= msx_scc_flag; |
222 | this->voice_count = ay_osc_count + scc_osc_count; | 226 | this->voice_count = ay_osc_count + scc_osc_count; |
227 | static int const types [ay_osc_count + scc_osc_count] = { | ||
228 | wave_type+1, wave_type+3, wave_type+2, | ||
229 | wave_type+0, wave_type+4, wave_type+5, wave_type+6, wave_type+7, | ||
230 | }; | ||
231 | this->voice_types = types; | ||
223 | } | 232 | } |
224 | } | 233 | } |
225 | 234 | ||
226 | this->silence_lookahead = 6; | 235 | this->tfilter.lookahead = 6; |
227 | if ( sms_fm_enabled( this ) || msx_music_enabled( this ) || msx_audio_enabled( this ) ) | 236 | if ( sms_fm_enabled( this ) || msx_music_enabled( this ) || msx_audio_enabled( this ) ) |
228 | { | 237 | { |
229 | if ( !Opl_supported() ) | 238 | if ( !Opl_supported() ) |
230 | ; /* warning( "FM sound not supported" ); */ | 239 | ; /* warning( "FM sound not supported" ); */ |
231 | else | 240 | else |
232 | this->silence_lookahead = 3; // Opl_Apu is really slow | 241 | this->tfilter.lookahead = 3; // Opl_Apu is really slow |
233 | } | 242 | } |
234 | 243 | ||
235 | this->clock_rate_ = clock_rate; | 244 | this->clock_rate_ = clock_rate; |
236 | Buffer_clock_rate( &this->stereo_buffer, clock_rate ); | 245 | Buffer_clock_rate( &this->stereo_buf, clock_rate ); |
237 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buffer ); | 246 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); |
247 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | ||
238 | 248 | ||
239 | Sound_set_tempo( this, this->tempo ); | 249 | Sound_set_tempo( this, this->tempo ); |
240 | Sound_mute_voices( this, this->mute_mask_ ); | 250 | Sound_mute_voices( this, this->mute_mask_ ); |
@@ -265,8 +275,8 @@ static void set_voice( struct Kss_Emu* this, int i, struct Blip_Buffer* center, | |||
265 | } | 275 | } |
266 | 276 | ||
267 | if ( msx_scc_enabled( this ) && i < scc_osc_count ) Scc_set_output( &this->msx.scc, i, center ); | 277 | if ( msx_scc_enabled( this ) && i < scc_osc_count ) Scc_set_output( &this->msx.scc, i, center ); |
268 | if ( msx_music_enabled( this ) && i < opl_osc_count ) Opl_set_output( &this->msx.music, center ); | 278 | if ( msx_music_enabled( this ) && i < opl_osc_count ) Opl_set_output( &this->msx.music, center ); |
269 | if ( msx_audio_enabled( this ) && i < opl_osc_count ) Opl_set_output( &this->msx.audio, center ); | 279 | if ( msx_audio_enabled( this ) && i < opl_osc_count ) Opl_set_output( &this->msx.audio, center ); |
270 | } | 280 | } |
271 | } | 281 | } |
272 | 282 | ||
@@ -465,15 +475,17 @@ blargg_err_t end_frame( struct Kss_Emu* this, kss_time_t end ) | |||
465 | 475 | ||
466 | // MUSIC | 476 | // MUSIC |
467 | 477 | ||
468 | 478 | blargg_err_t Kss_set_sample_rate( struct Kss_Emu* this, int rate ) | |
469 | blargg_err_t Kss_set_sample_rate( struct Kss_Emu* this, long rate ) | ||
470 | { | 479 | { |
471 | require( !this->sample_rate ); // sample rate can't be changed once set | 480 | require( !this->sample_rate ); // sample rate can't be changed once set |
472 | RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buffer, rate, 1000 / 20 ) ); | 481 | RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) ); |
473 | 482 | ||
474 | // Set bass frequency | 483 | // Set bass frequency |
475 | Buffer_bass_freq( &this->stereo_buffer, 180 ); | 484 | Buffer_bass_freq( &this->stereo_buf, 180 ); |
485 | |||
476 | this->sample_rate = rate; | 486 | this->sample_rate = rate; |
487 | RETURN_ERR( track_init( &this->track_filter, this ) ); | ||
488 | this->tfilter.max_silence = 6 * stereo * this->sample_rate; | ||
477 | return 0; | 489 | return 0; |
478 | } | 490 | } |
479 | 491 | ||
@@ -501,7 +513,7 @@ void Sound_mute_voices( struct Kss_Emu* this, int mask ) | |||
501 | } | 513 | } |
502 | else | 514 | else |
503 | { | 515 | { |
504 | struct channel_t ch = Buffer_channel( &this->stereo_buffer ); | 516 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); |
505 | assert( (ch.center && ch.left && ch.right) || | 517 | assert( (ch.center && ch.left && ch.right) || |
506 | (!ch.center && !ch.left && !ch.right) ); // all or nothing | 518 | (!ch.center && !ch.left && !ch.right) ); // all or nothing |
507 | set_voice( this, i, ch.center, ch.left, ch.right ); | 519 | set_voice( this, i, ch.center, ch.left, ch.right ); |
@@ -523,7 +535,6 @@ void Sound_set_tempo( struct Kss_Emu* this, int t ) | |||
523 | this->play_period = (blip_time_t) ((period * FP_ONE_TEMPO) / t); | 535 | this->play_period = (blip_time_t) ((period * FP_ONE_TEMPO) / t); |
524 | } | 536 | } |
525 | 537 | ||
526 | void fill_buf( struct Kss_Emu* this ); | ||
527 | blargg_err_t Kss_start_track( struct Kss_Emu* this, int track ) | 538 | blargg_err_t Kss_start_track( struct Kss_Emu* this, int track ) |
528 | { | 539 | { |
529 | clear_track_vars( this ); | 540 | clear_track_vars( this ); |
@@ -536,7 +547,7 @@ blargg_err_t Kss_start_track( struct Kss_Emu* this, int track ) | |||
536 | 547 | ||
537 | this->current_track = track; | 548 | this->current_track = track; |
538 | 549 | ||
539 | Buffer_clear( &this->stereo_buffer ); | 550 | Buffer_clear( &this->stereo_buf ); |
540 | 551 | ||
541 | if ( sms_psg_enabled( this ) ) Sms_apu_reset( &this->sms.psg, 0, 0 ); | 552 | if ( sms_psg_enabled( this ) ) Sms_apu_reset( &this->sms.psg, 0, 0 ); |
542 | if ( sms_fm_enabled( this ) ) Opl_reset( &this->sms.fm ); | 553 | if ( sms_fm_enabled( this ) ) Opl_reset( &this->sms.fm ); |
@@ -546,7 +557,7 @@ blargg_err_t Kss_start_track( struct Kss_Emu* this, int track ) | |||
546 | if ( msx_audio_enabled( this ) ) Opl_reset( &this->msx.audio ); | 557 | if ( msx_audio_enabled( this ) ) Opl_reset( &this->msx.audio ); |
547 | 558 | ||
548 | this->scc_accessed = false; | 559 | this->scc_accessed = false; |
549 | update_gain( this ); | 560 | update_gain_( this ); |
550 | 561 | ||
551 | memset( this->ram, 0xC9, 0x4000 ); | 562 | memset( this->ram, 0xC9, 0x4000 ); |
552 | memset( this->ram + 0x4000, 0, sizeof this->ram - 0x4000 ); | 563 | memset( this->ram + 0x4000, 0, sizeof this->ram - 0x4000 ); |
@@ -598,286 +609,106 @@ blargg_err_t Kss_start_track( struct Kss_Emu* this, int track ) | |||
598 | this->gain_updated = false; | 609 | this->gain_updated = false; |
599 | jsr( this, this->header.init_addr ); | 610 | jsr( this, this->header.init_addr ); |
600 | 611 | ||
601 | this->emu_track_ended_ = false; | 612 | // convert filter times to samples |
602 | this->track_ended = false; | 613 | struct setup_t s = this->tfilter; |
614 | s.max_initial *= this->sample_rate * stereo; | ||
615 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD | ||
616 | s.lookahead = 1; | ||
617 | #endif | ||
618 | track_setup( &this->track_filter, &s ); | ||
603 | 619 | ||
604 | if ( !this->ignore_silence ) | 620 | return track_start( &this->track_filter ); |
605 | { | ||
606 | // play until non-silence or end of track | ||
607 | long end; | ||
608 | for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; ) | ||
609 | { | ||
610 | fill_buf( this ); | ||
611 | if ( this->buf_remain | (int) this->emu_track_ended_ ) | ||
612 | break; | ||
613 | } | ||
614 | |||
615 | this->emu_time = this->buf_remain; | ||
616 | this->out_time = 0; | ||
617 | this->silence_time = 0; | ||
618 | this->silence_count = 0; | ||
619 | } | ||
620 | /* return track_ended() ? warning() : 0; */ | ||
621 | return 0; | ||
622 | } | 621 | } |
623 | 622 | ||
624 | // Tell/Seek | 623 | // Tell/Seek |
625 | 624 | ||
626 | static blargg_long msec_to_samples( blargg_long msec, long sample_rate ) | 625 | static int msec_to_samples( int msec, int sample_rate ) |
627 | { | 626 | { |
628 | blargg_long sec = msec / 1000; | 627 | int sec = msec / 1000; |
629 | msec -= sec * 1000; | 628 | msec -= sec * 1000; |
630 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; | 629 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; |
631 | } | 630 | } |
632 | 631 | ||
633 | long Track_tell( struct Kss_Emu* this ) | 632 | int Track_tell( struct Kss_Emu* this ) |
634 | { | 633 | { |
635 | blargg_long rate = this->sample_rate * stereo; | 634 | int rate = this->sample_rate * stereo; |
636 | blargg_long sec = this->out_time / rate; | 635 | int sec = track_sample_count( &this->track_filter ) / rate; |
637 | return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate; | 636 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; |
638 | } | 637 | } |
639 | 638 | ||
640 | blargg_err_t Track_seek( struct Kss_Emu* this, long msec ) | 639 | blargg_err_t Track_seek( struct Kss_Emu* this, int msec ) |
641 | { | 640 | { |
642 | blargg_long time = msec_to_samples( msec, this->sample_rate ); | 641 | int time = msec_to_samples( msec, this->sample_rate ); |
643 | if ( time < this->out_time ) | 642 | if ( time < track_sample_count( &this->track_filter ) ) |
644 | RETURN_ERR( Kss_start_track( this, this->current_track ) ); | 643 | RETURN_ERR( Kss_start_track( this, this->current_track ) ); |
645 | return Track_skip( this, time - this->out_time ); | 644 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); |
646 | } | 645 | } |
647 | 646 | ||
648 | blargg_err_t play_( struct Kss_Emu* this, long count, sample_t* out ); | 647 | blargg_err_t skip_( void *emu, int count ) |
649 | static blargg_err_t skip_( struct Kss_Emu* this, long count ) | ||
650 | { | 648 | { |
649 | struct Kss_Emu* this = (struct Kss_Emu*) emu; | ||
650 | |||
651 | // for long skip, mute sound | 651 | // for long skip, mute sound |
652 | const long threshold = 30000; | 652 | const int threshold = 32768; |
653 | if ( count > threshold ) | 653 | if ( count > threshold ) |
654 | { | 654 | { |
655 | int saved_mute = this->mute_mask_; | 655 | int saved_mute = this->mute_mask_; |
656 | Sound_mute_voices( this, ~0 ); | 656 | Sound_mute_voices( this, ~0 ); |
657 | |||
658 | while ( count > threshold / 2 && !this->emu_track_ended_ ) | ||
659 | { | ||
660 | RETURN_ERR( play_( this, buf_size, this->buf ) ); | ||
661 | count -= buf_size; | ||
662 | } | ||
663 | |||
664 | Sound_mute_voices( this, saved_mute ); | ||
665 | } | ||
666 | |||
667 | while ( count && !this->emu_track_ended_ ) | ||
668 | { | ||
669 | long n = buf_size; | ||
670 | if ( n > count ) | ||
671 | n = count; | ||
672 | count -= n; | ||
673 | RETURN_ERR( play_( this, n, this->buf ) ); | ||
674 | } | ||
675 | return 0; | ||
676 | } | ||
677 | 657 | ||
678 | blargg_err_t Track_skip( struct Kss_Emu* this, long count ) | 658 | int n = count - threshold/2; |
679 | { | 659 | n &= ~(2048-1); // round to multiple of 2048 |
680 | require( this->current_track >= 0 ); // start_track() must have been called already | ||
681 | this->out_time += count; | ||
682 | |||
683 | // remove from silence and buf first | ||
684 | { | ||
685 | long n = min( count, this->silence_count ); | ||
686 | this->silence_count -= n; | ||
687 | count -= n; | ||
688 | |||
689 | n = min( count, this->buf_remain ); | ||
690 | this->buf_remain -= n; | ||
691 | count -= n; | 660 | count -= n; |
692 | } | 661 | RETURN_ERR( skippy_( &this->track_filter, n ) ); |
693 | |||
694 | if ( count && !this->emu_track_ended_ ) | ||
695 | { | ||
696 | this->emu_time += count; | ||
697 | if ( skip_( this, count ) ) | ||
698 | this->emu_track_ended_ = true; | ||
699 | } | ||
700 | |||
701 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
702 | this->track_ended |= this->emu_track_ended_; | ||
703 | |||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | // Fading | ||
708 | 662 | ||
709 | void Track_set_fade( struct Kss_Emu* this, long start_msec, long length_msec ) | 663 | Sound_mute_voices( this, saved_mute ); |
710 | { | ||
711 | this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo); | ||
712 | this->fade_start = msec_to_samples( start_msec, this->sample_rate ); | ||
713 | } | ||
714 | |||
715 | // unit / pow( 2.0, (double) x / step ) | ||
716 | static int int_log( blargg_long x, int step, int unit ) | ||
717 | { | ||
718 | int shift = x / step; | ||
719 | int fraction = (x - shift * step) * unit / step; | ||
720 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
721 | } | ||
722 | |||
723 | static void handle_fade( struct Kss_Emu *this, long out_count, sample_t* out ) | ||
724 | { | ||
725 | int i; | ||
726 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
727 | { | ||
728 | int const shift = 14; | ||
729 | int const unit = 1 << shift; | ||
730 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
731 | this->fade_step, unit ); | ||
732 | if ( gain < (unit >> fade_shift) ) | ||
733 | this->track_ended = this->emu_track_ended_ = true; | ||
734 | |||
735 | sample_t* io = &out [i]; | ||
736 | int count; | ||
737 | for ( count = min( fade_block_size, out_count - i ); count; --count ) | ||
738 | { | ||
739 | *io = (sample_t) ((*io * gain) >> shift); | ||
740 | ++io; | ||
741 | } | ||
742 | } | 664 | } |
743 | } | ||
744 | |||
745 | // Silence detection | ||
746 | 665 | ||
747 | static void emu_play( struct Kss_Emu* this, long count, sample_t* out ) | 666 | return skippy_( &this->track_filter, count ); |
748 | { | ||
749 | check( current_track_ >= 0 ); | ||
750 | this->emu_time += count; | ||
751 | if ( this->current_track >= 0 && !this->emu_track_ended_ ) { | ||
752 | if ( play_( this, count, out ) ) | ||
753 | this->emu_track_ended_ = true; | ||
754 | } | ||
755 | else | ||
756 | memset( out, 0, count * sizeof *out ); | ||
757 | } | 667 | } |
758 | 668 | ||
759 | // number of consecutive silent samples at end | 669 | blargg_err_t Track_skip( struct Kss_Emu* this, int count ) |
760 | static long count_silence( sample_t* begin, long size ) | ||
761 | { | 670 | { |
762 | sample_t first = *begin; | 671 | require( this->current_track >= 0 ); // start_track() must have been called already |
763 | *begin = silence_threshold; // sentinel | 672 | return track_skip( &this->track_filter, count ); |
764 | sample_t* p = begin + size; | ||
765 | while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } | ||
766 | *begin = first; | ||
767 | return size - (p - begin); | ||
768 | } | 673 | } |
769 | 674 | ||
770 | // fill internal buffer and check it for silence | 675 | void Track_set_fade( struct Kss_Emu* this, int start_msec, int length_msec ) |
771 | void fill_buf( struct Kss_Emu* this ) | ||
772 | { | 676 | { |
773 | assert( !this->buf_remain ); | 677 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), |
774 | if ( !this->emu_track_ended_ ) | 678 | length_msec * this->sample_rate / (1000 / stereo) ); |
775 | { | ||
776 | emu_play( this, buf_size, this->buf ); | ||
777 | long silence = count_silence( this->buf, buf_size ); | ||
778 | if ( silence < buf_size ) | ||
779 | { | ||
780 | this->silence_time = this->emu_time - silence; | ||
781 | this->buf_remain = buf_size; | ||
782 | return; | ||
783 | } | ||
784 | } | ||
785 | this->silence_count += buf_size; | ||
786 | } | 679 | } |
787 | 680 | ||
788 | blargg_err_t Kss_play( struct Kss_Emu* this, long out_count, sample_t* out ) | 681 | blargg_err_t Kss_play( struct Kss_Emu* this, int out_count, sample_t* out ) |
789 | { | 682 | { |
790 | if ( this->track_ended ) | 683 | require( this->current_track >= 0 ); |
791 | { | 684 | require( out_count % stereo == 0 ); |
792 | memset( out, 0, out_count * sizeof *out ); | 685 | return track_play( &this->track_filter, out_count, out ); |
793 | } | ||
794 | else | ||
795 | { | ||
796 | require( this->current_track >= 0 ); | ||
797 | require( out_count % stereo == 0 ); | ||
798 | |||
799 | assert( this->emu_time >= this->out_time ); | ||
800 | |||
801 | // prints nifty graph of how far ahead we are when searching for silence | ||
802 | //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" ); | ||
803 | |||
804 | long pos = 0; | ||
805 | if ( this->silence_count ) | ||
806 | { | ||
807 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
808 | long ahead_time = this->silence_lookahead * (this->out_time + out_count -this->silence_time) + this->silence_time; | ||
809 | while ( this->emu_time < ahead_time && !(this->buf_remain |this-> emu_track_ended_) ) | ||
810 | fill_buf( this ); | ||
811 | |||
812 | // fill with silence | ||
813 | pos = min( this->silence_count, out_count ); | ||
814 | memset( out, 0, pos * sizeof *out ); | ||
815 | this->silence_count -= pos; | ||
816 | |||
817 | if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate ) | ||
818 | { | ||
819 | this->track_ended = this->emu_track_ended_ = true; | ||
820 | this->silence_count = 0; | ||
821 | this->buf_remain = 0; | ||
822 | } | ||
823 | } | ||
824 | |||
825 | if ( this->buf_remain ) | ||
826 | { | ||
827 | // empty silence buf | ||
828 | long n = min( this->buf_remain, out_count - pos ); | ||
829 | memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out ); | ||
830 | this->buf_remain -= n; | ||
831 | pos += n; | ||
832 | } | ||
833 | |||
834 | // generate remaining samples normally | ||
835 | long remain = out_count - pos; | ||
836 | if ( remain ) | ||
837 | { | ||
838 | emu_play( this, remain, out + pos ); | ||
839 | this->track_ended |= this->emu_track_ended_; | ||
840 | |||
841 | if ( !this->ignore_silence || this->out_time > this->fade_start ) | ||
842 | { | ||
843 | // check end for a new run of silence | ||
844 | long silence = count_silence( out + pos, remain ); | ||
845 | if ( silence < remain ) | ||
846 | this->silence_time = this->emu_time - silence; | ||
847 | |||
848 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
849 | fill_buf( this ); // cause silence detection on next play() | ||
850 | } | ||
851 | } | ||
852 | |||
853 | if ( this->out_time > this->fade_start ) | ||
854 | handle_fade( this, out_count, out ); | ||
855 | } | ||
856 | this->out_time += out_count; | ||
857 | return 0; | ||
858 | } | 686 | } |
859 | 687 | ||
860 | blargg_err_t play_( struct Kss_Emu* this, long count, sample_t* out ) | 688 | blargg_err_t play_( void *emu, int count, sample_t* out ) |
861 | { | 689 | { |
862 | long remain = count; | 690 | struct Kss_Emu* this = (struct Kss_Emu*) emu; |
691 | |||
692 | int remain = count; | ||
863 | while ( remain ) | 693 | while ( remain ) |
864 | { | 694 | { |
865 | remain -= Buffer_read_samples( &this->stereo_buffer, &out [count - remain], remain ); | 695 | Buffer_disable_immediate_removal( &this->stereo_buf ); |
696 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); | ||
866 | if ( remain ) | 697 | if ( remain ) |
867 | { | 698 | { |
868 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buffer ) ) | 699 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) |
869 | { | 700 | { |
870 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buffer ); | 701 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
702 | |||
703 | // Remute voices | ||
871 | Sound_mute_voices( this, this->mute_mask_ ); | 704 | Sound_mute_voices( this, this->mute_mask_ ); |
872 | } | 705 | } |
873 | int msec = Buffer_length( &this->stereo_buffer ); | 706 | int msec = Buffer_length( &this->stereo_buf ); |
874 | /* blip_time_t clocks_emulated = (blargg_long) msec * clock_rate_ / 1000; */ | ||
875 | blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; | 707 | blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; |
876 | RETURN_ERR( run_clocks( this, &clocks_emulated ) ); | 708 | RETURN_ERR( run_clocks( this, &clocks_emulated ) ); |
877 | assert( clocks_emulated ); | 709 | assert( clocks_emulated ); |
878 | Buffer_end_frame( &this->stereo_buffer, clocks_emulated ); | 710 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); |
879 | } | 711 | } |
880 | } | 712 | } |
881 | return 0; | 713 | return 0; |
882 | } | 714 | } |
883 | |||