如何在C语言中通过popen获取arecord的输出并处理?
通过C语言管道捕获arecord音频数据并绘图的实现
你这段代码的思路很清晰:通过popen调用arecord录制音频,读取采样数据写入文件,再调用gnuplot绘图展示。不过有几个细节可以优化或者需要注意,我帮你梳理一下:
原始代码(补全必要定义)
#include <stdio.h> // 必须定义GNUPLOT宏,否则编译会报错;-persist参数让绘图窗口保持打开 #define GNUPLOT "gnuplot -persist" int main(int argc,char *argv[]) { FILE* file = popen("arecord -r 8000 --format S32_LE -D plughw:0,0 -d 4", "r"); long buffer[100]; FILE *fp; fp=fopen("./record.dat", "w+"); int i; for (i=0; i<40000; i++){ fscanf(file, "%ld", &buffer[i%100]); fprintf(fp,"%d\t%ld\n", i , buffer[i%100] ) ; } pclose(file); fclose(fp) ; FILE *p = popen(GNUPLOT,"w"); fprintf(p,"plot 'record.dat' lt rgb 'red' title 'yeag' \n"); fclose(p); return 0; }
关键问题与优化建议
- 音频数据读取方式错误:你指定
arecord输出的是S32_LE格式,这是二进制32位小端整数,但用fscanf("%ld")按文本格式读取会完全解析错误——二进制数据会被当成字符处理,拿到的数值和实际采样值毫无关系。正确的做法是用fread读取二进制数据:// 替换原有的fscanf行 fread(&buffer[i%100], sizeof(long), 1, file); - 循环次数不合理:录制4秒、8000Hz采样率,总采样数应为
8000*4=32000,但你循环了40000次,最后8000次会读取失败。建议把循环条件改成i < 32000,避免无效操作。 - 缺少错误检查:代码没有判断
popen、fopen的返回值,如果这些调用失败(比如arecord不存在、文件无法创建),程序会直接崩溃。可以加上简单的错误处理:if (file == NULL) { perror("Failed to open arecord pipe"); return 1; } if (fp == NULL) { perror("Failed to create record.dat"); pclose(file); return 1; } - 缓冲区可以简化:用
i%100复用100个元素的缓冲区没问题,但如果只是临时存储单个采样值,用单个long变量就足够,没必要用数组。
优化后的核心循环示例
修正二进制读取和循环次数后的核心逻辑:
for (i=0; i<32000; i++){ // 检查读取是否成功 if (fread(&buffer[i%100], sizeof(long), 1, file) != 1) { fprintf(stderr, "Failed to read sample at index %d\n", i); break; } fprintf(fp,"%d\t%ld\n", i , buffer[i%100] ) ; }
这样修改后,程序就能正确捕获音频采样数据,并用gnuplot画出真实的音频波形了。
内容的提问来源于stack exchange,提问作者Peter Lustig
相关产品推荐
相关产品推荐

