ムライボックス (17) --- ソフトウェア (9)
XG Display Bitmap Data システム・エクスクルーシブ・メッセージにより、リマップ/ビットマスク・テーブルを MIDI シーケンス・データを使って書き換える手段を得ることができましたが、そのメッセージデータを作成する (ホスト PC 上で実行する) ユーティリティーを作りました。
テーブルを定義している C ソース・プログラムの初期値を記述している部分のテキストを標準入力に喰わせると、システム・エクスクルーシブ・メッセージに変換して出力します。
そのプログラム・リストを下に示します。
Windows 10 (バージョン 1709) の WSL (Windows Subsystem for Linux) 上の Ubuntu 16.04.3 LTS 上の gcc 5.4.0 で作成しています。
// gen_murai_sysx.c : generate system exclusive message // of remap/bitmask table loading // for MuraiBOX #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <stdint.h> char buf[65536] = " "; char line_buf[4096]; int vcode = 0; int hcode = 0; // default device number = 16 (1 origin) int dev_no = (16-1); // default = hex output mode int bin_flag = 0; // default = no prefix for hex int pref_flag = 0; #define SYSX_BUF_LEN (7 + (3*16) + 1) // array of bitmap data int d[16]; uint8_t sysx[SYSX_BUF_LEN] = { 0xf0, // Start Of Exclusive 0x43, // YAMAHA ID 0x10, // device number 0x4c, // XG model ID 0x07, // XG Display Bitmap Data }; // uint8_t sysx[] // optional argument handling void options(int argc, char * const argv[]) { int optc; if (1 < argc) { while (-1 != (optc = getopt(argc, argv, "BbD:d:H:h:PpV:v:"))){ switch (optc) { case 'B': case 'b': // binary output flag bin_flag ^= 0x01; // flip bin_flag break; case 'D': case 'd': // device number dev_no = atoi(optarg); if (0 > dev_no) { dev_no = 0; } if (15 < dev_no) { dev_no = 15; } break; case 'P': case 'p': // hex prefix flag pref_flag ^= 0x01; // flip pref_flag break; case 'V': case 'v': // vertical code vcode = atoi(optarg); if (0 > vcode) { vcode = 0; } if (7 < vcode) { vcode = 7; } break; case 'H': case 'h': // horizontal code hcode = atoi(optarg); if (0 > hcode) { hcode = 0; } if (15 < hcode) { hcode = 15; } break; default: break; } // switch (optc) { ... } // while (-1 != ... ) { ... } // if (0 < argc) { ... } // void options() int main(int argc, char * const argv[]) { char *p; uint16_t bm; options(argc, argv); while (!feof(stdin)) { char c; fgets(line_buf, sizeof(line_buf), stdin); for (int i = 0; i < strlen(line_buf); i++) { c = line_buf[i]; if ( (',' == c) || ('{' == c) || ('=' == c) || (0x20 > c) ) { line_buf[i] = ' '; // replace by white space } // if ( (',' == c) || ... ) { ... } // for (int i = 0; ... // look for 1-line comment "// ..." p = strstr(line_buf, "//"); if (NULL != p) { *p = 0; // trim comment } // if (NULL != p) { ... // look for 1-line comment "/* ... */" p = strstr(line_buf, "/*"); if (NULL != p) { *p = 0; // trim comment } // if (NULL != p) { ... strcat(buf, line_buf); } // while (!feof(stdin)) { ... sscanf(buf, "%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", &(d[0]), &(d[1]), &(d[2]), &(d[3]), &(d[4]), &(d[5]), &(d[6]), &(d[7]), &(d[8]), &(d[9]), &(d[10]), &(d[11]), &(d[12]), &(d[13]), &(d[14]), &(d[15])); for (int i = 0; i < 16; i++) { bm = (uint16_t)d[i]; // split 16 bit width bitmap to 7:7:2 sysx[i+7] = (0x7f & (bm >> 9)); sysx[i+7+16] = (0x7f & (bm >> 2)); sysx[i+7+32] = (0x60 & (bm << 5)); } // for (int i = 0; ... sysx[2] = (0x10 | dev_no); // device number sysx[5] = (0x70 & (vcode << 4)) | (0x0f & hcode); // v/h code sysx[SYSX_BUF_LEN-1] = 0xf7; // End Of Exclusive for (int i = 0; i < SYSX_BUF_LEN; i++) { if (bin_flag) { // binary mode printf("%c", sysx[i]); // binary output } else { // hex mode printf("%s%.2x ", (pref_flag ? "0x" : ""), sysx[i]); } // if (bin_flag) { ... } // for (int i = 0; ... } // int main()
デフォルトでは、"0x" プリフィクスなしの 2 桁 16 進出力ですが、"-b" オプションでバイナリ出力、"-p" オプションで "0x" プリフィクス付きの出力になります。
また、"-v n" オプションでテーブルの種別を "n" にします。 (デフォルトではリマップ・テーブルを表す "0")
入力としては、たとえば、
//uint16_t remap_tab[16] = { 0, // ch 1, no remap 1, // ch 2, no remap 2, // ch 3, no remap 3, // ch 4, no remap 4, // ch 5, no remap 5, // ch 6, no remap 6, // ch 7, no remap 7, // ch 8, no remap 8, // ch 9, no remap 9, // ch 10, (drum ch), no remap 10, // ch 11, no remap 11, // ch 12, no remap 12, // ch 13, no remap 13, // ch 14, no remap 14, // ch 15, no remap 15 // ch 16, no remap }; // uint16_t remap_tab[]
のように、変数名などの部分はコメント・アウトして、初期化数値の部分だけを有効にします。 この例では「すべてリマップしない」設定のリマップ・テーブルになっています。
f0 43 1f 4c 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 02 02 02 02 03 03 03 03 00 20 40 60 00 20 40 60 00 20 40 60 00 20 40 60 f7
出力は上のようになります。
見やすくするために後から手動で改行を挿入しています。
これをシステム・エクスクルーシブ・メッセージとして音源に送り、ディスプレイに表示させると左の写真のようになります。
ビットマスク・テーブルの例を下に示します。 これは Arduino 用の 7 ポート出力に対するものです。
//uint16_t mask_tab[16] = { 0x0001, // ch 1 --> port 1 0x0002, // ch 2 --> port 2 0x0004, // ch 3 --> port 3 0x0008, // ch 4 --> port 4 0x0010, // ch 5 --> port 5 0x0020, // ch 6 --> port 6 0x0040, // ch 7 --> port 7 0x0040, // ch 8 --> port 7 0x0040, // ch 9 --> port 7 0xffff, // ch 10 --> all port (broadcast drum ch) 0x0040, // ch 11 --> port 7 0x0040, // ch 12 --> port 7 0x0040, // ch 13 --> port 7 0x0040, // ch 14 --> port 7 0x0040, // ch 15 --> port 7 0x0040 // ch 16 --> port 7 }; // uint16_t mask_tab[]
"-v 1" オプションを付けて実行した結果は、
f0 43 1f 4c 07 10 00 00 00 00 00 00 00 00 00 00 7f 00 00 00 00 00 00 00 00 01 02 04 08 10 10 10 7f 10 10 10 10 10 10 20 40 00 00 00 00 00 00 00 60 00 00 00 00 00 00 f7
これを表示させると左の写真のようになります。
ただし、表示させるためにビットマスク・テーブルを表す 6 バイト目の「10」を「00」に書き換えています。
システムメッセージ・テーブルの例を下に示します。
これは各チップ共通です。
//uint16_t sysmsg_tab[16] = { 0xffff, // 0xF0, Start of Exclusive (arbitrary) 0xffff, // 0xF1, MTC Quarter frame (2 byte) 0xffff, // 0xF2, Song Position Pointer (3 byte) 0xffff, // 0xF3, Song Select (2 byte) 0x0000, // 0xF4, undefined 0x0000, // 0xF5, undefined 0xffff, // 0xF6, Tune Request (obsolete) 0xffff, // 0xF7, End of Exclusive 0xffff, // 0xF8, MIDI Clock 0x0000, // 0xF9, undefined 0xffff, // 0xFA, Start 0xffff, // 0xFB, Continue 0xffff, // 0xFC, Stop 0x0000, // 0xFD, undefined 0xffff, // 0xFE, Active sensing 0x0000 // 0xFF, System Reset (obsolete) }; // uint16_t sysmsg_tab[]
"-v 2" オプションを付けて実行した結果は、
f0 43 1f 4c 07 20 00 7f 7f 7f 7f 00 00 7f 7f 7f 00 7f 7f 7f 00 7f 00 7f 7f 7f 7f 00 00 7f 7f 7f 00 7f 7f 7f 00 7f 00 60 60 60 60 00 00 60 60 60 00 60 60 60 00 60 00 f7
これを表示させると左の写真のようになります。
ただし、表示させるためにシステムメッセージ・テーブルを表す 6 バイト目の「20」を「00」に書き換えています。