I was attempting to load a sinewave file as a wavetable and play it back at a certain frequency. But instead, it generates some buzzy sounds. Not sure if using std::vector<float> gBuffer as the wavetable buffer is a good idea. Could anyone help to see anything wrong with the code? I'm new to programming and Bela. Really appreciate that!
Custom Wavetable
- Edited
#include <Bela.h>
#include <cmath>
#include <libraries/AudioFile/AudioFile.h>
#include <libraries/Scope/Scope.h>
std::string gFileName = "sine.wav";
float gFrequency = 440.0;
float gPhase;
float gAmplitude = 0.5;
int gWavelength;
std::vector<float> gBuffer;
Scope gScope;
bool setup(BelaContext *context, void *userData)
{
gBuffer = AudioFileUtilities::loadMono(gFileName);
gWavelength = gBuffer.size();
gScope.setup(1, context->audioSampleRate);
return true;
}
void render(BelaContext *context, void *userData)
{
float out = 0.0;
for(int n =0; n < context->audioFrames; n++){
gPhase += gWavelength * (gFrequency/context->audioSampleRate);
int indexBelow = floorf(gPhase);
int indexAbove = indexBelow + 1;
float fractionAbove = gPhase - indexBelow;
float fractionBelow = 1.0 - fractionAbove;
if (indexAbove >= gWavelength){
indexAbove = 0;
}
while(gPhase >= gWavelength){
gPhase -= gWavelength;
}
out = (fractionBelow * gBuffer[indexBelow] + fractionAbove * gBuffer[indexAbove]) * gAmplitude;
for(int c = 0; c< context->audioOutChannels; c ++){
audioWrite(context, n, c, out);
}
gScope.log(out);
}
}
void cleanup(BelaContext *context, void *userData)
{
}
I don't spot anything obvious in the code. Could it be an issue with the file itself? In the following code I replaced the file loading with generating the wavetable on the fly and it sounds decent (insofar as linear interpolation can sound ...)
#include <Bela.h>
#include <cmath>
#include <libraries/AudioFile/AudioFile.h>
#include <libraries/Scope/Scope.h>
std::string gFileName = "sine.wav";
float gFrequency = 440.0;
float gPhase;
float gAmplitude = 0.5;
int gWavelength;
std::vector<float> gBuffer;
Scope gScope;
bool setup(BelaContext *context, void *userData)
{
size_t length = 1024;
for(size_t n = 0; n < length; ++n)
{
gBuffer.push_back(sinf(2.f * float(M_PI) * n / float(length)));
}
gWavelength = gBuffer.size();
gScope.setup(1, context->audioSampleRate);
return true;
}
void render(BelaContext *context, void *userData)
{
float out = 0.0;
for(int n =0; n < context->audioFrames; n++){
gPhase += gWavelength * (gFrequency/context->audioSampleRate);
int indexBelow = floorf(gPhase);
int indexAbove = indexBelow + 1;
float fractionAbove = gPhase - indexBelow;
float fractionBelow = 1.0 - fractionAbove;
if (indexAbove >= gWavelength){
indexAbove = 0;
}
while(gPhase >= gWavelength){
gPhase -= gWavelength;
}
out = (fractionBelow * gBuffer[indexBelow] + fractionAbove * gBuffer[indexAbove]) * gAmplitude;
for(int c = 0; c< context->audioOutChannels; c ++){
audioWrite(context, n, c, out);
}
gScope.log(out);
}
}
void cleanup(BelaContext *context, void *userData)
{
}
Hi guiliomoro! Thank you so much for checking my code. So I guess the buzzy sound is because of linear interpolation? (Since the wav. file is a sinewave)
The code I posted is exactly the same as yours except that instead of loading a file I create the wavetable algorithmically. I don't see (or hear) any mistake in the linear interpolation code.
However, I now see that you are first incrementing the phase, then using it and only after using it you are wrapping it around, which means that you may be using an out-of-range value when you compute indexBelow
.
Try moving the while()
immediately after gPhase +=
.
If that is not enough to fix it, verify that there is nothing wrong with your wavetable (i.e.: the wav file). How did you create that file? Print out the values in setup after you assign gBuffer
and see if you can spot any weird value at the first or last element.
for(size_t n = 0; n < gBuffer.size(); ++n)
{
printf("%.3f ", gBuffer[n]);
if(0 == n % 16)
printf("\n");
}