PCM 32 位和 PCM 16 位的音频编码转换问题
Audio Encoding conversion problems with PCM 32-bit yo PCM 16-bit
我在通用 Windows 应用程序中使用 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 也不起作用。
在上面的示例中,我只使用了帧输出节点。如果我创建一个自动写入原始文件的文件输出节点,它与 16 位 PCM 一样工作得很好,所以我的回调函数有问题导致它处于慢动作。
谢谢
//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];
这是正确的代码,应该可以工作。您的"slow motion"很可能与您之前错误设置的缓冲区大小有关。
我必须承认 Microsoft 需要有人审查他们臃肿的 API
我在通用 Windows 应用程序中使用 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 也不起作用。 在上面的示例中,我只使用了帧输出节点。如果我创建一个自动写入原始文件的文件输出节点,它与 16 位 PCM 一样工作得很好,所以我的回调函数有问题导致它处于慢动作。
谢谢
//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];
这是正确的代码,应该可以工作。您的"slow motion"很可能与您之前错误设置的缓冲区大小有关。
我必须承认 Microsoft 需要有人审查他们臃肿的 API