DJの選曲にもレコメンドがあると楽じゃないか?それTraktorでもできませんかね!? Vol.2

おはようございます

KAI-YOUエンジニアのコウベ(@cabbagekobe)です。

というわけで前回の記事の続きになります。 kai-you-tech.hatenablog.com

そして改めて10月29日にPOP TECH PARTYというイベントが開かれます。

POP TECH PARTYとは

kai-you.net

今まで来たことある人も、行けなかったようという方も、第4回ポプテクへ、ぜひ1周年のお祝いにきてください! 参加DJは随時おしらせしまーす!

参加表明をFacebookからしていただけると超嬉しい!! https://www.facebook.com/poptechparty/


という感じのイベントです。私もやるぞ!

楽しいイベントになること間違いなし!みんな来てください!!

ということで続き…

前回はとりあえず楽曲とDjay上のMatchタブに出てきた楽曲を比べてみましたがデータが少なすぎてわからないというのが正直な気持ち。

ということでやっていきたいことはデータの収集です。

最終的にやりたいことの筋道としてはこのように考えています。

  1. Traktorにてデータを収集したいトラックのプレイリストを作る
  2. 上記プレイリストのトラックがSpotifyにあるのか検索する
  3. Spotifyに会った場合はAudio Featuresに楽曲IDを投げる
  4. 手に入ったデータをDBに入れる
  5. TraktorでのDJ中に上記のDBにアクセスして情報を取得する

1. プレイリスト作成

というわけで適当にプレイリストを作りました。前回も起点にしたIZ*ONEの日本デビューシングル、好きと言わせたいを含んだプレイリストを適当に作りました。

f:id:KAI-YOU:20191018212831p:plain

作ったプレイリストをExportしていく。

f:id:KAI-YOU:20191021173245p:plain
f:id:KAI-YOU:20191021173434p:plain

Copy Tracks To Destinationのチェックは外しましょうね。

2. NMLファイルの読み込み

Traktorのプレイリストなどに使われるnmlファイルを読み込みましょう。

github.com

こちらを使います。

Gemfileなり、gem installなりで上記をインストールして、こんな感じのコードを書きましょう。

require 'traktor/nml'
require 'pp'

Traktor::NML.parse File.open("path/to/playlist.nml")
playlist = Traktor::NML.load "path/to/playlist.nml"

pp playlist

はい。下記の出力が得られましたね。(出力データ整理済み)

#<Traktor::NML::Playlist:0x00007fb43b8aa740 @tracks= [
  #<Traktor::NML::Track:0x00007fb43b896268
    @album={:title=>"好きと言わせたい (Type B)", :track=>"1"},
    @artist="IZ*ONE",
    @bpm=132.001007,
    @cues=[
      #<Traktor::NML::Cue:0x00007fb43b8975a0 @hotcue=0, @length=0.0, @name="1.16.32. - 32.", @repeats=-1, @start=633.25578, @type=3>,
      #<Traktor::NML::Cue:0x00007fb43b896b78 @hotcue=4, @length=0.0, @name="n.n.", @repeats=-1, @start=1087.797767, @type=4>,
      #<Traktor::NML::Cue:0x00007fb43b8962b8 @hotcue=3, @length=0.0, @name="n.n.", @repeats=-1, @start=88359.859206, @type=0>
    ],
    @genre="J-POP",
    @key="9d",
    @label="",
    @musical_key="8",
    @playtime=239.0,
    @primarykey="Macintosh HD/:Users/:cabbagekobe/:Music/:iTunes/:iTunes Media/:Music/:IZ_ONE/:好きと言わせたい (Type B)/:01 好きと言わせたい.mp3",
    @release_date=#<Date: 2019-01-01 ((2458485j,0s,0n),+0s,2299161j)>,
    @title="好きと言わせたい"
  >,
  #<Traktor::NML::Track:0x00007fb43b8aaa10
    @album={:title=>"ドレミソラシド [通常盤]", :track=>"1"},
    @artist="日向坂46",
    @bpm=132.991379,
    @cues=[
      #<Traktor::NML::Cue:0x00007fb43b8abd20 @hotcue=0, @length=0.0, @name="8.32. - 64. - 32", @repeats=-1, @start=7660.120709, @type=3>,
      #<Traktor::NML::Cue:0x00007fb43b8ab6e0 @hotcue=4, @length=0.0, @name="Beat Marker", @repeats=-1, @start=11269.377222, @type=4>,
      #<Traktor::NML::Cue:0x00007fb43b8ab0a0 @hotcue=2, @length=0.0, @name="n.n.", @repeats=-1, @start=92477.648756, @type=0>,
      #<Traktor::NML::Cue:0x00007fb43b8aaa60 @hotcue=3, @length=0.0, @name="n.n.", @repeats=-1, @start=124960.95737, @type=0>
    ],
    @genre="Pop",
    @key="9m",
    @label="",
    @musical_key="17",
    @playtime=305.0,
    @primarykey="Macintosh HD/:Users/:cabbagekobe/:Music/:iTunes/:iTunes Media/:Music/:日向坂46/:ドレミソラシド [通常盤]/:01 ドレミソラシド.mp3",
    @release_date=#<Date: 2019-01-01 ((2458485j,0s,0n),+0s,2299161j)>,
    @title="ドレミソラシド"
  >,
  #<Traktor::NML::Track:0x00007fb43d8b8d98
    @album={:title=>"ぐるぐるカーテン", :track=>"1"},
    @artist="乃木坂46",
    @bpm=132.0,
    @cues=[
      #<Traktor::NML::Cue:0x00007fb43d8baa08 @hotcue=0, @length=0.0, @name="8.32.", @repeats=-1, @start=423.779091, @type=3>,
      #<Traktor::NML::Cue:0x00007fb43d8b8e60 @hotcue=4, @length=0.0, @name="Beat Marker", @repeats=-1, @start=4060.142727, @type=4>
    ],
    @genre="Pop",
    @key="3d",
    @label="",
    @musical_key="2",
    @playtime=245.0,
    @primarykey="Macintosh HD/:Users/:cabbagekobe/:Music/:iTunes/:iTunes Media/:Music/:乃木坂46/:ぐるぐるカーテン/:01 ぐるぐるカーテン.mp3",
    @release_date=#<Date: 2012-01-01 ((2455928j,0s,0n),+0s,2299161j)>,
    @title="ぐるぐるカーテン"
  >,
  #<Traktor::NML::Track:0x00007fb43b85cd60
    @album={:title=>"ディスコの神様", :track=>"1"},
    @artist="tofubeats Feat. 藤井隆",
    @bpm=119.995003,
    @cues=[
      #<Traktor::NML::Cue:0x00007fb43b85f4c0 @hotcue=0, @length=0.0, @name="0.32 - 32.", @repeats=-1, @start=428.537, @type=3>,
      #<Traktor::NML::Cue:0x00007fb43b85d5f8 @hotcue=4, @length=0.0, @name="Beat Marker", @repeats=-1, @start=428.537, @type=4>,
      #<Traktor::NML::Cue:0x00007fb43b85cdd8 @hotcue=3, @length=0.0, @name="n.n.", @repeats=-1, @start=112433.201297, @type=0>
    ],
    @genre="Electronica",
    @key="9d",
    @label="",
    @musical_key="8",
    @playtime=294.0,
    @primarykey="Macintosh HD/:Users/:cabbagekobe/:Music/:iTunes/:iTunes Media/:Music/:tofubeats Feat. 藤井隆/:ディスコの神様/:01 ディスコの神様.mp3",
    @release_date=#<Date: 2013-01-01 ((2456294j,0s,0n),+0s,2299161j)>,
    @title="ディスコの神様"
  >
]>

3. SpotifyAPIを使う

まずはSpotifyAPIを利用するには、アカウント作ってclient_id, client_secretを発行する必要があります。

https://developer.spotify.com

こちらから適当なアプリを作ってそこからclient_id, client_secretを取得して使いましょう。

RSpotifyを使う

RubyでのSpotify APIのラッパーとしてRSpotifyというものがあります。

github.com

これを使いましょう。

Gemfileなり、gem installなりで上記をインストール。

上記gemのREADMEを参考に下記コードを実行します。

またSpotify API はすべての API に authenticateが必要になっています。 (client_id, client_secret)は上記で取得したやつをいれてね。

require 'rspotify'
require 'pp'

RSpotify.authenticate(client_id, client_secret)

tracks = RSpotify::Track.search('好きと言わせたい')
track = tracks.first

pp track

トラック情報取得できました!(出力データ整理済み)

#<RSpotify::Track:0x00007fe0f148ce28 @album=
  #<RSpotify::Album:0x00007fe0f1466d90
    @album_type="single",
    @artists=[
      #<RSpotify::Artist:0x00007fe0f1447a58
        @external_urls={"spotify"=>"https://open.spotify.com/artist/5r1tUTxVSgvBHnoDuDODPH"},
        @followers=nil,
        @genres=nil,
        @href="https://api.spotify.com/v1/artists/5r1tUTxVSgvBHnoDuDODPH",
        @id="5r1tUTxVSgvBHnoDuDODPH",
        @images=nil,
        @name="IZ*ONE",
        @popularity=nil,
        @top_tracks={},
        @type="artist",
        @uri="spotify:artist:5r1tUTxVSgvBHnoDuDODPH"
      >
    ],
    @available_markets=[
      "AD", "AE", "AR", "AT", "AU", "BE", "BG", "BH", "BO", "BR", "CA", "CH",
      "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "DZ", "EC", "EE", "EG",
      "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "ID", "IE", "IL",
      "IN", "IS", "IT", "JO", "KW", "LB", "LI", "LT", "LU", "LV", "MA", "MC",
      "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL",
      "PS", "PT", "PY", "QA", "RO", "SA", "SE", "SG", "SK", "SV", "TH", "TN",
      "TR", "TW", "US", "UY", "VN", "ZA"
    ],
    @copyrights=nil,
    @external_ids=nil,
    @external_urls={"spotify"=>"https://open.spotify.com/album/6esOExMaYIWvttAQYdn3Gb"},
    @genres=nil,
    @href="https://api.spotify.com/v1/albums/6esOExMaYIWvttAQYdn3Gb",
    @id="6esOExMaYIWvttAQYdn3Gb",
    @images=[
      {"height"=>640, "url"=> "https://i.scdn.co/image/ab67616d0000b2732d7ca7730cc00d57bfdab861", "width"=>640},
      {"height"=>300, "url"=> "https://i.scdn.co/image/ab67616d00001e022d7ca7730cc00d57bfdab861", "width"=>300},
      {"height"=>64, "url"=> "https://i.scdn.co/image/ab67616d000048512d7ca7730cc00d57bfdab861", "width"=>64}
    ],
    @label=nil,
    @name="好きと言わせたい (Type A)",
    @popularity=nil,
    @release_date="2019-02-05",
    @release_date_precision="day",
    @total_tracks=nil,
    @tracks_cache=nil,
    @type="album",
    @uri="spotify:album:6esOExMaYIWvttAQYdn3Gb"
  >,
  @artists=[
    #<RSpotify::Artist:0x00007fe0f1447760
      @external_urls={"spotify"=>"https://open.spotify.com/artist/5r1tUTxVSgvBHnoDuDODPH"},
      @followers=nil,
      @genres=nil,
      @href="https://api.spotify.com/v1/artists/5r1tUTxVSgvBHnoDuDODPH",
      @id="5r1tUTxVSgvBHnoDuDODPH",
      @images=nil,
      @name="IZ*ONE",
      @popularity=nil,
      @top_tracks={},
      @type="artist",
      @uri="spotify:artist:5r1tUTxVSgvBHnoDuDODPH"
    >
  ],
  @available_markets=[
    "AD", "AE", "AR", "AT", "AU", "BE", "BG", "BH", "BO", "BR", "CA", "CH",
    "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "DZ", "EC", "EE", "EG",
    "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "ID", "IE", "IL",
    "IN", "IS", "IT", "JO", "KW", "LB", "LI", "LT", "LU", "LV", "MA", "MC",
    "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL",
    "PS", "PT", "PY", "QA", "RO", "SA", "SE", "SG", "SK", "SV", "TH", "TN",
    "TR", "TW", "US", "UY", "VN", "ZA"
  ],
  @context_type=nil,
  @disc_number=1,
  @duration_ms=239333,
  @explicit=false,
  @external_ids={"isrc"=>"JPPO01806807"},
  @external_urls={"spotify"=>"https://open.spotify.com/track/7nimCdASI4W4j5C4zqvKO5"},
  @href="https://api.spotify.com/v1/tracks/7nimCdASI4W4j5C4zqvKO5",
  @id="7nimCdASI4W4j5C4zqvKO5",
  @is_playable=nil,
  @linked_from=nil,
  @name="好きと言わせたい",
  @played_at=nil,
  @popularity=49,
  @preview_url=nil,
  @track_number=1,
  @type="track",
  @uri="spotify:track:7nimCdASI4W4j5C4zqvKO5"
>

データは取れる!
取ったデータの曲idをもう一回SpotifyAPIに投げましょう。
下記のような感じ。

require 'rspotify'
require 'pp'

RSpotify.authenticate(client_id, client_secret)

tracks = RSpotify::Track.search('好きと言わせたい')
track = tracks.first

audio_features = RSpotify::AudioFeatures.find(track.id)

pp audio_features

うおー!という感じでデータが取得できたぞー!!!(出力データ整理済み)

#<RSpotify::AudioFeatures:0x00007fd388132f78
 @acousticness=0.122,
 @analysis_url="https://api.spotify.com/v1/audio-analysis/7nimCdASI4W4j5C4zqvKO5",
 @danceability=0.532,
 @duration_ms=239333,
 @energy=0.938,
 @external_urls=nil,
 @href=nil,
 @id="7nimCdASI4W4j5C4zqvKO5",
 @instrumentalness=0,
 @key=8,
 @liveness=0.245,
 @loudness=-1.409,
 @mode=1,
 @speechiness=0.0568,
 @tempo=132.023,
 @time_signature=4,
 @track_href="https://api.spotify.com/v1/tracks/7nimCdASI4W4j5C4zqvKO5",
 @type="audio_features",
 @uri="spotify:track:7nimCdASI4W4j5C4zqvKO5",
 @valence=0.716
>

4. というわけでまとめたやつがこんな感じ。

require 'rspotify'
require 'pp'
require 'traktor/nml'

RSpotify.authenticate(client_id, client_secret)

Traktor::NML.parse File.open("path/to/playlist.nml")
playlist = Traktor::NML.load "path/to/playlist.nml"

playlist.each{|track, value|
  tracks = RSpotify::Track.search(track.title)

  audio_features = RSpotify::AudioFeatures.find(tracks.first.id)

  pp audio_features
  pp "--------------------------------------------"
}

上記コードで、NMLファイルからSpotifyの楽曲情報を取得って感じになります。(エラー周りの処理は必要ですね…)

というわけで次回はこいつらをDBにいれてTraktorから参照していくぞ〜〜〜〜!!!