IOS核心音频-仅当有1声道时,MP3到WAV才能工作,如何获得立体声?

问题描述 投票:1回答:1

当前正在获取一个MP3文件以吐出WAV。我的代码已经运行了一段时间,但是现在我想在导出的WAV是2声道立体声文件的地方进行更改。

问题出在这里。这描述了所需的输出格式。

下面的代码是事先可以正常工作的(单声道):

AudioStreamBasicDescription outputFormat = new AudioStreamBasicDescription();
outputFormat.setFormat(AudioFormat.LinearPCM);
outputFormat.setFormatFlags(AudioFormatFlags.Canonical);
outputFormat.setBitsPerChannel(16);
outputFormat.setChannelsPerFrame(1);
outputFormat.setFramesPerPacket(1);
outputFormat.setBytesPerFrame(2);
outputFormat.setBytesPerPacket(2);
outputFormat.setSampleRate(pitch);

将其更改为setChannelsPerFrame(2);无效。不确定还需要更改什么?

错误是:

Launcher[318:12909] 224: SetDataFormat failed
Launcher[318:12909] 367: EXCEPTION (1718449215): "create audio file"

org.robovm.apple.corefoundation.OSStatusException: 1718449215
at org.robovm.apple.corefoundation.OSStatusException.throwIfNecessary(OSStatusException.java:53)
at org.robovm.apple.audiotoolbox.ExtAudioFile.create(ExtAudioFile.java:80)
at package.Launcher.mp3ToPCM(Launcher.java:1108)
...

所讨论的行在哪里

outputFileExtAudio = ExtAudioFile.create(outputFileURL, AudioFileType.WAVE, outputFormat, null, AudioFileFlags.EraseFile);

但是问题一定是由于我的outputFormat的AudioStreamBasicDescription所致,因为这是唯一更改为“ 2声道”的事情,突然间它不再起作用。

((这是Java代码,利用RoboVM转换为本地IOS代码。)

ios iphone core-audio
1个回答
0
投票

您还需要更新尺寸。

在Core Audio中,样本是一个单一值,而帧是所有通道中的一个样本。对于PCM音频,单个帧也是单个数据包。

对于16位单声道音频,帧和样本是同义词,占用2个字节。对于16位立体声音频,一帧包含两个样本(左和右),每个样本占2个字节,每个帧占4个字节。

AudioStreamBasicDescription的值在所描述的格式是否为交错格式方面略有不同。

您通常可以想到non-interleaved PCM AudioStreamBasicDescription像这样:

asbd.mBytesPerPacket    = asbd.mBitsPerChannel / 8;

interleaved像这样:

asbd.mBytesPerPacket    = (asbd.mBitsPerChannel / 8) * asbd.mChannelsPerFrame;

具有both具有

asbd.mFramesPerPacket   = 1;
asbd.mBytesPerFrame     = asbd.mBytesPerPacket * asbd.mFramesPerPacket;

AudioFormatFlags.Canonical已过时,但我在这里假定它等同于交错的压缩本机序号带符号整数。

因此,对于您的情况,交错的16位立体声为:

AudioStreamBasicDescription outputFormat = new AudioStreamBasicDescription();
outputFormat.setFormat(AudioFormat.LinearPCM);
outputFormat.setFormatFlags(AudioFormatFlags.Canonical);

outputFormat.setSampleRate(pitch);
outputFormat.setChannelsPerFrame(2);
outputFormat.setBitsPerChannel(16);

outputFormat.setBytesPerFrame(4);
outputFormat.setFramesPerPacket(1);
outputFormat.setBytesPerPacket(4);

以下是两个帮助函数(在C ++中),显示了这些关系:

static AudioFormatFlags CalculateLPCMFlags(UInt32 validBitsPerChannel, UInt32 totalBitsPerChannel, bool isFloat, bool isBigEndian, bool isNonInterleaved)
{
    return (isFloat ? kAudioFormatFlagIsFloat : kAudioFormatFlagIsSignedInteger) | (isBigEndian ? ((UInt32)kAudioFormatFlagIsBigEndian) : 0) | ((validBitsPerChannel == totalBitsPerChannel) ? kAudioFormatFlagIsPacked : kAudioFormatFlagIsAlignedHigh) | (isNonInterleaved ? ((UInt32)kAudioFormatFlagIsNonInterleaved) : 0);
}

static void FillOutASBDForLPCM(AudioStreamBasicDescription *asbd, Float64 sampleRate, UInt32 channelsPerFrame, UInt32 validBitsPerChannel, UInt32 totalBitsPerChannel, bool isFloat, bool isBigEndian, bool isNonInterleaved)
{
    asbd->mFormatID = kAudioFormatLinearPCM;
    asbd->mFormatFlags = CalculateLPCMFlags(validBitsPerChannel, totalBitsPerChannel, isFloat, isBigEndian, isNonInterleaved);

    asbd->mSampleRate = sampleRate;
    asbd->mChannelsPerFrame = channelsPerFrame;
    asbd->mBitsPerChannel = validBitsPerChannel;

    asbd->mBytesPerPacket = (isNonInterleaved ? 1 : channelsPerFrame) * (totalBitsPerChannel / 8);
    asbd->mFramesPerPacket = 1;
    asbd->mBytesPerFrame = (isNonInterleaved ? 1 : channelsPerFrame) * (totalBitsPerChannel / 8);
}
© www.soinside.com 2019 - 2024. All rights reserved.