You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求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的跨平台绑定库,支持几乎所有常见音频格式,可获取底层采样数据,适合需要复杂音频处理的场景。

实现步骤

  1. 安装NuGet包FFmpeg.AutoGen
  2. Linux服务器上通过包管理器安装FFmpeg(如apt install ffmpeg或yum install ffmpeg)
  3. 核心读取代码:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 17:43:12