美文网首页
alsa USB拾音器接入

alsa USB拾音器接入

作者: Caiaolun | 来源:发表于2019-12-20 15:48 被阅读0次

    做下面这些工作的前提先把 alsa 的库安装好:

    sudo apt-get install libasound2-dev
    

    查找设备名:



    API 库使用逻辑设备名而不是设备文件。设备名字可以是真实的硬件名字也可以是插件名字。硬件名
    字使用hw:i,j这样的格式。其中i是卡号,j是这块声卡上的设备号。第一个声音设备是hw:0,0.这个


    我的usb拾音器是4麦的,也统称的4通道

    我的设备是16K的采样率(16000个数据/s), 根据自己的设备来, 填错了, 就会小姐姐变大叔

    我的是小端 16位一个数据

    设置每路通道每次采集128个数据

    录制后我用\color{red}{Audacity}测试

    Code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <alsa/asoundlib.h>
    #include <pthread.h>
    
    using namespace std;
    
    #define REC_DEV "hw:1,0"
    #define CHANNELS 4
    #define RATE 16000
    #define FRAMES 128
    #define BITE 2
    #define PATH "../bin/"
    #define NAMELANGTH 128
    bool g_bRecord;
    bool g_bMainON;
    FILE* g_pFile[CHANNELS];
    
    
    void* run(void* args)
    {
        #define ALSA_PCM_NEW_HW_PARAMS_API
    
        char cNamePath[NAMELANGTH];
        memset(cNamePath, 0, sizeof(char) * NAMELANGTH);
        for(int i = 0; i < CHANNELS; i++)
        {      
            sprintf(cNamePath,"%sData-%02d.pcm",PATH, i);
            if((g_pFile[i] = fopen(cNamePath, "w")) == NULL)
            {
                printf("Read local pcm path failed!\n");
                exit(0);
            }
        }
     
        int rc;            //一个int变量 ,用来存放 snd_pcm_open(访问硬件)的返回值 
        int size;        //一个int变量 
        snd_pcm_t * handle;        // 一个指向snd_pcm_t的指针 
        snd_pcm_hw_params_t * params;    // 一个指向 snd_pcm_hw_params_t的指针 
        unsigned int val = RATE;        // 无符号整型变量 ,用来存放录音时候的采样率 
        snd_pcm_uframes_t frames = FRAMES;        // snd_pcm_uframes_t 型变量 
        int channels = CHANNELS;
        int dir;            // 整型变量 
        char * buffer;        // 一个字符型指针 
    
        /* open PCM device for recording (capture). */
        // 访问硬件,并判断硬件是否访问成功 
        rc = snd_pcm_open(&handle, REC_DEV, SND_PCM_STREAM_CAPTURE,0);
        if( rc < 0 )
        {
            fprintf(stderr,
                    "unable to open pcm device: %sn",
                    snd_strerror(rc));
            exit(1);
        }
        /* allocate a hardware parameters object */
        // 分配一个硬件变量对象 
        snd_pcm_hw_params_alloca(&params);
        /* fill it with default values. */
        // 按照默认设置对硬件对象进行设置 
        snd_pcm_hw_params_any(handle,params);
        /* set the desired hardware parameters */
        /* interleaved mode 设置数据为交叉模式*/
        snd_pcm_hw_params_set_access(handle,params,
                                    SND_PCM_ACCESS_RW_INTERLEAVED);
        /* signed 16-bit little-endian format */
        // 设置数据编码格式为PCM、有符号、16bit、LE格式 
        snd_pcm_hw_params_set_format(handle,params,
                                    SND_PCM_FORMAT_S16_LE);
        /* two channels(stereo) */
        // 设置单声道 
        snd_pcm_hw_params_set_channels(handle,params,channels);
        /* sampling rate */
        // 设置采样率 
        snd_pcm_hw_params_set_rate_near(handle,params,&val,&dir);
        /* set period size */
        // 周期长度(帧数) 
        frames = 32;
        snd_pcm_hw_params_set_period_size_near(handle,params,&frames,&dir);
        /* write parameters to the driver */
        // 将配置写入驱动程序中
        // 判断是否已经配置正确 
        rc = snd_pcm_hw_params(handle,params);
        if ( rc < 0 )
        {
            fprintf(stderr,
                    "unable to set hw parameters: %sn",
                    snd_strerror(rc));
            exit(1);
        }
        /* use a buffer large enough to hold one period */
        // 配置一个缓冲区用来缓冲数据,缓冲区要足够大,此处看意思应该是只配置了
        // 够两个声道用的缓冲内存 
        snd_pcm_hw_params_get_period_size(params,&frames,&dir);
        size = frames * BITE * channels; /* 2 bytes/sample, 2channels */
        buffer = ( char * ) malloc(size);
        /* loop for 5 seconds */
        // 记录五秒长的声音 
        snd_pcm_hw_params_get_period_time(params, &val, &dir);
        printf("revord start!\n");
        while(g_bRecord)
        {
            rc = snd_pcm_readi(handle,buffer,frames);
            if ( rc == -EPIPE )
            {
                /* EPIPE means overrun */
                fprintf(stderr,"overrun occuredn");
                snd_pcm_prepare(handle);
            }
            else if ( rc < 0 )
            {
                fprintf(stderr,"error from read: %sn",
                        snd_strerror(rc));
            }
            else if ( rc != (int)frames)
            {
                fprintf(stderr,"short read, read %d framesn",rc);
            }
            // // 将音频数据写入文件 
            for(int i = 0; i<frames * channels; i+=channels)
            {
                for(int j = 0; j<channels;j++)
                {
                    fwrite(buffer + (i+j)*BITE, BITE, 1, g_pFile[j]);
                }
            }
        }
    
        snd_pcm_drain(handle);
        snd_pcm_close(handle);
        free(buffer);
        for(int i = 0; i<CHANNELS; i++)
        {
                fclose(g_pFile[i]);
        }
        printf("record over!\n");
    
    }
    int main(int argc, char *argv[])
    {
        g_bRecord = true;
        g_bMainON = true;
        pthread_t stThread;
        int ret = pthread_create(&stThread, NULL, run, NULL);
        if (ret != 0)
        {
            printf("pthread_create error: error_code=%d\n", ret);
        }
        while(getchar() != 'c')
        {
            g_bRecord = false;
        }
        while(g_bMainON);
    
        exit (0);   
    }
    

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.5.1)
    
    project(MakePCM)
    
    
    set(CMAKE_CXX_STANDARD 11)
    
    
    set(SOURCE_FILES 
        ./src/main.cpp
        )
    
    
    set(INC_DIR ./3rdpart/include)
    
    set(LINK_DIR ./3rdpart/lib)
    
    
    include_directories(${INC_DIR})
    
    link_directories(${LINK_DIR})
    
    link_libraries(
        asound
        pthread
        )
    
    
    add_executable(MakePCM ${SOURCE_FILES})
    
    target_link_libraries(MakePCM 
        asound
        pthread
        )
    

    相关文章

      网友评论

          本文标题:alsa USB拾音器接入

          本文链接:https://www.haomeiwen.com/subject/solinctx.html