前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >miniaudio:音频开源库的首选

miniaudio:音频开源库的首选

作者头像
程序员的园
发布2024-07-18 13:32:03
1620
发布2024-07-18 13:32:03
举报
文章被收录于专栏:程序员的园——原创文章

软件开发中遇到需要播放音频文件时,可以使用操作系统提供的API也可以依赖于第三方库,通常第三方库多因其简单易用的接口而成为首选。miniaudio便是游戏的音频开源库之一。

miniaudio 是一个轻量级的音频播放、采集、播放+采集的库,专注于提供简单易用的 API 和跨平台的音频播放功能。它具有以下特点:

  • 轻量级: miniaudio 是一个小巧的库,header-only,不依赖于其他外部库,易于集成到各种项目中。
  • 跨平台: 支持 Windows、macOS、Linux 等多个主流操作系统,并提供了对于多种平台的兼容性。
  • 简单易用: miniaudio 提供了简洁的 API,无需复杂的配置,即使对音频编程不熟悉的开发者也能够快速上手。

下载和安装

下载链接见(https://github.com/mackron/miniaudio /tree/0.11.21),

miniaudio作为header-only的开源库,只需将miniaudio.h头文件集成到项目中即可。在使用时,需要在包含头文件前定义宏MINIAUDIO_IMPLEMENTATION,形如:

代码语言:javascript
复制
#define MINIAUDIO_IMPLEMENTATION
#include"miniaudio/miniaudio.h"

使用

miniaudio分为上层(High Low)接口和底层(Low Level)接口两种,高层接口做了封装,使用起来更加方便,对于开发者来讲更像一个黑盒子。=反而底层接口,开发者可以获得操作音频原始数据的机会。

接下来将分别使用上层接口、底层接口来播放本地文件以及录制声音。

代码语言:javascript
复制
#define MINIAUDIO_IMPLEMENTATION
#include"miniaudio/miniaudio.h"
//上层接口播放本地文件
void using_high_level_playback()
{
    ma_result result;
    ma_engine engine;
    result = ma_engine_init(NULL, &engine);
    if (result != MA_SUCCESS) {
        return ;
    }


    //"d://22.mp3"本地文件,需替换为自己的文件
    ma_engine_play_sound(&engine, "d://22.mp3", NULL);
    printf("Press Enter to quit...");
    getchar();

    ma_engine_uninit(&engine);
}



//底层接口播放本地文件
void data_callback_playback(ma_device*pDevice, void*pOutput,
        constvoid*pInput, ma_uint32frameCount)
{
    ma_decoder* pDecoder = (ma_decoder*)pDevice->pUserData;
    if (pDecoder == NULL) {
        return;
    }

    ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, NULL);
    (void)pInput;
}



void using_low_level_playback()
{
    ma_result result;
    ma_decoder decoder;
    ma_device_config deviceConfig;
    ma_device device;


    result = ma_decoder_init_file("d://22.mp3", NULL, &decoder);
    if (result != MA_SUCCESS) {
        return;
    }


    deviceConfig = ma_device_config_init(ma_device_type_playback);
    deviceConfig.playback.format = decoder.outputFormat;
    deviceConfig.playback.channels = decoder.outputChannels;
    deviceConfig.sampleRate = decoder.outputSampleRate;
    deviceConfig.dataCallback = data_callback_playback;
    deviceConfig.pUserData = &decoder;


    if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) {
        printf("Failed to open playback device.\n");
        ma_decoder_uninit(&decoder);
        return ;
    }


    if (ma_device_start(&device) != MA_SUCCESS) {
        printf("Failed to start playback device.\n");
        ma_device_uninit(&device);
        ma_decoder_uninit(&decoder);
        return ;
    }


    printf("Press Enter to quit...");
    getchar();


    ma_device_uninit(&device);
    ma_decoder_uninit(&decoder);
}




//采集声音
void data_callback_capture(ma_device*pDevice, void*pOutput,
            constvoid*pInput, ma_uint32frameCount)
{
    ma_encoder* pEncoder = (ma_encoder*)pDevice->pUserData;
    MA_ASSERT(pEncoder != NULL);
    ma_encoder_write_pcm_frames(pEncoder, pInput, frameCount, NULL);
    (void)pOutput;
}


int using_capture()
{
    ma_result result;
    ma_encoder_config encoderConfig;
    ma_encoder encoder;
    ma_device_config deviceConfig;
    ma_device device;



    encoderConfig = ma_encoder_config_init(ma_encoding_format_wav, ma_format_f32, 2, 48000);


    if (ma_encoder_init_file("d://capture.wav", &encoderConfig, &encoder) != MA_SUCCESS) {
        printf("Failed to initialize output file.\n");
        return -1;
    }


    deviceConfig = ma_device_config_init(ma_device_type_duplex);
    deviceConfig.capture.format = encoder.config.format;
    deviceConfig.capture.channels = encoder.config.channels;
    deviceConfig.sampleRate = encoder.config.sampleRate;
    deviceConfig.dataCallback = data_callback_capture;
    deviceConfig.pUserData = &encoder;


    result = ma_device_init(NULL, &deviceConfig, &device);
    if (result != MA_SUCCESS) {
        printf("Failed to initialize capture device.\n");
        return -2;
    }


    result = ma_device_start(&device);
    if (result != MA_SUCCESS) {
        ma_device_uninit(&device);
        printf("Failed to start device.\n");
        return -3;
    }


    printf("Press Enter to stop recording...\n");
    getchar();


    ma_device_uninit(&device);
    ma_encoder_uninit(&encoder);


    return0;
}

对比播放本地文件部分代码,扎心的发现,上层接口使用极其少量的代码实现了和底层接口相同的功能。但是底层接口,使得我们获得了在回调函数data_callback操作pcm数据的可能,当然若没有修改pcm的需求时,可以直接使用上层的接口。

总结

miniaudio作为一个header-only且MIT协议的开源库,极大地方便了在项目中的集成。同时,miniaudio支持播放、采集、采集同时播放的功能,可视为音频开源库的首选。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员的园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档