2011年7月27日水曜日

iPhoneのドックコネクタ接続シリアルケーブルのまとめ

*
概要: iPhoneのドックコネクタに接続するシリアルケーブルを紹介します。シリアル端子は、組み込み機器との接続によく使われるインタフェースですが、iPhoneにはこれまで汎用シリアルインタフェースがありませんでした。また独自の開発をスタートするには、まずMFiプログラムという壁を超える必要がありました。今回Redpark社から発売されたドックコネクタ接続のシリアルケーブルは、価格59米ドル、57.6kpbsまでのシリアル通信ができるもので、従来の障壁を崩すことができるものです。その内容を紹介します。


はじめに


iPhoneの魅力的なインタフェースと爆発的な普及数から、iPhoneと接続することで、既存装置にこれまでなかった魅力を付加することが可能になります。ですがiPhoneのドックコネクタ接続機器開発は、Apple社とMFiプログラム締結、およびドックコネクタの規格に従った接続回路設計という壁がありました。

ここでは、Redpark社[1]が発売したiPhoneドック接続の汎用シリアルケーブルの内容、アプリ開発、またカスタム装置開発の進め方をまとめます。

従来のiPhoneへの機器接続方法


従来のMFiプログラムを使わないiPhoneの外部機器接続には、1)Jail breakする、および、2)MIDIインタフェースの流用、の2方法があります。

1のJail breakはアプリケーションの実行権限を破ることで任意のアプリケーション実行を可能とするもので、これによりアプリからシリアルデバイスの操作権限が得られます。ただしアプリケーションの配布はJail breakをした端末でしかできません。

2のUSBアダプタの利用は、iPadのUSBアダプタにUSBのMIDIインタフェースを接続、もしくはiPhoneのドックコネクタMIDIインタフェースi-MX1[2]を接続して、iOSのCoreMIDIフレームワークからMIDI[3]でデータ送受信をするものです。iPadでフィジカルコンピューティングなどの実例があります[4]。この方法はMIDI規格(ビットレート31.25Kbps固定、非同期方式シリアル転送、データフォーマットが制約される)で、インターフェースが日本で容易に入手でき、かつ標準のCoreMIDフレームワークで開発できるため、手軽です。一方で、本来の使用目的である楽器制御から逸脱した使い方ですから、個人の利用を超える範囲、例えばストアでのアプリ配布等で承認されるかなどは、不明です。

汎用シリアルケーブル


ここでは、Redpark社[1]が発売したiPhoneドック接続の汎用シリアルケーブルの内容、アプリ開発、またカスタム装置開発の進め方をまとめます。

本体は、iPhone、touchおよびiPadのドックコネクタ接続で、RS-232−CのDサブ9ピンコネクタがついています。本体価格は60米ドルで、Redpark社がオンライン販売していますが、日本へは送付していません。Maker SHEDが日本向に販売しています[5]

本体および開発に必要なSDKおよびサンプルコードはロイヤリティーフリーで提供されています。これら知的財産の利用範囲は、ラインセスでプライベート利用に限定されています。ここでのプライベートとは、家や学校またはエンタープライズ(企業内部で限定したアプリケーション配布形態)を示します。AppStoreでのアプリ配布は許可されません。

アプリ開発には、Redpark社が提供するSDKを用います。SDKはメールアドレスを登録するだけでダウンロードできます。いわゆるUNIXでシリアル端子を制御する場合は/dev/ttyなどを使いますが、このSDKは独自の制御クラスを提供しています。その内容は、通常のシリアル端子制御と同じもので、フロー制御(ハード、ソフト、なし)、パリティやバイトのビット数、ビットレート(最大 57.6kpbs)が設定できます。

カスタム機器開発については、Readpark社はカスタム機器開発サポートを提供しています。このシリアルケーブルを使い、試作品のめぼしをつけてから、MFiプログラムを締結してRedpark社に開発依頼をすることで、スムースな機器開発の流れになるでしょう。

まとめ


iPhoneのドックコネクタ接続シリアルケーブルを紹介しました。現在は任意のアプリ実行手段としてJail breakが有効ですが、ネットワーク越しでiOSアップデートが可能になるiOS5以降も、この手段が有効かは不明です。公式のiOSでの開発が可能なこのシリアルケーブルの存在は、その場合には、手軽に利用できる唯一の手段となるでしょう。

またiPhone以外のAndroidやWindows Phone7との外部機器接続も求められてくると思います。AndroidではUSBに外部機器を接続するAndoroid open accessory development kit[6]が提供されています。ですが結局は、外部機器側がシリアル通信(非同期方式もしくはUSBシリアルとして見えるものでも)前提で設計されている場合がほとんどですから、最後にはシリアル通信をいかにサポートするか、になるでしょう。

2011年5月31日火曜日

iPhoneの動画編集アプリ開発での、動画の向き(Portrait/Landcape)の扱い方



概要: iOS SDKで、編集した動画を正しい方向(横向き/縦向き)でプレビュ/サムネイル画像生成/外部ファイル出力する方法を紹介します。例えば、標準のカメラアプリで撮影されたiPodライブラリにある動画ファイルは、AVPlayerクラスを使えば、その動画が撮影された(縦向き/横向き)の正しい向きで表示されます。しかし、この動画を編集すると、ソースの動画の向き情報が伝わらないので常に横向きで表示されてしまい、意図した表示となりません。ここではLayerInstructionを使い強制的に正しい向きで動画を表示するサンプルアプリを使って、この方法を紹介します。ソースコードはthe New BSDライセンスのもと、Githubで公開しています:https://github.com/reinforce-lab/ObjC_Codes/tree/master/moviePortraitLandscape 。

はじめに

この1ヶ月iPhoneの動画編集アプリ開発をしていました。iOSでの動画編集は、WWDC2010のセッション407  Editing Media with AV Foundation を見て、そのサンプルコード”AVEditDemo”を読めば、やや複雑ではあるものの難しくはありません。
しかし、動画編集ではその動画の向きの扱いは自分自身で手当てしなければなりません。iOSでは動画はAVAssetクラスのインスタンスで表現されます。AVAssetクラスは CGAffineTransform preferredTransformというアフィン変換をプロパティに持ちます。iPhoneの標準カメラアプリで撮影された動画は、その中のビデオフレームは横向き(ホームボタンが右側に来る方向)で保存されています。動画の向き情報は、縦向きか横向きか、このpreferredTransformの変換行列に設定されます。例えばホームボタンを下向きにして縦向きに動画を撮影すれば、保存された動画のpreferredTransformには時計回りに90度回転の行列が設定されます。従って、動画を編集するときは、ソースの動画の向きと同じ向きを、編集した動画にも設定しなければなりません。
iOSでの動画編集には、AVAssetクラスを継承するAVMutableCompositionクラスを使いますが、このクラスのprefferdTransformプロパティは、read-onlyで書き込めません。ですから、元動画のpreferredTransformをコピーしたくても書き込めません。それでは、このpreferredTransformプロパティが書き込めるクラスを、AVMutableCompositionクラスを継承して作ればいいかというと、それは難しいです。というのはAVMutableCompositionクラスは内部のクラスの単なるラッパークラスで、しかもインスタンスはクラスメソッドから生成するため、Objective-Cで単純にクラス継承をするだけではすまず、全てのメッセージをブリッジする仕組みを入れなければ、いけないからです。

編集動画の向きを設定する

そのため、編集動画の向きを正しい設定を、AVMutableVideoCompositionLayerInstructionクラスを使って強制的にフレームを回転させて、実現しました。まず最初にソースとなる動画の向きを判定します:(サンプルの avPlayerView.m の338行から)
  1. // AVURLAsset *asset;
  2. UIImageOrientation orientation_  = UIImageOrientationUp;
  3. BOOL  isPortrait_  = NO;
  4.  
  5.   NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
  6.   if([tracks  count] != 0) {
  7.     AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
  8.     CGAffineTransform t = videoTrack.preferredTransform;
  9.     if(t.== 0 && t.== 1.0 && t.== -1.0 && t.== 0)  {orientation_= UIImageOrientationRight; isPortrait_ = YES;}
  10.     if(t.== 0 && t.== -1.0 && t.== 1.0 && t.== 0)  {orientation_ =  UIImageOrientationLeft; isPortrait_ = YES;}
  11.     if(t.== 1.0 && t.== 0 && t.== 0 && t.== 1.0)   {orientation_ =  UIImageOrientationUp;}
  12.     if(t.== -1.0 && t.== 0 && t.== 0 && t.== -1.0) {orientation_ = UIImageOrientationDown;} }
前述したように、動画はAVURLAssetのインスタンスで表されます(1行目)。AVURLAssetの中のビデオトラックのpreferredTransformプロパティ(8行目)から、動画の向きを判定しています(9-12行目)。この行列は単純な回転行列なので係数を見るだけで判定できます。
ビデオフレームの回転は次のようにします:(avPlayerView.m 444行目から)
  1. AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
  2. AVMutableComposition *composition = [AVMutableComposition composition];
  3. AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
  4.  
  5. // get frame size. rotate the source frame rectangle if it is portrait.
  6. CGSize videoSize = videoTrack.naturalSize;
  7. if(isPortrait_) {    videoSize = CGSizeMake(videoSize.height, videoSize.width);  }
  8.  
  9.   // set frame size
  10. composition.naturalSize     = videoSize; // AVPlayerはこのサイズを見ない
  11. videoComposition.renderSize = videoSize; // AVPlayerはこのサイズを見る。
  12. videoComposition.frameDuration= CMTimeMakeWithSeconds( 1 / videoTrack.nominalFrameRate, 600);
  13.  
  14. // Trackを構築
  15. AVMutableCompositionTrack * compositionVideoTrack = [composition
  16.                addMutableTrackWithMediaType:AVMediaTypeVideo
  17.                preferredTrackID:kCMPersistentTrackID_Invalid]; 
  18.   [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
  19.                    ofTrack:videoTrack    
  20.                   atTime:kCMTimeZero error:nil];
  21.  
  22.   // レイヤを設定
  23.   AVMutableVideoCompositionLayerInstruction *layerInst;
  24.   layerInst = [AVMutableVideoCompositionLayerInstruction
  25. videoCompositionLayerInstructionWithAssetTrack:videoTrack];
  26. // ここがポイント! 変形を指定
  27.   [layerInst setTransform:videoTrack.preferredTransform atTime:kCMTimeZero];
  28.  // Layer instructionを設定
  29. AVMutableVideoCompositionInstruction *inst = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
  30. inst.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
  31. inst.layerInstructions = [NSArray arrayWithObject:layerInst];
  32. videoComposition.instructions = [NSArray arrayWithObject:inst];
  33. // プレビュ表示
  34. AVPlayerItem *playerItem_ = [[[AVPlayerItem alloc] initWithAsset:composition] autorelease];
  35. playerItem_.videoComposition = videoComposition;
  36. // AVPlayer player_
  37.  [player_ replaceCurrentItemWithPlayerItem:playerItem_];
まずAVMutableCompositionとVideoCompositionを作り(1-3行目)、サイズを設定し(5-12行目)、Compositionにソース動画のトラックを入れます(14-20行目)。そして、AVMutableVideoCompositionLayerInstructionを作り、それにソース動画のpreferredTransformの変換行列を設定します(22-23行目)。最後に編集動画をプレビュー表示に設定します(34-38)。これらのコードはiOSの標準的な動画編集ソースコードです。

サムネイル画像生成と動画ファイル出力

この方法はサムネイル画像生成と動画ファイル出力にも使えます。
AVAssetImageGeneratorクラスを使えば、複数のサムネイル画像を非同期に生成できます。私が、ソース動画のAssetのpreferredTransformがサムネイル画像に適用されることを期待して、このクラスのBOOL appliesPreferredTrackTransformをYESに設定すると、ホームボタンが右に来る横方向の動画以外は、サムネイル画像の生成に失敗しました。AVAssetImageGeneratorのドキュメントには、画像回転は90/120/360度のみ対応すると記載があるのですが、ソース動画のpreferredTransform はdx, dyの平行移動があることが、生成失敗の原因かもしれません。従って私はこのプロパティをNOに設定して、生成されたサムネイル画像に回転処理をしています。
AVAssetExportSessionクラスは、編集動画をプレビューでみたものそのままにローカルファイルに出力するクラスです。前述の方法で編集した動画をこのクラスで出力すると、動画の縦横向きをフレームに書き込んだ動画が出力されます。もしも、iPhone標準カメラアプリが撮影した動画と同じく、フレームは横向きでpreferredTransformで動画の向きを保存する一貫したやり方を通したいならば、カスタムの動画出力クラスを作り、AVAssetWriterInputクラスのtransformプロパティに適切な行列を設定することで、それを実現できます。

まとめ

編集動画の縦向き/横向きを正しく扱う方法を紹介しました。ただし、LayerInstructionを使っても、AVPlayerLayerのvideoGravityプロパティがAspectFillの場合は、プレビュー表示がおかしくなります。これはAVPlayerLayerは、レイヤサイズを求めるときに、LayerInstructionまではみておらず、そのため正しいサイズを計算できないのではないかと推測します。したがってAspectFillの表示をしたい場合は、AspectもしくはResizeの設定で、レンダーサイズと変換行列を適切な値に設定して自身で対処します。

2010年11月23日火曜日

iPhone_イヤホンジャックから電源を取る

概要:iPhoneのドックコネクタを使うにはApple社との秘密保持契約が必須です。iPhoneに外部機器を接続するインタフェースは、Jail Breakでもしない限り、イヤホン端子くらいしかありません。ここではiPhoneのイヤホン端子から電源を取る方法と、その出力電流-電圧特性を示します。イヤホン端子から正弦波を出力して、シリコンダイオードを使った倍圧整流回路[1]を通すと、開放電圧1.5 V、出力電流1 mAで1.2 Vの電圧が取れます。電圧損失が大きいのは、シリコンダイオードの大きな順方向電圧のためです。マイクロホン入力も電源として使うことができます。その開放電圧は2.7V、出力抵抗は2.3 kΩです。出力電力自体は数mWと小さいですが、動作クロック1MHzあたりの消費電流が0.3 mAの、ATMEL社のローパワーなAVRマイコンを動かすには十分です。

 iPhoneの外部機器を簡単に開発するために、ソフトウェア・モデムのプロジェクトがいくつか立ち上がっています [2]。これらのプロジェクにより、外部機器はオーディオ信号を通してiPhoneとデータ送受信をできるようになります。ここでは、外部機器の電池を省略するために、オーディオ端子から電源を供給する方法を試した結果を報告します。

音声出力から電源を取る

 iPhoneのヘッドホンジャックはL/Rの2チャンネルの出力があります。それぞれの出力インピーダンスは36 Ωで、最大出力電圧は 0.95 Vrms(2.7V peak-to-peak)です。したがって理論的には1チャネルあたり最大6mWの電力を取得できます。
Fig. 1: 測定回路.

 0.95Vrmsを整流しただけでは論理回路(1.8Vまたは3.3V)を動かすには電圧が不足しますから、Fig.1に示す倍圧整流回路[1]を使いました。ダイオードには汎用小信号シリコンダイオード1S1588を使いました。

Fig. 2: Measured output current-voltage.
 測定結果がFig.2です。入力した音声信号は周波数15kHzの正弦波です。波形発生アプリは、以前に紹介したAudioUnitのサンプルプログラム[3]を使いました。ボリュームは最大に設定しました。出力電流が0のときの出力電圧は1.5V、1mA出力したときは1.2Vでした。オーディオ信号の振幅(2.7 Vpp)に対して、1.2Vの電圧ロスがありますが、これはシリコンダイオードの準方法電圧のためです。Fig.2の結果が示すように、容量C1を4.7uFから330uFに変更しても、出力電圧は50mV程度しか上がりませんでした。これはこの電圧降下がダイオードの順方向電圧によるものだからです。もしもシリコンダイオードをショットキーバリアダイオードに置き換えたならば、(順方向電圧が0.4Vとして)出力電流1mAで電圧1.8Vが得られるでしょう。

マイク端子から電源を取る

 iPhoneの4極オーディオ端子にあるマイク端子は、コンデンサマイクを駆動するためのバイアス電圧が出ています。これの出力電流-電圧特性をFig.3に示します。開放電圧は2.7V、出力抵抗は2.3kΩです。
Fig.3 マイク端子の電流-電圧特性測定結果.

まとめ

 iPhoneのヘッドホン端子から電源の取り方、またその値について述べました。音声端子からは1.8V 1mA、マイク端子からは1.8V 300uAが得られます。これは低消費電力のマイコンを動かすには十分な量です。もしも、より高い電圧(だいたい4.5V程度まで)が必要ならば、L/Rのそれぞれの音声端子から逆相信号を出力して、それを整流回路に与えることで実現できます。

参考

  1. Wikipedia: Voltage doubler, http://en.wikipedia.org/wiki/Voltage_doubler
  2. サウンドモデムプロジェクト, http://www.reinforce-lab.com/projects/iphone-software-modem
  3. MonoTouch Audio Unit sample code, http://blog.reinforce-lab.com/2010/08/monotouchaudiounitsamplecodes.html



2010年8月2日月曜日

MonoTouch_AudioUnit_サンプルコード

概要: MonoTouchでAudioUnitを使った3つのサンプルコード、サイン波生成、AIFFオーディオファイル再生そしてマイクロフォンのモニタリング、を紹介します。iPhoneで利用出来る他のオーディオフレームワーク(Audio Queue ServiceとOpenAL)と比較して、AudioUnitを使うことで、楽器アプリや音が動作トリガになるアプリケーションに都合が良い、リアルタイムの波形操作と最小の出力遅延時間(~ 3ミリ秒)が実現できますサンプルコードはGithubにMITラインセスで公開しています [1]

 iPhoneのサウンドモデム開発で、当初はスピーカーとマイクロフォンにアクセスするのにAudioQueueを使うことにしました。しかし、AudioQueueの出力遅延時間は最小でも23ミリ秒でした。ロボットの制御にはこの遅延時間は、少々大きすぎます。したがって約3ミリ秒の出力遅延時間が得られるAudioUnitを試すことにしました。

MonoTouch で AudioUnit を使う

 AudioUnit はAudioToolboxフレームワークに含まれるC言語の関数群です。したがってMonoTouchから使うためにはアンマネージコードの呼び出しが必要になります [2]. この操作は、一般のC#からのC言語ライブラリの呼び出しと同じで、その詳細は(サンプルコードの プロジェクト MonoTouch.AudioUnit にある) ソースコードを参照してください。クラス名などは、AudioUnitの関数および構造体と1対1対応で作成しています。

AudioUnit で任意の波形を出力する

 AudioUnitでの任意波形出力は、基本はAudio Queue Service の解説記事 (http://jp.blog.reinforce-lab.com/2010/05/monotouchaudioqueue.html) で述べたものと同じです。

 手順は:

  1. 出力する Audio Unit (Remote IO) を設定する、
  2. レンダリング処理のイベントハンドラを設定する、
  3. ハンドラ内でバッファに波形データを書き込む。


 AudioUnit (Remote IO unit) の生成手順などはAppleの開発者ドキュメントなどで詳しく述べられています。まず, audio unit (Remote IO unit) を以下のコードで作成します:

   1:  void prepareAudioUnit()
   2:  {
   3:      // Creating AudioComponentDescription instance of RemoteIO Audio Unit
   4:      AudioComponentDescription cd = new AudioComponentDescription()
   5:      {
   6:          componentType    = AudioComponentDescription.AudioComponentType.kAudioUnitType_Output,
   7:          componentSubType = AudioComponentDescription.AudioComponentSubType.kAudioUnitSubType_RemoteIO,
   8:          componentManufacturer = AudioComponentDescription.AudioComponentManufacturerType.kAudioUnitManufacturer_Apple,
   9:          componentFlags = 0,
  10:          componentFlagsMask = 0
  11:      };
  12:      
  13:      // Getting AudioComponent from the description
  14:      _component = AudioComponent.FindComponent(cd);
  15:     
  16:      // Getting Audiounit
  17:      _audioUnit = AudioUnit.CreateInstance(_component);
  18:   
  19:      // setting AudioStreamBasicDescription
  20:      int AudioUnitSampleTypeSize;
  21:      if (MonoTouch.ObjCRuntime.Runtime.Arch == MonoTouch.ObjCRuntime.Arch.SIMULATOR)
  22:      {
  23:          AudioUnitSampleTypeSize = sizeof(float);
  24:      }
  25:      else
  26:      {
  27:          AudioUnitSampleTypeSize = sizeof(int);
  28:      }
  29:      AudioStreamBasicDescription audioFormat = new AudioStreamBasicDescription()
  30:      {
  31:          SampleRate = _sampleRate,
  32:          Format = AudioFormatType.LinearPCM,
  33:          //kAudioFormatFlagsAudioUnitCanonical = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved | (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift),
  34:          FormatFlags = (AudioFormatFlags)((int)AudioFormatFlags.IsSignedInteger | (int)AudioFormatFlags.IsPacked | (int)AudioFormatFlags.IsNonInterleaved | (int)(kAudioUnitSampleFractionBits << (int)AudioFormatFlags.LinearPCMSampleFractionShift)),
  35:          ChannelsPerFrame = 2,
  36:          BytesPerPacket = AudioUnitSampleTypeSize,
  37:          BytesPerFrame = AudioUnitSampleTypeSize,
  38:          FramesPerPacket = 1,
  39:          BitsPerChannel = 8 * AudioUnitSampleTypeSize,
  40:          Reserved = 0
  41:      };
  42:      _audioUnit.SetAudioFormat(audioFormat, AudioUnit.AudioUnitScopeType.kAudioUnitScope_Input, 0);            
  43:   
  44:      // setting callback
  45:      _audioUnit.RenderCallback += new EventHandler<AudioUnitEventArgs>(callback);
  46:  }


 AudioUnitの1サンプルを表すAudio unit sample type はシミュレータ (32-bit 浮動小数点) とデバイス(32-bit 整数)で異なります。その違いはコード (line #21-28) で吸収します。Audio Unitがバッファを必要とするたびに、設定された (line #45) レンダリングのイベントハンドラが、以下のように呼び出されます:


   1:  void callback(object sender, AudioUnitEventArgs args)
   2:  { 
   3:      // Generating sin waveform
   4:      double dphai = 440 * 2.0 * Math.PI / _sampleRate;
   5:      
   6:      // Getting a pointer to a buffer to be filled
   7:      IntPtr outL = args.Data.mBuffers[0].mData;            
   8:      IntPtr outR = args.Data.mBuffers[1].mData;
   9:      
  10:      // filling sin waveform.
  11:      // AudioUnitSampleType is different between a simulator (float32) and a real device (int32).
  12:      if (MonoTouch.ObjCRuntime.Runtime.Arch == MonoTouch.ObjCRuntime.Arch.SIMULATOR)
  13:      {
  14:          unsafe
  15:          {
  16:              var outLPtr = (float *) outL.ToPointer();
  17:              var outRPtr = (float *) outR.ToPointer();
  18:              for (int i = 0; i < args.NumberFrames; i++)
  19:              {                        
  20:                  float sample = (float)Math.Sin(_phase) / 2048;
  21:                  *outLPtr++ = sample;
  22:                  *outRPtr++ = sample;
  23:                  _phase += dphai;
  24:              }
  25:          }
  26:      }
  27:      else
  28:      {
  29:          unsafe 
  30:          {
  31:              var outLPtr = (int*)outL.ToPointer();
  32:              var outRPtr = (int*)outR.ToPointer();
  33:              for (int i = 0; i < args.NumberFrames; i++)
  34:              {                        
  35:                  int sample = (int)(Math.Sin(_phase) * int.MaxValue / 128); // signal waveform format is fixed-point (8.24)
  36:                  *outLPtr++ = sample;
  37:                  *outRPtr++ = sample;
  38:                  _phase += dphai;
  39:              }
  40:          }
  41:      }
  42:   
  43:      _phase %= 2 * Math.PI;
  44:  }


 AudioBufferは32-bit浮動小数点または32-bit整数の単なる配列です。したがってunsafeブロック内で直接配列に波形データを書き込みます。配列長はAudioSessionを使って設定でき、デフォルトで 512、最小 128まで設定できます。配列長を短くするほど出力遅延時間は短くなりますが、よりCPUパワーを消費します。


その他のサンプル

 ExtAudioFileを使った任意フォーマットの音楽ファイル再生およびマイクロフォンからの音入力とその録音処理のサンプルがあるのですが、もう面倒なので以下略です。ソースコードを参照ください。

References

  1. Sample codes, http://github.com/reinforce-lab/MonoTouch.AudioUnit
  2. Interoperating with unmanaged code, http://msdn.microsoft.com/en-us/library/sd10k43k.aspx