ハトネコエ Web がくしゅうちょう

プログラミングやサーバー・Web制作、チームマネジメントなど得た技術のまとめ

Ansible で、コマンドが存在するかどうかで処理を変える方法

冪等性(べきとうせい)を考えて、
パッケージ(コマンド)を apt で初めてインストールするときだけ処理をしたい。
という要望が自分の中で湧いてきて、さてどうしようと調べるも、なかなか出てこない。

「already installed ansible」とGoogle検索かけたら以下のサイトがヒットして、とても役立ちました。

Ansibleで冪等性を保つためにはfailed_whenとかstatを使うと便利 - 銀色うつ時間

いろいろ試してみたら、もうちょっと直感的な見た目に書けましたので、
それをご紹介。

それにあたりこちらのサイトも役立ちました。

ansibleでの実行結果のsuccess/failedとignore_errors/failed_whenがよくわからなかったので調べてみた

さて、どうなったのか、以下に書きます。

- name: check exist mysql command
  shell: type mysql
  register: exist_mysql
  failed_when: false

- set_fact:
    is_exist_mysql: "{{ exist_mysql | success }}"

- debug: msg="{{ is_exist_mysql }}"
  when: is_exist_mysql == true

これを実行すると、 mysql コマンドがすでに実行できるときはデバッグメッセージとして

ok: [123.456.78.90] => {
    "changed": false,
    "msg": true
}

と出ますし、逆に存在しなければ

skipping: [123.456.78.90]

と出力されます。

failed_when: false でなく ignore_errors: true と書いてもいいのですが、
ignore_errors は処理は続行されるのですが、エラーメッセージが出力されてしまって、
ちょっと心臓に悪いので、エラー扱いにならない failed_when: false を使用しています。

なお、 shell: type mysql としていますが、当然 shell: which mysql でも構いません。好みです。
(参考 : Bashでコマンドの存在チェックはwhichよりhashの方が良いかも→いやtypeが最強


ではでは、作業中なので要点だけで失礼…。

ansible で冪等性を保証するの、難しすぎて苦戦中です……。


【追記(2018/09/25): こっちのがいいかも】

上で ignore_errors がエラーメッセージとして表示されるからヤダって書いてるんですが、
でも type mysql の成功結果がわからないのも困らない? ってのが最近の考えなので、
今書くとしたら以下の書き方をします。シンプルですしね。

- command: which mysql
  register: result
  ignore_errors: true

- debug: msg="mysql is not exist"
  when: result is failed

続・SMF ( Standard MIDI File ) Format1 のバイナリを読んでみた

前回の記事の続きです。↓前回の記事

4D 54 68 64 00 00 00 06 00 01 00 02 03 C0 4D 54 
72 6B 00 00 00 17 00 FF 03 00 00 FF 51 03 06 8A 
1B 00 FF 58 04 04 02 18 08 00 FF 2F 00 4D 54 72 
6B 00 00 00 2B 00 FF 03 00 00 FF 21 01 00 00 B0 
79 00 00 B0 00 00 00 B0 20 00 00 C0 28 00 B0 07 
64 9E 00 90 3C 64 9E 00 80 3C 00 9E 00 FF 2F 00

前回の記事では、このバイナリファイルのヘッダーとコンダクタートラックまでを読みました。
3行目の13列目、つまり以下のところまでです。

4D 54 68 64 00 00 00 06 00 01 00 02 03 C0 4D 54 
72 6B 00 00 00 17 00 FF 03 00 00 FF 51 03 06 8A 
1B 00 FF 58 04 04 02 18 08 00 FF 2F 00

今回はその続きを読んでいきましょう。
前回の記事が前提知識となりますので、未読の方は前回の記事を先にお読みください

トラック(演奏トラック)

4D 54 72 
6B 00 00 00 2B 00 FF 03 00 00 FF 21 01 00 00 B0 
79 00 00 B0 00 00 00 B0 20 00 00 C0 28 00 B0 07 
64 9E 00 90 3C 64 9E 00 80 3C 00 9E 00 FF 2F 00

これがひとつの演奏トラックです。
Domino(MIDI編集ソフト)で見ると以下のようになっている箇所です。

f:id:nekonenene:20170225194904p:plain

開始宣言

4D 54 72 6B
これを、ASCIIコード表に沿って直すと MTrk
「ここからトラックについての記述が始まるよー」というサインになります。

トラックの長さ

00 00 00 2B
10進数に直すと 43 です。
「ここから 43 Byte 続くよー」と言ってくれています。

トラックのタイトル

00 FF 03 00
トラック名の指定です。
前回のコンダクタートラック同様、何も名付けていません。

ポート番号の指定

00 FF 21 01 00
ここから前回にはなかった新しい要素、
まずは「ポート番号の指定」です。

「FF 21」で「ポート番号の指定を始めますよー」という合図、
次の「01」が「それに1Byte使うよ」という宣言で、

最後の「00」で「Port A」だと言ってくれています。
Port Bの場合はここが「01」になります。

リセットオールコントローラー (CC#121)

00 B0 79 00

最初の「00」は0Tick経過したところで、の意味。(前回記事参照)
そして次の「B0」、これは「チャンネル1にコントロールチェンジを送るよ」という合図です。

最初の「B」がコントロールチェンジを指すサイン
次の「0」がチャンネル1を表しています。

なので、チャンネル2にコントロールチェンジを送るなら「B1」、
チャンネル16にコントロールチェンジを送るなら「BF」というふうになります。

そして、その次の「79」がコントロールチェンジ番号を表していて、
「79」を10進数に直すと121(7 * 16 + 9 = 121)。
コントロールチェンジ番号121「リセットオールコントローラー」を指します。

この信号でピッチベンドや音色などは初期値にリセットされます。
「79」の次にある「00」はValueで、リセットオールコントローラーの場合は別にどんな値でもいいんですが、通常は「00」としておきます。

バンクセレクトMSB (CC#0)

00 B0 00 00
「チャンネル1にコントロールチェンジ0番を送るよ」という合図になります。

コントロールチェンジ番号0は「バンクセレクトMSB」です。

MIDIの各チャンネルの音色は、
プログラムチェンジ と MSB と LSB の組み合わせ
によって決まります。
それぞれ128種類あり、MIDI音源は最大で 128 * 128 * 128 = 2,097,152 音色持てる計算になります。

今回の場合は、
プログラムチェンジ : 41(バイオリンの音色)
MSB : 0
LSB : 0

で、実際、「B0 00」のあとの最後の値(Value)は「00」です。

バンクセレクトLSB (CC#32)

00 B0 20 00
「チャンネル1にコントロールチェンジ32番を送るよ」という合図になります。

コントロールチェンジ番号32は「バンクセレクトLSB」です。
最後の値は「00」なので、LSB = 0 ということになりますね。

プログラムチェンジ

00 C0 28
チャンネル1にプログラムチェンジを送っています。
コントロールチェンジは「B」でしたが、プログラムチェンジは「C」で始まります。

ですので、チャンネル1にプログラムチェンジを送る合図は「C0」です。
その次の「28」が値(Value)で、10進数に直すと40……なんですけど、
ここの値は「00」(つまり0)から始まる一方、プログラムチェンジは1~128で規定されていますので、ここは41とお考えください。

GM規格ではプログラムチェンジ1~128が規定されており、
1 は Acoustic Piano、41 は Violin の音色です。
このチャンネル1はヴァイオリンの音色で鳴らされます。

ボリューム (CC#7)

00 B0 07 64
チャンネル1のチャンネルボリュームを100に設定しています。

「チャンネル1にコントロールチェンジ7番を送るよ」という合図で、
コントロールチェンジ番号7は「チャンネルボリューム」です。
最後の値(Value)は「64」なので、10進数に直すと100、トラックの音量は100です。
(なお、最大値は127です)

「ド」を鳴らす

9E 00 90 3C 64
設定が続きましたが、ようやく演奏の部分です。

最初の「9E 00」は「3840Tick経過したところで」の意味になります。

詳しくは前回記事のTickの項を読んでもらうとして、
9E - 80 = 1E で、これを10進数に直すと30。
「9E」の次は「00」で、「80」より小さな値ですからTickの値の指定はここまでとわかります。

よってTickは
128 * 30 + 1 * 0 = 3840 Tick と計算できます。

そして続くのが「90 3C 64」の部分。

「90」は「チャンネル1のノートON」を示します。
コントロールチェンジは「B」、
プログラムチェンジは「C」でしたが、
ノートON(音符の開始)は「9」が目印と決まっています。

そして音の高さは「3C」、10進数に直すと60、これはC4。MIDI音源にもよりますが、ト音記号のドの音です。
ヘ音記号のドの音はそこから12小さい48、16進数で表すと「30」の音です。

そして最後の値(Value)の「64」、10進数で表すと100であるこれが、
音の強さ(Velocity)の値を示しています。

「ド」を止める

9E 00 80 3C 00
先ほど鳴らしましたドの音を3840Tick経過したところで停止します。

「9E 00」が「3840Tick経過したところで」の意味、
そして次の「80」は「チャンネル1のノートOFF」を示します。
ノートON(音符の開始)は「9」でしたが、ノートOFF(音符の停止)は「8」というわけです。

で、どこのノートを止めるかというと「3C」の高さの音、
先ほど鳴らしました「ド」の音ですね。

そして最後の値(Value)が「00」です。
ノートOFFの音の強さ(Velocity)、「ノートオフベロシティ」は、
ごくごく一部のMIDI音源がリアルな演奏のために対応しているのですが、
ごくごくまれすぎるため、たいていのMIDI編集ソフトはここを0として処理します。

私がはるか昔に使っていた「Music Studio Producer」なんかは、ノートオフベロシティも編集しやすいようになっていましたね…。

トラックの終わり(End of Track)

9E 00 FF 2F 00
前回のコンダクタートラック同様、トラックの終了宣言をおこないます。

「9E 00」が「3840Tick経過したところで」の意味で、
「FF 2F 00」が「トラック終了(End of Track)」の意味です。

このトラックは4小節目の0Tick目で終了で、解説もこれで終了です。

おわりに

というわけで、2回にわたって続きましたMIDIファイルバイナリの解説、いかがでしたでしょうか!

バイナリって「難しそう」「マニア的なもの」という印象でしたが、
こうして覗いてみると、理路整然としていて思いのほかわかりやすいものであると感じました。(調べるの大変でしたけど…)
この記事を読んでくださった方も同じように感じてくださったのではないでしょうか?

こうなってくると png ファイルとか wav ファイルも気になってきますよね?
wav は読むの大変そうですが、でも気になる……。


最後に、今回参考にしたサイトを以下にまとめておきます。

ここまで読んでくださった方々、どうもありがとうございました!


そして流れを無視して貼っておくアフィリエイトリンク……
(接続部がよくある miniB端子でなく microB端子だからか、この1年くらい使ってるけど抜けにくくてけっこういい感じ)

SMF ( Standard MIDI File ) Format1 のバイナリを読んでみた

曲を作るためにお世話になっている MIDI
そういえばこれってどういうふうにできているんだろう、ってふと気になりました。

それでこの記事
SMF(Standard MIDI File)フォーマット解説 | 技術的読み物 | FISH&BREAD
を読んでいましたら、「意外と簡単?!」という気がしてきましたので、解読してみることにしました。

DominoMIDI編集ソフト)で、バイオリンの音でドを全音符ぶん鳴らすMIDIファイルを作成し、レッツトライです。

f:id:nekonenene:20170225194904p:plain

上のように作ったMIDIファイルを FavBinEdit で開いてみました。

4D 54 68 64 00 00 00 06 00 01 00 02 03 C0 4D 54 
72 6B 00 00 00 17 00 FF 03 00 00 FF 51 03 06 8A 
1B 00 FF 58 04 04 02 18 08 00 FF 2F 00 4D 54 72 
6B 00 00 00 2B 00 FF 03 00 00 FF 21 01 00 00 B0 
79 00 00 B0 00 00 00 B0 20 00 00 C0 28 00 B0 07 
64 9E 00 90 3C 64 9E 00 80 3C 00 9E 00 FF 2F 00

ヘッダー

まずはヘッダーを見てみましょう。

4D 54 68 64 00 00 00 06 00 01 00 02 03 C0

の部分です。

開始宣言

4D 54 68 64
これを、ASCIIコード表に沿って直すと MThd
たぶん MIDI Type header を略したのかなあ、と思いますが
自信ないですので、情報をお持ちの方いらっしゃいましたらお教えください。

ともかく、 4D 54 68 64 の並びが来たら、「ここからヘッダーだよー」っていうサインになります。

ヘッダーの長さ

00 00 00 06
「ヘッダーの長さは 6 Byte だよー」と言っています。

つまり 1行目
4D 54 68 64 00 00 00 06 00 01 00 02 03 C0 4D 54

00 01 00 02 03 C0
までがヘッダーの部分ですね。

(補足)
1Byte = 8bit なので、6Byte = 48bit です。(2進数で表現したときに数字が48個並びます)
16進数1つあたりのデータ量は 4bit(2 ^ 4 = 16 なので)だから、
16進数の場合では12個並ぶところまでが 6Byte です。

MIDIフォーマット

00 01
MIDI format = 1 であることを示しています。
SMF ( Standard MIDI File ) のファイルフォーマットは Format0, Format1, Format2 しかないので、
必然的にここの値は 00 00 ~ 00 02 までしか存在しません。

Wikipedia先生いわく

ヘッダチャンクとトラックチャンク1つのみで構成されるフォーマット0、複数トラックを持つフォーマット1、 マルチシーケンスでシーケンスパターンを指定するフォーマット2の3種類である。このうちフォーマット2は、現在ほとんど使われていない。

とのこと。
( https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%80%E3%83%BC%E3%83%89MIDI%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB )

私の感覚だと Format1 がもっとも一般的かなあと思います。
たいていのDTMソフトでのMIDI出力は Format1 で出力されていたかと思います。

トラック数

00 02
トラック数が 2個であることを示しています。

あとで説明する、 MTrk で始まるところが 2か所あると言い換えることができます。

MIDI分解能

03 C0
これを10進数に直すと 960 です。 分解能は960 です。

MIDI分解能というのは、1拍を何分割して表現できるか、ということです。
仮に分解能が2であれば、1拍(四分音符)を2分割するのが最大。
八分音符より短い音符を置くことはできませんし、音の長さはすべて八分音符単位。
「ほんのちょっとだけ鳴らす長さを短くしたい」などできません。

分解能が高いほど、「ほんのちょっとだけ鳴らす長さを短くしたい」とか「音の始まりを少しだけずらして和音を生演奏っぽく」などできるわけです。
480 とか 960 の設定値を見ることが多いですかね。

このファイルのヘッダー部分は以上です。

トラック(コンダクタートラック)

トラックはヘッダーに書いてある通り 2個ありますが、
まず 1個目の部分を見ていきましょう。

4D 54 
72 6B 00 00 00 17 00 FF 03 00 00 FF 51 03 06 8A 
1B 00 FF 58 04 04 02 18 08 00 FF 2F 00 

この部分です。

この1個目のトラックは「コンダクタートラック」と言う場合もあるもので、テンポや拍子の設定などをおこなっています。

開始宣言

4D 54 72 6B
これを、ASCIIコード表に沿って直すと MTrk
MIDI Track の略なんでしょうかね?

ともかく、4D 54 68 64 で「ここからトラックについての記述が始まるよー」というサインになります。

トラックの長さ

00 00 00 17
10進数に直すと 23 です。
「ここから 23 Byte 続くよー」と言ってくれています。

トラックのタイトル

00 FF 03 00

各トラックにはトラック名を付けることができます。
「Drums」などとタイトルを付けておくと、MIDIファイルを開いた人がなんのトラックなのかわかりやすいからです。
ただ、演奏には関係のない情報なので無くても構いません。

最初の「00」は「0Tick進んだところで信号を送るよ」って合図で(Tickについてはあとで説明します)、
「FF 03」は「トラック名を設定するよ」って合図で、その次にトラック名の長さを書きます。
この場合では「00」だから 0 Byte、ですのでそのあとに文字が続いていません。

この場合、トラック名を設定していないのだからバイナリを編集してこの部分を丸ごと削っても問題ありません。
ただし、そうするとトラックの長さも変わりますからそこの編集も忘れないようにしましょう。
(それを忘れると、再生できないMIDIファイルになってしまいます)

つまり、コンダクタートラックの
4D 54 72 6B 00 00 00 17 00 FF 03 00 00 FF 51 03 06 8A
の部分は、
4D 54 72 6B 00 00 00 13 00 FF 51 03 06 8A
と直してしまってかまいません。
こうすることで、無駄な 4Byte を削ることができます。(現代ではまったく意味をなさないレベルのファイル容量削減ですね!)

Tick

Tick は時間の単位です。
分解能が 960 の場合は、960Tick が1拍の長さです。

960Tick(1拍)を表すには、960は16進数で「3C0」だから「03 C0」とでもなるのかな、と思っていると、
そうではありません。「87 40」と表現します。

ポイントは、「960 ÷ 128 = 7 あまり 64」であることです。

Tickの値がどれだけ大きくてもいいように、Tickは何Byteでも表現できるようになっています。
しかし何Byteでも表現できるということは、どこかが終わりだとわからなければいけません。
ですので、「80」より小さい値を終わりと決めています。(つまり「7F」以下)
逆に「80」以上は「Tickを表現する値はこの次も続くんじゃ」と表していることになります。

この意味は2進数で考えるとわかりやすくて、16進数の「7F」は2進数では
01111111
16進数の「80」は2進数では
10000000
なので、勘のいい人は「先頭1ビットがフラグね」とわかるかと思います。

「7F」(10進数で言うところの127)より大きな値である128は以下のように書きます。
81 00
2進数に直すと
10000001 00000000
128 * 1 + 0 = 128
128進数で表現されていると言えるでしょう。

16800Tickならば、
81 83 20 と表します。
(128 ^ 2) * 1 + 128 * 3 + 32 = 16800

テンポの指定

00 FF 51 03 06 8A 1B

最初の「00」は「0Tick進んだところで信号を送るよ」って合図で、
つまり先ほどのトラック名の設定と同じタイミングで信号を送るよ、ってことになりますね。

「FF 51」は「テンポを設定するよ」って合図で、その次の「03」で「そのために 3Byte 使うよ」と伝えています。
そして値は「06 8A 1B」、10進数に直すと 428571 です。

428571、この大きな値は……? と思ったら、どうやらこれ、1拍あたりの秒数を指しているそうです。(単位はマイクロ秒)

BPM=120 のときの1拍の長さは 0.5 秒(500000マイクロ秒)であるから、
BPM=140 のときの1拍の長さは
0.5 * 120 ÷ 140 = 0.428571428... 秒
なるほど、たしかに 428571 マイクロ秒で間違いありませんね。

拍子の指定

00 FF 58 04 04 02 18 08
4分の4拍子であることの指定になります。

最初の「00」は「0Tick進んだところで信号を送るよ」って合図、
次の「FF 58」が「拍子を設定するよ」の合図、
次の「04」より、拍子の設定に 4Byte 使うことがわかります。

その4Byteが「04 02 18 08」の部分です。
「04 02 18 08」について順番に説明していきます。

拍子の指定1つ目

まずは最初の「04」。これは拍子の分子にあたります。
4分の3拍子なら「03」、4分の5拍子なら「05」が入ります。

拍子の指定2つ目

次の「02」。これは分母です。しかし、"4分の" なのに 2 っておかしいですよね?
これは 2 ^ (-2) (2のマイナス2乗)が4分の1であることがポイントです。
このマイナス2の2が、ここでの値なのです。

ですから、8分の6拍子でしたら、
ひとつめの部分は6拍子なので「06」、
ふたつめの部分は "8分の" なので、2のマイナス3乗が8分の1ですから「03」となります。

拍子の指定3つ目

そしてその次、「18 08」の部分。ここはなんのためにあるのか私よくわかっていません。

まず「18」の部分、10進数で言うと24であるここは、
1拍あたりのMIDIクロック数を示しています。*1

MIDIクロック」という言葉がわからなかったので調べたところ、
ここ( http://www.dipss.com/dipss/dtmkouza/whatsdtm/3-3.html )によると、

2台のシーケンサーMIDI接続されていて同時に演奏する場合、どちらもインターナルクロックで動いてしまうとバラバラの演奏になってしまいます。そこで、1台をインターナルクロックに、もう1台をエクスターナルクロックに設定してやります。すると、エクスターナルクロックに設定した方の機器はもう1方の機器が出すテンポに合わせて演奏するようになります。これが同期演奏です。

とあります。
つまるところ、複数のMIDIバイス間でのテンポ感を共有するものっぽいんですけど、よくわかってないです。
少なくとも、単純にMIDI再生するだけにおいてはどんな値でも良いっぽくて、ここを倍の「30」とかに変えても、なんの変わりもなく再生されます。

拍子の指定4つ目

最後の「08」、ここは
「4分音符1つと同じ長さになる32分音符の数」を指しているそうです。

「8以外になにか設定する値ある?!!」と思います。かなり不思議です。

トラックの終わり(End of Track)

00 FF 2F 00

最初の「00」は先ほどまでと同じく、0Tick経過後に、あとに続く信号を流すことを意味しています。
次に続く「FF 2F 00」が、「このトラックはここで終了します(End of Track)」という信号です。

この部分がなくても再生できるMIDIプレイヤーもありますが、
Windows Media Player などで再生できなくなりますので、しっかりと付けてあげましょう。

以上がコンダクタートラック部分の説明です。


長くなりましたので、残りの演奏トラック部分の説明は、また時間のできたときにおこないます。

【※追記 2017/03/06】
続き書きました!