diff options
68 files changed, 4036 insertions, 4816 deletions
diff --git a/apps/codecs/ay.c b/apps/codecs/ay.c index 914ffa9803..b11ad84294 100644 --- a/apps/codecs/ay.c +++ b/apps/codecs/ay.c | |||
@@ -74,7 +74,7 @@ enum codec_status codec_run(void) | |||
74 | } | 74 | } |
75 | 75 | ||
76 | if ((err = Ay_load_mem(&ay_emu, buf, ci->filesize))) { | 76 | if ((err = Ay_load_mem(&ay_emu, buf, ci->filesize))) { |
77 | DEBUGF("AY: Ay_load failed (%s)\n", err); | 77 | DEBUGF("AY: Ay_load_mem failed (%s)\n", err); |
78 | return CODEC_ERROR; | 78 | return CODEC_ERROR; |
79 | } | 79 | } |
80 | 80 | ||
@@ -118,7 +118,7 @@ next_track: | |||
118 | 118 | ||
119 | /* Generate audio buffer */ | 119 | /* Generate audio buffer */ |
120 | err = Ay_play(&ay_emu, CHUNK_SIZE, samples); | 120 | err = Ay_play(&ay_emu, CHUNK_SIZE, samples); |
121 | if (err || ay_emu.track_ended) { | 121 | if (err || Track_ended(&ay_emu)) { |
122 | track++; | 122 | track++; |
123 | if (track >= ay_emu.track_count) break; | 123 | if (track >= ay_emu.track_count) break; |
124 | goto next_track; | 124 | goto next_track; |
diff --git a/apps/codecs/gbs.c b/apps/codecs/gbs.c index c9c3420683..def05ed351 100644 --- a/apps/codecs/gbs.c +++ b/apps/codecs/gbs.c | |||
@@ -67,8 +67,8 @@ enum codec_status codec_run(void) | |||
67 | return CODEC_ERROR; | 67 | return CODEC_ERROR; |
68 | } | 68 | } |
69 | 69 | ||
70 | if ((err = Gbs_load(&gbs_emu, buf, ci->filesize))) { | 70 | if ((err = Gbs_load_mem(&gbs_emu, buf, ci->filesize))) { |
71 | DEBUGF("GBS: Gbs_load failed (%s)\n", err); | 71 | DEBUGF("GBS: Gbs_load_mem failed (%s)\n", err); |
72 | return CODEC_ERROR; | 72 | return CODEC_ERROR; |
73 | } | 73 | } |
74 | 74 | ||
@@ -95,7 +95,7 @@ next_track: | |||
95 | 95 | ||
96 | /* Generate audio buffer */ | 96 | /* Generate audio buffer */ |
97 | err = Gbs_play(&gbs_emu, CHUNK_SIZE, samples); | 97 | err = Gbs_play(&gbs_emu, CHUNK_SIZE, samples); |
98 | if (err || gbs_emu.track_ended) { | 98 | if (err || Track_ended(&gbs_emu)) { |
99 | track++; | 99 | track++; |
100 | if (track >= gbs_emu.track_count) break; | 100 | if (track >= gbs_emu.track_count) break; |
101 | goto next_track; | 101 | goto next_track; |
diff --git a/apps/codecs/hes.c b/apps/codecs/hes.c index c84134c01b..849fd88f12 100644 --- a/apps/codecs/hes.c +++ b/apps/codecs/hes.c | |||
@@ -67,8 +67,8 @@ enum codec_status codec_run(void) | |||
67 | return CODEC_ERROR; | 67 | return CODEC_ERROR; |
68 | } | 68 | } |
69 | 69 | ||
70 | if ((err = Hes_load(&hes_emu, buf, ci->filesize))) { | 70 | if ((err = Hes_load_mem(&hes_emu, buf, ci->filesize))) { |
71 | DEBUGF("HES: Hes_load failed (%s)\n", err); | 71 | DEBUGF("HES: Hes_load_mem failed (%s)\n", err); |
72 | return CODEC_ERROR; | 72 | return CODEC_ERROR; |
73 | } | 73 | } |
74 | 74 | ||
@@ -95,7 +95,7 @@ next_track: | |||
95 | 95 | ||
96 | /* Generate audio buffer */ | 96 | /* Generate audio buffer */ |
97 | err = Hes_play(&hes_emu, CHUNK_SIZE, samples); | 97 | err = Hes_play(&hes_emu, CHUNK_SIZE, samples); |
98 | if (err || hes_emu.track_ended) { | 98 | if (err || Track_ended(&hes_emu)) { |
99 | track++; | 99 | track++; |
100 | if (track >= hes_emu.track_count) break; | 100 | if (track >= hes_emu.track_count) break; |
101 | goto next_track; | 101 | goto next_track; |
diff --git a/apps/codecs/kss.c b/apps/codecs/kss.c index f519b3c706..92efcd4e5f 100644 --- a/apps/codecs/kss.c +++ b/apps/codecs/kss.c | |||
@@ -98,7 +98,7 @@ next_track: | |||
98 | 98 | ||
99 | /* Generate audio buffer */ | 99 | /* Generate audio buffer */ |
100 | err = Kss_play(&kss_emu, CHUNK_SIZE, samples); | 100 | err = Kss_play(&kss_emu, CHUNK_SIZE, samples); |
101 | if (err || kss_emu.track_ended) { | 101 | if (err || Track_ended(&kss_emu)) { |
102 | track++; | 102 | track++; |
103 | if (track >= kss_emu.track_count) break; | 103 | if (track >= kss_emu.track_count) break; |
104 | goto next_track; | 104 | goto next_track; |
diff --git a/apps/codecs/libgme/AYSOURCES b/apps/codecs/libgme/AYSOURCES index 51253fe2f1..f2b52a51d9 100644 --- a/apps/codecs/libgme/AYSOURCES +++ b/apps/codecs/libgme/AYSOURCES | |||
@@ -3,4 +3,5 @@ ay_cpu.c | |||
3 | ay_emu.c | 3 | ay_emu.c |
4 | blip_buffer.c | 4 | blip_buffer.c |
5 | multi_buffer.c | 5 | multi_buffer.c |
6 | track_filter.c | ||
6 | z80_cpu.c | 7 | z80_cpu.c |
diff --git a/apps/codecs/libgme/GBSSOURCES b/apps/codecs/libgme/GBSSOURCES index 5548fd85eb..a839a2156e 100644 --- a/apps/codecs/libgme/GBSSOURCES +++ b/apps/codecs/libgme/GBSSOURCES | |||
@@ -6,3 +6,4 @@ gbs_emu.c | |||
6 | blip_buffer.c | 6 | blip_buffer.c |
7 | multi_buffer.c | 7 | multi_buffer.c |
8 | rom_data.c | 8 | rom_data.c |
9 | track_filter.c | ||
diff --git a/apps/codecs/libgme/HESSOURCES b/apps/codecs/libgme/HESSOURCES index 58a38f2f5a..d529388978 100644 --- a/apps/codecs/libgme/HESSOURCES +++ b/apps/codecs/libgme/HESSOURCES | |||
@@ -5,3 +5,4 @@ hes_emu.c | |||
5 | blip_buffer.c | 5 | blip_buffer.c |
6 | multi_buffer.c | 6 | multi_buffer.c |
7 | rom_data.c | 7 | rom_data.c |
8 | track_filter.c | ||
diff --git a/apps/codecs/libgme/KSSSOURCES b/apps/codecs/libgme/KSSSOURCES index 2607c7364c..bde213364b 100644 --- a/apps/codecs/libgme/KSSSOURCES +++ b/apps/codecs/libgme/KSSSOURCES | |||
@@ -9,3 +9,4 @@ multi_buffer.c | |||
9 | rom_data.c | 9 | rom_data.c |
10 | emu8950.c | 10 | emu8950.c |
11 | emuadpcm.c | 11 | emuadpcm.c |
12 | track_filter.c | ||
diff --git a/apps/codecs/libgme/NSFSOURCES b/apps/codecs/libgme/NSFSOURCES index 54b4f82f60..60537ff8e4 100644 --- a/apps/codecs/libgme/NSFSOURCES +++ b/apps/codecs/libgme/NSFSOURCES | |||
@@ -12,3 +12,4 @@ nsfe_info.c | |||
12 | blip_buffer.c | 12 | blip_buffer.c |
13 | multi_buffer.c | 13 | multi_buffer.c |
14 | rom_data.c | 14 | rom_data.c |
15 | track_filter.c | ||
diff --git a/apps/codecs/libgme/SGCSOURCES b/apps/codecs/libgme/SGCSOURCES index d91c0e1731..d0e8abc2b7 100644 --- a/apps/codecs/libgme/SGCSOURCES +++ b/apps/codecs/libgme/SGCSOURCES | |||
@@ -4,3 +4,4 @@ z80_cpu.c | |||
4 | blip_buffer.c | 4 | blip_buffer.c |
5 | multi_buffer.c | 5 | multi_buffer.c |
6 | rom_data.c | 6 | rom_data.c |
7 | track_filter.c | ||
diff --git a/apps/codecs/libgme/VGMSOURCES b/apps/codecs/libgme/VGMSOURCES index 637f87e8b0..bb57e16e82 100644 --- a/apps/codecs/libgme/VGMSOURCES +++ b/apps/codecs/libgme/VGMSOURCES | |||
@@ -3,6 +3,7 @@ multi_buffer.c | |||
3 | resampler.c | 3 | resampler.c |
4 | vgm_emu.c | 4 | vgm_emu.c |
5 | ym2612_emu.c | 5 | ym2612_emu.c |
6 | track_filter.c | ||
6 | inflate/bbfuncs.c | 7 | inflate/bbfuncs.c |
7 | inflate/inflate.c | 8 | inflate/inflate.c |
8 | inflate/mallocer.c | 9 | inflate/mallocer.c |
diff --git a/apps/codecs/libgme/ay_emu.c b/apps/codecs/libgme/ay_emu.c index e961797dd3..42e739f2df 100644 --- a/apps/codecs/libgme/ay_emu.c +++ b/apps/codecs/libgme/ay_emu.c | |||
@@ -17,12 +17,6 @@ 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 | int const stereo = 2; // number of channels for stereo | ||
21 | int const silence_max = 6; // seconds | ||
22 | int const silence_threshold = 0x10; | ||
23 | long const fade_block_size = 512; | ||
24 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
25 | |||
26 | const char* const gme_wrong_file_type = "Wrong file type for this emulator"; | 20 | const char* const gme_wrong_file_type = "Wrong file type for this emulator"; |
27 | 21 | ||
28 | // TODO: probably don't need detailed errors as to why file is corrupt | 22 | // TODO: probably don't need detailed errors as to why file is corrupt |
@@ -38,16 +32,7 @@ int const cpc_clock = 2000000; | |||
38 | static void clear_track_vars( struct Ay_Emu *this ) | 32 | static void clear_track_vars( struct Ay_Emu *this ) |
39 | { | 33 | { |
40 | this->current_track = -1; | 34 | this->current_track = -1; |
41 | this->out_time = 0; | 35 | track_stop( &this->track_filter ); |
42 | this->emu_time = 0; | ||
43 | this->emu_track_ended_ = true; | ||
44 | this->track_ended = true; | ||
45 | this->fade_start = INT_MAX / 2 + 1; | ||
46 | this->fade_step = 1; | ||
47 | this->silence_time = 0; | ||
48 | this->silence_count = 0; | ||
49 | this->buf_remain = 0; | ||
50 | /* warning(); // clear warning */ | ||
51 | } | 36 | } |
52 | 37 | ||
53 | void Ay_init( struct Ay_Emu *this ) | 38 | void Ay_init( struct Ay_Emu *this ) |
@@ -59,18 +44,21 @@ void Ay_init( struct Ay_Emu *this ) | |||
59 | this->track_count = 0; | 44 | this->track_count = 0; |
60 | 45 | ||
61 | // defaults | 46 | // defaults |
62 | this->max_initial_silence = 2; | 47 | this->tfilter = *track_get_setup( &this->track_filter ); |
63 | this->ignore_silence = false; | 48 | this->tfilter.max_initial = 2; |
49 | this->tfilter.lookahead = 6; | ||
50 | this->track_filter.silence_ignored_ = false; | ||
64 | 51 | ||
65 | this->voice_count = 0; | ||
66 | clear_track_vars( this ); | ||
67 | this->beeper_output = NULL; | 52 | this->beeper_output = NULL; |
68 | disable_beeper( this ); | 53 | disable_beeper( this ); |
69 | 54 | ||
70 | Ay_apu_init( &this->apu ); | 55 | Ay_apu_init( &this->apu ); |
71 | Z80_init( &this->cpu ); | 56 | Z80_init( &this->cpu ); |
72 | 57 | ||
73 | this->silence_lookahead = 6 ; | 58 | // clears fields |
59 | this->voice_count = 0; | ||
60 | this->voice_types = 0; | ||
61 | clear_track_vars( this ); | ||
74 | } | 62 | } |
75 | 63 | ||
76 | // Track info | 64 | // Track info |
@@ -107,35 +95,22 @@ static blargg_err_t parse_header( byte const in [], int size, struct file_t* out | |||
107 | return 0; | 95 | return 0; |
108 | } | 96 | } |
109 | 97 | ||
110 | long Track_get_length( struct Ay_Emu* this, int n ) | ||
111 | { | ||
112 | long length = 0; | ||
113 | |||
114 | byte const* track_info = get_data( &this->file, this->file.tracks + n * 4 + 2, 6 ); | ||
115 | if ( track_info ) | ||
116 | length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec | ||
117 | |||
118 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { | ||
119 | struct entry_t* entry = &this->m3u.entries [n]; | ||
120 | length = entry->length; | ||
121 | } | ||
122 | |||
123 | if ( length <= 0 ) | ||
124 | length = 120 * 1000; /* 2 minutes */ | ||
125 | |||
126 | return length; | ||
127 | } | ||
128 | |||
129 | // Setup | 98 | // Setup |
130 | 99 | ||
131 | static void change_clock_rate( struct Ay_Emu *this, long rate ) | 100 | static void change_clock_rate( struct Ay_Emu *this, int rate ) |
132 | { | 101 | { |
133 | this->clock_rate_ = rate; | 102 | this->clock_rate_ = rate; |
134 | Buffer_clock_rate( &this->stereo_buf, rate ); | 103 | Buffer_clock_rate( &this->stereo_buf, rate ); |
135 | } | 104 | } |
136 | 105 | ||
137 | blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], int size ) | 106 | blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], long size ) |
138 | { | 107 | { |
108 | // Unload | ||
109 | this->voice_count = 0; | ||
110 | this->track_count = 0; | ||
111 | this->m3u.size = 0; | ||
112 | clear_track_vars( this ); | ||
113 | |||
139 | assert( offsetof (struct header_t,track_info [2]) == header_size ); | 114 | assert( offsetof (struct header_t,track_info [2]) == header_size ); |
140 | 115 | ||
141 | RETURN_ERR( parse_header( in, size, &this->file ) ); | 116 | RETURN_ERR( parse_header( in, size, &this->file ) ); |
@@ -144,19 +119,22 @@ blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], int size ) | |||
144 | warning( "Unknown file version" ); */ | 119 | warning( "Unknown file version" ); */ |
145 | 120 | ||
146 | this->voice_count = ay_osc_count + 1; // +1 for beeper | 121 | this->voice_count = ay_osc_count + 1; // +1 for beeper |
122 | static int const types [ay_osc_count + 1] = { | ||
123 | wave_type+0, wave_type+1, wave_type+2, mixed_type+1 | ||
124 | }; | ||
125 | this->voice_types = types; | ||
126 | |||
147 | Ay_apu_volume( &this->apu, this->gain); | 127 | Ay_apu_volume( &this->apu, this->gain); |
148 | 128 | ||
149 | // Setup buffer | 129 | // Setup buffer |
150 | change_clock_rate( this, spectrum_clock ); | 130 | change_clock_rate( this, spectrum_clock ); |
131 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); | ||
151 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 132 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
152 | 133 | ||
153 | Sound_set_tempo( this, this->tempo ); | 134 | Sound_set_tempo( this, this->tempo ); |
154 | |||
155 | // Remute voices | ||
156 | Sound_mute_voices( this, this->mute_mask_ ); | 135 | Sound_mute_voices( this, this->mute_mask_ ); |
157 | 136 | ||
158 | this->track_count = this->file.header->max_track + 1; | 137 | this->track_count = this->file.header->max_track + 1; |
159 | this->m3u.size = 0; | ||
160 | return 0; | 138 | return 0; |
161 | } | 139 | } |
162 | 140 | ||
@@ -298,7 +276,7 @@ enable_cpc: | |||
298 | } | 276 | } |
299 | } | 277 | } |
300 | 278 | ||
301 | blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, long rate ) | 279 | blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, int rate ) |
302 | { | 280 | { |
303 | require( !this->sample_rate ); // sample rate can't be changed once set | 281 | require( !this->sample_rate ); // sample rate can't be changed once set |
304 | Buffer_init( &this->stereo_buf ); | 282 | Buffer_init( &this->stereo_buf ); |
@@ -308,6 +286,8 @@ blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, long rate ) | |||
308 | Buffer_bass_freq( &this->stereo_buf, 160 ); | 286 | Buffer_bass_freq( &this->stereo_buf, 160 ); |
309 | 287 | ||
310 | this->sample_rate = rate; | 288 | this->sample_rate = rate; |
289 | RETURN_ERR( track_init( &this->track_filter, this ) ); | ||
290 | this->tfilter.max_silence = 6 * stereo * this->sample_rate; | ||
311 | return 0; | 291 | return 0; |
312 | } | 292 | } |
313 | 293 | ||
@@ -335,7 +315,7 @@ void Sound_mute_voices( struct Ay_Emu *this, int mask ) | |||
335 | } | 315 | } |
336 | else | 316 | else |
337 | { | 317 | { |
338 | struct channel_t ch = Buffer_channel( &this->stereo_buf ); | 318 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); |
339 | assert( (ch.center && ch.left && ch.right) || | 319 | assert( (ch.center && ch.left && ch.right) || |
340 | (!ch.center && !ch.left && !ch.right) ); // all or nothing | 320 | (!ch.center && !ch.left && !ch.right) ); // all or nothing |
341 | set_voice( this, i, ch.center ); | 321 | set_voice( this, i, ch.center ); |
@@ -359,7 +339,6 @@ void Sound_set_tempo( struct Ay_Emu *this, int t ) | |||
359 | this->play_period = (blip_time_t) ((p * FP_ONE_TEMPO) / t); | 339 | this->play_period = (blip_time_t) ((p * FP_ONE_TEMPO) / t); |
360 | } | 340 | } |
361 | 341 | ||
362 | void fill_buf( struct Ay_Emu *this );; | ||
363 | blargg_err_t Ay_start_track( struct Ay_Emu *this, int track ) | 342 | blargg_err_t Ay_start_track( struct Ay_Emu *this, int track ) |
364 | { | 343 | { |
365 | clear_track_vars( this ); | 344 | clear_track_vars( this ); |
@@ -496,272 +475,109 @@ blargg_err_t Ay_start_track( struct Ay_Emu *this, int track ) | |||
496 | Ay_apu_write_addr( &this->apu, 7 ); | 475 | Ay_apu_write_addr( &this->apu, 7 ); |
497 | Ay_apu_write_data( &this->apu, 0, 0x38 ); | 476 | Ay_apu_write_data( &this->apu, 0, 0x38 ); |
498 | 477 | ||
499 | this->emu_track_ended_ = false; | 478 | // convert filter times to samples |
500 | this->track_ended = false; | 479 | struct setup_t s = this->tfilter; |
480 | s.max_initial *= this->sample_rate * stereo; | ||
481 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD | ||
482 | s.lookahead = 1; | ||
483 | #endif | ||
484 | track_setup( &this->track_filter, &s ); | ||
501 | 485 | ||
502 | if ( !this->ignore_silence ) | 486 | return track_start( &this->track_filter ); |
503 | { | ||
504 | // play until non-silence or end of track | ||
505 | long end; | ||
506 | for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; ) | ||
507 | { | ||
508 | fill_buf( this ); | ||
509 | if ( this->buf_remain | (int) this->emu_track_ended_ ) | ||
510 | break; | ||
511 | } | ||
512 | |||
513 | this->emu_time = this->buf_remain; | ||
514 | this->out_time = 0; | ||
515 | this->silence_time = 0; | ||
516 | this->silence_count = 0; | ||
517 | } | ||
518 | /* return track_ended() ? warning() : 0; */ | ||
519 | return 0; | ||
520 | } | 487 | } |
521 | 488 | ||
522 | // Tell/Seek | 489 | // Tell/Seek |
523 | 490 | ||
524 | static blargg_long msec_to_samples( blargg_long msec, long sample_rate ) | 491 | static int msec_to_samples( int msec, int sample_rate ) |
525 | { | 492 | { |
526 | blargg_long sec = msec / 1000; | 493 | int sec = msec / 1000; |
527 | msec -= sec * 1000; | 494 | msec -= sec * 1000; |
528 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; | 495 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; |
529 | } | 496 | } |
530 | 497 | ||
531 | long Track_tell( struct Ay_Emu *this ) | 498 | int Track_tell( struct Ay_Emu *this ) |
532 | { | 499 | { |
533 | blargg_long rate = this->sample_rate * stereo; | 500 | int rate = this->sample_rate * stereo; |
534 | blargg_long sec = this->out_time / rate; | 501 | int sec = track_sample_count( &this->track_filter ) / rate; |
535 | return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate; | 502 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; |
536 | } | 503 | } |
537 | 504 | ||
538 | blargg_err_t Track_seek( struct Ay_Emu *this, long msec ) | 505 | blargg_err_t Track_seek( struct Ay_Emu *this, int msec ) |
539 | { | 506 | { |
540 | blargg_long time = msec_to_samples( msec, this->sample_rate ); | 507 | int time = msec_to_samples( msec, this->sample_rate ); |
541 | if ( time < this->out_time ) | 508 | if ( time < track_sample_count( &this->track_filter ) ) |
542 | RETURN_ERR( Ay_start_track( this, this->current_track ) ); | 509 | RETURN_ERR( Ay_start_track( this, this->current_track ) ); |
543 | return Track_skip( this, time - this->out_time ); | 510 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); |
544 | } | 511 | } |
545 | 512 | ||
546 | blargg_err_t play_( struct Ay_Emu *this, long count, sample_t* out ); | 513 | blargg_err_t skip_( void *emu, int count ) |
547 | static blargg_err_t skip_( struct Ay_Emu *this, long count ) | ||
548 | { | 514 | { |
515 | struct Ay_Emu* this = (struct Ay_Emu*) emu; | ||
516 | |||
549 | // for long skip, mute sound | 517 | // for long skip, mute sound |
550 | const long threshold = 30000; | 518 | const int threshold = 32768; |
551 | if ( count > threshold ) | 519 | if ( count > threshold ) |
552 | { | 520 | { |
553 | int saved_mute = this->mute_mask_; | 521 | int saved_mute = this->mute_mask_; |
554 | Sound_mute_voices( this, ~0 ); | 522 | Sound_mute_voices( this, ~0 ); |
555 | |||
556 | while ( count > threshold / 2 && !this->emu_track_ended_ ) | ||
557 | { | ||
558 | RETURN_ERR( play_( this, buf_size, this->buf ) ); | ||
559 | count -= buf_size; | ||
560 | } | ||
561 | |||
562 | Sound_mute_voices( this, saved_mute ); | ||
563 | } | ||
564 | |||
565 | while ( count && !this->emu_track_ended_ ) | ||
566 | { | ||
567 | long n = buf_size; | ||
568 | if ( n > count ) | ||
569 | n = count; | ||
570 | count -= n; | ||
571 | RETURN_ERR( play_( this, n, this->buf ) ); | ||
572 | } | ||
573 | return 0; | ||
574 | } | ||
575 | 523 | ||
576 | blargg_err_t Track_skip( struct Ay_Emu *this, long count ) | 524 | int n = count - threshold/2; |
577 | { | 525 | n &= ~(2048-1); // round to multiple of 2048 |
578 | require( this->current_track >= 0 ); // start_track() must have been called already | ||
579 | this->out_time += count; | ||
580 | |||
581 | // remove from silence and buf first | ||
582 | { | ||
583 | long n = min( count, this->silence_count ); | ||
584 | this->silence_count -= n; | ||
585 | count -= n; | 526 | count -= n; |
586 | 527 | RETURN_ERR( skippy_( &this->track_filter, n ) ); | |
587 | n = min( count, this->buf_remain ); | ||
588 | this->buf_remain -= n; | ||
589 | count -= n; | ||
590 | } | ||
591 | |||
592 | if ( count && !this->emu_track_ended_ ) | ||
593 | { | ||
594 | this->emu_time += count; | ||
595 | |||
596 | // End track if error | ||
597 | if ( skip_( this, count ) ) | ||
598 | this->emu_track_ended_ = true; | ||
599 | } | ||
600 | |||
601 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
602 | this->track_ended |= this->emu_track_ended_; | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | 528 | ||
607 | // Fading | 529 | Sound_mute_voices( this, saved_mute ); |
530 | } | ||
608 | 531 | ||
609 | void Track_set_fade( struct Ay_Emu *this, long start_msec, long length_msec ) | 532 | return skippy_( &this->track_filter, count ); |
610 | { | ||
611 | this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo); | ||
612 | this->fade_start = msec_to_samples( start_msec, this->sample_rate ); | ||
613 | } | 533 | } |
614 | 534 | ||
615 | // unit / pow( 2.0, (double) x / step ) | 535 | blargg_err_t Track_skip( struct Ay_Emu *this, int count ) |
616 | static int int_log( blargg_long x, int step, int unit ) | ||
617 | { | 536 | { |
618 | int shift = x / step; | 537 | require( this->current_track >= 0 ); // start_track() must have been called already |
619 | int fraction = (x - shift * step) * unit / step; | 538 | return track_skip( &this->track_filter, count ); |
620 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
621 | } | 539 | } |
622 | 540 | ||
623 | static void handle_fade( struct Ay_Emu *this, long out_count, sample_t* out ) | 541 | int Track_get_length( struct Ay_Emu* this, int n ) |
624 | { | 542 | { |
625 | int i; | 543 | int length = 0; |
626 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
627 | { | ||
628 | int const shift = 14; | ||
629 | int const unit = 1 << shift; | ||
630 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
631 | this->fade_step, unit ); | ||
632 | if ( gain < (unit >> fade_shift) ) | ||
633 | this->track_ended = this->emu_track_ended_ = true; | ||
634 | |||
635 | sample_t* io = &out [i]; | ||
636 | int count; | ||
637 | for ( count = min( fade_block_size, out_count - i ); count; --count ) | ||
638 | { | ||
639 | *io = (sample_t) ((*io * gain) >> shift); | ||
640 | ++io; | ||
641 | } | ||
642 | } | ||
643 | } | ||
644 | 544 | ||
645 | // Silence detection | 545 | byte const* track_info = get_data( &this->file, this->file.tracks + n * 4 + 2, 6 ); |
546 | if ( track_info ) | ||
547 | length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec | ||
646 | 548 | ||
647 | static void emu_play( struct Ay_Emu *this, long count, sample_t* out ) | 549 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { |
648 | { | 550 | struct entry_t* entry = &this->m3u.entries [n]; |
649 | check( current_track_ >= 0 ); | 551 | length = entry->length; |
650 | this->emu_time += count; | 552 | } |
651 | if ( this->current_track >= 0 && !this->emu_track_ended_ ) { | 553 | |
652 | if ( play_( this, count, out ) ) | 554 | if ( length <= 0 ) |
653 | this->emu_track_ended_ = true; | 555 | length = 120 * 1000; /* 2 minutes */ |
654 | } | ||
655 | else | ||
656 | memset( out, 0, count * sizeof *out ); | ||
657 | } | ||
658 | 556 | ||
659 | // number of consecutive silent samples at end | 557 | return length; |
660 | static long count_silence( sample_t* begin, long size ) | ||
661 | { | ||
662 | sample_t first = *begin; | ||
663 | *begin = silence_threshold; // sentinel | ||
664 | sample_t* p = begin + size; | ||
665 | while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } | ||
666 | *begin = first; | ||
667 | return size - (p - begin); | ||
668 | } | 558 | } |
669 | 559 | ||
670 | // fill internal buffer and check it for silence | 560 | void Track_set_fade( struct Ay_Emu *this, int start_msec, int length_msec ) |
671 | void fill_buf( struct Ay_Emu *this ) | ||
672 | { | 561 | { |
673 | assert( !this->buf_remain ); | 562 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), |
674 | if ( !this->emu_track_ended_ ) | 563 | length_msec * this->sample_rate / (1000 / stereo) ); |
675 | { | ||
676 | emu_play( this, buf_size, this->buf ); | ||
677 | long silence = count_silence( this->buf, buf_size ); | ||
678 | if ( silence < buf_size ) | ||
679 | { | ||
680 | this->silence_time = this->emu_time - silence; | ||
681 | this->buf_remain = buf_size; | ||
682 | return; | ||
683 | } | ||
684 | } | ||
685 | this->silence_count += buf_size; | ||
686 | } | 564 | } |
687 | 565 | ||
688 | blargg_err_t Ay_play( struct Ay_Emu *this, long out_count, sample_t* out ) | 566 | blargg_err_t Ay_play( struct Ay_Emu *this, int out_count, sample_t* out ) |
689 | { | 567 | { |
690 | if ( this->track_ended ) | 568 | require( this->current_track >= 0 ); |
691 | { | 569 | require( out_count % stereo == 0 ); |
692 | memset( out, 0, out_count * sizeof *out ); | 570 | return track_play( &this->track_filter, out_count, out ); |
693 | } | ||
694 | else | ||
695 | { | ||
696 | require( this->current_track >= 0 ); | ||
697 | require( out_count % stereo == 0 ); | ||
698 | |||
699 | assert( this->emu_time >= this->out_time ); | ||
700 | |||
701 | // prints nifty graph of how far ahead we are when searching for silence | ||
702 | //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" ); | ||
703 | |||
704 | long pos = 0; | ||
705 | if ( this->silence_count ) | ||
706 | { | ||
707 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
708 | long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time; | ||
709 | while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) | ||
710 | fill_buf( this ); | ||
711 | |||
712 | // fill with silence | ||
713 | pos = min( this->silence_count, out_count ); | ||
714 | memset( out, 0, pos * sizeof *out ); | ||
715 | this->silence_count -= pos; | ||
716 | |||
717 | if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate ) | ||
718 | { | ||
719 | this->track_ended = this->emu_track_ended_ = true; | ||
720 | this->silence_count = 0; | ||
721 | this->buf_remain = 0; | ||
722 | } | ||
723 | } | ||
724 | |||
725 | if ( this->buf_remain ) | ||
726 | { | ||
727 | // empty silence buf | ||
728 | long n = min( this->buf_remain, out_count - pos ); | ||
729 | memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out ); | ||
730 | this->buf_remain -= n; | ||
731 | pos += n; | ||
732 | } | ||
733 | |||
734 | // generate remaining samples normally | ||
735 | long remain = out_count - pos; | ||
736 | if ( remain ) | ||
737 | { | ||
738 | emu_play( this, remain, out + pos ); | ||
739 | this->track_ended |= this->emu_track_ended_; | ||
740 | |||
741 | if ( !this->ignore_silence || this->out_time > this->fade_start ) | ||
742 | { | ||
743 | // check end for a new run of silence | ||
744 | long silence = count_silence( out + pos, remain ); | ||
745 | if ( silence < remain ) | ||
746 | this->silence_time = this->emu_time - silence; | ||
747 | |||
748 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
749 | fill_buf( this ); // cause silence detection on next play() | ||
750 | } | ||
751 | } | ||
752 | |||
753 | if ( this->out_time > this->fade_start ) | ||
754 | handle_fade( this, out_count, out ); | ||
755 | } | ||
756 | this->out_time += out_count; | ||
757 | return 0; | ||
758 | } | 571 | } |
759 | 572 | ||
760 | blargg_err_t play_( struct Ay_Emu *this, long count, sample_t* out ) | 573 | blargg_err_t play_( void *emu, int count, sample_t* out ) |
761 | { | 574 | { |
762 | long remain = count; | 575 | struct Ay_Emu* this = (struct Ay_Emu*) emu; |
576 | |||
577 | int remain = count; | ||
763 | while ( remain ) | 578 | while ( remain ) |
764 | { | 579 | { |
580 | Buffer_disable_immediate_removal( &this->stereo_buf ); | ||
765 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); | 581 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); |
766 | if ( remain ) | 582 | if ( remain ) |
767 | { | 583 | { |
@@ -773,7 +589,7 @@ blargg_err_t play_( struct Ay_Emu *this, long count, sample_t* out ) | |||
773 | Sound_mute_voices( this, this->mute_mask_ ); | 589 | Sound_mute_voices( this, this->mute_mask_ ); |
774 | } | 590 | } |
775 | int msec = Buffer_length( &this->stereo_buf ); | 591 | int msec = Buffer_length( &this->stereo_buf ); |
776 | blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000 - 100; | 592 | blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; |
777 | RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); | 593 | RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); |
778 | assert( clocks_emulated ); | 594 | assert( clocks_emulated ); |
779 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); | 595 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); |
diff --git a/apps/codecs/libgme/ay_emu.h b/apps/codecs/libgme/ay_emu.h index b320e69653..7334167876 100644 --- a/apps/codecs/libgme/ay_emu.h +++ b/apps/codecs/libgme/ay_emu.h | |||
@@ -10,14 +10,12 @@ | |||
10 | #include "z80_cpu.h" | 10 | #include "z80_cpu.h" |
11 | #include "ay_apu.h" | 11 | #include "ay_apu.h" |
12 | #include "m3u_playlist.h" | 12 | #include "m3u_playlist.h" |
13 | 13 | #include "track_filter.h" | |
14 | typedef short sample_t; | ||
15 | 14 | ||
16 | // 64K memory to load code and data into before starting track. Caller | 15 | // 64K memory to load code and data into before starting track. Caller |
17 | // must parse the AY file. | 16 | // must parse the AY file. |
18 | enum { mem_size = 0x10000 }; | 17 | enum { mem_size = 0x10000 }; |
19 | enum { ram_addr = 0x4000 }; // where official RAM starts | 18 | enum { ram_addr = 0x4000 }; // where official RAM starts |
20 | enum { buf_size = 2048 }; | ||
21 | 19 | ||
22 | // AY file header | 20 | // AY file header |
23 | enum { header_size = 0x14 }; | 21 | enum { header_size = 0x14 }; |
@@ -62,43 +60,30 @@ struct Ay_Emu { | |||
62 | bool cpc_mode; | 60 | bool cpc_mode; |
63 | 61 | ||
64 | // general | 62 | // general |
65 | int max_initial_silence; | ||
66 | int voice_count; | 63 | int voice_count; |
64 | int const* voice_types; | ||
67 | int mute_mask_; | 65 | int mute_mask_; |
68 | int tempo; | 66 | int tempo; |
69 | int gain; | 67 | int gain; |
70 | 68 | ||
71 | long sample_rate; | 69 | int sample_rate; |
72 | 70 | ||
73 | // track-specific | 71 | // track-specific |
74 | int current_track; | 72 | int current_track; |
75 | int track_count; | 73 | int track_count; |
76 | blargg_long out_time; // number of samples played since start of track | 74 | |
77 | blargg_long emu_time; // number of samples emulator has generated since start of track | 75 | int clock_rate_; |
78 | volatile bool track_ended; | ||
79 | bool emu_track_ended_; // emulator has reached end of track | ||
80 | |||
81 | // fading | ||
82 | blargg_long fade_start; | ||
83 | int fade_step; | ||
84 | |||
85 | // silence detection | ||
86 | bool ignore_silence; | ||
87 | int silence_lookahead; // speed to run emulator when looking ahead for silence | ||
88 | long silence_time; // number of samples where most recent silence began | ||
89 | long silence_count; // number of samples of silence to play before using buf | ||
90 | long buf_remain; // number of samples left in silence buffer | ||
91 | |||
92 | long clock_rate_; | ||
93 | unsigned buf_changed_count; | 76 | unsigned buf_changed_count; |
94 | 77 | ||
95 | // M3u Playlist | 78 | // M3u Playlist |
96 | struct M3u_Playlist m3u; | 79 | struct M3u_Playlist m3u; |
97 | 80 | ||
98 | // large items | 81 | // large items |
82 | struct setup_t tfilter; | ||
83 | struct Track_Filter track_filter; | ||
84 | |||
99 | struct Ay_Apu apu; | 85 | struct Ay_Apu apu; |
100 | sample_t buf [buf_size]; | 86 | struct Multi_Buffer stereo_buf; // NULL if using custom buffer |
101 | struct Stereo_Buffer stereo_buf; // NULL if using custom buffer | ||
102 | struct Z80_Cpu cpu; | 87 | struct Z80_Cpu cpu; |
103 | struct mem_t mem; | 88 | struct mem_t mem; |
104 | }; | 89 | }; |
@@ -106,46 +91,58 @@ struct Ay_Emu { | |||
106 | // Basic functionality (see Gme_File.h for file loading/track info functions) | 91 | // Basic functionality (see Gme_File.h for file loading/track info functions) |
107 | void Ay_init( struct Ay_Emu* this ); | 92 | void Ay_init( struct Ay_Emu* this ); |
108 | 93 | ||
109 | blargg_err_t Ay_load_mem( struct Ay_Emu* this, byte const in [], int size ); | 94 | blargg_err_t Ay_load_mem( struct Ay_Emu* this, byte const in [], long size ); |
110 | 95 | ||
111 | // Set output sample rate. Must be called only once before loading file. | 96 | // Set output sample rate. Must be called only once before loading file. |
112 | blargg_err_t Ay_set_sample_rate( struct Ay_Emu* this, long sample_rate ); | 97 | blargg_err_t Ay_set_sample_rate( struct Ay_Emu* this, int sample_rate ); |
113 | 98 | ||
114 | // Start a track, where 0 is the first track. Also clears warning string. | 99 | // Start a track, where 0 is the first track. Also clears warning string. |
115 | blargg_err_t Ay_start_track( struct Ay_Emu* this, int track ); | 100 | blargg_err_t Ay_start_track( struct Ay_Emu* this, int track ); |
116 | 101 | ||
117 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation | 102 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation |
118 | // errors set warning string, and major errors also end track. | 103 | // errors set warning string, and major errors also end track. |
119 | blargg_err_t Ay_play( struct Ay_Emu* this, long count, sample_t* buf ); | 104 | blargg_err_t Ay_play( struct Ay_Emu* this, int count, sample_t* buf ); |
120 | 105 | ||
121 | 106 | ||
122 | // Track status/control | 107 | // Track status/control |
123 | 108 | ||
124 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track | 109 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track |
125 | long Track_tell( struct Ay_Emu* this ); | 110 | int Track_tell( struct Ay_Emu* this ); |
126 | 111 | ||
127 | // Seek to new time in track. Seeking backwards or far forward can take a while. | 112 | // Seek to new time in track. Seeking backwards or far forward can take a while. |
128 | blargg_err_t Track_seek( struct Ay_Emu* this, long msec ); | 113 | blargg_err_t Track_seek( struct Ay_Emu* this, int msec ); |
129 | 114 | ||
130 | // Skip n samples | 115 | // Skip n samples |
131 | blargg_err_t Track_skip( struct Ay_Emu* this, long n ); | 116 | blargg_err_t Track_skip( struct Ay_Emu* this, int n ); |
132 | 117 | ||
133 | // Set start time and length of track fade out. Once fade ends track_ended() returns | 118 | // Set start time and length of track fade out. Once fade ends track_ended() returns |
134 | // true. Fade time can be changed while track is playing. | 119 | // true. Fade time can be changed while track is playing. |
135 | void Track_set_fade( struct Ay_Emu* this, long start_msec, long length_msec ); | 120 | void Track_set_fade( struct Ay_Emu* this, int start_msec, int length_msec ); |
121 | |||
122 | // True if a track has reached its end | ||
123 | static inline bool Track_ended( struct Ay_Emu* this ) | ||
124 | { | ||
125 | return track_ended( &this->track_filter ); | ||
126 | } | ||
127 | |||
128 | // Disables automatic end-of-track detection and skipping of silence at beginning | ||
129 | static inline void Track_ignore_silence( struct Ay_Emu* this, bool disable ) | ||
130 | { | ||
131 | this->track_filter.silence_ignored_ = disable; | ||
132 | } | ||
136 | 133 | ||
137 | // Get track length in milliseconds | 134 | // Get track length in milliseconds |
138 | long Track_get_length( struct Ay_Emu* this, int n ); | 135 | int Track_get_length( struct Ay_Emu* this, int n ); |
139 | 136 | ||
140 | // Sound customization | 137 | // Sound customization |
141 | 138 | ||
142 | // Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. | 139 | // Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. |
143 | // Track length as returned by track_info() assumes a tempo of 1.0. | 140 | // Track length as returned by track_info() assumes a tempo of 1.0. |
144 | void Sound_set_tempo( struct Ay_Emu* this, int t ); | 141 | void Sound_set_tempo( struct Ay_Emu* this, int t ); |
145 | 142 | ||
146 | // Mute/unmute voice i, where voice 0 is first voice | 143 | // Mute/unmute voice i, where voice 0 is first voice |
147 | void Sound_mute_voice( struct Ay_Emu* this, int index, bool mute ); | 144 | void Sound_mute_voice( struct Ay_Emu* this, int index, bool mute ); |
148 | 145 | ||
149 | // Set muting state of all voices at once using a bit mask, where -1 mutes them all, | 146 | // Set muting state of all voices at once using a bit mask, where -1 mutes them all, |
150 | // 0 unmutes them all, 0x01 mutes just the first voice, etc. | 147 | // 0 unmutes them all, 0x01 mutes just the first voice, etc. |
151 | void Sound_mute_voices( struct Ay_Emu* this, int mask ); | 148 | void Sound_mute_voices( struct Ay_Emu* this, int mask ); |
@@ -168,5 +165,5 @@ static inline void disable_beeper( struct Ay_Emu *this ) | |||
168 | this->beeper_mask = 0; | 165 | this->beeper_mask = 0; |
169 | this->last_beeper = 0; | 166 | this->last_beeper = 0; |
170 | } | 167 | } |
171 | 168 | ||
172 | #endif | 169 | #endif |
diff --git a/apps/codecs/libgme/blargg_common.h b/apps/codecs/libgme/blargg_common.h index 65ae76ae99..a023d6b842 100644 --- a/apps/codecs/libgme/blargg_common.h +++ b/apps/codecs/libgme/blargg_common.h | |||
@@ -7,12 +7,12 @@ | |||
7 | #include <stddef.h> | 7 | #include <stddef.h> |
8 | #include <stdlib.h> | 8 | #include <stdlib.h> |
9 | #include <string.h> | 9 | #include <string.h> |
10 | #include <assert.h> | ||
11 | #include <limits.h> | 10 | #include <limits.h> |
12 | 11 | ||
13 | #undef BLARGG_COMMON_H | 12 | #undef BLARGG_COMMON_H |
14 | // allow blargg_config.h to #include blargg_common.h | 13 | // allow blargg_config.h to #include blargg_common.h |
15 | #include "blargg_config.h" | 14 | #include "blargg_config.h" |
15 | #include "blargg_source.h" | ||
16 | #ifndef BLARGG_COMMON_H | 16 | #ifndef BLARGG_COMMON_H |
17 | #define BLARGG_COMMON_H | 17 | #define BLARGG_COMMON_H |
18 | 18 | ||
@@ -98,19 +98,13 @@ | |||
98 | static bool false = 0; | 98 | static bool false = 0; |
99 | #endif | 99 | #endif |
100 | 100 | ||
101 | // blargg_long/blargg_ulong = at least 32 bits, int if it's big enough | 101 | /* My code depends on int being at least 32 bits. Almost everything these days |
102 | #include <limits.h> | 102 | uses at least 32-bit ints, so it's hard to even find a system with 16-bit ints |
103 | 103 | to test with. The issue can't be gotten around by using a suitable blargg_int | |
104 | #if INT_MAX >= 0x7FFFFFFF | 104 | everywhere either, because int is often converted to implicitly when doing |
105 | typedef int blargg_long; | 105 | arithmetic on smaller types. */ |
106 | #else | 106 | #if UINT_MAX < 0xFFFFFFFF |
107 | typedef long blargg_long; | 107 | #error "int must be at least 32 bits" |
108 | #endif | ||
109 | |||
110 | #if UINT_MAX >= 0xFFFFFFFF | ||
111 | typedef unsigned blargg_ulong; | ||
112 | #else | ||
113 | typedef unsigned long blargg_ulong; | ||
114 | #endif | 108 | #endif |
115 | 109 | ||
116 | // int8_t etc. | 110 | // int8_t etc. |
diff --git a/apps/codecs/libgme/blargg_endian.h b/apps/codecs/libgme/blargg_endian.h index ae55d7fd3b..dce5cb2048 100644 --- a/apps/codecs/libgme/blargg_endian.h +++ b/apps/codecs/libgme/blargg_endian.h | |||
@@ -64,45 +64,60 @@ static inline void blargg_verify_byte_order( void ) | |||
64 | #endif | 64 | #endif |
65 | } | 65 | } |
66 | 66 | ||
67 | static inline unsigned get_le16( void const* p ) { | 67 | static inline unsigned get_le16( void const* p ) |
68 | return ((unsigned char const*) p) [1] * 0x100u + | 68 | { |
69 | ((unsigned char const*) p) [0]; | 69 | return (unsigned) ((unsigned char const*) p) [1] << 8 | |
70 | (unsigned) ((unsigned char const*) p) [0]; | ||
70 | } | 71 | } |
71 | static inline unsigned get_be16( void const* p ) { | 72 | |
72 | return ((unsigned char const*) p) [0] * 0x100u + | 73 | static inline unsigned get_be16( void const* p ) |
73 | ((unsigned char const*) p) [1]; | 74 | { |
75 | return (unsigned) ((unsigned char const*) p) [0] << 8 | | ||
76 | (unsigned) ((unsigned char const*) p) [1]; | ||
74 | } | 77 | } |
75 | static inline blargg_ulong get_le32( void const* p ) { | 78 | |
76 | return ((unsigned char const*) p) [3] * 0x01000000u + | 79 | static inline unsigned get_le32( void const* p ) |
77 | ((unsigned char const*) p) [2] * 0x00010000u + | 80 | { |
78 | ((unsigned char const*) p) [1] * 0x00000100u + | 81 | return (unsigned) ((unsigned char const*) p) [3] << 24 | |
79 | ((unsigned char const*) p) [0]; | 82 | (unsigned) ((unsigned char const*) p) [2] << 16 | |
83 | (unsigned) ((unsigned char const*) p) [1] << 8 | | ||
84 | (unsigned) ((unsigned char const*) p) [0]; | ||
80 | } | 85 | } |
81 | static inline blargg_ulong get_be32( void const* p ) { | 86 | |
82 | return ((unsigned char const*) p) [0] * 0x01000000u + | 87 | static inline unsigned get_be32( void const* p ) |
83 | ((unsigned char const*) p) [1] * 0x00010000u + | 88 | { |
84 | ((unsigned char const*) p) [2] * 0x00000100u + | 89 | return (unsigned) ((unsigned char const*) p) [0] << 24 | |
85 | ((unsigned char const*) p) [3]; | 90 | (unsigned) ((unsigned char const*) p) [1] << 16 | |
91 | (unsigned) ((unsigned char const*) p) [2] << 8 | | ||
92 | (unsigned) ((unsigned char const*) p) [3]; | ||
86 | } | 93 | } |
87 | static inline void set_le16( void* p, unsigned n ) { | 94 | |
95 | static inline void set_le16( void* p, unsigned n ) | ||
96 | { | ||
88 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); | 97 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); |
89 | ((unsigned char*) p) [0] = (unsigned char) n; | 98 | ((unsigned char*) p) [0] = (unsigned char) n; |
90 | } | 99 | } |
91 | static inline void set_be16( void* p, unsigned n ) { | 100 | |
101 | static inline void set_be16( void* p, unsigned n ) | ||
102 | { | ||
92 | ((unsigned char*) p) [0] = (unsigned char) (n >> 8); | 103 | ((unsigned char*) p) [0] = (unsigned char) (n >> 8); |
93 | ((unsigned char*) p) [1] = (unsigned char) n; | 104 | ((unsigned char*) p) [1] = (unsigned char) n; |
94 | } | 105 | } |
95 | static inline void set_le32( void* p, blargg_ulong n ) { | 106 | |
96 | ((unsigned char*) p) [3] = (unsigned char) (n >> 24); | 107 | static inline void set_le32( void* p, unsigned n ) |
97 | ((unsigned char*) p) [2] = (unsigned char) (n >> 16); | 108 | { |
98 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); | ||
99 | ((unsigned char*) p) [0] = (unsigned char) n; | 109 | ((unsigned char*) p) [0] = (unsigned char) n; |
110 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); | ||
111 | ((unsigned char*) p) [2] = (unsigned char) (n >> 16); | ||
112 | ((unsigned char*) p) [3] = (unsigned char) (n >> 24); | ||
100 | } | 113 | } |
101 | static inline void set_be32( void* p, blargg_ulong n ) { | 114 | |
102 | ((unsigned char*) p) [0] = (unsigned char) (n >> 24); | 115 | static inline void set_be32( void* p, unsigned n ) |
103 | ((unsigned char*) p) [1] = (unsigned char) (n >> 16); | 116 | { |
104 | ((unsigned char*) p) [2] = (unsigned char) (n >> 8); | ||
105 | ((unsigned char*) p) [3] = (unsigned char) n; | 117 | ((unsigned char*) p) [3] = (unsigned char) n; |
118 | ((unsigned char*) p) [2] = (unsigned char) (n >> 8); | ||
119 | ((unsigned char*) p) [1] = (unsigned char) (n >> 16); | ||
120 | ((unsigned char*) p) [0] = (unsigned char) (n >> 24); | ||
106 | } | 121 | } |
107 | 122 | ||
108 | #if defined(BLARGG_NONPORTABLE) | 123 | #if defined(BLARGG_NONPORTABLE) |
@@ -132,15 +147,21 @@ static inline void set_be32( void* p, blargg_ulong n ) { | |||
132 | 147 | ||
133 | #ifndef GET_LE16 | 148 | #ifndef GET_LE16 |
134 | #define GET_LE16( addr ) get_le16( addr ) | 149 | #define GET_LE16( addr ) get_le16( addr ) |
135 | #define GET_LE32( addr ) get_le32( addr ) | ||
136 | #define SET_LE16( addr, data ) set_le16( addr, data ) | 150 | #define SET_LE16( addr, data ) set_le16( addr, data ) |
151 | #endif | ||
152 | |||
153 | #ifndef GET_LE32 | ||
154 | #define GET_LE32( addr ) get_le32( addr ) | ||
137 | #define SET_LE32( addr, data ) set_le32( addr, data ) | 155 | #define SET_LE32( addr, data ) set_le32( addr, data ) |
138 | #endif | 156 | #endif |
139 | 157 | ||
140 | #ifndef GET_BE16 | 158 | #ifndef GET_BE16 |
141 | #define GET_BE16( addr ) get_be16( addr ) | 159 | #define GET_BE16( addr ) get_be16( addr ) |
142 | #define GET_BE32( addr ) get_be32( addr ) | ||
143 | #define SET_BE16( addr, data ) set_be16( addr, data ) | 160 | #define SET_BE16( addr, data ) set_be16( addr, data ) |
161 | #endif | ||
162 | |||
163 | #ifndef GET_BE32 | ||
164 | #define GET_BE32( addr ) get_be32( addr ) | ||
144 | #define SET_BE32( addr, data ) set_be32( addr, data ) | 165 | #define SET_BE32( addr, data ) set_be32( addr, data ) |
145 | #endif | 166 | #endif |
146 | 167 | ||
diff --git a/apps/codecs/libgme/blargg_source.h b/apps/codecs/libgme/blargg_source.h index 4bea02a48b..ab8e1b072b 100644 --- a/apps/codecs/libgme/blargg_source.h +++ b/apps/codecs/libgme/blargg_source.h | |||
@@ -2,16 +2,13 @@ | |||
2 | #ifndef BLARGG_SOURCE_H | 2 | #ifndef BLARGG_SOURCE_H |
3 | #define BLARGG_SOURCE_H | 3 | #define BLARGG_SOURCE_H |
4 | 4 | ||
5 | // If debugging is enabled, abort program if expr is false. Meant for checking | ||
6 | // internal state and consistency. A failed assertion indicates a bug in the module. | ||
7 | // void assert( bool expr ); | ||
8 | #include <assert.h> | ||
9 | |||
10 | // If debugging is enabled and expr is false, abort program. Meant for checking | 5 | // If debugging is enabled and expr is false, abort program. Meant for checking |
11 | // caller-supplied parameters and operations that are outside the control of the | 6 | // caller-supplied parameters and operations that are outside the control of the |
12 | // module. A failed requirement indicates a bug outside the module. | 7 | // module. A failed requirement indicates a bug outside the module. |
13 | // void require( bool expr ); | 8 | // void require( bool expr ); |
14 | #if defined(ROCKBOX) | 9 | #if defined(ROCKBOX) |
10 | #undef assert | ||
11 | #define assert( expr ) | ||
15 | #undef require | 12 | #undef require |
16 | #define require( expr ) | 13 | #define require( expr ) |
17 | #else | 14 | #else |
@@ -36,28 +33,36 @@ static inline void blargg_dprintf_( const char* fmt, ... ) { } | |||
36 | #undef check | 33 | #undef check |
37 | #define check( expr ) ((void) 0) | 34 | #define check( expr ) ((void) 0) |
38 | 35 | ||
39 | // If expr yields error string, return it from current function, otherwise continue. | 36 | /* If expr yields non-NULL error string, returns it from current function, |
40 | #undef RETURN_ERR | 37 | otherwise continues normally. */ |
41 | #define RETURN_ERR( expr ) do { \ | 38 | #undef RETURN_ERR |
42 | blargg_err_t blargg_return_err_ = (expr); \ | 39 | #define RETURN_ERR( expr ) \ |
43 | if ( blargg_return_err_ ) return blargg_return_err_; \ | 40 | do {\ |
41 | blargg_err_t blargg_return_err_ = (expr);\ | ||
42 | if ( blargg_return_err_ )\ | ||
43 | return blargg_return_err_;\ | ||
44 | } while ( 0 ) | 44 | } while ( 0 ) |
45 | 45 | ||
46 | // If ptr is 0, return out of memory error string. | 46 | /* If ptr is NULL, returns out-of-memory error, otherwise continues normally. */ |
47 | #undef CHECK_ALLOC | 47 | #undef CHECK_ALLOC |
48 | #define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) | 48 | #define CHECK_ALLOC( ptr ) \ |
49 | do {\ | ||
50 | if ( !(ptr) )\ | ||
51 | return "Out of memory";\ | ||
52 | } while ( 0 ) | ||
49 | 53 | ||
50 | #ifndef max | 54 | #ifndef max |
51 | #define max(a,b) (((a) > (b)) ? (a) : (b)) | 55 | #define max(a,b) (((a) > (b)) ? (a) : (b)) |
52 | #endif | 56 | #endif |
57 | |||
53 | #ifndef min | 58 | #ifndef min |
54 | #define min(a,b) (((a) < (b)) ? (a) : (b)) | 59 | #define min(a,b) (((a) < (b)) ? (a) : (b)) |
55 | #endif | 60 | #endif |
56 | 61 | ||
57 | // TODO: good idea? bad idea? | 62 | // typedef unsigned char byte; |
58 | #undef byte | 63 | typedef unsigned char blargg_byte; |
59 | #define byte byte_ | 64 | #undef byte |
60 | typedef unsigned char byte; | 65 | #define byte blargg_byte |
61 | 66 | ||
62 | // deprecated | 67 | // deprecated |
63 | #define BLARGG_CHECK_ALLOC CHECK_ALLOC | 68 | #define BLARGG_CHECK_ALLOC CHECK_ALLOC |
diff --git a/apps/codecs/libgme/blip_buffer.c b/apps/codecs/libgme/blip_buffer.c index d8ecbb8bb2..ba0a6558d2 100644 --- a/apps/codecs/libgme/blip_buffer.c +++ b/apps/codecs/libgme/blip_buffer.c | |||
@@ -2,7 +2,6 @@ | |||
2 | 2 | ||
3 | #include "blip_buffer.h" | 3 | #include "blip_buffer.h" |
4 | 4 | ||
5 | #include <assert.h> | ||
6 | #include <limits.h> | 5 | #include <limits.h> |
7 | #include <string.h> | 6 | #include <string.h> |
8 | #include <stdlib.h> | 7 | #include <stdlib.h> |
@@ -19,96 +18,78 @@ details. You should have received a copy of the GNU Lesser General Public | |||
19 | License along with this module; if not, write to the Free Software Foundation, | 18 | License along with this module; if not, write to the Free Software Foundation, |
20 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | 19 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
21 | 20 | ||
22 | #ifdef BLARGG_ENABLE_OPTIMIZER | 21 | #include "blargg_source.h" |
23 | #include BLARGG_ENABLE_OPTIMIZER | ||
24 | #endif | ||
25 | |||
26 | int const silent_buf_size = 1; // size used for Silent_Blip_Buffer | ||
27 | 22 | ||
28 | void Blip_init( struct Blip_Buffer* this ) | 23 | void Blip_init( struct Blip_Buffer* this ) |
29 | { | 24 | { |
30 | this->factor_ = (blip_ulong)LONG_MAX; | 25 | this->factor_ = UINT_MAX/2 + 1;; |
31 | this->offset_ = 0; | 26 | this->buffer_center_ = NULL; |
32 | this->buffer_size_ = 0; | 27 | this->buffer_size_ = 0; |
33 | this->sample_rate_ = 0; | 28 | this->sample_rate_ = 0; |
34 | this->reader_accum_ = 0; | 29 | this->bass_shift_ = 0; |
35 | this->bass_shift_ = 0; | 30 | this->clock_rate_ = 0; |
36 | this->clock_rate_ = 0; | 31 | this->bass_freq_ = 16; |
37 | this->bass_freq_ = 16; | 32 | this->length_ = 0; |
38 | this->length_ = 0; | 33 | |
39 | |||
40 | // assumptions code makes about implementation-defined features | 34 | // assumptions code makes about implementation-defined features |
41 | #ifndef NDEBUG | 35 | #ifndef NDEBUG |
42 | // right shift of negative value preserves sign | 36 | // right shift of negative value preserves sign |
43 | buf_t_ i = -0x7FFFFFFE; | 37 | buf_t_ i = -0x7FFFFFFE; |
44 | assert( (i >> 1) == -0x3FFFFFFF ); | 38 | assert( (i >> 1) == -0x3FFFFFFF ); |
45 | 39 | ||
46 | // casting to short truncates to 16 bits and sign-extends | 40 | // casting to short truncates to 16 bits and sign-extends |
47 | i = 0x18000; | 41 | i = 0x18000; |
48 | assert( (short) i == -0x8000 ); | 42 | assert( (short) i == -0x8000 ); |
49 | #endif | 43 | #endif |
50 | } | ||
51 | 44 | ||
52 | void Blip_stop( struct Blip_Buffer* this ) | 45 | Blip_clear( this ); |
53 | { | ||
54 | if ( this->buffer_size_ != silent_buf_size ) | ||
55 | free( this->buffer_ ); | ||
56 | } | 46 | } |
57 | 47 | ||
58 | void Blip_clear( struct Blip_Buffer* this, int entire_buffer ) | 48 | void Blip_clear( struct Blip_Buffer* this ) |
59 | { | 49 | { |
60 | this->offset_ = 0; | 50 | bool const entire_buffer = true; |
51 | |||
52 | this->offset_ = 0; | ||
61 | this->reader_accum_ = 0; | 53 | this->reader_accum_ = 0; |
62 | this->modified_ = 0; | 54 | this->modified = false; |
55 | |||
63 | if ( this->buffer_ ) | 56 | if ( this->buffer_ ) |
64 | { | 57 | { |
65 | long count = (entire_buffer ? this->buffer_size_ : Blip_samples_avail( this )); | 58 | int count = (entire_buffer ? this->buffer_size_ : Blip_samples_avail( this )); |
66 | memset( this->buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) ); | 59 | memset( this->buffer_, 0, (count + blip_buffer_extra_) * sizeof (delta_t) ); |
67 | } | 60 | } |
68 | } | 61 | } |
69 | 62 | ||
70 | blargg_err_t Blip_set_sample_rate( struct Blip_Buffer* this, long new_rate, int msec ) | 63 | blargg_err_t Blip_set_sample_rate( struct Blip_Buffer* this, int new_rate, int msec ) |
71 | { | 64 | { |
72 | if ( this->buffer_size_ == silent_buf_size ) | 65 | // Limit to maximum size that resampled time can represent |
73 | { | 66 | int max_size = (((blip_resampled_time_t) -1) >> BLIP_BUFFER_ACCURACY) - |
74 | assert( 0 ); | 67 | blip_buffer_extra_ - 64; // TODO: -64 isn't needed |
75 | return "Internal (tried to resize Silent_Blip_Buffer)"; | 68 | int new_size = (new_rate * (msec + 1) + 999) / 1000; |
76 | } | 69 | if ( new_size > max_size ) |
77 | 70 | new_size = max_size; | |
78 | // start with maximum length that resampled time can represent | 71 | |
79 | long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64; | 72 | // Resize buffer |
80 | if ( msec != blip_max_length ) | 73 | if ( this->buffer_size_ != new_size ) { |
81 | { | 74 | this->buffer_center_ = this->buffer_ + BLIP_MAX_QUALITY/2; |
82 | long s = (new_rate * (msec + 1) + 999) / 1000; | 75 | this->buffer_size_ = new_size; |
83 | if ( s < new_size ) | 76 | } |
84 | new_size = s; | 77 | |
85 | else | ||
86 | assert( 0 ); // fails if requested buffer length exceeds limit | ||
87 | } | ||
88 | |||
89 | if ( new_size > blip_buffer_max ) | ||
90 | return "Out of memory"; | ||
91 | |||
92 | this->buffer_size_ = new_size; | ||
93 | assert( this->buffer_size_ != silent_buf_size ); | ||
94 | |||
95 | // update things based on the sample rate | 78 | // update things based on the sample rate |
96 | this->sample_rate_ = new_rate; | 79 | this->sample_rate_ = new_rate; |
97 | this->length_ = new_size * 1000 / new_rate - 1; | 80 | this->length_ = new_size * 1000 / new_rate - 1; |
98 | if ( msec ) | ||
99 | assert( this->length_ == msec ); // ensure length is same as that passed in | ||
100 | if ( this->clock_rate_ ) | 81 | if ( this->clock_rate_ ) |
101 | Blip_set_clock_rate( this, this->clock_rate_ ); | 82 | Blip_set_clock_rate( this, this->clock_rate_ ); |
102 | Blip_bass_freq( this, this->bass_freq_ ); | 83 | Blip_bass_freq( this, this->bass_freq_ ); |
103 | 84 | ||
104 | Blip_clear( this, 1 ); | 85 | Blip_clear( this ); |
105 | 86 | ||
106 | return 0; // success | 87 | return 0; // success |
107 | } | 88 | } |
108 | 89 | ||
109 | blip_resampled_time_t Blip_clock_rate_factor( struct Blip_Buffer* this, long rate ) | 90 | blip_resampled_time_t Blip_clock_rate_factor( struct Blip_Buffer* this, int rate ) |
110 | { | 91 | { |
111 | blip_long factor = (blip_long) ( this->sample_rate_ * (1LL << BLIP_BUFFER_ACCURACY) / rate); | 92 | int factor = (int) ( this->sample_rate_ * (1LL << BLIP_BUFFER_ACCURACY) / rate); |
112 | assert( factor > 0 || !this->sample_rate_ ); // fails if clock/output ratio is too large | 93 | assert( factor > 0 || !this->sample_rate_ ); // fails if clock/output ratio is too large |
113 | return (blip_resampled_time_t) factor; | 94 | return (blip_resampled_time_t) factor; |
114 | } | 95 | } |
@@ -117,119 +98,111 @@ void Blip_bass_freq( struct Blip_Buffer* this, int freq ) | |||
117 | { | 98 | { |
118 | this->bass_freq_ = freq; | 99 | this->bass_freq_ = freq; |
119 | int shift = 31; | 100 | int shift = 31; |
120 | if ( freq > 0 ) | 101 | if ( freq > 0 && this->sample_rate_ ) |
121 | { | 102 | { |
122 | shift = 13; | 103 | shift = 13; |
123 | long f = (freq << 16) / this->sample_rate_; | 104 | int f = (freq << 16) / this->sample_rate_; |
124 | while ( (f >>= 1) && --shift ) { } | 105 | while ( (f >>= 1) && --shift ) { } |
125 | } | 106 | } |
126 | this->bass_shift_ = shift; | 107 | this->bass_shift_ = shift; |
127 | } | 108 | } |
128 | 109 | ||
129 | void Blip_end_frame( struct Blip_Buffer* this, blip_time_t t ) | 110 | void Blip_end_frame( struct Blip_Buffer* this, blip_time_t t ) |
130 | { | 111 | { |
131 | this->offset_ += t * this->factor_; | 112 | this->offset_ += t * this->factor_; |
132 | assert( Blip_samples_avail( this ) <= (long) this->buffer_size_ ); // time outside buffer length | 113 | assert( Blip_samples_avail( this ) <= (int) this->buffer_size_ ); // time outside buffer length |
133 | } | 114 | } |
134 | 115 | ||
135 | void Blip_remove_silence( struct Blip_Buffer* this, long count ) | 116 | int Blip_count_samples( struct Blip_Buffer* this, blip_time_t t ) |
136 | { | 117 | { |
137 | assert( count <= Blip_samples_avail( this ) ); // tried to remove more samples than available | 118 | blip_resampled_time_t last_sample = Blip_resampled_time( this, t ) >> BLIP_BUFFER_ACCURACY; |
138 | this->offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; | 119 | blip_resampled_time_t first_sample = this->offset_ >> BLIP_BUFFER_ACCURACY; |
120 | return (int) (last_sample - first_sample); | ||
139 | } | 121 | } |
140 | 122 | ||
141 | long Blip_count_samples( struct Blip_Buffer* this, blip_time_t t ) | 123 | blip_time_t Blip_count_clocks( struct Blip_Buffer* this, int count ) |
142 | { | 124 | { |
143 | unsigned long last_sample = Blip_resampled_time( this, t ) >> BLIP_BUFFER_ACCURACY; | ||
144 | unsigned long first_sample = this->offset_ >> BLIP_BUFFER_ACCURACY; | ||
145 | return (long) (last_sample - first_sample); | ||
146 | } | ||
147 | |||
148 | blip_time_t Blip_count_clocks( struct Blip_Buffer* this, long count ) | ||
149 | { | ||
150 | if ( !this->factor_ ) | ||
151 | { | ||
152 | assert( 0 ); // sample rate and clock rates must be set first | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | if ( count > this->buffer_size_ ) | 125 | if ( count > this->buffer_size_ ) |
157 | count = this->buffer_size_; | 126 | count = this->buffer_size_; |
158 | blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; | 127 | blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; |
159 | return (blip_time_t) ((time - this->offset_ + this->factor_ - 1) / this->factor_); | 128 | return (blip_time_t) ((time - this->offset_ + this->factor_ - 1) / this->factor_); |
160 | } | 129 | } |
161 | 130 | ||
162 | void Blip_remove_samples( struct Blip_Buffer* this, long count ) | 131 | void Blip_remove_samples( struct Blip_Buffer* this, int count ) |
163 | { | 132 | { |
164 | if ( count ) | 133 | if ( count ) |
165 | { | 134 | { |
166 | Blip_remove_silence( this, count ); | 135 | Blip_remove_silence( this, count ); |
167 | 136 | ||
168 | // copy remaining samples to beginning and clear old samples | 137 | // copy remaining samples to beginning and clear old samples |
169 | long remain = Blip_samples_avail( this ) + blip_buffer_extra_; | 138 | int remain = Blip_samples_avail( this ) + blip_buffer_extra_; |
170 | memmove( this->buffer_, this->buffer_ + count, remain * sizeof *this->buffer_ ); | 139 | memmove( this->buffer_, this->buffer_ + count, remain * sizeof *this->buffer_ ); |
171 | memset( this->buffer_ + remain, 0, count * sizeof *this->buffer_ ); | 140 | memset( this->buffer_ + remain, 0, count * sizeof *this->buffer_ ); |
172 | } | 141 | } |
173 | } | 142 | } |
174 | 143 | ||
175 | long Blip_read_samples( struct Blip_Buffer* this, blip_sample_t* BLIP_RESTRICT out, long max_samples, int stereo ) | 144 | int Blip_read_samples( struct Blip_Buffer* this, blip_sample_t out_ [], int max_samples, bool stereo ) |
176 | { | 145 | { |
177 | long count = Blip_samples_avail( this ); | 146 | int count = Blip_samples_avail( this ); |
178 | if ( count > max_samples ) | 147 | if ( count > max_samples ) |
179 | count = max_samples; | 148 | count = max_samples; |
180 | 149 | ||
181 | if ( count ) | 150 | if ( count ) |
182 | { | 151 | { |
183 | int const bass = BLIP_READER_BASS( *this ); | 152 | int const bass = this->bass_shift_; |
184 | BLIP_READER_BEGIN( reader, *this ); | 153 | delta_t const* reader = this->buffer_ + count; |
185 | 154 | int reader_sum = this->reader_accum_; | |
155 | |||
156 | blip_sample_t* BLARGG_RESTRICT out = out_ + count; | ||
157 | if ( stereo ) | ||
158 | out += count; | ||
159 | int offset = -count; | ||
160 | |||
186 | if ( !stereo ) | 161 | if ( !stereo ) |
187 | { | 162 | { |
188 | blip_long n; | 163 | do |
189 | for ( n = count; n; --n ) | ||
190 | { | 164 | { |
191 | blip_long s = BLIP_READER_READ( reader ); | 165 | int s = reader_sum >> delta_bits; |
192 | if ( (blip_sample_t) s != s ) | 166 | |
193 | s = 0x7FFF - (s >> 24); | 167 | reader_sum -= reader_sum >> bass; |
194 | *out++ = (blip_sample_t) s; | 168 | reader_sum += reader [offset]; |
195 | BLIP_READER_NEXT( reader, bass ); | 169 | |
170 | BLIP_CLAMP( s, s ); | ||
171 | out [offset] = (blip_sample_t) s; | ||
196 | } | 172 | } |
173 | while ( ++offset ); | ||
197 | } | 174 | } |
198 | else | 175 | else |
199 | { | 176 | { |
200 | blip_long n; | 177 | do |
201 | for ( n = count; n; --n ) | ||
202 | { | 178 | { |
203 | blip_long s = BLIP_READER_READ( reader ); | 179 | int s = reader_sum >> delta_bits; |
204 | if ( (blip_sample_t) s != s ) | 180 | |
205 | s = 0x7FFF - (s >> 24); | 181 | reader_sum -= reader_sum >> bass; |
206 | *out = (blip_sample_t) s; | 182 | reader_sum += reader [offset]; |
207 | out += 2; | 183 | |
208 | BLIP_READER_NEXT( reader, bass ); | 184 | BLIP_CLAMP( s, s ); |
185 | out [offset * 2] = (blip_sample_t) s; | ||
209 | } | 186 | } |
187 | while ( ++offset ); | ||
210 | } | 188 | } |
211 | BLIP_READER_END( reader, *this ); | 189 | |
212 | 190 | this->reader_accum_ = reader_sum; | |
191 | |||
213 | Blip_remove_samples( this, count ); | 192 | Blip_remove_samples( this, count ); |
214 | } | 193 | } |
215 | return count; | 194 | return count; |
216 | } | 195 | } |
217 | 196 | ||
218 | void Blip_mix_samples( struct Blip_Buffer* this, blip_sample_t const* in, long count ) | 197 | void Blip_mix_samples( struct Blip_Buffer* this, blip_sample_t const in [], int count ) |
219 | { | 198 | { |
220 | if ( this->buffer_size_ == silent_buf_size ) | 199 | delta_t* out = this->buffer_center_ + (this->offset_ >> BLIP_BUFFER_ACCURACY); |
221 | { | 200 | |
222 | assert( 0 ); | ||
223 | return; | ||
224 | } | ||
225 | |||
226 | buf_t_* out = this->buffer_ + (this->offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2; | ||
227 | |||
228 | int const sample_shift = blip_sample_bits - 16; | 201 | int const sample_shift = blip_sample_bits - 16; |
229 | int prev = 0; | 202 | int prev = 0; |
230 | while ( count-- ) | 203 | while ( --count >= 0 ) |
231 | { | 204 | { |
232 | blip_long s = (blip_long) *in++ << sample_shift; | 205 | int s = *in++ << sample_shift; |
233 | *out += s - prev; | 206 | *out += s - prev; |
234 | prev = s; | 207 | prev = s; |
235 | ++out; | 208 | ++out; |
@@ -237,40 +210,16 @@ void Blip_mix_samples( struct Blip_Buffer* this, blip_sample_t const* in, long | |||
237 | *out -= prev; | 210 | *out -= prev; |
238 | } | 211 | } |
239 | 212 | ||
240 | void Blip_set_modified( struct Blip_Buffer* this ) | 213 | // Blip_Synth |
241 | { | ||
242 | this->modified_ = 1; | ||
243 | } | ||
244 | |||
245 | int Blip_clear_modified( struct Blip_Buffer* this ) | ||
246 | { | ||
247 | int b = this->modified_; | ||
248 | this->modified_ = 0; | ||
249 | return b; | ||
250 | } | ||
251 | |||
252 | blip_resampled_time_t Blip_resampled_duration( struct Blip_Buffer* this, int t ) | ||
253 | { | ||
254 | return t * this->factor_; | ||
255 | } | ||
256 | 214 | ||
257 | blip_resampled_time_t Blip_resampled_time( struct Blip_Buffer* this, blip_time_t t ) | 215 | void volume_unit( struct Blip_Synth* this, int new_unit ) |
258 | { | 216 | { |
259 | return t * this->factor_ + this->offset_; | 217 | this->delta_factor = (int) (new_unit * (1LL << blip_sample_bits) / FP_ONE_VOLUME); |
260 | } | 218 | } |
261 | 219 | ||
262 | |||
263 | // Blip_Synth | ||
264 | |||
265 | void Synth_init( struct Blip_Synth* this ) | 220 | void Synth_init( struct Blip_Synth* this ) |
266 | { | 221 | { |
267 | this->buf = 0; | 222 | this->buf = 0; |
268 | this->last_amp = 0; | 223 | this->last_amp = 0; |
269 | this->delta_factor = 0; | 224 | this->delta_factor = 0; |
270 | } | 225 | } |
271 | |||
272 | // Set overall volume of waveform | ||
273 | void Synth_volume( struct Blip_Synth* this, int v ) | ||
274 | { | ||
275 | this->delta_factor = (int) (v * (1LL << blip_sample_bits) / FP_ONE_VOLUME); | ||
276 | } | ||
diff --git a/apps/codecs/libgme/blip_buffer.h b/apps/codecs/libgme/blip_buffer.h index f9f1f6e969..d73a14b3eb 100644 --- a/apps/codecs/libgme/blip_buffer.h +++ b/apps/codecs/libgme/blip_buffer.h | |||
@@ -4,202 +4,238 @@ | |||
4 | #ifndef BLIP_BUFFER_H | 4 | #ifndef BLIP_BUFFER_H |
5 | #define BLIP_BUFFER_H | 5 | #define BLIP_BUFFER_H |
6 | 6 | ||
7 | #include <assert.h> | 7 | #include "blargg_common.h" |
8 | 8 | ||
9 | // internal | 9 | typedef unsigned blip_resampled_time_t; |
10 | #include "blargg_common.h" | 10 | typedef int blip_time_t; |
11 | #if INT_MAX >= 0x7FFFFFFF | 11 | typedef int clocks_t; |
12 | typedef int blip_long; | 12 | |
13 | typedef unsigned blip_ulong; | 13 | // Output samples are 16-bit signed, with a range of -32768 to 32767 |
14 | #else | 14 | typedef short blip_sample_t; |
15 | typedef long blip_long; | ||
16 | typedef unsigned long blip_ulong; | ||
17 | #endif | ||
18 | 15 | ||
19 | // Time unit at source clock rate | 16 | static int const blip_default_length = 1000 / 4; // Default Blip_Buffer length (1/4 second) |
20 | typedef blip_long blip_time_t; | 17 | |
18 | #ifndef BLIP_MAX_QUALITY | ||
19 | #define BLIP_MAX_QUALITY 2 | ||
20 | #endif | ||
21 | 21 | ||
22 | // Number of bits in resample ratio fraction. Higher values give a more accurate ratio | ||
23 | // but reduce maximum buffer size. | ||
24 | #ifndef BLIP_BUFFER_ACCURACY | 22 | #ifndef BLIP_BUFFER_ACCURACY |
25 | #define BLIP_BUFFER_ACCURACY 16 | 23 | #define BLIP_BUFFER_ACCURACY 16 |
26 | #endif | 24 | #endif |
27 | 25 | ||
28 | // Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in | 26 | // linear interpolation needs 8 bits |
29 | // noticeable broadband noise when synthesizing high frequency square waves. | ||
30 | // Affects size of Blip_Synth objects since they store the waveform directly. | ||
31 | #ifndef BLIP_PHASE_BITS | 27 | #ifndef BLIP_PHASE_BITS |
32 | #define BLIP_PHASE_BITS 8 | 28 | #define BLIP_PHASE_BITS 8 |
33 | #endif | 29 | #endif |
34 | 30 | ||
35 | // Output samples are 16-bit signed, with a range of -32768 to 32767 | 31 | static int const blip_res = 1 << BLIP_PHASE_BITS; |
36 | typedef short blip_sample_t; | 32 | static int const blip_buffer_extra_ = BLIP_MAX_QUALITY + 2; |
37 | enum { blip_sample_max = 32767 }; | 33 | |
38 | enum { blip_widest_impulse_ = 16 }; | 34 | // Properties of fixed-point sample position |
39 | enum { blip_buffer_extra_ = blip_widest_impulse_ + 2 }; | 35 | typedef unsigned ufixed_t; // unsigned for more range, optimized shifts |
40 | enum { blip_res = 1 << BLIP_PHASE_BITS }; | 36 | enum { fixed_bits = BLIP_BUFFER_ACCURACY }; // bits in fraction |
41 | enum { blip_max_length = 0 }; | 37 | enum { fixed_unit = 1 << fixed_bits }; // 1.0 samples |
42 | enum { blip_default_length = 250 }; | 38 | |
39 | // Deltas in buffer are fixed-point with this many fraction bits. | ||
40 | // Less than 16 for extra range. | ||
41 | enum { delta_bits = 14 }; | ||
42 | |||
43 | // Pointer to first committed delta sample | ||
44 | typedef int delta_t; | ||
43 | 45 | ||
44 | // Maximun buffer size (48Khz, 50 ms) | 46 | // Maximun buffer size (48Khz, 50 ms) |
45 | enum { blip_buffer_max = 2466 }; | 47 | enum { blip_buffer_max = 2466 }; |
46 | enum { blip_sample_bits = 30 }; | ||
47 | |||
48 | typedef blip_time_t buf_t_; | ||
49 | /* typedef const char* blargg_err_t; */ | ||
50 | typedef blip_ulong blip_resampled_time_t; | ||
51 | 48 | ||
52 | struct Blip_Buffer { | 49 | struct Blip_Buffer { |
53 | blip_ulong factor_; | 50 | unsigned factor_; |
54 | blip_resampled_time_t offset_; | 51 | ufixed_t offset_; |
55 | buf_t_ buffer_ [blip_buffer_max]; | 52 | delta_t* buffer_center_; |
56 | blip_long buffer_size_; | 53 | int buffer_size_; |
57 | blip_long reader_accum_; | 54 | int reader_accum_; |
58 | int bass_shift_; | 55 | int bass_shift_; |
59 | 56 | int bass_freq_; | |
60 | long sample_rate_; | 57 | int sample_rate_; |
61 | long clock_rate_; | 58 | int clock_rate_; |
62 | int bass_freq_; | 59 | int length_; |
63 | int length_; | 60 | bool modified; |
64 | int modified_; | 61 | |
62 | delta_t buffer_ [blip_buffer_max]; | ||
65 | }; | 63 | }; |
66 | 64 | ||
67 | // not documented yet | 65 | // Blip_Buffer_ implementation |
68 | void Blip_set_modified( struct Blip_Buffer* this ); | 66 | static inline ufixed_t to_fixed( struct Blip_Buffer *this, clocks_t t ) |
69 | int Blip_clear_modified( struct Blip_Buffer* this ); | 67 | { |
70 | void Blip_remove_silence( struct Blip_Buffer* this, long count ); | 68 | return t * this->factor_ + this->offset_; |
71 | blip_resampled_time_t Blip_resampled_duration( struct Blip_Buffer* this, int t ); | 69 | } |
72 | blip_resampled_time_t Blip_resampled_time( struct Blip_Buffer* this, blip_time_t t ); | ||
73 | blip_resampled_time_t Blip_clock_rate_factor( struct Blip_Buffer* this, long clock_rate ); | ||
74 | |||
75 | // Initializes Blip_Buffer structure | ||
76 | void Blip_init( struct Blip_Buffer* this ); | ||
77 | |||
78 | // Stops (clear) Blip_Buffer structure | ||
79 | void Blip_stop( struct Blip_Buffer* this ); | ||
80 | 70 | ||
81 | // Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults | 71 | static inline delta_t* delta_at( struct Blip_Buffer *this, ufixed_t f ) |
82 | // to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there | 72 | { |
83 | // isn't enough memory, returns error without affecting current buffer setup. | 73 | assert( (f >> fixed_bits) < (unsigned) this->buffer_size_ ); |
84 | blargg_err_t Blip_set_sample_rate( struct Blip_Buffer* this, long samples_per_sec, int msec_length ); | 74 | return this->buffer_center_ + (f >> fixed_bits); |
75 | } | ||
85 | 76 | ||
86 | // Set number of source time units per second | 77 | // Number of samples available for reading with read_samples() |
87 | static inline void Blip_set_clock_rate( struct Blip_Buffer* this, long cps ) | 78 | static inline int Blip_samples_avail( struct Blip_Buffer* this ) |
88 | { | 79 | { |
89 | this->factor_ = Blip_clock_rate_factor( this, this->clock_rate_ = cps ); | 80 | return (int) (this->offset_ >> BLIP_BUFFER_ACCURACY); |
90 | } | 81 | } |
91 | 82 | ||
92 | // End current time frame of specified duration and make its samples available | 83 | static inline void Blip_remove_silence( struct Blip_Buffer* this, int count ) |
93 | // (along with any still-unread samples) for reading with read_samples(). Begins | 84 | { |
94 | // a new time frame at the end of the current frame. | 85 | assert( count <= Blip_samples_avail( this ) ); // tried to remove more samples than available |
95 | void Blip_end_frame( struct Blip_Buffer* this, blip_time_t time ); | 86 | this->offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; |
87 | } | ||
96 | 88 | ||
97 | // Read at most 'max_samples' out of buffer into 'dest', removing them from from | 89 | // Initializes Blip_Buffer structure |
98 | // the buffer. Returns number of samples actually read and removed. If stereo is | 90 | void Blip_init( struct Blip_Buffer* this ); |
99 | // true, increments 'dest' one extra time after writing each sample, to allow | ||
100 | // easy interleving of two channels into a stereo output buffer. | ||
101 | long Blip_read_samples( struct Blip_Buffer* this, blip_sample_t* dest, long max_samples, int stereo ); | ||
102 | 91 | ||
103 | // Additional optional features | 92 | // Sets output sample rate and resizes and clears sample buffer |
93 | blargg_err_t Blip_set_sample_rate( struct Blip_Buffer* this, int samples_per_sec, int msec_length ); | ||
104 | 94 | ||
105 | // Current output sample rate | 95 | // Current output sample rate |
106 | static inline long Blip_sample_rate( struct Blip_Buffer* this ) | 96 | static inline int Blip_sample_rate( struct Blip_Buffer* this ) |
107 | { | 97 | { |
108 | return this->sample_rate_; | 98 | return this->sample_rate_; |
109 | } | 99 | } |
110 | 100 | ||
111 | // Length of buffer, in milliseconds | 101 | // Sets number of source time units per second |
112 | static inline int Blip_length( struct Blip_Buffer* this ) | 102 | blip_resampled_time_t Blip_clock_rate_factor( struct Blip_Buffer* this, int clock_rate ); |
103 | static inline void Blip_set_clock_rate( struct Blip_Buffer* this, int clocks_per_sec ) | ||
113 | { | 104 | { |
114 | return this->length_; | 105 | this->factor_ = Blip_clock_rate_factor( this, this->clock_rate_ = clocks_per_sec ); |
115 | } | 106 | } |
116 | 107 | ||
117 | // Number of source time units per second | 108 | // Number of source time units per second |
118 | static inline long Blip_clock_rate( struct Blip_Buffer* this ) | 109 | static inline int Blip_clock_rate( struct Blip_Buffer* this ) |
119 | { | 110 | { |
120 | return this->clock_rate_; | 111 | return this->clock_rate_; |
121 | } | 112 | } |
122 | 113 | ||
114 | static inline int Blip_length( struct Blip_Buffer* this ) | ||
115 | { | ||
116 | return this->length_; | ||
117 | } | ||
118 | |||
119 | // Clears buffer and removes all samples | ||
120 | void Blip_clear( struct Blip_Buffer* this ); | ||
121 | |||
122 | // Use Blip_Synth to add waveform to buffer | ||
123 | |||
124 | // Resamples to time t, then subtracts t from current time. Appends result of resampling | ||
125 | // to buffer for reading. | ||
126 | void Blip_end_frame( struct Blip_Buffer* this, blip_time_t time ) ICODE_ATTR; | ||
127 | |||
128 | |||
129 | // Reads at most n samples to out [0 to n-1] and returns number actually read. If stereo | ||
130 | // is true, writes to out [0], out [2], out [4] etc. instead. | ||
131 | int Blip_read_samples( struct Blip_Buffer* this, blip_sample_t out [], int n, bool stereo ) ICODE_ATTR; | ||
132 | |||
133 | |||
134 | // More features | ||
135 | |||
136 | // Sets flag that tells some Multi_Buffer types that sound was added to buffer, | ||
137 | // so they know that it needs to be mixed in. Only needs to be called once | ||
138 | // per time frame that sound was added. Not needed if not using Multi_Buffer. | ||
139 | static inline void Blip_set_modified( struct Blip_Buffer* this ) { this->modified = true; } | ||
123 | 140 | ||
124 | // Set frequency high-pass filter frequency, where higher values reduce bass more | 141 | // Set frequency high-pass filter frequency, where higher values reduce bass more |
125 | void Blip_bass_freq( struct Blip_Buffer* this, int frequency ); | 142 | void Blip_bass_freq( struct Blip_Buffer* this, int frequency ); |
126 | 143 | ||
127 | // Number of samples delay from synthesis to samples read out | ||
128 | static inline int Blip_output_latency( void ) | ||
129 | { | ||
130 | return blip_widest_impulse_ / 2; | ||
131 | } | ||
132 | 144 | ||
133 | // Remove all available samples and clear buffer to silence. If 'entire_buffer' is | 145 | // Low-level features |
134 | // false, just clears out any samples waiting rather than the entire buffer. | ||
135 | void Blip_clear( struct Blip_Buffer* this, int entire_buffer ); | ||
136 | 146 | ||
137 | // Number of samples available for reading with read_samples() | 147 | // Removes the first n samples |
138 | static inline long Blip_samples_avail( struct Blip_Buffer* this ) | 148 | void Blip_remove_samples( struct Blip_Buffer* this, int n ) ICODE_ATTR; |
139 | { | 149 | |
140 | return (long) (this->offset_ >> BLIP_BUFFER_ACCURACY); | 150 | // Returns number of clocks needed until n samples will be available. |
141 | } | 151 | // If buffer cannot even hold n samples, returns number of clocks |
152 | // until buffer becomes full. | ||
153 | blip_time_t Blip_count_clocks( struct Blip_Buffer* this, int count ) ICODE_ATTR; | ||
154 | |||
155 | // Number of samples that should be mixed before calling Blip_end_frame( t ) | ||
156 | int Blip_count_samples( struct Blip_Buffer* this, blip_time_t t ) ICODE_ATTR; | ||
157 | |||
158 | // Mixes n samples into buffer | ||
159 | void Blip_mix_samples( struct Blip_Buffer* this, blip_sample_t const in [], int n ) ICODE_ATTR; | ||
142 | 160 | ||
143 | // Remove 'count' samples from those waiting to be read | ||
144 | void Blip_remove_samples( struct Blip_Buffer* this, long count ); | ||
145 | 161 | ||
146 | // Experimental features | 162 | // Resampled time (sorry, poor documentation right now) |
147 | 163 | ||
148 | // Count number of clocks needed until 'count' samples will be available. | 164 | // Resampled time is fixed-point, in terms of output samples. |
149 | // If buffer can't even hold 'count' samples, returns number of clocks until | ||
150 | // buffer becomes full. | ||
151 | blip_time_t Blip_count_clocks( struct Blip_Buffer* this, long count ); | ||
152 | 165 | ||
153 | // Number of raw samples that can be mixed within frame of specified duration. | 166 | // Converts clock count to resampled time |
154 | long Blip_count_samples( struct Blip_Buffer* this, blip_time_t duration ); | 167 | static inline blip_resampled_time_t Blip_resampled_duration( struct Blip_Buffer* this, int t ) |
168 | { | ||
169 | return t * this->factor_; | ||
170 | } | ||
171 | |||
172 | // Converts clock time since beginning of current time frame to resampled time | ||
173 | static inline blip_resampled_time_t Blip_resampled_time( struct Blip_Buffer* this, blip_time_t t ) | ||
174 | { | ||
175 | return t * this->factor_ + this->offset_; | ||
176 | } | ||
155 | 177 | ||
156 | // Mix 'count' samples from 'buf' into buffer. | ||
157 | void Blip_mix_samples( struct Blip_Buffer* this, blip_sample_t const* buf, long count ); | ||
158 | 178 | ||
159 | // Range specifies the greatest expected change in amplitude. Calculate it | 179 | // Range specifies the greatest expected change in amplitude. Calculate it |
160 | // by finding the difference between the maximum and minimum expected | 180 | // by finding the difference between the maximum and minimum expected |
161 | // amplitudes (max - min). | 181 | // amplitudes (max - min). |
162 | 182 | ||
183 | typedef char coeff_t; | ||
184 | |||
163 | struct Blip_Synth { | 185 | struct Blip_Synth { |
164 | struct Blip_Buffer* buf; | ||
165 | int last_amp; | ||
166 | int delta_factor; | 186 | int delta_factor; |
187 | int last_amp; | ||
188 | struct Blip_Buffer* buf; | ||
167 | }; | 189 | }; |
168 | 190 | ||
191 | // Blip_Synth_ | ||
192 | void volume_unit( struct Blip_Synth* this, int new_unit ); | ||
193 | |||
169 | // Initializes Blip_Synth structure | 194 | // Initializes Blip_Synth structure |
170 | void Synth_init( struct Blip_Synth* this ); | 195 | void Synth_init( struct Blip_Synth* this ); |
171 | 196 | ||
172 | // Set overall volume of waveform | 197 | // Sets volume of amplitude delta unit |
173 | void Synth_volume( struct Blip_Synth* this, int v ); | 198 | static inline void Synth_volume( struct Blip_Synth* this, int v ) |
199 | { | ||
200 | volume_unit( this, v ); // new_unit = 1 / range * v | ||
201 | } | ||
174 | 202 | ||
175 | // Get/set Blip_Buffer used for output | ||
176 | const struct Blip_Buffer* Synth_output( struct Blip_Synth* this ); | ||
177 | 203 | ||
178 | // Low-level interface | 204 | // Low-level interface |
179 | 205 | ||
180 | #if defined (__GNUC__) || _MSC_VER >= 1100 | 206 | // (in >> sh & mask) * mul |
181 | #define BLIP_RESTRICT __restrict | 207 | #define BLIP_SH_AND_MUL( in, sh, mask, mul ) \ |
182 | #else | 208 | ((int) (in) / ((1U << (sh)) / (mul)) & (unsigned) ((mask) * (mul))) |
183 | #define BLIP_RESTRICT | 209 | |
184 | #endif | 210 | // (T*) ptr + (off >> sh) |
211 | #define BLIP_PTR_OFF_SH( T, ptr, off, sh ) \ | ||
212 | ((T*) (BLIP_SH_AND_MUL( off, sh, -1, sizeof (T) ) + (char*) (ptr))) | ||
185 | 213 | ||
186 | // Works directly in terms of fractional output samples. Contact author for more info. | 214 | // Works directly in terms of fractional output samples. Use resampled time functions in Blip_Buffer |
215 | // to convert clock counts to resampled time. | ||
187 | static inline void Synth_offset_resampled( struct Blip_Synth* this, blip_resampled_time_t time, | 216 | static inline void Synth_offset_resampled( struct Blip_Synth* this, blip_resampled_time_t time, |
188 | int delta, struct Blip_Buffer* blip_buf ) | 217 | int delta, struct Blip_Buffer* blip_buf ) |
189 | { | 218 | { |
190 | // Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the | 219 | int const half_width = 1; |
191 | // need for a longer buffer as set by set_sample_rate(). | 220 | |
192 | assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ ); | 221 | delta_t* BLARGG_RESTRICT buf = delta_at( blip_buf, time ); |
193 | delta *= this->delta_factor; | 222 | delta *= this->delta_factor; |
194 | blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY); | ||
195 | int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1)); | ||
196 | 223 | ||
197 | blip_long left = buf [0] + delta; | 224 | int const phase_shift = BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS; |
225 | int const phase = (half_width & (half_width - 1)) ? | ||
226 | (int) BLIP_SH_AND_MUL( time, phase_shift, blip_res - 1, sizeof (coeff_t) ) * half_width : | ||
227 | (int) BLIP_SH_AND_MUL( time, phase_shift, blip_res - 1, sizeof (coeff_t) * half_width ); | ||
228 | |||
229 | int left = buf [0] + delta; | ||
198 | 230 | ||
199 | // Kind of crappy, but doing shift after multiply results in overflow. | 231 | // Kind of crappy, but doing shift after multiply results in overflow. |
200 | // Alternate way of delaying multiply by delta_factor results in worse | 232 | // Alternate way of delaying multiply by delta_factor results in worse |
201 | // sub-sample resolution. | 233 | // sub-sample resolution. |
202 | blip_long right = (delta >> BLIP_PHASE_BITS) * phase; | 234 | int right = (delta >> BLIP_PHASE_BITS) * phase; |
235 | #ifdef BLIP_BUFFER_NOINTERP | ||
236 | // TODO: remove? (just a hack to see how it sounds) | ||
237 | right = 0; | ||
238 | #endif | ||
203 | left -= right; | 239 | left -= right; |
204 | right += buf [1]; | 240 | right += buf [1]; |
205 | 241 | ||
@@ -213,33 +249,38 @@ static inline void Synth_update( struct Blip_Synth* this, blip_time_t t, int amp | |||
213 | { | 249 | { |
214 | int delta = amp - this->last_amp; | 250 | int delta = amp - this->last_amp; |
215 | this->last_amp = amp; | 251 | this->last_amp = amp; |
216 | Synth_offset_resampled( this, t * this->buf->factor_ + this->buf->offset_, delta, this->buf ); | 252 | Synth_offset_resampled( this, to_fixed(this->buf, t), delta, this->buf ); |
217 | } | 253 | } |
218 | 254 | ||
219 | // Add an amplitude transition of specified delta, optionally into specified buffer | 255 | // Adds amplitude transition at time t. Delta can be positive or negative. |
220 | // rather than the one set with output(). Delta can be positive or negative. | 256 | // The actual change in amplitude is delta * volume. |
221 | // The actual change in amplitude is delta * (volume / range) | ||
222 | static inline void Synth_offset( struct Blip_Synth* this, blip_time_t t, int delta, struct Blip_Buffer* buf ) | ||
223 | { | ||
224 | Synth_offset_resampled( this, t * buf->factor_ + buf->offset_, delta, buf ); | ||
225 | } | ||
226 | |||
227 | // Same as offset(), except code is inlined for higher performance | ||
228 | static inline void Synth_offset_inline( struct Blip_Synth* this, blip_time_t t, int delta, struct Blip_Buffer* buf ) | 257 | static inline void Synth_offset_inline( struct Blip_Synth* this, blip_time_t t, int delta, struct Blip_Buffer* buf ) |
229 | { | 258 | { |
230 | Synth_offset_resampled( this, t * buf->factor_ + buf->offset_, delta, buf ); | 259 | Synth_offset_resampled( this, to_fixed(buf, t), delta, buf ); |
231 | } | 260 | } |
232 | 261 | ||
262 | #define Synth_offset( synth, time, delta, buf ) Synth_offset_inline( synth, time, delta, buf ) | ||
263 | |||
264 | // Number of bits in raw sample that covers normal output range. Less than 32 bits to give | ||
265 | // extra amplitude range. That is, | ||
266 | // +1 << (blip_sample_bits-1) = +1.0 | ||
267 | // -1 << (blip_sample_bits-1) = -1.0 | ||
268 | static int const blip_sample_bits = 30; | ||
269 | |||
233 | // Optimized reading from Blip_Buffer, for use in custom sample output | 270 | // Optimized reading from Blip_Buffer, for use in custom sample output |
234 | 271 | ||
235 | // Begin reading from buffer. Name should be unique to the current block. | 272 | // Begin reading from buffer. Name should be unique to the current block. |
236 | #define BLIP_READER_BEGIN( name, blip_buffer ) \ | 273 | #define BLIP_READER_BEGIN( name, blip_buffer ) \ |
237 | buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\ | 274 | const delta_t* BLARGG_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\ |
238 | blip_long name##_reader_accum = (blip_buffer).reader_accum_ | 275 | int name##_reader_accum = (blip_buffer).reader_accum_ |
239 | 276 | ||
240 | // Get value to pass to BLIP_READER_NEXT() | 277 | // Get value to pass to BLIP_READER_NEXT() |
241 | #define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_) | 278 | #define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_) |
242 | 279 | ||
280 | // Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal | ||
281 | // code at the cost of having no bass_freq() functionality | ||
282 | static int const blip_reader_default_bass = 9; | ||
283 | |||
243 | // Current sample | 284 | // Current sample |
244 | #define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16)) | 285 | #define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16)) |
245 | 286 | ||
@@ -254,7 +295,7 @@ static inline void Synth_offset_inline( struct Blip_Synth* this, blip_time_t t, | |||
254 | // using Blip_remove_samples(). | 295 | // using Blip_remove_samples(). |
255 | #define BLIP_READER_END( name, blip_buffer ) \ | 296 | #define BLIP_READER_END( name, blip_buffer ) \ |
256 | (void) ((blip_buffer).reader_accum_ = name##_reader_accum) | 297 | (void) ((blip_buffer).reader_accum_ = name##_reader_accum) |
257 | 298 | ||
258 | #define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset) | 299 | #define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset) |
259 | 300 | ||
260 | #define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\ | 301 | #define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\ |
@@ -262,18 +303,33 @@ static inline void Synth_offset_inline( struct Blip_Synth* this, blip_time_t t, | |||
262 | name##_reader_accum += name##_reader_buf [(idx)];\ | 303 | name##_reader_accum += name##_reader_buf [(idx)];\ |
263 | } | 304 | } |
264 | 305 | ||
306 | #define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\ | ||
307 | name##_reader_accum -= name##_reader_accum >> (bass);\ | ||
308 | name##_reader_accum +=\ | ||
309 | *(delta_t const*) ((char const*) name##_reader_buf + (idx));\ | ||
310 | } | ||
311 | |||
265 | //// BLIP_CLAMP | 312 | //// BLIP_CLAMP |
266 | 313 | ||
267 | #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ | 314 | #if ARM_ARCH >= 6 |
268 | defined (__x86_64__) || defined (__ia64__) || defined (__i386__) | 315 | #define BLIP_CLAMP( sample, out ) \ |
269 | #define BLIP_X86 1 | 316 | ({ \ |
270 | #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in | 317 | asm ("ssat %0, #16, %1" \ |
318 | : "=r" ( out ) : "r"( sample ) ); \ | ||
319 | out; \ | ||
320 | }) | ||
271 | #else | 321 | #else |
272 | #define BLIP_CLAMP_( in ) (blip_sample_t) in != in | 322 | #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ |
273 | #endif | 323 | defined (__x86_64__) || defined (__ia64__) || defined (__i386__) |
324 | #define BLIP_X86 1 | ||
325 | #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in | ||
326 | #else | ||
327 | #define BLIP_CLAMP_( in ) (blip_sample_t) in != in | ||
328 | #endif | ||
274 | 329 | ||
275 | // Clamp sample to blip_sample_t range | 330 | // Clamp sample to blip_sample_t range |
276 | #define BLIP_CLAMP( sample, out )\ | 331 | #define BLIP_CLAMP( sample, out )\ |
277 | { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 31) ^ 0x7FFF; } | 332 | { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 31) ^ 0x7FFF; } |
333 | #endif | ||
278 | 334 | ||
279 | #endif | 335 | #endif |
diff --git a/apps/codecs/libgme/gbs_cpu.c b/apps/codecs/libgme/gbs_cpu.c index 998888fe72..1015dd5358 100644 --- a/apps/codecs/libgme/gbs_cpu.c +++ b/apps/codecs/libgme/gbs_cpu.c | |||
@@ -20,7 +20,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | |||
20 | #define LOG_MEM( addr, str, data ) data | 20 | #define LOG_MEM( addr, str, data ) data |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | int Read_mem( struct Gbs_Emu* this, addr_t addr ) | 23 | int read_mem( struct Gbs_Emu* this, addr_t addr ) |
24 | { | 24 | { |
25 | int result = *Cpu_get_code( &this->cpu, addr ); | 25 | int result = *Cpu_get_code( &this->cpu, addr ); |
26 | if ( (unsigned) (addr - io_addr) < io_size ) | 26 | if ( (unsigned) (addr - io_addr) < io_size ) |
@@ -29,19 +29,19 @@ int Read_mem( struct Gbs_Emu* this, addr_t addr ) | |||
29 | return LOG_MEM( addr, ">", result ); | 29 | return LOG_MEM( addr, ">", result ); |
30 | } | 30 | } |
31 | 31 | ||
32 | static inline void Write_io_inline( struct Gbs_Emu* this, int offset, int data, int base ) | 32 | static inline void write_io_inline( struct Gbs_Emu* this, int offset, int data, int base ) |
33 | { | 33 | { |
34 | if ( (unsigned) (offset - (io_addr - base)) < io_size ) | 34 | if ( (unsigned) (offset - (io_addr - base)) < io_size ) |
35 | Apu_write_register( &this->apu, Time( this ), offset + base, data & 0xFF ); | 35 | Apu_write_register( &this->apu, Time( this ), offset + base, data & 0xFF ); |
36 | else if ( (unsigned) (offset - (0xFF06 - base)) < 2 ) | 36 | else if ( (unsigned) (offset - (0xFF06 - base)) < 2 ) |
37 | Update_timer( this ); | 37 | update_timer( this ); |
38 | else if ( offset == io_base - base ) | 38 | else if ( offset == io_base - base ) |
39 | this->ram [base - ram_addr + offset] = 0; // keep joypad return value 0 | 39 | this->ram [base - ram_addr + offset] = 0; // keep joypad return value 0 |
40 | else | 40 | else |
41 | this->ram [base - ram_addr + offset] = 0xFF; | 41 | this->ram [base - ram_addr + offset] = 0xFF; |
42 | } | 42 | } |
43 | 43 | ||
44 | void Write_mem( struct Gbs_Emu* this, addr_t addr, int data ) | 44 | void write_mem( struct Gbs_Emu* this, addr_t addr, int data ) |
45 | { | 45 | { |
46 | (void) LOG_MEM( addr, "<", data ); | 46 | (void) LOG_MEM( addr, "<", data ); |
47 | 47 | ||
@@ -52,11 +52,11 @@ void Write_mem( struct Gbs_Emu* this, addr_t addr, int data ) | |||
52 | 52 | ||
53 | offset -= 0xE000 - ram_addr; | 53 | offset -= 0xE000 - ram_addr; |
54 | if ( (unsigned) offset < 0x1F80 ) | 54 | if ( (unsigned) offset < 0x1F80 ) |
55 | Write_io_inline( this, offset, data, 0xE000 ); | 55 | write_io_inline( this, offset, data, 0xE000 ); |
56 | } | 56 | } |
57 | else if ( (unsigned) (offset - (0x2000 - ram_addr)) < 0x2000 ) | 57 | else if ( (unsigned) (offset - (0x2000 - ram_addr)) < 0x2000 ) |
58 | { | 58 | { |
59 | Set_bank( this, data & 0xFF ); | 59 | set_bank( this, data & 0xFF ); |
60 | } | 60 | } |
61 | #ifndef NDEBUG | 61 | #ifndef NDEBUG |
62 | else if ( unsigned (addr - 0x8000) < 0x2000 || unsigned (addr - 0xE000) < 0x1F00 ) | 62 | else if ( unsigned (addr - 0x8000) < 0x2000 || unsigned (addr - 0xE000) < 0x1F00 ) |
@@ -66,21 +66,21 @@ void Write_mem( struct Gbs_Emu* this, addr_t addr, int data ) | |||
66 | #endif | 66 | #endif |
67 | } | 67 | } |
68 | 68 | ||
69 | static void Write_io_( struct Gbs_Emu* this, int offset, int data ) | 69 | static void write_io_( struct Gbs_Emu* this, int offset, int data ) |
70 | { | 70 | { |
71 | Write_io_inline( this, offset, data, io_base ); | 71 | write_io_inline( this, offset, data, io_base ); |
72 | } | 72 | } |
73 | 73 | ||
74 | static inline void Write_io( struct Gbs_Emu* this, int offset, int data ) | 74 | static inline void write_io( struct Gbs_Emu* this, int offset, int data ) |
75 | { | 75 | { |
76 | (void) LOG_MEM( offset + io_base, "<", data ); | 76 | (void) LOG_MEM( offset + io_base, "<", data ); |
77 | 77 | ||
78 | this->ram [io_base - ram_addr + offset] = data; | 78 | this->ram [io_base - ram_addr + offset] = data; |
79 | if ( (unsigned) offset < 0x80 ) | 79 | if ( (unsigned) offset < 0x80 ) |
80 | Write_io_( this, offset, data ); | 80 | write_io_( this, offset, data ); |
81 | } | 81 | } |
82 | 82 | ||
83 | static int Read_io( struct Gbs_Emu* this, int offset ) | 83 | static int read_io( struct Gbs_Emu* this, int offset ) |
84 | { | 84 | { |
85 | int const io_base = 0xFF00; | 85 | int const io_base = 0xFF00; |
86 | int result = this->ram [io_base - ram_addr + offset]; | 86 | int result = this->ram [io_base - ram_addr + offset]; |
@@ -106,14 +106,14 @@ static int Read_io( struct Gbs_Emu* this, int offset ) | |||
106 | check( out == Read_mem( emu, addr ) );\ | 106 | check( out == Read_mem( emu, addr ) );\ |
107 | } | 107 | } |
108 | 108 | ||
109 | #define READ_MEM( emu, addr ) Read_mem( emu, addr ) | 109 | #define READ_MEM( emu, addr ) read_mem( emu, addr ) |
110 | #define WRITE_MEM( emu, addr, data ) Write_mem( emu, addr, data ) | 110 | #define WRITE_MEM( emu, addr, data ) write_mem( emu, addr, data ) |
111 | 111 | ||
112 | #define WRITE_IO( emu, addr, data ) Write_io( emu, addr, data ) | 112 | #define WRITE_IO( emu, addr, data ) write_io( emu, addr, data ) |
113 | #define READ_IO( emu, addr, out ) out = Read_io( emu, addr ) | 113 | #define READ_IO( emu, addr, out ) out = read_io( emu, addr ) |
114 | 114 | ||
115 | #define CPU_BEGIN \ | 115 | #define CPU_BEGIN \ |
116 | void Run_cpu( struct Gbs_Emu* this )\ | 116 | void run_cpu( struct Gbs_Emu* this )\ |
117 | { \ | 117 | { \ |
118 | struct Gb_Cpu* cpu = &this->cpu; | 118 | struct Gb_Cpu* cpu = &this->cpu; |
119 | #include "gb_cpu_run.h" | 119 | #include "gb_cpu_run.h" |
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 | } |
diff --git a/apps/codecs/libgme/gbs_emu.h b/apps/codecs/libgme/gbs_emu.h index 409cf2d6c2..72671b4658 100644 --- a/apps/codecs/libgme/gbs_emu.h +++ b/apps/codecs/libgme/gbs_emu.h | |||
@@ -9,15 +9,12 @@ | |||
9 | #include "gb_apu.h" | 9 | #include "gb_apu.h" |
10 | #include "gb_cpu.h" | 10 | #include "gb_cpu.h" |
11 | #include "m3u_playlist.h" | 11 | #include "m3u_playlist.h" |
12 | 12 | #include "track_filter.h" | |
13 | /* typedef uint8_t byte; */ | ||
14 | typedef short sample_t; | ||
15 | 13 | ||
16 | enum { joypad_addr = 0xFF00 }; | 14 | enum { joypad_addr = 0xFF00 }; |
17 | enum { ram_addr = 0xA000 }; | 15 | enum { ram_addr = 0xA000 }; |
18 | enum { hi_page = 0xFF00 - ram_addr }; | 16 | enum { hi_page = 0xFF00 - ram_addr }; |
19 | enum { io_base = 0xFF00 }; | 17 | enum { io_base = 0xFF00 }; |
20 | enum { buf_size = 2048 }; | ||
21 | 18 | ||
22 | // Selects which sound hardware to use. AGB hardware is cleaner than the | 19 | // Selects which sound hardware to use. AGB hardware is cleaner than the |
23 | // others. Doesn't take effect until next start_track(). | 20 | // others. Doesn't take effect until next start_track(). |
@@ -59,36 +56,19 @@ struct Gbs_Emu { | |||
59 | blip_time_t next_play; | 56 | blip_time_t next_play; |
60 | 57 | ||
61 | // Sound | 58 | // Sound |
62 | long clock_rate_; | 59 | int clock_rate_; |
63 | long sample_rate_; | 60 | int sample_rate_; |
64 | unsigned buf_changed_count; | 61 | unsigned buf_changed_count; |
65 | int voice_count_; | 62 | int voice_count_; |
63 | int const* voice_types_; | ||
64 | int mute_mask_; | ||
66 | int gain_; | 65 | int gain_; |
67 | int tempo_; | 66 | int tempo_; |
68 | 67 | ||
69 | // track-specific | 68 | // track-specific |
70 | byte track_count; | 69 | byte track_count; |
71 | volatile bool track_ended; | ||
72 | int current_track_; | 70 | int current_track_; |
73 | blargg_long out_time; // number of samples played since start of track | ||
74 | blargg_long emu_time; // number of samples emulator has generated since start of track | ||
75 | bool emu_track_ended_; // emulator has reached end of track | ||
76 | |||
77 | // fading | ||
78 | blargg_long fade_start; | ||
79 | int fade_step; | ||
80 | |||
81 | // silence detection | ||
82 | // Disable automatic end-of-track detection and skipping of silence at beginning | ||
83 | bool ignore_silence; | ||
84 | 71 | ||
85 | int max_initial_silence; | ||
86 | int mute_mask_; | ||
87 | int silence_lookahead; // speed to run emulator when looking ahead for silence | ||
88 | long silence_time; // number of samples where most recent silence began | ||
89 | long silence_count; // number of samples of silence to play before using buf | ||
90 | long buf_remain; // number of samples left in silence buffer | ||
91 | |||
92 | // Larger items at the end | 72 | // Larger items at the end |
93 | // Header for currently loaded file | 73 | // Header for currently loaded file |
94 | struct header_t header; | 74 | struct header_t header; |
@@ -96,11 +76,12 @@ struct Gbs_Emu { | |||
96 | // M3u Playlist | 76 | // M3u Playlist |
97 | struct M3u_Playlist m3u; | 77 | struct M3u_Playlist m3u; |
98 | 78 | ||
79 | struct setup_t tfilter; | ||
80 | struct Track_Filter track_filter; | ||
81 | |||
99 | struct Gb_Apu apu; | 82 | struct Gb_Apu apu; |
100 | struct Gb_Cpu cpu; | 83 | struct Gb_Cpu cpu; |
101 | struct Stereo_Buffer stereo_buf; | 84 | struct Multi_Buffer stereo_buf; |
102 | |||
103 | sample_t buf [buf_size]; | ||
104 | 85 | ||
105 | // rom & ram | 86 | // rom & ram |
106 | struct Rom_Data rom; | 87 | struct Rom_Data rom; |
@@ -116,36 +97,48 @@ void Gbs_init( struct Gbs_Emu* this ); | |||
116 | void Gbs_stop( struct Gbs_Emu* this ); | 97 | void Gbs_stop( struct Gbs_Emu* this ); |
117 | 98 | ||
118 | // Loads a file from memory | 99 | // Loads a file from memory |
119 | blargg_err_t Gbs_load( struct Gbs_Emu* this, void* data, long size ); | 100 | blargg_err_t Gbs_load_mem( struct Gbs_Emu* this, void* data, long size ); |
120 | 101 | ||
121 | // Set output sample rate. Must be called only once before loading file. | 102 | // Set output sample rate. Must be called only once before loading file. |
122 | blargg_err_t Gbs_set_sample_rate( struct Gbs_Emu* this, long sample_rate ); | 103 | blargg_err_t Gbs_set_sample_rate( struct Gbs_Emu* this, int sample_rate ); |
123 | 104 | ||
124 | // Start a track, where 0 is the first track. Also clears warning string. | 105 | // Start a track, where 0 is the first track. Also clears warning string. |
125 | blargg_err_t Gbs_start_track( struct Gbs_Emu* this, int ); | 106 | blargg_err_t Gbs_start_track( struct Gbs_Emu* this, int ); |
126 | 107 | ||
127 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation | 108 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation |
128 | // errors set warning string, and major errors also end track. | 109 | // errors set warning string, and major errors also end track. |
129 | blargg_err_t Gbs_play( struct Gbs_Emu* this, long count, sample_t* buf ); | 110 | blargg_err_t Gbs_play( struct Gbs_Emu* this, int count, sample_t* buf ); |
130 | 111 | ||
131 | // Track status/control | 112 | // Track status/control |
132 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track | 113 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track |
133 | long Track_tell( struct Gbs_Emu* this ); | 114 | int Track_tell( struct Gbs_Emu* this ); |
134 | 115 | ||
135 | // Seek to new time in track. Seeking backwards or far forward can take a while. | 116 | // Seek to new time in track. Seeking backwards or far forward can take a while. |
136 | blargg_err_t Track_seek( struct Gbs_Emu* this, long msec ); | 117 | blargg_err_t Track_seek( struct Gbs_Emu* this, int msec ); |
137 | 118 | ||
138 | // Skip n samples | 119 | // Skip n samples |
139 | blargg_err_t Track_skip( struct Gbs_Emu* this, long n ); | 120 | blargg_err_t Track_skip( struct Gbs_Emu* this, int n ); |
140 | 121 | ||
141 | // Set start time and length of track fade out. Once fade ends track_ended() returns | 122 | // Set start time and length of track fade out. Once fade ends track_ended() returns |
142 | // true. Fade time can be changed while track is playing. | 123 | // true. Fade time can be changed while track is playing. |
143 | void Track_set_fade( struct Gbs_Emu* this, long start_msec, long length_msec ); | 124 | void Track_set_fade( struct Gbs_Emu* this, int start_msec, int length_msec ); |
125 | |||
126 | // True if a track has reached its end | ||
127 | static inline bool Track_ended( struct Gbs_Emu* this ) | ||
128 | { | ||
129 | return track_ended( &this->track_filter ); | ||
130 | } | ||
131 | |||
132 | // Disables automatic end-of-track detection and skipping of silence at beginning | ||
133 | static inline void Track_ignore_silence( struct Gbs_Emu* this, bool disable ) | ||
134 | { | ||
135 | this->track_filter.silence_ignored_ = disable; | ||
136 | } | ||
144 | 137 | ||
145 | // Get track length in milliseconds | 138 | // Get track length in milliseconds |
146 | static inline long Track_get_length( struct Gbs_Emu* this, int n ) | 139 | static inline int Track_get_length( struct Gbs_Emu* this, int n ) |
147 | { | 140 | { |
148 | long length = 120 * 1000; /* 2 minutes */ | 141 | int length = 120 * 1000; /* 2 minutes */ |
149 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { | 142 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { |
150 | struct entry_t* entry = &this->m3u.entries [n]; | 143 | struct entry_t* entry = &this->m3u.entries [n]; |
151 | length = entry->length; | 144 | length = entry->length; |
@@ -175,19 +168,18 @@ static inline void Sound_set_gain( struct Gbs_Emu* this, int g ) | |||
175 | this->gain_ = g; | 168 | this->gain_ = g; |
176 | } | 169 | } |
177 | 170 | ||
178 | |||
179 | // Emulation (You shouldn't touch these) | 171 | // Emulation (You shouldn't touch these) |
180 | 172 | ||
181 | blargg_err_t Run_clocks( struct Gbs_Emu* this, blip_time_t duration ); | 173 | blargg_err_t run_clocks( struct Gbs_Emu* this, blip_time_t duration ); |
182 | void Set_bank( struct Gbs_Emu* this, int ); | 174 | void set_bank( struct Gbs_Emu* this, int ); |
183 | void Update_timer( struct Gbs_Emu* this ); | 175 | void update_timer( struct Gbs_Emu* this ); |
184 | 176 | ||
185 | // Runs CPU until time becomes >= 0 | 177 | // Runs CPU until time becomes >= 0 |
186 | void Run_cpu( struct Gbs_Emu* this ); | 178 | void run_cpu( struct Gbs_Emu* this ); |
187 | 179 | ||
188 | // Reads/writes memory and I/O | 180 | // Reads/writes memory and I/O |
189 | int Read_mem( struct Gbs_Emu* this, addr_t addr ); | 181 | int read_mem( struct Gbs_Emu* this, addr_t addr ); |
190 | void Write_mem( struct Gbs_Emu* this, addr_t addr, int data ); | 182 | void write_mem( struct Gbs_Emu* this, addr_t addr, int data ); |
191 | 183 | ||
192 | // Current time | 184 | // Current time |
193 | static inline blip_time_t Time( struct Gbs_Emu* this ) | 185 | static inline blip_time_t Time( struct Gbs_Emu* this ) |
@@ -195,6 +187,6 @@ static inline blip_time_t Time( struct Gbs_Emu* this ) | |||
195 | return Cpu_time( &this->cpu ) + this->end_time; | 187 | return Cpu_time( &this->cpu ) + this->end_time; |
196 | } | 188 | } |
197 | 189 | ||
198 | void Jsr_then_stop( struct Gbs_Emu* this, byte const [] ); | 190 | void jsr_then_stop( struct Gbs_Emu* this, byte const [] ); |
199 | 191 | ||
200 | #endif | 192 | #endif |
diff --git a/apps/codecs/libgme/gme_types.h b/apps/codecs/libgme/gme_types.h deleted file mode 100644 index 06226f4aa1..0000000000 --- a/apps/codecs/libgme/gme_types.h +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | #ifndef GME_TYPES_H | ||
2 | #define GME_TYPES_H | ||
3 | |||
4 | /* | ||
5 | * This is a default gme_types.h for use when *not* using | ||
6 | * CMake. If CMake is in use gme_types.h.in will be | ||
7 | * processed instead. | ||
8 | */ | ||
9 | #define USE_GME_AY | ||
10 | #define USE_GME_GBS | ||
11 | #define USE_GME_GYM | ||
12 | #define USE_GME_HES | ||
13 | #define USE_GME_KSS | ||
14 | #define USE_GME_NSF | ||
15 | #define USE_GME_NSFE | ||
16 | #define USE_GME_SAP | ||
17 | #define USE_GME_SPC | ||
18 | /* VGM and VGZ are a package deal */ | ||
19 | #define USE_GME_VGM | ||
20 | |||
21 | #endif /* GME_TYPES_H */ | ||
diff --git a/apps/codecs/libgme/hes_apu.c b/apps/codecs/libgme/hes_apu.c index 2a831426f5..054b164a9a 100644 --- a/apps/codecs/libgme/hes_apu.c +++ b/apps/codecs/libgme/hes_apu.c | |||
@@ -18,8 +18,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | |||
18 | 18 | ||
19 | enum { center_waves = 1 }; // reduces asymmetry and clamping when starting notes | 19 | enum { center_waves = 1 }; // reduces asymmetry and clamping when starting notes |
20 | 20 | ||
21 | static void Apu_balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc ); | 21 | static void balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc ) |
22 | static void Apu_balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc ) | ||
23 | { | 22 | { |
24 | static short const log_table [32] = { // ~1.5 db per step | 23 | static short const log_table [32] = { // ~1.5 db per step |
25 | #define ENTRY( factor ) (short) (factor * amp_range / 31.0 + 0.5) | 24 | #define ENTRY( factor ) (short) (factor * amp_range / 31.0 + 0.5) |
@@ -42,27 +41,40 @@ static void Apu_balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc ) | |||
42 | int right = vol + (osc->balance << 1 & 0x1E) + (this->balance << 1 & 0x1E); | 41 | int right = vol + (osc->balance << 1 & 0x1E) + (this->balance << 1 & 0x1E); |
43 | if ( right < 0 ) right = 0; | 42 | if ( right < 0 ) right = 0; |
44 | 43 | ||
45 | left = log_table [left ]; | ||
46 | right = log_table [right]; | ||
47 | |||
48 | // optimizing for the common case of being centered also allows easy | 44 | // optimizing for the common case of being centered also allows easy |
49 | // panning using Effects_Buffer | 45 | // panning using Effects_Buffer |
50 | osc->outputs [0] = osc->chans [0]; // center | 46 | |
51 | osc->outputs [1] = 0; | 47 | // Separate balance into center volume and additional on either left or right |
52 | if ( left != right ) | 48 | osc->output [0] = osc->outputs [0]; // center |
49 | osc->output [1] = osc->outputs [2]; // right | ||
50 | int base = log_table [left ]; | ||
51 | int side = log_table [right] - base; | ||
52 | if ( side < 0 ) | ||
53 | { | ||
54 | base += side; | ||
55 | side = -side; | ||
56 | osc->output [1] = osc->outputs [1]; // left | ||
57 | } | ||
58 | |||
59 | // Optimize when output is far left, center, or far right | ||
60 | if ( !base || osc->output [0] == osc->output [1] ) | ||
53 | { | 61 | { |
54 | osc->outputs [0] = osc->chans [1]; // left | 62 | base += side; |
55 | osc->outputs [1] = osc->chans [2]; // right | 63 | side = 0; |
64 | osc->output [0] = osc->output [1]; | ||
65 | osc->output [1] = NULL; | ||
66 | osc->last_amp [1] = 0; | ||
56 | } | 67 | } |
57 | 68 | ||
58 | if ( center_waves ) | 69 | if ( center_waves ) |
59 | { | 70 | { |
60 | osc->last_amp [0] += (left - osc->volume [0]) * 16; | 71 | // TODO: this can leave a non-zero level in a buffer (minor) |
61 | osc->last_amp [1] += (right - osc->volume [1]) * 16; | 72 | osc->last_amp [0] += (base - osc->volume [0]) * 16; |
73 | osc->last_amp [1] += (side - osc->volume [1]) * 16; | ||
62 | } | 74 | } |
63 | 75 | ||
64 | osc->volume [0] = left; | 76 | osc->volume [0] = base; |
65 | osc->volume [1] = right; | 77 | osc->volume [1] = side; |
66 | } | 78 | } |
67 | 79 | ||
68 | void Apu_init( struct Hes_Apu* this ) | 80 | void Apu_init( struct Hes_Apu* this ) |
@@ -71,11 +83,11 @@ void Apu_init( struct Hes_Apu* this ) | |||
71 | do | 83 | do |
72 | { | 84 | { |
73 | osc--; | 85 | osc--; |
74 | osc->outputs [0] = 0; | 86 | osc->output [0] = NULL; |
75 | osc->outputs [1] = 0; | 87 | osc->output [1] = NULL; |
76 | osc->chans [0] = 0; | 88 | osc->outputs [0] = NULL; |
77 | osc->chans [1] = 0; | 89 | osc->outputs [1] = NULL; |
78 | osc->chans [2] = 0; | 90 | osc->outputs [2] = NULL; |
79 | } | 91 | } |
80 | while ( osc != this->oscs ); | 92 | while ( osc != this->oscs ); |
81 | 93 | ||
@@ -92,139 +104,183 @@ void Apu_reset( struct Hes_Apu* this ) | |||
92 | { | 104 | { |
93 | osc--; | 105 | osc--; |
94 | memset( osc, 0, offsetof (struct Hes_Osc,outputs) ); | 106 | memset( osc, 0, offsetof (struct Hes_Osc,outputs) ); |
95 | osc->noise_lfsr = 1; | 107 | osc->lfsr = 1; |
96 | osc->control = 0x40; | 108 | osc->control = 0x40; |
97 | osc->balance = 0xFF; | 109 | osc->balance = 0xFF; |
98 | } | 110 | } |
99 | while ( osc != this->oscs ); | 111 | while ( osc != this->oscs ); |
112 | |||
113 | // Only last two oscs support noise | ||
114 | this->oscs [osc_count - 2].lfsr = 0x200C3; // equivalent to 1 in Fibonacci LFSR | ||
115 | this->oscs [osc_count - 1].lfsr = 0x200C3; | ||
100 | } | 116 | } |
101 | 117 | ||
102 | void Apu_osc_output( struct Hes_Apu* this, int index, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right ) | 118 | void Apu_osc_output( struct Hes_Apu* this, int i, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right ) |
103 | { | 119 | { |
104 | require( (unsigned) index < osc_count ); | 120 | // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL) |
105 | this->oscs [index].chans [0] = center; | 121 | require( !center || (center && !left && !right) || (center && left && right) ); |
106 | this->oscs [index].chans [1] = left; | 122 | require( (unsigned) i < osc_count ); // fails if you pass invalid osc index |
107 | this->oscs [index].chans [2] = right; | ||
108 | 123 | ||
109 | struct Hes_Osc* osc = &this->oscs [osc_count]; | 124 | if ( !center || !left || !right ) |
110 | do | ||
111 | { | 125 | { |
112 | osc--; | 126 | left = center; |
113 | Apu_balance_changed( this, osc ); | 127 | right = center; |
114 | } | 128 | } |
115 | while ( osc != this->oscs ); | 129 | |
130 | struct Hes_Osc* o = &this->oscs [i]; | ||
131 | o->outputs [0] = center; | ||
132 | o->outputs [1] = right; | ||
133 | o->outputs [2] = left; | ||
134 | balance_changed( this, o ); | ||
116 | } | 135 | } |
117 | 136 | ||
118 | void Osc_run_until( struct Hes_Osc* this, struct Blip_Synth* synth_, blip_time_t end_time ) | 137 | void run_osc( struct Hes_Osc* o, struct Blip_Synth* syn, blip_time_t end_time ) |
119 | { | 138 | { |
120 | struct Blip_Buffer* const osc_outputs_0 = this->outputs [0]; // cache often-used values | 139 | int vol0 = o->volume [0]; |
121 | if ( osc_outputs_0 && this->control & 0x80 ) | 140 | int vol1 = o->volume [1]; |
141 | int dac = o->dac; | ||
142 | |||
143 | struct Blip_Buffer* out0 = o->output [0]; // cache often-used values | ||
144 | struct Blip_Buffer* out1 = o->output [1]; | ||
145 | if ( !(o->control & 0x80) ) | ||
146 | out0 = NULL; | ||
147 | |||
148 | if ( out0 ) | ||
122 | { | 149 | { |
123 | int dac = this->dac; | 150 | // Update amplitudes |
124 | 151 | if ( out1 ) | |
125 | int const volume_0 = this->volume [0]; | ||
126 | { | 152 | { |
127 | int delta = dac * volume_0 - this->last_amp [0]; | 153 | int delta = dac * vol1 - o->last_amp [1]; |
128 | if ( delta ) | 154 | if ( delta ) |
129 | Synth_offset( synth_, this->last_time, delta, osc_outputs_0 ); | 155 | { |
130 | Blip_set_modified( osc_outputs_0 ); | 156 | Synth_offset( syn, o->last_time, delta, out1 ); |
157 | Blip_set_modified( out1 ); | ||
158 | } | ||
131 | } | 159 | } |
132 | 160 | int delta = dac * vol0 - o->last_amp [0]; | |
133 | struct Blip_Buffer* const osc_outputs_1 = this->outputs [1]; | 161 | if ( delta ) |
134 | int const volume_1 = this->volume [1]; | ||
135 | if ( osc_outputs_1 ) | ||
136 | { | 162 | { |
137 | int delta = dac * volume_1 - this->last_amp [1]; | 163 | Synth_offset( syn, o->last_time, delta, out0 ); |
138 | if ( delta ) | 164 | Blip_set_modified( out0 ); |
139 | Synth_offset( synth_, this->last_time, delta, osc_outputs_1 ); | ||
140 | Blip_set_modified( osc_outputs_1 ); | ||
141 | } | 165 | } |
142 | 166 | ||
143 | blip_time_t time = this->last_time + this->delay; | 167 | // Don't generate if silent |
168 | if ( !(vol0 | vol1) ) | ||
169 | out0 = NULL; | ||
170 | } | ||
171 | |||
172 | // Generate noise | ||
173 | int noise = 0; | ||
174 | if ( o->lfsr ) | ||
175 | { | ||
176 | noise = o->noise & 0x80; | ||
177 | |||
178 | blip_time_t time = o->last_time + o->noise_delay; | ||
144 | if ( time < end_time ) | 179 | if ( time < end_time ) |
145 | { | 180 | { |
146 | if ( this->noise & 0x80 ) | 181 | int period = (~o->noise & 0x1F) * 128; |
182 | if ( !period ) | ||
183 | period = 64; | ||
184 | |||
185 | if ( noise && out0 ) | ||
147 | { | 186 | { |
148 | if ( volume_0 | volume_1 ) | 187 | unsigned lfsr = o->lfsr; |
188 | do | ||
149 | { | 189 | { |
150 | // noise | 190 | int new_dac = -(lfsr & 1); |
151 | int const period = (32 - (this->noise & 0x1F)) * 64; // TODO: correct? | 191 | lfsr = (lfsr >> 1) ^ (0x30061 & new_dac); |
152 | unsigned noise_lfsr = this->noise_lfsr; | 192 | |
153 | do | 193 | int delta = (new_dac &= 0x1F) - dac; |
194 | if ( delta ) | ||
154 | { | 195 | { |
155 | int new_dac = 0x1F & -(noise_lfsr >> 1 & 1); | 196 | dac = new_dac; |
156 | // Implemented using "Galios configuration" | 197 | Synth_offset( syn, time, delta * vol0, out0 ); |
157 | // TODO: find correct LFSR algorithm | 198 | if ( out1 ) |
158 | noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & -(noise_lfsr & 1)); | 199 | Synth_offset( syn, time, delta * vol1, out1 ); |
159 | //noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1)); | ||
160 | int delta = new_dac - dac; | ||
161 | if ( delta ) | ||
162 | { | ||
163 | dac = new_dac; | ||
164 | Synth_offset( synth_, time, delta * volume_0, osc_outputs_0 ); | ||
165 | if ( osc_outputs_1 ) | ||
166 | Synth_offset( synth_, time, delta * volume_1, osc_outputs_1 ); | ||
167 | } | ||
168 | time += period; | ||
169 | } | 200 | } |
170 | while ( time < end_time ); | 201 | time += period; |
171 | |||
172 | this->noise_lfsr = noise_lfsr; | ||
173 | assert( noise_lfsr ); | ||
174 | } | 202 | } |
175 | } | 203 | while ( time < end_time ); |
176 | else if ( !(this->control & 0x40) ) | 204 | |
177 | { | 205 | if ( !lfsr ) |
178 | // wave | ||
179 | int phase = (this->phase + 1) & 0x1F; // pre-advance for optimal inner loop | ||
180 | int period = this->period * 2; | ||
181 | if ( period >= 14 && (volume_0 | volume_1) ) | ||
182 | { | 206 | { |
183 | do | 207 | lfsr = 1; |
184 | { | 208 | check( false ); |
185 | int new_dac = this->wave [phase]; | ||
186 | phase = (phase + 1) & 0x1F; | ||
187 | int delta = new_dac - dac; | ||
188 | if ( delta ) | ||
189 | { | ||
190 | dac = new_dac; | ||
191 | Synth_offset( synth_, time, delta * volume_0, osc_outputs_0 ); | ||
192 | if ( osc_outputs_1 ) | ||
193 | Synth_offset( synth_, time, delta * volume_1, osc_outputs_1 ); | ||
194 | } | ||
195 | time += period; | ||
196 | } | ||
197 | while ( time < end_time ); | ||
198 | } | 209 | } |
199 | else | 210 | o->lfsr = lfsr; |
211 | |||
212 | Blip_set_modified( out0 ); | ||
213 | if ( out1 ) | ||
214 | Blip_set_modified( out1 ); | ||
215 | } | ||
216 | else | ||
217 | { | ||
218 | // Maintain phase when silent | ||
219 | int count = (end_time - time + period - 1) / period; | ||
220 | time += count * period; | ||
221 | |||
222 | // not worth it | ||
223 | //while ( count-- ) | ||
224 | // o->lfsr = (o->lfsr >> 1) ^ (0x30061 * (o->lfsr & 1)); | ||
225 | } | ||
226 | } | ||
227 | o->noise_delay = time - end_time; | ||
228 | } | ||
229 | |||
230 | // Generate wave | ||
231 | blip_time_t time = o->last_time + o->delay; | ||
232 | if ( time < end_time ) | ||
233 | { | ||
234 | int phase = (o->phase + 1) & 0x1F; // pre-advance for optimal inner loop | ||
235 | int period = o->period * 2; | ||
236 | |||
237 | if ( period >= 14 && out0 && !((o->control & 0x40) | noise) ) | ||
238 | { | ||
239 | do | ||
240 | { | ||
241 | int new_dac = o->wave [phase]; | ||
242 | phase = (phase + 1) & 0x1F; | ||
243 | int delta = new_dac - dac; | ||
244 | if ( delta ) | ||
200 | { | 245 | { |
201 | if ( !period ) | 246 | dac = new_dac; |
202 | { | 247 | Synth_offset( syn, time, delta * vol0, out0 ); |
203 | // TODO: Gekisha Boy assumes that period = 0 silences wave | 248 | if ( out1 ) |
204 | //period = 0x1000 * 2; | 249 | Synth_offset( syn, time, delta * vol1, out1 ); |
205 | period = 1; | ||
206 | //if ( !(volume_0 | volume_1) ) | ||
207 | // dprintf( "Used period 0\n" ); | ||
208 | } | ||
209 | |||
210 | // maintain phase when silent | ||
211 | blargg_long count = (end_time - time + period - 1) / period; | ||
212 | phase += count; // phase will be masked below | ||
213 | time += count * period; | ||
214 | } | 250 | } |
215 | this->phase = (phase - 1) & 0x1F; // undo pre-advance | 251 | time += period; |
216 | } | 252 | } |
253 | while ( time < end_time ); | ||
254 | Blip_set_modified( out0 ); | ||
255 | if ( out1 ) | ||
256 | Blip_set_modified( out1 ); | ||
257 | } | ||
258 | else | ||
259 | { | ||
260 | // Maintain phase when silent | ||
261 | int count = end_time - time; | ||
262 | if ( !period ) | ||
263 | period = 1; | ||
264 | count = (count + period - 1) / period; | ||
265 | |||
266 | phase += count; // phase will be masked below | ||
267 | time += count * period; | ||
217 | } | 268 | } |
218 | time -= end_time; | ||
219 | if ( time < 0 ) | ||
220 | time = 0; | ||
221 | this->delay = time; | ||
222 | 269 | ||
223 | this->dac = dac; | 270 | // TODO: Find whether phase increments even when both volumes are zero. |
224 | this->last_amp [0] = dac * volume_0; | 271 | // CAN'T simply check for out0 being non-NULL, since it could be NULL |
225 | this->last_amp [1] = dac * volume_1; | 272 | // if channel is muted in player, but still has non-zero volume. |
273 | // City Hunter breaks when this check is removed. | ||
274 | if ( !(o->control & 0x40) && (vol0 | vol1) ) | ||
275 | o->phase = (phase - 1) & 0x1F; // undo pre-advance | ||
226 | } | 276 | } |
227 | this->last_time = end_time; | 277 | o->delay = time - end_time; |
278 | check( o->delay >= 0 ); | ||
279 | |||
280 | o->last_time = end_time; | ||
281 | o->dac = dac; | ||
282 | o->last_amp [0] = dac * vol0; | ||
283 | o->last_amp [1] = dac * vol1; | ||
228 | } | 284 | } |
229 | 285 | ||
230 | void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data ) | 286 | void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data ) |
@@ -243,8 +299,8 @@ void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data | |||
243 | do | 299 | do |
244 | { | 300 | { |
245 | osc--; | 301 | osc--; |
246 | Osc_run_until( osc, &this->synth, time ); | 302 | run_osc( osc, &this->synth, time ); |
247 | Apu_balance_changed( this, this->oscs ); | 303 | balance_changed( this, this->oscs ); |
248 | } | 304 | } |
249 | while ( osc != this->oscs ); | 305 | while ( osc != this->oscs ); |
250 | } | 306 | } |
@@ -252,7 +308,7 @@ void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data | |||
252 | else if ( this->latch < osc_count ) | 308 | else if ( this->latch < osc_count ) |
253 | { | 309 | { |
254 | struct Hes_Osc* osc = &this->oscs [this->latch]; | 310 | struct Hes_Osc* osc = &this->oscs [this->latch]; |
255 | Osc_run_until( osc, &this->synth, time ); | 311 | run_osc( osc, &this->synth, time ); |
256 | switch ( addr ) | 312 | switch ( addr ) |
257 | { | 313 | { |
258 | case 0x802: | 314 | case 0x802: |
@@ -267,12 +323,12 @@ void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data | |||
267 | if ( osc->control & 0x40 & ~data ) | 323 | if ( osc->control & 0x40 & ~data ) |
268 | osc->phase = 0; | 324 | osc->phase = 0; |
269 | osc->control = data; | 325 | osc->control = data; |
270 | Apu_balance_changed( this, osc ); | 326 | balance_changed( this, osc ); |
271 | break; | 327 | break; |
272 | 328 | ||
273 | case 0x805: | 329 | case 0x805: |
274 | osc->balance = data; | 330 | osc->balance = data; |
275 | Apu_balance_changed( this, osc ); | 331 | balance_changed( this, osc ); |
276 | break; | 332 | break; |
277 | 333 | ||
278 | case 0x806: | 334 | case 0x806: |
@@ -289,9 +345,9 @@ void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data | |||
289 | break; | 345 | break; |
290 | 346 | ||
291 | case 0x807: | 347 | case 0x807: |
292 | if ( osc >= &this->oscs [4] ) | 348 | osc->noise = data; |
293 | osc->noise = data; | ||
294 | break; | 349 | break; |
350 | |||
295 | case 0x809: | 351 | case 0x809: |
296 | if ( !(data & 0x80) && (data & 0x03) != 0 ) { | 352 | if ( !(data & 0x80) && (data & 0x03) != 0 ) { |
297 | dprintf( "HES LFO not supported\n" ); | 353 | dprintf( "HES LFO not supported\n" ); |
@@ -307,7 +363,7 @@ void Apu_end_frame( struct Hes_Apu* this, blip_time_t end_time ) | |||
307 | { | 363 | { |
308 | osc--; | 364 | osc--; |
309 | if ( end_time > osc->last_time ) | 365 | if ( end_time > osc->last_time ) |
310 | Osc_run_until( osc, &this->synth, end_time ); | 366 | run_osc( osc, &this->synth, end_time ); |
311 | assert( osc->last_time >= end_time ); | 367 | assert( osc->last_time >= end_time ); |
312 | osc->last_time -= end_time; | 368 | osc->last_time -= end_time; |
313 | } | 369 | } |
diff --git a/apps/codecs/libgme/hes_apu.h b/apps/codecs/libgme/hes_apu.h index 8f8a525108..0265e6a3ad 100644 --- a/apps/codecs/libgme/hes_apu.h +++ b/apps/codecs/libgme/hes_apu.h | |||
@@ -5,40 +5,46 @@ | |||
5 | #define HES_APU_H | 5 | #define HES_APU_H |
6 | 6 | ||
7 | #include "blargg_common.h" | 7 | #include "blargg_common.h" |
8 | #include "blargg_source.h" | ||
8 | #include "blip_buffer.h" | 9 | #include "blip_buffer.h" |
9 | 10 | ||
10 | enum { amp_range = 0x8000 }; | 11 | enum { amp_range = 0x8000 }; |
11 | enum { osc_count = 6 }; | 12 | enum { osc_count = 6 }; // 0 <= chan < osc_count |
12 | enum { start_addr = 0x0800 }; | 13 | |
13 | enum { end_addr = 0x0809 }; | 14 | // Registers are at io_addr to io_addr+io_size-1 |
15 | enum { apu_io_addr = 0x0800 }; | ||
16 | enum { apu_io_size = 10 }; | ||
14 | 17 | ||
15 | struct Hes_Osc | 18 | struct Hes_Osc |
16 | { | 19 | { |
17 | unsigned char wave [32]; | 20 | byte wave [32]; |
21 | int delay; | ||
22 | int period; | ||
23 | int phase; | ||
24 | |||
25 | int noise_delay; | ||
26 | byte noise; | ||
27 | unsigned lfsr; | ||
28 | |||
29 | byte control; | ||
30 | byte balance; | ||
31 | byte dac; | ||
18 | short volume [2]; | 32 | short volume [2]; |
19 | int last_amp [2]; | 33 | int last_amp [2]; |
20 | int delay; | ||
21 | int period; | ||
22 | unsigned char noise; | ||
23 | unsigned char phase; | ||
24 | unsigned char balance; | ||
25 | unsigned char dac; | ||
26 | blip_time_t last_time; | ||
27 | 34 | ||
28 | struct Blip_Buffer* outputs [2]; | 35 | blip_time_t last_time; |
29 | struct Blip_Buffer* chans [3]; | 36 | struct Blip_Buffer* output [2]; |
30 | unsigned noise_lfsr; | 37 | struct Blip_Buffer* outputs [3]; |
31 | unsigned char control; | ||
32 | }; | 38 | }; |
33 | 39 | ||
34 | void Osc_run_until( struct Hes_Osc* this, struct Blip_Synth* synth, blip_time_t ); | 40 | void Osc_run_until( struct Hes_Osc* this, struct Blip_Synth* synth, blip_time_t ); |
35 | 41 | ||
36 | struct Hes_Apu { | 42 | struct Hes_Apu { |
37 | struct Hes_Osc oscs [osc_count]; | ||
38 | 43 | ||
39 | int latch; | 44 | int latch; |
40 | int balance; | 45 | int balance; |
41 | struct Blip_Synth synth; | 46 | struct Blip_Synth synth; |
47 | struct Hes_Osc oscs [osc_count]; | ||
42 | }; | 48 | }; |
43 | 49 | ||
44 | // Init HES apu sound chip | 50 | // Init HES apu sound chip |
@@ -48,7 +54,12 @@ void Apu_init( struct Hes_Apu* this ); | |||
48 | void Apu_reset( struct Hes_Apu* this ); | 54 | void Apu_reset( struct Hes_Apu* this ); |
49 | 55 | ||
50 | void Apu_osc_output( struct Hes_Apu* this, int index, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right ); | 56 | void Apu_osc_output( struct Hes_Apu* this, int index, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right ); |
57 | |||
58 | // Emulates to time t, then writes data to addr | ||
51 | void Apu_write_data( struct Hes_Apu* this, blip_time_t, int addr, int data ); | 59 | void Apu_write_data( struct Hes_Apu* this, blip_time_t, int addr, int data ); |
60 | |||
61 | // Emulates to time t, then subtracts t from the current time. | ||
62 | // OK if previous write call had time slightly after t. | ||
52 | void Apu_end_frame( struct Hes_Apu* this, blip_time_t ); | 63 | void Apu_end_frame( struct Hes_Apu* this, blip_time_t ); |
53 | 64 | ||
54 | static inline void Apu_volume( struct Hes_Apu* this, int v ) { Synth_volume( &this->synth, (v*9)/5 / osc_count / amp_range ); } | 65 | static inline void Apu_volume( struct Hes_Apu* this, int v ) { Synth_volume( &this->synth, (v*9)/5 / osc_count / amp_range ); } |
diff --git a/apps/codecs/libgme/hes_apu_adpcm.h b/apps/codecs/libgme/hes_apu_adpcm.h index 4a2afb3e2a..afe160bb9c 100644 --- a/apps/codecs/libgme/hes_apu_adpcm.h +++ b/apps/codecs/libgme/hes_apu_adpcm.h | |||
@@ -12,8 +12,8 @@ enum { adpcm_amp_range = 2048 }; | |||
12 | enum { adpcm_osc_count = 1 }; // 0 <= chan < osc_count | 12 | enum { adpcm_osc_count = 1 }; // 0 <= chan < osc_count |
13 | 13 | ||
14 | // Registers are at io_addr to io_addr+io_size-1 | 14 | // Registers are at io_addr to io_addr+io_size-1 |
15 | enum { io_addr = 0x1800 }; | 15 | enum { adpcm_io_addr = 0x1800 }; |
16 | enum { io_size = 0x400 }; | 16 | enum { adpcm_io_size = 0x400 }; |
17 | 17 | ||
18 | struct State | 18 | struct State |
19 | { | 19 | { |
diff --git a/apps/codecs/libgme/hes_cpu.c b/apps/codecs/libgme/hes_cpu.c index 74b90593f2..6b833b3b98 100644 --- a/apps/codecs/libgme/hes_cpu.c +++ b/apps/codecs/libgme/hes_cpu.c | |||
@@ -1,6 +1,6 @@ | |||
1 | // Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ | 1 | // Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ |
2 | 2 | ||
3 | #include "hes_cpu.h" | 3 | #include "hes_emu.h" |
4 | 4 | ||
5 | #include "blargg_endian.h" | 5 | #include "blargg_endian.h" |
6 | 6 | ||
@@ -17,1305 +17,105 @@ details. You should have received a copy of the GNU Lesser General Public | |||
17 | License along with this module; if not, write to the Free Software Foundation, | 17 | License along with this module; if not, write to the Free Software Foundation, |
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | 18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
19 | 19 | ||
20 | // TODO: support T flag, including clearing it at appropriate times? | ||
21 | |||
22 | // all zero-page should really use whatever is at page 1, but that would | ||
23 | // reduce efficiency quite a bit | ||
24 | int const ram_addr = 0x2000; | ||
25 | |||
26 | #define FLUSH_TIME() (void) (s.time = s_time) | ||
27 | #define CACHE_TIME() (void) (s_time = s.time) | ||
28 | |||
29 | #include "hes_cpu_io.h" | ||
30 | |||
31 | #include "blargg_source.h" | 20 | #include "blargg_source.h" |
21 | #define PAGE HES_CPU_PAGE | ||
32 | 22 | ||
33 | #ifdef BLARGG_NONPORTABLE | 23 | int read_mem( struct Hes_Emu* this, hes_addr_t addr ) |
34 | #define PAGE_OFFSET( addr ) (addr) | ||
35 | #else | ||
36 | #define PAGE_OFFSET( addr ) ((addr) & (page_size - 1)) | ||
37 | #endif | ||
38 | |||
39 | // status flags | ||
40 | int const st_n = 0x80; | ||
41 | int const st_v = 0x40; | ||
42 | int const st_t = 0x20; | ||
43 | int const st_b = 0x10; | ||
44 | int const st_d = 0x08; | ||
45 | int const st_i = 0x04; | ||
46 | int const st_z = 0x02; | ||
47 | int const st_c = 0x01; | ||
48 | |||
49 | void Cpu_init( struct Hes_Cpu* this ) | ||
50 | { | 24 | { |
51 | this->state = &this->state_; | 25 | check( addr < 0x10000 ); |
26 | int result = *Cpu_get_code( &this->cpu, addr ); | ||
27 | if ( this->cpu.mmr [PAGE( addr )] == 0xFF ) | ||
28 | result = read_mem_( this, addr ); | ||
29 | return result; | ||
52 | } | 30 | } |
53 | 31 | ||
54 | void Cpu_reset( struct Hes_Cpu* this ) | 32 | void write_mem( struct Hes_Emu* this, hes_addr_t addr, int data ) |
55 | { | 33 | { |
56 | check( this->state == &state_ ); | 34 | check( addr < 0x10000 ); |
57 | this->state = &this->state_; | 35 | byte* out = this->write_pages [PAGE( addr )]; |
58 | 36 | if ( out ) | |
59 | this->state_.time = 0; | 37 | out [addr & (page_size - 1)] = data; |
60 | this->state_.base = 0; | 38 | else if ( this->cpu.mmr [PAGE( addr )] == 0xFF ) |
61 | this->irq_time = (hes_time_t)future_hes_time; | 39 | write_mem_( this, addr, data ); |
62 | this->end_time = (hes_time_t)future_hes_time; | ||
63 | |||
64 | this->r.status = st_i; | ||
65 | this->r.sp = 0; | ||
66 | this->r.pc = 0; | ||
67 | this->r.a = 0; | ||
68 | this->r.x = 0; | ||
69 | this->r.y = 0; | ||
70 | |||
71 | blargg_verify_byte_order(); | ||
72 | } | 40 | } |
73 | 41 | ||
74 | void Cpu_set_mmr( struct Hes_Emu* this, int reg, int bank ) | 42 | void set_mmr( struct Hes_Emu* this, int page, int bank ) |
75 | { | 43 | { |
76 | assert( (unsigned) reg <= page_count ); // allow page past end to be set | 44 | this->write_pages [page] = 0; |
77 | assert( (unsigned) bank < 0x100 ); | 45 | byte* data = Rom_at_addr( &this->rom, bank * page_size ); |
78 | this->cpu.mmr [reg] = bank; | 46 | if ( bank >= 0x80 ) |
79 | uint8_t const* code = CPU_SET_MMR( this, reg, bank ); | ||
80 | this->cpu.state->code_map [reg] = code - PAGE_OFFSET( reg << page_shift ); | ||
81 | } | ||
82 | |||
83 | #define TIME (s_time + s.base) | ||
84 | |||
85 | #define READ( addr ) CPU_READ( this, (addr), TIME ) | ||
86 | #define WRITE( addr, data ) {CPU_WRITE( this, (addr), (data), TIME );} | ||
87 | #define READ_LOW( addr ) (cpu->ram [(int) (addr)]) | ||
88 | #define WRITE_LOW( addr, data ) (void) (READ_LOW( addr ) = (data)) | ||
89 | #define READ_PROG( addr ) (s.code_map [(addr) >> page_shift] [PAGE_OFFSET( addr )]) | ||
90 | |||
91 | #define SET_SP( v ) (sp = ((v) + 1) | 0x100) | ||
92 | #define GET_SP() ((sp - 1) & 0xFF) | ||
93 | #define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v )) | ||
94 | |||
95 | // even on x86, using short and unsigned char was slower | ||
96 | typedef int fint16; | ||
97 | typedef unsigned fuint16; | ||
98 | typedef unsigned fuint8; | ||
99 | typedef blargg_long fint32; | ||
100 | |||
101 | bool Cpu_run( struct Hes_Emu* this, hes_time_t end_time ) | ||
102 | { | ||
103 | bool illegal_encountered = false; | ||
104 | |||
105 | // Set cpu end time | ||
106 | struct Hes_Cpu* cpu = &this->cpu; | ||
107 | cpu->state->time += Cpu_update_end_time( cpu, cpu->r.status, (cpu->end_time = end_time), cpu->irq_time ); | ||
108 | |||
109 | struct state_t s = cpu->state_; | ||
110 | cpu->state = &s; | ||
111 | |||
112 | // even on x86, using s.time in place of s_time was slower | ||
113 | fint16 s_time = s.time; | ||
114 | |||
115 | struct registers_t* r = &cpu->r; | ||
116 | |||
117 | // registers | ||
118 | fuint16 pc = r->pc; | ||
119 | fuint8 a = r->a; | ||
120 | fuint8 x = r->x; | ||
121 | fuint8 y = r->y; | ||
122 | fuint16 sp; | ||
123 | SET_SP( r->sp ); | ||
124 | |||
125 | #define IS_NEG (nz & 0x8080) | ||
126 | |||
127 | #define CALC_STATUS( out ) do {\ | ||
128 | out = status & (st_v | st_d | st_i);\ | ||
129 | out |= ((nz >> 8) | nz) & st_n;\ | ||
130 | out |= c >> 8 & st_c;\ | ||
131 | if ( !(nz & 0xFF) ) out |= st_z;\ | ||
132 | } while ( 0 ) | ||
133 | |||
134 | #define SET_STATUS( in ) do {\ | ||
135 | status = in & (st_v | st_d | st_i);\ | ||
136 | nz = in << 8;\ | ||
137 | c = nz;\ | ||
138 | nz |= ~in & st_z;\ | ||
139 | } while ( 0 ) | ||
140 | |||
141 | fuint8 status; | ||
142 | fuint16 c; // carry set if (c & 0x100) != 0 | ||
143 | fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 | ||
144 | { | ||
145 | fuint8 temp = r->status; | ||
146 | SET_STATUS( temp ); | ||
147 | } | ||
148 | |||
149 | goto loop; | ||
150 | branch_not_taken: | ||
151 | s_time -= 2; | ||
152 | loop: | ||
153 | |||
154 | #ifndef NDEBUG | ||
155 | { | ||
156 | hes_time_t correct = end_time_; | ||
157 | if ( !(status & st_i) && correct > irq_time_ ) | ||
158 | correct = irq_time_; | ||
159 | check( s.base == correct ); | ||
160 | /* | ||
161 | static long count; | ||
162 | if ( count == 1844 ) Debugger(); | ||
163 | if ( s.base != correct ) dprintf( "%ld\n", count ); | ||
164 | count++; | ||
165 | */ | ||
166 | } | ||
167 | #endif | ||
168 | |||
169 | check( (unsigned) GET_SP() < 0x100 ); | ||
170 | check( (unsigned) a < 0x100 ); | ||
171 | check( (unsigned) x < 0x100 ); | ||
172 | |||
173 | uint8_t const* instr = s.code_map [pc >> page_shift]; | ||
174 | fuint8 opcode; | ||
175 | |||
176 | // TODO: eliminate this special case | ||
177 | #ifdef BLARGG_NONPORTABLE | ||
178 | opcode = instr [pc]; | ||
179 | pc++; | ||
180 | instr += pc; | ||
181 | #else | ||
182 | instr += PAGE_OFFSET( pc ); | ||
183 | opcode = *instr++; | ||
184 | pc++; | ||
185 | #endif | ||
186 | |||
187 | // TODO: each reference lists slightly different timing values, ugh | ||
188 | static uint8_t const clock_table [256] = | ||
189 | {// 0 1 2 3 4 5 6 7 8 9 A B C D E F | ||
190 | 1,7,3, 4,6,4,6,7,3,2,2,2,7,5,7,6,// 0 | ||
191 | 4,7,7, 4,6,4,6,7,2,5,2,2,7,5,7,6,// 1 | ||
192 | 7,7,3, 4,4,4,6,7,4,2,2,2,5,5,7,6,// 2 | ||
193 | 4,7,7, 2,4,4,6,7,2,5,2,2,5,5,7,6,// 3 | ||
194 | 7,7,3, 4,8,4,6,7,3,2,2,2,4,5,7,6,// 4 | ||
195 | 4,7,7, 5,2,4,6,7,2,5,3,2,2,5,7,6,// 5 | ||
196 | 7,7,2, 2,4,4,6,7,4,2,2,2,7,5,7,6,// 6 | ||
197 | 4,7,7,17,4,4,6,7,2,5,4,2,7,5,7,6,// 7 | ||
198 | 4,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,6,// 8 | ||
199 | 4,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,6,// 9 | ||
200 | 2,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,6,// A | ||
201 | 4,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,6,// B | ||
202 | 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,6,// C | ||
203 | 4,7,7,17,2,4,6,7,2,5,3,2,2,5,7,6,// D | ||
204 | 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,6,// E | ||
205 | 4,7,7,17,2,4,6,7,2,5,4,2,2,5,7,6 // F | ||
206 | }; // 0x00 was 8 | ||
207 | |||
208 | fuint16 data; | ||
209 | data = clock_table [opcode]; | ||
210 | if ( (s_time += data) >= 0 ) | ||
211 | goto possibly_out_of_time; | ||
212 | almost_out_of_time: | ||
213 | |||
214 | data = *instr; | ||
215 | |||
216 | #ifdef HES_CPU_LOG_H | ||
217 | log_cpu( "new", pc - 1, opcode, instr [0], instr [1], instr [2], | ||
218 | instr [3], instr [4], instr [5] ); | ||
219 | //log_opcode( opcode ); | ||
220 | #endif | ||
221 | |||
222 | switch ( opcode ) | ||
223 | { | ||
224 | possibly_out_of_time: | ||
225 | if ( s_time < (int) data ) | ||
226 | goto almost_out_of_time; | ||
227 | s_time -= data; | ||
228 | goto out_of_time; | ||
229 | |||
230 | // Macros | ||
231 | |||
232 | #define GET_MSB() (instr [1]) | ||
233 | #define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()); | ||
234 | #define GET_ADDR() GET_LE16( instr ) | ||
235 | |||
236 | // TODO: is the penalty really always added? the original 6502 was much better | ||
237 | //#define PAGE_CROSS_PENALTY( lsb ) (void) (s_time += (lsb) >> 8) | ||
238 | #define PAGE_CROSS_PENALTY( lsb ) | ||
239 | |||
240 | // Branch | ||
241 | |||
242 | // TODO: more efficient way to handle negative branch that wraps PC around | ||
243 | #define BRANCH( cond )\ | ||
244 | {\ | ||
245 | fint16 offset = (int8_t) data;\ | ||
246 | pc++;\ | ||
247 | if ( !(cond) ) goto branch_not_taken;\ | ||
248 | pc = (uint16_t) (pc + offset);\ | ||
249 | goto loop;\ | ||
250 | } | ||
251 | |||
252 | case 0xF0: // BEQ | ||
253 | BRANCH( !((uint8_t) nz) ); | ||
254 | |||
255 | case 0xD0: // BNE | ||
256 | BRANCH( (uint8_t) nz ); | ||
257 | |||
258 | case 0x10: // BPL | ||
259 | BRANCH( !IS_NEG ); | ||
260 | |||
261 | case 0x90: // BCC | ||
262 | BRANCH( !(c & 0x100) ) | ||
263 | |||
264 | case 0x30: // BMI | ||
265 | BRANCH( IS_NEG ) | ||
266 | |||
267 | case 0x50: // BVC | ||
268 | BRANCH( !(status & st_v) ) | ||
269 | |||
270 | case 0x70: // BVS | ||
271 | BRANCH( status & st_v ) | ||
272 | |||
273 | case 0xB0: // BCS | ||
274 | BRANCH( c & 0x100 ) | ||
275 | |||
276 | case 0x80: // BRA | ||
277 | branch_taken: | ||
278 | BRANCH( true ); | ||
279 | |||
280 | case 0xFF: | ||
281 | if ( pc == idle_addr + 1 ) | ||
282 | goto idle_done; | ||
283 | case 0x0F: // BBRn | ||
284 | case 0x1F: | ||
285 | case 0x2F: | ||
286 | case 0x3F: | ||
287 | case 0x4F: | ||
288 | case 0x5F: | ||
289 | case 0x6F: | ||
290 | case 0x7F: | ||
291 | case 0x8F: // BBSn | ||
292 | case 0x9F: | ||
293 | case 0xAF: | ||
294 | case 0xBF: | ||
295 | case 0xCF: | ||
296 | case 0xDF: | ||
297 | case 0xEF: { | ||
298 | fuint16 t = 0x101 * READ_LOW( data ); | ||
299 | t ^= 0xFF; | ||
300 | pc++; | ||
301 | data = GET_MSB(); | ||
302 | BRANCH( t & (1 << (opcode >> 4)) ) | ||
303 | } | ||
304 | |||
305 | case 0x4C: // JMP abs | ||
306 | pc = GET_ADDR(); | ||
307 | goto loop; | ||
308 | |||
309 | case 0x7C: // JMP (ind+X) | ||
310 | data += x; | ||
311 | case 0x6C:{// JMP (ind) | ||
312 | data += 0x100 * GET_MSB(); | ||
313 | pc = GET_LE16( &READ_PROG( data ) ); | ||
314 | goto loop; | ||
315 | } | ||
316 | |||
317 | // Subroutine | ||
318 | |||
319 | case 0x44: // BSR | ||
320 | WRITE_LOW( 0x100 | (sp - 1), pc >> 8 ); | ||
321 | sp = (sp - 2) | 0x100; | ||
322 | WRITE_LOW( sp, pc ); | ||
323 | goto branch_taken; | ||
324 | |||
325 | case 0x20: { // JSR | ||
326 | fuint16 temp = pc + 1; | ||
327 | pc = GET_ADDR(); | ||
328 | WRITE_LOW( 0x100 | (sp - 1), temp >> 8 ); | ||
329 | sp = (sp - 2) | 0x100; | ||
330 | WRITE_LOW( sp, temp ); | ||
331 | goto loop; | ||
332 | } | ||
333 | |||
334 | case 0x60: // RTS | ||
335 | pc = 0x100 * READ_LOW( 0x100 | (sp - 0xFF) ); | ||
336 | pc += 1 + READ_LOW( sp ); | ||
337 | sp = (sp - 0xFE) | 0x100; | ||
338 | goto loop; | ||
339 | |||
340 | case 0x00: // BRK | ||
341 | goto handle_brk; | ||
342 | |||
343 | // Common | ||
344 | |||
345 | case 0xBD:{// LDA abs,X | ||
346 | PAGE_CROSS_PENALTY( data + x ); | ||
347 | fuint16 addr = GET_ADDR() + x; | ||
348 | pc += 2; | ||
349 | CPU_READ_FAST( this, addr, TIME, nz ); | ||
350 | a = nz; | ||
351 | goto loop; | ||
352 | } | ||
353 | |||
354 | case 0x9D:{// STA abs,X | ||
355 | fuint16 addr = GET_ADDR() + x; | ||
356 | pc += 2; | ||
357 | CPU_WRITE_FAST( this, addr, a, TIME ); | ||
358 | goto loop; | ||
359 | } | ||
360 | |||
361 | case 0x95: // STA zp,x | ||
362 | data = (uint8_t) (data + x); | ||
363 | case 0x85: // STA zp | ||
364 | pc++; | ||
365 | WRITE_LOW( data, a ); | ||
366 | goto loop; | ||
367 | |||
368 | case 0xAE:{// LDX abs | ||
369 | fuint16 addr = GET_ADDR(); | ||
370 | pc += 2; | ||
371 | CPU_READ_FAST( this, addr, TIME, nz ); | ||
372 | x = nz; | ||
373 | goto loop; | ||
374 | } | ||
375 | |||
376 | case 0xA5: // LDA zp | ||
377 | a = nz = READ_LOW( data ); | ||
378 | pc++; | ||
379 | goto loop; | ||
380 | |||
381 | // Load/store | ||
382 | |||
383 | { | 47 | { |
384 | fuint16 addr; | 48 | data = 0; |
385 | case 0x91: // STA (ind),Y | 49 | switch ( bank ) |
386 | addr = 0x100 * READ_LOW( (uint8_t) (data + 1) ); | 50 | { |
387 | addr += READ_LOW( data ) + y; | 51 | case 0xF8: |
388 | pc++; | 52 | data = this->ram; |
389 | goto sta_ptr; | 53 | break; |
390 | |||
391 | case 0x81: // STA (ind,X) | ||
392 | data = (uint8_t) (data + x); | ||
393 | case 0x92: // STA (ind) | ||
394 | addr = 0x100 * READ_LOW( (uint8_t) (data + 1) ); | ||
395 | addr += READ_LOW( data ); | ||
396 | pc++; | ||
397 | goto sta_ptr; | ||
398 | |||
399 | case 0x99: // STA abs,Y | ||
400 | data += y; | ||
401 | case 0x8D: // STA abs | ||
402 | addr = data + 0x100 * GET_MSB(); | ||
403 | pc += 2; | ||
404 | sta_ptr: | ||
405 | CPU_WRITE_FAST( this, addr, a, TIME ); | ||
406 | goto loop; | ||
407 | } | ||
408 | |||
409 | { | ||
410 | fuint16 addr; | ||
411 | case 0xA1: // LDA (ind,X) | ||
412 | data = (uint8_t) (data + x); | ||
413 | case 0xB2: // LDA (ind) | ||
414 | addr = 0x100 * READ_LOW( (uint8_t) (data + 1) ); | ||
415 | addr += READ_LOW( data ); | ||
416 | pc++; | ||
417 | goto a_nz_read_addr; | ||
418 | |||
419 | case 0xB1:// LDA (ind),Y | ||
420 | addr = READ_LOW( data ) + y; | ||
421 | PAGE_CROSS_PENALTY( addr ); | ||
422 | addr += 0x100 * READ_LOW( (uint8_t) (data + 1) ); | ||
423 | pc++; | ||
424 | goto a_nz_read_addr; | ||
425 | |||
426 | case 0xB9: // LDA abs,Y | ||
427 | data += y; | ||
428 | PAGE_CROSS_PENALTY( data ); | ||
429 | case 0xAD: // LDA abs | ||
430 | addr = data + 0x100 * GET_MSB(); | ||
431 | pc += 2; | ||
432 | a_nz_read_addr: | ||
433 | CPU_READ_FAST( this, addr, TIME, nz ); | ||
434 | a = nz; | ||
435 | goto loop; | ||
436 | } | ||
437 | |||
438 | case 0xBE:{// LDX abs,y | ||
439 | PAGE_CROSS_PENALTY( data + y ); | ||
440 | fuint16 addr = GET_ADDR() + y; | ||
441 | pc += 2; | ||
442 | FLUSH_TIME(); | ||
443 | x = nz = READ( addr ); | ||
444 | CACHE_TIME(); | ||
445 | goto loop; | ||
446 | } | ||
447 | |||
448 | case 0xB5: // LDA zp,x | ||
449 | a = nz = READ_LOW( (uint8_t) (data + x) ); | ||
450 | pc++; | ||
451 | goto loop; | ||
452 | |||
453 | case 0xA9: // LDA #imm | ||
454 | pc++; | ||
455 | a = data; | ||
456 | nz = data; | ||
457 | goto loop; | ||
458 | |||
459 | // Bit operations | ||
460 | |||
461 | case 0x3C: // BIT abs,x | ||
462 | data += x; | ||
463 | case 0x2C:{// BIT abs | ||
464 | fuint16 addr; | ||
465 | ADD_PAGE( addr ); | ||
466 | FLUSH_TIME(); | ||
467 | nz = READ( addr ); | ||
468 | CACHE_TIME(); | ||
469 | goto bit_common; | ||
470 | } | ||
471 | case 0x34: // BIT zp,x | ||
472 | data = (uint8_t) (data + x); | ||
473 | case 0x24: // BIT zp | ||
474 | data = READ_LOW( data ); | ||
475 | case 0x89: // BIT imm | ||
476 | nz = data; | ||
477 | bit_common: | ||
478 | pc++; | ||
479 | status &= ~st_v; | ||
480 | status |= nz & st_v; | ||
481 | if ( nz & a ) | ||
482 | goto loop; // Z should be clear, and nz must be non-zero if nz & a is | ||
483 | nz <<= 8; // set Z flag without affecting N flag | ||
484 | goto loop; | ||
485 | 54 | ||
486 | { | 55 | case 0xF9: |
487 | fuint16 addr; | 56 | case 0xFA: |
57 | case 0xFB: | ||
58 | data = &this->sgx [(bank - 0xF9) * page_size]; | ||
59 | break; | ||
488 | 60 | ||
489 | case 0xB3: // TST abs,x | 61 | default: |
490 | addr = GET_MSB() + x; | 62 | /* if ( bank != 0xFF ) |
491 | goto tst_abs; | 63 | dprintf( "Unmapped bank $%02X\n", bank ); */ |
492 | 64 | data = this->rom.unmapped; | |
493 | case 0x93: // TST abs | 65 | goto end; |
494 | addr = GET_MSB(); | 66 | } |
495 | tst_abs: | 67 | |
496 | addr += 0x100 * instr [2]; | 68 | this->write_pages [page] = data; |
497 | pc++; | ||
498 | FLUSH_TIME(); | ||
499 | nz = READ( addr ); | ||
500 | CACHE_TIME(); | ||
501 | goto tst_common; | ||
502 | } | ||
503 | |||
504 | case 0xA3: // TST zp,x | ||
505 | nz = READ_LOW( (uint8_t) (GET_MSB() + x) ); | ||
506 | goto tst_common; | ||
507 | |||
508 | case 0x83: // TST zp | ||
509 | nz = READ_LOW( GET_MSB() ); | ||
510 | tst_common: | ||
511 | pc += 2; | ||
512 | status &= ~st_v; | ||
513 | status |= nz & st_v; | ||
514 | if ( nz & data ) | ||
515 | goto loop; // Z should be clear, and nz must be non-zero if nz & data is | ||
516 | nz <<= 8; // set Z flag without affecting N flag | ||
517 | goto loop; | ||
518 | |||
519 | { | ||
520 | fuint16 addr; | ||
521 | case 0x0C: // TSB abs | ||
522 | case 0x1C: // TRB abs | ||
523 | addr = GET_ADDR(); | ||
524 | pc++; | ||
525 | goto txb_addr; | ||
526 | |||
527 | // TODO: everyone lists different behaviors for the status flags, ugh | ||
528 | case 0x04: // TSB zp | ||
529 | case 0x14: // TRB zp | ||
530 | addr = data + ram_addr; | ||
531 | txb_addr: | ||
532 | FLUSH_TIME(); | ||
533 | nz = a | READ( addr ); | ||
534 | if ( opcode & 0x10 ) | ||
535 | nz ^= a; // bits from a will already be set, so this clears them | ||
536 | status &= ~st_v; | ||
537 | status |= nz & st_v; | ||
538 | pc++; | ||
539 | WRITE( addr, nz ); | ||
540 | CACHE_TIME(); | ||
541 | goto loop; | ||
542 | } | ||
543 | |||
544 | case 0x07: // RMBn | ||
545 | case 0x17: | ||
546 | case 0x27: | ||
547 | case 0x37: | ||
548 | case 0x47: | ||
549 | case 0x57: | ||
550 | case 0x67: | ||
551 | case 0x77: | ||
552 | pc++; | ||
553 | READ_LOW( data ) &= ~(1 << (opcode >> 4)); | ||
554 | goto loop; | ||
555 | |||
556 | case 0x87: // SMBn | ||
557 | case 0x97: | ||
558 | case 0xA7: | ||
559 | case 0xB7: | ||
560 | case 0xC7: | ||
561 | case 0xD7: | ||
562 | case 0xE7: | ||
563 | case 0xF7: | ||
564 | pc++; | ||
565 | READ_LOW( data ) |= 1 << ((opcode >> 4) - 8); | ||
566 | goto loop; | ||
567 | |||
568 | // Load/store | ||
569 | |||
570 | case 0x9E: // STZ abs,x | ||
571 | data += x; | ||
572 | case 0x9C: // STZ abs | ||
573 | ADD_PAGE( data ); | ||
574 | pc++; | ||
575 | FLUSH_TIME(); | ||
576 | WRITE( data, 0 ); | ||
577 | CACHE_TIME(); | ||
578 | goto loop; | ||
579 | |||
580 | case 0x74: // STZ zp,x | ||
581 | data = (uint8_t) (data + x); | ||
582 | case 0x64: // STZ zp | ||
583 | pc++; | ||
584 | WRITE_LOW( data, 0 ); | ||
585 | goto loop; | ||
586 | |||
587 | case 0x94: // STY zp,x | ||
588 | data = (uint8_t) (data + x); | ||
589 | case 0x84: // STY zp | ||
590 | pc++; | ||
591 | WRITE_LOW( data, y ); | ||
592 | goto loop; | ||
593 | |||
594 | case 0x96: // STX zp,y | ||
595 | data = (uint8_t) (data + y); | ||
596 | case 0x86: // STX zp | ||
597 | pc++; | ||
598 | WRITE_LOW( data, x ); | ||
599 | goto loop; | ||
600 | |||
601 | case 0xB6: // LDX zp,y | ||
602 | data = (uint8_t) (data + y); | ||
603 | case 0xA6: // LDX zp | ||
604 | data = READ_LOW( data ); | ||
605 | case 0xA2: // LDX #imm | ||
606 | pc++; | ||
607 | x = data; | ||
608 | nz = data; | ||
609 | goto loop; | ||
610 | |||
611 | case 0xB4: // LDY zp,x | ||
612 | data = (uint8_t) (data + x); | ||
613 | case 0xA4: // LDY zp | ||
614 | data = READ_LOW( data ); | ||
615 | case 0xA0: // LDY #imm | ||
616 | pc++; | ||
617 | y = data; | ||
618 | nz = data; | ||
619 | goto loop; | ||
620 | |||
621 | case 0xBC: // LDY abs,X | ||
622 | data += x; | ||
623 | PAGE_CROSS_PENALTY( data ); | ||
624 | case 0xAC:{// LDY abs | ||
625 | fuint16 addr = data + 0x100 * GET_MSB(); | ||
626 | pc += 2; | ||
627 | FLUSH_TIME(); | ||
628 | y = nz = READ( addr ); | ||
629 | CACHE_TIME(); | ||
630 | goto loop; | ||
631 | } | ||
632 | |||
633 | { | ||
634 | fuint8 temp; | ||
635 | case 0x8C: // STY abs | ||
636 | temp = y; | ||
637 | goto store_abs; | ||
638 | |||
639 | case 0x8E: // STX abs | ||
640 | temp = x; | ||
641 | store_abs: | ||
642 | { | ||
643 | fuint16 addr = GET_ADDR(); | ||
644 | pc += 2; | ||
645 | FLUSH_TIME(); | ||
646 | WRITE( addr, temp ); | ||
647 | CACHE_TIME(); | ||
648 | goto loop; | ||
649 | } | ||
650 | } | 69 | } |
70 | end: | ||
71 | Cpu_set_mmr( &this->cpu, page, bank, data ); | ||
72 | } | ||
651 | 73 | ||
652 | // Compare | 74 | #define READ_FAST( addr, out ) \ |
653 | 75 | {\ | |
654 | case 0xEC:{// CPX abs | 76 | out = READ_CODE( addr );\ |
655 | fuint16 addr = GET_ADDR(); | 77 | if ( cpu->mmr [PAGE( addr )] == 0xFF )\ |
656 | pc++; | 78 | {\ |
657 | FLUSH_TIME(); | 79 | FLUSH_TIME();\ |
658 | data = READ( addr ); | 80 | out = read_mem_( this, addr );\ |
659 | CACHE_TIME(); | 81 | CACHE_TIME();\ |
660 | goto cpx_data; | 82 | }\ |
661 | } | 83 | } |
662 | |||
663 | case 0xE4: // CPX zp | ||
664 | data = READ_LOW( data ); | ||
665 | case 0xE0: // CPX #imm | ||
666 | cpx_data: | ||
667 | nz = x - data; | ||
668 | pc++; | ||
669 | c = ~nz; | ||
670 | nz &= 0xFF; | ||
671 | goto loop; | ||
672 | |||
673 | case 0xCC:{// CPY abs | ||
674 | fuint16 addr = GET_ADDR(); | ||
675 | pc++; | ||
676 | FLUSH_TIME(); | ||
677 | data = READ( addr ); | ||
678 | CACHE_TIME(); | ||
679 | goto cpy_data; | ||
680 | } | ||
681 | |||
682 | case 0xC4: // CPY zp | ||
683 | data = READ_LOW( data ); | ||
684 | case 0xC0: // CPY #imm | ||
685 | cpy_data: | ||
686 | nz = y - data; | ||
687 | pc++; | ||
688 | c = ~nz; | ||
689 | nz &= 0xFF; | ||
690 | goto loop; | ||
691 | |||
692 | // Logical | ||
693 | 84 | ||
694 | #define ARITH_ADDR_MODES( op )\ | 85 | #define WRITE_FAST( addr, data ) \ |
695 | case op - 0x04: /* (ind,x) */\ | 86 | {\ |
696 | data = (uint8_t) (data + x);\ | 87 | int page = PAGE( addr );\ |
697 | case op + 0x0D: /* (ind) */\ | 88 | byte* out = this->write_pages [page];\ |
698 | data = 0x100 * READ_LOW( (uint8_t) (data + 1) ) + READ_LOW( data );\ | 89 | addr &= page_size - 1;\ |
699 | goto ptr##op;\ | 90 | if ( out )\ |
700 | case op + 0x0C:{/* (ind),y */\ | 91 | {\ |
701 | fuint16 temp = READ_LOW( data ) + y;\ | 92 | out [addr] = data;\ |
702 | PAGE_CROSS_PENALTY( temp );\ | ||
703 | data = temp + 0x100 * READ_LOW( (uint8_t) (data + 1) );\ | ||
704 | goto ptr##op;\ | ||
705 | }\ | 93 | }\ |
706 | case op + 0x10: /* zp,X */\ | 94 | else if ( cpu->mmr [page] == 0xFF )\ |
707 | data = (uint8_t) (data + x);\ | 95 | {\ |
708 | case op + 0x00: /* zp */\ | ||
709 | data = READ_LOW( data );\ | ||
710 | goto imm##op;\ | ||
711 | case op + 0x14: /* abs,Y */\ | ||
712 | data += y;\ | ||
713 | goto ind##op;\ | ||
714 | case op + 0x18: /* abs,X */\ | ||
715 | data += x;\ | ||
716 | ind##op:\ | ||
717 | PAGE_CROSS_PENALTY( data );\ | ||
718 | case op + 0x08: /* abs */\ | ||
719 | ADD_PAGE( data );\ | ||
720 | ptr##op:\ | ||
721 | FLUSH_TIME();\ | 96 | FLUSH_TIME();\ |
722 | data = READ( data );\ | 97 | write_mem_( this, addr, data );\ |
723 | CACHE_TIME();\ | 98 | CACHE_TIME();\ |
724 | case op + 0x04: /* imm */\ | 99 | }\ |
725 | imm##op: | 100 | } |
726 | |||
727 | ARITH_ADDR_MODES( 0xC5 ) // CMP | ||
728 | nz = a - data; | ||
729 | pc++; | ||
730 | c = ~nz; | ||
731 | nz &= 0xFF; | ||
732 | goto loop; | ||
733 | |||
734 | ARITH_ADDR_MODES( 0x25 ) // AND | ||
735 | nz = (a &= data); | ||
736 | pc++; | ||
737 | goto loop; | ||
738 | |||
739 | ARITH_ADDR_MODES( 0x45 ) // EOR | ||
740 | nz = (a ^= data); | ||
741 | pc++; | ||
742 | goto loop; | ||
743 | |||
744 | ARITH_ADDR_MODES( 0x05 ) // ORA | ||
745 | nz = (a |= data); | ||
746 | pc++; | ||
747 | goto loop; | ||
748 | |||
749 | // Add/subtract | ||
750 | |||
751 | ARITH_ADDR_MODES( 0xE5 ) // SBC | ||
752 | data ^= 0xFF; | ||
753 | goto adc_imm; | ||
754 | |||
755 | ARITH_ADDR_MODES( 0x65 ) // ADC | ||
756 | adc_imm: { | ||
757 | if ( status & st_d ) { | ||
758 | dprintf( "Decimal mode not supported\n" ); | ||
759 | } | ||
760 | fint16 carry = c >> 8 & 1; | ||
761 | fint16 ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend | ||
762 | status &= ~st_v; | ||
763 | status |= ov >> 2 & 0x40; | ||
764 | c = nz = a + data + carry; | ||
765 | pc++; | ||
766 | a = (uint8_t) nz; | ||
767 | goto loop; | ||
768 | } | ||
769 | |||
770 | // Shift/rotate | ||
771 | |||
772 | case 0x4A: // LSR A | ||
773 | c = 0; | ||
774 | case 0x6A: // ROR A | ||
775 | nz = c >> 1 & 0x80; | ||
776 | c = a << 8; | ||
777 | nz |= a >> 1; | ||
778 | a = nz; | ||
779 | goto loop; | ||
780 | |||
781 | case 0x0A: // ASL A | ||
782 | nz = a << 1; | ||
783 | c = nz; | ||
784 | a = (uint8_t) nz; | ||
785 | goto loop; | ||
786 | |||
787 | case 0x2A: { // ROL A | ||
788 | nz = a << 1; | ||
789 | fint16 temp = c >> 8 & 1; | ||
790 | c = nz; | ||
791 | nz |= temp; | ||
792 | a = (uint8_t) nz; | ||
793 | goto loop; | ||
794 | } | ||
795 | |||
796 | case 0x5E: // LSR abs,X | ||
797 | data += x; | ||
798 | case 0x4E: // LSR abs | ||
799 | c = 0; | ||
800 | case 0x6E: // ROR abs | ||
801 | ror_abs: { | ||
802 | ADD_PAGE( data ); | ||
803 | FLUSH_TIME(); | ||
804 | int temp = READ( data ); | ||
805 | nz = (c >> 1 & 0x80) | (temp >> 1); | ||
806 | c = temp << 8; | ||
807 | goto rotate_common; | ||
808 | } | ||
809 | |||
810 | case 0x3E: // ROL abs,X | ||
811 | data += x; | ||
812 | goto rol_abs; | ||
813 | |||
814 | case 0x1E: // ASL abs,X | ||
815 | data += x; | ||
816 | case 0x0E: // ASL abs | ||
817 | c = 0; | ||
818 | case 0x2E: // ROL abs | ||
819 | rol_abs: | ||
820 | ADD_PAGE( data ); | ||
821 | nz = c >> 8 & 1; | ||
822 | FLUSH_TIME(); | ||
823 | nz |= (c = READ( data ) << 1); | ||
824 | rotate_common: | ||
825 | pc++; | ||
826 | WRITE( data, (uint8_t) nz ); | ||
827 | CACHE_TIME(); | ||
828 | goto loop; | ||
829 | |||
830 | case 0x7E: // ROR abs,X | ||
831 | data += x; | ||
832 | goto ror_abs; | ||
833 | |||
834 | case 0x76: // ROR zp,x | ||
835 | data = (uint8_t) (data + x); | ||
836 | goto ror_zp; | ||
837 | |||
838 | case 0x56: // LSR zp,x | ||
839 | data = (uint8_t) (data + x); | ||
840 | case 0x46: // LSR zp | ||
841 | c = 0; | ||
842 | case 0x66: // ROR zp | ||
843 | ror_zp: { | ||
844 | int temp = READ_LOW( data ); | ||
845 | nz = (c >> 1 & 0x80) | (temp >> 1); | ||
846 | c = temp << 8; | ||
847 | goto write_nz_zp; | ||
848 | } | ||
849 | |||
850 | case 0x36: // ROL zp,x | ||
851 | data = (uint8_t) (data + x); | ||
852 | goto rol_zp; | ||
853 | |||
854 | case 0x16: // ASL zp,x | ||
855 | data = (uint8_t) (data + x); | ||
856 | case 0x06: // ASL zp | ||
857 | c = 0; | ||
858 | case 0x26: // ROL zp | ||
859 | rol_zp: | ||
860 | nz = c >> 8 & 1; | ||
861 | nz |= (c = READ_LOW( data ) << 1); | ||
862 | goto write_nz_zp; | ||
863 | |||
864 | // Increment/decrement | ||
865 | |||
866 | #define INC_DEC_AXY( reg, n ) reg = (uint8_t) (nz = reg + n); goto loop; | ||
867 | |||
868 | case 0x1A: // INA | ||
869 | INC_DEC_AXY( a, +1 ) | ||
870 | |||
871 | case 0xE8: // INX | ||
872 | INC_DEC_AXY( x, +1 ) | ||
873 | |||
874 | case 0xC8: // INY | ||
875 | INC_DEC_AXY( y, +1 ) | ||
876 | |||
877 | case 0x3A: // DEA | ||
878 | INC_DEC_AXY( a, -1 ) | ||
879 | |||
880 | case 0xCA: // DEX | ||
881 | INC_DEC_AXY( x, -1 ) | ||
882 | |||
883 | case 0x88: // DEY | ||
884 | INC_DEC_AXY( y, -1 ) | ||
885 | |||
886 | case 0xF6: // INC zp,x | ||
887 | data = (uint8_t) (data + x); | ||
888 | case 0xE6: // INC zp | ||
889 | nz = 1; | ||
890 | goto add_nz_zp; | ||
891 | |||
892 | case 0xD6: // DEC zp,x | ||
893 | data = (uint8_t) (data + x); | ||
894 | case 0xC6: // DEC zp | ||
895 | nz = (unsigned) -1; | ||
896 | add_nz_zp: | ||
897 | nz += READ_LOW( data ); | ||
898 | write_nz_zp: | ||
899 | pc++; | ||
900 | WRITE_LOW( data, nz ); | ||
901 | goto loop; | ||
902 | |||
903 | case 0xFE: // INC abs,x | ||
904 | data = x + GET_ADDR(); | ||
905 | goto inc_ptr; | ||
906 | |||
907 | case 0xEE: // INC abs | ||
908 | data = GET_ADDR(); | ||
909 | inc_ptr: | ||
910 | nz = 1; | ||
911 | goto inc_common; | ||
912 | |||
913 | case 0xDE: // DEC abs,x | ||
914 | data = x + GET_ADDR(); | ||
915 | goto dec_ptr; | ||
916 | |||
917 | case 0xCE: // DEC abs | ||
918 | data = GET_ADDR(); | ||
919 | dec_ptr: | ||
920 | nz = (unsigned) -1; | ||
921 | inc_common: | ||
922 | FLUSH_TIME(); | ||
923 | nz += READ( data ); | ||
924 | pc += 2; | ||
925 | WRITE( data, (uint8_t) nz ); | ||
926 | CACHE_TIME(); | ||
927 | goto loop; | ||
928 | |||
929 | // Transfer | ||
930 | |||
931 | case 0xA8: // TAY | ||
932 | y = a; | ||
933 | nz = a; | ||
934 | goto loop; | ||
935 | |||
936 | case 0x98: // TYA | ||
937 | a = y; | ||
938 | nz = y; | ||
939 | goto loop; | ||
940 | |||
941 | case 0xAA: // TAX | ||
942 | x = a; | ||
943 | nz = a; | ||
944 | goto loop; | ||
945 | |||
946 | case 0x8A: // TXA | ||
947 | a = x; | ||
948 | nz = x; | ||
949 | goto loop; | ||
950 | |||
951 | case 0x9A: // TXS | ||
952 | SET_SP( x ); // verified (no flag change) | ||
953 | goto loop; | ||
954 | |||
955 | case 0xBA: // TSX | ||
956 | x = nz = GET_SP(); | ||
957 | goto loop; | ||
958 | |||
959 | #define SWAP_REGS( r1, r2 ) {\ | ||
960 | fuint8 t = r1;\ | ||
961 | r1 = r2;\ | ||
962 | r2 = t;\ | ||
963 | goto loop;\ | ||
964 | } | ||
965 | |||
966 | case 0x02: // SXY | ||
967 | SWAP_REGS( x, y ); | ||
968 | |||
969 | case 0x22: // SAX | ||
970 | SWAP_REGS( a, x ); | ||
971 | |||
972 | case 0x42: // SAY | ||
973 | SWAP_REGS( a, y ); | ||
974 | |||
975 | case 0x62: // CLA | ||
976 | a = 0; | ||
977 | goto loop; | ||
978 | |||
979 | case 0x82: // CLX | ||
980 | x = 0; | ||
981 | goto loop; | ||
982 | |||
983 | case 0xC2: // CLY | ||
984 | y = 0; | ||
985 | goto loop; | ||
986 | |||
987 | // Stack | ||
988 | |||
989 | case 0x48: // PHA | ||
990 | PUSH( a ); | ||
991 | goto loop; | ||
992 | |||
993 | case 0xDA: // PHX | ||
994 | PUSH( x ); | ||
995 | goto loop; | ||
996 | |||
997 | case 0x5A: // PHY | ||
998 | PUSH( y ); | ||
999 | goto loop; | ||
1000 | |||
1001 | case 0x40:{// RTI | ||
1002 | fuint8 temp = READ_LOW( sp ); | ||
1003 | pc = READ_LOW( 0x100 | (sp - 0xFF) ); | ||
1004 | pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100; | ||
1005 | sp = (sp - 0xFD) | 0x100; | ||
1006 | data = status; | ||
1007 | SET_STATUS( temp ); | ||
1008 | r->status = status; // update externally-visible I flag | ||
1009 | if ( (data ^ status) & st_i ) | ||
1010 | { | ||
1011 | hes_time_t new_time = cpu->end_time; | ||
1012 | if ( !(status & st_i) && new_time > cpu->irq_time ) | ||
1013 | new_time = cpu->irq_time; | ||
1014 | blargg_long delta = s.base - new_time; | ||
1015 | s.base = new_time; | ||
1016 | s_time += delta; | ||
1017 | } | ||
1018 | goto loop; | ||
1019 | } | ||
1020 | |||
1021 | #define POP() READ_LOW( sp ); sp = (sp - 0xFF) | 0x100 | ||
1022 | |||
1023 | case 0x68: // PLA | ||
1024 | a = nz = POP(); | ||
1025 | goto loop; | ||
1026 | |||
1027 | case 0xFA: // PLX | ||
1028 | x = nz = POP(); | ||
1029 | goto loop; | ||
1030 | |||
1031 | case 0x7A: // PLY | ||
1032 | y = nz = POP(); | ||
1033 | goto loop; | ||
1034 | |||
1035 | case 0x28:{// PLP | ||
1036 | fuint8 temp = POP(); | ||
1037 | fuint8 changed = status ^ temp; | ||
1038 | SET_STATUS( temp ); | ||
1039 | if ( !(changed & st_i) ) | ||
1040 | goto loop; // I flag didn't change | ||
1041 | if ( status & st_i ) | ||
1042 | goto handle_sei; | ||
1043 | goto handle_cli; | ||
1044 | } | ||
1045 | #undef POP | ||
1046 | |||
1047 | case 0x08: { // PHP | ||
1048 | fuint8 temp; | ||
1049 | CALC_STATUS( temp ); | ||
1050 | PUSH( temp | st_b ); | ||
1051 | goto loop; | ||
1052 | } | ||
1053 | |||
1054 | // Flags | ||
1055 | |||
1056 | case 0x38: // SEC | ||
1057 | c = (unsigned) ~0; | ||
1058 | goto loop; | ||
1059 | |||
1060 | case 0x18: // CLC | ||
1061 | c = 0; | ||
1062 | goto loop; | ||
1063 | |||
1064 | case 0xB8: // CLV | ||
1065 | status &= ~st_v; | ||
1066 | goto loop; | ||
1067 | |||
1068 | case 0xD8: // CLD | ||
1069 | status &= ~st_d; | ||
1070 | goto loop; | ||
1071 | |||
1072 | case 0xF8: // SED | ||
1073 | status |= st_d; | ||
1074 | goto loop; | ||
1075 | |||
1076 | case 0x58: // CLI | ||
1077 | if ( !(status & st_i) ) | ||
1078 | goto loop; | ||
1079 | status &= ~st_i; | ||
1080 | handle_cli: { | ||
1081 | r->status = status; // update externally-visible I flag | ||
1082 | blargg_long delta = s.base - cpu->irq_time; | ||
1083 | if ( delta <= 0 ) | ||
1084 | { | ||
1085 | if ( TIME < cpu->irq_time ) | ||
1086 | goto loop; | ||
1087 | goto delayed_cli; | ||
1088 | } | ||
1089 | s.base = cpu->irq_time; | ||
1090 | s_time += delta; | ||
1091 | if ( s_time < 0 ) | ||
1092 | goto loop; | ||
1093 | |||
1094 | if ( delta >= s_time + 1 ) | ||
1095 | { | ||
1096 | // delayed irq until after next instruction | ||
1097 | s.base += s_time + 1; | ||
1098 | s_time = -1; | ||
1099 | cpu->irq_time = s.base; // TODO: remove, as only to satisfy debug check in loop | ||
1100 | goto loop; | ||
1101 | } | ||
1102 | delayed_cli: | ||
1103 | dprintf( "Delayed CLI not supported\n" ); // TODO: implement | ||
1104 | goto loop; | ||
1105 | } | ||
1106 | |||
1107 | case 0x78: // SEI | ||
1108 | if ( status & st_i ) | ||
1109 | goto loop; | ||
1110 | status |= st_i; | ||
1111 | handle_sei: { | ||
1112 | r->status = status; // update externally-visible I flag | ||
1113 | blargg_long delta = s.base - cpu->end_time; | ||
1114 | s.base = cpu->end_time; | ||
1115 | s_time += delta; | ||
1116 | if ( s_time < 0 ) | ||
1117 | goto loop; | ||
1118 | dprintf( "Delayed SEI not supported\n" ); // TODO: implement | ||
1119 | goto loop; | ||
1120 | } | ||
1121 | |||
1122 | // Special | ||
1123 | |||
1124 | case 0x53:{// TAM | ||
1125 | fuint8 const bits = data; // avoid using data across function call | ||
1126 | pc++; | ||
1127 | int i; | ||
1128 | for ( i = 0; i < 8; i++ ) | ||
1129 | if ( bits & (1 << i) ) | ||
1130 | /* this->cpu.set_mmr( i, a ); */ | ||
1131 | Cpu_set_mmr( this, i, a ); | ||
1132 | goto loop; | ||
1133 | } | ||
1134 | |||
1135 | case 0x43:{// TMA | ||
1136 | pc++; | ||
1137 | byte const* in = cpu->mmr; | ||
1138 | do | ||
1139 | { | ||
1140 | if ( data & 1 ) | ||
1141 | a = *in; | ||
1142 | in++; | ||
1143 | } | ||
1144 | while ( (data >>= 1) != 0 ); | ||
1145 | goto loop; | ||
1146 | } | ||
1147 | |||
1148 | case 0x03: // ST0 | ||
1149 | case 0x13: // ST1 | ||
1150 | case 0x23:{// ST2 | ||
1151 | fuint16 addr = opcode >> 4; | ||
1152 | if ( addr ) | ||
1153 | addr++; | ||
1154 | pc++; | ||
1155 | FLUSH_TIME(); | ||
1156 | CPU_WRITE_VDP( this, addr, data, TIME ); | ||
1157 | CACHE_TIME(); | ||
1158 | goto loop; | ||
1159 | } | ||
1160 | |||
1161 | case 0xEA: // NOP | ||
1162 | goto loop; | ||
1163 | |||
1164 | case 0x54: // CSL | ||
1165 | dprintf( "CSL not supported\n" ); | ||
1166 | illegal_encountered = true; | ||
1167 | goto loop; | ||
1168 | |||
1169 | case 0xD4: // CSH | ||
1170 | goto loop; | ||
1171 | |||
1172 | case 0xF4: { // SET | ||
1173 | //fuint16 operand = GET_MSB(); | ||
1174 | dprintf( "SET not handled\n" ); | ||
1175 | //switch ( data ) | ||
1176 | //{ | ||
1177 | //} | ||
1178 | illegal_encountered = true; | ||
1179 | goto loop; | ||
1180 | } | ||
1181 | |||
1182 | // Block transfer | ||
1183 | 101 | ||
1184 | { | 102 | #define READ_LOW( addr ) (this->ram [addr]) |
1185 | fuint16 in_alt; | 103 | #define WRITE_LOW( addr, data ) (this->ram [addr] = data) |
1186 | fint16 in_inc; | 104 | #define READ_MEM( addr ) read_mem( this, addr ) |
1187 | fuint16 out_alt; | 105 | #define WRITE_MEM( addr, data ) write_mem( this, addr, data ) |
1188 | fint16 out_inc; | 106 | #define WRITE_VDP( addr, data ) write_vdp( this, addr, data ) |
1189 | 107 | #define CPU_DONE( result_out ) { FLUSH_TIME(); result_out = cpu_done( this ); CACHE_TIME(); } | |
1190 | case 0xE3: // TIA | 108 | #define SET_MMR( reg, bank ) set_mmr( this, reg, bank ) |
1191 | in_alt = 0; | ||
1192 | goto bxfer_alt; | ||
1193 | |||
1194 | case 0xF3: // TAI | ||
1195 | in_alt = 1; | ||
1196 | bxfer_alt: | ||
1197 | in_inc = in_alt ^ 1; | ||
1198 | out_alt = in_inc; | ||
1199 | out_inc = in_alt; | ||
1200 | goto bxfer; | ||
1201 | |||
1202 | case 0xD3: // TIN | ||
1203 | in_inc = 1; | ||
1204 | out_inc = 0; | ||
1205 | goto bxfer_no_alt; | ||
1206 | |||
1207 | case 0xC3: // TDD | ||
1208 | in_inc = -1; | ||
1209 | out_inc = -1; | ||
1210 | goto bxfer_no_alt; | ||
1211 | |||
1212 | case 0x73: // TII | ||
1213 | in_inc = 1; | ||
1214 | out_inc = 1; | ||
1215 | bxfer_no_alt: | ||
1216 | in_alt = 0; | ||
1217 | out_alt = 0; | ||
1218 | bxfer: { | ||
1219 | fuint16 in = GET_LE16( instr + 0 ); | ||
1220 | fuint16 out = GET_LE16( instr + 2 ); | ||
1221 | int count = GET_LE16( instr + 4 ); | ||
1222 | if ( !count ) | ||
1223 | count = 0x10000; | ||
1224 | pc += 6; | ||
1225 | WRITE_LOW( 0x100 | (sp - 1), y ); | ||
1226 | WRITE_LOW( 0x100 | (sp - 2), a ); | ||
1227 | WRITE_LOW( 0x100 | (sp - 3), x ); | ||
1228 | FLUSH_TIME(); | ||
1229 | do | ||
1230 | { | ||
1231 | // TODO: reads from $0800-$1400 in I/O page return 0 and don't access I/O | ||
1232 | fuint8 t = READ( in ); | ||
1233 | in += in_inc; | ||
1234 | in &= 0xFFFF; | ||
1235 | s.time += 6; | ||
1236 | if ( in_alt ) | ||
1237 | in_inc = -in_inc; | ||
1238 | WRITE( out, t ); | ||
1239 | out += out_inc; | ||
1240 | out &= 0xFFFF; | ||
1241 | if ( out_alt ) | ||
1242 | out_inc = -out_inc; | ||
1243 | } | ||
1244 | while ( --count ); | ||
1245 | CACHE_TIME(); | ||
1246 | goto loop; | ||
1247 | } | ||
1248 | } | ||
1249 | 109 | ||
1250 | // Illegal | 110 | #define IDLE_ADDR idle_addr |
1251 | 111 | ||
1252 | default: | 112 | #define CPU_BEGIN \ |
1253 | assert( (unsigned) opcode <= 0xFF ); | 113 | bool run_cpu( struct Hes_Emu* this, hes_time_t end_time )\ |
1254 | dprintf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 ); | 114 | {\ |
1255 | illegal_encountered = true; | 115 | struct Hes_Cpu* cpu = &this->cpu;\ |
1256 | goto loop; | 116 | Cpu_set_end_time( cpu, end_time ); |
1257 | } | ||
1258 | assert( false ); | ||
1259 | |||
1260 | int result_; | ||
1261 | handle_brk: | ||
1262 | pc++; | ||
1263 | result_ = 6; | ||
1264 | |||
1265 | interrupt: | ||
1266 | { | ||
1267 | s_time += 7; | ||
1268 | |||
1269 | WRITE_LOW( 0x100 | (sp - 1), pc >> 8 ); | ||
1270 | WRITE_LOW( 0x100 | (sp - 2), pc ); | ||
1271 | pc = GET_LE16( &READ_PROG( 0xFFF0 ) + result_ ); | ||
1272 | |||
1273 | sp = (sp - 3) | 0x100; | ||
1274 | fuint8 temp; | ||
1275 | CALC_STATUS( temp ); | ||
1276 | if ( result_ == 6 ) | ||
1277 | temp |= st_b; | ||
1278 | WRITE_LOW( sp, temp ); | ||
1279 | |||
1280 | status &= ~st_d; | ||
1281 | status |= st_i; | ||
1282 | r->status = status; // update externally-visible I flag | ||
1283 | |||
1284 | blargg_long delta = s.base - cpu->end_time; | ||
1285 | s.base = cpu->end_time; | ||
1286 | s_time += delta; | ||
1287 | goto loop; | ||
1288 | } | ||
1289 | |||
1290 | idle_done: | ||
1291 | s_time = 0; | ||
1292 | out_of_time: | ||
1293 | pc--; | ||
1294 | FLUSH_TIME(); | ||
1295 | CPU_DONE( this, TIME, result_ ); | ||
1296 | CACHE_TIME(); | ||
1297 | if ( result_ > 0 ) | ||
1298 | goto interrupt; | ||
1299 | if ( s_time < 0 ) | ||
1300 | goto loop; | ||
1301 | |||
1302 | s.time = s_time; | ||
1303 | |||
1304 | r->pc = pc; | ||
1305 | r->sp = GET_SP(); | ||
1306 | r->a = a; | ||
1307 | r->x = x; | ||
1308 | r->y = y; | ||
1309 | |||
1310 | { | ||
1311 | fuint8 temp; | ||
1312 | CALC_STATUS( temp ); | ||
1313 | r->status = temp; | ||
1314 | } | ||
1315 | 117 | ||
1316 | cpu->state_ = s; | 118 | #include "hes_cpu_run.h" |
1317 | cpu->state = &cpu->state_; | ||
1318 | 119 | ||
1319 | return illegal_encountered; | 120 | return illegal_encountered; |
1320 | } | 121 | } |
1321 | |||
diff --git a/apps/codecs/libgme/hes_cpu.h b/apps/codecs/libgme/hes_cpu.h index 4d76c83a3b..0429eeaba0 100644 --- a/apps/codecs/libgme/hes_cpu.h +++ b/apps/codecs/libgme/hes_cpu.h | |||
@@ -1,56 +1,52 @@ | |||
1 | // PC Engine CPU emulator for use with HES music files | 1 | // PC Engine CPU emulator for use with HES music files |
2 | 2 | ||
3 | // Game_Music_Emu 0.5.2 | 3 | // Game_Music_Emu 0.6-pre |
4 | #ifndef HES_CPU_H | 4 | #ifndef HES_CPU_H |
5 | #define HES_CPU_H | 5 | #define HES_CPU_H |
6 | 6 | ||
7 | #include "blargg_common.h" | 7 | #include "blargg_common.h" |
8 | #include "blargg_source.h" | ||
8 | 9 | ||
9 | typedef blargg_long hes_time_t; // clock cycle count | 10 | typedef int hes_time_t; // clock cycle count |
10 | typedef unsigned hes_addr_t; // 16-bit address | 11 | typedef int hes_addr_t; // 16-bit address |
11 | 12 | ||
12 | struct Hes_Emu; | 13 | struct Hes_Emu; |
13 | 14 | ||
14 | enum { future_hes_time = LONG_MAX / 2 + 1 }; | 15 | enum { future_time = INT_MAX/2 + 1 }; |
15 | enum { page_size = 0x2000 }; | 16 | enum { page_bits = 13 }; |
16 | enum { page_shift = 13 }; | 17 | enum { page_size = 1 << page_bits }; |
17 | enum { page_count = 8 }; | 18 | enum { page_count = 0x10000 / page_size }; |
18 | 19 | ||
19 | // Attempt to execute instruction here results in CPU advancing time to | ||
20 | // lesser of irq_time() and end_time() (or end_time() if IRQs are | ||
21 | // disabled) | ||
22 | enum { idle_addr = 0x1FFF }; | ||
23 | |||
24 | // Can read this many bytes past end of a page | 20 | // Can read this many bytes past end of a page |
25 | enum { cpu_padding = 8 }; | 21 | enum { cpu_padding = 8 }; |
26 | enum { irq_inhibit = 0x04 }; | 22 | enum { irq_inhibit_mask = 0x04 }; |
27 | 23 | enum { idle_addr = 0x1FFF }; | |
28 | 24 | ||
29 | // Cpu state | 25 | // Cpu state |
30 | struct state_t { | 26 | struct cpu_state_t { |
31 | uint8_t const* code_map [page_count + 1]; | 27 | byte const* code_map [page_count + 1]; |
32 | hes_time_t base; | 28 | hes_time_t base; |
33 | blargg_long time; | 29 | int time; |
34 | }; | 30 | }; |
35 | 31 | ||
36 | // Cpu registers | 32 | // NOT kept updated during emulation. |
37 | struct registers_t { | 33 | struct registers_t { |
38 | uint16_t pc; | 34 | uint16_t pc; |
39 | uint8_t a; | 35 | byte a; |
40 | uint8_t x; | 36 | byte x; |
41 | uint8_t y; | 37 | byte y; |
42 | uint8_t status; | 38 | byte flags; |
43 | uint8_t sp; | 39 | byte sp; |
44 | }; | 40 | }; |
45 | 41 | ||
46 | struct Hes_Cpu { | 42 | struct Hes_Cpu { |
47 | struct registers_t r; | 43 | struct registers_t r; |
48 | 44 | ||
49 | hes_time_t irq_time; | 45 | hes_time_t irq_time_; |
50 | hes_time_t end_time; | 46 | hes_time_t end_time_; |
51 | 47 | ||
52 | struct state_t* state; // points to state_ or a local copy within run() | 48 | struct cpu_state_t* cpu_state; // points to state_ or a local copy within run() |
53 | struct state_t state_; | 49 | struct cpu_state_t cpu_state_; |
54 | 50 | ||
55 | // page mapping registers | 51 | // page mapping registers |
56 | uint8_t mmr [page_count + 1]; | 52 | uint8_t mmr [page_count + 1]; |
@@ -58,7 +54,10 @@ struct Hes_Cpu { | |||
58 | }; | 54 | }; |
59 | 55 | ||
60 | // Init cpu state | 56 | // Init cpu state |
61 | void Cpu_init( struct Hes_Cpu* this ); | 57 | static inline void Cpu_init( struct Hes_Cpu* this ) |
58 | { | ||
59 | this->cpu_state = &this->cpu_state_; | ||
60 | } | ||
62 | 61 | ||
63 | // Reset hes cpu | 62 | // Reset hes cpu |
64 | void Cpu_reset( struct Hes_Cpu* this ); | 63 | void Cpu_reset( struct Hes_Cpu* this ); |
@@ -67,29 +66,67 @@ void Cpu_reset( struct Hes_Cpu* this ); | |||
67 | // instructions were encountered. | 66 | // instructions were encountered. |
68 | bool Cpu_run( struct Hes_Emu* this, hes_time_t end_time ); | 67 | bool Cpu_run( struct Hes_Emu* this, hes_time_t end_time ); |
69 | 68 | ||
70 | void Cpu_set_mmr( struct Hes_Emu* this, int reg, int bank ); | ||
71 | |||
72 | // Time of ning of next instruction to be executed | 69 | // Time of ning of next instruction to be executed |
73 | static inline hes_time_t Cpu_time( struct Hes_Cpu* this ) | 70 | static inline hes_time_t Cpu_time( struct Hes_Cpu* this ) |
74 | { | 71 | { |
75 | return this->state->time + this->state->base; | 72 | return this->cpu_state->time + this->cpu_state->base; |
76 | } | 73 | } |
77 | 74 | ||
75 | static inline void Cpu_set_time( struct Hes_Cpu* this, hes_time_t t ) { this->cpu_state->time = t - this->cpu_state->base; } | ||
76 | static inline void Cpu_adjust_time( struct Hes_Cpu* this, int delta ) { this->cpu_state->time += delta; } | ||
77 | |||
78 | #define HES_CPU_PAGE( addr ) ((unsigned) (addr) >> page_bits) | ||
79 | |||
80 | #ifdef BLARGG_NONPORTABLE | ||
81 | #define HES_CPU_OFFSET( addr ) (addr) | ||
82 | #else | ||
83 | #define HES_CPU_OFFSET( addr ) ((addr) & (page_size - 1)) | ||
84 | #endif | ||
85 | |||
78 | static inline uint8_t const* Cpu_get_code( struct Hes_Cpu* this, hes_addr_t addr ) | 86 | static inline uint8_t const* Cpu_get_code( struct Hes_Cpu* this, hes_addr_t addr ) |
79 | { | 87 | { |
80 | return this->state->code_map [addr >> page_shift] + addr | 88 | return this->cpu_state_.code_map [HES_CPU_PAGE( addr )] + HES_CPU_OFFSET( addr ); |
81 | #if !defined (BLARGG_NONPORTABLE) | 89 | } |
82 | % (unsigned) page_size | 90 | |
83 | #endif | 91 | static inline void update_end_time( struct Hes_Cpu* this, hes_time_t end, hes_time_t irq ) |
84 | ; | 92 | { |
93 | if ( end > irq && !(this->r.flags & irq_inhibit_mask) ) | ||
94 | end = irq; | ||
95 | |||
96 | this->cpu_state->time += this->cpu_state->base - end; | ||
97 | this->cpu_state->base = end; | ||
98 | } | ||
99 | |||
100 | static inline hes_time_t Cpu_end_time( struct Hes_Cpu* this ) { return this->end_time_; } | ||
101 | |||
102 | static inline void Cpu_set_irq_time( struct Hes_Cpu* this, hes_time_t t ) | ||
103 | { | ||
104 | this->irq_time_ = t; | ||
105 | update_end_time( this, this->end_time_, t ); | ||
106 | } | ||
107 | |||
108 | static inline void Cpu_set_end_time( struct Hes_Cpu* this, hes_time_t t ) | ||
109 | { | ||
110 | this->end_time_ = t; | ||
111 | update_end_time( this, t, this->irq_time_ ); | ||
112 | } | ||
113 | |||
114 | static inline void Cpu_end_frame( struct Hes_Cpu* this, hes_time_t t ) | ||
115 | { | ||
116 | assert( this->cpu_state == &this->cpu_state_ ); | ||
117 | this->cpu_state_.base -= t; | ||
118 | if ( this->irq_time_ < future_time ) this->irq_time_ -= t; | ||
119 | if ( this->end_time_ < future_time ) this->end_time_ -= t; | ||
85 | } | 120 | } |
86 | 121 | ||
87 | static inline int Cpu_update_end_time( struct Hes_Cpu* this, uint8_t reg_status, hes_time_t t, hes_time_t irq ) | 122 | static inline void Cpu_set_mmr( struct Hes_Cpu* this, int reg, int bank, void const* code ) |
88 | { | 123 | { |
89 | if ( irq < t && !(reg_status & irq_inhibit) ) t = irq; | 124 | assert( (unsigned) reg <= page_count ); // allow page past end to be set |
90 | int delta = this->state->base - t; | 125 | assert( (unsigned) bank < 0x100 ); |
91 | this->state->base = t; | 126 | this->mmr [reg] = bank; |
92 | return delta; | 127 | byte const* p = STATIC_CAST(byte const*,code) - HES_CPU_OFFSET( reg << page_bits ); |
128 | this->cpu_state->code_map [reg] = p; | ||
129 | this->cpu_state_.code_map [reg] = p; | ||
93 | } | 130 | } |
94 | 131 | ||
95 | #endif | 132 | #endif |
diff --git a/apps/codecs/libgme/hes_cpu_io.h b/apps/codecs/libgme/hes_cpu_io.h deleted file mode 100644 index 6b49c69e22..0000000000 --- a/apps/codecs/libgme/hes_cpu_io.h +++ /dev/null | |||
@@ -1,72 +0,0 @@ | |||
1 | |||
2 | #include "hes_emu.h" | ||
3 | |||
4 | #include "blargg_source.h" | ||
5 | |||
6 | int Cpu_read( struct Hes_Emu* this, hes_addr_t addr ) | ||
7 | { | ||
8 | check( addr <= 0xFFFF ); | ||
9 | int result = *Cpu_get_code( &this->cpu, addr ); | ||
10 | if ( this->cpu.mmr [addr >> page_shift] == 0xFF ) | ||
11 | result = Emu_cpu_read( this, addr ); | ||
12 | return result; | ||
13 | } | ||
14 | |||
15 | void Cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | ||
16 | { | ||
17 | check( addr <= 0xFFFF ); | ||
18 | byte* out = this->write_pages [addr >> page_shift]; | ||
19 | addr &= page_size - 1; | ||
20 | if ( out ) | ||
21 | out [addr] = data; | ||
22 | else if ( this->cpu.mmr [addr >> page_shift] == 0xFF ) | ||
23 | Emu_cpu_write( this, addr, data ); | ||
24 | } | ||
25 | |||
26 | #define CPU_READ_FAST( emu, addr, time, out ) \ | ||
27 | CPU_READ_FAST_( emu, addr, time, out ) | ||
28 | |||
29 | #define CPU_READ_FAST_( emu, addr, time, out ) \ | ||
30 | {\ | ||
31 | out = READ_PROG( addr );\ | ||
32 | if ( emu->cpu.mmr [addr >> page_shift] == 0xFF )\ | ||
33 | {\ | ||
34 | FLUSH_TIME();\ | ||
35 | out = Emu_cpu_read( emu, addr );\ | ||
36 | CACHE_TIME();\ | ||
37 | }\ | ||
38 | } | ||
39 | |||
40 | #define CPU_WRITE_FAST( emu, addr, data, time ) \ | ||
41 | CPU_WRITE_FAST_( emu, addr, data, time ) | ||
42 | |||
43 | #define CPU_WRITE_FAST_( emu, addr, data, time ) \ | ||
44 | {\ | ||
45 | byte* out = emu->write_pages [addr >> page_shift];\ | ||
46 | addr &= page_size - 1;\ | ||
47 | if ( out )\ | ||
48 | {\ | ||
49 | out [addr] = data;\ | ||
50 | }\ | ||
51 | else if ( emu->cpu.mmr [addr >> page_shift] == 0xFF )\ | ||
52 | {\ | ||
53 | FLUSH_TIME();\ | ||
54 | Emu_cpu_write( emu, addr, data );\ | ||
55 | CACHE_TIME();\ | ||
56 | }\ | ||
57 | } | ||
58 | |||
59 | #define CPU_READ( emu, addr, time ) \ | ||
60 | Cpu_read( emu, addr ) | ||
61 | |||
62 | #define CPU_WRITE( emu, addr, data, time ) \ | ||
63 | Cpu_write( emu, addr, data ) | ||
64 | |||
65 | #define CPU_WRITE_VDP( emu, addr, data, time ) \ | ||
66 | Cpu_write_vdp( emu, addr, data ) | ||
67 | |||
68 | #define CPU_SET_MMR( emu, page, bank ) \ | ||
69 | Emu_cpu_set_mmr( emu, page, bank ) | ||
70 | |||
71 | #define CPU_DONE( emu, time, result_out ) \ | ||
72 | result_out = Cpu_done( emu ) | ||
diff --git a/apps/codecs/libgme/hes_cpu_run.h b/apps/codecs/libgme/hes_cpu_run.h new file mode 100644 index 0000000000..bfba2b6109 --- /dev/null +++ b/apps/codecs/libgme/hes_cpu_run.h | |||
@@ -0,0 +1,1344 @@ | |||
1 | // Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ | ||
2 | |||
3 | #if 0 | ||
4 | /* Define these macros in the source file before #including this file. | ||
5 | - Parameters might be expressions, so they are best evaluated only once, | ||
6 | though they NEVER have side-effects, so multiple evaluation is OK. | ||
7 | - Output parameters might be a multiple-assignment expression like "a=x", | ||
8 | so they must NOT be parenthesized. | ||
9 | - Except where noted, time() and related functions will NOT work | ||
10 | correctly inside a macro. TIME() is always correct, and FLUSH_TIME() and | ||
11 | CACHE_TIME() allow the time changing functions to work. | ||
12 | - Macros "returning" void may use a {} statement block. */ | ||
13 | |||
14 | // 0 <= addr <= 0xFFFF + page_size | ||
15 | // time functions can be used | ||
16 | int READ_MEM( addr_t ); | ||
17 | void WRITE_MEM( addr_t, int data ); | ||
18 | |||
19 | // 0 <= addr <= 0x1FF | ||
20 | int READ_LOW( addr_t ); | ||
21 | void WRITE_LOW( addr_t, int data ); | ||
22 | |||
23 | // 0 <= addr <= 0xFFFF + page_size | ||
24 | // Used by common instructions. | ||
25 | int READ_FAST( addr_t, int& out ); | ||
26 | void WRITE_FAST( addr_t, int data ); | ||
27 | |||
28 | // 0 <= addr <= 2 | ||
29 | // ST0, ST1, ST2 instructions | ||
30 | void WRITE_VDP( int addr, int data ); | ||
31 | |||
32 | // The following can be used within macros: | ||
33 | |||
34 | // Current time | ||
35 | hes_time_t TIME(); | ||
36 | |||
37 | // Allows use of time functions | ||
38 | void FLUSH_TIME(); | ||
39 | |||
40 | // Must be used before end of macro if FLUSH_TIME() was used earlier | ||
41 | void CACHE_TIME(); | ||
42 | |||
43 | // Configuration (optional; commented behavior if defined) | ||
44 | |||
45 | // Expanded just before beginning of code, to help debugger | ||
46 | #define CPU_BEGIN void my_run_cpu() { | ||
47 | #endif | ||
48 | |||
49 | /* Copyright (C) 2003-2008 Shay Green. This module is free software; you | ||
50 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
51 | General Public License as published by the Free Software Foundation; either | ||
52 | version 2.1 of the License, or (at your option) any later version. This | ||
53 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
54 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
55 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
56 | details. You should have received a copy of the GNU Lesser General Public | ||
57 | License along with this module; if not, write to the Free Software Foundation, | ||
58 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
59 | |||
60 | // TODO: support T flag, including clearing it at appropriate times? | ||
61 | |||
62 | // all zero-page should really use whatever is at page 1, but that would | ||
63 | // reduce efficiency quite a bit | ||
64 | int const ram_addr = 0x2000; | ||
65 | |||
66 | void Cpu_reset( struct Hes_Cpu* this ) | ||
67 | { | ||
68 | check( this->cpu_state == &this->cpu_state_ ); | ||
69 | this->cpu_state = &this->cpu_state_; | ||
70 | |||
71 | this->cpu_state_.time = 0; | ||
72 | this->cpu_state_.base = 0; | ||
73 | this->irq_time_ = future_time; | ||
74 | this->end_time_ = future_time; | ||
75 | |||
76 | this->r.flags = 0x04; | ||
77 | this->r.sp = 0; | ||
78 | this->r.pc = 0; | ||
79 | this->r.a = 0; | ||
80 | this->r.x = 0; | ||
81 | this->r.y = 0; | ||
82 | |||
83 | // Be sure "blargg_endian.h" has been #included | ||
84 | blargg_verify_byte_order(); | ||
85 | } | ||
86 | |||
87 | // Allows MWCW debugger to step through code properly | ||
88 | #ifdef CPU_BEGIN | ||
89 | CPU_BEGIN | ||
90 | #endif | ||
91 | |||
92 | // Time | ||
93 | #define TIME() (s_time + s.base) | ||
94 | #define FLUSH_TIME() {s.time = s_time;} | ||
95 | #define CACHE_TIME() {s_time = s.time;} | ||
96 | |||
97 | // Memory | ||
98 | #define READ_STACK READ_LOW | ||
99 | #define WRITE_STACK WRITE_LOW | ||
100 | |||
101 | #define CODE_PAGE( addr ) s.code_map [HES_CPU_PAGE( addr )] | ||
102 | #define CODE_OFFSET( addr ) HES_CPU_OFFSET( addr ) | ||
103 | #define READ_CODE( addr ) CODE_PAGE( addr ) [CODE_OFFSET( addr )] | ||
104 | |||
105 | // Stack | ||
106 | #define SET_SP( v ) (sp = ((v) + 1) | 0x100) | ||
107 | #define GET_SP() ((sp - 1) & 0xFF) | ||
108 | #define SP( o ) ((sp + (o - (o>0)*0x100)) | 0x100) | ||
109 | |||
110 | // Truncation | ||
111 | #define BYTE( n ) ((uint8_t ) (n)) /* (unsigned) n & 0xFF */ | ||
112 | #define SBYTE( n ) ((int8_t ) (n)) /* (BYTE( n ) ^ 0x80) - 0x80 */ | ||
113 | #define WORD( n ) ((uint16_t) (n)) /* (unsigned) n & 0xFFFF */ | ||
114 | |||
115 | // Flags with hex value for clarity when used as mask. | ||
116 | // Stored in indicated variable during emulation. | ||
117 | int const n80 = 0x80; // nz | ||
118 | int const v40 = 0x40; // flags | ||
119 | //int const t20 = 0x20; | ||
120 | int const b10 = 0x10; | ||
121 | int const d08 = 0x08; // flags | ||
122 | int const i04 = 0x04; // flags | ||
123 | int const z02 = 0x02; // nz | ||
124 | int const c01 = 0x01; // c | ||
125 | |||
126 | #define IS_NEG (nz & 0x8080) | ||
127 | |||
128 | #define GET_FLAGS( out ) \ | ||
129 | {\ | ||
130 | out = flags & (v40 | d08 | i04);\ | ||
131 | out += ((nz >> 8) | nz) & n80;\ | ||
132 | out += c >> 8 & c01;\ | ||
133 | if ( !BYTE( nz ) )\ | ||
134 | out += z02;\ | ||
135 | } | ||
136 | |||
137 | #define SET_FLAGS( in ) \ | ||
138 | {\ | ||
139 | flags = in & (v40 | d08 | i04);\ | ||
140 | c = nz = in << 8;\ | ||
141 | nz += ~in & z02;\ | ||
142 | } | ||
143 | |||
144 | bool illegal_encountered = false; | ||
145 | { | ||
146 | struct cpu_state_t s = cpu->cpu_state_; | ||
147 | cpu->cpu_state = &s; | ||
148 | // even on x86, using s.time in place of s_time was slower | ||
149 | int s_time = s.time; | ||
150 | |||
151 | // registers | ||
152 | int pc = cpu->r.pc; | ||
153 | int a = cpu->r.a; | ||
154 | int x = cpu->r.x; | ||
155 | int y = cpu->r.y; | ||
156 | int sp; | ||
157 | SET_SP( cpu->r.sp ); | ||
158 | |||
159 | // Flags | ||
160 | int flags; | ||
161 | int c; // carry set if (c & 0x100) != 0 | ||
162 | int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 | ||
163 | { | ||
164 | int temp = cpu->r.flags; | ||
165 | SET_FLAGS( temp ); | ||
166 | } | ||
167 | |||
168 | loop: | ||
169 | |||
170 | #ifndef NDEBUG | ||
171 | { | ||
172 | hes_time_t correct = cpu->end_time_; | ||
173 | if ( !(flags & i04) && correct > cpu->irq_time_ ) | ||
174 | correct = cpu->irq_time_; | ||
175 | check( s.base == correct ); | ||
176 | /* | ||
177 | static int count; | ||
178 | if ( count == 1844 ) Debugger(); | ||
179 | if ( s.base != correct ) dprintf( "%ld\n", count ); | ||
180 | count++; | ||
181 | */ | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | // Check all values | ||
186 | check( (unsigned) sp - 0x100 < 0x100 ); | ||
187 | check( (unsigned) pc < 0x10000 + 0x100 ); // +0x100 so emulator can catch wrap-around | ||
188 | check( (unsigned) a < 0x100 ); | ||
189 | check( (unsigned) x < 0x100 ); | ||
190 | check( (unsigned) y < 0x100 ); | ||
191 | |||
192 | // Read instruction | ||
193 | byte const* instr = CODE_PAGE( pc ); | ||
194 | int opcode; | ||
195 | |||
196 | if ( CODE_OFFSET(~0) == ~0 ) | ||
197 | { | ||
198 | opcode = instr [pc]; | ||
199 | pc++; | ||
200 | instr += pc; | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | instr += CODE_OFFSET( pc ); | ||
205 | opcode = *instr++; | ||
206 | pc++; | ||
207 | } | ||
208 | |||
209 | // TODO: each reference lists slightly different timing values, ugh | ||
210 | static byte const clock_table [256] = | ||
211 | {// 0 1 2 3 4 5 6 7 8 9 A B C D E F | ||
212 | 1,7,3, 4,6,4,6,7,3,2,2,2,7,5,7,4,// 0 | ||
213 | 2,7,7, 4,6,4,6,7,2,5,2,2,7,5,7,4,// 1 | ||
214 | 7,7,3, 4,4,4,6,7,4,2,2,2,5,5,7,4,// 2 | ||
215 | 2,7,7, 2,4,4,6,7,2,5,2,2,5,5,7,4,// 3 | ||
216 | 7,7,3, 4,8,4,6,7,3,2,2,2,4,5,7,4,// 4 | ||
217 | 2,7,7, 5,2,4,6,7,2,5,3,2,2,5,7,4,// 5 | ||
218 | 7,7,2, 2,4,4,6,7,4,2,2,2,7,5,7,4,// 6 | ||
219 | 2,7,7,17,4,4,6,7,2,5,4,2,7,5,7,4,// 7 | ||
220 | 4,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,4,// 8 | ||
221 | 2,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,4,// 9 | ||
222 | 2,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,4,// A | ||
223 | 2,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,4,// B | ||
224 | 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,4,// C | ||
225 | 2,7,7,17,2,4,6,7,2,5,3,2,2,5,7,4,// D | ||
226 | 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,4,// E | ||
227 | 2,7,7,17,2,4,6,7,2,5,4,2,2,5,7,4 // F | ||
228 | }; // 0x00 was 8 | ||
229 | |||
230 | // Update time | ||
231 | if ( s_time >= 0 ) | ||
232 | goto out_of_time; | ||
233 | |||
234 | #ifdef HES_CPU_LOG_H | ||
235 | log_cpu( "new", pc - 1, opcode, instr [0], instr [1], instr [2], | ||
236 | instr [3], instr [4], instr [5], a, x, y ); | ||
237 | //log_opcode( opcode ); | ||
238 | #endif | ||
239 | |||
240 | s_time += clock_table [opcode]; | ||
241 | |||
242 | int data; | ||
243 | data = *instr; | ||
244 | |||
245 | switch ( opcode ) | ||
246 | { | ||
247 | // Macros | ||
248 | |||
249 | #define GET_MSB() (instr [1]) | ||
250 | #define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()); | ||
251 | #define GET_ADDR() GET_LE16( instr ) | ||
252 | |||
253 | // TODO: is the penalty really always added? the original 6502 was much better | ||
254 | //#define PAGE_PENALTY( lsb ) (void) (s_time += (lsb) >> 8) | ||
255 | #define PAGE_PENALTY( lsb ) | ||
256 | |||
257 | // Branch | ||
258 | |||
259 | // TODO: more efficient way to handle negative branch that wraps PC around | ||
260 | #define BRANCH_( cond, adj )\ | ||
261 | {\ | ||
262 | pc++;\ | ||
263 | if ( !(cond) ) goto loop;\ | ||
264 | pc = (uint16_t) (pc + SBYTE( data ));\ | ||
265 | s_time += adj;\ | ||
266 | goto loop;\ | ||
267 | } | ||
268 | |||
269 | #define BRANCH( cond ) BRANCH_( cond, 2 ) | ||
270 | |||
271 | case 0xF0: // BEQ | ||
272 | BRANCH( !BYTE( nz ) ); | ||
273 | |||
274 | case 0xD0: // BNE | ||
275 | BRANCH( BYTE( nz ) ); | ||
276 | |||
277 | case 0x10: // BPL | ||
278 | BRANCH( !IS_NEG ); | ||
279 | |||
280 | case 0x90: // BCC | ||
281 | BRANCH( !(c & 0x100) ) | ||
282 | |||
283 | case 0x30: // BMI | ||
284 | BRANCH( IS_NEG ) | ||
285 | |||
286 | case 0x50: // BVC | ||
287 | BRANCH( !(flags & v40) ) | ||
288 | |||
289 | case 0x70: // BVS | ||
290 | BRANCH( flags & v40 ) | ||
291 | |||
292 | case 0xB0: // BCS | ||
293 | BRANCH( c & 0x100 ) | ||
294 | |||
295 | case 0x80: // BRA | ||
296 | branch_taken: | ||
297 | BRANCH_( true, 0 ); | ||
298 | |||
299 | case 0xFF: | ||
300 | #ifdef IDLE_ADDR | ||
301 | if ( pc == IDLE_ADDR + 1 ) | ||
302 | goto idle_done; | ||
303 | #endif | ||
304 | |||
305 | pc = (uint16_t) pc; | ||
306 | |||
307 | case 0x0F: // BBRn | ||
308 | case 0x1F: | ||
309 | case 0x2F: | ||
310 | case 0x3F: | ||
311 | case 0x4F: | ||
312 | case 0x5F: | ||
313 | case 0x6F: | ||
314 | case 0x7F: | ||
315 | case 0x8F: // BBSn | ||
316 | case 0x9F: | ||
317 | case 0xAF: | ||
318 | case 0xBF: | ||
319 | case 0xCF: | ||
320 | case 0xDF: | ||
321 | case 0xEF: { | ||
322 | // Make two copies of bits, one negated | ||
323 | int t = 0x101 * READ_LOW( data ); | ||
324 | t ^= 0xFF; | ||
325 | pc++; | ||
326 | data = GET_MSB(); | ||
327 | BRANCH( t & (1 << (opcode >> 4)) ) | ||
328 | } | ||
329 | |||
330 | case 0x4C: // JMP abs | ||
331 | pc = GET_ADDR(); | ||
332 | goto loop; | ||
333 | |||
334 | case 0x7C: // JMP (ind+X) | ||
335 | data += x; | ||
336 | case 0x6C:{// JMP (ind) | ||
337 | data += 0x100 * GET_MSB(); | ||
338 | pc = GET_LE16( &READ_CODE( data ) ); | ||
339 | goto loop; | ||
340 | } | ||
341 | |||
342 | // Subroutine | ||
343 | |||
344 | case 0x44: // BSR | ||
345 | WRITE_STACK( SP( -1 ), pc >> 8 ); | ||
346 | sp = SP( -2 ); | ||
347 | WRITE_STACK( sp, pc ); | ||
348 | goto branch_taken; | ||
349 | |||
350 | case 0x20: { // JSR | ||
351 | int temp = pc + 1; | ||
352 | pc = GET_ADDR(); | ||
353 | WRITE_STACK( SP( -1 ), temp >> 8 ); | ||
354 | sp = SP( -2 ); | ||
355 | WRITE_STACK( sp, temp ); | ||
356 | goto loop; | ||
357 | } | ||
358 | |||
359 | case 0x60: // RTS | ||
360 | pc = 1 + READ_STACK( sp ); | ||
361 | pc += 0x100 * READ_STACK( SP( 1 ) ); | ||
362 | sp = SP( 2 ); | ||
363 | goto loop; | ||
364 | |||
365 | case 0x00: // BRK | ||
366 | goto handle_brk; | ||
367 | |||
368 | // Common | ||
369 | |||
370 | case 0xBD:{// LDA abs,X | ||
371 | PAGE_PENALTY( data + x ); | ||
372 | int addr = GET_ADDR() + x; | ||
373 | pc += 2; | ||
374 | READ_FAST( addr, nz ); | ||
375 | a = nz; | ||
376 | goto loop; | ||
377 | } | ||
378 | |||
379 | case 0x9D:{// STA abs,X | ||
380 | int addr = GET_ADDR() + x; | ||
381 | pc += 2; | ||
382 | WRITE_FAST( addr, a ); | ||
383 | goto loop; | ||
384 | } | ||
385 | |||
386 | case 0x95: // STA zp,x | ||
387 | data = BYTE( data + x ); | ||
388 | case 0x85: // STA zp | ||
389 | pc++; | ||
390 | WRITE_LOW( data, a ); | ||
391 | goto loop; | ||
392 | |||
393 | case 0xAE:{// LDX abs | ||
394 | int addr = GET_ADDR(); | ||
395 | pc += 2; | ||
396 | READ_FAST( addr, nz ); | ||
397 | x = nz; | ||
398 | goto loop; | ||
399 | } | ||
400 | |||
401 | case 0xA5: // LDA zp | ||
402 | a = nz = READ_LOW( data ); | ||
403 | pc++; | ||
404 | goto loop; | ||
405 | |||
406 | // Load/store | ||
407 | |||
408 | { | ||
409 | int addr; | ||
410 | case 0x91: // STA (ind),Y | ||
411 | addr = 0x100 * READ_LOW( BYTE( data + 1 ) ); | ||
412 | addr += READ_LOW( data ) + y; | ||
413 | pc++; | ||
414 | goto sta_ptr; | ||
415 | |||
416 | case 0x81: // STA (ind,X) | ||
417 | data = BYTE( data + x ); | ||
418 | case 0x92: // STA (ind) | ||
419 | addr = 0x100 * READ_LOW( BYTE( data + 1 ) ); | ||
420 | addr += READ_LOW( data ); | ||
421 | pc++; | ||
422 | goto sta_ptr; | ||
423 | |||
424 | case 0x99: // STA abs,Y | ||
425 | data += y; | ||
426 | case 0x8D: // STA abs | ||
427 | addr = data + 0x100 * GET_MSB(); | ||
428 | pc += 2; | ||
429 | sta_ptr: | ||
430 | WRITE_FAST( addr, a ); | ||
431 | goto loop; | ||
432 | } | ||
433 | |||
434 | { | ||
435 | int addr; | ||
436 | case 0xA1: // LDA (ind,X) | ||
437 | data = BYTE( data + x ); | ||
438 | case 0xB2: // LDA (ind) | ||
439 | addr = 0x100 * READ_LOW( BYTE( data + 1 ) ); | ||
440 | addr += READ_LOW( data ); | ||
441 | pc++; | ||
442 | goto a_nz_read_addr; | ||
443 | |||
444 | case 0xB1:// LDA (ind),Y | ||
445 | addr = READ_LOW( data ) + y; | ||
446 | PAGE_PENALTY( addr ); | ||
447 | addr += 0x100 * READ_LOW( BYTE( data + 1 ) ); | ||
448 | pc++; | ||
449 | goto a_nz_read_addr; | ||
450 | |||
451 | case 0xB9: // LDA abs,Y | ||
452 | data += y; | ||
453 | PAGE_PENALTY( data ); | ||
454 | case 0xAD: // LDA abs | ||
455 | addr = data + 0x100 * GET_MSB(); | ||
456 | pc += 2; | ||
457 | a_nz_read_addr: | ||
458 | READ_FAST( addr, nz ); | ||
459 | a = nz; | ||
460 | goto loop; | ||
461 | } | ||
462 | |||
463 | case 0xBE:{// LDX abs,y | ||
464 | PAGE_PENALTY( data + y ); | ||
465 | int addr = GET_ADDR() + y; | ||
466 | pc += 2; | ||
467 | FLUSH_TIME(); | ||
468 | x = nz = READ_MEM( addr ); | ||
469 | CACHE_TIME(); | ||
470 | goto loop; | ||
471 | } | ||
472 | |||
473 | case 0xB5: // LDA zp,x | ||
474 | a = nz = READ_LOW( BYTE( data + x ) ); | ||
475 | pc++; | ||
476 | goto loop; | ||
477 | |||
478 | case 0xA9: // LDA #imm | ||
479 | pc++; | ||
480 | a = data; | ||
481 | nz = data; | ||
482 | goto loop; | ||
483 | |||
484 | // Bit operations | ||
485 | |||
486 | case 0x3C: // BIT abs,x | ||
487 | data += x; | ||
488 | case 0x2C:{// BIT abs | ||
489 | int addr; | ||
490 | ADD_PAGE( addr ); | ||
491 | FLUSH_TIME(); | ||
492 | nz = READ_MEM( addr ); | ||
493 | CACHE_TIME(); | ||
494 | goto bit_common; | ||
495 | } | ||
496 | case 0x34: // BIT zp,x | ||
497 | data = BYTE( data + x ); | ||
498 | case 0x24: // BIT zp | ||
499 | data = READ_LOW( data ); | ||
500 | case 0x89: // BIT imm | ||
501 | nz = data; | ||
502 | bit_common: | ||
503 | pc++; | ||
504 | flags = (flags & ~v40) + (nz & v40); | ||
505 | if ( nz & a ) | ||
506 | goto loop; // Z should be clear, and nz must be non-zero if nz & a is | ||
507 | nz <<= 8; // set Z flag without affecting N flag | ||
508 | goto loop; | ||
509 | |||
510 | { | ||
511 | int addr; | ||
512 | |||
513 | case 0xB3: // TST abs,x | ||
514 | addr = GET_MSB() + x; | ||
515 | goto tst_abs; | ||
516 | |||
517 | case 0x93: // TST abs | ||
518 | addr = GET_MSB(); | ||
519 | tst_abs: | ||
520 | addr += 0x100 * instr [2]; | ||
521 | pc++; | ||
522 | FLUSH_TIME(); | ||
523 | nz = READ_MEM( addr ); | ||
524 | CACHE_TIME(); | ||
525 | goto tst_common; | ||
526 | } | ||
527 | |||
528 | case 0xA3: // TST zp,x | ||
529 | nz = READ_LOW( BYTE( GET_MSB() + x ) ); | ||
530 | goto tst_common; | ||
531 | |||
532 | case 0x83: // TST zp | ||
533 | nz = READ_LOW( GET_MSB() ); | ||
534 | tst_common: | ||
535 | pc += 2; | ||
536 | flags = (flags & ~v40) + (nz & v40); | ||
537 | if ( nz & data ) | ||
538 | goto loop; // Z should be clear, and nz must be non-zero if nz & data is | ||
539 | nz <<= 8; // set Z flag without affecting N flag | ||
540 | goto loop; | ||
541 | |||
542 | { | ||
543 | int addr; | ||
544 | case 0x0C: // TSB abs | ||
545 | case 0x1C: // TRB abs | ||
546 | addr = GET_ADDR(); | ||
547 | pc++; | ||
548 | goto txb_addr; | ||
549 | |||
550 | // TODO: everyone lists different behaviors for the flags flags, ugh | ||
551 | case 0x04: // TSB zp | ||
552 | case 0x14: // TRB zp | ||
553 | addr = data + ram_addr; | ||
554 | txb_addr: | ||
555 | FLUSH_TIME(); | ||
556 | nz = a | READ_MEM( addr ); | ||
557 | if ( opcode & 0x10 ) | ||
558 | nz ^= a; // bits from a will already be set, so this clears them | ||
559 | flags = (flags & ~v40) + (nz & v40); | ||
560 | pc++; | ||
561 | WRITE_MEM( addr, nz ); | ||
562 | CACHE_TIME(); | ||
563 | goto loop; | ||
564 | } | ||
565 | |||
566 | case 0x07: // RMBn | ||
567 | case 0x17: | ||
568 | case 0x27: | ||
569 | case 0x37: | ||
570 | case 0x47: | ||
571 | case 0x57: | ||
572 | case 0x67: | ||
573 | case 0x77: | ||
574 | pc++; | ||
575 | READ_LOW( data ) &= ~(1 << (opcode >> 4)); | ||
576 | goto loop; | ||
577 | |||
578 | case 0x87: // SMBn | ||
579 | case 0x97: | ||
580 | case 0xA7: | ||
581 | case 0xB7: | ||
582 | case 0xC7: | ||
583 | case 0xD7: | ||
584 | case 0xE7: | ||
585 | case 0xF7: | ||
586 | pc++; | ||
587 | READ_LOW( data ) |= 1 << ((opcode >> 4) - 8); | ||
588 | goto loop; | ||
589 | |||
590 | // Load/store | ||
591 | |||
592 | case 0x9E: // STZ abs,x | ||
593 | data += x; | ||
594 | case 0x9C: // STZ abs | ||
595 | ADD_PAGE( data ); | ||
596 | pc++; | ||
597 | FLUSH_TIME(); | ||
598 | WRITE_MEM( data, 0 ); | ||
599 | CACHE_TIME(); | ||
600 | goto loop; | ||
601 | |||
602 | case 0x74: // STZ zp,x | ||
603 | data = BYTE( data + x ); | ||
604 | case 0x64: // STZ zp | ||
605 | pc++; | ||
606 | WRITE_LOW( data, 0 ); | ||
607 | goto loop; | ||
608 | |||
609 | case 0x94: // STY zp,x | ||
610 | data = BYTE( data + x ); | ||
611 | case 0x84: // STY zp | ||
612 | pc++; | ||
613 | WRITE_LOW( data, y ); | ||
614 | goto loop; | ||
615 | |||
616 | case 0x96: // STX zp,y | ||
617 | data = BYTE( data + y ); | ||
618 | case 0x86: // STX zp | ||
619 | pc++; | ||
620 | WRITE_LOW( data, x ); | ||
621 | goto loop; | ||
622 | |||
623 | case 0xB6: // LDX zp,y | ||
624 | data = BYTE( data + y ); | ||
625 | case 0xA6: // LDX zp | ||
626 | data = READ_LOW( data ); | ||
627 | case 0xA2: // LDX #imm | ||
628 | pc++; | ||
629 | x = data; | ||
630 | nz = data; | ||
631 | goto loop; | ||
632 | |||
633 | case 0xB4: // LDY zp,x | ||
634 | data = BYTE( data + x ); | ||
635 | case 0xA4: // LDY zp | ||
636 | data = READ_LOW( data ); | ||
637 | case 0xA0: // LDY #imm | ||
638 | pc++; | ||
639 | y = data; | ||
640 | nz = data; | ||
641 | goto loop; | ||
642 | |||
643 | case 0xBC: // LDY abs,X | ||
644 | data += x; | ||
645 | PAGE_PENALTY( data ); | ||
646 | case 0xAC:{// LDY abs | ||
647 | int addr = data + 0x100 * GET_MSB(); | ||
648 | pc += 2; | ||
649 | FLUSH_TIME(); | ||
650 | y = nz = READ_MEM( addr ); | ||
651 | CACHE_TIME(); | ||
652 | goto loop; | ||
653 | } | ||
654 | |||
655 | { | ||
656 | int temp; | ||
657 | case 0x8C: // STY abs | ||
658 | temp = y; | ||
659 | if ( 0 ) | ||
660 | case 0x8E: // STX abs | ||
661 | temp = x; | ||
662 | int addr = GET_ADDR(); | ||
663 | pc += 2; | ||
664 | FLUSH_TIME(); | ||
665 | WRITE_MEM( addr, temp ); | ||
666 | CACHE_TIME(); | ||
667 | goto loop; | ||
668 | } | ||
669 | |||
670 | // Compare | ||
671 | |||
672 | case 0xEC:{// CPX abs | ||
673 | int addr = GET_ADDR(); | ||
674 | pc++; | ||
675 | FLUSH_TIME(); | ||
676 | data = READ_MEM( addr ); | ||
677 | CACHE_TIME(); | ||
678 | goto cpx_data; | ||
679 | } | ||
680 | |||
681 | case 0xE4: // CPX zp | ||
682 | data = READ_LOW( data ); | ||
683 | case 0xE0: // CPX #imm | ||
684 | cpx_data: | ||
685 | nz = x - data; | ||
686 | pc++; | ||
687 | c = ~nz; | ||
688 | nz = BYTE( nz ); | ||
689 | goto loop; | ||
690 | |||
691 | case 0xCC:{// CPY abs | ||
692 | int addr = GET_ADDR(); | ||
693 | pc++; | ||
694 | FLUSH_TIME(); | ||
695 | data = READ_MEM( addr ); | ||
696 | CACHE_TIME(); | ||
697 | goto cpy_data; | ||
698 | } | ||
699 | |||
700 | case 0xC4: // CPY zp | ||
701 | data = READ_LOW( data ); | ||
702 | case 0xC0: // CPY #imm | ||
703 | cpy_data: | ||
704 | nz = y - data; | ||
705 | pc++; | ||
706 | c = ~nz; | ||
707 | nz = BYTE( nz ); | ||
708 | goto loop; | ||
709 | |||
710 | // Logical | ||
711 | |||
712 | #define ARITH_ADDR_MODES( op )\ | ||
713 | case op - 0x04: /* (ind,x) */\ | ||
714 | data = BYTE( data + x );\ | ||
715 | case op + 0x0D: /* (ind) */\ | ||
716 | data = 0x100 * READ_LOW( BYTE( data + 1 ) ) + READ_LOW( data );\ | ||
717 | goto ptr##op;\ | ||
718 | case op + 0x0C:{/* (ind),y */\ | ||
719 | int temp = READ_LOW( data ) + y;\ | ||
720 | PAGE_PENALTY( temp );\ | ||
721 | data = temp + 0x100 * READ_LOW( BYTE( data + 1 ) );\ | ||
722 | goto ptr##op;\ | ||
723 | }\ | ||
724 | case op + 0x10: /* zp,X */\ | ||
725 | data = BYTE( data + x );\ | ||
726 | case op + 0x00: /* zp */\ | ||
727 | data = READ_LOW( data );\ | ||
728 | goto imm##op;\ | ||
729 | case op + 0x14: /* abs,Y */\ | ||
730 | data += y;\ | ||
731 | goto ind##op;\ | ||
732 | case op + 0x18: /* abs,X */\ | ||
733 | data += x;\ | ||
734 | ind##op:\ | ||
735 | PAGE_PENALTY( data );\ | ||
736 | case op + 0x08: /* abs */\ | ||
737 | ADD_PAGE( data );\ | ||
738 | ptr##op:\ | ||
739 | FLUSH_TIME();\ | ||
740 | data = READ_MEM( data );\ | ||
741 | CACHE_TIME();\ | ||
742 | case op + 0x04: /* imm */\ | ||
743 | imm##op: | ||
744 | |||
745 | ARITH_ADDR_MODES( 0xC5 ) // CMP | ||
746 | nz = a - data; | ||
747 | pc++; | ||
748 | c = ~nz; | ||
749 | nz = BYTE( nz ); | ||
750 | goto loop; | ||
751 | |||
752 | ARITH_ADDR_MODES( 0x25 ) // AND | ||
753 | nz = (a &= data); | ||
754 | pc++; | ||
755 | goto loop; | ||
756 | |||
757 | ARITH_ADDR_MODES( 0x45 ) // EOR | ||
758 | nz = (a ^= data); | ||
759 | pc++; | ||
760 | goto loop; | ||
761 | |||
762 | ARITH_ADDR_MODES( 0x05 ) // ORA | ||
763 | nz = (a |= data); | ||
764 | pc++; | ||
765 | goto loop; | ||
766 | |||
767 | // Add/subtract | ||
768 | |||
769 | ARITH_ADDR_MODES( 0xE5 ) // SBC | ||
770 | data ^= 0xFF; | ||
771 | goto adc_imm; | ||
772 | |||
773 | ARITH_ADDR_MODES( 0x65 ) // ADC | ||
774 | adc_imm: { | ||
775 | /* if ( flags & d08 ) | ||
776 | dprintf( "Decimal mode not supported\n" ); */ | ||
777 | int carry = c >> 8 & 1; | ||
778 | int ov = (a ^ 0x80) + carry + SBYTE( data ); | ||
779 | flags = (flags & ~v40) + (ov >> 2 & v40); | ||
780 | c = nz = a + data + carry; | ||
781 | pc++; | ||
782 | a = BYTE( nz ); | ||
783 | goto loop; | ||
784 | } | ||
785 | |||
786 | // Shift/rotate | ||
787 | |||
788 | case 0x4A: // LSR A | ||
789 | c = 0; | ||
790 | case 0x6A: // ROR A | ||
791 | nz = c >> 1 & 0x80; | ||
792 | c = a << 8; | ||
793 | nz += a >> 1; | ||
794 | a = nz; | ||
795 | goto loop; | ||
796 | |||
797 | case 0x0A: // ASL A | ||
798 | nz = a << 1; | ||
799 | c = nz; | ||
800 | a = BYTE( nz ); | ||
801 | goto loop; | ||
802 | |||
803 | case 0x2A: { // ROL A | ||
804 | nz = a << 1; | ||
805 | int temp = c >> 8 & 1; | ||
806 | c = nz; | ||
807 | nz += temp; | ||
808 | a = BYTE( nz ); | ||
809 | goto loop; | ||
810 | } | ||
811 | |||
812 | case 0x5E: // LSR abs,X | ||
813 | data += x; | ||
814 | case 0x4E: // LSR abs | ||
815 | c = 0; | ||
816 | case 0x6E: // ROR abs | ||
817 | ror_abs: { | ||
818 | ADD_PAGE( data ); | ||
819 | FLUSH_TIME(); | ||
820 | int temp = READ_MEM( data ); | ||
821 | nz = (c >> 1 & 0x80) + (temp >> 1); | ||
822 | c = temp << 8; | ||
823 | goto rotate_common; | ||
824 | } | ||
825 | |||
826 | case 0x3E: // ROL abs,X | ||
827 | data += x; | ||
828 | goto rol_abs; | ||
829 | |||
830 | case 0x1E: // ASL abs,X | ||
831 | data += x; | ||
832 | case 0x0E: // ASL abs | ||
833 | c = 0; | ||
834 | case 0x2E: // ROL abs | ||
835 | rol_abs: | ||
836 | ADD_PAGE( data ); | ||
837 | nz = c >> 8 & 1; | ||
838 | FLUSH_TIME(); | ||
839 | nz += (c = READ_MEM( data ) << 1); | ||
840 | rotate_common: | ||
841 | pc++; | ||
842 | WRITE_MEM( data, BYTE( nz ) ); | ||
843 | CACHE_TIME(); | ||
844 | goto loop; | ||
845 | |||
846 | case 0x7E: // ROR abs,X | ||
847 | data += x; | ||
848 | goto ror_abs; | ||
849 | |||
850 | case 0x76: // ROR zp,x | ||
851 | data = BYTE( data + x ); | ||
852 | goto ror_zp; | ||
853 | |||
854 | case 0x56: // LSR zp,x | ||
855 | data = BYTE( data + x ); | ||
856 | case 0x46: // LSR zp | ||
857 | c = 0; | ||
858 | case 0x66: // ROR zp | ||
859 | ror_zp: { | ||
860 | int temp = READ_LOW( data ); | ||
861 | nz = (c >> 1 & 0x80) + (temp >> 1); | ||
862 | c = temp << 8; | ||
863 | goto write_nz_zp; | ||
864 | } | ||
865 | |||
866 | case 0x36: // ROL zp,x | ||
867 | data = BYTE( data + x ); | ||
868 | goto rol_zp; | ||
869 | |||
870 | case 0x16: // ASL zp,x | ||
871 | data = BYTE( data + x ); | ||
872 | case 0x06: // ASL zp | ||
873 | c = 0; | ||
874 | case 0x26: // ROL zp | ||
875 | rol_zp: | ||
876 | nz = c >> 8 & 1; | ||
877 | nz += (c = READ_LOW( data ) << 1); | ||
878 | goto write_nz_zp; | ||
879 | |||
880 | // Increment/decrement | ||
881 | |||
882 | #define INC_DEC( reg, n ) reg = BYTE( nz = reg + n ); goto loop; | ||
883 | |||
884 | case 0x1A: // INA | ||
885 | INC_DEC( a, +1 ) | ||
886 | |||
887 | case 0xE8: // INX | ||
888 | INC_DEC( x, +1 ) | ||
889 | |||
890 | case 0xC8: // INY | ||
891 | INC_DEC( y, +1 ) | ||
892 | |||
893 | case 0x3A: // DEA | ||
894 | INC_DEC( a, -1 ) | ||
895 | |||
896 | case 0xCA: // DEX | ||
897 | INC_DEC( x, -1 ) | ||
898 | |||
899 | case 0x88: // DEY | ||
900 | INC_DEC( y, -1 ) | ||
901 | |||
902 | case 0xF6: // INC zp,x | ||
903 | data = BYTE( data + x ); | ||
904 | case 0xE6: // INC zp | ||
905 | nz = 1; | ||
906 | goto add_nz_zp; | ||
907 | |||
908 | case 0xD6: // DEC zp,x | ||
909 | data = BYTE( data + x ); | ||
910 | case 0xC6: // DEC zp | ||
911 | nz = -1; | ||
912 | add_nz_zp: | ||
913 | nz += READ_LOW( data ); | ||
914 | write_nz_zp: | ||
915 | pc++; | ||
916 | WRITE_LOW( data, nz ); | ||
917 | goto loop; | ||
918 | |||
919 | case 0xFE: // INC abs,x | ||
920 | data = x + GET_ADDR(); | ||
921 | goto inc_ptr; | ||
922 | |||
923 | case 0xEE: // INC abs | ||
924 | data = GET_ADDR(); | ||
925 | inc_ptr: | ||
926 | nz = 1; | ||
927 | goto inc_common; | ||
928 | |||
929 | case 0xDE: // DEC abs,x | ||
930 | data = x + GET_ADDR(); | ||
931 | goto dec_ptr; | ||
932 | |||
933 | case 0xCE: // DEC abs | ||
934 | data = GET_ADDR(); | ||
935 | dec_ptr: | ||
936 | nz = -1; | ||
937 | inc_common: | ||
938 | FLUSH_TIME(); | ||
939 | pc += 2; | ||
940 | nz += READ_MEM( data ); | ||
941 | WRITE_MEM( data, BYTE( nz ) ); | ||
942 | CACHE_TIME(); | ||
943 | goto loop; | ||
944 | |||
945 | // Transfer | ||
946 | |||
947 | case 0xA8: // TAY | ||
948 | y = nz = a; | ||
949 | goto loop; | ||
950 | |||
951 | case 0x98: // TYA | ||
952 | a = nz = y; | ||
953 | goto loop; | ||
954 | |||
955 | case 0xAA: // TAX | ||
956 | x = nz = a; | ||
957 | goto loop; | ||
958 | |||
959 | case 0x8A: // TXA | ||
960 | a = nz = x; | ||
961 | goto loop; | ||
962 | |||
963 | case 0x9A: // TXS | ||
964 | SET_SP( x ); // verified (no flag change) | ||
965 | goto loop; | ||
966 | |||
967 | case 0xBA: // TSX | ||
968 | x = nz = GET_SP(); | ||
969 | goto loop; | ||
970 | |||
971 | #define SWAP_REGS( r1, r2 ) {\ | ||
972 | int t = r1;\ | ||
973 | r1 = r2;\ | ||
974 | r2 = t;\ | ||
975 | goto loop;\ | ||
976 | } | ||
977 | |||
978 | case 0x02: // SXY | ||
979 | SWAP_REGS( x, y ); | ||
980 | |||
981 | case 0x22: // SAX | ||
982 | SWAP_REGS( a, x ); | ||
983 | |||
984 | case 0x42: // SAY | ||
985 | SWAP_REGS( a, y ); | ||
986 | |||
987 | case 0x62: // CLA | ||
988 | a = 0; | ||
989 | goto loop; | ||
990 | |||
991 | case 0x82: // CLX | ||
992 | x = 0; | ||
993 | goto loop; | ||
994 | |||
995 | case 0xC2: // CLY | ||
996 | y = 0; | ||
997 | goto loop; | ||
998 | |||
999 | // Stack | ||
1000 | |||
1001 | case 0x48: // PHA | ||
1002 | sp = SP( -1 ); | ||
1003 | WRITE_STACK( sp, a ); | ||
1004 | goto loop; | ||
1005 | |||
1006 | case 0x68: // PLA | ||
1007 | a = nz = READ_STACK( sp ); | ||
1008 | sp = SP( 1 ); | ||
1009 | goto loop; | ||
1010 | |||
1011 | case 0xDA: // PHX | ||
1012 | sp = SP( -1 ); | ||
1013 | WRITE_STACK( sp, x ); | ||
1014 | goto loop; | ||
1015 | |||
1016 | case 0x5A: // PHY | ||
1017 | sp = SP( -1 ); | ||
1018 | WRITE_STACK( sp, y ); | ||
1019 | goto loop; | ||
1020 | |||
1021 | case 0x40:{// RTI | ||
1022 | pc = READ_STACK( SP( 1 ) ); | ||
1023 | pc += READ_STACK( SP( 2 ) ) * 0x100; | ||
1024 | int temp = READ_STACK( sp ); | ||
1025 | sp = SP( 3 ); | ||
1026 | data = flags; | ||
1027 | SET_FLAGS( temp ); | ||
1028 | cpu->r.flags = flags; // update externally-visible I flag | ||
1029 | if ( (data ^ flags) & i04 ) | ||
1030 | { | ||
1031 | hes_time_t new_time = cpu->end_time_; | ||
1032 | if ( !(flags & i04) && new_time > cpu->irq_time_ ) | ||
1033 | new_time = cpu->irq_time_; | ||
1034 | int delta = s.base - new_time; | ||
1035 | s.base = new_time; | ||
1036 | s_time += delta; | ||
1037 | } | ||
1038 | goto loop; | ||
1039 | } | ||
1040 | |||
1041 | case 0xFA: // PLX | ||
1042 | x = nz = READ_STACK( sp ); | ||
1043 | sp = SP( 1 ); | ||
1044 | goto loop; | ||
1045 | |||
1046 | case 0x7A: // PLY | ||
1047 | y = nz = READ_STACK( sp ); | ||
1048 | sp = SP( 1 ); | ||
1049 | goto loop; | ||
1050 | |||
1051 | case 0x28:{// PLP | ||
1052 | int temp = READ_STACK( sp ); | ||
1053 | sp = SP( 1 ); | ||
1054 | int changed = flags ^ temp; | ||
1055 | SET_FLAGS( temp ); | ||
1056 | if ( !(changed & i04) ) | ||
1057 | goto loop; // I flag didn't change | ||
1058 | if ( flags & i04 ) | ||
1059 | goto handle_sei; | ||
1060 | goto handle_cli; | ||
1061 | } | ||
1062 | |||
1063 | case 0x08:{// PHP | ||
1064 | int temp; | ||
1065 | GET_FLAGS( temp ); | ||
1066 | sp = SP( -1 ); | ||
1067 | WRITE_STACK( sp, temp | b10 ); | ||
1068 | goto loop; | ||
1069 | } | ||
1070 | |||
1071 | // Flags | ||
1072 | |||
1073 | case 0x38: // SEC | ||
1074 | c = 0x100; | ||
1075 | goto loop; | ||
1076 | |||
1077 | case 0x18: // CLC | ||
1078 | c = 0; | ||
1079 | goto loop; | ||
1080 | |||
1081 | case 0xB8: // CLV | ||
1082 | flags &= ~v40; | ||
1083 | goto loop; | ||
1084 | |||
1085 | case 0xD8: // CLD | ||
1086 | flags &= ~d08; | ||
1087 | goto loop; | ||
1088 | |||
1089 | case 0xF8: // SED | ||
1090 | flags |= d08; | ||
1091 | goto loop; | ||
1092 | |||
1093 | case 0x58: // CLI | ||
1094 | if ( !(flags & i04) ) | ||
1095 | goto loop; | ||
1096 | flags &= ~i04; | ||
1097 | handle_cli: { | ||
1098 | //dprintf( "CLI at %d\n", TIME ); | ||
1099 | cpu->r.flags = flags; // update externally-visible I flag | ||
1100 | int delta = s.base - cpu->irq_time_; | ||
1101 | if ( delta <= 0 ) | ||
1102 | { | ||
1103 | if ( TIME() < cpu->irq_time_ ) | ||
1104 | goto loop; | ||
1105 | goto delayed_cli; | ||
1106 | } | ||
1107 | s.base = cpu->irq_time_; | ||
1108 | s_time += delta; | ||
1109 | if ( s_time < 0 ) | ||
1110 | goto loop; | ||
1111 | |||
1112 | if ( delta >= s_time + 1 ) | ||
1113 | { | ||
1114 | // delayed irq until after next instruction | ||
1115 | s.base += s_time + 1; | ||
1116 | s_time = -1; | ||
1117 | cpu->irq_time_ = s.base; // TODO: remove, as only to satisfy debug check in loop | ||
1118 | goto loop; | ||
1119 | } | ||
1120 | |||
1121 | // TODO: implement | ||
1122 | delayed_cli: | ||
1123 | dprintf( "Delayed CLI not supported\n" ); | ||
1124 | goto loop; | ||
1125 | } | ||
1126 | |||
1127 | case 0x78: // SEI | ||
1128 | if ( flags & i04 ) | ||
1129 | goto loop; | ||
1130 | flags |= i04; | ||
1131 | handle_sei: { | ||
1132 | cpu->r.flags = flags; // update externally-visible I flag | ||
1133 | int delta = s.base - cpu->end_time_; | ||
1134 | s.base = cpu->end_time_; | ||
1135 | s_time += delta; | ||
1136 | if ( s_time < 0 ) | ||
1137 | goto loop; | ||
1138 | |||
1139 | dprintf( "Delayed SEI not supported\n" ); | ||
1140 | goto loop; | ||
1141 | } | ||
1142 | |||
1143 | // Special | ||
1144 | |||
1145 | case 0x53:{// TAM | ||
1146 | int bits = data; // avoid using data across function call | ||
1147 | pc++; | ||
1148 | for ( int i = 0; i < 8; i++ ) | ||
1149 | if ( bits & (1 << i) ) | ||
1150 | SET_MMR( i, a ); | ||
1151 | goto loop; | ||
1152 | } | ||
1153 | |||
1154 | case 0x43:{// TMA | ||
1155 | pc++; | ||
1156 | byte const* in = cpu->mmr; | ||
1157 | do | ||
1158 | { | ||
1159 | if ( data & 1 ) | ||
1160 | a = *in; | ||
1161 | in++; | ||
1162 | } | ||
1163 | while ( (data >>= 1) != 0 ); | ||
1164 | goto loop; | ||
1165 | } | ||
1166 | |||
1167 | case 0x03: // ST0 | ||
1168 | case 0x13: // ST1 | ||
1169 | case 0x23:{// ST2 | ||
1170 | int addr = opcode >> 4; | ||
1171 | if ( addr ) | ||
1172 | addr++; | ||
1173 | pc++; | ||
1174 | FLUSH_TIME(); | ||
1175 | WRITE_VDP( addr, data ); | ||
1176 | CACHE_TIME(); | ||
1177 | goto loop; | ||
1178 | } | ||
1179 | |||
1180 | case 0xEA: // NOP | ||
1181 | goto loop; | ||
1182 | |||
1183 | case 0x54: // CSL | ||
1184 | dprintf( "CSL not supported\n" ); | ||
1185 | illegal_encountered = true; | ||
1186 | goto loop; | ||
1187 | |||
1188 | case 0xD4: // CSH | ||
1189 | goto loop; | ||
1190 | |||
1191 | case 0xF4: { // SET | ||
1192 | //int operand = GET_MSB(); | ||
1193 | dprintf( "SET not handled\n" ); | ||
1194 | //switch ( data ) | ||
1195 | //{ | ||
1196 | //} | ||
1197 | illegal_encountered = true; | ||
1198 | goto loop; | ||
1199 | } | ||
1200 | |||
1201 | // Block transfer | ||
1202 | |||
1203 | { | ||
1204 | int in_alt; | ||
1205 | int in_inc; | ||
1206 | int out_alt; | ||
1207 | int out_inc; | ||
1208 | |||
1209 | case 0xE3: // TIA | ||
1210 | in_alt = 0; | ||
1211 | goto bxfer_alt; | ||
1212 | |||
1213 | case 0xF3: // TAI | ||
1214 | in_alt = 1; | ||
1215 | bxfer_alt: | ||
1216 | in_inc = in_alt ^ 1; | ||
1217 | out_alt = in_inc; | ||
1218 | out_inc = in_alt; | ||
1219 | goto bxfer; | ||
1220 | |||
1221 | case 0xD3: // TIN | ||
1222 | in_inc = 1; | ||
1223 | out_inc = 0; | ||
1224 | goto bxfer_no_alt; | ||
1225 | |||
1226 | case 0xC3: // TDD | ||
1227 | in_inc = -1; | ||
1228 | out_inc = -1; | ||
1229 | goto bxfer_no_alt; | ||
1230 | |||
1231 | case 0x73: // TII | ||
1232 | in_inc = 1; | ||
1233 | out_inc = 1; | ||
1234 | bxfer_no_alt: | ||
1235 | in_alt = 0; | ||
1236 | out_alt = 0; | ||
1237 | bxfer: | ||
1238 | { | ||
1239 | int in = GET_LE16( instr + 0 ); | ||
1240 | int out = GET_LE16( instr + 2 ); | ||
1241 | int count = GET_LE16( instr + 4 ); | ||
1242 | if ( !count ) | ||
1243 | count = 0x10000; | ||
1244 | pc += 6; | ||
1245 | WRITE_STACK( SP( -1 ), y ); | ||
1246 | WRITE_STACK( SP( -2 ), a ); | ||
1247 | WRITE_STACK( SP( -3 ), x ); | ||
1248 | FLUSH_TIME(); | ||
1249 | do | ||
1250 | { | ||
1251 | // TODO: reads from $0800-$1400 in I/O page should do I/O | ||
1252 | int t = READ_MEM( in ); | ||
1253 | in = WORD( in + in_inc ); | ||
1254 | s.time += 6; | ||
1255 | if ( in_alt ) | ||
1256 | in_inc = -in_inc; | ||
1257 | WRITE_MEM( out, t ); | ||
1258 | out = WORD( out + out_inc ); | ||
1259 | if ( out_alt ) | ||
1260 | out_inc = -out_inc; | ||
1261 | } | ||
1262 | while ( --count ); | ||
1263 | CACHE_TIME(); | ||
1264 | goto loop; | ||
1265 | } | ||
1266 | } | ||
1267 | |||
1268 | // Illegal | ||
1269 | |||
1270 | default: | ||
1271 | check( (unsigned) opcode <= 0xFF ); | ||
1272 | dprintf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 ); | ||
1273 | illegal_encountered = true; | ||
1274 | goto loop; | ||
1275 | } | ||
1276 | assert( false ); // catch missing 'goto loop' or accidental 'break' | ||
1277 | |||
1278 | int result_; | ||
1279 | handle_brk: | ||
1280 | pc++; | ||
1281 | result_ = 6; | ||
1282 | |||
1283 | interrupt: | ||
1284 | { | ||
1285 | s_time += 7; | ||
1286 | |||
1287 | // Save PC and read vector | ||
1288 | WRITE_STACK( SP( -1 ), pc >> 8 ); | ||
1289 | WRITE_STACK( SP( -2 ), pc ); | ||
1290 | pc = GET_LE16( &READ_CODE( 0xFFF0 ) + result_ ); | ||
1291 | |||
1292 | // Save flags | ||
1293 | int temp; | ||
1294 | GET_FLAGS( temp ); | ||
1295 | if ( result_ == 6 ) | ||
1296 | temp |= b10; // BRK sets B bit | ||
1297 | sp = SP( -3 ); | ||
1298 | WRITE_STACK( sp, temp ); | ||
1299 | |||
1300 | // Update I flag in externally-visible flags | ||
1301 | flags &= ~d08; | ||
1302 | cpu->r.flags = (flags |= i04); | ||
1303 | |||
1304 | // Update time | ||
1305 | int delta = s.base - cpu->end_time_; | ||
1306 | if ( delta >= 0 ) | ||
1307 | goto loop; | ||
1308 | s_time += delta; | ||
1309 | s.base = cpu->end_time_; | ||
1310 | goto loop; | ||
1311 | } | ||
1312 | |||
1313 | idle_done: | ||
1314 | s_time = 0; | ||
1315 | |||
1316 | out_of_time: | ||
1317 | pc--; | ||
1318 | |||
1319 | // Optional action that triggers interrupt or changes irq/end time | ||
1320 | #ifdef CPU_DONE | ||
1321 | { | ||
1322 | CPU_DONE( result_ ); | ||
1323 | if ( result_ >= 0 ) | ||
1324 | goto interrupt; | ||
1325 | if ( s_time < 0 ) | ||
1326 | goto loop; | ||
1327 | } | ||
1328 | #endif | ||
1329 | |||
1330 | // Flush cached state | ||
1331 | cpu->r.pc = pc; | ||
1332 | cpu->r.sp = GET_SP(); | ||
1333 | cpu->r.a = a; | ||
1334 | cpu->r.x = x; | ||
1335 | cpu->r.y = y; | ||
1336 | |||
1337 | int temp; | ||
1338 | GET_FLAGS( temp ); | ||
1339 | cpu->r.flags = temp; | ||
1340 | |||
1341 | cpu->cpu_state_.base = s.base; | ||
1342 | cpu->cpu_state_.time = s_time; | ||
1343 | cpu->cpu_state = &cpu->cpu_state_; | ||
1344 | } | ||
diff --git a/apps/codecs/libgme/hes_emu.c b/apps/codecs/libgme/hes_emu.c index a428bee3fd..8ddbb9dc29 100644 --- a/apps/codecs/libgme/hes_emu.c +++ b/apps/codecs/libgme/hes_emu.c | |||
@@ -21,28 +21,14 @@ int const vdp_mask = 0x02; | |||
21 | int const i_flag_mask = 0x04; | 21 | int const i_flag_mask = 0x04; |
22 | int const unmapped = 0xFF; | 22 | int const unmapped = 0xFF; |
23 | 23 | ||
24 | long const period_60hz = 262 * 455L; // scanlines * clocks per scanline | 24 | int const period_60hz = 262 * 455; // scanlines * clocks per scanline |
25 | |||
26 | int const stereo = 2; // number of channels for stereo | ||
27 | int const silence_max = 6; // seconds | ||
28 | int const silence_threshold = 0x10; | ||
29 | long const fade_block_size = 512; | ||
30 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
31 | 25 | ||
32 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; | 26 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; |
33 | 27 | ||
34 | static void clear_track_vars( struct Hes_Emu* this ) | 28 | static void clear_track_vars( struct Hes_Emu* this ) |
35 | { | 29 | { |
36 | this->current_track_ = -1; | 30 | this->current_track_ = -1; |
37 | this->out_time = 0; | 31 | track_stop( &this->track_filter ); |
38 | this->emu_time = 0; | ||
39 | this->emu_track_ended_ = true; | ||
40 | this->track_ended = true; | ||
41 | this->fade_start = (blargg_long)(LONG_MAX / 2 + 1); | ||
42 | this->fade_step = 1; | ||
43 | this->silence_time = 0; | ||
44 | this->silence_count = 0; | ||
45 | this->buf_remain = 0; | ||
46 | } | 32 | } |
47 | 33 | ||
48 | void Hes_init( struct Hes_Emu* this ) | 34 | void Hes_init( struct Hes_Emu* this ) |
@@ -52,15 +38,12 @@ void Hes_init( struct Hes_Emu* this ) | |||
52 | this->tempo_ = (int)(FP_ONE_TEMPO); | 38 | this->tempo_ = (int)(FP_ONE_TEMPO); |
53 | 39 | ||
54 | // defaults | 40 | // defaults |
55 | this->max_initial_silence = 2; | 41 | this->tfilter = *track_get_setup( &this->track_filter ); |
56 | this->ignore_silence = false; | 42 | this->tfilter.max_initial = 2; |
57 | 43 | this->tfilter.lookahead = 6; | |
58 | // Unload | 44 | this->track_filter.silence_ignored_ = false; |
59 | this->voice_count_ = 0; | ||
60 | clear_track_vars( this ); | ||
61 | 45 | ||
62 | this->timer.raw_load = 0; | 46 | this->timer.raw_load = 0; |
63 | this->silence_lookahead = 6; | ||
64 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.11) ); | 47 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.11) ); |
65 | 48 | ||
66 | Rom_init( &this->rom, 0x2000 ); | 49 | Rom_init( &this->rom, 0x2000 ); |
@@ -71,6 +54,11 @@ void Hes_init( struct Hes_Emu* this ) | |||
71 | 54 | ||
72 | /* Set default track count */ | 55 | /* Set default track count */ |
73 | this->track_count = 255; | 56 | this->track_count = 255; |
57 | |||
58 | // clears fields | ||
59 | this->voice_count_ = 0; | ||
60 | this->voice_types_ = 0; | ||
61 | clear_track_vars( this ); | ||
74 | } | 62 | } |
75 | 63 | ||
76 | static blargg_err_t check_hes_header( void const* header ) | 64 | static blargg_err_t check_hes_header( void const* header ) |
@@ -82,10 +70,12 @@ static blargg_err_t check_hes_header( void const* header ) | |||
82 | 70 | ||
83 | // Setup | 71 | // Setup |
84 | 72 | ||
85 | blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size ) | 73 | blargg_err_t Hes_load_mem( struct Hes_Emu* this, void* data, long size ) |
86 | { | 74 | { |
87 | // Unload | 75 | // Unload |
88 | this->voice_count_ = 0; | 76 | this->voice_count_ = 0; |
77 | this->track_count = 255; | ||
78 | this->m3u.size = 0; | ||
89 | clear_track_vars( this ); | 79 | clear_track_vars( this ); |
90 | 80 | ||
91 | assert( offsetof (struct header_t,unused [4]) == header_size ); | 81 | assert( offsetof (struct header_t,unused [4]) == header_size ); |
@@ -106,15 +96,15 @@ blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size ) | |||
106 | // many files have bad sizes in the only block, so it's simpler to | 96 | // many files have bad sizes in the only block, so it's simpler to |
107 | // just try to load the damn data as best as possible. | 97 | // just try to load the damn data as best as possible. |
108 | 98 | ||
109 | long addr = get_le32( this->header.addr ); | 99 | int addr = get_le32( this->header.addr ); |
110 | /* long rom_size = get_le32( this->header.size ); */ | 100 | /* int rom_size = get_le32( this->header.size ); */ |
111 | long const rom_max = 0x100000; | 101 | int const rom_max = 0x100000; |
112 | if ( addr & ~(rom_max - 1) ) | 102 | if ( (unsigned) addr >= (unsigned) rom_max ) |
113 | { | 103 | { |
114 | /* warning( "Invalid address" ); */ | 104 | /* warning( "Invalid address" ); */ |
115 | addr &= rom_max - 1; | 105 | addr &= rom_max - 1; |
116 | } | 106 | } |
117 | /* if ( (unsigned long) (addr + size) > (unsigned long) rom_max ) | 107 | /* if ( (unsigned) (addr + size) > (unsigned) rom_max ) |
118 | warning( "Invalid size" ); | 108 | warning( "Invalid size" ); |
119 | 109 | ||
120 | if ( rom_size != rom.file_size() ) | 110 | if ( rom_size != rom.file_size() ) |
@@ -130,6 +120,10 @@ blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size ) | |||
130 | Rom_set_addr( &this->rom, addr ); | 120 | Rom_set_addr( &this->rom, addr ); |
131 | 121 | ||
132 | this->voice_count_ = osc_count + adpcm_osc_count; | 122 | this->voice_count_ = osc_count + adpcm_osc_count; |
123 | static int const types [osc_count + adpcm_osc_count] = { | ||
124 | wave_type+0, wave_type+1, wave_type+2, wave_type+3, mixed_type+0, mixed_type+1, mixed_type+2 | ||
125 | }; | ||
126 | this->voice_types_ = types; | ||
133 | 127 | ||
134 | Apu_volume( &this->apu, this->gain_ ); | 128 | Apu_volume( &this->apu, this->gain_ ); |
135 | Adpcm_volume( &this->adpcm, this->gain_ ); | 129 | Adpcm_volume( &this->adpcm, this->gain_ ); |
@@ -137,21 +131,17 @@ blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size ) | |||
137 | // Setup buffer | 131 | // Setup buffer |
138 | this->clock_rate_ = 7159091; | 132 | this->clock_rate_ = 7159091; |
139 | Buffer_clock_rate( &this->stereo_buf, 7159091 ); | 133 | Buffer_clock_rate( &this->stereo_buf, 7159091 ); |
134 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count_, this->voice_types_ ) ); | ||
140 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 135 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
141 | 136 | ||
142 | Sound_set_tempo( this, this->tempo_ ); | 137 | Sound_set_tempo( this, this->tempo_ ); |
143 | Sound_mute_voices( this, this->mute_mask_ ); | 138 | Sound_mute_voices( this, this->mute_mask_ ); |
144 | 139 | ||
145 | // Reset track count | ||
146 | this->track_count = 255; | ||
147 | this->m3u.size = 0; | ||
148 | return 0; | 140 | return 0; |
149 | } | 141 | } |
150 | 142 | ||
151 | |||
152 | // Emulation | 143 | // Emulation |
153 | 144 | ||
154 | void recalc_timer_load( struct Hes_Emu* this ); | ||
155 | void recalc_timer_load( struct Hes_Emu* this ) | 145 | void recalc_timer_load( struct Hes_Emu* this ) |
156 | { | 146 | { |
157 | this->timer.load = this->timer.raw_load * this->timer_base + 1; | 147 | this->timer.load = this->timer.raw_load * this->timer_base + 1; |
@@ -159,9 +149,25 @@ void recalc_timer_load( struct Hes_Emu* this ) | |||
159 | 149 | ||
160 | // Hardware | 150 | // Hardware |
161 | 151 | ||
162 | void irq_changed( struct Hes_Emu* this ); | 152 | void run_until( struct Hes_Emu* this, hes_time_t present ) |
163 | void run_until( struct Hes_Emu* this, hes_time_t present ); | 153 | { |
164 | void Cpu_write_vdp( struct Hes_Emu* this, int addr, int data ) | 154 | while ( this->vdp.next_vbl < present ) |
155 | this->vdp.next_vbl += this->play_period; | ||
156 | |||
157 | hes_time_t elapsed = present - this->timer.last_time; | ||
158 | if ( elapsed > 0 ) | ||
159 | { | ||
160 | if ( this->timer.enabled ) | ||
161 | { | ||
162 | this->timer.count -= elapsed; | ||
163 | if ( this->timer.count <= 0 ) | ||
164 | this->timer.count += this->timer.load; | ||
165 | } | ||
166 | this->timer.last_time = present; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | void write_vdp( struct Hes_Emu* this, int addr, int data ) | ||
165 | { | 171 | { |
166 | switch ( addr ) | 172 | switch ( addr ) |
167 | { | 173 | { |
@@ -178,77 +184,33 @@ void Cpu_write_vdp( struct Hes_Emu* this, int addr, int data ) | |||
178 | this->vdp.control = data; | 184 | this->vdp.control = data; |
179 | irq_changed( this ); | 185 | irq_changed( this ); |
180 | } | 186 | } |
181 | else | 187 | /* else |
182 | { | 188 | { |
183 | dprintf( "VDP not supported: $%02X <- $%02X\n", this->vdp.latch, data ); | 189 | dprintf( "VDP not supported: $%02X <- $%02X\n", vdp.latch, data ); |
184 | } | 190 | } */ |
185 | break; | 191 | break; |
186 | 192 | ||
187 | case 3: | 193 | case 3: |
188 | dprintf( "VDP MSB not supported: $%02X <- $%02X\n", this->vdp.latch, data ); | 194 | /* dprintf( "VDP MSB not supported: $%02X <- $%02X\n", vdp.latch, data ); */ |
189 | break; | 195 | break; |
190 | } | 196 | } |
191 | } | 197 | } |
192 | 198 | ||
193 | int Cpu_done( struct Hes_Emu* this ) | 199 | void write_mem_( struct Hes_Emu* this, hes_addr_t addr, int data ) |
194 | { | ||
195 | check( time() >= end_time() || | ||
196 | (!(r.status & i_flag_mask) && time() >= irq_time()) ); | ||
197 | |||
198 | if ( !(this->cpu.r.status & i_flag_mask) ) | ||
199 | { | ||
200 | hes_time_t present = Cpu_time( &this->cpu ); | ||
201 | |||
202 | if ( this->irq.timer <= present && !(this->irq.disables & timer_mask) ) | ||
203 | { | ||
204 | this->timer.fired = true; | ||
205 | this->irq.timer = (hes_time_t)future_hes_time; | ||
206 | irq_changed( this ); // overkill, but not worth writing custom code | ||
207 | #if defined (GME_FRAME_HOOK_DEFINED) | ||
208 | { | ||
209 | unsigned const threshold = period_60hz / 30; | ||
210 | unsigned long elapsed = present - last_frame_hook; | ||
211 | if ( elapsed - period_60hz + threshold / 2 < threshold ) | ||
212 | { | ||
213 | last_frame_hook = present; | ||
214 | GME_FRAME_HOOK( this ); | ||
215 | } | ||
216 | } | ||
217 | #endif | ||
218 | return 0x0A; | ||
219 | } | ||
220 | |||
221 | if ( this->irq.vdp <= present && !(this->irq.disables & vdp_mask) ) | ||
222 | { | ||
223 | // work around for bugs with music not acknowledging VDP | ||
224 | //run_until( present ); | ||
225 | //irq.vdp = future_hes_time; | ||
226 | //irq_changed(); | ||
227 | #if defined(GME_FRAME_HOOK_DEFINED) | ||
228 | last_frame_hook = present; | ||
229 | GME_FRAME_HOOK( this ); | ||
230 | #endif | ||
231 | return 0x08; | ||
232 | } | ||
233 | } | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | ||
238 | { | 200 | { |
239 | hes_time_t time = Cpu_time( &this->cpu ); | 201 | hes_time_t time = Cpu_time( &this->cpu ); |
240 | if ( (unsigned) (addr - start_addr) <= end_addr - start_addr ) | 202 | if ( (unsigned) (addr - apu_io_addr) < apu_io_size ) |
241 | { | 203 | { |
242 | GME_APU_HOOK( this, addr - apu.start_addr, data ); | 204 | // Avoid going way past end when a long block xfer is writing to I/O space. |
243 | // avoid going way past end when a long block xfer is writing to I/O space | 205 | // Not a problem for other registers below because they don't write to |
244 | hes_time_t t = min( time, this->cpu.end_time + 8 ); | 206 | // Blip_Buffer. |
207 | hes_time_t t = min( time, Cpu_end_time( &this->cpu ) + 8 ); | ||
245 | Apu_write_data( &this->apu, t, addr, data ); | 208 | Apu_write_data( &this->apu, t, addr, data ); |
246 | return; | 209 | return; |
247 | } | 210 | } |
248 | 211 | if ( (unsigned) (addr - adpcm_io_addr) < adpcm_io_size ) | |
249 | if ( (unsigned) (addr - io_addr) < io_size ) | ||
250 | { | 212 | { |
251 | hes_time_t t = min( time, this->cpu.end_time + 6 ); | 213 | hes_time_t t = min( time, Cpu_end_time( &this->cpu ) + 6 ); |
252 | Adpcm_write_data( &this->adpcm, t, addr, data ); | 214 | Adpcm_write_data( &this->adpcm, t, addr, data ); |
253 | return; | 215 | return; |
254 | } | 216 | } |
@@ -258,7 +220,7 @@ void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | |||
258 | case 0x0000: | 220 | case 0x0000: |
259 | case 0x0002: | 221 | case 0x0002: |
260 | case 0x0003: | 222 | case 0x0003: |
261 | Cpu_write_vdp( this, addr, data ); | 223 | write_vdp( this, addr, data ); |
262 | return; | 224 | return; |
263 | 225 | ||
264 | case 0x0C00: { | 226 | case 0x0C00: { |
@@ -282,11 +244,8 @@ void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | |||
282 | case 0x1402: | 244 | case 0x1402: |
283 | run_until( this, time ); | 245 | run_until( this, time ); |
284 | this->irq.disables = data; | 246 | this->irq.disables = data; |
285 | 247 | /* if ( (data & 0xF8) && (data & 0xF8) != 0xF8 ) // flag questionable values | |
286 | // flag questionable values | 248 | dprintf( "Int mask: $%02X\n", data ); */ |
287 | if ( (data & 0xF8) && (data & 0xF8) != 0xF8 ) { | ||
288 | dprintf( "Int mask: $%02X\n", data ); | ||
289 | } | ||
290 | break; | 249 | break; |
291 | 250 | ||
292 | case 0x1403: | 251 | case 0x1403: |
@@ -305,7 +264,7 @@ void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | |||
305 | return; | 264 | return; |
306 | 265 | ||
307 | default: | 266 | default: |
308 | dprintf( "unmapped write $%04X <- $%02X\n", addr, data ); | 267 | /* dprintf( "unmapped write $%04X <- $%02X\n", addr, data ); */ |
309 | return; | 268 | return; |
310 | #endif | 269 | #endif |
311 | } | 270 | } |
@@ -313,7 +272,7 @@ void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | |||
313 | irq_changed( this ); | 272 | irq_changed( this ); |
314 | } | 273 | } |
315 | 274 | ||
316 | int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t addr ) | 275 | int read_mem_( struct Hes_Emu* this, hes_addr_t addr ) |
317 | { | 276 | { |
318 | hes_time_t time = Cpu_time( &this->cpu ); | 277 | hes_time_t time = Cpu_time( &this->cpu ); |
319 | addr &= page_size - 1; | 278 | addr &= page_size - 1; |
@@ -322,21 +281,21 @@ int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t addr ) | |||
322 | case 0x0000: | 281 | case 0x0000: |
323 | if ( this->irq.vdp > time ) | 282 | if ( this->irq.vdp > time ) |
324 | return 0; | 283 | return 0; |
325 | this->irq.vdp = (hes_time_t)future_hes_time; | 284 | this->irq.vdp = future_time; |
326 | run_until( this, time ); | 285 | run_until( this, time ); |
327 | irq_changed( this ); | 286 | irq_changed( this ); |
328 | return 0x20; | 287 | return 0x20; |
329 | 288 | ||
330 | case 0x0002: | 289 | /* case 0x0002: |
331 | case 0x0003: | 290 | case 0x0003: |
332 | dprintf( "VDP read not supported: %d\n", addr ); | 291 | dprintf( "VDP read not supported: %d\n", addr ); |
333 | return 0; | 292 | return 0; */ |
334 | 293 | ||
335 | case 0x0C01: | 294 | case 0x0C01: |
336 | //return timer.enabled; // TODO: remove? | 295 | //return timer.enabled; // TODO: remove? |
337 | case 0x0C00: | 296 | case 0x0C00: |
338 | run_until( this, time ); | 297 | run_until( this, time ); |
339 | dprintf( "Timer count read\n" ); | 298 | /* dprintf( "Timer count read\n" ); */ |
340 | return (unsigned) (this->timer.count - 1) / this->timer_base; | 299 | return (unsigned) (this->timer.count - 1) / this->timer_base; |
341 | 300 | ||
342 | case 0x1402: | 301 | case 0x1402: |
@@ -349,7 +308,7 @@ int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t addr ) | |||
349 | if ( this->irq.vdp <= time ) status |= vdp_mask; | 308 | if ( this->irq.vdp <= time ) status |= vdp_mask; |
350 | return status; | 309 | return status; |
351 | } | 310 | } |
352 | 311 | ||
353 | case 0x180A: | 312 | case 0x180A: |
354 | case 0x180B: | 313 | case 0x180B: |
355 | case 0x180C: | 314 | case 0x180C: |
@@ -358,71 +317,75 @@ int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t addr ) | |||
358 | 317 | ||
359 | #ifndef NDEBUG | 318 | #ifndef NDEBUG |
360 | case 0x1000: // I/O port | 319 | case 0x1000: // I/O port |
361 | // case 0x180C: // CD-ROM | 320 | //case 0x180C: // CD-ROM |
362 | // case 0x180D: | 321 | //case 0x180D: |
363 | break; | 322 | break; |
364 | 323 | ||
365 | default: | 324 | /* default: |
366 | dprintf( "unmapped read $%04X\n", addr ); | 325 | dprintf( "unmapped read $%04X\n", addr ); */ |
367 | #endif | 326 | #endif |
368 | } | 327 | } |
369 | 328 | ||
370 | return unmapped; | 329 | return unmapped; |
371 | } | 330 | } |
372 | 331 | ||
373 | // see hes_cpu_io.h for core read/write functions | ||
374 | |||
375 | // Emulation | ||
376 | |||
377 | void run_until( struct Hes_Emu* this, hes_time_t present ) | ||
378 | { | ||
379 | while ( this->vdp.next_vbl < present ) | ||
380 | this->vdp.next_vbl += this->play_period; | ||
381 | |||
382 | hes_time_t elapsed = present - this->timer.last_time; | ||
383 | if ( elapsed > 0 ) | ||
384 | { | ||
385 | if ( this->timer.enabled ) | ||
386 | { | ||
387 | this->timer.count -= elapsed; | ||
388 | if ( this->timer.count <= 0 ) | ||
389 | this->timer.count += this->timer.load; | ||
390 | } | ||
391 | this->timer.last_time = present; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | void irq_changed( struct Hes_Emu* this ) | 332 | void irq_changed( struct Hes_Emu* this ) |
396 | { | 333 | { |
397 | hes_time_t present = Cpu_time( &this->cpu ); | 334 | hes_time_t present = Cpu_time( &this->cpu ); |
398 | 335 | ||
399 | if ( this->irq.timer > present ) | 336 | if ( this->irq.timer > present ) |
400 | { | 337 | { |
401 | this->irq.timer = (hes_time_t)future_hes_time; | 338 | this->irq.timer = future_time; |
402 | if ( this->timer.enabled && !this->timer.fired ) | 339 | if ( this->timer.enabled && !this->timer.fired ) |
403 | this->irq.timer = present + this->timer.count; | 340 | this->irq.timer = present + this->timer.count; |
404 | } | 341 | } |
405 | 342 | ||
406 | if ( this->irq.vdp > present ) | 343 | if ( this->irq.vdp > present ) |
407 | { | 344 | { |
408 | this->irq.vdp = (hes_time_t)future_hes_time; | 345 | this->irq.vdp = future_time; |
409 | if ( this->vdp.control & 0x08 ) | 346 | if ( this->vdp.control & 0x08 ) |
410 | this->irq.vdp = this->vdp.next_vbl; | 347 | this->irq.vdp = this->vdp.next_vbl; |
411 | } | 348 | } |
412 | 349 | ||
413 | hes_time_t time = (hes_time_t)future_hes_time; | 350 | hes_time_t time = future_time; |
414 | if ( !(this->irq.disables & timer_mask) ) time = this->irq.timer; | 351 | if ( !(this->irq.disables & timer_mask) ) time = this->irq.timer; |
415 | if ( !(this->irq.disables & vdp_mask) ) time = min( time, this->irq.vdp ); | 352 | if ( !(this->irq.disables & vdp_mask) ) time = min( time, this->irq.vdp ); |
416 | 353 | ||
417 | // Set cpu irq time | 354 | Cpu_set_irq_time( &this->cpu, time ); |
418 | this->cpu.state->time += Cpu_update_end_time( &this->cpu, this->cpu.r.status, | ||
419 | this->cpu.end_time, (this->cpu.irq_time = time) ); | ||
420 | } | 355 | } |
421 | 356 | ||
422 | static void adjust_time( blargg_long* time, hes_time_t delta ); | 357 | int cpu_done( struct Hes_Emu* this ) |
423 | static void adjust_time( blargg_long* time, hes_time_t delta ) | ||
424 | { | 358 | { |
425 | if ( *time < (blargg_long)future_hes_time ) | 359 | check( Cpu_time( &this->cpu ) >= Cpu_end_time( &this->cpu ) || |
360 | (!(this->cpu.r.flags & i_flag_mask) && Cpu_time( &this->cpu ) >= Cpu_irq_time( &this->cpu )) ); | ||
361 | |||
362 | if ( !(this->cpu.r.flags & i_flag_mask) ) | ||
363 | { | ||
364 | hes_time_t present = Cpu_time( &this->cpu ); | ||
365 | |||
366 | if ( this->irq.timer <= present && !(this->irq.disables & timer_mask) ) | ||
367 | { | ||
368 | this->timer.fired = true; | ||
369 | this->irq.timer = future_time; | ||
370 | irq_changed( this ); // overkill, but not worth writing custom code | ||
371 | return 0x0A; | ||
372 | } | ||
373 | |||
374 | if ( this->irq.vdp <= present && !(this->irq.disables & vdp_mask) ) | ||
375 | { | ||
376 | // work around for bugs with music not acknowledging VDP | ||
377 | //run_until( present ); | ||
378 | //irq.vdp = cpu.future_time; | ||
379 | //irq_changed(); | ||
380 | return 0x08; | ||
381 | } | ||
382 | } | ||
383 | return -1; | ||
384 | } | ||
385 | |||
386 | static void adjust_time( hes_time_t* time, hes_time_t delta ) | ||
387 | { | ||
388 | if ( *time < future_time ) | ||
426 | { | 389 | { |
427 | *time -= delta; | 390 | *time -= delta; |
428 | if ( *time < 0 ) | 391 | if ( *time < 0 ) |
@@ -430,15 +393,13 @@ static void adjust_time( blargg_long* time, hes_time_t delta ) | |||
430 | } | 393 | } |
431 | } | 394 | } |
432 | 395 | ||
433 | blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ); | 396 | blargg_err_t end_frame( struct Hes_Emu* this, hes_time_t duration ) |
434 | blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) | ||
435 | { | 397 | { |
436 | blip_time_t duration = *duration_; // cache | 398 | /* if ( run_cpu( this, duration ) ) |
399 | warning( "Emulation error (illegal instruction)" ); */ | ||
400 | run_cpu( this, duration ); | ||
437 | 401 | ||
438 | Cpu_run( this, duration ); | 402 | check( Cpu_time( &this->cpu ) >= duration ); |
439 | /* warning( "Emulation error (illegal instruction)" ); */ | ||
440 | |||
441 | check( time() >= duration ); | ||
442 | //check( time() - duration < 20 ); // Txx instruction could cause going way over | 403 | //check( time() - duration < 20 ); // Txx instruction could cause going way over |
443 | 404 | ||
444 | run_until( this, duration ); | 405 | run_until( this, duration ); |
@@ -446,15 +407,7 @@ blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) | |||
446 | // end time frame | 407 | // end time frame |
447 | this->timer.last_time -= duration; | 408 | this->timer.last_time -= duration; |
448 | this->vdp.next_vbl -= duration; | 409 | this->vdp.next_vbl -= duration; |
449 | #if defined (GME_FRAME_HOOK_DEFINED) | 410 | Cpu_end_frame( &this->cpu, duration ); |
450 | last_frame_hook -= *duration; | ||
451 | #endif | ||
452 | |||
453 | // End cpu frame | ||
454 | this->cpu.state_.base -= duration; | ||
455 | if ( this->cpu.irq_time < (hes_time_t)future_hes_time ) this->cpu.irq_time -= duration; | ||
456 | if ( this->cpu.end_time < (hes_time_t)future_hes_time ) this->cpu.end_time -= duration; | ||
457 | |||
458 | adjust_time( &this->irq.timer, duration ); | 411 | adjust_time( &this->irq.timer, duration ); |
459 | adjust_time( &this->irq.vdp, duration ); | 412 | adjust_time( &this->irq.vdp, duration ); |
460 | Apu_end_frame( &this->apu, duration ); | 413 | Apu_end_frame( &this->apu, duration ); |
@@ -463,24 +416,31 @@ blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) | |||
463 | return 0; | 416 | return 0; |
464 | } | 417 | } |
465 | 418 | ||
466 | blargg_err_t play_( struct Hes_Emu* this, long count, sample_t* out ); | 419 | blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) |
467 | blargg_err_t play_( struct Hes_Emu* this, long count, sample_t* out ) | 420 | { |
421 | return end_frame( this, *duration_ ); | ||
422 | } | ||
423 | |||
424 | blargg_err_t play_( void *emu, int count, sample_t out [] ) | ||
468 | { | 425 | { |
469 | long remain = count; | 426 | struct Hes_Emu* this = (struct Hes_Emu*) emu; |
427 | |||
428 | int remain = count; | ||
470 | while ( remain ) | 429 | while ( remain ) |
471 | { | 430 | { |
431 | Buffer_disable_immediate_removal( &this->stereo_buf ); | ||
472 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); | 432 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); |
473 | if ( remain ) | 433 | if ( remain ) |
474 | { | 434 | { |
475 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) | 435 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) |
476 | { | 436 | { |
477 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 437 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
438 | |||
478 | // Remute voices | 439 | // Remute voices |
479 | Sound_mute_voices( this, this->mute_mask_ ); | 440 | Sound_mute_voices( this, this->mute_mask_ ); |
480 | } | 441 | } |
481 | |||
482 | int msec = Buffer_length( &this->stereo_buf ); | 442 | int msec = Buffer_length( &this->stereo_buf ); |
483 | blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000; | 443 | blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; |
484 | RETURN_ERR( run_clocks( this, &clocks_emulated ) ); | 444 | RETURN_ERR( run_clocks( this, &clocks_emulated ) ); |
485 | assert( clocks_emulated ); | 445 | assert( clocks_emulated ); |
486 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); | 446 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); |
@@ -489,10 +449,9 @@ blargg_err_t play_( struct Hes_Emu* this, long count, sample_t* out ) | |||
489 | return 0; | 449 | return 0; |
490 | } | 450 | } |
491 | 451 | ||
492 | |||
493 | // Music emu | 452 | // Music emu |
494 | 453 | ||
495 | blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, long rate ) | 454 | blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, int rate ) |
496 | { | 455 | { |
497 | require( !this->sample_rate_ ); // sample rate can't be changed once set | 456 | require( !this->sample_rate_ ); // sample rate can't be changed once set |
498 | Buffer_init( &this->stereo_buf ); | 457 | Buffer_init( &this->stereo_buf ); |
@@ -502,6 +461,8 @@ blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, long rate ) | |||
502 | Buffer_bass_freq( &this->stereo_buf, 60 ); | 461 | Buffer_bass_freq( &this->stereo_buf, 60 ); |
503 | 462 | ||
504 | this->sample_rate_ = rate; | 463 | this->sample_rate_ = rate; |
464 | RETURN_ERR( track_init( &this->track_filter, this ) ); | ||
465 | this->tfilter.max_silence = 6 * stereo * this->sample_rate_; | ||
505 | return 0; | 466 | return 0; |
506 | } | 467 | } |
507 | 468 | ||
@@ -521,7 +482,7 @@ void Sound_mute_voices( struct Hes_Emu* this, int mask ) | |||
521 | this->mute_mask_ = mask; | 482 | this->mute_mask_ = mask; |
522 | 483 | ||
523 | // Set adpcm voice | 484 | // Set adpcm voice |
524 | struct channel_t ch = Buffer_channel( &this->stereo_buf ); | 485 | struct channel_t ch = Buffer_channel( &this->stereo_buf, this->voice_count_ ); |
525 | if ( mask & (1 << this->voice_count_ ) ) | 486 | if ( mask & (1 << this->voice_count_ ) ) |
526 | Adpcm_set_output( &this->adpcm, 0, 0, 0, 0 ); | 487 | Adpcm_set_output( &this->adpcm, 0, 0, 0, 0 ); |
527 | else | 488 | else |
@@ -536,7 +497,8 @@ void Sound_mute_voices( struct Hes_Emu* this, int mask ) | |||
536 | Apu_osc_output( &this->apu, i, 0, 0, 0 ); | 497 | Apu_osc_output( &this->apu, i, 0, 0, 0 ); |
537 | } | 498 | } |
538 | else | 499 | else |
539 | { | 500 | { |
501 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); | ||
540 | assert( (ch.center && ch.left && ch.right) || | 502 | assert( (ch.center && ch.left && ch.right) || |
541 | (!ch.center && !ch.left && !ch.right) ); // all or nothing | 503 | (!ch.center && !ch.left && !ch.right) ); // all or nothing |
542 | Apu_osc_output( &this->apu, i, ch.center, ch.left, ch.right ); | 504 | Apu_osc_output( &this->apu, i, ch.center, ch.left, ch.right ); |
@@ -557,7 +519,6 @@ void Sound_set_tempo( struct Hes_Emu* this, int t ) | |||
557 | this->tempo_ = t; | 519 | this->tempo_ = t; |
558 | } | 520 | } |
559 | 521 | ||
560 | void fill_buf( struct Hes_Emu* this ); | ||
561 | blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) | 522 | blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) |
562 | { | 523 | { |
563 | clear_track_vars( this ); | 524 | clear_track_vars( this ); |
@@ -572,7 +533,7 @@ blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) | |||
572 | 533 | ||
573 | Buffer_clear( &this->stereo_buf ); | 534 | Buffer_clear( &this->stereo_buf ); |
574 | 535 | ||
575 | memset( this->cpu.ram, 0, sizeof this->cpu.ram ); // some HES music relies on zero fill | 536 | memset( this->ram, 0, sizeof this->ram ); // some HES music relies on zero fill |
576 | memset( this->sgx, 0, sizeof this->sgx ); | 537 | memset( this->sgx, 0, sizeof this->sgx ); |
577 | 538 | ||
578 | Apu_reset( &this->apu ); | 539 | Apu_reset( &this->apu ); |
@@ -581,12 +542,12 @@ blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) | |||
581 | 542 | ||
582 | unsigned i; | 543 | unsigned i; |
583 | for ( i = 0; i < sizeof this->header.banks; i++ ) | 544 | for ( i = 0; i < sizeof this->header.banks; i++ ) |
584 | Cpu_set_mmr( this, i, this->header.banks [i] ); | 545 | set_mmr( this, i, this->header.banks [i] ); |
585 | Cpu_set_mmr( this, page_count, 0xFF ); // unmapped beyond end of address space | 546 | set_mmr( this, page_count, 0xFF ); // unmapped beyond end of address space |
586 | 547 | ||
587 | this->irq.disables = timer_mask | vdp_mask; | 548 | this->irq.disables = timer_mask | vdp_mask; |
588 | this->irq.timer = (hes_time_t)future_hes_time; | 549 | this->irq.timer = future_time; |
589 | this->irq.vdp = (hes_time_t)future_hes_time; | 550 | this->irq.vdp = future_time; |
590 | 551 | ||
591 | this->timer.enabled = false; | 552 | this->timer.enabled = false; |
592 | this->timer.raw_load= 0x80; | 553 | this->timer.raw_load= 0x80; |
@@ -598,280 +559,86 @@ blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) | |||
598 | this->vdp.control = 0; | 559 | this->vdp.control = 0; |
599 | this->vdp.next_vbl = 0; | 560 | this->vdp.next_vbl = 0; |
600 | 561 | ||
601 | this->cpu.ram [0x1FF] = (idle_addr - 1) >> 8; | 562 | this->ram [0x1FF] = (idle_addr - 1) >> 8; |
602 | this->cpu.ram [0x1FE] = (idle_addr - 1) & 0xFF; | 563 | this->ram [0x1FE] = (idle_addr - 1) & 0xFF; |
603 | this->cpu.r.sp = 0xFD; | 564 | this->cpu.r.sp = 0xFD; |
604 | this->cpu.r.pc = get_le16( this->header.init_addr ); | 565 | this->cpu.r.pc = get_le16( this->header.init_addr ); |
605 | this->cpu.r.a = track; | 566 | this->cpu.r.a = track; |
606 | 567 | ||
607 | recalc_timer_load( this ); | 568 | recalc_timer_load( this ); |
608 | this->last_frame_hook = 0; | ||
609 | 569 | ||
610 | this->emu_track_ended_ = false; | 570 | // convert filter times to samples |
611 | this->track_ended = false; | 571 | struct setup_t s = this->tfilter; |
572 | s.max_initial *= this->sample_rate_ * stereo; | ||
573 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD | ||
574 | s.lookahead = 1; | ||
575 | #endif | ||
576 | track_setup( &this->track_filter, &s ); | ||
612 | 577 | ||
613 | if ( !this->ignore_silence ) | 578 | return track_start( &this->track_filter ); |
614 | { | ||
615 | // play until non-silence or end of track | ||
616 | long end; | ||
617 | for ( end =this-> max_initial_silence * stereo * this->sample_rate_; this->emu_time < end; ) | ||
618 | { | ||
619 | fill_buf( this ); | ||
620 | if ( this->buf_remain | (int) this->emu_track_ended_ ) | ||
621 | break; | ||
622 | } | ||
623 | |||
624 | this->emu_time = this->buf_remain; | ||
625 | this->out_time = 0; | ||
626 | this->silence_time = 0; | ||
627 | this->silence_count = 0; | ||
628 | } | ||
629 | /* return track_ended() ? warning() : 0; */ | ||
630 | return 0; | ||
631 | } | 579 | } |
632 | 580 | ||
633 | // Tell/Seek | 581 | // Tell/Seek |
634 | 582 | ||
635 | static blargg_long msec_to_samples( blargg_long msec, long sample_rate ) | 583 | static int msec_to_samples( int msec, int sample_rate ) |
636 | { | 584 | { |
637 | blargg_long sec = msec / 1000; | 585 | int sec = msec / 1000; |
638 | msec -= sec * 1000; | 586 | msec -= sec * 1000; |
639 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; | 587 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; |
640 | } | 588 | } |
641 | 589 | ||
642 | long Track_tell( struct Hes_Emu* this ) | 590 | int Track_tell( struct Hes_Emu* this ) |
643 | { | 591 | { |
644 | blargg_long rate = this->sample_rate_ * stereo; | 592 | int rate = this->sample_rate_ * stereo; |
645 | blargg_long sec = this->out_time / rate; | 593 | int sec = track_sample_count( &this->track_filter ) / rate; |
646 | return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate; | 594 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; |
647 | } | 595 | } |
648 | 596 | ||
649 | blargg_err_t Track_seek( struct Hes_Emu* this, long msec ) | 597 | blargg_err_t Track_seek( struct Hes_Emu* this, int msec ) |
650 | { | 598 | { |
651 | blargg_long time = msec_to_samples( msec, this->sample_rate_ ); | 599 | int time = msec_to_samples( msec, this->sample_rate_ ); |
652 | if ( time < this->out_time ) | 600 | if ( time < track_sample_count( &this->track_filter ) ) |
653 | RETURN_ERR( Hes_start_track( this, this->current_track_ ) ); | 601 | RETURN_ERR( Hes_start_track( this, this->current_track_ ) ); |
654 | return Track_skip( this, time - this->out_time ); | 602 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); |
655 | } | 603 | } |
656 | 604 | ||
657 | blargg_err_t skip_( struct Hes_Emu* this, long count ); | 605 | blargg_err_t skip_( void* emu, int count ) |
658 | blargg_err_t skip_( struct Hes_Emu* this, long count ) | ||
659 | { | 606 | { |
607 | struct Hes_Emu* this = (struct Hes_Emu*) emu; | ||
608 | |||
660 | // for long skip, mute sound | 609 | // for long skip, mute sound |
661 | const long threshold = 30000; | 610 | const int threshold = 32768; |
662 | if ( count > threshold ) | 611 | if ( count > threshold ) |
663 | { | 612 | { |
664 | int saved_mute = this->mute_mask_; | 613 | int saved_mute = this->mute_mask_; |
665 | Sound_mute_voices( this, ~0 ); | 614 | Sound_mute_voices( this, ~0 ); |
666 | |||
667 | while ( count > threshold / 2 && !this->emu_track_ended_ ) | ||
668 | { | ||
669 | RETURN_ERR( play_( this, buf_size, this->buf ) ); | ||
670 | count -= buf_size; | ||
671 | } | ||
672 | |||
673 | Sound_mute_voices( this, saved_mute ); | ||
674 | } | ||
675 | |||
676 | while ( count && !this->emu_track_ended_ ) | ||
677 | { | ||
678 | long n = buf_size; | ||
679 | if ( n > count ) | ||
680 | n = count; | ||
681 | count -= n; | ||
682 | RETURN_ERR( play_( this, n, this->buf ) ); | ||
683 | } | ||
684 | return 0; | ||
685 | } | ||
686 | 615 | ||
687 | blargg_err_t Track_skip( struct Hes_Emu* this, long count ) | 616 | int n = count - threshold/2; |
688 | { | 617 | n &= ~(2048-1); // round to multiple of 2048 |
689 | require( this->current_track_ >= 0 ); // start_track() must have been called already | ||
690 | this->out_time += count; | ||
691 | |||
692 | // remove from silence and buf first | ||
693 | { | ||
694 | long n = min( count, this->silence_count ); | ||
695 | this->silence_count -= n; | ||
696 | count -= n; | ||
697 | |||
698 | n = min( count, this->buf_remain ); | ||
699 | this->buf_remain -= n; | ||
700 | count -= n; | 618 | count -= n; |
701 | } | 619 | RETURN_ERR( skippy_( &this->track_filter, n ) ); |
702 | |||
703 | if ( count && !this->emu_track_ended_ ) | ||
704 | { | ||
705 | this->emu_time += count; | ||
706 | |||
707 | // End track if error | ||
708 | if ( skip_( this, count ) ) | ||
709 | this->emu_track_ended_ = true; | ||
710 | } | ||
711 | |||
712 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
713 | this->track_ended |= this->emu_track_ended_; | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | 620 | ||
718 | 621 | Sound_mute_voices( this, saved_mute ); | |
719 | |||
720 | // Fading | ||
721 | |||
722 | void Track_set_fade( struct Hes_Emu* this, long start_msec, long length_msec ) | ||
723 | { | ||
724 | this->fade_step = this->sample_rate_ * length_msec / (fade_block_size * fade_shift * 1000 / stereo); | ||
725 | this->fade_start = msec_to_samples( start_msec, this->sample_rate_ ); | ||
726 | } | ||
727 | |||
728 | // unit / pow( 2.0, (double) x / step ) | ||
729 | static int int_log( blargg_long x, int step, int unit ); | ||
730 | static int int_log( blargg_long x, int step, int unit ) | ||
731 | { | ||
732 | int shift = x / step; | ||
733 | int fraction = (x - shift * step) * unit / step; | ||
734 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
735 | } | ||
736 | |||
737 | void handle_fade( struct Hes_Emu* this, long out_count, sample_t* out ); | ||
738 | void handle_fade( struct Hes_Emu* this, long out_count, sample_t* out ) | ||
739 | { | ||
740 | int i; | ||
741 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
742 | { | ||
743 | int const shift = 14; | ||
744 | int const unit = 1 << shift; | ||
745 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
746 | this->fade_step, unit ); | ||
747 | if ( gain < (unit >> fade_shift) ) | ||
748 | this->track_ended = this->emu_track_ended_ = true; | ||
749 | |||
750 | sample_t* io = &out [i]; | ||
751 | int count; | ||
752 | for ( count = min( fade_block_size, out_count - i ); count; --count ) | ||
753 | { | ||
754 | *io = (sample_t) ((*io * gain) >> shift); | ||
755 | ++io; | ||
756 | } | ||
757 | } | 622 | } |
758 | } | ||
759 | |||
760 | // Silence detection | ||
761 | 623 | ||
762 | void emu_play( struct Hes_Emu* this, long count, sample_t* out ); | 624 | return skippy_( &this->track_filter, count ); |
763 | void emu_play( struct Hes_Emu* this, long count, sample_t* out ) | ||
764 | { | ||
765 | check( current_track_ >= 0 ); | ||
766 | this->emu_time += count; | ||
767 | if ( this->current_track_ >= 0 && !this->emu_track_ended_ ) { | ||
768 | |||
769 | // End track if error | ||
770 | if ( play_( this, count, out ) ) | ||
771 | this->emu_track_ended_ = true; | ||
772 | } | ||
773 | else | ||
774 | memset( out, 0, count * sizeof *out ); | ||
775 | } | 625 | } |
776 | 626 | ||
777 | // number of consecutive silent samples at end | 627 | blargg_err_t Track_skip( struct Hes_Emu* this, int count ) |
778 | static long count_silence( sample_t* begin, long size ); | ||
779 | static long count_silence( sample_t* begin, long size ) | ||
780 | { | 628 | { |
781 | sample_t first = *begin; | 629 | require( this->current_track_ >= 0 ); // start_track() must have been called already |
782 | *begin = silence_threshold; // sentinel | 630 | return track_skip( &this->track_filter, count ); |
783 | sample_t* p = begin + size; | ||
784 | while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } | ||
785 | *begin = first; | ||
786 | return size - (p - begin); | ||
787 | } | 631 | } |
788 | 632 | ||
789 | // fill internal buffer and check it for silence | 633 | void Track_set_fade( struct Hes_Emu* this, int start_msec, int length_msec ) |
790 | void fill_buf( struct Hes_Emu* this ) | ||
791 | { | 634 | { |
792 | assert( !this->buf_remain ); | 635 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate_ ), |
793 | if ( !this->emu_track_ended_ ) | 636 | length_msec * this->sample_rate_ / (1000 / stereo) ); |
794 | { | ||
795 | emu_play( this, buf_size, this->buf ); | ||
796 | long silence = count_silence( this->buf, buf_size ); | ||
797 | if ( silence < buf_size ) | ||
798 | { | ||
799 | this->silence_time = this->emu_time - silence; | ||
800 | this->buf_remain = buf_size; | ||
801 | return; | ||
802 | } | ||
803 | } | ||
804 | this->silence_count += buf_size; | ||
805 | } | 637 | } |
806 | 638 | ||
807 | blargg_err_t Hes_play( struct Hes_Emu* this, long out_count, sample_t* out ) | 639 | blargg_err_t Hes_play( struct Hes_Emu* this, int out_count, sample_t* out ) |
808 | { | 640 | { |
809 | if ( this->track_ended ) | 641 | require( this->current_track_ >= 0 ); |
810 | { | 642 | require( out_count % stereo == 0 ); |
811 | memset( out, 0, out_count * sizeof *out ); | 643 | return track_play( &this->track_filter, out_count, out ); |
812 | } | ||
813 | else | ||
814 | { | ||
815 | require( this->current_track_ >= 0 ); | ||
816 | require( out_count % stereo == 0 ); | ||
817 | |||
818 | assert( this->emu_time >= this->out_time ); | ||
819 | |||
820 | // prints nifty graph of how far ahead we are when searching for silence | ||
821 | //dprintf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" ); | ||
822 | |||
823 | long pos = 0; | ||
824 | if ( this->silence_count ) | ||
825 | { | ||
826 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
827 | long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time; | ||
828 | while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) | ||
829 | fill_buf( this ); | ||
830 | |||
831 | // fill with silence | ||
832 | pos = min( this->silence_count, out_count ); | ||
833 | memset( out, 0, pos * sizeof *out ); | ||
834 | this->silence_count -= pos; | ||
835 | |||
836 | if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate_ ) | ||
837 | { | ||
838 | this->track_ended = this->emu_track_ended_ = true; | ||
839 | this->silence_count = 0; | ||
840 | this->buf_remain = 0; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | if ( this->buf_remain ) | ||
845 | { | ||
846 | // empty silence buf | ||
847 | long n = min( this->buf_remain, out_count - pos ); | ||
848 | memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out ); | ||
849 | this->buf_remain -= n; | ||
850 | pos += n; | ||
851 | } | ||
852 | |||
853 | // generate remaining samples normally | ||
854 | long remain = out_count - pos; | ||
855 | if ( remain ) | ||
856 | { | ||
857 | emu_play( this, remain, out + pos ); | ||
858 | this->track_ended |= this->emu_track_ended_; | ||
859 | |||
860 | if ( !this->ignore_silence || this->out_time > this->fade_start ) | ||
861 | { | ||
862 | // check end for a new run of silence | ||
863 | long silence = count_silence( out + pos, remain ); | ||
864 | if ( silence < remain ) | ||
865 | this->silence_time = this->emu_time - silence; | ||
866 | |||
867 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
868 | fill_buf( this ); // cause silence detection on next play() | ||
869 | } | ||
870 | } | ||
871 | |||
872 | if ( this->out_time > this->fade_start ) | ||
873 | handle_fade( this, out_count, out ); | ||
874 | } | ||
875 | this->out_time += out_count; | ||
876 | return 0; | ||
877 | } | 644 | } |
diff --git a/apps/codecs/libgme/hes_emu.h b/apps/codecs/libgme/hes_emu.h index 0dcd29a9c6..a1dd048498 100644 --- a/apps/codecs/libgme/hes_emu.h +++ b/apps/codecs/libgme/hes_emu.h | |||
@@ -12,88 +12,67 @@ | |||
12 | #include "hes_apu_adpcm.h" | 12 | #include "hes_apu_adpcm.h" |
13 | #include "hes_cpu.h" | 13 | #include "hes_cpu.h" |
14 | #include "m3u_playlist.h" | 14 | #include "m3u_playlist.h" |
15 | 15 | #include "track_filter.h" | |
16 | typedef short sample_t; | ||
17 | |||
18 | enum { buf_size = 2048 }; | ||
19 | 16 | ||
20 | // HES file header | 17 | // HES file header |
18 | enum { info_offset = 0x20 }; | ||
21 | enum { header_size = 0x20 }; | 19 | enum { header_size = 0x20 }; |
22 | struct header_t | 20 | struct header_t |
23 | { | 21 | { |
24 | byte tag [4]; | 22 | byte tag [4]; |
25 | byte vers; | 23 | byte vers; |
26 | byte first_track; | 24 | byte first_track; |
27 | byte init_addr [2]; | 25 | byte init_addr [2]; |
28 | byte banks [8]; | 26 | byte banks [8]; |
29 | byte data_tag [4]; | 27 | byte data_tag [4]; |
30 | byte size [4]; | 28 | byte size [4]; |
31 | byte addr [4]; | 29 | byte addr [4]; |
32 | byte unused [4]; | 30 | byte unused [4]; |
33 | }; | 31 | }; |
34 | 32 | ||
35 | 33 | ||
36 | struct timer_t { | 34 | struct timer_t { |
37 | hes_time_t last_time; | 35 | hes_time_t last_time; |
38 | blargg_long count; | 36 | int count; |
39 | blargg_long load; | 37 | int load; |
40 | int raw_load; | 38 | int raw_load; |
41 | byte enabled; | 39 | byte enabled; |
42 | byte fired; | 40 | byte fired; |
43 | }; | 41 | }; |
44 | 42 | ||
45 | struct vdp_t { | 43 | struct vdp_t { |
46 | hes_time_t next_vbl; | 44 | hes_time_t next_vbl; |
47 | byte latch; | 45 | byte latch; |
48 | byte control; | 46 | byte control; |
49 | }; | 47 | }; |
50 | 48 | ||
51 | struct irq_t { | 49 | struct irq_t { |
52 | hes_time_t timer; | 50 | hes_time_t timer; |
53 | hes_time_t vdp; | 51 | hes_time_t vdp; |
54 | byte disables; | 52 | byte disables; |
55 | }; | 53 | }; |
56 | 54 | ||
57 | |||
58 | struct Hes_Emu { | 55 | struct Hes_Emu { |
59 | hes_time_t play_period; | 56 | hes_time_t play_period; |
60 | hes_time_t last_frame_hook; | ||
61 | int timer_base; | 57 | int timer_base; |
62 | 58 | ||
63 | struct timer_t timer; | 59 | struct timer_t timer; |
64 | struct vdp_t vdp; | 60 | struct vdp_t vdp; |
65 | struct irq_t irq; | 61 | struct irq_t irq; |
66 | 62 | ||
67 | // Sound | 63 | // Sound |
68 | long clock_rate_; | 64 | int clock_rate_; |
69 | long sample_rate_; | 65 | int sample_rate_; |
70 | unsigned buf_changed_count; | 66 | unsigned buf_changed_count; |
71 | int voice_count_; | 67 | int voice_count_; |
68 | int const* voice_types_; | ||
69 | int mute_mask_; | ||
72 | int tempo_; | 70 | int tempo_; |
73 | int gain_; | 71 | int gain_; |
74 | 72 | ||
75 | // track-specific | 73 | // track-specific |
76 | byte track_count; | 74 | byte track_count; |
77 | volatile bool track_ended; | ||
78 | int current_track_; | 75 | int current_track_; |
79 | blargg_long out_time; // number of samples played since start of track | ||
80 | blargg_long emu_time; // number of samples emulator has generated since start of track | ||
81 | bool emu_track_ended_; // emulator has reached end of track | ||
82 | |||
83 | // fading | ||
84 | blargg_long fade_start; | ||
85 | int fade_step; | ||
86 | |||
87 | // silence detection | ||
88 | // Disable automatic end-of-track detection and skipping of silence at beginning | ||
89 | bool ignore_silence; | ||
90 | |||
91 | int max_initial_silence; | ||
92 | int mute_mask_; | ||
93 | int silence_lookahead; // speed to run emulator when looking ahead for silence | ||
94 | long silence_time; // number of samples where most recent silence began | ||
95 | long silence_count; // number of samples of silence to play before using buf | ||
96 | long buf_remain; // number of samples left in silence buffer | ||
97 | 76 | ||
98 | // Larger files at the end | 77 | // Larger files at the end |
99 | // Header for currently loaded file | 78 | // Header for currently loaded file |
@@ -102,19 +81,22 @@ struct Hes_Emu { | |||
102 | // M3u Playlist | 81 | // M3u Playlist |
103 | struct M3u_Playlist m3u; | 82 | struct M3u_Playlist m3u; |
104 | 83 | ||
84 | struct setup_t tfilter; | ||
85 | struct Track_Filter track_filter; | ||
86 | |||
105 | // Hes Cpu | 87 | // Hes Cpu |
106 | byte* write_pages [page_count + 1]; // 0 if unmapped or I/O space | ||
107 | struct Hes_Cpu cpu; | 88 | struct Hes_Cpu cpu; |
89 | struct Rom_Data rom; | ||
108 | 90 | ||
109 | struct Hes_Apu apu; | 91 | struct Hes_Apu apu; |
110 | struct Hes_Apu_Adpcm adpcm; | 92 | struct Hes_Apu_Adpcm adpcm; |
111 | 93 | ||
112 | struct Stereo_Buffer stereo_buf; | 94 | struct Multi_Buffer stereo_buf; |
113 | sample_t buf [buf_size]; | ||
114 | 95 | ||
115 | // rom & ram | 96 | // rom & ram |
116 | struct Rom_Data rom; | 97 | byte* write_pages [page_count + 1]; // 0 if unmapped or I/O space |
117 | byte sgx [3 * page_size + cpu_padding]; | 98 | byte ram [page_size]; |
99 | byte sgx [3 * page_size + cpu_padding]; | ||
118 | }; | 100 | }; |
119 | 101 | ||
120 | 102 | ||
@@ -126,36 +108,48 @@ void Hes_init( struct Hes_Emu* this ); | |||
126 | void Hes_stop( struct Hes_Emu* this ); | 108 | void Hes_stop( struct Hes_Emu* this ); |
127 | 109 | ||
128 | // Loads a file from memory | 110 | // Loads a file from memory |
129 | blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size ); | 111 | blargg_err_t Hes_load_mem( struct Hes_Emu* this, void* data, long size ); |
130 | 112 | ||
131 | // Set output sample rate. Must be called only once before loading file. | 113 | // Set output sample rate. Must be called only once before loading file. |
132 | blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, long sample_rate ); | 114 | blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, int sample_rate ); |
133 | 115 | ||
134 | // Start a track, where 0 is the first track. Also clears warning string. | 116 | // Start a track, where 0 is the first track. Also clears warning string. |
135 | blargg_err_t Hes_start_track( struct Hes_Emu* this, int ); | 117 | blargg_err_t Hes_start_track( struct Hes_Emu* this, int ); |
136 | 118 | ||
137 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation | 119 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation |
138 | // errors set warning string, and major errors also end track. | 120 | // errors set warning string, and major errors also end track. |
139 | blargg_err_t Hes_play( struct Hes_Emu* this, long count, sample_t* buf ); | 121 | blargg_err_t Hes_play( struct Hes_Emu* this, int count, sample_t* buf ); |
140 | 122 | ||
141 | // Track status/control | 123 | // Track status/control |
142 | // Number of milliseconds (1000 msec = 1 second) played since ning of track | 124 | // Number of milliseconds (1000 msec = 1 second) played since ning of track |
143 | long Track_tell( struct Hes_Emu* this ); | 125 | int Track_tell( struct Hes_Emu* this ); |
144 | 126 | ||
145 | // Seek to new time in track. Seeking backwards or far forward can take a while. | 127 | // Seek to new time in track. Seeking backwards or far forward can take a while. |
146 | blargg_err_t Track_seek( struct Hes_Emu* this, long msec ); | 128 | blargg_err_t Track_seek( struct Hes_Emu* this, int msec ); |
147 | 129 | ||
148 | // Skip n samples | 130 | // Skip n samples |
149 | blargg_err_t Track_skip( struct Hes_Emu* this, long n ); | 131 | blargg_err_t Track_skip( struct Hes_Emu* this, int n ); |
150 | 132 | ||
151 | // Set start time and length of track fade out. Once fade ends track_ended() returns | 133 | // Set start time and length of track fade out. Once fade ends track_ended() returns |
152 | // true. Fade time can be changed while track is playing. | 134 | // true. Fade time can be changed while track is playing. |
153 | void Track_set_fade( struct Hes_Emu* this, long start_msec, long length_msec ); | 135 | void Track_set_fade( struct Hes_Emu* this, int start_msec, int length_msec ); |
136 | |||
137 | // True if a track has reached its end | ||
138 | static inline bool Track_ended( struct Hes_Emu* this ) | ||
139 | { | ||
140 | return track_ended( &this->track_filter ); | ||
141 | } | ||
142 | |||
143 | // Disables automatic end-of-track detection and skipping of silence at beginning | ||
144 | static inline void Track_ignore_silence( struct Hes_Emu* this, bool disable ) | ||
145 | { | ||
146 | this->track_filter.silence_ignored_ = disable; | ||
147 | } | ||
154 | 148 | ||
155 | // Get track length in milliseconds | 149 | // Get track length in milliseconds |
156 | static inline long Track_get_length( struct Hes_Emu* this, int n ) | 150 | static inline int Track_get_length( struct Hes_Emu* this, int n ) |
157 | { | 151 | { |
158 | long length = 120 * 1000; /* 2 minutes */ | 152 | int length = 120 * 1000; /* 2 minutes */ |
159 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { | 153 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { |
160 | struct entry_t* entry = &this->m3u.entries [n]; | 154 | struct entry_t* entry = &this->m3u.entries [n]; |
161 | length = entry->length; | 155 | length = entry->length; |
@@ -185,45 +179,17 @@ static inline void Sound_set_gain( struct Hes_Emu* this, int g ) | |||
185 | this->gain_ = g; | 179 | this->gain_ = g; |
186 | } | 180 | } |
187 | 181 | ||
188 | |||
189 | // Emulation (You shouldn't touch these) | 182 | // Emulation (You shouldn't touch these) |
190 | 183 | ||
191 | int Cpu_read( struct Hes_Emu* this, hes_addr_t ); | 184 | void irq_changed( struct Hes_Emu* this ); |
192 | void Cpu_write( struct Hes_Emu* this, hes_addr_t, int ); | 185 | void run_until( struct Hes_Emu* this, hes_time_t ); |
193 | void Cpu_write_vdp( struct Hes_Emu* this, int addr, int data ); | 186 | bool run_cpu( struct Hes_Emu* this, hes_time_t end ); |
194 | int Cpu_done( struct Hes_Emu* this ); | 187 | int read_mem_( struct Hes_Emu* this, hes_addr_t ); |
195 | 188 | int read_mem( struct Hes_Emu* this, hes_addr_t ); | |
196 | int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t ); | 189 | void write_mem_( struct Hes_Emu* this, hes_addr_t, int data ); |
197 | void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t, int data ); | 190 | void write_mem( struct Hes_Emu* this, hes_addr_t, int ); |
198 | 191 | void write_vdp( struct Hes_Emu* this, int addr, int data ); | |
199 | static inline byte const* Emu_cpu_set_mmr( struct Hes_Emu* this, int page, int bank ) | 192 | void set_mmr( struct Hes_Emu* this, int reg, int bank ); |
200 | { | 193 | int cpu_done( struct Hes_Emu* this ); |
201 | this->write_pages [page] = 0; | ||
202 | if ( bank < 0x80 ) | ||
203 | return Rom_at_addr( &this->rom, bank * (blargg_long) page_size ); | ||
204 | |||
205 | byte* data = 0; | ||
206 | switch ( bank ) | ||
207 | { | ||
208 | case 0xF8: | ||
209 | data = this->cpu.ram; | ||
210 | break; | ||
211 | |||
212 | case 0xF9: | ||
213 | case 0xFA: | ||
214 | case 0xFB: | ||
215 | data = &this->sgx [(bank - 0xF9) * page_size]; | ||
216 | break; | ||
217 | |||
218 | default: | ||
219 | if ( bank != 0xFF ) { | ||
220 | dprintf( "Unmapped bank $%02X\n", bank ); | ||
221 | } | ||
222 | return this->rom.unmapped; | ||
223 | } | ||
224 | |||
225 | this->write_pages [page] = data; | ||
226 | return data; | ||
227 | } | ||
228 | 194 | ||
229 | #endif | 195 | #endif |
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 | |||
diff --git a/apps/codecs/libgme/kss_emu.h b/apps/codecs/libgme/kss_emu.h index 43df964fcc..382e4b807b 100644 --- a/apps/codecs/libgme/kss_emu.h +++ b/apps/codecs/libgme/kss_emu.h | |||
@@ -16,8 +16,8 @@ | |||
16 | #include "ay_apu.h" | 16 | #include "ay_apu.h" |
17 | #include "opl_apu.h" | 17 | #include "opl_apu.h" |
18 | #include "m3u_playlist.h" | 18 | #include "m3u_playlist.h" |
19 | #include "track_filter.h" | ||
19 | 20 | ||
20 | typedef short sample_t; | ||
21 | typedef int kss_time_t; | 21 | typedef int kss_time_t; |
22 | typedef int kss_addr_t; | 22 | typedef int kss_addr_t; |
23 | typedef struct Z80_Cpu Kss_Cpu; | 23 | typedef struct Z80_Cpu Kss_Cpu; |
@@ -35,7 +35,6 @@ enum { | |||
35 | enum { idle_addr = 0xFFFF }; | 35 | enum { idle_addr = 0xFFFF }; |
36 | enum { scc_enabled_true = 0xC000 }; | 36 | enum { scc_enabled_true = 0xC000 }; |
37 | enum { mem_size = 0x10000 }; | 37 | enum { mem_size = 0x10000 }; |
38 | enum { buf_size = 2048 }; | ||
39 | 38 | ||
40 | // KSS file header | 39 | // KSS file header |
41 | enum { header_size = 0x20 }; | 40 | enum { header_size = 0x20 }; |
@@ -53,7 +52,7 @@ struct header_t | |||
53 | byte bank_mode; | 52 | byte bank_mode; |
54 | byte extra_header; | 53 | byte extra_header; |
55 | byte device_flags; | 54 | byte device_flags; |
56 | 55 | ||
57 | // KSSX extended data, if extra_header==0x10 | 56 | // KSSX extended data, if extra_header==0x10 |
58 | byte data_size [4]; | 57 | byte data_size [4]; |
59 | byte unused [4]; | 58 | byte unused [4]; |
@@ -69,7 +68,7 @@ struct sms_t { | |||
69 | struct Sms_Apu psg; | 68 | struct Sms_Apu psg; |
70 | struct Opl_Apu fm; | 69 | struct Opl_Apu fm; |
71 | }; | 70 | }; |
72 | 71 | ||
73 | struct msx_t { | 72 | struct msx_t { |
74 | struct Ay_Apu psg; | 73 | struct Ay_Apu psg; |
75 | struct Scc_Apu scc; | 74 | struct Scc_Apu scc; |
@@ -84,8 +83,6 @@ struct Kss_Emu { | |||
84 | bool scc_accessed; | 83 | bool scc_accessed; |
85 | bool gain_updated; | 84 | bool gain_updated; |
86 | 85 | ||
87 | int track_count; | ||
88 | |||
89 | unsigned scc_enabled; // 0 or 0xC000 | 86 | unsigned scc_enabled; // 0 or 0xC000 |
90 | int bank_count; | 87 | int bank_count; |
91 | 88 | ||
@@ -94,48 +91,34 @@ struct Kss_Emu { | |||
94 | int ay_latch; | 91 | int ay_latch; |
95 | 92 | ||
96 | // general | 93 | // general |
97 | int max_initial_silence; | ||
98 | int voice_count; | 94 | int voice_count; |
95 | int const* voice_types; | ||
99 | int mute_mask_; | 96 | int mute_mask_; |
100 | int tempo; | 97 | int tempo; |
101 | int gain; | 98 | int gain; |
102 | 99 | ||
103 | long sample_rate; | 100 | int sample_rate; |
104 | 101 | ||
105 | // track-specific | 102 | // track-specific |
103 | int track_count; | ||
106 | int current_track; | 104 | int current_track; |
107 | blargg_long out_time; // number of samples played since start of track | ||
108 | blargg_long emu_time; // number of samples emulator has generated since start of track | ||
109 | bool emu_track_ended_; // emulator has reached end of track | ||
110 | volatile bool track_ended; | ||
111 | |||
112 | // fading | ||
113 | blargg_long fade_start; | ||
114 | int fade_step; | ||
115 | |||
116 | // silence detection | ||
117 | int silence_lookahead; // speed to run emulator when looking ahead for silence | ||
118 | bool ignore_silence; | ||
119 | long silence_time; // number of samples where most recent silence began | ||
120 | long silence_count; // number of samples of silence to play before using buf | ||
121 | long buf_remain; // number of samples left in silence buffer | ||
122 | 105 | ||
123 | struct Stereo_Buffer stereo_buffer; // NULL if using custom buffer | 106 | int clock_rate_; |
124 | long clock_rate_; | ||
125 | unsigned buf_changed_count; | 107 | unsigned buf_changed_count; |
126 | 108 | ||
127 | // M3u Playlist | 109 | // M3u Playlist |
128 | struct M3u_Playlist m3u; | 110 | struct M3u_Playlist m3u; |
129 | 111 | ||
130 | // large items | 112 | struct setup_t tfilter; |
131 | sample_t buf [buf_size]; | 113 | struct Track_Filter track_filter; |
132 | 114 | ||
133 | struct sms_t sms; | 115 | struct sms_t sms; |
134 | struct msx_t msx; | 116 | struct msx_t msx; |
135 | 117 | ||
136 | Kss_Cpu cpu; | 118 | Kss_Cpu cpu; |
119 | struct Multi_Buffer stereo_buf; // NULL if using custom buffer | ||
137 | struct Rom_Data rom; | 120 | struct Rom_Data rom; |
138 | 121 | ||
139 | byte unmapped_read [0x100]; | 122 | byte unmapped_read [0x100]; |
140 | byte unmapped_write [page_size]; | 123 | byte unmapped_write [page_size]; |
141 | byte ram [mem_size + cpu_padding]; | 124 | byte ram [mem_size + cpu_padding]; |
@@ -148,34 +131,46 @@ blargg_err_t Kss_load_mem( struct Kss_Emu* this, const void* data, long size ); | |||
148 | blargg_err_t end_frame( struct Kss_Emu* this, kss_time_t ); | 131 | blargg_err_t end_frame( struct Kss_Emu* this, kss_time_t ); |
149 | 132 | ||
150 | // Set output sample rate. Must be called only once before loading file. | 133 | // Set output sample rate. Must be called only once before loading file. |
151 | blargg_err_t Kss_set_sample_rate( struct Kss_Emu* this, long sample_rate ); | 134 | blargg_err_t Kss_set_sample_rate( struct Kss_Emu* this, int sample_rate ); |
152 | 135 | ||
153 | // Start a track, where 0 is the first track. Also clears warning string. | 136 | // Start a track, where 0 is the first track. Also clears warning string. |
154 | blargg_err_t Kss_start_track( struct Kss_Emu* this, int track ); | 137 | blargg_err_t Kss_start_track( struct Kss_Emu* this, int track ); |
155 | 138 | ||
156 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation | 139 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation |
157 | // errors set warning string, and major errors also end track. | 140 | // errors set warning string, and major errors also end track. |
158 | blargg_err_t Kss_play( struct Kss_Emu* this, long count, sample_t* buf ); | 141 | blargg_err_t Kss_play( struct Kss_Emu* this, int count, sample_t* buf ); |
159 | 142 | ||
160 | // Track status/control | 143 | // Track status/control |
161 | 144 | ||
162 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track | 145 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track |
163 | long Track_tell( struct Kss_Emu* this ); | 146 | int Track_tell( struct Kss_Emu* this ); |
164 | 147 | ||
165 | // Seek to new time in track. Seeking backwards or far forward can take a while. | 148 | // Seek to new time in track. Seeking backwards or far forward can take a while. |
166 | blargg_err_t Track_seek( struct Kss_Emu* this, long msec ); | 149 | blargg_err_t Track_seek( struct Kss_Emu* this, int msec ); |
167 | 150 | ||
168 | // Skip n samples | 151 | // Skip n samples |
169 | blargg_err_t Track_skip( struct Kss_Emu* this, long n ); | 152 | blargg_err_t Track_skip( struct Kss_Emu* this, int n ); |
170 | 153 | ||
171 | // Set start time and length of track fade out. Once fade ends track_ended() returns | 154 | // Set start time and length of track fade out. Once fade ends track_ended() returns |
172 | // true. Fade time can be changed while track is playing. | 155 | // true. Fade time can be changed while track is playing. |
173 | void Track_set_fade( struct Kss_Emu* this, long start_msec, long length_msec ); | 156 | void Track_set_fade( struct Kss_Emu* this, int start_msec, int length_msec ); |
157 | |||
158 | // True if a track has reached its end | ||
159 | static inline bool Track_ended( struct Kss_Emu* this ) | ||
160 | { | ||
161 | return track_ended( &this->track_filter ); | ||
162 | } | ||
163 | |||
164 | // Disables automatic end-of-track detection and skipping of silence at beginning | ||
165 | static inline void Track_ignore_silence( struct Kss_Emu* this, bool disable ) | ||
166 | { | ||
167 | this->track_filter.silence_ignored_ = disable; | ||
168 | } | ||
174 | 169 | ||
175 | // Get track length in milliseconds | 170 | // Get track length in milliseconds |
176 | static inline long Track_get_length( struct Kss_Emu* this, int n ) | 171 | static inline int Track_get_length( struct Kss_Emu* this, int n ) |
177 | { | 172 | { |
178 | long length = 0; | 173 | int length = 0; |
179 | 174 | ||
180 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { | 175 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { |
181 | struct entry_t* entry = &this->m3u.entries [n]; | 176 | struct entry_t* entry = &this->m3u.entries [n]; |
diff --git a/apps/codecs/libgme/kss_scc_apu.h b/apps/codecs/libgme/kss_scc_apu.h index bb20d1d64a..a6962469ac 100644 --- a/apps/codecs/libgme/kss_scc_apu.h +++ b/apps/codecs/libgme/kss_scc_apu.h | |||
@@ -34,7 +34,7 @@ void Scc_reset( struct Scc_Apu* this ); | |||
34 | 34 | ||
35 | // Set overall volume, where 1.0 is normal | 35 | // Set overall volume, where 1.0 is normal |
36 | void Scc_volume( struct Scc_Apu* this, int v ); | 36 | void Scc_volume( struct Scc_Apu* this, int v ); |
37 | 37 | ||
38 | static inline void Scc_set_output( struct Scc_Apu* this, int index, struct Blip_Buffer* b ) | 38 | static inline void Scc_set_output( struct Scc_Apu* this, int index, struct Blip_Buffer* b ) |
39 | { | 39 | { |
40 | assert( (unsigned) index < scc_osc_count ); | 40 | assert( (unsigned) index < scc_osc_count ); |
diff --git a/apps/codecs/libgme/multi_buffer.c b/apps/codecs/libgme/multi_buffer.c index 26cb8cdec6..554778c3de 100644 --- a/apps/codecs/libgme/multi_buffer.c +++ b/apps/codecs/libgme/multi_buffer.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // Blip_Buffer 0.4.1. http://www.slack.net/~ant/ | 1 | // Multi_Buffer 0.4.1. http://www.slack.net/~ant/ |
2 | 2 | ||
3 | #include "multi_buffer.h" | 3 | #include "multi_buffer.h" |
4 | 4 | ||
@@ -15,212 +15,272 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | |||
15 | 15 | ||
16 | #include "blargg_source.h" | 16 | #include "blargg_source.h" |
17 | 17 | ||
18 | #ifdef BLARGG_ENABLE_OPTIMIZER | 18 | // Tracked_Blip_Buffer |
19 | #include BLARGG_ENABLE_OPTIMIZER | 19 | |
20 | #endif | 20 | int const blip_buffer_extra = 32; // TODO: explain why this value |
21 | 21 | ||
22 | // Stereo_Buffer | 22 | void Tracked_init( struct Tracked_Blip_Buffer* this ) |
23 | 23 | { | |
24 | void Buffer_init( struct Stereo_Buffer* this ) | 24 | Blip_init( &this->blip ); |
25 | { | 25 | this->last_non_silence = 0; |
26 | Blip_init( &this->bufs [0] ); | ||
27 | Blip_init( &this->bufs [1] ); | ||
28 | Blip_init( &this->bufs [2] ); | ||
29 | |||
30 | this->chan.center = &this->bufs [0]; | ||
31 | this->chan.left = &this->bufs [1]; | ||
32 | this->chan.right = &this->bufs [2]; | ||
33 | |||
34 | this->length_ = 0; | ||
35 | this->sample_rate_ = 0; | ||
36 | this->channels_changed_count_ = 1; | ||
37 | this->samples_per_frame_ = 2; | ||
38 | } | 26 | } |
39 | 27 | ||
40 | blargg_err_t Buffer_set_sample_rate( struct Stereo_Buffer* this, long rate, int msec ) | 28 | void Tracked_clear( struct Tracked_Blip_Buffer* this ) |
41 | { | 29 | { |
42 | int i; | 30 | this->last_non_silence = 0; |
43 | for ( i = 0; i < buf_count; i++ ) | 31 | Blip_clear( &this->blip ); |
44 | RETURN_ERR( Blip_set_sample_rate( &this->bufs[i], rate, msec ) ); | ||
45 | |||
46 | this->sample_rate_ = Blip_sample_rate( &this->bufs [0] ); | ||
47 | this->length_ = Blip_length( &this->bufs [0] ); | ||
48 | return 0; | ||
49 | } | 32 | } |
50 | 33 | ||
51 | void Buffer_clock_rate( struct Stereo_Buffer* this, long rate ) | 34 | void Tracked_end_frame( struct Tracked_Blip_Buffer* this, blip_time_t t ) |
52 | { | 35 | { |
53 | int i; | 36 | Blip_end_frame( &this->blip, t ); |
54 | for ( i = 0; i < buf_count; i++ ) | 37 | if ( this->blip.modified ) |
55 | Blip_set_clock_rate( &this->bufs [i], rate ); | 38 | { |
39 | this->blip.modified = false; | ||
40 | this->last_non_silence = Blip_samples_avail( &this->blip ) + blip_buffer_extra; | ||
41 | } | ||
56 | } | 42 | } |
57 | 43 | ||
58 | void Buffer_bass_freq( struct Stereo_Buffer* this, int bass ) | 44 | unsigned Tracked_non_silent( struct Tracked_Blip_Buffer* this ) |
59 | { | 45 | { |
60 | unsigned i; | 46 | return this->last_non_silence | unsettled( &this->blip ); |
61 | for ( i = 0; i < buf_count; i++ ) | ||
62 | Blip_bass_freq( &this->bufs [i], bass ); | ||
63 | } | 47 | } |
64 | 48 | ||
65 | struct channel_t Buffer_channel( struct Stereo_Buffer* this ) | 49 | static inline void remove_( struct Tracked_Blip_Buffer* this, int n ) |
66 | { | 50 | { |
67 | return this->chan; | 51 | if ( (this->last_non_silence -= n) < 0 ) |
52 | this->last_non_silence = 0; | ||
68 | } | 53 | } |
69 | 54 | ||
70 | void Buffer_clear( struct Stereo_Buffer* this ) | 55 | void Tracked_remove_silence( struct Tracked_Blip_Buffer* this, int n ) |
71 | { | 56 | { |
72 | this->stereo_added = 0; | 57 | remove_( this, n ); |
73 | this->was_stereo = false; | 58 | Blip_remove_silence( &this->blip, n ); |
74 | int i; | ||
75 | for ( i = 0; i < buf_count; i++ ) | ||
76 | Blip_clear( &this->bufs [i], 1 ); | ||
77 | } | 59 | } |
78 | 60 | ||
79 | void Buffer_end_frame( struct Stereo_Buffer* this, blip_time_t clock_count ) | 61 | void Tracked_remove_samples( struct Tracked_Blip_Buffer* this, int n ) |
62 | { | ||
63 | remove_( this, n ); | ||
64 | Blip_remove_samples( &this->blip, n ); | ||
65 | } | ||
66 | |||
67 | void Tracked_remove_all_samples( struct Tracked_Blip_Buffer* this ) | ||
68 | { | ||
69 | int avail = Blip_samples_avail( &this->blip ); | ||
70 | if ( !Tracked_non_silent( this ) ) | ||
71 | Tracked_remove_silence( this, avail ); | ||
72 | else | ||
73 | Tracked_remove_samples( this, avail ); | ||
74 | } | ||
75 | |||
76 | int Tracked_read_samples( struct Tracked_Blip_Buffer* this, blip_sample_t out [], int count ) | ||
77 | { | ||
78 | count = Blip_read_samples( &this->blip, out, count, false ); | ||
79 | remove_( this, count ); | ||
80 | return count; | ||
81 | } | ||
82 | |||
83 | // Stereo_Mixer | ||
84 | |||
85 | // mixers use a single index value to improve performance on register-challenged processors | ||
86 | // offset goes from negative to zero | ||
87 | |||
88 | void Mixer_init( struct Stereo_Mixer* this ) | ||
80 | { | 89 | { |
81 | this->stereo_added = 0; | 90 | this->samples_read = 0; |
82 | unsigned i; | 91 | } |
83 | for ( i = 0; i < buf_count; i++ ) | 92 | |
93 | static void mix_mono( struct Stereo_Mixer* this, blip_sample_t out_ [], int count ) | ||
94 | { | ||
95 | int const bass = this->bufs [2]->blip.bass_shift_; | ||
96 | delta_t const* center = this->bufs [2]->blip.buffer_ + this->samples_read; | ||
97 | int center_sum = this->bufs [2]->blip.reader_accum_; | ||
98 | |||
99 | typedef blip_sample_t stereo_blip_sample_t [stereo]; | ||
100 | stereo_blip_sample_t* BLARGG_RESTRICT out = (stereo_blip_sample_t*) out_ + count; | ||
101 | int offset = -count; | ||
102 | do | ||
84 | { | 103 | { |
85 | this->stereo_added |= Blip_clear_modified( &this->bufs [i] ) << i; | 104 | int s = center_sum >> delta_bits; |
86 | Blip_end_frame( &this->bufs [i], clock_count ); | 105 | |
106 | center_sum -= center_sum >> bass; | ||
107 | center_sum += center [offset]; | ||
108 | |||
109 | BLIP_CLAMP( s, s ); | ||
110 | |||
111 | out [offset] [0] = (blip_sample_t) s; | ||
112 | out [offset] [1] = (blip_sample_t) s; | ||
87 | } | 113 | } |
114 | while ( ++offset ); | ||
115 | |||
116 | this->bufs [2]->blip.reader_accum_ = center_sum; | ||
88 | } | 117 | } |
89 | 118 | ||
90 | long Buffer_read_samples( struct Stereo_Buffer* this, blip_sample_t* out, long count ) | 119 | static void mix_stereo( struct Stereo_Mixer* this, blip_sample_t out_ [], int count ) |
91 | { | 120 | { |
92 | require( !(count & 1) ); // count must be even | 121 | blip_sample_t* BLARGG_RESTRICT out = out_ + count * stereo; |
93 | count = (unsigned) count / 2; | 122 | // do left + center and right + center separately to reduce register load |
94 | 123 | struct Tracked_Blip_Buffer* const* buf = &this->bufs [2]; | |
95 | long avail = Blip_samples_avail( &this->bufs [0] ); | 124 | while ( true ) // loop runs twice |
96 | if ( count > avail ) | ||
97 | count = avail; | ||
98 | if ( count ) | ||
99 | { | 125 | { |
100 | int bufs_used = this->stereo_added | this->was_stereo; | 126 | --buf; |
101 | //dprintf( "%X\n", bufs_used ); | 127 | --out; |
102 | if ( bufs_used <= 1 ) | 128 | |
103 | { | 129 | int const bass = this->bufs [2]->blip.bass_shift_; |
104 | Buffer_mix_mono( this, out, count ); | 130 | delta_t const* side = (*buf)->blip.buffer_ + this->samples_read; |
105 | Blip_remove_samples( &this->bufs [0], count ); | 131 | delta_t const* center = this->bufs [2]->blip.buffer_ + this->samples_read; |
106 | Blip_remove_silence( &this->bufs [1], count ); | 132 | |
107 | Blip_remove_silence( &this->bufs [2], count ); | 133 | int side_sum = (*buf)->blip.reader_accum_; |
108 | } | 134 | int center_sum = this->bufs [2]->blip.reader_accum_; |
109 | else if ( bufs_used & 1 ) | 135 | |
110 | { | 136 | int offset = -count; |
111 | Buffer_mix_stereo( this, out, count ); | 137 | do |
112 | Blip_remove_samples( &this->bufs [0], count ); | ||
113 | Blip_remove_samples( &this->bufs [1], count ); | ||
114 | Blip_remove_samples( &this->bufs [2], count ); | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | Buffer_mix_stereo_no_center( this, out, count ); | ||
119 | Blip_remove_silence( &this->bufs [0], count ); | ||
120 | Blip_remove_samples( &this->bufs [1], count ); | ||
121 | Blip_remove_samples( &this->bufs [2], count ); | ||
122 | } | ||
123 | |||
124 | // to do: this might miss opportunities for optimization | ||
125 | if ( !Blip_samples_avail( &this->bufs [0] ) ) | ||
126 | { | 138 | { |
127 | this->was_stereo = this->stereo_added; | 139 | int s = (center_sum + side_sum) >> delta_bits; |
128 | this->stereo_added = 0; | 140 | |
141 | side_sum -= side_sum >> bass; | ||
142 | center_sum -= center_sum >> bass; | ||
143 | |||
144 | side_sum += side [offset]; | ||
145 | center_sum += center [offset]; | ||
146 | |||
147 | BLIP_CLAMP( s, s ); | ||
148 | |||
149 | ++offset; // before write since out is decremented to slightly before end | ||
150 | out [offset * stereo] = (blip_sample_t) s; | ||
129 | } | 151 | } |
152 | while ( offset ); | ||
153 | |||
154 | (*buf)->blip.reader_accum_ = side_sum; | ||
155 | |||
156 | if ( buf != this->bufs ) | ||
157 | continue; | ||
158 | |||
159 | // only end center once | ||
160 | this->bufs [2]->blip.reader_accum_ = center_sum; | ||
161 | break; | ||
130 | } | 162 | } |
131 | |||
132 | return count * 2; | ||
133 | } | 163 | } |
134 | 164 | ||
135 | unsigned Buffer_channels_changed_count( struct Stereo_Buffer* this ) | 165 | void Mixer_read_pairs( struct Stereo_Mixer* this, blip_sample_t out [], int count ) |
136 | { | 166 | { |
137 | return this->channels_changed_count_; | 167 | // TODO: if caller never marks buffers as modified, uses mono |
168 | // except that buffer isn't cleared, so caller can encounter | ||
169 | // subtle problems and not realize the cause. | ||
170 | this->samples_read += count; | ||
171 | if ( Tracked_non_silent( this->bufs [0] ) | Tracked_non_silent( this->bufs [1] ) ) | ||
172 | mix_stereo( this, out, count ); | ||
173 | else | ||
174 | mix_mono( this, out, count ); | ||
138 | } | 175 | } |
139 | 176 | ||
140 | void Buffer_channels_changed( struct Stereo_Buffer* this ) | 177 | // Multi_Buffer |
178 | |||
179 | void Buffer_init( struct Multi_Buffer* this ) | ||
141 | { | 180 | { |
142 | this->channels_changed_count_++; | 181 | int const spf = 2; |
182 | |||
183 | Tracked_init( &this->bufs [0] ); | ||
184 | Tracked_init( &this->bufs [1] ); | ||
185 | Tracked_init( &this->bufs [2] ); | ||
186 | |||
187 | Mixer_init( &this->mixer ); | ||
188 | |||
189 | this->length_ = 0; | ||
190 | this->sample_rate_ = 0; | ||
191 | this->channels_changed_count_ = 1; | ||
192 | this->channel_types_ = NULL; | ||
193 | this->channel_count_ = 0; | ||
194 | this->samples_per_frame_ = spf; | ||
195 | this->immediate_removal_ = true; | ||
196 | |||
197 | this->mixer.bufs [2] = &this->bufs [2]; | ||
198 | this->mixer.bufs [0] = &this->bufs [0]; | ||
199 | this->mixer.bufs [1] = &this->bufs [1]; | ||
200 | |||
201 | this->chan.center = &this->bufs [2].blip; | ||
202 | this->chan.left = &this->bufs [0].blip; | ||
203 | this->chan.right = &this->bufs [1].blip; | ||
143 | } | 204 | } |
144 | 205 | ||
145 | void Buffer_mix_stereo( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) | 206 | blargg_err_t Buffer_set_sample_rate( struct Multi_Buffer* this, int rate, int msec ) |
146 | { | 207 | { |
147 | blip_sample_t* BLIP_RESTRICT out = out_; | 208 | int i; |
148 | int const bass = BLIP_READER_BASS( this->bufs [1] ); | 209 | for ( i = bufs_size; --i >= 0; ) |
149 | BLIP_READER_BEGIN( left, this->bufs [1] ); | 210 | RETURN_ERR( Blip_set_sample_rate( &this->bufs [i].blip, rate, msec ) ); |
150 | BLIP_READER_BEGIN( right, this->bufs [2] ); | 211 | |
151 | BLIP_READER_BEGIN( center, this->bufs [0] ); | 212 | this->sample_rate_ = Blip_sample_rate( &this->bufs [0].blip ); |
152 | 213 | this->length_ = Blip_length( &this->bufs [0].blip ); | |
153 | for ( ; count; --count ) | 214 | return 0; |
154 | { | ||
155 | int c = BLIP_READER_READ( center ); | ||
156 | blargg_long l = c + BLIP_READER_READ( left ); | ||
157 | blargg_long r = c + BLIP_READER_READ( right ); | ||
158 | if ( (int16_t) l != l ) | ||
159 | l = 0x7FFF - (l >> 24); | ||
160 | |||
161 | BLIP_READER_NEXT( center, bass ); | ||
162 | if ( (int16_t) r != r ) | ||
163 | r = 0x7FFF - (r >> 24); | ||
164 | |||
165 | BLIP_READER_NEXT( left, bass ); | ||
166 | BLIP_READER_NEXT( right, bass ); | ||
167 | |||
168 | out [0] = l; | ||
169 | out [1] = r; | ||
170 | out += 2; | ||
171 | } | ||
172 | |||
173 | BLIP_READER_END( center, this->bufs [0] ); | ||
174 | BLIP_READER_END( right, this->bufs [2] ); | ||
175 | BLIP_READER_END( left, this->bufs [1] ); | ||
176 | } | 215 | } |
177 | 216 | ||
178 | void Buffer_mix_stereo_no_center( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) | 217 | void Buffer_clock_rate( struct Multi_Buffer* this, int rate ) |
179 | { | 218 | { |
180 | blip_sample_t* BLIP_RESTRICT out = out_; | 219 | int i; |
181 | int const bass = BLIP_READER_BASS( this->bufs [1] ); | 220 | for ( i = bufs_size; --i >= 0; ) |
182 | BLIP_READER_BEGIN( left, this->bufs [1] ); | 221 | Blip_set_clock_rate( &this->bufs [i].blip, rate ); |
183 | BLIP_READER_BEGIN( right, this->bufs [2] ); | 222 | } |
184 | 223 | ||
185 | for ( ; count; --count ) | 224 | void Buffer_bass_freq( struct Multi_Buffer* this, int bass ) |
186 | { | 225 | { |
187 | blargg_long l = BLIP_READER_READ( left ); | 226 | int i; |
188 | if ( (int16_t) l != l ) | 227 | for ( i = bufs_size; --i >= 0; ) |
189 | l = 0x7FFF - (l >> 24); | 228 | Blip_bass_freq( &this->bufs [i].blip, bass ); |
190 | 229 | } | |
191 | blargg_long r = BLIP_READER_READ( right ); | 230 | |
192 | if ( (int16_t) r != r ) | 231 | blargg_err_t Buffer_set_channel_count( struct Multi_Buffer* this, int n, int const* types ) |
193 | r = 0x7FFF - (r >> 24); | 232 | { |
194 | 233 | this->channel_count_ = n; | |
195 | BLIP_READER_NEXT( left, bass ); | 234 | this->channel_types_ = types; |
196 | BLIP_READER_NEXT( right, bass ); | 235 | return 0; |
197 | |||
198 | out [0] = l; | ||
199 | out [1] = r; | ||
200 | out += 2; | ||
201 | } | ||
202 | |||
203 | BLIP_READER_END( right, this->bufs [2] ); | ||
204 | BLIP_READER_END( left, this->bufs [1] ); | ||
205 | } | 236 | } |
206 | 237 | ||
207 | void Buffer_mix_mono( struct Stereo_Buffer* this, blip_sample_t* out_, blargg_long count ) | 238 | struct channel_t Buffer_channel( struct Multi_Buffer* this, int i ) |
208 | { | 239 | { |
209 | blip_sample_t* BLIP_RESTRICT out = out_; | 240 | (void) i; |
210 | int const bass = BLIP_READER_BASS( this->bufs [0] ); | 241 | return this->chan; |
211 | BLIP_READER_BEGIN( center, this->bufs [0] ); | 242 | } |
212 | 243 | ||
213 | for ( ; count; --count ) | 244 | void Buffer_clear( struct Multi_Buffer* this ) |
245 | { | ||
246 | int i; | ||
247 | this->mixer.samples_read = 0; | ||
248 | for ( i = bufs_size; --i >= 0; ) | ||
249 | Tracked_clear( &this->bufs [i] ); | ||
250 | } | ||
251 | |||
252 | void Buffer_end_frame( struct Multi_Buffer* this, blip_time_t clock_count ) | ||
253 | { | ||
254 | int i; | ||
255 | for ( i = bufs_size; --i >= 0; ) | ||
256 | Tracked_end_frame( &this->bufs [i], clock_count ); | ||
257 | } | ||
258 | |||
259 | int Buffer_read_samples( struct Multi_Buffer* this, blip_sample_t out [], int out_size ) | ||
260 | { | ||
261 | require( (out_size & 1) == 0 ); // must read an even number of samples | ||
262 | out_size = min( out_size, Buffer_samples_avail( this ) ); | ||
263 | |||
264 | int pair_count = (int) (out_size >> 1); | ||
265 | if ( pair_count ) | ||
214 | { | 266 | { |
215 | blargg_long s = BLIP_READER_READ( center ); | 267 | Mixer_read_pairs( &this->mixer, out, pair_count ); |
216 | if ( (int16_t) s != s ) | 268 | |
217 | s = 0x7FFF - (s >> 24); | 269 | if ( Buffer_samples_avail( this ) <= 0 || this->immediate_removal_ ) |
218 | 270 | { | |
219 | BLIP_READER_NEXT( center, bass ); | 271 | int i; |
220 | out [0] = s; | 272 | for ( i = bufs_size; --i >= 0; ) |
221 | out [1] = s; | 273 | { |
222 | out += 2; | 274 | buf_t* b = &this->bufs [i]; |
275 | // TODO: might miss non-silence settling since it checks END of last read | ||
276 | if ( !Tracked_non_silent( b ) ) | ||
277 | Tracked_remove_silence( b, this->mixer.samples_read ); | ||
278 | else | ||
279 | Tracked_remove_samples( b, this->mixer.samples_read ); | ||
280 | } | ||
281 | this->mixer.samples_read = 0; | ||
282 | } | ||
223 | } | 283 | } |
224 | 284 | ||
225 | BLIP_READER_END( center, this->bufs [0] ); | 285 | return out_size; |
226 | } | 286 | } |
diff --git a/apps/codecs/libgme/multi_buffer.h b/apps/codecs/libgme/multi_buffer.h index cfdae4f077..e5efa5a230 100644 --- a/apps/codecs/libgme/multi_buffer.h +++ b/apps/codecs/libgme/multi_buffer.h | |||
@@ -1,4 +1,4 @@ | |||
1 | // Multi-channel sound buffer interface, and basic mono and stereo buffers | 1 | // Multi-channel sound buffer interface, stereo and effects buffers |
2 | 2 | ||
3 | // Blip_Buffer 0.4.1 | 3 | // Blip_Buffer 0.4.1 |
4 | #ifndef MULTI_BUFFER_H | 4 | #ifndef MULTI_BUFFER_H |
@@ -16,57 +16,99 @@ struct channel_t { | |||
16 | 16 | ||
17 | enum { type_index_mask = 0xFF }; | 17 | enum { type_index_mask = 0xFF }; |
18 | enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type }; | 18 | enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type }; |
19 | enum { buf_count = 3 }; | 19 | enum { stereo = 2 }; |
20 | 20 | enum { bufs_size = 3 }; | |
21 | struct Stereo_Buffer { | 21 | |
22 | struct Blip_Buffer bufs [buf_count]; | 22 | // Tracked_Blip_Buffer |
23 | struct channel_t chan; | 23 | struct Tracked_Blip_Buffer { |
24 | int stereo_added; | 24 | struct Blip_Buffer blip; |
25 | int was_stereo; | 25 | int last_non_silence; |
26 | 26 | }; | |
27 | |||
28 | void Tracked_init( struct Tracked_Blip_Buffer* this ); | ||
29 | unsigned Tracked_non_silent( struct Tracked_Blip_Buffer* this ); | ||
30 | void Tracked_remove_all_samples( struct Tracked_Blip_Buffer * this ); | ||
31 | int Tracked_read_samples( struct Tracked_Blip_Buffer* this, blip_sample_t [], int ); | ||
32 | void Tracked_remove_silence( struct Tracked_Blip_Buffer* this, int ); | ||
33 | void Tracked_remove_samples( struct Tracked_Blip_Buffer* this, int ); | ||
34 | void Tracked_clear( struct Tracked_Blip_Buffer* this ); | ||
35 | void Tracked_end_frame( struct Tracked_Blip_Buffer* this, blip_time_t ); | ||
36 | |||
37 | static inline delta_t unsettled( struct Blip_Buffer* this ) | ||
38 | { | ||
39 | return this->reader_accum_ >> delta_bits; | ||
40 | } | ||
41 | |||
42 | // Stereo Mixer | ||
43 | struct Stereo_Mixer { | ||
44 | struct Tracked_Blip_Buffer* bufs [3]; | ||
45 | int samples_read; | ||
46 | }; | ||
47 | |||
48 | void Mixer_init( struct Stereo_Mixer* this ); | ||
49 | void Mixer_read_pairs( struct Stereo_Mixer* this, blip_sample_t out [], int count ); | ||
50 | |||
51 | typedef struct Tracked_Blip_Buffer buf_t; | ||
52 | |||
53 | // Multi_Buffer | ||
54 | struct Multi_Buffer { | ||
27 | unsigned channels_changed_count_; | 55 | unsigned channels_changed_count_; |
28 | long sample_rate_; | 56 | int sample_rate_; |
29 | int length_; | 57 | int length_; |
58 | int channel_count_; | ||
30 | int samples_per_frame_; | 59 | int samples_per_frame_; |
60 | int const *channel_types_; | ||
61 | bool immediate_removal_; | ||
62 | |||
63 | buf_t bufs [bufs_size]; | ||
64 | struct Stereo_Mixer mixer; | ||
65 | struct channel_t chan; | ||
31 | }; | 66 | }; |
32 | 67 | ||
33 | // Initializes Stereo_Buffer structure | 68 | blargg_err_t Buffer_set_channel_count( struct Multi_Buffer* this, int n, int const* types ); |
34 | void Buffer_init( struct Stereo_Buffer* this ); | 69 | |
70 | // Buffers used for all channels | ||
71 | static inline struct Blip_Buffer* center( struct Multi_Buffer* this ) { return &this->bufs [2].blip; } | ||
72 | static inline struct Blip_Buffer* left( struct Multi_Buffer* this ) { return &this->bufs [0].blip; } | ||
73 | static inline struct Blip_Buffer* right( struct Multi_Buffer* this ) { return &this->bufs [1].blip; } | ||
35 | 74 | ||
36 | blargg_err_t Buffer_set_sample_rate( struct Stereo_Buffer* this, long, int msec ); | 75 | // Initializes Multi_Buffer structure |
37 | void Buffer_clock_rate( struct Stereo_Buffer* this, long ); | 76 | void Buffer_init( struct Multi_Buffer* this ); |
38 | void Buffer_bass_freq( struct Stereo_Buffer* this, int ); | ||
39 | void Buffer_clear( struct Stereo_Buffer* this ); | ||
40 | struct channel_t Buffer_channel( struct Stereo_Buffer* this ); | ||
41 | void Buffer_end_frame( struct Stereo_Buffer* this, blip_time_t ); | ||
42 | 77 | ||
43 | long Buffer_read_samples( struct Stereo_Buffer* this, blip_sample_t*, long ); | 78 | blargg_err_t Buffer_set_sample_rate( struct Multi_Buffer* this, int, int msec ); |
79 | void Buffer_clock_rate( struct Multi_Buffer* this, int ); | ||
80 | void Buffer_bass_freq( struct Multi_Buffer* this, int ); | ||
81 | void Buffer_clear( struct Multi_Buffer* this ); | ||
82 | void Buffer_end_frame( struct Multi_Buffer* this, blip_time_t ) ICODE_ATTR; | ||
83 | |||
84 | static inline int Buffer_length( struct Multi_Buffer* this ) | ||
85 | { | ||
86 | return this->length_; | ||
87 | } | ||
44 | 88 | ||
45 | // Count of changes to channel configuration. Incremented whenever | 89 | // Count of changes to channel configuration. Incremented whenever |
46 | // a change is made to any of the Blip_Buffers for any channel. | 90 | // a change is made to any of the Blip_Buffers for any channel. |
47 | unsigned Buffer_channels_changed_count( struct Stereo_Buffer* this ); | 91 | static inline unsigned Buffer_channels_changed_count( struct Multi_Buffer* this ) |
48 | void Buffer_channels_changed( struct Stereo_Buffer* this ); | 92 | { |
49 | 93 | return this->channels_changed_count_; | |
50 | void Buffer_mix_stereo_no_center( struct Stereo_Buffer* this, blip_sample_t*, blargg_long ); | 94 | } |
51 | void Buffer_mix_stereo( struct Stereo_Buffer* this, blip_sample_t*, blargg_long ); | ||
52 | void Buffer_mix_mono( struct Stereo_Buffer* this, blip_sample_t*, blargg_long ); | ||
53 | 95 | ||
54 | // Number of samples per output frame (1 = mono, 2 = stereo) | 96 | static inline void Buffer_disable_immediate_removal( struct Multi_Buffer* this ) |
55 | static inline int Buffer_samples_per_frame( struct Stereo_Buffer* this ) | ||
56 | { | 97 | { |
57 | return this->samples_per_frame_; | 98 | this->immediate_removal_ = false; |
58 | } | 99 | } |
59 | 100 | ||
60 | // See Blip_Buffer.h | 101 | static inline int Buffer_sample_rate( struct Multi_Buffer* this ) |
61 | static inline long Buffer_sample_rate( struct Stereo_Buffer* this ) | ||
62 | { | 102 | { |
63 | return this->sample_rate_; | 103 | return this->sample_rate_; |
64 | } | 104 | } |
65 | 105 | ||
66 | // Length of buffer, in milliseconds | 106 | static inline int Buffer_samples_avail( struct Multi_Buffer* this ) |
67 | static inline int Buffer_length( struct Stereo_Buffer* this ) | ||
68 | { | 107 | { |
69 | return this->length_; | 108 | return (Blip_samples_avail(&this->bufs [0].blip) - this->mixer.samples_read) * 2; |
70 | } | 109 | } |
71 | 110 | ||
111 | int Buffer_read_samples( struct Multi_Buffer* this, blip_sample_t*, int ) ICODE_ATTR; | ||
112 | struct channel_t Buffer_channel( struct Multi_Buffer* this, int i ); | ||
113 | |||
72 | #endif | 114 | #endif |
diff --git a/apps/codecs/libgme/nes_apu.c b/apps/codecs/libgme/nes_apu.c index 7d2814b3d8..630e71f450 100644 --- a/apps/codecs/libgme/nes_apu.c +++ b/apps/codecs/libgme/nes_apu.c | |||
@@ -39,19 +39,19 @@ void Apu_init( struct Nes_Apu* this ) | |||
39 | this->oscs [4] = &this->dmc.osc; | 39 | this->oscs [4] = &this->dmc.osc; |
40 | 40 | ||
41 | Apu_output( this, NULL ); | 41 | Apu_output( this, NULL ); |
42 | this->dmc.nonlinear = false; | ||
42 | Apu_volume( this, (int)FP_ONE_VOLUME ); | 43 | Apu_volume( this, (int)FP_ONE_VOLUME ); |
43 | Apu_reset( this, false, 0 ); | 44 | Apu_reset( this, false, 0 ); |
44 | } | 45 | } |
45 | 46 | ||
46 | void Apu_enable_nonlinear( struct Nes_Apu* this, int v ) | 47 | void Apu_enable_nonlinear_( struct Nes_Apu* this, double sq, double tnd ) |
47 | { | 48 | { |
48 | this->dmc.nonlinear = true; | 49 | this->dmc.nonlinear = true; |
49 | Synth_volume( &this->square_synth, (int)((long long)(1.3 * 0.25751258 / 0.742467605 * 0.25 * FP_ONE_VOLUME) / amp_range * v) ); | 50 | Synth_volume( &this->square_synth, (int)((long long)(sq * FP_ONE_VOLUME) / amp_range) ); |
50 | 51 | ||
51 | const int tnd = (int)(0.48 / 202 * 0.75 * FP_ONE_VOLUME); | 52 | Synth_volume( &this->triangle.synth, tnd * 2.752 ); |
52 | Synth_volume( &this->triangle.synth, 3 * tnd ); | 53 | Synth_volume( &this->noise.synth , tnd * 1.849 ); |
53 | Synth_volume( &this->noise.synth, 2 * tnd ); | 54 | Synth_volume( &this->dmc.synth , tnd ); |
54 | Synth_volume( &this->dmc.synth, tnd ); | ||
55 | 55 | ||
56 | this->square1 .osc.last_amp = 0; | 56 | this->square1 .osc.last_amp = 0; |
57 | this->square2 .osc.last_amp = 0; | 57 | this->square2 .osc.last_amp = 0; |
@@ -62,11 +62,13 @@ void Apu_enable_nonlinear( struct Nes_Apu* this, int v ) | |||
62 | 62 | ||
63 | void Apu_volume( struct Nes_Apu* this, int v ) | 63 | void Apu_volume( struct Nes_Apu* this, int v ) |
64 | { | 64 | { |
65 | this->dmc.nonlinear = false; | 65 | if ( !this->dmc.nonlinear ) |
66 | Synth_volume( &this->square_synth, (int)((long long)(0.1128 *FP_ONE_VOLUME) * v / amp_range / FP_ONE_VOLUME) ); | 66 | { |
67 | Synth_volume( &this->triangle.synth,(int)((long long)(0.12765*FP_ONE_VOLUME) * v / amp_range / FP_ONE_VOLUME) ); | 67 | Synth_volume( &this->square_synth, (int)((long long)((0.125 * (1.0 /1.11)) * FP_ONE_VOLUME) * v / amp_range / FP_ONE_VOLUME) ); // was 0.1128 1.108 |
68 | Synth_volume( &this->noise.synth, (int)((long long)(0.0741 *FP_ONE_VOLUME) * v / amp_range / FP_ONE_VOLUME) ); | 68 | Synth_volume( &this->triangle.synth,(int)((long long)((0.150 * (1.0 /1.11)) * FP_ONE_VOLUME) * v / amp_range / FP_ONE_VOLUME) ); // was 0.12765 1.175 |
69 | Synth_volume( &this->dmc.synth, (int)((long long)(0.42545*FP_ONE_VOLUME) * v / 127 / FP_ONE_VOLUME) ); | 69 | Synth_volume( &this->noise.synth, (int)((long long)((0.095 * (1.0 /1.11)) * FP_ONE_VOLUME) * v / amp_range / FP_ONE_VOLUME) ); // was 0.0741 1.282 |
70 | Synth_volume( &this->dmc.synth, (int)((long long)((0.450 * (1.0 /1.11)) * FP_ONE_VOLUME) * v / 2048 / FP_ONE_VOLUME) ); // was 0.42545 1.058 | ||
71 | } | ||
70 | } | 72 | } |
71 | 73 | ||
72 | void Apu_output( struct Nes_Apu* this, struct Blip_Buffer* buffer ) | 74 | void Apu_output( struct Nes_Apu* this, struct Blip_Buffer* buffer ) |
diff --git a/apps/codecs/libgme/nes_apu.h b/apps/codecs/libgme/nes_apu.h index 11f1f26cc7..0a2b1f57cd 100644 --- a/apps/codecs/libgme/nes_apu.h +++ b/apps/codecs/libgme/nes_apu.h | |||
@@ -1,6 +1,6 @@ | |||
1 | // NES 2A03 APU sound chip emulator | 1 | // NES 2A03 APU sound chip emulator |
2 | 2 | ||
3 | // Nes_Snd_Emu 0.1.8 | 3 | // Nes_Snd_Emu 0.2.0-pre |
4 | #ifndef NES_APU_H | 4 | #ifndef NES_APU_H |
5 | #define NES_APU_H | 5 | #define NES_APU_H |
6 | 6 | ||
@@ -9,7 +9,7 @@ | |||
9 | 9 | ||
10 | enum { apu_status_addr = 0x4015 }; | 10 | enum { apu_status_addr = 0x4015 }; |
11 | enum { apu_osc_count = 5 }; | 11 | enum { apu_osc_count = 5 }; |
12 | enum { apu_no_irq = INT_MAX / 2 + 1 }; | 12 | enum { apu_no_irq = INT_MAX/2 + 1 }; |
13 | enum { apu_irq_waiting = 0 }; | 13 | enum { apu_irq_waiting = 0 }; |
14 | 14 | ||
15 | enum { apu_io_addr = 0x4000 }; | 15 | enum { apu_io_addr = 0x4000 }; |
@@ -17,24 +17,16 @@ enum { apu_io_size = 0x18 }; | |||
17 | 17 | ||
18 | struct apu_state_t; | 18 | struct apu_state_t; |
19 | 19 | ||
20 | struct Nes_Apu { | 20 | struct Nes_Apu { |
21 | nes_time_t last_dmc_time; | ||
22 | int osc_enables; | ||
23 | |||
24 | struct Nes_Osc* oscs [apu_osc_count]; | ||
25 | struct Nes_Square square1; | ||
26 | struct Nes_Square square2; | ||
27 | struct Nes_Noise noise; | ||
28 | struct Nes_Triangle triangle; | ||
29 | struct Nes_Dmc dmc; | ||
30 | |||
31 | int tempo_; | 21 | int tempo_; |
32 | nes_time_t last_time; // has been run until this time in current frame | 22 | nes_time_t last_time; // has been run until this time in current frame |
23 | nes_time_t last_dmc_time; | ||
33 | nes_time_t earliest_irq_; | 24 | nes_time_t earliest_irq_; |
34 | nes_time_t next_irq; | 25 | nes_time_t next_irq; |
35 | int frame_period; | 26 | int frame_period; |
36 | int frame_delay; // cycles until frame counter runs next | 27 | int frame_delay; // cycles until frame counter runs next |
37 | int frame; // current frame (0-3) | 28 | int frame; // current frame (0-3) |
29 | int osc_enables; | ||
38 | int frame_mode; | 30 | int frame_mode; |
39 | bool irq_flag; | 31 | bool irq_flag; |
40 | 32 | ||
@@ -42,6 +34,13 @@ struct Nes_Apu { | |||
42 | void* irq_data; | 34 | void* irq_data; |
43 | 35 | ||
44 | Synth square_synth; // shared by squares | 36 | Synth square_synth; // shared by squares |
37 | |||
38 | struct Nes_Osc* oscs [apu_osc_count]; | ||
39 | struct Nes_Square square1; | ||
40 | struct Nes_Square square2; | ||
41 | struct Nes_Noise noise; | ||
42 | struct Nes_Triangle triangle; | ||
43 | struct Nes_Dmc dmc; | ||
45 | }; | 44 | }; |
46 | 45 | ||
47 | // Init Nes apu | 46 | // Init Nes apu |
@@ -49,22 +48,22 @@ void Apu_init( struct Nes_Apu* this ); | |||
49 | 48 | ||
50 | // Set buffer to generate all sound into, or disable sound if NULL | 49 | // Set buffer to generate all sound into, or disable sound if NULL |
51 | void Apu_output( struct Nes_Apu* this, struct Blip_Buffer* ); | 50 | void Apu_output( struct Nes_Apu* this, struct Blip_Buffer* ); |
52 | 51 | ||
53 | // All time values are the number of cpu clock cycles relative to the | 52 | // All time values are the number of cpu clock cycles relative to the |
54 | // beginning of the current time frame. Before resetting the cpu clock | 53 | // beginning of the current time frame. Before resetting the cpu clock |
55 | // count, call end_frame( last_cpu_time ). | 54 | // count, call end_frame( last_cpu_time ). |
56 | 55 | ||
57 | // Write to register (0x4000-0x4017, except 0x4014 and 0x4016) | 56 | // Write to register (0x4000-0x4017, except 0x4014 and 0x4016) |
58 | void Apu_write_register( struct Nes_Apu* this, nes_time_t, addr_t, int data ); | 57 | void Apu_write_register( struct Nes_Apu* this, nes_time_t, addr_t, int data ); |
59 | 58 | ||
60 | // Read from status register at 0x4015 | 59 | // Read from status register at 0x4015 |
61 | int Apu_read_status( struct Nes_Apu* this, nes_time_t ); | 60 | int Apu_read_status( struct Nes_Apu* this, nes_time_t ); |
62 | 61 | ||
63 | // Run all oscillators up to specified time, end current time frame, then | 62 | // Run all oscillators up to specified time, end current time frame, then |
64 | // start a new time frame at time 0. Time frames have no effect on emulation | 63 | // start a new time frame at time 0. Time frames have no effect on emulation |
65 | // and each can be whatever length is convenient. | 64 | // and each can be whatever length is convenient. |
66 | void Apu_end_frame( struct Nes_Apu* this, nes_time_t ); | 65 | void Apu_end_frame( struct Nes_Apu* this, nes_time_t ); |
67 | 66 | ||
68 | // Additional optional features (can be ignored without any problem) | 67 | // Additional optional features (can be ignored without any problem) |
69 | 68 | ||
70 | // Reset internal frame counter, registers, and all oscillators. | 69 | // Reset internal frame counter, registers, and all oscillators. |
@@ -72,13 +71,13 @@ void Apu_end_frame( struct Nes_Apu* this, nes_time_t ); | |||
72 | // Set the DMC oscillator's initial DAC value to initial_dmc_dac without | 71 | // Set the DMC oscillator's initial DAC value to initial_dmc_dac without |
73 | // any audible click. | 72 | // any audible click. |
74 | void Apu_reset( struct Nes_Apu* this, bool pal_mode, int initial_dmc_dac ); | 73 | void Apu_reset( struct Nes_Apu* this, bool pal_mode, int initial_dmc_dac ); |
75 | 74 | ||
76 | // Adjust frame period | 75 | // Adjust frame period |
77 | void Apu_set_tempo( struct Nes_Apu* this, int ); | 76 | void Apu_set_tempo( struct Nes_Apu* this, int ); |
78 | 77 | ||
79 | // Set overall volume (default is 1.0) | 78 | // Set overall volume (default is 1.0) |
80 | void Apu_volume( struct Nes_Apu* this, int ); | 79 | void Apu_volume( struct Nes_Apu* this, int ); |
81 | 80 | ||
82 | // Run DMC until specified time, so that any DMC memory reads can be | 81 | // Run DMC until specified time, so that any DMC memory reads can be |
83 | // accounted for (i.e. inserting cpu wait states). | 82 | // accounted for (i.e. inserting cpu wait states). |
84 | void Apu_run_until( struct Nes_Apu* this, nes_time_t ); | 83 | void Apu_run_until( struct Nes_Apu* this, nes_time_t ); |
@@ -124,11 +123,13 @@ static inline nes_time_t Dmc_next_read_time( struct Nes_Dmc* this ) | |||
124 | if ( this->osc.length_counter == 0 ) | 123 | if ( this->osc.length_counter == 0 ) |
125 | return apu_no_irq; // not reading | 124 | return apu_no_irq; // not reading |
126 | 125 | ||
127 | return this->apu->last_dmc_time + this->osc.delay + (long) (this->bits_remain - 1) * this->period; | 126 | return this->apu->last_dmc_time + this->osc.delay + (this->bits_remain - 1) * this->period; |
128 | } | 127 | } |
129 | 128 | ||
130 | // Time when next DMC memory read will occur | 129 | // Time when next DMC memory read will occur |
131 | static inline nes_time_t Apu_next_dmc_read_time( struct Nes_Apu* this ) { return Dmc_next_read_time( &this->dmc ); } | 130 | static inline nes_time_t Apu_next_dmc_read_time( struct Nes_Apu* this ) { return Dmc_next_read_time( &this->dmc ); } |
132 | void Apu_irq_changed( struct Nes_Apu* this ); | 131 | void Apu_irq_changed( struct Nes_Apu* this ); |
133 | 132 | ||
133 | // Experimental | ||
134 | void Apu_enable_nonlinear_( struct Nes_Apu* this, double sq, double tnd ); | ||
134 | #endif | 135 | #endif |
diff --git a/apps/codecs/libgme/nes_cpu_io.h b/apps/codecs/libgme/nes_cpu_io.h deleted file mode 100644 index 4f9d416c2d..0000000000 --- a/apps/codecs/libgme/nes_cpu_io.h +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | |||
2 | #include "nsf_emu.h" | ||
3 | |||
4 | #ifndef NSF_EMU_APU_ONLY | ||
5 | #include "nes_namco_apu.h" | ||
6 | #include "nes_fds_apu.h" | ||
7 | #include "nes_mmc5_apu.h" | ||
8 | #endif | ||
9 | |||
10 | #include "blargg_source.h" | ||
11 | |||
12 | int Cpu_read( struct Nsf_Emu* this, nes_addr_t addr ) | ||
13 | { | ||
14 | int result = this->cpu.low_mem [addr & 0x7FF]; | ||
15 | if ( addr & 0xE000 ) | ||
16 | { | ||
17 | result = *Cpu_get_code( &this->cpu, addr ); | ||
18 | if ( addr < sram_addr ) | ||
19 | { | ||
20 | if ( addr == status_addr ) | ||
21 | result = Apu_read_status( &this->apu, Cpu_time( &this->cpu ) ); | ||
22 | else | ||
23 | { | ||
24 | #ifndef NSF_EMU_APU_ONLY | ||
25 | if ( namco_enabled( this ) && addr == namco_data_reg_addr ) | ||
26 | return Namco_read_data( &this->namco ); | ||
27 | |||
28 | if ( fds_enabled( this ) && (unsigned) (addr - fds_io_addr) < fds_io_size ) | ||
29 | return Fds_read( &this->fds, Cpu_time( &this->cpu ), addr ); | ||
30 | |||
31 | if ( mmc5_enabled( this ) ) { | ||
32 | int i = addr - 0x5C00; | ||
33 | if ( (unsigned) i < mmc5_exram_size ) | ||
34 | return this->mmc5.exram [i]; | ||
35 | |||
36 | int m = addr - 0x5205; | ||
37 | if ( (unsigned) m < 2 ) | ||
38 | return (this->mmc5_mul [0] * this->mmc5_mul [1]) >> (m * 8) & 0xFF; | ||
39 | } | ||
40 | #endif | ||
41 | result = addr >> 8; // simulate open bus | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | /* if ( addr != 0x2002 ) | ||
47 | debug_printf( "Read unmapped $%.4X\n", (unsigned) addr ); */ | ||
48 | |||
49 | return result; | ||
50 | } | ||
51 | |||
52 | void Cpu_write( struct Nsf_Emu* this, nes_addr_t addr, int data ) | ||
53 | { | ||
54 | int offset = addr - sram_addr; | ||
55 | if ( (unsigned) offset < sram_size ) | ||
56 | { | ||
57 | this->sram [offset] = data; | ||
58 | } | ||
59 | else | ||
60 | { | ||
61 | // after sram because cpu handles most low_ram accesses internally already | ||
62 | int temp = addr & (low_ram_size-1); // also handles wrap-around | ||
63 | if ( !(addr & 0xE000) ) | ||
64 | { | ||
65 | this->cpu.low_mem [temp] = data; | ||
66 | } | ||
67 | else | ||
68 | { | ||
69 | int bank = addr - banks_addr; | ||
70 | if ( (unsigned) bank < bank_count ) | ||
71 | { | ||
72 | Write_bank( this, bank, data ); | ||
73 | } | ||
74 | else if ( (unsigned) (addr - start_addr) <= end_addr - start_addr ) | ||
75 | { | ||
76 | Apu_write_register( &this->apu, Cpu_time( &this->cpu ), addr, data ); | ||
77 | } | ||
78 | else | ||
79 | { | ||
80 | #ifndef NSF_EMU_APU_ONLY | ||
81 | // 0x8000-0xDFFF is writable | ||
82 | int i = addr - 0x8000; | ||
83 | if ( fds_enabled( this ) && (unsigned) i < fdsram_size ) | ||
84 | fdsram( this ) [i] = data; | ||
85 | else | ||
86 | #endif | ||
87 | Cpu_write_misc( this, addr, data ); | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | |||
93 | #define CPU_READ( emu, addr, time ) Cpu_read( emu, addr ) | ||
94 | #define CPU_WRITE( emu, addr, data, time ) Cpu_write( emu, addr, data ) | ||
diff --git a/apps/codecs/libgme/nes_fme7_apu.c b/apps/codecs/libgme/nes_fme7_apu.c index 8a2c21ea26..3e47e0b17c 100644 --- a/apps/codecs/libgme/nes_fme7_apu.c +++ b/apps/codecs/libgme/nes_fme7_apu.c | |||
@@ -64,8 +64,6 @@ void Fme7_run_until( struct Nes_Fme7_Apu* this, blip_time_t end_time ) | |||
64 | struct Blip_Buffer* const osc_output = this->oscs [index].output; | 64 | struct Blip_Buffer* const osc_output = this->oscs [index].output; |
65 | if ( !osc_output ) | 65 | if ( !osc_output ) |
66 | continue; | 66 | continue; |
67 | /* osc_output->set_modified(); */ | ||
68 | Blip_set_modified( osc_output ); | ||
69 | 67 | ||
70 | // check for unsupported mode | 68 | // check for unsupported mode |
71 | #ifndef NDEBUG | 69 | #ifndef NDEBUG |
@@ -92,11 +90,13 @@ void Fme7_run_until( struct Nes_Fme7_Apu* this, blip_time_t end_time ) | |||
92 | int amp = volume; | 90 | int amp = volume; |
93 | if ( !this->phases [index] ) | 91 | if ( !this->phases [index] ) |
94 | amp = 0; | 92 | amp = 0; |
93 | |||
95 | { | 94 | { |
96 | int delta = amp - this->oscs [index].last_amp; | 95 | int delta = amp - this->oscs [index].last_amp; |
97 | if ( delta ) | 96 | if ( delta ) |
98 | { | 97 | { |
99 | this->oscs [index].last_amp = amp; | 98 | this->oscs [index].last_amp = amp; |
99 | Blip_set_modified( osc_output ); | ||
100 | Synth_offset( &this->synth, this->last_time, delta, osc_output ); | 100 | Synth_offset( &this->synth, this->last_time, delta, osc_output ); |
101 | } | 101 | } |
102 | } | 102 | } |
@@ -105,6 +105,7 @@ void Fme7_run_until( struct Nes_Fme7_Apu* this, blip_time_t end_time ) | |||
105 | if ( time < end_time ) | 105 | if ( time < end_time ) |
106 | { | 106 | { |
107 | int delta = amp * 2 - volume; | 107 | int delta = amp * 2 - volume; |
108 | Blip_set_modified( osc_output ); | ||
108 | if ( volume ) | 109 | if ( volume ) |
109 | { | 110 | { |
110 | do | 111 | do |
@@ -123,7 +124,7 @@ void Fme7_run_until( struct Nes_Fme7_Apu* this, blip_time_t end_time ) | |||
123 | // maintain phase when silent | 124 | // maintain phase when silent |
124 | int count = (end_time - time + period - 1) / period; | 125 | int count = (end_time - time + period - 1) / period; |
125 | this->phases [index] ^= count & 1; | 126 | this->phases [index] ^= count & 1; |
126 | time += (blargg_long) count * period; | 127 | time += count * period; |
127 | } | 128 | } |
128 | } | 129 | } |
129 | 130 | ||
diff --git a/apps/codecs/libgme/nes_fme7_apu.h b/apps/codecs/libgme/nes_fme7_apu.h index 353d82d1df..c0eac4c765 100644 --- a/apps/codecs/libgme/nes_fme7_apu.h +++ b/apps/codecs/libgme/nes_fme7_apu.h | |||
@@ -1,6 +1,6 @@ | |||
1 | // Sunsoft FME-7 sound emulator | 1 | // Sunsoft FME-7 sound emulator |
2 | 2 | ||
3 | // Game_Music_Emu 0.5.5 | 3 | // Game_Music_Emu 0.6-pre |
4 | #ifndef NES_FME7_APU_H | 4 | #ifndef NES_FME7_APU_H |
5 | #define NES_FME7_APU_H | 5 | #define NES_FME7_APU_H |
6 | 6 | ||
diff --git a/apps/codecs/libgme/nes_namco_apu.c b/apps/codecs/libgme/nes_namco_apu.c index 0f64d3c84f..34df200bb6 100644 --- a/apps/codecs/libgme/nes_namco_apu.c +++ b/apps/codecs/libgme/nes_namco_apu.c | |||
@@ -68,8 +68,6 @@ void Namco_run_until( struct Nes_Namco_Apu* this, blip_time_t nes_end_time ) | |||
68 | struct Blip_Buffer* output = osc->output; | 68 | struct Blip_Buffer* output = osc->output; |
69 | if ( !output ) | 69 | if ( !output ) |
70 | continue; | 70 | continue; |
71 | /* output->set_modified(); */ | ||
72 | Blip_set_modified( output ); | ||
73 | 71 | ||
74 | blip_resampled_time_t time = | 72 | blip_resampled_time_t time = |
75 | Blip_resampled_time( output, this->last_time ) + osc->delay; | 73 | Blip_resampled_time( output, this->last_time ) + osc->delay; |
@@ -85,12 +83,17 @@ void Namco_run_until( struct Nes_Namco_Apu* this, blip_time_t nes_end_time ) | |||
85 | if ( !volume ) | 83 | if ( !volume ) |
86 | continue; | 84 | continue; |
87 | 85 | ||
88 | blargg_long freq = (osc_reg [4] & 3) * 0x10000 + osc_reg [2] * 0x100L + osc_reg [0]; | 86 | int freq = (osc_reg [4] & 3) * 0x10000 + osc_reg [2] * 0x100L + osc_reg [0]; |
89 | if ( freq < 64 * active_oscs ) | 87 | if ( freq < 64 * active_oscs ) |
90 | continue; // prevent low frequencies from excessively delaying freq changes | 88 | continue; // prevent low frequencies from excessively delaying freq changes |
89 | |||
90 | int const master_clock_divider = 12; // NES time derived via divider of master clock | ||
91 | int const n106_divider = 45; // N106 then divides master clock by this | ||
92 | int const max_freq = 0x3FFFF; | ||
93 | int const lowest_freq_period = (max_freq + 1) * n106_divider / master_clock_divider; | ||
94 | // divide by 8 to avoid overflow | ||
91 | blip_resampled_time_t period = | 95 | blip_resampled_time_t period = |
92 | /* output->resampled_duration( 983040 ) / freq * active_oscs; */ | 96 | Blip_resampled_duration( output, lowest_freq_period / 8 ) / freq * 8 * active_oscs; |
93 | Blip_resampled_duration( output, 983040 ) / freq * active_oscs; | ||
94 | 97 | ||
95 | int wave_size = 32 - (osc_reg [4] >> 2 & 7) * 4; | 98 | int wave_size = 32 - (osc_reg [4] >> 2 & 7) * 4; |
96 | if ( !wave_size ) | 99 | if ( !wave_size ) |
@@ -99,6 +102,8 @@ void Namco_run_until( struct Nes_Namco_Apu* this, blip_time_t nes_end_time ) | |||
99 | int last_amp = osc->last_amp; | 102 | int last_amp = osc->last_amp; |
100 | int wave_pos = osc->wave_pos; | 103 | int wave_pos = osc->wave_pos; |
101 | 104 | ||
105 | Blip_set_modified( output ); | ||
106 | |||
102 | do | 107 | do |
103 | { | 108 | { |
104 | // read wave sample | 109 | // read wave sample |
diff --git a/apps/codecs/libgme/nes_namco_apu.h b/apps/codecs/libgme/nes_namco_apu.h index c47eacc4bb..c428c894c3 100644 --- a/apps/codecs/libgme/nes_namco_apu.h +++ b/apps/codecs/libgme/nes_namco_apu.h | |||
@@ -15,13 +15,13 @@ enum { namco_data_reg_addr = 0x4800 }; | |||
15 | enum { namco_reg_count = 0x80 }; | 15 | enum { namco_reg_count = 0x80 }; |
16 | 16 | ||
17 | struct Namco_Osc { | 17 | struct Namco_Osc { |
18 | blargg_long delay; | 18 | int delay; |
19 | struct Blip_Buffer* output; | 19 | struct Blip_Buffer* output; |
20 | short last_amp; | 20 | short last_amp; |
21 | short wave_pos; | 21 | short wave_pos; |
22 | }; | 22 | }; |
23 | 23 | ||
24 | struct Nes_Namco_Apu { | 24 | struct Nes_Namco_Apu { |
25 | struct Namco_Osc oscs [namco_osc_count]; | 25 | struct Namco_Osc oscs [namco_osc_count]; |
26 | 26 | ||
27 | blip_time_t last_time; | 27 | blip_time_t last_time; |
diff --git a/apps/codecs/libgme/nes_oscs.c b/apps/codecs/libgme/nes_oscs.c index 4402b60a61..f97ce2176d 100644 --- a/apps/codecs/libgme/nes_oscs.c +++ b/apps/codecs/libgme/nes_oscs.c | |||
@@ -90,7 +90,7 @@ static inline nes_time_t Square_maintain_phase( struct Nes_Square* this, nes_tim | |||
90 | { | 90 | { |
91 | int count = (remain + timer_period - 1) / timer_period; | 91 | int count = (remain + timer_period - 1) / timer_period; |
92 | this->phase = (this->phase + count) & (square_phase_range - 1); | 92 | this->phase = (this->phase + count) & (square_phase_range - 1); |
93 | time += (blargg_long) count * timer_period; | 93 | time += count * timer_period; |
94 | } | 94 | } |
95 | return time; | 95 | return time; |
96 | } | 96 | } |
@@ -107,8 +107,6 @@ void Square_run( struct Nes_Square* this, nes_time_t time, nes_time_t end_time ) | |||
107 | return; | 107 | return; |
108 | } | 108 | } |
109 | 109 | ||
110 | Blip_set_modified( osc->output ); | ||
111 | |||
112 | int offset = period >> (osc->regs [1] & shift_mask); | 110 | int offset = period >> (osc->regs [1] & shift_mask); |
113 | if ( osc->regs [1] & negate_flag ) | 111 | if ( osc->regs [1] & negate_flag ) |
114 | offset = 0; | 112 | offset = 0; |
@@ -117,6 +115,7 @@ void Square_run( struct Nes_Square* this, nes_time_t time, nes_time_t end_time ) | |||
117 | if ( volume == 0 || period < 8 || (period + offset) >= 0x800 ) | 115 | if ( volume == 0 || period < 8 || (period + offset) >= 0x800 ) |
118 | { | 116 | { |
119 | if ( osc->last_amp ) { | 117 | if ( osc->last_amp ) { |
118 | Blip_set_modified( osc->output ); | ||
120 | Synth_offset( this->synth, time, -osc->last_amp, osc->output ); | 119 | Synth_offset( this->synth, time, -osc->last_amp, osc->output ); |
121 | osc->last_amp = 0; | 120 | osc->last_amp = 0; |
122 | } | 121 | } |
@@ -137,6 +136,7 @@ void Square_run( struct Nes_Square* this, nes_time_t time, nes_time_t end_time ) | |||
137 | if ( this->phase < duty ) | 136 | if ( this->phase < duty ) |
138 | amp ^= volume; | 137 | amp ^= volume; |
139 | 138 | ||
139 | Blip_set_modified( osc->output ); | ||
140 | { | 140 | { |
141 | int delta = Osc_update_amp( osc, amp ); | 141 | int delta = Osc_update_amp( osc, amp ); |
142 | if ( delta ) | 142 | if ( delta ) |
@@ -201,7 +201,7 @@ static inline nes_time_t Triangle_maintain_phase( struct Nes_Triangle* this, nes | |||
201 | int count = (remain + timer_period - 1) / timer_period; | 201 | int count = (remain + timer_period - 1) / timer_period; |
202 | this->phase = ((unsigned) this->phase + 1 - count) & (Triangle_phase_range * 2 - 1); | 202 | this->phase = ((unsigned) this->phase + 1 - count) & (Triangle_phase_range * 2 - 1); |
203 | this->phase++; | 203 | this->phase++; |
204 | time += (blargg_long) count * timer_period; | 204 | time += count * timer_period; |
205 | } | 205 | } |
206 | return time; | 206 | return time; |
207 | } | 207 | } |
@@ -219,14 +219,15 @@ void Triangle_run( struct Nes_Triangle* this, nes_time_t time, nes_time_t end_ti | |||
219 | return; | 219 | return; |
220 | } | 220 | } |
221 | 221 | ||
222 | Blip_set_modified( osc->output ); | ||
223 | |||
224 | // to do: track phase when period < 3 | 222 | // to do: track phase when period < 3 |
225 | // to do: Output 7.5 on dac when period < 2? More accurate, but results in more clicks. | 223 | // to do: Output 7.5 on dac when period < 2? More accurate, but results in more clicks. |
226 | 224 | ||
227 | int delta = Osc_update_amp( osc, Triangle_calc_amp( this ) ); | 225 | int delta = Osc_update_amp( osc, Triangle_calc_amp( this ) ); |
228 | if ( delta ) | 226 | if ( delta ) |
227 | { | ||
228 | Blip_set_modified( osc->output ); | ||
229 | Synth_offset( &this->synth, time, delta, osc->output ); | 229 | Synth_offset( &this->synth, time, delta, osc->output ); |
230 | } | ||
230 | 231 | ||
231 | time += osc->delay; | 232 | time += osc->delay; |
232 | if ( osc->length_counter == 0 || this->linear_counter == 0 || timer_period < 3 ) | 233 | if ( osc->length_counter == 0 || this->linear_counter == 0 || timer_period < 3 ) |
@@ -243,13 +244,15 @@ void Triangle_run( struct Nes_Triangle* this, nes_time_t time, nes_time_t end_ti | |||
243 | phase -= Triangle_phase_range; | 244 | phase -= Triangle_phase_range; |
244 | volume = -volume; | 245 | volume = -volume; |
245 | } | 246 | } |
247 | Blip_set_modified( osc->output ); | ||
246 | 248 | ||
247 | do { | 249 | do { |
248 | if ( --phase == 0 ) { | 250 | if ( --phase == 0 ) { |
249 | phase = Triangle_phase_range; | 251 | phase = Triangle_phase_range; |
250 | volume = -volume; | 252 | volume = -volume; |
251 | } | 253 | } |
252 | else { | 254 | else |
255 | { | ||
253 | Synth_offset_inline( &this->synth, time, volume, output ); | 256 | Synth_offset_inline( &this->synth, time, volume, output ); |
254 | } | 257 | } |
255 | 258 | ||
@@ -340,18 +343,27 @@ static inline void Dmc_reload_sample( struct Nes_Dmc* this ) | |||
340 | this->osc.length_counter = this->osc.regs [3] * 0x10 + 1; | 343 | this->osc.length_counter = this->osc.regs [3] * 0x10 + 1; |
341 | } | 344 | } |
342 | 345 | ||
343 | static byte const dac_table [128] = | 346 | static int const dmc_table [128] = |
344 | { | 347 | { |
345 | 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9,10,11,12,13,14, | 348 | 0, 24, 48, 71, 94, 118, 141, 163, 186, 209, 231, 253, 275, 297, 319, 340, |
346 | 15,15,16,17,18,19,20,20,21,22,23,24,24,25,26,27, | 349 | 361, 383, 404, 425, 445, 466, 486, 507, 527, 547, 567, 587, 606, 626, 645, 664, |
347 | 27,28,29,30,31,31,32,33,33,34,35,36,36,37,38,38, | 350 | 683, 702, 721, 740, 758, 777, 795, 813, 832, 850, 867, 885, 903, 920, 938, 955, |
348 | 39,40,41,41,42,43,43,44,45,45,46,47,47,48,48,49, | 351 | 972, 989,1006,1023,1040,1056,1073,1089,1105,1122,1138,1154,1170,1185,1201,1217, |
349 | 50,50,51,52,52,53,53,54,55,55,56,56,57,58,58,59, | 352 | 1232,1248,1263,1278,1293,1308,1323,1338,1353,1368,1382,1397,1411,1425,1440,1454, |
350 | 59,60,60,61,61,62,63,63,64,64,65,65,66,66,67,67, | 353 | 1468,1482,1496,1510,1523,1537,1551,1564,1578,1591,1604,1618,1631,1644,1657,1670, |
351 | 68,68,69,70,70,71,71,72,72,73,73,74,74,75,75,75, | 354 | 1683,1695,1708,1721,1733,1746,1758,1771,1783,1795,1807,1819,1831,1843,1855,1867, |
352 | 76,76,77,77,78,78,79,79,80,80,81,81,82,82,82,83, | 355 | 1879,1890,1902,1914,1925,1937,1948,1959,1971,1982,1993,2004,2015,2026,2037,2048, |
353 | }; | 356 | }; |
354 | 357 | ||
358 | static inline int update_amp_nonlinear( struct Nes_Dmc* this, int in ) | ||
359 | { | ||
360 | if ( !this->nonlinear ) | ||
361 | in = dmc_table [in]; | ||
362 | int delta = in - this->osc.last_amp; | ||
363 | this->osc.last_amp = in; | ||
364 | return delta; | ||
365 | } | ||
366 | |||
355 | void Dmc_write_register( struct Nes_Dmc* this, int addr, int data ) | 367 | void Dmc_write_register( struct Nes_Dmc* this, int addr, int data ) |
356 | { | 368 | { |
357 | if ( addr == 0 ) | 369 | if ( addr == 0 ) |
@@ -363,14 +375,7 @@ void Dmc_write_register( struct Nes_Dmc* this, int addr, int data ) | |||
363 | } | 375 | } |
364 | else if ( addr == 1 ) | 376 | else if ( addr == 1 ) |
365 | { | 377 | { |
366 | int old_dac = this->dac; | ||
367 | this->dac = data & 0x7F; | 378 | this->dac = data & 0x7F; |
368 | |||
369 | // adjust last_amp so that "pop" amplitude will be properly non-linear | ||
370 | // with respect to change in dac | ||
371 | int faked_nonlinear = this->dac - (dac_table [this->dac] - dac_table [old_dac]); | ||
372 | if ( !this->nonlinear ) | ||
373 | this->osc.last_amp = faked_nonlinear; | ||
374 | } | 379 | } |
375 | } | 380 | } |
376 | 381 | ||
@@ -407,16 +412,15 @@ void Dmc_fill_buffer( struct Nes_Dmc* this ) | |||
407 | void Dmc_run( struct Nes_Dmc* this, nes_time_t time, nes_time_t end_time ) | 412 | void Dmc_run( struct Nes_Dmc* this, nes_time_t time, nes_time_t end_time ) |
408 | { | 413 | { |
409 | struct Nes_Osc* osc = &this->osc; | 414 | struct Nes_Osc* osc = &this->osc; |
410 | int delta = Osc_update_amp( osc, this->dac ); | 415 | int delta = update_amp_nonlinear( this, this->dac ); |
411 | if ( !osc->output ) | 416 | if ( !osc->output ) |
412 | { | 417 | { |
413 | this->silence = true; | 418 | this->silence = true; |
414 | } | 419 | } |
415 | else | 420 | else if ( delta ) |
416 | { | 421 | { |
417 | Blip_set_modified( osc->output ); | 422 | Blip_set_modified( osc->output ); |
418 | if ( delta ) | 423 | Synth_offset( &this->synth, time, delta, osc->output ); |
419 | Synth_offset( &this->synth, time, delta, osc->output ); | ||
420 | } | 424 | } |
421 | 425 | ||
422 | time += osc->delay; | 426 | time += osc->delay; |
@@ -435,6 +439,8 @@ void Dmc_run( struct Nes_Dmc* this, nes_time_t time, nes_time_t end_time ) | |||
435 | const int period = this->period; | 439 | const int period = this->period; |
436 | int bits = this->bits; | 440 | int bits = this->bits; |
437 | int dac = this->dac; | 441 | int dac = this->dac; |
442 | if ( output ) | ||
443 | Blip_set_modified( output ); | ||
438 | 444 | ||
439 | do | 445 | do |
440 | { | 446 | { |
@@ -444,7 +450,7 @@ void Dmc_run( struct Nes_Dmc* this, nes_time_t time, nes_time_t end_time ) | |||
444 | bits >>= 1; | 450 | bits >>= 1; |
445 | if ( (unsigned) (dac + step) <= 0x7F ) { | 451 | if ( (unsigned) (dac + step) <= 0x7F ) { |
446 | dac += step; | 452 | dac += step; |
447 | Synth_offset_inline( &this->synth, time, step, output ); | 453 | Synth_offset_inline( &this->synth, time, update_amp_nonlinear( this, dac ), output ); |
448 | } | 454 | } |
449 | } | 455 | } |
450 | 456 | ||
@@ -456,7 +462,8 @@ void Dmc_run( struct Nes_Dmc* this, nes_time_t time, nes_time_t end_time ) | |||
456 | if ( !this->buf_full ) { | 462 | if ( !this->buf_full ) { |
457 | this->silence = true; | 463 | this->silence = true; |
458 | } | 464 | } |
459 | else { | 465 | else |
466 | { | ||
460 | this->silence = false; | 467 | this->silence = false; |
461 | bits = this->buf; | 468 | bits = this->buf; |
462 | this->buf_full = false; | 469 | this->buf_full = false; |
@@ -469,7 +476,7 @@ void Dmc_run( struct Nes_Dmc* this, nes_time_t time, nes_time_t end_time ) | |||
469 | while ( time < end_time ); | 476 | while ( time < end_time ); |
470 | 477 | ||
471 | this->dac = dac; | 478 | this->dac = dac; |
472 | osc->last_amp = dac; | 479 | //osc->last_amp = dac; |
473 | this->bits = bits; | 480 | this->bits = bits; |
474 | } | 481 | } |
475 | this->bits_remain = bits_remain; | 482 | this->bits_remain = bits_remain; |
@@ -519,14 +526,15 @@ void Noise_run( struct Nes_Noise* this, nes_time_t time, nes_time_t end_time ) | |||
519 | return; | 526 | return; |
520 | } | 527 | } |
521 | 528 | ||
522 | Blip_set_modified( osc->output ); | ||
523 | |||
524 | const int volume = Noise_volume( this ); | 529 | const int volume = Noise_volume( this ); |
525 | int amp = (this->noise & 1) ? volume : 0; | 530 | int amp = (this->noise & 1) ? volume : 0; |
526 | { | 531 | { |
527 | int delta = Osc_update_amp( osc, amp ); | 532 | int delta = Osc_update_amp( osc, amp ); |
528 | if ( delta ) | 533 | if ( delta ) |
534 | { | ||
535 | Blip_set_modified( osc->output ); | ||
529 | Synth_offset( &this->synth, time, delta, osc->output ); | 536 | Synth_offset( &this->synth, time, delta, osc->output ); |
537 | } | ||
530 | } | 538 | } |
531 | 539 | ||
532 | time += osc->delay; | 540 | time += osc->delay; |
@@ -557,6 +565,7 @@ void Noise_run( struct Nes_Noise* this, nes_time_t time, nes_time_t end_time ) | |||
557 | int noise = this->noise; | 565 | int noise = this->noise; |
558 | int delta = amp * 2 - volume; | 566 | int delta = amp * 2 - volume; |
559 | const int tap = (osc->regs [2] & mode_flag ? 8 : 13); | 567 | const int tap = (osc->regs [2] & mode_flag ? 8 : 13); |
568 | Blip_set_modified( osc->output ); | ||
560 | 569 | ||
561 | do { | 570 | do { |
562 | int feedback = (noise << tap) ^ (noise << 14); | 571 | int feedback = (noise << tap) ^ (noise << 14); |
diff --git a/apps/codecs/libgme/nes_oscs.h b/apps/codecs/libgme/nes_oscs.h index fa6b8ab4b0..1eeb302e6c 100644 --- a/apps/codecs/libgme/nes_oscs.h +++ b/apps/codecs/libgme/nes_oscs.h | |||
@@ -46,7 +46,7 @@ enum { shift_mask = 0x07 }; | |||
46 | enum { square_phase_range = 8 }; | 46 | enum { square_phase_range = 8 }; |
47 | 47 | ||
48 | typedef struct Blip_Synth Synth; | 48 | typedef struct Blip_Synth Synth; |
49 | 49 | ||
50 | struct Nes_Square | 50 | struct Nes_Square |
51 | { | 51 | { |
52 | struct Nes_Osc osc; | 52 | struct Nes_Osc osc; |
@@ -54,12 +54,12 @@ struct Nes_Square | |||
54 | int env_delay; | 54 | int env_delay; |
55 | int phase; | 55 | int phase; |
56 | int sweep_delay; | 56 | int sweep_delay; |
57 | 57 | ||
58 | Synth* synth; // shared between squares | 58 | Synth* synth; // shared between squares |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static inline void Square_set_synth( struct Nes_Square* this, Synth* s ) { this->synth = s; } | 61 | static inline void Square_set_synth( struct Nes_Square* this, Synth* s ) { this->synth = s; } |
62 | 62 | ||
63 | void Square_clock_sweep( struct Nes_Square* this, int adjust ); | 63 | void Square_clock_sweep( struct Nes_Square* this, int adjust ); |
64 | void Square_run( struct Nes_Square* this, nes_time_t, nes_time_t ); | 64 | void Square_run( struct Nes_Square* this, nes_time_t, nes_time_t ); |
65 | 65 | ||
@@ -73,15 +73,15 @@ static inline void Square_reset( struct Nes_Square* this ) | |||
73 | 73 | ||
74 | void Square_clock_envelope( struct Nes_Square* this ); | 74 | void Square_clock_envelope( struct Nes_Square* this ); |
75 | int Square_volume( struct Nes_Square* this ); | 75 | int Square_volume( struct Nes_Square* this ); |
76 | 76 | ||
77 | // Nes_Triangle | 77 | // Nes_Triangle |
78 | 78 | ||
79 | enum { Triangle_phase_range = 16 }; | 79 | enum { Triangle_phase_range = 16 }; |
80 | 80 | ||
81 | struct Nes_Triangle | 81 | struct Nes_Triangle |
82 | { | 82 | { |
83 | struct Nes_Osc osc; | 83 | struct Nes_Osc osc; |
84 | 84 | ||
85 | int phase; | 85 | int phase; |
86 | int linear_counter; | 86 | int linear_counter; |
87 | struct Blip_Synth synth; | 87 | struct Blip_Synth synth; |
@@ -123,11 +123,11 @@ static inline void Noise_reset( struct Nes_Noise* this ) | |||
123 | // Nes_Dmc | 123 | // Nes_Dmc |
124 | 124 | ||
125 | enum { loop_flag = 0x40 }; | 125 | enum { loop_flag = 0x40 }; |
126 | 126 | ||
127 | struct Nes_Dmc | 127 | struct Nes_Dmc |
128 | { | 128 | { |
129 | struct Nes_Osc osc; | 129 | struct Nes_Osc osc; |
130 | 130 | ||
131 | int address; // address of next byte to read | 131 | int address; // address of next byte to read |
132 | int period; | 132 | int period; |
133 | int buf; | 133 | int buf; |
@@ -144,7 +144,7 @@ struct Nes_Dmc | |||
144 | bool pal_mode; | 144 | bool pal_mode; |
145 | bool nonlinear; | 145 | bool nonlinear; |
146 | 146 | ||
147 | int (*prg_reader)( void*, addr_t ); // needs to be initialized to prg read function | 147 | int (*prg_reader)( void*, int ); // needs to be initialized to prg read function |
148 | void* prg_reader_data; | 148 | void* prg_reader_data; |
149 | 149 | ||
150 | struct Nes_Apu* apu; | 150 | struct Nes_Apu* apu; |
diff --git a/apps/codecs/libgme/nes_vrc6_apu.c b/apps/codecs/libgme/nes_vrc6_apu.c index f712216424..55fccb7b0f 100644 --- a/apps/codecs/libgme/nes_vrc6_apu.c +++ b/apps/codecs/libgme/nes_vrc6_apu.c | |||
@@ -83,7 +83,6 @@ void run_square( struct Nes_Vrc6_Apu* this, struct Vrc6_Osc* osc, blip_time_t en | |||
83 | struct Blip_Buffer* output = osc->output; | 83 | struct Blip_Buffer* output = osc->output; |
84 | if ( !output ) | 84 | if ( !output ) |
85 | return; | 85 | return; |
86 | Blip_set_modified( output ); | ||
87 | 86 | ||
88 | int volume = osc->regs [0] & 15; | 87 | int volume = osc->regs [0] & 15; |
89 | if ( !(osc->regs [2] & 0x80) ) | 88 | if ( !(osc->regs [2] & 0x80) ) |
@@ -96,6 +95,7 @@ void run_square( struct Nes_Vrc6_Apu* this, struct Vrc6_Osc* osc, blip_time_t en | |||
96 | if ( delta ) | 95 | if ( delta ) |
97 | { | 96 | { |
98 | osc->last_amp += delta; | 97 | osc->last_amp += delta; |
98 | Blip_set_modified( output ); | ||
99 | Synth_offset( &this->square_synth, time, delta, output ); | 99 | Synth_offset( &this->square_synth, time, delta, output ); |
100 | } | 100 | } |
101 | 101 | ||
diff --git a/apps/codecs/libgme/nes_vrc6_apu.h b/apps/codecs/libgme/nes_vrc6_apu.h index 8f3cbf4629..57b8a42a79 100644 --- a/apps/codecs/libgme/nes_vrc6_apu.h +++ b/apps/codecs/libgme/nes_vrc6_apu.h | |||
@@ -1,6 +1,6 @@ | |||
1 | // Konami VRC6 sound chip emulator | 1 | // Konami VRC6 sound chip emulator |
2 | 2 | ||
3 | // Nes_Snd_Emu 0.1.8 | 3 | // Nes_Snd_Emu 0.2.0-pre |
4 | #ifndef NES_VRC6_APU_H | 4 | #ifndef NES_VRC6_APU_H |
5 | #define NES_VRC6_APU_H | 5 | #define NES_VRC6_APU_H |
6 | 6 | ||
@@ -14,7 +14,7 @@ enum { vrc6_addr_step = 0x1000 }; | |||
14 | 14 | ||
15 | struct Vrc6_Osc | 15 | struct Vrc6_Osc |
16 | { | 16 | { |
17 | uint8_t regs [vrc6_reg_count]; | 17 | uint8_t regs [3]; |
18 | struct Blip_Buffer* output; | 18 | struct Blip_Buffer* output; |
19 | int delay; | 19 | int delay; |
20 | int last_amp; | 20 | int last_amp; |
diff --git a/apps/codecs/libgme/nsf_emu.c b/apps/codecs/libgme/nsf_emu.c index a4873c81cb..705c345fa6 100644 --- a/apps/codecs/libgme/nsf_emu.c +++ b/apps/codecs/libgme/nsf_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 "nsf_emu.h" | 3 | #include "nsf_emu.h" |
4 | #include "multi_buffer.h" | 4 | #include "multi_buffer.h" |
@@ -19,33 +19,19 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | |||
19 | #include "blargg_source.h" | 19 | #include "blargg_source.h" |
20 | 20 | ||
21 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; | 21 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; |
22 | long const clock_divisor = 12; | ||
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 | 22 | ||
30 | // number of frames until play interrupts init | 23 | // number of frames until play interrupts init |
31 | int const initial_play_delay = 7; // KikiKaikai needed this to work | 24 | int const initial_play_delay = 7; // KikiKaikai needed this to work |
25 | int const bank_size = 0x1000; | ||
32 | int const rom_addr = 0x8000; | 26 | int const rom_addr = 0x8000; |
33 | 27 | ||
34 | static void clear_track_vars( struct Nsf_Emu* this ) | 28 | static void clear_track_vars( struct Nsf_Emu* this ) |
35 | { | 29 | { |
36 | this->current_track = -1; | 30 | this->current_track = -1; |
37 | this->out_time = 0; | 31 | track_stop( &this->track_filter ); |
38 | this->emu_time = 0; | ||
39 | this->emu_track_ended_ = true; | ||
40 | this->track_ended = true; | ||
41 | this->fade_start = INT_MAX / 2 + 1; | ||
42 | this->fade_step = 1; | ||
43 | this->silence_time = 0; | ||
44 | this->silence_count = 0; | ||
45 | this->buf_remain = 0; | ||
46 | } | 32 | } |
47 | 33 | ||
48 | static int pcm_read( void* emu, addr_t addr ) | 34 | static int pcm_read( void* emu, int addr ) |
49 | { | 35 | { |
50 | return *Cpu_get_code( &((struct Nsf_Emu*) emu)->cpu, addr ); | 36 | return *Cpu_get_code( &((struct Nsf_Emu*) emu)->cpu, addr ); |
51 | } | 37 | } |
@@ -58,18 +44,16 @@ void Nsf_init( struct Nsf_Emu* this ) | |||
58 | this->gain = (int)(FP_ONE_GAIN); | 44 | this->gain = (int)(FP_ONE_GAIN); |
59 | 45 | ||
60 | // defaults | 46 | // defaults |
61 | this->max_initial_silence = 2; | 47 | this->tfilter = *track_get_setup( &this->track_filter ); |
62 | this->ignore_silence = false; | 48 | this->tfilter.max_initial = 2; |
63 | this->voice_count = 0; | 49 | this->tfilter.lookahead = 6; |
50 | this->track_filter.silence_ignored_ = false; | ||
64 | 51 | ||
65 | // Set sound gain | 52 | // Set sound gain |
66 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); | 53 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); |
67 | 54 | ||
68 | // Unload | ||
69 | clear_track_vars( this ); | ||
70 | |||
71 | // Init rom | 55 | // Init rom |
72 | Rom_init( &this->rom, 0x1000 ); | 56 | Rom_init( &this->rom, bank_size ); |
73 | 57 | ||
74 | // Init & clear nsfe info | 58 | // Init & clear nsfe info |
75 | Info_init( &this->info ); | 59 | Info_init( &this->info ); |
@@ -78,16 +62,36 @@ void Nsf_init( struct Nsf_Emu* this ) | |||
78 | Cpu_init( &this->cpu ); | 62 | Cpu_init( &this->cpu ); |
79 | Apu_init( &this->apu ); | 63 | Apu_init( &this->apu ); |
80 | Apu_dmc_reader( &this->apu, pcm_read, this ); | 64 | Apu_dmc_reader( &this->apu, pcm_read, this ); |
65 | |||
66 | // Unload | ||
67 | this->voice_count = 0; | ||
68 | memset( this->voice_types, 0, sizeof this->voice_types ); | ||
69 | clear_track_vars( this ); | ||
81 | } | 70 | } |
82 | 71 | ||
83 | // Setup | 72 | // Setup |
84 | 73 | ||
74 | static void append_voices( struct Nsf_Emu* this, int const types [], int count ) | ||
75 | { | ||
76 | assert( this->voice_count + count < max_voices ); | ||
77 | int i; | ||
78 | for ( i = 0; i < count; i++ ) { | ||
79 | this->voice_types [this->voice_count + i] = types [i]; | ||
80 | } | ||
81 | this->voice_count += count; | ||
82 | } | ||
83 | |||
85 | static blargg_err_t init_sound( struct Nsf_Emu* this ) | 84 | static blargg_err_t init_sound( struct Nsf_Emu* this ) |
86 | { | 85 | { |
87 | /* if ( header_.chip_flags & ~(fds_flag | namco_flag | vrc6_flag | fme7_flag) ) | 86 | /* if ( header_.chip_flags & ~(fds_flag | namco_flag | vrc6_flag | fme7_flag) ) |
88 | warning( "Uses unsupported audio expansion hardware" ); **/ | 87 | warning( "Uses unsupported audio expansion hardware" ); **/ |
89 | 88 | ||
90 | this->voice_count = apu_osc_count; | 89 | { |
90 | static int const types [apu_osc_count] = { | ||
91 | wave_type+1, wave_type+2, mixed_type+1, noise_type+0, mixed_type+1 | ||
92 | }; | ||
93 | append_voices( this, types, apu_osc_count ); | ||
94 | } | ||
91 | 95 | ||
92 | int adjusted_gain = (this->gain * 4) / 3; | 96 | int adjusted_gain = (this->gain * 4) / 3; |
93 | 97 | ||
@@ -103,7 +107,10 @@ static blargg_err_t init_sound( struct Nsf_Emu* this ) | |||
103 | Vrc6_init( &this->vrc6 ); | 107 | Vrc6_init( &this->vrc6 ); |
104 | adjusted_gain = (adjusted_gain*3) / 4; | 108 | adjusted_gain = (adjusted_gain*3) / 4; |
105 | 109 | ||
106 | this->voice_count += vrc6_osc_count; | 110 | static int const types [vrc6_osc_count] = { |
111 | wave_type+3, wave_type+4, wave_type+5, | ||
112 | }; | ||
113 | append_voices( this, types, vrc6_osc_count ); | ||
107 | } | 114 | } |
108 | 115 | ||
109 | if ( fme7_enabled( this ) ) | 116 | if ( fme7_enabled( this ) ) |
@@ -111,7 +118,10 @@ static blargg_err_t init_sound( struct Nsf_Emu* this ) | |||
111 | Fme7_init( &this->fme7 ); | 118 | Fme7_init( &this->fme7 ); |
112 | adjusted_gain = (adjusted_gain*3) / 4; | 119 | adjusted_gain = (adjusted_gain*3) / 4; |
113 | 120 | ||
114 | this->voice_count += fme7_osc_count; | 121 | static int const types [fme7_osc_count] = { |
122 | wave_type+3, wave_type+4, wave_type+5, | ||
123 | }; | ||
124 | append_voices( this, types, fme7_osc_count ); | ||
115 | } | 125 | } |
116 | 126 | ||
117 | if ( mmc5_enabled( this ) ) | 127 | if ( mmc5_enabled( this ) ) |
@@ -119,7 +129,11 @@ static blargg_err_t init_sound( struct Nsf_Emu* this ) | |||
119 | Mmc5_init( &this->mmc5 ); | 129 | Mmc5_init( &this->mmc5 ); |
120 | adjusted_gain = (adjusted_gain*3) / 4; | 130 | adjusted_gain = (adjusted_gain*3) / 4; |
121 | 131 | ||
122 | this->voice_count += mmc5_osc_count; | 132 | |
133 | static int const types [mmc5_osc_count] = { | ||
134 | wave_type+3, wave_type+4, mixed_type+2 | ||
135 | }; | ||
136 | append_voices( this, types, mmc5_osc_count ); | ||
123 | } | 137 | } |
124 | 138 | ||
125 | if ( fds_enabled( this ) ) | 139 | if ( fds_enabled( this ) ) |
@@ -127,7 +141,10 @@ static blargg_err_t init_sound( struct Nsf_Emu* this ) | |||
127 | Fds_init( &this->fds ); | 141 | Fds_init( &this->fds ); |
128 | adjusted_gain = (adjusted_gain*3) / 4; | 142 | adjusted_gain = (adjusted_gain*3) / 4; |
129 | 143 | ||
130 | this->voice_count += fds_osc_count ; | 144 | static int const types [fds_osc_count] = { |
145 | wave_type+0 | ||
146 | }; | ||
147 | append_voices( this, types, fds_osc_count ); | ||
131 | } | 148 | } |
132 | 149 | ||
133 | if ( namco_enabled( this ) ) | 150 | if ( namco_enabled( this ) ) |
@@ -135,22 +152,31 @@ static blargg_err_t init_sound( struct Nsf_Emu* this ) | |||
135 | Namco_init( &this->namco ); | 152 | Namco_init( &this->namco ); |
136 | adjusted_gain = (adjusted_gain*3) / 4; | 153 | adjusted_gain = (adjusted_gain*3) / 4; |
137 | 154 | ||
138 | this->voice_count += namco_osc_count; | 155 | static int const types [namco_osc_count] = { |
156 | wave_type+3, wave_type+4, wave_type+5, wave_type+ 6, | ||
157 | wave_type+7, wave_type+8, wave_type+9, wave_type+10, | ||
158 | }; | ||
159 | append_voices( this, types, namco_osc_count ); | ||
139 | } | 160 | } |
140 | 161 | ||
141 | if ( vrc7_enabled( this ) ) | ||
142 | { | ||
143 | #ifndef NSF_EMU_NO_VRC7 | 162 | #ifndef NSF_EMU_NO_VRC7 |
163 | if ( vrc7_enabled( this ) ) | ||
164 | { | ||
165 | |||
144 | Vrc7_init( &this->vrc7 ); | 166 | Vrc7_init( &this->vrc7 ); |
145 | Vrc7_set_rate( &this->vrc7, this->sample_rate ); | 167 | Vrc7_set_rate( &this->vrc7, this->sample_rate ); |
146 | #endif | ||
147 | 168 | ||
148 | adjusted_gain = (adjusted_gain*3) / 4; | 169 | adjusted_gain = (adjusted_gain*3) / 4; |
170 | |||
171 | static int const types [vrc7_osc_count] = { | ||
172 | wave_type+3, wave_type+4, wave_type+5, wave_type+6, | ||
173 | wave_type+7, wave_type+8 | ||
174 | }; | ||
175 | append_voices( this, types, vrc7_osc_count ); | ||
176 | } | ||
149 | 177 | ||
150 | this->voice_count += vrc7_osc_count; | 178 | if ( vrc7_enabled( this ) ) Vrc7_volume( &this->vrc7, adjusted_gain ); |
151 | } | 179 | #endif |
152 | |||
153 | if ( vrc7_enabled( this ) ) Vrc7_volume( &this->vrc7, adjusted_gain ); | ||
154 | if ( namco_enabled( this ) ) Namco_volume( &this->namco, adjusted_gain ); | 180 | if ( namco_enabled( this ) ) Namco_volume( &this->namco, adjusted_gain ); |
155 | if ( vrc6_enabled( this ) ) Vrc6_volume( &this->vrc6, adjusted_gain ); | 181 | if ( vrc6_enabled( this ) ) Vrc6_volume( &this->vrc6, adjusted_gain ); |
156 | if ( fme7_enabled( this ) ) Fme7_volume( &this->fme7, adjusted_gain ); | 182 | if ( fme7_enabled( this ) ) Fme7_volume( &this->fme7, adjusted_gain ); |
@@ -179,9 +205,9 @@ static bool pal_only( struct header_t* this ) | |||
179 | return (this->speed_flags & 3) == 1; | 205 | return (this->speed_flags & 3) == 1; |
180 | } | 206 | } |
181 | 207 | ||
182 | static long clock_rate( struct header_t* this ) | 208 | static int clock_rate( struct header_t* this ) |
183 | { | 209 | { |
184 | return pal_only( this ) ? (long)1662607.125 : (long)1789772.727272727; | 210 | return pal_only( this ) ? (int)1662607.125 : (int)1789772.727272727; |
185 | } | 211 | } |
186 | 212 | ||
187 | static int play_period( struct header_t* this ) | 213 | static int play_period( struct header_t* this ) |
@@ -227,7 +253,7 @@ static blargg_err_t check_nsf_header( struct header_t* h ) | |||
227 | return 0; | 253 | return 0; |
228 | } | 254 | } |
229 | 255 | ||
230 | blargg_err_t Nsf_load( struct Nsf_Emu* this, void* data, long size ) | 256 | blargg_err_t Nsf_load_mem( struct Nsf_Emu* this, void* data, long size ) |
231 | { | 257 | { |
232 | // Unload | 258 | // Unload |
233 | Info_unload( &this->info ); // TODO: extremely hacky! | 259 | Info_unload( &this->info ); // TODO: extremely hacky! |
@@ -258,11 +284,10 @@ blargg_err_t Nsf_post_load( struct Nsf_Emu* this ) | |||
258 | warning( "Unknown file version" ); */ | 284 | warning( "Unknown file version" ); */ |
259 | 285 | ||
260 | // set up data | 286 | // set up data |
261 | addr_t load_addr = get_le16( this->header.load_addr ); | 287 | addr_t load_addr = get_addr( this->header.load_addr ); |
262 | |||
263 | /* if ( load_addr < (fds_enabled() ? sram_addr : rom_addr) ) | 288 | /* if ( load_addr < (fds_enabled() ? sram_addr : rom_addr) ) |
264 | warning( "Load address is too low" ); */ | 289 | warning( "Load address is too low" ); */ |
265 | 290 | ||
266 | Rom_set_addr( &this->rom, load_addr % this->rom.bank_size ); | 291 | Rom_set_addr( &this->rom, load_addr % this->rom.bank_size ); |
267 | 292 | ||
268 | /* if ( header_.vers != 1 ) | 293 | /* if ( header_.vers != 1 ) |
@@ -277,17 +302,16 @@ blargg_err_t Nsf_post_load( struct Nsf_Emu* this ) | |||
277 | 302 | ||
278 | // Post load | 303 | // Post load |
279 | Sound_set_tempo( this, this->tempo ); | 304 | Sound_set_tempo( this, this->tempo ); |
280 | |||
281 | // Remute voices | ||
282 | Sound_mute_voices( this, this->mute_mask_ ); | 305 | Sound_mute_voices( this, this->mute_mask_ ); |
283 | 306 | ||
284 | // Set track_count | 307 | // Set track_count |
285 | this->track_count = this->header.track_count; | 308 | this->track_count = this->header.track_count; |
286 | 309 | ||
287 | // Change clock rate & setup buffer | 310 | // Change clock rate & setup buffer |
288 | this->clock_rate__ = (long) clock_rate( &this->header ); | 311 | this->clock_rate__ = clock_rate( &this->header ); |
289 | Buffer_clock_rate( &this->stereo_buf, this->clock_rate__ ); | 312 | Buffer_clock_rate( &this->stereo_buf, this->clock_rate__ ); |
290 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 313 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); |
314 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | ||
291 | return 0; | 315 | return 0; |
292 | } | 316 | } |
293 | 317 | ||
@@ -416,11 +440,13 @@ static void set_voice( struct Nsf_Emu* this, int i, struct Blip_Buffer* buf, str | |||
416 | return; | 440 | return; |
417 | } | 441 | } |
418 | 442 | ||
419 | if ( vrc7_enabled( this ) && (i -= vrc7_osc_count) < 0 ) | 443 | #ifndef NSF_EMU_NO_VRC7 |
420 | { | 444 | if ( vrc7_enabled( this ) && (i -= vrc7_osc_count) < 0 ) |
421 | Vrc7_set_output( &this->vrc7, i + vrc7_osc_count, buf ); | 445 | { |
422 | return; | 446 | Vrc7_set_output( &this->vrc7, i + vrc7_osc_count, buf ); |
423 | } | 447 | return; |
448 | } | ||
449 | #endif | ||
424 | } | 450 | } |
425 | #endif | 451 | #endif |
426 | } | 452 | } |
@@ -429,7 +455,7 @@ static void set_voice( struct Nsf_Emu* this, int i, struct Blip_Buffer* buf, str | |||
429 | 455 | ||
430 | // Music Emu | 456 | // Music Emu |
431 | 457 | ||
432 | blargg_err_t Nsf_set_sample_rate( struct Nsf_Emu* this, long rate ) | 458 | blargg_err_t Nsf_set_sample_rate( struct Nsf_Emu* this, int rate ) |
433 | { | 459 | { |
434 | require( !this->sample_rate ); // sample rate can't be changed once set | 460 | require( !this->sample_rate ); // sample rate can't be changed once set |
435 | Buffer_init( &this->stereo_buf ); | 461 | Buffer_init( &this->stereo_buf ); |
@@ -439,6 +465,8 @@ blargg_err_t Nsf_set_sample_rate( struct Nsf_Emu* this, long rate ) | |||
439 | Buffer_bass_freq( &this->stereo_buf, 80 ); | 465 | Buffer_bass_freq( &this->stereo_buf, 80 ); |
440 | 466 | ||
441 | this->sample_rate = rate; | 467 | this->sample_rate = rate; |
468 | RETURN_ERR( track_init( &this->track_filter, this ) ); | ||
469 | this->tfilter.max_silence = 6 * stereo * this->sample_rate; | ||
442 | return 0; | 470 | return 0; |
443 | } | 471 | } |
444 | 472 | ||
@@ -466,7 +494,7 @@ void Sound_mute_voices( struct Nsf_Emu* this, int mask ) | |||
466 | } | 494 | } |
467 | else | 495 | else |
468 | { | 496 | { |
469 | struct channel_t ch = Buffer_channel( &this->stereo_buf ); | 497 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); |
470 | assert( (ch.center && ch.left && ch.right) || | 498 | assert( (ch.center && ch.left && ch.right) || |
471 | (!ch.center && !ch.left && !ch.right) ); // all or nothing | 499 | (!ch.center && !ch.left && !ch.right) ); // all or nothing |
472 | set_voice( this, i, ch.center, ch.left, ch.right ); | 500 | set_voice( this, i, ch.center, ch.left, ch.right ); |
@@ -533,32 +561,13 @@ int cpu_read( struct Nsf_Emu* this, addr_t addr ) | |||
533 | return addr >> 8; | 561 | return addr >> 8; |
534 | } | 562 | } |
535 | 563 | ||
536 | #if 0 /* function currently unused */ | ||
537 | static int unmapped_read( struct Nsf_Emu* this, addr_t addr ) | ||
538 | { | ||
539 | (void) this; | ||
540 | |||
541 | switch ( addr ) | ||
542 | { | ||
543 | case 0x2002: | ||
544 | case 0x4016: | ||
545 | case 0x4017: | ||
546 | return addr >> 8; | ||
547 | } | ||
548 | |||
549 | // Unmapped read | ||
550 | return addr >> 8; | ||
551 | } | ||
552 | #endif | ||
553 | |||
554 | void cpu_write( struct Nsf_Emu* this, addr_t addr, int data ) | 564 | void cpu_write( struct Nsf_Emu* this, addr_t addr, int data ) |
555 | { | 565 | { |
556 | #ifndef NSF_EMU_APU_ONLY | 566 | #ifndef NSF_EMU_APU_ONLY |
557 | { | 567 | { |
558 | nes_time_t time = Cpu_time( &this->cpu ); | ||
559 | if ( fds_enabled( this) && (unsigned) (addr - fds_io_addr) < fds_io_size ) | 568 | if ( fds_enabled( this) && (unsigned) (addr - fds_io_addr) < fds_io_size ) |
560 | { | 569 | { |
561 | Fds_write( &this->fds, time, addr, data ); | 570 | Fds_write( &this->fds, Cpu_time( &this->cpu ), addr, data ); |
562 | return; | 571 | return; |
563 | } | 572 | } |
564 | 573 | ||
@@ -572,7 +581,7 @@ void cpu_write( struct Nsf_Emu* this, addr_t addr, int data ) | |||
572 | 581 | ||
573 | if ( addr == namco_data_reg_addr ) | 582 | if ( addr == namco_data_reg_addr ) |
574 | { | 583 | { |
575 | Namco_write_data( &this->namco, time, data ); | 584 | Namco_write_data( &this->namco, Cpu_time( &this->cpu ), data ); |
576 | return; | 585 | return; |
577 | } | 586 | } |
578 | } | 587 | } |
@@ -583,7 +592,7 @@ void cpu_write( struct Nsf_Emu* this, addr_t addr, int data ) | |||
583 | int osc = (unsigned) (addr - vrc6_base_addr) / vrc6_addr_step; | 592 | int osc = (unsigned) (addr - vrc6_base_addr) / vrc6_addr_step; |
584 | if ( (unsigned) osc < vrc6_osc_count && (unsigned) reg < vrc6_reg_count ) | 593 | if ( (unsigned) osc < vrc6_osc_count && (unsigned) reg < vrc6_reg_count ) |
585 | { | 594 | { |
586 | Vrc6_write_osc( &this->vrc6, time, osc, reg, data ); | 595 | Vrc6_write_osc( &this->vrc6, Cpu_time( &this->cpu ), osc, reg, data ); |
587 | return; | 596 | return; |
588 | } | 597 | } |
589 | } | 598 | } |
@@ -597,7 +606,7 @@ void cpu_write( struct Nsf_Emu* this, addr_t addr, int data ) | |||
597 | return; | 606 | return; |
598 | 607 | ||
599 | case fme7_data_addr: | 608 | case fme7_data_addr: |
600 | Fme7_write_data( &this->fme7, time, data ); | 609 | Fme7_write_data( &this->fme7, Cpu_time( &this->cpu ), data ); |
601 | return; | 610 | return; |
602 | } | 611 | } |
603 | } | 612 | } |
@@ -606,7 +615,7 @@ void cpu_write( struct Nsf_Emu* this, addr_t addr, int data ) | |||
606 | { | 615 | { |
607 | if ( (unsigned) (addr - mmc5_regs_addr) < mmc5_regs_size ) | 616 | if ( (unsigned) (addr - mmc5_regs_addr) < mmc5_regs_size ) |
608 | { | 617 | { |
609 | Mmc5_write_register( &this->mmc5, time, addr, data ); | 618 | Mmc5_write_register( &this->mmc5, Cpu_time( &this->cpu ), addr, data ); |
610 | return; | 619 | return; |
611 | } | 620 | } |
612 | 621 | ||
@@ -625,49 +634,28 @@ void cpu_write( struct Nsf_Emu* this, addr_t addr, int data ) | |||
625 | } | 634 | } |
626 | } | 635 | } |
627 | 636 | ||
628 | if ( vrc7_enabled( this) ) | 637 | #ifndef NSF_EMU_NO_VRC7 |
629 | { | 638 | if ( vrc7_enabled( this) ) |
630 | if ( addr == 0x9010 ) | ||
631 | { | 639 | { |
632 | Vrc7_write_reg( &this->vrc7, data ); | 640 | if ( addr == 0x9010 ) |
633 | return; | 641 | { |
634 | } | 642 | Vrc7_write_reg( &this->vrc7, data ); |
643 | return; | ||
644 | } | ||
635 | 645 | ||
636 | if ( (unsigned) (addr - 0x9028) <= 0x08 ) | 646 | if ( (unsigned) (addr - 0x9028) <= 0x08 ) |
637 | { | 647 | { |
638 | Vrc7_write_data( &this->vrc7, time, data ); | 648 | Vrc7_write_data( &this->vrc7, Cpu_time( &this->cpu ), data ); |
639 | return; | 649 | return; |
650 | } | ||
640 | } | 651 | } |
641 | } | 652 | #endif |
642 | } | 653 | } |
643 | #endif | 654 | #endif |
644 | 655 | ||
645 | // Unmapped_write | 656 | // Unmapped_write |
646 | } | 657 | } |
647 | 658 | ||
648 | #if 0 /* function currently unused */ | ||
649 | static void unmapped_write( struct Nsf_Emu* this, addr_t addr, int data ) | ||
650 | { | ||
651 | (void) data; | ||
652 | |||
653 | switch ( addr ) | ||
654 | { | ||
655 | case 0x8000: // some write to $8000 and $8001 repeatedly | ||
656 | case 0x8001: | ||
657 | case 0x4800: // probably namco sound mistakenly turned on in MCK | ||
658 | case 0xF800: | ||
659 | case 0xFFF8: // memory mapper? | ||
660 | return; | ||
661 | } | ||
662 | |||
663 | if ( mmc5_enabled( this ) && addr == 0x5115 ) return; | ||
664 | |||
665 | // FDS memory | ||
666 | if ( fds_enabled( this ) && (unsigned) (addr - 0x8000) < 0x6000 ) return; | ||
667 | } | ||
668 | #endif | ||
669 | |||
670 | void fill_buf( struct Nsf_Emu* this ); | ||
671 | blargg_err_t Nsf_start_track( struct Nsf_Emu* this, int track ) | 659 | blargg_err_t Nsf_start_track( struct Nsf_Emu* this, int track ) |
672 | { | 660 | { |
673 | clear_track_vars( this ); | 661 | clear_track_vars( this ); |
@@ -695,7 +683,9 @@ blargg_err_t Nsf_start_track( struct Nsf_Emu* this, int track ) | |||
695 | if ( vrc6_enabled( this ) ) Vrc6_reset( &this->vrc6 ); | 683 | if ( vrc6_enabled( this ) ) Vrc6_reset( &this->vrc6 ); |
696 | if ( fme7_enabled( this ) ) Fme7_reset( &this->fme7 ); | 684 | if ( fme7_enabled( this ) ) Fme7_reset( &this->fme7 ); |
697 | if ( mmc5_enabled( this ) ) Apu_reset( &this->mmc5.apu, false, 0 ); | 685 | if ( mmc5_enabled( this ) ) Apu_reset( &this->mmc5.apu, false, 0 ); |
698 | if ( vrc7_enabled( this ) ) Vrc7_reset( &this->vrc7 ); | 686 | #ifndef NSF_EMU_NO_VRC7 |
687 | if ( vrc7_enabled( this ) ) Vrc7_reset( &this->vrc7 ); | ||
688 | #endif | ||
699 | #endif | 689 | #endif |
700 | 690 | ||
701 | int speed_flags = 0; | 691 | int speed_flags = 0; |
@@ -728,27 +718,15 @@ blargg_err_t Nsf_start_track( struct Nsf_Emu* this, int track ) | |||
728 | /* if ( this->cpu.r.pc < get_addr( header.load_addr ) ) | 718 | /* if ( this->cpu.r.pc < get_addr( header.load_addr ) ) |
729 | warning( "Init address < load address" ); */ | 719 | warning( "Init address < load address" ); */ |
730 | 720 | ||
731 | this->emu_track_ended_ = false; | 721 | // convert filter times to samples |
732 | this->track_ended = false; | 722 | struct setup_t s = this->tfilter; |
723 | s.max_initial *= this->sample_rate * stereo; | ||
724 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD | ||
725 | s.lookahead = 1; | ||
726 | #endif | ||
727 | track_setup( &this->track_filter, &s ); | ||
733 | 728 | ||
734 | if ( !this->ignore_silence ) | 729 | return track_start( &this->track_filter ); |
735 | { | ||
736 | // play until non-silence or end of track | ||
737 | long end; | ||
738 | for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; ) | ||
739 | { | ||
740 | fill_buf( this ); | ||
741 | if ( this->buf_remain | (int) this->emu_track_ended_ ) | ||
742 | break; | ||
743 | } | ||
744 | |||
745 | this->emu_time = this->buf_remain; | ||
746 | this->out_time = 0; | ||
747 | this->silence_time = 0; | ||
748 | this->silence_count = 0; | ||
749 | } | ||
750 | /* return track_ended() ? warning() : 0; */ | ||
751 | return 0; | ||
752 | } | 730 | } |
753 | 731 | ||
754 | void run_once( struct Nsf_Emu* this, nes_time_t end ) | 732 | void run_once( struct Nsf_Emu* this, nes_time_t end ) |
@@ -831,265 +809,99 @@ static void end_frame( struct Nsf_Emu* this, nes_time_t end ) | |||
831 | if ( mmc5_enabled( this ) ) Apu_end_frame( &this->mmc5.apu, end ); | 809 | if ( mmc5_enabled( this ) ) Apu_end_frame( &this->mmc5.apu, end ); |
832 | if ( namco_enabled( this ) ) Namco_end_frame( &this->namco, end ); | 810 | if ( namco_enabled( this ) ) Namco_end_frame( &this->namco, end ); |
833 | if ( vrc6_enabled( this ) ) Vrc6_end_frame( &this->vrc6, end ); | 811 | if ( vrc6_enabled( this ) ) Vrc6_end_frame( &this->vrc6, end ); |
812 | #ifndef NSF_EMU_NO_VRC7 | ||
834 | if ( vrc7_enabled( this ) ) Vrc7_end_frame( &this->vrc7, end ); | 813 | if ( vrc7_enabled( this ) ) Vrc7_end_frame( &this->vrc7, end ); |
814 | #endif | ||
835 | #endif | 815 | #endif |
836 | } | 816 | } |
837 | 817 | ||
838 | // Tell/Seek | 818 | // Tell/Seek |
839 | 819 | ||
840 | static blargg_long msec_to_samples( long sample_rate, blargg_long msec ) | 820 | static int msec_to_samples( int msec, int sample_rate ) |
841 | { | 821 | { |
842 | blargg_long sec = msec / 1000; | 822 | int sec = msec / 1000; |
843 | msec -= sec * 1000; | 823 | msec -= sec * 1000; |
844 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; | 824 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; |
845 | } | 825 | } |
846 | 826 | ||
847 | long Track_tell( struct Nsf_Emu* this ) | 827 | int Track_tell( struct Nsf_Emu* this ) |
848 | { | 828 | { |
849 | blargg_long rate = this->sample_rate * stereo; | 829 | int rate = this->sample_rate * stereo; |
850 | blargg_long sec = this->out_time / rate; | 830 | int sec = track_sample_count( &this->track_filter ) / rate; |
851 | return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate; | 831 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; |
852 | } | 832 | } |
853 | 833 | ||
854 | blargg_err_t Track_seek( struct Nsf_Emu* this, long msec ) | 834 | blargg_err_t Track_seek( struct Nsf_Emu* this, int msec ) |
855 | { | 835 | { |
856 | blargg_long time = msec_to_samples( this->sample_rate, msec ); | 836 | int time = msec_to_samples( msec, this->sample_rate ); |
857 | if ( time < this->out_time ) | 837 | if ( time < track_sample_count( &this->track_filter ) ) |
858 | RETURN_ERR( Nsf_start_track( this, this->current_track ) ); | 838 | RETURN_ERR( Nsf_start_track( this, this->current_track ) ); |
859 | return Track_skip( this, time - this->out_time ); | 839 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); |
860 | } | 840 | } |
861 | 841 | ||
862 | blargg_err_t skip_( struct Nsf_Emu* this, long count ); | 842 | blargg_err_t Track_skip( struct Nsf_Emu* this, int count ) |
863 | blargg_err_t Track_skip( struct Nsf_Emu* this, long count ) | ||
864 | { | 843 | { |
865 | require( this->current_track >= 0 ); // start_track() must have been called already | 844 | require( this->current_track >= 0 ); // start_track() must have been called already |
866 | this->out_time += count; | 845 | return track_skip( &this->track_filter, count ); |
867 | |||
868 | // remove from silence and buf first | ||
869 | { | ||
870 | long n = min( count, this->silence_count ); | ||
871 | this->silence_count -= n; | ||
872 | count -= n; | ||
873 | |||
874 | n = min( count, this->buf_remain ); | ||
875 | this->buf_remain -= n; | ||
876 | count -= n; | ||
877 | } | ||
878 | |||
879 | if ( count && !this->emu_track_ended_ ) | ||
880 | { | ||
881 | this->emu_time += count; | ||
882 | // End track if error | ||
883 | if ( skip_( this, count ) ) | ||
884 | this->emu_track_ended_ = true; | ||
885 | } | ||
886 | |||
887 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
888 | this->track_ended |= this->emu_track_ended_; | ||
889 | |||
890 | return 0; | ||
891 | } | 846 | } |
892 | 847 | ||
893 | blargg_err_t play_( struct Nsf_Emu* this, long count, sample_t* out ); | 848 | blargg_err_t skip_( void *emu, int count ) |
894 | blargg_err_t skip_( struct Nsf_Emu* this, long count ) | ||
895 | { | 849 | { |
850 | struct Nsf_Emu* this = (struct Nsf_Emu*) emu; | ||
851 | |||
896 | // for long skip, mute sound | 852 | // for long skip, mute sound |
897 | const long threshold = 30000; | 853 | const int threshold = 32768; |
898 | if ( count > threshold ) | 854 | if ( count > threshold ) |
899 | { | 855 | { |
900 | int saved_mute = this->mute_mask_; | 856 | int saved_mute = this->mute_mask_; |
901 | Sound_mute_voices( this, ~0 ); | 857 | Sound_mute_voices( this, ~0 ); |
902 | |||
903 | while ( count > threshold / 2 && !this->emu_track_ended_ ) | ||
904 | { | ||
905 | RETURN_ERR( play_( this, buf_size, this->buf ) ); | ||
906 | count -= buf_size; | ||
907 | } | ||
908 | |||
909 | Sound_mute_voices( this, saved_mute ); | ||
910 | } | ||
911 | |||
912 | while ( count && !this->emu_track_ended_ ) | ||
913 | { | ||
914 | long n = buf_size; | ||
915 | if ( n > count ) | ||
916 | n = count; | ||
917 | count -= n; | ||
918 | RETURN_ERR( play_( this, n, this->buf ) ); | ||
919 | } | ||
920 | return 0; | ||
921 | } | ||
922 | |||
923 | // Fading | ||
924 | 858 | ||
925 | void Track_set_fade( struct Nsf_Emu* this, long start_msec, long length_msec ) | 859 | int n = count - threshold/2; |
926 | { | 860 | n &= ~(2048-1); // round to multiple of 2048 |
927 | this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo); | 861 | count -= n; |
928 | this->fade_start = msec_to_samples( this->sample_rate, start_msec ); | 862 | RETURN_ERR( skippy_( &this->track_filter, n ) ); |
929 | } | ||
930 | |||
931 | // unit / pow( 2.0, (double) x / step ) | ||
932 | static int int_log( blargg_long x, int step, int unit ) | ||
933 | { | ||
934 | int shift = x / step; | ||
935 | int fraction = (x - shift * step) * unit / step; | ||
936 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
937 | } | ||
938 | 863 | ||
939 | static void handle_fade( struct Nsf_Emu* this, long out_count, sample_t* out ) | 864 | Sound_mute_voices( this, saved_mute ); |
940 | { | ||
941 | int i; | ||
942 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
943 | { | ||
944 | int const shift = 14; | ||
945 | int const unit = 1 << shift; | ||
946 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
947 | this->fade_step, unit ); | ||
948 | if ( gain < (unit >> fade_shift) ) | ||
949 | this->track_ended = this->emu_track_ended_ = true; | ||
950 | |||
951 | sample_t* io = &out [i]; | ||
952 | int count; | ||
953 | for ( count = min( fade_block_size, out_count - i ); count; --count ) | ||
954 | { | ||
955 | *io = (sample_t) ((*io * gain) >> shift); | ||
956 | ++io; | ||
957 | } | ||
958 | } | 865 | } |
959 | } | ||
960 | |||
961 | // Silence detection | ||
962 | 866 | ||
963 | void emu_play( struct Nsf_Emu* this, long count, sample_t* out ); | 867 | return skippy_( &this->track_filter, count ); |
964 | void emu_play( struct Nsf_Emu* this, long count, sample_t* out ) | ||
965 | { | ||
966 | check( current_track_ >= 0 ); | ||
967 | this->emu_time += count; | ||
968 | if ( this->current_track >= 0 && !this->emu_track_ended_ ) { | ||
969 | |||
970 | // End track if error | ||
971 | if ( play_( this, count, out ) ) | ||
972 | this->emu_track_ended_ = true; | ||
973 | } | ||
974 | else | ||
975 | memset( out, 0, count * sizeof *out ); | ||
976 | } | 868 | } |
977 | 869 | ||
978 | // number of consecutive silent samples at end | 870 | // Fading |
979 | static long count_silence( sample_t* begin, long size ) | ||
980 | { | ||
981 | sample_t first = *begin; | ||
982 | *begin = silence_threshold; // sentinel | ||
983 | sample_t* p = begin + size; | ||
984 | while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } | ||
985 | *begin = first; | ||
986 | return size - (p - begin); | ||
987 | } | ||
988 | 871 | ||
989 | // fill internal buffer and check it for silence | 872 | void Track_set_fade( struct Nsf_Emu* this, int start_msec, int length_msec ) |
990 | void fill_buf( struct Nsf_Emu* this ) | ||
991 | { | 873 | { |
992 | assert( !this->buf_remain ); | 874 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), |
993 | if ( !this->emu_track_ended_ ) | 875 | length_msec * this->sample_rate / (1000 / stereo) ); |
994 | { | ||
995 | emu_play( this, buf_size, this->buf ); | ||
996 | long silence = count_silence( this->buf, buf_size ); | ||
997 | if ( silence < buf_size ) | ||
998 | { | ||
999 | this->silence_time = this->emu_time - silence; | ||
1000 | this->buf_remain = buf_size; | ||
1001 | return; | ||
1002 | } | ||
1003 | } | ||
1004 | this->silence_count += buf_size; | ||
1005 | } | 876 | } |
1006 | 877 | ||
1007 | blargg_err_t Nsf_play( struct Nsf_Emu* this, long out_count, sample_t* out ) | 878 | blargg_err_t Nsf_play( struct Nsf_Emu* this, int out_count, sample_t* out ) |
1008 | { | 879 | { |
1009 | if ( this->track_ended ) | 880 | require( this->current_track >= 0 ); |
1010 | { | 881 | require( out_count % stereo == 0 ); |
1011 | memset( out, 0, out_count * sizeof *out ); | 882 | return track_play( &this->track_filter, out_count, out ); |
1012 | } | ||
1013 | else | ||
1014 | { | ||
1015 | require( this->current_track >= 0 ); | ||
1016 | require( out_count % stereo == 0 ); | ||
1017 | |||
1018 | assert( this->emu_time >= this->out_time ); | ||
1019 | |||
1020 | long pos = 0; | ||
1021 | if ( this->silence_count ) | ||
1022 | { | ||
1023 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
1024 | long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time; | ||
1025 | while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) | ||
1026 | fill_buf( this ); | ||
1027 | |||
1028 | // fill with silence | ||
1029 | pos = min( this->silence_count, out_count ); | ||
1030 | memset( out, 0, pos * sizeof *out ); | ||
1031 | this->silence_count -= pos; | ||
1032 | |||
1033 | if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate ) | ||
1034 | { | ||
1035 | this->track_ended = this->emu_track_ended_ = true; | ||
1036 | this->silence_count = 0; | ||
1037 | this->buf_remain = 0; | ||
1038 | } | ||
1039 | } | ||
1040 | |||
1041 | if ( this->buf_remain ) | ||
1042 | { | ||
1043 | // empty silence buf | ||
1044 | long n = min( this->buf_remain, out_count - pos ); | ||
1045 | memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out ); | ||
1046 | this->buf_remain -= n; | ||
1047 | pos += n; | ||
1048 | } | ||
1049 | |||
1050 | // generate remaining samples normally | ||
1051 | long remain = out_count - pos; | ||
1052 | if ( remain ) | ||
1053 | { | ||
1054 | emu_play( this, remain, out + pos ); | ||
1055 | this->track_ended |= this->emu_track_ended_; | ||
1056 | |||
1057 | if ( !this->ignore_silence || this->out_time > this->fade_start ) | ||
1058 | { | ||
1059 | // check end for a new run of silence | ||
1060 | long silence = count_silence( out + pos, remain ); | ||
1061 | if ( silence < remain ) | ||
1062 | this->silence_time = this->emu_time - silence; | ||
1063 | |||
1064 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
1065 | fill_buf( this ); // cause silence detection on next play() | ||
1066 | } | ||
1067 | } | ||
1068 | |||
1069 | if ( this->out_time > this->fade_start ) | ||
1070 | handle_fade( this, out_count, out ); | ||
1071 | } | ||
1072 | this->out_time += out_count; | ||
1073 | return 0; | ||
1074 | } | 883 | } |
1075 | 884 | ||
1076 | blargg_err_t play_( struct Nsf_Emu* this, long count, sample_t* out ) | 885 | blargg_err_t play_( void* emu, int count, sample_t* out ) |
1077 | { | 886 | { |
1078 | long remain = count; | 887 | struct Nsf_Emu* this = (struct Nsf_Emu*) emu; |
888 | |||
889 | int remain = count; | ||
1079 | while ( remain ) | 890 | while ( remain ) |
1080 | { | 891 | { |
892 | Buffer_disable_immediate_removal( &this->stereo_buf ); | ||
1081 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); | 893 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); |
1082 | if ( remain ) | 894 | if ( remain ) |
1083 | { | 895 | { |
1084 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) | 896 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) |
1085 | { | 897 | { |
1086 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 898 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
1087 | 899 | ||
1088 | // Remute voices | 900 | // Remute voices |
1089 | Sound_mute_voices( this, this->mute_mask_ ); | 901 | Sound_mute_voices( this, this->mute_mask_ ); |
1090 | } | 902 | } |
1091 | int msec = Buffer_length( &this->stereo_buf ); | 903 | int msec = Buffer_length( &this->stereo_buf ); |
1092 | blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate__ / 1000 - 100; | 904 | blip_time_t clocks_emulated = msec * this->clock_rate__ / 1000 - 100; |
1093 | RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); | 905 | RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) ); |
1094 | assert( clocks_emulated ); | 906 | assert( clocks_emulated ); |
1095 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); | 907 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); |
diff --git a/apps/codecs/libgme/nsf_emu.h b/apps/codecs/libgme/nsf_emu.h index dccfa8c5d5..00bdad4a4e 100644 --- a/apps/codecs/libgme/nsf_emu.h +++ b/apps/codecs/libgme/nsf_emu.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "nes_cpu.h" | 10 | #include "nes_cpu.h" |
11 | #include "nsfe_info.h" | 11 | #include "nsfe_info.h" |
12 | #include "m3u_playlist.h" | 12 | #include "m3u_playlist.h" |
13 | #include "track_filter.h" | ||
13 | 14 | ||
14 | #ifndef NSF_EMU_APU_ONLY | 15 | #ifndef NSF_EMU_APU_ONLY |
15 | #include "nes_namco_apu.h" | 16 | #include "nes_namco_apu.h" |
@@ -17,11 +18,11 @@ | |||
17 | #include "nes_fme7_apu.h" | 18 | #include "nes_fme7_apu.h" |
18 | #include "nes_fds_apu.h" | 19 | #include "nes_fds_apu.h" |
19 | #include "nes_mmc5_apu.h" | 20 | #include "nes_mmc5_apu.h" |
20 | #include "nes_vrc7_apu.h" | 21 | #ifndef NSF_EMU_NO_VRC7 |
22 | #include "nes_vrc7_apu.h" | ||
23 | #endif | ||
21 | #endif | 24 | #endif |
22 | 25 | ||
23 | typedef short sample_t; | ||
24 | |||
25 | // Sound chip flags | 26 | // Sound chip flags |
26 | enum { | 27 | enum { |
27 | vrc6_flag = 1 << 0, | 28 | vrc6_flag = 1 << 0, |
@@ -50,8 +51,7 @@ enum { fdsram_size = 0x6000 }; | |||
50 | enum { fdsram_offset = 0x2000 + page_size + 8 }; | 51 | enum { fdsram_offset = 0x2000 + page_size + 8 }; |
51 | enum { sram_addr = 0x6000 }; | 52 | enum { sram_addr = 0x6000 }; |
52 | enum { unmapped_size= page_size + 8 }; | 53 | enum { unmapped_size= page_size + 8 }; |
53 | 54 | enum { max_voices = 32 }; | |
54 | enum { buf_size = 2048 }; | ||
55 | 55 | ||
56 | // NSF file header | 56 | // NSF file header |
57 | enum { header_size = 0x80 }; | 57 | enum { header_size = 0x80 }; |
@@ -82,37 +82,21 @@ struct Nsf_Emu { | |||
82 | int play_extra; | 82 | int play_extra; |
83 | int play_delay; | 83 | int play_delay; |
84 | struct registers_t saved_state; // of interrupted init routine | 84 | struct registers_t saved_state; // of interrupted init routine |
85 | |||
86 | int track_count; | ||
87 | 85 | ||
88 | // general | 86 | // general |
89 | int max_initial_silence; | ||
90 | int voice_count; | 87 | int voice_count; |
88 | int voice_types [32]; | ||
91 | int mute_mask_; | 89 | int mute_mask_; |
92 | int tempo; | 90 | int tempo; |
93 | int gain; | 91 | int gain; |
94 | 92 | ||
95 | long sample_rate; | 93 | int sample_rate; |
96 | 94 | ||
97 | // track-specific | 95 | // track-specific |
96 | int track_count; | ||
98 | int current_track; | 97 | int current_track; |
99 | blargg_long out_time; // number of samples played since start of track | ||
100 | blargg_long emu_time; // number of samples emulator has generated since start of track | ||
101 | bool emu_track_ended_; // emulator has reached end of track | ||
102 | volatile bool track_ended; | ||
103 | |||
104 | // fading | ||
105 | blargg_long fade_start; | ||
106 | int fade_step; | ||
107 | 98 | ||
108 | // silence detection | 99 | int clock_rate__; |
109 | int silence_lookahead; // speed to run emulator when looking ahead for silence | ||
110 | bool ignore_silence; | ||
111 | long silence_time; // number of samples where most recent silence began | ||
112 | long silence_count; // number of samples of silence to play before using buf | ||
113 | long buf_remain; // number of samples left in silence buffer | ||
114 | |||
115 | long clock_rate__; | ||
116 | unsigned buf_changed_count; | 100 | unsigned buf_changed_count; |
117 | 101 | ||
118 | // M3u Playlist | 102 | // M3u Playlist |
@@ -127,7 +111,9 @@ struct Nsf_Emu { | |||
127 | struct Nes_Namco_Apu namco; | 111 | struct Nes_Namco_Apu namco; |
128 | struct Nes_Vrc6_Apu vrc6; | 112 | struct Nes_Vrc6_Apu vrc6; |
129 | struct Nes_Fme7_Apu fme7; | 113 | struct Nes_Fme7_Apu fme7; |
130 | struct Nes_Vrc7_Apu vrc7; | 114 | #ifndef NSF_EMU_NO_VRC7 |
115 | struct Nes_Vrc7_Apu vrc7; | ||
116 | #endif | ||
131 | #endif | 117 | #endif |
132 | 118 | ||
133 | struct Nes_Cpu cpu; | 119 | struct Nes_Cpu cpu; |
@@ -136,13 +122,15 @@ struct Nsf_Emu { | |||
136 | // Header for currently loaded file | 122 | // Header for currently loaded file |
137 | struct header_t header; | 123 | struct header_t header; |
138 | 124 | ||
139 | struct Stereo_Buffer stereo_buf; | 125 | struct setup_t tfilter; |
126 | struct Track_Filter track_filter; | ||
127 | |||
128 | struct Multi_Buffer stereo_buf; | ||
140 | struct Rom_Data rom; | 129 | struct Rom_Data rom; |
141 | 130 | ||
142 | // Extended nsf info | 131 | // Extended nsf info |
143 | struct Nsfe_Info info; | 132 | struct Nsfe_Info info; |
144 | 133 | ||
145 | sample_t buf [buf_size]; | ||
146 | byte high_ram[fdsram_size + fdsram_offset]; | 134 | byte high_ram[fdsram_size + fdsram_offset]; |
147 | byte low_ram [low_ram_size]; | 135 | byte low_ram [low_ram_size]; |
148 | }; | 136 | }; |
@@ -150,18 +138,18 @@ struct Nsf_Emu { | |||
150 | // Basic functionality (see Gme_File.h for file loading/track info functions) | 138 | // Basic functionality (see Gme_File.h for file loading/track info functions) |
151 | 139 | ||
152 | void Nsf_init( struct Nsf_Emu* this ); | 140 | void Nsf_init( struct Nsf_Emu* this ); |
153 | blargg_err_t Nsf_load( struct Nsf_Emu* this, void* data, long size ); | 141 | blargg_err_t Nsf_load_mem( struct Nsf_Emu* this, void* data, long size ); |
154 | blargg_err_t Nsf_post_load( struct Nsf_Emu* this ); | 142 | blargg_err_t Nsf_post_load( struct Nsf_Emu* this ); |
155 | 143 | ||
156 | // Set output sample rate. Must be called only once before loading file. | 144 | // Set output sample rate. Must be called only once before loading file. |
157 | blargg_err_t Nsf_set_sample_rate( struct Nsf_Emu* this, long sample_rate ); | 145 | blargg_err_t Nsf_set_sample_rate( struct Nsf_Emu* this, int sample_rate ); |
158 | 146 | ||
159 | // Start a track, where 0 is the first track. Also clears warning string. | 147 | // Start a track, where 0 is the first track. Also clears warning string. |
160 | blargg_err_t Nsf_start_track( struct Nsf_Emu* this , int ); | 148 | blargg_err_t Nsf_start_track( struct Nsf_Emu* this , int ); |
161 | 149 | ||
162 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation | 150 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation |
163 | // errors set warning string, and major errors also end track. | 151 | // errors set warning string, and major errors also end track. |
164 | blargg_err_t Nsf_play( struct Nsf_Emu* this, long count, sample_t* buf ); | 152 | blargg_err_t Nsf_play( struct Nsf_Emu* this, int count, sample_t* buf ); |
165 | 153 | ||
166 | void Nsf_clear_playlist( struct Nsf_Emu* this ); | 154 | void Nsf_clear_playlist( struct Nsf_Emu* this ); |
167 | void Nsf_disable_playlist( struct Nsf_Emu* this, bool b ); // use clear_playlist() | 155 | void Nsf_disable_playlist( struct Nsf_Emu* this, bool b ); // use clear_playlist() |
@@ -169,20 +157,32 @@ void Nsf_disable_playlist( struct Nsf_Emu* this, bool b ); // use clear_playlist | |||
169 | // Track status/control | 157 | // Track status/control |
170 | 158 | ||
171 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track | 159 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track |
172 | long Track_tell( struct Nsf_Emu* this ); | 160 | int Track_tell( struct Nsf_Emu* this ); |
173 | 161 | ||
174 | // Seek to new time in track. Seeking backwards or far forward can take a while. | 162 | // Seek to new time in track. Seeking backwards or far forward can take a while. |
175 | blargg_err_t Track_seek( struct Nsf_Emu* this, long msec ); | 163 | blargg_err_t Track_seek( struct Nsf_Emu* this, int msec ); |
176 | 164 | ||
177 | // Skip n samples | 165 | // Skip n samples |
178 | blargg_err_t Track_skip( struct Nsf_Emu* this, long n ); | 166 | blargg_err_t Track_skip( struct Nsf_Emu* this, int n ); |
179 | 167 | ||
180 | // Set start time and length of track fade out. Once fade ends track_ended() returns | 168 | // Set start time and length of track fade out. Once fade ends track_ended() returns |
181 | // true. Fade time can be changed while track is playing. | 169 | // true. Fade time can be changed while track is playing. |
182 | void Track_set_fade( struct Nsf_Emu* this, long start_msec, long length_msec ); | 170 | void Track_set_fade( struct Nsf_Emu* this, int start_msec, int length_msec ); |
171 | |||
172 | // True if a track has reached its end | ||
173 | static inline bool Track_ended( struct Nsf_Emu* this ) | ||
174 | { | ||
175 | return track_ended( &this->track_filter ); | ||
176 | } | ||
177 | |||
178 | // Disables automatic end-of-track detection and skipping of silence at beginning | ||
179 | static inline void Track_ignore_silence( struct Nsf_Emu* this, bool disable ) | ||
180 | { | ||
181 | this->track_filter.silence_ignored_ = disable; | ||
182 | } | ||
183 | 183 | ||
184 | // Get track length in milliseconds | 184 | // Get track length in milliseconds |
185 | long Track_length( struct Nsf_Emu* this, int n ); | 185 | int Track_length( struct Nsf_Emu* this, int n ); |
186 | 186 | ||
187 | // Sound customization | 187 | // Sound customization |
188 | 188 | ||
@@ -217,28 +217,28 @@ bool run_cpu_until( struct Nsf_Emu* this, nes_time_t end ); | |||
217 | 217 | ||
218 | // Sets clocks between calls to play routine to p + 1/2 clock | 218 | // Sets clocks between calls to play routine to p + 1/2 clock |
219 | static inline void set_play_period( struct Nsf_Emu* this, int p ) { this->play_period = p; } | 219 | static inline void set_play_period( struct Nsf_Emu* this, int p ) { this->play_period = p; } |
220 | 220 | ||
221 | // Time play routine will next be called | 221 | // Time play routine will next be called |
222 | static inline nes_time_t play_time( struct Nsf_Emu* this ) { return this->next_play; } | 222 | static inline nes_time_t play_time( struct Nsf_Emu* this ) { return this->next_play; } |
223 | 223 | ||
224 | // Emulates to at least time t. Might emulate a few clocks extra. | 224 | // Emulates to at least time t. Might emulate a few clocks extra. |
225 | void run_until( struct Nsf_Emu* this, nes_time_t t ); | 225 | void run_until( struct Nsf_Emu* this, nes_time_t t ); |
226 | 226 | ||
227 | // Runs cpu to at least time t and returns false, or returns true | 227 | // Runs cpu to at least time t and returns false, or returns true |
228 | // if it encounters illegal instruction (halt). | 228 | // if it encounters illegal instruction (halt). |
229 | bool run_cpu_until( struct Nsf_Emu* this, nes_time_t t ); | 229 | bool run_cpu_until( struct Nsf_Emu* this, nes_time_t t ); |
230 | 230 | ||
231 | // cpu calls through to these to access memory (except instructions) | 231 | // cpu calls through to these to access memory (except instructions) |
232 | int read_mem( struct Nsf_Emu* this, addr_t ); | 232 | int read_mem( struct Nsf_Emu* this, addr_t ); |
233 | void write_mem( struct Nsf_Emu* this, addr_t, int ); | 233 | void write_mem( struct Nsf_Emu* this, addr_t, int ); |
234 | 234 | ||
235 | // Address of play routine | 235 | // Address of play routine |
236 | static inline addr_t play_addr( struct Nsf_Emu* this ) { return get_addr( this->header.play_addr ); } | 236 | static inline addr_t play_addr( struct Nsf_Emu* this ) { return get_addr( this->header.play_addr ); } |
237 | 237 | ||
238 | // Same as run_until, except emulation stops for any event (routine returned, | 238 | // Same as run_until, except emulation stops for any event (routine returned, |
239 | // play routine called, illegal instruction). | 239 | // play routine called, illegal instruction). |
240 | void run_once( struct Nsf_Emu* this, nes_time_t ); | 240 | void run_once( struct Nsf_Emu* this, nes_time_t ); |
241 | 241 | ||
242 | // Reads byte as cpu would when executing code. Only works for RAM/ROM, | 242 | // Reads byte as cpu would when executing code. Only works for RAM/ROM, |
243 | // NOT I/O like sound chips. | 243 | // NOT I/O like sound chips. |
244 | int read_code( struct Nsf_Emu* this, addr_t addr ); | 244 | int read_code( struct Nsf_Emu* this, addr_t addr ); |
@@ -248,12 +248,14 @@ static inline byte* sram( struct Nsf_Emu* this ) { return this->high_ | |||
248 | static inline byte* unmapped_code( struct Nsf_Emu* this ) { return &this->high_ram [sram_size]; } | 248 | static inline byte* unmapped_code( struct Nsf_Emu* this ) { return &this->high_ram [sram_size]; } |
249 | 249 | ||
250 | #ifndef NSF_EMU_APU_ONLY | 250 | #ifndef NSF_EMU_APU_ONLY |
251 | static inline int fds_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & fds_flag; } | 251 | static inline int fds_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & fds_flag; } |
252 | static inline int vrc6_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & vrc6_flag; } | 252 | static inline int vrc6_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & vrc6_flag; } |
253 | static inline int vrc7_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & vrc7_flag; } | 253 | #ifndef NSF_EMU_NO_VRC7 |
254 | static inline int mmc5_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & mmc5_flag; } | 254 | static inline int vrc7_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & vrc7_flag; } |
255 | static inline int namco_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & namco_flag; } | 255 | #endif |
256 | static inline int fme7_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & fme7_flag; } | 256 | static inline int mmc5_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & mmc5_flag; } |
257 | static inline int namco_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & namco_flag; } | ||
258 | static inline int fme7_enabled( struct Nsf_Emu* this ) { return this->header.chip_flags & fme7_flag; } | ||
257 | #endif | 259 | #endif |
258 | 260 | ||
259 | #endif | 261 | #endif |
diff --git a/apps/codecs/libgme/nsfe_info.c b/apps/codecs/libgme/nsfe_info.c index d22b763173..337b1e580a 100644 --- a/apps/codecs/libgme/nsfe_info.c +++ b/apps/codecs/libgme/nsfe_info.c | |||
@@ -154,8 +154,8 @@ blargg_err_t Info_load( struct Nsfe_Info* this, void* data, long size, struct Ns | |||
154 | byte block_header [2] [4]; | 154 | byte block_header [2] [4]; |
155 | RETURN_ERR( in_read( block_header, sizeof block_header, data, &offset, size ) ); | 155 | RETURN_ERR( in_read( block_header, sizeof block_header, data, &offset, size ) ); |
156 | 156 | ||
157 | blargg_long chunk_size = get_le32( block_header [0] ); | 157 | int chunk_size = get_le32( block_header [0] ); |
158 | blargg_long tag = get_le32( block_header [1] ); | 158 | int tag = get_le32( block_header [1] ); |
159 | 159 | ||
160 | switch ( tag ) | 160 | switch ( tag ) |
161 | { | 161 | { |
@@ -168,7 +168,7 @@ blargg_err_t Info_load( struct Nsfe_Info* this, void* data, long size, struct Ns | |||
168 | finfo.track_count = 1; | 168 | finfo.track_count = 1; |
169 | finfo.first_track = 0; | 169 | finfo.first_track = 0; |
170 | 170 | ||
171 | RETURN_ERR( in_read( &finfo, min( chunk_size, (blargg_long) nsfe_info_size ), | 171 | RETURN_ERR( in_read( &finfo, min( chunk_size, nsfe_info_size ), |
172 | (char*) data, &offset, size ) ); | 172 | (char*) data, &offset, size ) ); |
173 | 173 | ||
174 | if ( chunk_size > nsfe_info_size ) | 174 | if ( chunk_size > nsfe_info_size ) |
@@ -248,9 +248,9 @@ blargg_err_t Info_load( struct Nsfe_Info* this, void* data, long size, struct Ns | |||
248 | return 0; | 248 | return 0; |
249 | } | 249 | } |
250 | 250 | ||
251 | long Track_length( struct Nsf_Emu* this, int n ) | 251 | int Track_length( struct Nsf_Emu* this, int n ) |
252 | { | 252 | { |
253 | long length = 0; | 253 | int length = 0; |
254 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { | 254 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { |
255 | struct entry_t* entry = &this->m3u.entries [n]; | 255 | struct entry_t* entry = &this->m3u.entries [n]; |
256 | length = entry->length; | 256 | length = entry->length; |
diff --git a/apps/codecs/libgme/opl_apu.h b/apps/codecs/libgme/opl_apu.h index 5ea8185f5f..f24a8d60c2 100644 --- a/apps/codecs/libgme/opl_apu.h +++ b/apps/codecs/libgme/opl_apu.h | |||
@@ -37,10 +37,10 @@ struct Opl_Apu { | |||
37 | 37 | ||
38 | blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type ); | 38 | blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type ); |
39 | void Opl_shutdown( struct Opl_Apu* this ); | 39 | void Opl_shutdown( struct Opl_Apu* this ); |
40 | 40 | ||
41 | void Opl_reset( struct Opl_Apu* this ); | 41 | void Opl_reset( struct Opl_Apu* this ); |
42 | static inline void Opl_volume( struct Opl_Apu* this, int v ) { Synth_volume( &this->synth, v / (4096 * 6) ); } | 42 | static inline void Opl_volume( struct Opl_Apu* this, int v ) { Synth_volume( &this->synth, v / (4096 * 6) ); } |
43 | 43 | ||
44 | static inline void Opl_osc_output( struct Opl_Apu* this, int i, struct Blip_Buffer* buf ) | 44 | static inline void Opl_osc_output( struct Opl_Apu* this, int i, struct Blip_Buffer* buf ) |
45 | { | 45 | { |
46 | #if defined(ROCKBOX) | 46 | #if defined(ROCKBOX) |
diff --git a/apps/codecs/libgme/resampler.c b/apps/codecs/libgme/resampler.c index 837f01ed13..91677cbb8a 100644 --- a/apps/codecs/libgme/resampler.c +++ b/apps/codecs/libgme/resampler.c | |||
@@ -64,7 +64,7 @@ void Resampler_resize( struct Resampler* this, int pairs ) | |||
64 | } | 64 | } |
65 | } | 65 | } |
66 | 66 | ||
67 | void mix_samples( struct Resampler* this, struct Blip_Buffer* blip_buf, sample_t out_ [] ) | 67 | void mix_samples( struct Resampler* this, struct Blip_Buffer* blip_buf, dsample_t out_ [] ) |
68 | { | 68 | { |
69 | int const bass = BLIP_READER_BASS( *blip_buf ); | 69 | int const bass = BLIP_READER_BASS( *blip_buf ); |
70 | BLIP_READER_BEGIN( sn, *blip_buf ); | 70 | BLIP_READER_BEGIN( sn, *blip_buf ); |
@@ -72,7 +72,7 @@ void mix_samples( struct Resampler* this, struct Blip_Buffer* blip_buf, sample_t | |||
72 | int count = this->sample_buf_size >> 1; | 72 | int count = this->sample_buf_size >> 1; |
73 | BLIP_READER_ADJ_( sn, count ); | 73 | BLIP_READER_ADJ_( sn, count ); |
74 | 74 | ||
75 | typedef sample_t stereo_dsample_t [2]; | 75 | typedef dsample_t stereo_dsample_t [2]; |
76 | stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; | 76 | stereo_dsample_t* BLARGG_RESTRICT out = (stereo_dsample_t*) out_ + count; |
77 | stereo_dsample_t const* BLARGG_RESTRICT in = | 77 | stereo_dsample_t const* BLARGG_RESTRICT in = |
78 | (stereo_dsample_t const*) this->sample_buf + count; | 78 | (stereo_dsample_t const*) this->sample_buf + count; |
@@ -97,14 +97,14 @@ void mix_samples( struct Resampler* this, struct Blip_Buffer* blip_buf, sample_t | |||
97 | BLIP_READER_END( sn, *blip_buf ); | 97 | BLIP_READER_END( sn, *blip_buf ); |
98 | } | 98 | } |
99 | 99 | ||
100 | sample_t const* resample_( struct Resampler* this, sample_t** out_, | 100 | dsample_t const* resample_( struct Resampler* this, dsample_t** out_, |
101 | sample_t const* out_end, sample_t const in [], int in_size ) | 101 | dsample_t const* out_end, dsample_t const in [], int in_size ) |
102 | { | 102 | { |
103 | in_size -= write_offset; | 103 | in_size -= write_offset; |
104 | if ( in_size > 0 ) | 104 | if ( in_size > 0 ) |
105 | { | 105 | { |
106 | sample_t* BLARGG_RESTRICT out = *out_; | 106 | dsample_t* BLARGG_RESTRICT out = *out_; |
107 | sample_t const* const in_end = in + in_size; | 107 | dsample_t const* const in_end = in + in_size; |
108 | 108 | ||
109 | int const step = this->step; | 109 | int const step = this->step; |
110 | int pos = this->pos; | 110 | int pos = this->pos; |
@@ -135,12 +135,12 @@ sample_t const* resample_( struct Resampler* this, sample_t** out_, | |||
135 | return in; | 135 | return in; |
136 | } | 136 | } |
137 | 137 | ||
138 | static inline int resample_wrapper( struct Resampler* this, sample_t out [], int* out_size, | 138 | static inline int resample_wrapper( struct Resampler* this, dsample_t out [], int* out_size, |
139 | sample_t const in [], int in_size ) | 139 | dsample_t const in [], int in_size ) |
140 | { | 140 | { |
141 | assert( Resampler_rate( this ) ); | 141 | assert( Resampler_rate( this ) ); |
142 | 142 | ||
143 | sample_t* out_ = out; | 143 | dsample_t* out_ = out; |
144 | int result = resample_( this, &out_, out + *out_size, in, in_size ) - in; | 144 | int result = resample_( this, &out_, out + *out_size, in, in_size ) - in; |
145 | assert( out_ <= out + *out_size ); | 145 | assert( out_ <= out + *out_size ); |
146 | assert( result <= in_size ); | 146 | assert( result <= in_size ); |
@@ -161,7 +161,7 @@ int skip_input( struct Resampler* this, int count ) | |||
161 | return count; | 161 | return count; |
162 | } | 162 | } |
163 | 163 | ||
164 | void play_frame_( struct Resampler* this, struct Blip_Buffer* blip_buf, sample_t* out ) | 164 | void play_frame_( struct Resampler* this, struct Blip_Buffer* blip_buf, dsample_t* out ) |
165 | { | 165 | { |
166 | int pair_count = this->sample_buf_size >> 1; | 166 | int pair_count = this->sample_buf_size >> 1; |
167 | blip_time_t blip_time = Blip_count_clocks( blip_buf, pair_count ); | 167 | blip_time_t blip_time = Blip_count_clocks( blip_buf, pair_count ); |
@@ -185,7 +185,7 @@ void play_frame_( struct Resampler* this, struct Blip_Buffer* blip_buf, sample_t | |||
185 | Blip_remove_samples( blip_buf, pair_count ); | 185 | Blip_remove_samples( blip_buf, pair_count ); |
186 | } | 186 | } |
187 | 187 | ||
188 | void Resampler_play( struct Resampler* this, int count, sample_t* out, struct Blip_Buffer* blip_buf ) | 188 | void Resampler_play( struct Resampler* this, int count, dsample_t* out, struct Blip_Buffer* blip_buf ) |
189 | { | 189 | { |
190 | // empty extra buffer | 190 | // empty extra buffer |
191 | int remain = this->sample_buf_size - this->buf_pos; | 191 | int remain = this->sample_buf_size - this->buf_pos; |
diff --git a/apps/codecs/libgme/resampler.h b/apps/codecs/libgme/resampler.h index 1d8f86670b..3f3710a54a 100644 --- a/apps/codecs/libgme/resampler.h +++ b/apps/codecs/libgme/resampler.h | |||
@@ -7,16 +7,15 @@ | |||
7 | #include "blargg_common.h" | 7 | #include "blargg_common.h" |
8 | #include "multi_buffer.h" | 8 | #include "multi_buffer.h" |
9 | 9 | ||
10 | typedef short sample_t; | 10 | typedef short dsample_t; |
11 | 11 | ||
12 | enum { stereo = 2 }; | ||
13 | enum { max_buf_size = 3960 }; | 12 | enum { max_buf_size = 3960 }; |
14 | enum { max_resampler_size = 5942 }; | 13 | enum { max_resampler_size = 5942 }; |
15 | enum { write_offset = 8 * stereo }; | 14 | enum { write_offset = 8 * stereo }; |
16 | enum { gain_bits = 14 }; | 15 | enum { gain_bits = 14 }; |
17 | 16 | ||
18 | struct Resampler { | 17 | struct Resampler { |
19 | int (*callback)( void*, blip_time_t, int, sample_t* ); | 18 | int (*callback)( void*, blip_time_t, int, dsample_t* ); |
20 | void* callback_data; | 19 | void* callback_data; |
21 | 20 | ||
22 | int sample_buffer_size; | 21 | int sample_buffer_size; |
@@ -34,8 +33,8 @@ struct Resampler { | |||
34 | 33 | ||
35 | int rate_; | 34 | int rate_; |
36 | 35 | ||
37 | sample_t sample_buf [max_buf_size]; | 36 | dsample_t sample_buf [max_buf_size]; |
38 | sample_t buf [max_resampler_size]; // Internal resampler | 37 | dsample_t buf [max_resampler_size]; // Internal resampler |
39 | }; | 38 | }; |
40 | 39 | ||
41 | static inline void Resampler_init( struct Resampler* this ) | 40 | static inline void Resampler_init( struct Resampler* this ) |
@@ -50,9 +49,9 @@ static inline void Resampler_init( struct Resampler* this ) | |||
50 | 49 | ||
51 | blargg_err_t Resampler_reset( struct Resampler* this, int max_pairs ); | 50 | blargg_err_t Resampler_reset( struct Resampler* this, int max_pairs ); |
52 | void Resampler_resize( struct Resampler* this, int pairs_per_frame ); | 51 | void Resampler_resize( struct Resampler* this, int pairs_per_frame ); |
53 | void Resampler_play( struct Resampler* this, int count, sample_t* out, struct Blip_Buffer* ); | 52 | void Resampler_play( struct Resampler* this, int count, dsample_t* out, struct Blip_Buffer* ); |
54 | 53 | ||
55 | static inline void Resampler_set_callback(struct Resampler* this, int (*func)( void*, blip_time_t, int, sample_t* ), void* user_data ) | 54 | static inline void Resampler_set_callback(struct Resampler* this, int (*func)( void*, blip_time_t, int, dsample_t* ), void* user_data ) |
56 | { | 55 | { |
57 | this->callback = func; | 56 | this->callback = func; |
58 | this->callback_data = user_data; | 57 | this->callback_data = user_data; |
diff --git a/apps/codecs/libgme/rom_data.c b/apps/codecs/libgme/rom_data.c index 5fe3115130..9c36a99d2d 100644 --- a/apps/codecs/libgme/rom_data.c +++ b/apps/codecs/libgme/rom_data.c | |||
@@ -21,7 +21,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | |||
21 | blargg_err_t Rom_load( struct Rom_Data* this, const void* data, long size, | 21 | blargg_err_t Rom_load( struct Rom_Data* this, const void* data, long size, |
22 | int header_size, void* header_out, int fill ) | 22 | int header_size, void* header_out, int fill ) |
23 | { | 23 | { |
24 | long file_offset = this->pad_size; | 24 | int file_offset = this->pad_size; |
25 | 25 | ||
26 | this->rom_addr = 0; | 26 | this->rom_addr = 0; |
27 | this->mask = 0; | 27 | this->mask = 0; |
@@ -43,11 +43,11 @@ blargg_err_t Rom_load( struct Rom_Data* this, const void* data, long size, | |||
43 | return 0; | 43 | return 0; |
44 | } | 44 | } |
45 | 45 | ||
46 | void Rom_set_addr( struct Rom_Data* this, long addr ) | 46 | void Rom_set_addr( struct Rom_Data* this, int addr ) |
47 | { | 47 | { |
48 | this->rom_addr = addr - this->bank_size - pad_extra; | 48 | this->rom_addr = addr - this->bank_size - pad_extra; |
49 | 49 | ||
50 | long rounded = (addr + this->file_size + this->bank_size - 1) / this->bank_size * this->bank_size; | 50 | int rounded = (addr + this->file_size + this->bank_size - 1) / this->bank_size * this->bank_size; |
51 | if ( rounded <= 0 ) | 51 | if ( rounded <= 0 ) |
52 | { | 52 | { |
53 | rounded = 0; | 53 | rounded = 0; |
@@ -55,7 +55,7 @@ void Rom_set_addr( struct Rom_Data* this, long addr ) | |||
55 | else | 55 | else |
56 | { | 56 | { |
57 | int shift = 0; | 57 | int shift = 0; |
58 | unsigned long max_addr = (unsigned long) (rounded - 1); | 58 | unsigned int max_addr = (unsigned int) (rounded - 1); |
59 | while ( max_addr >> shift ) | 59 | while ( max_addr >> shift ) |
60 | shift++; | 60 | shift++; |
61 | this->mask = (1L << shift) - 1; | 61 | this->mask = (1L << shift) - 1; |
diff --git a/apps/codecs/libgme/rom_data.h b/apps/codecs/libgme/rom_data.h index 28b34f2a70..b8bc54cd3f 100644 --- a/apps/codecs/libgme/rom_data.h +++ b/apps/codecs/libgme/rom_data.h | |||
@@ -20,22 +20,22 @@ enum { max_rom_size = 2 * max_pad_size }; | |||
20 | 20 | ||
21 | struct Rom_Data { | 21 | struct Rom_Data { |
22 | byte* file_data; | 22 | byte* file_data; |
23 | blargg_ulong file_size; | 23 | unsigned file_size; |
24 | 24 | ||
25 | blargg_long rom_addr; | 25 | int rom_addr; |
26 | blargg_long bank_size; | 26 | int bank_size; |
27 | blargg_long rom_size; | 27 | int rom_size; |
28 | blargg_ulong pad_size; | 28 | unsigned pad_size; |
29 | blargg_long mask; | 29 | int mask; |
30 | blargg_long size; // TODO: eliminate | 30 | int size; // TODO: eliminate |
31 | blargg_long rsize_; | 31 | int rsize_; |
32 | 32 | ||
33 | // Unmapped space | 33 | // Unmapped space |
34 | byte unmapped [max_rom_size]; | 34 | byte unmapped [max_rom_size]; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | // Initialize rom | 37 | // Initialize rom |
38 | static inline void Rom_init( struct Rom_Data* this, blargg_long bank_size ) | 38 | static inline void Rom_init( struct Rom_Data* this, int bank_size ) |
39 | { | 39 | { |
40 | this->bank_size = bank_size; | 40 | this->bank_size = bank_size; |
41 | this->pad_size = this->bank_size + pad_extra; | 41 | this->pad_size = this->bank_size + pad_extra; |
@@ -47,10 +47,10 @@ static inline void Rom_init( struct Rom_Data* this, blargg_long bank_size ) | |||
47 | blargg_err_t Rom_load( struct Rom_Data* this, const void* data, long size, int header_size, void* header_out, int fill ); | 47 | blargg_err_t Rom_load( struct Rom_Data* this, const void* data, long size, int header_size, void* header_out, int fill ); |
48 | 48 | ||
49 | // Set address that file data should start at | 49 | // Set address that file data should start at |
50 | void Rom_set_addr( struct Rom_Data* this, long addr ); | 50 | void Rom_set_addr( struct Rom_Data* this, int addr ); |
51 | 51 | ||
52 | // Mask address to nearest power of two greater than size() | 52 | // Mask address to nearest power of two greater than size() |
53 | static inline blargg_long mask_addr( blargg_long addr, blargg_long mask ) | 53 | static inline int mask_addr( int addr, int mask ) |
54 | { | 54 | { |
55 | #ifdef check | 55 | #ifdef check |
56 | check( addr <= mask ); | 56 | check( addr <= mask ); |
@@ -59,10 +59,10 @@ static inline blargg_long mask_addr( blargg_long addr, blargg_long mask ) | |||
59 | } | 59 | } |
60 | 60 | ||
61 | // Pointer to page starting at addr. Returns unmapped() if outside data. | 61 | // Pointer to page starting at addr. Returns unmapped() if outside data. |
62 | static inline byte* Rom_at_addr( struct Rom_Data* this, blargg_long addr ) | 62 | static inline byte* Rom_at_addr( struct Rom_Data* this, int addr ) |
63 | { | 63 | { |
64 | blargg_ulong offset = mask_addr( addr, this->mask ) - this->rom_addr; | 64 | unsigned offset = mask_addr( addr, this->mask ) - this->rom_addr; |
65 | if ( offset > (blargg_ulong) (this->rsize_ - this->pad_size) ) | 65 | if ( offset > (unsigned) (this->rsize_ - this->pad_size) ) |
66 | offset = 0; // unmapped | 66 | offset = 0; // unmapped |
67 | 67 | ||
68 | if ( offset < this->pad_size ) return &this->unmapped [offset]; | 68 | if ( offset < this->pad_size ) return &this->unmapped [offset]; |
diff --git a/apps/codecs/libgme/sgc_emu.c b/apps/codecs/libgme/sgc_emu.c index 3c3586611c..a2e6b8df29 100644 --- a/apps/codecs/libgme/sgc_emu.c +++ b/apps/codecs/libgme/sgc_emu.c | |||
@@ -10,34 +10,19 @@ module is distributed in the hope that it will be useful, but WITHOUT ANY | |||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | 11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
12 | details. You should have received a copy of the GNU Lesser General Public | 12 | details. You should have received a copy of the GNU Lesser General Public |
13 | License along with this module; if not, write to the Free Software Foundation, | 13 | License aint with this module; if not, write to the Free Software Foundation, |
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | 14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
15 | 15 | ||
16 | #include "blargg_source.h" | 16 | #include "blargg_source.h" |
17 | 17 | ||
18 | int const osc_count = sms_osc_count + fm_apu_osc_count; | 18 | int const osc_count = sms_osc_count + fm_apu_osc_count; |
19 | 19 | ||
20 | int const stereo = 2; // number of channels for stereo | ||
21 | int const silence_max = 6; // seconds | ||
22 | int const silence_threshold = 0x10; | ||
23 | long const fade_block_size = 512; | ||
24 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
25 | |||
26 | 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"; |
27 | 21 | ||
28 | static void clear_track_vars( struct Sgc_Emu* this ) | 22 | static void clear_track_vars( struct Sgc_Emu* this ) |
29 | { | 23 | { |
30 | this->current_track = -1; | 24 | this->current_track = -1; |
31 | this->out_time = 0; | 25 | track_stop( &this->track_filter ); |
32 | this->emu_time = 0; | ||
33 | this->emu_track_ended_ = true; | ||
34 | this->track_ended = true; | ||
35 | this->fade_start = INT_MAX / 2 + 1; | ||
36 | this->fade_step = 1; | ||
37 | this->silence_time = 0; | ||
38 | this->silence_count = 0; | ||
39 | this->buf_remain = 0; | ||
40 | /* warning(); // clear warning */ | ||
41 | } | 26 | } |
42 | 27 | ||
43 | void Sgc_init( struct Sgc_Emu* this ) | 28 | void Sgc_init( struct Sgc_Emu* this ) |
@@ -48,12 +33,12 @@ void Sgc_init( struct Sgc_Emu* this ) | |||
48 | this->mute_mask_ = 0; | 33 | this->mute_mask_ = 0; |
49 | this->tempo = (int)FP_ONE_TEMPO; | 34 | this->tempo = (int)FP_ONE_TEMPO; |
50 | this->gain = (int)FP_ONE_GAIN; | 35 | this->gain = (int)FP_ONE_GAIN; |
51 | this->voice_count = 0; | ||
52 | 36 | ||
53 | // defaults | 37 | // defaults |
54 | this->max_initial_silence = 2; | 38 | this->tfilter = *track_get_setup( &this->track_filter ); |
55 | this->silence_lookahead = 6; | 39 | this->tfilter.max_initial = 2; |
56 | this->ignore_silence = false; | 40 | this->tfilter.lookahead = 6; |
41 | this->track_filter.silence_ignored_ = false; | ||
57 | 42 | ||
58 | Sms_apu_init( &this->apu ); | 43 | Sms_apu_init( &this->apu ); |
59 | Fm_apu_create( &this->fm_apu ); | 44 | Fm_apu_create( &this->fm_apu ); |
@@ -62,8 +47,10 @@ void Sgc_init( struct Sgc_Emu* this ) | |||
62 | Z80_init( &this->cpu ); | 47 | Z80_init( &this->cpu ); |
63 | 48 | ||
64 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); | 49 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.2) ); |
65 | 50 | ||
66 | // Unload | 51 | // Unload |
52 | this->voice_count = 0; | ||
53 | this->voice_types = 0; | ||
67 | clear_track_vars( this ); | 54 | clear_track_vars( this ); |
68 | } | 55 | } |
69 | 56 | ||
@@ -95,6 +82,10 @@ blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ) | |||
95 | this->m3u.size = 0; | 82 | this->m3u.size = 0; |
96 | this->track_count = this->header.song_count; | 83 | this->track_count = this->header.song_count; |
97 | this->voice_count = sega_mapping( this ) ? osc_count : sms_osc_count; | 84 | this->voice_count = sega_mapping( this ) ? osc_count : sms_osc_count; |
85 | static int const types [osc_count + 1] = { | ||
86 | wave_type+1, wave_type+2, wave_type+3, mixed_type+1, mixed_type+2 | ||
87 | }; | ||
88 | this->voice_types = types; | ||
98 | 89 | ||
99 | Sms_apu_volume( &this->apu, this->gain ); | 90 | Sms_apu_volume( &this->apu, this->gain ); |
100 | Fm_apu_volume( &this->fm_apu, this->gain ); | 91 | Fm_apu_volume( &this->fm_apu, this->gain ); |
@@ -102,10 +93,10 @@ blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ) | |||
102 | // Setup buffer | 93 | // Setup buffer |
103 | this->clock_rate_ = clock_rate( this ); | 94 | this->clock_rate_ = clock_rate( this ); |
104 | Buffer_clock_rate( &this->stereo_buf, clock_rate( this ) ); | 95 | Buffer_clock_rate( &this->stereo_buf, clock_rate( this ) ); |
96 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count, this->voice_types ) ); | ||
105 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 97 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
106 | Sound_set_tempo( this, this->tempo ); | ||
107 | 98 | ||
108 | // Remute voices | 99 | Sound_set_tempo( this, this->tempo ); |
109 | Sound_mute_voices( this, this->mute_mask_ ); | 100 | Sound_mute_voices( this, this->mute_mask_ ); |
110 | return 0; | 101 | return 0; |
111 | } | 102 | } |
@@ -249,7 +240,7 @@ void cpu_write( struct Sgc_Emu* this, addr_t addr, int data ) | |||
249 | } | 240 | } |
250 | } | 241 | } |
251 | 242 | ||
252 | blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, long rate ) | 243 | blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, int rate ) |
253 | { | 244 | { |
254 | require( !this->sample_rate ); // sample rate can't be changed once set | 245 | require( !this->sample_rate ); // sample rate can't be changed once set |
255 | Buffer_init( &this->stereo_buf ); | 246 | Buffer_init( &this->stereo_buf ); |
@@ -259,6 +250,8 @@ blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, long rate ) | |||
259 | Buffer_bass_freq( &this->stereo_buf, 80 ); | 250 | Buffer_bass_freq( &this->stereo_buf, 80 ); |
260 | 251 | ||
261 | this->sample_rate = rate; | 252 | this->sample_rate = rate; |
253 | RETURN_ERR( track_init( &this->track_filter, this ) ); | ||
254 | this->tfilter.max_silence = 6 * stereo * this->sample_rate; | ||
262 | return 0; | 255 | return 0; |
263 | } | 256 | } |
264 | 257 | ||
@@ -286,7 +279,7 @@ void Sound_mute_voices( struct Sgc_Emu* this, int mask ) | |||
286 | } | 279 | } |
287 | else | 280 | else |
288 | { | 281 | { |
289 | struct channel_t ch = Buffer_channel( &this->stereo_buf ); | 282 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); |
290 | assert( (ch.center && ch.left && ch.right) || | 283 | assert( (ch.center && ch.left && ch.right) || |
291 | (!ch.center && !ch.left && !ch.right) ); // all or nothing | 284 | (!ch.center && !ch.left && !ch.right) ); // all or nothing |
292 | Sound_set_voice( this, i, ch.center, ch.left, ch.right ); | 285 | Sound_set_voice( this, i, ch.center, ch.left, ch.right ); |
@@ -306,7 +299,6 @@ void Sound_set_tempo( struct Sgc_Emu* this, int t ) | |||
306 | this->play_period = (int) ((clock_rate( this ) * FP_ONE_TEMPO) / (this->header.rate ? 50 : 60) / t); | 299 | this->play_period = (int) ((clock_rate( this ) * FP_ONE_TEMPO) / (this->header.rate ? 50 : 60) / t); |
307 | } | 300 | } |
308 | 301 | ||
309 | void fill_buf( struct Sgc_Emu* this ); | ||
310 | blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ) | 302 | blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ) |
311 | { | 303 | { |
312 | clear_track_vars( this ); | 304 | clear_track_vars( this ); |
@@ -383,275 +375,90 @@ blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ) | |||
383 | 375 | ||
384 | Buffer_clear( &this->stereo_buf ); | 376 | Buffer_clear( &this->stereo_buf ); |
385 | 377 | ||
386 | this->emu_track_ended_ = false; | 378 | // convert filter times to samples |
387 | this->track_ended = false; | 379 | struct setup_t s = this->tfilter; |
388 | 380 | s.max_initial *= this->sample_rate * stereo; | |
389 | if ( !this->ignore_silence ) | 381 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD |
390 | { | 382 | s.lookahead = 1; |
391 | // play until non-silence or end of track | 383 | #endif |
392 | long end; | 384 | track_setup( &this->track_filter, &s ); |
393 | for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; ) | 385 | |
394 | { | 386 | return track_start( &this->track_filter ); |
395 | fill_buf( this ); | ||
396 | if ( this->buf_remain | (int) this->emu_track_ended_ ) | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | this->emu_time = this->buf_remain; | ||
401 | this->out_time = 0; | ||
402 | this->silence_time = 0; | ||
403 | this->silence_count = 0; | ||
404 | } | ||
405 | /* return track_ended() ? warning() : 0; */ | ||
406 | return 0; | ||
407 | } | 387 | } |
408 | 388 | ||
409 | // Tell/Seek | 389 | // Tell/Seek |
410 | 390 | ||
411 | static blargg_long msec_to_samples( blargg_long msec, long sample_rate ) | 391 | static int msec_to_samples( int msec, int sample_rate ) |
412 | { | 392 | { |
413 | blargg_long sec = msec / 1000; | 393 | int sec = msec / 1000; |
414 | msec -= sec * 1000; | 394 | msec -= sec * 1000; |
415 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; | 395 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; |
416 | } | 396 | } |
417 | 397 | ||
418 | long Track_tell( struct Sgc_Emu* this ) | 398 | int Track_tell( struct Sgc_Emu* this ) |
419 | { | 399 | { |
420 | blargg_long rate = this->sample_rate * stereo; | 400 | int rate = this->sample_rate * stereo; |
421 | blargg_long sec = this->out_time / rate; | 401 | int sec = track_sample_count( &this->track_filter ) / rate; |
422 | return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate; | 402 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; |
423 | } | 403 | } |
424 | 404 | ||
425 | blargg_err_t Track_seek( struct Sgc_Emu* this, long msec ) | 405 | blargg_err_t Track_seek( struct Sgc_Emu* this, int msec ) |
426 | { | 406 | { |
427 | blargg_long time = msec_to_samples( msec, this->sample_rate ); | 407 | int time = msec_to_samples( msec, this->sample_rate ); |
428 | if ( time < this->out_time ) | 408 | if ( time < track_sample_count( &this->track_filter ) ) |
429 | RETURN_ERR( Sgc_start_track( this, this->current_track ) ); | 409 | RETURN_ERR( Sgc_start_track( this, this->current_track ) ); |
430 | return Track_skip( this, time - this->out_time ); | 410 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); |
431 | } | 411 | } |
432 | 412 | ||
433 | blargg_err_t skip_( struct Sgc_Emu* this, long count ); | 413 | blargg_err_t Track_skip( struct Sgc_Emu* this, int count ) |
434 | blargg_err_t Track_skip( struct Sgc_Emu* this, long count ) | ||
435 | { | 414 | { |
436 | require( this->current_track >= 0 ); // start_track() must have been called already | 415 | require( this->current_track >= 0 ); // start_track() must have been called already |
437 | this->out_time += count; | 416 | return track_skip( &this->track_filter, count ); |
438 | |||
439 | // remove from silence and buf first | ||
440 | { | ||
441 | long n = min( count, this->silence_count ); | ||
442 | this->silence_count -= n; | ||
443 | count -= n; | ||
444 | |||
445 | n = min( count, this->buf_remain ); | ||
446 | this->buf_remain -= n; | ||
447 | count -= n; | ||
448 | } | ||
449 | |||
450 | if ( count && !this->emu_track_ended_ ) | ||
451 | { | ||
452 | this->emu_time += count; | ||
453 | |||
454 | // End track if error | ||
455 | if ( skip_( this, count ) ) { | ||
456 | this->emu_track_ended_ = true; | ||
457 | } | ||
458 | } | ||
459 | |||
460 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
461 | this->track_ended |= this->emu_track_ended_; | ||
462 | |||
463 | return 0; | ||
464 | } | 417 | } |
465 | 418 | ||
466 | blargg_err_t play_( struct Sgc_Emu* this, long count, sample_t* out ); | 419 | blargg_err_t skip_( void* emu, int count ) |
467 | blargg_err_t skip_( struct Sgc_Emu* this, long count ) | ||
468 | { | 420 | { |
421 | struct Sgc_Emu* this = (struct Sgc_Emu*) emu; | ||
422 | |||
469 | // for long skip, mute sound | 423 | // for long skip, mute sound |
470 | const long threshold = 30000; | 424 | const int threshold = 32768; |
471 | if ( count > threshold ) | 425 | if ( count > threshold ) |
472 | { | 426 | { |
473 | int saved_mute = this->mute_mask_; | 427 | int saved_mute = this->mute_mask_; |
474 | Sound_mute_voices( this, ~0 ); | 428 | Sound_mute_voices( this, ~0 ); |
475 | |||
476 | while ( count > threshold / 2 && !this->emu_track_ended_ ) | ||
477 | { | ||
478 | RETURN_ERR( play_( this, buf_size, this->buf ) ); | ||
479 | count -= buf_size; | ||
480 | } | ||
481 | |||
482 | Sound_mute_voices( this, saved_mute ); | ||
483 | } | ||
484 | |||
485 | while ( count && !this->emu_track_ended_ ) | ||
486 | { | ||
487 | long n = buf_size; | ||
488 | if ( n > count ) | ||
489 | n = count; | ||
490 | count -= n; | ||
491 | RETURN_ERR( play_( this, n, this->buf ) ); | ||
492 | } | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | // Fading | ||
497 | |||
498 | void Track_set_fade( struct Sgc_Emu* this, long start_msec, long length_msec ) | ||
499 | { | ||
500 | this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo); | ||
501 | this->fade_start = msec_to_samples( start_msec, this->sample_rate ); | ||
502 | } | ||
503 | |||
504 | // unit / pow( 2.0, (double) x / step ) | ||
505 | static int int_log( blargg_long x, int step, int unit ) | ||
506 | { | ||
507 | int shift = x / step; | ||
508 | int fraction = (x - shift * step) * unit / step; | ||
509 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
510 | } | ||
511 | |||
512 | static void handle_fade( struct Sgc_Emu* this, long out_count, sample_t* out ) | ||
513 | { | ||
514 | int i; | ||
515 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
516 | { | ||
517 | int const shift = 14; | ||
518 | int const unit = 1 << shift; | ||
519 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
520 | this->fade_step, unit ); | ||
521 | if ( gain < (unit >> fade_shift) ) | ||
522 | this->track_ended = this->emu_track_ended_ = true; | ||
523 | |||
524 | sample_t* io = &out [i]; | ||
525 | int count; | ||
526 | for ( count = min( fade_block_size, out_count - i ); count; --count ) | ||
527 | { | ||
528 | *io = (sample_t) ((*io * gain) >> shift); | ||
529 | ++io; | ||
530 | } | ||
531 | } | ||
532 | } | ||
533 | 429 | ||
534 | // Silence detection | 430 | int n = count - threshold/2; |
431 | n &= ~(2048-1); // round to multiple of 2048 | ||
432 | count -= n; | ||
433 | RETURN_ERR( skippy_( &this->track_filter, n ) ); | ||
535 | 434 | ||
536 | static void emu_play( struct Sgc_Emu* this, long count, sample_t* out ) | 435 | Sound_mute_voices( this, saved_mute ); |
537 | { | ||
538 | check( this->current_track_ >= 0 ); | ||
539 | this->emu_time += count; | ||
540 | if ( this->current_track >= 0 && !this->emu_track_ended_ ) { | ||
541 | // End track if error | ||
542 | if ( play_( this, count, out ) ) | ||
543 | this->emu_track_ended_ = true; | ||
544 | } | 436 | } |
545 | else | ||
546 | memset( out, 0, count * sizeof *out ); | ||
547 | } | ||
548 | 437 | ||
549 | // number of consecutive silent samples at end | 438 | return skippy_( &this->track_filter, count ); |
550 | static long count_silence( sample_t* begin, long size ) | ||
551 | { | ||
552 | sample_t first = *begin; | ||
553 | *begin = silence_threshold; // sentinel | ||
554 | sample_t* p = begin + size; | ||
555 | while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } | ||
556 | *begin = first; | ||
557 | return size - (p - begin); | ||
558 | } | 439 | } |
559 | 440 | ||
560 | // fill internal buffer and check it for silence | 441 | void Track_set_fade( struct Sgc_Emu* this, int start_msec, int length_msec ) |
561 | void fill_buf( struct Sgc_Emu* this ) | ||
562 | { | 442 | { |
563 | assert( !this->buf_remain ); | 443 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate ), |
564 | if ( !this->emu_track_ended_ ) | 444 | length_msec * this->sample_rate / (1000 / stereo) ); |
565 | { | ||
566 | emu_play( this, buf_size, this->buf ); | ||
567 | long silence = count_silence( this->buf, buf_size ); | ||
568 | if ( silence < buf_size ) | ||
569 | { | ||
570 | this->silence_time = this->emu_time - silence; | ||
571 | this->buf_remain = buf_size; | ||
572 | return; | ||
573 | } | ||
574 | } | ||
575 | this->silence_count += buf_size; | ||
576 | } | 445 | } |
577 | 446 | ||
578 | blargg_err_t Sgc_play( struct Sgc_Emu* this, long out_count, sample_t* out ) | 447 | blargg_err_t Sgc_play( struct Sgc_Emu* this, int out_count, sample_t* out ) |
579 | { | 448 | { |
580 | if ( this->track_ended ) | 449 | require( this->current_track >= 0 ); |
581 | { | 450 | require( out_count % stereo == 0 ); |
582 | memset( out, 0, out_count * sizeof *out ); | 451 | return track_play( &this->track_filter, out_count, out ); |
583 | } | ||
584 | else | ||
585 | { | ||
586 | require( this->current_track >= 0 ); | ||
587 | require( out_count % stereo == 0 ); | ||
588 | |||
589 | assert( this->emu_time >= this->out_time ); | ||
590 | |||
591 | // prints nifty graph of how far ahead we are when searching for silence | ||
592 | //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" ); | ||
593 | |||
594 | long pos = 0; | ||
595 | if ( this->silence_count ) | ||
596 | { | ||
597 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
598 | long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time; | ||
599 | while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) | ||
600 | fill_buf( this ); | ||
601 | |||
602 | // fill with silence | ||
603 | pos = min( this->silence_count, out_count ); | ||
604 | memset( out, 0, pos * sizeof *out ); | ||
605 | this->silence_count -= pos; | ||
606 | |||
607 | if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate ) | ||
608 | { | ||
609 | this->track_ended = this->emu_track_ended_ = true; | ||
610 | this->silence_count = 0; | ||
611 | this->buf_remain = 0; | ||
612 | } | ||
613 | } | ||
614 | |||
615 | if ( this->buf_remain ) | ||
616 | { | ||
617 | // empty silence buf | ||
618 | long n = min( this->buf_remain, out_count - pos ); | ||
619 | memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out ); | ||
620 | this->buf_remain -= n; | ||
621 | pos += n; | ||
622 | } | ||
623 | |||
624 | // generate remaining samples normally | ||
625 | long remain = out_count - pos; | ||
626 | if ( remain ) | ||
627 | { | ||
628 | emu_play( this, remain, out + pos ); | ||
629 | this->track_ended |= this->emu_track_ended_; | ||
630 | |||
631 | if ( !this->ignore_silence || this->out_time > this->fade_start ) | ||
632 | { | ||
633 | // check end for a new run of silence | ||
634 | long silence = count_silence( out + pos, remain ); | ||
635 | if ( silence < remain ) | ||
636 | this->silence_time = this->emu_time - silence; | ||
637 | |||
638 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
639 | fill_buf( this ); // cause silence detection on next play() | ||
640 | } | ||
641 | } | ||
642 | |||
643 | if ( this->out_time > this->fade_start ) | ||
644 | handle_fade( this, out_count, out ); | ||
645 | } | ||
646 | this->out_time += out_count; | ||
647 | return 0; | ||
648 | } | 452 | } |
649 | 453 | ||
650 | blargg_err_t play_( struct Sgc_Emu* this, long count, sample_t* out ) | 454 | blargg_err_t play_( void* emu, int count, sample_t out [] ) |
651 | { | 455 | { |
652 | long remain = count; | 456 | struct Sgc_Emu* this = (struct Sgc_Emu*) emu; |
457 | |||
458 | int remain = count; | ||
653 | while ( remain ) | 459 | while ( remain ) |
654 | { | 460 | { |
461 | Buffer_disable_immediate_removal( &this->stereo_buf ); | ||
655 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); | 462 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); |
656 | if ( remain ) | 463 | if ( remain ) |
657 | { | 464 | { |
diff --git a/apps/codecs/libgme/sgc_emu.h b/apps/codecs/libgme/sgc_emu.h index 779ef2d923..6595c02daf 100644 --- a/apps/codecs/libgme/sgc_emu.h +++ b/apps/codecs/libgme/sgc_emu.h | |||
@@ -12,16 +12,14 @@ | |||
12 | #include "sms_fm_apu.h" | 12 | #include "sms_fm_apu.h" |
13 | #include "sms_apu.h" | 13 | #include "sms_apu.h" |
14 | #include "m3u_playlist.h" | 14 | #include "m3u_playlist.h" |
15 | #include "track_filter.h" | ||
15 | 16 | ||
16 | typedef short sample_t; | ||
17 | typedef struct Z80_Cpu Sgc_Cpu; | 17 | typedef struct Z80_Cpu Sgc_Cpu; |
18 | 18 | ||
19 | enum { buf_size = 2048 }; | ||
20 | |||
21 | // SGC file header | 19 | // SGC file header |
22 | enum { header_size = 0xA0 }; | 20 | enum { header_size = 0xA0 }; |
23 | struct header_t | 21 | struct header_t |
24 | { | 22 | { |
25 | char tag [4]; // "SGC\x1A" | 23 | char tag [4]; // "SGC\x1A" |
26 | byte vers; // 0x01 | 24 | byte vers; // 0x01 |
27 | byte rate; // 0=NTSC 1=PAL | 25 | byte rate; // 0=NTSC 1=PAL |
@@ -48,12 +46,11 @@ struct header_t | |||
48 | static inline bool valid_tag( struct header_t* h ) | 46 | static inline bool valid_tag( struct header_t* h ) |
49 | { | 47 | { |
50 | return 0 == memcmp( h->tag, "SGC\x1A", 4 ); | 48 | return 0 == memcmp( h->tag, "SGC\x1A", 4 ); |
51 | } | 49 | } |
52 | |||
53 | static inline int effect_count( struct header_t* h ) { return h->last_effect ? h->last_effect - h->first_effect + 1 : 0; } | ||
54 | 50 | ||
51 | static inline int effect_count( struct header_t* h ) { return h->last_effect ? h->last_effect - h->first_effect + 1 : 0; } | ||
55 | 52 | ||
56 | struct Sgc_Emu { | 53 | struct Sgc_Emu { |
57 | bool fm_accessed; | 54 | bool fm_accessed; |
58 | 55 | ||
59 | cpu_time_t play_period; | 56 | cpu_time_t play_period; |
@@ -65,40 +62,28 @@ struct Sgc_Emu { | |||
65 | 62 | ||
66 | // general | 63 | // general |
67 | int voice_count; | 64 | int voice_count; |
65 | int const* voice_types; | ||
68 | int mute_mask_; | 66 | int mute_mask_; |
69 | int tempo; | 67 | int tempo; |
70 | int gain; | 68 | int gain; |
71 | 69 | ||
72 | long sample_rate; | 70 | int sample_rate; |
73 | 71 | ||
74 | // track-specific | 72 | // track-specific |
75 | volatile bool track_ended; | ||
76 | int current_track; | 73 | int current_track; |
77 | int track_count; | 74 | int track_count; |
78 | blargg_long out_time; // number of samples played since start of track | 75 | |
79 | blargg_long emu_time; // number of samples emulator has generated since start of track | 76 | int clock_rate_; |
80 | bool emu_track_ended_; // emulator has reached end of track | ||
81 | |||
82 | // fading | ||
83 | blargg_long fade_start; | ||
84 | int fade_step; | ||
85 | |||
86 | // silence detection | ||
87 | bool ignore_silence; | ||
88 | int max_initial_silence; | ||
89 | int silence_lookahead; // speed to run emulator when looking ahead for silence | ||
90 | long silence_time; // number of samples where most recent silence began | ||
91 | long silence_count; // number of samples of silence to play before using buf | ||
92 | long buf_remain; // number of samples left in silence buffer | ||
93 | |||
94 | long clock_rate_; | ||
95 | unsigned buf_changed_count; | 77 | unsigned buf_changed_count; |
96 | 78 | ||
97 | // M3u Playlist | 79 | // M3u Playlist |
98 | struct M3u_Playlist m3u; | 80 | struct M3u_Playlist m3u; |
81 | struct header_t header; | ||
99 | 82 | ||
100 | sample_t buf [buf_size]; | 83 | struct setup_t tfilter; |
101 | struct Stereo_Buffer stereo_buf; | 84 | struct Track_Filter track_filter; |
85 | |||
86 | struct Multi_Buffer stereo_buf; | ||
102 | 87 | ||
103 | struct Sms_Apu apu; | 88 | struct Sms_Apu apu; |
104 | struct Sms_Fm_Apu fm_apu; | 89 | struct Sms_Fm_Apu fm_apu; |
@@ -106,12 +91,11 @@ struct Sgc_Emu { | |||
106 | Sgc_Cpu cpu; | 91 | Sgc_Cpu cpu; |
107 | 92 | ||
108 | // large items | 93 | // large items |
109 | struct header_t header; | ||
110 | struct Rom_Data rom; | 94 | struct Rom_Data rom; |
111 | byte vectors [page_size + page_padding]; | 95 | byte vectors [page_size + page_padding]; |
96 | byte unmapped_write [0x4000]; | ||
112 | byte ram [0x2000 + page_padding]; | 97 | byte ram [0x2000 + page_padding]; |
113 | byte ram2 [0x4000 + page_padding]; | 98 | byte ram2 [0x4000 + page_padding]; |
114 | byte unmapped_write [0x4000]; | ||
115 | }; | 99 | }; |
116 | 100 | ||
117 | // Basic functionality (see Gme_File.h for file loading/track info functions) | 101 | // Basic functionality (see Gme_File.h for file loading/track info functions) |
@@ -119,41 +103,53 @@ struct Sgc_Emu { | |||
119 | void Sgc_init( struct Sgc_Emu* this ); | 103 | void Sgc_init( struct Sgc_Emu* this ); |
120 | 104 | ||
121 | blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ); | 105 | blargg_err_t Sgc_load_mem( struct Sgc_Emu* this, const void* data, long size ); |
122 | 106 | ||
123 | static inline int clock_rate( struct Sgc_Emu* this ) { return this->header.rate ? 3546893 : 3579545; } | 107 | static inline int clock_rate( struct Sgc_Emu* this ) { return this->header.rate ? 3546893 : 3579545; } |
124 | 108 | ||
125 | // 0x2000 bytes | 109 | // 0x2000 bytes |
126 | static inline void set_coleco_bios( struct Sgc_Emu* this, void* p ) { this->coleco_bios = p; } | 110 | static inline void set_coleco_bios( struct Sgc_Emu* this, void* p ) { this->coleco_bios = p; } |
127 | 111 | ||
128 | // Set output sample rate. Must be called only once before loading file. | 112 | // Set output sample rate. Must be called only once before loading file. |
129 | blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, long sample_rate ); | 113 | blargg_err_t Sgc_set_sample_rate( struct Sgc_Emu* this, int sample_rate ); |
130 | 114 | ||
131 | // Start a track, where 0 is the first track. Also clears warning string. | 115 | // Start a track, where 0 is the first track. Also clears warning string. |
132 | blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ); | 116 | blargg_err_t Sgc_start_track( struct Sgc_Emu* this, int track ); |
133 | 117 | ||
134 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation | 118 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation |
135 | // errors set warning string, and major errors also end track. | 119 | // errors set warning string, and major errors also end track. |
136 | blargg_err_t Sgc_play( struct Sgc_Emu* this, long count, sample_t* buf ); | 120 | blargg_err_t Sgc_play( struct Sgc_Emu* this, int count, sample_t* buf ); |
137 | 121 | ||
138 | // Track status/control | 122 | // Track status/control |
139 | 123 | ||
140 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track | 124 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track |
141 | long Track_tell( struct Sgc_Emu* this ); | 125 | int Track_tell( struct Sgc_Emu* this ); |
142 | 126 | ||
143 | // Seek to new time in track. Seeking backwards or far forward can take a while. | 127 | // Seek to new time in track. Seeking backwards or far forward can take a while. |
144 | blargg_err_t Track_seek( struct Sgc_Emu* this, long msec ); | 128 | blargg_err_t Track_seek( struct Sgc_Emu* this, int msec ); |
145 | 129 | ||
146 | // Skip n samples | 130 | // Skip n samples |
147 | blargg_err_t Track_skip( struct Sgc_Emu* this, long n ); | 131 | blargg_err_t Track_skip( struct Sgc_Emu* this, int n ); |
148 | 132 | ||
149 | // Set start time and length of track fade out. Once fade ends track_ended() returns | 133 | // Set start time and length of track fade out. Once fade ends track_ended() returns |
150 | // true. Fade time can be changed while track is playing. | 134 | // true. Fade time can be changed while track is playing. |
151 | void Track_set_fade( struct Sgc_Emu* this, long start_msec, long length_msec ); | 135 | void Track_set_fade( struct Sgc_Emu* this, int start_msec, int length_msec ); |
136 | |||
137 | // True if a track has reached its end | ||
138 | static inline bool Track_ended( struct Sgc_Emu* this ) | ||
139 | { | ||
140 | return track_ended( &this->track_filter ); | ||
141 | } | ||
142 | |||
143 | // Disables automatic end-of-track detection and skipping of silence at beginning | ||
144 | static inline void Track_ignore_silence( struct Sgc_Emu* this, bool disable ) | ||
145 | { | ||
146 | this->track_filter.silence_ignored_ = disable; | ||
147 | } | ||
152 | 148 | ||
153 | // Get track length in milliseconds | 149 | // Get track length in milliseconds |
154 | static inline long Track_get_length( struct Sgc_Emu* this, int n ) | 150 | static inline int Track_get_length( struct Sgc_Emu* this, int n ) |
155 | { | 151 | { |
156 | long length = 120 * 1000; /* 2 minutes */ | 152 | int length = 120 * 1000; /* 2 minutes */ |
157 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { | 153 | if ( (this->m3u.size > 0) && (n < this->m3u.size) ) { |
158 | struct entry_t* entry = &this->m3u.entries [n]; | 154 | struct entry_t* entry = &this->m3u.entries [n]; |
159 | length = entry->length; | 155 | length = entry->length; |
diff --git a/apps/codecs/libgme/sms_apu.c b/apps/codecs/libgme/sms_apu.c index 965e4836c4..379fcf1cbf 100644 --- a/apps/codecs/libgme/sms_apu.c +++ b/apps/codecs/libgme/sms_apu.c | |||
@@ -158,9 +158,7 @@ static void run_until( struct Sms_Apu* this, blip_time_t end_time ) | |||
158 | if ( delta ) | 158 | if ( delta ) |
159 | { | 159 | { |
160 | osc->last_amp = amp; | 160 | osc->last_amp = amp; |
161 | /* norm_synth.offset( last_time, delta, out ); */ | ||
162 | Synth_offset( &this->synth, this->last_time, delta, out ); | 161 | Synth_offset( &this->synth, this->last_time, delta, out ); |
163 | /* out->set_modified(); */ | ||
164 | Blip_set_modified( out ); | 162 | Blip_set_modified( out ); |
165 | } | 163 | } |
166 | } | 164 | } |
@@ -200,7 +198,6 @@ static void run_until( struct Sms_Apu* this, blip_time_t end_time ) | |||
200 | do | 198 | do |
201 | { | 199 | { |
202 | delta = -delta; | 200 | delta = -delta; |
203 | /* norm_synth.offset( time, delta, out ); */ | ||
204 | Synth_offset( &this->synth, time, delta, out ); | 201 | Synth_offset( &this->synth, time, delta, out ); |
205 | time += period; | 202 | time += period; |
206 | } | 203 | } |
@@ -218,7 +215,6 @@ static void run_until( struct Sms_Apu* this, blip_time_t end_time ) | |||
218 | if ( changed & 2 ) // true if bits 0 and 1 differ | 215 | if ( changed & 2 ) // true if bits 0 and 1 differ |
219 | { | 216 | { |
220 | delta = -delta; | 217 | delta = -delta; |
221 | /* fast_synth.offset_inline( time, delta, out ); */ | ||
222 | Synth_offset_inline( &this->synth, time, delta, out ); | 218 | Synth_offset_inline( &this->synth, time, delta, out ); |
223 | } | 219 | } |
224 | time += period; | 220 | time += period; |
diff --git a/apps/codecs/libgme/sms_apu.h b/apps/codecs/libgme/sms_apu.h index f887dc611e..6dd65591ce 100644 --- a/apps/codecs/libgme/sms_apu.h +++ b/apps/codecs/libgme/sms_apu.h | |||
@@ -44,10 +44,10 @@ void Sms_apu_set_output( struct Sms_Apu* this, int i, struct Blip_Buffer* center | |||
44 | 44 | ||
45 | // Emulates to time t, then writes data to Game Gear left/right assignment byte | 45 | // Emulates to time t, then writes data to Game Gear left/right assignment byte |
46 | void Sms_apu_write_ggstereo( struct Sms_Apu* this, blip_time_t t, int data ); | 46 | void Sms_apu_write_ggstereo( struct Sms_Apu* this, blip_time_t t, int data ); |
47 | 47 | ||
48 | // Emulates to time t, then writes data | 48 | // Emulates to time t, then writes data |
49 | void Sms_apu_write_data( struct Sms_Apu* this, blip_time_t t, int data ); | 49 | void Sms_apu_write_data( struct Sms_Apu* this, blip_time_t t, int data ); |
50 | 50 | ||
51 | // Emulates to time t, then subtracts t from the current time. | 51 | // Emulates to time t, then subtracts t from the current time. |
52 | // OK if previous write call had time slightly after t. | 52 | // OK if previous write call had time slightly after t. |
53 | void Sms_apu_end_frame( struct Sms_Apu* this, blip_time_t t ); | 53 | void Sms_apu_end_frame( struct Sms_Apu* this, blip_time_t t ); |
diff --git a/apps/codecs/libgme/sms_fm_apu.h b/apps/codecs/libgme/sms_fm_apu.h index cf8cd6c5cb..00bc2b409c 100644 --- a/apps/codecs/libgme/sms_fm_apu.h +++ b/apps/codecs/libgme/sms_fm_apu.h | |||
@@ -25,19 +25,19 @@ void Fm_apu_create( struct Sms_Fm_Apu* this ); | |||
25 | 25 | ||
26 | static inline bool Fm_apu_supported( void ) { return Ym2413_supported(); } | 26 | static inline bool Fm_apu_supported( void ) { return Ym2413_supported(); } |
27 | blargg_err_t Fm_apu_init( struct Sms_Fm_Apu* this, int clock_rate, int sample_rate ); | 27 | blargg_err_t Fm_apu_init( struct Sms_Fm_Apu* this, int clock_rate, int sample_rate ); |
28 | 28 | ||
29 | static inline void Fm_apu_set_output( struct Sms_Fm_Apu* this, struct Blip_Buffer* b ) | 29 | static inline void Fm_apu_set_output( struct Sms_Fm_Apu* this, struct Blip_Buffer* b ) |
30 | { | 30 | { |
31 | this->output_ = b; | 31 | this->output_ = b; |
32 | } | 32 | } |
33 | 33 | ||
34 | static inline void Fm_apu_volume( struct Sms_Fm_Apu* this, int v ) { Synth_volume( &this->synth, (v*2) / 5 / 4096 ); } | 34 | static inline void Fm_apu_volume( struct Sms_Fm_Apu* this, int v ) { Synth_volume( &this->synth, (v*2) / 5 / 4096 ); } |
35 | 35 | ||
36 | void Fm_apu_reset( struct Sms_Fm_Apu* this ); | 36 | void Fm_apu_reset( struct Sms_Fm_Apu* this ); |
37 | 37 | ||
38 | static inline void Fm_apu_write_addr( struct Sms_Fm_Apu* this, int data ) { this->addr = data; } | 38 | static inline void Fm_apu_write_addr( struct Sms_Fm_Apu* this, int data ) { this->addr = data; } |
39 | void Fm_apu_write_data( struct Sms_Fm_Apu* this, blip_time_t, int data ); | 39 | void Fm_apu_write_data( struct Sms_Fm_Apu* this, blip_time_t, int data ); |
40 | 40 | ||
41 | void Fm_apu_end_frame( struct Sms_Fm_Apu* this, blip_time_t t ); | 41 | void Fm_apu_end_frame( struct Sms_Fm_Apu* this, blip_time_t t ); |
42 | 42 | ||
43 | #endif | 43 | #endif |
diff --git a/apps/codecs/libgme/track_filter.c b/apps/codecs/libgme/track_filter.c new file mode 100644 index 0000000000..f468a8c4b6 --- /dev/null +++ b/apps/codecs/libgme/track_filter.c | |||
@@ -0,0 +1,294 @@ | |||
1 | // Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ | ||
2 | |||
3 | #include "track_filter.h" | ||
4 | |||
5 | /* Copyright (C) 2003-2008 Shay Green. This module is free software; you | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | int const fade_block_size = 512; | ||
19 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
20 | int const silence_threshold = 8; | ||
21 | |||
22 | void track_create( struct Track_Filter* this ) | ||
23 | { | ||
24 | this->emu_ = NULL; | ||
25 | this->setup_.max_initial = 0; | ||
26 | this->setup_.lookahead = 0; | ||
27 | this->setup_.max_silence = indefinite_count; | ||
28 | this->silence_ignored_ = false; | ||
29 | track_stop( this ); | ||
30 | } | ||
31 | |||
32 | blargg_err_t track_init( struct Track_Filter* this, void* emu ) | ||
33 | { | ||
34 | this->emu_ = emu; | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | void clear_time_vars( struct Track_Filter* this ) | ||
39 | { | ||
40 | this->emu_time = this->buf_remain; | ||
41 | this->out_time = 0; | ||
42 | this->silence_time = 0; | ||
43 | this->silence_count = 0; | ||
44 | } | ||
45 | |||
46 | void track_stop( struct Track_Filter* this ) | ||
47 | { | ||
48 | this->emu_track_ended_ = true; | ||
49 | this->track_ended_ = true; | ||
50 | this->fade_start = indefinite_count; | ||
51 | this->fade_step = 1; | ||
52 | this->buf_remain = 0; | ||
53 | this->emu_error = NULL; | ||
54 | clear_time_vars( this ); | ||
55 | } | ||
56 | |||
57 | blargg_err_t track_start( struct Track_Filter* this ) | ||
58 | { | ||
59 | this->emu_error = NULL; | ||
60 | track_stop( this ); | ||
61 | |||
62 | this->emu_track_ended_ = false; | ||
63 | this->track_ended_ = false; | ||
64 | |||
65 | if ( !this->silence_ignored_ ) | ||
66 | { | ||
67 | // play until non-silence or end of track | ||
68 | while ( this->emu_time < this->setup_.max_initial ) | ||
69 | { | ||
70 | fill_buf( this ); | ||
71 | if ( this->buf_remain | this->emu_track_ended_ ) | ||
72 | break; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | clear_time_vars( this ); | ||
77 | return this->emu_error; | ||
78 | } | ||
79 | |||
80 | void end_track_if_error( struct Track_Filter* this, blargg_err_t err ) | ||
81 | { | ||
82 | if ( err ) | ||
83 | { | ||
84 | this->emu_error = err; | ||
85 | this->emu_track_ended_ = true; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | blargg_err_t track_skip( struct Track_Filter* this, int count ) | ||
90 | { | ||
91 | this->emu_error = NULL; | ||
92 | this->out_time += count; | ||
93 | |||
94 | // remove from silence and buf first | ||
95 | { | ||
96 | int n = min( count, this->silence_count ); | ||
97 | this->silence_count -= n; | ||
98 | count -= n; | ||
99 | |||
100 | n = min( count, this->buf_remain ); | ||
101 | this->buf_remain -= n; | ||
102 | count -= n; | ||
103 | } | ||
104 | |||
105 | if ( count && !this->emu_track_ended_ ) | ||
106 | { | ||
107 | this->emu_time += count; | ||
108 | this->silence_time = this->emu_time; // would otherwise be invalid | ||
109 | end_track_if_error( this, skip_( this->emu_, count ) ); | ||
110 | } | ||
111 | |||
112 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
113 | this->track_ended_ |= this->emu_track_ended_; | ||
114 | |||
115 | return this->emu_error; | ||
116 | } | ||
117 | |||
118 | blargg_err_t skippy_( struct Track_Filter* this, int count ) | ||
119 | { | ||
120 | while ( count && !this->emu_track_ended_ ) | ||
121 | { | ||
122 | int n = buf_size; | ||
123 | if ( n > count ) | ||
124 | n = count; | ||
125 | count -= n; | ||
126 | RETURN_ERR( play_( this->emu_, n, this->buf ) ); | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | // Fading | ||
132 | |||
133 | void track_set_fade( struct Track_Filter* this, int start, int length ) | ||
134 | { | ||
135 | this->fade_start = start; | ||
136 | this->fade_step = length / (fade_block_size * fade_shift); | ||
137 | if ( this->fade_step < 1 ) | ||
138 | this->fade_step = 1; | ||
139 | } | ||
140 | |||
141 | bool is_fading( struct Track_Filter* this ) | ||
142 | { | ||
143 | return this->out_time >= this->fade_start && this->fade_start != indefinite_count; | ||
144 | } | ||
145 | |||
146 | // unit / pow( 2.0, (double) x / step ) | ||
147 | static int int_log( int x, int step, int unit ) | ||
148 | { | ||
149 | int shift = x / step; | ||
150 | int fraction = (x - shift * step) * unit / step; | ||
151 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
152 | } | ||
153 | |||
154 | void handle_fade( struct Track_Filter* this, sample_t out [], int out_count ) | ||
155 | { | ||
156 | int i; | ||
157 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
158 | { | ||
159 | int const shift = 14; | ||
160 | int const unit = 1 << shift; | ||
161 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
162 | this->fade_step, unit ); | ||
163 | if ( gain < (unit >> fade_shift) ) | ||
164 | this->track_ended_ = this->emu_track_ended_ = true; | ||
165 | |||
166 | sample_t* io = &out [i]; | ||
167 | for ( int count = min( fade_block_size, out_count - i ); count; --count ) | ||
168 | { | ||
169 | *io = (sample_t) ((*io * gain) >> shift); | ||
170 | ++io; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | // Silence detection | ||
176 | |||
177 | void emu_play( struct Track_Filter* this, sample_t out [], int count ) | ||
178 | { | ||
179 | this->emu_time += count; | ||
180 | if ( !this->emu_track_ended_ ) | ||
181 | end_track_if_error( this, play_( this->emu_, count, out ) ); | ||
182 | else | ||
183 | memset( out, 0, count * sizeof *out ); | ||
184 | } | ||
185 | |||
186 | // number of consecutive silent samples at end | ||
187 | static int count_silence( sample_t begin [], int size ) | ||
188 | { | ||
189 | sample_t first = *begin; | ||
190 | *begin = silence_threshold * 2; // sentinel | ||
191 | sample_t* p = begin + size; | ||
192 | while ( (unsigned) (*--p + silence_threshold) <= (unsigned) silence_threshold * 2 ) { } | ||
193 | *begin = first; | ||
194 | return size - (p - begin); | ||
195 | } | ||
196 | |||
197 | // fill internal buffer and check it for silence | ||
198 | void fill_buf( struct Track_Filter* this ) | ||
199 | { | ||
200 | assert( !this->buf_remain ); | ||
201 | if ( !this->emu_track_ended_ ) | ||
202 | { | ||
203 | emu_play( this, this->buf, buf_size ); | ||
204 | int silence = count_silence( this->buf, buf_size ); | ||
205 | if ( silence < buf_size ) | ||
206 | { | ||
207 | this->silence_time = this->emu_time - silence; | ||
208 | this->buf_remain = buf_size; | ||
209 | return; | ||
210 | } | ||
211 | } | ||
212 | this->silence_count += buf_size; | ||
213 | } | ||
214 | |||
215 | blargg_err_t track_play( struct Track_Filter* this, int out_count, sample_t out [] ) | ||
216 | { | ||
217 | this->emu_error = NULL; | ||
218 | if ( this->track_ended_ ) | ||
219 | { | ||
220 | memset( out, 0, out_count * sizeof *out ); | ||
221 | } | ||
222 | else | ||
223 | { | ||
224 | assert( this->emu_time >= this->out_time ); | ||
225 | |||
226 | // prints nifty graph of how far ahead we are when searching for silence | ||
227 | //dprintf( "%*s \n", int ((emu_time - out_time) * 7 / 44100), "*" ); | ||
228 | |||
229 | // use any remaining silence samples | ||
230 | int pos = 0; | ||
231 | if ( this->silence_count ) | ||
232 | { | ||
233 | if ( !this->silence_ignored_ ) | ||
234 | { | ||
235 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
236 | int ahead_time = this->setup_.lookahead * (this->out_time + out_count - this->silence_time) + | ||
237 | this->silence_time; | ||
238 | while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) | ||
239 | fill_buf( this ); | ||
240 | |||
241 | // end track if sufficient silence has been found | ||
242 | if ( this->emu_time - this->silence_time > this->setup_.max_silence ) | ||
243 | { | ||
244 | this->track_ended_ = this->emu_track_ended_ = true; | ||
245 | this->silence_count = out_count; | ||
246 | this->buf_remain = 0; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | // fill from remaining silence | ||
251 | pos = min( this->silence_count, out_count ); | ||
252 | memset( out, 0, pos * sizeof *out ); | ||
253 | this->silence_count -= pos; | ||
254 | } | ||
255 | |||
256 | // use any remaining samples from buffer | ||
257 | if ( this->buf_remain ) | ||
258 | { | ||
259 | int n = min( this->buf_remain, (int) (out_count - pos) ); | ||
260 | memcpy( out + pos, this->buf + (buf_size - this->buf_remain), n * sizeof *out ); | ||
261 | this->buf_remain -= n; | ||
262 | pos += n; | ||
263 | } | ||
264 | |||
265 | // generate remaining samples normally | ||
266 | int remain = out_count - pos; | ||
267 | if ( remain ) | ||
268 | { | ||
269 | emu_play( this, out + pos, remain ); | ||
270 | this->track_ended_ |= this->emu_track_ended_; | ||
271 | |||
272 | if ( this->silence_ignored_ && !is_fading( this ) ) | ||
273 | { | ||
274 | // if left unupdated, ahead_time could become too large | ||
275 | this->silence_time = this->emu_time; | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | // check end for a new run of silence | ||
280 | int silence = count_silence( out + pos, remain ); | ||
281 | if ( silence < remain ) | ||
282 | this->silence_time = this->emu_time - silence; | ||
283 | |||
284 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
285 | fill_buf( this ); // cause silence detection on next play() | ||
286 | } | ||
287 | } | ||
288 | |||
289 | if ( is_fading( this ) ) | ||
290 | handle_fade( this, out, out_count ); | ||
291 | } | ||
292 | this->out_time += out_count; | ||
293 | return this->emu_error; | ||
294 | } | ||
diff --git a/apps/codecs/libgme/track_filter.h b/apps/codecs/libgme/track_filter.h new file mode 100644 index 0000000000..35049b91bb --- /dev/null +++ b/apps/codecs/libgme/track_filter.h | |||
@@ -0,0 +1,90 @@ | |||
1 | // Removes silence from beginning of track, fades end of track. Also looks ahead | ||
2 | // for excessive silence, and if found, ends track. | ||
3 | |||
4 | // Game_Music_Emu 0.6-pre | ||
5 | #ifndef TRACK_FILTER_H | ||
6 | #define TRACK_FILTER_H | ||
7 | |||
8 | #include "blargg_common.h" | ||
9 | |||
10 | typedef short sample_t; | ||
11 | typedef int sample_count_t; | ||
12 | |||
13 | enum { indefinite_count = INT_MAX/2 + 1 }; | ||
14 | enum { buf_size = 2048 }; | ||
15 | |||
16 | struct setup_t { | ||
17 | sample_count_t max_initial; // maximum silence to strip from beginning of track | ||
18 | sample_count_t max_silence; // maximum silence in middle of track without it ending | ||
19 | int lookahead; // internal speed when looking ahead for silence (2=200% etc.) | ||
20 | }; | ||
21 | |||
22 | struct Track_Filter { | ||
23 | void* emu_; | ||
24 | struct setup_t setup_; | ||
25 | const char* emu_error; | ||
26 | bool silence_ignored_; | ||
27 | |||
28 | // Timing | ||
29 | int out_time; // number of samples played since start of track | ||
30 | int emu_time; // number of samples emulator has generated since start of track | ||
31 | int emu_track_ended_; // emulator has reached end of track | ||
32 | volatile int track_ended_; | ||
33 | |||
34 | // Fading | ||
35 | int fade_start; | ||
36 | int fade_step; | ||
37 | |||
38 | // Silence detection | ||
39 | int silence_time; // absolute number of samples where most recent silence began | ||
40 | int silence_count; // number of samples of silence to play before using buf | ||
41 | int buf_remain; // number of samples left in silence buffer | ||
42 | sample_t buf [buf_size]; | ||
43 | }; | ||
44 | |||
45 | // Initializes filter. Must be done once before using object. | ||
46 | blargg_err_t track_init( struct Track_Filter* this, void* ); | ||
47 | void track_create( struct Track_Filter* this ); | ||
48 | |||
49 | // Gets/sets setup | ||
50 | static inline struct setup_t const* track_get_setup( struct Track_Filter* this ) { return &this->setup_; } | ||
51 | static inline void track_setup( struct Track_Filter* this, struct setup_t const* s ) { this->setup_ = *s; } | ||
52 | |||
53 | // Disables automatic end-of-track detection and skipping of silence at beginning | ||
54 | static inline void track_ignore_silence( struct Track_Filter* this, bool disable ) { this->silence_ignored_ = disable; } | ||
55 | |||
56 | // Clears state and skips initial silence in track | ||
57 | blargg_err_t track_start( struct Track_Filter* this ); | ||
58 | |||
59 | // Sets time that fade starts, and how long until track ends. | ||
60 | void track_set_fade( struct Track_Filter* this, sample_count_t start, sample_count_t length ); | ||
61 | |||
62 | // Generates n samples into buf | ||
63 | blargg_err_t track_play( struct Track_Filter* this, int n, sample_t buf [] ); | ||
64 | |||
65 | // Skips n samples | ||
66 | blargg_err_t track_skip( struct Track_Filter* this, int n ); | ||
67 | |||
68 | // Number of samples played/skipped since start_track() | ||
69 | static inline int track_sample_count( struct Track_Filter* this ) { return this->out_time; } | ||
70 | |||
71 | // True if track ended. Causes are end of source samples, end of fade, | ||
72 | // or excessive silence. | ||
73 | static inline bool track_ended( struct Track_Filter* this ) { return this->track_ended_; } | ||
74 | |||
75 | // Clears state | ||
76 | void track_stop( struct Track_Filter* this ); | ||
77 | |||
78 | // For use by callbacks | ||
79 | |||
80 | // Sets internal "track ended" flag and stops generation of further source samples | ||
81 | static inline void track_set_end( struct Track_Filter* this ) { this->emu_track_ended_ = true; } | ||
82 | |||
83 | // For use by skip_() callback | ||
84 | blargg_err_t skippy_( struct Track_Filter* this, int count ); | ||
85 | void fill_buf( struct Track_Filter* this ); | ||
86 | |||
87 | // Skip and play callbacks | ||
88 | blargg_err_t skip_( void* emu, int count ); | ||
89 | blargg_err_t play_( void* emu, int count, sample_t out [] ); | ||
90 | #endif | ||
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 | } |
diff --git a/apps/codecs/libgme/vgm_emu.h b/apps/codecs/libgme/vgm_emu.h index 773b850a09..8c39482008 100644 --- a/apps/codecs/libgme/vgm_emu.h +++ b/apps/codecs/libgme/vgm_emu.h | |||
@@ -1,11 +1,13 @@ | |||
1 | // Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro VGM music file emulator | 1 | // Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro VGM music file emulator |
2 | 2 | ||
3 | // Game_Music_Emu 0.5.5 | 3 | // Game_Music_Emu 0.6-pre |
4 | #ifndef VGM_EMU_H | 4 | #ifndef VGM_EMU_H |
5 | #define VGM_EMU_H | 5 | #define VGM_EMU_H |
6 | 6 | ||
7 | #include "blargg_common.h" | 7 | #include "blargg_common.h" |
8 | #include "blargg_source.h" | 8 | #include "blargg_source.h" |
9 | |||
10 | #include "track_filter.h" | ||
9 | #include "resampler.h" | 11 | #include "resampler.h" |
10 | #include "multi_buffer.h" | 12 | #include "multi_buffer.h" |
11 | #include "ym2413_emu.h" | 13 | #include "ym2413_emu.h" |
@@ -17,7 +19,6 @@ typedef int fm_time_t; | |||
17 | 19 | ||
18 | enum { fm_time_bits = 12 }; | 20 | enum { fm_time_bits = 12 }; |
19 | enum { blip_time_bits = 12 }; | 21 | enum { blip_time_bits = 12 }; |
20 | enum { buf_size = 2048 }; | ||
21 | 22 | ||
22 | // VGM header format | 23 | // VGM header format |
23 | enum { header_size = 0x40 }; | 24 | enum { header_size = 0x40 }; |
@@ -46,9 +47,9 @@ enum { gme_max_field = 63 }; | |||
46 | struct track_info_t | 47 | struct track_info_t |
47 | { | 48 | { |
48 | /* times in milliseconds; -1 if unknown */ | 49 | /* times in milliseconds; -1 if unknown */ |
49 | long length; | 50 | int length; |
50 | long intro_length; | 51 | int intro_length; |
51 | long loop_length; | 52 | int loop_length; |
52 | 53 | ||
53 | /* empty string if not available */ | 54 | /* empty string if not available */ |
54 | char game [64]; | 55 | char game [64]; |
@@ -63,11 +64,11 @@ struct track_info_t | |||
63 | // YM2413 sound chip emulator. I can provide one I've modified to work with the library. | 64 | // YM2413 sound chip emulator. I can provide one I've modified to work with the library. |
64 | struct Vgm_Emu { | 65 | struct Vgm_Emu { |
65 | int fm_rate; | 66 | int fm_rate; |
66 | long psg_rate; | 67 | int psg_rate; |
67 | long vgm_rate; | 68 | int vgm_rate; |
68 | bool disable_oversampling; | 69 | bool disable_oversampling; |
69 | 70 | ||
70 | long fm_time_offset; | 71 | int fm_time_offset; |
71 | int fm_time_factor; | 72 | int fm_time_factor; |
72 | 73 | ||
73 | int blip_time_factor; | 74 | int blip_time_factor; |
@@ -84,47 +85,34 @@ struct Vgm_Emu { | |||
84 | int dac_amp; | 85 | int dac_amp; |
85 | int dac_disabled; // -1 if disabled | 86 | int dac_disabled; // -1 if disabled |
86 | 87 | ||
87 | struct Blip_Buffer blip_buf; | ||
88 | |||
89 | // general | 88 | // general |
90 | long clock_rate_; | 89 | int current_track; |
90 | int clock_rate_; | ||
91 | unsigned buf_changed_count; | 91 | unsigned buf_changed_count; |
92 | int max_initial_silence; | 92 | int max_initial_silence; |
93 | int voice_count; | 93 | int voice_count; |
94 | int const *voice_types; | ||
94 | int mute_mask_; | 95 | int mute_mask_; |
95 | int tempo; | 96 | int tempo; |
96 | int gain; | 97 | int gain; |
97 | 98 | ||
98 | long sample_rate; | 99 | int sample_rate; |
99 | |||
100 | // track-specific | ||
101 | blargg_long out_time; // number of samples played since start of track | ||
102 | blargg_long emu_time; // number of samples emulator has generated since start of track | ||
103 | bool emu_track_ended_; // emulator has reached end of track | ||
104 | volatile bool track_ended; | ||
105 | |||
106 | // fading | ||
107 | blargg_long fade_start; | ||
108 | int fade_step; | ||
109 | |||
110 | // silence detection | ||
111 | int silence_lookahead; // speed to run emulator when looking ahead for silence | ||
112 | bool ignore_silence; | ||
113 | long silence_time; // number of samples where most recent silence began | ||
114 | long silence_count; // number of samples of silence to play before using buf | ||
115 | long buf_remain; // number of samples left in silence buffer | ||
116 | 100 | ||
117 | // larger items at the end | 101 | // larger items at the end |
118 | struct track_info_t info; | 102 | struct track_info_t info; |
119 | sample_t buf_ [buf_size]; | 103 | |
104 | struct setup_t tfilter; | ||
105 | struct Track_Filter track_filter; | ||
120 | 106 | ||
121 | struct Ym2612_Emu ym2612; | 107 | struct Ym2612_Emu ym2612; |
122 | struct Ym2413_Emu ym2413; | 108 | struct Ym2413_Emu ym2413; |
123 | 109 | ||
124 | struct Sms_Apu psg; | 110 | struct Sms_Apu psg; |
125 | struct Blip_Synth pcm; | 111 | struct Blip_Synth pcm; |
112 | struct Blip_Buffer blip_buf; | ||
113 | |||
126 | struct Resampler resampler; | 114 | struct Resampler resampler; |
127 | struct Stereo_Buffer buf; | 115 | struct Multi_Buffer stereo_buf; |
128 | }; | 116 | }; |
129 | 117 | ||
130 | void Vgm_init( struct Vgm_Emu* this ); | 118 | void Vgm_init( struct Vgm_Emu* this ); |
@@ -135,7 +123,7 @@ static inline void Vgm_disable_oversampling( struct Vgm_Emu* this, bool disable | |||
135 | 123 | ||
136 | // Header for currently loaded file | 124 | // Header for currently loaded file |
137 | static inline struct header_t *header( struct Vgm_Emu* this ) { return (struct header_t*) this->file_begin; } | 125 | static inline struct header_t *header( struct Vgm_Emu* this ) { return (struct header_t*) this->file_begin; } |
138 | 126 | ||
139 | // Basic functionality (see Gme_File.h for file loading/track info functions) | 127 | // Basic functionality (see Gme_File.h for file loading/track info functions) |
140 | blargg_err_t Vgm_load_mem( struct Vgm_Emu* this, byte const* new_data, long new_size, bool parse_info ); | 128 | blargg_err_t Vgm_load_mem( struct Vgm_Emu* this, byte const* new_data, long new_size, bool parse_info ); |
141 | 129 | ||
@@ -144,34 +132,46 @@ blargg_err_t Vgm_load_mem( struct Vgm_Emu* this, byte const* new_data, long new_ | |||
144 | static inline bool uses_fm( struct Vgm_Emu* this ) { return Ym2612_enabled( &this->ym2612 ) || Ym2413_enabled( &this->ym2413 ); } | 132 | static inline bool uses_fm( struct Vgm_Emu* this ) { return Ym2612_enabled( &this->ym2612 ) || Ym2413_enabled( &this->ym2413 ); } |
145 | 133 | ||
146 | // Set output sample rate. Must be called only once before loading file. | 134 | // Set output sample rate. Must be called only once before loading file. |
147 | blargg_err_t Vgm_set_sample_rate( struct Vgm_Emu* this, long sample_rate ); | 135 | blargg_err_t Vgm_set_sample_rate( struct Vgm_Emu* this, int sample_rate ); |
148 | 136 | ||
149 | // Start a track, where 0 is the first track. Also clears warning string. | 137 | // Start a track, where 0 is the first track. Also clears warning string. |
150 | blargg_err_t Vgm_start_track( struct Vgm_Emu* this ); | 138 | blargg_err_t Vgm_start_track( struct Vgm_Emu* this ); |
151 | 139 | ||
152 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation | 140 | // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation |
153 | // errors set warning string, and major errors also end track. | 141 | // errors set warning string, and major errors also end track. |
154 | blargg_err_t Vgm_play( struct Vgm_Emu* this, long count, sample_t* buf ); | 142 | blargg_err_t Vgm_play( struct Vgm_Emu* this, int count, sample_t* buf ); |
155 | 143 | ||
156 | // Track status/control | 144 | // Track status/control |
157 | 145 | ||
158 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track | 146 | // Number of milliseconds (1000 msec = 1 second) played since beginning of track |
159 | long Track_tell( struct Vgm_Emu* this ); | 147 | int Track_tell( struct Vgm_Emu* this ); |
160 | 148 | ||
161 | // Seek to new time in track. Seeking backwards or far forward can take a while. | 149 | // Seek to new time in track. Seeking backwards or far forward can take a while. |
162 | blargg_err_t Track_seek( struct Vgm_Emu* this, long msec ); | 150 | blargg_err_t Track_seek( struct Vgm_Emu* this, int msec ); |
163 | 151 | ||
164 | // Skip n samples | 152 | // Skip n samples |
165 | blargg_err_t Track_skip( struct Vgm_Emu* this, long n ); | 153 | blargg_err_t Track_skip( struct Vgm_Emu* this, int n ); |
166 | 154 | ||
167 | // Set start time and length of track fade out. Once fade ends track_ended() returns | 155 | // Set start time and length of track fade out. Once fade ends track_ended() returns |
168 | // true. Fade time can be changed while track is playing. | 156 | // true. Fade time can be changed while track is playing. |
169 | void Track_set_fade( struct Vgm_Emu* this, long start_msec, long length_msec ); | 157 | void Track_set_fade( struct Vgm_Emu* this, int start_msec, int length_msec ); |
158 | |||
159 | // True if a track has reached its end | ||
160 | static inline bool Track_ended( struct Vgm_Emu* this ) | ||
161 | { | ||
162 | return track_ended( &this->track_filter ); | ||
163 | } | ||
164 | |||
165 | // Disables automatic end-of-track detection and skipping of silence at beginning | ||
166 | static inline void Track_ignore_silence( struct Vgm_Emu* this, bool disable ) | ||
167 | { | ||
168 | this->track_filter.silence_ignored_ = disable; | ||
169 | } | ||
170 | 170 | ||
171 | // Get track length in milliseconds | 171 | // Get track length in milliseconds |
172 | static inline long Track_get_length( struct Vgm_Emu* this ) | 172 | static inline int Track_get_length( struct Vgm_Emu* this ) |
173 | { | 173 | { |
174 | long length = this->info.length; | 174 | int length = this->info.length; |
175 | if ( length <= 0 ) | 175 | if ( length <= 0 ) |
176 | { | 176 | { |
177 | length = this->info.intro_length + 2 * this->info.loop_length; // intro + 2 loops | 177 | length = this->info.intro_length + 2 * this->info.loop_length; // intro + 2 loops |
@@ -181,20 +181,20 @@ static inline long Track_get_length( struct Vgm_Emu* this ) | |||
181 | 181 | ||
182 | return length; | 182 | return length; |
183 | } | 183 | } |
184 | 184 | ||
185 | // Sound customization | 185 | // Sound customization |
186 | 186 | ||
187 | // Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. | 187 | // Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. |
188 | // Track length as returned by track_info() assumes a tempo of 1.0. | 188 | // Track length as returned by track_info() assumes a tempo of 1.0. |
189 | void Sound_set_tempo( struct Vgm_Emu* this, int t ); | 189 | void Sound_set_tempo( struct Vgm_Emu* this, int t ); |
190 | 190 | ||
191 | // Mute/unmute voice i, where voice 0 is first voice | 191 | // Mute/unmute voice i, where voice 0 is first voice |
192 | void Sound_mute_voice( struct Vgm_Emu* this, int index, bool mute ); | 192 | void Sound_mute_voice( struct Vgm_Emu* this, int index, bool mute ); |
193 | 193 | ||
194 | // Set muting state of all voices at once using a bit mask, where -1 mutes them all, | 194 | // Set muting state of all voices at once using a bit mask, where -1 mutes them all, |
195 | // 0 unmutes them all, 0x01 mutes just the first voice, etc. | 195 | // 0 unmutes them all, 0x01 mutes just the first voice, etc. |
196 | void Sound_mute_voices( struct Vgm_Emu* this, int mask ); | 196 | void Sound_mute_voices( struct Vgm_Emu* this, int mask ); |
197 | 197 | ||
198 | // Change overall output amplitude, where 1.0 results in minimal clamping. | 198 | // Change overall output amplitude, where 1.0 results in minimal clamping. |
199 | // Must be called before set_sample_rate(). | 199 | // Must be called before set_sample_rate(). |
200 | static inline void Sound_set_gain( struct Vgm_Emu* this, int g ) | 200 | static inline void Sound_set_gain( struct Vgm_Emu* this, int g ) |
@@ -203,5 +203,4 @@ static inline void Sound_set_gain( struct Vgm_Emu* this, int g ) | |||
203 | this->gain = g; | 203 | this->gain = g; |
204 | } | 204 | } |
205 | 205 | ||
206 | |||
207 | #endif | 206 | #endif |
diff --git a/apps/codecs/libgme/ym2612_emu.c b/apps/codecs/libgme/ym2612_emu.c index a1f96e3d70..ee7947ef3b 100644 --- a/apps/codecs/libgme/ym2612_emu.c +++ b/apps/codecs/libgme/ym2612_emu.c | |||
@@ -4,7 +4,6 @@ | |||
4 | 4 | ||
5 | #include "ym2612_emu.h" | 5 | #include "ym2612_emu.h" |
6 | 6 | ||
7 | #include <assert.h> | ||
8 | #include <stdlib.h> | 7 | #include <stdlib.h> |
9 | #include <string.h> | 8 | #include <string.h> |
10 | #include <limits.h> | 9 | #include <limits.h> |
diff --git a/apps/codecs/nsf.c b/apps/codecs/nsf.c index 533972e110..7214b5d2a2 100644 --- a/apps/codecs/nsf.c +++ b/apps/codecs/nsf.c | |||
@@ -74,8 +74,8 @@ enum codec_status codec_run(void) | |||
74 | return CODEC_ERROR; | 74 | return CODEC_ERROR; |
75 | } | 75 | } |
76 | 76 | ||
77 | if ((err = Nsf_load(&nsf_emu, buf, ci->filesize))) { | 77 | if ((err = Nsf_load_mem(&nsf_emu, buf, ci->filesize))) { |
78 | DEBUGF("NSF: Nsf_load failed (%s)\n", err); | 78 | DEBUGF("NSF: Nsf_load_mem failed (%s)\n", err); |
79 | return CODEC_ERROR; | 79 | return CODEC_ERROR; |
80 | } | 80 | } |
81 | 81 | ||
@@ -116,7 +116,7 @@ next_track: | |||
116 | 116 | ||
117 | /* Generate audio buffer */ | 117 | /* Generate audio buffer */ |
118 | err = Nsf_play(&nsf_emu, CHUNK_SIZE, samples); | 118 | err = Nsf_play(&nsf_emu, CHUNK_SIZE, samples); |
119 | if (err || nsf_emu.track_ended) { | 119 | if (err || Track_ended(&nsf_emu)) { |
120 | track++; | 120 | track++; |
121 | if (track >= nsf_emu.track_count) break; | 121 | if (track >= nsf_emu.track_count) break; |
122 | goto next_track; | 122 | goto next_track; |
diff --git a/apps/codecs/sgc.c b/apps/codecs/sgc.c index 993c606c7e..348a54a2d3 100644 --- a/apps/codecs/sgc.c +++ b/apps/codecs/sgc.c | |||
@@ -83,7 +83,7 @@ enum codec_status codec_run(void) | |||
83 | } | 83 | } |
84 | 84 | ||
85 | if ((err = Sgc_load_mem(&sgc_emu, buf, ci->filesize))) { | 85 | if ((err = Sgc_load_mem(&sgc_emu, buf, ci->filesize))) { |
86 | DEBUGF("SGC: Sgc_load failed (%s)\n", err); | 86 | DEBUGF("SGC: Sgc_load_mem failed (%s)\n", err); |
87 | return CODEC_ERROR; | 87 | return CODEC_ERROR; |
88 | } | 88 | } |
89 | 89 | ||
@@ -110,7 +110,7 @@ next_track: | |||
110 | 110 | ||
111 | /* Generate audio buffer */ | 111 | /* Generate audio buffer */ |
112 | err = Sgc_play(&sgc_emu, CHUNK_SIZE, samples); | 112 | err = Sgc_play(&sgc_emu, CHUNK_SIZE, samples); |
113 | if (err || sgc_emu.track_ended) { | 113 | if (err || Track_ended(&sgc_emu)) { |
114 | track++; | 114 | track++; |
115 | if (track >= sgc_emu.track_count) break; | 115 | if (track >= sgc_emu.track_count) break; |
116 | goto next_track; | 116 | goto next_track; |
diff --git a/apps/codecs/vgm.c b/apps/codecs/vgm.c index 9e4f88779c..d7390291e1 100644 --- a/apps/codecs/vgm.c +++ b/apps/codecs/vgm.c | |||
@@ -130,7 +130,7 @@ enum codec_status codec_run(void) | |||
130 | 130 | ||
131 | /* Generate audio buffer */ | 131 | /* Generate audio buffer */ |
132 | err = Vgm_play(&vgm_emu, CHUNK_SIZE, samples); | 132 | err = Vgm_play(&vgm_emu, CHUNK_SIZE, samples); |
133 | if (err || vgm_emu.track_ended) break; | 133 | if (err || Track_ended(&vgm_emu)) break; |
134 | 134 | ||
135 | ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE >> 1); | 135 | ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE >> 1); |
136 | 136 | ||