MIDI drum

Тема в разделе "Arduino & Shields", создана пользователем zsm, 28 июн 2013.

  1. zsm

    zsm Гик

    Добрый день , нашел на просторах интернета вот такой проект.
    Решив не бросаться сразу на амбразуру попробовал просто передать MIDI с помощью официального примера через Serial MIDI Converter и midi_yoke всё завелось на скорости 19200.
    Но когда попробовал пример из первой ссылки столкнулся с тем что данные на любой скорости передаются с ошибками. По факту доходит не читаемая белиберда:(
    Подозреваю что дело в функции Serial.print используемой в midi drum . Если заменять Serial.print на Serial.write как в примере то ошибки передачи пропадают, но передаются сразу все ноты...
    Буду рад любым советам или просто соображениям по теме :)

    Код (C):
    //  *****************************************************************************************************************
    //  *                                                                                                              *
    //  *                                        SpikenzieLabs.com                                                   *
    //  *                                                                                                              *
    //  *                                          Drum Kit - Kit                                                     *
    //  *                                                                                                              *
    //  *                                                                                                              *
    //  *****************************************************************************************************************
    //
    //  BY: MARK DEMERS Copywrite 20009
    //  April. 2009
    //  VERSION: 1.b
    //
    //  DESCRIPTION:
    //  Arduino analog input used to sense piezo drum hits then sent serialy to processing.
    //  
    //  Required - Hardware:
    //  1. Drum kit - kit (From SpikenzieLabs.com)
    //  2. Arduino
    //
    //  Required - Software:
    //  1. Serial MIDI converter
    //  2. Garage Band, Ableton Live etc ...
    //
    // LEGAL:
    // This code is provided as is. No guaranties or warranties are given in any form. It is your responsibilty to
    // determine this codes suitability for your application.




    //*******************************************************************************************************************
    // User settable variables         
    //*******************************************************************************************************************

    unsigned char PadNote[6] = {52,16,66,63,40,65};      // MIDI notes from 0 to 127 (Mid C = 60)

    int PadCutOff[6] = {600,600,600,600,600,600};          // Minimum Analog value to cause a drum hit

    int MaxPlayTime[6] = {90,90,90,90,90,90};              // Cycles before a 2nd hit is allowed

    #define  midichannel    0;                            // MIDI channel from 0 to 15 (+1 in "real world")

    boolean VelocityFlag  = true;                          // Velocity ON (true) or OFF (false)





    //*******************************************************************************************************************
    // Internal Use Variables          
    //*******************************************************************************************************************

    boolean activePad[6] = {0,0,0,0,0,0};                  // Array of flags of pad currently playing
    int PinPlayTime[6] = {0,0,0,0,0,0};                  // Counter since pad started to play

    unsigned char status;

    int pin = 0;     
    int hitavg = 0;

    //*******************************************************************************************************************
    // Setup           
    //*******************************************************************************************************************

    void setup()
    {
      Serial.begin(57600);                                // connect to the serial port 115200
    }

    //*******************************************************************************************************************
    // Main Program        
    //*******************************************************************************************************************

    void loop()
    {
      for(int pin=0; pin < 6; pin++)
      {
        hitavg = analogRead(pin);                             // read the input pin

        if((hitavg > PadCutOff[pin]))
        {
          if((activePad[pin] == false))
          {
            if(VelocityFlag == true)
            {
    //        hitavg = 127 / ((1023 - PadCutOff[pin]) / (hitavg - PadCutOff[pin])); // With full range (Too sensitive ?)
              hitavg = (hitavg / 8) -1 ;                                                 // Upper range
            }
            else
            {
              hitavg = 127;
            }

            MIDI_TX(144,PadNote[pin],hitavg);
            PinPlayTime[pin] = 0;
            activePad[pin] = true;
          }
          else
          {
            PinPlayTime[pin] = PinPlayTime[pin] + 1;
          }
        }
        else if((activePad[pin] == true))
        {
          PinPlayTime[pin] = PinPlayTime[pin] + 1;
         
          if(PinPlayTime[pin] > MaxPlayTime[pin])
          {
            activePad[pin] = false;
            MIDI_TX(128,PadNote[pin],127);
          }
        }
      }
    }


    //*******************************************************************************************************************
    // Transmit MIDI Message           
    //*******************************************************************************************************************
    void MIDI_TX(unsigned char MESSAGE, unsigned char PITCH, unsigned char VELOCITY)
    {
      status = MESSAGE + midichannel;
      Serial.print(status);
      Serial.print(PITCH);
      Serial.print(VELOCITY);
    }

     
     
  2. nailxx

    nailxx Официальный Нерд Администратор

    Смотрите, Serial.print и Serial.write — разные вещи. print отсылает по проводу данные, переведённые в текст, а write — данные непосредственно. Например:

    Serial.print(123) — отправит 3 байта: код символа '1', код символа '2', код символа '3'
    Serial.write(123) — отправит 1 байт: число 123, т.е. байт 01111011

    Протокол MIDI по определению, насколько я понимаю, требует «сырые данные», т.е. отправку через `write`. При этом, опять же по стандарту, строго на скорости 31250, а не 57600, как в вашем скетче.

    Можете пояснить подробнее что значит «передаются сразу все ноты» и как вы предполагаете, что должно быть?
     
    zsm нравится это.
  3. zsm

    zsm Гик

    Спасибо за ответ.
    Оказалось что сразу все ноты передавались из за помех (подавал сигнал на один аналоговый вход, а в аудио редактор приходили сообщения как будто ударили сразу по всем барабанам) ,притянул аналоговые пины к земле , всё заработало :)
    естественно с serial.write на скорости 19200 через Serial_MIDI_Converter
    вообще не понятно почему в "каноническом" скетче Serial.print используется...

    Вот скетч рабочий если надо кому...

    Код (C):

    //*******************************************************************************************************************
    // User settable variables         
    //*******************************************************************************************************************

    unsigned char PadNote[6] = {36,37,38,39,40,41};      // MIDI notes from 0 to 127 (Mid C = 60)

    int PadCutOff[6] = {600,600,600,600,600,600};          // Minimum Analog value to cause a drum hit

    int MaxPlayTime[6] = {90,90,90,90,90,90};              // Cycles before a 2nd hit is allowed

    #define  midichannel    0;                            // MIDI channel from 0 to 15 (+1 in "real world")

    boolean VelocityFlag  = true;                          // Velocity ON (true) or OFF (false)





    //*******************************************************************************************************************
    // Internal Use Variables          
    //*******************************************************************************************************************

    boolean activePad[6] = {0,0,0,0,0,0};                  // Array of flags of pad currently playing
    int PinPlayTime[6] = {0,0,0,0,0,0};                  // Counter since pad started to play

    unsigned char status;

    int pin = 0;     
    int hitavg = 0;

    //*******************************************************************************************************************
    // Setup           
    //*******************************************************************************************************************

    void setup()
    {
      Serial.begin(19200);                                // connect to the serial port 115200
    }

    //*******************************************************************************************************************
    // Main Program        
    //*******************************************************************************************************************

    void loop()
    {
      for(int pin=0; pin < 6; pin++)
      {
        hitavg = analogRead(pin);                             // read the input pin

        if((hitavg > PadCutOff[pin]))
        {
          if((activePad[pin] == false))
          {
            if(VelocityFlag == true)
            {
    //        hitavg = 127 / ((1023 - PadCutOff[pin]) / (hitavg - PadCutOff[pin])); // With full range (Too sensitive ?)
              hitavg = (hitavg / 8) -1 ;                                                 // Upper range
            }
            else
            {
              hitavg = 127;
            }

            MIDI_TX(144,PadNote[pin],hitavg);
            PinPlayTime[pin] = 0;
            activePad[pin] = true;
          }
          else
          {
            PinPlayTime[pin] = PinPlayTime[pin] + 1;
          }
        }
        else if((activePad[pin] == true))
        {
          PinPlayTime[pin] = PinPlayTime[pin] + 1;
         
          if(PinPlayTime[pin] > MaxPlayTime[pin])
          {
            activePad[pin] = false;
            MIDI_TX(128,PadNote[pin],127);
          }
        }
      }
    }


    //*******************************************************************************************************************
    // Transmit MIDI Message           
    //*******************************************************************************************************************
    void MIDI_TX(unsigned char MESSAGE, unsigned char PITCH, unsigned char VELOCITY)
    {
      status = MESSAGE + midichannel;
      Serial.write(status);
      Serial.write(PITCH);
      Serial.write(VELOCITY);
    }

     
     
    SergyPozitiF1 и nailxx нравится это.
  4. nailxx

    nailxx Официальный Нерд Администратор

    Немногие работают со звуком через Arduino. А зря, много ведь всего интересного можно сделать :)
     
  5. zsm

    zsm Гик

    Это точно, вот интересный проэкт например.