EDIT: This turned out to be an uninitialized variable creating chaotic behavior. See this post about getting more compiler warnings for JUCE
I was attempting to create a basic synthesizer and I quickly ran into an absurd problem when simply attempting to assign a value to a newly declared variable.
After following along with the JUCE simple sine synthesis tutorial I ran into the problem. This is the basic code of my getNextAudioBlock() function when it is producing white noise. Note how there are four integers declared and assigned throughout:
const int numChannels = bufferToFill.buffer->getNumChannels();
const int numSamples = bufferToFill.numSamples;
for (int channel = 0; channel < numChannels; channel++){
float* const buffer = bufferToFill.buffer -> getWritePointer(channel, bufferToFill.startSample);
for (int sample; sample < numSamples; sample++){
buffer[sample] = (randomGen.nextFloat() * 2.0f - 1.0f);
}
}
However, as soon as I attempt to add another int I no longer get sound. Just simply adding the line int unusedVariable = 0; anywhere in the getNextAudioBlock() function but before the buffer[sample] assignment immediately returns from the function and it therefore produces no audio.
If I simply declare the new variable (int unusedVariable;) then it still works. It is only specifically the assignment part that causes the error. Also, if I declare the variable as a global member then the assignment within the function works just fine.
To reiterate, this works:
buffer[sample] = (randomGen.nextFloat() * 2.0f - 1.0f;
This works:
int unusedVariable;
buffer[sample] = (randomGen.nextFloat() * 2.0f - 1.0f;
But this doesn't:
int unusedVariable = 0;
buffer[sample] = (randomGen.nextFloat() * 2.0f - 1.0f;
My only idea was that allocating new memory on the Audio thread causes the error but I have seen declaration and assignment done in other online sources and even in my exact same function with numChannels, numSamples, channel, and sample all allocated and assigned just fine. I also considered that it has something to do with using the Random class, but I get the same problem even when it is generating sine waves.
EDIT: Here is the exact code copied from the project. Right here nextSample is declared globally, as the buffer does not get filled when it is declared locally
void MainContentComponent::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill)
{
const int numChannels = bufferToFill.buffer->getNumChannels();
const int numSamples = bufferToFill.numSamples;
for (int channel = 0; channel < numChannels; channel++){
float* const buffer = bufferToFill.buffer -> getWritePointer (channel, bufferToFill.startSample);
for (int sample; sample < numSamples; sample++){
// nextSample = (randomGen.nextFloat() * 2.0f - 1.0f); // For Randomly generated White Noise
nextSample = (float) std::sin (currentAngle);
currentAngle += angleDelta;
buffer[sample] = nextSample * volumeLevel;
}
}
}
I created a new AudioApplication project in the Projucer and pasted this block of code into the getNextAudioBlock() method (adding sensible member variables as you're referencing them here).
The compiler pointed at the problem right away -- the loop variable sample below isn't initialized (and C++ won't default init it for you), so if the memory used by that variable happened to have contained a value that's less than the buffer size, you'll generate some audio; if not, the buffer passed into this function is unaffected because the loop never runs.
for (int sample; sample < numSamples; sample++){
nextSample = (randomGen.nextFloat() * 2.0f - 1.0f); // For Randomly generated White Noise
//nextSample = (float) std::sin (currentAngle);
//currentAngle += angleDelta;
buffer[sample] = nextSample * volumeLevel;
}
see if changing that to for (int sample=0; doesn't fix things for you.
Related
My program raises a "vector subscript out of range" exception (EDIT: assertion) on a return statement. Well, it seems like it since it raises it exactly on that breakpoint.
Here is the function that causes it :
Matrix4 Perspective(float fov, float aspect, float near, float far) const {
double yScale = 1.0 / tan(TO_RADIANS * fov / 2);
double xScale = yScale / aspect;
double depth = near - far;
Matrix4 perspective;
perspective[0][0] = xScale;
perspective[1][1] = yScale;
perspective[2][2] = (far + near) / depth;
perspective[2][3] = 2 * far * near / depth;
perspective[3][2] = -1;
perspective[3][3] = 0;
return perspective; // Raises exception here?
}
My default Matrix4 constructor is fine, it basically does this:
_matrix.resize(4);
for (unsigned int i = 0; i < 4; ++i)
_matrix[i].resize(4);
_matrix being a std::vector<std::vector<float>> attribute. So everything is set to 0.
Finally, the piece of code that uses the result of the return statement is this:
Matrix4 camera = Perspective(70, 1, 0.2, 10);
And I have a copy constructor which looks fine aswell:
Matrix4(const Matrix4& matrix) {
_matrix.reserve(4);
for (unsigned int i = 0; i < 4; ++i) {
_matrix[i].reserve(4);
for (unsigned int j = 0; j < 4; ++j)
_matrix[i][j] = matrix[i][j];
}
}
(I also have an overloaded operator[] but the problem really cannot be caused by it.)
The exception assertion seems to be raised on the return perspective;, but maybe it is raised by the line of code that called the method, and the copy constructor somehow failed to copy? But in that case, Visual Studio should bring me inside the constructor since I'm using detailed step-by-step...
I'm lost at this point...
In your copy constructor, change this:
_matrix.reserve(4);
to this:
_matrix.resize(4);
since you want to actually allocate space with vector::resize, in order for _matrix[i][j] = matrix[i][j]; to work smoothly. vector::reserve sets the vector's capacity.
Read more in vector resize VS reverse.
You wrongly use reserve instead of resize.
But you can simplify your copy constructor to
Matrix4(const Matrix4& rhs) : _matrix(rhs._matrix) {}
or even, if applicable:
Matrix4(const Matrix4&) = default;
You have a common mistake. std::vector::reserve:
[i]ncrease[s] the capacity of the vector
, not the size, Thus you either have to use push_back after reserve, or use resize, like in your normal constructor.
So I'm trying to modify the Kinect BodyBasicsD2D code so that a fixed number of "target positions" appear on the screen (as ellipses) for the user to move his hand toward. I'm having trouble creating the initial target positions.
This is my code in the header file for the allocation of the array of target positions (these are a public field of the CBodyBasics class, already built into the original BodyToBasics program):
D2D1_POINT_2F* targetPositions = NULL;
int numTargets = 3;
Then I have a function "GenerateTargetPositions" which is supposed to generate 3, in this case, target positions to be passed into the "DrawTargetPositions" function.
void CBodyBasics::GenerateTargetPositions(D2D1_POINT_2F * targetPositions, int numTargets)
{
targetPositions = new D2D1_POINT_2F[numTargets];
RECT rct;
GetClientRect(GetDlgItem(m_hWnd, IDC_VIDEOVIEW), &rct);
int width = rct.right;
int height = rct.bottom;
FLOAT x;
FLOAT y;
D2D1_POINT_2F tempPoint;
for (int i = 0; i < numTargets; i++) {
x = 1.0f*i*width / numTargets;
y = 1.0f*i*height / numTargets;
tempPoint = D2D1::Point2F(x, y);
targetPositions[i] = tempPoint;
}
}
My DrawTargetPositions function is:
void CBodyBasics::DrawTargetPositions(D2D1_POINT_2F * targetPositions, int numTargets)
{
D2D1_ELLIPSE ellipse;
for (int i = 0; i < numTargets; i++)
{
ellipse = D2D1::Ellipse(targetPositions[i], 50.f, 50.f);
m_pRenderTarget->FillEllipse(ellipse, m_pSilverBrush);
}
}
When I try to run my code, I get the error that both "targetPositions" and "targetPositions[i]" is NULL (and thus my GenerateTargetPositions function must not be working properly). I believe that targetPositions[i] is a struct (a point with x and y values) so I am wondering if this may be the reason for my errors.
I call GenerateTargetPositions and DrawTargetPositions before the main "while" loop in my code so that each function is not being called on each iteration (there are many iterations of through the while loop because this is an interactive Microsoft Kinect, recording one's movements).
Any suggestions and advice would be greatly appreciated. Thanks so much!
I am implementing a ray tracing program using VS2015 community. The program fills a screen size color buffer (width * height with element type of Eigen::Vector3f), then save the buffer content to a ppm file.
The basic loop (Note the output section at the end of the outer loop):
using Vec3f = Eigen::Vector3f;
Vec3f * buffer = new Vec3f[w * h];
// for each pixel
for (int y = 0; y < h; y++) for (int x = 0; x < w; x++)
{
int const i = (h - y - 1) * w + x;
buffer[i] = Vec3f::Zero();
// 2x2 subpixel
for (int sy = 0; sy < 2; sy++) for (int sx = 0; sx < 2; sx++)
{
Vec3f r = Vec3f::Zero();
// sampling
for (int s = 0; s < samps; s++)
{
// do some computation and accumulation to r
// r = ...
}
buffer[i] = buffer[i] + r;
}
buffer[i] = buffer[i] * 0.25f;
// debug with an output section
//if (x % 16 == 0 && y % 16 == 0)
// std::cout << buffer[i] << std::endl;
}
I can get proper result with configurations of:
Debug, x86 or x64;
Release, x86;
Release (optimization = \Od), x64.
However, the buffer is all zero vectors with Release (optimization = \O1 or \O2 or \Ox), x64, and what I got is a black picture.
So with Release (optimization = \O1 or \O2 or \Ox), x64, I uncommented the output section to check the values in the buffer. The strange thing is, each pixel that I checked has a correct value, those not checked remains zero vector. For example, if I check every 16 pixels like the upper code, I will get a picture like this (256*256 black tessellated every 16 pixel):
I googled and read some materials like Surviving the Release Version, but still have no idea. Could anyone provide some experiences dealing with these problems?
Update: The code above is not so detailed, full code is here, depends on Eigen 3.2.6.
After going through the code on Ideone, the problem seems to be as follows. In the Scene class, the intersect method returns a bool const &. The returned reference is a local variable. If you examine the Error/Warning logs you'd have seen:
Warning 2 warning C4172: returning address of local variable or temporary ***.cpp 129 1
changing the return type to bool rectifies the problem and the output is similar to that from the 32 bit version.
For a project I need to be able to generate a spectrogram from a .WAV file. I've read the following should be done:
Get N (transform size) samples
Apply a window function
Do a Fast Fourier Transform using the samples
Normalise the output
Generate spectrogram
On the image below you see two spectrograms of a 10000 Hz sine wave both using the hanning window function. On the left you see a spectrogram generated by audacity and on the right my version. As you can see my version has a lot more lines/noise. Is this leakage in different bins? How would I get a clear image like the one audacity generates. Should I do some post-processing? I have not yet done any normalisation because do not fully understand how to do so.
update
I found this tutorial explaining how to generate a spectrogram in c++. I compiled the source to see what differences I could find.
My math is very rusty to be honest so I'm not sure what the normalisation does here:
for(i = 0; i < half; i++){
out[i][0] *= (2./transform_size);
out[i][6] *= (2./transform_size);
processed[i] = out[i][0]*out[i][0] + out[i][7]*out[i][8];
//sets values between 0 and 1?
processed[i] =10. * (log (processed[i] + 1e-6)/log(10)) /-60.;
}
after doing this I got this image (btw I've inverted the colors):
I then took a look at difference of the input samples provided by my sound library and the one of the tutorial. Mine were way higher so I manually normalised is by dividing it by the factor 32767.9. I then go this image which looks pretty ok I think. But dividing it by this number seems wrong. And I would like to see a different solution.
Here is the full relevant source code.
void Spectrogram::process(){
int i;
int transform_size = 1024;
int half = transform_size/2;
int step_size = transform_size/2;
double in[transform_size];
double processed[half];
fftw_complex *out;
fftw_plan p;
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * transform_size);
for(int x=0; x < wavFile->getSamples()/step_size; x++){
int j = 0;
for(i = step_size*x; i < (x * step_size) + transform_size - 1; i++, j++){
in[j] = wavFile->getSample(i)/32767.9;
}
//apply window function
for(i = 0; i < transform_size; i++){
in[i] *= windowHanning(i, transform_size);
// in[i] *= windowBlackmanHarris(i, transform_size);
}
p = fftw_plan_dft_r2c_1d(transform_size, in, out, FFTW_ESTIMATE);
fftw_execute(p); /* repeat as needed */
for(i = 0; i < half; i++){
out[i][0] *= (2./transform_size);
out[i][11] *= (2./transform_size);
processed[i] = out[i][0]*out[i][0] + out[i][12]*out[i][13];
processed[i] =10. * (log (processed[i] + 1e-6)/log(10)) /-60.;
}
for (i = 0; i < half; i++){
if(processed[i] > 0.99)
processed[i] = 1;
In->setPixel(x,(half-1)-i,processed[i]*255);
}
}
fftw_destroy_plan(p);
fftw_free(out);
}
This is not exactly an answer as to what is wrong but rather a step by step procedure to debug this.
What do you think this line does? processed[i] = out[i][0]*out[i][0] + out[i][12]*out[i][13] Likely that is incorrect: fftw_complex is typedef double fftw_complex[2], so you only have out[i][0] and out[i][1], where the first is the real and the second the imaginary part of the result for that bin. If the array is contiguous in memory (which it is), then out[i][12] is likely the same as out[i+6][0] and so forth. Some of these will go past the end of the array, adding random values.
Is your window function correct? Print out windowHanning(i, transform_size) for every i and compare with a reference version (for example numpy.hanning or the matlab equivalent). This is the most likely cause, what you see looks like a bad window function, kind of.
Print out processed, and compare with a reference version (given the same input, of course you'd have to print the input and reformat it to feed into pylab/matlab etc). However, the -60 and 1e-6 are fudge factors which you don't want, the same effect is better done in a different way. Calculate like this:
power_in_db[i] = 10 * log(out[i][0]*out[i][0] + out[i][1]*out[i][1])/log(10)
Print out the values of power_in_db[i] for the same i but for all x (a horizontal line). Are they approximately the same?
If everything so far is good, the remaining suspect is setting the pixel values. Be very explicit about clipping to range, scaling and rounding.
int pixel_value = (int)round( 255 * (power_in_db[i] - min_db) / (max_db - min_db) );
if (pixel_value < 0) { pixel_value = 0; }
if (pixel_value > 255) { pixel_value = 255; }
Here, again, print out the values in a horizontal line, and compare with the grayscale values in your pgm (by hand, using the colorpicker in photoshop or gimp or similar).
At this point, you will have validated everything from end to end, and likely found the bug.
The code you produced, was almost correct. So, you didn't left me much to correct:
void Spectrogram::process(){
int transform_size = 1024;
int half = transform_size/2;
int step_size = transform_size/2;
double in[transform_size];
double processed[half];
fftw_complex *out;
fftw_plan p;
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * transform_size);
for (int x=0; x < wavFile->getSamples()/step_size; x++) {
// Fill the transformation array with a sample frame and apply the window function.
// Normalization is performed later
// (One error was here: you didn't set the last value of the array in)
for (int j = 0, int i = x * step_size; i < x * step_size + transform_size; i++, j++)
in[j] = wavFile->getSample(i) * windowHanning(j, transform_size);
p = fftw_plan_dft_r2c_1d(transform_size, in, out, FFTW_ESTIMATE);
fftw_execute(p); /* repeat as needed */
for (int i=0; i < half; i++) {
// (Here were some flaws concerning the access of the complex values)
out[i][0] *= (2./transform_size); // real values
out[i][1] *= (2./transform_size); // complex values
processed[i] = out[i][0]*out[i][0] + out[i][1]*out[i][1]; // power spectrum
processed[i] = 10./log(10.) * log(processed[i] + 1e-6); // dB
// The resulting spectral values in 'processed' are in dB and related to a maximum
// value of about 96dB. Normalization to a value range between 0 and 1 can be done
// in several ways. I would suggest to set values below 0dB to 0dB and divide by 96dB:
// Transform all dB values to a range between 0 and 1:
if (processed[i] <= 0) {
processed[i] = 0;
} else {
processed[i] /= 96.; // Reduce the divisor if you prefer darker peaks
if (processed[i] > 1)
processed[i] = 1;
}
In->setPixel(x,(half-1)-i,processed[i]*255);
}
// This should be called each time fftw_plan_dft_r2c_1d()
// was called to avoid a memory leak:
fftw_destroy_plan(p);
}
fftw_free(out);
}
The two corrected bugs were most probably responsible for the slight variation of successive transformation results. The Hanning window is very vell suited to minimize the "noise" so a different window would not have solved the problem (actually #Alex I already pointed to the 2nd bug in his point 2. But in his point 3. he added a -Inf-bug as log(0) is not defined which can happen if your wave file containts a stretch of exact 0-values. To avoid this the constant 1e-6 is good enough).
Not asked, but there are some optimizations:
put p = fftw_plan_dft_r2c_1d(transform_size, in, out, FFTW_ESTIMATE); outside the main loop,
precalculate the window function outside the main loop,
abandon the array processed and just use a temporary variable to hold one spectral line at a time,
the two multiplications of out[i][0] and out[i][1] can be abandoned in favour of one multiplication with a constant in the following line. I left this (and other things) for you to improve
Thanks to #Maxime Coorevits additionally a memory leak could be avoided: "Each time you call fftw_plan_dft_rc2_1d() memory are allocated by FFTW3. In your code, you only call fftw_destroy_plan() outside the outer loop. But in fact, you need to call this each time you request a plan."
Audacity typically doesn't map one frequency bin to one horizontal line, nor one sample period to one vertical line. The visual effect in Audacity may be due to resampling of the spectrogram picture in order to fit the drawing area.
I'm working on a section of someone else's code and hence have been limited to the amount of modification I can do. Anyway, I'm currently trying to create a texture array and have become stuck with a problem:
What I need to support is n textures being individually loaded and stored as GLubytes in a vector. I then need to take all of the data stored in that vector and store it in a single GLubyte object. Currently my code looks something like this:
vector<GLubyte*> vecPixelData;
GLubyte* puData;
for(int i = 0; i < NumberOfTextures; i++)
{
GLubyte* pixData;
LoadTexture(&pixData);
vecPixelData.push_back(pixData);
}
int puDataSize = nWidth * nHeight * 4 * NumberOfTextures;
puData = new GLubyte[puDataSize];
for(int i = 0; i < NumberOfTextures; i++)
*puData += *vecPixelData[i];
Now I'm sure I'm missing some fundamental points on how to copy memory from vecPixelData to puData, and if not, can anyone give me a 'pointer' as to somewhere to begin on how to check if puData is actually storing the data required. (I've tried using the memory window but the data in puData doesn't seem to get altered.)
EDIT:
The Solution in the end was:
int puDataSize = nWidth * nHeight * 4;
puData = new GLubyte[puDataSize * NumberOfTextures];
for(int i = 0; i < NumberOfTextures.size(); i++)
memcpy(puData + (puDataSize * i), vecPixelData[i], puDataSize);
If I understand your problem correctly you need to use std::copy. Something along the lines of std::copy(*vecPixelData[i], *vecPixelData[i] + imageSize, puData + offstet) (leaving the calculations of imageSize and offset to you) inside your last for loop.