ジャミネータと遊ぼう(^_^)
長嶋 洋一
その発端
- ある日、友人の作曲家・m2氏がmixi日記に「ジャミネータを入手」と書いた
- 「ジャミネータ」という名前に遠い記憶しかないのでちょっとだけ調べてみた
- Jaminatorページ
- ネット通販ページ たぶん製造中止で購入不可。定価は120ポンド(2-3万円)
- m2氏のmixi日記へのコメから「ジャミネータからMIDI送信」の改造を依頼されるが、現品1台だけでは壊しても困るので「ヤフオクで中古を複数ゲットするまで待って」と宣言
- ヤフオクに「中古(ジャンク)のジャミネータ」が出るとメイルが来るように登録
- だいたいジャンクの相場は1台1000円から1500円程度。5000円とかの高飛車なものは華麗にスルー(^_^;)
- ・・・ 1年以上かけて、ヤフオクで計7台のジャンクのジャミネータを入手(かろうじて動くのは2台)
- 2011年夏の「第35期・虎の穴」で、メンバー1回生5人とともに、何か作ってみる材料とすることに
ジャミネータを分解する
- 2011年8月28日(日)、35虎の学生と、電子回路について解説しながら、ジャミネータを分解 → ここを参照
- ネジは全てタッピング、ネック部分は分解の必要ナシ
- ネック内から本体まで異常に延びた長大な基板を発見
- 電池は単2を6本(9V)。これを基板上の7805で+5Vの単一電源としている
- CPUは8039。あまりに懐かしい(^_^;)
- 音源LSIは「Noise Toys Inc」社と書かれた40ピンDIP。テキサスインスツルメンツ社のフィリピン工場製
- スイッチは全てダイオードマトリクスによる導電ゴム接点スイッチ
- ベンドのレバーはボリューム(アナログ)でなく、単なる回転角度の電極が基板上をスライドするだけ
ジャミネータを解析する
- 2011年8月29日(月)、35虎の学生と、Max5のデモを兼ねて、ジャミネータを解析 → ここを参照
- 8039の横で4ビットのpull-up抵抗(22kΩ)を発見、スキャンバスは4本と推定、これをGainerでモニタ
- 基板の印刷から4本のスキャンバスは「Row1」から「Row4」
- カラムは基板の印刷から「Col11」から「Col17」の7本と推定、これを出力するGainerも用意
- この2個のGainerをジャミネータのネック基板に接続して、Max5パッチから試してみると見事に正解(^_^)
- 基本的にカラムの各ビットはノーマル「H」で、スキャンラインだけを排他的に「L」にする
- 「Col11」が「L」の時、「Row1-Row3」は3本の弦スイッチ、「Row4」は「Start/Next」スイッチ
- 「Col12」が「L」の時、「Row1-Row4」は本体のお尻の4つの鍵盤スイッチ
- 「Col13」が「L」の時、「Row1-Row3」は3つの丸パッド、「Row4」は「Finale」スイッチ
- 「Col14」が「L」の時、「Row1-Row4」はネックの低音域の4つのフレットスイッチ
- 「Col15」が「L」の時、「Row1-Row4」はネックの中音域の4つのフレットスイッチ
- 「Col16」が「L」の時、「Row1-Row4」はネックの高音域の4つのフレットスイッチ
- 「Col17」が「L」の時、「Row1-Row4」は4ビット2進数としてベンドのレバーの角度
- ベンドのレバーはスプリングで中央に戻るので、MIDIベンドのように脱力した状態ではほぼ中央値
ジャミネータを改造する
- 2011年9月11日(日)、35虎の学生と相談しながら、Arduinoを使ってジャミネータを改造 → ここを参照
- MIDI出力を取り付け(オープンドレイン74HC05)
- Arduinoのアナログ入力4ポート0-3の4本を22kΩpull-upでスイッチスキャンバスに
- Arduinoのディジタル出力2-8の7ビットをスイッチスキャンラインに
- 各スイッチの情報はMIDIノートオン情報としてノートナンバ30から順に割り当て
- ベンドのレバーの4ビットはエンコードしてコントロールチェンジの2番に割り当て
- ネック先端部分に3次元加速度センサを取り付け、XとYをArduinoのアナログ入力4ポート4-5の2本へ
- XとYの加速度情報はコントロールチェンジの0-1番に割り当て
- ヘッド部分に3色LEDを取り付け、Arduinoのディジタル出力10-12の3本を割り当て
- Arduinoのディジタル入力ポート9にpull-upしたスライドスイッチを取り付け
- このスライドスイッチがONの時、「弦スイッチ」の3本に対応して3色LEDのRGBが点灯
- ・・・以上、回路図ナシの空中配線にてあっさり完成(^_^)
- Arduinoソースコード (改良の余地あり(^_^;))
char note = 64; char scan_data, bend, bend_old; int ledPin = 13; int i, j, k; long timer = 0; int new_data[7][4], old_data[7][4]; int acc1_old, acc1_new, acc2_old, acc2_new; int led_status=0; void loop() { led_display(); sw_scan(); event_check(); acc_scan(); led_check(); } void led_check(){ if(digitalRead(9) == HIGH){ led_status = 1; } else{ led_status = 0; } } void acc_scan(){ acc1_new = analogRead(4) / 16; if ( acc1_new != acc1_old ) { noteOn(0xb0, 0, acc1_new); acc1_old = acc1_new; } acc2_new = analogRead(5) / 16; if ( acc2_new != acc2_old ) { noteOn(0xb0, 1, acc2_new); acc2_old = acc2_new; } } void sw_scan(){ for (i = 0; i < 7; i++) { digitalWrite(i+2, LOW); delay(3); for (j = 0; j < 4; j++) { if(analogRead(j) < 600){ new_data[i][j] = 1; } else{ new_data[i][j] = 0; } } all_high(); } } void event_check(){ for (i = 0; i < 6; i++) { for (j = 0; j < 4; j++) { if(new_data[i][j] != old_data[i][j]){ old_data[i][j] = new_data[i][j]; note = 4*i + j + 36; if(old_data[i][j] == 1){ noteOn(0x90, note, 100); if((note==36)&&(led_status==1)){ digitalWrite(10, HIGH); } else if((note==37)&&(led_status==1)){ digitalWrite(11, HIGH); } else if((note==38)&&(led_status==1)){ digitalWrite(12, HIGH); } } else{ noteOn(0x90, note, 0); if((note==36)&&(led_status==1)){ digitalWrite(10, LOW); } else if((note==37)&&(led_status==1)){ digitalWrite(11, LOW); } else if((note==38)&&(led_status==1)){ digitalWrite(12, LOW); } } } } } i = 6; bend = 0; for (j = 0; j < 4; j++) { bend = bend + (new_data[i][j] << j); } if(bend_old != bend){ bend_old = bend; noteOn(0xb0, 2, bend); } } void led_display() { timer++; if(timer == 100){ digitalWrite(ledPin, HIGH); } if(timer == 200){ digitalWrite(ledPin, LOW); timer = 0; } } void all_high(){ for (k = 2; k < 9; k++) { digitalWrite(k, HIGH); } } void setup() { Serial.begin(31250); pinMode(ledPin, OUTPUT); pinMode(2,OUTPUT); pinMode(3,OUTPUT); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(9,INPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); all_high(); for (i = 0; i < 7; i++) { for (j = 0; j < 4; j++) { old_data[i][j] = 0; } } } void noteOn(char cmd, char data1, char data2) { Serial.print(cmd, BYTE); Serial.print(data1, BYTE); Serial.print(data2, BYTE); }
改造ジャミネータを量産する (1)
- 2011年9月19日(月)、35虎の学生と2-3台目のジャミネータの改造に着手 → ここを参照
- それぞれ中古・ジャンクのジャミネータなので、接触不良等で使えないスイッチは無視することにする
- 1号機はMIDIの1channelを出力するので「1ちゃんねる」と命名
- さすがに「2ちゃんねる」は敬意を表して欠番に(^_^;)
- 2号機はMIDIの3channelを出力するので「3ちゃんねる」と命名
- 3号機はMIDIの4channelを出力するので「4ちゃんねる」と命名
- 「4ちゃんねる」は「弦スイッチ」が全滅なので、スライドスイッチがONの時、3個の「パッド」に対応して3色LEDのRGBが点灯
- 「3ちゃんねる」Arduinoソースコード
char note = 64; char scan_data, bend, bend_old; int ledPin = 13; long timer = 0; int new_data[7][4], old_data[7][4]; int acc1_old, acc1_new, acc2_old, acc2_new; int led_status = 0; int channel = 2; /*** MIDI 3 channel ***/ void loop() { led_display(); sw_scan(); event_check(); acc_scan(); led_check(); } void led_check(){ if(digitalRead(9) == HIGH){ led_status = 1; } else{ led_status = 0; } } void acc_scan(){ acc1_new = analogRead(4) / 16; if ( acc1_new != acc1_old ) { noteOn(0xb0+channel, 0, acc1_new); acc1_old = acc1_new; } acc2_new = analogRead(5) / 16; if ( acc2_new != acc2_old ) { noteOn(0xb0+channel, 1, acc2_new); acc2_old = acc2_new; } } void sw_scan(){ int i,j; for (i = 0; i < 7; i++) { digitalWrite(i+2, LOW); delay(3); for (j = 0; j < 4; j++) { if(analogRead(j) < 600){ new_data[i][j] = 1; } else{ new_data[i][j] = 0; } } all_high(); } } void event_check(){ int i,j; for (i = 0; i < 6; i++) { for (j = 0; j < 4; j++) { if(new_data[i][j] != old_data[i][j]){ old_data[i][j] = new_data[i][j]; note = 4*i + j + 36; if(old_data[i][j] == 1){ noteOn(0x90+channel, note, 100); if((note==44)&&(led_status==1)){ /* 36 */ digitalWrite(10, HIGH); } else if((note==45)&&(led_status==1)){ /* 37 */ digitalWrite(11, HIGH); } else if((note==46)&&(led_status==1)){ /* 38 */ digitalWrite(12, HIGH); } } else{ noteOn(0x90+channel, note, 0); if((note==44)&&(led_status==1)){ /* 36 */ digitalWrite(10, LOW); } else if((note==45)&&(led_status==1)){ /* 37 */ digitalWrite(11, LOW); } else if((note==46)&&(led_status==1)){ /* 38 */ digitalWrite(12, LOW); } } } } } i = 6; bend = 0; for (j = 0; j < 4; j++) { bend = bend + (new_data[i][j] << j); } if(bend_old != bend){ bend_old = bend; noteOn(0xb0+channel, 2, bend); } } void led_display() { timer++; if(timer == 100){ digitalWrite(ledPin, HIGH); } if(timer == 200){ digitalWrite(ledPin, LOW); timer = 0; } } void all_high(){ int k; for (k = 2; k < 9; k++) { digitalWrite(k, HIGH); } } void setup() { int i,j; Serial.begin(31250); pinMode(ledPin, OUTPUT); pinMode(2,OUTPUT); pinMode(3,OUTPUT); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(9,INPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); all_high(); for (i = 0; i < 7; i++) { for (j = 0; j < 4; j++) { old_data[i][j] = 0; } } } void noteOn(char cmd, char data1, char data2) { Serial.print(cmd, BYTE); Serial.print(data1, BYTE); Serial.print(data2, BYTE); }- 「4ちゃんねる」Arduinoソースコード
char note = 64; char scan_data, bend, bend_old; int ledPin = 13; long timer = 0; int new_data[7][4], old_data[7][4]; int acc1_old, acc1_new, acc2_old, acc2_new; int led_status = 0; int channel = 3; /*** MIDI 4 channel ***/ void loop() { led_display(); sw_scan(); event_check(); acc_scan(); led_check(); } void led_check(){ if(digitalRead(9) == HIGH){ led_status = 1; } else{ led_status = 0; } } void acc_scan(){ acc1_new = analogRead(4) / 16; if ( acc1_new != acc1_old ) { noteOn(0xb0+channel, 0, acc1_new); acc1_old = acc1_new; } acc2_new = analogRead(5) / 16; if ( acc2_new != acc2_old ) { noteOn(0xb0+channel, 1, acc2_new); acc2_old = acc2_new; } } void sw_scan(){ int i,j; for (i = 0; i < 7; i++) { digitalWrite(i+2, LOW); delay(3); for (j = 0; j < 4; j++) { if(analogRead(j) < 600){ new_data[i][j] = 1; } else{ new_data[i][j] = 0; } } all_high(); } } void event_check(){ int i,j; for (i = 0; i < 6; i++) { for (j = 0; j < 4; j++) { if(new_data[i][j] != old_data[i][j]){ old_data[i][j] = new_data[i][j]; note = 4*i + j + 36; if(old_data[i][j] == 1){ noteOn(0x90+channel, note, 100); if((note==36)&&(led_status==1)){ /* 36 */ digitalWrite(10, HIGH); } else if((note==37)&&(led_status==1)){ /* 37 */ digitalWrite(11, HIGH); } else if((note==38)&&(led_status==1)){ /* 38 */ digitalWrite(12, HIGH); } } else{ noteOn(0x90+channel, note, 0); if((note==36)&&(led_status==1)){ /* 36 */ digitalWrite(10, LOW); } else if((note==37)&&(led_status==1)){ /* 37 */ digitalWrite(11, LOW); } else if((note==38)&&(led_status==1)){ /* 38 */ digitalWrite(12, LOW); } } } } } i = 6; bend = 0; for (j = 0; j < 4; j++) { bend = bend + (new_data[i][j] << j); } if(bend_old != bend){ bend_old = bend; noteOn(0xb0+channel, 2, bend); } } void led_display() { timer++; if(timer == 100){ digitalWrite(ledPin, HIGH); } if(timer == 200){ digitalWrite(ledPin, LOW); timer = 0; } } void all_high(){ int k; for (k = 2; k < 9; k++) { digitalWrite(k, HIGH); } } void setup() { int i,j; Serial.begin(31250); pinMode(ledPin, OUTPUT); pinMode(2,OUTPUT); pinMode(3,OUTPUT); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(9,INPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); all_high(); for (i = 0; i < 7; i++) { for (j = 0; j < 4; j++) { old_data[i][j] = 0; } } } void noteOn(char cmd, char data1, char data2) { Serial.print(cmd, BYTE); Serial.print(data1, BYTE); Serial.print(data2, BYTE); }- パフォーマンスのイメージも検討し、効果的なショートループムービーを検討・試作
改造ジャミネータを量産する (2)
- 2011年9月23日(金)、35虎の学生と3台目のジャミネータまで改造 → ここを参照
- 電源スイッチ(ロックレバータイプ)と電源LEDを全てに増設
- 単2アルカリ電池6本は重いので、「リチウム単3」+「単3→単2アダプタ」を利用して軽量化
- LEDの「緑」だけ点灯しないトラブルに悩まされる
- ケーブルの一部が圧迫されているためのショートと原因判明、「こんなこともあろうかと」採用した4芯シールドケーブルの未使用のラインにバイパスすることで奇跡的に解決。この「はやぶさ」修理に一同、感涙(;_;)
改造ジャミネータを量産する (3)
- 2011年9月24日(土)、35虎の学生と4台目のジャミネータまで改造 → ここを参照
- 4号機はMIDIの5channelを出力するので「5ちゃんねる」と命名
- 「5ちゃんねる」Arduinoソースコード
char note = 64; char scan_data, bend, bend_old; int ledPin = 13; long timer = 0; int new_data[7][4], old_data[7][4]; int acc1_old, acc1_new, acc2_old, acc2_new; int led_status = 0; int channel = 4; /*** MIDI 5 channel ***/ void loop() { led_display(); sw_scan(); event_check(); acc_scan(); led_check(); } void led_check(){ if(digitalRead(9) == HIGH){ led_status = 1; } else{ led_status = 0; } } void acc_scan(){ acc1_new = analogRead(4) / 16; if ( acc1_new != acc1_old ) { noteOn(0xb0+channel, 0, acc1_new); acc1_old = acc1_new; } acc2_new = analogRead(5) / 16; if ( acc2_new != acc2_old ) { noteOn(0xb0+channel, 1, acc2_new); acc2_old = acc2_new; } } void sw_scan(){ int i,j; for (i = 0; i < 7; i++) { digitalWrite(i+2, LOW); delay(3); for (j = 0; j < 4; j++) { if(analogRead(j) < 600){ new_data[i][j] = 1; } else{ new_data[i][j] = 0; } } all_high(); } } void event_check(){ int i,j; for (i = 0; i < 6; i++) { for (j = 0; j < 4; j++) { if(new_data[i][j] != old_data[i][j]){ old_data[i][j] = new_data[i][j]; note = 4*i + j + 36; if(old_data[i][j] == 1){ noteOn(0x90+channel, note, 100); if((note==44)&&(led_status==1)){ /* 36 */ digitalWrite(10, HIGH); } else if((note==45)&&(led_status==1)){ /* 37 */ digitalWrite(11, HIGH); } else if((note==46)&&(led_status==1)){ /* 38 */ digitalWrite(12, HIGH); } } else{ noteOn(0x90+channel, note, 0); if((note==44)&&(led_status==1)){ /* 36 */ digitalWrite(10, LOW); } else if((note==45)&&(led_status==1)){ /* 37 */ digitalWrite(11, LOW); } else if((note==46)&&(led_status==1)){ /* 38 */ digitalWrite(12, LOW); } } } } } i = 6; bend = 0; for (j = 0; j < 4; j++) { bend = bend + (new_data[i][j] << j); } if(bend_old != bend){ bend_old = bend; noteOn(0xb0+channel, 2, bend); } } void led_display() { timer++; if(timer == 100){ digitalWrite(ledPin, HIGH); } if(timer == 200){ digitalWrite(ledPin, LOW); timer = 0; } } void all_high(){ int k; for (k = 2; k < 9; k++) { digitalWrite(k, HIGH); } } void setup() { int i,j; Serial.begin(31250); pinMode(ledPin, OUTPUT); pinMode(2,OUTPUT); pinMode(3,OUTPUT); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(9,INPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); all_high(); for (i = 0; i < 7; i++) { for (j = 0; j < 4; j++) { old_data[i][j] = 0; } } } void noteOn(char cmd, char data1, char data2) { Serial.print(cmd, BYTE); Serial.print(data1, BYTE); Serial.print(data2, BYTE); }
改造ジャミネータを量産する (4)
- 2011年9月25日(日)、35虎の学生と5台目のジャミネータまで改造完了 → ここを参照
- 5号機はMIDIの6channelを出力するので「6ちゃんねる」と命名
- 「6ちゃんねる」も「弦スイッチ」が全滅なので、スライドスイッチがONの時、3個の「パッド」に対応して3色LEDのRGBが点灯
- 「6ちゃんねる」Arduinoソースコード
char note = 64; char scan_data, bend, bend_old; int ledPin = 13; long timer = 0; int new_data[7][4], old_data[7][4]; int acc1_old, acc1_new, acc2_old, acc2_new; int led_status = 0; int channel = 5; /*** MIDI 6 channel ***/ void loop() { led_display(); sw_scan(); event_check(); acc_scan(); led_check(); } void led_check(){ if(digitalRead(9) == HIGH){ led_status = 1; } else{ led_status = 0; } } void acc_scan(){ acc1_new = analogRead(4) / 16; if ( acc1_new != acc1_old ) { noteOn(0xb0+channel, 0, acc1_new); acc1_old = acc1_new; } acc2_new = analogRead(5) / 16; if ( acc2_new != acc2_old ) { noteOn(0xb0+channel, 1, acc2_new); acc2_old = acc2_new; } } void sw_scan(){ int i,j; for (i = 0; i < 7; i++) { digitalWrite(i+2, LOW); delay(3); for (j = 0; j < 4; j++) { if(analogRead(j) < 600){ new_data[i][j] = 1; } else{ new_data[i][j] = 0; } } all_high(); } } void event_check(){ int i,j; for (i = 0; i < 6; i++) { for (j = 0; j < 4; j++) { if(new_data[i][j] != old_data[i][j]){ old_data[i][j] = new_data[i][j]; note = 4*i + j + 36; if(old_data[i][j] == 1){ noteOn(0x90+channel, note, 100); if((note==36)&&(led_status==1)){ /* 36 */ digitalWrite(10, HIGH); } else if((note==37)&&(led_status==1)){ /* 37 */ digitalWrite(11, HIGH); } else if((note==38)&&(led_status==1)){ /* 38 */ digitalWrite(12, HIGH); } } else{ noteOn(0x90+channel, note, 0); if((note==36)&&(led_status==1)){ /* 36 */ digitalWrite(10, LOW); } else if((note==37)&&(led_status==1)){ /* 37 */ digitalWrite(11, LOW); } else if((note==38)&&(led_status==1)){ /* 38 */ digitalWrite(12, LOW); } } } } } i = 6; bend = 0; for (j = 0; j < 4; j++) { bend = bend + (new_data[i][j] << j); } if(bend_old != bend){ bend_old = bend; noteOn(0xb0+channel, 2, bend); } } void led_display() { timer++; if(timer == 100){ digitalWrite(ledPin, HIGH); } if(timer == 200){ digitalWrite(ledPin, LOW); timer = 0; } } void all_high(){ int k; for (k = 2; k < 9; k++) { digitalWrite(k, HIGH); } } void setup() { int i,j; Serial.begin(31250); pinMode(ledPin, OUTPUT); pinMode(2,OUTPUT); pinMode(3,OUTPUT); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(9,INPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); all_high(); for (i = 0; i < 7; i++) { for (j = 0; j < 4; j++) { old_data[i][j] = 0; } } } void noteOn(char cmd, char data1, char data2) { Serial.print(cmd, BYTE); Serial.print(data1, BYTE); Serial.print(data2, BYTE); }- だいぶ昔に製作した2台の「MIDIマージャ」を活用して、5人の5台のジャミネータからの情報を全てミックスしてMax5で受信し、5画面のムービーの同時表示・切り替えまで確認、パフォーマンスのプラットフォームは一応完成した(^_^)
技術資料 (備忘録)
Arduino UNO
3色LED (秋月電子)
加速度センサ (秋月電子)
不調スイッチ(^_^;)のマップ等
全回路図
その後の展開