Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with writing a 16bit raw PCM file

Tags:

c

16-bit

wav

pcm

As a small experimental music piece I am attempting to program a song in standard C. The code outputs a raw PCM file which can be imported into Audacity. At the moment everything works as expected, but I'm encountering problems when trying to write each sample as 16 bit as opposed to the current 8 bit I am using.

Up until the point of being written, the current sample is calculated as a float, and its bounds are kept pretty much within the range of a signed 8 bit integer. It is then written as a 8 bit integer before repeating the process for the next sample. This works fine and plays properly. The problem occurs when I try to write it as a 16bit raw PCM file - I multiply the float by 256 and copy the result to a integer, whereupon I use fwrite to write the resulting 16bit integer. This does not give the expected results when imported, resulting in a highly distorted version of what I was expecting.

I've added the valid code below, since the problem occurs only at the writing stage.

Working 8bit code:

if (out<-127) {out=-128;} else if (out>126) {out=127;}
putc(out,fo);

Not working 16bit code:

if (out<-127) {out=-128;} else if (out>126) {out=127;}
pcm=out*256;
fwrite(&pcm,2,1,fo);

I'm probably just missing something obvious, but I've been trying to work it out for hours. Thanks in advance!

like image 307
blkrbt Avatar asked Jul 24 '10 14:07

blkrbt


1 Answers

I can't tell what exactly is wrong in your code without seeing it, but this will make you a nice 1 KHz sine wave 16-bit PCM openable in Audacity:

#include <stdio.h>
#include <math.h>

#ifndef M_PI
#define M_PI 3.14159265358
#endif

int main(void)
{
  FILE* f = fopen("sinewave.pcm", "wb");
  double t;
  for (t = 0; t < 1; t += 1./8000) // 8000 is the sample rate in Hz
  {
    double sample = 15000 * sin(2 * M_PI * 1000 * t); // 1000 Hz sine wave
    short s16 = (short)sample;
    unsigned char c;
    c = (unsigned)s16 % 256;
    fwrite(&c, 1, 1, f);
    c = (unsigned)s16 / 256 % 256;
    fwrite(&c, 1, 1, f);
  }
  fclose(f);
  return 0;
}

In Audacity navigate through File->Import->Raw Data:

Encoding: Signed 16-bit PCM
Byte Order: Little-endian
Channels: 1 Channel (Mono)
Sample rate: 8000

Import.

like image 134
Alexey Frunze Avatar answered Nov 01 '22 04:11

Alexey Frunze