【TouchDesigner】MIDI通信時の不要なnoteをPythonで制御する

備忘録です。

TouchDesignerにMIDIコントローラーを繋げて遊ぼうとしたところ、思わぬ挙動に遭遇。 Pythonを利用して解決したという内容です。

noteが2つ出る

MIDIコントローラーのボタンを押した時に拾ったnoteを見ると同じ信号を二つ送信していました。

今回行いたかった制御は ボタンを押したら映像が切り替わる です。

つまりこのままだと瞬時に2回押されていることになり、映像もババッと二度切り替わるという事態に。
これをコードを書いて制御し、解決しました。

CHOP Execute DAT を利用する

CHOP Execute DATの中にコードを書いて今回の信号の問題を解決しました。
信号は二度送られますが、一度目と二度目の時間の差を見て短すぎれば二度目で0を送るという仕組みです。
CHOP Execute DATに予め用意されているonOffToOnを利用し、信号が送られたときに発火するようにします。

constantObj = op('constant3') # 通信時のtimeを保持する変数(Constant CHOP)
lastSeconds = constantObj.par.value0 # 保持したtime

forwardObj = op('constant1') # 値を送信したいオブジェクト

def onOffToOn(channel, sampleIndex, val, prev):        
    now = absTime.seconds
    diff = now - lastSeconds
    
    constantObj.par.value0 = now # ボタン押下時のtimeを保持
    
    if diff < 0.1:
        forwardObj.par.value1 = 0 # 二度目は0を返す
        return
        
    forwardObj.par.value1 = 1 # 一度目は1を返す
    
    return

これでボタンを1回押したときの挙動は「1が代入されたあと、0が代入される」となります。 (制御前は「1 → 0 → 1 → 0」)

映像の切り替わりも無事1回だけになりました。

なぜ2回送信されるのか

未だに謎です。 そもそもそれがスタンダード? そんなことあるのか?

同じような場面で毎度このコードを引っ張り出してくると思うと少々億劫です。
TouchDesignerでこのようなDATをモジュール化していつでも使えるようにできると思うのですが、その辺のやり方が分かっていない。
音のパラメータを3バンドで分けるロジックもいちいち構築しているので、早めに習得したいですね。

2022年を振り返る

今年ももう終わりを迎えますね。
ふと1年の振り返りをしたことってあんまりないなと思いました。
ということで雑に個人的2022年の振り返りを残します。

 

と下書きを書き、気づけば2023年1月3日
遅れた振り返りを投稿します。

くら寿司にハマる

くら寿司は素晴らしい。
サイドメニューが豊富で子供と行きやすく、外食となれば必ずくら寿司を候補にあげていました。
最近はかっぱ寿司にもよく行きます。
混んでなければスシローにも行きたい。

例年よりも風邪をひいた

というのも1歳8ヶ月の娘が保育園でもらってきたものばかり。
12月24日、25日は胃腸炎をもらい悶え、なかなかのクリスマスを過ごしました。

一軍キーボードが定まる

たくさんのキーボードを3年ほど前から試しに試し、結果的に
・HHKB Professional HYBRID Type-s
・BAROCCO MD600v3
を気分で使い分けるという形に収束しました。
長い旅でした。

 

そして未だにちょっと気になるのはこちらのキーボード

7sProshop.yushakobo.jp

HHKB配列の分離なんて良いに決まってるんだよな〜。
収束してない?

家族で京都旅行に

当時1歳と1ヶ月の娘を飛行機に乗せ、京都へ行きました。
抱っこ紐をしながら約2万歩を歩きお寺を巡ったり。
鈴虫寺というお寺へ必ず願いを叶えてくれるというお地蔵さんに会いにいったり。

幼い子を連れての旅行は不安もありましたがとても大人しくしてくれ、
大人たちは楽しむことができました。娘よ、ありがとう。

競馬の勝率44%・・・

はい。
2023年こそは100%超えを目指して・・・。

 

久しぶりのQUAT OUT

QUAT OUTとは数年前まで仙台で定期的に行われていた音楽×映像なクリエイティビティ溢れるイベントです。
ある日オーガナイザーの一人、Kannoさんからお声がけいただき、
久々にメンバー全員が集まっての開催となりました。

日々早朝に起きてライブの準備をし、当日なんとか間に合ったのを覚えています。
昨年はこれがきっかけで音楽を作る熱が復活。
そしてさすがにAbleton Live9から11にしました。

画像はSatoshi Kannoさんのライブ。
何台だったか覚えてないほどのPCを使った圧巻のパフォーマンスでした。

www.youtube.com

私もやりきりました。楽しかった〜!

株式会社iCAREに転職

9月1日から現職、株式会社iCAREに転職しました。
職種は同じくエンジニア。

以前よりパートナーとしてお手伝いはしていたものの、正社員となったからにはドメイン知識をより叩き込む必要がでてきたり、より制作物に責任が伴ったりと「あー、業務委託と正社員って全然違うなぁ」という感覚に襲われました。いい意味で。

今年は課題ばかり

入社して、丸4ヶ月。
開発に対してもそうですし、担っている立場に対しても課題が多く残った4ヶ月だったと思います。

2023年はこれを糧に頑張りたい所存。

社員でイベントが組めそう

まず入社初日で「Takaaki ItoさんとDJされてましたよね」とデザイナーの方に声をかけられ、同期がDJ & 作曲家。私の数日後に入社された方はかなりの経験をお持ちのVJの方。

すごいなぁ東京。
いつか社員オンリーでイベントを組んでみたいです。

奥さんの躍動が半端じゃなかった

私の奥さんは今年、大きな躍進を遂げました。

JHA

Japan Hairdressing Awards(JHA)という大きなコンテストで見事ノミネートを果たし、表彰式の舞台に招待されるという快挙を果たしました。
なんかもう凄過ぎました。
「いつかあの舞台に家族を連れていく」と言っていた奥さん。
一つ夢を叶えました。

www.j-h-a.comSENSIBILITY2022 

SENSIBILITYという東北エリアのコンテストではなんとグランプリを受賞。
もう凄過ぎますね。

apolloshoji.co.jp

お店を拡大し、髪だけでなく身体から整う美容を目指す

以前からトータルでケアをしたいという思いから様々な勉強をしていました。
ヘアケアからボディケアの領域に手を広げ、ついに今年から本格的にスタートします。
なんだかもうほんと凄いですね(3回目)。

お金じゃなく、常に人を綺麗にしたい一心で努力を続けてきた結果が花開いた年だったのかなと傍らで見ていました。
今年は私も見習って頑張ろうと思います。

2022年ののクリエイティブコーディング

p5.jsからTouchDesignerへ

2021年はほぼ一人p5.jsアドベントカレンダーを書くなど、p5に打ち込む日々を過ごしていました。

しかし自分がやってみたいことにはリアルタイムレンダリングが必要と判断し、TouchDesignerを使うことにしました。

改めて初学者の勢いで着手しましたが、3Dモデルまわりの考え方や座標などなど、p5で学んだことがかなり活かされているように思います。

YouTubeを始める

Ableton LiveとTouchDesignerで制作した映像を外に出そうと思い、YouTubeを始めました。
年内で再生数30、チャンネル登録者1人くらいいけば良かったところ、各動画数百回、チャンネル登録者14人と思った以上でした。

いつも作ってはTwitterに載せるくらいでしたが、YouTubeにステレオな環境で観てもらえる場を作れたのはとても良いことでした。

www.youtube.com

 

2023年は

  • 今の仕事により向き合う
  • 趣味に費やす時間を増やす
  • 読書時間を復活させる
  • 健康第一

を目標に、何事も楽しく取り組んでいきます。

元旦に壁に貼った毎日の目標



【TouchDesigner】音の周波数を分割して取り出す

すぐ忘れるからメモ。
こちらの動画を参考にしました。

www.youtube.com

1. リサンプルする

Audio File In chopで音を読み込んだらAudoio Spectram chop につないで低周波〜高周波をマッピングする。
Audoio Spectram chopOutput LengthSet Length Manuallyにして、予めサンプル数を減らしておく。
またここで極端に減らすと不具合が起こるらしく、resampleでやるのが無難らしい。

で、情報をみるとSpectramで設定されているものと同じ2048の点で表している。

ここまで利用することはないので、Resample chopに繋いでサンプルの数を減らす。 commonタブのTime SliceをOffにする。
さらにResampleタブのMethodをNew Rate, New Intervalに。Unit ValuesをAbsoluteに。
StartとEndの設定をsecondsからsampleにしたら、好きな量のサンプルを設定する(今回は600にしたかったので0~599)。

ちなみにMethodについてはリファレンスを見ると下記のように書いてある。
正直よくわからない。

New Rate, New Interval / newint サンプルレートとCHOPの伸縮の両方を変更します。

リサンプル後の頂点を取り出す

Resample chopInfo chopに食わせ、Select chopでlengthだけを取り出す。
これを次のTrim chopで利用する。

Trimで音域ごとに分ける

Resample chopから3つTrim chopを繋いだら、先ほどのSelect chopのlengthをから切り出す部分を指定する。
Unit ValuesをAbsoluteにし、各StartとEndを次のように設定。

# High
op('select1')['length'] * 2/3 # start
op('select1')['length'] # end

# Mid
op('select1')['length'] / 3 # start
op('select1')['length'] * 2/3 # end

# Low
0 # start
op('select1')['length'] / 3 # end

最後にNull chopにそれぞれつないで完了。

あとがき

前述の動画のResample部分は比嘉 了さんのブログを参考にしたとのこと。

twitter.com

satoruhiga.com

動画もブログも大変参考になりました。

GraphQL Mutationのテストにて、整数な引数が型エラーで怒られた

RspecでGraphQLのmutationを叩いたときに問題が発生したのでメモ。

mutationが謎に落ちた

下記のようなユーザー登録のmutationのspecを実行しようとした。
(graphql-deviseのmutationをテスト)

let!(:query) do
  <<~GRAPHQL
    mutation userRegister(
      $email: String!
      $password: String!
      $passwordConfirmation: String!
      $gender: Int!
    ) {
      userRegister (
        email: $email,
        password: $password,
        passwordConfirmation: $passwordConfirmation,
        gender: $gender,
      ) {
        credentials {
          accessToken
        }
        user {
          email
          gender
        }
      }
    }
  GRAPHQL
end

let!(:path) { '/graphql_auth' }
let!(:variables) { 
  { 
    email: 'test@example.com', 
    password: 'password1234!', 
    passwordConfirmation: 'password1234!',
    gender: 0,
  } 
}
let!(:params) { { query: query, variables: variables } }
let(:post_request) { post path, params: params }

before do
  post_request
end

it 'ユーザーが作成されている' do
  expect(User.count).to eq 1
end

だがテストが失敗する。。

Failure/Error: expect(Coach.count).to eq 1

  expected: 1
      got: 0

  (compared using ==)
# ./spec/requests/mutations/coach/register.rb:95:in `block (3 levels) in <top (required)>'

Finished in 40.95 seconds (files took 7.89 seconds to load)
1 example, 1 failure

エラーの詳細も出てこず、何が原因かよくわからなかった。

gemの中を見にいく

同僚に相談したところ、gemの中でbinding.pryする方法を教えていただいた。
docekrコンテナでvimを使えるようにした後bundle open graphql_devise
graphql-deviseのファイルを開き、
graphql_devise/graphql_controller.rbbinding.pryを差し込む。

再びテストを実行すると止まってくれた。

    9: def auth
    10:   binding.pry
    11:   result = if params[:_json]
    12:     GraphqlDevise::Schema.multiplex(
    13:       params[:_json].map do |param|
    14:         { query: param[:query] }.merge(execute_params(param))
    15:       end
    16:     )
    17:   else
 => 18:     GraphqlDevise::Schema.execute(params[:query], **execute_params(params))
    19:   end
    20:
    21:   render json: result unless performed?
    22: end

ここで
GraphqlDevise::Schema.execute(params[:query], **execute_params(params))
を実行してみると次のようなエラーが出た。

[1] pry(#<GraphqlDevise::GraphqlController>)> GraphqlDevise::Schema.execute(params[:query], **execute_params(params)).to_h
=> {"errors"=>
  [{"message"=>"Variable $gender of type Int! was provided invalid value",
    "locations"=>[{"line"=>9, "column"=>3}],
    "extensions"=>
     {"value"=>"0", "problems"=>[{"path"=>[], "explanation"=>"Could not coerce value \"0\" to Int"}]}}]}

$genderは整数を期待しているが"0"という文字列が渡っているらしい。 困惑・・。

パラメータをjsonにして解決した

調べているとこちらのissueを発見。
コメントを読むとRailsが文字列としか認識できていないとのこと。
またそれを回避するにはjsonにしてあげる必要があるようです。

let!(:params) { { query: query, variables: variables.to_json } } # to_jsonを加えた
let(:post_request) { post path, params: params }

このようにしてmutationが正常に実行され、無事テストも通すことができました。

OSCメッセージを利用したオーディオリアクティブを作ってみたい

私は今まで音量のみでオーディオリアクティブのような映像を作成していました。
最近だとこういうの。

ですが映像の幅に頭を悩ませており、というのも音量の情報だけでは表現に限界があります。

で、barbe_generative_diaryさんがツイートされていたご本人の記事で
SuperColliderが吐くOSCメッセージをProcessingに渡してあげる手順が細かく記載されており、「これだ〜!」と思いました。

この記事で世の中のオーディオリアクティブクリエイターはOSCを利用していたのか〜(多分)と一歩前身した気分に。

いざ

もろもろのセットアップを済ませ、SuperColliderから音を出し、いざProcessingを実行!

### [2022/5/3 1:36:14] PROCESS @ OscP5 stopped.
### [2022/5/3 1:36:14] PROCESS @ UdpClient.openSocket udp socket initialized.
### [2022/5/3 1:36:15] ERROR @ UdpServer.start()  IOException, couldnt create new DatagramSocket @ port 2020 java.net.BindException: Address already in use
### [2022/5/3 1:36:16] INFO @ OscP5 is running. you (127.0.0.1) are listening @ port 2020

2020番がすでに使用されている?
試しにOSC_Data_Monitorから2020番を外してみたところ正常にOSCメッセージの内容が表示されました!
他ツールで使用していると競合してしまうのでしょうか。

-OscMessage----------
received from   /127.0.0.1:57120
addrpattern /dirt/play
typetag sssfsfsfsfsfsiss
[0] _id_
[1] 3
[2] cps
[3] 0.5625
[4] cutoff
[5] 800.0
[6] cycle
[7] 1232.0
[8] delta
[9] 1.7777777
[10] n
[11] 16.0
[12] orbit
[13] 2
[14] s
[15] jungbass

---------------------

これで1サンプルごとの細かい情報を得ることに成功!
情報がたくさんでやれることもたくさんなので、まず音名([15])での分岐を試してみたいと思います。

GraphQL Rubyで型を生成するとスキーマ上uuidであればちゃんとuuid型を参照しようとする

RailsでGraphQLを使っているのですが、Typeを自動生成するときに妙な問題に出くわした。

postgresqlは標準でuuid型という型を装備している。 https://www.postgresql.jp/document/9.4/html/datatype-uuid.html

で、マイグレーションファイルに下記のように書くだけでuuidを自動的に設定してくれる。

t.uuid :uuid, null: false, default: 'gen_random_uuid()'
# schemafile.rb
t.uuid "uuid", default: -> { "gen_random_uuid()" }, null: false

このとき、GraphQLの型を自動生成するコマンドを叩くと、uuidフィールドは次のようになる。

$ bundle exec rails g graphql:object モデル名
field :uuid, Types::UuidType, null: false

おそらくuuid型はプリミティブではないので、uuid_type.rbを参照しにいこうとしている。 だがuuid型などないのでこのままだとエラーとなる。

試行錯誤したものの、結局String型にして落ち着かせた。

field :uuid, String, null: false

uuid型があるものなら使いたいが、良い解決策があれば誰か教えてほしい...。

【Tidal Cycles・Haskell】パターンマッチの記法に気づけなかった

最近こちらの書籍を読みながらTidal Cyclesで遊んでいます。

その中で謎に思えた記法があったのでメモ。

Tidal Cyclesとは

TidalCyclesは、音楽の即興演奏と作曲のために設計されたライブコーディング環境です。特に、Haskellに埋め込まれたドメイン固有言語であり、可聴パターンまたは視覚パターンの生成と操作に重点を置いています。 (ウィキペディアより)

理解できなかった記法

Tidal CyclesはHaskellを利用するのですが、下記のコードが不思議でした。

do
  let 
    inverse 1 = 0
    inverse 0 = 1
    pat1 = "{1 0 0 1 0 1 0 1/2 1 0 0 1/3}%8"
  d1 
    $ gain pat1 # s "bd"
  d2
    $ gain (inverse <$> pat1) 
    # sound "cp"

inverse 0inverse 1という変数を定義して〜(ここから間違ってる)。
d1ではキックをならし、d2でクラップを鳴らす。
$ gain (inverse <$> pat1)で、pat1の値を渡して。。
????

let
  inverse 1 = 0
  inverse 0 = 1
・
・
・
$ gain (inverse <$> pat1)

この挙動がよく分かりませんでした。 本の中では「patが0のときは1を、1のときは0を返すのでbdが鳴っていないときにcpが鳴る」的なことが書かれていたのですが、理屈が分からず困惑しました。

そもそも変数のような書き方じゃないぞこれは。

let
  inverse 1 = 0
  inverse 0 = 1

fmap

調べると<$>はfmapと呼ばれ、ここではpat1を回して前述のinverseに引数を渡すような動きになる。

$ gain (inverse <$> pat1)

ということはinverseは変数ではない、関数か。
(後から本を読み返したらちゃんと「関数」と書いてありました・・。)

パターンマッチだった

https://www.tohoho-web.com/ex/haskell.html#pattern_match

答えはパターンマッチ!ということでした。
分からなかった!

let
  -- 1を受け取ったら0を返す
  inverse 1 = 0
  -- 0を受け取ったら1を返す
  inverse 0 = 1

にしてもRubyの場合3系からパターンマッチが導入されたりと触れる機会が少ないと感じていたのですが、どうやら関数型言語だとよくあるそうです。
普段はオブジェクト指向の言語を触っているせいか、関数型言語は難しく感じるな〜〜〜。

おわり。