caudiotrigonometrysynthesizersample-rate

Generating sin wave creates noise


I have a simple program in C to generate a square wave at a specific frequency, sample-rate, and amplitude, which works fine. However, if I comment out the relevant line and uncomment the new sine-wave line, it generates my sine wave, but also creates a lot of noise when I process the output into Audacity or SoX.

However, a log file containing the data in my generated buffer reads as expected, with signed values within the amplitude, oscillating in time (samples) relative to the specified frequency, with no unexpected values or noise...

That might lead me to think something is wrong with the sample-rate or some other setting (endianness, mono/stereo, data type, etc.), but as I said before, the square wave has no such troubles. Also I ensured that all calculation was done using a double-precision float type so that I know integer coercion isn't my problem. I am stumped. Any help or insight is welcome.

Here's what I have:

#define pi 3.1415926

int main()
{
    FILE *fer=fopen("log.txt","w");
    double f=440; //freq
    double a=1000; //amplitude
    double p=44100/f; //period

    int16_t *b=malloc(sizeof(int16_t)*44100);
    if(!b)return 1;

    for(int i=0;i<44100;i++)
    {
        double ll=sin( (2.0L*pi/p)*i ) * a;   //SINE WAVE
        // double ll=fmod(i,p)<p/2?a:-a;   //SQUARE WAVE
        b[i]= ll;
        fprintf(fer,"%i\n",b[i]);
    }

    fwrite(b,sizeof(int16_t),44100,stdout);

    free(b);
    fclose(fer);
}

Solution

  • You have sent the binary output to stdout, which is a text stream, and you presumably redirect it to a file. On some OSs the newline character in a text stream is converted. So when the byte value 0x0A or perhaps 0x0D is seen, it is converted to another value, or possibly to two values. It might be part of a 16-bit value, for example 0x0D00 and the system doesn't know these are 16-bit values. One clue is that the resultant file size is larger than expected.

    The solution is to open a file in binary mode and write the data to that.

    About the other comment: the base value. Sometimes the data should have its centre (zero value) at 0x8000 and the data is treated as unsigned and adjusted by the player. I notice yours is treated as signed data with no zero offset.

    This means that for your amplitude of 1000 the data is either in the range -1000 to +1000, or in the range 31768 to 33768.