0

novacaine的创建者提供了示例代码,其中从文件中读取音频数据并将其馈送到环形缓冲区。但是,当创建文件阅读器时,输出被强制为 PCM:

- (id)initWithAudioFileURL:(NSURL *)urlToAudioFile samplingRate:(float)thisSamplingRate numChannels:(UInt32)thisNumChannels
{

...

    // We're going to impose a format upon the input file
    // Single-channel float does the trick.
    _outputFormat.mSampleRate = self.samplingRate;
    _outputFormat.mFormatID = kAudioFormatLinearPCM;
    _outputFormat.mFormatFlags = kAudioFormatFlagIsFloat;
    _outputFormat.mBytesPerPacket = 4*self.numChannels;
    _outputFormat.mFramesPerPacket = 1;
    _outputFormat.mBytesPerFrame = 4*self.numChannels;
    _outputFormat.mChannelsPerFrame = self.numChannels;
    _outputFormat.mBitsPerChannel = 32;

}

我正试图通过允许它为 novacaine 项目做出贡献

  • 从 iPod 库中读取(只能通过 AVAssetReader 访问,而不是音频文件服务库)
  • 读写 VBR 数据包而不是 PCM。

所以这就是我上面的等效功能的样子(见注:部分)

- (id)initWithAudioAssetURL:(NSURL *)urlToAsset samplingRate:(float)thisSamplingRate numChannels:(UInt32)thisNumChannels
{
    self = [super init];
    if (self)
    {

        // Zero-out our timer, so we know we're not using our callback yet
        self.callbackTimer = nil;

        // Open a reference to the audio Asset Track and setup the reader
        self.assetURL = urlToAsset;
        AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:self.assetURL options:nil];
        NSError * error = nil;
        AVAssetReader* reader = [[AVAssetReader alloc] initWithAsset:songAsset error:&error];
        AVAssetTrack* track = [songAsset.tracks objectAtIndex:0];

        //NOTE: we use the track's native settings here, as opposed to forcing it to be PCM
        //like the example above
        _readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track
                                                                  outputSettings:NULL];

        _nativeTrackASBD = [self getTrackNativeSettings:track];

        [reader addOutput:_readerOutput];
        [reader startReading];


        // Set a few defaults and presets
        self.samplingRate = thisSamplingRate;
        self.numChannels = thisNumChannels;
        self.latency = .011609977; // 512 samples / ( 44100 samples / sec ) default

        // Arbitrary buffer sizes that don't matter so much as long as they're "big enough"
        self.outputBufferSize = 100000; //buffer sample sizes vary around 60-70k, we keep it @ 100k to be safe
        self.numSamplesReadPerPacket = 8192;
        self.desiredPrebufferedSamples = self.numSamplesReadPerPacket*2;

        //NOTE: these buffers are float, where as the above audio code is in SInt16
        self.outputBuffer = (float *)calloc(2*self.samplingRate, sizeof(float));
        self.holdingBuffer = (float *)calloc(2*self.samplingRate, sizeof(float));


        // Allocate a ring buffer (this is what's going to buffer our audio)
        ringBuffer = new RingBuffer(self.outputBufferSize, self.numChannels);


        // Fill up the buffers, so we're ready to play immediately
        [self bufferNewAudioFromAsset];

    }
    return self;
}

查看代码,似乎一切都是浮点数(音频缓冲区、输出格式等)。这有什么原因吗?(请记住,iOS 音频规范格式是 SInt16,而不是浮点数).. 例如在 Novocaine::renderCallback 函数中查看:

else if ( sm.numBytesPerSample == 2 ) // then we need to convert SInt16 -> Float (and also scale)
{
    float scale = (float)INT16_MAX;
    vDSP_vsmul(sm.outData, 1, &scale, sm.outData, 1, inNumberFrames*sm.numOutputChannels);

    for (int iBuffer=0; iBuffer < ioData->mNumberBuffers; ++iBuffer) {  

        int thisNumChannels = ioData->mBuffers[iBuffer].mNumberChannels;

        for (int iChannel = 0; iChannel < thisNumChannels; ++iChannel) {
            vDSP_vfix16(sm.outData+iChannel, sm.numOutputChannels, (SInt16 *)ioData->mBuffers[iBuffer].mData+iChannel, thisNumChannels, inNumberFrames);
        }
    }

}

为了使该库与读写 VBR 数据兼容,我必须更改哪些内容?

一个

4

0 回答 0