1

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);
}
C. Dunn
  • 101
  • 1
  • 6
  • What does the noise look like in Audacity, for example? – Sami Kuhmonen Mar 23 '19 at 11:56
  • This has been asked before but I can't find it. The problem was in opening the file in text mode (by default), and data `0x0D` was converted, when it was one byte of, say `0x140D` 16-bit value. Open a file in binary mode. I don't understand why you are sending binary data to `stdout`. Presumably you redirect the output. Have a look at the resultant file size, is it larger than expected? – Weather Vane Mar 23 '19 at 12:05
  • Also, there is no zero-offset in the data. Does Audacity mind that? Or does it expect the 16-bit data to be centred around `0x8000`? – Weather Vane Mar 23 '19 at 12:18
  • @WeatherVane Yes, you were exactly right, on all counts. Using stdout was simply CLI shorthand to substitute for actual file management. It never crossed my mind that `stdout` wasn't a binary stream. Now I feel dumb. I suppose you could create an answer if you want, or I can delete the question since it's a duplicate. Also, I'm not sure if I understand the second question. Perhaps Audacity gleans the offset value from the encoding (signed 16-bit, 32-bit float, etc.) - same for SoX – C. Dunn Mar 23 '19 at 12:40

1 Answers1

1

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.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
  • Thanks again. So for that question, I believe SoX and Audacity behave differently, if simply just for the difference in UI. SoX is more flexible, in that it allows input of raw audio data as 16-bit unsigned or signed, while Audacity (as of v 2.3.0) only allows _signed_ 16-bit raw audio data (it does allow unsigned 8-bit). In that case, SoX will interpret 0x8000 as the base value (unsigned), and both will use 0x0000 if signed. I actually checked that with both, and SoX will kind of invert each half of signed input (in unsigned mode). Hope that was somewhat clear – C. Dunn Mar 23 '19 at 13:12
  • Hm yes, I suppose the coding system can be detected by a lack of data in the extreme regions (if unsaturated / not clipped). – Weather Vane Mar 23 '19 at 13:15