音楽プレイヤの作成

2010. 07. 21
基礎からのiPhone SDK 改訂版』も今回の『iPodライブラリアクセス+音楽プレイヤ』が最後のお題となります。


●音楽プレイヤの概要

表題の通りMedia Playerフレームワークを使ってiPodライブラリにアクセスし、自身のアプリケーションから楽曲を再生するものです。

画面構成は下図のようなインターフェイスになっています。

553

背景は(スライドショーのBGMとしての利用を前提としていますが)ただの画像です。

画面下方にあるパネルは、再生中の曲名、アルバム名、アーティスト名をラベルで表示し、『前の曲へ戻る』『再生/一時停止』『次の曲へ進む』ボタンで再生曲を制御します。

『More』と『Back』ボタンでパネルが回転して切り替えるようになっており、裏面にはアートワークを表示します。

554


●プロジェクトの作成

Window-based Applicationテンプレートでプロジェクト名を『MusicPlayer』とします。


●nibファイルの編集


1)画像素材の準備

編集の前に使用する素材を集めます。

背景画像はBackground.png(320x480ピクセル)を使っています)

それと出版社のサイトにあるサンプルコード(iPhoneBG2/SampleCode/MusicPlayer.01 iPodControl)から素材をお借りしてきます。

bg.png制御パネルの背景画像260 x 180
bgButton.pngボタンの背景画像70 x 37
next.png『次の曲へ進む』ボタンの画像36 x 24
noimage.pngアートワーク画像が無い場合のデフォルト画像150 x 150
play.png『再生/一時停止』ボタンの画像36 x 24
prev.png『前の曲へ戻る』ボタンの画像36 x 24

※背景画像を用意するのが面倒な場合は、サンプルコードの『photo1.jpg』を使用してください。

素材画像をプロジェクトの『MusicPlayer』フォルダにコピーし、XcodeのResourcesフォルダに使用する画像を登録します。

556


2)背景画像の設定

MainWindow.xibをダブルクリックしてInterface Builderを開きます。

LibraryウィンドウからImage Viewをドラッグ&ドロップでViewウィンドウに配置し、InspectorウィンドウのAttributesタブのImageでBackground.pngまたは背景用の画像を選択します。

557


3)制御パネルの設置

ウィンドウの下方に制御パネルを設置します。

LibraryウィンドウからImage Viewをドラッグ&ドロップでViewウィンドウに配置し、InspectorウィンドウのSizeタブでX:30、Y:290、W:260、H:180に設定します。

XとYに関しては背景画像に合わせて調整してください。本書ではW:280、H:160となっていますが、ここでは素材のbg.pngのサイズに合わせてW:260、H:180としています。

558

Attributesタブの『Image View』の『Image』で制御パネルの背景画像をbg.pngにします。

続いてUIImageViewの背景画像を消去するため、『View』の『Background』で『Colors』ウィンドウでOpacityを0%にします。

559

それと『Drawing』のOpaqueのチェックを外し、透明化を有効にします。

『Clear Context Before Drawing(前の描画内容をクリアしてから再描画する)』のチェックは今回の場合どちらでも構いません。

制御パネルへの操作を受け付けられるように、『Interaction』の『User Interaction Enable(ユーザ操作を有効にする)』にチェックを入れます。

560

メインウィンドウのレイアウトはこれで完了です。

561


4)制御パネルのレイアウト

実際の制御パネルには表と裏があり、メインウィンドウ上に貼り付けるのではなく、別のビューでレイアウトを組んでプログラム上で貼り付ける手法になっています。

まずLibraryウィンドウからViewをドラッグ&ドロップでDocumentウィンドウに2つ加え、Viewの名前をクリックし、識別のため『View Main Side』と『View More Side』に変更します。

562

それぞれをダブルクリックして開き、InspectorウィンドウのSizeタブでW:260、H:180に設定します。

563

まずMain Sideのレイアウトを行います。

View Main SideのViewウィンドウに、LibraryウィンドウからLabelを3つ、Round Rect Buttonを4つドラッグ&ドロップで配置します。
(ここでの位置やサイズはおおよそで構いません)

564

作業を円滑に進めるため、先に識別名を入力します。

ラベルは、InspectorウィンドウのAttributesタブで『Label』の『Text』を上から順に『Song Name』『Album Name』『Artist Name』とします。

再生制御のボタン3つに関しては、InspectorウィンドウのAttributesタブで『Button』の『Type』を『Custom』とし、Documentウィンドウで『Custom Button』となる名前をクリックして左から順に『Custom Button (Prev)』『Custom Button (Play)』『Custom Button (Next)』とします。
(Attributesタブの『Button』の『Title』で設定するとボタンの表示に反映されてしまうので、Documentウィンドウで名前の変更をしています)

裏面にするボタンはRound Rect Buttonのまま、InspectorウィンドウのAttributesタブで『Button』の『Title』を『More』とします。

565

次に位置とサイズをInspectorウィンドウのSizeタブで下表のように設定します。

NameXYWH
Label (Song Name)51325023
Label (Album Name)53925021
Label (Artist Name)56425023
Custom Button (Prev)11997037
Custom Button (Play)95997037
Custom Button (Next)180997037
Round Rect Button (More)1801477224

続いてAttributesタブでの設定を行います。

まずビューの背景を透明化するため、DocumentウィンドウでView Main Sideを選択し、『View』の『Background』を『Clear Color』にし、『Drawing』の『Opaque』のチェックを外します。

566

ラベルは3つとも『Label』の『Layout』で『Alignment』を中央に、『View』の『Mode』を『Scale To Fill』にします。

『Label』の『Font』は、Song Nameは『Helvetica Bold, 17.0』に、Album NameとArtist Nameは『Helvetica, 14.0』に設定します。

567

568

再生制御のボタンは、『Button』の『Background』を3つとも『bgButton.png』にし、『Image』はそれぞれ左から『prev.png』『play.png』『next.png』と設定します。

569

裏面にするボタンは既に『Title』の設定も済んでいるので、そのままです。

Main Sideのレイアウトはこれで完了です。

571

続いて裏面になるMore Sideのレイアウトをします。

View Main Sideと同様にビューの背景を透明化するため、DocumentウィンドウでView More Sideを選択し、『View』の『Background』を『Clear Color』にし、『Drawing』の『Opaque』のチェックを外します。

View More SideのViewウィンドウに、LibraryウィンドウからImage Viewを1つ、Round Rect Buttonを1つドラッグ&ドロップで配置します。
(ここでの位置やサイズはおおよそで構いません)

572

InspectorウィンドウのSizeタブで、Image ViewはX:15、Y:15、W:150、H:150に、Round Rect Buttonは(表面のMoreボタンと同じ)X:180、Y:147、W:72、H:24に設定します。

続いてAttributesタブでの設定を行います。

Image Viewは『Image View』の『Image』を『noimage.png』に、『View』の『Drawing』の『Opaque』はアートワークを透明化しないのでチェックを入れたままに、『Interaction』の『User Interaction Enabled』は今回何も仕掛けをしないのですが後々のことを考えて一応チェックを入れています。

573

Round Rect Buttonは、『Button』の『Title』を『Back』にするだけです。

574

More Sideのレイアウトはこれで完了です。

575

この時点でのDocumentウィンドウの構成は下図のようになります。

576


●PanelControllerクラスの作成

Xcodeの『グループとファイル』ペインの『Classes』を右クリックして、コンテキストメニューから『追加』→『新規ファイル』を選択し、NSObjectのサブクラスとしてPanelControllerクラスを追加します。


●アウトレットとアクションの定義

生成したPanelControllerクラスのヘッダファイルPanelController.hに、アウトレットとアクションを定義します。
(太字が追加した部分)

#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h> // MediaPlayerフレームワークを使用

@interface PanelController : NSObject {
    MPMusicPlayerController *player;    // 音楽制御用プレイヤ

    // 制御パネルの表側
    IBOutlet UIView *viewMainSide;    // 表側の下地
    IBOutlet UILabel *labelSongTitle;    // 曲名表示
    IBOutlet UILabel *labelAlbumTitle;    // アルバム名表示
    IBOutlet UILabel *labelArtist;    // アーティスト名表示

    // 制御パネルの裏側
    IBOutlet UIView *viewMoreSide;    // 裏側の下地
    IBOutlet UIImageView *imageArtWork;    // アートワーク表示

    // その他
    IBOutlet UIView *viewPlace;    // 制御パネルの配置場所
}

- (IBAction)playOrPause;    // 再生と一時停止
- (IBAction)skipToNext;    // 次の曲にスキップ
- (IBAction)skipToPrevious;    // 前の曲にスキップ
- (IBAction)flipToMoreSide;    // 裏側を表示
- (IBAction)flipToMainSide;    // 表側を表示

@end

577


●フレームワークの追加

iPodライブラリを利用するためMediaPlayerフレームワークを追加します。

Xcodeの『グループとファイル』ペインの『Frameworks』を右クリックして、コンテキストメニューから『追加』→『既存のフレームワーク』を選択し、MediaPlayer.frameworkを追加します。

578


●アウトレットとアクションの接続

Xcodeでの変更を保存し、Interface Builderでアウトレットとアクションの接続を行います。

まずPanelControllerクラスのインスタンスを追加するため、LibraryウィンドウからObjectをDocumentウィンドウにドラッグ&ドロップします。

Documentウィンドウの追加したObjectを選択した状態で、InspectorウィンドウのIdentityタブを開き、『Class Identity』の『Class』を『Panel Controller』にします。

579

InspectorウィンドウのConnectionsタブを開き、アウトレットとアクションを接続します。

ボタン類のアクションは全て『Touch Up Inside』に設定します。

580


●アクションメソッドの実装

PanelController.mソースファイルにメソッドを実装します。
(太字が追加した部分)

#import "PanelController.h"

@implementation PanelController

- (void)updateView {
    // 現在再生中の曲を取得
    MPMediaItem *curItem = [player nowPlayingItem];

    // 曲情報の取得とビューへの反映(曲名/アルバム名/アーティスト名)
    labelSongTitle.text = [curItem valueForProperty:MPMediaItemPropertyTitle];
    labelAlbumTitle.text = [curItem valueForProperty:MPMediaItemPropertyAlbumTitle];
    labelArtist.text = [curItem valueForProperty:MPMediaItemPropertyArtist];

    // アートワークの取得とビューへの反映
    MPMediaItemArtwork *artWork;
    artWork = [curItem valueForProperty:MPMediaItemPropertyArtwork];
    imageArtWork.image = [artWork imageWithSize:imageArtWork.frame.size];
}

- (void)awakeFromNib {
    // プレイヤ生成
    player = [MPMusicPlayerController iPodMusicPlayer];

    // 音楽再生
    player.repeatMode = MPMusicRepeatModeAll;    // 全曲リピートに設定
    player.shuffleMode = MPMusicShuffleModeOff;    // シャッフル無しに設定
    [player play];    // 再生開始

    // 制御パネルの表側を貼り付ける
    [viewPlace addSubview:viewMainSide];

    // 現在再生中の曲の情報を画面に表示する
    [self updateView];

    // 通知センターのインスタンスを取得
    NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];

    // 再生曲が変化した時の通知先を登録
    [noteCenter addObserver:self selector:@selector(didItemChanged:) name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification object:player];

    // 通知の開始を指示
    [player beginGeneratingPlaybackNotifications];
}

// 再生/一時停止
- (IBAction)playOrPause {
    // 現在の再生状態を取得
    MPMusicPlaybackState state = player.playbackState;

    // 一時停止中なら再生
    if (state == MPMusicPlaybackStatePaused) {
        [player play];
    }
    // 再生中なら一時停止
    else if (state == MPMusicPlaybackStatePlaying) {
        [player pause];
    }
}

// 次の曲へスキップ
- (IBAction)skipToNext {
    [player skipToNextItem];
}

// 前の曲へスキップ
- (IBAction)skipToPrevious {
    // 再生位置が曲の先頭から3秒未満なら前の曲へスキップ
    if (player.currentPlaybackTime < 3.0) {
        [player skipToPreviousItem];
    }
    // 再生位置が曲の先頭から3秒以上なら曲の先頭にスキップ
    else {
        [player skipToBeginning];
    }
}

- (void)didItemChanged:(NSNotification *)aNote {
    // 通知名を取得
    NSString *noteName = [aNote name];

    // 通知が『現在再生中の曲の変化』なら画面を更新
    if ([noteName isEqualToString:MPMusicPlayerControllerNowPlayingItemDidChangeNotification]) {
        [self updateView];    // 曲情報表示を更新
    }
}

- (void)dealloc {
    // 通知の停止を指示
    [player endGeneratingPlaybackNotifications];

    // 通知センターのインスタンスを取得
    NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];

    // 通知先の登録を解除
    [noteCenter removeObserver:self];

    [super dealloc];
}

- (IBAction)flipToMoreSide {
    // アニメーションの準備
    [UIView setAnimationsEnabled:YES];
    [UIView beginAnimations:@"Flip" context:nil];
    [UIView setAnimationDuration:0.5f];

    // トランジションアニメーションの設定
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:viewPlace cache:YES];

    // ビューの貼り替え
    [viewMainSide removeFromSuperview];    // 表側の制御パネルを外す
    [viewPlace addSubview:viewMoreSide];    // 裏側の制御パネルを貼り付ける

    // アニメーション実行
    [UIView commitAnimations];
}

- (IBAction)flipToMainSide {
    // アニメーションの準備
    [UIView setAnimationsEnabled:YES];
    [UIView beginAnimations:@"Flip" context:nil];
    [UIView setAnimationDuration:0.5f];

    // トランジションアニメーションの設定
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:viewPlace cache:YES];

    // ビューの貼り替え
    [viewMoreSide removeFromSuperview];    // 裏側の制御パネルを外す
    [viewPlace addSubview:viewMainSide];    // 表側の制御パネルを貼り付ける

    // アニメーション実行
    [UIView commitAnimations];
}

@end

581

本書の説明の順序ですと、awakeFromNibメソッド内で呼び出すupdateViewメソッドの記述が後になってビルド時にエラーになりますので、updateViewメソッドはawakeFromNibメソッドの前に記述してください。


●ビルドと実行

本書内でも解説されているように、iPhone本体のiPodアプリケーションで再生曲が選択されていない場合(音楽ではなくビデオを再生した後など)では音楽が再生されず、アートワークも含めて楽曲情報も表示されません。

582

583

アートワークは楽曲にアートワークが指定されていない場合に『noimage.png』が表示されるので、楽曲が指定されていない場合は何も表示されません。

再生制御の3つのボタンも機能せず、動作が確認できるのは制御パネルを切り替える『More』と『Back』ボタンのみです。

この場合、iPodアプリケーションで一度音楽を再生してから再度MusicPlayerアプリケーションを立ち上げると、起動と同時に選択されている音楽が再生されます。



参考文献

基礎からのiOS SDK基礎からのiOS SDK
(2010/10/09)
鶴薗 賢吾、松浦 健一郎 他

商品詳細を見る






Wave SoundTouch music system IV
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
06 | 2017/07 | 08
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

Wave SoundTouch music system IV
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR