店舗やクラブなどで気になる曲が流れていたらShazamなどの音楽識別アプリを使い曲名を探すことがあると思います。
アニソンの場合、曲名よりも何のアニメで使用された曲なのかが重要であることがあります。
そこで、音楽識別サービスAPIを使って曲名を取り出し、曲名を元にネット上のデータベースサイトから使われているアニメを割り出す、ということをやってみます。
音楽識別にはGracenoteのAPIを使います。
Gracenoteは音楽識別技術や音楽のメタデータを提供するサービスで、iTunesやSpotifyにも使われているそうです。
今回はGracenoteの音楽識別技術を使うためのアプリ開発用SDKであるGNSDKを使います。
Gracenoteユーザ登録とSDKダウンロード
GNSDKを使うためにはユーザ登録とアプリ登録が必要なので、下記ページからユーザ登録を行います。
https://developer.gracenote.com/user/register
ユーザ登録後ログインしたら、MyAppsページの「Add a new app」でアプリ登録を行います。
アプリを登録すると、「Client ID」「Client Tag」「License String」が表示されるので、これを保存しておきます。
次にGracenoteのサイトからGNSDKをダウンロードします。
GNSDK
https://developer.gracenote.com/gnsdk
今回はiOS版SDK、SDKのバージョンは1.3.1.5172。
他にAndroid版、Windows/Mac/Linux版もあります。
ダウンロードしたファイルを解凍すると、以下のようなディレクトリになっています。
- /docs
- HTMLマニュアル
- /mmid
- サンプルコード
- /sample_music
- サンプルMP3ファイル
サンプルコードを実行
mmid/のサンプルコードをビルドしてみます。
まずはGracenoteMusicId.xcodeprojをXcodeで開きます。
次にアプリ登録時に取得したLicense Stringをlicense.txtに入力して保存します。
また、同様にClient ID、Client Tagの情報を下記ファイルに入力します。
※Objective-CとSwiftのどちらでビルドするかでファイルが違います。
Objective-C
MusicIdObjectiveC/MusicidObjectiveC-Prefix.pch
#define CLIENTID @"" #define CLIENTIDTAG @""
Swift
MusicIdSwift/GnViewControllerSwift.swift
let CLIENT_ID = "" let CLIENT_TAG = ""
そして、ビルドする言語に合わせて以下のように変更してビルドします。
Objective-C
storyboardのViewControllerをGnViewControllerに変更
Swift
BuildTargetをGracenoteMusicIdSwiftへ変更
ビルドが完了するとこのようなアプリが立ち上がります。
「ID Now」ボタンを押すと音楽識別が開始されます。
音楽識別コード
このサンプルアプリを改造してもいいのですが、GNSDKの情報があまりネット上に無いため、単純な機能のみのコードを書きました。
https://github.com/tobetchi/anisong_gracenote
GNSDKの使い方は付属のHTMLマニュアルに書いてあるのですが、内容が更新されてなかったり記載漏れがあったりします。
今回のコードはHTMLマニュアルを参考にしつつ、詳細はサンプルコードを元にしています。
下記に要点を記載していきます。
Xcodeプロジェクト設定
サンプルコードからGnSDKObjC.frameworkをコピーしてきてプロジェクトへ追加
Build Settings > Linking > Other Linker Flags
へ以下を追加
- lstdc++
- ObjC
license.txt
サンプルコード時と同様にlicense.txt を追加
Client ID、Client Tagを定数などで追加
Info.plist
Info.plistへマイクアクセス許可のため以下を追加
<key>NSMicrophoneUsageDescription</key> <string>Microphone Access To Find Matches</string>
GNユーザオブジェクト初期化
Gracenoteへクエリを飛ばすために必要なGNユーザオブジェクトを作成
self.gnUserStore = [GnUserStore new]; self.gnUser = [[GnUser alloc] initWithUserStoreDelegate:self.gnUserStore clientId:CLIENTID clientTag:CLIENTIDTAG applicationVersion:@"1.0.0.0" error:&error];
GNユーザのロケールを設定
NSError *localeError = nil; self.locale = [[GnLocale alloc] initWithLocaleGroup:kLocaleGroupMusic language:kLanguageJapanese region:kRegionGlobal descriptor:kDescriptorSimplified user:self.gnUser statusEventsDelegate:nil error:&localeError]; [self.locale setGroupDefault:&localeError];
マイク設定
AVAudioSessionの設定
AVAudioSession *session = [AVAudioSession sharedInstance]; [session setPreferredSampleRate:44100 error:nil]; [session setInputGain:0.5 error:nil]; [session setActive:YES error:nil];
マイク設定はGnMicというヘルパークラスが用意されており、AVAudioSessionの設定をした上で、以下のようにします。
self.gnMic = [[GnMic alloc] initWithSampleRate:44100 bitsPerChannel:16 numberOfChannels:1]; self.internalQueue = dispatch_queue_create("gnsdk.TaskQueue", DISPATCH_QUEUE_CONCURRENT);
オーディオストリームの処理
マイクから入力されるオーディオストリームを処理するGnMusicIdStreamクラスを作成し、GnMusicIdStreamOptionsクラスでクエリのオプションを設定します。
resultSingleは最良の単一結果のみ返すかどうか、lookupDataは返すデータの設定です。
audioProcessStartメソッドを実行するとオーディオの検索と処理が開始されます。
self.gnMusicIDStream = [[GnMusicIdStream alloc] initWithUser:self.gnUser preset:kPresetMicrophone locale:self.locale musicIdStreamEventsDelegate:self error:&musicIDStreamError]; musicIDStreamError = nil; GnMusicIdStreamOptions *options = [self.gnMusicIDStream options]; [options resultSingle:YES error:&musicIDStreamError]; [options lookupData:kLookupDataSonicData enable:YES error:&musicIDStreamError]; [options lookupData:kLookupDataContent enable:YES error:&musicIDStreamError]; [options preferResultCoverart:YES error:&musicIDStreamError]; musicIDStreamError = nil; dispatch_async(self.internalQueue, ^{ self.idNowButton.enabled = NO; [self.gnMusicIDStream audioProcessStart:self.gnMic error:&musicIDStreamError]; if (musicIDStreamError) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"Error while starting Audio Process With AudioSource - %@", [musicIDStreamError localizedDescription]); }); } });
音楽識別の開始
GnMusicIDStreamのidentifyAlbumAsyncメソッドを呼び出すと識別が開始されます。
[self.gnMusicIDStream identifyAlbumAsync:&error];
識別結果からトラック情報を取得
識別された結果は下記デリゲートに渡されます。
- (void)musicIdStreamAlbumResult:(GnResponseAlbums *)result cancellableDelegate:(id <GnCancellableDelegate>)canceller;
デリゲートで渡されたGnResponseAlbumsにはトラック情報が入っており、アーティスト名や曲タイトルを取得できます。
if ([responseAlbums isKindOfClass:[GnResponseAlbums class]]) albums = [responseAlbums albums]; else albums = responseAlbums; for (GnAlbum *album in albums) { GnTrackEnumerator *tracksMatched = [album tracksMatched]; albumArtist = [[[album artist] name] display]; albumTitle = [[album title] display]; for (GnTrack *track in tracksMatched) { trackTitle = [[track title] display]; } }
曲名から使用アニメを検索
取得した曲データから何のアニメで使われた曲かを検索します。
今回、アニメと曲の対応データはAnison Generation(http://anison.info)のデータベース検索を利用しています。
WKWebViewから上記サイトへ曲名で検索リクエストを投げるというやり方です。
また、Info.plistへATSの設定を追加しておきます。
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoadsInWebContent</key> <true/> <key>NSExceptionDomains</key> <dict> <key>anison.info</key> <dict> <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> </dict>
以下は実際に動作させてる動画です。
流れている曲から使用されているアニメを検索できています。
vimeo.com
とべっち (Tobetchi)
ART Teknika佐賀スタジオマネージャ、プログラマ。WebプログラマからiOSプログラマへ転身。VJとしても活動中。