잡동사니

동방 BGM 추출 관련(thbgm.fmt에 관해)글

픔스 2017. 5. 7. 20:10

※이 글은 다음 글의 도움으로 작성되었습니다.

 

동방프로젝트의 BGM은 항상 많은 동방 팬들의 관심을 받기 마련이다. 물론, 게임 CD를 구매하자 마자 BGM을 들어보는 사람 또한 있을 것이다.

그러나 정작 음악을 추출하려고 하면 전혀 감도 못 잡겠고, 추출 툴은 몇 주 심하면 반 년 이후에나 업데이트 되는 경우가 허다하다.

동방 BGM을 추출하기 위해 많은 노력을 했지만, 코딩 쪽에는 일자무식인 나로써는 너무나도 힘든 일이었다. 그러나, 웹 서핑을 통해 BGM을 읽는 헤더 파일의 해석을 구할 수 있게 되어 이를 분석한 글을 올려둔다.

 

먼저, 헤더 파일에 상응하는 파일인 thbgm.fmt에 대해 알아보자.

이는 th**.dat 안에 들어 있는 파일로써, 추출하기 위해서는 thtk 등을 통해 직접 dat 파일을 분해해야만 한다. 가장 유명한 툴인 thtk는 현재 th16까지 대응되며, 최신 버전은 thtk-9이다. 다운로드는 공식 깃허브에서 가능하다.

 

잠깐 thtk의 사용법을 알아보자.

본디 이 툴은 구미권 동방 프로젝트 팬덤에서 영어 패치를 위해 개발된 툴로, 각종 데이터를 분해하고 조립하는 기능을 가지고 있다.

여기에서는 간단하게 dat를 분해하는 thdat.exe의 사용법을 짚고 넘어가겠다. thtk의 자세한 사용법은 이 곳을 참조하라.

 

thdat.exe는 CUI 응용 프로그램으로, 커맨드라인에서 명령값을 주어 사용가능하다.

대상 프로그램인 thdat.exe이 존재하는 경로로 이동한 뒤에 thdat.exe을 지정하고, 커맨드를 쓴 뒤에 thdat.exe이 작업할 해당 파일을 지정하면 된다.

즉, 다음과 같이

thdat.exe -COMMAND[OPTION...] [ARCHIVE [FILE...]]

사용하면 된다. 커멘드에는 c, l, x, V가 있으며, 각 커멘드에는 옵션을 붙여 사용하면 된다. 옵션에는 해당 파일의 동방 버전을 적으면 된다.

c는 대상을 생성하며, l은 대상에 포함된 파일들의 리스트를 보여준다. x는 대상을 분해하며, V 커맨드는 thtk의 버전 정보를 보여준다.

 

thtk를 통해 th**.dat을 분해했다면, 수많은 파일들이 나올 텐데, 이 중 BGM의 헤더 역할을 하는 파일인 thbgm.fmt를 찾아보자.

thbgm.fmt는 헥스 에디터 등을 통해 열어야만 해당 데이터를 16진수로 접근할 수 있다. 적당한 hex editor를 구해 열어보도록 하자.

 

 

해당 예제는 th16의 체험판 데이터다. 헥스 에디터는 기본적으로 데이터의 16진수 값과 이를 특정 인코딩으로 변환하여 보여준다. 예제에서는 ANSI를 사용한다. 처음에는 이 데이터를 보고도 도통 감을 못 잡았지만, 몇가지 단서를 통해 데이터를 유추해 낼 수 있었다. 그것은 다음과 같다.

74 68 31 36 5F 30 31 2E 77 61 76→th16_01.wav
00 00 00 00 00
10 00 00 00→00 00 00 10
00 78 ED 00→00 ED 78 00-00 11 EC 00→00 DB 8C 00
00 EC 11 00→00 11 EC 00
00 78 ED 00→00 ED 78 00-00 11 EC 00→00 DB 8C 00
01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10→PCMWAVEFORMAT구조체
00 00 00 00 00
74 68 31 36 5F 30 32 2E 77 61 76→th16_02.wav
00 00 00 00 00
10 78 ED 00→00 ED 78 10
C8 2C 20 01→01 20 2C C8-00 09 AB 70→01 16 81 58
70 AB 09 00→00 09 AB 70
C8 2C 20 01→01 20 2C C8-00 09 AB 70→01 16 81 58
01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10→PCMWAVEFORMAT구조체
00 00 00 00 00
74 68 31 36 5F 30 33 2E 77 61 76→th16_03.wav
00 00 00 00 00
D8 A4 0D 02→02 0D A4 D8
80 31 25 01→01 25 31 80-00 10 57 00→01 14 DA 80
00 57 10 00→00 10 57 00
80 31 25 01→01 25 31 80-00 10 57 00→01 14 DA 80
01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10→PCMWAVEFORMAT구조체
00 00 00 00 00
74 68 31 36 5F 30 34 2E 77 61 76→th16_04.wav
00 00 00 00 00
58 D6 32 03→03 32 D6 58
80 ED 3B 01→01 3B ED 80-00 11 29 00→01 2A C4 80
00 29 11 00→00 11 29 00
80 ED 3B 01→01 3B ED 80-00 11 29 00→01 2A C4 80
01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10→PCMWAVEFORMAT구조체
00 00 00 00 00
74 68 31 36 5F 30 35 2E 77 61 76→th16_05.wav
00 00 00 00 00
D8 C3 6E 04→04 6E C3 D8
00 AD 14 01→01 14 AD 00-00 22 E2 00→00 F1 CB 00
00 E2 22 00→00 22 E2 00
00 AD 14 01→01 14 AD 00-00 22 E2 00→00 F1 CB 00
01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10→PCMWAVEFORMAT구조체
00 00 00 00 00
74 68 31 36 5F 30 36 2E 77 61 76→th16_06.wav
00 00 00 00 00
D8 70 83 05→05 83 70 D8
78 2E 5C 01→01 5C 2E 78-00 08 B9 F0→01 53 74 88
F0 B9 08 00→00 08 B9 F0
78 2E 5C 01→01 5C 2E 78-00 08 B9 F0→01 53 74 88
01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10→PCMWAVEFORMAT구조체
00 00 00 00 00
74 68 31 36 5F 30 37 2E 77 61 76→th16_07.wav
00 00 00 00 00
50 9F DF 06→06 DF 9F 50
BC 0A 64 01→01 64 0A BC-00 72 43 D4→00 F1 C6 E8
D4 43 72 00→00 72 43 D4
BC 0A 64 01→01 64 0A BC-00 72 43 D4→00 F1 C6 E8
01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10→PCMWAVEFORMAT구조체
00 00 00 00 00
74 68 31 32 38 5F 30 38 2E 77 61 76→th128_08.wav
00 00 00 00
0C AA 43 08→08 43 AA 0C
C0 DC 66 00→00 66 DC C0-00 1C AC C8→00 4A 2F F8
C8 AC 1C 00→00 1C AC C8
C0 DC 66 00→00 66 DC C0-00 1C AC C8→00 4A 2F F8
01 00 02 00 44 AC 00 00 10 B1 02 00 04 00 10→PCMWAVEFORMAT구조체
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

이를 해석하면 다음과 같다.

 

먼저, 처음 74와 76 사이의 값은 ANSI 0x74(t)~0x76(v)으로, 각 곡의 제목을 의미한다.

그리고 더미값 00이 연속한다. 데이터 값을 구분하기 위해 집어넣은 것 같다.

 

다음으로 오는 6개의 16진수는 곡이 시작하는 개시 위치를 의미한다. 이 값은 거꾸로 뒤집혀 있으며, 10 00 00 00은 곧 00 00 00 10이 되며, 의미는 10진수 16을 의미한다.

 

개시 위치 값 다음으로 오는 6개의 16진수는 인트로 부분의 길이와 루프 부분의 길이의 합을 의미한다. 처음에 thbgm.fmt를 분석할 때, 이 부분을 해석하지 못해 결국 분석을 포기했던 적이 있는데 웹 서핑을 통해 우연히 이 값이 인트로부와 루프부의 합이라는 것을 알게 되었다. 다시 한번 해당 정보를 게시해 준 네티즌에게 감사를 표한다. 이 값 역시 개시 위치 값과 동일하게 거꾸로 뒤집혀 있다.

 

인트로 부분의 길이와 루프 부분의 길이의 합인 값 다음으로 오는 6개의 16진수는 인트로 부분의 길이를 의미한다. 이를 통해 루프 부분의 길이 값을 유추해낼 수 있다. 역시, 이 값도 동일하게 거꾸로 뒤집혀 있다.

 

인트로 부분의 길이 값 다음으로 오는 6개의 16진수는 앞서 살펴 본 인트로 부분의 길이와 루프 부분의 길이의 합인 값과 동일하다. 신령묘 이전 동방에서는 이 부분만이 인트로부 길이+루프부 길이였으며, 개시 위치 값과 인트로 부분의 길이 값 사이에 위치한 6개의 16진수는 해석하지 못한 전혀 다른 데이터였다고 한다. 여기에서는 해당 내용을 다루지 않겠다.

 

마지막으로 따라오는 15개의 16진수는 PCM WAV 포맷 구조체라고 하는데, 솔직히 잘 모르겠다. 여기에서 설명은 생략한다.

그 후에 더미값 00이 연속한다.

 

이 구조가 한 덩어리로, 각 곡마다 이 정보가 계속 반복된다.

 

동방 BGM을 추출하려는 사람에게 혹시 도움이 될까 이 정보를 블로그에 게시한다. 다른 사람들은 나와 같이 해메지 않길 바라며 글을 마친다.

'잡동사니' 카테고리의 다른 글

무제  (0) 2019.02.28
저주·통곡·피어나다.  (0) 2019.02.28
HTML 테스트  (0) 2015.08.23
[카연갤] 휴머노이드 테스트하는 만화  (0) 2015.04.24
당황  (0) 2015.04.17