Барабанная установка и гитара на Arduino UNO

Идея создать автоматизированный аккомпанемент родилась еще в прошлом веке, но до недавнего времени я не был знаком с микроконтроллерами. Arduino позволило довольно просто реализовать задуманное устройство.

Этап 1. Барабанная установка



Вся конструкция барабанной установки в сборе.

Основным компонентом барабанной установки послужили два сувенирных барабана, которые были позаимствованы у супруги на время экспериментов.



Все элементы конструкции собраны из алюминиевого профиля, который легко пилится и сверлится. Принцип колотушки был взят с педали настоящей барабанной установки. Пружина возвращает колотушку в свое начальное положение, а настройка угла производится перекидыванием пружины по резьбе настроечного болта.



Собиралось все итеративно по принципу экономии пространства, т.е. нужно было все уместить в каком то конечном объеме. Плюс, каждый механизм должен быть независим.



Для Hi-Hat тарелки очень хорошо подошла миска для собак. Для заглушки тарелки использовался обычный компакт-диск.
Конструкция Hi-Hat тарелки разобранная и в сборе.



Для приведения колотушек в движение на китайских торговых площадках были куплены дешевые соленоиды JF-0730B с рабочей силой тока 1 Ампер и напряжением 12 Вольт. Но, как показала практика, одного электромагнита оказалась недостаточно для обеспечения достаточной силы удара. Поэтому мною было принято решение для колотушек использовать по два параллельно соединенных соленоида, так как ждать 2-х амперные не хотелось. Но, тем не менее, они были заказаны для привода открывания Hi-Hat тарелки.


Поступательное движение соленоида создает крутящий момент посредством синтетической нити.
Для того чтобы бас-барабан звучал глухо и более «басово», его колотушка была заглушена игрушечным синтетическим носком.



Управление соленоидами осуществляется через популярные в узких кругах транзисторы TIP120.



Для большой Crash тарелки использовалась крупная металлическая посуда. Для большей реалистичности блюдо обвешано старыми цепочками.

Видео:



Этап 2. Гитара



Первым делом собирался блок соленоидов для прижимания струн на грифе гитары.


На гриф блок соленоидов крепится на два ремешковых каподастра и может быть легко монтирован или демонтирован. Для заглушки звона струн и сокращения времени звучания ноты используется кусок поролона.



Для дергания струн иcпользованы более мощные соленоиды с прикрепленными к сердечникам медиаторами.



Этап 3. Подключение и настройка.



Схема подключения барабанной установки.
Все сопротивления 1KOm. Диоды 1N4007.


Установка и гитара управляются одним Arduino UNO через USB кабель. Барабанная и басовая дорожки в секвенсоре в виде midi-команд посылаются на виртуальный midi-порт созданный виртуальным midi-драйвером LoopBe1 (http://www.nerds.de/en/loopbe1.html).

Уже в программе Processing (https://www.processing.org) подготовленный скетч перехватывает midi-команды и посылает в порт Arduino соответствующие команды в виде байтов.

Скетч processing:


import processing.serial.*;
import promidi.*;


Serial myPort;
MidiIO midiIO;


int message=0;
boolean[] notes = new boolean[48];
void setup()
{
  myPort = new Serial(this, "COM4", 9600);
 midiIO = MidiIO.getInstance(this);
midiIO.printDevices();
midiIO.openInput(0 ,0);
  String message = "Starting...";
println(message);

for (int i = 28; i <= 39; i = i++) {
   myPort.write(i);
}

}


void draw() {}

void noteOn(Note note, int deviceNum, int midiChan)
{
 int vel = note.getVelocity();
 int pitch = note.getPitch();
 int _length = note.getNoteLength();
int _noteIndex = 0;

if (vel>0) 
{
 if (pitch >= 60 && pitch <= 95) {
  _noteIndex = pitch-60;
   message=pitch;
 } 
 else {message=0;}
}
else
 {
 _noteIndex = 0;
 message =0;}
 
 
 if (message>0 && notes[_noteIndex] == false)
 {
    println("on pitch: "+pitch);
     notes[_noteIndex] = true;
 myPort.write(message);
 }
}
void noteOff(Note note, int deviceNum, int midiChan)
{
 int vel = note.getVelocity();
 int pitch = note.getPitch();
 int _length = note.getNoteLength();
 int _noteIndex = 0;

 if (pitch >= 60 && pitch <= 95) {
 message=pitch-48;
  _noteIndex = pitch-60;
 } 
 else {message=0;}

 if (message>0 && notes[_noteIndex])
 {
   println("off pitch: "+(pitch));
    notes[_noteIndex] = false;
 myPort.write(message);
 }
}



Для удобства был выбран диапазон нот от «До» третей октавы (код 60) до «Си» — пятой (код 95). Диапазон управляющих байтов от 60 до 95. Так как в стандарте протокола midi нажатие и отпускание соответствует двум разным командам, условился, что диапазон от 12 до 47 ([код ноты] — 48) будет соответствовать кодам отпускания клавиш.

Так как в общей сложности одним контроллером мне пришлось управлять 18 соленоидами, то я воспользовался статьей SPI и Arduino: плодим выходы (http://robocraft.ru/blog/arduino/519.html). Еще одним плюсом управления гитарой через сдвиговые регистры стало то, что для ее подключения используется стандартный ethernet провод с восемью проводами.

Схема подключения гитары:


Основной проблемой при написании дорожки барабанов было то, что механизм колотушки имеет переменную задержку, связанную с инерцией и текущим угловым положением. Поэтому каждая барабанная партия писалась индивидуально удар за ударом.

Скетч Arduino:


#include <SPI.h>
int val;
int drumpins[] = {2, 3, 4, 5, 6, 7};

int srringpins[] = {10, 14};
int smokePin = 17;

enum { REG1 = 9, REG2 = 8 };
uint8_t register_1 = 0, register_2 = 0;

void setup() {

  /* SPI init*/
  SPI.begin();

  /* Example from http://robocraft.ru/blog/arduino/519.html */
  pinMode(REG1, OUTPUT);
  pinMode(REG2, OUTPUT);
  
  // put your setup code here, to run once:
  for (int i = 0; i < 6; i++)
  {
    pinMode(drumpins[i], OUTPUT) ; //set pin as OUTPUT
  }

  // put your setup code here, to run once:
  for (int i = 0; i < 2; i++)
  {
    pinMode(srringpins[i], OUTPUT) ; //set pin as OUTPUT
  }

  writeShiftRegister(REG1, 0);
  writeShiftRegister(REG2, 0);
  resetPins();
  Serial.begin(9600); //Start serial communication

}

void loop() {

  if (Serial.available())
  {
    val = Serial.read();


    if (val == 60) { //BassDrum
      digitalWrite(drumpins[1], HIGH);
    } else if (val == 12) {
      digitalWrite(drumpins[1], LOW);
    } else if (val == 62 || val == 64) { //Snare
      digitalWrite(drumpins[0], HIGH);
    } else if (val == 14 || val == 16) {
      digitalWrite(drumpins[0], LOW);
    } else if (val == 66) { //Close HiHat
      digitalWrite(drumpins[3], HIGH);
    } else if (val == 18) {
      digitalWrite(drumpins[3], LOW);
    } else if (val == 68 || val == 70) { //Open HiHat
      digitalWrite(drumpins[4], HIGH);
    } else if (val == 20 || val == 22) {
      digitalWrite(drumpins[4], LOW);
    } else if (val == 63) { // Lamp
      digitalWrite(drumpins[2], HIGH);
    } else if (val == 15) {
      digitalWrite(drumpins[2], LOW);
    } else if (val == 73) { //Crash
      digitalWrite(drumpins[5], HIGH);
    } else if (val == 25) {
      digitalWrite(drumpins[5], LOW);
    } else if (val == 74) { //Low pick bass string
      digitalWrite(srringpins[0], HIGH);
    } else if (val == 26) {
      digitalWrite(srringpins[0], LOW);
    } else if (val == 75) { //High pick bass string
      digitalWrite(srringpins[1], HIGH);
    } else if (val == 27) {
      digitalWrite(srringpins[1], LOW);
    } else if (val >= 76 && val <= 87) { //Finger string notes
      writeStringNote(val - 76, HIGH);
    } else if (val >= 28 && val <= 39) {
      writeStringNote(val - 28, LOW);
    }
  }
}

void writeStringNote(uint8_t note, uint8_t state)
{

  switch (note)
  {
    case 1: //F
      switch (state)
      {
        case LOW:
          register_1 = register_1 & B11110111;
          break;
        case HIGH:
          register_1 = register_1 | B00001000;
          break;
      }
      break;
    case 2: //F#
      switch (state)
      {
        case LOW:
          register_1 = register_1 & B11011111;
          break;
        case HIGH:
          register_1 = register_1 | B00100000;
          break;
      }
      break;
    case 3: //G
      switch (state)
      {
        case LOW:
          register_2 = register_2 & B11111011;
          break;
        case HIGH:
          register_2 = register_2 | B00000100;
          break;
      }
      break;
    case 4: //G#
      switch (state)
      {
        case LOW:
          register_2 = register_2 & B11110111;
          break;
        case HIGH:
          register_2 = register_2 | B00001000;
          break;
      }
      break;
    case 6: //A#
      switch (state)
      {
        case LOW:
          register_2 = register_2 & B11011111;
          break;
        case HIGH:
          register_2 = register_2 | B00100000;
          break;
      }
      break;
    case 7: //B
      switch (state)
      {
        case LOW:
          register_1 = register_1 & B11111101;
          break;
        case HIGH:
          register_1 = register_1 | B00000010;
          break;
      }
      break;
    case 8: //C
      switch (state)
      {
        case LOW:
          register_2 = register_2 & B11101111;
          break;
        case HIGH:
          register_2 = register_2 | B00010000;
          break;
      }
      break;
    case 9: //C#
      switch (state)
      {
        case LOW:
          register_1 = register_1 & B11111011;
          break;
        case HIGH:
          register_1 = register_1 | B00000100;
          break;
      }
      break;

    case 10: //D
      switch (state)
      {
        case LOW:
          register_1 = register_1 & B11101111;
          break;
        case HIGH:
          register_1 = register_1 | B00010000;
          break;
      }
      break;
    case 11: //D#
      switch (state)
      {
        case LOW:
          register_2 = register_2 & B11111101;
          break;
        case HIGH:
          register_2 = register_2 | B00000010;
          break;
      }
      break;

  }

  writeShiftRegister(REG1, register_1);
  writeShiftRegister(REG2, register_2);
}

/* Push byte to shift register */
void writeShiftRegister(int ss_pin, uint8_t value)
{
  digitalWrite(ss_pin, LOW);
  SPI.transfer(value);
  digitalWrite(ss_pin, HIGH);
}

/* Reset all pins */
void resetPins()
{
  for (int i = 0; i < 6; i++)
  {
    digitalWrite(drumpins[i], LOW);
  }
  for (int i = 0; i < 2; i++)
  {
    digitalWrite(srringpins[i], LOW);
  }
}


Гитара и барабанная установка в сборе.



Видео:



Надеюсь, изобретение кому то было интересно.
Желаю, чтобы всё у всех работало с первого раза!
  • +2
  • 27 мая 2015, 22:07
  • Muiota

Комментарии (7)

RSS свернуть / развернуть
+
0
Получилось здорово!
avatar

admin

  • 28 мая 2015, 09:14
+
0
Спасибо!
avatar

Muiota

  • 28 мая 2015, 09:40
+
0
Супер! Ждём продолжения!
Либо группу сколотить

либо инструмент расширить
avatar

Zoltberg

  • 28 мая 2015, 15:08
+
0
Спасибо! Надо попробовать, если будет время.
В компрессорхэд дядьки хорошо постарались.
avatar

Muiota

  • 28 мая 2015, 20:39
+
0
Очень здорово!

Ну а за Hell March отдельное спасибо!
avatar

danil_borchevkin

  • 28 мая 2015, 15:20
+
0
Спасибо! \m/
avatar

Muiota

  • 28 мая 2015, 21:12
+
0
музыка-это мне по душе=)
avatar

Ivan2

  • 31 мая 2015, 22:45

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.