- 안영기의 개발실 -
http://smgal.ismine.net/tc_191/blog1/
게임 개발을 기반으로 한, 잡다한 개발 기록 저장소
2019-07-07T02:32:49+09:00
Textcube 1.9.1
[Python] MIDI viewer
안영기
http://smgal.ismine.net/tc_191/blog1/55
2019-07-07T00:52:11+09:00
2019-07-07T00:38:39+09:00
<div style="margin: 0px; padding: 0px; font-size: 12px; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: left; -en-clipboard: true;">
<div><span style="font-size: 12px; color: #666666; font-family: arial, helvetica, sans-serif; font-variant-caps: normal; font-variant-ligatures: normal;">개인적으로 MIDI 파일을 처리하는 간단한 툴을 만들어야해서, 그 첫번 째 단계로 MIDI 파일을 분석해서 화면에 보여주는 기능을 만들었다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"><span style="font-size: 12px; color: #666666; font-variant-caps: normal; font-variant-ligatures: normal;">이 기능은 실제 런타임의 일부가 아니라 전처리를 위한 툴의 형식이었으므로 사용 언어는 Python으로 하였다.</span> </span></div>
<div> <div class="imageblock center" style="text-align: center; clear: both;"><img src="http://smgal.ismine.net/tc_191/attach/1/1284720333.png" alt="사용자 삽입 이미지" height="188" width="470" /></div></div>
<div> <span style="font-family: arial, helvetica, sans-serif;">그림 1. 이 앱을 통해 트랙별 MIDI 출력을 한 예</span></div>
</div>
<div style="margin: 0px; padding: 0px; font-size: 12px; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: left;">
<div><span style="font-size: 9pt; font-family: arial, helvetica, sans-serif;"> </span></div>
</div>
<div style="margin: 0px; padding: 0px; font-size: 12px; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: left;">
<div><span style="font-size: 12px; color: #666666; font-family: arial, helvetica, sans-serif; font-variant-caps: normal; font-variant-ligatures: normal;">[첨부] Source code (Python)</span></div>
<div><span style="color: #666666; font-family: arial, helvetica, sans-serif;"><div class="imageblock center" style="text-align: center; clear: both;"><a class="extensionIcon" href="http://smgal.ismine.net/tc_191/blog1/attachment/1408385992.zip"><img src="http://smgal.ismine.net/tc_191/resources/image/extension/zip.gif" alt="" /> midi_viewer.zip</a></div></span></div>
<div><span style="color: #666666; font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="color: #666666; font-family: arial, helvetica, sans-serif;"><br /> </span></div>
<div><span style="color: #666666; font-family: arial, helvetica, sans-serif;">이왕 만든 김에 첨부한 소스 코드에 대한 간단한 설명을 덧붙였다.</span></div>
</div>
<div><br /><hr /></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-size: 9pt; font-family: Consolas;"><span style="color: #eb0073;">import</span> midi</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-size: 9pt; font-family: Consolas;"><span style="color: #eb0073;">import</span> math</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-size: 9pt; font-family: Consolas;"><span style="color: #eb0073;">import</span> numpy <span style="color: #eb0073;">as</span> np</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-size: 9pt; font-family: Consolas;"><span style="color: #eb0073;">import</span> matplotlib.pyplot <span style="color: #eb0073;">as</span> plt</span></div>
<div> </div>
<div><span style="font-family: arial, helvetica, sans-serif;">MIDI viewer를 만들기 위해 사용하는 모듈들이다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">이중에 'midi'는 python-midi인데, 일반적인 방법으로는 3.x에서 설치가 안 되어서</span></div>
<div style="margin-left: 40px;"><span style="font-family: 'courier new', courier;">pip install git+https://github.com/vishnubob/python-midi@feature/python3</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">와 같은 방법으로 설치를 하였다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">그 이외의 나머지는 수치 계산을 위한 모듈(numpy)과 그래프를 그리기 위한 모듈(matplotlib.pyplot)이다.</span></div>
<div> <hr /></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">pattern <span style="color: #eb0073;">=</span> midi.read_midifile(<span style="color: #147191;">"somewhere_over_the_rainbow.mid"</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">pattern.make_ticks_abs()</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">tracks <span style="color: #eb0073;">=</span> midi.Track(pattern)</span></div>
<div> </div>
<div><span style="font-family: arial, helvetica, sans-serif;">여기는 MIDI 파일을 읽어서 분해하는 부분인데, pattern에는 MIDI의 헤더부분과 트랙들으로 나누어 저장된다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">MIDI의 tick(일종의 time-stamp)은 항상 바로 앞의 이벤트와의 상대적인 길이로 저장이 되는데, 여기서는 시간대 별로 이벤트를 나열해야 하므로 tick을 절대적인 값으로 변경을 하였다. 그리고 tracks에는 pattern에 있는 트랙의 집합을 꺼내서 따로 저장을 하였다.</span></div>
<div> </div>
<div><hr /></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">resolution </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">pattern.resolution</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">bpm </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #3665ee;">0</span></span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">max_channel </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #3665ee;">-1</span></span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">beats </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #3665ee;">0</span></span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">beat_type </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #3665ee;">0</span></span></div>
<div> </div>
<div><span style="font-family: arial, helvetica, sans-serif;">MIDI의 tick의 단위는 resolution에 의해 정의가 된다. 일반적으로는 ticks per quarter-note 라고 하는데 480 또는 960으로 정의할 때가 많다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">그리고 추가로 더 알아내어야 하는 것은 채널의 개수와 몇 분의 몇 박자인지를 파악하는 것인데, 이것은 MIDI 이벤트를 모두 뒤져봐야 알 수 있는 것이라서 아직은 invalid로 정의하였다. 채널의 경우도 트랙과는 다른 개념이어서 모든 MIDI 이벤트를 확인해야지만 어떤 채널이 사용되었는지 알 수 있다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">4분의 3박자(3/4) 라면 beats = 3, beat_type = 4 를 의미한다.</span></div>
<div><br /><hr /></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #eb0073;">for</span> track <span style="color: #eb0073;">in</span> tracks:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">for</span> event <span style="color: #eb0073;">in</span> track:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">if</span> <span style="color: #9e00f3;">isinstance</span>(event, midi.events.TimeSignatureEvent):</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <em><span style="color: #328712;"># data=[4, 2, 24, 8]</span></em></span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> beats <span style="color: #eb0073;"><=</span> <span style="color: #3665ee;">0</span>:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> beats </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">event.data[</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> beat_type <span style="color: #eb0073;"><=</span> <span style="color: #3665ee;">0</span>:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> beat_type </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"><</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"><</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">event.data[</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">if </span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #9e00f3;">isinstance</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(event, midi.events.NoteOnEvent):</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> max_channel </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"><</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">event.channel:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> max_channel </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">event.channel</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">if</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #9e00f3;">isinstance</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(event, midi.events.SetTempoEvent):</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> tempo_in_msec </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(event.data[</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">] <span style="color: #eb0073;">&</span> <span style="color: #3665ee;">0xFF</span>) </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"><</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"><</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #3665ee;">16</span> <span style="color: #eb0073;">|</span> (event.data[</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">] & <span style="color: #3665ee;">0xFF</span>) </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"><</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"><</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">8</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">|</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> (event.data[</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">2</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">] <span style="color: #eb0073;">&</span> <span style="color: #3665ee;">0xFF</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> tempo_in_msec <span style="color: #eb0073;">></span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> bpm </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1000000</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> *</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">60</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><em><span style="color: #328712;"> // tempo_in_msec</span></em></span></div>
<div> </div>
<div><span style="font-family: arial, helvetica, sans-serif;">여기서는 BPM(Beats Per Minute)과 박자와 제일 큰 채널 번호를 찾는다. (중간에 변경 가능한 값들이지만 그 경우는 고려하지 않는다)</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">전체 MIDI 이벤트에서 박자 변경 이벤트를 찾은 뒤, 그 이벤트의 data에서 data[0]을 beats로, 2^data[1]을 beat_type으로 둔다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">채널의 경우는 최대 값만 찾도록 하였는데, 중간에 쓰이지 않는 채널이나 특정 용도(drum)로 지정된 채널도 있을 수 있다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">마지막으로 템포 변경 이벤트를 찾은 후에 그 값을 읽는데, 가변 길이가 아닌, 24-bit big-endian 형식의 숫자로 읽으면 된다.</span></div>
<div> <hr /></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">bpm </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">bpm <span style="color: #eb0073;">if</span> bpm <span style="color: #eb0073;">></span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">else</span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">72</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">beats </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">beats</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">beats <span style="color: #eb0073;">></span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">else </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">4</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">beat_type </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">beat_type </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">beat_type <span style="color: #eb0073;">></span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">else </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">4</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">max_channel </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">max_channel +</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #9e00f3;"> </span></span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #9e00f3;">print</span>(<span style="color: #147191;">"RESOLUTION =</span> <span style="color: #1a90b9;">{0}</span><span style="color: #147191;">"</span>.<span style="color: #9e00f3;">format</span>(resolution))</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #9e00f3;">print</span>(<span style="color: #147191;">"BPM =</span> <span style="color: #1a90b9;">{0}</span><span style="color: #147191;">"</span>.<span style="color: #9e00f3;">format</span>(bpm))</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #9e00f3;">print</span>(<span style="color: #147191;">"MAX CHANNEL =</span> <span style="color: #1a90b9;">{0}</span><span style="color: #147191;">"</span>.<span style="color: #9e00f3;">format</span>(max_channel))</span></div>
<div> </div>
<div><span style="font-family: arial, helvetica, sans-serif;">여기에는, 해당 MIDI 이벤트가 누락된 경우에는 디폴트 값으로 설정하게 하는 부분을 두었다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">BPM은 72, 박자는 4/4를 디폴트로 하였는데, max_channel의 경우는 현재 발견된 채널 번호 +1 을 하였다. channel 번호는 0번부터 시작하기 때문이다.</span></div>
<div> </div>
<div><hr /></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">noduvels </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">[[]</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">for </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">i</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">in </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #9e00f3;">range</span>(max_channel)]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">for </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">track <span style="color: #eb0073;">in</span> tracks:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> incomplete </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">{}</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> incomplete_2nd </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">{}</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">for </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">event</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">in </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">track:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> is_note_on</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #9e00f3;">isinstance</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(event, midi.events.NoteOnEvent) <span style="color: #eb0073;">and</span> event.velocity <span style="color: #eb0073;">></span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> is_note_off</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #9e00f3;">isinstance</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(event, midi.events.NoteOffEvent) <span style="color: #eb0073;">or</span> (</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #9e00f3;">isinstance</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(event, midi.events.NoteOnEvent) and event.velocity <span style="color: #eb0073;">==</span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">is_note_on:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> time_stamp </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">event.tick <span style="color: #eb0073;">/</span> resolution <span style="color: #eb0073;">/</span> beats</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> key </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">event.channel <span style="color: #eb0073;"><<</span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">8</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">|</span> event.pitch</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">not key </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">in </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">incomplete:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> incomplete[key]</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> [time_stamp, event.velocity]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">elif </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">not key</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">in </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">incomplete_2nd:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> incomplete_2nd[key]</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> [time_stamp, event.velocity]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">else</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #9e00f3;">print</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(<span style="color: #147191;">"[WARNING] Too many intersections"</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">is_note_off:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> time_stamp</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> event.tick <span style="color: #eb0073;">/</span> resolution</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">/</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> beats</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> key </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">event.channel <span style="color: #eb0073;"><<</span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">8</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">|</span> event.pitch</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">if</span> key <span style="color: #eb0073;">in</span> incomplete_2nd:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> noduvels[event.channel].<span style="color: #9e00f3;">append</span>([event.pitch, incomplete_2nd[key][</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">], time_stamp, incomplete_2nd[key][</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">]])</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">del</span> incomplete_2nd[key]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">elif</span> key</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">in </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">incomplete:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> noduvels[event.channel].<span style="color: #9e00f3;">append</span>([event.pitch, incomplete[key][</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">], time_stamp, incomplete[key][</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">]])</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">del</span> incomplete[key]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">else</span>:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #9e00f3;">print</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(<span style="color: #147191;">"[WARNING] Cannot find NoteOn before NoteOff"</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #9e00f3;">assert</span> <span style="color: #eb0073;">len</span>(incomplete_2nd) <span style="color: #eb0073;">==</span> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #eb0073;">and</span> len(incomplete) <span style="color: #eb0073;">==</span></span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span></div>
<div><span style="font-family: D2Coding;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">이전까지가 속성 값을 읽기 위한 작업이었다면, 이번부터는 제대로된 트랙별 note를 읽는 과정이 들어가 있다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">주로 확인할 이벤트는 NoteOn과 NoteOff인데, 일부 DAW에서는 NoteOff 대신 NoteOn의 velocity를 0으로 하여 off의 효과를 내는 것도 있기 때문에 NoteOff의 경우는 조금 더 복잡하게 판단을 한다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">incomplete 변수를 두는 이유는 아직 NoteOff가 일어나지 않은 note들을 임시로 보관하기 위함인데, 간혹 표준과는 다르게 사람의 실수에 의해 같은 pitch의 note인데도 on과 off가 중첩되는 구간이 생기기도한다. 이런 것을 한 번 정도는 허용해 주기 위해 incomplete_2nd 변수를 추가로 두었다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">NoteOff 이벤트가 발생하면 incomplete 에 있는 note를 꺼내어서 완성을 하게 되는데, pitch, 시작 time stamp, 끝 time stamp, velocity를 각 채널별로 저장한다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">(제대로 하려면 expression과 sustain pedal과 pitch bend 등도 저장을 해야 하나, 재생의 목적이 아니므로 생략하였다)</span></div>
<div><br /><hr /></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #de5700;"><span>def</span></span> <span style="color: #ad0000;">_getColorList</span>(selected_cmap):</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #eb0073;">return</span> [selected_cmap(a) <span style="color: #eb0073;">for</span> a <span style="color: #eb0073;">in</span> np.linspace(<span style="color: #3665ee;">0.0</span>, <span style="color: #3665ee;">1.0</span>, max_channel)]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">color_list <span style="color: #eb0073;">=</span> _getColorList(plt.get_cmap(<span style="color: #147191;">'rainbow'</span>))</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">sub_plt_1</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> plt.figure(<span style="text-decoration: underline;">figsize</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">14</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">,</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">5</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">)).add_subplot(</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">,</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">,</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">max_measure</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">-1</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">min_note</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">128</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">max_note</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">for </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">ix_channel</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">in </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #9e00f3;">reversed</span>(<span style="color: #9e00f3;">range</span>(max_channel)):</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> label_name</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #147191;">'Track {0:0>2}'</span>.<span style="color: #9e00f3;">format</span>(ix_channel)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">for </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">noduvel</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">in </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">noduvels[ix_channel]:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> note</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> noduvel[</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> x_1</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> noduvel[</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> x_2</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> noduvel[</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">2</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> vel</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> noduvel[</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">3</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">]</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">max_measure</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"><</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> x_2:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> max_measure</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> x_2</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">min_note</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> note:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> min_note</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> note</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">if </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">max_note</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;"><</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> note:</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> max_note</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> note</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> plt.plot([x_1, x_2], [note</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">+</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #3665ee;">0.5</span>, note</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">+</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0.5</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">], <span style="text-decoration: underline;">c</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">color_list[ix_channel], <span style="text-decoration: underline;">alpha</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">(vel</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">*</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0.8</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">/</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">127</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">+</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0.2</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">), <span style="text-decoration: underline;">linewidth</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">2.5</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">, <span style="text-decoration: underline;">solid_capstyle</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #147191;">'butt'</span>, <span style="text-decoration: underline;">label</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">label_name)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> label_name</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> None</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">max_measure</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> math.ceil(max_measure)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"> </div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">plt.title(<span style="color: #147191;">"MIDI track"</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">plt.xlabel(<span style="color: #147191;">"measure"</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">sub_plt_1.set_xticks(np.arange(</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">, max_measure,</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">4</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">))</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">sub_plt_1.set_xticks(np.arange(</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">, max_measure,</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">), <span style="text-decoration: underline;">minor</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #eb0073;">True</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">plt.ylabel(<span style="color: #147191;">"pitch"</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">sub_plt_1.set_yticks(np.arange(</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">24, 100, 12</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">))</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">sub_plt_1.set_yticks(np.arange(</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">24, 100, 1</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">), <span style="text-decoration: underline;">minor</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #eb0073;">True</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">sub_plt_1.grid(<span style="text-decoration: underline;">which</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #147191;">'major'</span>, <span style="text-decoration: underline;">alpha</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0.5</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">sub_plt_1.grid(<span style="text-decoration: underline;">which</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #147191;">'minor'</span>, <span style="text-decoration: underline;">alpha</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">0.2</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">handles, labels </span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">sub_plt_1.get_legend_handles_labels()</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">labels, handles</span> <span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> <span style="color: #9e00f3;">zip</span>(*<span style="color: #9e00f3;">sorted</span>(<span style="color: #9e00f3;">zip</span>(labels, handles), <span style="text-decoration: underline;">key</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">lambda t: t[<span style="color: #3665ee;">0</span>]))</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">sub_plt_1.legend(handles, labels, <span style="text-decoration: underline;">fontsize</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #3665ee;">8</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">, <span style="text-decoration: underline;">loc</span></span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt; color: #eb0073;">=</span><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"><span style="color: #147191;">'upper left'</span>)</span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;"> </span></div>
<div style="min-height: 11pt; text-align: left; margin-left: 40px;"><span style="min-height: 11pt; font-family: Consolas; font-size: 9pt;">plt.show()</span></div>
<div><span style="font-family: D2Coding;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">위의 과정에서 채널별로 저장된 note 정보를 화면에 출력한다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">가로는 마디의 단위이고, 세로는 pitch의 단위인데, 옥타브 단위로 구분선을 두었다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">채널별로 색깔을 다르게 하고, velocity별로 alpha 값을 다르게 주었다.</span></div>
<div><span style="font-family: arial, helvetica, sans-serif;"> </span></div>
<div><span style="font-family: arial, helvetica, sans-serif;">matplotlib.pyplot 의 내용은 MIDI와 직접적인 관계는 없으므로 설명은 생략한다.</span></div>
<div><br /><hr /><span style="font-family: arial, helvetica, sans-serif;">그리고 그 결과이다.</span><br /><br /></div>
<div><div class="imageblock center" style="text-align: center; clear: both;"><img src="http://smgal.ismine.net/tc_191/attach/1/1268536022.png" alt="사용자 삽입 이미지" height="189" width="470" /></div><span style="font-family: arial, helvetica, sans-serif;">그림 2. 위의 코드로 트랙별 MIDI 출력을 한 예</span></div><p><strong><a href="http://smgal.ismine.net/tc_191/blog1/55?commentInput=true#entry55WriteComment">댓글 쓰기</a></strong></p>
64-bit NDK에서, <dlopen failed: cannot locate symbol "__register_atfork"> 문제
안영기
http://smgal.ismine.net/tc_191/blog1/53
2019-06-27T07:10:07+09:00
2019-06-27T07:09:35+09:00
<div style="-en-clipboard: true;">[문제의 발단]</div>
<div style="margin-left: 40px;">2019년 8월부터 구글 플레이에 올라가는 앱은 64비트를 대응해야 한다고 한다.</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">지금 서비스 하고 있는 앱의 경우, 핵심 모듈은 C++로 되어 있는데 모두 몇 년 전에 만들었던 32비트 so 를 사용하고 있었다.</div>
<div style="margin-left: 40px;">그래서 예전의 C++ 소스 코드를 꺼내서 다시 64비트 so로 만드는 과정이 필요했다.</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">예전에는 Eclipse에서 ndkBuild로 만들었다면, 지금은 최신 Android Studio에서 새로운 NDK 빌드 방식으로 만들어야 하는 점이 달랐는데,</div>
<div style="margin-left: 40px;">새로 NDK Makefile을 만드는 것도 우여곡절이 많았지만 그건 어쨌든 과정의 일부였고, 최종적으로는 NDK 빌드를 성공하고 64비트 so를 적용하여 테스트를 거친 뒤 public release를 했다.</div>
<div> </div>
<div>[문제의 발생]</div>
<div style="margin-left: 40px;">그런데 릴리즈가 되자마자 며칠만에 에러 보고가 날아오기 시작했는데, 다음과 같은 메시지였다.</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">Fatal Exception: java.lang.UnsatisfiedLinkError</div>
<div style="margin-left: 40px;">dlopen failed: cannot locate symbol "__register_atfork" referenced by "lib*****.so"...</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">java.lang.Runtime.loadLibrary (Runtime.java:372)</div>
<div style="margin-left: 40px;">java.lang.System.loadLibrary (System.java:988)</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">JNI 연결을 위해 so를 읽는 과정에서 특정 내부 함수를 찾을 수 없다는 에러이다.</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">한국의 메이저 안드로이드 제조사 것은 문제가 없어서 자체 테스트에서는 발견이 안 되었던 것이고, 화웨이, OPPO, HTC, ZET 등의 기기에서도 OS 5 버전에서만 문제가 발생했다.</div>
<div> </div>
<div>[문제의 원인]</div>
<div style="margin-left: 40px;">위의 에러 상황으로 검색을 해보니, 이런 버그 레포트가 올라왔고</div>
<div style="margin-left: 40px;"><a href="https://android-review.googlesource.com/c/platform/bionic/+/948880">https://android-review.googlesource.com/c/platform/bionic/+/948880</a></div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">최종 review confirm된 코드의 diff를 보면 다음과 같은 내용의 추가로 문제를 해결을 하였다.</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">## `__register_atfork` (Available in API level >= 23)</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">To allow `atfork` and `pthread_atfork` handlers to be unregistered on</div>
<div style="margin-left: 40px;">`dlclose`, the implementation changed in API level 23. Unfortunately this</div>
<div style="margin-left: 40px;">requires a new libc function `__register_atfork`. Code using these functions</div>
<div style="margin-left: 40px;">that is built with a target API level >= 23 therefore will not load on earlier</div>
<div style="margin-left: 40px;">versions of Android, with an error referencing `__register_atfork`.</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">*Resolution*: build your code with an NDK target API level that matches your</div>
<div style="margin-left: 40px;">app's minimum API level, or avoid using `atfork`/`pthread_atfork`.</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">위의 패치의 결과로, 공식 매뉴얼에서 다음과 같이 추가되었으며 (글 중간에 있음)</div>
<div style="margin-left: 40px;"><a href="https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md">https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md</a></div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">
<div>결론적으로는, 앱의 minSDK API level과 NDK의 minSDK API level이 다른 것이 문제로 보였다.</div>
<div>API level 23 이후로 내부 standard so에 저러한 것들이 많이 추가가 된 모양이다.</div>
</div>
<div> </div>
<div>[문제의 해결]</div>
<div style="margin-left: 40px;">앱은 원래부터 minSDK를 19로 지정하고 있었지만, NDK는 이번에 발드를 위해 새로 프로젝트를 만드는 바람에 minSDK 는 현재 가장 높은 버전인 28로 맞춰져 있었다,'</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">그래서 NDK 빌드를 위한 프로젝트에서 app/build.gradle 를 android:defaultConfig:minSdkVersion : 28 -> 19 로 수정하여 빌드를 하였고 문제가 해결된 것을 nm으로 확인할 수 있었다.</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;"><minSdkVersion 28일 때></div>
<div style="margin-left: 40px;">00000000001285f8 A __end__</div>
<div style="margin-left: 40px;"> U __errno</div>
<div style="margin-left: 40px;"> U __register_atfork <- 여기</div>
<div style="margin-left: 40px;"> U __stack_chk_fail</div>
<div style="margin-left: 40px;">00000000001285f8 A _bss_end__</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;"><minSdkVersion 19일 때></div>
<div style="margin-left: 40px;">00000000001295f8 A __end__</div>
<div style="margin-left: 40px;"> U __errno</div>
<div style="margin-left: 40px;"> U __sF</div>
<div style="margin-left: 40px;"> U __stack_chk_fail</div>
<div style="margin-left: 40px;">00000000001295f8 A _bss_end__</div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;"> </div>
<div style="margin-left: 40px;">arm64와 x64 모두 동일하게 문제의 심볼인 '_register_atfork' 의 dynamic refrence가 사라진 것을 확인 하였다.</div><p><strong><a href="http://smgal.ismine.net/tc_191/blog1/53?commentInput=true#entry53WriteComment">댓글 쓰기</a></strong></p>
컴파일 때 trigraph 에 대한 경고문
안영기
http://smgal.ismine.net/tc_191/blog1/52
2019-05-15T00:26:05+09:00
2019-05-14T23:24:00+09:00
<div style="-en-clipboard: true;"><span style="font-size: small; font-family: arial, helvetica, sans-serif;">오랜만에 멀티플랫폼 빌드에서 특이한 경고를 보았다.</span></div>
<div> </div>
<pre><span style="font-family: 'courier new', courier; font-size: small;">sprintf(s, <span style="color: #008080;">"%s:?-??(??)"</span>, mi.pattern.c_str());</span></pre>
<div><span style="font-family: arial, helvetica, sans-serif; font-size: small;"><br />위의 코드가 문제의 코드인데, 다음과 같은 경고가 나왔다.</span></div>
<div> </div>
<pre><span style="font-family: 'courier new', courier; font-size: small;">warning: trigraph converted to '[' character [-Wtrigraphs]</span><br /><span style="font-family: 'courier new', courier; font-size: small;">sprintf(s, "%s:?-??(??)", mi.pattern.c_str());</span><br /><span style="font-family: 'courier new', courier; font-size: small;"> ^</span><br /><span style="font-family: 'courier new', courier; font-size: small;">warning: trigraph converted to ']' character [-Wtrigraphs]</span><br /><span style="font-family: 'courier new', courier; font-size: small;">sprintf(s, "%s:?-??(??)", mi.pattern.c_str());</span><br /><span style="font-family: 'courier new', courier; font-size: small;"> ^</span></pre>
<div> </div>
<div><span style="font-family: arial, helvetica, sans-serif; font-size: small;">최근에는 거의 생각치도 않던 spec인 trigraph가 여기에 적용된 것인데,</span></div>
<div><span style="font-family: arial, helvetica, sans-serif; font-size: small;">예상을 못했던 것은 따옴표 안의 문장에서도 trigraph가 적용된다는 것이었다.</span></div>
<div> </div>
<div><span style="font-family: arial, helvetica, sans-serif;">??( 는 [ 로, ??) 는 ] 로 변환이 되니, 문제의 </span></div>
<div><span style="font-family: 'courier new', courier; font-size: small;">"%s:?-??(??)"</span> 는</div>
<div><span style="font-family: 'courier new', courier; font-size: small;">"%s:?-[]"</span> 가 된다.</div><p><strong><a href="http://smgal.ismine.net/tc_191/blog1/52?commentInput=true#entry52WriteComment">댓글 쓰기</a></strong></p>
[Unity] Android에서만 www.error == "Unknown Error" 가 발생하는 문제
안영기
http://smgal.ismine.net/tc_191/blog1/51
2019-05-12T12:15:56+09:00
2019-05-12T12:12:44+09:00
비교적 최근부터, 개인적으로 만든 API server를 돌리면서 자체 app이나 자체 웹 페이지에서 그 기능을 이용하도록 하는 개인 프로젝트를 하고 있었다.<br /><br />API server를 이용하는 app 중에는 Unity로 만든 것도 2개가 있었는데, 며칠 전에 그 중 하나의 GUI를 업데이트 하는 작업을 하였다. Unity의 테스트는 Windows에서 하기 때문에 개발 시의 테스트는 아무런 문제가 없이 잘 진행되었다. 그리고 최종 타겟 디바이스는 Android이기 때문에 마지막으로 디바이스에서 테스트만 하면 업데이트 테스트는 끝나는 상황이었다.<br /><br />그런데, 그 중에 일부 기능이 타겟 동작을 하지 않았다.<br /><br /><상황><br />1. Windows에서는 잘 되던 app이 Android 디바이스에서는 제대로 동작하지 않았다.<br />2. 문제의 부분은 API server를 이용하는 부분이었다.<br />3. Server 쪽의 로그를 보면 app으로부터 아예 요청이 가지 않았다.<br />4. Unity 쪽에서 원인을 좁혀가니 www.error 가 "Unknown Error"가 발생하는 문제였다.<br />5. 네트워크와 관련된 부분은 이번에 code를 손댄 적이 없다.<br />6. 같은 API 서비스를 이용하는 또 다른 app은 문제없이 구동되고 있다.<br /><br />흔한 오류 패턴은 아니었기 때문에 제일 먼저는 나의 실수인지를 체크했다.<br />잘 동작하고 있는 또 다른 app의 네트워크 부분과 diff 툴로 확인을 했지만 문제는 찾을 수가 없었다.<br /><br />따로 방법이 없다보니 adb의 로그를 봐야 했다.<br /><br />adb logcat -s Unity ActivityManager PackageManager dalvikvm DEBUG<br /><br />그리고 유의미해 보이는 로그를 찾았다.<br /><br />
<div>05-12 10:19:12.331 19641 19670 E Unity : java.io.IOException: Cleartext HTTP traffic to api.******.net not permitted</div>
<div>05-12 10:19:12.344 19641 19657 I Unity : ERROR: Unknown Error</div>
<div> </div>
저 'Cleartext HTTP traffic'라는 것이 생소해서 검색을 했더니, '안드로이드 9.0 파이(API level 28)'부터는 TLS 기반의 통신이 아니면 이 에러를 낸다고 한다.<br /><br /><a href="https://android-developers.googleblog.com/2018/04/protecting-users-with-tls-by-default-in.html">https://android-developers.googleblog.com/2018/04/protecting-users-with-tls-by-default-in.html</a><br /><br />즉, HTTP를 HTTPS로 바꾸어야 한다는 것인데, 그렇다고 당장에 server를 HTTPS로 바꾸는 것은 무리이다. 그리고 애시당초 내 쪽에서는 code를 손 댄 적이 없는데 발생하는 것이라서 더 원인을 알아 내야만 했다.<br /><br />일단 1차적인 원인을 제거하기 위해서 Unity - Project Setting - Player 쪽으로 가서 Android의 빌드 버전을 바꾸기로 했는데 거기서 문제의 원인을 찾았다.<br />Android의 SDK가 다른 PC와의 작업을 위해서 Target API Level을 Automatic(highest installed) 로 했는데 그것이 문제였다.<br /><br />최근에, Unity의 개발과는 별도로 또 다른 Android project를 위해 Android Studio를 업그레이드 하고 SDK도 가장 최신인 Pie를 추가로 설치했는데 이것이 문제의 발단이다.<br />원래는 제일 높은 버전이 27이었지만, 이 작업으로 인해 제일 높은 버전이 28로 바뀌게 되었고, Unity의 app을 Android용으로 재빌드를 하는 순간 API level 28이 적용되어 버린 것이었다.<br />
<div> </div>
<div class="imageblock center" style="text-align: center; clear: both;"><img src="http://smgal.ismine.net/tc_191/attach/1/1394883733.png" alt="사용자 삽입 이미지" height="223" width="324" /></div>결국 가장 빠른 문제 해결인 다음의 방법으로 해결하였다.<br />
<div style="text-align: left;"> </div>
<div class="imageblock center" style="text-align: center; clear: both;"><img src="http://smgal.ismine.net/tc_191/attach/1/1325131621.png" alt="사용자 삽입 이미지" height="296" width="470" /></div><p><strong><a href="http://smgal.ismine.net/tc_191/blog1/51?commentInput=true#entry51WriteComment">댓글 쓰기</a></strong></p>
기어2S의 Watchface 제작
안영기
http://smgal.ismine.net/tc_191/blog1/48
2015-10-05T23:43:44+09:00
2015-10-05T23:36:25+09:00
<span style="color: #ff0000;"><strong>(본문 내용은 추후에 넣을 예정)</strong></span><br /><br />Tizen 2.3.1 SDK의 wearable profile에는 Watchface App이라는 app 타입을 만들 수 있다.<br /><br /><<Watchface app으로 등록>><br /><div class="imageblock left" style="float: left; margin-right: 10px;"><img src="http://smgal.ismine.net/tc_191/attach/1/1181952125.jpg" alt="사용자 삽입 이미지" height="470" width="470" /></div><br />
<div><br /><br /><br /><br /><br /><br /></div>
<div><br /><br /><br /><br /><br /><br /></div>
<div><br /><br /><br /><br /><br /><br /></div>
<div><br /><br /><br /><br /><br /><br /></div>
<div><br /><<일반 상태의 시간 출력>><br /><div class="imageblock left" style="float: left; margin-right: 10px;"><img src="http://smgal.ismine.net/tc_191/attach/1/1229369480.jpg" alt="사용자 삽입 이미지" height="470" width="470" /></div><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><span style="line-height: 20.4px;"><<Ambient 모드의 시간 출력>><br /><div class="imageblock left" style="float: left; margin-right: 10px;"><img src="http://smgal.ismine.net/tc_191/attach/1/1289703880.jpg" alt="사용자 삽입 이미지" height="470" width="470" /></div><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />만드는 방법은 다음의 소스를 참고하면 된다.<br /><div class="imageblock left" style="float: left; margin-right: 10px;"><a class="extensionIcon" href="http://smgal.ismine.net/tc_191/blog1/attachment/1309155579.7z"><img src="http://smgal.ismine.net/tc_191/resources/image/extension/unknown.gif" alt="" /> smwatch_151005a.7z</a><p class="cap1">다운로드 (451K)</p></div><br /><br /></span></div><p><strong><a href="http://smgal.ismine.net/tc_191/blog1/48?commentInput=true#entry48WriteComment">댓글 쓰기</a></strong></p>