【Gracenote Rhythm API】世界最大級音楽ビッグデータGracenoteのAPIで楽曲をレコメンド

2014年12月2日

Pocket

gracenote_thumb

GracenoteのデータはiTunes、Spotifyなど、皆さんもお馴染みの音楽アプリやサービスで使われています。
音楽サービスを始めるならなくてはならないGracenote!!世界最大級の音楽ビッグデータを持つGracenoteのRhythm APIを使って楽曲をレコメンドしてみました!
 
またまた、ハッカソンの話なのですが、GracenoteのAPIは、MUSICIANS HACKATHONとTechCrunch Tokyo Hackathon 2014に参加した時に使わせていただいた、私たちTicaLabお気に入りのAPIです!
情報量が多いので使い道もさまざまで、今までハッカソンだけでもGracenoteを使用した面白いソフトウェアがたくさん作られています。
では、さっそく使ってみましょう。今回は、Rhythm APIを利用してみました。
 
 

APP作成

GracenoteのAPIを利用するためには、まずアカウントを作成しなくてはいけません。
さっそくアカウントを作りましょう。
GracenoteのDeveloperサイトにアクセスし、アカウントを作成して下さい。
Gracenote | Developer Portal
 
アカウント作成が完了したらAPPを作成します。
gracenote1
 
App Nameの名前を入力し、Create Appをクリックします。
gracenote2
 
APPが作成されました。
gracenote4
Client IDは後で使用します。
 
 

ユーザーIDを取得する

user.xmlというファイルをデスクトップに作成します。
user.xmlの中に下記のコードを記入して保存してください。
CLIENT IDのところは、先ほどのCLIENT ID(XXXXXXX-◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯)を入力してください。

<QUERIES>
  <QUERY CMD="REGISTER">
    <CLIENT>CLIENT ID</CLIENT>
  </QUERY>
</QUERIES> 

 
ターミナルを起動します。

//デスクトップに移動
$ cd Desktop
$ curl -d @user.xml https://cXXXXXXX.web.cddbp.net/webapi/xml/1.0/

“XXXXXXX”のところはCLIENT IDのハイフン前の7桁の数字を入れます。
すると下記のようなレスポンスが返ってきます。
 

<RESPONSES>
 <RESPONSE STATUS="OK">
   <USER>△△△△△△△△△△-■■■■■■■■■■■■■■■■■■■■■</USER>
 </RESPONSE>
</RESPONSES>

USERのタグの中に放っているユーザーIDを使用するのでメモしておいてください。
 
 

Rhythm APIで使えるムード、ジャンル、年代を調べる

今回は、Rhythm APIを使用しますのでムード、ジャンル、年代のIDが欲しいので一覧を調べます。
Rhythm APIでは曲名、アーティスト名、ジャンル、年代、ムードなどで楽曲を選曲できるAPIです。
Rhythm API | Gracenote
下記のURLを叩くと一覧情報が返ってきます。
 
ジャンル一覧を見る
”https:/cXXXXXXX.web.cddbp.net/webapi/xml/1.0/radio/fieldvalues?fieldname=RADIOGENRE&lang=jpn&client=CLIENT ID&user=USER ID”
 
gracenote3
 
ムード一覧を見る
”https:/cXXXXXXX.web.cddbp.net/webapi/xml/1.0/radio/fieldvalues?fieldname=RADIOMOOD&lang=jpn&client=CLIENT ID&user=USER ID”
 
年代一覧を見る
”https:/cXXXXXXX.web.cddbp.net/webapi/xml/1.0/radio/fieldvalues?fieldname=RADIOERA&lang=jpn&client=CLIENT ID&user=USER ID”
 
 

ジャンルで楽曲を検索

ジャンルで検索してみたいと思います。
先ほど調べたIDを使用して検索します。
とりあえずポップのジャンルを検索。

<?php
$genre_coad = 36056; //ジャンルーポップのID
$xml = "https://c634880.web.cddbp.net/webapi/xml/1.0/radio/create?genre=" . $genre_coad ."&lang=jpn&return_count=10&client=CLIENT ID&user=USER ID";//ファイルを指定
$xmlData = simplexml_load_file($xml);//xmlを読み込む

echo "<pre>";
var_dump($xmlData);
echo "</pre>";
?>

ポップのジャンルの楽曲データが10曲取得できました。
 
 

ムードで楽曲を検索

ムードで検索してみたいと思います。
センチメンタルのムードを検索。

<?php
$mood_coad = 65324; //ムードーセンチメンタルのID
$xml = "https://c634880.web.cddbp.net/webapi/xml/1.0/radio/create?mood=" . $mood_coad . "&lang=jpn&return_count=10&client=CLIENT ID&user=USER ID";//ファイルを指定
$xmlData = simplexml_load_file($xml);//xmlを読み込む

echo "<pre>";
var_dump($xmlData);
echo "</pre>";
?>

センチメンタルのムードの楽曲データが10曲取得できました。
 
 

年代で楽曲を検索

年代で検索してみたいと思います。
2010年代を検索。

<?php
$era_coad = 42877; //年代ー2010年代のID
$xml = "https://c634880.web.cddbp.net/webapi/xml/1.0/radio/create?era=" . $era_coad . "&lang=jpn&return_count=10&client=CLIENT ID&user=USER ID";//ファイルを指定
$xmlData = simplexml_load_file($xml);//xmlを読み込む

echo "<pre>";
var_dump($xmlData);
echo "</pre>";
?>

2010年代の楽曲データが10曲取得できました。
 
 

気分で楽曲レコメンドDEMO

上記の検索を使ってジャンル、ムード、年代を選んで楽曲をレコメンドしてくれるデモを作ってみました!
楽曲再生にはiTunes APIを使用しています。
 
DEMO
 
HTML

<?php
$submit_flg = false;

if($_POST['submit']){

	$submit_flg = true;

	$genre_id = htmlspecialchars($_POST['genre'],ENT_QUOTES);
	$mood_id = htmlspecialchars($_POST['mood'],ENT_QUOTES);
	$era_id = htmlspecialchars($_POST['era'],ENT_QUOTES);

	$xml = "https://c634880.web.cddbp.net/webapi/xml/1.0/radio/create?focus_popularity=1000&genre=" . $genre_id . "&mood=" . $mood_id . "&era=" . $era_id . "&lang=jpn&return_count=10&client=CLIENT ID&user=USER ID";//ファイルを指定
	$xmlData = simplexml_load_file($xml);

}

//ジャンルリスト
$xml = "https://c634880.web.cddbp.net/webapi/xml/1.0/radio/fieldvalues?fieldname=RADIOGENRE&lang=jpn&client=CLIENT ID&user=USER ID";
$genre_xmlData = simplexml_load_file($xml);

//ムードリスト
$xml = "https://c634880.web.cddbp.net/webapi/xml/1.0/radio/fieldvalues?fieldname=RADIOMOOD&lang=jpn&client=CLIENT ID&user=USER ID";
$mood_xmlData = simplexml_load_file($xml);

//年代
$xml = "https://c634880.web.cddbp.net/webapi/xml/1.0/radio/fieldvalues?fieldname=RADIOERA&lang=jpn&client=CLIENT ID&user=USER ID";
$era_xmlData = simplexml_load_file($xml);
?>

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	
	<title>Gracenote DEMO</title>

	<!-- js -->
	<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
	
</head>
<body>

<form action="" method="post">

	<div>
		ジャンル
		<select name="genre">
			<?php foreach ($genre_xmlData->RESPONSE->GENRE as $genre_list) : ?>
				<option value="<?php echo $genre_list[0]['ID']; ?>"><?php echo $genre_list[0][0]; ?></option>
			<?php endforeach; ?>
		</select>
	</div>
	
	<div>
		ムード
		<select name="mood">
			<?php foreach ($mood_xmlData->RESPONSE->MOOD as $mood_list) : ?>
				<option value="<?php echo $mood_list[0]['ID']; ?>"><?php echo $mood_list[0][0]; ?></option>
			<?php endforeach; ?>
		</select>
	</div>
	
	<div>
		年代
		<select name="era">
			<?php foreach ($era_xmlData->RESPONSE->ERA as $era_list) : ?>
				<option value="<?php echo $era_list[0]['ID']; ?>"><?php echo $era_list[0][0]; ?></option>
			<?php endforeach; ?>
		</select>
	</div>
	<input type="submit" name="submit" value="検索">

</form>

<?php if($submit_flg) : ?>

	<div class="player">
		<div class="image"></div>
		<p class="play_title"></p>
		<p class="play_artist"></p>
	</div>

	<ul>
		<?php 
		$track_no = 0;
		foreach ($xmlData->RESPONSE->ALBUM as $music) : 
			$track_no++;
		?>
			<li id="track_<?php echo $track_no; ?>">
				<p class="title"><?php echo $music->TRACK->TITLE; ?></p>
				<p class="artist"><?php echo $music->ARTIST; ?></p>
			</li>
		<?php endforeach; ?>
	</ul>
<?php endif; ?>
</body>
</html>

focus_popularity=1000としているのですが、曲のポピュラー度を制御しています、。
数値が大きくなるほどポピュラー度が高くなります。
 
JS

var track_count = 1;

var artist_name = $('#track_1').children('.artist').html();
var music_title = $('#track_1').children('.title').html();

// 検索する
search({
  term: artist_name + ' ' + music_title,
  limit: 1,
  entity: 'song',
  country: 'JP',
});

//iTunes APIから楽曲を取得する
function search(options) {

  var params = {
    lang: 'ja_jp',
    entry: 'music',
    media: 'music',
    country: 'JP',
  };

  if (options && options.term) {
    params.term = options.term;
  }

  if (options && options.limit) {
    params.limit = options.limit;
  }

  $.ajax({
    url: 'https://itunes.apple.com/search',
    method: 'GET',
    data: params,
    dataType: 'jsonp',

    success: function(json) {
      showData(json, options);
    },

    error: function() {
      console.log('itunes api search error. ', arguments);
    },
  });
};

//取得した楽曲を表示
var music_url = "";
var TARGET;
var showData = function(json) {

	if(json.results.length == 0){

		track_count++;

		artist_name = $('#track_' + track_count).children('.artist').html();
		music_title = $('#track_' + track_count).children('.title').html();
        	
		// 検索する
		search({
		term: artist_name[data_key] + ' ' + music_title[data_key],
		limit: 1,
		entity: 'song',
		country: 'JP',
		});

	 }else{
  
	    for (var i = 0, len = json.results.length; i < len; i++) {

	      var result = json.results[i];

	      music_url = result.previewUrl;

	      var html = '<audio id="sound" src="' + result.previewUrl + '" controls />';
	      $('.player').children('audio').remove();
	      $('.player').append(html);
	      var html = '<img src="' + result.artworkUrl100 + '">';
	      $('.player').children('.image').empty().append(html);

	      $('.player').children('.play_artist').html(artist_name);
	      $('.player').children('.play_title').html(music_title);

	      TARGET = document.getElementById('sound');

	      play();

	      track_count++;
	    }

	}

}

function play(){
    TARGET.play();
    timeupdate();
}

function timeupdate(){
    TARGET.play();
    TARGET.addEventListener("timeupdate", function() {
  
        if(TARGET.currentTime == TARGET.duration){

        	artist_name = $('#track_' + track_count).children('.artist').html();
			music_title = $('#track_' + track_count).children('.title').html();
        	// 検索する
			search({
			  term: artist_name + ' ' + music_title,
			  limit: 1,
			  entity: 'song',
			  country: 'JP',
			});
        }

    }, true);
}

 
 
 

他にもざまざまな方法で楽曲をレコメンドできるので、いろいろ試してみてください。
自分専用に好みの検索のかけ方をプログラミングして楽曲レコメンドアプリを作ってもいいかもしれません!
http://www.gracenote.com/?language=ja

続きを読む

【Spotify WEB API】SpotifyのWEB APIを使って楽曲を取得し再生する

2014年12月1日

Pocket

spotify_thamb

海外では大人気の音楽ストリーミングサービス『Spotify』
日本上陸も目前!?のはずなので、いち早くSpotifyのAPIの使い方を解説したいと思います!
Spotify WEB APIを利用して検索をかけたり、プレイヤーを埋め込んだりしてみました。
 
先日、
MUSICIANS HACKATHONに参加したのですが、参加者は期間限定でSpotifyのプレミアム会員になれるのです!
これは使わなくては損だということで、ハッカソンではSpotifyとGracenoteのAPIを利用してサービスを作りました!!
今回のハッカソンで私はGracenote使用部分を作成していたので、Spotifyの部分は担当していないのですが、勉強のためにSpotifyも個人的に実験してみました。
 
 
Spotify Web API – Spotify Developer
 
 
 

アプリ作成

まず、Spotifyのログインします。
Spotify DeveloperのMy Applicationsのページでアプリを作成します。
アプリ作成
 
“CREATE AN APP”をクリックします。
spotify1
アプリが作成されました。
Application NameとApplication Descriptionを入力し、”CREATE”をクリックします。
spotify2
 
Redirect URIsを設定します。
spotify3
見えないように伏せていますが、Client IDとClient Secretが表示されているはずです。
Client IDとClient Secretはあとで使います。
 
 

情報取得

アプリの作成が終わったので、次に使用ファイルをダウンロードします。
Spotify DeveloperサイトのWeb API -> Code Exampleページでさまざまなサンプルコードが見れます。
今回は、spotify-web-api-phpを利用しますので、下の方にあるjwilsson/spotify-web-api-phpをクリックし、spotify-web-api-phpのzipファイルをダウンロードします。
https://github.com/jwilsson/spotify-web-api-php
 
spotify4
 
ダウロードしたファイルを解凍し中にあるsrcフォルダを任意の場所に置きます。
私は、spotifyをいうファルダを作成しその中にsrcフォルダを入れましたので、それで解説していきます。
 
spotifyフォルダの中にdemo.phpというファイルを作り、下記のコードを書きます

<?php
require 'src/SpotifyWebAPI.php';
require 'src/Request.php';
require 'src/Session.php';
require 'src/SpotifyWebAPIException.php';

$session = new Session(
'SPOTIFY_CLIENT_ID', //APPのCLIENT_IDを入れる
'SPOTIFY_CLIENT_SECRET', //APPのCLIENT_SECRETを入れる
'SPOTIFY_REDIRECT_URI' //APPのRedirect URIsを入れる
);
$api = new SpotifyWebAPI();

if (isset($_GET['code'])) {
    $session->requestToken($_GET['code']);
    $api->setAccessToken($session->getAccessToken());

    print_r($api->me());
} else {
    header('Location: ' . $session->getAuthorizeUrl(array(
        'scope' => array('user-read-email', 'user-library-modify')
    )));
}
?>

 
実行するとログイン画面が表示されます。
spotify6
 
ログインするとログインしたアカウントのユーザー情報が取得でき、表示されます。
ログインすると他のユーザーのプレイリストを見れたり、ログインした人のプレイリストにトラックを追加したり、さまざまなことができるようになります。
 
 

プレイリスト作成デモ

ユーザー『pixiesofficial』のプレイリストを一つ取得して、トラックを表示させるデモを作ってみました。
Spotifyのアカウントお持ちの方はログインすると見れます。
 
DEMO
 
spotify7
 
コード

<?php
require 'src/SpotifyWebAPI.php';
require 'src/Request.php';
require 'src/Session.php';
require 'src/SpotifyWebAPIException.php';

$session = new Session('SPOTIFY_CLIENT_ID', 'SPOTIFY_CLIENT_SECRET', 'SPOTIFY_REDIRECT_URI');
$api = new SpotifyWebAPI();

if (isset($_GET['code'])) {
    $session->requestToken($_GET['code']);
    $api->setAccessToken($session->getAccessToken());

    //pixiesofficialというユーザー名でプレイリストを一つ取得
    $playlists = $api->getUserPlaylists('pixiesofficial', array(
        'limit' => 1
    ));
    //取得したプレイリストのIDを変数へ代入
    $playlist_id = $playlists->items[0]->id;

    //pixiesofficialというユーザー名での$playlist_idのトラックを取得
    $tracks = $api->getUserPlaylistTracks('pixiesofficial', $playlist_id);

} else {
    header('Location: ' . $session->getAuthorizeUrl(array(
        'scope' => array('user-read-email', 'user-library-modify')
    )));
}

?>


<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
</head>
<body>

	<?php foreach ($tracks->items as $track) : ?>
	       <!-- Spotify埋め込み -->
		<iframe src="https://embed.spotify.com/?uri=spotify:track:<?php echo $track->track->id; ?>" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>

	<? endforeach; ?>

</body>
</html>

 
 

楽曲を検索デモ

会員じゃない人がログインしないでも見れる検索方法もあります。
楽曲を検索してヒットしたトラックのプレイヤーを作成します。
 
DEMO
 
 
コード

<?php
require 'src/SpotifyWebAPI.php';
require 'src/Request.php';
require 'src/Session.php';
require 'src/SpotifyWebAPIException.php';

$submit_flg = false;

if($_POST['submit']){

	$submit_flg = true;

	$artist = htmlspecialchars($_POST['artist'],ENT_QUOTES);
	$title = htmlspecialchars($_POST['title'],ENT_QUOTES);

	$api = new SpotifyWebAPI();

	//キーワードの含まれるトラックを検索
	$tracks = $api->search($artist . '  ' . $title, 'track',array(
    'limit' => 1
));

	//トラックのIDを変数へ代入
	$track_id = $tracks->tracks->items[0]->id;

}


?>

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
</head>
<body>

<form action="" method="post">
	アーティスト<input type="input" name="artist"><br>
	曲名<input type="input" name="title"><br>
	<input type="submit" name="submit" value="検索">
</form>

<?php if($submit_flg) : ?>
	       
		<iframe src="https://embed.spotify.com/?uri=spotify:track:<?php echo $track_id; ?>" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>

<?php endif; ?>

</body>
</html>

 
 
Spotifyは、まだ日本に入ってきてないサービスですのす。プレミアム会員になるには対応している国のクレジット情報が必要ですので、現状日本ではまだしばらく全てのAPIは利用できない状態です。

続きを読む

【Web Audio API入門】音楽プレイヤー作成 第3弾

2014年9月19日

Pocket

PLANTILLA_FREEPIK

今回は、音楽データを視覚化します。
SoundCloudなど、音楽サイトなんかでよく見かけるアレを作ります。
これを作るとグッとプレイヤー感が上がりますよ。

波形を描画

波形を描画するには、canvasを使います。
なので、まずはhtmlにcanvasタグを記述しましょう。
HTML

<body>
    <p class="botton" onClick="play()">PLAY</p>
    <p class="botton" onClick="stop()">STOP</p>
    <p>Volume</p>
    <input id="volume" type="range" value="50" onChange="volumeChange()">
</body>
<canvas width="650" height="200"></canvas>

 
波形のデータを得るにはgetChannelDataメソッドを使います。
 
JavaScript

xml.onload = function() {
    if (xml.status === 200) {
        //引数を受け取る
        var arrayBuffer = xml.response;
        if (arrayBuffer instanceof ArrayBuffer) {
            var successCallback = function(audioBuffer) {
                //AudioBufferインスタンスを変数へ格納
                buffer = audioBuffer;

                var channelLs = new Float32Array(audioBuffer.length);

                //オーディオデータのチャンネル数が0以上のとき
		if (audioBuffer.numberOfChannels > 0) {
		    //getChannelDataメソッドで波形データ取得
		    channelLs.set(audioBuffer.getChannelData(0));
		}

                //10ミリ秒
                var n10msec = Math.floor(10 * Math.pow(10, -3) * context.sampleRate);

                //canvas
                var canvas = document.querySelector('canvas');
                var canvasContext = canvas.getContext('2d');
                //canvasをクリアにする
                canvasContext.clearRect(0, 0, canvas.width, canvas.height);

                //channelLsの長さだけループ
                for (var i = 0, len = channelLs.length; i < len; i++) {
                    //10ミリ秒ごとに描画
                    if((i % n10msec) === 0){
                        var x = (i / len) * canvas.width;
                        var y = ((1 - channelLs[i]) / 2) * canvas.height;
                        if(i === 0){
                            //canvasの描画初期位置
                            canvasContext.moveTo(x, y);
                        }else{
                            canvasContext.lineTo(x, y);
                        }
                    }
                }
                canvasContext.stroke();
            };

            var errorCallback = function() {
                window.alert('読み込みに失敗しました');
            };
 
            //ArrayBufferデコードする
            context.decodeAudioData(arrayBuffer, successCallback, errorCallback);
 
        }
    }
};

getChannelDataでチャンネルデータを配列で取得します。
その配列の数だけループさせ、10ミリ秒単位のところで、canvasを描画していきます。
1ミリ秒にすればさらに細かい波形になっていきます。
配列に格納されている数値(−1〜1)がY軸になります。
canvasの高さを1として考えます。
Y軸は下へ伸びるので、この波形では真ん中を0にしたいので、1からチャンネルの数値を引いて、
さらに波形は上下に動くので、canvasの高さが1なので割る2をします。
 
こんな感じの波形が描かれています。
スクリーンショット 2014-09-03 16.43.55
 
 

グリッド描画

次は、波形のグリッドを描いていきます。

xml.onload = function() {

    //〜〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜〜

    //曲の秒数
    soundtime = Math.floor(audioBuffer.length / context.sampleRate);

    //1秒あたりのX軸へ動く数値
    xRate = canvas.width / soundtime;
    for(var i = 0; i < soundtime; i++){
	var x = xRate * i;
	if (i === 0) {
	    canvasContext.moveTo(x, canvas.height);
	} else {
	    if( i % 10 === 0 ){
		//10秒毎にグリッドを描画
		    canvasContext.fillRect(x, 0, 0.5, canvas.height);
	    }
        }
    }
    canvasContext.stroke();

    //〜〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜〜
}

audioBuffer.lengthで曲の長さを取得できます。
でもそのままだと、値が違うので秒数にわかりやすく秒数にします。
そのためにはsampleRateでaudioBuffer.lengthを割ります。
sampleRateはオーディオの1秒あたりのサンプルフレーム数です。
あとは、秒数分ループさせてグリッドを入れたい秒数で描画していきます。
 
グリッドを足しました。
スクリーンショット 2014-09-03 16.43.29
 
 
 

DEMO

最後にデザインをちょっと入れて自作音楽プレイヤーの完成です。
 
DEMO
 
スクリーンショット 2014-09-03 16.50.57
 
HTML

<!DOCTYPE html>
<html>
<head>
    <!--jQueryを使用する-->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
<div class="contents">
    <div class="audio_contents">
	<p id="playBotton" class="botton play" onClick="play()">PLAY</p>
	<p class="botton" onClick="stop()">STOP</p>
	<input id="volume" type="range" value="50" onChange="volumeChange()">
    </div>
    <canvas width="650" height="200"></canvas>
</div>
</body>
</html>

 
Javascript

window.AudioContext = window.AudioContext || window.webkitAudioContext || mozAudioContext; 
try {
    var context = new AudioContext();
} catch (error) {
    alert('このブラウザは未対応です');
}

 
var xml = new XMLHttpRequest();
//読み込むデータのURLを書く
xml.open('GET', '音楽ファイル', true);
xml.responseType = 'arraybuffer';
xml.onload = function() {
    if (xml.status === 200) {
        //引数を受け取る
        var arrayBuffer = xml.response;
        if (arrayBuffer instanceof ArrayBuffer) {
            var successCallback = function(audioBuffer) {
                //AudioBufferインスタンスを変数へ格納
                buffer = audioBuffer;

                var channelLs = new Float32Array(audioBuffer.length);

		//オーディオデータのチャンネル数が0以上のとき
		if (audioBuffer.numberOfChannels > 0) {
		    //getChannelDataメソッドで波形データ取得
                    channelLs.set(audioBuffer.getChannelData(0));
		}

		//10ミリ秒
		var n10msec = Math.floor(10 * Math.pow(10, -3) * context.sampleRate);

		var canvas = document.querySelector('canvas');
		var canvasContext = canvas.getContext('2d');
		//canvasをクリアにする
		canvasContext.clearRect(0, 0, canvas.width, canvas.height);

		//描画色設定
		canvasContext.strokeStyle='#50EAFF';
		//channelLsの長さだけループ
		for (var i = 0, len = channelLs.length; i < len; i++) {
		    //10ミリ秒ごとに描画
	            if ((i % n10msec) === 0) {
		        var x = (i / len) * canvas.width;
			var y = ((1 - channelLs[i]) / 2) * (canvas.height - 20) + 20;
			if (i === 0) {
			    //canvasの描画初期位置
			    canvasContext.moveTo(x, y);
			} else {
			    canvasContext.lineTo(x, y);
			}
                    }
		}
		//描画
		canvasContext.stroke();

		//曲の秒数
		soundtime = Math.floor(audioBuffer.length / context.sampleRate);

		//目盛り表示欄
		canvasContext.fillStyle = '#6e6e6e';
		canvasContext.fillRect(0, 0, canvas.width, 20);

		//1秒あたりのX軸へ動く数値
		xRate = canvas.width / soundtime;
		canvasContext.fillStyle = '#eee';
		for(var i = 0; i < soundtime; i++){
		    var x = xRate * i;
	            if (i === 0) {
			canvasContext.moveTo(x, canvas.height);
	       	    } else {
			if( i % 10 === 0 ){
                            //10秒毎にグリッドを描画
			    canvasContext.fillRect(x, 10, 0.5, canvas.height - 10);
			    canvasContext.fillText(i, x-7, 10);
			}else if(i % 2 === 0 ){
			    //2秒毎に目盛りを描画
       			    canvasContext.fillRect(x, 15, 0.3, 5);
			}
		    }
		}
		canvasContext.stroke();

            };
            var errorCallback = function() {
                window.alert('読み込みに失敗しました');
            };
 
            //ArrayBufferデコードする
            context.decodeAudioData(arrayBuffer, successCallback, errorCallback);
 
        }
    }
};
xml.send(null);


//始めからスタートのフラグをたてる
var first_flg = true;   

function play(){

    if($('#playBotton').hasClass('pause')){

        pause();

    }else if($('#playBotton').hasClass('play')){

        //AudioBufferSourceNodeを作成する
        source = context.createBufferSource();
        //bufferプロパティにAudioBufferインスタンスを設定
        source.buffer = buffer;
        //ループ
        source.loop = false; 
        //AudioBufferSourceNodeインスタンスをdestinationプロパティに接続
        source.connect(context.destination);

        //GainNodeを作成する
        gainNode = context.createGain();
        //sourceをGainNodeへ接続する
        source.connect(gainNode);
        //GainNodeをAudioDestinationNodeに接続
        gainNode.connect(context.destination);
        gainNode.gain.value = 4;

        source.start = source.start || source.noteOn;
        source.stop  = source.stop  || source.noteOff;

        //始めからの再生の場合
        if(first_flg){
    	    //スタート時間を変数startTimeに格納
    	    startTime = context.currentTime;
    	    replayTime = startTime;
    	    //停止されている時間を初期は0にしておく
    	    pausingTime = 0;
    	    first_flg = false;
        }else{
    	    //再スタート時間を変数replayTimeに格納
	    replayTime = context.currentTime;
	    //再スタートの時間からpauseした時間を引いて、停止されている時間の合計に足していく
	    pausingTime += replayTime - pauseTime;
        }

        //replayTimeからstartTimeとpausingTime引いた時間が曲のスタート時間
        var playTime = replayTime - startTime - pausingTime;

        //再生
        source.start(0,playTime);

        //クラスとテキスト変更
        $('.play').removeClass('play').addClass('pause').html('PAUSE');
    }
}

 
function pause() {	
    //止めた時間を変数pauseTimeに格納
    pauseTime = context.currentTime;
    source.stop(0);

    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}


function stop(){
    source.stop();
    first_flg = true;
    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}


function volumeChange(){
    //range属性のvalue取得
    var value = document.getElementById( "volume" ).value;
    //gainNodeの値に変更
    var volume = ( value / 10 ) - 1;

    //gainNodeに代入
    gainNode.gain.value = volume;
} 

 
CSS

.contents{
	width: 1000px;
	margin: 50px;
}
.audio_contents{
	border-radius: 5px 0 0 5px / 5px 0 0 5px;
	background-color: #ccc;
	float: left;
	height: 150px;
	padding: 25px;
	text-align: center;
	width: 300px;
}
.title{
	font-size: 16px;
	color: #4e4e4e;
}
.botton{
	border-radius: 5px;
	background-color: #4e4e4e;
	cursor: pointer;
	color: #eee;
	font-size: 13px;
	float: left;
	height: 45px;
	line-height: 50px;
	margin: 25px 25px 0;
	text-align: center;
	width: 100px;
}
#volume{
	margin-top: 40px; 
	width: 250px;
}
canvas{
	border-radius: 0 5px 5px 0 / 0 5px 5px 0;
	background-color: #4e4e4e;
}

シンプルではありますが、これを応用していけばかなり充実したプレイヤーが作れそうですね。
入門編は3回で終わりましたが、またいつかWeb Audio API中級編を書きたいと思います。
 
 
 
参考:WEB SOUNDER – Web Audio API 解説 -
 
 
 
【Web Audio API入門】音楽プレイヤー作成 第1弾
【Web Audio API入門】音楽プレイヤー作成 第2弾

続きを読む

【Web Audio API入門】音楽プレイヤー作成 第2弾

2014年9月15日

Pocket

aud0002-009 のコピー

音楽プレイヤー作成 第2弾です!
今回は、一時停止、音量調整機能を実装します。
 

音量調節

inputの属性rangeを使用してボリュームを調節するつまみを作ります。
rangeのValueは0から100までです。真ん中の50に初期値を設定します。
rangeが変更されたらvolumeChange()のファンクションが呼び出されます。
 
HTML

<body>
    <p class="botton" onClick="play()">PLAY</p>
    <p class="botton" onClick="stop()">STOP</p>
    <p>Volume</p>
    <input id="volume" type="range" value="50" onChange="volumeChange()">
</body>

 
音量を調整するにはGainNodeを使用します。
gainNodeのValue属性に音量の値を設定することによって音量を設定できます。
 
JavaScript

function play(){
     //〜〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜〜

     //GainNodeを作成する
     gainNode = context.createGain();

     //sourceをGainNodeへ接続する
          source.connect(gainNode);

     //GainNodeをAudioDestinationNodeに接続
     gainNode.connect(context.destination);

     //音量を表記
     gainNode.gain.value = 3.0;

     //〜〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜〜
}

function volumeChange(){
    //range属性のvalue取得
    var value = document.getElementById( "volume" ).value;
    //gainNodeの値に変更
    var volume = ( value / 10 ) - 1;

    //gainNodeに代入
    gainNode.gain.value = volume;
} 

range属性からvalueを取得し、gainNodeのvalueに代入します。
rangeのvalueをそのまま代入すると音がでかすぎるので、valueの値を10分の1にします。
gainNodeのvalueは-1で音がなくなるのでrangeが0のとき、gainNodeが-1になるようにvalueから-1をしています。
 
 

一時停止

再生をストップしたら、AudioBufferSourceNodeが削除されるので、次に再生を押しても始めからのスタートになってしまいます。
一時停止ができないプレイヤーは使い勝手が悪いので、一時停止機能を作っていきます。
 
実はstart()関数には、スタートする時間と、曲のどの位置からスタートするかを入れれるのです。
start(スタート時間,曲のスタートする位置の時間)と表記します。
とは言うものの、その時間は自分で計算しなくてはなりません。
 
少し複雑なコードになってきました。
 
HTML

<body>
    <p id="playBotton" class="botton play" onClick="play()">PLAY</p>
    <p class="botton" onClick="stop()">STOP</p>
    <p>Volume</p>
    <input id="volume" type="range" value="50" onChange="volumeChange()">
</body>

 
JavaScript

//始めからスタートのフラグをたてる
var first_flg = true;

function play(){

    if($('#playBotton').hasClass('pause')){

        pause();

    }else if($('#playBotton').hasClass('play')){

         //〜〜〜〜〜〜〜省略〜〜〜〜〜〜〜〜〜

         //始めからの再生の場合
        if(first_flg){
    	    //スタート時間を変数startTimeに格納
    	    startTime = context.currentTime;
    	    replayTime = startTime;
    	    //停止されている時間を初期は0にしておく
    	    pausingTime = 0;
    	    first_flg = false;
        }else{
    	    //再スタート時間を変数replayTimeに格納
    	    replayTime = context.currentTime;
    	    //再スタートの時間からpauseした時間を引いて、停止されている時間の合計に足していく
    	    pausingTime += replayTime - pauseTime;
        }

        //replayTimeからstartTimeとpausingTime引いた時間が曲のスタート時間
        var playTime = replayTime - startTime - pausingTime;

        //再生
        source.start(0,playTime);

        //クラスとテキスト変更
        $('.play').removeClass('play').addClass('pause').html('PAUSE');
    }
} 

function pause() {	
    //止めた時間を変数pauseTimeに格納
    pauseTime = context.currentTime;
    source.stop(0);

    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}

function stop(){
    source.stop();
    //初期値に戻す
    first_flg = true;
    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}

ここで重要なのがcontext.currentTime属性です。
context.currentTimeはcontextが作成された時点からの時間を取得します。
なので、再生ボタンを押した時間ではありません。
これがややこしいのですが、この時間をもとにスタートした時間やストップした時間を変数などに格納し、足したり引いたりして目的の数値を計算します。
再生ボタンにidをふり、play()が呼び出されたとき、id=”playBotton”がplayのクラスを持っていたら再生をpauseのクラスを持っていたら一時停止するように分岐しています。
 
 
 

DEMO

下記は今回の機能を追加したソースです。
 
DEMO
 
 
HTML

<!DOCTYPE html>
<html>
<head>
    <!--jQueryを使用する-->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
    <p id="playBotton" class="botton play" onClick="play()">PLAY</p>
    <p class="botton" onClick="stop()">STOP</p>
    <p>Volume</p>
    <input id="volume" type="range" value="50" onChange="volumeChange()">
</body>
</html>

 
JavaScript

window.AudioContext = window.AudioContext || window.webkitAudioContext || mozAudioContext; 
try {
    var context = new AudioContext();
} catch (error) {
    alert('このブラウザは未対応です');
}

 
var xml = new XMLHttpRequest();
//読み込むデータのURLを書く
xml.open('GET', '音楽ファイル', true);
xml.responseType = 'arraybuffer';
xml.onload = function() {
    if (xml.status === 200) {
        //引数を受け取る
        var arrayBuffer = xml.response;
        if (arrayBuffer instanceof ArrayBuffer) {
            var successCallback = function(audioBuffer) {
                //AudioBufferインスタンスを変数へ格納
                buffer = audioBuffer;
            };
            var errorCallback = function() {
                window.alert('読み込みに失敗しました');
            };
 
            //ArrayBufferデコードする
            context.decodeAudioData(arrayBuffer, successCallback, errorCallback);
 
        }
    }
};
xml.send(null);


//始めからスタートのフラグをたてる
var first_flg = true;   

function play(){

    if($('#playBotton').hasClass('pause')){

        pause();

    }else if($('#playBotton').hasClass('play')){

        //AudioBufferSourceNodeを作成する
        source = context.createBufferSource();
        //bufferプロパティにAudioBufferインスタンスを設定
        source.buffer = buffer;
        //ループ
        source.loop = false; 
        //AudioBufferSourceNodeインスタンスをdestinationプロパティに接続
        source.connect(context.destination);

        //GainNodeを作成する
        gainNode = context.createGain();
        //sourceをGainNodeへ接続する
        source.connect(gainNode);
        //GainNodeをAudioDestinationNodeに接続
        gainNode.connect(context.destination);
        gainNode.gain.value = 4;

        source.start = source.start || source.noteOn;
        source.stop  = source.stop  || source.noteOff;

        //始めからの再生の場合
        if(first_flg){
    	    //スタート時間を変数startTimeに格納
    	    startTime = context.currentTime;
    	    replayTime = startTime;
    	    //停止されている時間を初期は0にしておく
    	    pausingTime = 0;
    	    first_flg = false;
        }else{
    	    //再スタート時間を変数replayTimeに格納
	    replayTime = context.currentTime;
	    //再スタートの時間からpauseした時間を引いて、停止されている時間の合計に足していく
	    pausingTime += replayTime - pauseTime;
        }

        //replayTimeからstartTimeとpausingTime引いた時間が曲のスタート時間
        var playTime = replayTime - startTime - pausingTime;

        //再生
        source.start(0,playTime);

        //クラスとテキスト変更
        $('.play').removeClass('play').addClass('pause').html('PAUSE');
    }
}

 
function pause() {	
    //止めた時間を変数pauseTimeに格納
    pauseTime = context.currentTime;
    source.stop(0);

    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}


function stop(){
    source.stop();
    first_flg = true;
    //クラスとテキスト変更
    $('.pause').removeClass('pause').addClass('play').html('PLAY');
}


function volumeChange(){
    //range属性のvalue取得
    var value = document.getElementById( "volume" ).value;
    //gainNodeの値に変更
    var volume = ( value / 10 ) - 1;

    //gainNodeに代入
    gainNode.gain.value = volume;
} 

 
 
 
今回はコードの量の割には機能がしょぼい感じがしますが、とりあえずオーディオになってきましたね。
次回は、音楽データの視覚化についてリポートします。
 
 
 
【Web Audio API入門】音楽プレイヤー作成 第1弾
【Web Audio API入門】音楽プレイヤー作成 第3弾

続きを読む

【Web Audio API入門】音楽プレイヤー作成 第1弾

2014年9月2日

Pocket

picjumbo.com_HNCK0644 のコピー

色々な機能を盛り込める今あついWeb Audio APIを使って音楽プレイヤーを自作してみましょう!
Web Audio API入門編は三回に分けて、少しづつ作っていこうと思います。
HTML5から<audio>を使えるので、ただ音楽を再生するならそれを使えば一番簡単なのですが、Web Audio APIではエフェクトをかけたり音楽データを視覚化したり、高度な機能を実装できます。
 
 
今回はとりあえず再生するところまでやってみます。
 
 

AudioContextを作成する

AudioContextは構成ブロックであるAudioNodeの集合やそれらの接続を表すインターフェースでオーディオが入力から出力までの流れを定義します。
まずはAudioContextを作成します。

window.AudioContext = window.AudioContext || window.webkitAudioContext || mozAudioContext; 
	try {
	    var context = new AudioContext();
	} catch (error) {
	    alert('このブラウザは未対応です');
	}

作成に成功したら変数contextにAudioContextを代入しています。
作成に失敗したらアラートを出しています。
 

サウンドをロードする

音楽ファイルをWeb Audio APIへロードするには、XMLHttpRequestを使います。

var xml = new XMLHttpRequest();
//読み込むデータのURLを書く
xml.open('GET', '音楽ファイル', true);
xml.responseType = 'arraybuffer';
xml.onload = function() {
    if (xml.status === 200) {
        //引数を受け取る
        var arrayBuffer = xml.response;
        if (arrayBuffer instanceof ArrayBuffer) {
            var successCallback = function(audioBuffer) {
                //AudioBufferインスタンスを変数へ格納
                buffer = audioBuffer;
            };
            var errorCallback = function() {
                window.alert('読み込みに失敗しました');
            };

            //ArrayBufferデコードする
            context.decodeAudioData(arrayBuffer, successCallback, errorCallback);

        }
    }
};
xml.send(null);

AudioBufferSourceNodeを作成する

//AudioBufferSourceNodeを作成する
source = context.createBufferSource();

//bufferプロパティにAudioBufferインスタンスを設定
source.buffer = buffer;

//ループをオフにする
source.loop = false; 

//AudioBufferSourceNodeインスタンスをAudioDestinationNodeに接続
source.connect(context.destination);

AudioDestinationNode(destination)は音の出口です。
ソースを作成したらAudioDestinationNodeにつないで音が出力できるようにします。
※AudioBufferSourceNodeは使い捨てとなっているので、一度曲をストップするともう一度AudioBufferSourceNodeを作成しなくてはいけないです。
 

サウンドを再生する

//スイッチを入れる
source.start = source.start || source.noteOn;
source.stop  = source.stop  || source.noteOff;

//再生する
source.start(0);

停止するには下記のように表記します。

//停止する
source.stop(0);

 
 
 

DEMO

これらを一連の流れで書いたのが下記のソースです
 
DEMO
 

HTML

<!DOCTYPE html>
<html>
<body>
    <p class="botton" onClick="play()">PLAY</p>
    <p class="botton" onClick="stop()">STOP</p>
</body>
</html>

JavaScript

window.AudioContext = window.AudioContext || window.webkitAudioContext || mozAudioContext; 
try {
    var context = new AudioContext();
} catch (error) {
    alert('このブラウザは未対応です');
}

var xml = new XMLHttpRequest();
//読み込むデータのURLを書く
xml.open('GET', '音楽ファイル', true);
xml.responseType = 'arraybuffer';
xml.onload = function() {
    if (xml.status === 200) {
        //引数を受け取る
        var arrayBuffer = xml.response;
        if (arrayBuffer instanceof ArrayBuffer) {
            var successCallback = function(audioBuffer) {
                //AudioBufferインスタンスを変数へ格納
                buffer = audioBuffer;
            };
            var errorCallback = function() {
                window.alert('読み込みに失敗しました');
            };

            //ArrayBufferデコードする
            context.decodeAudioData(arrayBuffer, successCallback, errorCallback);

        }
    }
};
xml.send(null);

function play(){

    //AudioBufferSourceNodeを作成する
    source = context.createBufferSource();

    //bufferプロパティにAudioBufferインスタンスを設定
    source.buffer = buffer;

    //ループをオフにする
    source.loop = false; 

    //AudioBufferSourceNodeインスタンスをAudioDestinationNodeに接続
    source.connect(context.destination);

    source.start = source.start || source.noteOn;
    source.stop  = source.stop  || source.noteOff;

    //再生
    source.start(0);
}

function stop(){
    source.stop(0);
}

 
 
 
ざっくり再生までの流れをリポートしました。
次回は、一時停止や音量などの機能を付けていきます。
 
 
 
【Web Audio API入門】音楽プレイヤー作成 第2弾
【Web Audio API入門】音楽プレイヤー作成 第3弾

続きを読む

このサイトについて


『意識低い系女と高い系男の一年戦争』はクリエイティブ会社エアゼの代表2人が運営するブログです。エアゼは、アプリ・Web・IoT・インタラクティブコンテンツのデザイン・開発を手がけています。

エアゼ ホームページ