1 // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
2
3 #include "Music_Emu.h"
4
5 #include "gme_types.h"
6 #if !GME_DISABLE_STEREO_DEPTH
7 #include "Effects_Buffer.h"
8 #endif
9 #include "blargg_endian.h"
10 #include <string.h>
11 #include <ctype.h>
12
13 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you
14 can redistribute it and/or modify it under the terms of the GNU Lesser
15 General Public License as published by the Free Software Foundation; either
16 version 2.1 of the License, or (at your option) any later version. This
17 module is distributed in the hope that it will be useful, but WITHOUT ANY
18 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20 details. You should have received a copy of the GNU Lesser General Public
21 License along with this module; if not, write to the Free Software Foundation,
22 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
23
24 #include "blargg_source.h"
25
gme_type_list()26 BLARGG_EXPORT gme_type_t const* gme_type_list()
27 {
28 static gme_type_t const gme_type_list_ [] = {
29 #ifdef GME_TYPE_LIST
30 GME_TYPE_LIST,
31 #else
32 #ifdef USE_GME_AY
33 gme_ay_type,
34 #endif
35 #ifdef USE_GME_GBS
36 gme_gbs_type,
37 #endif
38 #ifdef USE_GME_GYM
39 gme_gym_type,
40 #endif
41 #ifdef USE_GME_HES
42 gme_hes_type,
43 #endif
44 #ifdef USE_GME_KSS
45 gme_kss_type,
46 #endif
47 #ifdef USE_GME_NSF
48 gme_nsf_type,
49 #endif
50 #ifdef USE_GME_NSFE
51 gme_nsfe_type,
52 #endif
53 #ifdef USE_GME_SAP
54 gme_sap_type,
55 #endif
56 #ifdef USE_GME_SPC
57 gme_spc_type,
58 #endif
59 #ifdef USE_GME_VGM
60 gme_vgm_type,
61 gme_vgz_type,
62 #endif
63 #endif
64 0
65 };
66
67 return gme_type_list_;
68 }
69
gme_identify_header(void const * header)70 BLARGG_EXPORT const char* gme_identify_header( void const* header )
71 {
72 switch ( get_be32( header ) )
73 {
74 case BLARGG_4CHAR('Z','X','A','Y'): return "AY";
75 case BLARGG_4CHAR('G','B','S',0x01): return "GBS";
76 case BLARGG_4CHAR('G','Y','M','X'): return "GYM";
77 case BLARGG_4CHAR('H','E','S','M'): return "HES";
78 case BLARGG_4CHAR('K','S','C','C'):
79 case BLARGG_4CHAR('K','S','S','X'): return "KSS";
80 case BLARGG_4CHAR('N','E','S','M'): return "NSF";
81 case BLARGG_4CHAR('N','S','F','E'): return "NSFE";
82 case BLARGG_4CHAR('S','A','P',0x0D): return "SAP";
83 case BLARGG_4CHAR('S','N','E','S'): return "SPC";
84 case BLARGG_4CHAR('V','g','m',' '): return "VGM";
85 }
86 return "";
87 }
88
to_uppercase(const char * in,int len,char * out)89 static void to_uppercase( const char* in, int len, char* out )
90 {
91 for ( int i = 0; i < len; i++ )
92 {
93 if ( !(out [i] = toupper( in [i] )) )
94 return;
95 }
96 *out = 0; // extension too long
97 }
98
gme_identify_extension(const char * extension_)99 BLARGG_EXPORT gme_type_t gme_identify_extension( const char* extension_ )
100 {
101 char const* end = strrchr( extension_, '.' );
102 if ( end )
103 extension_ = end + 1;
104
105 char extension [6];
106 to_uppercase( extension_, sizeof extension, extension );
107
108 for ( gme_type_t const* types = gme_type_list(); *types; types++ )
109 if ( !strcmp( extension, (*types)->extension_ ) )
110 return *types;
111 return 0;
112 }
113
gme_identify_file(const char * path,gme_type_t * type_out)114 BLARGG_EXPORT gme_err_t gme_identify_file( const char* path, gme_type_t* type_out )
115 {
116 *type_out = gme_identify_extension( path );
117 // TODO: don't examine header if file has extension?
118 if ( !*type_out )
119 {
120 char header [4];
121 GME_FILE_READER in;
122 RETURN_ERR( in.open( path ) );
123 RETURN_ERR( in.read( header, sizeof header ) );
124 *type_out = gme_identify_extension( gme_identify_header( header ) );
125 }
126 return 0;
127 }
128
gme_open_data(void const * data,long size,Music_Emu ** out,int sample_rate)129 BLARGG_EXPORT gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate )
130 {
131 require( (data || !size) && out );
132 *out = 0;
133
134 gme_type_t file_type = 0;
135 if ( size >= 4 )
136 file_type = gme_identify_extension( gme_identify_header( data ) );
137 if ( !file_type )
138 return gme_wrong_file_type;
139
140 Music_Emu* emu = gme_new_emu( file_type, sample_rate );
141 CHECK_ALLOC( emu );
142
143 gme_err_t err = gme_load_data( emu, data, size );
144
145 if ( err )
146 delete emu;
147 else
148 *out = emu;
149
150 return err;
151 }
152
gme_open_file(const char * path,Music_Emu ** out,int sample_rate)153 BLARGG_EXPORT gme_err_t gme_open_file( const char* path, Music_Emu** out, int sample_rate )
154 {
155 require( path && out );
156 *out = 0;
157
158 GME_FILE_READER in;
159 RETURN_ERR( in.open( path ) );
160
161 char header [4];
162 int header_size = 0;
163
164 gme_type_t file_type = gme_identify_extension( path );
165 if ( !file_type )
166 {
167 header_size = sizeof header;
168 RETURN_ERR( in.read( header, sizeof header ) );
169 file_type = gme_identify_extension( gme_identify_header( header ) );
170 }
171 if ( !file_type )
172 return gme_wrong_file_type;
173
174 Music_Emu* emu = gme_new_emu( file_type, sample_rate );
175 CHECK_ALLOC( emu );
176
177 // optimization: avoids seeking/re-reading header
178 Remaining_Reader rem( header, header_size, &in );
179 gme_err_t err = emu->load( rem );
180 in.close();
181
182 if ( err )
183 delete emu;
184 else
185 *out = emu;
186
187 return err;
188 }
189
gme_new_emu(gme_type_t type,int rate)190 BLARGG_EXPORT Music_Emu* gme_new_emu( gme_type_t type, int rate )
191 {
192 if ( type )
193 {
194 if ( rate == gme_info_only )
195 return type->new_info();
196
197 Music_Emu* me = type->new_emu();
198 if ( me )
199 {
200 #if !GME_DISABLE_STEREO_DEPTH
201 if ( type->flags_ & 1 )
202 {
203 me->effects_buffer = BLARGG_NEW Effects_Buffer;
204 if ( me->effects_buffer )
205 me->set_buffer( me->effects_buffer );
206 }
207
208 if ( !(type->flags_ & 1) || me->effects_buffer )
209 #endif
210 {
211 if ( !me->set_sample_rate( rate ) )
212 {
213 check( me->type() == type );
214 return me;
215 }
216 }
217 delete me;
218 }
219 }
220 return 0;
221 }
222
gme_load_file(Music_Emu * me,const char * path)223 BLARGG_EXPORT gme_err_t gme_load_file( Music_Emu* me, const char* path ) { return me->load_file( path ); }
224
gme_load_data(Music_Emu * me,void const * data,long size)225 BLARGG_EXPORT gme_err_t gme_load_data( Music_Emu* me, void const* data, long size )
226 {
227 Mem_File_Reader in( data, size );
228 return me->load( in );
229 }
230
gme_load_custom(Music_Emu * me,gme_reader_t func,long size,void * data)231 BLARGG_EXPORT gme_err_t gme_load_custom( Music_Emu* me, gme_reader_t func, long size, void* data )
232 {
233 Callback_Reader in( func, size, data );
234 return me->load( in );
235 }
236
gme_delete(Music_Emu * me)237 BLARGG_EXPORT void gme_delete( Music_Emu* me ) { delete me; }
238
gme_type(Music_Emu const * me)239 BLARGG_EXPORT gme_type_t gme_type( Music_Emu const* me ) { return me->type(); }
240
gme_warning(Music_Emu * me)241 BLARGG_EXPORT const char* gme_warning( Music_Emu* me ) { return me->warning(); }
242
gme_track_count(Music_Emu const * me)243 BLARGG_EXPORT int gme_track_count( Music_Emu const* me ) { return me->track_count(); }
244
245 struct gme_info_t_ : gme_info_t
246 {
247 track_info_t info;
248
249 BLARGG_DISABLE_NOTHROW
250 };
251
gme_track_info(Music_Emu const * me,gme_info_t ** out,int track)252 BLARGG_EXPORT gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, int track )
253 {
254 *out = NULL;
255
256 gme_info_t_* info = BLARGG_NEW gme_info_t_;
257 CHECK_ALLOC( info );
258
259 gme_err_t err = me->track_info( &info->info, track );
260 if ( err )
261 {
262 gme_free_info( info );
263 return err;
264 }
265
266 #define COPY(name) info->name = info->info.name;
267
268 COPY( length );
269 COPY( intro_length );
270 COPY( loop_length );
271
272 info->i4 = -1;
273 info->i5 = -1;
274 info->i6 = -1;
275 info->i7 = -1;
276 info->i8 = -1;
277 info->i9 = -1;
278 info->i10 = -1;
279 info->i11 = -1;
280 info->i12 = -1;
281 info->i13 = -1;
282 info->i14 = -1;
283 info->i15 = -1;
284
285 info->s7 = "";
286 info->s8 = "";
287 info->s9 = "";
288 info->s10 = "";
289 info->s11 = "";
290 info->s12 = "";
291 info->s13 = "";
292 info->s14 = "";
293 info->s15 = "";
294
295 COPY( system );
296 COPY( game );
297 COPY( song );
298 COPY( author );
299 COPY( copyright );
300 COPY( comment );
301 COPY( dumper );
302
303 #undef COPY
304
305 info->play_length = info->length;
306 if ( info->play_length <= 0 )
307 {
308 info->play_length = info->intro_length + 2 * info->loop_length; // intro + 2 loops
309 if ( info->play_length <= 0 )
310 info->play_length = 150 * 1000; // 2.5 minutes
311 }
312
313 *out = info;
314
315 return 0;
316 }
317
gme_free_info(gme_info_t * info)318 BLARGG_EXPORT void gme_free_info( gme_info_t* info )
319 {
320 delete STATIC_CAST(gme_info_t_*,info);
321 }
322
gme_set_stereo_depth(Music_Emu * me,double depth)323 BLARGG_EXPORT void gme_set_stereo_depth( Music_Emu* me, double depth )
324 {
325 #if !GME_DISABLE_STEREO_DEPTH
326 if ( me->effects_buffer )
327 STATIC_CAST(Effects_Buffer*,me->effects_buffer)->set_depth( depth );
328 #endif
329 }
330
gme_user_data(Music_Emu const * me)331 BLARGG_EXPORT void* gme_user_data ( Music_Emu const* me ) { return me->user_data(); }
gme_set_user_data(Music_Emu * me,void * new_user_data)332 BLARGG_EXPORT void gme_set_user_data ( Music_Emu* me, void* new_user_data ) { me->set_user_data( new_user_data ); }
gme_set_user_cleanup(Music_Emu * me,gme_user_cleanup_t func)333 BLARGG_EXPORT void gme_set_user_cleanup(Music_Emu* me, gme_user_cleanup_t func ) { me->set_user_cleanup( func ); }
334
gme_start_track(Music_Emu * me,int index)335 BLARGG_EXPORT gme_err_t gme_start_track ( Music_Emu* me, int index ) { return me->start_track( index ); }
gme_play(Music_Emu * me,int n,short * p)336 BLARGG_EXPORT gme_err_t gme_play ( Music_Emu* me, int n, short* p ) { return me->play( n, p ); }
gme_set_fade(Music_Emu * me,int start_msec)337 BLARGG_EXPORT void gme_set_fade ( Music_Emu* me, int start_msec ) { me->set_fade( start_msec ); }
gme_track_ended(Music_Emu const * me)338 BLARGG_EXPORT int gme_track_ended ( Music_Emu const* me ) { return me->track_ended(); }
gme_tell(Music_Emu const * me)339 BLARGG_EXPORT int gme_tell ( Music_Emu const* me ) { return me->tell(); }
gme_tell_samples(Music_Emu const * me)340 BLARGG_EXPORT int gme_tell_samples ( Music_Emu const* me ) { return me->tell_samples(); }
gme_seek(Music_Emu * me,int msec)341 BLARGG_EXPORT gme_err_t gme_seek ( Music_Emu* me, int msec ) { return me->seek( msec ); }
gme_seek_samples(Music_Emu * me,int n)342 BLARGG_EXPORT gme_err_t gme_seek_samples ( Music_Emu* me, int n ) { return me->seek_samples( n ); }
gme_voice_count(Music_Emu const * me)343 BLARGG_EXPORT int gme_voice_count ( Music_Emu const* me ) { return me->voice_count(); }
gme_ignore_silence(Music_Emu * me,int disable)344 BLARGG_EXPORT void gme_ignore_silence ( Music_Emu* me, int disable ) { me->ignore_silence( disable != 0 ); }
gme_set_tempo(Music_Emu * me,double t)345 BLARGG_EXPORT void gme_set_tempo ( Music_Emu* me, double t ) { me->set_tempo( t ); }
gme_mute_voice(Music_Emu * me,int index,int mute)346 BLARGG_EXPORT void gme_mute_voice ( Music_Emu* me, int index, int mute ) { me->mute_voice( index, mute != 0 ); }
gme_mute_voices(Music_Emu * me,int mask)347 BLARGG_EXPORT void gme_mute_voices ( Music_Emu* me, int mask ) { me->mute_voices( mask ); }
gme_enable_accuracy(Music_Emu * me,int enabled)348 BLARGG_EXPORT void gme_enable_accuracy( Music_Emu* me, int enabled ) { me->enable_accuracy( enabled ); }
gme_clear_playlist(Music_Emu * me)349 BLARGG_EXPORT void gme_clear_playlist ( Music_Emu* me ) { me->clear_playlist(); }
gme_type_multitrack(gme_type_t t)350 BLARGG_EXPORT int gme_type_multitrack( gme_type_t t ) { return t->track_count != 1; }
351
gme_set_equalizer(Music_Emu * me,gme_equalizer_t const * eq)352 BLARGG_EXPORT void gme_set_equalizer ( Music_Emu* me, gme_equalizer_t const* eq )
353 {
354 Music_Emu::equalizer_t e = me->equalizer();
355 e.treble = eq->treble;
356 e.bass = eq->bass;
357 me->set_equalizer( e );
358 }
359
gme_equalizer(Music_Emu const * me,gme_equalizer_t * out)360 BLARGG_EXPORT void gme_equalizer( Music_Emu const* me, gme_equalizer_t* out )
361 {
362 gme_equalizer_t e = gme_equalizer_t(); // Default-init all fields to 0.0f
363 e.treble = me->equalizer().treble;
364 e.bass = me->equalizer().bass;
365 *out = e;
366 }
367
gme_voice_name(Music_Emu const * me,int i)368 BLARGG_EXPORT const char* gme_voice_name( Music_Emu const* me, int i )
369 {
370 assert( (unsigned) i < (unsigned) me->voice_count() );
371 return me->voice_names() [i];
372 }
373
gme_type_system(gme_type_t type)374 BLARGG_EXPORT const char* gme_type_system( gme_type_t type )
375 {
376 assert( type );
377 return type->system;
378 }
379