こんばんは、SOSOHまるです。
ZOOM MS-70CDR+のMIDIコントローラーを完成させました。
81番からのユーザープリセットにアクセスできるようにしています。
バンクは長押しで切り替えし[81-84][85-89][89-92][93-96]の4バンクを使えるようにしました。
時間かけりゃ素人のおっさんでもなんとかなるもんだなー。
#include <MIDI.h>
// #include <Wire.h>
#include <Usb.h>
#include <usbh_midi.h>
#include <SSD1306Ascii.h>
#include <SSD1306AsciiAvrI2c.h>
#define I2C_ADDRESS 0x3C
#define RST_PIN -1
MIDI_CREATE_DEFAULT_INSTANCE();
SSD1306AsciiAvrI2c display;
USB Usb;
USBH_MIDI Midi(&Usb);
const byte pushButtons[] = {2, 17, 4, 15}; // ボタンのピン番号
const byte leds[] = {3, 16, 5, 14}; // LEDのピン番号
const byte bypass = 99; // バイパス時のプリセットの値-1 この場合100
const byte midiOutPin = 1; // MIDI DIN出力ピン(TX)
const byte midiInPin = 2; // MIDI DIN入力ピン
int dlay = 80; // ボタンの反応速度
int patch = 80; // プリセットを何番-1から使うか この場合81
int oled = 0;
byte buttonPushCounter[] = {0, 0, 0, 0}; // ボタンが押された回数のカウンター
bool prevButtonState[4] = {false, false, false, false}; // ボタンの直前の状態
bool buttonState;
int currentBank = 0;
unsigned long buttonPressStartTime17 = 0;
bool buttonLongPressDetected17 = false;
unsigned long buttonPressStartTime2 = 0;
bool buttonLongPressDetected2 = false;
void setup()
{
// Wire.begin(); // I2Cバスの初期化
display.begin(&SH1106_128x64, I2C_ADDRESS, RST_PIN);
display.clear();
for (byte m = 0; m < 4; m++)
{
pinMode(pushButtons[m], INPUT_PULLUP);
pinMode(leds[m], OUTPUT);
}
if (Usb.Init() == -1)
{
while (1);
}
MIDI.begin(16); // MIDI DINチャンネルを16に設定
intro();
}
void loop()
{
handleButtonPress(currentBank * 4 + patch);
// 17番ピンが長押しされたかどうかを確認
if (!digitalRead(17))
{
if (!buttonLongPressDetected17)
{
if (buttonPressStartTime17 == 0)
{
buttonPressStartTime17 = millis();
} else if (millis() - buttonPressStartTime17 >= 2000)//2秒間長押ししたら
{
buttonLongPressDetected17 = true;
currentBank = (currentBank + 1) % 4; //バンクを増やす
resetCounter();
// updateBankLed();
flashLEDs(5, 14, 1000); // 5番と14番LEDを1秒間点滅させる
}
}
}
else
{
buttonPressStartTime17 = 0;
buttonLongPressDetected17 = false;
}
// 2番ピンが長押しされたかどうかを確認
if (!digitalRead(2))
{
if (!buttonLongPressDetected2)
{
if (buttonPressStartTime2 == 0)
{
buttonPressStartTime2 = millis();
} else if (millis() - buttonPressStartTime2 >= 1000)// 1秒間長押ししたら
{
buttonLongPressDetected2 = true;
currentBank = (currentBank - 1 + 4) % 4; // バンクを減らす
resetCounter();
flashLEDs(5, 14, 800); // 5番と14番LEDを1秒間点滅させる
}
}
}
else
{
buttonPressStartTime2 = 0;
buttonLongPressDetected2 = false;
}
// MIDI INからのメッセージを処理
if (MIDI.read())
{
// 受信したMIDIメッセージを取得
byte type = MIDI.getType();
byte channel = MIDI.getChannel();
byte data1 = MIDI.getData1();
byte data2 = MIDI.getData2();
// 受信したMIDIメッセージをMIDI DIN OUTおよびUSB MIDIに送信
SendMIDIMessage(type, channel, data1, data2);
}
// USB MIDIのタスクを処理
Usb.Task();
}
void handleButtonPress(int patchOffset)
{
for (byte i = 0; i < 4; i++)
{
buttonState = !digitalRead(pushButtons[i]);
if (buttonState != prevButtonState[i])
{
prevButtonState[i] = buttonState;
if (buttonState)
{
if (buttonPushCounter[i] == 0)
{
SendMIDI(i + patchOffset);
resetCounter();
resetAllLeds();
buttonPushCounter[i]++;
ligarLed(leds[i]);
oled = i + patchOffset;
OledDisplay();
}
else
{
SendMIDI(bypass);
resetCounter();
resetAllLeds();
OledDisplayBypass();
}
}
delay(dlay);
}
}
}
void resetAllLeds()
{
for (byte k = 0; k < 4; k++)
{
digitalWrite(leds[k], LOW);
}
}
void resetCounter()
{
for (byte j = 0; j < 4; j++)
{
buttonPushCounter[j] = 0;
}
}
void SendMIDI(byte number) {
Usb.Task();
if (Usb.getUsbTaskState() == USB_STATE_RUNNING) {
SendMIDIUSB(number);
} else if (Usb.getUsbTaskState() == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
resetCounter();
resetAllLeds();
for (byte p = 0; p < 4; p++) {
digitalWrite(leds[p], HIGH);
delay(50);
digitalWrite(leds[p], LOW);
delay(50);
}
}
// MIDI DIN出力
MIDI.sendProgramChange(number, 16); // チャンネル16で送信
}
void SendMIDIUSB(byte number) {
byte Message[2];
Message[0] = 0xC0 | 0; // チャンネル1に設定 (0xC0はProgram Changeのステータスバイトで、チャンネル番号は下位4ビット)
Message[1] = number;
Midi.SendData(Message);
}
void SendMIDIMessage(byte type, byte channel, byte data1, byte data2)
{
// USB MIDIに送信
if (Usb.getUsbTaskState() == USB_STATE_RUNNING)
{
byte message[3];
message[0] = type | (channel - 1);
message[1] = data1;
message[2] = data2;
Midi.SendData(message);
}
// MIDI DINに送信
switch (type)
{
case midi::NoteOff:
case midi::NoteOn:
case midi::AfterTouchPoly:
case midi::ControlChange:
case midi::ProgramChange:
case midi::AfterTouchChannel:
case midi::PitchBend:
MIDI.send(type, data1, data2, 16);
break;
case midi::SystemExclusive:
// Handle SysEx messages if needed
break;
default:
break;
}
}
void OledDisplay()
{
display.clear();
display.setCursor(25, 0);
display.setFont(CalBlk36);
display.set2X();
display.print(oled + 1);
delay(dlay);
}
void OledDisplayBypass()
{
display.clear();
display.setFont(CalBlk36);
display.set2X();
display.setCursor(25, 0);
display.print("BP");
delay(dlay);
}
void OledDisplayIntro()
{
display.clear();
display.setFont(Arial_bold_14);
display.setCursor(5, 1);
display.println("ZOOM");
display.setCursor(5, 16);
display.println("MS-70CDR+");
display.setCursor(5, 31);
display.println("MIDI CONTROLLER");
}
void intro()
{
OledDisplayIntro();
delay(5000);
for (byte pos = 0; pos < 4; pos++)
{
SendMIDIUSB(pos);
digitalWrite(leds[pos], HIGH);
delay(350);
digitalWrite(leds[pos], LOW);
}
for (int b = 0; b < 8; b++)
{
for (byte k = 0; k < 4; k++)
{
digitalWrite(leds[k], HIGH);
}
delay(75);
for (byte l = 0; l < 4; l++)
{
digitalWrite(leds[l], LOW);
}
delay(75);
}
delay(3000);
OledDisplayBypass();
SendMIDIUSB(bypass);
}
void ligarLed(byte pinPort)
{
digitalWrite(pinPort, HIGH);
delay(40);
digitalWrite(pinPort, LOW);
delay(40);
digitalWrite(pinPort, HIGH);
}
void flashLEDs(byte led1, byte led2, unsigned int duration)
{
unsigned long startTime = millis();
while (millis() - startTime < duration)
{
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
delay(100);
digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
delay(100);
}
}
コメント