HiTEL 게제동(GMA) 공개자료실

새로운 ADLIB 연주 포맷 TMF!!!
작성자:김자량(yunjr)
94-01-29
첨 부:[185]tmflib.lzh
새로운 애드립용 음악 파일 포맷..... 제 생각엔 게임 제작 하시는 분들 중 대다수가 음악 파일 포맷으로 IMS 파일을 쓰고 있으리라고 생각됩니다. IMS 파일은 예전의 ROL 포맷 보다 크기도 작고, 제어도 훨씬쉽기 때문이겠죠. 하지만 저는 IMS 파일 포맷을 읽어 들이는 프로그램을 연구하다가 (뭐 여러분들이 잘 아시는 AdLib Tool Kit 죠..뭐....) 거의 포기하다 시피 해 버렸습니다. 어느 정도 High Level 의 제어 부분은 알아 듣겠 는데, Low Level 부분은...영....... 그리고 ADLIB.C 를 분석해 보니 음악 ? 컥? 연주하는데 너무 복잡한 루틴이 많더군요. 음악 연주의 경우 타이머 인터럽트를 제어해야 하니, 될 수 있으면 루틴들을 줄여서 빨리 인터럽트를 끝내야지 다른 프로그램도 무리 없이 작동 될수 있지 않겠 느냐는 생각이 들더군요. 그래서 저는 두가지 목표를 가지고 새로운 음악 파일 포맷을 구상하 게 되었습니다. "최대한 빠르고 간단하게 하자." 바로 이거죠. : 파일로 들어 있는 PLAYTMF.C 소스를 보면 아시겠지만 여러분 도 잘 아시는 TIMEOUT 함수가 100라인도 체 안됩니다. 어떤 분은 IMS PLAY.C 의 TIMEOUT 함수는 20 라인도 안되는데 하실 지 모르겠지만, 그건 모르고 하시는 말씀이죠. TIMEOUT 함수 에서 값을 읽어서 ADLIB.C라는 1000라인이 넘는 거대한 라이 브러리를 호출하게 되죠. 하지만 저의 'TMF' 포맷에서는 TI- MEOUT 함수 안에서 다른 루틴을 호출하지 않고 모든 애드립 제어를 수행합니다. (흐~ 사실 AdLibOut 이라는 루틴은 한번 불러요. 애드립 포트에 써 넣는 함수니...... 부르기 싫어도 할 수 없죠.) 그리고, TIMEOUT 함수가 100라인? 繭箚? 했는데 사실 그것도 제가 속도 개선을 위해서 똑 같은 루틴을 두번 반복한 것이예요. 그러니 실제 데이터를 읽어서 쓰는 것은 50라인도 체 안되죠. 그리고 제가 부수적으로 한가지 더 개선된 점을 말씀드리면, 바로 파일의 크기가 줄어들었다는 것입니다. 한 예를 들어서 약 80,000 정도 의 ROL 포맷으로 된 음악 파일을 IMS 포맷으로 바꾸면 약 50,000 정도 가 됩니다. 그리고 이것을 다시 TMF 포맷으로 바꾸면 약 30,000 정도로 됩니다. 압축률은 음악 파일에 따라서 틀리나 절대로 IMS 포맷 보다 늘 어나는 일은 없고( 혹시 한번도 음의 반복 없이 연주되는 10초 미만의 곡이라면 몰라도~) 대략적인 압축률은 한 0.7 ~ 0.8 배 정도입니다. 그리고 가장 큰 단점이 있다면 좀 고차원적인 음악연주에서는 쓸 수 없다는 겁니다. 뒤에 설명 하겠지만 TMF라는 포맷은 모든 연주 데이터 가 붕괴(?)된 상태이기 때문에 어떤 제어도 불가능합니다. 볼륨 조정 정도야 머리를 좀 굴리면 가능하겠지만, 다른 것들은 좀 힘들꺼예요. 그렇다면 TMF 포맷의 원리에 대해서 설명하겠습니다. 저는 ROL 포맷은 잘 모르니 IMS 포맷과 비 교해서 설명하겠습니다. IMS 포맷의 경우 ROL에서 넘어 올때 데이터가 많이 파괴(?) 된 상태 이지만 그래도 다시 ROL 포맷으로도 바꿀 수 있고, 여러가지 고차원적 제어(예를 들자면 한음당 볼륨을 조절한다던가...)도 가능했었습니다. 그러나 IMS 포맷에서 TMF 포맷으로 넘어 올때는 볼륨, 피치, 노트, 인 스트루먼트등의 템포를 제외한 모든 데이터가 파괴(?) 되어 버립니다. 이게 무슨뜻이냐 하면, 볼륨, 피치, 노트등의 것을 구분하지 않고, TMF 파일 포맷으로 만들때에는 그냥 AdLib Card에 직접 쓰는 데이터만 을 기록해 두기 때문입니다. (물론 카드에 쓸때의 어드레스를 역추적 하면 어떻게 했는지 알수야 있겠지만.) TMF 포맷이 50 라인도 안되는 짧은 함수로 연주 할 수 있는 이유가 바로 이것 때문입니다. 그런데 안타깝게도 이렇게 해 버리면 파일의 크기가 엄청나게 늘어나게 됩니다. 실례를 들어서 약 53,000 짜리의 IMS 파일을 이렇게 바꾸면 약 130,000 정도가 되어 버립니다. 그렇다면 어떻게 130,000 정도가 되는 것을 더 줄여서 30,000 대로 만드느냐 하면...... 바로 데이터를 Pack 단위로 묶어서 계산하는겁 니다. 그러니까 IMS 포맷의 명령 으로 NoteOn이라는 명령이 있으면 거 기에 따라서 제어 되는 실제 AdLib Card의 입력도 같은 명령에서는 똑같이 됩니다. 그러니 그런 데이터를 한 Pack 단위로 구성해서 압축 을 해주는 방식이죠. 물론 그냥 이렇게 압축한다고 해도 사실 50,000 정도로 밖에 안되더군요. 그래서 제가 별의 별 머리를 다 짜서 만든 것이 바로 TMF 포맷입니다. TMF 포맷으로 파일을 만들기 위해서는 우선 바꾸고 싶은 IMS 파일과 그에 따르는 뱅크 파일이 있어야 합니다. TMF 파일은 생성후에 뱅크 파일은 쓰지 않게됩니다. (이걸 말하니 또 생각나? 째? 있군요. 예전 에 MID 포맷이 한창 유행했을때(?) MID 포맷의 단점으로 뱅크를 파일 속에 넣어두어서 악기를 자주 바꿀경우 길이가 늘어난다고 하셨는데, 하지만 TMF는 그런 데이터를 Pack으로 만들어 저장하니 늘어나는 경우 는 없어요. 줄어 들면 줄어 들었지......) 그러면 구체적으로 TMF라는 포맷에대해서 간략하게만 설명하겠습니 다. 뭐 꼭 알 필요는 없다고 생각하니까요. Offset 0 : char id_byte[25] - TMF 포맷인가를 판별하는 곳입니다. 25 바이트의 스트링 "TMF File by Ahn Young Hun" Offset 25 : unsigned char d_mode - 멜로디 모드인가 퍼큐시브 모드인가를 알려줍니다. Offset 26 : unsigned basic_tempo - 기본적인 템포입니다. Offset 28 : unsigned LCount - Pack으로 저장된 데이터가 몇개인지를 말합니다. Offset 29 : 이후 부터는 Pack 데이터입니다. 먼저 제어에 대한 설명을 잠시 해야겠는데, TMF 포맷의 음악 출력은 이렇게 되어있습니다. Offset 0 : length Offset 1 ~ length : Data Offset 1 + length : Delay length 는 뒤에 나올 Data의 양입니다. Data는 기본적으로 2Byte씩으로 구성되어 있습니다. 첫 바이트는 어드레스, 두번째 바이트는 데이터... 그리고 어드레스에 0xe6이 오면 템포처리를 하게 되는데 템포만 예외적으로 3Byte로 구성되어 있습니다. 그리고 Delay는 TimeOut 함수에서 넘겨주는 지연값입니다. 만일 Delay가 0xff라면 다음의 2Byte를 더 읽어서 지연값 을 정하게 됩니다. 이런식으로 Offset 29 부터 L Count만큼 데이터를 읽게 됩니다. 그리고 그 뒤부터는 실제 연주부분의 데이터가 들어가게 됩니다. 실제 연주부분의 데이터도 위에 설명한것과 크게 다른게 없습니 다. 단지 length 부분이 약간 틀린데, length가 0xff이고, 그 뒤의 데이터도 0xff이면 음악이 종료 된 것을 뜻합니다. 그리고, length가 0x30보다 크다면 1Byte의 Pack 데이터이고, length가 0x20보다 크고 0x30보다 작다면 2Byte의 Pack 데이터가 됩니다. (흐억~~ 힘들다.....) 그러면 실제 만 들어진 파일에 대해서 설명을 하겠습니다. MAKETMF.EXE 와 PLAYTMF.EXE의 두 파일이 있습니다. MAKETMF.EXE는 IMS 포맷을 TMF 포맷으로 바꾸어 주는 것이고, PLAYTMF.EXE는 TMF 포맷으로 된것을 간단하게 연주하는 프로그 램입니다. 소스도 제가 올리겠지만, 소스를 제작하는 실력이 워 낙 떨어지기 때문에 보기가 이상해도 좀 양해해 주시기 바라겠습 니다. MAKETMF는 MAKETMF imsfile[.ims] [tmffile[.tmf]] [bankfile[.bnk]] 로 하면 됩니다. bankfile을 안 적을 경우는 standard.bnk를, tmffile 를 안 적 을 경우는 imsfile과 같은 이름으로 확장자만 달리하여 생성 시킵니다. 그리고 PLAYTMF는 단순히 PLAYTMF tmffile[.tmf] 로 하면 됩니다. 그리고 소스를 컴파일 하려면 프로젝트로 만들어야 합니다. PLAYTMF.C는 다른것을 링크 시킬 필요 없구요. MAKETMF는 MT.OBJ SETFREQ.OBJ TIMER.LIB과 같이 링크 시켜야합 니다. 모델은 전부 Large로 하면 되겠고요. 그리고, MAKETMF는 아마 unsigned char 옵션을 On 시켜야 작동할꺼예요. (제가 IMS 포맷 읽는 부분을 만들기 싫어서 IMSPLAY에서 배꼈거든 요.) 그 럼 이만..... [ I can see you, but you can't. I can kill you, but you can't ] [ In Dark, Never Seen, Never Told, Never Recognized ] [ Dark Mage Cyllian Cominus ] 버그가 몇개 있어서....이렇게 게시판 상으로나마 고치겠습니다.. 먼저 MAKETMF에서 뱅크 로드하는 부분에.. LoadBank 함수에서 strcmp 함수를 stricmp 로 바꾸세요... 어떤분이 뱅크가 안읽어진다길래 보니까.. 대소문자 구분이 되어 있더군요.. 그리고 PLAYTMF를 하면 갑자기 시계가 빨리 가게 되는? ?.... Clk_install 과 Clk_uninstall 부분을 바꾸면 되요.. void Clk_install() { asm { mov al, 00110110b out 43h, al xor al, al out 40h, al out 40h, al } ClkDivh = 1; ClkDivl = 0; ClkMod = 0; User_Routine = 0; oldTimer = getvect(8); setvect(8, ClkInt); } void Clk_uninstall() { asm { mov al, 00110110b out 43h, al xor al, al out 40h, al out 40h, al } setvect(8,oldTimer); } 그러니까 out 43h, al 하고 out 40h, al 사이에.. xor al, al 을 집어 넣으세요... 그리고 지금 tmflib 라고 연주용 라이브러리를 만들었는데.. 제가 예전에 올린 Super VGA 제어 라이브러리인 SLIB 와 연결 시키고 있어요... 다 완성되면 올려 드릴깨요...