diff options
Diffstat (limited to 'apps/codecs/libgme/hes_emu.c')
-rw-r--r-- | apps/codecs/libgme/hes_emu.c | 581 |
1 files changed, 174 insertions, 407 deletions
diff --git a/apps/codecs/libgme/hes_emu.c b/apps/codecs/libgme/hes_emu.c index a428bee3fd..8ddbb9dc29 100644 --- a/apps/codecs/libgme/hes_emu.c +++ b/apps/codecs/libgme/hes_emu.c | |||
@@ -21,28 +21,14 @@ int const vdp_mask = 0x02; | |||
21 | int const i_flag_mask = 0x04; | 21 | int const i_flag_mask = 0x04; |
22 | int const unmapped = 0xFF; | 22 | int const unmapped = 0xFF; |
23 | 23 | ||
24 | long const period_60hz = 262 * 455L; // scanlines * clocks per scanline | 24 | int const period_60hz = 262 * 455; // scanlines * clocks per scanline |
25 | |||
26 | int const stereo = 2; // number of channels for stereo | ||
27 | int const silence_max = 6; // seconds | ||
28 | int const silence_threshold = 0x10; | ||
29 | long const fade_block_size = 512; | ||
30 | int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) | ||
31 | 25 | ||
32 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; | 26 | const char gme_wrong_file_type [] = "Wrong file type for this emulator"; |
33 | 27 | ||
34 | static void clear_track_vars( struct Hes_Emu* this ) | 28 | static void clear_track_vars( struct Hes_Emu* this ) |
35 | { | 29 | { |
36 | this->current_track_ = -1; | 30 | this->current_track_ = -1; |
37 | this->out_time = 0; | 31 | track_stop( &this->track_filter ); |
38 | this->emu_time = 0; | ||
39 | this->emu_track_ended_ = true; | ||
40 | this->track_ended = true; | ||
41 | this->fade_start = (blargg_long)(LONG_MAX / 2 + 1); | ||
42 | this->fade_step = 1; | ||
43 | this->silence_time = 0; | ||
44 | this->silence_count = 0; | ||
45 | this->buf_remain = 0; | ||
46 | } | 32 | } |
47 | 33 | ||
48 | void Hes_init( struct Hes_Emu* this ) | 34 | void Hes_init( struct Hes_Emu* this ) |
@@ -52,15 +38,12 @@ void Hes_init( struct Hes_Emu* this ) | |||
52 | this->tempo_ = (int)(FP_ONE_TEMPO); | 38 | this->tempo_ = (int)(FP_ONE_TEMPO); |
53 | 39 | ||
54 | // defaults | 40 | // defaults |
55 | this->max_initial_silence = 2; | 41 | this->tfilter = *track_get_setup( &this->track_filter ); |
56 | this->ignore_silence = false; | 42 | this->tfilter.max_initial = 2; |
57 | 43 | this->tfilter.lookahead = 6; | |
58 | // Unload | 44 | this->track_filter.silence_ignored_ = false; |
59 | this->voice_count_ = 0; | ||
60 | clear_track_vars( this ); | ||
61 | 45 | ||
62 | this->timer.raw_load = 0; | 46 | this->timer.raw_load = 0; |
63 | this->silence_lookahead = 6; | ||
64 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.11) ); | 47 | Sound_set_gain( this, (int)(FP_ONE_GAIN*1.11) ); |
65 | 48 | ||
66 | Rom_init( &this->rom, 0x2000 ); | 49 | Rom_init( &this->rom, 0x2000 ); |
@@ -71,6 +54,11 @@ void Hes_init( struct Hes_Emu* this ) | |||
71 | 54 | ||
72 | /* Set default track count */ | 55 | /* Set default track count */ |
73 | this->track_count = 255; | 56 | this->track_count = 255; |
57 | |||
58 | // clears fields | ||
59 | this->voice_count_ = 0; | ||
60 | this->voice_types_ = 0; | ||
61 | clear_track_vars( this ); | ||
74 | } | 62 | } |
75 | 63 | ||
76 | static blargg_err_t check_hes_header( void const* header ) | 64 | static blargg_err_t check_hes_header( void const* header ) |
@@ -82,10 +70,12 @@ static blargg_err_t check_hes_header( void const* header ) | |||
82 | 70 | ||
83 | // Setup | 71 | // Setup |
84 | 72 | ||
85 | blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size ) | 73 | blargg_err_t Hes_load_mem( struct Hes_Emu* this, void* data, long size ) |
86 | { | 74 | { |
87 | // Unload | 75 | // Unload |
88 | this->voice_count_ = 0; | 76 | this->voice_count_ = 0; |
77 | this->track_count = 255; | ||
78 | this->m3u.size = 0; | ||
89 | clear_track_vars( this ); | 79 | clear_track_vars( this ); |
90 | 80 | ||
91 | assert( offsetof (struct header_t,unused [4]) == header_size ); | 81 | assert( offsetof (struct header_t,unused [4]) == header_size ); |
@@ -106,15 +96,15 @@ blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size ) | |||
106 | // many files have bad sizes in the only block, so it's simpler to | 96 | // many files have bad sizes in the only block, so it's simpler to |
107 | // just try to load the damn data as best as possible. | 97 | // just try to load the damn data as best as possible. |
108 | 98 | ||
109 | long addr = get_le32( this->header.addr ); | 99 | int addr = get_le32( this->header.addr ); |
110 | /* long rom_size = get_le32( this->header.size ); */ | 100 | /* int rom_size = get_le32( this->header.size ); */ |
111 | long const rom_max = 0x100000; | 101 | int const rom_max = 0x100000; |
112 | if ( addr & ~(rom_max - 1) ) | 102 | if ( (unsigned) addr >= (unsigned) rom_max ) |
113 | { | 103 | { |
114 | /* warning( "Invalid address" ); */ | 104 | /* warning( "Invalid address" ); */ |
115 | addr &= rom_max - 1; | 105 | addr &= rom_max - 1; |
116 | } | 106 | } |
117 | /* if ( (unsigned long) (addr + size) > (unsigned long) rom_max ) | 107 | /* if ( (unsigned) (addr + size) > (unsigned) rom_max ) |
118 | warning( "Invalid size" ); | 108 | warning( "Invalid size" ); |
119 | 109 | ||
120 | if ( rom_size != rom.file_size() ) | 110 | if ( rom_size != rom.file_size() ) |
@@ -130,6 +120,10 @@ blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size ) | |||
130 | Rom_set_addr( &this->rom, addr ); | 120 | Rom_set_addr( &this->rom, addr ); |
131 | 121 | ||
132 | this->voice_count_ = osc_count + adpcm_osc_count; | 122 | this->voice_count_ = osc_count + adpcm_osc_count; |
123 | static int const types [osc_count + adpcm_osc_count] = { | ||
124 | wave_type+0, wave_type+1, wave_type+2, wave_type+3, mixed_type+0, mixed_type+1, mixed_type+2 | ||
125 | }; | ||
126 | this->voice_types_ = types; | ||
133 | 127 | ||
134 | Apu_volume( &this->apu, this->gain_ ); | 128 | Apu_volume( &this->apu, this->gain_ ); |
135 | Adpcm_volume( &this->adpcm, this->gain_ ); | 129 | Adpcm_volume( &this->adpcm, this->gain_ ); |
@@ -137,21 +131,17 @@ blargg_err_t Hes_load( struct Hes_Emu* this, void* data, long size ) | |||
137 | // Setup buffer | 131 | // Setup buffer |
138 | this->clock_rate_ = 7159091; | 132 | this->clock_rate_ = 7159091; |
139 | Buffer_clock_rate( &this->stereo_buf, 7159091 ); | 133 | Buffer_clock_rate( &this->stereo_buf, 7159091 ); |
134 | RETURN_ERR( Buffer_set_channel_count( &this->stereo_buf, this->voice_count_, this->voice_types_ ) ); | ||
140 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 135 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
141 | 136 | ||
142 | Sound_set_tempo( this, this->tempo_ ); | 137 | Sound_set_tempo( this, this->tempo_ ); |
143 | Sound_mute_voices( this, this->mute_mask_ ); | 138 | Sound_mute_voices( this, this->mute_mask_ ); |
144 | 139 | ||
145 | // Reset track count | ||
146 | this->track_count = 255; | ||
147 | this->m3u.size = 0; | ||
148 | return 0; | 140 | return 0; |
149 | } | 141 | } |
150 | 142 | ||
151 | |||
152 | // Emulation | 143 | // Emulation |
153 | 144 | ||
154 | void recalc_timer_load( struct Hes_Emu* this ); | ||
155 | void recalc_timer_load( struct Hes_Emu* this ) | 145 | void recalc_timer_load( struct Hes_Emu* this ) |
156 | { | 146 | { |
157 | this->timer.load = this->timer.raw_load * this->timer_base + 1; | 147 | this->timer.load = this->timer.raw_load * this->timer_base + 1; |
@@ -159,9 +149,25 @@ void recalc_timer_load( struct Hes_Emu* this ) | |||
159 | 149 | ||
160 | // Hardware | 150 | // Hardware |
161 | 151 | ||
162 | void irq_changed( struct Hes_Emu* this ); | 152 | void run_until( struct Hes_Emu* this, hes_time_t present ) |
163 | void run_until( struct Hes_Emu* this, hes_time_t present ); | 153 | { |
164 | void Cpu_write_vdp( struct Hes_Emu* this, int addr, int data ) | 154 | while ( this->vdp.next_vbl < present ) |
155 | this->vdp.next_vbl += this->play_period; | ||
156 | |||
157 | hes_time_t elapsed = present - this->timer.last_time; | ||
158 | if ( elapsed > 0 ) | ||
159 | { | ||
160 | if ( this->timer.enabled ) | ||
161 | { | ||
162 | this->timer.count -= elapsed; | ||
163 | if ( this->timer.count <= 0 ) | ||
164 | this->timer.count += this->timer.load; | ||
165 | } | ||
166 | this->timer.last_time = present; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | void write_vdp( struct Hes_Emu* this, int addr, int data ) | ||
165 | { | 171 | { |
166 | switch ( addr ) | 172 | switch ( addr ) |
167 | { | 173 | { |
@@ -178,77 +184,33 @@ void Cpu_write_vdp( struct Hes_Emu* this, int addr, int data ) | |||
178 | this->vdp.control = data; | 184 | this->vdp.control = data; |
179 | irq_changed( this ); | 185 | irq_changed( this ); |
180 | } | 186 | } |
181 | else | 187 | /* else |
182 | { | 188 | { |
183 | dprintf( "VDP not supported: $%02X <- $%02X\n", this->vdp.latch, data ); | 189 | dprintf( "VDP not supported: $%02X <- $%02X\n", vdp.latch, data ); |
184 | } | 190 | } */ |
185 | break; | 191 | break; |
186 | 192 | ||
187 | case 3: | 193 | case 3: |
188 | dprintf( "VDP MSB not supported: $%02X <- $%02X\n", this->vdp.latch, data ); | 194 | /* dprintf( "VDP MSB not supported: $%02X <- $%02X\n", vdp.latch, data ); */ |
189 | break; | 195 | break; |
190 | } | 196 | } |
191 | } | 197 | } |
192 | 198 | ||
193 | int Cpu_done( struct Hes_Emu* this ) | 199 | void write_mem_( struct Hes_Emu* this, hes_addr_t addr, int data ) |
194 | { | ||
195 | check( time() >= end_time() || | ||
196 | (!(r.status & i_flag_mask) && time() >= irq_time()) ); | ||
197 | |||
198 | if ( !(this->cpu.r.status & i_flag_mask) ) | ||
199 | { | ||
200 | hes_time_t present = Cpu_time( &this->cpu ); | ||
201 | |||
202 | if ( this->irq.timer <= present && !(this->irq.disables & timer_mask) ) | ||
203 | { | ||
204 | this->timer.fired = true; | ||
205 | this->irq.timer = (hes_time_t)future_hes_time; | ||
206 | irq_changed( this ); // overkill, but not worth writing custom code | ||
207 | #if defined (GME_FRAME_HOOK_DEFINED) | ||
208 | { | ||
209 | unsigned const threshold = period_60hz / 30; | ||
210 | unsigned long elapsed = present - last_frame_hook; | ||
211 | if ( elapsed - period_60hz + threshold / 2 < threshold ) | ||
212 | { | ||
213 | last_frame_hook = present; | ||
214 | GME_FRAME_HOOK( this ); | ||
215 | } | ||
216 | } | ||
217 | #endif | ||
218 | return 0x0A; | ||
219 | } | ||
220 | |||
221 | if ( this->irq.vdp <= present && !(this->irq.disables & vdp_mask) ) | ||
222 | { | ||
223 | // work around for bugs with music not acknowledging VDP | ||
224 | //run_until( present ); | ||
225 | //irq.vdp = future_hes_time; | ||
226 | //irq_changed(); | ||
227 | #if defined(GME_FRAME_HOOK_DEFINED) | ||
228 | last_frame_hook = present; | ||
229 | GME_FRAME_HOOK( this ); | ||
230 | #endif | ||
231 | return 0x08; | ||
232 | } | ||
233 | } | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | ||
238 | { | 200 | { |
239 | hes_time_t time = Cpu_time( &this->cpu ); | 201 | hes_time_t time = Cpu_time( &this->cpu ); |
240 | if ( (unsigned) (addr - start_addr) <= end_addr - start_addr ) | 202 | if ( (unsigned) (addr - apu_io_addr) < apu_io_size ) |
241 | { | 203 | { |
242 | GME_APU_HOOK( this, addr - apu.start_addr, data ); | 204 | // Avoid going way past end when a long block xfer is writing to I/O space. |
243 | // avoid going way past end when a long block xfer is writing to I/O space | 205 | // Not a problem for other registers below because they don't write to |
244 | hes_time_t t = min( time, this->cpu.end_time + 8 ); | 206 | // Blip_Buffer. |
207 | hes_time_t t = min( time, Cpu_end_time( &this->cpu ) + 8 ); | ||
245 | Apu_write_data( &this->apu, t, addr, data ); | 208 | Apu_write_data( &this->apu, t, addr, data ); |
246 | return; | 209 | return; |
247 | } | 210 | } |
248 | 211 | if ( (unsigned) (addr - adpcm_io_addr) < adpcm_io_size ) | |
249 | if ( (unsigned) (addr - io_addr) < io_size ) | ||
250 | { | 212 | { |
251 | hes_time_t t = min( time, this->cpu.end_time + 6 ); | 213 | hes_time_t t = min( time, Cpu_end_time( &this->cpu ) + 6 ); |
252 | Adpcm_write_data( &this->adpcm, t, addr, data ); | 214 | Adpcm_write_data( &this->adpcm, t, addr, data ); |
253 | return; | 215 | return; |
254 | } | 216 | } |
@@ -258,7 +220,7 @@ void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | |||
258 | case 0x0000: | 220 | case 0x0000: |
259 | case 0x0002: | 221 | case 0x0002: |
260 | case 0x0003: | 222 | case 0x0003: |
261 | Cpu_write_vdp( this, addr, data ); | 223 | write_vdp( this, addr, data ); |
262 | return; | 224 | return; |
263 | 225 | ||
264 | case 0x0C00: { | 226 | case 0x0C00: { |
@@ -282,11 +244,8 @@ void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | |||
282 | case 0x1402: | 244 | case 0x1402: |
283 | run_until( this, time ); | 245 | run_until( this, time ); |
284 | this->irq.disables = data; | 246 | this->irq.disables = data; |
285 | 247 | /* if ( (data & 0xF8) && (data & 0xF8) != 0xF8 ) // flag questionable values | |
286 | // flag questionable values | 248 | dprintf( "Int mask: $%02X\n", data ); */ |
287 | if ( (data & 0xF8) && (data & 0xF8) != 0xF8 ) { | ||
288 | dprintf( "Int mask: $%02X\n", data ); | ||
289 | } | ||
290 | break; | 249 | break; |
291 | 250 | ||
292 | case 0x1403: | 251 | case 0x1403: |
@@ -305,7 +264,7 @@ void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | |||
305 | return; | 264 | return; |
306 | 265 | ||
307 | default: | 266 | default: |
308 | dprintf( "unmapped write $%04X <- $%02X\n", addr, data ); | 267 | /* dprintf( "unmapped write $%04X <- $%02X\n", addr, data ); */ |
309 | return; | 268 | return; |
310 | #endif | 269 | #endif |
311 | } | 270 | } |
@@ -313,7 +272,7 @@ void Emu_cpu_write( struct Hes_Emu* this, hes_addr_t addr, int data ) | |||
313 | irq_changed( this ); | 272 | irq_changed( this ); |
314 | } | 273 | } |
315 | 274 | ||
316 | int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t addr ) | 275 | int read_mem_( struct Hes_Emu* this, hes_addr_t addr ) |
317 | { | 276 | { |
318 | hes_time_t time = Cpu_time( &this->cpu ); | 277 | hes_time_t time = Cpu_time( &this->cpu ); |
319 | addr &= page_size - 1; | 278 | addr &= page_size - 1; |
@@ -322,21 +281,21 @@ int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t addr ) | |||
322 | case 0x0000: | 281 | case 0x0000: |
323 | if ( this->irq.vdp > time ) | 282 | if ( this->irq.vdp > time ) |
324 | return 0; | 283 | return 0; |
325 | this->irq.vdp = (hes_time_t)future_hes_time; | 284 | this->irq.vdp = future_time; |
326 | run_until( this, time ); | 285 | run_until( this, time ); |
327 | irq_changed( this ); | 286 | irq_changed( this ); |
328 | return 0x20; | 287 | return 0x20; |
329 | 288 | ||
330 | case 0x0002: | 289 | /* case 0x0002: |
331 | case 0x0003: | 290 | case 0x0003: |
332 | dprintf( "VDP read not supported: %d\n", addr ); | 291 | dprintf( "VDP read not supported: %d\n", addr ); |
333 | return 0; | 292 | return 0; */ |
334 | 293 | ||
335 | case 0x0C01: | 294 | case 0x0C01: |
336 | //return timer.enabled; // TODO: remove? | 295 | //return timer.enabled; // TODO: remove? |
337 | case 0x0C00: | 296 | case 0x0C00: |
338 | run_until( this, time ); | 297 | run_until( this, time ); |
339 | dprintf( "Timer count read\n" ); | 298 | /* dprintf( "Timer count read\n" ); */ |
340 | return (unsigned) (this->timer.count - 1) / this->timer_base; | 299 | return (unsigned) (this->timer.count - 1) / this->timer_base; |
341 | 300 | ||
342 | case 0x1402: | 301 | case 0x1402: |
@@ -349,7 +308,7 @@ int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t addr ) | |||
349 | if ( this->irq.vdp <= time ) status |= vdp_mask; | 308 | if ( this->irq.vdp <= time ) status |= vdp_mask; |
350 | return status; | 309 | return status; |
351 | } | 310 | } |
352 | 311 | ||
353 | case 0x180A: | 312 | case 0x180A: |
354 | case 0x180B: | 313 | case 0x180B: |
355 | case 0x180C: | 314 | case 0x180C: |
@@ -358,71 +317,75 @@ int Emu_cpu_read( struct Hes_Emu* this, hes_addr_t addr ) | |||
358 | 317 | ||
359 | #ifndef NDEBUG | 318 | #ifndef NDEBUG |
360 | case 0x1000: // I/O port | 319 | case 0x1000: // I/O port |
361 | // case 0x180C: // CD-ROM | 320 | //case 0x180C: // CD-ROM |
362 | // case 0x180D: | 321 | //case 0x180D: |
363 | break; | 322 | break; |
364 | 323 | ||
365 | default: | 324 | /* default: |
366 | dprintf( "unmapped read $%04X\n", addr ); | 325 | dprintf( "unmapped read $%04X\n", addr ); */ |
367 | #endif | 326 | #endif |
368 | } | 327 | } |
369 | 328 | ||
370 | return unmapped; | 329 | return unmapped; |
371 | } | 330 | } |
372 | 331 | ||
373 | // see hes_cpu_io.h for core read/write functions | ||
374 | |||
375 | // Emulation | ||
376 | |||
377 | void run_until( struct Hes_Emu* this, hes_time_t present ) | ||
378 | { | ||
379 | while ( this->vdp.next_vbl < present ) | ||
380 | this->vdp.next_vbl += this->play_period; | ||
381 | |||
382 | hes_time_t elapsed = present - this->timer.last_time; | ||
383 | if ( elapsed > 0 ) | ||
384 | { | ||
385 | if ( this->timer.enabled ) | ||
386 | { | ||
387 | this->timer.count -= elapsed; | ||
388 | if ( this->timer.count <= 0 ) | ||
389 | this->timer.count += this->timer.load; | ||
390 | } | ||
391 | this->timer.last_time = present; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | void irq_changed( struct Hes_Emu* this ) | 332 | void irq_changed( struct Hes_Emu* this ) |
396 | { | 333 | { |
397 | hes_time_t present = Cpu_time( &this->cpu ); | 334 | hes_time_t present = Cpu_time( &this->cpu ); |
398 | 335 | ||
399 | if ( this->irq.timer > present ) | 336 | if ( this->irq.timer > present ) |
400 | { | 337 | { |
401 | this->irq.timer = (hes_time_t)future_hes_time; | 338 | this->irq.timer = future_time; |
402 | if ( this->timer.enabled && !this->timer.fired ) | 339 | if ( this->timer.enabled && !this->timer.fired ) |
403 | this->irq.timer = present + this->timer.count; | 340 | this->irq.timer = present + this->timer.count; |
404 | } | 341 | } |
405 | 342 | ||
406 | if ( this->irq.vdp > present ) | 343 | if ( this->irq.vdp > present ) |
407 | { | 344 | { |
408 | this->irq.vdp = (hes_time_t)future_hes_time; | 345 | this->irq.vdp = future_time; |
409 | if ( this->vdp.control & 0x08 ) | 346 | if ( this->vdp.control & 0x08 ) |
410 | this->irq.vdp = this->vdp.next_vbl; | 347 | this->irq.vdp = this->vdp.next_vbl; |
411 | } | 348 | } |
412 | 349 | ||
413 | hes_time_t time = (hes_time_t)future_hes_time; | 350 | hes_time_t time = future_time; |
414 | if ( !(this->irq.disables & timer_mask) ) time = this->irq.timer; | 351 | if ( !(this->irq.disables & timer_mask) ) time = this->irq.timer; |
415 | if ( !(this->irq.disables & vdp_mask) ) time = min( time, this->irq.vdp ); | 352 | if ( !(this->irq.disables & vdp_mask) ) time = min( time, this->irq.vdp ); |
416 | 353 | ||
417 | // Set cpu irq time | 354 | Cpu_set_irq_time( &this->cpu, time ); |
418 | this->cpu.state->time += Cpu_update_end_time( &this->cpu, this->cpu.r.status, | ||
419 | this->cpu.end_time, (this->cpu.irq_time = time) ); | ||
420 | } | 355 | } |
421 | 356 | ||
422 | static void adjust_time( blargg_long* time, hes_time_t delta ); | 357 | int cpu_done( struct Hes_Emu* this ) |
423 | static void adjust_time( blargg_long* time, hes_time_t delta ) | ||
424 | { | 358 | { |
425 | if ( *time < (blargg_long)future_hes_time ) | 359 | check( Cpu_time( &this->cpu ) >= Cpu_end_time( &this->cpu ) || |
360 | (!(this->cpu.r.flags & i_flag_mask) && Cpu_time( &this->cpu ) >= Cpu_irq_time( &this->cpu )) ); | ||
361 | |||
362 | if ( !(this->cpu.r.flags & i_flag_mask) ) | ||
363 | { | ||
364 | hes_time_t present = Cpu_time( &this->cpu ); | ||
365 | |||
366 | if ( this->irq.timer <= present && !(this->irq.disables & timer_mask) ) | ||
367 | { | ||
368 | this->timer.fired = true; | ||
369 | this->irq.timer = future_time; | ||
370 | irq_changed( this ); // overkill, but not worth writing custom code | ||
371 | return 0x0A; | ||
372 | } | ||
373 | |||
374 | if ( this->irq.vdp <= present && !(this->irq.disables & vdp_mask) ) | ||
375 | { | ||
376 | // work around for bugs with music not acknowledging VDP | ||
377 | //run_until( present ); | ||
378 | //irq.vdp = cpu.future_time; | ||
379 | //irq_changed(); | ||
380 | return 0x08; | ||
381 | } | ||
382 | } | ||
383 | return -1; | ||
384 | } | ||
385 | |||
386 | static void adjust_time( hes_time_t* time, hes_time_t delta ) | ||
387 | { | ||
388 | if ( *time < future_time ) | ||
426 | { | 389 | { |
427 | *time -= delta; | 390 | *time -= delta; |
428 | if ( *time < 0 ) | 391 | if ( *time < 0 ) |
@@ -430,15 +393,13 @@ static void adjust_time( blargg_long* time, hes_time_t delta ) | |||
430 | } | 393 | } |
431 | } | 394 | } |
432 | 395 | ||
433 | blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ); | 396 | blargg_err_t end_frame( struct Hes_Emu* this, hes_time_t duration ) |
434 | blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) | ||
435 | { | 397 | { |
436 | blip_time_t duration = *duration_; // cache | 398 | /* if ( run_cpu( this, duration ) ) |
399 | warning( "Emulation error (illegal instruction)" ); */ | ||
400 | run_cpu( this, duration ); | ||
437 | 401 | ||
438 | Cpu_run( this, duration ); | 402 | check( Cpu_time( &this->cpu ) >= duration ); |
439 | /* warning( "Emulation error (illegal instruction)" ); */ | ||
440 | |||
441 | check( time() >= duration ); | ||
442 | //check( time() - duration < 20 ); // Txx instruction could cause going way over | 403 | //check( time() - duration < 20 ); // Txx instruction could cause going way over |
443 | 404 | ||
444 | run_until( this, duration ); | 405 | run_until( this, duration ); |
@@ -446,15 +407,7 @@ blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) | |||
446 | // end time frame | 407 | // end time frame |
447 | this->timer.last_time -= duration; | 408 | this->timer.last_time -= duration; |
448 | this->vdp.next_vbl -= duration; | 409 | this->vdp.next_vbl -= duration; |
449 | #if defined (GME_FRAME_HOOK_DEFINED) | 410 | Cpu_end_frame( &this->cpu, duration ); |
450 | last_frame_hook -= *duration; | ||
451 | #endif | ||
452 | |||
453 | // End cpu frame | ||
454 | this->cpu.state_.base -= duration; | ||
455 | if ( this->cpu.irq_time < (hes_time_t)future_hes_time ) this->cpu.irq_time -= duration; | ||
456 | if ( this->cpu.end_time < (hes_time_t)future_hes_time ) this->cpu.end_time -= duration; | ||
457 | |||
458 | adjust_time( &this->irq.timer, duration ); | 411 | adjust_time( &this->irq.timer, duration ); |
459 | adjust_time( &this->irq.vdp, duration ); | 412 | adjust_time( &this->irq.vdp, duration ); |
460 | Apu_end_frame( &this->apu, duration ); | 413 | Apu_end_frame( &this->apu, duration ); |
@@ -463,24 +416,31 @@ blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) | |||
463 | return 0; | 416 | return 0; |
464 | } | 417 | } |
465 | 418 | ||
466 | blargg_err_t play_( struct Hes_Emu* this, long count, sample_t* out ); | 419 | blargg_err_t run_clocks( struct Hes_Emu* this, blip_time_t* duration_ ) |
467 | blargg_err_t play_( struct Hes_Emu* this, long count, sample_t* out ) | 420 | { |
421 | return end_frame( this, *duration_ ); | ||
422 | } | ||
423 | |||
424 | blargg_err_t play_( void *emu, int count, sample_t out [] ) | ||
468 | { | 425 | { |
469 | long remain = count; | 426 | struct Hes_Emu* this = (struct Hes_Emu*) emu; |
427 | |||
428 | int remain = count; | ||
470 | while ( remain ) | 429 | while ( remain ) |
471 | { | 430 | { |
431 | Buffer_disable_immediate_removal( &this->stereo_buf ); | ||
472 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); | 432 | remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain ); |
473 | if ( remain ) | 433 | if ( remain ) |
474 | { | 434 | { |
475 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) | 435 | if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) ) |
476 | { | 436 | { |
477 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); | 437 | this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf ); |
438 | |||
478 | // Remute voices | 439 | // Remute voices |
479 | Sound_mute_voices( this, this->mute_mask_ ); | 440 | Sound_mute_voices( this, this->mute_mask_ ); |
480 | } | 441 | } |
481 | |||
482 | int msec = Buffer_length( &this->stereo_buf ); | 442 | int msec = Buffer_length( &this->stereo_buf ); |
483 | blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000; | 443 | blip_time_t clocks_emulated = msec * this->clock_rate_ / 1000 - 100; |
484 | RETURN_ERR( run_clocks( this, &clocks_emulated ) ); | 444 | RETURN_ERR( run_clocks( this, &clocks_emulated ) ); |
485 | assert( clocks_emulated ); | 445 | assert( clocks_emulated ); |
486 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); | 446 | Buffer_end_frame( &this->stereo_buf, clocks_emulated ); |
@@ -489,10 +449,9 @@ blargg_err_t play_( struct Hes_Emu* this, long count, sample_t* out ) | |||
489 | return 0; | 449 | return 0; |
490 | } | 450 | } |
491 | 451 | ||
492 | |||
493 | // Music emu | 452 | // Music emu |
494 | 453 | ||
495 | blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, long rate ) | 454 | blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, int rate ) |
496 | { | 455 | { |
497 | require( !this->sample_rate_ ); // sample rate can't be changed once set | 456 | require( !this->sample_rate_ ); // sample rate can't be changed once set |
498 | Buffer_init( &this->stereo_buf ); | 457 | Buffer_init( &this->stereo_buf ); |
@@ -502,6 +461,8 @@ blargg_err_t Hes_set_sample_rate( struct Hes_Emu* this, long rate ) | |||
502 | Buffer_bass_freq( &this->stereo_buf, 60 ); | 461 | Buffer_bass_freq( &this->stereo_buf, 60 ); |
503 | 462 | ||
504 | this->sample_rate_ = rate; | 463 | this->sample_rate_ = rate; |
464 | RETURN_ERR( track_init( &this->track_filter, this ) ); | ||
465 | this->tfilter.max_silence = 6 * stereo * this->sample_rate_; | ||
505 | return 0; | 466 | return 0; |
506 | } | 467 | } |
507 | 468 | ||
@@ -521,7 +482,7 @@ void Sound_mute_voices( struct Hes_Emu* this, int mask ) | |||
521 | this->mute_mask_ = mask; | 482 | this->mute_mask_ = mask; |
522 | 483 | ||
523 | // Set adpcm voice | 484 | // Set adpcm voice |
524 | struct channel_t ch = Buffer_channel( &this->stereo_buf ); | 485 | struct channel_t ch = Buffer_channel( &this->stereo_buf, this->voice_count_ ); |
525 | if ( mask & (1 << this->voice_count_ ) ) | 486 | if ( mask & (1 << this->voice_count_ ) ) |
526 | Adpcm_set_output( &this->adpcm, 0, 0, 0, 0 ); | 487 | Adpcm_set_output( &this->adpcm, 0, 0, 0, 0 ); |
527 | else | 488 | else |
@@ -536,7 +497,8 @@ void Sound_mute_voices( struct Hes_Emu* this, int mask ) | |||
536 | Apu_osc_output( &this->apu, i, 0, 0, 0 ); | 497 | Apu_osc_output( &this->apu, i, 0, 0, 0 ); |
537 | } | 498 | } |
538 | else | 499 | else |
539 | { | 500 | { |
501 | struct channel_t ch = Buffer_channel( &this->stereo_buf, i ); | ||
540 | assert( (ch.center && ch.left && ch.right) || | 502 | assert( (ch.center && ch.left && ch.right) || |
541 | (!ch.center && !ch.left && !ch.right) ); // all or nothing | 503 | (!ch.center && !ch.left && !ch.right) ); // all or nothing |
542 | Apu_osc_output( &this->apu, i, ch.center, ch.left, ch.right ); | 504 | Apu_osc_output( &this->apu, i, ch.center, ch.left, ch.right ); |
@@ -557,7 +519,6 @@ void Sound_set_tempo( struct Hes_Emu* this, int t ) | |||
557 | this->tempo_ = t; | 519 | this->tempo_ = t; |
558 | } | 520 | } |
559 | 521 | ||
560 | void fill_buf( struct Hes_Emu* this ); | ||
561 | blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) | 522 | blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) |
562 | { | 523 | { |
563 | clear_track_vars( this ); | 524 | clear_track_vars( this ); |
@@ -572,7 +533,7 @@ blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) | |||
572 | 533 | ||
573 | Buffer_clear( &this->stereo_buf ); | 534 | Buffer_clear( &this->stereo_buf ); |
574 | 535 | ||
575 | memset( this->cpu.ram, 0, sizeof this->cpu.ram ); // some HES music relies on zero fill | 536 | memset( this->ram, 0, sizeof this->ram ); // some HES music relies on zero fill |
576 | memset( this->sgx, 0, sizeof this->sgx ); | 537 | memset( this->sgx, 0, sizeof this->sgx ); |
577 | 538 | ||
578 | Apu_reset( &this->apu ); | 539 | Apu_reset( &this->apu ); |
@@ -581,12 +542,12 @@ blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) | |||
581 | 542 | ||
582 | unsigned i; | 543 | unsigned i; |
583 | for ( i = 0; i < sizeof this->header.banks; i++ ) | 544 | for ( i = 0; i < sizeof this->header.banks; i++ ) |
584 | Cpu_set_mmr( this, i, this->header.banks [i] ); | 545 | set_mmr( this, i, this->header.banks [i] ); |
585 | Cpu_set_mmr( this, page_count, 0xFF ); // unmapped beyond end of address space | 546 | set_mmr( this, page_count, 0xFF ); // unmapped beyond end of address space |
586 | 547 | ||
587 | this->irq.disables = timer_mask | vdp_mask; | 548 | this->irq.disables = timer_mask | vdp_mask; |
588 | this->irq.timer = (hes_time_t)future_hes_time; | 549 | this->irq.timer = future_time; |
589 | this->irq.vdp = (hes_time_t)future_hes_time; | 550 | this->irq.vdp = future_time; |
590 | 551 | ||
591 | this->timer.enabled = false; | 552 | this->timer.enabled = false; |
592 | this->timer.raw_load= 0x80; | 553 | this->timer.raw_load= 0x80; |
@@ -598,280 +559,86 @@ blargg_err_t Hes_start_track( struct Hes_Emu* this, int track ) | |||
598 | this->vdp.control = 0; | 559 | this->vdp.control = 0; |
599 | this->vdp.next_vbl = 0; | 560 | this->vdp.next_vbl = 0; |
600 | 561 | ||
601 | this->cpu.ram [0x1FF] = (idle_addr - 1) >> 8; | 562 | this->ram [0x1FF] = (idle_addr - 1) >> 8; |
602 | this->cpu.ram [0x1FE] = (idle_addr - 1) & 0xFF; | 563 | this->ram [0x1FE] = (idle_addr - 1) & 0xFF; |
603 | this->cpu.r.sp = 0xFD; | 564 | this->cpu.r.sp = 0xFD; |
604 | this->cpu.r.pc = get_le16( this->header.init_addr ); | 565 | this->cpu.r.pc = get_le16( this->header.init_addr ); |
605 | this->cpu.r.a = track; | 566 | this->cpu.r.a = track; |
606 | 567 | ||
607 | recalc_timer_load( this ); | 568 | recalc_timer_load( this ); |
608 | this->last_frame_hook = 0; | ||
609 | 569 | ||
610 | this->emu_track_ended_ = false; | 570 | // convert filter times to samples |
611 | this->track_ended = false; | 571 | struct setup_t s = this->tfilter; |
572 | s.max_initial *= this->sample_rate_ * stereo; | ||
573 | #ifdef GME_DISABLE_SILENCE_LOOKAHEAD | ||
574 | s.lookahead = 1; | ||
575 | #endif | ||
576 | track_setup( &this->track_filter, &s ); | ||
612 | 577 | ||
613 | if ( !this->ignore_silence ) | 578 | return track_start( &this->track_filter ); |
614 | { | ||
615 | // play until non-silence or end of track | ||
616 | long end; | ||
617 | for ( end =this-> max_initial_silence * stereo * this->sample_rate_; this->emu_time < end; ) | ||
618 | { | ||
619 | fill_buf( this ); | ||
620 | if ( this->buf_remain | (int) this->emu_track_ended_ ) | ||
621 | break; | ||
622 | } | ||
623 | |||
624 | this->emu_time = this->buf_remain; | ||
625 | this->out_time = 0; | ||
626 | this->silence_time = 0; | ||
627 | this->silence_count = 0; | ||
628 | } | ||
629 | /* return track_ended() ? warning() : 0; */ | ||
630 | return 0; | ||
631 | } | 579 | } |
632 | 580 | ||
633 | // Tell/Seek | 581 | // Tell/Seek |
634 | 582 | ||
635 | static blargg_long msec_to_samples( blargg_long msec, long sample_rate ) | 583 | static int msec_to_samples( int msec, int sample_rate ) |
636 | { | 584 | { |
637 | blargg_long sec = msec / 1000; | 585 | int sec = msec / 1000; |
638 | msec -= sec * 1000; | 586 | msec -= sec * 1000; |
639 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; | 587 | return (sec * sample_rate + msec * sample_rate / 1000) * stereo; |
640 | } | 588 | } |
641 | 589 | ||
642 | long Track_tell( struct Hes_Emu* this ) | 590 | int Track_tell( struct Hes_Emu* this ) |
643 | { | 591 | { |
644 | blargg_long rate = this->sample_rate_ * stereo; | 592 | int rate = this->sample_rate_ * stereo; |
645 | blargg_long sec = this->out_time / rate; | 593 | int sec = track_sample_count( &this->track_filter ) / rate; |
646 | return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate; | 594 | return sec * 1000 + (track_sample_count( &this->track_filter ) - sec * rate) * 1000 / rate; |
647 | } | 595 | } |
648 | 596 | ||
649 | blargg_err_t Track_seek( struct Hes_Emu* this, long msec ) | 597 | blargg_err_t Track_seek( struct Hes_Emu* this, int msec ) |
650 | { | 598 | { |
651 | blargg_long time = msec_to_samples( msec, this->sample_rate_ ); | 599 | int time = msec_to_samples( msec, this->sample_rate_ ); |
652 | if ( time < this->out_time ) | 600 | if ( time < track_sample_count( &this->track_filter ) ) |
653 | RETURN_ERR( Hes_start_track( this, this->current_track_ ) ); | 601 | RETURN_ERR( Hes_start_track( this, this->current_track_ ) ); |
654 | return Track_skip( this, time - this->out_time ); | 602 | return Track_skip( this, time - track_sample_count( &this->track_filter ) ); |
655 | } | 603 | } |
656 | 604 | ||
657 | blargg_err_t skip_( struct Hes_Emu* this, long count ); | 605 | blargg_err_t skip_( void* emu, int count ) |
658 | blargg_err_t skip_( struct Hes_Emu* this, long count ) | ||
659 | { | 606 | { |
607 | struct Hes_Emu* this = (struct Hes_Emu*) emu; | ||
608 | |||
660 | // for long skip, mute sound | 609 | // for long skip, mute sound |
661 | const long threshold = 30000; | 610 | const int threshold = 32768; |
662 | if ( count > threshold ) | 611 | if ( count > threshold ) |
663 | { | 612 | { |
664 | int saved_mute = this->mute_mask_; | 613 | int saved_mute = this->mute_mask_; |
665 | Sound_mute_voices( this, ~0 ); | 614 | Sound_mute_voices( this, ~0 ); |
666 | |||
667 | while ( count > threshold / 2 && !this->emu_track_ended_ ) | ||
668 | { | ||
669 | RETURN_ERR( play_( this, buf_size, this->buf ) ); | ||
670 | count -= buf_size; | ||
671 | } | ||
672 | |||
673 | Sound_mute_voices( this, saved_mute ); | ||
674 | } | ||
675 | |||
676 | while ( count && !this->emu_track_ended_ ) | ||
677 | { | ||
678 | long n = buf_size; | ||
679 | if ( n > count ) | ||
680 | n = count; | ||
681 | count -= n; | ||
682 | RETURN_ERR( play_( this, n, this->buf ) ); | ||
683 | } | ||
684 | return 0; | ||
685 | } | ||
686 | 615 | ||
687 | blargg_err_t Track_skip( struct Hes_Emu* this, long count ) | 616 | int n = count - threshold/2; |
688 | { | 617 | n &= ~(2048-1); // round to multiple of 2048 |
689 | require( this->current_track_ >= 0 ); // start_track() must have been called already | ||
690 | this->out_time += count; | ||
691 | |||
692 | // remove from silence and buf first | ||
693 | { | ||
694 | long n = min( count, this->silence_count ); | ||
695 | this->silence_count -= n; | ||
696 | count -= n; | ||
697 | |||
698 | n = min( count, this->buf_remain ); | ||
699 | this->buf_remain -= n; | ||
700 | count -= n; | 618 | count -= n; |
701 | } | 619 | RETURN_ERR( skippy_( &this->track_filter, n ) ); |
702 | |||
703 | if ( count && !this->emu_track_ended_ ) | ||
704 | { | ||
705 | this->emu_time += count; | ||
706 | |||
707 | // End track if error | ||
708 | if ( skip_( this, count ) ) | ||
709 | this->emu_track_ended_ = true; | ||
710 | } | ||
711 | |||
712 | if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended | ||
713 | this->track_ended |= this->emu_track_ended_; | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | 620 | ||
718 | 621 | Sound_mute_voices( this, saved_mute ); | |
719 | |||
720 | // Fading | ||
721 | |||
722 | void Track_set_fade( struct Hes_Emu* this, long start_msec, long length_msec ) | ||
723 | { | ||
724 | this->fade_step = this->sample_rate_ * length_msec / (fade_block_size * fade_shift * 1000 / stereo); | ||
725 | this->fade_start = msec_to_samples( start_msec, this->sample_rate_ ); | ||
726 | } | ||
727 | |||
728 | // unit / pow( 2.0, (double) x / step ) | ||
729 | static int int_log( blargg_long x, int step, int unit ); | ||
730 | static int int_log( blargg_long x, int step, int unit ) | ||
731 | { | ||
732 | int shift = x / step; | ||
733 | int fraction = (x - shift * step) * unit / step; | ||
734 | return ((unit - fraction) + (fraction >> 1)) >> shift; | ||
735 | } | ||
736 | |||
737 | void handle_fade( struct Hes_Emu* this, long out_count, sample_t* out ); | ||
738 | void handle_fade( struct Hes_Emu* this, long out_count, sample_t* out ) | ||
739 | { | ||
740 | int i; | ||
741 | for ( i = 0; i < out_count; i += fade_block_size ) | ||
742 | { | ||
743 | int const shift = 14; | ||
744 | int const unit = 1 << shift; | ||
745 | int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size, | ||
746 | this->fade_step, unit ); | ||
747 | if ( gain < (unit >> fade_shift) ) | ||
748 | this->track_ended = this->emu_track_ended_ = true; | ||
749 | |||
750 | sample_t* io = &out [i]; | ||
751 | int count; | ||
752 | for ( count = min( fade_block_size, out_count - i ); count; --count ) | ||
753 | { | ||
754 | *io = (sample_t) ((*io * gain) >> shift); | ||
755 | ++io; | ||
756 | } | ||
757 | } | 622 | } |
758 | } | ||
759 | |||
760 | // Silence detection | ||
761 | 623 | ||
762 | void emu_play( struct Hes_Emu* this, long count, sample_t* out ); | 624 | return skippy_( &this->track_filter, count ); |
763 | void emu_play( struct Hes_Emu* this, long count, sample_t* out ) | ||
764 | { | ||
765 | check( current_track_ >= 0 ); | ||
766 | this->emu_time += count; | ||
767 | if ( this->current_track_ >= 0 && !this->emu_track_ended_ ) { | ||
768 | |||
769 | // End track if error | ||
770 | if ( play_( this, count, out ) ) | ||
771 | this->emu_track_ended_ = true; | ||
772 | } | ||
773 | else | ||
774 | memset( out, 0, count * sizeof *out ); | ||
775 | } | 625 | } |
776 | 626 | ||
777 | // number of consecutive silent samples at end | 627 | blargg_err_t Track_skip( struct Hes_Emu* this, int count ) |
778 | static long count_silence( sample_t* begin, long size ); | ||
779 | static long count_silence( sample_t* begin, long size ) | ||
780 | { | 628 | { |
781 | sample_t first = *begin; | 629 | require( this->current_track_ >= 0 ); // start_track() must have been called already |
782 | *begin = silence_threshold; // sentinel | 630 | return track_skip( &this->track_filter, count ); |
783 | sample_t* p = begin + size; | ||
784 | while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } | ||
785 | *begin = first; | ||
786 | return size - (p - begin); | ||
787 | } | 631 | } |
788 | 632 | ||
789 | // fill internal buffer and check it for silence | 633 | void Track_set_fade( struct Hes_Emu* this, int start_msec, int length_msec ) |
790 | void fill_buf( struct Hes_Emu* this ) | ||
791 | { | 634 | { |
792 | assert( !this->buf_remain ); | 635 | track_set_fade( &this->track_filter, msec_to_samples( start_msec, this->sample_rate_ ), |
793 | if ( !this->emu_track_ended_ ) | 636 | length_msec * this->sample_rate_ / (1000 / stereo) ); |
794 | { | ||
795 | emu_play( this, buf_size, this->buf ); | ||
796 | long silence = count_silence( this->buf, buf_size ); | ||
797 | if ( silence < buf_size ) | ||
798 | { | ||
799 | this->silence_time = this->emu_time - silence; | ||
800 | this->buf_remain = buf_size; | ||
801 | return; | ||
802 | } | ||
803 | } | ||
804 | this->silence_count += buf_size; | ||
805 | } | 637 | } |
806 | 638 | ||
807 | blargg_err_t Hes_play( struct Hes_Emu* this, long out_count, sample_t* out ) | 639 | blargg_err_t Hes_play( struct Hes_Emu* this, int out_count, sample_t* out ) |
808 | { | 640 | { |
809 | if ( this->track_ended ) | 641 | require( this->current_track_ >= 0 ); |
810 | { | 642 | require( out_count % stereo == 0 ); |
811 | memset( out, 0, out_count * sizeof *out ); | 643 | return track_play( &this->track_filter, out_count, out ); |
812 | } | ||
813 | else | ||
814 | { | ||
815 | require( this->current_track_ >= 0 ); | ||
816 | require( out_count % stereo == 0 ); | ||
817 | |||
818 | assert( this->emu_time >= this->out_time ); | ||
819 | |||
820 | // prints nifty graph of how far ahead we are when searching for silence | ||
821 | //dprintf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" ); | ||
822 | |||
823 | long pos = 0; | ||
824 | if ( this->silence_count ) | ||
825 | { | ||
826 | // during a run of silence, run emulator at >=2x speed so it gets ahead | ||
827 | long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time; | ||
828 | while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) ) | ||
829 | fill_buf( this ); | ||
830 | |||
831 | // fill with silence | ||
832 | pos = min( this->silence_count, out_count ); | ||
833 | memset( out, 0, pos * sizeof *out ); | ||
834 | this->silence_count -= pos; | ||
835 | |||
836 | if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate_ ) | ||
837 | { | ||
838 | this->track_ended = this->emu_track_ended_ = true; | ||
839 | this->silence_count = 0; | ||
840 | this->buf_remain = 0; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | if ( this->buf_remain ) | ||
845 | { | ||
846 | // empty silence buf | ||
847 | long n = min( this->buf_remain, out_count - pos ); | ||
848 | memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out ); | ||
849 | this->buf_remain -= n; | ||
850 | pos += n; | ||
851 | } | ||
852 | |||
853 | // generate remaining samples normally | ||
854 | long remain = out_count - pos; | ||
855 | if ( remain ) | ||
856 | { | ||
857 | emu_play( this, remain, out + pos ); | ||
858 | this->track_ended |= this->emu_track_ended_; | ||
859 | |||
860 | if ( !this->ignore_silence || this->out_time > this->fade_start ) | ||
861 | { | ||
862 | // check end for a new run of silence | ||
863 | long silence = count_silence( out + pos, remain ); | ||
864 | if ( silence < remain ) | ||
865 | this->silence_time = this->emu_time - silence; | ||
866 | |||
867 | if ( this->emu_time - this->silence_time >= buf_size ) | ||
868 | fill_buf( this ); // cause silence detection on next play() | ||
869 | } | ||
870 | } | ||
871 | |||
872 | if ( this->out_time > this->fade_start ) | ||
873 | handle_fade( this, out_count, out ); | ||
874 | } | ||
875 | this->out_time += out_count; | ||
876 | return 0; | ||
877 | } | 644 | } |