HITONE開発日誌-02.〜AudioQueueでサイン波の出力〜

HITONEではオーディオの出力に、AudioQueueを使用しています。(AudioToolBox/AudioQueue)

オーディオデバイスに送る波形を自前で作れるので、後々拡張しやすいだろうと思いまして。

今後も音を扱う作品を作っていくつもりですのでね。

さて、HITONEの音源はサイン波です。

今回はAudioQueueのコールバックを使ってスピーカからサイン波を出力してみます。

※iPhone/iPadでの開発ですが、Objective-CではなくC++を使っています。

Objective-C++の話は、どこかでちょこっと触れるかも。

NIAudioRenderer.h

#ifndef NI_AUDIO_RENDERER_H
#define NI_AUDIO_RENDERER_H

#include <AudioToolbox/AudioQueue.h>

#include “NIDef.h”
#include “NIAudioDef.h”

#define NUM_BUFFERS 3

typedef struct AQCallbackStruct {
AudioQueueRef queue;
NIUint32 frameCount;
AudioQueueBufferRef mBuffers[NUM_BUFFERS];
AudioStreamBasicDescription mDataFormat;
} AQCallbackStruct;

class NIAudioRenderer {
public:
static void Init();
static void Term();

private:
static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB);

private:
static AQCallbackStruct _in;
static AudioQueueRef _queue;
static NIUint32 _sampleIndex;
};

#endif // AUDIO_RENDERER_H

/* EOF */

NIAudioRenderer.cpp

#include <math.h>
#include “NIAudioRenderer.h”

AQCallbackStruct NIAudioRenderer::_in;
AudioQueueRef NIAudioRenderer::_queue;

void NIAudioRenderer::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB)
{
NIFloat floatVal;
NISint16 sampleValue; // -32767 bis +32767

AQCallbackStruct *inData = (AQCallbackStruct *)in;
NISint16 *coreAudioBuffer = (NISint16*) outQB->mAudioData;

if (inData->frameCount > 0) {
outQB->mAudioDataByteSize = 4*inData->frameCount;

for(int i=0; iframeCount*2; i=i+2) {
floatVal = sin(((NIFloat)_sampleIndex * 2 * M_PI * 440) / NI_AUDIO_SAMPLE_RATE);
sampleValue = (NISint16)(floatVal * 32767.0f);
coreAudioBuffer[i] = sampleValue;
coreAudioBuffer[i+1] = sampleValue;
_sampleIndex++;
}
AudioQueueEnqueueBuffer(inQ, outQB, 0, NULL);
} else {
AudioQueueStop(inData->queue, false);
}
}

void NIAudioRenderer::Init()
{
_in.mDataFormat.mSampleRate = NI_AUDIO_SAMPLE_RATE;
_in.mDataFormat.mFormatID = kAudioFormatLinearPCM;
_in.mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
_in.mDataFormat.mBytesPerPacket = 4;
_in.mDataFormat.mFramesPerPacket = 1;
_in.mDataFormat.mBytesPerFrame = 4;
_in.mDataFormat.mChannelsPerFrame = 2;
_in.mDataFormat.mBitsPerChannel = 16;
_in.frameCount = 1024;

_sampleIndex = 0;

AudioQueueNewOutput(&_in.mDataFormat, AQBufferCallback, &_in, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &_in.queue);

UInt32 bufferBytes = _in.frameCount * _in.mDataFormat.mBytesPerFrame;

for (int i=0; i< NUM_BUFFERS; i++) {
AudioQueueAllocateBuffer(_in.queue, bufferBytes, &_in.mBuffers[i]);
AQBufferCallback (&_in, _in.queue, _in.mBuffers[i]);
}
AudioQueueSetParameter(_in.queue, kAudioQueueParam_Volume, 1.0);
AudioQueueStart(_in.queue, NULL);
_queue = _in.queue;
}

void NIAudioRenderer::Term()
{
AudioQueueStop(_queue,true);
AudioQueueDispose(_queue, true);
}
/* EOF */

ちなみに、
NIAudioDef.hとNIDef.hには
NI_AUDIO_SAMPLE_RATE
NIUint32
NISint16
NIFloat
などが定義してあります。
使う際は、ご自分の環境に合わせて定義してください。

“NI”っていうのは、あれです、自分の開発用ライブラリの名前ですね。

気にしないでOKです。

で、使うところで

#include “NIAudioRenderer.h” して

NIAudioRenderer::Init(); すれば440Hzのサイン波が出力される、はず。

終了時にNIAudiorenderer::Term(); するのをお忘れなく。

参考にしたサイト
CSPhone Project -サイン波の出力-

HITONE過去記事
01-導入-

次回はサイン波を複数鳴らしてみます。

HITONE開発日誌-01.〜導入〜

お久しぶりに書きます。

ちょっとiPhone App.の開発から離れてたんですが、ちょっときっかけがあって再開しました。

前に途中まで作っていたTiLoopは少し置いておいて、今はHITONEというアプリを作っています。

もともとは大学の卒研で、Macで(Java+Processing+Max/MSP(OpenSoundControl))動くものを作ったんですが、

そもそもタッチスクリーンで動かしてなんぼなものなので、iPhone/iPad用にリメイクしてます。

(ソース見ながら移植も考えたんですが、思い出すのも嫌になるくらい汚いコーディングをしていたのでイチから書き直してます。。。いやーおはずかしい)

卒研のときのがこれで

HITONEHITONE

現在製作中のはこんな感じになってます。

これから数回に渡って、HITONEの制作状況を記事にしていこうと思ってます。

今回、サイン波を出力するのにAudioQueueを使用していますのでまずはそこの話からですかね。

日誌と書きつつ毎日更新は出来ないと思いますが(だって書くことがなくなってしまう)

乞うご期待。

春にはリリースしたいな!