使用建议:
-
参数调节指南:
-
低频人声残留:降低
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-1
public 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),但这需要额外部署机器学习框架。
750

被折叠的 条评论
为什么被折叠?



