1 // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
2
3 #include "Nsf_Emu.h"
4
5 #include "blargg_endian.h"
6 #include <string.h>
7 #include <stdio.h>
8
9 #if !NSF_EMU_APU_ONLY
10 #include "Nes_Namco_Apu.h"
11 #include "Nes_Vrc6_Apu.h"
12 #include "Nes_Fme7_Apu.h"
13 #endif
14
15 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you
16 can redistribute it and/or modify it under the terms of the GNU Lesser
17 General Public License as published by the Free Software Foundation; either
18 version 2.1 of the License, or (at your option) any later version. This
19 module is distributed in the hope that it will be useful, but WITHOUT ANY
20 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
22 details. You should have received a copy of the GNU Lesser General Public
23 License along with this module; if not, write to the Free Software Foundation,
24 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
25
26 #include "blargg_source.h"
27
28 int const vrc6_flag = 0x01;
29 int const namco_flag = 0x10;
30 int const fme7_flag = 0x20;
31
32 long const clock_divisor = 12;
33
34 Nsf_Emu::equalizer_t const Nsf_Emu::nes_eq =
35 Music_Emu::make_equalizer( -1.0, 80 );
36 Nsf_Emu::equalizer_t const Nsf_Emu::famicom_eq =
37 Music_Emu::make_equalizer( -15.0, 80 );
38
pcm_read(void * emu,nes_addr_t addr)39 int Nsf_Emu::pcm_read( void* emu, nes_addr_t addr )
40 {
41 return *((Nsf_Emu*) emu)->cpu::get_code( addr );
42 }
43
Nsf_Emu()44 Nsf_Emu::Nsf_Emu()
45 {
46 vrc6 = 0;
47 namco = 0;
48 fme7 = 0;
49
50 set_type( gme_nsf_type );
51 set_silence_lookahead( 6 );
52 apu.dmc_reader( pcm_read, this );
53 Music_Emu::set_equalizer( nes_eq );
54 set_gain( 1.4 );
55 memset( unmapped_code, Nes_Cpu::bad_opcode, sizeof unmapped_code );
56 }
57
~Nsf_Emu()58 Nsf_Emu::~Nsf_Emu() { unload(); }
59
unload()60 void Nsf_Emu::unload()
61 {
62 #if !NSF_EMU_APU_ONLY
63 {
64 delete vrc6;
65 vrc6 = 0;
66
67 delete namco;
68 namco = 0;
69
70 delete fme7;
71 fme7 = 0;
72 }
73 #endif
74
75 rom.clear();
76 Music_Emu::unload();
77 }
78
79 // Track info
80
copy_nsf_fields(Nsf_Emu::header_t const & h,track_info_t * out)81 static void copy_nsf_fields( Nsf_Emu::header_t const& h, track_info_t* out )
82 {
83 GME_COPY_FIELD( h, out, game );
84 GME_COPY_FIELD( h, out, author );
85 GME_COPY_FIELD( h, out, copyright );
86 if ( h.chip_flags )
87 Gme_File::copy_field_( out->system, "Famicom" );
88 }
89
track_info_(track_info_t * out,int) const90 blargg_err_t Nsf_Emu::track_info_( track_info_t* out, int ) const
91 {
92 copy_nsf_fields( header_, out );
93 return 0;
94 }
95
check_nsf_header(void const * header)96 static blargg_err_t check_nsf_header( void const* header )
97 {
98 if ( memcmp( header, "NESM\x1A", 5 ) )
99 return gme_wrong_file_type;
100 return 0;
101 }
102
103 struct Nsf_File : Gme_Info_
104 {
105 Nsf_Emu::header_t h;
106
Nsf_FileNsf_File107 Nsf_File() { set_type( gme_nsf_type ); }
108
load_Nsf_File109 blargg_err_t load_( Data_Reader& in )
110 {
111 blargg_err_t err = in.read( &h, Nsf_Emu::header_size );
112 if ( err )
113 return (err == in.eof_error ? gme_wrong_file_type : err);
114
115 if ( h.chip_flags & ~(namco_flag | vrc6_flag | fme7_flag) )
116 set_warning( "Uses unsupported audio expansion hardware" );
117
118 set_track_count( h.track_count );
119 return check_nsf_header( &h );
120 }
121
track_info_Nsf_File122 blargg_err_t track_info_( track_info_t* out, int ) const
123 {
124 copy_nsf_fields( h, out );
125 return 0;
126 }
127 };
128
new_nsf_emu()129 static Music_Emu* new_nsf_emu () { return BLARGG_NEW Nsf_Emu ; }
new_nsf_file()130 static Music_Emu* new_nsf_file() { return BLARGG_NEW Nsf_File; }
131
132 static gme_type_t_ const gme_nsf_type_ = { "Nintendo NES", 0, &new_nsf_emu, &new_nsf_file, "NSF", 1 };
133 gme_type_t const gme_nsf_type = &gme_nsf_type_;
134
135
136 // Setup
137
set_tempo_(double t)138 void Nsf_Emu::set_tempo_( double t )
139 {
140 unsigned playback_rate = get_le16( header_.ntsc_speed );
141 unsigned standard_rate = 0x411A;
142 clock_rate_ = 1789772.72727;
143 play_period = 262 * 341L * 4 - 2; // two fewer PPU clocks every four frames
144
145 if ( pal_only )
146 {
147 play_period = 33247 * clock_divisor;
148 clock_rate_ = 1662607.125;
149 standard_rate = 0x4E20;
150 playback_rate = get_le16( header_.pal_speed );
151 }
152
153 if ( !playback_rate )
154 playback_rate = standard_rate;
155
156 if ( playback_rate != standard_rate || t != 1.0 )
157 play_period = long (playback_rate * clock_rate_ / (1000000.0 / clock_divisor * t));
158
159 apu.set_tempo( t );
160 }
161
init_sound()162 blargg_err_t Nsf_Emu::init_sound()
163 {
164 if ( header_.chip_flags & ~(namco_flag | vrc6_flag | fme7_flag) )
165 set_warning( "Uses unsupported audio expansion hardware" );
166
167 {
168 #define APU_NAMES "Square 1", "Square 2", "Triangle", "Noise", "DMC"
169
170 int const count = Nes_Apu::osc_count;
171 static const char* const apu_names [count] = { APU_NAMES };
172 set_voice_count( count );
173 set_voice_names( apu_names );
174
175 }
176
177 static int const types [] = {
178 wave_type | 1, wave_type | 2, wave_type | 0,
179 noise_type | 0, mixed_type | 1,
180 wave_type | 3, wave_type | 4, wave_type | 5,
181 wave_type | 6, wave_type | 7, wave_type | 8, wave_type | 9,
182 wave_type |10, wave_type |11, wave_type |12, wave_type |13
183 };
184 set_voice_types( types ); // common to all sound chip configurations
185
186 double adjusted_gain = gain();
187
188 #if NSF_EMU_APU_ONLY
189 {
190 if ( header_.chip_flags )
191 set_warning( "Uses unsupported audio expansion hardware" );
192 }
193 #else
194 {
195 if ( header_.chip_flags & (namco_flag | vrc6_flag | fme7_flag) )
196 set_voice_count( Nes_Apu::osc_count + 3 );
197
198 if ( header_.chip_flags & namco_flag )
199 {
200 namco = BLARGG_NEW Nes_Namco_Apu;
201 CHECK_ALLOC( namco );
202 adjusted_gain *= 0.75;
203
204 int const count = Nes_Apu::osc_count + Nes_Namco_Apu::osc_count;
205 static const char* const names [count] = {
206 APU_NAMES,
207 "Wave 1", "Wave 2", "Wave 3", "Wave 4",
208 "Wave 5", "Wave 6", "Wave 7", "Wave 8"
209 };
210 set_voice_count( count );
211 set_voice_names( names );
212 }
213
214 if ( header_.chip_flags & vrc6_flag )
215 {
216 vrc6 = BLARGG_NEW Nes_Vrc6_Apu;
217 CHECK_ALLOC( vrc6 );
218 adjusted_gain *= 0.75;
219
220 {
221 int const count = Nes_Apu::osc_count + Nes_Vrc6_Apu::osc_count;
222 static const char* const names [count] = {
223 APU_NAMES,
224 "Saw Wave", "Square 3", "Square 4"
225 };
226 set_voice_count( count );
227 set_voice_names( names );
228 }
229
230 if ( header_.chip_flags & namco_flag )
231 {
232 int const count = Nes_Apu::osc_count + Nes_Vrc6_Apu::osc_count +
233 Nes_Namco_Apu::osc_count;
234 static const char* const names [count] = {
235 APU_NAMES,
236 "Saw Wave", "Square 3", "Square 4",
237 "Wave 1", "Wave 2", "Wave 3", "Wave 4",
238 "Wave 5", "Wave 6", "Wave 7", "Wave 8"
239 };
240 set_voice_count( count );
241 set_voice_names( names );
242 }
243 }
244
245 if ( header_.chip_flags & fme7_flag )
246 {
247 fme7 = BLARGG_NEW Nes_Fme7_Apu;
248 CHECK_ALLOC( fme7 );
249 adjusted_gain *= 0.75;
250
251 int const count = Nes_Apu::osc_count + Nes_Fme7_Apu::osc_count;
252 static const char* const names [count] = {
253 APU_NAMES,
254 "Square 3", "Square 4", "Square 5"
255 };
256 set_voice_count( count );
257 set_voice_names( names );
258 }
259
260 if ( namco ) namco->volume( adjusted_gain );
261 if ( vrc6 ) vrc6 ->volume( adjusted_gain );
262 if ( fme7 ) fme7 ->volume( adjusted_gain );
263 }
264 #endif
265
266 apu.volume( adjusted_gain );
267
268 return 0;
269 }
270
load_(Data_Reader & in)271 blargg_err_t Nsf_Emu::load_( Data_Reader& in )
272 {
273 assert( offsetof (header_t,unused [4]) == header_size );
274 RETURN_ERR( rom.load( in, header_size, &header_, 0 ) );
275
276 set_track_count( header_.track_count );
277 RETURN_ERR( check_nsf_header( &header_ ) );
278
279 if ( header_.vers != 1 )
280 set_warning( "Unknown file version" );
281
282 // sound and memory
283 blargg_err_t err = init_sound();
284 if ( err )
285 return err;
286
287 // set up data
288 nes_addr_t load_addr = get_le16( header_.load_addr );
289 init_addr = get_le16( header_.init_addr );
290 play_addr = get_le16( header_.play_addr );
291 if ( !load_addr ) load_addr = rom_begin;
292 if ( !init_addr ) init_addr = rom_begin;
293 if ( !play_addr ) play_addr = rom_begin;
294 if ( load_addr < rom_begin || init_addr < rom_begin )
295 {
296 const char* w = warning();
297 if ( !w )
298 w = "Corrupt file (invalid load/init/play address)";
299 return w;
300 }
301
302 rom.set_addr( load_addr % bank_size );
303 int total_banks = rom.size() / bank_size;
304
305 // bank switching
306 int first_bank = (load_addr - rom_begin) / bank_size;
307 for ( int i = 0; i < bank_count; i++ )
308 {
309 unsigned bank = i - first_bank;
310 if ( bank >= (unsigned) total_banks )
311 bank = 0;
312 initial_banks [i] = bank;
313
314 if ( header_.banks [i] )
315 {
316 // bank-switched
317 memcpy( initial_banks, header_.banks, sizeof initial_banks );
318 break;
319 }
320 }
321
322 pal_only = (header_.speed_flags & 3) == 1;
323
324 #if !NSF_EMU_EXTRA_FLAGS
325 header_.speed_flags = 0;
326 #endif
327
328 set_tempo( tempo() );
329
330 return setup_buffer( (long) (clock_rate_ + 0.5) );
331 }
332
update_eq(blip_eq_t const & eq)333 void Nsf_Emu::update_eq( blip_eq_t const& eq )
334 {
335 apu.treble_eq( eq );
336
337 #if !NSF_EMU_APU_ONLY
338 {
339 if ( namco ) namco->treble_eq( eq );
340 if ( vrc6 ) vrc6 ->treble_eq( eq );
341 if ( fme7 ) fme7 ->treble_eq( eq );
342 }
343 #endif
344 }
345
set_voice(int i,Blip_Buffer * buf,Blip_Buffer *,Blip_Buffer *)346 void Nsf_Emu::set_voice( int i, Blip_Buffer* buf, Blip_Buffer*, Blip_Buffer* )
347 {
348 if ( i < Nes_Apu::osc_count )
349 {
350 apu.osc_output( i, buf );
351 return;
352 }
353 i -= Nes_Apu::osc_count;
354
355 #if !NSF_EMU_APU_ONLY
356 {
357 if ( fme7 && i < Nes_Fme7_Apu::osc_count )
358 {
359 fme7->osc_output( i, buf );
360 return;
361 }
362
363 if ( vrc6 )
364 {
365 if ( i < Nes_Vrc6_Apu::osc_count )
366 {
367 // put saw first
368 if ( --i < 0 )
369 i = 2;
370 vrc6->osc_output( i, buf );
371 return;
372 }
373 i -= Nes_Vrc6_Apu::osc_count;
374 }
375
376 if ( namco && i < Nes_Namco_Apu::osc_count )
377 {
378 namco->osc_output( i, buf );
379 return;
380 }
381 }
382 #endif
383 }
384
385 // Emulation
386
387 // see nes_cpu_io.h for read/write functions
388
cpu_write_misc(nes_addr_t addr,int data)389 void Nsf_Emu::cpu_write_misc( nes_addr_t addr, int data )
390 {
391 #if !NSF_EMU_APU_ONLY
392 {
393 if ( namco )
394 {
395 switch ( addr )
396 {
397 case Nes_Namco_Apu::data_reg_addr:
398 namco->write_data( time(), data );
399 return;
400
401 case Nes_Namco_Apu::addr_reg_addr:
402 namco->write_addr( data );
403 return;
404 }
405 }
406
407 if ( addr >= Nes_Fme7_Apu::latch_addr && fme7 )
408 {
409 switch ( addr & Nes_Fme7_Apu::addr_mask )
410 {
411 case Nes_Fme7_Apu::latch_addr:
412 fme7->write_latch( data );
413 return;
414
415 case Nes_Fme7_Apu::data_addr:
416 fme7->write_data( time(), data );
417 return;
418 }
419 }
420
421 if ( vrc6 )
422 {
423 unsigned reg = addr & (Nes_Vrc6_Apu::addr_step - 1);
424 unsigned osc = unsigned (addr - Nes_Vrc6_Apu::base_addr) / Nes_Vrc6_Apu::addr_step;
425 if ( osc < Nes_Vrc6_Apu::osc_count && reg < Nes_Vrc6_Apu::reg_count )
426 {
427 vrc6->write_osc( time(), osc, reg, data );
428 return;
429 }
430 }
431 }
432 #endif
433
434 // unmapped write
435
436 #ifndef NDEBUG
437 {
438 // some games write to $8000 and $8001 repeatedly
439 if ( addr == 0x8000 || addr == 0x8001 ) return;
440
441 // probably namco sound mistakenly turned on in mck
442 if ( addr == 0x4800 || addr == 0xF800 ) return;
443
444 // memory mapper?
445 if ( addr == 0xFFF8 ) return;
446
447 debug_printf( "write_unmapped( 0x%04X, 0x%02X )\n", (unsigned) addr, (unsigned) data );
448 }
449 #endif
450 }
451
start_track_(int track)452 blargg_err_t Nsf_Emu::start_track_( int track )
453 {
454 RETURN_ERR( Classic_Emu::start_track_( track ) );
455
456 memset( low_mem, 0, sizeof low_mem );
457 memset( sram, 0, sizeof sram );
458
459 cpu::reset( unmapped_code ); // also maps low_mem
460 cpu::map_code( sram_addr, sizeof sram, sram );
461 for ( int i = 0; i < bank_count; ++i )
462 cpu_write( bank_select_addr + i, initial_banks [i] );
463
464 apu.reset( pal_only, (header_.speed_flags & 0x20) ? 0x3F : 0 );
465 apu.write_register( 0, 0x4015, 0x0F );
466 apu.write_register( 0, 0x4017, (header_.speed_flags & 0x10) ? 0x80 : 0 );
467 #if !NSF_EMU_APU_ONLY
468 {
469 if ( namco ) namco->reset();
470 if ( vrc6 ) vrc6 ->reset();
471 if ( fme7 ) fme7 ->reset();
472 }
473 #endif
474
475 play_ready = 4;
476 play_extra = 0;
477 next_play = play_period / clock_divisor;
478
479 saved_state.pc = badop_addr;
480 low_mem [0x1FF] = (badop_addr - 1) >> 8;
481 low_mem [0x1FE] = (badop_addr - 1) & 0xFF;
482 r.sp = 0xFD;
483 r.pc = init_addr;
484 r.a = track;
485 r.x = pal_only;
486
487 return 0;
488 }
489
run_clocks(blip_time_t & duration,int)490 blargg_err_t Nsf_Emu::run_clocks( blip_time_t& duration, int )
491 {
492 set_time( 0 );
493 while ( time() < duration )
494 {
495 nes_time_t end = min( (blip_time_t) next_play, duration );
496 end = min( end, time() + 32767 ); // allows CPU to use 16-bit time delta
497 if ( cpu::run( end ) )
498 {
499 if ( r.pc != badop_addr )
500 {
501 set_warning( "Emulation error (illegal instruction)" );
502 r.pc++;
503 }
504 else
505 {
506 play_ready = 1;
507 if ( saved_state.pc != badop_addr )
508 {
509 cpu::r = saved_state;
510 saved_state.pc = badop_addr;
511 }
512 else
513 {
514 set_time( end );
515 }
516 }
517 }
518
519 if ( time() >= next_play )
520 {
521 nes_time_t period = (play_period + play_extra) / clock_divisor;
522 play_extra = play_period - period * clock_divisor;
523 next_play += period;
524 if ( play_ready && !--play_ready )
525 {
526 check( saved_state.pc == badop_addr );
527 if ( r.pc != badop_addr )
528 saved_state = cpu::r;
529
530 r.pc = play_addr;
531 low_mem [0x100 + r.sp--] = (badop_addr - 1) >> 8;
532 low_mem [0x100 + r.sp--] = (badop_addr - 1) & 0xFF;
533 GME_FRAME_HOOK( this );
534 }
535 }
536 }
537
538 if ( cpu::error_count() )
539 {
540 cpu::clear_error_count();
541 set_warning( "Emulation error (illegal instruction)" );
542 }
543
544 duration = time();
545 next_play -= duration;
546 check( next_play >= 0 );
547 if ( next_play < 0 )
548 next_play = 0;
549
550 apu.end_frame( duration );
551
552 #if !NSF_EMU_APU_ONLY
553 {
554 if ( namco ) namco->end_frame( duration );
555 if ( vrc6 ) vrc6 ->end_frame( duration );
556 if ( fme7 ) fme7 ->end_frame( duration );
557 }
558 #endif
559
560 return 0;
561 }
562