본문 바로가기
나도 개발자다!/삽질의 추억

가장 저렴한 또는 값비싼 루프페달 만들기!

by 개발새발자 2023. 6. 27.

루프페달은 실시간으로 녹음하고 반복 재생하여 다양한 음악 효과를 만들 수 있는 도구다. 나는 에드시런을 좋아하는데, 자신만의 루프 페달인 CHWIE를 활용해서 공연하는 영상을 보고 '아.. 나도 갖고 싶다...'라는 생각을 종종 하곤 했다. 하지만, 주머니 사정이 넉넉지 않아 직접 만드는 방법을 택했다.

 

준비물:

두꺼운 박스(루프스테이션 프레임으로 사용) - 무료

아이패드(루프 앱 실행) - 원래 있다면 무료

오디오인터페이스(기타 및 마이크 연결 후 아이패드로 신호 전송) - 원래 있다면 무료

풋스위치(아두이노에 연결해서 미디 신호 조작) - 개당 3천원 총 1만 5천 원

아두이노 레오나르도(midi를 지원하면서 가격이 저렴한 게 레오나르도였음) - 약 5천 원으로 기억

Quantiloop pro앱 - 7.99달러.

아이패드와 오디오 인터페이스가 있기 때문에 가격은 3만 원 남짓 들었다. 이거 만들자고 아이패드랑 오인페를 사는 사람은 없겠지?

 

0. 미리 보기

어릴 적 꿈이 화가였다.

 

1. 아두이노 레오나르도에 준비한 코드를 업로드한다. (미디 헤더 미리 다운로드해야 함)

아래 코드를 보면 알겠지만, 미디 헤더 넣는 법을 몰라서... 헤더 속 코드를 복사해서 붙여 넣었다. 처음 의도는 페달을 8개 붙이는 거라 버튼 변수가 8개이지만 이 중 5개만 사용하였다.

#include "MIDIUSB.h"
#include "PitchToNote.h"
#define NUM_BUTTONS  8
#define B4  71
#define B4b 70
#define A4  69
#define A4b 68
#define G4  67
#define G4b 66
#define F4  65
#define E4  64
#define E4b 63
#define D4  62
#define D4b 61
#define C4  60
#define B3  59
#define B3b 58
#define A3  57
#define A3b 56
#define G3  55
#define G3b 54
#define F3  53
#define E3  52
#define E3b 51
#define D3  50
#define D3b 49
#define C3  48
#define B2  47
#define B2b 46
#define A2  45
#define A2b 44
#define G2  43
#define G2b 42
#define F2  41
#define E2  40
#define E2b 39
#define D2  38
#define D2b 37
#define C2  36
const uint8_t button1 = 2;
const uint8_t button2 = 3;
const uint8_t button3 = 4;
const uint8_t button4 = 5;
const uint8_t button5 = 6;
const uint8_t button6 = 7;
const uint8_t button7 = 8;
const uint8_t button8 = 9;
const int intensityPot = 0;  //A0 input
const uint8_t buttons[NUM_BUTTONS] = {button1, button2, button3, button4, button5, button6, button7, button8};

const byte notePitches[NUM_BUTTONS] = {C3, D3, E3, F3, G3, A3, B3, C4};

uint8_t notesTime[NUM_BUTTONS];

uint8_t pressedButtons = 0x00;

uint8_t previousButtons = 0x00;

uint8_t intensity;

void setup() {

  for (int i = 0; i < NUM_BUTTONS; i++)

    pinMode(buttons[i], INPUT_PULLUP);
}

void loop() {

  readButtons();

  readIntensity();

  playNotes();
}

// First parameter is the event type (0x0B = control change).
// Second parameter is the event type, combined with the channel.
// Third parameter is the control number number (0-119).
// Fourth parameter is the control value (0-127).

void controlChange(byte channel, byte control, byte value) {

  midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};

  MidiUSB.sendMIDI(event);
}

void readButtons()
{

  for (int i = 0; i < NUM_BUTTONS; i++)

  {

    if (digitalRead(buttons[i]) == LOW)

    {

      bitWrite(pressedButtons, i, 1);

      delay(50);

    }

    else

      bitWrite(pressedButtons, i, 0);

  }
}

void readIntensity()
{

  int val = analogRead(intensityPot);

  intensity = (uint8_t) (map(val, 0, 1023, 0, 127));
}

void playNotes()
{

  for (int i = 0; i < NUM_BUTTONS; i++)

  {

    if (bitRead(pressedButtons, i) != bitRead(previousButtons, i))

    {

      if (bitRead(pressedButtons, i))

      {

        bitWrite(previousButtons, i , 1);

        noteOn(0, notePitches[i], intensity);

        MidiUSB.flush();

      }

      else

      {

        bitWrite(previousButtons, i , 0);

        noteOff(0, notePitches[i], 0);

        MidiUSB.flush();

      }

    }

  }
}
// First parameter is the event type (0x09 = note on, 0x08 = note off).
// Second parameter is note-on/note-off, combined with the channel.
// Channel can be anything between 0-15. Typically reported to the user as 1-16.
// Third parameter is the note number (48 = middle C).
// Fourth parameter is the velocity (64 = normal, 127 = fastest).

void noteOn(byte channel, byte pitch, byte velocity) {

  midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};

  MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity) {

  midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};

  MidiUSB.sendMIDI(noteOff);
}

 

2. 박스 재단 및 조립

 원래 아크릴판이나 합판을 주문해서 만들 계획이었다. 하지만 제대로 될지도 자주 사용할지도 모르는 상황에 지출을 키우고 싶지는 않았다. 마침 아기 기저귀 박스가 튼튼해서 재료로 찜했다. 그래서 이 페달의 이름은 Pamperstation! (기저귀 브랜드가 팸퍼스...)

 

같은 크기의 판을 두 개 만들고 하나는 바닥, 하다는 상판으로 한다. 상판은 페달이 들어갈 수 있게 잘랐다.

 

 

바닥면에 풋스위치를 가지런히 놓는다.

 

각 스위치의 선 두 가닥 중 하나는 핀 번호에 맞게 아두이노에 부착했다. 나머지 한 가닥이 문제인데, 이 선들이 모두 모여서 그라운드 핀으로 들어가야 한다. 그래서 메인 선을 하나 정해서 중간 피복을 벗기고, 나머지 선들을 벗긴 자리에 모두 묶었다. 전기 지식이 없어, 이렇게 해도 되는지는 모르겠지만 결과적으로 작동은 했다.

 

마지막으로 상판을 덮고, 박스 잔해들로 좌우 기둥을 세워 글루건으로 고정했다.

Pamperstation 1

 

3. Quantiloop pro에 연결

연결 후 미디 장치 매핑을 해 줘야 한다. 앱 속의 페달 또는 버튼과 팸퍼스테이션의 풋스위치를 적절히 매핑하면 된다. 미디 신호의 장점은 짧은 입력 긴 입력 두 번 입력이 따로 인식된다는 점이다. 

나는 전체 재생, Dub Mode(덮어쓰기 여부 설정), 트랙 1, 2, 3으로 총 다섯 개를 설정했다.

 

 

4. 마치며

루프페달을 가지고 놀다 보면 밀란 쿤데라의 소설 '참을 수 없는 존재의 가벼움'이 생각난다. 소설 속에서 우리의 존재가 참을 수 없이 가벼운 이유는 반복되지 않기 때문이라고 했다. 기나긴 시간의 흐름 속 찰나의 지나지 않는 우리의 삶은 너무나도 가볍다. 하지만 우리의 삶이 반복된다면? 이는 압도하는 무게로 우리를 짓누를 것이다. 1회의 공연 연주라면 잠깐의 실수는 금방 잊히고 넘어갈 수 있다. 하지만 그 실수가 녹음되고 루프로 재생되는 순간 밀린 박자와, 잘못 튀어나온 음의 무게는 나를 누르고 눌러 연습을 게을리 한 나를 고문한다.

 

무한히 재생되는 실수의 무게를 한 번 느껴보시라.

 

어버버..