zoukankan      html  css  js  c++  java
  • Linux对于录音

    一、原理简介

    在Linux下,记录——从dsp读取数据。播放——至dsp设备写入数据。

    开发板採用声卡UDA1341实现音频编解码,完毕A/D和D/A转换,芯片UDA1341与CPU的连接图例如以下:

    为了实现全双工,传输数据须要使用两个DMA通道。以音频回放为例,传输数据先由内部总线送到内存。 然后传到DMA控制器通道1,再通过IIS控制器写入IIS总线并传输给音频芯片,通道2用来录音。

    二、WAV文件

    WAVE是录音时用的标准的Windows文件格式,文件的扩展名为“wav”。数据本身的格式为PCM或压缩型。属于无损音乐格式的一种,符合RIFF(Resource Interchange File Format)规范。全部的WAV都有一个文件头,这个文件头音频流的编码參数。

    数据块的记录方式是小端(little-endian字节顺序,标志符并非字符串而是单独的符号


    採样率为8kHz,量化位数为16,单通道的record.wav文件为例,文件前三行信息例如以下:


    第一列表示地址,一行表示16个字节。

    0x52,0x49,0x46,0x46   //“RIFF”4个字符相应的ASCII码值

    0x57,0x41,0x56,0x45,0x66,0x6D,0x74,0x20  //“WAVEfmt ”各个字符相应的ASCII码值

    0x10,0x00,0x00,0x00,0x01,0x00,0x01,0x00//sizeof(PCMWAVEFORMAT)4Byte,格式类别2B,通道数1B(声道)

    0x40,0x1F,0x00,0x00,0x80,0x3E,0x00,0x00, //採样频率0X0001F40= 8kHZ(8000Hz)4B。0x00003E80B/s=16kB/s 4B

    0x02,0x00,0x10,0x00,0x64,0x61,0x74,0x61};//数据调整数0x0002(1*16/8)2B,即一个採样点所占的字节数。样本数据位数0x10(16位)2B,即一个採样点所表示的位数    “data”4B

    地址000014H~000017H的值:2400 01 00即十六进制0x00010024,相应十进制65572(65536+36),表示从0x08開始到文件尾的总字节数;

    地址000028H~00002BH的值:0080 0C 00即十六进制0x00010000,相应十进制65536,表示採样数据总数。

    录音測试命令:cat  /dev/sound/dsp > audio.wav 

    使用cat命令生成的audio.wav是一个PCM纯音频文件:


    通过加入wav文件头,能够生成一个标准的wav音频文件:


    三、Linux下实现录放音

    注意驱动程序中的默认參数,应用程序能够通过ioctl()函数设置新的取值。


    Open()函数:採用何种模式对声卡进行操作也必须在打开设备时指定,对于不支持全双工的声卡来说,应该使用仅仅读或者仅仅写的方式打开。仅仅有那些支持全双工的声卡。才干以读写的方式打开,这还依赖于驱动程序的详细实现。open_mode有三种选择:O_RDONLY。O_WRONLY和O_RDWR,分别表示仅仅读、仅仅写和读写。

    OSS建议尽量使用仅仅读或仅仅写。仅仅有在全双工的情况下(即录音和放音同一时候)才使用读写模式。Linux 同意应用程序多次打开或者关闭与声卡相应的设备文件,从而可以非常方便地在放音状态和录音状态之间进行切换。

    注意,用户始终要读/写一个完整的採样。比如一个16-bit的立体声模式下。每一个採样有4个字节。所以应用程序每次必须读/写4的倍数个字节。

    源代码例如以下:

    #include<unistd.h>
    #include<fcntl.h>
    #include<sys/types.h>
    #include<sys/ioctl.h>
    #include<stdlib.h>
    #include<stdio.h>
    #include<linux/soundcard.h>
     
    #define LENGTH 3    // 存储秒数
    #define RATE 44100  // 採样频率
    #define SIZE 16     // 量化位数
    #define CHANNELS 2  // 声道数目
    /* 用于保存数字音频数据的内存缓冲区*/
    unsigned charbuf[LENGTH*RATE*SIZE*CHANNELS/8];
    int main()
    {
                    intfd;     // 声音设备的文件描写叙述符
                    intarg;    // 用于ioctl调用的參数
                    intstatus; // 系统调用的返回值    
                    /*打开声音设备 */
                    fd= open("/dev/sound/dsp", O_RDONLY);
                    if(fd< 0)
                    {
                            perror("openof /dev/sound/dsp failed");
                            exit(1);
                    }
     
                    /*设置採样时的量化位数 */
                    arg= SIZE;
                    status= ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
                    if(status== -1)
                            perror("SOUND_PCM_WRITE_BITSioctl failed");
                    if(arg!= SIZE)
                            perror("unableto set sample size");
                    /*设置採样时的声道数目 */
                    arg= CHANNELS;
                    status= ioctl(fd, SNDCTL_DSP_STEREO, &arg);
                    if(status== -1)
                            perror("SNDCTL_DSP_STEREOioctl failed");
                    if(arg!= CHANNELS)
                            perror("unableto set number of channels");
                    /*设置採样时的採样频率 */
                    arg= RATE;
                    status= ioctl(fd, SNDCTL_DSP_SPEED, &arg);
                    if(status== -1)
                            perror("SNDCTL_DSP_SPEEDioctl failed");
                    if(arg!= RATE)
                            perror("unableto set rate");
     
                    printf("Saysomething:
    ");
                    status= read(fd, buf, sizeof(buf)); //recording
                    if(status!= sizeof(buf))
                            perror("readwrong number of bytes");
                    printf("Yousaid:
    ");
                    close(fd);
                    fd= open("/dev/sound/dsp", O_WRONLY);
                    if(fd< 0)
                    {
                            perror("openof /dev/sound/dsp failed");
                            exit(1);
                    } 
                   
                    /*设置採样时的量化位数 */
                    arg= SIZE;
                    status= ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
                    if(status == -1)
                           perror("SOUND_PCM_WRITE_BITS ioctl failed");
                    if(arg != SIZE)
                            perror("unable toset sample size");
                    /*设置採样时的声道数目 */
                    arg = CHANNELS;
                    status = ioctl(fd, SNDCTL_DSP_STEREO,&arg);
                    if(status == -1)
                           perror("SNDCTL_DSP_STEREO ioctl failed");
                    if(arg != CHANNELS)
                            perror("unable toset number of channels");
                    /* 设置採样时的採样频率 */
                    arg = RATE;
                    status = ioctl(fd,SNDCTL_DSP_SPEED, &arg);
                    if(status == -1)
                           perror("SNDCTL_DSP_SPEED ioctl failed");
                    if(arg != RATE)
                            perror("unable toset rate");
     
                    status= write(fd, buf, sizeof(buf)); //playing
                    if(status!= sizeof(buf))
                            perror("wrotewrong number of bytes");
                    close(fd);
                    return0;
    }
     

    程序中的注意点是open()函数的參数设置,之前採用參数O_RDWR,结果放音时总是出现错误。详细出错原因可能与驱动程序的设置有关。本设计中。正确的设置是当recording时,选择O_RDONLY,什么时候playing时间。选择O_WRONLY

  • 相关阅读:
    Lucene学习总结之七:Lucene搜索过程解析
    Lucene学习总结之六:Lucene打分公式的数学推导
    Lucene学习总结之五:Lucene段合并(merge)过程分析
    Lucene学习总结之四:Lucene索引过程分析
    Lucene学习总结之三:Lucene的索引文件格式(1)
    Lucene学习总结之二:Lucene的总体架构
    Lucene学习总结之一:全文检索的基本原理
    解决Eclipse中文乱码
    【Lucene4.8教程之五】Luke
    【Tika基础教程之一】Tika基础教程
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5034154.html
Copyright © 2011-2022 走看看