Недавно я нашел коробку с надписью Elenberg MS-5420.
Было решено переделать его в MIDI-клавиатуру.
Для начала решил оставить в нем только самое необходимое, чтобы уменьшить вес.
Самым важным компонентом для задумки оказалась диодная матрица, которая используется в простых синтезаторах для определения нажатой клавиши.
Найти схему в интернете не составило большого труда.
По схеме видно, что для клавиш используется диодная матрица (др. название scan matrix), физически представляющая собой 8 входов, которые соединяются при помощи диодов с 7 выходами через общий катод. Таким образом можно создать до 56 комбинаций = клавиш.
Когда мы нажимаем клавишу, мы активируем диод.
Если в момент нажатия клавиши отправить сигнал на один из входов, то выходной сигнал будет строго на одном из выходов. Для определения нажатой клавиши мы должны последовательно отправлять сигнал на каждый вход до тех пор, пока не получим выходной сигнал на одном из выходов.
В качестве нового сердца синтезатора решил использовать Arduino Uno.
У нее уже есть USB разъем для подключения к компьютеру, как у большинства MIDI клавиатур нашего времени. Необходимости в MIDI разъеме не было, так как я не планировал подключать синтезатор к звуковой карте или другим устройствам.
Задача состояла в том, чтобы подключить к Arduino 7+8 проводов, что довольно много.
7 проводов для выходного сигнала я подключил напрямую к цифровым пинам Arduino, а 8 входов подключил через регистр сдвига 74HC595.
В моем случае первая нота на синтезаторе (C1) До первой октавы, что соответствует коду 36 из спецификации MIDI. Для удобства сразу заполнил матрицы клавиш и нот.
#define NUM_ROWS 7
#define NUM_COLS 8
int note = 36;
for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
{
for (int rowCtr = 0; rowCtr < NUM_ROWS + 1; ++rowCtr)
{
keyPressed[rowCtr][colCtr] = false;
keyToMidiMap[colCtr][rowCtr] = note;
note++;
}
}
Далее на каждый из входов отправляется сигнал, а затем проверяется наличие сигнала на выходе.
for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
{
scanColumn(colCtr);
int rowValue[NUM_ROWS];
rowValue[0] = digitalRead(row1Pin);
rowValue[1] = digitalRead(row2Pin);
rowValue[2] = digitalRead(row3Pin);
rowValue[3] = digitalRead(row4Pin);
rowValue[4] = digitalRead(row5Pin);
rowValue[5] = digitalRead(row6Pin);
rowValue[6] = digitalRead(row7Pin);
// process keys pressed
for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
{
if (rowValue[rowCtr] != 0 && !keyPressed[rowCtr][colCtr])
{
keyPressed[rowCtr][colCtr] = true;
noteOn(rowCtr, colCtr);
}
}
// process keys released
for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
{
if (rowValue[rowCtr] == 0 && keyPressed[rowCtr][colCtr])
{
keyPressed[rowCtr][colCtr] = false;
noteOff(rowCtr, colCtr);
}
}
}
void scanColumn(int colNum)
{
digitalWrite(latchPin, LOW);
if (0 <= colNum && colNum <= 7)
{
shiftOut(dataPin, clockPin, MSBFIRST, B00000000); //right sr
shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum]); //left sr
}
else
{
shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum - 8]); //right sr
shiftOut(dataPin, clockPin, MSBFIRST, B00000000); //left sr
}
digitalWrite(latchPin, HIGH);
}
Код для отправки нажатой клавиши в MIDI-драйвер:
#define NOTE_ON_CMD 0x90
#define NOTE_OFF_CMD 0x80
#define NOTE_VELOCITY 127
void noteOn(int row, int col)
{
Serial.write(NOTE_ON_CMD);
Serial.write(keyToMidiMap[row][col]);
Serial.write(NOTE_VELOCITY);
}
void noteOff(int row, int col)
{
Serial.write(NOTE_OFF_CMD);
Serial.write(keyToMidiMap[row][col]);
Serial.write(NOTE_VELOCITY);
}
Исходный код можно скачать здесь.
Готовую схему решил перенести на Arduino Prototype Shield v.5.
Слева припаян шлейф проводов выходного сигнала синтезатора с понижающими резисторами.
Справа шлейф проводов для входного сигнала, подключенных через сдвиговый регистр.
Сделал отверстие в синтезаторе под разъем при помощи бормашинки и закрепил Arduino на шуруп. Приложив немного усилий по расчистке лишнего пластика, Arduino встала как родная.
Я использовал следующий pipeline: