質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • Raspberry Pi

    1065questions

    Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

  • Raspbian

    144questions

RPi 3 で 'amidi' の MIDI ダンプをパイプで受け取るとMIDIシーケンスが1つ前のものになる

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 600

KEINOS

score 6

 TL;DR(概要)

RaspberryPi 3 に MIDI キーボードをつなげ、受け取った MIDI シーケンスデータが、 $ amidi --port="hw:1,0,0" --dump で表示される内容と、$ amidi --port="hw:1,0,0" --dump | php sample.php でパイプでプログラムに渡された内容が異なる。

 押下/押上の結果

続けて「ド・レ・レ」と弾いた場合の信号の違いは以下の通りです。
「Dump RAW」は $ amidi --port="hw:1,0,0" --dump の値、「パイプ経由」は $ amidi --port="hw:1,0,0" --dump | php sample.php で標準入力をおうむ返しした値です。

ノート番号  操作   Dump RAW   パイプ経由 
 3C   押下↓   90 3C 33   80 3C 00 
 3C   押上↑   80 3C 00   90 3C 74 
 3E   押下↓   90 3E 42   80 3C 00 
 3E   押上↑   80 3E 00   90 3E 24 
 3E   押下↓   90 3E 2C   80 3E 00 
 3E   押上↑   80 3E 00   90 3E 64 

 備考

  • MIDIチャンネル「0
  • 押下 = 9x xx xx(ノート・オン)
  • 押上 = 8x xx xx(ノート・オフ)
  • ド = 真ん中のC(3C
  • レ = 真ん中のD(3E
  • 3バイト目の値はベロシティなので00以外は毎回ランダム

 パイプで受け取るプログラム例(PHP)

<?php
/* sample.php */
while (true) {
    $input = trim(fgets(STDIN));
    echo $input . PHP_EOL;
}

 問題点

上記「Dump RAW」($ amidi --port="hw:1,0,0" --dump でダンプした値)は正常に表示されているのですが、それをパイプでプログラムに渡すとズレが発生します。

 他に試したこと

$ mkfifo pipemidi で名前付きパイプを作成し、$ amidi --port="hw:1,0,0" --dump > pipemidi と別ターミナルから $ cat pipemidi で正常に受け取れることを確認後、sample.phpを以下のように変更しましたが、同じズレが発生しました。

<?php

$path_file_pipe_midi = './pipemidi';

if(! file_exists($path_file_pipe_midi)){
    die('Can not read file.');
}

$file = new NoRewindIterator( new SplFileObject($path_file_pipe_midi, 'r') );

$file->setFlags(SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE);

foreach ($file as $n => $line) {
    if (false === $line) continue;
    echo "$n $line", PHP_EOL;
}

 環境/条件

 ビット長

  • 1 アクションで受け取るMIDIデータ = 3バイト FF FF FF

 ビットマスク

項目 ビットマスク
キー Down/Up   F0 00 00
MIDI チャンネル   0F 00 00
ノート番号        00 FF 00
ベロシティー      00 00 FF

 MIDIデータの値

項目
MIDI チャンネル   0Ch0
ノート  C3 = 真ん中のド(60=0xC3
ノート  3E = 真ん中のレ(62=0x3E
押下アクション   8x xx xx9x xx xx
押上アクション   9x xx xx8x xx xx

 検証環境

項目 内容
本体   RaspberryPi3 B
MIDI キーボード   AKAI MPKmini MK2
MIDI 接続   USB ケーブル直結
SSH 接続   WiFi 経由
PHP   v7.0.27-0+deb9u1 (cli)
MIDI ポート($ amidi -l)   IO  hw:1,0,0  MPKmini2 MIDI 1
$amidi --version   v1.0.28
OS Jessie, ヘッドレス
$ lsb_release -a (以下を参照)
No LSB modules are available.
Distributor ID:  Raspbian
Description:     Raspbian GNU/Linux 8.0 (jessie)
Release:         8.0
Codename:        jessie
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • miiika

    2018/04/05 15:51

    的外れでしたらごめんなさい。一つ目のコードについてですが、trimを外してみてください。 あるいは、echoしている個所で`.`ではなく`,`にしてみてください。おそらくphpの問題だと思いますので、phpのタグをつけたらよろしいかと思います。

    キャンセル

  • KEINOS

    2018/04/05 18:40

    ご指摘の2点と PHP 以外で シェル・スクリプトでも試してみましたが、いずれもズレは発生しました。ただ、「trimを外して」みたところ、意図しない改行が入っていることに気づきました!もしかすると制御コード系の問題かもしれないので、もう少し検証して原因をしぼったら質問を修正したいと思います!ありがとうございます!

    キャンセル

  • miiika

    2018/04/05 19:31

    進展があったようで何よりです。

    キャンセル

回答 1

check解決した方法

+1

解決しました。

信号が1つズレた原因は amidi の仕様で改行コードが出力されるタイミングでした。

 TL;DR

amidi のダンプデータは、1 アクションごとに出力する MIDI シーケンスの先頭に改行コードが付いてくるので、1 アクションを検知するのは EOL や \n で判断するのではなく読み込んだバイト数(9バイト)で判断する必要があります。

 TS;DR

MIDI キーボードのキーやパッドを押すと「90 3C 16」といった3バイトの MIDI 信号(シーケンス・データ)が流れてきますが、厳密には「\n90 3c 16」という9バイトの文字列データです。ここで注意すべきは先頭に「\n」の改行コードが付いていることです。

パイプ渡しによる標準入力だけでなく名前付きパイプによるファイル読み込みであっても、データを読み込む際に1行ごとに読み込みながら処理する場合は注意が必要になります。

なぜなら、MIDI キーボード上でアクションを起こしても改行が入らないため「1行のデータ」として認識されないので、次のアクションを起こし改行が付いて初めて1行と認識されるからです。これが1アクション、ズレる原因でした。

そのため、プログラム言語を問わず、標準入力もしくは(名前付きパイプ経由の)ファイル読み込みであっても、データを読み込む時は9バイトを境に読み込みを区切る必要があります。

 パイプ渡しで確認する例

<?php
// sample.php
while(true){
    $input = trim(fgets(STDIN, 9)); //9バイト区切りで読み込む
    echo  $input ? $input . PHP_EOL : '';
}
$ #実行
$ $ amidi --port="hw:1,0,0" --dump | php sample.php

 名前付きパイプで確認する例

2つのターミナル・ウィンドウを開いて試してください。

各々のウィンドウで下記コマンドを打ったのち、MIDI キーボードで操作すると、ウィンドウ2にもダンプデータが流れてきます。

この時、一発目の操作で空行が入ることと、カーソルが行末に来たままであることに注目してください。

$ # ウィンドウ1の作業内奥
$ # MIDI ポートの確認
$ amidi -l
Dir Device    Name
IO  hw:1,0,0  MPKmini2 MIDI 1
$ # 名前付きパイプの作成
$ mkfifo dump
$ # MIDI信号のダンプを作成した名前付きパイプに書き込みつつ表示
$ amidi --port="hw:1,0,0" --dump | tee dump
$ # ウィンドウ2の作業内容
$ # dump ファイルの中身を表示する
$ cat dump

 MIDI シーケンスの誤記

なお、質問時の MIDI キーボード押下時および押上時の MIDI シーケンスが間違っていました。正しくは以下です。

操作 備考
押下 9x xx xx シグナル・オン(9nH
押上 8x xx xx シグナル・オフ(8nH

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • Raspberry Pi

    1065questions

    Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

  • Raspbian

    144questions