1. libsndfile
进行音乐文件操作时总是面临一个问题需要适配很多种音频文件格式。如WAV、AIFF、FLAC、OGG、MP3、AAC……每一种格式都有各自的结构、编码方式、压缩算法。通常都是借助FFmpeg进行处理但是FFmpeg的API比较复杂需要学习成本较高。反观libsndfile则是一个简单、易用的音频读写库。它的具备如下特性统一 API同一套函数读写几十种音频格式无需为每种格式编写解析代码跨平台Windows / macOS / Linux 全平台支持双 APIC API 灵活底层C 封装SndfileHandle提供 RAII 便利成熟稳定1999 年诞生25 年持续维护被 Audacity、FFmpeg 等知名项目广泛使用多种数据类型支持 short / int / float / double 四种精度的读写适配不同应用场景1. libsndfilelibsndfile由 Erik de Castro Lopo 在 1999 年创建它提供了C/C两套 API。借助该库可以实现一套代码就可以读写几十种格式的音频文件。当前libsndfile支持超过 30 种文件格式和编码类型包括但不限于大类具体格式未压缩格式WAV, AIFF, AU, RAW无损压缩FLAC, ALAC (Apple Lossless)有损压缩Ogg/Vorbis, MPEG Audio, Opus乐器/采样XI (FastTracker), VOC科学计算MAT4/MAT5 (MATLAB), NIST (Sphere)专业音频CAF (Core Audio), RF64, W642. 使用 libsndfile2.1 源码编译2.1.1 下载源码官方 GitHub 仓库https://github.com/libsndfile/libsndfile最新的稳定版本是 1.2.2可以直接下载源码包或 clone 仓库。2.1.2 编译libsndfile 使用 CMake 构建系统编译非常标准gitclone https://github.com/libsndfile/libsndfile.gitcdlibsndfile cmake-S.-Bbuild-DCMAKE_BUILD_TYPERelease cmake--buildbuild2.1.3 编译选项libsndfile 在 CMakeLists.txt 中提供了一系列编译选项方便用户按需定制库的行为和产物选项默认值说明BUILD_SHARED_LIBSOFF构建共享库Windows 下为 DLLOFF时构建静态库BUILD_EXAMPLESON构建示例代码BUILD_TESTINGON构建测试程序BUILD_SHARED_LIBSON时自动禁用ENABLE_EXTERNAL_LIBSON如果找到依赖启用 Ogg、Vorbis、FLAC、Opus 支持ENABLE_MPEGON如果找到依赖启用 MP3 支持ENABLE_BOW_DOCSOFF启用黑底白字文档主题ENABLE_EXPERIMENTALOFF启用实验性代码非专家勿用ENABLE_STATIC_RUNTIMEOFFWindows 平台启用静态运行时MSVC/MinGW常用组合示例# 构建共享库DLL关闭工具和测试cmake-S.-Bbuild-DCMAKE_BUILD_TYPERelease\-DBUILD_SHARED_LIBSON\-DBUILD_EXAMPLESOFF\-DBUILD_TESTINGOFF# 构建带 Ogg/Vorbis/FLAC/Opus 支持的静态库cmake-S.-Bbuild-DCMAKE_BUILD_TYPERelease\-DBUILD_SHARED_LIBSOFF\-DENABLE_EXTERNAL_LIBSON2.2 使用 vcpkg 安装推荐如果你使用 vcpkg 管理第三方库一行命令搞定vcpkginstalllibsndfile如果需要支持 Ogg/Vorbis/Opus 等编码vcpkginstalllibsndfile[external-libs]vcpkg 会自动处理所有依赖并且集成到 CMake 中非常省心。2.3 预编译包对于 Windows 开发者GitHub Releases 页面提供了预编译的 DLL 和库文件。见预编译包。直接将sndfile.h、sndfile.lib、sndfile.dll放入你的项目即可。3. 代码示例下面我们通过一个完整的例子演示如何使用libsndfile读取一个 WAV 文件。3.1 完整代码#includeiostream#includevector#includecstring#includesndfile.h#includewindows.hintmain(){SetConsoleOutputCP(CP_UTF8);constchar*filepathtest.wav;// 1. 打开文件获取音频信息SF_INFO sfinfo;std::memset(sfinfo,0,sizeof(sfinfo));SNDFILE*sfsf_open(filepath,SFM_READ,sfinfo);if(!sf){std::cerr打开文件失败: sf_strerror(nullptr)std::endl;return1;}// 2. 打印文件信息std::cout 采样率: sfinfo.samplerate Hz\n;std::cout 通道数: sfinfo.channels\n;std::cout 总帧数: sfinfo.frames\n;std::cout 总时长: static_castdouble(sfinfo.frames)/sfinfo.samplerate 秒\n;// 3. 使用 sf_readf_float 读取所有音频数据sf_count_t total_framessfinfo.frames;intchannelssfinfo.channels;std::vectorfloatbuffer(static_castsize_t(total_frames*channels));sf_count_t frames_readsf_readf_float(sf,buffer.data(),total_frames);//sf_count_t frames_read sf_read_float(sf, buffer.data(), total_frames*channels);std::cout读取帧数: frames_read\n;// 4. 计算各声道统计信息for(intch0;chchannels;ch){doublesum0,max_val0;for(sf_count_t i0;iframes_read;i){floatvalbuffer[i*channelsch];sumval;if(std::abs(val)max_val)max_valstd::abs(val);}doublemeansum/frames_read;std::cout\n声道 ch1:\n;std::cout 均值: mean\n;std::cout 最大值: max_val\n;}// 5. 关闭文件sf_close(sf);return0;}3.2 函数解读//功能 打开文件//参数// filepath: 文件路径// mode: 打开模式SFM_READ、SFM_WRITE、SFM_RDWR// SFM_READ: 只读// SFM_WRITE: 只写// SFM_RDWR: 读写// struct SF_INFO// {// sf_count_t frames ; /* Used to be called samples. Changed to avoid confusion. */// int samplerate ;// int channels ;// int format ;// int sections ;// int seekable ;// } ;//返回值SNDFILE 指针失败时返回 nullptrSNDFILE*sf_open(constchar*filepath,intmode,SF_INFO*sfinfo);//功能 读取音频数据//参数// sf: SNDFILE 指针// buffer: 存储读取数据的缓冲区// frames: 读取的帧数//返回值实际读取的帧数失败时返回 0sf_count_tsf_readf_float(SNDFILE*sf,float*buffer,sf_count_t frames);//功能 读取音频数据//参数// sf: SNDFILE 指针// buffer: 存储读取数据的缓冲区// items: 读取的采样点数 frames * channels//返回值实际读取的采样点数sf_count_tsf_read_float(SNDFILE*sf,float*buffer,sf_count_t items);//功能 关闭文件//参数// sf: SNDFILE 指针//返回值成功返回 0失败返回非 0intsf_close(SNDFILE*sf);3.3 C 接口libsndfile也提供了一个 C 封装SndfileHandle接口内部调用C API但是他借助 RAII 机制和引用计数自动管理文件资源日常使用比 C API 方便很多。4. 注意事项libsndfile具备强大的音频格式支持能力但是也有其限制。格式限制libsndfile不处理实时音频流如麦克风输入、网络流媒体它只专注于文件的读写。实时音频需要配合 PortAudio、RtAudio 等库使用。MP3 支持有限libsndfile对 MP3 的支持是只读的且需要通过外部库如 libmp3lame支持。如果需要完整的 MP3 编码能力建议直接使用 LAME 或 FFmpeg。浮点数据范围使用sf_readf_float读取时数据会被归一化到[-1.0, 1.0]范围。如果要关闭这个归一化行为可以使用sf_command设置。floatnorm0;sf_command(sf,SFC_SET_NORM_FLOAT,norm,sizeof(norm));文件资源管理C API 需要手动调用sf_close()关闭文件而 C 封装SndfileHandle会自动管理资源无需手动关闭。5. 总结本文介绍了libsndfile的基本使用方法包括打开文件、读取音频数据、关闭文件等。同时我们也提到了一些注意事项。希望本文对你有所帮助