0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

簡易MIDIシーケンサ(Mido)とシグナルタワー(パトライト)で星野源をアゲアゲにする

Last updated at Posted at 2020-05-24

はじめに

画像処理の勉強のためにパトライトの点灯状況をカメラから取得するプログラムを作っているつもりが、いつの間にか星野源をアゲアゲにしていました。どうしてこうなった。
スクリーンショット 2020-05-24 14.54.24.png

作成した動画 

今回使用した楽譜

星野源「うちで踊ろう」をmusescoreで楽譜を書き起こしてmidi化。(単音)

Midoとは

Midiファイルの読み取り、Midiメッセージの送信などを簡単に行うことができるpythonライブラリ。
https://mido.readthedocs.io/en/latest/
実装にあたっては、こちらを参考にしました。
https://qiita.com/tjsurume/items/75a96381fd57d5350971

Midiシーケンサとは

(簡単に言うと)Midiメッセージ受付可能なデバイスに、Midiメッセージを送信して音楽を演奏させる機構を持つもの

シグナルタワーとは

工場などで工作機械などの動作状況を信号等でお知らせするもの。遠くからでもよく見えます。今回はご家庭にもよくあるパトライト社のシグナルタワー「NHS-FB2」を使用しています。http://www.patlite.jp/product/nh-spl.html

技術概要

用語整理

  • 鳴音/消音:MIDIデバイスに発音/消音させること
  • 点灯/消灯:シグナルタワーに点灯/消灯させること

MIDIシーケンサ部(Python,Mido)

  • 鳴音(消音含む)単位で、MIDIメッセージ(msg)を作成する
  • msg note_onメッセージのみみることとしています。概要は以下のとおり。
    • channel→今回は考慮しない
    • note→音程
    • velocity→音量
    • time→前のメッセージから、次のメッセージを鳴動させるまでの時間
  • 一度に送信するのではなく、時間で分割し、鳴音(消音)させたいタイミングでmsgをMIDIデバイスに送信している。

シグナルタワー接続部

  • パトライトにURLクエリパラメータを投げる
  • msg.noteの値によって点灯/消灯するライトの種類を変更する

シグナルタワーの仕組み

  • ネットワークで接続。点灯させるパラメータをURLクエリパラメータ(alert)に含め、送信する
  • 上位3ビットがそれぞれ三色のシグナルタワーに対応している。(下位3ビットはブザー。今回は未使用)
http://192.168.10.1/api/control?alert=000000

技術課題 

シグナルタワーはネットワーク接続であるため、遅延が発生する

  • そもそもこの製品は遅延があることを許容される製品である
  • URLクエリを投げてからレスポンスを受け取るまでの時間を計算し、次回の待ち時間を調整

MIDIメッセージに「消音」が毎回挟まれる

  • スラーで繋いでいない音形なのだから毎回消音があるのは当然
  • 「消音」=「消灯」として毎回リクエスト送信すると、消音の部分が間に合わない
  • 基本は消音の場合、シグナルタワーにリクエストを送信しない設計にした
    • ただし、その場合に「消音」時でも常に点灯し続ける問題が発生
  • ウォッチドッグタイマの機構を導入
    • 「消音」時にウォッチドッグタイマをスタートさせる、時間内にリセットされなければ「消灯」リクエストを送信
    • 「鳴音」時にウォッチドッグタイマをストップさせる。 
    • 一定時間「消音」のときのみ、「消灯」リクエストを送信できるようにした

そもそも動画とMIDIのテンポが合わない

  • 動画編集でどうにかしました(気合い)

プログラム

mido-patlite.py
import mido
import time
import urllib.request
from threading import Timer

ports = mido.get_output_names()
url_base = 'http://192.168.10.1/api/control?alert='
url_val = ['000000','001000','010000','011000','100000','101000','110000','111000']
note_idx = [0,50,52,55,57,59,60,62]
watchdog_time = 0.1
elapsed_time = 0

class Watchdog:
  def __init__(self, timeout, userHandler=None):
    self.timeout = timeout
    self.handler = userHandler if userHandler is not None else self.defaultHandler
    self.timer = Timer(self.timeout, self.handler)
    self.timer.start()

  def reset(self):
    self.timer.cancel()
    self.timer = Timer(self.timeout, self.handler)
    self.timer.start()

  def stop(self):
    self.timer.cancel()

  def defaultHandler(self):
    raise self

def myHandler():
  global watchdog
  url = url_base + url_val[0]
  print(url) # Debug Code
  req = urllib.request.urlopen(url)
  watchdog.stop()

watchdog = Watchdog(watchdog_time, myHandler)
watchdog.stop()

with mido.open_output(ports[0]) as outport:
  for msg in mido.MidiFile('DanceOnTheInside.mid'):
    sleep_time = msg.time - elapsed_time
    if sleep_time <0:
      msg.time = msg.time + sleep_time
      elapsed_time = abs(sleep_time)
      sleep_time = 0
    else:
      elapsed_time = 0

    time.sleep(sleep_time)
    if not msg.is_meta:
      if(str(msg.type)=="note_on"):
        if(msg.velocity == 0):
          watchdog.reset()
        else:
          index = note_idx.index(msg.note)
          url = url_base + url_val[index]
          print(url) # Debug Code

          start = time.time()
          req = urllib.request.urlopen(url)
          elapsed_time = elapsed_time + time.time() - start
          watchdog.stop()

      outport.send(msg) 

おわりに

  • ネットワークの実遅延と、MIDIデバイスは(限界があるものの)ある程度歩み寄れることが分かりました
  • 最初の自分の課題をなんとかしないと・・
     
0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?