美文网首页
c++ 播放音频文件【linux】

c++ 播放音频文件【linux】

作者: simbanyan | 来源:发表于2022-07-03 21:44 被阅读0次

c++ 编译播放wav格式音频文件, 并设置音量

环境

  • ubuntu 18.04

  • 依赖库

 sudo apt-get install libasound2-dev

c++ 源码 main.cpp

#include <alsa/asoundlib.h>
#include <iostream>
#include <cstdint>
#include <unistd.h>
#include <fstream>

#pragma pack(1)
struct WavHeader
{
    uint32_t id;
    uint32_t chunk_size;
    uint32_t form_type;
    uint32_t fmt;
    uint32_t subchunk_size;
    uint16_t audio_format;
    uint16_t channel_nums;
    uint32_t sample_rate;
    uint32_t byte_rate;
    uint16_t block_align;
    uint16_t bits_per_sample;
    uint32_t data;
    uint32_t data_size;
};
#pragma pack()

void set_master_volume(long volume){
    long min, max;
    snd_mixer_t *handle;
    snd_mixer_selem_id_t *sid;
    const char *card = "default";
    const char *selem_name = "Master";

    snd_mixer_open(&handle, 0);
    snd_mixer_attach(handle, card);
    snd_mixer_selem_register(handle, NULL, NULL);
    snd_mixer_load(handle);

    snd_mixer_selem_id_alloca(&sid);
    snd_mixer_selem_id_set_index(sid, 0);
    snd_mixer_selem_id_set_name(sid, selem_name);
    snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);

    snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
    snd_mixer_selem_set_playback_volume_all(elem, volume * max / 100);

    snd_mixer_close(handle);
}

int main(int argc, char **argv) {
    if(argc < 2){
        std::cout << std::string(argv[0]) << " wav_file_path" << std::endl;
        return -1;
    }

    std::string wav_file_name(argv[1]);
    if(access(wav_file_name.c_str(), F_OK) != 0){
        std::cout << "File (" << wav_file_name << ") not exist!" << std::endl;
        return -1; 
    }

    // open wav file 
    std::fstream wav(wav_file_name, std::ios_base::in|std::ios::binary );
    if(wav.fail()){
        std::cout << wav_file_name << " open failed!" << std::endl;
        return -1;
    }

    // parse wav file 
    WavHeader wav_header; 

    wav.read((char*)&wav_header, sizeof(wav_header));
    if(wav.fail()){
        std::cout << "Read file failed!" << std::endl;
        return -1;
    }
    if(wav_header.id != (uint32_t)0x46464952 or wav_header.fmt != (u_int32_t)0x20746d66 \
        or wav_header.audio_format != 1){
        std::cout << std::hex << wav_header.id << std::endl;
        std::cout << std::hex << wav_header.fmt << std::endl;
        std::cout << std::hex << wav_header.data << std::endl;
        std::cout << "audio format: " << wav_header.audio_format << std::endl; 
        // audio format 为1 表示
        std::cout << "File format error!" << std::endl;
        return -1;
    }
    
    //summary 
    std::cout << "sample_rate: " << wav_header.sample_rate <<  std::endl;
    std::cout << "bit per sample: " << wav_header.bits_per_sample << std::endl;
    std::cout << "channel nums: " << wav_header.channel_nums << std::endl;

    set_master_volume(99); // 99%
    // play audio 
    int err;
    unsigned int i;
    snd_pcm_t *handle;
    snd_pcm_sframes_t frames;
    std::string device("default");
    unsigned char buffer[512];

    if ((err = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
        printf("Playback open error: %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }

    snd_pcm_format_t pcm_format;
    switch (wav_header.bits_per_sample)
    {
    
    case 8:
        pcm_format = SND_PCM_FORMAT_S8;
        break;
    case 16:
        pcm_format = SND_PCM_FORMAT_S16_LE;
        break;
    case 32:
        pcm_format = SND_PCM_FORMAT_S32_LE;
        break;
    default:
        break;
    }

    if ((err = snd_pcm_set_params(handle,
                      pcm_format,
                      SND_PCM_ACCESS_RW_INTERLEAVED,
                      wav_header.channel_nums,
                      wav_header.sample_rate,
                      1,
                      500000)) < 0) {   /* 0.5sec */
        printf("Playback open error: %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }
 
    while (true) {
        wav.read((char *)&buffer, 512);
        if(wav.gcount() <= 0){
            std::cout << "END" << std::endl;
            break;
        }
        frames = snd_pcm_writei(handle, buffer, wav.gcount()/(wav_header.bits_per_sample * 2 / 8));
        if (frames < 0)
            frames = snd_pcm_recover(handle, frames, 0);
        if (frames < 0) {
            printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
            break;
        }
        if(wav.gcount() != 512){
            std::cout << "END" << std::endl;
            break;
        }
    }
 
    /* pass the remaining samples, otherwise they're dropped in close */
    err = snd_pcm_drain(handle);
    if (err < 0)
        printf("snd_pcm_drain failed: %s\n", snd_strerror(err));
    snd_pcm_close(handle);
}

编译

g++ -o main main.cpp -lasound

运行

./main 1.wav 
  • 运行结果
sample_rate: 44100
bit per sample: 16
channel nums: 2
END

相关文章

网友评论

      本文标题:c++ 播放音频文件【linux】

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