Самодельные электронные ударные

Тема в разделе "Arduino & Shields", создана пользователем Dan, 24 дек 2016.

  1. Stas48

    Stas48 Нерд

    ну хз. у меня все работает. попробуй именно этот.
     
  2. Dan

    Dan Гик

    Пробовать нужно это ща, но с пэдом тоже нужно конструкцию хорошо проработать)у меня она несколько иная
     
  3. Stas48

    Stas48 Нерд

    интересно какая?
     
  4. Stas48

    Stas48 Нерд

    https://cloud.mail.ru/public/C6cj/ePbHBYAX9
    вот записывал на днях под минус без барабасов. можешь сам оценить работоспособность системы.
    За технику исполнения просьба не ругать- я вообще не барабанщик)
     
  5. Dan

    Dan Гик

    Снизу вверх:

    1 - Диск фанеры 10 мм
    2 - Губка для мытья посуды
    3 - Металлический диск (снизу к диску приклеен диск ДВП 2-3 мм толщиной, к ДВП приклеен датчик. Проклеено "Моментом")
    4 - Толстый слой поролона
    5 - Деревянный обод с сетчатой тканью

    Обод 5 винтами стягивается с диском фанеры 1, прижимая весь "пирог" из элементов 2-4

    Фото если получится, сегодня скину
     
  6. Dan

    Dan Гик

    Ок, послушаю)
    Да я сам гитарист, так что мне не техника важна)
     
  7. Stas48

    Stas48 Нерд

    да уж, интересно тоже посмотреть. ждем фоток
     
  8. sslobodyan

    sslobodyan Гик

    Простите за занудство - какому сигналу делать нечего?
    Полез искать сам. И таки да, только для ударных (10 канал) время выключения ноты не зависит от времени поступления ноте_офф. А так, как ноту все равно надо выключать для освобождения буфера секвенсора, то ноте_офф для ударных разрешается посылать сразу за ноте_он. Теперь все понятно. Дело было не в сигнале :).
     
  9. Stas48

    Stas48 Нерд

    а с предыдущим вопросом по кнопкам сможете помочь?
     
  10. sslobodyan

    sslobodyan Гик

    напишите словами как вы видите функционал. попробую.
     
  11. Stas48

    Stas48 Нерд

    Нужно подключить две кнопки к цифровым входам, чтобы при их нажатии уходил миди сигнал c кодом 78 и 80 соответственно.
     
    Последнее редактирование: 14 ноя 2017
  12. sslobodyan

    sslobodyan Гик

    Везде использовал 78 и 80 в названиях чтобы было понятно где правил. Попробуйте. Кнопки нажимаются замыканием на землю. Подтяжку на портах настроил, но для надежности подтяните резистором в несколько килоом к питанию. Пины 3 и 4.
    Код (C++):
    // задаем константы
    const int buttonPin = 2;     // номер входа, подключенный к кнопке

    #define BUTT_78_PIN 3
    #define BUTT_80_PIN 4
    #define INTERVAL_BUTTONS 50 // нажимать кнопки не чаще чем 50 мс

    // переменные
    int buttonState = 0;         // переменная для хранения состояния кнопки

    bool but78_pressed = false, but80_pressed = false;

    //Piezo defines
    #define NUM_PIEZOS 8
    #define SNARE_THRESHOLD 300     //настройка чувствительности датчиков
    #define LTOM_THRESHOLD 30
    #define CTOM_THRESHOLD 30
    #define RTOM_THRESHOLD 30
    #define LCYM_THRESHOLD 30
    #define RCYM_THRESHOLD 30
    #define KICK_THRESHOLD 30
    #define HIHAT_THRESHOLD 30
    #define RIDE_THRESHOLD 30
    //#define SIDE_THRESHOLD 50
    #define START_SLOT 0     //first analog slot of piezos

    //   назначение миди карты датчиков
      #define SNARE_NOTE 38
      #define LTOM_NOTE 71
      #define CTOM_NOTE 69
      #define RTOM_NOTE 65
      #define LCYM_NOTE 79
      #define RCYM_NOTE 77
      #define KICK_NOTE 36
      #define HIHAT_NOTE 55
      #define RIDE_NOTE 60
    // #define SIDE_NOTE 42


    //MIDI defines
    #define NOTE_ON_CMD 0x90
    #define NOTE_OFF_CMD 0x80
    #define MAX_MIDI_VELOCITY 127

    //MIDI baud rate
    #define SERIAL_RATE 31250

    //Program defines
    //ALL TIME MEASURED IN MILLISECONDS
    #define SIGNAL_BUFFER_SIZE 100
    #define PEAK_BUFFER_SIZE 30
    #define MAX_TIME_BETWEEN_PEAKS 20
    #define MIN_TIME_BETWEEN_NOTES 50

    //map that holds the mux slots of the piezos
    unsigned short slotMap[NUM_PIEZOS];

    //map that holds the respective note to each piezo
    unsigned short noteMap[NUM_PIEZOS];

    //map that holds the respective threshold to each piezo
    unsigned short thresholdMap[NUM_PIEZOS];

    //Ring buffers to store analog signal and peaks
    short currentSignalIndex[NUM_PIEZOS];
    short currentPeakIndex[NUM_PIEZOS];
    unsigned short signalBuffer[NUM_PIEZOS][SIGNAL_BUFFER_SIZE];
    unsigned short peakBuffer[NUM_PIEZOS][PEAK_BUFFER_SIZE];

    boolean noteReady[NUM_PIEZOS];
    unsigned short noteReadyVelocity[NUM_PIEZOS];
    boolean isLastPeakZeroed[NUM_PIEZOS];

    unsigned long lastPeakTime[NUM_PIEZOS];
    unsigned long lastNoteTime[NUM_PIEZOS];

    void setup()
    {
      Serial.begin(SERIAL_RATE);
     
      //initialize globals
      for(short i=0; i<NUM_PIEZOS; ++i)
      {
        currentSignalIndex[i] = 0;
        currentPeakIndex[i] = 0;
        memset(signalBuffer[i],0,sizeof(signalBuffer[i]));
        memset(peakBuffer[i],0,sizeof(peakBuffer[i]));
        noteReady[i] = false;
        noteReadyVelocity[i] = 0;
        isLastPeakZeroed[i] = true;
        lastPeakTime[i] = 0;
        lastNoteTime[i] = 0;  
        slotMap[i] = START_SLOT + i;
      }
     
      thresholdMap[0] = KICK_THRESHOLD;
      thresholdMap[6] = RTOM_THRESHOLD;
      thresholdMap[7] = RCYM_THRESHOLD;
      thresholdMap[4] = LCYM_THRESHOLD;
      thresholdMap[1] = SNARE_THRESHOLD;
      thresholdMap[3] = LTOM_THRESHOLD;
      thresholdMap[2] = HIHAT_THRESHOLD;
      thresholdMap[8] = CTOM_THRESHOLD;
      thresholdMap[5] = RIDE_THRESHOLD;
    //thresholdMap[9] = SIDE_THRESHOLD;


     
     
      noteMap[0] = KICK_NOTE;
      noteMap[6] = RTOM_NOTE;
      noteMap[7] = RCYM_NOTE;
      noteMap[4] = LCYM_NOTE;
      noteMap[1] = SNARE_NOTE;
      noteMap[3] = LTOM_NOTE;
      noteMap[2] = HIHAT_NOTE;
      noteMap[7] = CTOM_NOTE;
      noteMap[5] = RIDE_NOTE;
    //noteMap[9] = SIDE_NOTE;
     

      // инициализируем пин, подключенный к кнопке, как вход
      pinMode(buttonPin, INPUT);
     
      pinMode(BUTT_78_PIN, INPUT_PULLUP);
      pinMode(BUTT_80_PIN, INPUT_PULLUP);
    }

    uint32_t time_78=0, time_80=0;

    void loop()
    {

      buttonState = digitalRead(buttonPin);

      if ( time_78 < millis() ) {
        if ( !digitalRead(BUTT_78_PIN) ) { // кнопка нажата
            if ( !but78_pressed ) { // перед этим была отпущена
                but78_pressed = true;
                time_78 = millis() + INTERVAL_BUTTONS;
                noteFire(78, 64); // громкость?              
            }
        } else {
            but78_pressed = false;
        }
      }

      if ( time_80 < millis() ) {
        if ( !digitalRead(BUTT_80_PIN) ) { // кнопка нажата
            if ( !but80_pressed ) { // перед этим была отпущена
                but80_pressed = true;
                time_80 = millis() + INTERVAL_BUTTONS;
                noteFire(80, 64); // громкость?              
            }
        } else {
            but80_pressed = false;
        }
      }
     
      unsigned long currentTime = millis();
     
      for(short i=0; i<NUM_PIEZOS; ++i)
      {
        //get a new signal from analog read
        unsigned short newSignal = analogRead(slotMap[i]);
        signalBuffer[i][currentSignalIndex[i]] = newSignal;
       
        //if new signal is 0
        if(newSignal < thresholdMap[i])
        {
          if(!isLastPeakZeroed[i] && (currentTime - lastPeakTime[i]) > MAX_TIME_BETWEEN_PEAKS)
          {
            recordNewPeak(i,0);
          }
          else
          {
            //get previous signal
            short prevSignalIndex = currentSignalIndex[i]-1;
            if(prevSignalIndex < 0) prevSignalIndex = SIGNAL_BUFFER_SIZE-1;      
            unsigned short prevSignal = signalBuffer[i][prevSignalIndex];
           
            unsigned short newPeak = 0;
           
            //find the wave peak if previous signal was not 0 by going
            //through previous signal values until another 0 is reached
            while(prevSignal >= thresholdMap[i])
            {
              if(signalBuffer[i][prevSignalIndex] > newPeak)
              {
                newPeak = signalBuffer[i][prevSignalIndex];      
              }
             
              //decrement previous signal index, and get previous signal
              prevSignalIndex--;
              if(prevSignalIndex < 0) prevSignalIndex = SIGNAL_BUFFER_SIZE-1;
              prevSignal = signalBuffer[i][prevSignalIndex];
            }
           
            if(newPeak > 0)
            {
              recordNewPeak(i, newPeak);
            }
          }
     
        }
           
        currentSignalIndex[i]++;
        if(currentSignalIndex[i] == SIGNAL_BUFFER_SIZE) currentSignalIndex[i] = 0;
      }
    }

    void recordNewPeak(short slot, short newPeak)
    {
      isLastPeakZeroed[slot] = (newPeak == 0);
     
      unsigned long currentTime = millis();
      lastPeakTime[slot] = currentTime;
     
      //new peak recorded (newPeak)
      peakBuffer[slot][currentPeakIndex[slot]] = newPeak;
     
      //1 of 3 cases can happen:
      // 1) note ready - if new peak >= previous peak
      // 2) note fire - if new peak < previous peak and previous peak was a note ready
      // 3) no note - if new peak < previous peak and previous peak was NOT note ready
     
      //get previous peak
      short prevPeakIndex = currentPeakIndex[slot]-1;
      if(prevPeakIndex < 0) prevPeakIndex = PEAK_BUFFER_SIZE-1;      
      unsigned short prevPeak = peakBuffer[slot][prevPeakIndex];
     
      if(newPeak > prevPeak && (currentTime - lastNoteTime[slot])>MIN_TIME_BETWEEN_NOTES)
      {
        noteReady[slot] = true;
        if(newPeak > noteReadyVelocity[slot])
          noteReadyVelocity[slot] = newPeak;
      }
      else if(newPeak < prevPeak && noteReady[slot])
      {
        noteFire(noteMap[slot], noteReadyVelocity[slot]);
        noteReady[slot] = false;
        noteReadyVelocity[slot] = 0;
        lastNoteTime[slot] = currentTime;
      }
     
      currentPeakIndex[slot]++;
      if(currentPeakIndex[slot] == PEAK_BUFFER_SIZE) currentPeakIndex[slot] = 0;
    }

    void noteFire(unsigned short note, unsigned short velocity)
    {
      if(velocity > MAX_MIDI_VELOCITY)
        velocity = MAX_MIDI_VELOCITY;
     
      midiNoteOn(note, velocity);
      midiNoteOff(note, velocity);
    }


    void midiNoteOn(byte note, byte midiVelocity)

    {
     
    if (note == 55 && buttonState == HIGH ) {
     
      Serial.write(NOTE_ON_CMD);
      Serial.write(52);
      Serial.write(midiVelocity);
      }
      else
      {
      Serial.write(NOTE_ON_CMD);
      Serial.write(note);
      Serial.write(midiVelocity);
      }

    }

    void midiNoteOff(byte note, byte midiVelocity)
    {
      Serial.write(NOTE_OFF_CMD);
      Serial.write(note);
      Serial.write(midiVelocity);
    }

     
     
    Иосиф Виссарионович и Stas48 нравится это.
  13. Stas48

    Stas48 Нерд

    Спасибо! попробую сегодня.
     
  14. Stas48

    Stas48 Нерд

    Пока некогда было заняться этим делом. У меня вопрос по коду: подскажите, вот эта строка не будет ли замедлять работу всего устройства на 50мс?

    #define INTERVAL_BUTTONS 50 // нажимать кнопки не чаще чем 50 мс
     
  15. sslobodyan

    sslobodyan Гик

  16. Stas48

    Stas48 Нерд

    Интересно что в итоге. Получилось у тебя или нет. В чем проблема была в коде или пэдах?
     
  17. Dan

    Dan Гик

    Мне кажется, во всем понемногу
     
  18. Dan

    Dan Гик

    Наконец то добрались руки до фоток своего пэда. Вот какая конструкция окончательная получилась у меня:
     

    Вложения:

    • 1.jpg
      1.jpg
      Размер файла:
      1,8 МБ
      Просмотров:
      696
    • 2.jpg
      2.jpg
      Размер файла:
      1,3 МБ
      Просмотров:
      700
    • 3.jpg
      3.jpg
      Размер файла:
      1,3 МБ
      Просмотров:
      793
    • 4.jpg
      4.jpg
      Размер файла:
      1,3 МБ
      Просмотров:
      558
    • 5.jpg
      5.jpg
      Размер файла:
      1,4 МБ
      Просмотров:
      695
  19. Stas48

    Stas48 Нерд

    Мне кажется данная конструкция не будет передавать нужную вибрацию на датчик - слишком толстый поролон. Да он и вообще никакой сверху не нужен. Лучше использовать пористую резину 3-8 мм. Ну или просто резину, если нет пористой. Да и обтянется тканью наверное поаккуратнее. Использование двп также сомнительно. Двп будет сильно скрадывать вибрацию. Фонера, пластик 3-5мм или металл предпочтительнее.
     
  20. Dan

    Dan Гик

    Насчет поролона. Может он и толстый, но передается удар через него хорошо, хотя возможно, можно и тоньше можно использовать.
    Пробовал наклеивать сверху на металлическую пластину резину, полиуретан - не давало такого эффекта как в данной консьрукции.
    Что касается ДВП то она здесь не случайна и гасит лишние колебания металоической пластины. В оригинальной конструкции, я думаю, использовано с этой же целью оргстекло. Без ДВП результат был намного хуже, так как металлическая пластина слишком долго затухает.
    Посмотрите конструкцию оригинального пэда, там суть та же, только все аккуратнее и некоторые материалы заменены.
    Если есть возможность, снимите видео рвботы Вашего пэда, было бы интенесно глянуть.