別にスマホに限った技術ではないが、これを使えば、音を生成する部分を抽象的なモデルにして切り出すことができ、これを操作するためのライブラリである libpd を介して、いろんなプラットフォーム上で統一的に操作できるらしい。Android でも iOS でもいけるようだ。
というわけで、試しに Pure Dataを iPhoneで動かしてみる。
お題は音叉とした。iPhoneを膝に当てたら鳴るようにしたら、いかにも本物の音叉っぽいが、単なるボタン押下に留めておいた。実験なので簡単なコードにしたいし、iPhone 買ったばかりで、どの程度の衝撃に耐えられるか分からなくて怖いしな。
■ Pure Data のインストール
PureDataのダウンロードサイトにいくと、Vanilla版ってのがある。そこから mac版をダウンロードして普通にインストール。音を生成する仕組みをモデル化した「パッチ(patch)」を作成したり、それを鳴らしてみたりできる、Pure Data の開発ツール。
■ fork.pdの作成
・Command+Nで新しい”patch”を作成する。この patch単位で作成した"*.pd"ファイルを、後でプログラムからリソースとして読み込んで操作することになる。
- 左上の[○]は、メニューの Put > Bangから生成する。さらに、この要素上のコンテキストメニューから Propertiesを開いて、Receive Symbolに
fork
と入力しておく。この文字列でプログラムからレシーバを識別して操作する。 - その下の [1 10, 0 3000 2000]は、10msかけて0から1になって、その後、2000ms待ってから、3000msかけて0に戻るというエンベロープの指定で、Put > Messageで生成。
- [vline~]は Put > Objectで生成。 ②の指定に基づいたエンベロープを生成。
- [osc~ 440]は Put > Object。 440Hzの正弦波発振器。
- [*~]も Put > Object。 ④の正弦波を③のエンベロープに整形するオブジェクト。
- [dac~]も Put > Object。 デジタル信号をアナログにして、最終的に音を出力するオブジェクト。
この時点で、①のBangか、②のMessageをクリックすれば、音叉っぽい感じで音が鳴るのを確認できる。
■ libpdのダウンロード
$ git clone git://github.com/libpd/pd-for-ios.git $ cd pd-for-ios $ git submodule init $ git submodule updatepd-for-ios下に、libpd 本体とサンプルプロジェクトが入ってる。
■ プロジェクトの作成
以下の指定でプロジェクトを作成する。
- Single View Applicationを選択
- Product Name: Fork
- Class Prefix: なし
- Device: iPhone
- その他、適当
■ プロジェクトの作成
- libpd/libpd.xcodeprojを、"Add Files To〜"でプロジェクトに追加する。サブプロジェクトになるので、一応、TARGETS に libpd-iosがあるのを確認しておく。
- プロジェクトの Build Phases > Target Dependencies に libpd-iosを追加。
- プロジェクトの Build Settings > Search Paths > Header Search Paths に libpd へのパスをrecursive で追加。
- プロジェクトの Build Settings > Architectures > Architectures の $(ARCHS_STANDARD)を$(ARCHS_STANDARD_32_BIT)に変更(これをやらないとリンカエラーになる)。
- General > Linked Frameworks and Libraries で、libpd-ios.a を追加
- fork.pdをインポートする. プロジェクトの Build Phases > Copy Bundle Resources で、fork.pdが含まれていることを確認しておく。
■ AppDelegate.h の編集
ヘッダのインポートと@propertyの追加
#import <UIKit/UIKit.h> #import "PdAudioController.h" @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic, readonly) PdAudioController *audioController; @end
■ AppDelegate.m の編集
@implementation の冒頭に以下を追加
@synthesize audioController = _audioController;・以下のメソッドを編集
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { _audioController = [[PdAudioController alloc] init]; if ([self.audioController configureAmbientWithSampleRate:44100 numberChannels:2 mixingEnabled:YES] != PdAudioOK) { NSLog(@"failed to initialize audio components"); } return YES; } - (void)applicationDidBecomeActive:(UIApplication *)application { self.audioController.active = YES; } - (void)applicationWillResignActive:(UIApplication *)application { self.audioController.active = NO; }
■ ViewController.mの編集
・まず、UIKit のインポートの下で、"PdBase.h"をインポートしておく。
#import "PdBase.h"
・次に fork.pd を開くコード。
※ openFile で開いた patchを後で閉じるためには、どこかで保持しておく必要があるが、ここでは持ちっぱなしにしておく。
- (void)viewDidLoad { [super viewDidLoad]; if (![PdBase openFile:@"fork.pd" path:[[NSBundle mainBundle] resourcePath]]) { NSLog(@"Failed to open patch!"); } }
次にボタンとそのイベントハンドラ
- Main.storyboard を選択して、画面の真ん中に適当にボタンを置く。Title は “A”とかにしておく。
- Assistant Editor にして、ViewController.m への Ctrl+ドラッグで Touch Down のイベントハンドラを作る。
- 中身は以下のような感じ
- (IBAction)bang:(id)sender { [PdBase sendBangToReceiver:@"fork"]; }
■ 動かしてみる
味も素っ気もない画面だが、真ん中の[A]ボタンを押せば、Aの音がポーンとなる。キャプチャ画像は iOSシミュレータだけど、実機の iPhone 5sでも問題なく鳴る。