タグ「Art-net」を含む投稿[102件](8ページ目)
ちょっと忙しかった今月もヒト段落。
本業があるのは有難いことですが、訛りきった感覚と体では押っ付けるのが大変でした。
良くも悪くもしばらくヒマです。
4月は例年ヒマですから、コロナが収束傾向にあっても増える元がありません。
そんなワケでArt-Netパッチを進めます。
まずは入力部を手直しして複数の送信機への対応です。結果的にHTPミキサーになるのですが、間違って複数を接続しても破綻しない様にすることが目的です。入力部を出来るだけ無駄なく丁寧に作ることが機能を実現する上で重要です。
あとは、人が操作する部分を後付けで作っても無理が出ない様にしておくことです。主機能と操作部を完全に切り離し、指示経路を一本化しつつ出来るだけシンプルにします。経路にqueueを使うかsocketを使うか考えていますが、queueの方が速度が出ますしpythonの変数のまま送受信できるメリットがありますが、操作部との通信には速度を求めていないのでscoketにした方がいいかもしれません。socketにしておけば操作部を別なデバイスにすることも可能なのでいいかなと。書いたことも調べたこともありませんが、iPadなどを操作部にすることも可能だと思うのです。
#Python #[Art-Net]
本業があるのは有難いことですが、訛りきった感覚と体では押っ付けるのが大変でした。
良くも悪くもしばらくヒマです。
4月は例年ヒマですから、コロナが収束傾向にあっても増える元がありません。
そんなワケでArt-Netパッチを進めます。
まずは入力部を手直しして複数の送信機への対応です。結果的にHTPミキサーになるのですが、間違って複数を接続しても破綻しない様にすることが目的です。入力部を出来るだけ無駄なく丁寧に作ることが機能を実現する上で重要です。
あとは、人が操作する部分を後付けで作っても無理が出ない様にしておくことです。主機能と操作部を完全に切り離し、指示経路を一本化しつつ出来るだけシンプルにします。経路にqueueを使うかsocketを使うか考えていますが、queueの方が速度が出ますしpythonの変数のまま送受信できるメリットがありますが、操作部との通信には速度を求めていないのでscoketにした方がいいかもしれません。socketにしておけば操作部を別なデバイスにすることも可能なのでいいかなと。書いたことも調べたこともありませんが、iPadなどを操作部にすることも可能だと思うのです。
#Python #[Art-Net]
SPI-DMXを使うにはSPIに渡す配列に少し工夫が必要です。
レベル値の2次元配列[ユニバース,スロットアドレス]を1次元配列[スロットアドレス]に変換してSPIに渡すのですが、<ユニバースnのスロットx>を<n.x>と書くなら、
[<0.1>,<1.1>,<2.1>,・・・,<6.1>,<7.1>,<0.2>,<1.2>,<2.2>,・・・,<6.2>,<7.2>,
・・・,
<0.512>,<1.512>,<2.512>,・・・,<6.512>,<7.512>]
としなければなりません。[ユニバース,スロットアドレス]だったものを[スロットアドレス,ユニバース]の順番で1次元配列にするのです。
ちなみに元のスロットデータは
[[<0.1>,<0.2>,<0.3>,・・・,<0.512>],
[<1.1>,<1.2>,<1.3>,・・・,<1.512>],
・・・,
[<7.1>,<7.2>,<7.3>,・・・,<7.512>]]
こんな2次元配列です。
元のスロットデータをout_routeとし、SPIに渡すスロットデータをout_spi_arrayとするなら
out_spi_array = out_route.ravel( 'F' )
あれま、たった一行。
カッコ内の'F'はravelの動作モードを表すものらしい。
これまたPythonの繰り返しコマンドを用いずにnumpyだけで変換出来てしまった。
numpy素晴らしい。
#Python #[Art-Net]
レベル値の2次元配列[ユニバース,スロットアドレス]を1次元配列[スロットアドレス]に変換してSPIに渡すのですが、<ユニバースnのスロットx>を<n.x>と書くなら、
[<0.1>,<1.1>,<2.1>,・・・,<6.1>,<7.1>,<0.2>,<1.2>,<2.2>,・・・,<6.2>,<7.2>,
・・・,
<0.512>,<1.512>,<2.512>,・・・,<6.512>,<7.512>]
としなければなりません。[ユニバース,スロットアドレス]だったものを[スロットアドレス,ユニバース]の順番で1次元配列にするのです。
ちなみに元のスロットデータは
[[<0.1>,<0.2>,<0.3>,・・・,<0.512>],
[<1.1>,<1.2>,<1.3>,・・・,<1.512>],
・・・,
[<7.1>,<7.2>,<7.3>,・・・,<7.512>]]
こんな2次元配列です。
元のスロットデータをout_routeとし、SPIに渡すスロットデータをout_spi_arrayとするなら
out_spi_array = out_route.ravel( 'F' )
あれま、たった一行。
カッコ内の'F'はravelの動作モードを表すものらしい。
これまたPythonの繰り返しコマンドを用いずにnumpyだけで変換出来てしまった。
numpy素晴らしい。
#Python #[Art-Net]
Art-Netは入口の処理がまとまったので肝心のパッチ処理を考えています。
パッチとは入口と出口を1対多の関係で結びつける処理です。基本的な考え方は簡単ですがどう処理したものか。
と、言いますのも、処理の回数が多いので、1回1回の処理を限りなく軽くしないと間に合いません。
単純に考えればfor文を使ってスロット単位に移し替えをすればいいのですが、これではちょいと遅いようです。
何か無いかと調べたところnumpyに良い処理方法がありました。
「ファンシーインデックス」と呼ばれる方法です。
numpyの配列はインデックスで内容を参照できますが、インデックスに配列を使うことも出来、これを「ファンシーインデックス」と呼ぶようです。
パッチにおいては、出力側が参照する入口側のスロットのインデックスを配列にして使います(パッチマップ)。
一番単純な入力1ユニバース-出力1ユニバースを処理するとして、
入口側の配列が5スロットある場合
input = np.array( [ 11, 22, 30, 44, 50 ] )
とし、
これに対するパッチマップを
map = np.array( [ 0, 3, 4, 2, 2, 3, 1 ] )
とした場合、
patched_values = input[ map ] ※ 内部的には input[ [ 0, 3, 4, 2, 2, 3, 1 ] ] と同意
print( patched_values )
>>> [ 11 44 50 30 30 44 22 ]
インデックスの基底数がゼロなので注意が必要ですが、mapに記載されたインデックスでinputを参照し、配列としてoutputを得られます。
入力のスタック(input_stack)が[ delay, route, address ]の3次元配列の場合は、出力側スロット視点で次の3つの配列をインデックスにします。
delay_index_map:スロットごとのディレイレイヤーのインデックスを表すインデックスの配列 (取り扱いスロット数分・現在のカレントindexからオフセット済み)
※ delay_index_map = ( <ディレイレイヤーのスタック数> + <現在のカレントindex> - delay_map ) % <ディレイレイヤーのスタック数>
in_route_map:入力スロットのルートを表すインデックスの配列 (取り扱いスロット数分)
in_slot_map:入力スロットのアドレスを表すインデックスの配列 (取り扱いスロット数分)
※ in_route_mapとin_slot_mapを合わせてpatch_mapとなる。
とすると、
patched_values = input_stack[ [ delay_index_map, in_route_map, in_slot_map ] ]
patched_values は取り扱いスロット数分の1次元配列です。
ディレイの処理も含めて1行のコマンドで出力値を得られます。素晴らしい。
ここでスロットデータが1次元配列になるので、ここから先、出力ポートに渡すまではスロットを1本の通し番号で扱った方が良さそう。
同様の方法でカーブプロファイル変換も出来ます。
カーブプロファイル(curve_profile_values)を 変換後レベル値[ プロファイルナンバー, 元レベル値 ] 、カーブプロファイルマップ(curve_profile_map)をプロファイルナンバー[ スロットアドレス ]とし、変換した配列を curve_converted_values とすると。
curve_converted_values = curve_profile_values[ curve_profile_map, patched_values ]
※ len( curve_profile_map ) == len( patched_values ) がTrueなこと。
curve_converted_valuesを出力ルートとスロットアドレスの2次元配列にするなら、
output_values = curve_converted_values.reshape( <ルートの本数>, 512 )
※ <ルートの本数> × 512 = 取り扱いスロット総数 であること
コマンドが少ないから処理時間が短いとは限りませんが、少なくともfor文を用いた処理より軽いことは間違いありません。
numpy素晴らしい。
#Python #[Art-Net]
パッチとは入口と出口を1対多の関係で結びつける処理です。基本的な考え方は簡単ですがどう処理したものか。
と、言いますのも、処理の回数が多いので、1回1回の処理を限りなく軽くしないと間に合いません。
単純に考えればfor文を使ってスロット単位に移し替えをすればいいのですが、これではちょいと遅いようです。
何か無いかと調べたところnumpyに良い処理方法がありました。
「ファンシーインデックス」と呼ばれる方法です。
numpyの配列はインデックスで内容を参照できますが、インデックスに配列を使うことも出来、これを「ファンシーインデックス」と呼ぶようです。
パッチにおいては、出力側が参照する入口側のスロットのインデックスを配列にして使います(パッチマップ)。
一番単純な入力1ユニバース-出力1ユニバースを処理するとして、
入口側の配列が5スロットある場合
input = np.array( [ 11, 22, 30, 44, 50 ] )
とし、
これに対するパッチマップを
map = np.array( [ 0, 3, 4, 2, 2, 3, 1 ] )
とした場合、
patched_values = input[ map ] ※ 内部的には input[ [ 0, 3, 4, 2, 2, 3, 1 ] ] と同意
print( patched_values )
>>> [ 11 44 50 30 30 44 22 ]
インデックスの基底数がゼロなので注意が必要ですが、mapに記載されたインデックスでinputを参照し、配列としてoutputを得られます。
入力のスタック(input_stack)が[ delay, route, address ]の3次元配列の場合は、出力側スロット視点で次の3つの配列をインデックスにします。
delay_index_map:スロットごとのディレイレイヤーのインデックスを表すインデックスの配列 (取り扱いスロット数分・現在のカレントindexからオフセット済み)
※ delay_index_map = ( <ディレイレイヤーのスタック数> + <現在のカレントindex> - delay_map ) % <ディレイレイヤーのスタック数>
in_route_map:入力スロットのルートを表すインデックスの配列 (取り扱いスロット数分)
in_slot_map:入力スロットのアドレスを表すインデックスの配列 (取り扱いスロット数分)
※ in_route_mapとin_slot_mapを合わせてpatch_mapとなる。
とすると、
patched_values = input_stack[ [ delay_index_map, in_route_map, in_slot_map ] ]
patched_values は取り扱いスロット数分の1次元配列です。
ディレイの処理も含めて1行のコマンドで出力値を得られます。素晴らしい。
ここでスロットデータが1次元配列になるので、ここから先、出力ポートに渡すまではスロットを1本の通し番号で扱った方が良さそう。
同様の方法でカーブプロファイル変換も出来ます。
カーブプロファイル(curve_profile_values)を 変換後レベル値[ プロファイルナンバー, 元レベル値 ] 、カーブプロファイルマップ(curve_profile_map)をプロファイルナンバー[ スロットアドレス ]とし、変換した配列を curve_converted_values とすると。
curve_converted_values = curve_profile_values[ curve_profile_map, patched_values ]
※ len( curve_profile_map ) == len( patched_values ) がTrueなこと。
curve_converted_valuesを出力ルートとスロットアドレスの2次元配列にするなら、
output_values = curve_converted_values.reshape( <ルートの本数>, 512 )
※ <ルートの本数> × 512 = 取り扱いスロット総数 であること
コマンドが少ないから処理時間が短いとは限りませんが、少なくともfor文を用いた処理より軽いことは間違いありません。
numpy素晴らしい。
#Python #[Art-Net]
Art-Netを受信してから一時保存する流れ
● Art-Netの受信・・・タイムアウトしたらすべての受信情報を初期化する
● 受信日時の取得
● 受信したバイナリをデコード
● 対象ユニバースか確認
● ルートIDを取得
● 送信元のIDを取得・新規送信元なら保存し送信元IDを取得
● 送信元の最終受信日時を上書き保存
● 送信元,ルートの最終受信日時を上書き保存
● 送信元,ルートで受信値を上書き保存(必ず512スロットで保存)
タイムアウト処理・・・0.2~0.5秒毎
● 送信元のタイムアウトを確認・・・タイムアウトしていたら送信元からの受信情報を初期化する
● ユニバースのタイムアウトを確認・・・タイムアウトしていたらユニバースをゼロデータにする
次工程からの読み出し要求への返信
● 送信元,ルートで保存した受信値から最大値を取り出す
● 返信
といった感じで、細かいコマンド処理とアルゴリズムが見えてきましたが、本業が忙しくなってソースを書くことが出来ません。
#Python #[Art-Net]
● Art-Netの受信・・・タイムアウトしたらすべての受信情報を初期化する
● 受信日時の取得
● 受信したバイナリをデコード
● 対象ユニバースか確認
● ルートIDを取得
● 送信元のIDを取得・新規送信元なら保存し送信元IDを取得
● 送信元の最終受信日時を上書き保存
● 送信元,ルートの最終受信日時を上書き保存
● 送信元,ルートで受信値を上書き保存(必ず512スロットで保存)
タイムアウト処理・・・0.2~0.5秒毎
● 送信元のタイムアウトを確認・・・タイムアウトしていたら送信元からの受信情報を初期化する
● ユニバースのタイムアウトを確認・・・タイムアウトしていたらユニバースをゼロデータにする
次工程からの読み出し要求への返信
● 送信元,ルートで保存した受信値から最大値を取り出す
● 返信
といった感じで、細かいコマンド処理とアルゴリズムが見えてきましたが、本業が忙しくなってソースを書くことが出来ません。
#Python #[Art-Net]
Art-Netを受信した後、送信元別だった受信値をミックス(HTP)する方法。
numpy.maxを用いれば簡単
受信値を3次元のnumpy.arrayで保存します。
3次元のnumpy.arrayはエクセルでイメージするとわかりやすいかなと。
1スロットの受信値は0-255の数値で、これが横方向(行)に512個並んだ状態をユニバースとします。
これをルート別に縦方向(列)で並べます。ここまでは縦横の1枚のシートです。
この1枚を送信元別のシートとし、レイヤーとして重ねます。もちろん、スロットアドレスとルートは同様にします。
あとはレイヤーを串刺しで最大値を得ればHTPでミックスしたルートとスロットの2次元のnumpu.arrayを得られます。
numpyをnpの名前でimportし、3次元のnumpy.arrayをan_cache_senders_route、最大値の2次元のnumpy.arrayをan_cache_htpとすると次の様になります。
an_cache_htp = np.max( an_cache_senders_route, axis=0 )
こんな感じの1行で計算出来ます。axis=0は最大値を得る次元方向の指示です。3次元なら、axis=2は横で、axis=1は縦で、axis=0は奥行という指示です。
以下、ちょいとオレメモ
受信値、付随するデータ
an_bytes 受信したArt-Netパケットのデータ(type=bytes、別途デコード必要)
an_sender_ipaddress 受信したArt-Netパケットの送信元IPアドレス(type=string、4つのドット切り10進数 IPv4の一般的な表記)
an_received_datetime 受信された時点でdatetime.datetime.now()により取得した日時(type=datetime.datetime)
処理の処理を指示するデータ
an_universes2route 対象ユニバースの1次元配列 ( Net, Subnet, Universe )[ ルート ]
受信値を処理、管理するデータ
an_ipaddress_senders 送信元のIPアドレスの1次元配列 IPアドレス [ 送信元 ]
an_datetime_senders 送信元ごとの最終受信日時の1次元配列 最終受信日時 [ 送信元 ]
an_datetime_senders_route 送信元ごとにルートの最終受信日時の2次元配列 最終受信日時 [ 送信元, ルート ]
an_cache_senders_route 送信元とルートごとに受信値を保存する3次元配列 受信値 [ 送信元, ルート, スロットアドレス ]
an_cache_htp 次の処理へ渡す処理済み受信値の2次元配列 受信値 [ ルート, スロットアドレス ]
※ [ ]内はインデックスの要素([3次元目,2次元目,1次元目])
※ 同名のindexは同じ値になるように設定
#an_ipaddress_senders から an_sender_ipaddress と同じIPアドレスを持つ[ 送信元 ]のindex配列を得る
list( zip( *np.where( an_ipaddress_senders == an_sender_ipaddress ) ) )
※ 受信した際に重複しない様に送信元情報を保存してインデックスを発行し、送信元別に日時と受信値を保存するために使う。
※ ただし、対象のユニバースを送って来ない送信元は無いものとする。早い段階でフィルタしないと後が面倒。
#an_datetime_senders から現在日時より1秒以上前の日時を持つ[ 送信元 ]のindexの配列を得る
list( zip( *np.where( an_datetime_senders < ( datetime.datetime.now() - datetime.timedelta( seconds=1 ) ) ) ) )
※ 送信元の存在を確認するために使う。1秒間受信が無い送信元は無いものとする。
#an_datetime_senders_route から現在日時より1秒以上前の日時を持つ[ 送信元, ルート ]のindexの配列を得る
list( zip( *np.where( an_datetime_senders_route < ( datetime.datetime.now() - datetime.timedelta( seconds=1 ) ) ) ) )
※ ユニバースの存在を確認するために使う。1秒間受信が無いユニバース(=送信元,ルート)はゼロデータにする。
#Python #[Art-Net]
numpy.maxを用いれば簡単
受信値を3次元のnumpy.arrayで保存します。
3次元のnumpy.arrayはエクセルでイメージするとわかりやすいかなと。
1スロットの受信値は0-255の数値で、これが横方向(行)に512個並んだ状態をユニバースとします。
これをルート別に縦方向(列)で並べます。ここまでは縦横の1枚のシートです。
この1枚を送信元別のシートとし、レイヤーとして重ねます。もちろん、スロットアドレスとルートは同様にします。
あとはレイヤーを串刺しで最大値を得ればHTPでミックスしたルートとスロットの2次元のnumpu.arrayを得られます。
numpyをnpの名前でimportし、3次元のnumpy.arrayをan_cache_senders_route、最大値の2次元のnumpy.arrayをan_cache_htpとすると次の様になります。
an_cache_htp = np.max( an_cache_senders_route, axis=0 )
こんな感じの1行で計算出来ます。axis=0は最大値を得る次元方向の指示です。3次元なら、axis=2は横で、axis=1は縦で、axis=0は奥行という指示です。
以下、ちょいとオレメモ
受信値、付随するデータ
an_bytes 受信したArt-Netパケットのデータ(type=bytes、別途デコード必要)
an_sender_ipaddress 受信したArt-Netパケットの送信元IPアドレス(type=string、4つのドット切り10進数 IPv4の一般的な表記)
an_received_datetime 受信された時点でdatetime.datetime.now()により取得した日時(type=datetime.datetime)
処理の処理を指示するデータ
an_universes2route 対象ユニバースの1次元配列 ( Net, Subnet, Universe )[ ルート ]
受信値を処理、管理するデータ
an_ipaddress_senders 送信元のIPアドレスの1次元配列 IPアドレス [ 送信元 ]
an_datetime_senders 送信元ごとの最終受信日時の1次元配列 最終受信日時 [ 送信元 ]
an_datetime_senders_route 送信元ごとにルートの最終受信日時の2次元配列 最終受信日時 [ 送信元, ルート ]
an_cache_senders_route 送信元とルートごとに受信値を保存する3次元配列 受信値 [ 送信元, ルート, スロットアドレス ]
an_cache_htp 次の処理へ渡す処理済み受信値の2次元配列 受信値 [ ルート, スロットアドレス ]
※ [ ]内はインデックスの要素([3次元目,2次元目,1次元目])
※ 同名のindexは同じ値になるように設定
#an_ipaddress_senders から an_sender_ipaddress と同じIPアドレスを持つ[ 送信元 ]のindex配列を得る
list( zip( *np.where( an_ipaddress_senders == an_sender_ipaddress ) ) )
※ 受信した際に重複しない様に送信元情報を保存してインデックスを発行し、送信元別に日時と受信値を保存するために使う。
※ ただし、対象のユニバースを送って来ない送信元は無いものとする。早い段階でフィルタしないと後が面倒。
#an_datetime_senders から現在日時より1秒以上前の日時を持つ[ 送信元 ]のindexの配列を得る
list( zip( *np.where( an_datetime_senders < ( datetime.datetime.now() - datetime.timedelta( seconds=1 ) ) ) ) )
※ 送信元の存在を確認するために使う。1秒間受信が無い送信元は無いものとする。
#an_datetime_senders_route から現在日時より1秒以上前の日時を持つ[ 送信元, ルート ]のindexの配列を得る
list( zip( *np.where( an_datetime_senders_route < ( datetime.datetime.now() - datetime.timedelta( seconds=1 ) ) ) ) )
※ ユニバースの存在を確認するために使う。1秒間受信が無いユニバース(=送信元,ルート)はゼロデータにする。
#Python #[Art-Net]
オレメモ
受信時に得られるArt-Netの情報
・Art-Netパケットのバイナリデータ
・送信元IPv4アドレス
・受信日時
指示データ
・ユニバースとルートの対照マップ
受信処理のアウトプット
・ルートで仕訳けた直近の受信値(直近値)
処理の第一段階
・バイナリデータのデコード
・インデックスをユニバースからルートへ変換
処理の第二段階
・送信元を有効期限でフィルタ出来るキャッシュ
・送信元ごとに、デコードしたデータを有効期限でフィルタ出来るキャッシュ
処理の第三段階
・送信元を有効期限でフィルタ(送信元が期限切れなら受信データもクリア)
・受信データを有効期限でフィルタ
処理の第四段階
・送信元ごとの受信データを一つにまとめ、ルート単位の直近値とする(実質ミックス処理)
処理の第五段階
・直近値を次に渡す
#[Art-Net]
受信時に得られるArt-Netの情報
・Art-Netパケットのバイナリデータ
・送信元IPv4アドレス
・受信日時
指示データ
・ユニバースとルートの対照マップ
受信処理のアウトプット
・ルートで仕訳けた直近の受信値(直近値)
処理の第一段階
・バイナリデータのデコード
・インデックスをユニバースからルートへ変換
処理の第二段階
・送信元を有効期限でフィルタ出来るキャッシュ
・送信元ごとに、デコードしたデータを有効期限でフィルタ出来るキャッシュ
処理の第三段階
・送信元を有効期限でフィルタ(送信元が期限切れなら受信データもクリア)
・受信データを有効期限でフィルタ
処理の第四段階
・送信元ごとの受信データを一つにまとめ、ルート単位の直近値とする(実質ミックス処理)
処理の第五段階
・直近値を次に渡す
#[Art-Net]
オレメモ
● Art-Netの受信の準備でするべきこと。
・受信のタイムアウトを定義し、タイムアウトを例外としてキチンと処理する。
● Art-Netを受信したらするべきこと。
・受信した「Art-Netのバイナリデータ」に「いつ」「どこからか(送信元)」を絡めて受信データとする。
・ユニバースと内部ルートの対照データを基に、データの参照キーを「ユニバース」から「ルート」に変換してキャッシュする。
・「いつ」をキーに送信元からの送信が無くなったと見なせるならキャッシュも含め送信元情報を消去する。
・「いつ」をキーにキャッシュの有効期限が切れたならキャッシュのレベル値をすべてゼロにする。
・送信元ごとのキャッシュをルートで丸めて一意のキャッシュにする。
#[Art-Net]
● Art-Netの受信の準備でするべきこと。
・受信のタイムアウトを定義し、タイムアウトを例外としてキチンと処理する。
● Art-Netを受信したらするべきこと。
・受信した「Art-Netのバイナリデータ」に「いつ」「どこからか(送信元)」を絡めて受信データとする。
・ユニバースと内部ルートの対照データを基に、データの参照キーを「ユニバース」から「ルート」に変換してキャッシュする。
・「いつ」をキーに送信元からの送信が無くなったと見なせるならキャッシュも含め送信元情報を消去する。
・「いつ」をキーにキャッシュの有効期限が切れたならキャッシュのレベル値をすべてゼロにする。
・送信元ごとのキャッシュをルートで丸めて一意のキャッシュにする。
#[Art-Net]
実機を離れて考えを進めると抜けが見えてきます。
一つ前のオレメモはArt-Netを受信していないときの対策です。タイムアウトを設定しませんと延々と待つだけの無限ループになり、適切な終了すら出来なくなります。一定時間受信が無いならそれをユーザーに伝えることも大切な処理です。
その前の送信元が複数になった時の対策もそうです。ミキサー機能が無いと謳っても複数の接続をする人が居ないとも限りませんし、そんな人に限って勝手な想像通りに動かないと作った奴が悪いとかダメな製品だとかレッテルを貼ってくるものです。この件については副産物としてミキサー機能に至れそうな可能性が見えましたので「災い転じて何とやら」ですが、先入観を排除して可能性を熟慮することの大切さを改めて痛感です。
受信処理は試行錯誤しながらディレイを可能にしたことでソースコードが読みにくくなってきましたので、タイムアウトと複数の送信元への対応を加えながら読みやすく書き直しです。
パラメータが増えてくると変数の命名に配慮するだけでも読みやすさが違ってきますので、この辺りも含めてよく考えていきます。
ここまでやってきて、思った以上に受信処理が大切なことに驚いています。
ミキサーしかり、ディレイしかり、思い描いている機能の大半が受信直後の処理にかかっていたとは当初は全く思いもしませんでした。
この辺りは所詮アマチュアの所業でありますが、まだまだ修行です。
#Python #[Art-Net]
一つ前のオレメモはArt-Netを受信していないときの対策です。タイムアウトを設定しませんと延々と待つだけの無限ループになり、適切な終了すら出来なくなります。一定時間受信が無いならそれをユーザーに伝えることも大切な処理です。
その前の送信元が複数になった時の対策もそうです。ミキサー機能が無いと謳っても複数の接続をする人が居ないとも限りませんし、そんな人に限って勝手な想像通りに動かないと作った奴が悪いとかダメな製品だとかレッテルを貼ってくるものです。この件については副産物としてミキサー機能に至れそうな可能性が見えましたので「災い転じて何とやら」ですが、先入観を排除して可能性を熟慮することの大切さを改めて痛感です。
受信処理は試行錯誤しながらディレイを可能にしたことでソースコードが読みにくくなってきましたので、タイムアウトと複数の送信元への対応を加えながら読みやすく書き直しです。
パラメータが増えてくると変数の命名に配慮するだけでも読みやすさが違ってきますので、この辺りも含めてよく考えていきます。
ここまでやってきて、思った以上に受信処理が大切なことに驚いています。
ミキサーしかり、ディレイしかり、思い描いている機能の大半が受信直後の処理にかかっていたとは当初は全く思いもしませんでした。
この辺りは所詮アマチュアの所業でありますが、まだまだ修行です。
#Python #[Art-Net]
本日は久しぶりの現地照明。現場って感じでホッとします。
実機での研究や試験は出来ませんが、アイデアが出てきたら整理しています。今日出てきたアイデアはArt-Netの受信に関するものです。
Art-Netは複数の送信機を同じネットワークに接続することが出来ます。正しくはないけど間違ってもいない使い方ですが、期待してない挙動が起こっても面白くないので対応しといた方が良さそう。
socketによる受信からはデータと送信元アドレスを取り出せますから、送信元アドレスをキーにデータを仕分けます。採用するデータは送信元を一つに限るのが道理な気もしますが、同じユニバース・スロットの最大値を採用したらHTPのミキサーになってしまいます。
ミキサーは欲しい機能ですが、バカよけを施した副産物でミキサーになりそう。
#[Art-Net]
実機での研究や試験は出来ませんが、アイデアが出てきたら整理しています。今日出てきたアイデアはArt-Netの受信に関するものです。
Art-Netは複数の送信機を同じネットワークに接続することが出来ます。正しくはないけど間違ってもいない使い方ですが、期待してない挙動が起こっても面白くないので対応しといた方が良さそう。
socketによる受信からはデータと送信元アドレスを取り出せますから、送信元アドレスをキーにデータを仕分けます。採用するデータは送信元を一つに限るのが道理な気もしますが、同じユニバース・スロットの最大値を採用したらHTPのミキサーになってしまいます。
ミキサーは欲しい機能ですが、バカよけを施した副産物でミキサーになりそう。
#[Art-Net]
Art-Netは受信したデータのスタックの仕方を変えてうまくいきました。
約1/100秒毎でスタックし、1/40秒毎で出力しています。
試験的な処理ですが、Delayもユニバース単位で綺麗に動きます。
Art-Netの送受信の試験製作はこれにて終了。
ただ、テストで使っていた中華電器のArt-Netデコーダが不良品でした。
8アウトの製品ですが、普通に使うとDMXポートが1つしか信号を出さない。
組み合わせを吟味すると半分の4ポートは出力されますが、マニュアル通りに使って正しく動かないのでは現場じゃ使えません。
届いた時にMAdot2でテストしてちゃんと動いたような気がするのですが・・・
Art-Netのデコーダは市販品もありますが、RaspberryPiでここまで出来てしまうと自作した方が圧倒的に安い。市販品の国内価格は7-8万円ですが、材料費だけなら2万もしません。
レガシーDMXのインターフェースは基板から自作になりますが、PICマイコンでSPIからDMXにプロトコル変換するだけなのでそれほど難しくないハズ。パッチマシンとしてまとめる際には必要ですから作ってしまいましょう。
#RaspberryPi #[Art-Net]
約1/100秒毎でスタックし、1/40秒毎で出力しています。
試験的な処理ですが、Delayもユニバース単位で綺麗に動きます。
Art-Netの送受信の試験製作はこれにて終了。
ただ、テストで使っていた中華電器のArt-Netデコーダが不良品でした。
8アウトの製品ですが、普通に使うとDMXポートが1つしか信号を出さない。
組み合わせを吟味すると半分の4ポートは出力されますが、マニュアル通りに使って正しく動かないのでは現場じゃ使えません。
届いた時にMAdot2でテストしてちゃんと動いたような気がするのですが・・・
Art-Netのデコーダは市販品もありますが、RaspberryPiでここまで出来てしまうと自作した方が圧倒的に安い。市販品の国内価格は7-8万円ですが、材料費だけなら2万もしません。
レガシーDMXのインターフェースは基板から自作になりますが、PICマイコンでSPIからDMXにプロトコル変換するだけなのでそれほど難しくないハズ。パッチマシンとしてまとめる際には必要ですから作ってしまいましょう。
#RaspberryPi #[Art-Net]