【问题标题】:How to split a wav file on WP8?如何在 WP8 上拆分 wav 文件?
【发布时间】:2014-06-22 16:59:14
【问题描述】:

有没有办法在 C# WP8 中拆分 wav 文件?我想保存一个 wav 文件的样本,例如,从 00:30 开始,到 00:40 结束。

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

我该怎么做?

【问题讨论】:

  • 你是如何阅读文件的? NAudio之类的? (或者你还没到那一步?)
  • 我找到了一个使用 xaudio2 和 c++ 的示例,但它只是给了我播放/暂停的选项。我将尝试将其与 Oliver 的示例代码合并。
  • 好的,如果您有兴趣,我将建议您创建自己的实现?这真的很容易。
  • 好吧,我可以使用示例代码在裁剪之前播放该音频示例,以进行确认。你能帮忙吗?
  • 是的,我可以,我已经开设了阅读大量格式的 Wav 文件的课程,因此裁剪只是从 X 到 Y 中选择样本...如果您仍然可以,我会发布答案有兴趣吗?

标签: c# windows-phone-8 split wav


【解决方案1】:

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

【讨论】:

  • 谢谢你,多么棒的帖子!我会试试你的代码。这需要一段时间,因为我会尝试与 xaudio2、c++、directX 集成,而且我不是那个专家……但我会在完成后报告:)
  • 我有机会测试你的代码,它也可以工作。谢谢。
【解决方案2】:

由于 wav 文件的标头可以从 44(标准)到 100 多个字节不等,因此您需要首先确定标头的确切大小并阅读重要的元信息,然后才能开始切割您的 wav 文件(s )。

因此,您需要了解有关您的 wav 文件的以下元数据,

  • 采样率,
  • 位深度,
  • 频道数,
  • 音频数据格式(样本是 PCM 还是浮点数)
  • 标题大小。

在继续之前,我建议您先阅读format of a wav file header,以便您更好地了解代码的作用。

所以首先我们需要获取元信息,

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

【讨论】:

  • 好吧,现在更简单了。它只是工作:) 谢谢。现在我只需要想办法从手机上的 mp3 收藏中创建这些 wav,但那是另一回事了。
  • @user2962761 所以你需要将mp3s转换成wavs?如果是这样,您是否尝试过使用NAudio
  • 是的,这是一个很好的项目,但是当我尝试通过 nuget 添加引用时,出现错误:“Could not install package 'NAudio 1.7.1'. You are trying to install this package into一个以“WindowsPhone,Version=v8.0”为目标的项目,但包不包含任何与该框架兼容的程序集引用或内容文件。有关详细信息,请联系包作者。”
  • @user2962761 那你为什么不直接download dll 并手动添加对它的引用呢?
  • 我不能因为“无法将对更高版本或不兼容程序集的引用添加到项目中”
猜你喜欢
  • 2016-10-26
  • 2017-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-19
相关资源
最近更新 更多