I try to load a sound file from the SD to build a wave table. I am playing around and somehow it is working. My main concern is how to handle the frequency. At first I though to think about a sound sample like a cycle, so at 1Hz the sound would be played once, 2Hz twice... But this didn't sound right to me when it came to play notes. So I decided to have a base frequency (C4) and modulate the speed to play the sample base on this frequency. This seem to work better, at least for what I want to do. But I actually wonder if there is not a proper algorithm to do this. (I am still beginning with synthetisis and mainly trying thing out in a freestyle way) Following is the code:
I would love to get feedback to improve the code
Code:
#ifndef AUDIO_SYNTH_WAVE_TABLE_SD_H_
#define AUDIO_SYNTH_WAVE_TABLE_SD_H_
#include <Arduino.h>
#include <AudioStream.h>
template <uint16_t MAX_TABLE_SIZE = 24000>
class AudioSynthWaveTableSD : public AudioStream {
public:
AudioSynthWaveTableSD() : AudioStream(0, NULL), magnitude(16384) {}
AudioSynthWaveTableSD *frequency(float freq) {
if (freq <= 0.0) {
phase_increment = 0.0;
} else {
phase_increment = freq / baseFreq;
}
return this;
}
AudioSynthWaveTableSD *amplitude(float n) {
magnitude = constrain(n, 0.0, 1.0);
return this;
}
void update(void) {
audio_block_t *block = allocate();
if (block == NULL || magnitude == 0.0 || phase_increment == 0.0)
return; // but here we might still want to increase the
// phase_accumulator
for (unsigned int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
phase_accumulator += phase_increment;
if ((uint32_t)phase_accumulator > end) {
phase_accumulator = start;
}
block->data[i] =
(int16_t)(data[(uint32_t)phase_accumulator] * magnitude);
}
transmit(block);
release(block);
}
bool load(const char *filename) {
File rawfile;
rawfile = SD.open(filename);
if (!rawfile || !rawfile.available()) {
return false;
}
size = rawfile.read(data, min(MAX_TABLE_SIZE, rawfile.size()));
end = min(end, size);
rawfile.close();
return true;
}
AudioSynthWaveTableSD *setBaseFreq(float freq) {
baseFreq = freq;
return this;
}
AudioSynthWaveTableSD *setStart(uint32_t val) {
start = val;
return this;
}
AudioSynthWaveTableSD *setEnd(uint32_t val) {
end = min(val, size);
return this;
}
private:
float baseFreq = 440.0;
float phase_accumulator;
float phase_increment;
float magnitude;
int16_t data[MAX_TABLE_SIZE];
uint32_t size = 0;
uint32_t end = MAX_TABLE_SIZE;
uint32_t start = 0;
};
#endif
I would love to get feedback to improve the code