-1

I've just started programming in C. I'm trying to write a code able to analyse the values from a wav audio file and write them into the array buf[num_samples]; num_samples is defined by reading the info contained in the header of the audio file (it is defined as a uint32_t variable because the audio file can consist of a huge amount of samples). I found this piece of code:

uint16_t buf[num_samples];

// Open WAV file with FFmpeg and read raw samples via the pipe.
FILE *pipe = popen("ffmpeg -i 45s.wav -f s16le -ac 1 -", "r");

// check on the pipe work
if ((pipe = popen("ffmpeg -i 45s.wav -f s16le -ac 1 -", "r"))==NULL) {
    perror("ERROR\n");
}

fread(buf, 2, num_samples, pipe);
pclose(pipe);

Where the second argument of fread() is 2 (referring to bytes) because I'm using a recorder which works with the parameter Bit_per_sample = 16.

However there are problems, in fact the array is filled with "illogical values": I expect values representing a waveform (more or less they should belong to the interval [-20,000; 32,767]).
In order to verify the correct filling of the array I have added a printf with %d of buf[i] in a cicle from i=0 to i=num_samples-1. Below some of the values I got from the output:

64947    65002    65046    65080    65110    65150    65188    65236  
65264    65306    65338    65378    65434    65472    65517    8    
81       128      168      206      241      268      306      322    
424      458      497      520      543      566      586      622       
676      699      728      745      765      796      825      840    
917      950      970      996      1018     1040     1064     1072 
1106     1128     

Can anybody help me or give me some useful advises?
Thank you in advance, hoping I didn't waste your time.

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
  • Could be a byte order issue. Btw you are calling `popen()` twice. Also a 16bit signed integer cannot reach 35,000... – neuhaus Aug 23 '17 at 13:20
  • Could also be a wrong format specifier problem. What is the exact array declaration and how do you print? – Andre Kampling Aug 23 '17 at 13:21
  • You can find the exact array declaration in the question, it is an int array, containing num_samples positions. I print it with the following code: uint32_t i; for (i=0; i – Niccolò Cirone Aug 23 '17 at 13:27
  • Try declaring the `buf` array to be `int16_t`. – neuhaus Aug 23 '17 at 13:28
  • Why you are using `popen()` 2 times? Also you have to read starting at the right position. – Andre Kampling Aug 23 '17 at 13:28
  • Did you read the specs? http://soundfile.sapp.org/doc/WaveFormat/ – Jean-Baptiste Yunès Aug 23 '17 at 13:28
  • Very sorry, I made a mistake when I wrote the code in the question: the array buf[num_samples] is already declared as a uint16_t, but the problem, stays. Now I'm going to correct the question. Anyway could you explain me why I'm using popen() twice? Do you mean in the check I wrote in the 'if'? – Niccolò Cirone Aug 23 '17 at 13:33
  • @NiccolòCirone: Yes you use it before the check and in the check. Because you are doing it before the if statement you just need `if (pipe == NULL)` or doing the assignment inside of the if and not before. Further to print your values the right way cast them in your printf: `printf("%d ", (int)buf[i]);` – Andre Kampling Aug 23 '17 at 13:36
  • 1
    Do you understand what `u` in `uint16_t` means? It means unsigned. It means that you will not ever see a negative value in such a variable! – Antti Haapala -- Слава Україні Aug 23 '17 at 13:37
  • 2
    Furthermore, despite us helping you ages ago, you seem to be not reading *any* comments left to your questions, including the ones asking why the `popen` is being called twice in a question [that has now been deleted](https://stackoverflow.com/questions/45775690/segmentation-fault-caused-by-popen), so you indeed **are** wasting our time. – Antti Haapala -- Слава Україні Aug 23 '17 at 13:41
  • @AnttiHaapala thank you a lot for your answer, it was not clear to me. Anyway can you explain me the reason why these values have totally no relation with a waveform? Even without a sign I expect to see a local wave behaviour of data, isn't it? – Niccolò Cirone Aug 23 '17 at 13:44
  • 2
    **You're reading signed 2's complement numbers as unsigned numbers. The waveform is there, you're just not seeing it, because the signed to unsigned conversion.**, thus -1 becomes 65535, -10 => 65525.Change the type to **`int16_t`** as suggested by Paul originally! Notice the lack of `u` in there. It is `int16_t`. – Antti Haapala -- Слава Україні Aug 23 '17 at 13:45
  • Also reading this: [Signed to unsigned conversion in C](https://stackoverflow.com/a/50632/8051589) would help because that's what happens! Don't ignore what was said here. The answer is already here, read carefully. – Andre Kampling Aug 23 '17 at 13:46
  • Finally of the various answers to the question that I linked, please read [this one especially carefully](https://stackoverflow.com/a/5789914/918959) – Antti Haapala -- Слава Україні Aug 23 '17 at 13:53
  • NiccolòCirone, "more or less they should belong to the interval [-20000; 35000]" is a problem for 2-byte values, how about a more limited range, only up to 32,767? – chux - Reinstate Monica Aug 23 '17 at 14:45
  • @chux Yes, of course the maximum value is 32767, I've been inaccurate! Thank you for the correction – Niccolò Cirone Aug 23 '17 at 15:57
  • You can use sizeof() function to compute the amount of bytes that the function fread will read. – Rafael Coelho Aug 24 '17 at 18:43

1 Answers1

1

Your type is wrong, You're using uint16_t as unsigned type and expect signed values between [-20,000; 32,767].

Declare buf as int16_t buf[num_samples]; so the buffer is declared as elements of 2 (signed) bytes.

Also, to open and check the pipe use

FILE *pipe;
if ((pipe = popen("ffmpeg -i 45s.wav -f s16le -ac 1 -", "r"))==NULL) {
    perror("ERROR\n");
    exit(1);
}
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41