본문 바로가기

프로그래밍

MIDI 포맷에 대해 알아보자.araboza

일단 MIDI는 악보의 컴퓨터버전이라고 생각하면 좋다.

제목, 작곡가같은 음악이랑은 별로 상관없는 메타데이터도 들어있고,

실질적으로 연주가 어떻게 되는지, 즉 악보에서 음표에 해당하는 정보도 들어있다.

예를들어, 악기에서 '도' 건반을 어느 순간에 누르고, 언제 뗴어야하는지같은 정보가 들어있는 셈이다.


확장자는 보통 .mid인데, 이런 파일을 어떻게 읽어낼수 있을까.

당연하게도, 어떻게 생긴지 알아서 어떻게 읽어야 원하는 정보를 얻을수 있는지 배워야한다.


일단 MIDI는 크게 1개의 헤더 청크n개의 트랙 청크로 이루어져있다.


왜 이런 구조가 되었느냐 생각해보자.

트랙 청크는 실질적인 MIDI파일의 내용물을 담고 있다. 즉, 어떤 건반이 언제 눌러져야하는지, 실질적인 음표에 해당하는 정보를 담고있는 오선지와도 같은 존재다.

하지만 악보를 본적 있는 사람이라면 알고 있을 것이다.

보통 피아노의 경우에도 높은음자리와 낮은음자리 두개의 트랙이 있다.

오케스트라의 경우는 그보다 훨씬 많은 수의 트랙이 있을 것이다.

그래서 MIDI파일에는 n개의 트랙 청크가 들어있는 것이다.


근데 이 N은 몇인지 트랙청크들만 봐선 알 수 없다.

그래서 이런 데이터를 담아두는 한개의 헤더 청크를 파일 맨 앞에 붙여두는 것이다.


즉, MIDI파일은

헤더 청크-트랙 청크-트랙청크-트랙청크....

이런식으로 되어있다.


MIDI 파일 포맷의 제작자는 아마 좀더 쉽게 이해하기 위해서인지, 이 트랙 청크와 헤더 청크의 형태를 비슷하게 만들어두었다.

아래는 헤더청크와 트랙 청크의 형식을 나타낸것이다.


Header Chunk
Chunk TypelengthData
4 bytes 
(ascii)
4 bytes 
(32-bit binary)
<-- length (= 6 bytes) -->
16-bit16-bit16-bit
MThd<length><format><tracks><division>
Track Chunk

Chunk type

lengthData
4 bytes 
(ascii)
4 bytes 
(32-bit binary)
<-- length bytes --> 
(binary data)
MTrk<length><delta_time> <event> ...

보다시피 헤더, 트랙은 형태가

청크 타입+길이+데이터

의 형태가 되어있다.

이렇게 형태적으로 유사하기 때문에 그냥 '헤더', '트랙'이라고 안하고, '헤더 청크', '트랙 청크'라고 이야기 하는 것이다.

즉, 청크는 이처럼 (청크 타입+길이+데이터)의 형식인 놈들을 싹다 청크인 것이다.


이제 청크의 내용물이 뭔지 확인해보자.


1. 청크 타입

청크 타입은 이 청크가 '헤더 청크'인지, '트랙 청크'인지 적혀있다.

헤더청크는 MThd

트랙청크는 MTrk가 적혀있다.


2.길이

이 길이는 바로 오른쪽에 붙어있는 데이터의 길이다.


헤더 청크는 이후 오는 데이터가 정해져 있다. 그래서 기본적으로 6이다.

(언제나 포맷, 트랙수, 약수 세가지의 데이터가 오기 떄문에 길이가 고정이다.)


반면 트랙 청크는 이후 오는 데이터가 길이가 고정이 아니다. 

(모든 악보의 길이가 동일하지 않다는걸 생각하면 된다. 동요랑 오케스트라의 길이가 같지는 않으니...)


3.데이터

사실상 여기가 제일 중요하다.

청크에 들어있는 데이터가 저장되기 때문이다.

특히 트랙 청크에는 음악에 대한 정보가 몽땅 들어있다고 보면 된다.


이제 이것에 대해 설명해보자.


헤더 청크에 들어있는 데이터와, 트랙 청크에 들어있는 데이터는 다르다.

헤더 청크에는 트랙의 개수는 몇개인지와 같은 데이터가 들어가고

트랙 청크에서는 실제 연주를 어떻게 해야하는지에 대한 정보 같은게 들어간다.

그러므로, 각각 나누어서 설명해보자.


a)헤더 청크의 데이터

앞서 헤더 청크는 데이터의 길이가 6이라고 말했다.

이 6바이트의 데이터가 무엇인지 알아보자.

일단, 2바이트씩 끊어서 읽어보자

2바이트/2바이트/2바이트

각각은

포맷/트랙수/디비전을 의미한다.

각각이 무엇인지 알아보자.


-포맷:

미디 포맷을 의미하는데, 트랙을 어떻게 해석할지 말해준다.


값은 0,1,2 셋중 하나인데, 각각은 다음을 의미한다

0인 경우, 트랙 청크가 하나임을 의미한다.

1인 경우, 트랙 청크가 둘 이상이고 각 트랙이 동시에 연주됨을 의미한다. (피아노 악보의 높은음자리와 낮은음자리가 동시에 연주되는걸 생각하면 된다)

2인 경우, 트랙 청크가 둘 이상이고 각 트랙이 동시에 연주되지 않고 독립적임을 의미한다. (아마 트랙 길이가 4바이트가이므로, 4바이트로 트랙 하나를 표현할 수 없는 경우 사용되는것 같다.)


-트랙수:

이녀석은 간단하다.

아까 트랙 청크가 n개라고 하지 않았던가.

그 n의 값이다.


-디비전(division):

한글로 옮길 마땅한 말이 없어서 그대로 가져왔다.

이름만 보면 정말 뭔지 감이 안올것이다.

그 정체는, MIDI에서 사용되는 시간의 단위를 정의한다.


그렇다고 순진하게 2바이트 정수값을 그대로 쓰면 안된다.

좀더 자세히 알아보자.


디비전은 2바이트 값이다.

이 2바이트의 가장 왼쪽 비트( 즉 최상위 비트)가 0인지 1인지에 따라 뒤의 15비트 값의 의미가 달라진다.


0인경우에는 4분음표의 길이가 몇 틱[각주:1]인지를 의미한다.

1인경우에는 1 뒤의 15비트를 7비트/8비트로 나누어서 각각을 이렇게 읽으면 된다.

7비트: -frames/second

초당 SMTPE 프레임 수를 의미한다.

8비트: ticks / frame

SMTPE 프레임당 틱수를 의미한다




맨 왼쪽 비트가 1이면, 파일내 델타타임은 1초를 쪼갠 조각과 같아진다. 어떤 면에서 SMPTE와 미디 타임코드와 일치한다. 8~14비트는 -24, -25, -29, -30 네 값중 하나를 포함한다. (이는 네가지 표준 SMPTE와 MIDI 타임 코드 포맷과 일치한다)

그리고 8~14비트는 초당 프레임 수를 표현한다

이 음수는 2의 보수 형태로 저장된다. 양수로 저장된 두번째 바이트는 프레임 동안의 해상도이다. (대표값으로, 보통 4,8,10,80,100일것이다) 이 스트림은 타임코드기반의 트랙의 정확한 명시를 가능케한다. 그러나 동시에 밀리초 기반 트랙 또한 초당 25프레임임으로, 그리고 초당 40프레임의 해상도를 명시함으로 가능케한다. 만약 파일내 이벤트가 30프레임 타임코드의 비트 해상도와 저장된다면, 디비전 워드는 E250가 될것이다.


*2020-04-17 수정: 본 글은 쓰다 만 글입니다. 마지막 문단은 이해가 안가는게 정상입니다 또한 헤더 청크에 대한 설명밖에 없습니다. 나중에 다시 써볼까 싶긴하네요

  1. 틱은 컴퓨터가 내부적으로 돌아가는 시간 단위다. [본문으로]