1 // Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
2 
3 #include "Vgm_Emu.h"
4 
5 #include "blargg_endian.h"
6 #include <string.h>
7 #include <math.h>
8 
9 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you
10 can redistribute it and/or modify it under the terms of the GNU Lesser
11 General Public License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version. This
13 module is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16 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,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
19 
20 #include "blargg_source.h"
21 
22 double const fm_gain = 3.0; // FM emulators are internally quieter to avoid 16-bit overflow
23 double const rolloff = 0.990;
24 double const oversample_factor = 1.5;
25 
Vgm_Emu()26 Vgm_Emu::Vgm_Emu()
27 {
28 	disable_oversampling_ = false;
29 	psg_rate   = 0;
30 	set_type( gme_vgm_type );
31 
32 	static int const types [8] = {
33 		wave_type | 1, wave_type | 0, wave_type | 2, noise_type | 0
34 	};
35 	set_voice_types( types );
36 
37 	set_silence_lookahead( 1 ); // tracks should already be trimmed
38 
39 	set_equalizer( make_equalizer( -14.0, 80 ) );
40 }
41 
~Vgm_Emu()42 Vgm_Emu::~Vgm_Emu() { }
43 
44 // Track info
45 
skip_gd3_str(byte const * in,byte const * end)46 static byte const* skip_gd3_str( byte const* in, byte const* end )
47 {
48 	while ( end - in >= 2 )
49 	{
50 		in += 2;
51 		if ( !(in [-2] | in [-1]) )
52 			break;
53 	}
54 	return in;
55 }
56 
get_gd3_str(byte const * in,byte const * end,char * field)57 static byte const* get_gd3_str( byte const* in, byte const* end, char* field )
58 {
59 	byte const* mid = skip_gd3_str( in, end );
60 	int len = (mid - in) / 2 - 1;
61 	if ( len > 0 )
62 	{
63 		len = min( len, (int) Gme_File::max_field_ );
64 		field [len] = 0;
65 		for ( int i = 0; i < len; i++ )
66 			field [i] = (in [i * 2 + 1] ? '?' : in [i * 2]); // TODO: convert to utf-8
67 	}
68 	return mid;
69 }
70 
get_gd3_pair(byte const * in,byte const * end,char * field)71 static byte const* get_gd3_pair( byte const* in, byte const* end, char* field )
72 {
73 	return skip_gd3_str( get_gd3_str( in, end, field ), end );
74 }
75 
parse_gd3(byte const * in,byte const * end,track_info_t * out)76 static void parse_gd3( byte const* in, byte const* end, track_info_t* out )
77 {
78 	in = get_gd3_pair( in, end, out->song );
79 	in = get_gd3_pair( in, end, out->game );
80 	in = get_gd3_pair( in, end, out->system );
81 	in = get_gd3_pair( in, end, out->author );
82 	in = get_gd3_str ( in, end, out->copyright );
83 	in = get_gd3_pair( in, end, out->dumper );
84 	in = get_gd3_str ( in, end, out->comment );
85 }
86 
87 int const gd3_header_size = 12;
88 
check_gd3_header(byte const * h,long remain)89 static long check_gd3_header( byte const* h, long remain )
90 {
91 	if ( remain < gd3_header_size ) return 0;
92 	if ( memcmp( h, "Gd3 ", 4 ) ) return 0;
93 	if ( get_le32( h + 4 ) >= 0x200 ) return 0;
94 
95 	long gd3_size = get_le32( h + 8 );
96 	if ( gd3_size > remain - gd3_header_size ) return 0;
97 
98 	return gd3_size;
99 }
100 
gd3_data(int * size) const101 byte const* Vgm_Emu::gd3_data( int* size ) const
102 {
103 	if ( size )
104 		*size = 0;
105 
106 	long gd3_offset = get_le32( header().gd3_offset ) - 0x2C;
107 	if ( gd3_offset < 0 )
108 		return 0;
109 
110 	byte const* gd3 = data + header_size + gd3_offset;
111 	long gd3_size = check_gd3_header( gd3, data_end - gd3 );
112 	if ( !gd3_size )
113 		return 0;
114 
115 	if ( size )
116 		*size = gd3_size + gd3_header_size;
117 
118 	return gd3;
119 }
120 
get_vgm_length(Vgm_Emu::header_t const & h,track_info_t * out)121 static void get_vgm_length( Vgm_Emu::header_t const& h, track_info_t* out )
122 {
123 	long length = get_le32( h.track_duration ) * 10 / 441;
124 	if ( length > 0 )
125 	{
126 		long loop = get_le32( h.loop_duration );
127 		if ( loop > 0 && get_le32( h.loop_offset ) )
128 		{
129 			out->loop_length = loop * 10 / 441;
130 			out->intro_length = length - out->loop_length;
131 		}
132 		else
133 		{
134 			out->length = length; // 1000 / 44100 (VGM files used 44100 as timebase)
135 			out->intro_length = length; // make it clear that track is no longer than length
136 			out->loop_length = 0;
137 		}
138 	}
139 }
140 
track_info_(track_info_t * out,int) const141 blargg_err_t Vgm_Emu::track_info_( track_info_t* out, int ) const
142 {
143 	get_vgm_length( header(), out );
144 
145 	int size;
146 	byte const* gd3 = gd3_data( &size );
147 	if ( gd3 )
148 		parse_gd3( gd3 + gd3_header_size, gd3 + size, out );
149 
150 	return 0;
151 }
152 
check_vgm_header(Vgm_Emu::header_t const & h)153 static blargg_err_t check_vgm_header( Vgm_Emu::header_t const& h )
154 {
155 	if ( memcmp( h.tag, "Vgm ", 4 ) )
156 		return gme_wrong_file_type;
157 	return 0;
158 }
159 
160 struct Vgm_File : Gme_Info_
161 {
162 	Vgm_Emu::header_t h;
163 	blargg_vector<byte> gd3;
164 
Vgm_FileVgm_File165 	Vgm_File() { set_type( gme_vgm_type ); }
166 
load_Vgm_File167 	blargg_err_t load_( Data_Reader& in )
168 	{
169 		long file_size = in.remain();
170 		if ( file_size <= Vgm_Emu::header_size )
171 			return gme_wrong_file_type;
172 
173 		RETURN_ERR( in.read( &h, Vgm_Emu::header_size ) );
174 		RETURN_ERR( check_vgm_header( h ) );
175 
176 		long gd3_offset = get_le32( h.gd3_offset ) - 0x2C;
177 		long remain = file_size - Vgm_Emu::header_size - gd3_offset;
178 		byte gd3_h [gd3_header_size];
179 		if ( gd3_offset > 0 && remain >= gd3_header_size )
180 		{
181 			RETURN_ERR( in.skip( gd3_offset ) );
182 			RETURN_ERR( in.read( gd3_h, sizeof gd3_h ) );
183 			long gd3_size = check_gd3_header( gd3_h, remain );
184 			if ( gd3_size )
185 			{
186 				RETURN_ERR( gd3.resize( gd3_size ) );
187 				RETURN_ERR( in.read( gd3.begin(), gd3.size() ) );
188 			}
189 		}
190 		return 0;
191 	}
192 
track_info_Vgm_File193 	blargg_err_t track_info_( track_info_t* out, int ) const
194 	{
195 		get_vgm_length( h, out );
196 		if ( gd3.size() )
197 			parse_gd3( gd3.begin(), gd3.end(), out );
198 		return 0;
199 	}
200 };
201 
new_vgm_emu()202 static Music_Emu* new_vgm_emu () { return BLARGG_NEW Vgm_Emu ; }
new_vgm_file()203 static Music_Emu* new_vgm_file() { return BLARGG_NEW Vgm_File; }
204 
205 static gme_type_t_ const gme_vgm_type_ = { "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGM", 1 };
206 BLARGG_EXPORT extern gme_type_t const gme_vgm_type = &gme_vgm_type_;
207 
208 static gme_type_t_ const gme_vgz_type_ = { "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGZ", 1 };
209 BLARGG_EXPORT extern gme_type_t const gme_vgz_type = &gme_vgz_type_;
210 
211 
212 // Setup
213 
set_tempo_(double t)214 void Vgm_Emu::set_tempo_( double t )
215 {
216 	if ( psg_rate )
217 	{
218 		vgm_rate = (long) (44100 * t + 0.5);
219 		blip_time_factor = (long) floor( double (1L << blip_time_bits) / vgm_rate * psg_rate + 0.5 );
220 		//debug_printf( "blip_time_factor: %ld\n", blip_time_factor );
221 		//debug_printf( "vgm_rate: %ld\n", vgm_rate );
222 		// TODO: remove? calculates vgm_rate more accurately (above differs at most by one Hz only)
223 		//blip_time_factor = (long) floor( double (1L << blip_time_bits) * psg_rate / 44100 / t + 0.5 );
224 		//vgm_rate = (long) floor( double (1L << blip_time_bits) * psg_rate / blip_time_factor + 0.5 );
225 
226 		fm_time_factor = 2 + (long) floor( fm_rate * (1L << fm_time_bits) / vgm_rate + 0.5 );
227 	}
228 }
229 
set_sample_rate_(long sample_rate)230 blargg_err_t Vgm_Emu::set_sample_rate_( long sample_rate )
231 {
232 	RETURN_ERR( blip_buf.set_sample_rate( sample_rate, 1000 / 30 ) );
233 	return Classic_Emu::set_sample_rate_( sample_rate );
234 }
235 
set_multi_channel(bool is_enabled)236 blargg_err_t Vgm_Emu::set_multi_channel ( bool is_enabled )
237 {
238 	// we acutally should check here whether this is classic emu or not
239 	// however set_multi_channel() is called before setup_fm() resulting in uninited is_classic_emu()
240 	// hard code it to unsupported
241 #if 0
242 	if ( is_classic_emu() )
243 	{
244 		RETURN_ERR( Music_Emu::set_multi_channel_( is_enabled ) );
245 		return 0;
246 	}
247 	else
248 #endif
249 	{
250 		(void) is_enabled;
251 		return "multichannel rendering not supported for YM2*** FM sound chip emulators";
252 	}
253 }
254 
update_eq(blip_eq_t const & eq)255 void Vgm_Emu::update_eq( blip_eq_t const& eq )
256 {
257 	psg.treble_eq( eq );
258 	dac_synth.treble_eq( eq );
259 }
260 
set_voice(int i,Blip_Buffer * c,Blip_Buffer * l,Blip_Buffer * r)261 void Vgm_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r )
262 {
263 	if ( i < psg.osc_count )
264 		psg.osc_output( i, c, l, r );
265 }
266 
mute_voices_(int mask)267 void Vgm_Emu::mute_voices_( int mask )
268 {
269 	Classic_Emu::mute_voices_( mask );
270 	dac_synth.output( &blip_buf );
271 	if ( uses_fm )
272 	{
273 		psg.output( (mask & 0x80) ? 0 : &blip_buf );
274 		if ( ym2612.enabled() )
275 		{
276 			dac_synth.volume( (mask & 0x40) ? 0.0 : 0.1115 / 256 * fm_gain * gain() );
277 			ym2612.mute_voices( mask );
278 		}
279 
280 		if ( ym2413.enabled() )
281 		{
282 			int m = mask & 0x3F;
283 			if ( mask & 0x20 )
284 				m |= 0x01E0; // channels 5-8
285 			if ( mask & 0x40 )
286 				m |= 0x3E00;
287 			ym2413.mute_voices( m );
288 		}
289 	}
290 }
291 
load_mem_(byte const * new_data,long new_size)292 blargg_err_t Vgm_Emu::load_mem_( byte const* new_data, long new_size )
293 {
294 	assert( offsetof (header_t,unused2 [8]) == header_size );
295 
296 	if ( new_size <= header_size )
297 		return gme_wrong_file_type;
298 
299 	header_t const& h = *(header_t const*) new_data;
300 
301 	RETURN_ERR( check_vgm_header( h ) );
302 
303 	check( get_le32( h.version ) <= 0x150 );
304 
305 	// psg rate
306 	psg_rate = get_le32( h.psg_rate );
307 	if ( !psg_rate )
308 		psg_rate = 3579545;
309 	blip_buf.clock_rate( psg_rate );
310 
311 	data     = new_data;
312 	data_end = new_data + new_size;
313 
314 	// get loop
315 	loop_begin = data_end;
316 	if ( get_le32( h.loop_offset ) )
317 		loop_begin = &data [get_le32( h.loop_offset ) + offsetof (header_t,loop_offset)];
318 
319 	set_voice_count( psg.osc_count );
320 
321 	RETURN_ERR( setup_fm() );
322 
323 	static const char* const fm_names [] = {
324 		"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PCM", "PSG"
325 	};
326 	static const char* const psg_names [] = { "Square 1", "Square 2", "Square 3", "Noise" };
327 	set_voice_names( uses_fm ? fm_names : psg_names );
328 
329 	// do after FM in case output buffer is changed
330 	return Classic_Emu::setup_buffer( psg_rate );
331 }
332 
setup_fm()333 blargg_err_t Vgm_Emu::setup_fm()
334 {
335 	long ym2612_rate = get_le32( header().ym2612_rate );
336 	long ym2413_rate = get_le32( header().ym2413_rate );
337 	if ( ym2413_rate && get_le32( header().version ) < 0x110 )
338 		update_fm_rates( &ym2413_rate, &ym2612_rate );
339 
340 	uses_fm = false;
341 
342 	fm_rate = blip_buf.sample_rate() * oversample_factor;
343 
344 	if ( ym2612_rate )
345 	{
346 		uses_fm = true;
347 		if ( disable_oversampling_ )
348 			fm_rate = ym2612_rate / 144.0;
349 		Dual_Resampler::setup( fm_rate / blip_buf.sample_rate(), rolloff, fm_gain * gain() );
350 		RETURN_ERR( ym2612.set_rate( fm_rate, ym2612_rate ) );
351 		ym2612.enable( true );
352 		set_voice_count( 8 );
353 	}
354 
355 	if ( !uses_fm && ym2413_rate )
356 	{
357 		uses_fm = true;
358 		if ( disable_oversampling_ )
359 			fm_rate = ym2413_rate / 72.0;
360 		Dual_Resampler::setup( fm_rate / blip_buf.sample_rate(), rolloff, fm_gain * gain() );
361 		int result = ym2413.set_rate( fm_rate, ym2413_rate );
362 		if ( result == 2 )
363 			return "YM2413 FM sound isn't supported";
364 		CHECK_ALLOC( !result );
365 		ym2413.enable( true );
366 		set_voice_count( 8 );
367 	}
368 
369 	if ( uses_fm )
370 	{
371 		RETURN_ERR( Dual_Resampler::reset( blip_buf.length() * blip_buf.sample_rate() / 1000 ) );
372 		psg.volume( 0.135 * fm_gain * gain() );
373 	}
374 	else
375 	{
376 		ym2612.enable( false );
377 		ym2413.enable( false );
378 		psg.volume( gain() );
379 	}
380 
381 	return 0;
382 }
383 
384 // Emulation
385 
start_track_(int track)386 blargg_err_t Vgm_Emu::start_track_( int track )
387 {
388 	RETURN_ERR( Classic_Emu::start_track_( track ) );
389 	psg.reset( get_le16( header().noise_feedback ), header().noise_width );
390 
391 	dac_disabled = -1;
392 	pos          = data + header_size;
393 	pcm_data     = pos;
394 	pcm_pos      = pos;
395 	dac_amp      = -1;
396 	vgm_time     = 0;
397 	if ( get_le32( header().version ) >= 0x150 )
398 	{
399 		long data_offset = get_le32( header().data_offset );
400 		check( data_offset );
401 		if ( data_offset )
402 			pos += data_offset + offsetof (header_t,data_offset) - 0x40;
403 	}
404 
405 	if ( uses_fm )
406 	{
407 		if ( ym2413.enabled() )
408 			ym2413.reset();
409 
410 		if ( ym2612.enabled() )
411 			ym2612.reset();
412 
413 		fm_time_offset = 0;
414 		blip_buf.clear();
415 		Dual_Resampler::clear();
416 	}
417 	return 0;
418 }
419 
run_clocks(blip_time_t & time_io,int msec)420 blargg_err_t Vgm_Emu::run_clocks( blip_time_t& time_io, int msec )
421 {
422 	time_io = run_commands( msec * vgm_rate / 1000 );
423 	psg.end_frame( time_io );
424 	return 0;
425 }
426 
play_(long count,sample_t * out)427 blargg_err_t Vgm_Emu::play_( long count, sample_t* out )
428 {
429 	if ( !uses_fm )
430 		return Classic_Emu::play_( count, out );
431 
432 	Dual_Resampler::dual_play( count, out, blip_buf );
433 	return 0;
434 }
435