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