iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
一応、録音した音が再生できた。だが、かなり荒いコードだ。そもそも、iPhoneシミュレータでAudio Unitを使用する場合、今のXcodeのバージョンだと問題があるようで、エラーメッセージが表示されていて、意図した動きをしない。自分のバグの可能性もあるが。実機で動作できたが、モノラル/ステレオの扱い等がいい加減なコードだ。でも、第一歩としては、今回はこれでヨシとしよう。
録音したデータをバッファに保存するコードだ。
- (void)write:(UInt32)inNumberFrames data:(AudioBufferList *)ioData
{
uint32_t available = self.maxSampleCount - self.startingSampleCount;
if (available < inNumberFrames) {
inNumberFrames = available;
}
memcpy(self.buffer + self.startingSampleCount, ioData->mBuffers[0].mData, sizeof(AudioUnitSampleType) * inNumberFrames);
self.startingSampleCount = self.startingSampleCount + inNumberFrames;
if (self.maxSampleCount <= self.startingSampleCount) {
[self stop:nil];
}
}
:
static OSStatus MyAURenderCallack(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
AudioUnitViewController *viewController = (AudioUnitViewController *)inRefCon;
[viewController write:inNumberFrames data:ioData];
return noErr;
}
ループ再生するコードだ。
- (void)read:(UInt32)inNumberFrames data:(AudioBufferList *)ioData
{
uint32_t available = self.maxSampleCount - self.startingSampleCount;
uint32_t num = inNumberFrames;
if (available < num) {
num = available;
}
memcpy(ioData->mBuffers[0].mData, self.buffer + self.startingSampleCount, sizeof(AudioUnitSampleType) * num);
self.startingSampleCount = self.startingSampleCount + num;
if (self.maxSampleCount <= self.startingSampleCount)
self.startingSampleCount = 0;
if (num < inNumberFrames) {
num = inNumberFrames - num;
memcpy(ioData->mBuffers[0].mData, self.buffer + self.startingSampleCount, sizeof(AudioUnitSampleType) * num);
self.startingSampleCount = self.startingSampleCount + num;
}
memcpy(ioData->mBuffers[1].mData, ioData->mBuffers[0].mData, sizeof(AudioUnitSampleType) * inNumberFrames);
}
:
static OSStatus MyPlayAURenderCallack (
void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData
)
{
AudioUnitViewController *viewController = (AudioUnitViewController *)inRefCon;
[viewController read:inNumberFrames data:ioData];
return noErr;
}
例えば、鍵盤楽器のようなアプリケーションを作る場合は、Audio Unitのレスポンスの早さは魅力的だと思う。そうでなければ、ちょっと、面倒かな。