音频编码转换问题与PCM 32位和PCM 16位

时间:2016-06-07 14:00:18

标签: c# speech-recognition universal

我在Universal Windows App中使用C#来编写Watson语音到文本服务。 现在,不是使用Watson服务,而是写入文件,然后在Audacity中读取它以确认它的格式正确,因为Watson服务没有向我返回正确的响应,以下内容解释了原因。

出于某种原因,当我创建16位PCM编码属性和读取缓冲区时,我只能将数据读取为32位PCM,并且它运行良好,但如果我在16位PCM中读取它,那么慢动作,所有的讲话基本上都是腐败的。

我真的不知道从32位转换到16位究竟需要做些什么,但这就是我在C#应用程序中所拥有的:

//Creating PCM Encoding properties
var pcmEncoding = AudioEncodingProperties.CreatePcm(16000, 1, 16);
var result = await AudioGraph.CreateAsync(
    new AudioGraphSettings(AudioRenderCategory.Speech)
    {
        DesiredRenderDeviceAudioProcessing = AudioProcessing.Raw,
        AudioRenderCategory = AudioRenderCategory.Speech,
        EncodingProperties = pcmEncoding
    }
);
graph = result.Graph;

//Initialize microphone
var microphone = await DeviceInformation.CreateFromIdAsync(MediaDevice.GetDefaultAudioCaptureId(AudioDeviceRole.Default));
var micInputResult = await graph.CreateDeviceInputNodeAsync(MediaCategory.Speech, pcmEncoding, microphone);

//Create frame output node
frameOutputNode = graph.CreateFrameOutputNode(pcmEncoding);

//Callback function to fire when buffer is filled with data
graph.QuantumProcessed += (s, a) => ProcessFrameOutput(frameOutputNode.GetFrame());
frameOutputNode.Start();

//Make the microphone write into the frame node
micInputResult.DeviceInputNode.AddOutgoingConnection(frameOutputNode);
micInputResult.DeviceInputNode.Start();

graph.Start();

初始化步骤在此阶段完成。现在,实际上从缓冲区读取并写入文件只有在我使用具有以下功能的32位PCM编码时才会起作用(注释掉是导致慢动作语音输出的PCM 16位代码):

private void ProcessFrameOutput(AudioFrame frame)
{
    //Making a copy of the audio frame buffer
    var audioBuffer = frame.LockBuffer(AudioBufferAccessMode.Read);
    var buffer = Windows.Storage.Streams.Buffer.CreateCopyFromMemoryBuffer(audioBuffer);
    buffer.Length = audioBuffer.Length;

    using (var dataReader = DataReader.FromBuffer(buffer))
    {
        dataReader.ByteOrder = ByteOrder.LittleEndian;

        byte[] byteData = new byte[buffer.Length];
        int pos = 0;

        while (dataReader.UnconsumedBufferLength > 0)
        {
            /*Reading Float -> Int 32*/
            /*With this code I can import raw wav file into the Audacity
              using Signed 32-bit PCM Encoding, and it is working well*/
            var singleTmp = dataReader.ReadSingle();
            var int32Tmp = (Int32)(singleTmp * Int32.MaxValue);
            byte[] chunkBytes = BitConverter.GetBytes(int32Tmp);
            byteData[pos++] = chunkBytes[0];
            byteData[pos++] = chunkBytes[1];
            byteData[pos++] = chunkBytes[2];
            byteData[pos++] = chunkBytes[3];

            /*Reading Float -> Int 16 (Slow Motion)*/
            /*With this code I can import raw wav file into the Audacity
              using Signed 16-bit PCM Encoding, but when I play it, it's in
              a slow motion*/
            //var singleTmp = dataReader.ReadSingle();
            //var int16Tmp = (Int16)(singleTmp * Int16.MaxValue);
            //byte[] chunkBytes = BitConverter.GetBytes(int16Tmp);
            //byteData[pos++] = chunkBytes[0];
            //byteData[pos++] = chunkBytes[1];
        }

        WriteBytesToFile(byteData);
    }
}

有谁能想到这种情况发生的原因?是因为Int32 PCM的尺寸更大,当我使用Int16时,它会扩展它并使声音更长?或者我没有正确抽样?

注意:我尝试直接从缓冲区读取字节,然后将其用作原始数据,但它不是以这种方式编码为PCM。 直接从缓冲区读取Int16 / 32也不起作用。 在上面的例子中,我只使用Frame Output节点。如果我创建一个自动写入原始文件的文件输出节点,它可以很好地用作16位PCM,因此我的回调函数出现问题导致它处于慢速运动状态。

由于

1 个答案:

答案 0 :(得分:2)

//Creating PCM Encoding properties
var pcmEncoding = AudioEncodingProperties.CreatePcm(16000, 1, 16);
var result = await AudioGraph.CreateAsync(
    new AudioGraphSettings(AudioRenderCategory.Speech)
    {
        DesiredRenderDeviceAudioProcessing = AudioProcessing.Raw,
        AudioRenderCategory = AudioRenderCategory.Speech,
        EncodingProperties = pcmEncoding
    }
);
graph = result.Graph;

pcmEncoding在这里没有多大意义,因为AudioGraph只支持Float编码。

        byte[] byteData = new byte[buffer.Length];

它应该是buffer.Length / 2,因为你从每个样本4个字节的浮点数据转换为每个样本2个字节的int16数据

        /*Reading Float -> Int 16 (Slow Motion)*/
        /*With this code I can import raw wav file into the Audacity
          using Signed 16-bit PCM Encoding, but when I play it, it's in
          a slow motion*/
        var singleTmp = dataReader.ReadSingle();
        var int16Tmp = (Int16)(singleTmp * Int16.MaxValue);
        byte[] chunkBytes = BitConverter.GetBytes(int16Tmp);
        byteData[pos++] = chunkBytes[0];
        byteData[pos++] = chunkBytes[1];

这是正确的代码,它应该工作。您的“慢动作”很可能与之前错误设置的缓冲区大小有关。

我必须承认微软需要有人来审核其膨胀的API