Можно ли воспроизводить звук с короткого [] вместо байта [] с помощью NAudio? - PullRequest
1 голос
/ 03 ноября 2011

Я пытаюсь воспроизвести звук, полученный по сети, который поступает в виде массива шортов. Я пытаюсь сделать эту работу с объектом WaveOut из NAudio, но из того, что я смог найти, это работает только с байтом []. Итак, мои вопросы до сих пор:

  • Можно ли воспроизводить звук с короткого [] вместо байта []?
  • Если так, как это будет сделано?

Это немного, но сейчас у меня есть следующее (которое, очевидно, воспроизводит звук из байта []):

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.


Редактировать

Я попробовал «хитрость», о которой говорил мне Марк, с моим Интерфейсом, похожим на это:

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[]'.

Что-то не так с тем, как я это реализовал?

Ответы [ 2 ]

3 голосов
/ 03 ноября 2011

NAudio включает в себя хитрый трюк (или грязный хак в зависимости от вашей точки зрения), который позволяет вам «кастовать» от short[] до byte[]. Он называется классом WaveBuffer и работает с использованием структуры с явным макетом. Просто запишите в свойство ShortBuffer и прочитайте из свойства ByteBuffer.

Я написал об этом некоторое время назад. Он надежно работает уже несколько лет и экономит накладные расходы при использовании Buffer.BlockCopy.

2 голосов
/ 03 ноября 2011

Не уверен насчет бита 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();
...