A40i使用笔记:QT使用alsa采集音频pcm信息

一、前言

目的是实现一种效果,就是在音频识别时,能够实时显示当前人员说话的声音幅度,通过波形曲线的形式显示出来。如下效果(非我实现)

还可以实现在实时采集的同时,将需要的数据保存成指定格式文件,如csv,wav,pcm等。 

目前函数模式是存储为pcm格式,如需转成其他格式需要使用不同的库函数或者按照协议格式重写

二、环境

全志A40i

linux3.10

alsa

三、正文

从硬件上首先要具备Audio音频部分,这里硬件支持的话具备硬件电路接口就不同多说什么了,其次就主要是软件层次了

首先要在linux上使用音频采集,就要使用alsa库,交叉安装alsa库的方式也有很多

有的平台环境上和硬件上都默认是已经包含的了,可以通过find -name libasound.so查看

这里我是用的是qt交叉编译程序,一开始总是没有找到libasound库,后来把lib去掉才能正常识别

在pro文件中加入

LIBS +=   -L/root/workspace/allwinner/A40i/bsp/lichee/out/sun8iw11p1/linux/common/buildroot/host/usr/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/ -lasound

头文件中加入

#include <alsa/asoundlib.h>

至此,我终于能够在我的编译环境中正常不报错的编译程序了,但是才刚刚入坑,后面的问题一把又一把的出现,每次都是以为解决当前的问题后面就都不是问题了,结果,,,哎,都是泪

我是用的源码如下:

void menu::on_btn_Ingames_2_clicked()
{



    snd_pcm_t *handle;//PCM句柄
    snd_pcm_hw_params_t *params;//配置硬件参数结构体(PCM硬件配置空间容器)

//    snd_pcm_close(handle);
    int ret = snd_pcm_open(&handle,"hw:/dev/snd/controlC0",SND_PCM_STREAM_CAPTURE,0);//SND_PCM_STREAM_PLAYBACK 或 SND_PCM_STREAM_CAPTURE,分别表示播放和录音的PCM流
    if(ret < 0){
        fprintf(stderr,"unable to open pcm device: %s\n",snd_strerror(ret));
        exit(1);
    }
    else{
        qDebug()<<QString("open pcm device:%1").arg(snd_strerror(ret));
    }
    //params申请内存(使用标准alloca分配无效的snd_pcm_hw_参数)
    snd_pcm_hw_params_alloca(&params);
    //使用pcm设备初始化hwparams(用PCM的完整配置空间填充参数)
   snd_pcm_hw_params_any(handle,params);
   //设置多路数据在buffer中的存储方式
       //SND_PCM_ACCESS_RW_INTERLEAVED每个周期(period)左右声道的数据交叉存放
   snd_pcm_hw_params_set_access(handle,params,SND_PCM_ACCESS_RW_INTERLEAVED);//SND_PCM_ACCESS_RW_INTERLEAVED//SND_PCM_ACCESS_RW_NONINTERLEAVED
    //设置16位采样格式
   snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
   //设置声道数1
   ret = snd_pcm_hw_params_set_channels(handle,params,1);
   if(ret <0){
       fprintf(stderr,"Error setting channels.\n");
       exit(1);
   }
   else
      qDebug()<<"set channels ok";


   int dir=0;
   int rate = 44100; /* Sample rate */
   unsigned int exact_rate;   /* Sample rate returned by */
   //设置采样率44100,如果采样率不支持,会用硬件支持最接近的采样率
   exact_rate=rate;
   ret = snd_pcm_hw_params_set_rate_near(handle,params,&exact_rate,0);
  if(ret <0){
      fprintf(stderr,"Error setting rate.\n");
      exit(1);
  }
  else
     qDebug()<<"set rate ok";
  if (rate != exact_rate) {
    fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n Using %d Hz instead.\n", rate, exact_rate);
  }
  else
      qDebug()<<"best rate is "<<QString::number(exact_rate);



//    int periods = 2; //2      /* Number of periods */
//    /* Set number of periods. Periods used to be called fragments. */
//   ret = snd_pcm_hw_params_set_periods(handle,params,periods,0);
//   if(ret <0){
//       fprintf(stderr,"Error setting periods.\n");
//       exit(1);
//   }
//   else
//      qDebug()<<"set periods ok ,periods is "<<QString::number(periods);


   long unsigned int frames = 128;//32
//    //设置周期大小(将配置空间限制为最接近目标的周期大小)
//   snd_pcm_hw_params_set_period_size_near(handle,params,&frames,0);//0
//   qDebug()<<"frames near "<<QString::number(frames);


//   snd_pcm_uframes_t periodsize = 4096;
//   if (snd_pcm_hw_params_set_buffer_size(handle, params, (periodsize * periods)>>2) < 0) {
//         fprintf(stderr, "Error setting buffersize.\n");
//         exit(1);
//       }
//   else
//       qDebug()<<"set buffersize ok";

//让这些参数作用于PCM设备(安装从配置空间和SND_PCM_PREPARE选自配置空间的PCM硬件配置)
   ret = snd_pcm_hw_params(handle,params);
   if(ret <0){
       fprintf(stderr,"unable toset hw params: %s\n",snd_strerror(ret));
       exit(1);
   }
   else
       qDebug()<<"set hw params ok";


   //
//long unsigned int frames = 0;//32
 //从配置空间中提取周期大小。
   snd_pcm_hw_params_get_period_size(params,&frames,0);
   int size = frames *4;
   qDebug()<<"frames is "<<QString::number(frames)<<",size is "<<QString::number(size);

   char* pcmBuff = (char*)malloc(size);
//从配置空间中提取周期时间
   unsigned int val =0;
   snd_pcm_hw_params_get_period_time(params,&val,0);
   qDebug()<<"val is "<<QString::number(val);
//打开输出文件
   FILE* pFile;
   pFile = fopen("test.pcm","wb");

  int index=0;
   while(index<10)
   {
        //从PCM读取交错帧
       ret = snd_pcm_readi(handle,pcmBuff,frames);
       if(ret == -EPIPE){//发生暂停事件(Stream被暂停并等待应用程序恢复)
           fprintf(stderr,"overrun.... \n");
           snd_pcm_prepare(handle);
       }
       else if(ret < 0){
           fprintf(stderr,"error read: %s\n",snd_strerror(ret));
           exit(1);
       }
       else if(ret != frames ){
           fprintf(stderr,"less read: %s\n",ret);
       }

       ret = fwrite(pcmBuff,sizeof(char),size,pFile);
       if(ret != size){
           fprintf(stderr,"less write: %s\n",ret);
       }
       printf("%d\n",index);
       index++;

   }

   snd_pcm_drain(handle);
   snd_pcm_close(handle);

   free(pcmBuff);
   fclose(pFile);


   printf("audio capture exit.. \n");


   ui->label_44->setText(QString::number(qrand()%100));





}

各位看官先不要着急ctrl+c,这里源码未经过最终调试,因为我在第一步snd_pcm_open就卡住了,哭晕。

第一步解决了第二部又出现问题,真是一步一个坎啊,总共需要配置10多个函数,每个函数都要搞明白具体含义是什么,才能具体调试,上述代码是暂时能够简单录制声音,并生成pcm文件,通过audacity-win-2.2.2.exe软件可以播放录制的pcm声音。

程序执行打印信息

pcm文件解析播放声音

接下来就是详细梳理分析每个使用到的函数功能作用,并加上注释去消化理解,不知不觉凌晨2点了,下面(等哟时间的)功能还差将读取的数据解析细化出来每个帧含义,将数据分类显示成曲线和生成其他格式文件。


第二天20230418和19凌晨更新

不知不觉有时凌晨2点,每天都是计划12点之前睡觉,然后一调试总是有各种各样的问题,就要去抓紧解决,否则又要多耽误一天,不过功夫不负有心人,目前所有的问题基本算是都解决了,比如开机崩溃问题,存储数据格式问题,格式解析问题,曲线刷新问题,采集数据问题等等

这个项目由于部分原因,不能把最终的源码开放出来,这里就说一下思路吧

1.音频采集必须单独开启一个线程,和主线程绑定信号进行交互通信

2.性能差的主板不建议实时刷新曲线,因为在主线程刷新曲线会造成现成数据通讯阻塞,从而导致数据有几十甚至几百甚至全部数据失真,因为进程阻塞,新的数据没有传递过来,数据还在刷新,就丢失了原始数据,后来我为了实时看数据曲线,专门改成了3秒刷新一次曲线

3.数据最终采集后存储表格的话也需要注意,因为xlsx表格上限104万行, 采样频率44.1khz之后每秒采集44100个采样点,基本24秒左右表格一列就存储到上限了,这时候如果不处理的话再继续存储数据也会丢失

下面附上我实现的最终效果图

这张图片是采集数据总曲线,导出的pcm数据用软件复现曲线,导出的csv用wps复现曲线,完全一致

 

此图也是基本实现了我想要的效果图,如前言那张图片

 

 wps复现曲线图

四、结语

有时候项目没有调完就写上博客了,为什么呢,所以这个文章的内容主要时干嘛的呢

第一:记录前期环境准备和铺路方式,后续在走就能少走点弯路

第二:立下此flag,以后要解决,以后解决更新此文

第三:把我的问题发布出来,如果有同道中人遇到此问题或有解决方式,可以互相探讨解决。

第四:分享给可能进度还没有到达我这一步的新人们,互相沟通互相交流i互相学习

未完待续


20230419 完

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本课程详细、全面地介绍了 Qt 开发中的各个技术细节,并且额外赠送在嵌入式端编写Qt程序的技巧。整个课程涵盖知识点非常多,知识模块囊括 Qt-Core 组件、QWidgets、多媒体、网络、绘图、数据库,超过200个 C++ 类的分析和使用,学完之后将拥有 Qt 图形界面开发的非常坚实的功底。 每个知识点不仅仅会通过视频讲解清楚,并且会配以精心安排的实验和作业,用来保证学习过程中切实掌握核心技术和概念,通过实验来巩固,通过实验来检验,实验与作业的目的是发现问题,发现技术盲点,通过答疑和沟通夯实技术技能。注意:本套视频教程来源于线下的实体班级,因此视频中有少量场景对话和学生问答,对此比较介意的亲们谨慎购买。注意:本套视频教程包含大量课堂源码,包含对应每个知识点的精心编排的作业。由于CSDN官方规定在课程介绍中不能出现作者的联系方式,因此在这里无法直接给出QQ答疑号,视频中的源码、资料和作业文档链接统一在购买后从CSDN平台跟我沟通,我会及时回复跟进。注意:本套视频教程包含全套10套作业题,覆盖所有视频知识点,循序渐进,各个击破,作业总纲如下:下面是部分作业题目展示,每道题都有知识点说明,是检验学习效果的一大利器:(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)…… ……
### 回答1: a40i-linuxsdk是一个用于开发人脸识别系统的软件开发工具包。以下是对a40i-linuxsdk使用手册的回答: a40i-linuxsdk使用手册提供了关于如何使用a40i-linuxsdk的详细指导。手册中包含了安装、配置、编译和运行a40i-linuxsdk所需的步骤和说明。 首先,手册介绍了如何下载和安装a40i-linuxsdk。它提供了下载链接和安装指南,让用户能够迅速将a40i-linuxsdk部署到自己的开发环境中。 接下来,手册详细解释了如何配置a40i-linuxsdk。配置过程包括设置开发环境变量、添加所需的依赖项和库文件等。手册提供了清晰的步骤和示例,让用户能够轻松完成配置工作。 然后,手册介绍了如何编译和构建使用a40i-linuxsdk的应用程序。它提供了编译的指令和示例代码,帮助用户理解如何将a40i-linuxsdk集成到自己的项目中。 最后,手册讲解了如何运行a40i-linuxsdk开发的应用程序。它提供了启动应用程序的命令和参数的解释,帮助用户正确地运行和调试他们的应用程序。 总之,a40i-linuxsdk使用手册是一个详细的指南,提供了使用a40i-linuxsdk进行开发的全面支持。无论是初学者还是有经验的开发人员,都能从手册中获得所需的信息和指导,快速上手a40i-linuxsdk开发。 ### 回答2: a40i-linuxsdk是一种提供给开发者使用的软件开发工具包,用于开发基于Linux操作系统的应用程序。下面是关于如何使用a40i-linuxsdk的简要说明: 1. 下载和安装:首先,您需要从官方网站或其他可靠渠道下载a40i-linuxsdk软件包。然后,按照提供的安装指南进行安装。确保您的计算机符合所需的操作系统和硬件要求。 2. 环境设置:安装完成后,您需要设置适当的开发环境。这可能涉及设置路径变量、配置编译器和构建工具,以及安装其他必要的依赖项。阅读提供的环境设置指南以获得详细说明。 3. API文档和示例:查阅提供的API文档,了解可用的函数、类和方法,以及如何使用它们。如果有提供示例代码,建议您将其下载并尝试运行,以便更好地理解SDK的功能和用法。 4. 开发应用程序:现在,您可以开始编写自己的应用程序了。使用SDK提供的功能和工具,根据自己的需求来开发您的应用。您可以调用相应的API函数、处理事件、进行数据交互等等。 5. 调试和测试:在编写和构建应用程序的过程中,可能会出现一些错误或问题。通过使用SDK提供的调试工具和日志功能,可以帮助您找出并解决这些问题。测试您的应用程序以确保其在不同的情况下正常运行。 6. 发布应用程序:当您完成应用程序的开发、调试和测试后,您可以将其部署到目标设备上。按照提供的部署指南进行操作,将应用程序转移到目标设备上,并确保其能够正确运行。 总之,a40i-linuxsdk是一个提供开发工具和资源的软件开发工具包,可以帮助开发者在Linux操作系统上构建应用程序。通过阅读手册、查阅API文档和示例,开发者可以快速上手并使用该SDK进行应用程序开发。 ### 回答3: a40i-linuxsdk使用手册是一本详细介绍a40i-linuxsdk使用方法和指导的手册。它包含了以下几个方面的内容: 1. 安装指南:手册中会详细介绍如何在不同的操作系统上安装a40i-linuxsdk,并提供相应的安装包和命令。 2. 系统配置:手册会指导用户如何配置a40i-linuxsdk的系统环境,包括操作系统版本、依赖库、驱动程序等。 3. SDK基础:手册会介绍a40i-linuxsdk的基本概念、目录结构和核心组件,帮助用户快速了解整个开发框架。 4. API文档:手册会提供完整的API文档,详细说明每个API的功能、参数和调用方法,并提供示例代码供参考。 5. 开发示例:手册中会提供一些常见的开发示例,涵盖图像处理、声音处理、人脸识别等领域,帮助用户快速上手并实现自己的应用。 6. 故障排除:手册中会列举一些常见的问题和解决方法,帮助用户在开发过程中遇到问题时进行自助排查。 总之,a40i-linuxsdk使用手册是一本非常实用的参考资料,对于初学者帮助其快速上手并进行应用开发,对于有经验的开发者则提供了全面的文档和示例,为他们的开发工作提供支持和便利。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大桶矿泉水

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值