summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/ay_emu.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/ay_emu.c')
-rw-r--r--apps/codecs/libgme/ay_emu.c783
1 files changed, 783 insertions, 0 deletions
diff --git a/apps/codecs/libgme/ay_emu.c b/apps/codecs/libgme/ay_emu.c
new file mode 100644
index 0000000000..dc775cbf79
--- /dev/null
+++ b/apps/codecs/libgme/ay_emu.c
@@ -0,0 +1,783 @@
1// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
2
3#include "ay_emu.h"
4
5#include "blargg_endian.h"
6
7/* Copyright (C) 2006-2009 Shay Green. This module is free software; you
8can redistribute it and/or modify it under the terms of the GNU Lesser
9General Public License as published by the Free Software Foundation; either
10version 2.1 of the License, or (at your option) any later version. This
11module is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14details. You should have received a copy of the GNU Lesser General Public
15License along with this module; if not, write to the Free Software Foundation,
16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include "blargg_source.h"
19
20int const stereo = 2; // number of channels for stereo
21int const silence_max = 6; // seconds
22int const silence_threshold = 0x10;
23long const fade_block_size = 512;
24int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
25
26const char* const gme_wrong_file_type = "Wrong file type for this emulator";
27
28// TODO: probably don't need detailed errors as to why file is corrupt
29
30int const spectrum_clock = 3546900; // 128K Spectrum
31int const spectrum_period = 70908;
32
33//int const spectrum_clock = 3500000; // 48K Spectrum
34//int const spectrum_period = 69888;
35
36int const cpc_clock = 2000000;
37
38void clear_track_vars( struct Ay_Emu *this )
39{
40 this->current_track = -1;
41 this->out_time = 0;
42 this->emu_time = 0;
43 this->emu_track_ended_ = true;
44 this->track_ended = true;
45 this->fade_start = INT_MAX / 2 + 1;
46 this->fade_step = 1;
47 this->silence_time = 0;
48 this->silence_count = 0;
49 this->buf_remain = 0;
50 /* warning(); // clear warning */
51}
52
53void Ay_init( struct Ay_Emu *this )
54{
55 this->sample_rate = 0;
56 this->mute_mask_ = 0;
57 this->tempo = 1.0;
58 this->gain = 1.0;
59 this->track_count = 0;
60
61 // defaults
62 this->max_initial_silence = 2;
63 this->ignore_silence = false;
64
65 this->voice_count = 0;
66 clear_track_vars( this );
67 this->beeper_output = NULL;
68 disable_beeper( this );
69
70 Ay_apu_init( &this->apu );
71 Z80_init( &this->cpu );
72
73 this->silence_lookahead = 6 ;
74}
75
76// Track info
77
78// Given pointer to 2-byte offset of data, returns pointer to data, or NULL if
79// offset is 0 or there is less than min_size bytes of data available.
80static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size )
81{
82 int offset = (int16_t) get_be16( ptr );
83 int pos = ptr - (byte const*) file->header;
84 int size = file->end - (byte const*) file->header;
85 assert( (unsigned) pos <= (unsigned) size - 2 );
86 int limit = size - min_size;
87 if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit )
88 return NULL;
89 return ptr + offset;
90}
91
92static blargg_err_t parse_header( byte const in [], int size, struct file_t* out )
93{
94 if ( size < header_size )
95 return gme_wrong_file_type;
96
97 out->header = (struct header_t const*) in;
98 out->end = in + size;
99 struct header_t const* h = (struct header_t const*) in;
100 if ( memcmp( h->tag, "ZXAYEMUL", 8 ) )
101 return gme_wrong_file_type;
102
103 out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 );
104 if ( !out->tracks )
105 return "missing track data";
106
107 return 0;
108}
109
110long Track_get_length( struct Ay_Emu* this, int n )
111{
112 long length = 0;
113
114 byte const* track_info = get_data( &this->file, this->file.tracks + n * 4 + 2, 6 );
115 if ( track_info )
116 length = get_be16( track_info + 4 ) * (1000 / 50); // frames to msec
117
118 if ( (this->m3u.size > 0) && (n < this->m3u.size) ) {
119 struct entry_t* entry = &this->m3u.entries [n];
120 length = entry->length;
121 }
122
123 if ( length <= 0 )
124 length = 120 * 1000; /* 2 minutes */
125
126 return length;
127}
128
129// Setup
130
131void change_clock_rate( struct Ay_Emu *this, long rate )
132{
133 this->clock_rate_ = rate;
134 Buffer_clock_rate( &this->stereo_buf, rate );
135}
136
137blargg_err_t Ay_load_mem( struct Ay_Emu *this, byte const in [], int size )
138{
139 assert( offsetof (struct header_t,track_info [2]) == header_size );
140
141 RETURN_ERR( parse_header( in, size, &this->file ) );
142
143 /* if ( file.header->vers > 2 )
144 warning( "Unknown file version" ); */
145
146 this->voice_count = ay_osc_count + 1; // +1 for beeper
147 Ay_apu_volume( &this->apu, this->gain );
148
149 // Setup buffer
150 change_clock_rate( this, spectrum_clock );
151 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
152
153 Sound_set_tempo( this, this->tempo );
154
155 // Remute voices
156 Sound_mute_voices( this, this->mute_mask_ );
157
158 this->track_count = this->file.header->max_track + 1;
159 this->m3u.size = 0;
160 return 0;
161}
162
163void set_beeper_output( struct Ay_Emu *this, struct Blip_Buffer* b )
164{
165 this->beeper_output = b;
166 if ( b && !this->cpc_mode )
167 this->beeper_mask = 0x10;
168 else
169 disable_beeper( this );
170}
171
172void set_voice( struct Ay_Emu *this, int i, struct Blip_Buffer* center )
173{
174 if ( i >= ay_osc_count )
175 set_beeper_output( this, center );
176 else
177 Ay_apu_set_output( &this->apu, i, center );
178}
179
180blargg_err_t run_clocks( struct Ay_Emu *this, blip_time_t* duration, int msec )
181{
182#if defined(ROCKBOX)
183 (void) msec;
184#endif
185
186 cpu_time_t *end = duration;
187 struct Z80_Cpu* cpu = &this->cpu;
188 Z80_set_time( cpu, 0 );
189
190 // Since detection of CPC mode will halve clock rate during the frame
191 // and thus generate up to twice as much sound, we must generate half
192 // as much until mode is known.
193 if ( !(this->spectrum_mode | this->cpc_mode) )
194 *end /= 2;
195
196 while ( Z80_time( cpu ) < *end )
197 {
198 run_cpu( this, min( *end, this->next_play ) );
199
200 if ( Z80_time( cpu ) >= this->next_play )
201 {
202 // next frame
203 this->next_play += this->play_period;
204
205 if ( cpu->r.iff1 )
206 {
207 // interrupt enabled
208
209 if ( this->mem.ram [cpu->r.pc] == 0x76 )
210 cpu->r.pc++; // advance past HALT instruction
211
212 cpu->r.iff1 = 0;
213 cpu->r.iff2 = 0;
214
215 this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc >> 8);
216 this->mem.ram [--cpu->r.sp] = (byte) (cpu->r.pc);
217
218 // fixed interrupt
219 cpu->r.pc = 0x38;
220 Z80_adjust_time( cpu, 12 );
221
222 if ( cpu->r.im == 2 )
223 {
224 // vectored interrupt
225 addr_t addr = cpu->r.i * 0x100 + 0xFF;
226 cpu->r.pc = this->mem.ram [(addr + 1) & 0xFFFF] * 0x100 + this->mem.ram [addr];
227 Z80_adjust_time( cpu, 6 );
228 }
229 }
230 }
231 }
232
233 // End time frame
234 *end = Z80_time( cpu );
235 this->next_play -= *end;
236 check( this->next_play >= 0 );
237 Z80_adjust_time( cpu, -*end );
238 Ay_apu_end_frame( &this->apu, *end );
239 return 0;
240}
241
242// Emulation
243
244void cpu_out_( struct Ay_Emu *this, cpu_time_t time, addr_t addr, int data )
245{
246 // Spectrum
247 if ( !this->cpc_mode )
248 {
249 switch ( addr & 0xFEFF )
250 {
251 case 0xFEFD:
252 this->spectrum_mode = true;
253 Ay_apu_write_addr( &this->apu, data );
254 return;
255
256 case 0xBEFD:
257 this->spectrum_mode = true;
258 Ay_apu_write_data( &this->apu, time, data );
259 return;
260 }
261 }
262
263 // CPC
264 if ( !this->spectrum_mode )
265 {
266 switch ( addr >> 8 )
267 {
268 case 0xF6:
269 switch ( data & 0xC0 )
270 {
271 case 0xC0:
272 Ay_apu_write_addr( &this->apu, this->cpc_latch );
273 goto enable_cpc;
274
275 case 0x80:
276 Ay_apu_write_data( &this->apu, time, this->cpc_latch );
277 goto enable_cpc;
278 }
279 break;
280
281 case 0xF4:
282 this->cpc_latch = data;
283 goto enable_cpc;
284 }
285 }
286
287 /* dprintf( "Unmapped OUT: $%04X <- $%02X\n", addr, data ); */
288 return;
289
290enable_cpc:
291 if ( !this->cpc_mode )
292 {
293 this->cpc_mode = true;
294 disable_beeper( this );
295
296 change_clock_rate( this, cpc_clock );
297 Sound_set_tempo( this, this->tempo );
298 }
299}
300
301blargg_err_t Ay_set_sample_rate( struct Ay_Emu *this, long rate )
302{
303 require( !this->sample_rate ); // sample rate can't be changed once set
304 Buffer_init( &this->stereo_buf );
305 RETURN_ERR( Buffer_set_sample_rate( &this->stereo_buf, rate, 1000 / 20 ) );
306
307 // Set buffer bass
308 Buffer_bass_freq( &this->stereo_buf, 160 );
309
310 this->sample_rate = rate;
311 return 0;
312}
313
314void Sound_mute_voice( struct Ay_Emu *this, int index, bool mute )
315{
316 require( (unsigned) index < (unsigned) this->voice_count );
317 int bit = 1 << index;
318 int mask = this->mute_mask_ | bit;
319 if ( !mute )
320 mask ^= bit;
321 Sound_mute_voices( this, mask );
322}
323
324void Sound_mute_voices( struct Ay_Emu *this, int mask )
325{
326 require( this->sample_rate ); // sample rate must be set first
327 this->mute_mask_ = mask;
328
329 int i;
330 for ( i = this->voice_count; i--; )
331 {
332 if ( mask & (1 << i) )
333 {
334 set_voice( this, i, 0 );
335 }
336 else
337 {
338 struct channel_t ch = Buffer_channel( &this->stereo_buf );
339 assert( (ch.center && ch.left && ch.right) ||
340 (!ch.center && !ch.left && !ch.right) ); // all or nothing
341 set_voice( this, i, ch.center );
342 }
343 }
344}
345
346void Sound_set_tempo( struct Ay_Emu *this, double t )
347{
348 require( this->sample_rate ); // sample rate must be set first
349 double const min = 0.02;
350 double const max = 4.00;
351 if ( t < min ) t = min;
352 if ( t > max ) t = max;
353 this->tempo = t;
354
355 int p = spectrum_period;
356 if ( this->clock_rate_ != spectrum_clock )
357 p = this->clock_rate_ / 50;
358
359 this->play_period = (blip_time_t) (p / t);
360}
361
362void fill_buf( struct Ay_Emu *this ) ICODE_ATTR;;
363blargg_err_t Ay_start_track( struct Ay_Emu *this, int track )
364{
365 clear_track_vars( this );
366
367 // Remap track if playlist available
368 if ( this->m3u.size > 0 ) {
369 struct entry_t* e = &this->m3u.entries[track];
370 track = e->track;
371 }
372
373 this->current_track = track;
374 Buffer_clear( &this->stereo_buf );
375
376 byte* const mem = this->mem.ram;
377
378 memset( mem + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET
379 memset( mem + 0x0100, 0xFF, 0x4000 - 0x100 );
380 memset( mem + ram_addr, 0x00, mem_size - ram_addr );
381
382 // locate data blocks
383 byte const* const data = get_data( &this->file, this->file.tracks + track * 4 + 2, 14 );
384 if ( !data )
385 return "file data missing";
386
387 byte const* const more_data = get_data( &this->file, data + 10, 6 );
388 if ( !more_data )
389 return "file data missing";
390
391 byte const* blocks = get_data( &this->file, data + 12, 8 );
392 if ( !blocks )
393 return "file data missing";
394
395 // initial addresses
396 unsigned addr = get_be16( blocks );
397 if ( !addr )
398 return "file data missing";
399
400 unsigned init = get_be16( more_data + 2 );
401 if ( !init )
402 init = addr;
403
404 // copy blocks into memory
405 do
406 {
407 blocks += 2;
408 unsigned len = get_be16( blocks ); blocks += 2;
409 if ( addr + len > mem_size )
410 {
411 /* warning( "Bad data block size" ); */
412 len = mem_size - addr;
413 }
414 check( len );
415 byte const* in = get_data( &this->file, blocks, 0 ); blocks += 2;
416 if ( len > (unsigned) (this->file.end - in) )
417 {
418 /* warning( "File data missing" ); */
419 len = this->file.end - in;
420 }
421
422 memcpy( mem + addr, in, len );
423
424 if ( this->file.end - blocks < 8 )
425 {
426 /* warning( "File data missing" ); */
427 break;
428 }
429 }
430 while ( (addr = get_be16( blocks )) != 0 );
431
432 // copy and configure driver
433 static byte const passive [] = {
434 0xF3, // DI
435 0xCD, 0, 0, // CALL init
436 0xED, 0x5E, // LOOP: IM 2
437 0xFB, // EI
438 0x76, // HALT
439 0x18, 0xFA // JR LOOP
440 };
441 static byte const active [] = {
442 0xF3, // DI
443 0xCD, 0, 0, // CALL init
444 0xED, 0x56, // LOOP: IM 1
445 0xFB, // EI
446 0x76, // HALT
447 0xCD, 0, 0, // CALL play
448 0x18, 0xF7 // JR LOOP
449 };
450 memcpy( mem, passive, sizeof passive );
451 int const play_addr = get_be16( more_data + 4 );
452 if ( play_addr )
453 {
454 memcpy( mem, active, sizeof active );
455 mem [ 9] = play_addr;
456 mem [10] = play_addr >> 8;
457 }
458 mem [2] = init;
459 mem [3] = init >> 8;
460
461 mem [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET)
462
463 // start at spectrum speed
464 change_clock_rate( this, spectrum_clock );
465 Sound_set_tempo( this, this->tempo );
466
467 struct registers_t r;
468 memset( &r, 0, sizeof(struct registers_t) );
469
470 r.sp = get_be16( more_data );
471 r.b.a = r.b.b = r.b.d = r.b.h = data [8];
472 r.b.flags = r.b.c = r.b.e = r.b.l = data [9];
473 r.alt.w = r.w;
474 r.ix = r.iy = r.w.hl;
475
476 memset( this->mem.padding1, 0xFF, sizeof this->mem.padding1 );
477
478 int const mirrored = 0x80; // this much is mirrored after end of memory
479 memset( this->mem.ram + mem_size + mirrored, 0xFF, sizeof this->mem.ram - mem_size - mirrored );
480 memcpy( this->mem.ram + mem_size, this->mem.ram, mirrored ); // some code wraps around (ugh)
481
482 Z80_reset( &this->cpu, this->mem.padding1, this->mem.padding1 );
483 Z80_map_mem( &this->cpu, 0, mem_size, this->mem.ram, this->mem.ram );
484 this->cpu.r = r;
485
486 this->beeper_delta = (int) (ay_amp_range * 0.8);
487 this->last_beeper = 0;
488 this->next_play = this->play_period;
489 this->spectrum_mode = false;
490 this->cpc_mode = false;
491 this->cpc_latch = 0;
492 set_beeper_output( this, this->beeper_output );
493 Ay_apu_reset( &this->apu );
494
495 // a few tunes rely on channels having tone enabled at the beginning
496 Ay_apu_write_addr( &this->apu, 7 );
497 Ay_apu_write_data( &this->apu, 0, 0x38 );
498
499 this->emu_track_ended_ = false;
500 this->track_ended = false;
501
502 if ( !this->ignore_silence )
503 {
504 // play until non-silence or end of track
505 long end;
506 for ( end = this->max_initial_silence * stereo * this->sample_rate; this->emu_time < end; )
507 {
508 fill_buf( this );
509 if ( this->buf_remain | (int) this->emu_track_ended_ )
510 break;
511 }
512
513 this->emu_time = this->buf_remain;
514 this->out_time = 0;
515 this->silence_time = 0;
516 this->silence_count = 0;
517 }
518 /* return track_ended() ? warning() : 0; */
519 return 0;
520}
521
522// Tell/Seek
523
524blargg_long msec_to_samples( blargg_long msec, long sample_rate )
525{
526 blargg_long sec = msec / 1000;
527 msec -= sec * 1000;
528 return (sec * sample_rate + msec * sample_rate / 1000) * stereo;
529}
530
531long Track_tell( struct Ay_Emu *this )
532{
533 blargg_long rate = this->sample_rate * stereo;
534 blargg_long sec = this->out_time / rate;
535 return sec * 1000 + (this->out_time - sec * rate) * 1000 / rate;
536}
537
538blargg_err_t Track_seek( struct Ay_Emu *this, long msec )
539{
540 blargg_long time = msec_to_samples( msec, this->sample_rate );
541 if ( time < this->out_time )
542 RETURN_ERR( Ay_start_track( this, this->current_track ) );
543 return Track_skip( this, time - this->out_time );
544}
545
546blargg_err_t play_( struct Ay_Emu *this, long count, sample_t* out ) ICODE_ATTR;
547blargg_err_t skip_( struct Ay_Emu *this, long count )
548{
549 // for long skip, mute sound
550 const long threshold = 30000;
551 if ( count > threshold )
552 {
553 int saved_mute = this->mute_mask_;
554 Sound_mute_voices( this, ~0 );
555
556 while ( count > threshold / 2 && !this->emu_track_ended_ )
557 {
558 RETURN_ERR( play_( this, buf_size, this->buf ) );
559 count -= buf_size;
560 }
561
562 Sound_mute_voices( this, saved_mute );
563 }
564
565 while ( count && !this->emu_track_ended_ )
566 {
567 long n = buf_size;
568 if ( n > count )
569 n = count;
570 count -= n;
571 RETURN_ERR( play_( this, n, this->buf ) );
572 }
573 return 0;
574}
575
576blargg_err_t Track_skip( struct Ay_Emu *this, long count )
577{
578 require( this->current_track >= 0 ); // start_track() must have been called already
579 this->out_time += count;
580
581 // remove from silence and buf first
582 {
583 long n = min( count, this->silence_count );
584 this->silence_count -= n;
585 count -= n;
586
587 n = min( count, this->buf_remain );
588 this->buf_remain -= n;
589 count -= n;
590 }
591
592 if ( count && !this->emu_track_ended_ )
593 {
594 this->emu_time += count;
595
596 // End track if error
597 if ( skip_( this, count ) )
598 this->emu_track_ended_ = true;
599 }
600
601 if ( !(this->silence_count | this->buf_remain) ) // caught up to emulator, so update track ended
602 this->track_ended |= this->emu_track_ended_;
603
604 return 0;
605}
606
607// Fading
608
609void Track_set_fade( struct Ay_Emu *this, long start_msec, long length_msec )
610{
611 this->fade_step = this->sample_rate * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
612 this->fade_start = msec_to_samples( start_msec, this->sample_rate );
613}
614
615// unit / pow( 2.0, (double) x / step )
616static int int_log( blargg_long x, int step, int unit )
617{
618 int shift = x / step;
619 int fraction = (x - shift * step) * unit / step;
620 return ((unit - fraction) + (fraction >> 1)) >> shift;
621}
622
623void handle_fade( struct Ay_Emu *this, long out_count, sample_t* out )
624{
625 int i;
626 for ( i = 0; i < out_count; i += fade_block_size )
627 {
628 int const shift = 14;
629 int const unit = 1 << shift;
630 int gain = int_log( (this->out_time + i - this->fade_start) / fade_block_size,
631 this->fade_step, unit );
632 if ( gain < (unit >> fade_shift) )
633 this->track_ended = this->emu_track_ended_ = true;
634
635 sample_t* io = &out [i];
636 int count;
637 for ( count = min( fade_block_size, out_count - i ); count; --count )
638 {
639 *io = (sample_t) ((*io * gain) >> shift);
640 ++io;
641 }
642 }
643}
644
645// Silence detection
646
647void emu_play( struct Ay_Emu *this, long count, sample_t* out )
648{
649 check( current_track_ >= 0 );
650 this->emu_time += count;
651 if ( this->current_track >= 0 && !this->emu_track_ended_ ) {
652 if ( play_( this, count, out ) )
653 this->emu_track_ended_ = true;
654 }
655 else
656 memset( out, 0, count * sizeof *out );
657}
658
659// number of consecutive silent samples at end
660static long count_silence( sample_t* begin, long size )
661{
662 sample_t first = *begin;
663 *begin = silence_threshold; // sentinel
664 sample_t* p = begin + size;
665 while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
666 *begin = first;
667 return size - (p - begin);
668}
669
670// fill internal buffer and check it for silence
671void fill_buf( struct Ay_Emu *this )
672{
673 assert( !this->buf_remain );
674 if ( !this->emu_track_ended_ )
675 {
676 emu_play( this, buf_size, this->buf );
677 long silence = count_silence( this->buf, buf_size );
678 if ( silence < buf_size )
679 {
680 this->silence_time = this->emu_time - silence;
681 this->buf_remain = buf_size;
682 return;
683 }
684 }
685 this->silence_count += buf_size;
686}
687
688blargg_err_t Ay_play( struct Ay_Emu *this, long out_count, sample_t* out )
689{
690 if ( this->track_ended )
691 {
692 memset( out, 0, out_count * sizeof *out );
693 }
694 else
695 {
696 require( this->current_track >= 0 );
697 require( out_count % stereo == 0 );
698
699 assert( this->emu_time >= this->out_time );
700
701 // prints nifty graph of how far ahead we are when searching for silence
702 //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" );
703
704 long pos = 0;
705 if ( this->silence_count )
706 {
707 // during a run of silence, run emulator at >=2x speed so it gets ahead
708 long ahead_time = this->silence_lookahead * (this->out_time + out_count - this->silence_time) + this->silence_time;
709 while ( this->emu_time < ahead_time && !(this->buf_remain | this->emu_track_ended_) )
710 fill_buf( this );
711
712 // fill with silence
713 pos = min( this->silence_count, out_count );
714 memset( out, 0, pos * sizeof *out );
715 this->silence_count -= pos;
716
717 if ( this->emu_time - this->silence_time > silence_max * stereo * this->sample_rate )
718 {
719 this->track_ended = this->emu_track_ended_ = true;
720 this->silence_count = 0;
721 this->buf_remain = 0;
722 }
723 }
724
725 if ( this->buf_remain )
726 {
727 // empty silence buf
728 long n = min( this->buf_remain, out_count - pos );
729 memcpy( &out [pos], this->buf + (buf_size - this->buf_remain), n * sizeof *out );
730 this->buf_remain -= n;
731 pos += n;
732 }
733
734 // generate remaining samples normally
735 long remain = out_count - pos;
736 if ( remain )
737 {
738 emu_play( this, remain, out + pos );
739 this->track_ended |= this->emu_track_ended_;
740
741 if ( !this->ignore_silence || this->out_time > this->fade_start )
742 {
743 // check end for a new run of silence
744 long silence = count_silence( out + pos, remain );
745 if ( silence < remain )
746 this->silence_time = this->emu_time - silence;
747
748 if ( this->emu_time - this->silence_time >= buf_size )
749 fill_buf( this ); // cause silence detection on next play()
750 }
751 }
752
753 if ( this->out_time > this->fade_start )
754 handle_fade( this, out_count, out );
755 }
756 this->out_time += out_count;
757 return 0;
758}
759
760blargg_err_t play_( struct Ay_Emu *this, long count, sample_t* out )
761{
762 long remain = count;
763 while ( remain )
764 {
765 remain -= Buffer_read_samples( &this->stereo_buf, &out [count - remain], remain );
766 if ( remain )
767 {
768 if ( this->buf_changed_count != Buffer_channels_changed_count( &this->stereo_buf ) )
769 {
770 this->buf_changed_count = Buffer_channels_changed_count( &this->stereo_buf );
771
772 // Remute voices
773 Sound_mute_voices( this, this->mute_mask_ );
774 }
775 int msec = Buffer_length( &this->stereo_buf );
776 blip_time_t clocks_emulated = (blargg_long) msec * this->clock_rate_ / 1000 - 100;
777 RETURN_ERR( run_clocks( this, &clocks_emulated, msec ) );
778 assert( clocks_emulated );
779 Buffer_end_frame( &this->stereo_buf, clocks_emulated );
780 }
781 }
782 return 0;
783}