I am generating from C++ code various forms of a PCM sound wave using composed harmonics of sine functions, then after importing file in Audacity to see the result, import is done at a maximum sample rate Audacity can support for raw data files (signed 16 bits, 384000Hz) just to spot possible errors in sampled harmonics. The problem what I have spotted is that after 5000 samples the sawtooth wave differ in length than the original sin base and the square one (these 2 are aligned in the final width). Where the length error is coming for the sawtooth wave I really do not understand.
Code:
#include <iostream>
#include <fstream>
#include <cmath>
typedef char sint8;
typedef unsigned char uint8;
typedef signed short int sint16;
typedef unsigned short int uint16;
typedef unsigned int uint32;
using namespace std;
#define PI 3.14159265F
#define DEG2RAD(value) ((float)(value) * (PI/180.F))
// Just for debugging LSB and MSB
void dec2bin(signed long int number, unsigned short size)
{
int c, k;
for (c = (size*8)-1; c >= 0; c--)
{
k = number >> c;
if (k & 1)
printf("1");
else
printf("0");
if (c % 4 == 0)
printf(" ");
}
printf("\n");
}
float generateSquareWave(uint32 degreeValue, uint32 harmonics, uint32 frequency)
{
float resultSinSum = 0.F;
for(uint32 degreeIndex = 0x00000001U; degreeIndex <= 0x00000002U*harmonics; degreeIndex += 0x00000002U)
{
resultSinSum += ((1.F/(float)(degreeIndex))*sin(((float)(frequency))*((float)(degreeIndex))*DEG2RAD(degreeValue)));
}
return resultSinSum;
}
float generateSawTooth(uint32 degreeValue, uint32 harmonics, uint32 frequency)
{
float resultSinSum = 0.F;
for(uint32 degreeIndex = 0x00000001U; degreeIndex <= 0x00000002U*harmonics; degreeIndex += 0x00000001U)
{
resultSinSum += ((1.F/(float)(degreeIndex))*sin(((float)(frequency))*((float)(degreeIndex))*DEG2RAD(degreeValue)));
}
return -(0.615F * resultSinSum);
}
int main()
{
const uint32 WAVE_CYCLES = 5000U;
const uint32 DEGREE_PER_CYCLE = 360U;
const uint32 NUMBER_OF_SAMPLES = WAVE_CYCLES * DEGREE_PER_CYCLE;
sint8 functionSamples[NUMBER_OF_SAMPLES] = {};
ofstream myfile;
myfile.open("sound.raw");
for(uint32 degreeIndex = 0x00000000; degreeIndex <= NUMBER_OF_SAMPLES; degreeIndex += 0x00000001U)
{
// ORIGINAL: float soundFunction = sin(DEG2RAD(degreeIndex));
//float soundFunction = cos(DEG2RAD(degreeIndex));
//float soundFunction = sqrt(DEG2RAD(degreeIndex));
//float soundFunction = generateSquareWave(degreeIndex, 16U, 1U);
float soundFunction = generateSawTooth(degreeIndex, 16U, 1U);
soundFunction = soundFunction * 32768;
if( soundFunction > 32767 ) soundFunction = 32767;
if( soundFunction < -32768 ) soundFunction = -32768;
// Write LSB 16b int PCM from float32
functionSamples[degreeIndex] = static_cast<sint8>(static_cast<sint16>(soundFunction) >> 8);
functionSamples[degreeIndex+1] = static_cast<sint8>(soundFunction);
}
myfile.write(&functionSamples[0], NUMBER_OF_SAMPLES);
myfile.close();
return 0;
}
First 5 cycles are aligned in width:
After 5000 cycles:
Seems that sawtooth wave have a bigger number of periods, but is same as the other 2 initial waves just the length in the cycle width differ for which I don't have a explanation.
I also overlap waves in the Google plot view to spot the error but no error: