자... 그래서 이제는 두번째 Track Chunk를 분석해야 된다. 사실 이게 핵심.
사실 이 트랙청크는 너무나도 복잡하고 분석 할 부분이 많은 녀석이다. 하지만 내가 필요한 것은 별로 없다.
악보프로그램을 만드는 것이 아니기 때문에.. 나는 피아노 건반이 내려오는 영상으로 대강의 악보를 만들어 연주만 할 수 있으면 문제가 되지 않기 때문이다. 여러번의 삽질을 통해 알아낸 결과, Muse Score라는 악보 프로그램은 midi파일이 정상적이지 않아도(약간의 binary 문제가 있어도) 이를 수정해주는 능력이 있다는 것을 알아냈다.
따라서 이번 포스팅은 핵심부분만 설명할 것이다. 사실 이것도 상당한 양이 된다.
핵심부분은 다음과 같다.
1) Track Chunk의 구조와 delta time 구하기
2) 저 delta time을 현실의 시간으로 변환하기
3) 소리 내기
Track Chunk 의 구조는 다음 사진과 같다
청크 타입과 길이는 헤드청크와 같은데 달라진 것은 뒷 부분의 Data 영역이다. 이 데이터 영역은
delta time 과 event를 포함하고 있는 구조다. 즉 트랙청크는 type - length - dt -event -dt -event ....
라고 볼 수 있다. 이벤트는 전 이벤트가 끝난 후 delta time 뒤에 실행이 된다.
먼저 저 delta time을 구하는 방법이다. delta time은 1~4바이트의 가변 길이를 가진다.
실제 파일에서의 사례로 설명하겠다.
여기서 선택영역 A9 39가 delta time 부분이다. 이를 이진수로 변환하면
10101001 00111001 이다.
가변길이인데 어떻게 2바이트인지 알았을까?
첫번째 delta time 부분의 최상위 비트가 0일시에는 다음 바이트에 이벤트 데이터가 오는 것이고, 최상위 비트가 1일시에는 다음 바이트에도 델타 타임이 오는 것이다.
즉 여기서 10101001에서 가장 왼쪽 부분이 1이므로 그 다음 39또한 델타타임이 된다. 다시한번 39(00111001)을 분석하면 최상위 비트가 0이므로 그 다음 바이트는 이벤트가 온다.
그 다음 이것들을 합쳐주는데 단순히 더하는 것이 아니라 이어 붙이는 개념이다. 최상위 비트를 제외하고 각각 이어 붙여주면 01010010111001 (5305) 가 된다. 이 delta time의 단위는 Tick 이다.
그래서 이제 delta time 구하는 법을 알았다. 그래서 이 Tick이라는 단위를 현실의 시간(초)로 바꾸어 줄 방법을 알아보자.
일단 앞서 헤드 청크의 division 값을 구해야 한다. 위 파일에서 디비전 부분은 헤드청크의 마지막 2바이트 이므로 01 E0
=480ticks = 4분음표 길이가 된다.
그리고 설명 순서가 틀린 것 같지만, 이벤트 데이터는 메타 이벤트 , 미디 이벤트, 시스템 이벤트로 나뉘는데
이를 구분하는 방법은 delta time 뒤 상태를 나타내는 바이트의 값에 따라서 구분된다. 이 바이트가
0~0xEF까지는 미디 이벤트, 0xF0~0xFE까지는 시스템 이벤트, 0xFF는 메타 이벤트이다.
메타이벤트 중에서는 4분음표의 길이를 마이크로 초로 정의하는 이벤트가 있고 이 이벤트를 통해 tick을 초로 바꾸어 줄 것이다. 아래표는 메타이벤트 정리표이다. FF 51에 주목
FF 51은 템포를 조절하는 이벤트로 형식은 FF 51 03 tt tt tt 이다.
이는 4분음표의 길이= tt tt tt Ticks 로 정의한다는 것이다. 실제로 살펴보자
이파일에서는 07 A1 20이고 이는 500000 에 해당한다. 이 단위는 마이크로초에 해당하며 환산해 보면 0.5초이다.
즉 지금까지 나온 것을 다 합산하면
4분음표의 길이 = 480ticks =0.5초
1ticks = 1/960 초
아까전에 위에서 구했던 델타 타임은 5305ticks 고 이는 5.526초에 해당한다.
마지막으로 음은 어떻게 나타내는 것인가?
단순하다 상태이벤트가 9X 면 note on 8X 이면 note off
뒤에 있는 X는 채널.. 인데 잘 모르겠다.
9X 계이름 세기 형식으로 이루어진다. 아래는 계이름에 따른 코드 표. 기본 도는 72부터 시작한다.
|
C |
C# |
D |
D# |
E |
F |
F# |
G |
G# |
A |
A# |
B |
0 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
2 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
3 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
4 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
5 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
6 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
7 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
8 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
9 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
10 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
|
|
|
|
그.런.데 실제로 8X 같은 형식은 쓰지 않는 것 같다. 9X 계이름 00 을 주면 음의 세기가 0이 되어 꺼지는 것을 수행하기 때문이다. 왜 이런 방법을 쓰냐 하면 파일의 크기를 줄일 수 있기 때문이다.
이제 이 파일의 정체를 공개할 수 있게 되었다 . 같이 보면서 이해해 보자.
위 hex에서 처음 90은 0번채널에서 note를 on 시켜주겠다는 것이다. 그런데 악보를 보면 음은 두번 소리를 낸다. 하지만 hex에 90이 2개 있는가? 아니다. 한개밖에 없다. 즉 저 90이라는 상태바이트를 통해 다른 상태 바이트가 나올때까지 계속 상태를 90으로 유지시켜주겠다는 것이다.
그러면 이렇게 볼수 있다.
00 90 47 50 -> 00ticks 뒤에 90(note on) 47(시) 50(세기)
83 47 47 00 -> 455(111000111)ticks (0x83 47) 뒤에 47(시) 00(세기)
-> 즉 시를 누르고 시를 뗀다
A9 39 48 50 -> 5305ticks 뒤에 48(도) 세기(83)
83 47 48 00 -> 455ticks 뒤에 48(도) 세기 (00)
01 FF 2F 00 -> 1ticks 뒤에 메타이벤트 부분으로 트랙의 끝을 나타냄
이정도만 알아도 midi 자체 제작은 가능할 것같다. 앞에 있는 meta data 부분은 복사해서 그대로 사용하고 음 길이 부분만 생성해 주면 되기 때문
'개인 프로젝트 > 악보영상 midi 변환기' 카테고리의 다른 글
[도전 프로젝트] 악보영상으로 midi파일 만들기 #끝 (1) | 2020.06.09 |
---|---|
midi 파일의 구조와 분석기 #1 기본적인 청크 구조 (0) | 2020.06.08 |
[도전 프로젝트] 악보 동영상으로 midi 만들기 #3 (0) | 2020.06.07 |
[도전 프로젝트] 악보 동영상으로 midi 만들기 #2 (0) | 2020.06.07 |
[도전 프로젝트] 악보동영상으로 midi 만들기 #1 (0) | 2020.06.05 |