是否有可能播放音频从短[]而不是字节[]与NAudio

本文关键字:字节 NAudio 有可能 音频 是否 播放 | 更新日期: 2023-09-27 18:13:29

我正在尝试播放通过网络接收的音频,该网络作为一组短片到达。我正试图使这项工作与来自NAudio的WaveOut对象,但从我能找到的,这只适用于一个字节[]。到目前为止,我的问题是:

  • 是否有可能从短[]而不是字节[]播放音频?
  • 如果是这样,如何做到这一点?

它不是很多,但我现在有这个(显然播放音频从一个字节[]):

protected override void Write(VoiceSource source, VoicePacket packet)
{
      if (connected)
      {
            try
            {
                dispatcher.Invoke((WriteCallback)provider.Write, packet.Data);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
      }
}

其中WriteCallback定义为:

private delegate void WriteCallback(byte[] data);

我要写的提供者是IWaveProvider接口的实现。


编辑

我尝试了Mark告诉我的"诀窍",我的界面是这样的:

interface ISampleBuffer {
    byte[] Bytes { get; set; }
    short[] Shorts { get; set; }
}

和这样的缓冲结构体:

[StructLayout(LayoutKind.Explicit, Pack = 2)]
public struct SampleBuffer : ISampleBuffer
{
    [FieldOffset(0)]
    private byte[] bytes;
    [FieldOffset(0)]
    private short[] shorts;
    public byte[] Bytes { get { return bytes; } set { bytes = value; } }
    public short[] Shorts { get { return shorts; } set { shorts = value; } }
}

我已经实现了这个缓冲区如下:

short[] audio = decoder.Decode(packet.Data);
buffer.Bytes = new byte[audio.Length * 2];
buffer.Shorts = audio;
dispatcher.Invoke((WriteCallback)provider.Write, buffer.Bytes);

然而,每当我运行这个设置时,我在日志中得到一个带有以下异常的堆栈跟踪:

Object of type 'System.Int16[]' cannot be converted to type 'System.Byte[]'.

是有什么问题,我如何实现这一点?

是否有可能播放音频从短[]而不是字节[]与NAudio

NAudio包含一个聪明的技巧(或肮脏的hack取决于你的观点),它允许你从short[]"cast"到byte[]。它被称为WaveBuffer类,通过使用具有显式布局的结构体来工作。只需写入ShortBuffer属性并从ByteBuffer属性中读取。

我之前在博客上写过。它已经可靠地工作了好几年,并且节省了使用Buffer.BlockCopy的开销。

不确定NAudio位,但我可以帮助您将short[]转换为byte[]Buffer.BlockCopy在这里可能很有用,因为它可以在不同类型的数组之间复制字节:

 short[] shortArray = ...
 byte[] byteArray = new byte[shortArray.Length*2];
 Buffer.BlockCopy(shortArray, 0, byteArray, 0, byteArray.Length);
但是,

可能会遇到端序问题。你需要尝试一下,看看会发生什么。如果需要交换包含单个短消息的两个字节,可以手动交换:

 for (int i=0; i<byteArray.Length; i += 2) {
     byte b = byteArray[i];
     byteArray[i] = byteArray[i+1];
     byteArray[i] = b;
 }

或者,如果您希望事情更整洁,并且不想担心尾端转换,您可以使用BinaryWriter来为您完成转换:

BinaryWriter writer = new BinaryWriter(new MemoryStream(shortArray.Length*2));
foreach (short s in shortArray)
    writer.Write(s);
byte[] byteArray = ((MemoryStream)writer.BaseStream).ToArray();