gpt4 book ai didi

c# - 连接/加入两个或多个 WAV 文件时的咔嗒声

转载 作者:行者123 更新时间:2023-12-02 23:42:14 26 4
gpt4 key购买 nike

我正在做一个音乐项目,我需要加入几个 WAV 文件。我的代码运行良好,但您可以清楚地听到两个连接的 WAV 文件之间的咔嗒声。这是一个巨大的问题。

我是一名音频工程师。当我工作时,例如DAW(数字音频工作站)中的连续样本,我想防止两个 WAV 样本之间出现这种咔哒声,然后我必须创建交叉淡入淡出(基本上这是第一个样本的淡出和下一个样本的淡入)。

因此我的问题是我是否可以在连接两个 WAV 文件时创建这样的交叉淡入淡出。我需要消除级联波形文件之间的咔嗒声。

我在如何连接 WAV 文件下方提供了我的 C# 代码。这适用于相同“格式”的 WAV 文件。我在 (How to join 2 or more .WAV files together programatically?) 上找到了这段代码。此外,我发现了这个 FadeIn/FadeOut possibility但我不知道如何在代码上应用它。此外,我不知道这是否会阻止咔嗒声。

感谢您的建议和解决方案。希望马克希思能读到这个:)。

最好的祝福,
亚历克斯

波形文件格式:

平均字节每秒:264600 |
BitsPerSample:24 |
block 对齐:6 |
channel :2 |
编码:PCM |
额外尺寸:0 |
采样率:44100 |

    public static void Concatenate(string outputFile, IEnumerable<string> sourceFiles)
{
byte[] buffer = new byte[6]; //1024 was the original. but my wave file format has the blockAlign 6. So 1024 was not working for me. 6 does.
WaveFileWriter waveFileWriter = null;

try
{
foreach (string sourceFile in sourceFiles)
{
using (WaveFileReader reader = new WaveFileReader(sourceFile))
{
if (waveFileWriter == null)
{
// first time in create new Writer
waveFileWriter = new WaveFileWriter(outputFile, reader.WaveFormat);
}
else
{
if (!reader.WaveFormat.Equals(waveFileWriter.WaveFormat))
{
throw new InvalidOperationException("Can't concatenate WAV Files that don't share the same format");
}
}

int read;
while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
{
waveFileWriter.WriteData(buffer, 0, read);
}
}
}
}
finally
{
if (waveFileWriter != null)
{
waveFileWriter.Dispose();
}
}
}

最佳答案

这听起来很有趣:)

这是我为此编写的示例。它接受输入文件名模式的列表(假设当前目录)和输出文件的名称。它将文件拼接在一起,在一个文件的末尾淡出约 1 秒,然后在下一个文件的约 1 秒内淡入,依此类推。注意:它不会混合约 1 秒的重叠。不想那样做:)

我用了ReadNextSampleFrame WaveFileReader 上的方法将数据读取为 IEEE 浮点样本(每个 channel 一个浮点数)。这使得单方面应用音量调整变得更加容易,而不必担心实际的输入 PCM 表示。在输出中,它使用 WriteSamples在作家写调整样本。

我第一次使用 NAudio FadeInFadeOutSampleProvider .但是当你有多个音频 channel 时,我发现了一个奇怪的错误。

因此,代码手动为每个样本读取应用一个体积,在每个文件的开头(第一个文件除外)将体积从 0.0 增加到 1.0。然后它直接复制文件的“中间”。然后在文件结束前大约 1 秒(实际上, ( WaveFormat.SampleRate * WaveFormat.Channels ) 在文件结束前采样),它将音量从 1.0f 降低到 0.0f。

我测试了一下,使用sox生成一个5秒长的440Hz正弦波文件,采样率=96K,立体声,如下:

sox -n -c 2 -r 96000 -b 24 sine.wav synth 5 sine 440

测试调用如下:
FadeWeaver.FadeWeave("weaved.wav", "sine.wav", "sine.wav", "sine.wav");

这是代码:
public class FadeWeaver
{
static
public
void
FadeWeave( string _outfilename,
params string [] _inpatterns )
{
WaveFileWriter output = null;
WaveFormat waveformat = null;
float [] sample = null;

float volume = 1.0f;
float volumemod = 0.0f;

// Add .wav extension to the output if not specified.
string extension = Path.GetExtension(_outfilename);
if( string.Compare(extension, ".wav", true) != 0 ) _outfilename += ".wav";

// Assume we're using the current directory. Let's get the
// list of filenames.
List<string> filenames = new List<string>();
foreach( string pattern in _inpatterns )
{
filenames.AddRange(Directory.GetFiles(Directory.GetCurrentDirectory(), pattern));
}

try
{
// Alrighty. Let's march over them. We'll index them (rather than
// foreach'ing) so that we can monitor first/last file.
for( int index = 0; index < filenames.Count; ++index )
{
// Grab the file and use an 'audiofilereader' to load it.
string filename = filenames[index];
using( WaveFileReader reader = new WaveFileReader(filename) )
{
// Get our first/last flags.
bool firstfile = (index == 0 );
bool lastfile = (index == filenames.Count - 1);

// If it's the first...
if( firstfile )
{
// Initialize the writer.
waveformat = reader.WaveFormat;
output = new WaveFileWriter(_outfilename, waveformat);
}
else
{
// All files must have a matching format.
if( !reader.WaveFormat.Equals(waveformat) )
{
throw new InvalidOperationException("Different formats");
}
}


long fadeinsamples = 0;
if( !firstfile )
{
// Assume 1 second of fade in, but set it to total size
// if the file is less than one second.
fadeinsamples = waveformat.SampleRate;
if( fadeinsamples > reader.SampleCount ) fadeinsamples = reader.SampleCount;

}

// Initialize volume and read from the start of the file to
// the 'fadeinsamples' count (which may be 0, if it's the first
// file).
volume = 0.0f;
volumemod = 1.0f / (float)fadeinsamples;
int sampleix = 0;
while( sampleix < (long)fadeinsamples )
{
sample = reader.ReadNextSampleFrame();
for( int floatix = 0; floatix < waveformat.Channels; ++floatix )
{
sample[floatix] = sample[floatix] * volume;
}

// Add modifier to volume. We'll make sure it isn't over
// 1.0!
if( (volume = (volume + volumemod)) > 1.0f ) volume = 1.0f;

// Write them to the output and bump the index.
output.WriteSamples(sample, 0, sample.Length);
++sampleix;
}

// Now for the time between fade-in and fade-out.
// Determine when to start.
long fadeoutstartsample = reader.SampleCount;
//if( !lastfile )
{
// We fade out every file except the last. Move the
// sample counter back by one second.
fadeoutstartsample -= waveformat.SampleRate;
if( fadeoutstartsample < sampleix )
{
// We've actually crossed over into our fade-in
// timeframe. We'll have to adjust the actual
// fade-out time accordingly.
fadeoutstartsample = reader.SampleCount - sampleix;
}
}

// Ok, now copy everything between fade-in and fade-out.
// We don't mess with the volume here.
while( sampleix < (int)fadeoutstartsample )
{
sample = reader.ReadNextSampleFrame();
output.WriteSamples(sample, 0, sample.Length);
++sampleix;
}

// Fade out is next. Initialize the volume. Note that
// we use a bit-shorter of a time frame just to make sure
// we hit 0.0f as our ending volume.
long samplesleft = reader.SampleCount - fadeoutstartsample;
volume = 1.0f;
volumemod = 1.0f / ((float)samplesleft * 0.95f);

// And loop over the reamaining samples
while( sampleix < (int)reader.SampleCount )
{
// Grab a sample (one float per channel) and adjust by
// volume.
sample = reader.ReadNextSampleFrame();
for( int floatix = 0; floatix < waveformat.Channels; ++floatix )
{
sample[floatix] = sample[floatix] * volume;
}

// Subtract modifier from volume. We'll make sure it doesn't
// accidentally go below 0.
if( (volume = (volume - volumemod)) < 0.0f ) volume = 0.0f;

// Write them to the output and bump the index.
output.WriteSamples(sample, 0, sample.Length);
++sampleix;
}
}
}
}
catch( Exception _ex )
{
Console.WriteLine("Exception: {0}", _ex.Message);
}
finally
{
if( output != null ) try{ output.Dispose(); } catch(Exception){}
}
}
}

关于c# - 连接/加入两个或多个 WAV 文件时的咔嗒声,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36859363/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com