MIDI - клавиатура на ардуино

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем XxOinvizioNxX, 19 фев 2017.

  1. XxOinvizioNxX

    XxOinvizioNxX Нерд

    *Начну с того, что я первый раз на этом форуме, так что если выбрал не тот раздел - извините.

    А теперь, к делу!

    И так, я решил сделать MIDI клавиатуру на базе Arduino Nano.
    На днях нашёл детский синтезатор с клавиатурой на 44 клавиши (маловато, согласен. Но мне пойдёт.)
    [​IMG]
    Загуглил приблизительную схему на неё:
    [​IMG]
    Т.е. у меня 14 выводов (6 - от анодов диодов, 8 от кнопок)
    При помощи Keypad сделал считывание значений с клавиатуры:
    Код (C++):
    #include <Keypad.h>

    const byte ROWS = 8;
    const byte COLS = 6;
    char hexaKeys[ROWS][COLS] = {
      {'1','9','G','O','X','^'},
      {'2','0','H','P','Y','&'},
      {'3','A','I','Q','Z','/'},
      {'4','B','J','R','!','*'},
      {'5','C','K','S','@','0'},
      {'6','D','L','T','#','0'},
      {'7','E','M','U','$','0'},
      {'8','F','N','W','%','0'},
    };
    byte rowPins[ROWS] = {2, 3, 4, 5, 6, 7, 8, 9}; // выводы с кнопок
    byte colPins[COLS] = {10, 11, A0, A1, A2, A3}; // выводы с диодов

    Keypad keypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS );



    void setup(){
      Serial.begin(9600);
    }
     
    void loop(){
      char key = keypad.getKey();
     
       if (key){
         Serial.println(key);
       }
    }

     
    Нашёл в гугле код, его переделал под себя:

    Код (C++):
    #include <Keypad.h>
    const byte ROWS = 8;
    const byte COLS = 6;
    char hexaKeys[ROWS][COLS] = {
      {'1','9','G','O','X','^'},
      {'2','0','H','P','Y','&'},
      {'3','A','I','Q','Z','/'},
      {'4','B','J','R','!','*'},
      {'5','C','K','S','@','0'},
      {'6','D','L','T','#','0'},
      {'7','E','M','U','$','0'},
      {'8','F','N','W','%','0'},
    };
    byte rowPins[ROWS] = {2, 3, 4, 5, 6, 7, 8, 9}; // выводы с кнопок
    byte colPins[COLS] = {10, 11, A0, A1, A2, A3}; // выводы с диодов

    Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
    #define note_C 0x3C  // C4
    #define note_D 0x3E  // D4
    #define note_E 0x40  // E4
    #define note_F 0x41  // F4
    #define note_G 0x43  // G4
    #define note_A 0x45  // A4
    #define note_B 0x47  // B4
    int buttonState_C = 0;
    int buttonState_D = 0;
    int buttonState_E = 0;
    int buttonState_F = 0;
    int buttonState_G = 0;
    int buttonState_A = 0;
    int buttonState_B = 0;

    int note_C_send_off = false;
    int note_C_send_on = false;
    int note_D_send_off = false;
    int note_D_send_on = false;
    int note_E_send_off = false;
    int note_E_send_on = false;
    int note_F_send_off = false;
    int note_F_send_on = false;
    int note_G_send_off = false;
    int note_G_send_on = false;
    int note_A_send_off = false;
    int note_A_send_on = false;
    int note_B_send_off = false;
    int note_B_send_on = false;

    uint8_t buf[8] = {
      0 };

    void setup() {
      Serial.begin(115200);

    }

    void loop() {
       char key = customKeypad.getKey();
        // Нота C
      if (key == '1' && note_C_send_on == false)
      {
        noteOn(0x90, note_C, 0x7F);
        note_C_send_on = true;    // Команда Note On послана
        note_C_send_off = false;  // Команда Note Off не послана
      }
      else if (key == '1' && note_C_send_on == true)
      {
        noteOn(0x00, note_C, 0x7F);
        note_C_send_on = true;
        note_C_send_off = false;
      }
      else if (key != '1' && note_C_send_off == false)
      {
        noteOn(0x90, note_C, 0x00);
        note_C_send_on = false;
        note_C_send_off = true;
      }
     
      // Нота D
      if (key == '2' && note_D_send_on == false)
      {
        noteOn(0x90, note_D, 0x7F);
        note_D_send_on = true;
        note_D_send_off = false;
      }
      else if (key == '2' && note_D_send_on == true)
      {
        noteOn(0x00, note_D, 0x7F);
        note_D_send_on = true;
        note_D_send_off = false;
      }
      else if (key != '2' && note_D_send_off == false)
      {
        noteOn(0x90, note_D, 0x00);
        note_D_send_on = false;
        note_D_send_off = true;
      }
     
      // Нота E
      if (key == '3' && note_E_send_on == false)
      {
        noteOn(0x90, note_E, 0x7F);
        note_E_send_on = true;
        note_E_send_off = false;
      }
      else if (key == '3' && note_E_send_on == true)
      {
        noteOn(0x00, note_E, 0x7F);
        note_E_send_on = true;
        note_E_send_off = false;
      }
      else if (key != '3' && note_E_send_off == false)
      {
        noteOn(0x90, note_E, 0x00);
        note_E_send_on = false;
        note_E_send_off = true;
      }
     
      // Нота F
      if (key == '4' && note_F_send_on == false)
      {
        noteOn(0x90, note_F, 0x7F);
        note_F_send_on = true;
        note_F_send_off = false;
      }
      else if (key == '4' && note_F_send_on == true)
      {
        noteOn(0x00, note_F, 0x7F);
        note_F_send_on = true;
        note_F_send_off = false;
      }
      else if (key != '4' && note_F_send_off == false)
      {
        noteOn(0x90, note_F, 0x00);
        note_F_send_on = false;
        note_F_send_off = true;
      }


      // Нота G
      if (key == '5' && note_G_send_on == false)
      {
        noteOn(0x90, note_G, 0x7F);
        note_G_send_on = true;
        note_G_send_off = false;
      }
      else if (key == '5' && note_G_send_on == true)
      {
        noteOn(0x00, note_G, 0x7F);
        note_G_send_on = true;
        note_G_send_off = false;
      }
      else if (key != '5' && note_G_send_off == false)
      {
        noteOn(0x90, note_G, 0x00);
        note_G_send_on = false;
        note_G_send_off = true;
      }
     
      // Нота A
      if (key == '6' && note_A_send_on == false)
      {
        noteOn(0x90, note_A, 0x7F);
        note_A_send_on = true;
        note_A_send_off = false;
      }
      else if (key == '6' && note_A_send_on == true)
      {
        noteOn(0x00, note_A, 0x7F);
        note_A_send_on = true;
        note_A_send_off = false;
      }
      else if (key != '6' && note_A_send_off == false)
      {
        noteOn(0x90, note_A, 0x00);
        note_A_send_on = false;
        note_A_send_off = true;
      }  
     
      // Нота B
      if (key == '7' && note_B_send_on == false)
      {
        noteOn(0x90, note_B, 0x7F);
        note_B_send_on = true;
        note_B_send_off = false;
      }
      else if (key == '7' && note_B_send_on == true)
      {
        noteOn(0x00, note_B, 0x7F);
        note_B_send_on = true;
        note_B_send_off = false;
      }
      else if (key != '7' && note_B_send_off == false)
      {
        noteOn(0x90, note_B, 0x00);
        note_B_send_on = false;
        note_B_send_off = true;
      }

    }
    void noteOn(int cmd, int pitch, int velocity) {
      Serial.write(cmd);
      Serial.write(pitch);
      Serial.write(velocity);
      delay(20);
    }
    Но оно не может считывать удержание клавиши или нажатие нескольких клавиш.
    Помогите пожалуйста осуществить это.
    Сделать надо без всяких сдвиговых регистров, расширителей и т.п. просто всё к ардуино. Также, обязательна возможность нажатия и удержания сразу нескольких клавиш (на самом синтезаторе одновременно можно было зажимать 8 клавиш).
    Заранее спасибо!
     
  2. rkit

    rkit Гуру

    А где вопрос? Загляните в keypad.h, даст общее представление. Дальше дополняйте до нужного вам функционала.
     
  3. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Да вот я и задал вопрос, как дополнить-то?
     
  4. rkit

    rkit Гуру

    Сесть и написать программу, как. Или идите в "закажу проект", там за вас напишут. Не бесплатно, разумеется.
     
  5. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Мда... хороший видимо этот форум, с наидобрейшими людьми.....
    Можно хоть принцип объяснить, как должно происходить считывание клавиши, которая ужерживается? И считывание зажатых одновременно клавиш.
     
  6. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Я не прошу ни у кого сделать за меня проект и т.п. Я прошу помочь СО СЧИТЫВАНИЕМ КЛАВИШ!!!!
     
  7. rkit

    rkit Гуру

    У вас уже есть на руках код, который опрашивает клавиши.
    Дальше надо просто написать автомат, который после каждого цикла опроса будет сравнивать состояние клавиатуры с предыдущим. И на основе этого решать, что нажали, что отпустили, что удержали. Была нажата, а теперь нет - значит отпустили.
     
  8. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Понятно, лучше напишу на нормальные форумы, тут я ответа не дождусь.
     
  9. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Проще самому докапаться.... и сделать по-человечески
     
  10. rkit

    rkit Гуру

    Ну и как тут быть добрым? Когда уже на пальцах разжевываешь, а человек просто игнорирует. что ты пишешь.
     
  11. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Это даёт возможность зажимать одновременно не более 2-ух клавиш, а как сделать больше?
    Код (C++):
    #include <Keypad.h>

    const byte ROWS = 8;
    const byte COLS = 6;
    char keys[ROWS][COLS] = {
      {'1','9','G','O','X','^'},
      {'2','0','H','P','Y','&'},
      {'3','A','I','Q','Z','/'},
      {'4','B','J','R','!','*'},
      {'5','C','K','S','@','0'},
      {'6','D','L','T','#','0'},
      {'7','E','M','U','$','0'},
      {'8','F','N','W','%','0'},
    };
    byte rowPins[ROWS] = {2, 3, 4, 5, 6, 7, 8, 9};
    byte colPins[COLS] = {10, 11, A0, A1, A2, A3};
    String msg;
    Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
    #define note_C 0x3C  // C4
    #define note_D 0x3E  // D4
    #define note_E 0x40  // E4
    #define note_F 0x41  // F4
    #define note_G 0x43  // G4
    #define note_A 0x45  // A4
    #define note_B 0x47  // B4
    unsigned long loopCount;
    unsigned long startTime;

    void setup() {
        Serial.begin(115200);
        loopCount = 0;
        startTime = millis();
        msg = "";
    }


    void loop() {
        if (kpd.getKeys())
        {
            for (int i=0; i<LIST_MAX; i++)   // Scan the whole key list.
            {
                if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
                {
                    switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
                        case PRESSED:
                        kpress(kpd.key[i].kchar);
                    break;
                        case HOLD:
                        msg = " HOLD.";
                    break;
                        case RELEASED:
                        kreleased(kpd.key[i].kchar);
                    break;
                        case IDLE:
                        msg = " IDLE.";
                    }
                    //Serial.print("Key ");
                    //Serial.print(kpd.key[i].kchar);
                    //Serial.println(msg);
                }
            }
        }
    }  // End loop
    void noteOn(int cmd, int pitch, int velocity) {
      Serial.write(cmd);
      Serial.write(pitch);
      Serial.write(velocity);
      //delay(20);
    }
    void kpress(char knum) {
      switch (knum) {
        case '1':
        noteOn(0x90, note_C, 0x7F);
        break;
        case '2':
        noteOn(0x90, note_D, 0x7F);
        break;
        case '3':
        noteOn(0x90, note_E, 0x7F);
        break;
        case '4':
        noteOn(0x90, note_F, 0x7F);
        break;
        case '5':
        noteOn(0x90, note_G, 0x7F);
        break;
        case '6':
        noteOn(0x90, note_A, 0x7F);
        break;
        case '7':
        noteOn(0x90, note_B, 0x7F);
        break;
      }
    }
    void kreleased(char knum) {
    switch (knum) {
        case '1':
        noteOn(0x90, note_C, 0x00);
        break;
        case '2':
        noteOn(0x90, note_D, 0x00);
        break;
        case '3':
        noteOn(0x90, note_E, 0x00);
        break;
        case '4':
        noteOn(0x90, note_F, 0x00);
        break;
        case '5':
        noteOn(0x90, note_G, 0x00);
        break;
        case '6':
        noteOn(0x90, note_A, 0x00);
        break;
        case '7':
        noteOn(0x90, note_B, 0x00);
        break;
      }
    }
     
  12. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Всё, решение нашёл сам, экспериментальным путём- поставить подтягивающие резисторы на выводы с кнопок и на 5 вольт по 10к
     
  13. XxOinvizioNxX

    XxOinvizioNxX Нерд

    остался по - сути один вопрос, как сделать переключение по октавам?
     
  14. XxOinvizioNxX

    XxOinvizioNxX Нерд

    С помощью кнопочек или реостата, без энкодера
     
  15. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Требуется помощь!
    У меня есть номер клавиши, например 41. Её надо переконвертировать в MIDI - формат, т.е. в HEX и 0x вначале, Например просто в HEX, это так: (41, HEX), а как на выходе ещё в начало поставить 0x?
     
  16. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Причём на выходе должен быть int
     
  17. XxOinvizioNxX

    XxOinvizioNxX Нерд

    Обрыл весь гугл, нигде не нашёл как конвертировать DEC- число в формат 0xHEX
     
  18. XxOinvizioNxX

    XxOinvizioNxX Нерд