void end_audio_frame() { if (frame_offset == 0) // No audio added; blip_end_frame() dislikes being called with an // offset of 0 return; assert(!(is_backwards_frame && frame_offset != get_frame_len())); // Bring the signal level at the end of the frame to zero as outlined in // set_audio_signal_level() set_audio_signal_level(0); blip_end_frame(blip, frame_offset); if (playback_started) { // Fudge playback rate by an amount proportional to the difference // between the desired and current buffer fill levels to try to steer // towards it double const fudge_factor = 1.0 + 2*max_adjust*(0.5 - fill_level()); blip_set_rates(blip, cpu_clock_rate, sample_rate*fudge_factor); } else { if (fill_level() >= 0.5) { start_audio_playback(); playback_started = true; } } int const n_samples = blip_read_samples(blip, blip_samples, ARRAY_LEN(blip_samples), 0); // We expect to read all samples from blip_buf. If something goes wrong and // we don't, clear the buffer to prevent data piling up in blip_buf's // buffer (which lacks bounds checking). int const avail = blip_samples_avail(blip); if (avail != 0) { printf("Warning: didn't read all samples from blip_buf (%d samples remain) - dropping samples\n", avail); blip_clear(blip); } #ifdef RECORD_MOVIE add_movie_audio_frame(blip_samples, n_samples); #endif // Save the samples to the audio ring buffer lock_audio(); write_samples(blip_samples, n_samples); unlock_audio(); }
ECL_EXPORT void FrameAdvance(MyFrameInfo &f) { if (sgb) { sgb_set_controller_data((uint8_t *)&f.Keys); } else { GB_set_key_state(&GB, f.Keys & 0xff); } sound_start_clock = GB_epoch(&GB); CurrentFramebuffer = f.VideoBuffer; GB_set_lagged(&GB, true); GB.frontend_rtc_time = f.Time; uint32_t target = 35112 - FrameOverflow; f.Cycles = GB_run_cycles(&GB, target); FrameOverflow = f.Cycles - target; if (sgb) { f.Width = 256; f.Height = 224; sgb_render_audio(GB_epoch(&GB), SgbSampleCallback); } else { f.Width = 160; f.Height = 144; } blip_end_frame(leftblip, f.Cycles); blip_end_frame(rightblip, f.Cycles); f.Samples = blip_read_samples(leftblip, f.SoundBuffer, 2048, 1); blip_read_samples(rightblip, f.SoundBuffer + 1, 2048, 1); CurrentFramebuffer = NULL; f.Lagged = GB_get_lagged(&GB); }
int sound_update(unsigned int cycles) { int delta, preamp, time, l, r, *ptr; /* Run PSG & FM chips until end of frame */ SN76489_Update(cycles); fm_update(cycles); /* FM output pre-amplification */ preamp = config.fm_preamp; /* FM frame initial timestamp */ time = fm_cycles_start; /* Restore last FM outputs from previous frame */ l = fm_last[0]; r = fm_last[1]; /* FM buffer start pointer */ ptr = fm_buffer; /* flush FM samples */ if (config.hq_fm) { /* high-quality Band-Limited synthesis */ do { /* left channel */ delta = ((*ptr++ * preamp) / 100) - l; l += delta; blip_add_delta(snd.blips[0][0], time, delta); /* right channel */ delta = ((*ptr++ * preamp) / 100) - r; r += delta; blip_add_delta(snd.blips[0][1], time, delta); /* increment time counter */ time += fm_cycles_ratio; } while (time < cycles); } else { /* faster Linear Interpolation */ do { /* left channel */ delta = ((*ptr++ * preamp) / 100) - l; l += delta; blip_add_delta_fast(snd.blips[0][0], time, delta); /* right channel */ delta = ((*ptr++ * preamp) / 100) - r; r += delta; blip_add_delta_fast(snd.blips[0][1], time, delta); /* increment time counter */ time += fm_cycles_ratio; } while (time < cycles); } /* reset FM buffer pointer */ fm_ptr = fm_buffer; /* save last FM output for next frame */ fm_last[0] = l; fm_last[1] = r; /* adjust FM cycle counters for next frame */ fm_cycles_count = fm_cycles_start = time - cycles; /* end of blip buffers time frame */ blip_end_frame(snd.blips[0][0], cycles); blip_end_frame(snd.blips[0][1], cycles); /* return number of available samples */ return blip_samples_avail(snd.blips[0][0]); }