2017-08-09 58 views
0

我寫了一段代碼,該代碼應該讀取一個音頻文件作爲輸入,以便編寫包含每個樣本的csv文件。這是代碼:gnuplot - 軸上的物理尺寸

FILE *pipein; 
      pipein = popen("ffmpeg -i test1.wav -f s16le -ac 1 -", "r"); 
      fread(buf, 2, sample_number, pipein); 
      pclose(pipein); 

      // Print the sample values in the buffer to a CSV file 
      FILE *csvfile; 
      csvfile = fopen("samples.csv", "w"); 

      while (n<=sample_number) { 

      //if (buf[n]!=0) { 

        fprintf(csvfile, "%d %f\n", buf[cont], Sam_freq*cont); 
        cont++; 

     // } 

      n++; 

      } 

      fclose(csvfile); 

這是CSV文件看起來像運行的代碼之後:

10 43.150544 
-36 43.150567 
11 43.150590 
30 43.150612 
-29 43.150635 
61 43.150658 
13 43.150680 
46 43.150703 
121 43.150726 
61 43.150748 
144 43.150771 
128 43.150794 
130 43.150816 
131 43.150839 

我試着用gnuplot的繪製samples.csv的數據,但我不明白該物理尺寸在y軸上表示。

waveform plot 我在其他帖子上看到,y軸上的值代表麥克風膜的變形。有沒有人知道一個數學關係,以從這些值中提取我需要的物理尺寸?

+1

[PCM音頻幅度值?]可能重複?(https://stackoverflow.com/questions/5890499/pcm-audio-amplitude-values) – user8153

回答

4

問題:

  1. 這不是一個CSV文件,它只是一個文本文件。

  2. 你的代碼看起來不像那樣。它遠不是可編譯的,你錯誤地將「相關部分」複製到這個問題上。

    尤其是,您使用n作爲循環變量,但使用cont訪問緩衝區。如果你的代碼實際上是那樣的話,你只會在輸出中看到一對重複的值。

  3. 您沒有定義採樣率。

考慮以下反例:

#include <stdlib.h> 
#include <stdint.h> 
#include <limits.h> 
#include <string.h> 
#include <endian.h> 
#include <stdio.h> 

#ifndef SAMPLE_RATE 
#define SAMPLE_RATE 48000 
#endif 

#define NO_SAMPLE INT_MIN 

#if (__BYTE_ORDER-0 == __BIG_ENDIAN-0) 

/* Use big-endian samples */ 

#define SAMPLE_FORMAT "s16be" 
static inline int read_sample(FILE *source) 
{ 
    int16_t sample; 

    if (fread(&sample, sizeof sample, 1, source) == 1) 
     return (int)sample; 
    else 
     return NO_SAMPLE; 
} 

#elif (__BYTE_ORDER-0 == __LITTLE_ENDIAN-0) || (__BYTE_ORDER-0 == __PDP_ENDIAN-0) 

/* Use little-endian samples */ 

#define SAMPLE_FORMAT "s16le" 
static inline int read_sample(FILE *source) 
{ 
    int16_t sample; 

    if (fread(&sample, sizeof sample, 1, source) == 1) 
     return (int)sample; 
    else 
     return NO_SAMPLE; 
} 

#else 

/* Use little-endian (two's complement) samples, but 
    read them byte-by-byte. */ 

#define SAMPLE_FORMAT "s16le" 
static inline int16_t read_sample(FILE *source) 
{ 
    unsigned char bytes[2]; 
    int   sample; 
    if (fread(bytes, 2, 1, source) != 2) 
     return NO_SAMPLE; 

    sample = bytes[0] + 256*bytes[1]; 
    if (sample > 32767) 
     return sample - 65536; 
    else 
     return sample; 
} 
#endif 

int main(void) 
{ 
    const double sample_rate = SAMPLE_RATE; 
    FILE   *in; 
    unsigned long i; 
    int   sample; 

    in = popen("ffmpeg -i test1.wav -v -8 -nostats -f " SAMPLE_FORMAT " -ac 1 -", "r"); 
    if (!in) 
     return EXIT_FAILURE; 

    i = 0u; 
    while ((sample = read_sample(in)) != NO_SAMPLE) { 
     printf("%.6f %9.6f\n", (double)i/sample_rate, (double)sample/32768.0); 
     i++; 
    } 

    pclose(in); 

    return EXIT_SUCCESS; 
} 

它假定採樣速率是每秒48000個採樣(可以使用ffmpeg先找出採樣速率),則打印出每一樣品,每行一個樣本,第一列有時間,第二列有樣本值(-1.0到剛剛低於+1.0)。

在物理意義上,第一列反映了樣本的時間維度,第二列是傳感器當時的相對壓力變化 - 但是,壓力變化的符號或線性都不是真的衆所周知,因爲它取決於所使用的麥克風,放大器和ADC。

比方說,你編譯並運行上述情況,輸出重定向到test1.out

gcc -Wall -O2 example.c -o example 
./example > test1.out 

你可以很容易的Gnuplot得出這樣的。啓動gnuplot,並告訴它

set xlabel "Time [seconds]" 
set ylabel "Relative pressure change [f((P-P0)/Pmax)]" 
plot "test1.out" u 1:2 notitle w lines 

對於垂直軸,P是在橫軸上指示的時刻的壓力,P0是環境壓力,Pmax是最大壓力改變麥克風可以檢測,和f()是所使用的麥克風,麥克風放大器和模數轉換器電路的非線性的倒數。 (f()Pmax都可能取決於環境壓力P0。)

+0

好奇#define NO_SAMPLE中'-65536'的任何特定原因-65536'也許'#define NO_SAMPLE INT_MIN'? – chux

+1

@chux:沒理由。好的建議;應用。謝謝! –