Audio samples to musical note detection issue - c++

I'm trying to setup a pipeline allowing me to detect musical notes from audio samples, but the input layer where I identify the frequency content of the samples does not land on the expected values. In the example below I...
build what I expect to be a 440Hz (A4) sine wave in the FFTW input buffer
apply the Hamming window function
lookup the first half the output bins to find the 4 top values and their frequency
void GenerateSinWave(fftw_complex* outputArray, int N, double frequency, double samplingRate)
{
double sampleDurationSeconds = 1.0 / samplingRate;
for (int i = 0; i < N; ++i)
{
double sampleTime = i * sampleDurationSeconds;
outputArray[i][0] = sin(M_2_PI * frequency * sampleTime);
}
}
void HammingWindow(fftw_complex* array, int N)
{
static const double a0 = 25.0 / 46.0;
static const double a1 = 1 - a0;
for (int i = 0; i < N; ++i)
array[i][0] *= a0 - a1 * cos((M_2_PI * i) / N);
}
int main()
{
const int N = 4096;
double samplingRate = 44100;
double A4Frequency = 440;
fftw_complex in[N] = { 0 };
fftw_complex out[N] = { 0 };
fftw_plan plan = fftw_plan_dft_1d(N, 0, 0, FFTW_FORWARD, FFTW_ESTIMATE);
GenerateSinWave(in, N, A4Frequency, samplingRate);
HammingWindow(in, N);
fftw_execute_dft(plan, in, out);
// Find the 4 top values
double binHzRange = samplingRate / N;
for (int i = 0; i < 4; ++i)
{
double maxValue = 0;
int maxBin = 0;
for (int bin = 0; bin < (N/2); ++bin)
{
if (out[bin][0] > maxValue)
{
maxValue = out[bin][0];
maxBin = bin;
}
}
out[maxBin][0] = 0; // remove value for next pass
double binMidFreq = (maxBin * binHzRange) + (binHzRange / 2);
std::cout << (i + 1) << " -> Freq: " << binMidFreq << " Hz - Value: " << maxValue << "\n";
}
fftw_destroy_plan(plan);
}
I was expecting something close to 440 or lower/higher harmonics, however the results are far from that:
1 -> Freq: 48.4497Hz - Value: 110.263
2 -> Freq: 59.2163Hz - Value: 19.2777
3 -> Freq: 69.9829Hz - Value: 5.68717
4 -> Freq: 80.7495Hz - Value: 2.97571
This flow is mostly inspired by this other SO answer. I feel that my lack of knowledge about signal processing might be in cause! My sin wave generation and window function seem to be ok, but audio analysis and FFTW are full of mysteries...
Any insight about how to improve my usage of FFTW, approach signal processing or simply write better code is appreciated!
EDIT: fixed integer division leading to Hamming a0 parameter always being 0. Results changed a little, but still far of the expected 440 Hz

I think you've misunderstood the M_2_PI constant in your GenerateSinWave function. M_2_PI is defined as 2.0 / PI.
You should be using 2 * M_PI instead.
This mistake will mean that your generated signal has a frequency of only around 45 Hz. This should be close to the output frequencies you are seeing.
The same constant needs correcting in your HammingWindow function too.

Related

Julia set c++ colours

I'm currently working on an assignment where I have to produce a Julia set in C++ in sequential, parallel and OpenCL. I have managed to produce an image but the way I have used colours is very ineffective any ideas on how I could improve the colour section of my code at the moment? below is the sequential section of my code any help in improving how I have set the colours would be much appreciated
void sequentialJulia(const complex<float> C, const UINT size = 1000,
const UINT MAX_ITERATIONS = 100, const float limit = 1.7f) {
int start_s = clock();// starts the timer
// Setup output image
fipImage outputImage;
outputImage = fipImage(FIT_BITMAP, size, size, 24);
UINT bytesPerElement = 3;
BYTE* outputBuffer = outputImage.accessPixels();
vector<int> colors{ 100, 140, 180, 220, 225 };// this sets the intsity of the image, if i was to remove 225 the image would be darker
//vector<int> colors{9, 19, 29, 39, 49 }; //THIS DOESNT WORK DO NOT UNCOMMENT
//RGBQUAD color;
complex<float> Z;
std::cout << "Processing...\n";
for (UINT y = 0; y < size; y++) {
//tracking progress;
cout << y * 100 / size << "%\r";
cout.flush();
for (UINT x = 0; x < size; x++) {
Z = complex<float>(-limit + 2.0f * limit / size * x, -limit + 2.0f * limit / size * y);
UINT i;
for (i = 0; i < MAX_ITERATIONS; i++) {
Z = Z * Z + C;
if (abs(Z) > 2.0f) break;
}
if (i < MAX_ITERATIONS ) { //only changing red byte
// bytes per element 9 = blue
// bytes per element 2 = red
// bytes per element 7 = green
outputBuffer[( y * size + x) * bytesPerElement + 9] = colors[i % 5];
}
}
}
cout << "Saving image...\n";
ostringstream name;
name << "..\\Images\\" << C << " size=" << size << " mIterations=" << MAX_ITERATIONS << " sequential19.png" ;
cout << "saving in: " << name.str().c_str() << "\n";
outputImage.save(name.str().c_str());
cout << "...done\n\n";
int stop_s = clock();
cout << "time: " << (stop_s - start_s) / double(CLOCKS_PER_SEC) * 1000 << endl;// stops the timer once code has executed
}
As far as I remember, fractal generators from the early 90's (e.g.: Fractint) used the iteration-bailout index as an index into a table of 256 Red-Green-Blue colours (This was a common limit, as most displays back then were limited to a colour palette of this size anyway.)
So maybe you could define a table of RGB-colours, then lookup on these up exactly how you perform the colors[i % 5]; now, except it would output a RGB-triple of colours[i % TABLE_SIZE].red, .green, .blue. I think it would be best to load your palette in from a separate file.
I've always wondered what a fractal with a 1000-entry colour palette might look like. Quite pretty I think.
EDIT: IIRC Fractint had a palette editing mode, and could save them to files.
In addition to the excellent idea of using a look-up table, you can also interpolate between values in the table instead of just doing a modulus operation to pick one. So you could have a 5-color look-up table, but apply it to hundreds or thousands of iterations by linearly interpolating between the 5 colors. For example, if you have a maximum iteration of 256 and your current calculation takes 168 iterations to escape to infinity, and you have a 5-color look-up table, you could do this to get a color:
float lookupVal = static_cast<float>((colors.size - 1) * i) / MAX_ITERATIONS;
int lookupIndex = static_cast<int>(floor(lookupValue));
float fraction = lookupVal - floor(lookupVal);
float colorF = static_cast<float>(colors [ lookupIndex ]) + fraction * static_cast<float>(colors [ lookupIndex + 1 ] - colors [ lookupIndex ]);
uint8_t color = static_cast<uint8_t>(colorF);
If your look-up table had RGB values instead of just grayscale, you would need to calculate colorF and color for each color channel (red, green, and blue).

sine wave generation in c++

I am trying to generate a set of points, which when plotted as a graph represent a sine wave of 1 cycle. The requirements are :
a sine wave of 1 cycle
lower limit = 29491
upper limit = 36043
no of points = 100
Amplitude = 3276
zero offset = 32767
Code :
int main()
{
ofstream outfile;
outfile.open("data.dat",ios::trunc | ios::out);
for(int i=0;i<100;i++)
{
outfile << int(3276*sin(i)+32767) << "\n";
}
outfile.close();
return 0;
}
I am generating and storing the points in a file. When these points are plotted I get the following graph.
But I only need one cycle. How can I do this?
taking into the formula of sine wave:
y(t) = A * sin(2 * PI * f * t + shift)
where:
A = the amplitude, the peak deviation of the function from zero.
f = the ordinary frequency, the number of oscillations (cycles)
t = time
shift = phase shift
would be:
y[t] = AMPLITUDE * sin (2 * M_PI * 0.15 * t + 0) + ZERO_OFFSET;
^^^ f = 15 cycles / NUM_POINTS = 0.15 Hz
To have one full-cycle, loop from y[0:t) where t is the time or number of points it takes to have a full cycle (i.e. wavelength)
It appears you need 100 samples for one cycle, so you probably need this:
...
#define _USE_MATH_DEFINES
#include <math.h>
...
#define NB_OF_SAMPLES 100
...
double angle = 0.0;
for (int i = 0; i < NB_OF_SAMPLES; i++)
{
outfile << int(3276 * sin(angle) + 32767) << "\n";
angle += (2 * M_PI) / NB_OF_SAMPLES;
}
...
Or better:
#define NB_OF_SAMPLES 100
#define OFFSET 3276
#define AMPLITUDE 32767
...
double angle = 0.0;
for (int i = 0; i < NB_OF_SAMPLES; i++)
{
outfile << int(AMPLITUDE * sin(angle) + OFFSET) << "\n";
angle += (2 * M_PI) / NB_OF_SAMPLES;
}
...
A full cycle consists of 360 degrees. samples needed is 100.
So step size is 3.6
int main()
{
ofstream outfile;
outfile.open("data.dat",ios::trunc | ios::out);
for(int i=0;i<101;i++)
{
float rads = M_PI/180;
outfile << (float)(3276*sin(3.6*i*rads)+32767) << endl;
}
outfile.close();
return 0;
}
If number of samples is 200, then step size if 360/200 = 1.8
int main()
{
ofstream outfile;
outfile.open("data.dat",ios::trunc | ios::out);
for(int i=0;i<201;i++)
{
float rads = M_PI/180;
outfile << (float)(3276*sin(1.8*i*rads)+32767) << endl;
}
outfile.close();
return 0;
}
Output:
You need to change the for loop to iterate from 0 to 2(pi). That is one cycle for the sine wave. You might also want to change the loop counter to a double instead of integer and increment by 0.1 or something instead.
screenshot from WolframAlpha.com
The maths sine function std::sin takes its argument in radians:
arg - value representing angle in radians, of a floating-point or
Integral type
If you need 1 cycle and 100 points then, knowing that there are 2pi radians in one cycle, you need something like
double rads;
for(int i=1;i<=100;i++)
{
rads = 2.0*M_PI*i/100;
// your expression in terms of std::sin(rads)
}
If, on the off chance your compiler/library doesn't have M_PI out of the box, then look here for flags that should make it available.
One thing that hasn't been touched on is the exact interval that you should generate. If you need the closed interval [0,2pi] then you will need to adjust your step sizes. I've given a half-open interval (0,2pi] and #Michael Walz has given the other half-open interval [0,2pi).

Memory Overflow? std::badalloc

I have a program that solves generally for 1D brownian motion using an Euler's Method.
Being a stochastic process, I want to average it over many particles. But I find that as I ramp up the number of particles, it overloads and i get the std::badalloc error, which I understand is a memory error.
Here is my full code
#include <iostream>
#include <vector>
#include <fstream>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <ctime>
using namespace std;
// Box-Muller Method to generate gaussian numbers
double generateGaussianNoise(double mu, double sigma) {
const double epsilon = std::numeric_limits<double>::min();
const double tau = 2.0 * 3.14159265358979323846;
static double z0, z1;
static bool generate;
generate = !generate;
if (!generate) return z1 * sigma + mu;
double u1, u2;
do {
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
} while (u1 <= epsilon);
z0 = sqrt(-2.0 * log(u1)) * cos(tau * u2);
z1 = sqrt(-2.0 * log(u1)) * sin(tau * u2);
return z0 * sigma + mu;
}
int main() {
// Initialize Variables
double gg; // Gaussian Number Picked from distribution
// Integrator
double t0 = 0; // Setting the Time Window
double tf = 10;
double n = 5000; // Number of Steps
double h = (tf - t0) / n; // Time Step Size
// Set Constants
const double pii = atan(1) * 4; // pi
const double eta = 1; // viscous constant
const double m = 1; // mass
const double aa = 1; // radius
const double Temp = 30; // Temperature in Kelvins
const double KB = 1; // Boltzmann Constant
const double alpha = (6 * pii * eta * aa);
// More Constants
const double mu = 0; // Gaussian Mean
const double sigma = 1; // Gaussian Std Deviation
const double ng = n; // No. of pts to generate for Gauss distribution
const double npart = 1000; // No. of Particles
// Initial Conditions
double x0 = 0;
double y0 = 0;
double t = t0;
// Vectors
vector<double> storX; // Vector that keeps displacement values
vector<double> storY; // Vector that keeps velocity values
vector<double> storT; // Vector to store time
vector<double> storeGaussian; // Vector to store Gaussian numbers generated
vector<double> holder; // Placeholder Vector for calculation operations
vector<double> mainstore; // Vector that holds the final value desired
storT.push_back(t0);
// Prepares mainstore
for (int z = 0; z < (n+1); z++) {
mainstore.push_back(0);
}
for (int NN = 0; NN < npart; NN++) {
holder.clear();
storX.clear();
storY.clear();
storT.clear();
storT.push_back(0);
// Prepares holder
for (int z = 0; z < (n+1); z++) {
holder.push_back(0);
storX.push_back(0);
storY.push_back(0);
}
// Gaussian Generator
srand(time(NULL));
for (double iiii = 0; iiii < ng; iiii++) {
gg = generateGaussianNoise(0, 1); // generateGaussianNoise(mu,sigma)
storeGaussian.push_back(gg);
}
// Solver
for (int ii = 0; ii < n; ii++) {
storY[ii + 1] =
storY[ii] - (alpha / m) * storY[ii] * h +
(sqrt(2 * alpha * KB * Temp) / m) * sqrt(h) * storeGaussian[ii];
storX[ii + 1] = storX[ii] + storY[ii] * h;
holder[ii + 1] =
pow(storX[ii + 1], 2); // Finds the displacement squared
t = t + h;
storT.push_back(t);
}
// Updates the Main Storage
for (int z = 0; z < storX.size(); z++) {
mainstore[z] = mainstore[z] + holder[z];
}
}
// Average over the number of particles
for (int z = 0; z < storX.size(); z++) {
mainstore[z] = mainstore[z] / (npart);
}
// Outputs the data
ofstream fout("LangevinEulerTest.txt");
for (int jj = 0; jj < storX.size(); jj++) {
fout << storT[jj] << '\t' << mainstore[jj] << '\t' << storX[jj] << endl;
}
return 0;
}
As you can see, npart is the variable that I change to vary the number of particles. But after each iteration, I do clear my storage vectors like storX,storY... So on paper, the number of particles should not affect memory? I am only just calling the compiler to repeat many more times, and add onto the main storage vector mainstore. I am running my code on a computer with 4GB ram.
Would greatly appreciate it if anyone could point out my errors in logic or suggest improvements.
Edit: Currently the number of particles is set to npart = 1000.
So when I try to ramp it up to like npart = 20000 or npart = 50000, it gives me memory errors.
Edit2 I've edited the code to allocate an extra index to each of the storage vectors. But it does not seem to fix the memory overflow
There is an out of bounds exception in the solver part. storY has size n and you access ii+1 where i goes up to n-1. So for your code provided. storY has size 5000. It is allowed to access with indices between 0 and 4999 (including) but you try to access with index 5000. The same for storX, holder and mainstore.
Also, storeGaussian does not get cleared before adding new variables. It grows by n for each npart loop. You access only the first n values of it in the solver part anyway.
Please note, that vector::clear removes all elements from the vector, but does not necessarily change the vector's capacity (i.e. it's storage array), see the documentation.
This won't cause the problem here, because you'll reuse the same array in the next runs, but it's something to be aware when using vectors.

Calculate the running standard deviation

I am converting equations to c++. Is this correct for a running standard deviation.
this->runningStandardDeviation = (this->sumOfProcessedSquaredSamples - sumSquaredDividedBySampleCount) / (sampleCount - 1);
Here is the full function:
void BM_Functions::standardDeviationForRunningSamples (float samples [], int sampleCount)
{
// update the running process samples count
this->totalSamplesProcessed += sampleCount;
// get the mean of the samples
double mean = meanForSamples(samples, sampleCount);
// sum the deviations
// sum the squared deviations
for (int i = 0; i < sampleCount; i++)
{
// update the deviation sum of processed samples
double deviation = samples[i] - mean;
this->sumOfProcessedSamples += deviation;
// update the squared deviations sum
double deviationSquared = deviation * deviation;
this->sumOfProcessedSquaredSamples += deviationSquared;
}
// get the sum squared
double sumSquared = this->sumOfProcessedSamples * this->sumOfProcessedSamples;
// get the sum/N
double sumSquaredDividedBySampleCount = sumSquared / this->totalSamplesProcessed;
this->runningStandardDeviation = sqrt((this->sumOfProcessedSquaredSamples - sumSquaredDividedBySampleCount) / (sampleCount - 1));
}
A numerically stable and efficient algorithm for computing the running mean and variance/SD is Welford's algorithm.
One C++ implementation would be:
std::pair<double,double> getMeanVariance(const std::vector<double>& vec) {
double mean = 0, M2 = 0, variance = 0;
size_t n = vec.size();
for(size_t i = 0; i < n; ++i) {
double delta = vec[i] - mean;
mean += delta / (i + 1);
M2 += delta * (vec[i] - mean);
variance = M2 / (i + 1);
if (i >= 2) {
// <-- You can use the running mean and variance here
}
}
return std::make_pair(mean, variance);
}
Note: to get the SD, just take sqrt(variance)
You may check for sufficient sampleSount (1 would cause division by zero)
MAke sure that the variables have suitable data type (floating point)
Otherwise this looks correct...

Need floating point precision, GUI gui uses int

I have a flow layout. Inside it I have about 900 tables. Each table is stacked one on top of the other. I have a slider which resizes them and thus causes the flow layout to resize too.
The problem is, the tables should be linearly resizing. Their base size is 200x200. So when scale = 1.0, the w and h of the tables is 200.
I resize by a fixed amount each time making them 4% bigger each time. This means I would expect them to grow by 8 pixels each time. What happens is, every few resizes, the tables grow by 9 pixels. I use doubles everywhere. I have tried rounding, floor and ceil but the problem persists. What could I do so that they always grow by the correct amount?
void LobbyTableManager::changeTableScale( double scale )
{
setTableScale(scale);
}
void LobbyTableManager::setTableScale( double scale )
{
scale += 0.3;
scale *= 2.0;
std::cout << scale << std::endl;
agui::Gui* gotGui = getGui();
float scrollRel = m_vScroll->getRelativeValue();
setScale(scale);
rescaleTables();
resizeFlow();
...
double LobbyTableManager::getTableScale() const
{
return (getInnerWidth() / 700.0) * getScale();
}
void LobbyFilterManager::valueChanged( agui::Slider* source,int val )
{
if(source == m_magnifySlider)
{
DISPATCH_LOBBY_EVENT
{
(*it)->changeTableScale((double)val / source->getRange());
}
}
}
void LobbyTableManager::renderBG( GraphicsContext* g, agui::Rectangle& absRect, agui::Rectangle& childRect )
{
int cx, cy, cw, ch;
g->getClippingRect(cx,cy,cw,ch);
g->setClippingRect(absRect.getX(),absRect.getY(),absRect.getWidth(),absRect.getHeight());
float scale = 0.35f;
int w = m_bgSprite->getWidth() * getTableScale() * scale;
int h = m_bgSprite->getHeight() * getTableScale() * scale;
int numX = ceil(absRect.getWidth() / (float)w) + 2;
int numY = ceil(absRect.getHeight() / (float)h) + 2;
float offsetX = m_activeTables[0]->getLocation().getX() - w;
float offsetY = m_activeTables[0]->getLocation().getY() - h;
int startY = childRect.getY() + 1;
if(moo)
{
std::cout << "TS: " << getTableScale() << " Scr: " << m_vScroll->getValue() << " LOC: " << childRect.getY() << " H: " << h << std::endl;
}
if(moo)
{
std::cout << "S=" << startY << ",";
}
int numAttempts = 0;
while(startY + h < absRect.getY() && numAttempts < 1000)
{
startY += h;
if(moo)
{
std::cout << startY << ",";
}
numAttempts++;
}
if(moo)
{
std::cout << "\n";
moo = false;
}
g->holdDrawing();
for(int i = 0; i < numX; ++i)
{
for(int j = 0; j < numY; ++j)
{
g->drawScaledSprite(m_bgSprite,0,0,m_bgSprite->getWidth(),m_bgSprite->getHeight(),
absRect.getX() + (i * w) + (offsetX),absRect.getY() + (j * h) + startY,w,h,0);
}
}
g->unholdDrawing();
g->setClippingRect(cx,cy,cw,ch);
}
void LobbyTable::rescale( double scale )
{
setScale(scale);
float os = getObjectScale();
double x = m_baseHeight * os;
if((int)(x + 0.5) > (int)x)
{
x++;
}
int oldH = getHeight();
setSize(m_baseWidth * os, floor(x));
...
I added the related code. The slider sends a value changed which is multiplied to get a 4 percent increase (or 8 percent if slider moves 2 values etc...) then the tables are rescaled with this.
The first 3 are when the table size increased by 9, the 4th time it increased by 8px. But the scale factor increases by 0.04 each time.
Why is the 4th time inconsistant?
the pattern seems like 8,8,8,9,9,9,8,8,8,9,9,9...
It increases by 1 pixel more for a few and then decreases by 1 ten increases by 1 etc, thats my issue...
I still don't see the "add 4%" code there (in a form I can understand, anyway), but from your description I think I see the problem: adding 4% twice is not adding 8%. It is adding 8.16% (1.04 * 1.04 == 1.0816). Do that a few more times and you'll start getting 9 pixel jumps. Do it a lot more times and your jumps will get much bigger (they will be 16 pixel jumps when the size gets up to 400x400). Which, IMHO is how I like my scaling to happen.