iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
音楽関連アプリケーションも興味がある分野だ。アプリケーション開発の為に調べたことを記事にしてみた。
調と調号の関係を図にしてみた。
ハ長調 C C#D D#E F F#G G#A A#B C C#D D#E F F#G G#A A#B C
□■□■□□■□■□■□□■□■□□■□■□■□□
全 全 半全 全 全 半全 全 半全 全 全 半全
ト長調 #→ #→
全 全 全 半全 全 半全 全 全 半全 全 半全
↑主音 ↑主音
ニ長調 #→ #→ #→ #→
半全 全 半全 全 全 半全 全 半全 全 全
↑主音 ↑主音
嬰(シャープ)や変(フラット)で変化できる音は決まっていて、これをやるというのは、全音と半音がずれるという事で、長調の場合、全全半全全全半とう並びがずれるという理解で良さそうだ。
『Core Animation for Max OS X and the iPhone』の『6.4 Compositing Filters』について説明する。
サンプルコードのFilteredViewは、アウトレットのスペルが間違っている。なので、スペル間違いを我慢して、FilteredView.mのメソッド名を変更するか、FilteredView.hのアウトレットをただしいスペルに変更し、MainMenu.nibのアウトレットの繋がりを張り直す必要がある。ちなみに、著者は後者を選択した。
合成フィルタ (Compositing Filters)は、異なる画像を合成するフィルターで、書籍ではブレンドモードフィルタ (Blend Mode Filters)と呼ばれる、重ねた画像を描画するフィルタのサンプルを説明している。
フィルタの定義は以下のとおり。
- (void) applyFilter
{
CIFilter *filter = [CIFilter filterWithName:@"CIColorBurnBlendMode"
keysAndValues:nil];
[[controls animator] setCompositingFilter:filter];
}
灰色で描画しているビューで、
- (void)drawRect:(NSRect)rect
{
[[NSColor lightGrayColor] set];
NSRectFill(rect);
}
子ビューに対してフィルタを適用すると
- (IBAction)addFilter:(id)sender
{
if (nil == [controls compositingFilter]) {
[self applyFilter];
}
}
子ビューが灰色になるということのようだ。
楽器の練習用にiOSのiPod Libraryに格納されている曲をスロー再生するアプリケーションが欲しくなり自作する事にした。
はるか昔、放送局向けの録音再生アプリケーションを製作した事があって、その時は、再生速度を上げる場合、音声データを間引いた事があったのだが、最新のCoreAudioのAVFoundationでは、自由に再生速度が変更できるようになっているようで、せっかくなので、それを利用しない手はない。
iOSのオーディオ関連のフレームワークは多数あり、かつ、変化も激しく、そして、似た名前の物があるので、一つ一つ、確認しながら作業を進める事にする。
いきなり、主要な機能の曲の再生に取りかかりたいのが人情だが、アプリケーションとしては、曲の選択のUIも重量な機能なので、どんな事が出来るのか、Appleのサンプルコードで確認する事にする。
このサンプルコードから、曲のリストを表示できるようにしてみた。
曲の一覧を取得し、それ表題を配列に格納する。
- (void)viewDidLoad
{
[super viewDidLoad];
self.songsList = [[NSMutableArray alloc] init];
self.musicPlayerController = [MPMusicPlayerController iPodMusicPlayer];
MPMediaQuery *songsQuery = [MPMediaQuery songsQuery];
NSArray *mediaItems = [songsQuery items];
for (MPMediaItem *mediaItem in mediaItems) {
NSURL *URL = (NSURL*)[mediaItem valueForProperty:MPMediaItemPropertyAssetURL];
if (URL) {
NSString *title = (NSString*)[mediaItem valueForProperty:MPMediaItemPropertyTitle];
[self.songsList addObject:title];
}
}
}
配列に格納した情報をテーブルに表示する。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.songsList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"SongsCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *title = [self.songsList objectAtIndex:indexPath.row];
cell.textLabel.text = title;
return cell;
}
一覧が表示できた。
本日は、調査途中のグダグダな内容となってしまった。申し訳ない。とりあえずの動作確認の報告とさせていただきたい。
前回の続き。得られたURLからAVPlayerのインスタンスを生成する。
NSURL *url = [self.dict objectForKey:@"URL"];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:url];
self.player = [AVPlayer playerWithPlayerItem:playerItem];
それのplayメソッドを読んだあげれば再生を開始する。
[self.player play];
AVPlayerでは、playメソッドはrateプロパティを1.0に設定するという意味だ。なので、playメソッドを呼ばず、rateプロパティに値を設定すれば再生する。
例えば、0.5を設定すると、1/2の速度で再生する。
self.player.rate = 0.5;
いちおう、これで、耳コピ用の再生機能が実現できる事が分かる。
アプリケーションとして完成させる為、あまり深く調べなかった事について、調査してみる。
曲の閲覧は、Musicアプリケーションを真似る事にした。画面下部のタブバーにプレイリストとアーティスト、曲、アルバムのボタンが並んでいて、それを選択すると対応したテーブルが表示される。
これは、iPodライブラリから曲情報を抽出する際に、対応したフィルタをかけて事になると予想されるが、MPMediaQueryクラスには、目的にあったメソッドが用意されている。
項目 | メソッド |
---|---|
プレイリスト | playlistsQuery |
アーティスト | artistsQuery |
曲 | songsQuery |
アルバム | albumsQuery |
アーティストの一覧を取得する場合は以下のとおり。
MPMediaQuery *artistsQuery = [MPMediaQuery artistsQuery];
NSArray *artistsArray = [artistsQuery collections];
for (MPMediaItemCollection *mediaItemCollection in artistsArray) {
MPMediaItem *mediaItem = [mediaItemCollection representativeItem];
NSURL *title = (NSURL*)[mediaItem valueForProperty:MPMediaItemPropertyArtist];
NSLog(@"mediaItem:%@", title);
}
曲の一覧を取得する場合は以下のとおり。
MPMediaQuery *songsQuery = [MPMediaQuery songsQuery];
NSArray *mediaItems = [songsQuery items];
for (MPMediaItem *mediaItem in mediaItems) {
NSString *title = (NSString*)[mediaItem valueForProperty:MPMediaItemPropertyTitle];
NSLog(@"mediaItem:%@", title);
}
アルバムの一覧を取得する場合は以下のとおり。
MPMediaQuery *albumsQuery = [MPMediaQuery albumsQuery];
NSArray *albumsArray = [albumsQuery collections];
for (MPMediaItemCollection *mediaItemCollection in albumsArray) {
MPMediaItem *mediaItem = [mediaItemCollection representativeItem];
NSURL *title = (NSURL*)[mediaItem valueForProperty:MPMediaItemPropertyAlbumTitle];
NSLog(@"mediaItem:%@", title);
}
ただし、プレイリストの一覧の取得方法がよく分からなかった。以下だと駄目みたい。
MPMediaQuery *playlistsQuery = [MPMediaQuery playlistsQuery];
NSArray *playlistsArray = [playlistsQuery collections];
for (MPMediaItemCollection *mediaItemCollection in playlistsArray) {
MPMediaItem *mediaItem = [mediaItemCollection representativeItem];
NSURL *title = (NSURL*)[mediaItem valueForProperty:MPMediaItemPropertyTitle];
NSLog(@"mediaItem:%@", title);
}
これが結果。
2013-04-25 23:50:33.531 AudioPlayer[21637:907] mediaItem:やくしまるえつこ みんなのクリスマスセッション - Dec 25, 2012
2013-04-25 23:50:33.543 AudioPlayer[21637:907] mediaItem:Age Of Consent
2013-04-25 23:50:33.548 AudioPlayer[21637:907] mediaItem:A Child's Christmas in Wales
2013-04-25 23:50:33.554 AudioPlayer[21637:907] mediaItem:Istanbul
2013-04-25 23:50:33.560 AudioPlayer[21637:907] mediaItem:Question Everything
2013-04-25 23:50:33.576 AudioPlayer[21637:907] mediaItem:Out of Control
2013-04-25 23:50:33.582 AudioPlayer[21637:907] mediaItem:サウンドストリート・アーカイブス - Mar 28, 2009
プロパティとしてMPMediaPlaylistPropertyNameを使い方法を紹介している方がいたが、上手くいかなかった。何故だ王。
サンプルコードをみると、この処理は時間がかかるので、GCDやブロックを使って、非同期に行っていた。
まだ、試作レベルだが個人利用の範囲では、十分、耳コピアプリケーションとして利用できるので活用しているのだが、スクリーンがロックされると、再生が止まるという課題があったので、改善してみた。
まだ、試作という事で、詳細画面のViewControllerでの対応としたが、AVAudioSessionクラスを使って、再生機能を利用するプロパティを設定した。
- (void)viewDidLoad
{
[super viewDidLoad];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
}
そして、プロパティリストAudioPlayer-Info.plistにバックグラウンドに回っても、再生を続ける設定をした。