Чтение аудиоданных AVAudioPCMBuffer в виде числа с плавающей запятой[] в C # Xamarin.iOS

#c# #xamarin.ios #avaudioengine

#c# #xamarin.ios #avaudioengine

Вопрос:

Я пытаюсь считывать аудиоданные из an AVAudioPCMBuffer в массив float значений. Ниже приведен метод расширения, который я создал для этой цели:

 public static float[] ToFloatArray(this AVAudioPcmBuffer pcmBuffer)
{
    if ((pcmBuffer != null) amp;amp; 
        (pcmBuffer.FloatChannelData != IntPtr.Zero))
    {
        int length = (Convert.ToInt32(pcmBuffer.FrameLength) * 2);
        if (length > 0)
        {
            var data = new float[length];
            Marshal.Copy(pcmBuffer.FloatChannelData, data, 0, length);
            return data;
        }
        else return new float[0];
    }
    else return null;
}
 

Похоже, что метод возвращает данные соответствующей длины (8820 выборок при частоте дискретизации 44100), однако значения, по-видимому, не имеют смысла, причем многие из них являются NaN .

Ниже приведен быстрый data просмотр в приведенном выше методе сразу после Marshal.Copy операции:

Быстрое наблюдение за выводом данных из AVAudioPCMBuffer

Я намеревался использовать float[] значения для создания измерителя VU, но при мониторинге в режиме реального времени значения, похоже, существенно не меняются при вводе микрофона, и я не понимаю, почему многие значения не содержат Number ( NaN ) .

Я знаю, что AVAudioPcmBuffer они содержат действительные аудиоданные, поскольку я отправляю их на SFSpeechAudioBufferRecognitionRequest via Append(AVAudioPcmBuffer audioPcmBuffer) , и распознавание речи работает отлично.

У меня есть подозрение, что Marshal.Copy это может быть копирование неправильных данных. Может ли кто-нибудь подтвердить это и / или представить правильный способ доступа float[] к значениям из AVAudioPcmBuffer C # Xamarin для iOS?

Ответ №1:

FloatChannelData возвращает указатель на указатели с плавающей запятой, а не один указатель. Поэтому вам нужно разыменовать float ** , чтобы добраться до вашего float * . Итак, предполагая, что в вашем примере вы имеете дело с mono, вам просто нужно изменить:

Marshal.Copy(pcmBuffer.FloatChannelData, data, 0, length)

Для

Marshal.Copy(pcmBuffer.FloatChannelData[0], data, 0, length)

Комментарии:

1. Я пытался это сделать, но FloatChannelData имеет тип IntPtr , который не может принимать индексатор. Я обновил свой код выше, чтобы попытаться прочитать как double значения вместо float (как nfloat представляется, 64-разрядные), но прочитанные данные по-прежнему не являются допустимыми образцами звука. У вас есть какие-либо другие предложения?

Ответ №2:

FloatChannelData — это указатель на каналы, поэтому для получения байтов вам нужно сделать это —

 var channels = (IntPtr*)buffer.FloatChannelData.ToPointer();
Marshal.Copy(channels[0], data, 0, length);