首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IOS核心音频- MP3到WAV时只工作一个通道,如何获得立体声?

IOS核心音频- MP3到WAV时只工作一个通道,如何获得立体声?
EN

Stack Overflow用户
提问于 2020-05-27 22:47:42
回答 1查看 159关注 0票数 1

当前正在接收一个MP3文件,该文件吐出一个WAV。我的代码运行良好已经有一段时间了,但是我现在想要更改导出的WAV是一个2通道立体声文件的地方。

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

--下面的代码是预先运行良好的代码(mono):

代码语言:javascript
复制
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);不起作用。不知道还有什么需要改变吗?

错误是:

代码语言:javascript
复制
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);

但问题肯定来自于我的AudioStreamBasicDescription of outputFormat,因为这是唯一一件改变为"2通道“的事情,突然它不再起作用了。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-28 14:50:56

您还需要更新大小。

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

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

AudioStreamBasicDescription的值随所描述的格式是否交织而略有不同。

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

代码语言:javascript
复制
asbd.mBytesPerFrame     = asbd.mBitsPerChannel / 8;

像这样交错着

代码语言:javascript
复制
asbd.mBytesPerFrame     = (asbd.mBitsPerChannel / 8) * asbd.mChannelsPerFrame;

对于,两个都有

代码语言:javascript
复制
asbd.mFramesPerPacket   = 1;
asbd.mBytesPerPacket    = asbd.mBytesPerFrame;

AudioFormatFlags.Canonical是不推荐的,但我假设这里它等同于交错打包的本地endian有符号整数。

所以就你的情况而言,交错的16位立体声音响是:

代码语言:javascript
复制
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++中),显示了这些关系:

代码语言:javascript
复制
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);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62054103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档