summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/nsf_emu.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/nsf_emu.c')
-rw-r--r--apps/codecs/libgme/nsf_emu.c1105
1 files changed, 1105 insertions, 0 deletions
diff --git a/apps/codecs/libgme/nsf_emu.c b/apps/codecs/libgme/nsf_emu.c
new file mode 100644
index 0000000000..c805780cb1
--- /dev/null
+++ b/apps/codecs/libgme/nsf_emu.c
@@ -0,0 +1,1105 @@
1// Game_Music_Emu 0.5.5. http://www.slack.net/~ant/
2
3#include "nsf_emu.h"
4#include "multi_buffer.h"
5
6#include "blargg_endian.h"
7
8/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. This
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19#include "blargg_source.h"
20
21const char gme_wrong_file_type [] ICONST_ATTR = "Wrong file type for this emulator";
22long const clock_divisor = 12;
23
24int const stereo = 2; // number of channels for stereo
25int const silence_max = 6; // seconds
26int const silence_threshold = 0x10;
27long const fade_block_size = 512;
28int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
29
30// number of frames until play interrupts init
31int const initial_play_delay = 7; // KikiKaikai needed this to work
32int const rom_addr = 0x8000;
33
34void clear_track_vars( struct Nsf_Emu* this )
35{
36 this->current_track = -1;
37 this->out_time = 0;
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}
47
48static int pcm_read( void* emu, addr_t addr )
49{
50 return *Cpu_get_code( &((struct Nsf_Emu*) emu)->cpu, addr );
51}
52
53void Nsf_init( struct Nsf_Emu* this )
54{
55 this->sample_rate = 0;
56 this->mute_mask_ = 0;
57 this->tempo = 1.0;
58 this->gain = 1.0;
59
60 // defaults
61 this->max_initial_silence = 2;
62 this->ignore_silence = false;
63 this->voice_count = 0;
64
65 // Set sound gain
66 Sound_set_gain( this, 1.2 );
67
68 // Unload
69 clear_track_vars( this );
70
71 // Init rom
72 Rom_init( &this->rom, 0x1000 );
73
74 // Init & clear nsfe info
75 Info_init( &this->info );
76 Info_unload( &this->info ); // TODO: extremely hacky!
77
78 Cpu_init( &this->cpu );
79 Apu_init( &this->apu );
80 Apu_dmc_reader( &this->apu, pcm_read, this );
81}
82
83// Setup
84
85blargg_err_t init_sound( struct Nsf_Emu* this )
86{
87 /* if ( header_.chip_flags & ~(fds_flag | namco_flag | vrc6_flag | fme7_flag) )
88 warning( "Uses unsupported audio expansion hardware" ); **/
89
90 this->voice_count = apu_osc_count;
91
92 double adjusted_gain = 1.0 / 0.75 * this->gain;
93
94 #ifdef NSF_EMU_APU_ONLY
95 {
96 if ( this->header_.chip_flags )
97 set_warning( "Uses unsupported audio expansion hardware" );
98 }
99 #else
100 {
101 if ( vrc6_enabled( this ) )
102 {
103 Vrc6_init( &this->vrc6 );
104 adjusted_gain *= 0.75;
105
106 this->voice_count += vrc6_osc_count;
107 }
108
109 if ( fme7_enabled( this ) )
110 {
111 Fme7_init( &this->fme7 );
112 adjusted_gain *= 0.75;
113
114 this->voice_count += fme7_osc_count;
115 }
116
117 if ( mmc5_enabled( this ) )
118 {
119 Mmc5_init( &this->mmc5 );
120 adjusted_gain *= 0.75;
121
122 this->voice_count += mmc5_osc_count;
123 }
124
125 if ( fds_enabled( this ) )
126 {
127 Fds_init( &this->fds );
128 adjusted_gain *= 0.75;
129
130 this->voice_count += fds_osc_count ;
131 }
132
133 if ( namco_enabled( this ) )
134 {
135 Namco_init( &this->namco );
136 adjusted_gain *= 0.75;
137
138 this->voice_count += namco_osc_count;
139 }
140
141 if ( vrc7_enabled( this ) )
142 {
143 #ifndef NSF_EMU_NO_VRC7
144 Vrc7_init( &this->vrc7 );
145 Vrc7_set_rate( &this->vrc7, this->sample_rate );
146 #endif
147
148 adjusted_gain *= 0.75;
149
150 this->voice_count += vrc7_osc_count;
151 }
152
153 if ( vrc7_enabled( this ) ) Vrc7_volume( &this->vrc7, adjusted_gain );
154 if ( namco_enabled( this ) ) Namco_volume( &this->namco, adjusted_gain );
155 if ( vrc6_enabled( this ) ) Vrc6_volume( &this->vrc6, adjusted_gain );
156 if ( fme7_enabled( this ) ) Fme7_volume( &this->fme7, adjusted_gain );
157 if ( mmc5_enabled( this ) ) Apu_volume( &this->mmc5.apu, adjusted_gain );
158 if ( fds_enabled( this ) ) Fds_volume( &this->fds, adjusted_gain );
159 }
160 #endif
161
162 if ( adjusted_gain > this->gain )
163 adjusted_gain = this->gain;
164
165 Apu_volume( &this->apu, adjusted_gain );
166
167 return 0;
168}
169
170// Header stuff
171bool valid_tag( struct header_t* this )
172{
173 return 0 == memcmp( this->tag, "NESM\x1A", 5 );
174}
175
176// True if file supports only PAL speed
177static bool pal_only( struct header_t* this )
178{
179 return (this->speed_flags & 3) == 1;
180}
181
182static double clock_rate( struct header_t* this )
183{
184 return pal_only( this ) ? 1662607.125 : 1789772.727272727;
185}
186
187int play_period( struct header_t* this )
188{
189 // NTSC
190 int clocks = 29780;
191 int value = 0x411A;
192 byte const* rate_ptr = this->ntsc_speed;
193
194 // PAL
195 if ( pal_only( this ) )
196 {
197 clocks = 33247;
198 value = 0x4E20;
199 rate_ptr = this->pal_speed;
200 }
201
202 // Default rate
203 int rate = get_le16( rate_ptr );
204 if ( rate == 0 )
205 rate = value;
206
207 // Custom rate
208 if ( rate != value )
209 clocks = (int) (rate * clock_rate( this ) * (1.0/1000000.0));
210
211 return clocks;
212}
213
214// Gets address, given pointer to it in file header. If zero, returns rom_addr.
215addr_t get_addr( byte const in [] )
216{
217 addr_t addr = get_le16( in );
218 if ( addr == 0 )
219 addr = rom_addr;
220 return addr;
221}
222
223static blargg_err_t check_nsf_header( struct header_t* h )
224{
225 if ( !valid_tag( h ) )
226 return gme_wrong_file_type;
227 return 0;
228}
229
230blargg_err_t Nsf_load( struct Nsf_Emu* this, void* data, long size )
231{
232 // Unload
233 Info_unload( &this->info ); // TODO: extremely hacky!
234 this->m3u.size = 0;
235
236 this->voice_count = 0;
237 clear_track_vars( this );
238
239 assert( offsetof (struct header_t,unused [4]) == header_size );
240
241 if ( !memcmp( data, "NESM\x1A", 5 ) ) {
242 Nsf_disable_playlist( this, true );
243
244 RETURN_ERR( Rom_load( &this->rom, data, size, header_size, &this->header, 0 ) );
245 return Nsf_post_load( this );
246 }
247
248 blargg_err_t err = Info_load( &this->info, data, size, this );
249 Nsf_disable_playlist( this, false );
250 return err;
251}
252
253blargg_err_t Nsf_post_load( struct Nsf_Emu* this )
254{
255 RETURN_ERR( check_nsf_header( &this->header ) );
256
257 /* if ( header_.vers != 1 )
258 warning( "Unknown file version" ); */
259
260 // set up data
261 addr_t load_addr = get_le16( this->header.load_addr );
262
263 /* if ( load_addr < (fds_enabled() ? sram_addr : rom_addr) )
264 warning( "Load address is too low" ); */
265
266 Rom_set_addr( &this->rom, load_addr % this->rom.bank_size );
267
268 /* if ( header_.vers != 1 )
269 warning( "Unknown file version" ); */
270
271 set_play_period( this, play_period( &this->header ) );
272
273 // sound and memory
274 blargg_err_t err = init_sound( this );
275 if ( err )
276 return err;
277
278 // Post load
279 Sound_set_tempo( this, this->tempo );
280
281 // Remute voices
282 Sound_mute_voices( this, this->mute_mask_ );
283
284 // Set track_count
285 this->track_count = this->header.track_count;
286
287 // Change clock rate & setup buffer
288 this->clock_rate__ = (long) (clock_rate( &this->header ) + 0.5);
289 Buffer_clock_rate( &this->stereo_buf, this->clock_rate__ );
290 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
291 return 0;
292}
293
294void Nsf_disable_playlist( struct Nsf_Emu* this, bool b )
295{
296 Info_disable_playlist( &this->info, b );
297 this->track_count = this->info.track_count;
298}
299
300void Nsf_clear_playlist( struct Nsf_Emu* this )
301{
302 Nsf_disable_playlist( this, true );
303}
304
305void write_bank( struct Nsf_Emu* this, int bank, int data )
306{
307 // Find bank in ROM
308 int offset = mask_addr( data * this->rom.bank_size, this->rom.mask );
309 /* if ( offset >= rom.size() )
310 warning( "invalid bank" ); */
311 void const* rom_data = Rom_at_addr( &this->rom, offset );
312
313 #ifndef NSF_EMU_APU_ONLY
314 if ( bank < bank_count - fds_banks && fds_enabled( this ) )
315 {
316 // TODO: FDS bank switching is kind of hacky, might need to
317 // treat ROM as RAM so changes won't get lost when switching.
318 byte* out = sram( this );
319 if ( bank >= fds_banks )
320 {
321 out = fdsram( this );
322 bank -= fds_banks;
323 }
324 memcpy( &out [bank * this->rom.bank_size], rom_data, this->rom.bank_size );
325 return;
326 }
327 #endif
328
329 if ( bank >= fds_banks )
330 Cpu_map_code( &this->cpu, (bank + 6) * this->rom.bank_size, this->rom.bank_size, rom_data, false );
331}
332
333void map_memory( struct Nsf_Emu* this )
334{
335 // Map standard things
336 Cpu_reset( &this->cpu, unmapped_code( this ) );
337 Cpu_map_code( &this->cpu, 0, 0x2000, this->low_ram, low_ram_size ); // mirrored four times
338 Cpu_map_code( &this->cpu, sram_addr, sram_size, sram( this ), 0 );
339
340 // Determine initial banks
341 byte banks [bank_count];
342 static byte const zero_banks [sizeof this->header.banks] = { 0 };
343 if ( memcmp( this->header.banks, zero_banks, sizeof zero_banks ) )
344 {
345 banks [0] = this->header.banks [6];
346 banks [1] = this->header.banks [7];
347 memcpy( banks + fds_banks, this->header.banks, sizeof this->header.banks );
348 }
349 else
350 {
351 // No initial banks, so assign them based on load_addr
352 int i, first_bank = (get_addr( this->header.load_addr ) - sram_addr) / this->rom.bank_size;
353 unsigned total_banks = this->rom.size / this->rom.bank_size;
354 for ( i = bank_count; --i >= 0; )
355 {
356 int bank = i - first_bank;
357 if ( (unsigned) bank >= total_banks )
358 bank = 0;
359 banks [i] = bank;
360 }
361 }
362
363 // Map banks
364 int i;
365 for ( i = (fds_enabled( this ) ? 0 : fds_banks); i < bank_count; ++i )
366 write_bank( this, i, banks [i] );
367
368 // Map FDS RAM
369 if ( fds_enabled( this ) )
370 Cpu_map_code( &this->cpu, rom_addr, fdsram_size, fdsram( this ), 0 );
371}
372
373void set_voice( struct Nsf_Emu* this, int i, struct Blip_Buffer* buf, struct Blip_Buffer* left, struct Blip_Buffer* right)
374{
375#if defined(ROCKBOX)
376 (void) left;
377 (void) right;
378#endif
379
380 if ( i < apu_osc_count )
381 {
382 Apu_osc_output( &this->apu, i, buf );
383 return;
384 }
385 i -= apu_osc_count;
386
387 #ifndef NSF_EMU_APU_ONLY
388 {
389 if ( vrc6_enabled( this ) && (i -= vrc6_osc_count) < 0 )
390 {
391 Vrc6_osc_output( &this->vrc6, i + vrc6_osc_count, buf );
392 return;
393 }
394
395 if ( fme7_enabled( this ) && (i -= fme7_osc_count) < 0 )
396 {
397 Fme7_osc_output( &this->fme7, i + fme7_osc_count, buf );
398 return;
399 }
400
401 if ( mmc5_enabled( this ) && (i -= mmc5_osc_count) < 0 )
402 {
403 Mmc5_set_output( &this->mmc5, i + mmc5_osc_count, buf );
404 return;
405 }
406
407 if ( fds_enabled( this ) && (i -= fds_osc_count) < 0 )
408 {
409 Fds_set_output( &this->fds, i + fds_osc_count, buf );
410 return;
411 }
412
413 if ( namco_enabled( this ) && (i -= namco_osc_count) < 0 )
414 {
415 Namco_osc_output( &this->namco, i + namco_osc_count, buf );
416 return;
417 }
418
419 if ( vrc7_enabled( this ) && (i -= vrc7_osc_count) < 0 )
420 {
421 Vrc7_set_output( &this->vrc7, i + vrc7_osc_count, buf );
422 return;
423 }
424 }
425 #endif
426}
427
428// Emulation
429
430// Music Emu
431
432blargg_err_t Nsf_set_sample_rate( struct Nsf_Emu* this, long rate )
433{
434 require( !this->sample_rate ); // sample rate can't be changed once set
435 Buffer_init( &this->stereo_buf );
436 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) );
437
438 // Set bass frequency
439 Buffer_bass_freq( &this->stereo_buf, 80 );
440
441 this->sample_rate = rate;
442 return 0;
443}
444
445void Sound_mute_voice( struct Nsf_Emu* this, int index, bool mute )
446{
447 require( (unsigned) index < (unsigned) this->voice_count );
448 int bit = 1 << index;
449 int mask = this->mute_mask_ | bit;
450 if ( !mute )
451 mask ^= bit;
452 Sound_mute_voices( this, mask );
453}
454
455void Sound_mute_voices( struct Nsf_Emu* this, int mask )
456{
457 require( this->sample_rate ); // sample rate must be set first
458 this->mute_mask_ = mask;
459
460 int i;
461 for ( i = this->voice_count; i--; )
462 {
463 if ( mask & (1 << i) )
464 {
465 set_voice( this, i, 0, 0, 0 );
466 }
467 else
468 {
469 struct channel_t ch = Buffer_channel( &this->stereo_buf );
470 assert( (ch.center && ch.left && ch.right) ||
471 (!ch.center && !ch.left && !ch.right) ); // all or nothing
472 set_voice( this, i, ch.center, ch.left, ch.right );
473 }
474 }
475}
476
477void Sound_set_tempo( struct Nsf_Emu* this, double t )
478{
479 require( this->sample_rate ); // sample rate must be set first
480 double const min = 0.02;
481 double const max = 4.00;
482 if ( t < min ) t = min;
483 if ( t > max ) t = max;
484 this->tempo = t;
485
486 set_play_period( this, (int) (play_period( &this->header ) / t) );
487
488 Apu_set_tempo( &this->apu, t );
489
490#ifndef NSF_EMU_APU_ONLY
491 if ( fds_enabled( this ) )
492 Fds_set_tempo( &this->fds, t );
493#endif
494}
495
496inline void push_byte( struct Nsf_Emu* this, int b )
497{
498 this->low_ram [0x100 + this->cpu.r.sp--] = b;
499}
500
501// Jumps to routine, given pointer to address in file header. Pushes idle_addr
502// as return address, NOT old PC.
503void jsr_then_stop( struct Nsf_Emu* this, byte const addr [] )
504{
505 this->cpu.r.pc = get_addr( addr );
506 push_byte( this, (idle_addr - 1) >> 8 );
507 push_byte( this, (idle_addr - 1) );
508}
509
510int cpu_read( struct Nsf_Emu* this, addr_t addr )
511{
512 #ifndef NSF_EMU_APU_ONLY
513 {
514 if ( namco_enabled( this ) && addr == namco_data_reg_addr )
515 return Namco_read_data( &this->namco );
516
517 if ( fds_enabled( this ) && (unsigned) (addr - fds_io_addr) < fds_io_size )
518 return Fds_read( &this->fds, Cpu_time( &this->cpu ), addr );
519
520 if ( mmc5_enabled( this ) ) {
521 int i = addr - 0x5C00;
522 if ( (unsigned) i < mmc5_exram_size )
523 return this->mmc5.exram [i];
524
525 int m = addr - 0x5205;
526 if ( (unsigned) m < 2 )
527 return (this->mmc5_mul [0] * this->mmc5_mul [1]) >> (m * 8) & 0xFF;
528 }
529 }
530 #endif
531
532 /* Unmapped read */
533 return addr >> 8;
534}
535
536int unmapped_read( struct Nsf_Emu* this, addr_t addr )
537{
538 (void) this;
539
540 switch ( addr )
541 {
542 case 0x2002:
543 case 0x4016:
544 case 0x4017:
545 return addr >> 8;
546 }
547
548 // Unmapped read
549 return addr >> 8;
550}
551
552void cpu_write( struct Nsf_Emu* this, addr_t addr, int data )
553{
554 #ifndef NSF_EMU_APU_ONLY
555 {
556 nes_time_t time = Cpu_time( &this->cpu );
557 if ( fds_enabled( this) && (unsigned) (addr - fds_io_addr) < fds_io_size )
558 {
559 Fds_write( &this->fds, time, addr, data );
560 return;
561 }
562
563 if ( namco_enabled( this) )
564 {
565 if ( addr == namco_addr_reg_addr )
566 {
567 Namco_write_addr( &this->namco, data );
568 return;
569 }
570
571 if ( addr == namco_data_reg_addr )
572 {
573 Namco_write_data( &this->namco, time, data );
574 return;
575 }
576 }
577
578 if ( vrc6_enabled( this) )
579 {
580 int reg = addr & (vrc6_addr_step - 1);
581 int osc = (unsigned) (addr - vrc6_base_addr) / vrc6_addr_step;
582 if ( (unsigned) osc < vrc6_osc_count && (unsigned) reg < vrc6_reg_count )
583 {
584 Vrc6_write_osc( &this->vrc6, time, osc, reg, data );
585 return;
586 }
587 }
588
589 if ( fme7_enabled( this) && addr >= fme7_latch_addr )
590 {
591 switch ( addr & fme7_addr_mask )
592 {
593 case fme7_latch_addr:
594 Fme7_write_latch( &this->fme7, data );
595 return;
596
597 case fme7_data_addr:
598 Fme7_write_data( &this->fme7, time, data );
599 return;
600 }
601 }
602
603 if ( mmc5_enabled( this) )
604 {
605 if ( (unsigned) (addr - mmc5_regs_addr) < mmc5_regs_size )
606 {
607 Mmc5_write_register( &this->mmc5, time, addr, data );
608 return;
609 }
610
611 int m = addr - 0x5205;
612 if ( (unsigned) m < 2 )
613 {
614 this->mmc5_mul [m] = data;
615 return;
616 }
617
618 int i = addr - 0x5C00;
619 if ( (unsigned) i < mmc5_exram_size )
620 {
621 this->mmc5.exram [i] = data;
622 return;
623 }
624 }
625
626 if ( vrc7_enabled( this) )
627 {
628 if ( addr == 0x9010 )
629 {
630 Vrc7_write_reg( &this->vrc7, data );
631 return;
632 }
633
634 if ( (unsigned) (addr - 0x9028) <= 0x08 )
635 {
636 Vrc7_write_data( &this->vrc7, time, data );
637 return;
638 }
639 }
640 }
641 #endif
642
643 // Unmapped_write
644}
645
646void unmapped_write( struct Nsf_Emu* this, addr_t addr, int data )
647{
648 (void) data;
649
650 switch ( addr )
651 {
652 case 0x8000: // some write to $8000 and $8001 repeatedly
653 case 0x8001:
654 case 0x4800: // probably namco sound mistakenly turned on in MCK
655 case 0xF800:
656 case 0xFFF8: // memory mapper?
657 return;
658 }
659
660 if ( mmc5_enabled( this ) && addr == 0x5115 ) return;
661
662 // FDS memory
663 if ( fds_enabled( this ) && (unsigned) (addr - 0x8000) < 0x6000 ) return;
664}
665
666void fill_buf( struct Nsf_Emu* this );
667blargg_err_t Nsf_start_track( struct Nsf_Emu* this, int track )
668{
669 clear_track_vars( this );
670
671 // Remap track if playlist available
672 if ( this->m3u.size > 0 ) {
673 struct entry_t* e = &this->m3u.entries[track];
674 track = e->track;
675 }
676 else track = Info_remap_track( &this->info, track );
677
678 this->current_track = track;
679 Buffer_clear( &this->stereo_buf );
680
681 #ifndef NSF_EMU_APU_ONLY
682 if ( mmc5_enabled( this ) )
683 {
684 this->mmc5_mul [0] = 0;
685 this->mmc5_mul [1] = 0;
686 memset( this->mmc5.exram, 0, mmc5_exram_size );
687 }
688
689 if ( fds_enabled( this ) ) Fds_reset( &this->fds );
690 if ( namco_enabled( this ) ) Namco_reset( &this->namco );
691 if ( vrc6_enabled( this ) ) Vrc6_reset( &this->vrc6 );
692 if ( fme7_enabled( this ) ) Fme7_reset( &this->fme7 );
693 if ( mmc5_enabled( this ) ) Apu_reset( &this->mmc5.apu, false, 0 );
694 if ( vrc7_enabled( this ) ) Vrc7_reset( &this->vrc7 );
695 #endif
696
697 int speed_flags = 0;
698 #ifdef NSF_EMU_EXTRA_FLAGS
699 speed_flags = this->header.speed_flags;
700 #endif
701
702 Apu_reset( &this->apu, pal_only( &this->header ), (speed_flags & 0x20) ? 0x3F : 0 );
703 Apu_write_register( &this->apu, 0, 0x4015, 0x0F );
704 Apu_write_register( &this->apu, 0, 0x4017, (speed_flags & 0x10) ? 0x80 : 0 );
705
706 memset( unmapped_code( this ), halt_opcode, unmapped_size );
707 memset( this->low_ram, 0, low_ram_size );
708 memset( sram( this ), 0, sram_size );
709
710 map_memory( this );
711
712 // Arrange time of first call to play routine
713 this->play_extra = 0;
714 this->next_play = this->play_period;
715
716 this->play_delay = initial_play_delay;
717 this->saved_state.pc = idle_addr;
718
719 // Setup for call to init routine
720 this->cpu.r.a = track;
721 this->cpu.r.x = pal_only( &this->header );
722 this->cpu.r.sp = 0xFF;
723 jsr_then_stop( this, this->header.init_addr );
724 /* if ( this->cpu.r.pc < get_addr( header.load_addr ) )
725 warning( "Init address < load address" ); */
726
727 this->emu_track_ended_ = false;
728 this->track_ended = false;
729
730 if ( !this->ignore_silence )
731 {
732 // play until non-silence or end of track
733 long end;
734 for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; )
735 {
736 fill_buf( this );
737 if ( this->buf_remain | (int) this->emu_track_ended_ )
738 break;
739 }
740
741 this->emu_time = this->buf_remain;
742 this->out_time = 0;
743 this->silence_time = 0;
744 this->silence_count = 0;
745 }
746 /* return track_ended() ? warning() : 0; */
747 return 0;
748}
749
750void run_once( struct Nsf_Emu* this, nes_time_t end )
751{
752 // Emulate until next play call if possible
753 if ( run_cpu_until( this, min( this->next_play, end ) ) )
754 {
755 // Halt instruction encountered
756
757 if ( this->cpu.r.pc != idle_addr )
758 {
759 // special_event( "illegal instruction" );
760 Cpu_set_time( &this->cpu, this->cpu.end_time );
761 return;
762 }
763
764 // Init/play routine returned
765 this->play_delay = 1; // play can now be called regularly
766
767 if ( this->saved_state.pc == idle_addr )
768 {
769 // nothing to run
770 nes_time_t t = this->cpu.end_time;
771 if ( Cpu_time( &this->cpu ) < t )
772 Cpu_set_time( &this->cpu, t );
773 }
774 else
775 {
776 // continue init routine that was interrupted by play routine
777 this->cpu.r = this->saved_state;
778 this->saved_state.pc = idle_addr;
779 }
780 }
781
782 if ( Cpu_time( &this->cpu ) >= this->next_play )
783 {
784 // Calculate time of next call to play routine
785 this->play_extra ^= 1; // extra clock every other call
786 this->next_play += this->play_period + this->play_extra;
787
788 // Call routine if ready
789 if ( this->play_delay && !--this->play_delay )
790 {
791 // Save state if init routine is still running
792 if ( this->cpu.r.pc != idle_addr )
793 {
794 check( this->saved_state.pc == idle_addr );
795 this->saved_state = this->cpu.r;
796 // special_event( "play called during init" );
797 }
798
799 jsr_then_stop( this, this->header.play_addr );
800 }
801 }
802}
803
804void run_until( struct Nsf_Emu* this, nes_time_t end )
805{
806 while ( Cpu_time( &this->cpu ) < end )
807 run_once( this, end );
808}
809
810void end_frame( struct Nsf_Emu* this, nes_time_t end )
811{
812 if ( Cpu_time( &this->cpu ) < end )
813 run_until( this, end );
814 Cpu_adjust_time( &this->cpu, -end );
815
816 // Localize to new time frame
817 this->next_play -= end;
818 check( this->next_play >= 0 );
819 if ( this->next_play < 0 )
820 this->next_play = 0;
821
822 Apu_end_frame( &this->apu, end );
823
824 #ifndef NSF_EMU_APU_ONLY
825 if ( fds_enabled( this ) ) Fds_end_frame( &this->fds, end );
826 if ( fme7_enabled( this ) ) Fme7_end_frame( &this->fme7, end );
827 if ( mmc5_enabled( this ) ) Apu_end_frame( &this->mmc5.apu, end );
828 if ( namco_enabled( this ) ) Namco_end_frame( &this->namco, end );
829 if ( vrc6_enabled( this ) ) Vrc6_end_frame( &this->vrc6, end );
830 if ( vrc7_enabled( this ) ) Vrc7_end_frame( &this->vrc7, end );
831 #endif
832}
833
834// Tell/Seek
835
836blargg_long msec_to_samples( long sample_rate, blargg_long msec )
837{
838 blargg_long sec = msec / 1000;
839 msec -= sec * 1000;
840 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
841}
842
843long Track_tell( struct Nsf_Emu* this )
844{
845 blargg_long rate = this->sample_rate * stereo;
846 blargg_long sec = this->out_time / rate;
847 return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate;
848}
849
850blargg_err_t Track_seek( struct Nsf_Emu* this, long msec )
851{
852 blargg_long time = msec_to_samples( this->sample_rate, msec );
853 if ( time < this->out_time )
854 RETURN_ERR( Nsf_start_track( this, this->current_track ) );
855 return Track_skip( this, time - this->out_time );
856}
857
858blargg_err_t skip_( struct Nsf_Emu* this, long count ) ICODE_ATTR;
859blargg_err_t Track_skip( struct Nsf_Emu* this, long count )
860{
861 require( this->current_track >= 0 ); // start_track() must have been called already
862 this->out_time += count;
863
864 // remove from silence and buf first
865 {
866 long n = min( count, this->silence_count );
867 this->silence_count -= n;
868 count -= n;
869
870 n = min( count, this->buf_remain );
871 this->buf_remain -= n;
872 count -= n;
873 }
874
875 if ( count && !this->emu_track_ended_ )
876 {
877 this->emu_time += count;
878 // End track if error
879 if ( skip_( this, count ) )
880 this->emu_track_ended_ = true;
881 }
882
883 if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended
884 this->track_ended |= this->emu_track_ended_;
885
886 return 0;
887}
888
889blargg_err_t play_( struct Nsf_Emu* this, long count, sample_t* out ) ICODE_ATTR;
890blargg_err_t skip_( struct Nsf_Emu* this, long count )
891{
892 // for long skip, mute sound
893 const long threshold = 30000;
894 if ( count > threshold )
895 {
896 int saved_mute = this->mute_mask_;
897 Sound_mute_voices( this, ~0 );
898
899 while ( count > threshold / 2 && !this->emu_track_ended_ )
900 {
901 RETURN_ERR( play_( this, buf_size, this->buf ) );
902 count -= buf_size;
903 }
904
905 Sound_mute_voices( this, saved_mute );
906 }
907
908 while ( count && !this->emu_track_ended_ )
909 {
910 long n = buf_size;
911 if ( n > count )
912 n = count;
913 count -= n;
914 RETURN_ERR( play_( this, n, this->buf ) );
915 }
916 return 0;
917}
918
919// Fading
920
921void Track_set_fade( struct Nsf_Emu* this, long start_msec, long length_msec )
922{
923 this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
924 this->fade_start = msec_to_samples( this->sample_rate, start_msec );
925}
926
927// unit / pow( 2.0, (double) x / step )
928static int int_log( blargg_long x, int step, int unit )
929{
930 int shift = x / step;
931 int fraction = (x - shift * step) * unit / step;
932 return ((unit - fraction) + (fraction >> 1)) >> shift;
933}
934
935void handle_fade( struct Nsf_Emu* this, long out_count, sample_t* out )
936{
937 int i;
938 for ( i = 0; i < out_count; i += fade_block_size )
939 {
940 int const shift = 14;
941 int const unit = 1 << shift;
942 int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size,
943 this->fade_step, unit );
944 if ( gain < (unit >> fade_shift) )
945 this->track_ended = this->emu_track_ended_ = true;
946
947 sample_t* io = &out [i];
948 int count;
949 for ( count = min( fade_block_size, out_count - i ); count; --count )
950 {
951 *io = (sample_t) ((*io * gain) >> shift);
952 ++io;
953 }
954 }
955}
956
957// Silence detection
958
959void emu_play( struct Nsf_Emu* this, long count, sample_t* out ) ICODE_ATTR;
960void emu_play( struct Nsf_Emu* this, long count, sample_t* out )
961{
962 check( current_track_ >= 0 );
963 this->emu_time += count;
964 if ( this->current_track >= 0 && !this->emu_track_ended_ ) {
965
966 // End track if error
967 if ( play_( this, count, out ) )
968 this->emu_track_ended_ = true;
969 }
970 else
971 memset( out, 0, count * sizeof *out );
972}
973
974// number of consecutive silent samples at end
975static long count_silence( sample_t* begin, long size )
976{
977 sample_t first = *begin;
978 *begin = silence_threshold; // sentinel
979 sample_t* p = begin + size;
980 while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
981 *begin = first;
982 return size - (p - begin);
983}
984
985// fill internal buffer and check it for silence
986void fill_buf( struct Nsf_Emu* this )
987{
988 assert( !this->buf_remain );
989 if ( !this->emu_track_ended_ )
990 {
991 emu_play( this, buf_size, this->buf );
992 long silence = count_silence( this->buf, buf_size );
993 if ( silence < buf_size )
994 {
995 this->silence_time = this->emu_time - silence;
996 this->buf_remain = buf_size;
997 return;
998 }
999 }
1000 this->silence_count += buf_size;
1001}
1002
1003blargg_err_t Nsf_play( struct Nsf_Emu* this, long out_count, sample_t* out )
1004{
1005 if ( this->track_ended )
1006 {
1007 memset( out, 0, out_count * sizeof *out );
1008 }
1009 else
1010 {
1011 require( this->current_track >= 0 );
1012 require( out_count % stereo == 0 );
1013
1014 assert( this->emu_time >= this->out_time );
1015
1016 long pos = 0;
1017 if ( this->silence_count )
1018 {
1019 // during a run of silence, run emulator at >=2x speed so it gets ahead
1020 long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time;
1021 while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) )
1022 fill_buf( this );
1023
1024 // fill with silence
1025 pos = min( this->silence_count, out_count );
1026 memset( out, 0, pos * sizeof *out );
1027 this->silence_count -= pos;
1028
1029 if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate )
1030 {
1031 this->track_ended = this->emu_track_ended_ = true;
1032 this->silence_count = 0;
1033 this->buf_remain = 0;
1034 }
1035 }
1036
1037 if ( this->buf_remain )
1038 {
1039 // empty silence buf
1040 long n = min( this->buf_remain, out_count - pos );
1041 memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out );
1042 this->buf_remain -= n;
1043 pos += n;
1044 }
1045
1046 // generate remaining samples normally
1047 long remain = out_count - pos;
1048 if ( remain )
1049 {
1050 emu_play( this, remain, out + pos );
1051 this->track_ended |= this->emu_track_ended_;
1052
1053 if ( !this->ignore_silence || this->out_time > this->fade_start )
1054 {
1055 // check end for a new run of silence
1056 long silence = count_silence( out + pos, remain );
1057 if ( silence < remain )
1058 this->silence_time = this->emu_time - silence;
1059
1060 if ( this->emu_time - this->silence_time >= buf_size )
1061 fill_buf( this ); // cause silence detection on next play()
1062 }
1063 }
1064
1065 if ( this->out_time > this->fade_start )
1066 handle_fade( this, out_count, out );
1067 }
1068 this->out_time += out_count;
1069 return 0;
1070}
1071
1072blargg_err_t play_( struct Nsf_Emu* this, long count, sample_t* out )
1073{
1074 long remain = count;
1075 while ( remain )
1076 {
1077 remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain );
1078 if ( remain )
1079 {
1080 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) )
1081 {
1082 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
1083
1084 // Remute voices
1085 Sound_mute_voices( this, this->mute_mask_ );
1086 }
1087 int msec = Buffer_length( &this->stereo_buf );
1088 blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate__ / 1000 - 100;
1089 RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) );
1090 assert( clocks_emulated );
1091 Buffer_end_frame( &this->stereo_buf, clocks_emulated );
1092 }
1093 }
1094 return 0;
1095}
1096
1097blargg_err_t run_clocks( struct Nsf_Emu* this, blip_time_t* duration, int msec )
1098{
1099#if defined(ROCKBOX)
1100 (void) msec;
1101#endif
1102
1103 end_frame( this, *duration );
1104 return 0;
1105}