寻求C#中跨平台替代NAudio读取音频文件数据的类库
跨平台音频采样读取方案(替代NAudio的AudioFileReader)
当前使用NAudio的AudioFileReader读取音频文件,将采样转换为double[]向量用于生成频谱图,核心代码如下:
private List<double[]> CreateFFTs(double[] audio, int sampleRate) { SpectrogramGenerator sg = new SpectrogramGenerator(sampleRate, 4096, 500, MIN_FREQUENCY, MAX_FREQUENCY); sg.Add(audio); return sg.GetFFTs(); }
using (AudioFileReader afr = new AudioFileReader(audiofile)) { int sampleRate = afr.WaveFormat.SampleRate; int bytesPerSample = afr.WaveFormat.BitsPerSample / 8; int sampleCount = (int)(afr.Length / bytesPerSample); int channelCount = afr.WaveFormat.Channels; var audio = new List<double>(sampleCount); var buffer = new float[sampleRate * channelCount]; int samplesRead = 0; while ((samplesRead = afr.Read(buffer, 0, buffer.Length)) > 0) { audio.AddRange(buffer.Take(samplesRead).Select(x => x * 1d)); currentBuffers++; if (currentBuffers > maxBuffers) { result.AddRange(CreateFFTs(audio.ToArray(), sampleRate)); audio = new List<double>(sampleCount); currentBuffers = 0; } } result.AddRange(CreateFFTs(audio.ToArray(), sampleRate)); }
该方案在Windows环境运行正常,但部署到Linux服务器时,因NAudio依赖Windows专属API无法运行。需要找到可替代AudioFileReader的跨平台类库,要求支持读取WAV、MP3等格式,并输出double[]向量数据(此前找到的类库多侧重音频播放,不符合需求)。
可行的跨平台替代方案
1. NAudio 2.0+(官方跨平台版本)
NAudio 2.0及以上版本已完成跨平台重构,移除了Windows专属API依赖,支持Linux、macOS和Windows。API与旧版兼容,代码改动极小。
实现示例
安装NuGet包NAudio(版本≥2.0),修改后的读取代码:
using (var afr = new AudioFileReader(audiofile)) { int sampleRate = afr.WaveFormat.SampleRate; int channelCount = afr.WaveFormat.Channels; var audio = new List<double>(); var buffer = new float[sampleRate * channelCount]; int samplesRead = 0; while ((samplesRead = afr.Read(buffer, 0, buffer.Length)) > 0) { audio.AddRange(buffer.Take(samplesRead).Select(x => (double)x)); currentBuffers++; if (currentBuffers > maxBuffers) { result.AddRange(CreateFFTs(audio.ToArray(), sampleRate)); audio.Clear(); currentBuffers = 0; } } if (audio.Count > 0) { result.AddRange(CreateFFTs(audio.ToArray(), sampleRate)); } }
2. FFmpeg.AutoGen(基于FFmpeg的全格式支持方案)
FFmpeg.AutoGen是FFmpeg的跨平台绑定库,支持几乎所有常见音频格式,可获取底层采样数据,适合需要复杂音频处理的场景。
实现步骤
- 安装NuGet包
FFmpeg.AutoGen - Linux服务器上通过包管理器安装FFmpeg(如
apt install ffmpeg或yum install ffmpeg) - 核心读取代码:
public static List<double> ReadAudioSamples(string filePath, out int sampleRate) { FFmpegHelper.RegisterFFmpeg(); var samples = new List<double>(); using (var formatContext = new AVFormatContextPtr()) { if (ffmpeg.avformat_open_input(&formatContext, filePath, null, null) != 0) throw new InvalidOperationException("无法打开音频文件"); if (ffmpeg.avformat_find_stream_info(formatContext, null) < 0) throw new InvalidOperationException("无法获取音频流信息"); int audioStreamIndex = ffmpeg.av_find_best_stream(formatContext, AVMediaType.AVMEDIA_TYPE_AUDIO, -1, -1, null, 0); if (audioStreamIndex < 0) throw new InvalidOperationException("未找到音频流"); var codecParameters = formatContext->streams[audioStreamIndex]->codecpar; var codec = ffmpeg.avcodec_find_decoder(codecParameters->codec_id); if (codec == null) throw new InvalidOperationException("未找到对应解码器"); using (var codecContext = ffmpeg.avcodec_alloc_context3(codec)) { if (ffmpeg.avcodec_parameters_to_context(codecContext, codecParameters) < 0) throw new InvalidOperationException("无法配置解码器上下文"); if (ffmpeg.avcodec_open2(codecContext, codec, null) < 0) throw new InvalidOperationException("无法启动解码器"); sampleRate = codecContext->sample_rate; int channelCount = codecContext->channels; var packet = new AVPacket(); var frame = ffmpeg.av_frame_alloc(); try { while (ffmpeg.av_read_frame(formatContext, &packet) >= 0) { if (packet.stream_index == audioStreamIndex) { if (ffmpeg.avcodec_send_packet(codecContext, &packet) == 0) { while (ffmpeg.avcodec_receive_frame(codecContext, frame) == 0) { float* floatSamples = (float*)frame->data[0]; for (int i = 0; i < frame->nb_samples * channelCount; i++) { samples.Add((double)floatSamples[i]); } } } } ffmpeg.av_packet_unref(&packet); } } finally { ffmpeg.av_frame_free(&frame); } } ffmpeg.avformat_close_input(&formatContext); } return samples; }
3. TagLibSharp(轻量级采样读取方案)
TagLibSharp主打音频元数据处理,但也支持读取原始采样数据,跨平台兼容性好,适合需求简单的场景。
实现示例
安装NuGet包TagLibSharp,读取代码:
public static List<double> ReadAudioSamples(string filePath, out int sampleRate) { var file = TagLib.File.Create(filePath); var audioProperties = file.Properties as TagLib.AudioProperties; sampleRate = audioProperties.SampleRate; int channelCount = audioProperties.Channels; var samples = new List<double>(); var sampleBuffer = new float[audioProperties.TotalSamples * channelCount]; file.ReadAudioSamples(sampleBuffer, 0, sampleBuffer.Length); samples.AddRange(sampleBuffer.Select(x => (double)x)); return samples; }
选择建议
- 优先选NAudio 2.0+:API兼容旧代码,改动最小,无需额外依赖。
- 需要全格式支持选FFmpeg.AutoGen:支持几乎所有音频格式,但代码复杂度较高。
- 轻量需求选TagLibSharp:代码简洁,适合快速实现基础采样读取。
内容的提问来源于stack exchange,提问作者Aaginor
相关产品推荐
相关产品推荐

