1 // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
2
3 #include "Vgm_Emu.h"
4
5 #include <math.h>
6 #include <string.h>
7 #include "blargg_endian.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 enum {
23 cmd_gg_stereo = 0x4F,
24 cmd_psg = 0x50,
25 cmd_ym2413 = 0x51,
26 cmd_ym2612_port0 = 0x52,
27 cmd_ym2612_port1 = 0x53,
28 cmd_ym2151 = 0x54,
29 cmd_delay = 0x61,
30 cmd_delay_735 = 0x62,
31 cmd_delay_882 = 0x63,
32 cmd_byte_delay = 0x64,
33 cmd_end = 0x66,
34 cmd_data_block = 0x67,
35 cmd_short_delay = 0x70,
36 cmd_pcm_delay = 0x80,
37 cmd_pcm_seek = 0xE0,
38
39 pcm_block_type = 0x00,
40 ym2612_dac_port = 0x2A
41 };
42
command_len(int command)43 inline int command_len( int command )
44 {
45 switch ( command >> 4 )
46 {
47 case 0x03:
48 case 0x04:
49 return 2;
50
51 case 0x05:
52 case 0x0A:
53 case 0x0B:
54 return 3;
55
56 case 0x0C:
57 case 0x0D:
58 return 4;
59
60 case 0x0E:
61 case 0x0F:
62 return 5;
63 }
64
65 check( false );
66 return 1;
67 }
68
69 template<class Emu>
begin_frame(short * p)70 inline void Ym_Emu<Emu>::begin_frame( short* p )
71 {
72 require( enabled() );
73 out = p;
74 last_time = 0;
75 }
76
77 template<class Emu>
run_until(int time)78 inline int Ym_Emu<Emu>::run_until( int time )
79 {
80 int count = time - last_time;
81 if ( count > 0 )
82 {
83 if ( last_time < 0 )
84 return false;
85 last_time = time;
86 short* p = out;
87 out += count * Emu::out_chan_count;
88 Emu::run( count, p );
89 }
90 return true;
91 }
92
to_fm_time(vgm_time_t t) const93 inline Vgm_Emu_Impl::fm_time_t Vgm_Emu_Impl::to_fm_time( vgm_time_t t ) const
94 {
95 return (t * fm_time_factor + fm_time_offset) >> fm_time_bits;
96 }
97
to_blip_time(vgm_time_t t) const98 inline blip_time_t Vgm_Emu_Impl::to_blip_time( vgm_time_t t ) const
99 {
100 return (t * blip_time_factor) >> blip_time_bits;
101 }
102
write_pcm(vgm_time_t vgm_time,int amp)103 void Vgm_Emu_Impl::write_pcm( vgm_time_t vgm_time, int amp )
104 {
105 blip_time_t blip_time = to_blip_time( vgm_time );
106 int old = dac_amp;
107 int delta = amp - old;
108 dac_amp = amp;
109 if ( old >= 0 )
110 dac_synth.offset_inline( blip_time, delta, &blip_buf );
111 else
112 dac_amp |= dac_disabled;
113 }
114
run_commands(vgm_time_t end_time)115 blip_time_t Vgm_Emu_Impl::run_commands( vgm_time_t end_time )
116 {
117 vgm_time_t vgm_time = this->vgm_time;
118 byte const* pos = this->pos;
119 if ( pos >= data_end )
120 {
121 set_track_ended();
122 if ( pos > data_end )
123 set_warning( "Stream lacked end event" );
124 }
125
126 while ( vgm_time < end_time && pos < data_end )
127 {
128 // TODO: be sure there are enough bytes left in stream for particular command
129 // so we don't read past end
130 switch ( *pos++ )
131 {
132 case cmd_end:
133 pos = loop_begin; // if not looped, loop_begin == data_end
134 break;
135
136 case cmd_delay_735:
137 vgm_time += 735;
138 break;
139
140 case cmd_delay_882:
141 vgm_time += 882;
142 break;
143
144 case cmd_gg_stereo:
145 psg.write_ggstereo( to_blip_time( vgm_time ), *pos++ );
146 break;
147
148 case cmd_psg:
149 psg.write_data( to_blip_time( vgm_time ), *pos++ );
150 break;
151
152 case cmd_delay:
153 vgm_time += pos [1] * 0x100L + pos [0];
154 pos += 2;
155 break;
156
157 case cmd_byte_delay:
158 vgm_time += *pos++;
159 break;
160
161 case cmd_ym2413:
162 if ( ym2413.run_until( to_fm_time( vgm_time ) ) )
163 ym2413.write( pos [0], pos [1] );
164 pos += 2;
165 break;
166
167 case cmd_ym2612_port0:
168 if ( pos [0] == ym2612_dac_port )
169 {
170 write_pcm( vgm_time, pos [1] );
171 }
172 else if ( ym2612.run_until( to_fm_time( vgm_time ) ) )
173 {
174 if ( pos [0] == 0x2B )
175 {
176 dac_disabled = (pos [1] >> 7 & 1) - 1;
177 dac_amp |= dac_disabled;
178 }
179 ym2612.write0( pos [0], pos [1] );
180 }
181 pos += 2;
182 break;
183
184 case cmd_ym2612_port1:
185 if ( ym2612.run_until( to_fm_time( vgm_time ) ) )
186 ym2612.write1( pos [0], pos [1] );
187 pos += 2;
188 break;
189
190 case cmd_data_block: {
191 check( *pos == cmd_end );
192 int type = pos [1];
193 long size = get_le32( pos + 2 );
194 pos += 6;
195 if ( type == pcm_block_type )
196 pcm_data = pos;
197 pos += size;
198 break;
199 }
200
201 case cmd_pcm_seek:
202 pcm_pos = pcm_data + pos [3] * 0x1000000L + pos [2] * 0x10000L +
203 pos [1] * 0x100L + pos [0];
204 pos += 4;
205 break;
206
207 default:
208 int cmd = pos [-1];
209 switch ( cmd & 0xF0 )
210 {
211 case cmd_pcm_delay:
212 write_pcm( vgm_time, *pcm_pos++ );
213 vgm_time += cmd & 0x0F;
214 break;
215
216 case cmd_short_delay:
217 vgm_time += (cmd & 0x0F) + 1;
218 break;
219
220 case 0x50:
221 pos += 2;
222 break;
223
224 default:
225 pos += command_len( cmd ) - 1;
226 set_warning( "Unknown stream event" );
227 }
228 }
229 }
230 vgm_time -= end_time;
231 this->pos = pos;
232 this->vgm_time = vgm_time;
233
234 return to_blip_time( end_time );
235 }
236
play_frame(blip_time_t blip_time,int sample_count,sample_t * buf)237 int Vgm_Emu_Impl::play_frame( blip_time_t blip_time, int sample_count, sample_t* buf )
238 {
239 // to do: timing is working mostly by luck
240
241 int min_pairs = sample_count >> 1;
242 int vgm_time = ((long) min_pairs << fm_time_bits) / fm_time_factor - 1;
243 assert( to_fm_time( vgm_time ) <= min_pairs );
244 int pairs = min_pairs;
245 while ( (pairs = to_fm_time( vgm_time )) < min_pairs )
246 vgm_time++;
247 //debug_printf( "pairs: %d, min_pairs: %d\n", pairs, min_pairs );
248
249 if ( ym2612.enabled() )
250 {
251 ym2612.begin_frame( buf );
252 memset( buf, 0, pairs * stereo * sizeof *buf );
253 }
254 else if ( ym2413.enabled() )
255 {
256 ym2413.begin_frame( buf );
257 }
258
259 run_commands( vgm_time );
260 ym2612.run_until( pairs );
261 ym2413.run_until( pairs );
262
263 fm_time_offset = (vgm_time * fm_time_factor + fm_time_offset) -
264 ((long) pairs << fm_time_bits);
265
266 psg.end_frame( blip_time );
267
268 return pairs * stereo;
269 }
270
271 // Update pre-1.10 header FM rates by scanning commands
update_fm_rates(long * ym2413_rate,long * ym2612_rate) const272 void Vgm_Emu_Impl::update_fm_rates( long* ym2413_rate, long* ym2612_rate ) const
273 {
274 byte const* p = data + 0x40;
275 while ( p < data_end )
276 {
277 switch ( *p )
278 {
279 case cmd_end:
280 return;
281
282 case cmd_psg:
283 case cmd_byte_delay:
284 p += 2;
285 break;
286
287 case cmd_delay:
288 p += 3;
289 break;
290
291 case cmd_data_block:
292 p += 7 + get_le32( p + 3 );
293 break;
294
295 case cmd_ym2413:
296 *ym2612_rate = 0;
297 return;
298
299 case cmd_ym2612_port0:
300 case cmd_ym2612_port1:
301 *ym2612_rate = *ym2413_rate;
302 *ym2413_rate = 0;
303 return;
304
305 case cmd_ym2151:
306 *ym2413_rate = 0;
307 *ym2612_rate = 0;
308 return;
309
310 default:
311 p += command_len( *p );
312 }
313 }
314 }
315