如何分割WP8上的wav文件

本文关键字:WP8 上的 wav 文件 分割 何分割 | 更新日期: 2023-09-27 18:09:53

是否有办法在c# WP8中拆分wav文件?我想保存一个wav文件的示例,例如,从00:30开始,以00:40结束。

可能使用某种流或缓冲区,但是我必须知道何时开始/完成将流复制到另一个wav文件。

我该怎么做?

如何分割WP8上的wav文件

我在我的博客上发表了这篇文章,从这篇文章(http://csharp-tricks-en.blogspot.de/2011/03/read-in-wave-files.html)开始,关于阅读一个波文件,接下来的两篇文章建立在这个基础上。希望这对你有帮助!最好的奥利弗

由于wav文件的头可以从44(标准)到超过100字节不等,因此您需要首先确定头的确切大小,并在开始切割wav文件之前读取重要的元信息。

所以你需要知道以下关于你的wav文件的元数据,

  • 采样率,
  • 深度,
  • 通道数,
  • 音频数据格式(无论采样是PCM还是浮点)
  • 头大小。

在继续之前,我建议先阅读wav文件头的格式,这样您就可以更好地了解代码的功能。

首先我们需要得到meta信息,

private void ReadMetaData(FileStream stream, out bool isFloatinfPoint, out int channelCount, out int sampleRate, out int bitDepth, out int headerSize)
{
    var headerBytes = new byte[200];
    // Read header bytes.
    stream.Position = 0;
    stream.Read(headerBytes, 0, 200);
    headerSize = new string(Encoding.ASCII.GetChars(headerBytes)).IndexOf("data") + 8;
    isFloatinfPoint = BitConverter.ToUInt16(new byte[] { headerBytes[20], headerBytes[21] }, 0) == 3 ? true : false;
    channelCount = BitConverter.ToUInt16(new byte[] { headerBytes[22] , headerBytes[23] }, 0);
    sampleRate = (int)BitConverter.ToUInt32(new byte[] { headerBytes[24], headerBytes[25], headerBytes[26], headerBytes[27] }, 0);
    bitDepth = BitConverter.ToUInt16(new byte[] { headerBytes[34], headerBytes[35] }, 0);
}
有了这些数据之后,我们就可以计算从哪里开始和停止读取文件。要计算开始索引和结束索引,我们执行
var startIndex = (int)(start.TotalSeconds * sampleRate * byteDepth * channelCount);
var endIndex = (int)(end.TotalSeconds * sampleRate * byteDepth * channelCount);

start &end是指示何时开始和停止裁剪的TimeSpan

我们现在可以使用我们新计算的信息从我们的文件中读取字节,如果您使用FileStream,您将执行以下操作,

var newBytes = new byte[endIndex - startIndex];
myStream.Position = headerSize + startIndex; // Add headerSize to position to make sure we don't read the header.
myStream.Read(newBytes, 0, newBytes.Length);

您所要做的就是将wav头与新提取的音频一起写入目标文件。所以,把这些放在一起你应该得到像这样的东西,

private void CropWavFile(string inputFilePath, string outputFilePath, TimeSpan start, TimeSpan end)
{
    var stream = new FileStream(inputFilePath, FileMode.Open);
    var newStream = new FileStream(outputFilePath, FileMode.OpenOrCreate);
    var isFloatingPoint = false;
    var sampleRate = 0;
    var bitDepth = 0;
    var channelCount = 0;
    var headerSize = 0;
    // Get meta info
    ReadMetaData(stream, out isFloatingPoint, out channelCount, out sampleRate, out bitDepth, out headerSize);
    // Calculate where we need to start and stop reading.
    var startIndex = (int)(start.TotalSeconds * sampleRate * (bitDepth / 8) * channelCount);
    var endIndex = (int)(end.TotalSeconds * sampleRate * (bitDepth / 8) * channelCount);
    var bytesCount = endIndex - startIndex;
    var newBytes = new byte[bytesCount];
    // Read audio data.
    stream.Position = startIndex + headerSize;
    stream.Read(newBytes, 0, bytesCount);
    // Write the wav header and our newly extracted audio to the new wav file.
    WriteMetaData(newStream, isFloatingPoint, (ushort)channelCount, (ushort)bitDepth, sampleRate, newBytes.Length / (bitDepth / 8));
    newStream.Write(newBytes, 0, newBytes.Length);
    stream.Dispose();
    newStream.Dispose();
}
private void WriteMetaData(FileStream stream, bool isFloatingPoint, ushort channels, ushort bitDepth, int sampleRate, int totalSampleCount)
{
    stream.Position = 0;
    // RIFF header.
    // Chunk ID.
    stream.Write(Encoding.ASCII.GetBytes("RIFF"), 0, 4);
    // Chunk size.
    stream.Write(BitConverter.GetBytes(((bitDepth / 8) * totalSampleCount) + 36), 0, 4);
    // Format.
    stream.Write(Encoding.ASCII.GetBytes("WAVE"), 0, 4);

    // Sub-chunk 1.
    // Sub-chunk 1 ID.
    stream.Write(Encoding.ASCII.GetBytes("fmt "), 0, 4);
    // Sub-chunk 1 size.
    stream.Write(BitConverter.GetBytes(16), 0, 4);
    // Audio format (floating point (3) or PCM (1)). Any other format indicates compression.
    stream.Write(BitConverter.GetBytes((ushort)(isFloatingPoint ? 3 : 1)), 0, 2);
    // Channels.
    stream.Write(BitConverter.GetBytes(channels), 0, 2);
    // Sample rate.
    stream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
    // Bytes rate.
    stream.Write(BitConverter.GetBytes(sampleRate * channels * (bitDepth / 8)), 0, 4);
    // Block align.
    stream.Write(BitConverter.GetBytes((ushort)channels * (bitDepth / 8)), 0, 2);
    // Bits per sample.
    stream.Write(BitConverter.GetBytes(bitDepth), 0, 2);

    // Sub-chunk 2.
    // Sub-chunk 2 ID.
    stream.Write(Encoding.ASCII.GetBytes("data"), 0, 4);
    // Sub-chunk 2 size.
    stream.Write(BitConverter.GetBytes((bitDepth / 8) * totalSampleCount), 0, 4);
}
private void ReadMetaData(FileStream stream, out bool isFloatinfPoint, out int channelCount, out int sampleRate, out int bitDepth, out int headerSize)
{
    var headerBytes = new byte[200];
    // Read header bytes.
    stream.Position = 0;
    stream.Read(headerBytes, 0, 200);
    headerSize = new string(Encoding.ASCII.GetChars(headerBytes)).IndexOf("data") + 8;
    isFloatinfPoint = BitConverter.ToUInt16(new byte[] { headerBytes[20], headerBytes[21] }, 0) == 3 ? true : false;
    channelCount = BitConverter.ToUInt16(new byte[] { headerBytes[22] , headerBytes[23] }, 0);
    sampleRate = (int)BitConverter.ToUInt32(new byte[] { headerBytes[24], headerBytes[25], headerBytes[26], headerBytes[27] }, 0);
    bitDepth = BitConverter.ToUInt16(new byte[] { headerBytes[34], headerBytes[35] }, 0);
}