投稿

ラベル(iOSアプリ開発(音楽))が付いた投稿を表示しています

iOS10.3 で MPMusicPlayerController クラスの挙動が変わった

デバイスをiOS10.3にアップデートしたら自作の音楽再生アプリでバグが発生しました。選んだ曲と別のものが再生されるバグです。 はじめに この問題について述べる前にMPMusicPlayerControllerクラスのことを軽く書きます。 デバイスに入っている音楽を自作アプリ内で流すとき、曲のリストを取得してMPMusicPlayerControllerクラスのインスタンス(この記事ではこれをPlayerと呼ぶことにします)にセットします。その後、Playerに対して曲の再生、停止などの指令を出します。 //.h MPMusicPlayerController *iPodMusicPlayer; MPMediaQuery *albumsQuery; MPMediaItemCollection *selectedAlbumCollection; //.m iPodMusicPlayer = [MPMusicPlayerController systemMusicPlayer]; //Playerの作成 albumsQuery = [MPMediaQuery albumsQuery]; //アルバム単位で情報を取得 selectedAlbumCollection = [albumsQuery.collections objectAtIndex:6]; //6のアルバムの情報を取得 [iPodMusicPlayer setQueueWithItemCollection:selectedAlbumCollection]; //取得した6のアルバムの情報をPlayerにセット [iPodMusicPlayer play]; //再生指令 Playerの作成するときは systemMusicPlayer applicationMusicPlayer のいずれかで作成します。 ここから今回の問題についてです。 何パターンかの操作を行うことで問題の症状を細かく炙り出しました。 症状1 曲の再生を停止すると、Playerに設定した曲のリストが無効になる。(再設定が必要。) Playerに対するstop指令で失う。pause指令では失わない。 曲のリストを失ったら、次に再生する前にリストを設定し直します。新たにMPMediaQueryから曲...

AVAudioSession細かいことまとめ(late 2014)

以前も書きました「AudioSessionの細かいことまとめ」のlate 2014版を書きます。 個人的なあらすじ 以前アプリを作る際に、AudioSession(C言語)とAVAudioSession(Obj-C)のどちらを使おうかと検討したことがありました。そのときはAVAudioSession(Obj-C)の方に機能が足りない部分が多少あって、これは主流にならないのではと思い、AudioSession(C言語)の方で実装しました。しかし予想は外れ、AudioSession(C言語)の方がiOS7より非推奨となったので、今回改めてAVAudioSession(Obj-C)の方でまとめてみます。せっかくなのでSwiftの方も併記して書いてみようと思います。基本的にAVAudioSessionのクラスリファレンスを読んでまとめるだけなので詳しく知りたいことがある場合はそちらを見て下さい。 ちなみに作っているアプリは SilentBonusTrack というカセットテープアプリで、iPodのような音楽再生機能が中心となっています。私の興味の対象はその辺の音楽再生系が中心になります。 重要な項目 まずは音を扱う場合には目を通しておく必要があるAudioSession関係です。 importするもの //Swift import AVFoundation //Objective-C #import <AVFoundation/AVFoundation.h> インスタンスの取得 このインスタンスに対して音の扱いに関するいろいろなメソッドを実行出来ます。 //Swift let session: AVAudioSession = AVAudioSession.sharedInstance() //Objective-C AVAudioSession *audioSession = [AVAudioSession sharedInstance]; Swiftの方はもしvarにする必要があればvarにしてください。 カテゴリーの指定 アプリの音の扱い方法を数パターンの中から選んで指定します。 //Swift var error: NSError? session.setCategory(AVAudioSessionCategoryPlayba...

AVMIDIPlayer

iOSのAPIの中にAVMIDIPlayerというものを発見。これは音楽ファイルを再生するもので、対象フォーマットはMIDIとiMelody。iMelodyというのは着メロのような単音の音楽を扱うものらしい。所属はAVFoundationでiOS 8より追加になった。 初期化メソッドは2つ。 initWithContentsOfURL: soundBankURL: error: initWithData: soundBankURL: error: 上のメソッドでは1つ目の引数はファイルのURLを渡し、2つ目の引数でsoundBankというもののURLを渡す。2つ目のsoundBankURLだが、これは再生に使う音源の指定でSoundFont2かDLS bank(のURL)を指定する。OS Xではnilが可能だが、iOSではnilはだめ。 下のメソッドでは1つ目の引数はNSDataインスタンス(の形式にした音楽ファイル)を渡す。2つ目以降は上のと同じ。 SoundFont2は音色のデータフォーマット。世の中でよく(?)使われている。DLSも音色のデータフォーマットだがSoundFont2の方がメジャー。 再生データ(第一引数)と音色データ(第二引数)の違いがややこしいと思う。音色データにはいろいろな音色のいろいろな音程の音が含まれている。それをどのタイミングでどの音を鳴らすかを指定するのが再生データ。 再生関係メソッドは普通に play: stop prepareToPlay playの引数で再生完了時に実行する処理を渡せる プロパティは playing (再生中かどうか readOnly) duration (全体の時間 readOnly) currentPosition (現在ポジション 読み書き可能) そのほかに、MIDIらしく rate (再生速度、1.0が標準 読み書き可能) というものがある。 手持ちのMIDIファイルとダウンロードしたSoundFontで鳴らしてみたらiPad mini 2から音が出ました。まあ普通に再生出来ています。複数チャンネルにも対応しています。 しかしこうなるとiOSに初めから手頃な音源が搭載されていて欲しくなります。

iPod library access クラウド音源への対応

iOS 6よりMPMediaItemのプロパティに MPMediaItemPropertyIsCloudItem というものが追加されました。 これはデバイス内にはなく、クラウド上にある曲の場合にYES(を包んだNSNumber)が返されます。 このクラウド上にある曲というのは、私のデバイスですとiTunes Storeで購入したがデバイスには入っていない曲が該当しました。説明によるとiTunes Matchがどうこうと書いてありますが、現在日本ではiTunes Matchが使えないので確認はしていません。 (この段落の話はiOS 7)iOSに付属のミュージックアプリでは設定項目にこれを表示するかしないかを選択するところがあり、選択した場合はデバイスに入ってなくてもクラウドにあれば一覧に表示され、再生操作をするとダウンロード(ストリーミング?)されて再生します。選択しなければ表示されません。また、クラウド曲を再生した時にデバイス内にデータが残るようで、これは設定を選択しない方に切り替えても表示されます。ところが、自作アプリ内からライブラリにアクセスし、データを取得するとこの設定に関わらず全てのクラウド上の曲が得られる(得られてしまう)ようです(もしかしたらどこかで変更が出来るかもしれない)。インターネット上から取得するとどうしてもレスポンス遅延がありますので、排除したいというときはMPMediaItemPropertyIsCloudItemがYESを返すアイテムを排除する処理が必要になります。

iPod library access

iPodライブラリアクセスを使う上での注意点のメモです。 使用バージョン:iOS 5あるいはiOS 6 特徴 iPodプレーヤである曲を再生中にその曲を含むコレクションを設定しても曲は途切れることがない。 説明ではMPMusicPlayerControllerはMPMediaPlaybackデリゲートを実装している。このデリゲートの中でprepareToPlayはrequiredとなっているが対応してないようだ。 (追記2014/12)Base SDKがiOS5.0ではprepareToPlayでアラームが発生する。これはそのバージョンのMPMusicPlayerControllerがMPMediaPlaybackデリゲートを実装していないため。それより後のどこかのバージョンで実装されている模様。 使うプレーヤの選択 オーディオを再生できるのは一度に1つのミュージックプレーヤーのみです。ミュー ジックプレーヤーは、アプリケーションのメインスレッドでのみ使用できます。2種類あります。 iPodMusicPlayer-バックグラウンドで再生可(追記2014/12 iOS 8よりsystemMusicPlayerに変更) applicationMusicPlayer-バックグランドで再生不可 listenerの設定 ライブラリ更新 曲が変わった時 曲の再生状態が変わった時 ボリュームが変わった時 大量の曲を更新する時はライブラリ更新のメソッドがかなり頻繁によばれます。 iPod再生中にライブラリから曲を削除すると、現在再生中の曲と次の曲は再生されますが、その次の曲は再生されません。エラーも出ません。 停止状態からある曲を再生させた時に呼ばれる順番は 1アイテムチェンジのメソッド(このとき再生状態はstop) 2再生状態変更のメソッド(このとき再生状態はplay) の順です。 逆に再生状態(または一時停止)から停止させた時は 1再生状態変更のメソッド 2アイテムチェンジのメソッド の順。 再生状態と一時停止の変更では 再生状態変更のメソッド のみです。 デバイスで新規プレイリストを作成したときにもライブラリ更新のコールバックが呼ばれます。 Sessionの設定 セッションの設定がしてあると思います。...

iOS 7について

気になるのはC言語ベースのAudioSessionが非推奨になったこと。 AVAudioSessionを使え、とのこと。 以前、AVAudioSessionの一部分が非推奨になったために、アプリを作る際はAudioSessionのほうに統一した方がいいんじゃないかという内容を書きましたが、こんどはAVAudioSessionの方を推奨するようです。 他に気付いたもの AVSpeechSynthesizer AVSpeechUtterance しゃべらせることが出来る?

AVQueuePlayer

AVQueuePlayer AVPlayerのサブクラス。 複数のアイテム(曲)を登録しておき一度の指令でそれらを連続再生出来る。 インスタンス生成時、または生成後の初期化時に、AVPlayerItemを含んだNSArrayを渡す。 再生途中に他のアイテムの追加が出来るのがすばらしい。再生が途切れることがない。 seekToTime:という指定した場所に再生場所を移動させるメソッドがある。これはAVPlayerから継承している。このメソッドでの指令の仕方の時間は1曲目の頭からの時間ではなく、その曲の頭からの時間。つまり5曲目再生中にseekToTime:で5秒を指定すると、5曲目の5秒のところに移る。 インスタンス作成 queuePlayerWithItems: 曲追加 insertItem:afterItem: プロパティ currentItem これはAVPlayerから継承。割り込みによる停止中でもnilにはならない。 全部の曲の再生が終わるとnilになる。 AVPlayerItem インスタンス生成時、または生成後の初期化時に、NSURLかAVAssetを渡す。 AVPlayer CMTime time = CMTimeMake(1800, 600); CMTimeGetSeconds(time)

Audio Session細かいことまとめ

SessionActive化のタイミング 電話がかかってきて電話に出た時は、End Interruptionが呼ばれないそうなので、どこでSessionをActiveにするか、検討する必要がある。 割り込みのタイミング アプリをバックグラウンドにしたときに音楽を再生していない場合は割り込みが入る(イニシャライズ時に指定した関数が走る)。再生している時は入らない。「何もしていないなら切りますよ」的なニュアンスで何かの処理が走る模様。割り込み関数が実際に走るのはフォアグラウンドにしたとき。begin分とend分の2回走る。 バックグラウンド機能のON OFFやmixWithOthersのON OFFも関係あります。 AVPlayerの割り込みメソッド呼び出しについて AudioSessionのイニシャライズ時に指定する割り込みメソッドは再生中で無くても呼ばれるが、AVPlayerの割り込みメソッドはplay中でないと呼ばれない。(検証不十分) AVPlayerの自動SessionActive機能について AVPlayerには割り込み完了時にSessionActiveをYESにする機能があるのだが、この機能が少し癖があるので気を付けたい。 まずはいろいろなパターンを調べた。割り込みはiOSに付属しているアラームを使った。ちなみにタイマーだと1つしか登録できないが、アラームだと複数登録できる。 パターン1:初めにアラーム設定し、アプリを起動する アラーム設定する アプリ起動 AVPlayerインスタンス作成 セッション初期化 セッションアクティブ化 アラーム発生 アラーム処理(OKをタップ) 次のアラーム発生で割り込みメソッドが呼ばれない → 自動でアクティブ化されない パターン2:アプリを起動してから一旦バックグラウンドにして、アラーム設定し、再びアプリを起動する アプリ起動 AVPlayerインスタンス作成 セッション初期化 セッションアクティブ化 アラーム設定する アプリ起動 AVPlayerインスタンス作成(viewDidLoadに入れていたので再び処理が走った) セッション初期化(viewDidLoadに入れていたので再び処理が走った) セッションアクティブ化(viewDidLoadに入れ...

AudioUnit細かいことまとめ

AudioUnitに出てくる細かいことについて void * int *と同じようにポインタですが、int *との違いはポインタの指す先です。int *の場合はintですが、void *の場合はどのような型でもよいです。使用するときには状況に応じてキャストすることもある。 関数ポインタ 関数ポインタは検索すると説明しているページがたくさん出てきます。関数へのポインタなのですが、AudioUnitでは関数の引数として関数を渡すときに使います。 関数ポインタの中でもtypedefを使った宣言の理解が難しい。 普通のtypedefは typedef int abc; で「abcをintとして扱う」「abcにintと同じ役割を与える」というような意味になります。「何を」と「何として」がスペースを挟んで書かれています。 関数ポインタのtypedefは typedef int (*abcd)(int a,int b); というようになります。 これに対し、同じように「何を」と「何として」をスペースを挟んで解釈しようとすると混乱します。 関数ポインタの場合は 「何を」abcd 「何として」int (*)(int a,int b) 引数をintで2つ持つ、戻り値がintの関数のポインタ という変則的な読み方をします。 AudioUnitSampleTypeとAudioSampleType iOS5.xだと実機でもシミュレータでもIntのほうが定義されています。 /*! @typedef AudioSampleType @abstract The canonical audio sample type used by the various CoreAudio APIs */ #if !CA_PREFER_FIXED_POINT typedef Float32 AudioSampleType; typedef Float32 AudioUnitSampleType; #else typedef SInt16 AudioSampleType; typedef SInt32 AudioUnitSampleType; #define kAudioUnitS...

iPhone Core Audioプログラミング

iPhone Core Audioプログラミングという本の感想。 iOSで音を出すやりかたは4パターンほどあります。それぞれ、作りやすさ、機能、理解しやすさなどが違います。全部を網羅しようとすると結構大変なのですが日本語で書かれたiPhone Core Audioプログラミングという良書がありますので助かります。 最初本屋でぱらぱらと見た感じではかなり難しそうな印象があります。特にC言語による部分はObjective-Cに慣れた目には完全に別言語に見えます。 しかし、何度も読んでいくうちにだんだんとCore Audioのパターンが見えてきます。その山を超えるとわりと楽に読めるようになります。 chapter 1 System Sound Service 効果音用のAPIの説明。初めのchapterにしては結構いろんなことが詰め込んである。読むペースをつかむ前に次から次へと話題が変わるので注意。コールバックというのが理解できない場合はchapter 2 AVFoundationを検討するのもいいと思います。 chapter 2 AVFoundation 音を出すAPIの中でこのAPIが一番わかりやすい。ARCならreleaseも必要なし。 chapter 3 項目が多いがひとつひとつは単純な知識。 オーディオフォーマットの情報とパケットの情報を混乱しないようにする。 iOSアプリからプログラムを始めた人は、取得したいデータのアドレスを関数の引数として渡すやり方がイメージしにくいかもしれない。このやり方はCoreAudioではすごくよく使う。 chapter 4 AudioSessionの基礎 ここはどんなアプリを作る場合でも目を通しておいたほうがよいでしょう。 ユーザーの使用状況に応じて音の出力の挙動を変化させること方法が書いてあります。 内容は主に2つ、カテゴリ(アプリは音の扱いをどうするか、マナーモード?に従うとか)の設定と割り込み(電話受信など)への対応。 この割り込みへの対応に2つのやり方が紹介されている。一つは直接AudioSessionを扱うやり方、もうひとつはAVAudioPlayerの機能を使うやり方。 AVAudioPlayerはサウンドの扱いを簡単にするために割と後から出来たもの。ソースから想像するにAV...