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 }