아두이노 3채널 미디 오케스트라
프로젝트/다채널 미디 플레이어

아두이노 3채널 미디 오케스트라

반응형

 

아두이노를 이용해 컴퓨터의 미디 신호를 입력 받아 스피커로 출력하는 3채널 미디 오케스트라를 만들어 보았다. 아래는 간단한 소개 영상이다.

 

 

 

 

[제작과정]

제작 방법은 1개의 스피커를 사용하는 1채널을 기준으로 설명한다. (같은 방법으로 채널수를 늘릴수있다.) 우선 필요한 재료는 아래와 같다.

 

하드웨어

 

  아두이노 레오나르도


아두이노보드가 미디 장치로 인식되어야 하기 때문에 HID가 포함된 레오나르도 보드나 프로마이크로 보드가 필요하다.  
 
   
  스피커 또는 부저


스피커의 경우 0.5W에서 1W가 적당하다.
일부 아두이노 관련 판매처에서는 앰프와
같이 판매하기도 하지만 스피커에 저항을
달아주어야 할 정도로 소리가 상당히 크다. 

 

 

소프트웨어

 

       
  MIDI-OX


다운로드 링크 :
http://www.midiox.com/zip/midioxse.exe
 
        

loopMIDI


필수 x
다운로드 링크 :
http://www.tobias-erichsen.de/wp-content/uploads/2015/08/loopMIDISetup_1_0_13_24.zip

 

 

위에서도 언급했듯 아두이노를 미디 파일로 인식하기 위해서는 아두이노 레오나르도와 같이 HID가 포함된 보드가 필요하다.

 

1. 우선 다음 라이브러리를 다운로드하여 아두이노 IDE에 추가한다.

 

MIDIUSB-master.zip
다운로드

 

2. 라이브러리를 추가했다면 레오나르도 보드에 아래의 코드를 업로드 한다.

#include <MIDIUSB.h> 
#include "pitchToFrequency.h" 

#define BUZZ_PIN 9 

const char* pitch_name(byte pitch) { 
  static const char* names[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; 
  return names[pitch % 12]; 
} 
 
int pitch_octave(byte pitch) { 
  return (pitch / 12) - 1; 
} 

void noteOn(byte channel, byte pitch, byte velocity) { 
  tone(BUZZ_PIN, pitchFrequency[pitch]); 
 
  Serial.print("Note On: "); 
  Serial.print(pitch_name(pitch)); 
  Serial.print(pitch_octave(pitch)); 
  Serial.print(", channel="); 
  Serial.print(channel); 
  Serial.print(", velocity="); 
  Serial.println(velocity); 
} 
 
void noteOff(byte channel, byte pitch, byte velocity) { 
  noTone(BUZZ_PIN); 
 
  Serial.print("Note Off: "); 
  Serial.print(pitch_name(pitch)); 
  Serial.print(pitch_octave(pitch)); 
  Serial.print(", channel="); 
  Serial.print(channel); 
  Serial.print(", velocity="); 
  Serial.println(velocity); 
} 
 
void controlChange(byte channel, byte control, byte value) { 
  Serial.print("Control change: control="); 
  Serial.print(control); 
  Serial.print(", value="); 
  Serial.print(value); 
  Serial.print(", channel="); 
  Serial.println(channel); 
} 
 
void setup() { 
  Serial.begin(115200); 
} 
 
void loop() { 
  midiEventPacket_t rx = MidiUSB.read(); 
  switch (rx.header) { 
    case 0: 
     break; //No pending events 
       
    case 0x9: 
      noteOn( 
        rx.byte1 & 0xF,  //channel 
        rx.byte2,        //pitch 
        rx.byte3         //velocity 
      ); 
     break; 
       
    case 0x8: 
      noteOff( 
        rx.byte1 & 0xF,  //channel 
        rx.byte2,        //pitch 
        rx.byte3         //velocity 
      ); 
      break;
        
    case 0xB: 
      controlChange( 
        rx.byte1 & 0xF,  //channel 
        rx.byte2,        //control 
        rx.byte3         //value 
      ); 
      break; 
       
    default: 
      Serial.print("Unhandled MIDI message: "); 
      Serial.print(rx.header, HEX); 
      Serial.print("-"); 
      Serial.print(rx.byte1, HEX); 
      Serial.print("-"); 
      Serial.print(rx.byte2, HEX); 
      Serial.print("-"); 
      Serial.println(rx.byte3, HEX); 
  } 
}

 

위의 코드는 USB를 통해 미디를 시리얼 통신하고 부저를 제어하는 예제 코드이다. 코드에 나와있듯 스피커 또는 부저는 디지털핀 9번에 연결하면 된다.

 

3. MIDI-OX를 실행시킨다. 실행시 첫 화면이다.

 

 

이제 Options -> MIDI-Devices를 선택한다.

 

 

MIDI Inputs에 Arduino Leonardo는 선택 해제, MIDI Outputs에서 Arduino Leonardo가 선택되어있는지 확인한 후 확인 버튼을 누른다.

 

 

Actions메뉴에서 Keyboard 항목을 선택 하거나 위의 사진처럼 건반 아이콘을 클릭 한다. 클릭 후 키보드 자판을 눌러보면 위와 같이 미디 메세지가 생성됨을 알 수 있다.

 

레오나르도에 부저가 연결된 상태이면 키보드를 누를때마다 소리를 낼 것이다. (자세히 보면 키보드의 숫자를 포함한 위쪽 두 줄이 높은 음계, 아래쪽 두 줄이 낮은 음계를 출력한다.) 시리얼 모니터를 열어 보내고 있는 미디신호가 제대로 출력되는지 확인하자, 만약 Port busy라는 에러와 함께 시리얼 모니터가 열리지 않는다면, MIDI-OX와의 연결을 먼저 끊고 시리얼 모니터를 연 뒤, 다시 연결을 하면 된다.

 

4. 이제 연주할 준비는 모두 끝난 샘이다. 영상과 같이 미디 파일을 재생하는 방법은 다양한데, 필자는 MIDI-OX에 내장된 기능을 이용했다. (위의 사진에서 왼쪽에서 13번째 아이콘을 누르면 된다.) 다만 MIDI-OX의 경우 해당 기능을 사용할 때 레오나르도 보드와 직접 연결이 안되는 문제가 있어 loopMIDI를 이용해 문제를 해결했다.

 

 

loopMIDI를 실행후 +기호를 눌러 미디 포트를 활성화 시킨다. 다음 MIDI-OX에서 미디 입력을 loopMIDI port, 출력을 레오나르도로 설정하면 된다. 이제 위에서 말한 아이콘을 눌러 미디 포트를 loopMIDI port로 설정하고 미디 파일을 업로드한다. 이제 플레이 버튼을 누르면 해당 미디 파일에 맞추어 부저가 소리를 낼 것이다.

 

5-1. 아직 해결해야 할 문제가 있다. 대부분의 미디 파일은 channel 0와 1 두 신호가 입력될텐데, 각각 피아노의 오른손과 왼손 연주이다. 해당 아두이노 코드의 경우 이 두 채널을 동시에 받으며 한번에 1개의 음만 출력이 가능하다. 따라서 화음의 경우 소리가 제대로 발생하지 못하며, 이 경우 한손으로 연주하는 미디 파일을 실행하거나, 아니면 각 채널을 분리해야한다.

 

각 채널을 분리하는 방법은 OpenMPT라는 프로그램을 이용하면 된다. 아래 링크에서 다운 가능하다.

 

https://openmpt.org/download

반응형

 

 

위의 사진처럼 OpenMPT를 실행한뒤 미디 파일을 열면 각 채널별로 (여기서의 각 채널은 화음이 아닌 단음으로 된 각 채널들이다. 그래서 대부분 2개의 채널보다 더 많다.) 분리된 채 실행된다. 필자가 영상에 사용한 음악에 경우 처음에 4채널로 이루어져 있었으며, 상대적으로 노트수가 적은 채널 4번을 제거하고 일부 노트를 수정하여 새롭게 만든 미디 파일이다. 이렇게 미디 파일을 수정한 뒤, 다시 미디 파일로 저장한 뒤 실행하면 된다.  

  
5-2. 여러 채널을 동시에 실행시키기 위해서는 일단 여러개의 보드가 필요하다. (아두이노의 tone()함수는 한번에 하나의 음만 처리할 수 있다.) 필자가 이 방법을 선택했으며, 보드의 개수에 관계없이 같은 방법으로 실행하면 된다. 물론 각 채널에 맞은 음만 선택적으로 출력하기 위해 위의 코드를 약간 수정해야 한다. (노트를 온, 오프 시키는 함수에 if문을 추가해서 해당 채널만 선택적으로 받으면 된다.) 다만 컴퓨터의 USB 포트수가 부족하면 허브를 이용해야 할지도 모른다.

이 방법은 사실 좀 비효율적이긴 하다. 그래서 외국의 경우 대부분 플로피 디스크나 스탭모터 등을 출력으로 하며 tone()함수의 중첩을 해결한다. (PWM신호는 마음대로 사용가능하므로) 해당 방법은 아직 시도해보지 않았지만 성공하면 이 방법 또한 소개할 계획이다. 

 

6. 마지막으로...

미디에 대해 공부하면서 참고한 자료와 사이트는 정말 많지만 일일이 저장해둔 것이 아니라 당장은 공개하지 않을 계획이다. 국내에 아두이노미디에 관련된 자료가 거의 없어 외국의 자료를 토대로 삽질을 좀 하며 성공했다. 그래서 일부 정보는 부정확할 수 있으며 더 좋은 의견이나 오류에 관한 피드백은 적극 환영한다. 이 자료가 아두이노로 미디를 시작하는 사람들에게 많은 도움이 되길 바란다.

 

 

같이보면 좋은 글 

2018/02/15 - [아두이노/기초] - 미디파일을 tone()으로 변환하기 [아두이노]

2018/08/27 - [아두이노/프로젝트] - 아두이노 다채널 미디 플레이어 제작 #1 - I2C 통신 테스트

2018/08/31 - [아두이노/프로젝트] - 에어드럼 제작하기 (OpenCV+아두이노 Air Drum)

2018/10/10 - [아두이노/프로젝트] - 아두이노 다채널 미디 플레이어 제작 #2 - 중간점검

2018/10/28 - [아두이노/프로젝트] - 아두이노 다채널 미디 플레이어 제작 #3 - 5채널 테스트

2018/11/03 - [아두이노/프로젝트] - 아두이노 다채널 미디 플레이어 제작 #4 - Attiny85 ver

2019/01/10 - [아두이노/프로젝트] - 아두이노 다채널 미디 플레이어 제작 #5 - PCB 발주 및 완성

 

 

 

반응형
    # 테스트용