comparison src/Input/console/Vgm_Emu.cxx @ 0:13389e613d67 trunk

[svn] - initial import of audacious-plugins tree (lots to do)
author nenolod
date Mon, 18 Sep 2006 01:11:49 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:13389e613d67
1
2 // Game_Music_Emu 0.3.0. http://www.slack.net/~ant/
3
4 #include "Vgm_Emu.h"
5
6 #include <math.h>
7 #include <string.h>
8 #include "blargg_endian.h"
9
10 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you
11 can redistribute it and/or modify it under the terms of the GNU Lesser
12 General Public License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version. This
14 module is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17 more details. You should have received a copy of the GNU Lesser General
18 Public License along with this module; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
20
21 #include BLARGG_SOURCE_BEGIN
22
23 double const gain = 3.0; // FM emulators are internally quieter to avoid 16-bit overflow
24 double const rolloff = 0.990;
25 double const oversample_factor = 1.5;
26
27 Vgm_Emu::Vgm_Emu( bool os, double tempo )
28 {
29 oversample = os;
30 pos = NULL;
31 data = NULL;
32 uses_fm = false;
33 vgm_rate = (long) (header_t::time_rate * tempo + 0.5);
34
35 static equalizer_t const eq = { -14.0, 80 };
36 set_equalizer( eq );
37 psg.volume( 1.0 );
38 }
39
40 Vgm_Emu::~Vgm_Emu()
41 {
42 unload();
43 }
44
45 void Vgm_Emu::unload()
46 {
47 data = NULL;
48 pos = NULL;
49 set_track_ended( false );
50 mem.clear();
51 }
52
53 blargg_err_t Vgm_Emu::set_sample_rate( long sample_rate )
54 {
55 BLARGG_RETURN_ERR( blip_buf.set_sample_rate( sample_rate, 1000 / 30 ) );
56 return Classic_Emu::set_sample_rate( sample_rate );
57 }
58
59 BOOST::uint8_t const* Vgm_Emu::gd3_data( int* size ) const
60 {
61 if ( size )
62 *size = 0;
63
64 long gd3_offset = get_le32( header_.gd3_offset );
65 if ( !gd3_offset )
66 return NULL;
67
68 gd3_offset -= 0x40 - offsetof (header_t,gd3_offset);
69 if ( gd3_offset < 0 )
70 return NULL;
71
72 byte const* gd3 = data + gd3_offset;
73 if ( data_end - gd3 < 16 || 0 != memcmp( gd3, "Gd3 ", 4 ) || get_le32( gd3 + 4 ) >= 0x200 )
74 return NULL;
75
76 long gd3_size = get_le32( gd3 + 8 );
77 if ( data_end - gd3 < gd3_size - 12 )
78 return NULL;
79
80 if ( size )
81 *size = data_end - gd3;
82 return gd3;
83 }
84
85 void Vgm_Emu::update_eq( blip_eq_t const& eq )
86 {
87 psg.treble_eq( eq );
88 dac_synth.treble_eq( eq );
89 }
90
91 void Vgm_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r )
92 {
93 if ( i < psg.osc_count )
94 psg.osc_output( i, c, l, r );
95 }
96
97 const char** Vgm_Emu::voice_names() const
98 {
99 static const char* fm_names [] = {
100 "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PCM", "PSG"
101 };
102 if ( uses_fm )
103 return fm_names;
104
105 static const char* psg_names [] = { "Square 1", "Square 2", "Square 3", "Noise" };
106 return psg_names;
107 }
108
109 void Vgm_Emu::mute_voices( int mask )
110 {
111 Classic_Emu::mute_voices( mask );
112 dac_synth.output( &blip_buf );
113 if ( uses_fm )
114 {
115 psg.output( (mask & 0x80) ? 0 : &blip_buf );
116 if ( ym2612.enabled() )
117 {
118 dac_synth.volume( (mask & 0x40) ? 0.0 : 0.1115 / 256 * gain );
119 ym2612.mute_voices( mask );
120 }
121
122 if ( ym2413.enabled() )
123 {
124 int m = mask & 0x3f;
125 if ( mask & 0x20 )
126 m |= 0x01e0; // channels 5-8
127 if ( mask & 0x40 )
128 m |= 0x3e00;
129 ym2413.mute_voices( m );
130 }
131 }
132 }
133
134 blargg_err_t Vgm_Emu::load_( const header_t& h, void const* new_data, long new_size )
135 {
136 header_ = h;
137
138 // compatibility
139 if ( 0 != memcmp( header_.tag, "Vgm ", 4 ) )
140 return "Not a VGM file";
141 check( get_le32( header_.version ) <= 0x150 );
142
143 // psg rate
144 long psg_rate = get_le32( header_.psg_rate );
145 if ( !psg_rate )
146 psg_rate = 3579545;
147 blip_time_factor = (long) floor( (double) (1L << blip_time_bits) / vgm_rate * psg_rate + 0.5 );
148 blip_buf.clock_rate( psg_rate );
149
150 data = (byte*) new_data;
151 data_end = data + new_size;
152
153 // get loop
154 loop_begin = data_end;
155 if ( get_le32( header_.loop_offset ) )
156 loop_begin = &data [get_le32( header_.loop_offset ) + offsetof (header_t,loop_offset) - 0x40];
157
158 set_voice_count( psg.osc_count );
159 set_track_count( 1 );
160
161 BLARGG_RETURN_ERR( setup_fm() );
162
163 // do after FM in case output buffer is changed
164 BLARGG_RETURN_ERR( Classic_Emu::setup_buffer( psg_rate ) );
165
166 return blargg_success;
167 }
168
169 blargg_err_t Vgm_Emu::setup_fm()
170 {
171 long ym2612_rate = get_le32( header_.ym2612_rate );
172 long ym2413_rate = get_le32( header_.ym2413_rate );
173 if ( ym2413_rate && get_le32( header_.version ) < 0x110 )
174 update_fm_rates( &ym2413_rate, &ym2612_rate );
175
176 uses_fm = false;
177
178 double fm_rate = blip_buf.sample_rate() * oversample_factor;
179
180 if ( ym2612_rate )
181 {
182 uses_fm = true;
183 if ( !oversample )
184 fm_rate = ym2612_rate / 144.0;
185 Dual_Resampler::setup( fm_rate / blip_buf.sample_rate(), rolloff, gain );
186 BLARGG_RETURN_ERR( ym2612.set_rate( fm_rate, ym2612_rate ) );
187 ym2612.enable( true );
188 set_voice_count( 8 );
189 }
190
191 if ( !uses_fm && ym2413_rate )
192 {
193 uses_fm = true;
194 if ( !oversample )
195 fm_rate = ym2413_rate / 72.0;
196 Dual_Resampler::setup( fm_rate / blip_buf.sample_rate(), rolloff, gain );
197 int result = ym2413.set_rate( fm_rate, ym2413_rate );
198 if ( result == 2 )
199 return "YM2413 FM sound isn't supported";
200 BLARGG_CHECK_ALLOC( !result );
201 ym2413.enable( true );
202 set_voice_count( 8 );
203 }
204
205 if ( uses_fm )
206 {
207 //dprintf( "fm_rate: %f\n", fm_rate );
208 fm_time_factor = 2 + (long) floor( fm_rate * (1L << fm_time_bits) / vgm_rate + 0.5 );
209 BLARGG_RETURN_ERR( Dual_Resampler::resize( blip_buf.length() * blip_buf.sample_rate() / 1000 ) );
210 psg.volume( 0.135 * gain );
211 }
212 else
213 {
214 ym2612.enable( false );
215 ym2413.enable( false );
216 psg.volume( 1.0 );
217 }
218
219 return blargg_success;
220 }
221
222 blargg_err_t Vgm_Emu::load( Data_Reader& reader )
223 {
224 header_t h;
225 BLARGG_RETURN_ERR( reader.read( &h, sizeof h ) );
226 return load( h, reader );
227 }
228
229 blargg_err_t Vgm_Emu::load( const header_t& h, Data_Reader& reader )
230 {
231 unload();
232
233 // allocate and read data
234 long data_size = reader.remain();
235 int const padding = 8;
236 BLARGG_RETURN_ERR( mem.resize( data_size + padding ) );
237 blargg_err_t err = reader.read( mem.begin(), data_size );
238 if ( err ) {
239 unload();
240 return err;
241 }
242 memset( &mem [data_size], 0x66, padding ); // pad with end command
243
244 return load_( h, mem.begin(), data_size );
245 }
246
247 void Vgm_Emu::start_track( int track )
248 {
249 require( data ); // file must have been loaded
250
251 Classic_Emu::start_track( track );
252 psg.reset();
253
254 dac_disabled = -1;
255 pcm_data = data;
256 pcm_pos = data;
257 dac_amp = -1;
258 vgm_time = 0;
259 pos = data;
260 if ( get_le32( header_.version ) >= 0x150 )
261 {
262 long data_offset = get_le32( header_.data_offset );
263 check( data_offset );
264 if ( data_offset )
265 pos += data_offset + offsetof (header_t,data_offset) - 0x40;
266 }
267
268 if ( uses_fm )
269 {
270 if ( ym2413.enabled() )
271 ym2413.reset();
272
273 if ( ym2612.enabled() )
274 ym2612.reset();
275
276 fm_time_offset = 0;
277 blip_buf.clear();
278 Dual_Resampler::clear();
279 }
280 }
281
282 long Vgm_Emu::run( int msec, bool* added_stereo )
283 {
284 blip_time_t psg_end = run_commands( msec * vgm_rate / 1000 );
285 *added_stereo = psg.end_frame( psg_end );
286 return psg_end;
287 }
288
289 void Vgm_Emu::play( long count, sample_t* out )
290 {
291 require( pos ); // track must have been started
292
293 if ( uses_fm )
294 Dual_Resampler::play( count, out, blip_buf );
295 else
296 Classic_Emu::play( count, out );
297 }
298