2023年6月 この範囲を時系列順で読む この範囲をファイルに出力する
python-vlc で音源を流す試験をしました。
単に再生するだけなら簡単。
ちょっと難儀したのは再生終了を確定する処理。再生後自動的にリセットされませんので、再生が終了したことを確認して後処理をしないといけません。
vlc.MediaPlayer.is_playing()は再生中かどうかを把握出来ますが、これだけでは再生が終了したフェーズかわかりません。オレフラグ(下記ではis_playing)を併用して再生前か再生後かを判別します。再生後ならstop()を実行します。きちんとstop()しないともう一度再生が出来ないpython-vlc。
下記は再生終了を確定する試験として繰り返し再生するモノです。
# -*- coding: utf-8 -*-
import time
import vlc
def play() :
# 音声ファイルを定義
play_music = ( [ vlc.MediaPlayer() ] )
try :
play_music[0].set_mrl( 'C:/音源.mp3' )
except :
return -1
# 再生ボリューム設定
play_music[0].audio_set_volume( 60 )
# フラグ定義
is_playing = 0 # 再生実行済みフラグ
# Main Loop
while True :
try :
# 予備睡眠
time.sleep( 0.0001 ) # Ctl-Cの反応を良くするのに少しsleepを入れるといい
# 停止中
if( play_music[0].is_playing() == 0 ) :
# 未開始で停止中
if( is_playing == 0 ) :
play_music[0].play()
while ( play_music[0].is_playing() == 0 ) : # 再生状態が確定するまで待つ
time.sleep( 0.001 )
play_music[0].set_time( 0 )
is_playing = 1
# 再生終了で停止中
else : # if( is_playing == 1 ) :
play_music[0].stop() # 再生終了を宣言してインスタンスをリセットする 主にこれをやりたいがための処理
is_playing = 0
# 再生中
else :
pass # 再生中に行う処理は書いていないのでとりあえずpass
# Ctl-Cで終了
except KeyboardInterrupt :
play_music[0].stop()
break
return 0
if __name__ == "__main__" :
play()
python-vlc便利過ぎ。
追記
vlc.MediaPlayer.get_length()とvlc.MediaPlayer.get_time()を使って再生が最後まで行ったかチェックしました。
何曲か試しましたが、概ねlengthの-0.1~-0.2秒で終了しています。vlc.MediaPlayer.get_time()は取得単位の1msecで厳密にカウントされているモノでも無さそうなので表示上の誤差かもしれません。トラック別で音繋がり場合は少し不安がありますが、音のお尻には1-2秒の余白があるのが一般的ですし、そこまで突き詰めるシステムではありませんのでいいかなと。
画面作りをやって LTC Generator と合わせれば完成が見えてきそうです。
ウィンドウマネージャーはPython標準のtkinterを使う勉強をしています。書式は違いますが、考え方はHTMLとCSSを使ったweb画面作りに酷似していますので、方言的に翻訳が出来れば何とかなりそうです。ただ、ボタン操作や画面の更新をオブジェクト指向のイベント処理(割り込み)で書くので少し面倒ですし、LTC Generator の制御やvlcの部分はバックグラウンドの常駐処理にしたいのでウィンドウ制御とは別スレッドとなり手間がかかるかも。
#Python #タイムコード
単に再生するだけなら簡単。
ちょっと難儀したのは再生終了を確定する処理。再生後自動的にリセットされませんので、再生が終了したことを確認して後処理をしないといけません。
vlc.MediaPlayer.is_playing()は再生中かどうかを把握出来ますが、これだけでは再生が終了したフェーズかわかりません。オレフラグ(下記ではis_playing)を併用して再生前か再生後かを判別します。再生後ならstop()を実行します。きちんとstop()しないともう一度再生が出来ないpython-vlc。
下記は再生終了を確定する試験として繰り返し再生するモノです。
# -*- coding: utf-8 -*-
import time
import vlc
def play() :
# 音声ファイルを定義
play_music = ( [ vlc.MediaPlayer() ] )
try :
play_music[0].set_mrl( 'C:/音源.mp3' )
except :
return -1
# 再生ボリューム設定
play_music[0].audio_set_volume( 60 )
# フラグ定義
is_playing = 0 # 再生実行済みフラグ
# Main Loop
while True :
try :
# 予備睡眠
time.sleep( 0.0001 ) # Ctl-Cの反応を良くするのに少しsleepを入れるといい
# 停止中
if( play_music[0].is_playing() == 0 ) :
# 未開始で停止中
if( is_playing == 0 ) :
play_music[0].play()
while ( play_music[0].is_playing() == 0 ) : # 再生状態が確定するまで待つ
time.sleep( 0.001 )
play_music[0].set_time( 0 )
is_playing = 1
# 再生終了で停止中
else : # if( is_playing == 1 ) :
play_music[0].stop() # 再生終了を宣言してインスタンスをリセットする 主にこれをやりたいがための処理
is_playing = 0
# 再生中
else :
pass # 再生中に行う処理は書いていないのでとりあえずpass
# Ctl-Cで終了
except KeyboardInterrupt :
play_music[0].stop()
break
return 0
if __name__ == "__main__" :
play()
python-vlc便利過ぎ。
追記
vlc.MediaPlayer.get_length()とvlc.MediaPlayer.get_time()を使って再生が最後まで行ったかチェックしました。
何曲か試しましたが、概ねlengthの-0.1~-0.2秒で終了しています。vlc.MediaPlayer.get_time()は取得単位の1msecで厳密にカウントされているモノでも無さそうなので表示上の誤差かもしれません。トラック別で音繋がり場合は少し不安がありますが、音のお尻には1-2秒の余白があるのが一般的ですし、そこまで突き詰めるシステムではありませんのでいいかなと。
画面作りをやって LTC Generator と合わせれば完成が見えてきそうです。
ウィンドウマネージャーはPython標準のtkinterを使う勉強をしています。書式は違いますが、考え方はHTMLとCSSを使ったweb画面作りに酷似していますので、方言的に翻訳が出来れば何とかなりそうです。ただ、ボタン操作や画面の更新をオブジェクト指向のイベント処理(割り込み)で書くので少し面倒ですし、LTC Generator の制御やvlcの部分はバックグラウンドの常駐処理にしたいのでウィンドウ制御とは別スレッドとなり手間がかかるかも。
#Python #タイムコード
オレメモ
PythonでVLCを使った音楽再生方法を再整理。
Windows11x64
Python3.7
VLC media player ver.3.0.18
pipでpython-vlcをインストール。
コマンドプロンプト(管理者権限にて)
> pip3 install python-vlc
pipとはPythonのライブラリを提供してくれるリポジトリのこと。先達に感謝。
pythonでvlcによる再生。
import vlc
if __name__ == '__main__':
p = vlc.MediaPlayer() #vlc.MediaPlayerのインスタンスを作成
p.set_mrl('sound.mp3') #インスタンスに音源ファイルを関連付け 相対パスも可能らしいがフルパス指定を推奨
p.play() #再生開始
これだけで音声ファイルが再生されます。
以下基本的なAPI。
p = vlc.MediaPlayer() #vlc.MediaPlayerのインスタンスを作成
p.set_mrl('<file_name>') #インスタンスに音源ファイルを関連付け 相対パスも可能らしいがフルパス指定を推奨 ファイルはVLC media player で扱える物なら何でも。
p.play() #再生開始 戻り値 0=正常再生/-1=再生出来ない ※ pauseされていれば再生再開
p.is_playing() #再生中か 戻り値 0=再生していない/1=再生中
p.pause() #再生中なら一時停止、一時停止中なら再生再開 戻り値無し
p.get_length() #音源の長さを取得 戻り値 秒数(msec.)
p.get_time() #音源の最初からの再生位置を取得 戻り値 秒数(msec.)
p.set_time(<msec.>) #再生再開位置を秒数(msec.)で指定 戻り値無し ※ 再生中やpause()中でないと指定出来ない
p.audio_set_volume(<パーセント>) #0=mute,100=0dB(パーセント指示だと思っていいみたい。100以上も指定可能。)戻り値 0=再生中に設定成功/-1=設定はしたが再生はしていない
p.stop() #停止 戻り値無し 次回のplay()では最初から始まる
※ 最後まで再生しきっても、stop()をしないと次回のplay()はスタートしない。再生終了で必ずstop()を実行する。
※ 停止中は次の再生開始秒数を指定出来ないので、特定の秒数(msec.)から再生する場合は、play()に続いてset_time(<msec.>)を実行する。ただし、pause()中は指定可能。
p.play()
p.set_time(<msec.>)
複数の音源ファイルをプレイリストとして扱ってくれるクラスもあるのですが、LTCを作るには少し不便がありそうなため、1曲単位で扱うことにしています。
vlc.MediaPlayer()のリストを作成する。
p = ( [vlc.MediaPlayer(), vlc.MediaPlayer(), vlc.MediaPlayer()] )
# p[0]、p[1]、p[2] などと使える。
普通にオフジェクトのリストとして扱える。
これだけはメモ。
リストのオブジェクトを追加する。
p.append( vlc.MediaPlayer() )
# 上記に続いた場合は p[3] が追加される
再生操作のレスポンスはとても良く、タイムラグはほとんど感じない。
ただ、プレイリスト分のインスタンスを設定するにはメモリに注意かもしれない。
参考
python-vlcのドキュメント
ここの「vlc.MediaPlayer」を参照。
#Python
PythonでVLCを使った音楽再生方法を再整理。
Windows11x64
Python3.7
VLC media player ver.3.0.18
pipでpython-vlcをインストール。
コマンドプロンプト(管理者権限にて)
> pip3 install python-vlc
pipとはPythonのライブラリを提供してくれるリポジトリのこと。先達に感謝。
pythonでvlcによる再生。
import vlc
if __name__ == '__main__':
p = vlc.MediaPlayer() #vlc.MediaPlayerのインスタンスを作成
p.set_mrl('sound.mp3') #インスタンスに音源ファイルを関連付け 相対パスも可能らしいがフルパス指定を推奨
p.play() #再生開始
これだけで音声ファイルが再生されます。
以下基本的なAPI。
p = vlc.MediaPlayer() #vlc.MediaPlayerのインスタンスを作成
p.set_mrl('<file_name>') #インスタンスに音源ファイルを関連付け 相対パスも可能らしいがフルパス指定を推奨 ファイルはVLC media player で扱える物なら何でも。
p.play() #再生開始 戻り値 0=正常再生/-1=再生出来ない ※ pauseされていれば再生再開
p.is_playing() #再生中か 戻り値 0=再生していない/1=再生中
p.pause() #再生中なら一時停止、一時停止中なら再生再開 戻り値無し
p.get_length() #音源の長さを取得 戻り値 秒数(msec.)
p.get_time() #音源の最初からの再生位置を取得 戻り値 秒数(msec.)
p.set_time(<msec.>) #再生再開位置を秒数(msec.)で指定 戻り値無し ※ 再生中やpause()中でないと指定出来ない
p.audio_set_volume(<パーセント>) #0=mute,100=0dB(パーセント指示だと思っていいみたい。100以上も指定可能。)戻り値 0=再生中に設定成功/-1=設定はしたが再生はしていない
p.stop() #停止 戻り値無し 次回のplay()では最初から始まる
※ 最後まで再生しきっても、stop()をしないと次回のplay()はスタートしない。再生終了で必ずstop()を実行する。
※ 停止中は次の再生開始秒数を指定出来ないので、特定の秒数(msec.)から再生する場合は、play()に続いてset_time(<msec.>)を実行する。ただし、pause()中は指定可能。
p.play()
p.set_time(<msec.>)
複数の音源ファイルをプレイリストとして扱ってくれるクラスもあるのですが、LTCを作るには少し不便がありそうなため、1曲単位で扱うことにしています。
vlc.MediaPlayer()のリストを作成する。
p = ( [vlc.MediaPlayer(), vlc.MediaPlayer(), vlc.MediaPlayer()] )
# p[0]、p[1]、p[2] などと使える。
普通にオフジェクトのリストとして扱える。
これだけはメモ。
リストのオブジェクトを追加する。
p.append( vlc.MediaPlayer() )
# 上記に続いた場合は p[3] が追加される
再生操作のレスポンスはとても良く、タイムラグはほとんど感じない。
ただ、プレイリスト分のインスタンスを設定するにはメモリに注意かもしれない。
参考
python-vlcのドキュメント
ここの「vlc.MediaPlayer」を参照。
#Python
LTC Generator のLTC信号を卓(MA dot2)が認識しました。
ただ、同じ値を送り続けても認識しません。LTCを入力してから認識するまで1秒弱かかるので、カウントを進めずに信号を認識し続ける方法が欲しいのです。
試しに数フレームの繰り返しを組んでみたところ認識し、数フレームの繰り返しを一定回数行ってから抜ける様にしたところ期待する結果を得ました。
最初のCUEポイントのマイナス数フレームの位置で2-3フレームの繰り返し待機をし、トリガが立ったらそれを抜ける考え方で良さそうです。
ともかく、卓が認識したので一安心です。
#タイムコード
ただ、同じ値を送り続けても認識しません。LTCを入力してから認識するまで1秒弱かかるので、カウントを進めずに信号を認識し続ける方法が欲しいのです。
試しに数フレームの繰り返しを組んでみたところ認識し、数フレームの繰り返しを一定回数行ってから抜ける様にしたところ期待する結果を得ました。
最初のCUEポイントのマイナス数フレームの位置で2-3フレームの繰り返し待機をし、トリガが立ったらそれを抜ける考え方で良さそうです。
ともかく、卓が認識したので一安心です。
#タイムコード
LTC Generator は30fpsも他のfpsと同様の誤差でした。時間の勘定に期待値が出たので PIC のファームウェアは一応の完成とします。あとは、卓が認識するかです。
今後はPC側のアプリケーションの製作です。Pythonベースでvlcライブラリを使い、LTCとVLCは同時スタートの疑似シンクです。VLCの現在時からLTCを生成することは難しいからです。途中スタートではLTCの現在時からVLCの開始時を補正して合わせる様にします。
音声ファイルはプレイリストとしてまとめ、スタートタイム、エンドタイム、ボリューム、連続再生、曲間時間などを個別に設定出来る様にします。複数の音声ファイルを並列で再生する用途は想定しませんので、1トラックのわかりやすいモノを目指します。もちろん、LTCのタイムが被らない様にチェックする機能も大切です。
#タイムコード
今後はPC側のアプリケーションの製作です。Pythonベースでvlcライブラリを使い、LTCとVLCは同時スタートの疑似シンクです。VLCの現在時からLTCを生成することは難しいからです。途中スタートではLTCの現在時からVLCの開始時を補正して合わせる様にします。
音声ファイルはプレイリストとしてまとめ、スタートタイム、エンドタイム、ボリューム、連続再生、曲間時間などを個別に設定出来る様にします。複数の音声ファイルを並列で再生する用途は想定しませんので、1トラックのわかりやすいモノを目指します。もちろん、LTCのタイムが被らない様にチェックする機能も大切です。
#タイムコード
RaspberryPi pico はとても面白いマイコンです。少なくとも私好みです。RaspberryPi のブランドですが、RaspberryPi の廉価版、簡易版ではなく、Arduino の親戚と思った方が自然な存在感です。想定される用途、ソースコードを書いてから実行に至るまでの流れが Arduino のそれととても似ています。
純正の開発・実行環境は MicroPython と呼ばれるシステムですが、MicroPython からの派生品である CircuitPython を使うことで自由度が更に広がるようです。MicroPython がスタンドアロンでの実装を主眼としているなら、CircuitPython はPCなどの周辺機器を作ることを強く意識しているように思います。MicroPython、CircuitPython のどちらもとても良く整備された開発・実行環境だと思いますが、CircuitPythonの方が私の趣向に合っている気がします。実際、CircuitPython の存在を知って pico に興味を持ったのは事実です。
pico のプロセッサはarm系32bit133MHzです。Arduinoは、高速化高機能化が進んではいますが、基本はAVR系8bitマイコンです。処理能力は pico に格段の優位性があります。その余裕を使って Python を動かしているとも言えますが、C/C++の開発環境を使えば攻めた造りも出来そうな気がします。また、pico は ArduinoIDE と呼ばれる Arduino の開発環境でもコーディング出来るので、Arduino に親しんだ方がシームレスに使えるメリットもあります。ArduinoIDE を用いてこれらのデバイスの開発環境を一本化するのもアリですね。
#RaspberryPi
純正の開発・実行環境は MicroPython と呼ばれるシステムですが、MicroPython からの派生品である CircuitPython を使うことで自由度が更に広がるようです。MicroPython がスタンドアロンでの実装を主眼としているなら、CircuitPython はPCなどの周辺機器を作ることを強く意識しているように思います。MicroPython、CircuitPython のどちらもとても良く整備された開発・実行環境だと思いますが、CircuitPythonの方が私の趣向に合っている気がします。実際、CircuitPython の存在を知って pico に興味を持ったのは事実です。
pico のプロセッサはarm系32bit133MHzです。Arduinoは、高速化高機能化が進んではいますが、基本はAVR系8bitマイコンです。処理能力は pico に格段の優位性があります。その余裕を使って Python を動かしているとも言えますが、C/C++の開発環境を使えば攻めた造りも出来そうな気がします。また、pico は ArduinoIDE と呼ばれる Arduino の開発環境でもコーディング出来るので、Arduino に親しんだ方がシームレスに使えるメリットもあります。ArduinoIDE を用いてこれらのデバイスの開発環境を一本化するのもアリですね。
#RaspberryPi
LTC Generator は29.97fpsも25fpsと同等の誤差でした。30fpsと24fpsも同等に収まればPICのファームウェアは完成とします。
比較に使っている時計はカタログスペックで月差±15秒。1日あたり0.5秒の誤差とみなせます。基準にするには十分でしょう。
「卓がLTCとして認識するか」を早々に確認したいですね。これが一番重要です。
#タイムコード
比較に使っている時計はカタログスペックで月差±15秒。1日あたり0.5秒の誤差とみなせます。基準にするには十分でしょう。
「卓がLTCとして認識するか」を早々に確認したいですね。これが一番重要です。
#タイムコード
LTC Generator のタイマーを修正してみました。
8時間経過で約1秒ズレていますが、以前より良くなっていますし、SMPTEが求める精度には十分収まっています。何よりも比較に使っている時計の精度がどこまでなのかわかりませんからこんなもんでしょう。
PICに与えている水晶発振子の精度は30ppmですから(ppmは100万分の1を表す単位なので比率だと0.00003)、1日(86,400秒)あたり±2.592秒の誤差がありえます。実測値は想定される誤差相当なのでソフトウェアは間違ってなさそうです。
現在値以上を求めるなら、ソフトウェアの修正ではなく個体差に対する補正となりそうですし、もっと精度の高い発振子を使うべき話です。
補正計算が無い25fpsでテストしていますが、補正計算が入る他のfpsも同等に収まればいいでしょう。
秋月電子通商さんで手に入る高精度な発振子は最高で1ppmです。高精度に越したことはありませんが、ここまで必要か、これで十分か、30ppmに比べてメリットがあるかは別問題です。
求めているのは数分間の音楽の時間座標を表す信号です。卓がエラーを出さない条件を満たし、目視でズレを感じない繰り返し精度があればいいのです。高精度の時計や放送用の基準を作っているワケではありませんから、無制限に高精度を求めても意味がありません。十分に使えて低価格も大切な精度です。
#PIC #タイムコード
8時間経過で約1秒ズレていますが、以前より良くなっていますし、SMPTEが求める精度には十分収まっています。何よりも比較に使っている時計の精度がどこまでなのかわかりませんからこんなもんでしょう。
PICに与えている水晶発振子の精度は30ppmですから(ppmは100万分の1を表す単位なので比率だと0.00003)、1日(86,400秒)あたり±2.592秒の誤差がありえます。実測値は想定される誤差相当なのでソフトウェアは間違ってなさそうです。
現在値以上を求めるなら、ソフトウェアの修正ではなく個体差に対する補正となりそうですし、もっと精度の高い発振子を使うべき話です。
補正計算が無い25fpsでテストしていますが、補正計算が入る他のfpsも同等に収まればいいでしょう。
秋月電子通商さんで手に入る高精度な発振子は最高で1ppmです。高精度に越したことはありませんが、ここまで必要か、これで十分か、30ppmに比べてメリットがあるかは別問題です。
求めているのは数分間の音楽の時間座標を表す信号です。卓がエラーを出さない条件を満たし、目視でズレを感じない繰り返し精度があればいいのです。高精度の時計や放送用の基準を作っているワケではありませんから、無制限に高精度を求めても意味がありません。十分に使えて低価格も大切な精度です。
#PIC #タイムコード
LTC Player には外付けスイッチが欲しい。
RaspberryPipicoはUSBキーボードやマウスを簡単に作れるとのこと。
てことは、picoでキーボードシステムを構築しといてもいい。USBのHIDはもちろん、UART、I2Cなども使える様にしとけば便利だと思われる。チャタリングを含めたセンシングのマトリクスと通信まで作っておくのです。
picoについて調べてみましょう。
#RaspberryPi
RaspberryPipicoはUSBキーボードやマウスを簡単に作れるとのこと。
てことは、picoでキーボードシステムを構築しといてもいい。USBのHIDはもちろん、UART、I2Cなども使える様にしとけば便利だと思われる。チャタリングを含めたセンシングのマトリクスと通信まで作っておくのです。
picoについて調べてみましょう。
#RaspberryPi
LTC Generator は24時間カウントの関数をPythonで書いてみました。限りなく本チャンに近いモノです。
期待通りの動作をします。卓への接続テストはまだですが、オシロスコープには波形が出ます。
ただ、24時間で約40秒の遅れが出ます。1時間あたり約1.7秒ですから無視出来ません。
時間のクリックカウントはPICで行っていますが、TMR1のコンペア値が1個多いと仮定すると辻褄が合います。そういえば、TMR2でコンペアと同様の機構と思われるPWMを作る場合は折り返しで1カウント余計にかかるハズ。データシートには記載が見受けられなかったけど、TMR1のコンペアモードでも同様なのかもしれません。
コンペアの定数値を変更して改めてテストしましょう。
#PIC #タイムコード
期待通りの動作をします。卓への接続テストはまだですが、オシロスコープには波形が出ます。
ただ、24時間で約40秒の遅れが出ます。1時間あたり約1.7秒ですから無視出来ません。
時間のクリックカウントはPICで行っていますが、TMR1のコンペア値が1個多いと仮定すると辻褄が合います。そういえば、TMR2でコンペアと同様の機構と思われるPWMを作る場合は折り返しで1カウント余計にかかるハズ。データシートには記載が見受けられなかったけど、TMR1のコンペアモードでも同様なのかもしれません。
コンペアの定数値を変更して改めてテストしましょう。
#PIC #タイムコード
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131