본문 바로가기

유니티

MIDI 프로그램을 만들어보자 1 - 청크 구분 및 출력

생각보다 일찍 시작하게 되었습니다. 물론 다음도 빠르게 진행한단 이야기는 아니지만.

그리고 MIDI 글들의 카테고리가 유니티였던 이유는 유니티로 만들 계획이기 때문입니다.

 

이제까지 공부한 토대로 다른 분의 소스도 참고해가며 만들었습니다.

요근래 공식문서만 보고 만들었더니 분석력, 추측력 등 상승에 큰 도움이 되었지만, 현재로써 시간의 압박이 있기 때문입니다. 사실 남의 코드를 보는 것도 이해한다는 전제 하에 도움이 되기도 하고요.

 

ehclub.co.kr/3358?category=762014

 

[미디 파일] 미디 파일 구조 분석 및 프로그래밍 1 - 청크 목록

[미디 파일] 미디 파일 구조 분석 및 프로그래밍 1 - 청크 목록  안녕하세요. 언제나 휴일, 언휴예요.  이번에는 미디 파일 구조를 간단히 알아보고 이를 분석하는 간단한 응용 프로그램을 작성

ehclub.co.kr

(이 분의 글이 큰 도움이 되었습니다.)

 

 

아무튼 본론으로 들어가서,

테스트용으로 쓰였던 123.mid 파일을 어느정도 사람이 편하게 볼 수 있을정도로 만드는 것이 첫 번째 목표입니다.

 

그 과정중 하나인 청크 구분 및 출력입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
using System.Text;
using System.Net;
 
public class Chunk
{
    public string Type { get; set; }
    public int Length { get; set; }
    public byte[] Data { get; set; }
 
    public Chunk(string type, int length, byte[] data)
    {
        Type = type;
        Length = length;
        Data = data;
    }
}
 
public class Test : MonoBehaviour
{
    TextAsset textAsset;
    BinaryReader binaryReader;
 
    // Start is called before the first frame update
    void Start()
    {
        textAsset = Resources.Load("123"as TextAsset;
        using (binaryReader = new BinaryReader(new MemoryStream(textAsset.bytes)))
        {
            while (binaryReader.PeekChar() != -1)
            {
                Chunk chunk = Parse();
 
                if (chunk != null)
                {
                    Debug.Log(
                        "청크타입 : " + chunk.Type +
                        " / 길이 : " + chunk.Length +
                        " / 데이터 : " + ConvertHexToString(chunk)
                        );
                }
            }
        }
    }
 
    Chunk Parse()
    {
        string type = ConvertASCII(binaryReader.ReadInt32());
        int length = ConvertHostOrder(binaryReader.ReadInt32());
        byte[] data = binaryReader.ReadBytes(length);
 
        return new Chunk(type, length, data);
    }
 
    string ConvertHexToString(Chunk chunk)
    {
        string str = "";
        for(int i = 0; i < chunk.Data.Length; i++)
        {
            str += Convert.ToString(chunk.Data[i], 16+ " ";
        }
 
        return str;
    }
 
    string ConvertASCII(int value)
    {
        byte[] data = BitConverter.GetBytes(value);
        ASCIIEncoding encoding = new ASCIIEncoding();
 
        return encoding.GetString(data);
    }
 
    int ConvertHostOrder(int value)
    {
        return IPAddress.NetworkToHostOrder(value);
    }
 
    // Update is called once per frame
    void Update()
    {
        
    }
}
 
cs

 

구조는 간단합니다.

파일을 불러와 필요한만큼 바이트 단위로 읽어서 저장해두었다가 출력한 것이 전부입니다.

 

ConvertHostOrder : 데이터가 Big Endian 바이트 정렬 방식을 사용하고 있기 때문에 호스트 정렬 방식으로 변환해야 정상적으로 읽을 수 있게 됩니다.

 

이를 무시하고 한 번 출력을 해보았는데 데이터가 비정상적으로 출력이 되었습니다.

 

(참고)

genesis8.tistory.com/37

 

리틀 엔디안 VS 빅 엔디안

먼저 둘을 비교하기에 앞서 엔디언이란 무엇인가? 엔디언(Endianness)은 컴퓨터의 메모리와 같은 1차원의 공간에 여러 개의 연속된 대상을 배열하는 방법을 뜻하며, 바이트를 배열하는 방법을 특히

genesis8.tistory.com

 

이 외에 특이사항은 데이터들을 그냥 Debug.Log() 를 통해 출력시키면 10진수 형태로 나오기 때문에 ConvertHexToString 메소드를 만들어 16진수 형태로 변환하였습니다.

 

출력 결과
비교해볼까요?

 

Hex 에디터보다는 비교적 데이터가 가공되어, 좀 더 쉽게 알아볼 수 있게 되었습니다.

 

하지만 아직 알아보기 어려운 부분들이 보이네요.

다음에는 아직 가공이 되지 않은 청크들의 데이터를 구분해보도록 하겠습니다.