メインコンテンツへスキップ
見出し画像

Linuxサーバーを音楽プレイヤー化 ~音響サーバーの作成~

    こんにちはRcatです。
    前回の記事で、必要な環境は整いましたので、今回はサーバーの作りこみをしていきます

    前回がまだの方はこちら

    次回はこちら


    はじめに

    利用規約

    情報や作品の活用時は事前に利用規約をご確認ください。

    コメントについて

    利用規約のガイドラインを確認の上コメントしてください


    そのまえに

    コマンドラインからシステム音量を変更する

    テストランしていたところ突然音が出なくなり(0になってた)調べたので載せておきます

    以下のコマンドでWindowsのサウンド設定的なパネルが開きます

    alsamixer

    コンソールながらなんとリッチなグラフィックです!
    左右で項目を選択して上下で変更します。今回はなぜかマスターが0になっていました…。なんで?

    画像

    今回はマスターとFrontの項目をUPして治りました。
    ちなみにmplayerのボリュームはPCMの項目が変化するようです。

    これをコマンドでやると以下

    amixer set Master 100% unmute
    amixer set Headphone 100% unmute
    amixer set PCM 100% unmute

    PCMはmplayerからなのでやらず、上ふたつは組み込んじゃいます(Frontは人によると思うので変更しないといけませんね)

    というわけで以下のメソッドを追加

    画像

    呼出しはこんな感じ。リストは一応取得できるが、まず自分で見ること推奨。

    >>> P.System_GetAudioDeviceName()
    ['Master', 'Headphone', 'PCM', 'Front', 'Front Mic', 'Front Mic Boost', 'Surround', 'Center', 'LFE', 'Line', 'Line Boost', 'IEC958', 'IEC958', 'IEC958', 'IEC958', 'Capture', 'Capture', 'Auto-Mute Mode', 'Channel Mode', 'Input Source', 'Input Source', 'Loopback Mixing', 'Rear Mic', 'Rear Mic Boost']
    >>> P.System_AudioDeviceVolumeControl(["Master"],100)
    Simple mixer control 'Master',0
      Capabilities: pvolume pvolume-joined pswitch pswitch-joined
      Playback channels: Mono
      Limits: Playback 0 - 87
      Mono: Playback 87 [100%] [0.00dB] [on]

    音量のノーマライズ

    mp3プレイヤー時代はMP3Gainというのを使って、メタデータで係数を変更して音量をそろえていたのですが、今回はmp3に変換前のデータをそのまま使った結果音量がばらついてしまいました…。
    なのでファイルをノーマライズをしてしまいましょう。

    チャッピーに聞いたり、調べたりするとFFMPEGを使って音量を正規化できそうです。
    YouTubeに動画をあげている人なんかはこういうので、ちゃんと音量を設定してるらしい。(そういや自分の動画って音ちっちゃかったような)。

    というわけでおすすめされたコマンドがこちら。
    これは2段階に分かれており、まずはファイルを解析、そして解析結果を使ってノーマライズという流れです。

    $ffmpeg -i input.wav -af loudnorm=I=-14:TP=-1.5:LRA=11:print_format=json -f null -
    {
      "input_i" : "-20.50",
      "input_tp" : "-2.00",
      "input_lra" : "5.00",
      "input_thresh" : "-30.00",
      "output_i" : "-14.00",
      "output_tp" : "-1.50",
      "output_lra" : "5.00",
      "output_thresh" : "-23.00",
      "normalization_type" : "dynamic",
      "target_offset" : "6.50"
    }
    
    $ffmpeg -i input.wav -af loudnorm=I=-14:TP=-1.5:LRA=11:measured_I=-20.50:measured_TP=-2.00:measured_LRA=5.00:measured_thresh=-30.00:offset=6.50:linear=true:print_format=summary output.wav

    上のコマンドを実行すると、以下のジェイソンデータが取得可能です(実際はいろんな出力が出るのでここだけ切り取ります)。
    次に各項目の値を引用して2番目のノーマライズコマンドを実行します。
    こうすることで、音量を指定した値にしたファイルを作成することができます。

    今回はノーマライズが有効になっている場合はノーマライズファイルを検索しない場合は、ノーマライズを行い特定のフォルダに格納するということを行います。

    というわけでノーマライズ用のメソッドがこちら
    上が解析で下が適用です。

    画像

    一応下側の関数だけでも動くようになってます。
    動作としては、上側の関数は解析結果を保存できるようになっているので、保存されている場合はそれを読み込むという感じですね。引き数でターゲットの音量やその他パラメーターを指定することもできます。

    ちなみにこれをどこでやるかというところなんですが、一番末端の再生関数で行います。

    画像

    この関数はどんな方法で再生を行っても必ず呼び出される関数でファイルパスを指定して再生します。
    インスタンス変数でノーマライズが有効になっている場合は、自動的にノーマライズフォルダの中に同じ名前のファイルがあるか確認しない場合は、先ほどのノーマライズ関数を叩いて再生するという手順を取ることで、自動的にノーマライズを行います。

    まあ、これだと再生までに数秒かかってしまうので、連続再生の場合は再生待ちの間に次の曲をチョイスして、それのノーマライスもやってしまいます。ざっとこんな感じでしょうか?

    画像

    なんかどんどん重くなっちゃってますが、事前に曲を選択することで高速化を測りますが、曲を選択されてしまうと事前に選択した曲は破棄しなければならないので、一番上で分岐を入れてます。

    音量の設定方法の変更

    ファイルをノーマライズして気づいたんですが、ファイルによってボリュームを設定した時のPCMの上がり具合が違う。音がすごく小さくなったと思ったら100まで上げても全然PCMが上がってない。
    ドキュメントの方を確認すると、ソフトウェアボリュームは使用せずにサウンドカードのマスターボリュームを使うことが推奨と書いてあったので、Mプレイヤーのボリューム引き数は使うのやめます。

    ということで、先ほど上のコマンドでシステムの音量を変更しましたが、ボリューム変更、メソッドはそのコマンドを叩くように変更します。
    まこんな感じですね。

    画像

    なので、基本的にはPCMとフロントは強制的に100%に設定しつつ、マスター音量をいじるという感じにします。

    事前準備まとめ

    というわけで、ここまでの変更によりクラスのインスタンス方法が少し変わりました。
    まずはインスタント時にノーマライズのフラグを設定します。
    その後、デバイスの音量をいじる必要があるので、私の場合はPCとフロントを100に設定します。

    画像

    計画

    まずはどのような感じにするのか、軽く計画を立てていきます。

    操作画面

    ベースとなるのは前作のESPマイコンMP3プレイヤーのこちらの画面です。
    こんな感じでアクセスすると操作画面が現れ、再生操作や音量曲の変更などができます。
    使える要素は流用していきます。

    画像

    盛り込む機能

    次はcgiとして作る場合、何が必要か考えていきます。
    パッと見こんな感じでしょうか?

    • コントロールCGI

      • 再生

        • フォルダの指定

        • プレイリストの指定

      • 停止

      • 一時停止

      • 音量

      • イコライザ

      • ファイルの指定再生方法指定

      • タイマー

    • 専用ページ

      • イコライザ作成

      • プレイリスト作成

      • ファイルのアップロード/削除

    操作に必要なものは基本的に1つのcgiで済ませます。GETでコマンドと引き数を送れば簡単にできます。

    今回新しく追加される専用ページとしては、イコライザーの作成とファイルのアップロードです。
    プレイリストの作成については、一応前作でもページはあったので若干流用しつつ作成という感じです。

    メイン画面の作成

    さて、まずは中央の画面がないと始まらないので、メイン画面から作っていきましょう。

    というわけで現段階でレイアウトしたのがこんな感じです。

    画像

    操作ボタンと音量バーのあたりは完全に前作から流用です。
    フォルダや曲の選択部分は若干違ってくるので、ここは作り直しました。

    そして左側に各種機能へのリンクをまとめたメニューのボタン。
    右側にタイマー機能を乗せてみました。

    HTML側

    操作画面を構成するフロントエンド側は大体300行程度です。細かいところ話し始めると終わらないので、ちょっとだけ工夫してある再生ボタンのところだけ解説しようと思います。

    再生ボタンは実は1枚の画像です。パワーポイントで図形を並べたものを一気に画像に変換しただけですね。

    画像

    そして、これを触った時に特定のcgiにアクセスして操作するわけですが、以下のようにしています。

    画像

    ネタが割れてしまえば簡単ですが、画像のタッチしたX座標を取得し、それが5分割のどの位置にあるのかによってアクセスするcgiが変わるという仕組みです。これによりかなりコンパクトに実装できました。

    サーバー側

    やっぱりメインはサーバー側でしょう。
    曲の選択や先ほどの再生や一時停止の操作も全て以下のcgiで操作しています。

    画像

    ここでインスタンスしているPLAYEROBJというのが前回までに作ったMプレイヤーのクラスです。前回まではコンソールで叩いていたメソッドをcgiに渡された引数により叩くという仕組みです。

    ここのcgiだけで再生、停止、一時停止、音量、イコライザー、ファイルを指定して再生、タイマー、モード変更の機能が全て実装できました。

    ちなみにメイン画面に曲のリストまでを読み込むために叩くcgiがこちらです。このCCIに対して何のリストが欲しいのか問い合わせることで、ジェイソン形式でリストが返ってくる仕組みです。

    画像

    画面に現在の状態が表示されないと不便なので、現在のステータスを返すcgiがこちら。
    ここに現在のモードや再生している曲名、フォルダーなどを返すことによって、メイン画面に情報がセットされる仕組みです。

    画像

    そういえばもう1つだけ工夫しているところがありました。
    それは曲が変わった時に画面に反映されることです。と言っても情報を再読み込みするのが手っ取り早いので、曲が終わった瞬間に自動的にリロードするだけなんですが。

    先ほどお見せしたコントロールcgiの中で再生の時だけコールバックがついているの見えたでしょうか?
    それで呼び出しているのが以下になります。これは曲が終わった時に自動的に呼び出す仕組みです。

    画像

    呼び出される関数はソケットIOです。ソケットIOは自由な通信を行うもので、サーバー側からでも情報を送りつけることができます。
    なので再生終わったよということをクライアントに投げつけると、クライアントはページリロードしますね。という風に動きます。
    こうすることで、曲が変わった時に自動的に画面がリフレッシュされるという仕組みです。

    画像

    プレイリストの管理

    プレイリスト管理について考えていきます。

    サーバー側

    まずは前回作成したプレイヤーオブジェクト内のプレイリストを管理するメソッドがこちらです。
    このメソッドに対して、どのフォルダの中の何の曲がプレイリストになるのかというものを送れば、あとは勝手にファイルが作られます。

    画像

    ちなみに前回もお話ししましたが、フォルダを指定して再生する時にプレイリストの名前を指定すると自動的に認識してそっちを再生するようになります。なので、極力ファイル管理についてはサーバーでやらず、このオブジェクトに丸投げする感じです。

    というわけでサーバー側がこちら。超簡単です。
    ちなみに大量のファイル名を送ることになるので、これだけPOSTです。ファイル名についてはJSONの文字列としてリストを変換して送ります。そして、受け取った文字列をもう一度辞書にシリアライズし、直せば簡単にリストとして受け取れるという仕組みです。

    画像

    HTML側

    こちらに関してもただ長いだけで特筆すべき点は特にないので、詳しくはダウンロードでお願いします。
    画面レイアウトできるのはこんな感じで、どのフォルダに対してのプレイリストにするのかという考え方なので、フォルダーの中に入っている曲の一覧が表示され、それに対してチェックを入れるとその曲だけが再生されるプレイリストになります。

    画像

    なので、処理としてはチェックが入っている曲の名前をcgiにPOSTするという感じですね。

    イコライザーの設定

    イコライザーについてはこんな感じです。
    それぞれの周波数に対しての値をスライドバーで調整できる画面です。

    画像

    サーバー側

    イコライザーについてはサーバーが最も単純です。
    というのも、そもそもイコライザーの設定は各周波数ごとの値を":"区切って渡すだけなので、その文字列を投げるだけでいいのです。ちなみにリムーブのフラグを入れると削除する処理が入ってます。

    画像

    HTML側

    サーバー側はたかが数行なんですが、HTMLは200行ぐらいあります。
    何と言うか、リアルタイムに情報を反映させられるようにしたり、バーがたくさんあったりするのが面倒なんですよね。

    ちなみにバーを初期化する関数がこちら
    事前にサーバーに問い合わせると、全てのイコライザーの名前とその値を取得することができるので、グローバルで保持している前提です。

    画像

    そしてこの関数では名前を指定されると各イコライザーの値に対してバーを作成します。レイアウトを重視したので、動的にテーブルを作っています。
    他にも機能はあるんですが、その辺は使い方の方で説明しようと思います。

    ファイルの管理

    最後にファイルの管理ですね。
    ぶっちゃけLinuxという時点でFTPかなんかで転送していると思うんですが、まぁいちいち繋がなくてもこのアプリだけで完結しますよという機能です。

    こちらに関しては数年前に作成したテンプレートのファイルブラウザを使います。

    この機能なんですが、このようにある特定のルートフォルダを指定すると、クラウドストレージのような使い方ができます。
    これを活用して音楽を入れるためのフォルダを作ったり、そこに楽曲ファイルを転送したりすることができます。
    詳しい使い方に関しては、こちらも使い方のフェーズで紹介しようと思います。

    画像

    ちなみに解説は・・・

    数年も前のものなので勘弁してください。覚えてないです。今から500行のhtml読み直したくないです…。


    まとめ

    今回は前回作成したクラスを使ってサーバーのcgiに割り当ててきました。
    ソースコードは全部足すと2100行くらいあるので、説明に関してはだいぶはしょってしまいましたので、気になる部分がある方はダウンロードの方をご利用いただければなと思います。

    ただ、自分では特筆すべき点がないと言ってはいるものの、人によって気になるところは違うかと思いますので、もしこういうところの説明が足りてないんじゃないかと思った場合は、コメントいただければ追記しようかなと思います(ただし、記事が出て早い段階に限る)。

    配布は次回の方の記事で行いますので、またそちらでお会いしましょう。



     
     
    モノづくりが趣味。 "売ってないなら自分で作ればいいじゃない"をコンセプトに、機械/電気/AI/プログラム/ネットワーク 全部やります。 記事執筆はAI不使用。 ご連絡や利用規約はプロフィール記事参照。

    あなたへのおすすめ