简体   繁体   English

如何在WP8上分割wav文件?

[英]How to split a wav file on WP8?

Is there a way to split a wav file in C# WP8? 有没有办法在C#WP8中拆分WAV文件? I'd like to save a sample of a wav file, starting at, for example, 00:30 and ending at 00:40. 我想保存一个wav文件的样本,例如从00:30开始到00:40结束。

Maybe using some kind of stream or buffer, but then I'd have to know when to start/finish copying the stream to another wav file. 也许使用某种流或缓冲区,但随后我必须知道何时开始/完成将流复制到另一个wav文件。

How can I do this? 我怎样才能做到这一点?

on my blog I posted about this, starting with this post ( http://csharp-tricks-en.blogspot.de/2011/03/read-in-wave-files.html ) aboud reading a wave file with the next 2 posts building up on this .. hope that helps! 在我的博客上,我对此发表了一篇文章,从这篇文章( http://csharp-tricks-en.blogspot.de/2011/03/read-in-wave-files.html )开始,接着阅读了一个Wave文件,接下来的2个建立在此的帖子..希望能有所帮助! Best Oliver 最佳奥利弗

Since a wav file's header can vary from 44 (standard) to over 100 bytes, you'll need to first determine the exact size of the header and also read important meta information before you can start chopping up your wav file(s). 由于wav文件的头文件可能从44(标准)字节到100多个字节不等,因此您需要首先确定头文件的确切大小,并读取重要的元信息,然后才能开始分解wav文件。

So you need to know the following meta data about your wav file(s), 因此,您需要了解有关wav文件的以下元数据,

  • Sample rate, 采样率,
  • Bit depth, 位深
  • Channel count, 频道数
  • Audio data format (whether samples are PCM or Floating-Point) 音频数据格式(样本是PCM还是浮点型)
  • Header size. 标头大小。

Before continuing, I'd recommend reading the format of a wav file header first so you'll have a better idea of what the code is doing. 在继续之前,建议您先阅读wav文件标头格式,以便您更好地了解代码的作用。

So first we need to get our meta info, 所以首先我们需要获取我们的元信息,

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);
}

Once we have this data we can then calculate where we need to start and stop reading our file. 有了这些数据后,我们便可以计算需要在哪里开始和停止读取文件了。 To calculate the start and end indexes we do, 要计算起始索引和终止索引,

var startIndex = (int)(start.TotalSeconds * sampleRate * byteDepth * channelCount);
var endIndex = (int)(end.TotalSeconds * sampleRate * byteDepth * channelCount);

start & end would be a TimeSpan indicating when to start and stop cropping. startend将是一个TimeSpan指示何时开始和停止裁剪。

We can now read the bytes from our file using our newly calculated info, if you're using a FileStream you would do the following, 现在,我们可以使用新计算的信息从文件中读取字节,如果您使用的是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);

The all you have to do is write a wav header to the destination file along with the newly extracted audio. 您要做的就是将wav标头与新提取的音频一起写入目标文件。 So, putting this altogether you should end up with something like this, 因此,总的来说,您应该得到这样的结果,

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM