1 // Game_Music_Emu $vers. http://www.slack.net/~ant/
2
3 #include "Nsf_Emu.h"
4
5 #if !NSF_EMU_APU_ONLY
6 #include "Nes_Namco_Apu.h"
7 #include "Nes_Vrc6_Apu.h"
8 #include "Nes_Fme7_Apu.h"
9 #include "Nes_Fds_Apu.h"
10 #include "Nes_Mmc5_Apu.h"
11 #include "Nes_Vrc7_Apu.h"
12 #endif
13
14 /* Copyright (C) 2003-2008 Shay Green. This module is free software; you
15 can redistribute it and/or modify it under the terms of the GNU Lesser
16 General Public License as published by the Free Software Foundation; either
17 version 2.1 of the License, or (at your option) any later version. This
18 module is distributed in the hope that it will be useful, but WITHOUT ANY
19 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
21 details. You should have received a copy of the GNU Lesser General Public
22 License along with this module; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
24
25 #include "blargg_source.h"
26
27 Nsf_Emu::equalizer_t const Nsf_Emu::nes_eq = { -1.0, 80, 0,0,0,0,0,0,0,0 };
28 Nsf_Emu::equalizer_t const Nsf_Emu::famicom_eq = { -15.0, 80, 0,0,0,0,0,0,0,0 };
29
Nsf_Emu()30 Nsf_Emu::Nsf_Emu()
31 {
32 set_type( gme_nsf_type );
33 set_silence_lookahead( 6 );
34 set_gain( 1.4 );
35 set_equalizer( nes_eq );
36 }
37
~Nsf_Emu()38 Nsf_Emu::~Nsf_Emu()
39 {
40 unload();
41 }
42
unload()43 void Nsf_Emu::unload()
44 {
45 core_.unload();
46 Music_Emu::unload();
47 }
48
49 // Track info
50
copy_nsf_fields(Nsf_Emu::header_t const & h,track_info_t * out)51 static void copy_nsf_fields( Nsf_Emu::header_t const& h, track_info_t* out )
52 {
53 GME_COPY_FIELD( h, out, game );
54 GME_COPY_FIELD( h, out, author );
55 GME_COPY_FIELD( h, out, copyright );
56 if ( h.chip_flags )
57 Music_Emu::copy_field_( out->system, "Famicom" );
58 }
59
hash_nsf_file(Nsf_Core::header_t const & h,unsigned char const * data,int data_size,Music_Emu::Hash_Function & out)60 void hash_nsf_file( Nsf_Core::header_t const& h, unsigned char const* data, int data_size, Music_Emu::Hash_Function& out )
61 {
62 out.hash_( &h.vers, sizeof(h.vers) );
63 out.hash_( &h.track_count, sizeof(h.track_count) );
64 out.hash_( &h.first_track, sizeof(h.first_track) );
65 out.hash_( &h.load_addr[0], sizeof(h.load_addr) );
66 out.hash_( &h.init_addr[0], sizeof(h.init_addr) );
67 out.hash_( &h.play_addr[0], sizeof(h.play_addr) );
68 out.hash_( &h.ntsc_speed[0], sizeof(h.ntsc_speed) );
69 out.hash_( &h.banks[0], sizeof(h.banks) );
70 out.hash_( &h.pal_speed[0], sizeof(h.pal_speed) );
71 out.hash_( &h.speed_flags, sizeof(h.speed_flags) );
72 out.hash_( &h.chip_flags, sizeof(h.chip_flags) );
73 out.hash_( &h.unused[0], sizeof(h.unused) );
74
75 out.hash_( data, data_size );
76 }
77
track_info_(track_info_t * out,int) const78 blargg_err_t Nsf_Emu::track_info_( track_info_t* out, int ) const
79 {
80 copy_nsf_fields( header(), out );
81 return blargg_ok;
82 }
83
check_nsf_header(Nsf_Emu::header_t const & h)84 static blargg_err_t check_nsf_header( Nsf_Emu::header_t const& h )
85 {
86 if ( !h.valid_tag() )
87 return blargg_err_file_type;
88 return blargg_ok;
89 }
90
91 struct Nsf_File : Gme_Info_
92 {
93 Nsf_Emu::header_t const* h;
94
Nsf_FileNsf_File95 Nsf_File() { set_type( gme_nsf_type ); }
96
load_mem_Nsf_File97 blargg_err_t load_mem_( byte const begin [], int size )
98 {
99 h = ( Nsf_Emu::header_t const* ) begin;
100
101 if ( h->vers != 1 )
102 set_warning( "Unknown file version" );
103
104 int unsupported_chips = ~Nsf_Core::chips_mask;
105 #if NSF_EMU_NO_VRC7
106 unsupported_chips |= Nsf_Emu::header_t::vrc7_mask;
107 #endif
108 if ( h->chip_flags & unsupported_chips )
109 set_warning( "Uses unsupported audio expansion hardware" );
110
111 set_track_count( h->track_count );
112 return check_nsf_header( *h );
113 }
114
track_info_Nsf_File115 blargg_err_t track_info_( track_info_t* out, int ) const
116 {
117 copy_nsf_fields( *h, out );
118 return blargg_ok;
119 }
120
hash_Nsf_File121 blargg_err_t hash_( Hash_Function& out ) const
122 {
123 hash_nsf_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out );
124 return blargg_ok;
125 }
126 };
127
new_nsf_emu()128 static Music_Emu* new_nsf_emu () { return BLARGG_NEW Nsf_Emu ; }
new_nsf_file()129 static Music_Emu* new_nsf_file() { return BLARGG_NEW Nsf_File; }
130
131 gme_type_t_ const gme_nsf_type [1] = {{ "Nintendo NES", 0, &new_nsf_emu, &new_nsf_file, "NSF", 1 }};
132
133 // Setup
134
set_tempo_(double t)135 void Nsf_Emu::set_tempo_( double t )
136 {
137 core_.set_tempo( t );
138 }
139
append_voices(const char * const names[],int const types[],int count)140 void Nsf_Emu::append_voices( const char* const names [], int const types [], int count )
141 {
142 assert( voice_count_ + count < max_voices );
143 for ( int i = 0; i < count; i++ )
144 {
145 voice_names_ [voice_count_ + i] = names [i];
146 voice_types_ [voice_count_ + i] = types [i];
147 }
148 voice_count_ += count;
149 set_voice_count( voice_count_ );
150 set_voice_types( voice_types_ );
151 }
152
init_sound()153 blargg_err_t Nsf_Emu::init_sound()
154 {
155 voice_count_ = 0;
156 set_voice_names( voice_names_ );
157
158 {
159 int const count = Nes_Apu::osc_count;
160 static const char* const names [Nes_Apu::osc_count] = {
161 "Square 1", "Square 2", "Triangle", "Noise", "DMC"
162 };
163 static int const types [count] = {
164 wave_type+1, wave_type+2, mixed_type+1, noise_type+0, mixed_type+1
165 };
166 append_voices( names, types, count );
167 }
168
169 // Make adjusted_gain * 0.75 = 1.0 so usual APU and one sound chip uses 1.0
170 double adjusted_gain = 1.0 / 0.75 * gain();
171
172 #if !NSF_EMU_APU_ONLY
173 // TODO: order of chips here must match that in set_voice()
174
175 if ( core_.vrc6_apu() )
176 {
177 int const count = Nes_Vrc6_Apu::osc_count;
178 static const char* const names [count] = {
179 "Square 3", "Square 4", "Saw Wave"
180 };
181 static int const types [count] = {
182 wave_type+3, wave_type+4, wave_type+5,
183 };
184 append_voices( names, types, count );
185 adjusted_gain *= 0.75;
186 }
187
188 if ( core_.fme7_apu() )
189 {
190 int const count = Nes_Fme7_Apu::osc_count;
191 static const char* const names [count] = {
192 "Square 3", "Square 4", "Square 5"
193 };
194 static int const types [count] = {
195 wave_type+3, wave_type+4, wave_type+5,
196 };
197 append_voices( names, types, count );
198 adjusted_gain *= 0.75;
199 }
200
201 if ( core_.mmc5_apu() )
202 {
203 int const count = Nes_Mmc5_Apu::osc_count;
204 static const char* const names [count] = {
205 "Square 3", "Square 4", "PCM"
206 };
207 static int const types [count] = {
208 wave_type+3, wave_type+4, mixed_type+2
209 };
210 append_voices( names, types, count );
211 adjusted_gain *= 0.75;
212 }
213
214 if ( core_.fds_apu() )
215 {
216 int const count = Nes_Fds_Apu::osc_count;
217 static const char* const names [count] = {
218 "FM"
219 };
220 static int const types [count] = {
221 wave_type+0
222 };
223 append_voices( names, types, count );
224 adjusted_gain *= 0.75;
225 }
226
227 if ( core_.namco_apu() )
228 {
229 int const count = Nes_Namco_Apu::osc_count;
230 static const char* const names [count] = {
231 "Wave 1", "Wave 2", "Wave 3", "Wave 4",
232 "Wave 5", "Wave 6", "Wave 7", "Wave 8"
233 };
234 static int const types [count] = {
235 wave_type+3, wave_type+4, wave_type+5, wave_type+ 6,
236 wave_type+7, wave_type+8, wave_type+9, wave_type+10,
237 };
238 append_voices( names, types, count );
239 adjusted_gain *= 0.75;
240 }
241
242 if ( core_.vrc7_apu() )
243 {
244 int const count = Nes_Vrc7_Apu::osc_count;
245 static const char* const names [count] = {
246 "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6"
247 };
248 static int const types [count] = {
249 wave_type+3, wave_type+4, wave_type+5, wave_type+6,
250 wave_type+7, wave_type+8
251 };
252 append_voices( names, types, count );
253 adjusted_gain *= 0.75;
254 }
255
256 if ( core_.vrc7_apu() ) core_.vrc7_apu() ->volume( adjusted_gain );
257 if ( core_.namco_apu() ) core_.namco_apu()->volume( adjusted_gain );
258 if ( core_.vrc6_apu() ) core_.vrc6_apu() ->volume( adjusted_gain );
259 if ( core_.fme7_apu() ) core_.fme7_apu() ->volume( adjusted_gain );
260 if ( core_.mmc5_apu() ) core_.mmc5_apu() ->volume( adjusted_gain );
261 if ( core_.fds_apu() ) core_.fds_apu() ->volume( adjusted_gain );
262 #endif
263
264 if ( adjusted_gain > gain() )
265 adjusted_gain = gain(); // only occurs if no other sound chips
266
267 core_.nes_apu()->volume( adjusted_gain );
268
269 return blargg_ok;
270 }
271
load_(Data_Reader & in)272 blargg_err_t Nsf_Emu::load_( Data_Reader& in )
273 {
274 RETURN_ERR( core_.load( in ) );
275 set_track_count( header().track_count );
276 RETURN_ERR( check_nsf_header( header() ) );
277 set_warning( core_.warning() );
278 RETURN_ERR( init_sound() );
279 set_tempo( tempo() );
280 return setup_buffer( (int) (header().clock_rate() + 0.5) );
281 }
282
update_eq(blip_eq_t const & eq)283 void Nsf_Emu::update_eq( blip_eq_t const& eq )
284 {
285 core_.nes_apu()->treble_eq( eq );
286
287 #if !NSF_EMU_APU_ONLY
288 {
289 if ( core_.namco_apu() ) core_.namco_apu()->treble_eq( eq );
290 if ( core_.vrc6_apu() ) core_.vrc6_apu() ->treble_eq( eq );
291 if ( core_.fme7_apu() ) core_.fme7_apu() ->treble_eq( eq );
292 if ( core_.mmc5_apu() ) core_.mmc5_apu() ->treble_eq( eq );
293 if ( core_.fds_apu() ) core_.fds_apu() ->treble_eq( eq );
294 if ( core_.vrc7_apu() ) core_.vrc7_apu() ->treble_eq( eq );
295 }
296 #endif
297 }
298
set_voice(int i,Blip_Buffer * buf,Blip_Buffer *,Blip_Buffer *)299 void Nsf_Emu::set_voice( int i, Blip_Buffer* buf, Blip_Buffer*, Blip_Buffer* )
300 {
301 #define HANDLE_CHIP( chip ) \
302 if ( chip && (i -= chip->osc_count) < 0 )\
303 {\
304 chip->set_output( i + chip->osc_count, buf );\
305 return;\
306 }\
307
308 HANDLE_CHIP( core_.nes_apu() );
309
310 #if !NSF_EMU_APU_ONLY
311 {
312 // TODO: order of chips here must match that in init_sound()
313 HANDLE_CHIP( core_.vrc6_apu() );
314 HANDLE_CHIP( core_.fme7_apu() );
315 HANDLE_CHIP( core_.mmc5_apu() );
316 HANDLE_CHIP( core_.fds_apu() );
317 HANDLE_CHIP( core_.namco_apu() );
318 HANDLE_CHIP( core_.vrc7_apu() );
319 }
320 #endif
321 }
322
start_track_(int track)323 blargg_err_t Nsf_Emu::start_track_( int track )
324 {
325 RETURN_ERR( Classic_Emu::start_track_( track ) );
326 return core_.start_track( track );
327 }
328
run_clocks(blip_time_t & duration,int)329 blargg_err_t Nsf_Emu::run_clocks( blip_time_t& duration, int )
330 {
331 core_.end_frame( duration );
332 const char* w = core_.warning();
333 if ( w )
334 set_warning( w );
335 return blargg_ok;
336 }
337
hash_(Hash_Function & out) const338 blargg_err_t Nsf_Emu::hash_( Hash_Function& out ) const
339 {
340 hash_nsf_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out );
341 return blargg_ok;
342 }