void blip_end_frame( blip_buffer_t* s, int clocks ) { s->offset += clocks * s->factor; /* Ensure time wasn't past end of buffer */ assert( blip_samples_avail( s ) <= s->size ); }
/* Removes n samples from buffer */ static void remove_samples( blip_buffer_t* s, int n ) { int remain = blip_samples_avail( s ) + buf_extra - n; s->offset -= n * time_unit; assert( s->offset >= 0 ); /* Copy remaining samples to beginning of buffer and clear the rest */ memmove( s->buf, &s->buf [n], remain * sizeof (buf_t) ); memset( &s->buf [remain], 0, n * sizeof (buf_t) ); }
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(); }
static void _mSDLAudioCallback(void* context, Uint8* data, int len) { struct mSDLAudio* audioContext = context; if (!context || !audioContext->core) { memset(data, 0, len); return; } blip_t* left = NULL; blip_t* right = NULL; int32_t clockRate = GBA_ARM7TDMI_FREQUENCY; if (audioContext->core) { left = audioContext->core->getAudioChannel(audioContext->core, 0); right = audioContext->core->getAudioChannel(audioContext->core, 1); clockRate = audioContext->core->frequency(audioContext->core); } double fauxClock = 1; if (audioContext->sync) { if (audioContext->sync->fpsTarget > 0) { fauxClock = GBAAudioCalculateRatio(1, audioContext->sync->fpsTarget, 1); } mCoreSyncLockAudio(audioContext->sync); } blip_set_rates(left, clockRate, audioContext->obtainedSpec.freq * fauxClock); blip_set_rates(right, clockRate, audioContext->obtainedSpec.freq * fauxClock); len /= 2 * audioContext->obtainedSpec.channels; int available = blip_samples_avail(left); if (available > len) { available = len; } blip_read_samples(left, (short*) data, available, audioContext->obtainedSpec.channels == 2); if (audioContext->obtainedSpec.channels == 2) { blip_read_samples(right, ((short*) data) + 1, available, 1); } if (audioContext->sync) { mCoreSyncConsumeAudio(audioContext->sync); } if (available < len) { memset(((short*) data) + audioContext->obtainedSpec.channels * available, 0, (len - available) * audioContext->obtainedSpec.channels * sizeof(short)); } }
static void _GBASDLAudioCallback(void* context, Uint8* data, int len) { struct GBASDLAudio* audioContext = context; if (!context || !audioContext->thread || !audioContext->thread->gba) { memset(data, 0, len); return; } #if RESAMPLE_LIBRARY == RESAMPLE_NN audioContext->ratio = GBAAudioCalculateRatio(audioContext->thread->gba->audio.sampleRate, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq); if (audioContext->ratio == INFINITY) { memset(data, 0, len); return; } struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data; len /= 2 * audioContext->obtainedSpec.channels; if (audioContext->obtainedSpec.channels == 2) { GBAAudioResampleNN(&audioContext->thread->gba->audio, audioContext->ratio, &audioContext->drift, ssamples, len); } #elif RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF double fauxClock = GBAAudioCalculateRatio(1, audioContext->thread->fpsTarget, 1); GBASyncLockAudio(&audioContext->thread->sync); blip_set_rates(audioContext->thread->gba->audio.left, GBA_ARM7TDMI_FREQUENCY, audioContext->obtainedSpec.freq * fauxClock); blip_set_rates(audioContext->thread->gba->audio.right, GBA_ARM7TDMI_FREQUENCY, audioContext->obtainedSpec.freq * fauxClock); len /= 2 * audioContext->obtainedSpec.channels; int available = blip_samples_avail(audioContext->thread->gba->audio.left); if (available > len) { available = len; } blip_read_samples(audioContext->thread->gba->audio.left, (short*) data, available, audioContext->obtainedSpec.channels == 2); if (audioContext->obtainedSpec.channels == 2) { blip_read_samples(audioContext->thread->gba->audio.right, ((short*) data) + 1, available, 1); } GBASyncConsumeAudio(&audioContext->thread->sync); if (available < len) { memset(((short*) data) + audioContext->obtainedSpec.channels * available, 0, (len - available) * audioContext->obtainedSpec.channels * sizeof(short)); } #endif }
int blip_read_samples( blip_buffer_t* s, short out [], int count, int stereo ) { /* can't read more than available */ int avail = blip_samples_avail( s ); if ( count > avail ) count = avail; if ( count ) { /* Sum deltas and write out */ int i; for ( i = 0; i < count; ++i ) { int sample; /* Apply slight high-pass filter */ s->amp -= s->amp >> 9; /* Add next delta */ s->amp += s->buf [i]; /* Calculate output sample */ sample = s->amp >> phase_bits; /* Keep within 16-bit sample range */ if ( sample < -32768 ) sample = -32768; if ( sample > +32767 ) sample = +32767; out [i << stereo] = sample; } remove_samples( s, count ); } return count; }
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]); }