Voxel Horizon – MIDI지원

온라인 상에서 옹기종기 모여서 음악을 연주할 수 있는 기능을 넣고 싶었다.
직접 soft synth를 만들까 하고 꽤 찾아봤다.
파형을 합성해서 wav출력으로 쏴주면 되는데 일단 멀쩡한 소리 나게 하기가 쉽지 않아보인다.

개인적으로는 어릴때 써보고 싶었지만 돈이 없어서 써볼 수 없었던 MIDI장비를 지원하고 싶었다.
모든 Windows시스템은 Microsoft GS Wavetable Synth이라는 soft midi를 내장하고 있다. 그러니까 사용자의 장비에 하드웨어 MIDI 장치가 없어도 상관없다. 나는 사운드캔버스가 있으니 SW MIDI와 HW MIDI를 선택해서 쓰면 된다.
또한 MIDI를 사용하면 싸구려 건반이라도 있으면 훨씬 우아하고 편리하게 음계를 입력할 수 있다.

MIDI API로는 win32 api를 사용할수도 있지만 오래된 MIDI관련 코드들을 보면 눈이 침침하다.
새 술은 새부대에 담고 싶다. 몇 년전에 MIDI Player만들려다가 말았던 프로젝트가 하나 있다. UWP API로 만들려고 했는데 빌어먹을 MS가 C++소스코드는 아예 제공하지 않았고 단 한개의 예제만 있는데 C#으로 작성되어있다. 그걸 분석해서 C++/CX로 짜던 프로젝트다.
다시 코드를 꺼내보니 디바이스 초기화 말고는 뭐 해놓은게 없네.
뭐 잘됐다. 겸사겸사 이번에 게임에 미디 기능 넣으면서 좀 학습이 되면 추후에 미디 플레이어도 만들어 볼수 있을것이다.
MIDI제어를 위해 UWP API를 사용한다.

MIDI관련 DLL을 하나 따로 만들었다.
UWP API를 쓸건데 이게 win32 프로젝트에 코드를 막바로 붙여버리면 귀찮은 일이 많이 발생할 수 있다. 따라서 이렇게 UWP API를 쓰는 기능은 따로 DLL로 만드는게 좋다.
UWP용 DLL도 만들었는데 XBOX버전을 위해서다. 근데 XBOX에서 돌릴때 SW MIDI가 지원되려나? 기능 구현이 대충 완료된 후 XBOX에 배포해서 테스트해 봤는데 소리 잘 나온다.

어쨌든 MIDI디바이스들을 열거하고 In/Out별로 구분해서 관리하는 기능, 그리고 Note On/Off 메시지를 보내는 간단한 MIDI 라이브러리를 만들었다. 기능이 많은건 아니지만 필요한 기능은 차차 추가해가면 된다.

처음엔 로컬에서 입력을 받아서 메모리에 저장하고 리플레이하는 식으로 접근했다. 기본적으로 작동은 잘됐다.
여기에 개노가다로 다이얼로그를 만들어 붙였다. 36개의 건반을 버튼으로 만들어서 붙였다. 처음엔 텍스트 버튼을 사용했고 이후에 파워포인트로 건반을 그려서 만들어붙였다. 이 과정에서 UI라이브러리를 상당히 뜯어고쳤다. 덕택에 UI라이브러리가 좀더 쓸만해졌다.

그리고 네트워크 기능을 추가. 여기서 삽질이 좀 많았다.
결론적으로 3번을 거의 다시 짰다. 처음에 ‘녹음/재생’식으로 접근했던게 결과적으로는 나쁜 설계가 됐다.
네트워크 전송을 우선시하고 ‘녹음/재생’기능은 옵션으로 두기로 하고 접근하니 다른 설계가 됐다. 방송모드와 로컬모드를 명시적으로 구분하고 녹음은 다른 자료구조로 저장, 재생은 미디 신호 입력코드를 다시 호출하는 식으로 처리했다.
3번쯤 다시 짜니까 이제 내가 뭘 목적하고 있었는지, 지금껏 짜놓은 기능은 어떻게 작동하는지, 뭐가 문제인지가 눈에 보인다.
이게 리팩토링이지.

이 문서를 작성하는 시점에서 1차로는 거의 최종버전이다.
아마존에 주문한 싸구려 건반이 도착하면 입력 기능을 더 보강할 예정이다.

현재까지 구현된 기능은 이렇다.

  1. MIDI In/Out 디바이스 열거, 선택 기능.
  2. 로컬에서 건반UI를 입력해서 SW or HW MIDI장치로 음악 연주.
  3. 입력한 미디신호를 녹음.
  4. 입력한 미디신호를 재생.
  5. 입력한 미디 신호를 네트워크로 주변 캐릭터들에게 브로드캐스팅.
  6. 미디 연주중인 캐릭터는 채팅 메시지로 표시.
  7. 녹음/재생 기능은 브로드캐스팅 모드에서도 완벽하게 동작함.
  8. 미디 연주중인 캐릭터에 가까이 가면 즉시 미디연주가 동기화됨.
  9. 미디 연주중인 캐릭터로부터 멀어지면 즉시 미디 연주가 중지됨.


답글 남기기

댓글을 게시하려면 다음의 방법 중 하나를 사용하여 로그인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중