본 글을 통해 최근 동영상을 통해 알려드렸던 DIY 전자악기 만드는 법을 안내해 드리고자 합니다.

하드웨어 제작은  반제품의 쉴드를 아두이노에 결합하고 스위치를 몇개 장착하는게 전부이므로 매우 쉽습니다.  하지만 프로그래밍을 통해 제어를 하려면 MIDI 프로토콜을 이해해야 하는데 인터넷에 공개된 관련 글을 봐도 곧바로 이해하고 활용하기 쉽지 않았습니다.  결국, 정확한 신호 파악을위해 직접 마스터 키보드를 구입하여;;  건반을 누를때, 뗄때, 악기가 변경될때, 기타 콘트롤시 어떤 MIDI 신호가 출력되는지 분석을 한 후에야 대충 이해가 가더군요,,  하지만 많은 분들이 그럴 여유가 없으시죠;;;

우선은 이미 제조사에서 일련의 내장된 악기음을 순서대로 반복해주는 정도의 예제가 있으므로 참고가 되실 겁니다.
하지만, 위 소스만으로는 응용이 어려우신 분들도 많으시므로 실제 스위치(건반대응)로 연결하여 기초적인 악기를 구현한 예제(연결방법 + 소스코드)를 소개드리오니 참고하시기 바랍니다.  여러분의 좀더 멋진 DIY 악기 개발에 작으나마 도움이 되었으면 합니다

추가사항.  현재 화면상의 소스코드는 Sketch 0022 버전에서 테스트된 소스입니다.  최신 아두이노 개발환경(Arduino 1.0)용 소스코드도 첨부파일에 링크되어있으니 참고하시기 바랍니다.  첨부된 파일2개는 동일한 기능 두가지 버전입니다.)

.  -로보밥-


준비물

아두이노 UNO 1개
아두이노 용 USB케이블
MIDI 악기 쉴드 1개
재적측 가능한 헤더셋(아두이노용) 1세트
결합형 브레드보드 중형  4개
스위치 12개 (마이크로 스위치  , 5색칼라버튼)
점퍼케이블 1세트

하드웨어 준비

1. 재적층 가능 해더셋을 MIDI 악기쉴드에 납땜합니다. 여분의 헤더핀들을 아두이노에 결합 후 재적층 가능 헤더셋을 뒤집어 꽂은 상태로 납땜을 하면 수직(90도)상태로 납땜하기 용이해 집니다.
 
2. 아래의 이미지를 참고하셔서 MIDI 악기 쉴드에 아래와 같은 방식으로 스위치를 장착합니다. 버튼 3개만 보이지만 나머지 버튼들도 동일한 방법으로 연결하면 됩니다.  어떤 핀에 연결해야하는지는 소스코드에 나오는 버튼별 핀번호 정의부분을 보시면 됩니다.  싱겁게도 회로 연결 작업은 이것으로 끝입니다. ( 아직 MIDI쉴드를 아두이노에 장착하지 마세요!)

 

 



 아두이노 프로그래밍 준비작업

1. 아두이노에 내장된 기존 프로그램이 장착된 하드웨어와 맞지 않는 경우에 대비하기위해 첫프로그래밍시엔 쉴드를 제거한 상태에서 프로그래밍(업로딩) 하실 것을 권장드립니다.

2. 컴파일전에 NewSoftSerial 라이브러리를 설치 하셔야합니다. 아두이노 프로그래밍 방법 및 라이브러리 설치방법등을 모르시는 분들은 아두이노 해당 기초 학습을 완료 후 시도하시기 바랍니다.

3. 소스코드를 웹화면에서 복사하여 사용시 일부 문자가 누락되는 경우가 있습니다. 하단에 링크된 첨부파일(MusicArtRobot.pde)을 다운로드 받으셔서 사용하실것을 권장드립니다.


DIY 전자 악기 ( Music Art Robot )소스코드


/*
 Music Art Robot v0.1(2012.Feb.4)
 ---------------------------------------------------------
 아두이노 + MIDI악기쉴드 이용한 DIY 건반악기 예제소스
 ---------------------------------------------------------
https://robobob.tistory.com/
 재배포시, 위 URL 유지부탁드리고요, 자유롭게 사용해주세요!
 ---------------------------------------------------------
 
 아두이노 D3,D4핀은 MIDI악기쉴드 제어용이므로 다른용도로 사용하지 마세요
 아두이노 D3핀을 통해 MIDI악기쉴드에 MIDI신호를 전송합니다.(NewSerailSoft 라이브러리 필요함)
 D2핀도 SoftSerial 수신용으로 선언은됐지만, 재세팅하고 버튼 입력용으로 사용됩니다.

 버튼1 ~ 8 : 도/레/미/파/솔/라/시/도  임의 note(음계)로 변경하시면 됩니다.
 버튼9: 다른 악기 선택(현재 악기번호 + 1)  0~127
 버튼10: 다른 악기 선택(현재 악기번호 - 1)  0~127
 버튼11: 악기를 드럼셋으로 설정.
 버튼12: defaultPatch 에 정의된 악기로 변경

 외부스위치 연결방법:
 버튼의 양쪽선 중 한쪽은 아두이노 해당 핀에 연결하고, 나머지 한쪽은 GND에 공통 연결하면 끝.
 
 참고사항, 전원을 켠 후 소리가 나지않을 경우 리셋버튼을 눌러서 초기화 해주면 작동됩니다.


 MIDI악기쉴드에 대한 아래의 영문정보도 참고하세요.
 
 This code works with the VS1053 Breakout Board and controls the VS1053 in what is called Real Time MIDI mode.
 To get the VS1053 into RT MIDI mode, power up the VS1053 breakout board with GPIO0 tied low, GPIO1 tied high.
 
 I use the NewSoftSerial library to send out the MIDI serial at 31250bps. This allows me to print regular messages
 for debugging to the terminal window. This helped me out a ton.
 
 5V : VS1053 VCC
 GND : VS1053 GND
 D3 (SoftSerial TX) : VS1053 RX
 D4 : VS1053 RESET
 
 Attach a headphone breakout board to the VS1053:
 VS1053 LEFT : TSH
 VS1053 RIGHT : RSH
 VS1053 GBUF : GND
 
 When in the drum bank (0x78), there are not different instruments, only different notes.
 To play the different sounds, select an instrument # like 5, then play notes 27 to 87.
 
 To play "Sticks" (31):
 talkMIDI(0xB0, 0, 0x78); //Bank select: drums
 talkMIDI(0xC0, 5, 0); //Set instrument number
 //Play note on channel 1 (0x90), some note value (note), middle velocity (60):
 noteOn(0, 31, 60);
 
 */
 
#include <NewSoftSerial.h>
#define btn1  11    // 버튼1의 아두이노 핀번호 정의
#define btn2  10    // 버튼2의 아두이노 핀번호 정의
#define btn3  9        // 버튼3의 아두이노 핀번호 정의
#define btn4  8        // 버튼4의 아두이노 핀번호 정의
#define btn5  7        // 버튼5의 아두이노 핀번호 정의
#define btn6  6        // 버튼6의 아두이노 핀번호 정의
#define btn7  5   // 버튼7의 아두이노 핀번호 정의
// 3:midi rx , 4:midi reset  아두이노 핀 3번 4번은 이미 사용중
#define btn8  2   // 버튼8의 아두이노 핀번호 정의
                  //(SoftSerial에서 Rx핀으로 선언되지만 재 세팅 후 버튼용으로 사용)
#define btn9 A5   // 버튼9의 아두이노 핀번호 정의
#define btn10 A4  // 버튼10의 아두이노 핀번호 정의
#define btn11 A3  // 버튼11의 아두이노 핀번호 정의
#define btn12 A2  // 버튼12의 아두이노 핀번호 정의

#define defaultPatch 15 //악기 초기화 버튼 설정 악기번호

NewSoftSerial mySerial(2, 3); //SW시리얼핀 정의 D3이 MIDI신호 전송용,  D2는 미사용

byte note = 0; //The MIDI연주될 note(음계)
byte resetMIDI = 4; // VS1053 Reset용 핀
byte ledPin = 13; //MIDI 트래픽 표시용 LED
 
boolean bs1 = false;  // 버튼1의 현재상태(눌림 or 안눌림)
boolean bs2 = false;  // 이하, 위와 유사
boolean bs3 = false;
boolean bs4 = false;
boolean bs5 = false;
boolean bs6 = false;
boolean bs7 = false;
boolean bs8 = false;
boolean bs9 = false;
boolean bs10 = false;
boolean bs11 = false;
boolean bs12 = false;

boolean br1;  // 버튼1 상태 확인용 입력값 임시저장용
boolean br2;  // 이하, 위와 유사
boolean br3;
boolean br4;
boolean br5;
boolean br6;
boolean br7;
boolean br8;
boolean br9;
boolean br10;
boolean br11;
boolean br12;

int patch = 0; //악기 대응, 연주될 악기 종류 (0~127: 기본 128 가지 선택가능)

int bn1 = 60; //버튼1의  note(음계)  가령 "도"  0~127까지 지정가능 (정확한 음계 설정은 MIDI관련정보참고)
int bn2 = 62; //버튼2의  note(음계)  가령 "레"
int bn3 = 64; //버튼3의  note(음계)  가령 "미"
int bn4 = 65; //버튼4의  note(음계)  가령 "파"
int bn5 = 67; //버튼5의  note(음계)  가령 "솔"
int bn6 = 69; //버튼6의  note(음계)  가령 "라"
int bn7 = 71; //버튼7의  note(음계)  가령 "시"
int bn8 = 72; //버튼8의  note(음계)  가령 "도~"

byte byteData;

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

  //Setup soft serial for MIDI control
  mySerial.begin(31250);
//  mySerial2.begin(57600);
 
  //Reset the VS1053
  pinMode(resetMIDI, OUTPUT);
  digitalWrite(resetMIDI, LOW);
  delay(100);
  digitalWrite(resetMIDI, HIGH);
  delay(100);
 
  pinMode( btn1, INPUT);      // 버튼1 입력용 핀모드를  입력모드로 전환
  digitalWrite( btn1, HIGH);  // 내부 PullUp 설정, 스위치의 나머지 한선은 GND에 물리면 됩니다.(초간단)

  pinMode( btn2, INPUT);      // 이하, 위와 유사
  digitalWrite( btn2, HIGH);
 
  pinMode( btn3, INPUT);
  digitalWrite( btn3, HIGH);
  pinMode( btn4, INPUT);
  digitalWrite( btn4, HIGH);
  pinMode( btn5, INPUT);
  digitalWrite( btn5, HIGH);
  pinMode( btn6, INPUT);
  digitalWrite( btn6, HIGH);
  pinMode( btn7, INPUT);
  digitalWrite( btn7, HIGH);
  pinMode( btn8, INPUT);
  digitalWrite( btn8, HIGH);
 
  pinMode( btn9, INPUT);
  digitalWrite( btn9, HIGH);
  pinMode( btn10, INPUT);
  digitalWrite( btn10, HIGH);
  pinMode( btn11, INPUT);
  digitalWrite( btn11, HIGH); 
  pinMode( btn12, INPUT);
  digitalWrite( btn12, HIGH); 

}

void loop() {
    br1 = digitalRead(btn1);
    br2 = digitalRead(btn2);
    br3 = digitalRead(btn3);
    br4 = digitalRead(btn4);
    br5 = digitalRead(btn5);
    br6 = digitalRead(btn6);
    br7 = digitalRead(btn7);
    br8 = digitalRead(btn8);
    br9 = digitalRead(btn9);
    br10 = digitalRead(btn10);
    br11 = digitalRead(btn11);
    br12 = digitalRead(btn12);   
   
   if( !bs1 && !br1 ){
     noteOn(0, bn1,100);
     bs1 = true;
   }else if(bs1 && br1){
     noteOff(0, bn1,0);  
     bs1 = false;
   }
   if( !bs2 && !br2 ){
     noteOn(0, bn2,100);
     bs2 = true;
   }else if(bs2 && br2){
     noteOff(0, bn2,0);  

     bs2 = false;
   }  
   if( !bs3 && !br3 ){
     noteOn(0, bn3,100);
     bs3 = true;
   }else if(bs3 && br3){
     noteOff(0, bn3,0);  
     bs3 = false;
   }
   if( !bs4 && !br4 ){
     noteOn(0, bn4,100);
     bs4 = true;
   }else if(bs4 && br4){
     noteOff(0, bn4,0);  
     bs4 = false;
   }
   if( !bs5 && !br5 ){
     noteOn(0, bn5,100);
     bs5 = true;
   }else if(bs5 && br5){
     noteOff(0, bn5,0);  
     bs5 = false;
   }  
   if( !bs6 && !br6 ){
     noteOn(0, bn6,100);
     bs6 = true;
   }else if(bs6 && br6){
     noteOff(0, bn6,0);  
     bs6 = false;
   }  
  
   if( !bs7 && !br7 ){
     noteOn(0, bn7,100);
     bs7 = true;
   }else if(bs7 && br7){
     noteOff(0, bn7,0);  
     bs7 = false;
   }  
   if( !bs8 && !br8 ){
     noteOn(0, bn8,100);
     bs8 = true;
   }else if(bs8 && br8){
     noteOff(0, bn8,0);  
     bs8 = false;
   }  
  
   if( !bs9 && !br9 ){ //patch up (max:127)
     patch++;
     if(patch >127) patch = 0;
     talkMIDI(0xc0, patch, 0);    
     bs9 = true;
   }else if(bs9 && br9){
     bs9 = false;
   }  
   if( !bs10 && !br10 ){ //patch down (min:0)
     patch--;
     if(patch < 0) patch = 127;
     talkMIDI(0xc0, patch, 0);      
     bs10 = true;
   }else if(bs10 && br10){
     bs10 = false;
   }  
  
   if( !bs11 && !br11 ){
     //bank 0x78(drum)
     talkMIDI(0xb0, 0, 0x78);
     talkMIDI(0xb0,20, 0);
     talkMIDI(0xc0, patch, 0);    
     bs11 = true;
   }else if(bs11 && br11){
     bs11 = false;
   }  
  
   if( !bs12 && !br12 ){
     //bank MSB 0, default instruments
     patch = defaultPatch;
     talkMIDI(0xb0, 0, 0);
     talkMIDI(0xb0,20, 0);
     talkMIDI(0xc0, patch, 0);      
     bs12 = true;
   }else if(bs12 && br12){
     bs12 = false;
   }  
           

  //*************** MIDI LOOPBACK ******************//
  if(Serial.available() > 0)
  {
    byteData =  Serial.read();
    mySerial.print(byteData, BYTE);
  } 
    

}

//Send a MIDI note-on message.  Like pressing a piano key
//channel ranges from 0-15
void noteOn(byte channel, byte note, byte attack_velocity) {
  talkMIDI( (0x90 | channel), note, attack_velocity);
}

//Send a MIDI note-off message.  Like releasing a piano key
void noteOff(byte channel, byte note, byte release_velocity) {
  talkMIDI( (0x80 | channel), note, release_velocity);
}

//Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127
void talkMIDI(byte cmd, byte data1, byte data2) {
  digitalWrite(ledPin, HIGH);
  mySerial.print(cmd, BYTE);
  mySerial.print(data1, BYTE);

  //Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
  //(sort of: http://253.ccarh.org/handout/midiprotocol/)
  if( (cmd & 0xF0) <= 0xB0)
    mySerial.print(data2, BYTE);

  digitalWrite(ledPin, LOW);
}





소스코드 파일 다운로드:
(순서대로 스케치 구버전용 pde 파일, 아두이노 1.0 포팅된 ino 소스)

 

로보밥

..

robobob.tistory.com

 

로보밥

..

robobob.tistory.com

 

MusicArtRobot.pde
다운로드

 

MusicArtRobot10.ino
다운로드


후기
MIDI 용어문제:  관련 용어 파악이 어려운것 같습니다. 가령 악기와 대응되는 용어만 instrument, patch, program 이 있네요.

아두이노 1.0용 소스 추가 안내. 2012년 5월 30일
많은분들이 Arduino 1.0 스케치용으로 포팅된 소스를 요청하셨는데요  변환된 파일을 이제야 올려드렸습니다. 2번째 첨부파일을 참고하시기 바랍니다.  바뀐것이라곤   NewSoftSerial.h 대신  기본제공되는 시리얼 라이브러리를 사용하기위해  SoftwareSerial.h 헤더선언을 변경한것과   Serial.print( val, BYTE)  함수를  Serial.write( val ) 로 변경한것 뿐입니다.  어렵지 않으니 직접 한번 수정(포팅)해보시고 성취감을 맛보시는것도 좋으실 것 같습니다.


관련자료 링크
http://www.midi.org/aboutmidi/tutorials.php (해당페이지에 pdf 문서 추천)
http://253.ccarh.org/handout/midiprotocol/


 

아두이노에 WaveShield를 얹히면 음악재생기가 됩니다.  여기에 9V 전지등을 연결해주면 곧바로 휴대형이 되는데요, 무공해 에너지를 사용하면 더욱 좋겠죠?!  그래서 건전지 없이 태양전지를 연결하여 구동해 봤습니다.  쨍쨍 비치는 태양에너지를 쓸모있게 활용하는데 태양전지만한게 없겠죠...  날씨가 좋은경우 그늘에서도 문제없이 구동되네요.  생각과 달리 태양전지는 흐린날에도 약간이지만 전기를 생산합니다.  눈으로 한번 보시죠,  여러분의 창작품에도 응용하시면 좋을것 같습니다.

 

 

 

동영상1.음원은 개구리 우는소리로 넣었습니다.  개구리 우는 소리가 제법 큽니다.   확인을 위해 태양전지를 뒤집자 개구리가 울음을 끄치네요 ^^.   다시 태양을 바라보자 소리를 내기 시작합니다.


동영상2. 이제 제법 여름 기운이 느껴집니다.  너무 덥죠!  그늘에서도 작동하는지 테스트 해봤습니다.  잘~ 나오네요..  낮잠잘때 배경음으로 딱 좋을것 같습니다.  공원 밴치등에 불필요한 전력없이 태양전지로 작동되는  자연의 소리를 넣어주면 좋을것 같습니다.

동영상3.공원에서 되돌아 오는길에 자전거 뒷자석에 태양전지를 달고, 달려오면서 음악을 감상해 봤습니다.   제법 좋네요 ^^.
건전지 걱정없고,  스위치도 필요없습니다.  실내에 들어오면 자연히 꺼지고요,  밝은 곳으로 이동하면 다시 자동 재생됩니다.  와우~ Wow!!





^^. 로보밥 얼뚱연구소에 또하나의 재밌는 제품이 들어왔습니다. 예전부터 이제품 찾는 분들이 많았는데 드디어 입수하게 되었습니다.
 자세한 소개이전에 일단 테스트 영상을 올려봅니다.

Adafruit Industries사의 아두이노용 웨이브 쉴드이며,  직접 납땜하여 조립하는 DIY형 제품입니다.
mp3플레이어의 경우 전용 하드웨어 코덱칩을 사용하곤 하는데요, 요제품은 걍 wav파일을 곧바로 DAC칩으로 재생해버리므로 코덱같은거 없습니다.  단점일수있지만 반대로 장점일 수 도있죠,
low level 의 wav데이타를 곧바로 DA로 변형후 OPamp로 증폭하여 출력합니다.
그리고, 사실 mp3 배우기 전에  wav부터 배우는게 순서가 맞을것 같습니다.
SD메모리 슬롯도 내장하여 용량문제없이 음악재생이 가능하고, SD메모리만 응용할 수도 있습니다.

아래의 예제는 sd메모리에 미리 넣어둔 wav파일 몇개를 지정된 키를 누를때마다 재생하는 예제입니다.
관련예제는 해당제품 안내페이지에서 모두 보실 수 있습니다.
기회가 되면 상세 리뷰도 소개해 드리겠습니다.

 

 

 

 

 

PCB와 조립용 부품이 제공되며 직접 납땜으로 완성시키는 DIY형 제품입니다.

 

+ Recent posts