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