MIDI Барабаны на 2560
- Войдите на сайт для отправки комментариев
Здравствуйте.
Я, ничего не смылся в программировании, пытаюсь собрать барабанный контроллер, преобразующий сигнал с пьезо-звукоснимателей в MIDI-данные)
Использую Arduino MEGA 2560.
В интернете куча скетчей подобных поделок. Я выбрал самый подходящий, немного переделал(изменил количество используемых входов, переназначил MIDI ноты и использовал библиотеку Arduino MIDI LIbrary).
В таком виде все работает отлично:
#include <MIDI.h> //Piezo defines #define NUM_PIEZOS 12 #define KICK_THRESHOLD 30 //anything < TRIGGER_THRESHOLD is treated as 0 #define TOM1_THRESHOLD 30 #define TOM2_THRESHOLD 30 #define TOM3_THRESHOLD 100 #define SNARE_THRESHOLD 100 #define RIM_THRESHOLD 50 #define HAT_THRESHOLD 100 #define CRASH_THRESHOLD 100 #define RIDE_THRESHOLD 100 #define BELL_THRESHOLD 100 #define CHINA_THRESHOLD 100 #define COWBELL_THRESHOLD 100 #define START_SLOT 0 //first analog slot of piezos //MIDI note defines for each trigger #define KICK_NOTE 36 #define TOM1_NOTE 71 #define TOM2_NOTE 69 #define TOM3_NOTE 67 #define SNARE_NOTE 38 #define RIM_NOTE 37 #define HAT_NOTE 7 #define CRASH_NOTE 77 #define RIDE_NOTE 62 #define BELL_NOTE 61 #define CHINA_NOTE 79 #define COWBELL_NOTE 47 //MIDI defines #define MAX_MIDI_VELOCITY 127 //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() { MIDI.begin(); //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[1] = TOM1_THRESHOLD; thresholdMap[2] = TOM2_THRESHOLD; thresholdMap[3] = TOM3_THRESHOLD; thresholdMap[4] = SNARE_THRESHOLD; thresholdMap[5] = RIM_THRESHOLD; thresholdMap[6] = HAT_THRESHOLD; thresholdMap[7] = CRASH_THRESHOLD; thresholdMap[8] = RIDE_THRESHOLD; thresholdMap[9] = BELL_THRESHOLD; thresholdMap[10] = CHINA_THRESHOLD; thresholdMap[11] = COWBELL_THRESHOLD; noteMap[0] = KICK_NOTE; noteMap[1] = TOM1_NOTE; noteMap[2] = TOM2_NOTE; noteMap[3] = TOM3_NOTE; noteMap[4] = SNARE_NOTE; noteMap[5] = RIM_NOTE; noteMap[6] = HAT_NOTE; noteMap[7] = CRASH_NOTE; noteMap[8] = RIDE_NOTE; noteMap[9] = BELL_NOTE; noteMap[10] = CHINA_NOTE; noteMap[11] = COWBELL_NOTE; } void loop() { 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; MIDI.send(NoteOn, note, velocity, 1); MIDI.send(NoteOff, note, velocity, 1); }
Хочу добавить потенциометр, который будет управлять положением педали хай хета(midi control change)
Вот код для потенциометра, который по отдельности тоже работает исправно:
#include <MIDI.h> // Variables: int cc = 1; int AnalogValue = 0; // define variables for the controller data int lastAnalogValue = 0; // define the "lastValue" variables void setup() { // launch MIDI MIDI.begin(); } void loop() { AnalogValue = analogRead(15); //knob 1 cutoff // convert to a range from 0 to 127: cc = AnalogValue / 8; // check if analog input has changed if (abs(lastAnalogValue - cc) > 1) { MIDI.sendControlChange(1, cc, 1); // update lastAnalogValue zero variable lastAnalogValue = cc; } }
Помогите объединить эти две задачи.
Я попробовал просто скопировать второй код в первый, предварительно объявив переменные, но в таком случает работает только первая часть, а значения с потенциометра не отправляются.
Куда мне следует поместить второй код, чтоб всё вместе отправлялось на выход?
Здравствуйте.
Я, ничего не смылся в программировании, пытаюсь собрать барабанный контроллер, преобразующий сигнал с пьезо-звукоснимателей в MIDI-данные)
Вы, судя по всему, музыкант? Давайте я Вам задам вопрос, подобный Вашему.
"Я, ничего не смылся в" музыке и никогда ни на чём не играл, пытаюсь выступить на концерте с симфоний №3 Бетховена. Погуглил немного, скачал таблицу соответсвия клавиш пианино этим ... как их ... кружочкам, которыми музыка записывается. Нажимаю клавиши. Каждая в отдельности звучит отлично! Осталось только объединить их, чтобы "Героическая" симфония зазвучала, но тут засада. Пытался и подряд их нажимать и в обратном порядке и случайным образом - "не выходит каменный цветок". Подскажите, куда копать-то!
А если серьёзно, то Вы затеяли непростую работу и Вам надо либо почитать. позаниматься и таки освоить программирование хоть на началльном уровне, либо идти в специальный раздел и заказть эту работу специалисту за некую плату по договрённости.
спасибо.
я не знаю что вы собираете но понимаю что такое потенциометр и чуть чуть в коде.., давайте так, вы добавляете весь код потенциометра в первый, теперь добавлять нужно так.. все что обьявлено с верху то так же копируем в верх, все что в функции сетап тоже должно быль в сетапе (2 функции сетап не должно быть) и все что в loop() тоже должно в такую же функцию переехать... но вот куда в какое место это я вам не скажу, и скорее всего там должно быть какоето условие типа if (проверка){сюда копируете код}
Тоесть определите в каком случае что должно произойти и после чего. кстати loop() выпорняется постоянно начиная с верху и до конца и потом снова на верхх...
Мне нужно, чтоб код для потенциометра исполнялся независимо от основного. они друг на друга никак не влияют, просто нужно чтоб при прохождении каждого цикла на выход отправлялись еще и данные из второго куска кода. Это я к тому, что условие тут, судя по всему, неуместно.
Переменные в сетапе-то я объявил, а куда остальной код из loop вставлять, не знаю)
Про это и спрашиваю)
или после первой открывающейся скобкой {
или перед последней закрывающей }
имею в виду в функции loop() { //СЮДА МОЖНО ЭТОТ КУСОК
сую перед последний, компилятор говорит
"exit status 1
'AnalogValue' was not declared in this scope"
вот так сейчас выглядит код:
Я не понял, что я сделал, но всё заработало) Большое спасибо за помощь.
А можно схему и рабочую прошивку увидеть?
И еще вопрос к програмистам как реализовать глушилку на краш?
И еще вопрос к програмистам как реализовать глушилку на краш?
В программировании не используются эти термины: "глушилка" и "краш".
Заглушить крэш - это когда ударяют по тарелке "крэш" (crash), а потом сразу берутся за неё рукой, чтобы погасить вибрации - заглушить звук (вот тут хорошо видно на первых 30 сек). В электроных ударнных установках такое тоже есть. Насколько я понял - там обычная кнопка в виде небольшой пластины снизу, за которую берутся рукой и прижимают. Но как это реализовано в MIDI не знаю, т.к. никогда этим не занимался.
Jeka_M все верно, задача в том чтобы скетч
переработать так чтобы на цифровые входы повесить две кнопки: одну кнопку использовать как контролер хета, а вторую как глушилку краша, есле кто знает как это реализовать буду весьма признателен.
Как к Ардуино подключить две кнопки, здесь знают практически все. А вот как их использовать - нужно представлять, что именно должна делать Ардуина при нажатии на эти кнопки. Вы этого, судя по всему, не знаете и знать не хотите.
Если это так, - Вам, вероятнее всего, в раздел "Ищу исполнителя".
andriano я не могу понять Вы хотите помочь или просто поглумится?
vinichenko.dl, я сам занимаюсь музыкальным проектом, естественно, не без MIDI. С удовольствием пообщаюсь с коллегой, но что-то делать за того, кому лень самому разбираться, желания у меня нет.
Как к Ардуино подключить две кнопки, здесь знают практически все. А вот как их использовать - нужно представлять, что именно должна делать Ардуина при нажатии на эти кнопки. Вы этого, судя по всему, не знаете и знать не хотите.
Если это так, - Вам, вероятнее всего, в раздел "Ищу исполнителя".
так, а что там сложного?
и все получилось, затем интегрировал его в скетч с пьезиками, получилось вот так
а вот с глушилкой краша все хуже, я просто не понимаю какую миди команду нужно послать чтобы замолчала тарелка, у кого какие мысли?
я просто не понимаю какую миди команду нужно послать чтобы замолчала тарелка
Так а что у Вас там на приёмной стороне стоит? Я вот вижу - ардуина отправляет MIDI-код по Serial, а принимает их кто? Вы же взяли где-то вот эти коды:
Так а что у Вас там на приёмной стороне стоит? Я вот вижу - ардуина отправляет MIDI-код по Serial, а принимает их кто? Вы же взяли где-то вот эти коды:
Кстати, интересный вопрос.
Насколько я помню, скорость MIDI 31250, а у vinichenko.dl:
я просто не понимаю какую миди команду нужно послать чтобы замолчала тарелка
Из общих соображений либо Note Off, либо Note On с vel=0.
Значит так:
Я всё это мастерил для использования с Addictive Drums. Там функция Choke организована следующим образом:
В миди-карте плагина у каждой тарелки есть нота, которая её глушит. Обычно - соседняя от основной. То есть, чтоб заглушить извлеченный звук тарелки, нужно отправить noteOn этой ноты, а не noteOff. Addictive не воспринимает длительности нот. Я не знаю, как работают другие VST, но в моём вот так. Велосити ноты-глушилки, по моему, может быть любым, но я ставил максимальное - 127.
Принажатии кнопки глушения, должна посылаться команда о взятии ноты, на которую назначено глушение крэша(или что ты там собрался глушить), а потом сразу же команда о её снятии, чтоб была нулевая длительность. Тогда всё будет работать.
А вообще, мусор это всё. Купи лучше дешевый роланд)
я просто не понимаю какую миди команду нужно послать чтобы замолчала тарелка
Так а что у Вас там на приёмной стороне стоит? Я вот вижу - ардуина отправляет MIDI-код по Serial, а принимает их кто? Вы же взяли где-то вот эти коды:
Я использую программы hairless-midiserial и loopmidi .
Кстати, интересный вопрос.
Насколько я помню, скорость MIDI 31250, а у vinichenko.dl:
так на скорости 115200 ардуинно "общается" с hairless-midiserial.
С глушением тарелок разобрался как и сказал ex3mgamer нужно послать команду взятия ноты глушения (CHOKE) этой тарелки.