Buffering of audio
This commit is contained in:
+44
-31
@@ -26,6 +26,12 @@ double phase = 0.0;
|
||||
unsigned long lastNoteChangeTime = 0;
|
||||
// ---
|
||||
|
||||
// Ring Buffer
|
||||
int16_t audioBuffer[AUDIO_BUFFER_SIZE];
|
||||
int audioHead = 0;
|
||||
int audioTail = 0;
|
||||
bool audioBuffering = true;
|
||||
|
||||
void setupAudio() {
|
||||
// Configure I2S pins
|
||||
i2s.setBCLK(I2S_BCLK_PIN);
|
||||
@@ -43,7 +49,9 @@ void setupAudio() {
|
||||
|
||||
// Initialize the portable synth engine
|
||||
globalSynth = new SynthEngine(SAMPLE_RATE);
|
||||
globalSynth->loadPreset(2);
|
||||
if (globalSynth) {
|
||||
globalSynth->loadPreset(2);
|
||||
}
|
||||
}
|
||||
|
||||
void loopAudio() {
|
||||
@@ -71,38 +79,43 @@ void loopAudio() {
|
||||
}
|
||||
}
|
||||
|
||||
const int BATCH_SIZE = 16;
|
||||
|
||||
// Ensure we don't generate samples faster than the I2S can consume them.
|
||||
// We write 2 samples (Left + Right) for every 1 synth sample.
|
||||
if (i2s.availableForWrite() < BATCH_SIZE * 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process a small batch of samples
|
||||
static int16_t samples[BATCH_SIZE];
|
||||
|
||||
// Generate sound samples
|
||||
if (globalSynth) {
|
||||
// using synth engine
|
||||
globalSynth->process(samples, BATCH_SIZE);
|
||||
// Produce samples in a cyclic buffer
|
||||
int nextHead = (audioHead + 1) % AUDIO_BUFFER_SIZE;
|
||||
if (nextHead != audioTail) {
|
||||
if (audioHead == audioTail) {
|
||||
audioBuffering = true;
|
||||
}
|
||||
int16_t sample = 0;
|
||||
if (globalSynth) {
|
||||
globalSynth->process(&sample, 1);
|
||||
} else {
|
||||
if (currentFrequency > 0) {
|
||||
phase += 2.0 * M_PI * currentFrequency / SAMPLE_RATE;
|
||||
if (phase >= 2.0 * M_PI) phase -= 2.0 * M_PI;
|
||||
sample = phase * 0.1f * AMPLITUDE;
|
||||
} else {
|
||||
sample = 0;
|
||||
}
|
||||
}
|
||||
audioBuffer[audioHead] = sample;
|
||||
audioHead = nextHead;
|
||||
} else {
|
||||
// using fallback sawtooth
|
||||
for (int i = 0; i < BATCH_SIZE; ++i) {
|
||||
if (currentFrequency > 0) {
|
||||
//samples[i] = (int16_t)(sin(phase) * AMPLITUDE);
|
||||
phase += 2.0 * M_PI * currentFrequency / SAMPLE_RATE;
|
||||
if (phase >= 2.0 * M_PI) phase -= 2.0 * M_PI;
|
||||
samples[i] = phase * 0.1f * AMPLITUDE;
|
||||
} else {
|
||||
samples[i] = 0;
|
||||
}
|
||||
}
|
||||
audioBuffering = false;
|
||||
}
|
||||
|
||||
// write out stereo samples
|
||||
for (int i = 0; i < BATCH_SIZE; ++i) {
|
||||
i2s.write(samples[i]);
|
||||
i2s.write(samples[i]);
|
||||
// Consume samples from this buffer whenever there is capacity in i2s
|
||||
while (!audioBuffering && audioHead != audioTail) {
|
||||
if (i2s.availableForWrite() < 2) {
|
||||
break;
|
||||
}
|
||||
int16_t s = audioBuffer[audioTail];
|
||||
i2s.write(s);
|
||||
i2s.write(s);
|
||||
audioTail = (audioTail + 1) % AUDIO_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Update usage stats
|
||||
int usage = audioHead - audioTail;
|
||||
if (usage < 0) usage += AUDIO_BUFFER_SIZE;
|
||||
audioBufferUsage = usage;
|
||||
}
|
||||
Reference in New Issue
Block a user