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;
}
私は許可することでノバカイン プロジェクトに貢献しようとしています。
- iPod ライブラリから読み取ります (オーディオ ファイル サービス ライブラリではなく、AVAssetReader 経由でのみアクセスできます)。
- PCM ではなく VBR パケットを読み書きします。
したがって、これは上記の同等の機能がどのように見えるかです(注:部品を参照)
- (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;
}
コードを見ると、すべてが float で作成されているようです (オーディオ バッファ、出力形式など)。これには理由がありますか? (iOS オーディオの標準形式は、float ではなく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 データの読み書きに対応させるために変更しなければならないことのリストは何ですか?
あ