当前位置: 首页 > news >正文

C# 音频分离(MP3伴奏)

编程语言:C#

库:NAudio

NAudio 是一个开源的 .NET 音频处理库,它为开发者提供了丰富的功能,能在 Windows 平台上方便地进行音频的录制、播放、处理等操作。以下是关于 NAudio 库的详细介绍:

主要特性

  1. 多格式支持:支持多种常见的音频文件格式,如 WAV、MP3、OGG 等。这意味着你可以使用 NAudio 来播放或处理这些格式的音频文件。
  2. 音频录制:能够从系统的音频输入设备(如麦克风)录制音频,并保存为指定格式的文件。
  3. 音频播放:可以播放本地音频文件,也可以通过网络流式播放音频。同时,还支持对播放进行控制,如暂停、继续、停止等。
  4. 音频处理:提供了一些音频处理功能,如音量控制、音调调整、音频混合等。
  5. 低延迟:对于需要实时音频处理的应用场景,NAudio 能够保证较低的延迟。

常见使用场景

  1. 音频播放器开发:可以使用 NAudio 快速开发一个简单的音频播放器,支持多种音频格式的播放。
  2. 语音录制应用:开发语音备忘录、会议录音等应用程序。
  3. 音频处理工具:实现音频的剪辑、混音、格式转换等功能。
//核心代码 private void ProcessingWorker_DoWork(object sender, DoWorkEventArgs e){processedSamples = 0;var parameters = e.Argument as ProcessingParameters;if (parameters == null) return;try{using (var reader = CreateAudioReader(parameters.InputPath)){var sampleProvider = reader.ToSampleProvider();var format = sampleProvider.WaveFormat;sampleRate = format.SampleRate; // 使用文件实际采样率var channelCount = format.Channels;var outputPaths = GetOutputPaths(parameters.InputPath, parameters.OutputDirectory);// 优化缓冲区:4倍采样率缓冲区减少I/O次数int bufferSize = format.SampleRate * channelCount * 4;var buffer = new float[bufferSize];using (var vocalsWriter = new WaveFileWriter(outputPaths.Item1, format))using (var accompWriter = new WaveFileWriter(outputPaths.Item2, format)){long totalSamples = reader.Length / (format.BitsPerSample / 8 * channelCount);int samplesRead;// var buffer = new float[bufferSize];var newBuffer = new float[bufferSize];while ((samplesRead = sampleProvider.Read(buffer, 0, bufferSize)) > 0){if (processingWorker.CancellationPending){e.Cancel = true;return;}// 按声道对处理(支持单/双声道)for (int i = 0; i < samplesRead; i += channelCount){float left = buffer[i];float right = channelCount == 2 ? (i + 1 < samplesRead ? buffer[i + 1] : 0) : left;if (parameters.SeparationMode == SeparationMode.KaraokeMode){// 卡拉OK模式核心处理:左右声道相减 + 带通滤波float karaoke = left - right;float filtered = ApplyBandPassFilter(karaoke, channelCount == 1 ? leftFilterState : (i % 2 == 0 ? leftFilterState : rightFilterState));left = right = filtered * gain; // 双声道保持一致}buffer[i] = left;if (channelCount == 2 && i + 1 < samplesRead){buffer[i + 1] = right;}}if (parameters.SeparationMode == SeparationMode.KaraokeMode){// 对伴奏轨道应用低音增强(仅处理双声道)for (int i = 0; i < samplesRead; i += channelCount){float left = buffer[i];float right = channelCount == 2 ? buffer[i + 1] : left;// 应用低音增强left = ApplyBassBoost(left, sampleRate);right = ApplyBassBoost(right, sampleRate);buffer[i] = left;if (channelCount == 2) buffer[i + 1] = right;}}WriteSeparatedTracks(buffer, samplesRead, vocalsWriter, accompWriter, channelCount, parameters.SeparationMode);processedSamples += samplesRead;//processedSamples += samplesRead;processingWorker.ReportProgress((int)(processedSamples * 100 / totalSamples));}}}}catch (Exception ex){e.Result = ex;MessageBox.Show($"An error occurred during the processing: {ex.Message}",this .Text, MessageBoxButtons.OK, MessageBoxIcon.Error);}}private float ApplyBandPassFilter(float input, FilterState state){// 带通滤波器系数计算(IIR滤波器,改进型Sallen-Key结构)double w0 = 2 * Math.PI * ((lowerCutoff + upperCutoff) / 2) / sampleRate;double bw = upperCutoff - lowerCutoff;double q = (lowerCutoff + upperCutoff) / (2 * bw); // 品质因数double alpha = Math.Sin(w0) / (2 * q);// 滤波器系数double a0 = alpha;double a1 = 0;double a2 = -alpha;double b0 = 1 + alpha;double b1 = -2 * Math.Cos(w0);double b2 = 1 - alpha;// 移位寄存器更新state.x[2] = state.x[1];state.x[1] = state.x[0];state.x[0] = input;state.y[2] = state.y[1];state.y[1] = state.y[0];// 差分方程计算state.y[0] = (a0 * state.x[0] + a1 * state.x[1] + a2 * state.x[2]- b1 * state.y[1] - b2 * state.y[2]) / b0;return (float)state.y[0];}private void ProcessSample(float[] buffer, int n, ProcessingParameters parameters, int channelCount){if (parameters.SeparationMode != SeparationMode.KaraokeMode) return;float left = buffer[n];float right = 0;if (channelCount == 2 && n + 1 < buffer.Length){right = buffer[n + 1];}// 基础消人声算法float karaoke = left - right;// 优化滤波器:直接计算,避免类实例开销double w0 = 2 * Math.PI * ((lowerCutoff + upperCutoff) / 2) / sampleRate;double alpha = Math.Sin(w0) * Math.Sinh(Math.Log(2) / 2 * (upperCutoff - lowerCutoff) * w0 / Math.Sin(w0));double a0 = 1 / (1 + alpha);double a1 = -2 * Math.Cos(w0) * a0;double a2 = (1 - alpha) * a0;// 直接计算滤波后的样本(示例,可替换为更高效的滤波器实现)double filtered = a0 * karaoke + a1 * left + a2 * (n > 0 ? buffer[n - 1] : 0);buffer[n] = (float)(filtered * gain);if (channelCount == 2 && n + 1 < buffer.Length){buffer[n + 1] = buffer[n]; // 保持双声道一致}// 避免输出为零if (Math.Abs(buffer[n]) < 0.00001f){buffer[n] = 0.00001f;}if (channelCount == 2 && n + 1 < buffer.Length && Math.Abs(buffer[n + 1]) < 0.00001f){buffer[n + 1] = 0.00001f;}}private void WriteSeparatedTracks(float[] buffer, int samplesRead,WaveFileWriter vocalsWriter, WaveFileWriter accompWriter,int channelCount, SeparationMode mode){try{if (mode == SeparationMode.VocalIsolation){// 人声隔离模式:写入人声轨道(需要其他算法,此处简化)vocalsWriter.WriteSamples(buffer, 0, samplesRead);accompWriter.WriteSamples(buffer, 0, samplesRead); // 示例写法,需根据实际算法调整}else if (mode == SeparationMode.KaraokeMode){// 卡拉OK模式:伴奏轨道为处理后信号,人声轨道为原始信号相减结果(或静音)accompWriter.WriteSamples(buffer, 0, samplesRead);// 人声轨道(可选:写入差值信号或静音)for (int i = 0; i < samplesRead; i += 2)  //i ++{// buffer[i] = 0; // 消除人声后的人声轨道设为静音(可选逻辑)//=========================================================================float left = buffer[i];float right = buffer[i + 1];float difference = (left - right) * differenceGain;buffer[i] = difference;buffer[i + 1] = difference;}vocalsWriter.WriteSamples(buffer, 0, samplesRead);}}catch (Exception ex){MessageBox.Show($"Error occurred while writing audio file: {ex.Message}",this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);}}private void WriteSeparatedTracks(float[] buffer, int samplesRead,WaveFileWriter vocalsWriter, WaveFileWriter accompWriter, int channelCount){try{// 直接写入缓冲区,避免额外内存分配vocalsWriter.WriteSamples(buffer, 0, samplesRead);accompWriter.WriteSamples(buffer, 0, samplesRead);}catch (Exception ex){MessageBox.Show($"写入音频文件时出现错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);}}#endregion// 实现缺失的事件处理方法//private void ProcessingWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)//{//    int progressValue = Math.Max(0, Math.Min(100, e.ProgressPercentage));//    if (progressBar.InvokeRequired)//    {//        progressBar.Invoke(new Action(() => progressBar.Value = progressValue));//    }//    else//    {//        progressBar.Value = progressValue;//    }//    if (lblStatus.InvokeRequired)//    {//        lblStatus.Invoke(new Action(() => lblStatus.Text = $"处理中... {progressValue}%"));//    }//    else//    {//        lblStatus.Text = $"处理中... {progressValue}%";//    }//}private float ApplyBassBoost(float input, double sampleRate){// 低频搁架滤波器参数(固定截止频率100Hz,可添加TrackBar调节截止频率)double w0 = 2 * Math.PI * bassCutoff / sampleRate;double q = 0.707; // 临界阻尼系数double gainDb = 20 * Math.Log10(bassGain); // 转换为分贝// 计算滤波器系数(正向增益)double a0, a1, a2, b0, b1, b2;double V = Math.Pow(10, gainDb / 20);double alpha = Math.Sin(w0) / (2 * q);if (gainDb > 0) // 增益模式(增强低音){b0 = 1 + alpha * V;b1 = -2 * Math.Cos(w0);b2 = 1 - alpha * V;a0 = (1 + alpha / V) / b0;a1 = (-2 * Math.Cos(w0)) / b0;a2 = (1 - alpha / V) / b0;}else // 衰减模式(可省略,当前需求仅增强){// 衰减系数计算(略,当前功能暂不考虑)a0 = a1 = a2 = b0 = b1 = b2 = 0;}// 示例:简单低音增强(直接提升低频信号,临时实现用于快速验证)// 实际应用建议使用IIR滤波器或FFT频域处理if (input < 0) return (float)(input * bassGain);return input;}

相关文章:

  • WHAT - 区分 Git PR 和 MR
  • 使用setGraphicsEffect重新设置阴影导致程序崩溃的问题
  • IP的基础知识以及相关机制
  • QTcpSocket 和 QUdpSocket 来实现基于 TCP 和 UDP 的网络通信
  • 爬虫学习——使用HTTP服务代理、redis使用、通过Scrapy实现分布式爬取
  • kubernetes》》k8s》》Dashboard
  • 2025新版懒人精灵零基础及各板块核心系统视频教程-全分辨率免ROOT自动化开发
  • idea连接远程服务器kafka
  • MySQL:数据库设计
  • 主流操作系统对比分析(macOS、Linux、Windows、Unix)
  • GitHub万星项目维护者分享:开源协作的避坑指南
  • 【技术派后端篇】技术派中 Session/Cookie 与 JWT 身份验证技术的应用及实现解析
  • Trae+DeepSeek学习Python开发MVC框架程序笔记(一):1个程序实现MVC
  • R/G-B/G色温坐标系下对横纵坐标取对数的优势
  • Volcano 实战快速入门 (一)
  • Long类型封装Json传输时精度丢失问题
  • 每日Html 4.24
  • 关于Qt对Html/CSS的支持
  • Java中正则表达式使用方法
  • docker 配置代理
  • 4500万失能人员如何养老?没参保是否能享受长护师服务?
  • 海上生明月,九天揽星河,2025年“中国航天日”主场活动在上海启动
  • 中国天主教组织发唁电对教皇去世表示哀悼
  • 男子闲鱼卖手机卷入电诈案后成“网逃”续:警方已排除其作案嫌疑
  • 李公明︱一周书记:大学的价值、韧性以及……不相称的对抗
  • 大家聊中国式现代化|彭羽:为国家试制度探新路,推进高水平对外开放