1 // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
2 
3 #include "Music_Player.h"
4 
5 #include <string.h>
6 #include <ctype.h>
7 
8 /* Copyright (C) 2005-2010 by Shay Green. Permission is hereby granted, free of
9 charge, to any person obtaining a copy of this software module and associated
10 documentation files (the "Software"), to deal in the Software without
11 restriction, including without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell copies of the Software, and
13 to permit persons to whom the Software is furnished to do so, subject to the
14 following conditions: The above copyright notice and this permission notice
15 shall be included in all copies or substantial portions of the Software. THE
16 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
17 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
18 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
22 
23 #define RETURN_ERR( expr ) \
24 	do {\
25 		gme_err_t err_ = (expr);\
26 		if ( err_ )\
27 			return err_;\
28 	} while ( 0 )
29 
30 // Number of audio buffers per second. Adjust if you encounter audio skipping.
31 const int fill_rate = 45;
32 
33 // Simple sound driver using SDL
34 typedef void (*sound_callback_t)( void* data, short* out, int count );
35 static const char* sound_init( long sample_rate, int buf_size, sound_callback_t, void* data );
36 static void sound_start();
37 static void sound_stop();
38 static void sound_cleanup();
39 
Music_Player()40 Music_Player::Music_Player()
41 {
42 	emu_        = 0;
43 	scope_buf   = 0;
44 	paused      = false;
45 	track_info_ = NULL;
46 }
47 
init(long rate)48 gme_err_t Music_Player::init( long rate )
49 {
50 	sample_rate = rate;
51 
52 	int min_size = sample_rate * 2 / fill_rate;
53 	int buf_size = 512;
54 	while ( buf_size < min_size )
55 		buf_size *= 2;
56 
57 	return sound_init( sample_rate, buf_size, fill_buffer, this );
58 }
59 
stop()60 void Music_Player::stop()
61 {
62 	sound_stop();
63 	gme_delete( emu_ );
64 	emu_ = NULL;
65 }
66 
~Music_Player()67 Music_Player::~Music_Player()
68 {
69 	stop();
70 	sound_cleanup();
71 	gme_free_info( track_info_ );
72 }
73 
load_file(const char * path)74 gme_err_t Music_Player::load_file( const char* path )
75 {
76 	stop();
77 
78 	RETURN_ERR( gme_open_file( path, &emu_, sample_rate ) );
79 
80 	char m3u_path [256 + 5];
81 	strncpy( m3u_path, path, 256 );
82 	m3u_path [256] = 0;
83 	char* p = strrchr( m3u_path, '.' );
84 	if ( !p )
85 		p = m3u_path + strlen( m3u_path );
86 	strcpy( p, ".m3u" );
87 	if ( gme_load_m3u( emu_, m3u_path ) ) { } // ignore error
88 
89 	return 0;
90 }
91 
track_count() const92 int Music_Player::track_count() const
93 {
94 	return emu_ ? gme_track_count( emu_ ) : false;
95 }
96 
start_track(int track)97 gme_err_t Music_Player::start_track( int track )
98 {
99 	if ( emu_ )
100 	{
101 		gme_free_info( track_info_ );
102 		track_info_ = NULL;
103 		RETURN_ERR( gme_track_info( emu_, &track_info_, track ) );
104 
105 		// Sound must not be running when operating on emulator
106 		sound_stop();
107 		RETURN_ERR( gme_start_track( emu_, track ) );
108 
109 		// Calculate track length
110 		if ( track_info_->length <= 0 )
111 			track_info_->length = track_info_->intro_length +
112 						track_info_->loop_length * 2;
113 
114 		if ( track_info_->length <= 0 )
115 			track_info_->length = (long) (2.5 * 60 * 1000);
116 		gme_set_fade( emu_, track_info_->length );
117 
118 		paused = false;
119 		sound_start();
120 	}
121 	return 0;
122 }
123 
pause(int b)124 void Music_Player::pause( int b )
125 {
126 	paused = b;
127 	if ( b )
128 		sound_stop();
129 	else
130 		sound_start();
131 }
132 
suspend()133 void Music_Player::suspend()
134 {
135 	if ( !paused )
136 		sound_stop();
137 }
138 
resume()139 void Music_Player::resume()
140 {
141 	if ( !paused )
142 		sound_start();
143 }
144 
track_ended() const145 bool Music_Player::track_ended() const
146 {
147 	return emu_ ? gme_track_ended( emu_ ) : false;
148 }
149 
set_stereo_depth(double tempo)150 void Music_Player::set_stereo_depth( double tempo )
151 {
152 	suspend();
153 	gme_set_stereo_depth( emu_, tempo );
154 	resume();
155 }
156 
enable_accuracy(bool b)157 void Music_Player::enable_accuracy( bool b )
158 {
159 	suspend();
160 	gme_enable_accuracy( emu_, b );
161 	resume();
162 }
163 
set_tempo(double tempo)164 void Music_Player::set_tempo( double tempo )
165 {
166 	suspend();
167 	gme_set_tempo( emu_, tempo );
168 	resume();
169 }
170 
mute_voices(int mask)171 void Music_Player::mute_voices( int mask )
172 {
173 	suspend();
174 	gme_mute_voices( emu_, mask );
175 	gme_ignore_silence( emu_, mask != 0 );
176 	resume();
177 }
178 
fill_buffer(void * data,sample_t * out,int count)179 void Music_Player::fill_buffer( void* data, sample_t* out, int count )
180 {
181 	Music_Player* self = (Music_Player*) data;
182 	if ( self->emu_ )
183 	{
184 		if ( gme_play( self->emu_, count, out ) ) { } // ignore error
185 
186 		if ( self->scope_buf )
187 			memcpy( self->scope_buf, out, self->scope_buf_size * sizeof *self->scope_buf );
188 	}
189 }
190 
191 // Sound output driver using SDL
192 
193 #include "SDL.h"
194 
195 static sound_callback_t sound_callback;
196 static void* sound_callback_data;
197 
sdl_callback(void * data,Uint8 * out,int count)198 static void sdl_callback( void* data, Uint8* out, int count )
199 {
200 	if ( sound_callback )
201 		sound_callback( sound_callback_data, (short*) out, count / 2 );
202 }
203 
sound_init(long sample_rate,int buf_size,sound_callback_t cb,void * data)204 static const char* sound_init( long sample_rate, int buf_size,
205 		sound_callback_t cb, void* data )
206 {
207 	sound_callback = cb;
208 	sound_callback_data = data;
209 
210 	static SDL_AudioSpec as; // making static clears all fields to 0
211 	as.freq     = sample_rate;
212 	as.format   = AUDIO_S16SYS;
213 	as.channels = 2;
214 	as.callback = sdl_callback;
215 	as.samples  = buf_size;
216 	if ( SDL_OpenAudio( &as, 0 ) < 0 )
217 	{
218 		const char* err = SDL_GetError();
219 		if ( !err )
220 			err = "Couldn't open SDL audio";
221 		return err;
222 	}
223 
224 	return 0;
225 }
226 
sound_start()227 static void sound_start()
228 {
229 	SDL_PauseAudio( false );
230 }
231 
sound_stop()232 static void sound_stop()
233 {
234 	SDL_PauseAudio( true );
235 
236 	// be sure audio thread is not active
237 	SDL_LockAudio();
238 	SDL_UnlockAudio();
239 }
240 
sound_cleanup()241 static void sound_cleanup()
242 {
243 	sound_stop();
244 	SDL_CloseAudio();
245 }
246