是否可以使用 NAudio 从短 [] 而不是字节 [] 播放音频?
Posted
技术标签:
【中文标题】是否可以使用 NAudio 从短 [] 而不是字节 [] 播放音频?【英文标题】:Is it possible to play audio from a short[] instead of a byte[] with NAudio? 【发布时间】:2011-11-03 10:32:22 【问题描述】:我正在尝试播放通过网络接收到的音频,该音频以一系列短裤的形式到达。我正在尝试使用 NAudio 的 WaveOut 对象来完成这项工作,但据我所知,这仅适用于字节 []。所以到目前为止我的问题是:
是否可以从 short[] 而不是 byte[] 播放音频? 如果是这样,该怎么做?不多,但我现在拥有的是这个(显然是从一个字节[]播放音频):
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[]'.
我的实现方式有问题吗?
【问题讨论】:
您误解了byte[]
和 short[]
的实际含义。数组是引用类型,因此byte[]
类型的变量实际上是指向堆上其他位置的指针。要做这样的事情,你需要在不安全的结构中使用fixed
字段,并且你需要在编译时知道数组的大小。
数组的大小在编译时是已知的。我得到的音频是 24o 长度的短数组。所以应该是可以的。我需要改变什么才能让它工作?
使用固定缓冲区:msdn.microsoft.com/en-us/library/zycewsya%28v=VS.100%29.aspx。您必须使用指针和其他错误将其转换为数组。虽然我觉得你从错误的角度解决问题,但如果你不得不求助于那些......
好吧,由于实现它的复杂性,我宁愿不使用它。但我只是在探索各个角度,看看什么是有效的。我已经尝试过您的方法,从技术上讲,它可以顺利运行。但实际上,我什么也没听到。没有音频正在播放。
应该反过来。 buffer.Shorts = decoder.Decode... 然后将 buffer.Bytes 传递给你的函数
【参考方案1】:
NAudio 包含一个巧妙的技巧(或根据您的观点而定的肮脏技巧),它允许您从 short[]
转换为 byte[]
。它被称为WaveBuffer
类,并通过使用具有显式布局的结构来工作。只需写入ShortBuffer
属性并读出ByteBuffer
属性即可。
我刚才blogged 谈到了它。它已经可靠运行了好几年,并且节省了使用Buffer.BlockCopy
的开销。
【讨论】:
你有这个类的具体使用例子吗?我真的不知道如何实现 IWaveBuffer 接口......:S【参考方案2】:不确定 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();
【讨论】:
+1,很好的答案,而 Buffer.BlockCopy 是在 .NET 中执行此操作的“正确”方法,尽管 NAudio 确实有一个技巧,我在另一个答案中已经写过。 我已经尝试过了,从程序的角度来看,它没有任何抱怨。我得到的唯一问题是我根本没有音频...... 再次尝试您的最后一个建议后,我能够获得音频。然而,扬声器发出的声音与我给出的输入完全不同。即使我只是对着麦克风吹气,输出也会断断续续,有轻微的回声......我知道让这些东西工作起来很困难,但没那么难......以上是关于是否可以使用 NAudio 从短 [] 而不是字节 [] 播放音频?的主要内容,如果未能解决你的问题,请参考以下文章