使用建議:
-
參數調節指南:
-
低頻人聲殘留:降低
CenterFrequency
(800-1500Hz) -
高頻人聲殘留:提高
CenterFrequency
(2500-3500Hz) -
消除力度不足:提高
EliminationStrength
(0.9-1.0) -
伴奏失真:降低
EliminationStrength
(0.7-0.9) 并提高GainCompensation
(1.3-1.5)
-
using System;
using System.IO;
using NAudio.Wave;
using NAudio.Lame;public class AudioConverter
{public event EventHandler<int> ProgressChanged;public event EventHandler ConversionCompleted;public float EliminationStrength { get; set; } = 0.95f; // 消除強度 0-1public void ConvertToAccompaniment(string inputPath, string outputPath){try{if (!File.Exists(inputPath)){throw new FileNotFoundException($"輸入文件未找到: {inputPath}");}using (var mp3Reader = new Mp3FileReader(inputPath)){var sampleProvider = mp3Reader.ToSampleProvider();var originalFormat = sampleProvider.WaveFormat;if (originalFormat.Channels != 2){throw new InvalidOperationException("僅支持立體聲音頻文件");}// 創建16位PCM格式var pcm16Format = new WaveFormat(originalFormat.SampleRate, 16, originalFormat.Channels);long totalBytes = mp3Reader.Length;long processedBytes = 0;using (var pcmMemoryStream = new MemoryStream()){WaveFileWriter wavWriter = null;try{wavWriter = new WaveFileWriter(new IgnoreDisposeStream(pcmMemoryStream), pcm16Format);float[] buffer = new float[originalFormat.SampleRate * originalFormat.Channels];int samplesRead;while ((samplesRead = sampleProvider.Read(buffer, 0, buffer.Length)) > 0){ProcessVocalRemoval(buffer, samplesRead);// 將浮點數組轉換為16位PCM字節數組byte[] pcm16Bytes = new byte[samplesRead * 2]; // 每個樣本占2字節for (int i = 0; i < samplesRead; i++){// 鉗制值并轉換為16位整數float sample = Math.Max(-1.0f, Math.Min(1.0f, buffer[i]));short pcmSample = (short)(sample * short.MaxValue);pcm16Bytes[i * 2] = (byte)(pcmSample);pcm16Bytes[i * 2 + 1] = (byte)(pcmSample >> 8);}wavWriter.Write(pcm16Bytes, 0, pcm16Bytes.Length);processedBytes += pcm16Bytes.Length;// 計算進度時可能需要調整總長度,此處假設totalBytes為PCM數據估算長度int percent = (int)((double)processedBytes / (totalBytes * 2) * 100);ProgressChanged?.Invoke(this, percent);}}finally{wavWriter?.Dispose();}pcmMemoryStream.Position = 0;// 使用16位PCM格式初始化LAME編碼器using (var mp3Writer = new LameMP3FileWriter(outputPath, pcm16Format, LAMEPreset.VBR_90)){pcmMemoryStream.CopyTo(mp3Writer);}}ProgressChanged?.Invoke(this, 100);ConversionCompleted?.Invoke(this, EventArgs.Empty);}}catch (FileNotFoundException ex){Console.WriteLine($"文件未找到: {ex.FileName}");}catch (InvalidOperationException ex){Console.WriteLine($"處理錯誤: {ex.Message}");}catch (Exception ex){Console.WriteLine($"發生未知錯誤: {ex.Message}");}}private void ProcessVocalRemoval(float[] buffer, int samplesRead){for (int i = 0; i < samplesRead; i += 2){float left = buffer[i];float right = buffer[i + 1];float difference = (left - right) * EliminationStrength;buffer[i] = difference;buffer[i + 1] = difference;}}// 修正4:添加流包裝器防止WaveFileWriter關閉底層流private class IgnoreDisposeStream : Stream{private readonly Stream _baseStream;public IgnoreDisposeStream(Stream baseStream) => _baseStream = baseStream;public override bool CanRead => _baseStream.CanRead;public override bool CanSeek => _baseStream.CanSeek;public override bool CanWrite => _baseStream.CanWrite;public override long Length => _baseStream.Length;public override long Position{get => _baseStream.Position;set => _baseStream.Position = value;}public override void Flush() => _baseStream.Flush();public override int Read(byte[] buffer, int offset, int count) => _baseStream.Read(buffer, offset, count);public override long Seek(long offset, SeekOrigin origin) => _baseStream.Seek(offset, origin);public override void SetLength(long value) => _baseStream.SetLength(value);public override void Write(byte[] buffer, int offset, int count) => _baseStream.Write(buffer, offset, count);protected override void Dispose(bool disposing){// 不關閉底層流}}
}
效果對比表:
參數組合 | 適用場景 | 副作用 |
---|---|---|
Strength=0.9, Freq=1500 | 清晰人聲消除 | 可能損失部分低頻伴奏 |
Strength=0.8, Freq=2500 | 保留貝斯/鼓點 | 高頻人聲可能有殘留 |
Strength=1.0, Freq=800 | 消除低沉男聲 | 可能產生金屬感失真 |
注意事項:
-
源音頻質量直接影響效果,推薦使用無損音源
-
復雜音樂(如交響樂)可能需要分層處理
-
完全消除人聲可能伴隨伴奏損失,需平衡參數
如果需要進一步優化,可以考慮集成AI人聲分離模型(如Spleeter),但這需要額外部署機器學習框架。