static void SampleCallback(GB_gameboy_t *gb, GB_sample_t sample, uint64_t clock) { int l = sample.left - sample_gb.left; int r = sample.right - sample_gb.right; if (l) blip_add_delta(leftblip, clock - sound_start_clock, l); if (r) blip_add_delta(rightblip, clock - sound_start_clock, r); sample_gb = sample; }
static void SgbSampleCallback(int16_t sl, int16_t sr, uint64_t clock) { int l = sl - sample_sgb.left; int r = sr - sample_sgb.right; if (l) blip_add_delta(leftblip, clock - sound_start_clock, l); if (r) blip_add_delta(rightblip, clock - sound_start_clock, r); sample_sgb.left = sl; sample_sgb.right = sr; }
static inline void square_add_delta(blip_t *blip, uint32_t clocks, int32_t *cur_sample, int32_t new_sample) { if ( new_sample != *cur_sample ) { blip_add_delta(blip, clocks, new_sample - *cur_sample); *cur_sample = new_sample; } }
void set_audio_signal_level(int16_t level) { // TODO: Do something to reduce the initial pop here? static int16_t previous_signal_level = 0; unsigned time = frame_offset; int delta = level - previous_signal_level; if (is_backwards_frame) { // Flip deltas and add them from the end of the frame to reverse audio. // Since the exact length of the frame can't be known in advance, the // length of each frame is recorded when it is saved to the rewind // buffer. // // This is easiest to visualize by thinking of deltas as fenceposts and // the signal level as spans between them. While rewinding, the signal // level that's being set should be considered the one to the left of // the fencepost. // // One complication is the boundary between frames while rewinding - // there the final sample added to one frame is not followed in time by // the first sample of the next frame. To solve this, we bring the // signal level down to zero at the end of each frame, and then adjust // it to the correct value in the next frame (when rewinding, "to zero" // becomes "from zero", and everything still works out). We also call // begin_frame() between frames to invalidate the cached signal level // in apu.cpp. Together this allows frames to be mixed-and-matched // arbitrarily in time. // // Thanks to Blargg for help on this. time = get_frame_len() - time; delta = -delta; } blip_add_delta(blip, time, delta); previous_signal_level = level; }
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]); }
int psg_context_load(uint8 *state) { int delta[2]; int i, bufferptr = 0; /* initialize delta with current noise channel output */ if (psg.noiseShiftValue & 1) { delta[0] = -psg.chanOut[3][0]; delta[1] = -psg.chanOut[3][1]; } else { delta[0] = 0; delta[1] = 0; } /* add current tone channels output */ for (i=0; i<3; i++) { if (psg.polarity[i] > 0) { delta[0] -= psg.chanOut[i][0]; delta[1] -= psg.chanOut[i][1]; } } load_param(&psg.clocks,sizeof(psg.clocks)); load_param(&psg.latch,sizeof(psg.latch)); load_param(&psg.noiseShiftValue,sizeof(psg.noiseShiftValue)); load_param(psg.regs,sizeof(psg.regs)); load_param(psg.freqInc,sizeof(psg.freqInc)); load_param(psg.freqCounter,sizeof(psg.freqCounter)); load_param(psg.polarity,sizeof(psg.polarity)); load_param(psg.chanOut,sizeof(psg.chanOut)); /* add noise channel output variation */ if (psg.noiseShiftValue & 1) { delta[0] += psg.chanOut[3][0]; delta[1] += psg.chanOut[3][1]; } /* add tone channels output variation */ for (i=0; i<3; i++) { if (psg.polarity[i] > 0) { delta[0] += psg.chanOut[i][0]; delta[1] += psg.chanOut[i][1]; } } /* update mixed channels output */ if (config.hq_psg) { blip_add_delta(snd.blips[0], psg.clocks, delta[0], delta[1]); } else { blip_add_delta_fast(snd.blips[0], psg.clocks, delta[0], delta[1]); } return bufferptr; }