Reputation: 21
When I change the waveFormat of a wav file the "data" identifier shifts to the right. The data identifier which represents the beginning of the da chunk has to be at the 0x24 position but after I change the waveFormat with the NAudio library it shiffts to the 0x26 position.
WAV format
This is the code I use to change the waveFormat:
private void TurnTo16bitsAudio(string path)
{
NAudio.Wave.WaveFileReader wave = new NAudio.Wave.WaveFileReader(@path);
System.Console.WriteLine(wave.WaveFormat);
if (wave.WaveFormat.BitsPerSample >= 16 && wave.WaveFormat.Channels<2)
{
wave.Dispose();
return;
}
var newFormat = new WaveFormat(44100, 16, 1);
var conversionStream = new WaveFormatConversionStream(newFormat, wave);
WaveFileWriter.CreateWaveFile(@path + '1', conversionStream);
wave.Dispose();
wave = new NAudio.Wave.WaveFileReader(@path + '1');
conversionStream = new WaveFormatConversionStream(newFormat, wave);
WaveFileWriter.CreateWaveFile(@path, conversionStream);
wave.Dispose();
conversionStream.Dispose();
System.IO.File.Delete(@path + '1');
}
There is any possibility to change the wav header with NAudio or to change the waveFormat without shiffting the "data" identifier
Upvotes: 1
Views: 1853
Reputation: 1384
Method Serialize in WaveFormat class never outputs 0x10 in Subchunk1Size field. Minimum value is 0x12.
public virtual void Serialize(BinaryWriter writer)
{
writer.Write((int)(18 + extraSize)); // wave format length
writer.Write((short)Encoding);
writer.Write((short)Channels);
writer.Write((int)SampleRate);
writer.Write((int)AverageBytesPerSecond);
writer.Write((short)BlockAlign);
writer.Write((short)BitsPerSample);
writer.Write((short)extraSize);
}
Additional 2 bytes are for ExtraParamSize which is ignored when encoding is set to WaveFormatEncoding.Pcm (its value == 0). This is related to change in the WAV format done by Microsoft (Windows 2000 and later) when WAVEFORMATEX was introduced.
Here you can find answers on subchunk1size 16/18 different size question: C++ read wav file, subchunk1size = 18
Detailed information about WAVEFORMATEX structure: https://msdn.microsoft.com/library/windows/hardware/ff538799
If you really want to force creation of wav header without extraSize field you can extend WaveFormat class.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 2)]
class CustomWaveFormat : WaveFormat
{
public CustomWaveFormat(int rate, int bits, int channels)
: base(rate, bits, channels)
{
extraSize = 0;
}
public override void Serialize(BinaryWriter writer)
{
writer.Write((int)16); // wave format length
writer.Write((short)Encoding);
writer.Write((short)Channels);
writer.Write((int)SampleRate);
writer.Write((int)AverageBytesPerSecond);
writer.Write((short)BlockAlign);
writer.Write((short)BitsPerSample);
}
}
Usage:
...
var newFormat = new CustomWaveFormat(44100, 16, 1);
using (var conversionStream = new WaveFormatConversionStream(newFormat, waveFileReader))
{
WaveFileWriter.CreateWaveFile("example_new.wav", conversionStream);
}
...
Upvotes: 1