2025년 11월 14일 금요일

쌀-프리 도시락 그리고 아두화상(Ardu和尙)

오전에 직원 채용을 위한 면접 자리에 갔다가 무세포(cell-free) 단백질 발현 시스템에 관한 이야기를 들었다. 대학원 시절에 토끼의 망상적혈구(reticulocyte) 추출물을 이용한 cell-free translation system으로 실험을 했던 기억이 떠올랐다.

면접을 마치고 위원들에게 점심 도시락이 제공되었다. 뚜껑을 열어 보니 밥이 보이지 않는다. 나중에 발견한 것이었지만 김밥과 유부초밥과 같은 형태로 가려져 있었기 때문에 즉시 눈에 뜨이지 않았던 것이다.

"흠, 셀-프리 이야기를 듣다 보니 쌀-프리(free) 도시락인 줄 알았어요"

탄수화물이 좋지 않다는 정보가 워낙 넘쳐나는 세상이라 쌀이나 빵과 같이 정제 탄수화물에 가까운 음식을 되도록 배제하면 좋을 것만 같다. 이런 점을 배려한 것이라 생각하고 농담을 던졌다.

...

어제 출장차 김천을 들른 김에 황악산(최고봉은 1,111m의 비로봉) 입구에 자리잡은 직지사를 방문하였다. 직지사는 아도화상(阿道和尙)이 창건하였다고 한다. '화상'은 승려에 대한 존칭의 하나라는 것을 얼마전 청주 고인쇄박물관의 해설사를 통해 알게 되었다. 

  • 선사: 선수행을 오래한 스님
  • 율사: 계율 공부와 지계에 철저한 스님
  • 강백: 교학·경전에 매진한 스님
  • 종사: 종파를 계승·발전 시킨 스님
  • 화상: 계를 내려주신 스승(스님들이 사용)
  • 대사: ‘큰스님’으로 풀어 사용 [출처 : 법보신문(https://www.beopbo.com)]

아도는 신라에 최초로 불교를 전한 사람으로 알려져 있다. 하지만 자료에 의하면 아도는 어느 한 명을 특정할 수 없는 이름이라는 견해도 있다. 직지사는 418년 아도화상에 의해 창건되었으며, 구미 도리사에 이어 신라에 세워진 두 번째 절이라고 하는데...

'아도화상'을 되뇌다가 요즘 내가 한창 몰두하고 있는 '아두이노(Arduino)'를 떠올렸다. 아도, 아두... 아두화상(Ardu和尙)! 별명으로 아주 적당한 것 같다.

아두이노 나노를 이용한 DIY에 열중인 아두화상(Ardu和尙).

그래서 Nano Ardule Drum Pattern Player는 어떻게 되어 가고 있는가?

이렇게 어려운 일이 될 것임을 미리 알았더라면 아마 시작을 하지 않았을 것이다. 클래식 아두이노 나노보다 성능이 더 좋은 아두이노 나노 에브리로 바꿈으로써 최종 목적을 향해 가까이 가고 있지만, 같은 실수를 반복하는 챗GPT를 잘 달래 가면서 더 나은 스케치(.ino)를 만드는 것이 참 어렵다. 요즘은 중간 단계 문서를 만들어 저장하고 이를 다시 업로드하면서 아주 구체적으로 추가 기능을 요구하고 있다. 다시 말해서 일종의 설계 요약문와 바로 직전 버전의 스케치를 같이 업로드한 다음 개선된 스케치를 다운로드하게 요청하는 것이다.

Nano Ardule 드럼 패턴 플레이어는 특별한 파이썬 스크립트를 써서 드럼 연주 정보가 담긴 type 0 MIDI 파일을 2-bar 단위의 패턴으로 잘라서 SD카드에 장르별로 저장한 뒤(ROCK_P01.MID, ROCK_P02.MID...) 원하는 것을 선택하여 반복 재생을 하는 것을 기본으로 하고 있다. 이외에도 비상용으로 사용하기 위하여 드럼 패턴을 그리드화하는 초소형 자료 체계(Ardule Drum Pattern, ADP)를 만들어 놓기까지 하였다. MIDI 파일을 이용할 경우에는 음악적 표현력을 최대한으로 유지할 수 있다. 그러나 두 마디가 끝난 뒤 다시 처음으로 돌아가 재생을 반복할 때, 타이밍이 잘 맞지 않아서 무척 애를 먹었다. MIDI 데이터는 근본적으로 이전 이벤트로부터 지정된 시간(이를 '델타 타임'이라고 함)이 지난 뒤 다음 이벤트를 처리하게 설계되어 있다고 한다. 따라서 마지막 노트 뒤 '쉼표'에 해당하는 것이 마디의 끝에 딱 맞게 채워지지 않은 상태로 패턴이 끝나면, 조금씩 앞으로 당겨지는 일이 발생한다. 영화 <위플래쉬>에서 프레처 교수가 마일스를 무섭게 쏘아붙이던 질문, 'Rushing or dragging?'이 생각나는 순간이다. 지금까지의 스케치는 계속 rushing이었기 때문이다.

많은 노력 끝에 델타-타임이 아니라 절대시간에 기반한 루프 재생 개념을 수립하고 스케치로 구현하게 되었다. 이를 자동 생성된 문서로 정리하였다.

Absolute-Time Loop Playback(절대시간 기반 루프 재생) <- GenoGlobe.com 위키 

그러나 나를 몇 달 동안이나 괴롭히던 여전히 '당겨짐' 현상이 없어지지 않았다. 반복 시작 지점에서 템포가 빨라진다고 아무리 텍스트 입력으로 설명해 봐도 소용이 없었다. 고민 끝에 현재 재생되는 결과물을 녹음하여 파일로 만든 후 업로드하니 훨씬 정확한 분석이 이루어졌고, 구체적인 개선 포인트가 드러나는 것 같다. 약 120~130msec 정도의 rush가 분명히 존재하였고, 빠른 점검에 의하면 기존 스케치에는 분명히 오차가 발생할 소지가 있다고 하였다.

한 박자에 해당하는 피크 사이의 간격이 유난히 좁은 곳이 있다. 두꺼운 세로선으로 해당 위치를 표시하였다. 2-bar 패턴의 재생이 끝나고 다음 회차로 넘어가는 순간이다.

모든 분석이 끝난 뒤 챗GPT도 기존 코드의 문제점을 순순히 인정하였다. 개선된 코드에서는 이러한 rush 현상이 완전히 사라졌다. 위 GenoGlobe.com 위키의 문서에 다음의 내용을 추가하였다.

3-1. 절대시간 방식에서도 “루프 길이를 정확히 정의하는 것”이 중요하다

절대시간 기반 루프 엔진은 이벤트 재생 자체에는 오차가 없다. 그러나 루프 전체 구간(loopLength)을 잘못 정의하면, 루프를 반복할 때마다 시작점이 당겨지거나 늦어지는 문제가 발생할 수 있다.

특히 MIDI 패턴에서:

마지막 노트의 절대 tick(absTicks)은 “패턴이 끝나는 지점”이 아니라 마지막 노트가 있는 지점이다. 마지막 노트 뒤에 존재하는 음악적 ‘쉼(rest)’ 구간은 absTicks에 포함되지 않음. 따라서 absTicks를 loopLength로 사용하면 실제 루프가 원래보다 짧아진다. 이 경우 반복할 때마다 루프 시작점이 일정한 양만큼 앞당겨져 rushing이 발생한다.

이를 방지하려면 루프 길이를 다음처럼 고정 그리드로 정의해야 한다:

loopLengthTicks = PPQ × beatsPerBar × numberOfBars
예: 480 × 4 × 2 = 3840 ticks

이렇게 하면 패턴의 내용과 무관하게 항상 정확히 동일한 길이의 루프가 만들어지고, 완전히 안정적인 반복이 가능해진다.

Nano Ardule을 개발하면서 정말 오랫동안 나를 괴롭혔던 문제를 해결하였다. 집에서 사용할 모니터를 새로 구입한 후 생산성이 절대적으로 높아졌음을 느낀다. 


2025년 11월 13일 목요일

자벌레를 건드리면 일어나는 일

열심히 갈 길을 가는 자벌레를 건드리면?



화를 내는 것도 아니고, 부풀어 오르는 것도 아니다. 그저 몸을 꼿꼿이 세우고 나뭇가지인 척하다가 위험이 사라졌다고 판단하면 다시 제 갈 길을 열심히 간다.


자벌레는 자나방(geometrid moths)의 애벌레이다. Geometrid moth라! 기하학을 아주 잘 이해하는 나방 종류라고 해도 과언이 아니다. 영어로는 geometer moth라고도 하는데, geometer는 바로 'r기하학자'라는 뜻이다. 자나방과에 속하는 나방은 국내에만 무려 700종 가까이 확인되었다고 한다. 자벌레를 만난 곳, 가을이 깊어가는 김천 직지사는 정말 포근하고 아름다웠다. 4:3 비율의 사진은 펜탁스 Q10으로 찍은 것이다.

챗GPT가 그린 자벌레.




사명대사(泗溟大師, 법명은 유정, 1544-1610)로 더 많이 알려진 는 직지사에서 출가하고 18세 때에 승과에 장원 급제한 뒤 30세에 직자사의 주지가 되었다. 직지사 사명각.








2025년 11월 11일 화요일

LG FHD급 모니터(27U421A)의 새벽 배송

집에서 14인치급 노트북 컴퓨터을 펼쳐놓고 고개를 수그리고 일을 하는 것이 너무나 불편하여 제대로 된 모니터를 구입하기로 하였다. 쿠팡을 적당히 뒤져서 미개봉 반품된 LG전자의 27U421A라는 2025년도 출시 제품을  모니터 받침대와 함께 주문하였더니 새벽 배송으로 덜컥 도착하였다. 출근길을 재촉하는 입장에서 새벽 배송은 편리하지만, 누군가는 잠을 설쳐 가면서 노동을 한 댓가 아닐까. 비용을 지불하였으니 마땅히 내가 누려야 할 권리라고 생각하기 이전에 감사히 여길 일이다.

출근 전 바쁜 시간에 상자를 풀고 설치한 뒤 화면까지 나오는 것을 확인하였다.

상자를 뜯는 행위, 즉 언박싱(unboxing)은 언제나 가슴을 설레게 한다.


해상도는 FHD라서 노트북 컴퓨터(ThinkPad E14 G3)의 그것과 완전히 똑같다.


내 기억에 의하면 신품 모니터를 구입한 일은 거의 없다. 늘 주변에서 굴러다니던 것을 얻어서 쓰고는 했기 때문이다. 2024년 8월에 작성한 '집에서 일하기 위한 컴퓨터 활용 환경 정비하기'라는 글에 비교적 최근까지 사용하던 2007년 제조 LG Flatron L226WTP-PF에 대한 내용이 있다.

이 모니터의 해상도는 1920 x 1080(FHD), 최대 주사율은 100Hz, 픽셀피치 0.3114mm이다. 일반적인 사무용 모니터로 적당한 극히 평범한 사양을 갖추었다. 비슷한 가격대에서는 평면 혹은 곡면의 차이가 있는 것 같고, 20만원대 후반으로 가면 해상도가 2560 x 1440(QHD)으로 높아진다. 사무실에서 쓰는 삼성 모니터는 더욱 길쭉한 모양인데(아마도 울트라와이드?), 해상도는 3840 x 1200이다. 이번에 새로 구입한 모니터의 글씨가 좀 커 보인다 했더니 아마도 수직 해상도가 1080이라서 더 크게 느껴지는 것 같다. 사무실 모니터 중 우분투 데스크톱에 물린 것은 LG전자 32UN500인데, 이것은 3840 x 2160(4K/UHD)에 해당한다. 나열한 모니터 중 생각해 보니 '더 작은 글씨, 더 많은 정보'를 보여주었던 가장 마지막 것은 32인치 제품 아니었던가. 

구글 검색의 AI 개요('모니터 해상도 일람표').


[LG전자] 나에게 딱 맞는 모니터 구매 가이드 

10만원쯤 더 주고 27인치 모니터에서 얻을 수 있는 최대 해상도인 QHD급 모니터를 고를 것을 그랬나? 하지만 고해상도 영상 작업을 하는 것도 아니고, 현재 내가 갖고 있는 노트북에서 출력을 제대로 지원할지 알 수가 없다. 찾아보니 HDMI 출력에서 최대 4K를 지원하지만 주사율인 30Hz에 그친다. 주사율 60Hz가 되려면 USB-C 포트로 연결해야 된다고 한다. 주사율 문제는 차치하고서라도 작업을 위해서 단지 화면에 더 많은 창을 띄위기 위함이라면 고해상도일수록 좋은 선택일지 모르겠으나, 글씨가 작아지니 이를 가까이 보기 위해 고개를 더 수그리게 될지도 모른다. 

QHD 모니터의 주요 단점은 작은 아이콘과 글씨로 인한 불편함, 고화질 영상 시청 시 화질 열화 현상, 그리고 게임 시 더 높은 그래픽 성능 요구입니다. 27인치 모니터의 경우 QHD 해상도를 기본 설정으로 사용하면 아이콘과 글자가 작게 보여 불편할 수 있으며, FHD 이하의 영상을 QHD 모니터에서 보면 화질 열화가 발생할 수 있습니다. 또한, QHD는 FHD보다 더 많은 픽셀을 처리해야 하므로 게임에서 더 높은 성능의 그래픽카드가 요구됩니다. (구글 검색의 AI 개요 'QHD 모니터 단점')

신속한 결정, 빠른 배송, 그리고 출근 전 '후다닥' 설치 후 테스트! 이것으로 만족한다.


2025년 11월 10일 월요일

가깝고도 먼 나라, 중국

블로그에 글을 쓰는 도중 대부분이 날아가는 일을 최근 두 차례 경험하였다. 이번 글도 마찬가지. 갑자기 의욕이 떨어진다. 가끔씩 저장 버튼을 눌러야 되겠다.

상하이 출장을 계기로 중국에 대한 관심이 더욱 높아졌다. 좋은 면에서든, 또는 그렇지 않은 면에서든. 중국을 알아야 한다고, 우리의 미래는 중국(과의 관계)에 있다고 시간만 되면 역설하시던 어느 원로 생명과학자가 떠오른다. 그런데 몇 살부터 원로라고 부를 수 있는 것일까?

원로(元老)는 누구인가? - 건치 2025년 2월 12일 

'원로는 꽃이 아닌 거름이 되어라. 입을 닫고 지갑을 열자.'는 글귀가 매우 인상적이다.

어떤 이에게 중국(또는 베이징)은 다시 가고 싶지 않은 곳이었다고 한다. 이토록 늦은 나이에 처음으로 가게 된 중국 방문지가 상하이였다는 것은 나로서는 매우 다행일 수도 있다. 왜냐하면 상하이는 기대한 것 이상으로 활기가 넘치고 현대적이었으며, 또 깨끗했기 때문이다. 미국에 비유한다면 상하이는 뉴욕에 해당한다. 모든 곳에서 QR 코드 스캔을 이용한 정보 제공 및 결제를 하도록 만들어 놓은 것도 놀라웠다. 이는 상하이가 아니라 중국 전역에 해당할 것이다. 비록 횡단보도를 건너는 보행자에 대한 오토바이 또는 자전거 운전자의 배려는 조금 미흡했지만. 

11월 7일에 쓴 글 '푸단대학에서 보내는 첫날 밤'이 이번 여행을 소개하는 첫 글에 해당한다. 지금 와서 고백하는 것이지만 이번에는 바쁘다는 핑계로 출장지(그리고 국가)에 대한 사전 조사가 너무 미흡했다. 이는 방문지에 대한 예의가 아니다. 아니, 그로 인해서 여행자 자신도 불편해진다.

멀리 상하이의 랜드마크인 동방명주(東方明珠)가 보인다. 실은 높이 468미터에 이르는 송신탑이다.

상하이 중심가에서 만난 현대적인 빌딩과 쇼핑센터는 마치 내가 서울 강남 한복판을 거니는 느낌을 주었다. 거리를 다니는 대부분의 차량은 오토바이를 포함하여 전기로 구동되는 것이었다. 그런 탓인지 공기는 한국의 웬만한 대도시보다 더욱 깨끗한 것 같았다. 하루 종일 입은 흰 셔츠의 옷깃에 별로 때가 타지 않을 정도였으니 말이다. 

곳곳에 스타벅스 매장이 있지만 토종 브랜드에 밀려 직영 체제를 포기하게 되었다. 관련 기사는 여기에서.



중국 토종 브랜드 루이신(Luckin) 커피. 현재는 스타벅스를 능가하였다.

우리가 정보(information)라고 쓰는 단어를 중국에서는 신식(信息)이라고 표기한다. 중국에서는 오직 '인텔리전스'(주로 첩보 활동과 관계된)만을 정보라 부른다고 한다. 같은 한자어 문화권 안에서도 이렇게 단어의 쓰임새가 다르다.

무엇보다 놀라운 것은 이번 학술행사에 초대된 외국인 손님을 맞는 현지 과학자들의 극진한 정성이었다. 요즘 우리나라 같으면 상상하기 어려울 정도라도 느껴질 정도로 학생들을 동원하여 편의를 보살펴 주었다. 숙소와 음식도 모두 만족스러웠다. 조금 미안한 이야기지만 한국 참가자 중 VIP급으로 취급되어 이런 대접을 받았을 수도 있다. 다음에 우리가 주최국이 되면, 우리도 이에 상응하는 손님 맞이를 해야 되겠다는 부담감이 들 정도로 말이다.

이러한 접대 문화는 '꽌시(關系)'의 한 표현일 수도 있다. 이에 따라서 누구에게나 나 보편적으로 적용되는 규칙보다 지인을 통해서 일을 처리하는 것이 더 빠르다고 설명들을 한다. 물론 실용적이고 개방적인 성향이 강하며 계약 정신이 투철한 상하이에서는 베이징만큼 꽌시 문화가 강하지 않다는 말을 이번 행사에 참석한 조선족 과학자로부터 들었다. 여기서 잠깐, 우리나라에서는 조선족이라는 말을 부정적의미를 갖는 것으로 받아들이기 쉬운데, 이 말을 한 사람이 직접 자신을 조선족이라고 소개했기 때문에 큰 주저함 없이 그대로 옮겼다.

점심 때 나를 몹시 힘들게 했던 마오타이주. 만찬 자리에서는 또 다른 술이 나를 기다리고 있었다. '라이라이라이(来来来)'를 외친 것은 중국인이 아니고 우리측이었다.

이러한 친절함 속에 다른 속내가 있다고 경계하는 목소리도 있을 법하다. 어쩌면 학계에서 친중적인 사람을 많이 확보하려는 '공정(工程)'의 일환일지도? 난 그렇게까지 심각하게 생각하고 싶지는 않다. 사람으로 태어나서 어쩌다가 국적이라는 타이틀을 달고 살게 되었지만, 인류애라는 보편적인 정서의 발로라고 생각하고 싶다.



최근 중국의 과학기술 및 산업 발전은 놀라울 정도이다. 당과 국가가 일체가 된 시스템은 놀라운 응집력을 발휘한다. 그러는 중에 신사답지 못한 행동을 하기도 한다. 들은 말에 의하면, 중국 사람들은 이러한 행동을 모두 '애국'의 실천으로 여긴다고 한다. 물론 약간은 과장이겠으나, 공작원이나 할 만한 일을 일반인도 기꺼이 한다는... 놀라운 성과를 이루어 낸 중국 특유의 혁신 시스템을 부러워하다가도 그 어딘가에는 어두운 구석이 반드시 있을 것으로 여기고 이를 비판하려는 상반된 시각이 상존한다. 

모든 것에 속셈과 음모가 있으리라고 생각하지는 말자. 어디나 다 사람이 사는 곳이기 때문이다. 다음에 중국에 또 가게 된다면, 모바일 결제 시스템에 대해서 조금 더 알아보고 가기로 한다. 상점에서 제시하는 QR 코드를 내가 스캔하는 것보다 내 휴대폰에 표시된 QR 코드를 내어 놓는 것이 결제하기에 더욱 수월하였다. 전 세계적으로 통용되는 신용카드가 중국에서도 잘 통한다면 더욱 좋을 것이라는 아쉬운 점이 남는다.

어느 나라, 문화든지 다양성이 존재한다. 겨우 상하이 한 번 가 보았다고 하여 어찌 감히 중국을 이해했다고 볼 수 있겠는가. Quora의 글 '상하이와 베이징의 차이점은 무엇인가요?'가 중국 내 핵심 지역 두 곳이 얼마나 다른지에 대해 좋은 정보를 제공한다. 이번 방문을 계기로 중국 이해의 첫 걸음을 떼었다고 생각하면 좋을 것이다. 두 달 공부하고 말았던 중국어를 다시 익히고 싶어졌다.

2025년 11월 7일 금요일

푸단대학에서 보내는 첫날 밤

제22회를 맞는 CJK(China-Japan-Korea) Bioinformatics Symposium을 참석하기 위해 해외 출장을 오게 되었다. 이번 공무 출장은 생애 최초의 중국 방문이기도 하다. 공항철도 김포공항역에서 내려 국내선과 정반대 방향에 위치한 국제선을 타 본 것도 처음이다. 인천공항이나 김포공항 국내선보다 사람이 적어서 좋았다. 무빙워크가 수리 중이라 한참을 걸어야 했지만. 

두 시간도 걸리지 않는 운항 시간에도 불구하고 식사가 나오는 것도 미처 몰랐다. 그저 음료수 정도만 줄 것으로 생각했으까. 국제선이라서 그런 것일까? 일본 여행 때는 어땠었는지 잘 기억이 나지 않는다.

 


지금 머무는 곳은 상하이에 위치한 푸단대학 한단 캠퍼스 안의 Fudan Qing Yun Hotel이다. 



푸단대학의 '푸단'은《상서대전 우하전(尙書大傳 虞下傳)》 중에서 "일월광화 단복단혜(日月光華, 旦復旦兮) (해와 달이 빛남이여, 환하고 또 환하도다)"라는 명언에서 차용하였다 - 나무위키


중국에서는 구글 서비스가 안된다고 하지만, 로밍을 해 가면 문제가 없다. 호텔에서 잡은 구글맵 화면. 로밍 상태에서는 카카오톡도 잘 된다.
 

CJK 생명정보학 심포지엄은 한-중-일 세 나라가 번갈아 가면서 개최한다. 아주 처음(2002년)에는 한-일 생명정보학 트레이닝 코스로 시작하였다가 2006년 중국이 합류하였고, 지금은 교육 행사 성격은 많이 사라졌다. 30~40명 정도의 소수가 모이는 생명정보학 분야의 학술행사로서 아직까지는 참가비가 없다. 따라서 개최국에서 장소와 숙식을 제공하는 것이 전통이다. 코로나 시기에는 온라인으로 개최를 하기도 하였고, 최근 몇 년 동안은 개최 순서가 약간 흐트려졌다. 중국에서 개최하면 CJK, 한국에서 개최하면 KCJ, 일본에서 개최하면 JKC로 부른다. 공식 명칭은 알파벳 순서대로 CJK Bioinformatics Synposium. 한때는 ABC(Asian Bioinformatics Consortium)이라고도 불렸는데, 올해에는 다시 CJK로 되돌아갔다. 나 개인적으로는 처음 참석하였다. 이번 제22차 행사의 프로그램 및 초록 등은 인터넷에 공개된 The 22nd CJK Bioinformatics Conference Handbook에서 참조할 수 있다.

푸단대학은 중국 3위, 세계 30위의 우수한 대학이다. 이런 대학의 인재들이 교문 앞에서 호텔까지 가방을 끌어 주어 미안할 지경이었다.

상하이 홍차오 공항에서.


인터넷이 잘 되는지, 신용카드나 현금은 잘 통하지 않는다는데 결제는 도대체 어떻게 해야 하는지 걱정이 많았다. 그러나 휴대폰 로밍을 해 오니 별다른 문제가 없었다. 휴대폰에서 핫스팟을 설정한 뒤 노트북 컴퓨터를 연결하여 연구소 인트라넷에 접속, 문서 결재를 하는 것도 평소와 다르지 않았다. 아직 현지에서 물건을 살 일은 없었는데, 네이버페이나 카카오페이에서 유니온페이 또는 알리페이 플러스가 된다고 하니 별 걱정을 하지 않는다. 알리페이 앱을 정식으로 깔게 되면 외국인의 경우 여권 사진을 찍어서 인증을 해야 한다는데, 운이 나쁘면 삼일씩 걸리기도 한단다.

22년이라면 결코 짧은 기간이 아니다. 환영 리셉션 후 내년의 개최지를 논의하는 회의에서 이 행사의 의미를 생각해 보았다. KOBIC의 황승우 박사를 비롯하여 이러한 역사를 일구어 온 세 나라의 고참 과학자들의 노고를 높이 사고 싶다. 특히 중국은 생명정보학 관련 컨퍼런스가 너무나 많아서, CJK 생명정보학 심포지엄의 성격을 어떻게 유지해 나가야 하는지 많은 고민을 하고 있는 것 같다. 개최국에서 숙식을 제공하여 오던 전통도 실은 많은 부담이 된다. 실비 수준의 참가비를 받는 것도 생각해 볼 일이다. 적은 수의 사람이 모여서 친목을 다지는 밀도 깊은 학술행사 성격을 유지하는 것이 오히려 좋은 CJK 생명정보학 심포지엄만의 특성이 될 수 있을 것으로 본다.

학술행사가 열렸던 Guanghua Tower. 푸단대학의 랜드마크라고 한다. 대학 설립 120년을 기념하는 조형물이 보인다. 이 건물의 저층부는 마치 카페와 같은 느낌이다. 바깥이 잘 내다보이는 테이블에 학생들이 앉아서 저마다 뭔가를 들여다보고 있었다.


"갈까 말까 할 때는 가라"는 말이 있다. 이번 출장은 이웃 나라인 중국에 대한 이해를 높이는 좋은 기회가 될 것으로 본다. 

 다음의 유뷰트 쇼츠 영상 'Visiting Fudan University'는 한국에 돌아온 뒤 만든 것이다.


상하이를 떠나기 전 공항 면세점에서 여행 기념품으로 뭘 살까 고민하던 과정도 쇼츠로 담았다.





2025년 11월 2일 일요일

펜탁스 Q10과 함께 한 전주 나들이

펜탁스 Q10과 여분의 배터리를 챙겨서 가을의 분위기가 물씬 나는 전주 한옥마을을 다녀왔다. 한동안 잊고 있었던 조작법을 기억에서 다시 되살리는 기분이다. 작고 가벼우니 가방속에 쑤셔넣거나 늘 목에 걸고 다녀도 전혀 부담이 없다. 화면은 크기나 밝기 등 모든 면에서 스마트폰의 그것보다 나을 것이 없다. 밝은 야외에서는 도대체 잘 보이지 않는다. 그렇지만 화면 터치가 아니라 하드웨어 버튼과 휠에 의한 '조작'의 재미가 있으며, 촬영 후 화상에 이리저리 효과를 주면서 즐거움을 더할 수 있다.

아직 전주향교의 은행잎은 노랗게 물들지 않았다. 유난히 길고 더웠던 여름이 지금까지 영향을 미치고 있는 듯하다.

"극채색" 효과에 의해서 자동차와 단풍잎의 색조가 잘 대비된다. 집을 떠나기 직전.

중이 제 머리 못 깍는다고, 이것과 바로 다음 사진은 휴대폰으로 찍은 것. 찍은 사진을 구글 포토에 옮기고 나서 어느 카메라로 찍었는지 가장 쉽게 확인하는 방법은 종횡비율이다. 4:3이면 Q10, 16:9면 스마트폰. 







예쁜 골목의 모습을 수채화로 그리는 젊은 여성이 있었다.



최명희 문학관 앞에서. 보수 중이라 문을 닫았다.


누군가 잊어버리고 간 물건. 아침까지 내린 비로 젖은 것을 보니 아마도 며칠 동안 이 자리에 있었던 것 같다. 담배가 거의 꽉 차 있었는데...

영화의거리까지 걸어가서 조이앤시네마에서 영화 "빅 볼드 뷰티풀(원제: A Big Bold Beautiful Journey)를 보았다. 넓은 객석에는 우리 부부를 포함하여 단 네 사람밖에 없었다. 영화관의 팝콘이란 원래 쏟거나 남기라고 만든 것.

영화가 끝난 뒤 저녁을 먹고 나서 객사길을 걷다. 야경은 SCN 모드에서 있다는 것을 기억하지 못해서 프로그램 모드에서 -1.3스톱 줄여서 촬영해 보았다.

다음은 동영상 촬영 결과물이다. 쇼츠 형태, 즉 세로 포맷으로 바꾸려면 오픈샷 비디오 에디터 작업을 해야 한다.


렌즈에 햇빛이 직접 닿으면 화질이 좋을 수가 없다. 


출시된지 이미 십여 년이 훌쩍 지난 펜탁스 Q10의 센서(이면조사형 CMOS) 크기는 1/2.3인치로 갤럭시 S23의 1/1.56인치보다 작다. 소형 경량화를 위한 어쩔 수 없는 선택이었을 것이며, 대신 당시로서는 활용도가 높은 아기자기한 기능을 많이 넣은 것으로 알고 있다. 즉, 진지하고 사실적인 기록을 위한 사진기라기보다는 '재미'를 위한 사진기라고 보는 것이 타당하다. 여행길에 가볍게 들고 다닐 수 있는.

캐논 EOS 500D는 언제나 되어야 펜탁스 Q10만큼의 관심을 받게 될런지 알 수가 없다. 아마 집에서 동영상을 찍어야 할 때나 쓰게 될 것 같다.

2025년 10월 31일 금요일

펜탁스 Q10으로 담은 도심의 가을 풍경

되살아난 펜탁스 Q10을 들고 서울 출장을 다녀왔다. 워낙 작고 가벼워서 휴대하는데 별다른 부담이 없다. 남대문 근처의 풍경을 몇 장 찍어서 콜라주를 만들었다. 일부 사진은 '극채색' 효과를 넣어 보았다.


HDR(High Dynamic Range) 기능은 스마트폰을 따라갈 수 없다. 하지만 필름 카메라 시절을 생각해 본다면, 한 화면 내에서 밝은 곳이 완전히 날아가는 것을 감내하지 않았던가.

마침 쿠팡에 주문했던 40.5mm 렌즈캡도 도착하였다. 앞으로 어딜 다니든지 갖고 다니면서 잘 활용해 볼 생각이다. 


아두이노 나노 에브리(왼쪽; ATmega4809)와 아두이노 나노(ATmega328P) 호환보드.

 

얼마 전에 구입해 놓았던 아두이노 나노 에브리에 핀 헤더를 납땜하였다. 그런데 컴퓨터에 연결할 방법이 없다. 아두이노 나노에서 쓰이는 USB mini B도 아니고, 휴대폰에 쓰이는 USB-C도 아니다. 아... 휴대폰 생태계에서 퇴출되었던 마이크로 5핀 타입(micro type B)인 것 같다. 라즈베리파이 3B의 전원 커넥터에도 쓰이던 썼던 바로 그것.  그러나 갖고 있는 케이블을 연결해 보니 Arduino IDE에서 인식이 되지 않는다. 케이블이 고장났거나, 또는 충전 전용 케이블이거나. 쿠팡에서 케이블을 새로 주문하였다. USB 커넥터의 다양한 타입에 대해서는 나무위키의 그림 자료(링크)를 확인해 보자.


2025년 10월 30일 목요일

[Nano Ardule] MIDI 파일 재생기를 만들기가 이렇게 어렵다니...

그림 자료를 곁들여 꽤 긴 글을 쓰고 있었는데 순식간에 날아가 버렸다. 키보드를 잘못 건드린 것도 없는데 도대체 무슨 일이 벌어진 것일까? 시스템 또는 서비스의 일시적인 문제라고 믿기로 했다. 지금까지 이런 일은 없었기 때문이다.

Nano Adrule MIDI controller는 키보드 컨트롤러와 사운드 모듈 사이에 위치하여 음색을 바꾸거나 레이어 또는 스플릿을 하기 위한 목적으로 만든 것이다. 여기서 말하는 사운드 모듈은 디스플레이나 조절 기능이 없이 아주 단순한 구조로 된 것을 뜻한다. 즉, 노래방 반주기에서 적출한 도터보드 형태의 것을 포함한다.

내놓기 민망한 수준으로 회로를 꾸미고 아두이노를 제어하기 위한 스케치(.ino) 파일을 만들어 소기의 목적을 달성하는 데에는 성공하였다. 이 과정에서 챗GPT가 큰 기여를 하였다. 처음에는 마이크로SD카드에 저장한 type 0 MIDI 파일을 재생하는 기능까지 넣으려고 했으나 아두이노 나노라는 제한된 '두뇌'에 펌웨어를 다 밀어넣기가 곤란하여 일단 기능을 분리하게 되었다. 아두이노 나노 호환보드와 아두이노 나노 에브리를 하나씩 갖고 있으니 각각에 대해여 서로 다른 기능의 펌웨어를 업로드해 놓은 뒤 필요에 따라 소켓에 바꿔 끼워 가면서 쓸 수도 있을 것이다.

그러나 안정적인 MIDI 파일 재생 기능을 구현하는 것이 키보드 컨트롤러의 보조 역할을 하는 것보다 훨씬 어렵다는 것을 알게 되었다. 마이크로SD카드에서 파일 목록을 얻는 것부터 쉽지 않았다. 실패를 반복하면서 거의 포기 상태로 한동안 손을 놓고 있다가 또다시 열정을 갖고 파고들기 시작하였다. 수없는 시행착오를 거쳐서 SD카드 접근용 라이브러리 SDFat를 선택하고, MIDI 파일명을 기록한 인덱스 파일(INDEX.TXT)을 통해서 개별 파일을 접근하는 등 최적화를 위해 할 일이 너무나 많았다. 단계별로 적용하여 재생 안정화에 기여한 대책을 정리해 보면 다음과 같다.

MIDI 파싱/타이밍(논리) 안정화

  • 러닝 스테이터스 규칙 고정: runningStatus는 오직 채널 보이스(0x80–0xEF)에서만 갱신.
  • 메타(0xFF)/SysEx(0xF0/0xF7) 이후에는 runningStatus를 건드리지 않음.
  • 프리롤 정합성: Δ=0 구간에서 메타·SysEx는 소비하되, 첫 채널 상태를 만나면 firstStatusPending = true, runningStatus = 해당 상태로 초기화 후 메인루프에 인계.
  • 데이터바이트 보호: runningStatus 없이 데이터바이트(<0x80) 등장 시 다음 상태바이트(≥0x80)까지 스캔하여 동기화(트랙 경계 내에서만).
  • 트랙 경계 가드: trackEndPos를 프리롤/메인루프/메타파서 전 구간에 적용하여 조기 EOT/읽기 초과 방지.
  • 절대시간 스케줄러: songStartMicros + tick*micro_per_tick 방식으로 이벤트 스케줄, Δ=0 클러스터도 순차 처리.

“버스트(폭주)” 완화/전송 안정화

  • 스타트 가드: 재생 시작 시 2비트(count-in) 지연 + 15ms 프리롤로 초기 버스트 완화.
  • TX 페이싱(옵션): parseMidiEvent() 끝에 delayMicroseconds(200~350) 삽입해 UART 과부하 예방.(권장값: 250µs. 문제 파일에서만 필요하면 컴파일 타임 옵션으로 관리)
  • 하드웨어 버퍼 대기(대안): 필요 시 Serial.write() 전에 UDRE 체크로 송신 버퍼 여유 확인.
SD 파일 접근 안정화
  • SPI 속도 보수화: SD.begin(CS, SD_SCK_MHZ(1)) 로 1 MHz로 시작(호환성↑).
  • 오픈 재시도 래퍼: sdSafeOpen()으로 최대 3회 재시도 후 실패 판정.
  • 고정 버퍼 라인리더: String 대신 char[] 버퍼 기반 readNextLine()로 CR/LF/CRLF, BOM(UTF-8) 처리.→ countIndexLines(), loadIndexPage() 모두 이 라인리더 사용.
  • INDEX 포맷 규칙: 8.3 파일명, 빈 줄/주석(#) 무시, 마지막 줄 개행 보장. 필요 시 PC에서 파이썬 스크립트로 BOM 제거 + 줄바꿈 통일.
UI/입력 안정화

  • 버튼 디바운스: 모든 버튼에 소프트 디바운스(약 18ms + 릴리즈 대기).
  • 인코더 스텝 고정: detent=2 기준(두 클릭=1스텝)으로 과다 이동 억제.
  • 방향 반전은 #define ENC_DIR_INVERT 한 줄로 토글.
  • 표시 정렬: Vol/BPM/Reb/Kit 숫자 3자리 고정(오른쪽 정렬)로 상태 확인 용이.

모듈/보드 특성 대응

  • /SONGS vs /DRUMS 분리: 
    • /SONGS: 원본 그대로 재생(초기 CC/PC 미전송) → 불필요한 설정 충돌 차단
    • /DRUMS: 시작 시 CH10에만 Volume/Reverb/DrumKit(PC) 전송(SAM9703는 PC만으로 킷 변경)
  • All Notes Off: 인코더 버튼 롱프레스로 긴급 음 끊김 방지.

나노 아두이노 설계를 시작할 때만 하더라도 이렇게 복잡하고 까다로운 난관을 타개해 나가야 할 것이라고는 전혀 생각하지 못하였다. PC에서 .mid 파일을 만나면 단순히 더블클릭만 해서 어쨌든 소리를 들을 수 있다. 하지만 아두이노는 그렇지 못하다. 예를 들어 C:\Windows\Media 폴더에 전통적으로 존재해 오던 ONESTOP.MID라는 약 4분 분량의 MIDI 파일을 보자. html-midi-player("Play and display MIDI files on the web")에 업로드하면 노트 정보의 시각화는 물론 재생까지 이루어진다. 이 는 다양한 악기가 여러 장르를 거쳐 연주되는 매우 수준 높은 MIDI 파일이다.

html-midi-player("Play and display MIDI files on the web")에 로드한 ONESTOP.MID 파일.

Nano Ardule은 이 파일을 재생하다가 1분이 되기 전에 타악기 소리를 와르르 쏟아내고는 멈춘다. 그 이유를 알기 위해서 문제가 일어난 구간의 MIDI 파일의 이벤트를 텍스트 형태로 출력한 뒤(챗GPT를 이용하여 이러한 용도의 파이썬 스크립트를 만들었음) 분석을 해 보았다. 이외에도 부수적으로 만든 파이썬 스크립트가 여럿 있다.

00:35:000 ~ 00:45:500 
Time(mm:ss:ms) | AbsTick | Δ? | Kind | Detail 
----------------+---------+----+--------+-------------------------------------- 
00:35:051 | 9125 | 0 | CHAN | NOTE_ON ch= 1 note= 72 vel= 0 
00:35:067 | 9129 | 4 | CHAN | NOTE_ON ch= 1 note= 74 vel= 64 
00:35:082 | 9133 | 4 | CHAN | NOTE_ON ch= 8 note= 72 vel= 0 
00:35:121 | 9143 | 10 | CHAN | NOTE_ON ch=12 note= 38 vel=115
...

분석 결론은 다음과 같았다. 핵심은 노트보다 컨트롤 메시지(특히 Pitch Bend, CC, Bank/PC)가 폭주하는 구간이 있다는 점이다.

  • Pitch Bend 홍수
  • Bank Select + Program Change의 동시 발생
  • Mode Wheel(CC#1), Volume(CC#7) 연속 변화
  • Δ=0/2/4 정도의 촘촘한 이벤트 다발

PC에서는 내부 버퍼·타임스탬프 큐·멀티스레드로 완충되지만, 아두이노는 UART 대역폭과 싱글 루프 때문에 그대로 내보내면 밀립니다.

오늘의 목표는 ONESTOP.MID 파일을 제대로 재생하게 만드는 것이다. 그 다음으로는 드럼 연주 데이터만 들어있는 MIDI 파일을 2-마디 패턴으로 분해한 뒤 반복 재생하거나. 또는 '패턴 체인' 형태를 만들어서 곡 전체에 해당하는 드럼 연주를 제공하는 것.

아두이노를 이용한 드럼 패턴 플레이어를 만들기 위해 많은 아이디어가 스쳐 지나갔다. 실은 구글에서 online drum machine이라고만 입력하여 검색을 해도 꽤 좋은 서비스가 많다. 하지만 나는 인터넷에 연결되지 않은 상태에서도 이동하면서 사용 가능한 드럼 패턴 플레이어를 원한다. 

2마디 단위의 드럼 패턴을 그리드 형태로 양자화한 파일(Ardule Drum Pattern System; 바이너리 파일은 .ADP, 사람이 이해하기 쉬운 텍스트 버전은 .APT)을 마이크로SD카드에 저장해 놓은 뒤 원하는 것을 골라서 반복 재생하는 방식을 비롯하여 MIDI 파일을 2마디 단위로 직접 쪼개서 별도의 파일로 저장한 다음 활용하는 것에 이르기까지 여러 방법의 가능성을 따져 보았다. ADP 체계는 마이크로SD카드 의 MIDI 파일 접근이 쉽지 않아 애를 먹던 시절, 아예 메모리에 저용량의 패턴 데이터를 담아 보려고 생각한 것이다. 코드에 넣어 두었다면 Flash(PROGMEM)을, SD에서 불러온 패턴이라면 SRAM(겨우 2KB!)를, 그리고 사용자 커스텀 패턴이라면 EEPROM(이건 겨우 1kb에 불과함)를 쓰려고 했었다.

텍스트 형태인 APT(Ardule Pattern Text)의 사례. 이는 설계 및 편집을 위한 저장용 포맷이고, 실제로 프로그램 내부에서는 바이너리 형태(ADP)로 저장하려고 계획하였다. 드럼 전용이라면 ADT라고 쓰는 것이 옳다.


챗GPT의 해결책에는 이해하기 어려운 전문적인 내용도 많다. 계속되는 질문과 대답 속에서 다음과 같은 방법으로 거의 구체화가 되어가고 있다.

  1. (PC) 드럼 연주 정보가 담긴 type 0 MIDI 파일을 2마디 단위의 패턴으로 나눈 뒤, 출현빈도 역순으로 정리한다. 하나의 MIDI 파일에서 유래한 각 패턴은 위치 정보와 MIDI 이벤트 형태로 묶어서 하나의 파일에 정리한다. 이를 self-contained multi-ADT(.MAD)라고 부르기로 한다.
  2. MAD 파일의 뒷부분에는 완성된 곡 형태의 ARR 데이터를 담을 수 있다.
  3. (Nano Ardule) .MAD 파일을 읽어서 지정한 패턴의 반복 연주, 또는 ARR 데이터 연주를 실시한다.

초창기에는 ADP system을 고려하다가 표현력에 제한이 있으리라는 것을 이내 알게 되었다. 따라서 온전한 형태의 드럼 MIDI 파일을 아두이노에서 로드한 뒤 스캔하여 패턴 위치 및 빈도 정보를 추출한 뒤 이를 반복 재생하는 방법을 생각했었다. 그러나 서로 떨어진 위치의 패턴을 조합하여 체인을 만들기에는 아두이노에게 부담이 된다. 그래서 이러한 방식까지 진화하였다. .MAD의 개념 도입 초기에는 원본 MIDI 파일을 참조하는 방식을 생각했다가 생각을 바꾸었다. 하지만 ADP는 데모용 기본 리듬 등으로 활용할 가치가 있으니 아직 내다 버리지는 말도록 하자.

제안: multi-ADT 포맷 (권장 확장자: .MAD)

  • 파일명: FOO.MAD (8.3 호환)

  • 목적: 여러 2-bar 패턴 + 어레인지(패턴 번호/반복수) + 메타(템포, 드럼킷, 카운트-인) 모두 한 파일에.

  • 재생: 아두이노는 헤더의 오프셋 테이블을 읽어 패턴 위치로 즉시 seek끊김 없이 루프/점프.

바이너리 구조(간결 사양)

Offset Size Field 0x00 4 Magic = "MADT" 0x04 1 Version = 1 0x05 1 Flags (bit0=RAW-tick, bit1=GRID, bit2=HasTempoMap ...) 0x06 2 PPQN (e.g., 480) 0x08 2 Default BPM (for count-in; 곡 중 템포맵은 패턴 내 이벤트에 포함 가능) 0x0A 1 DrumKit PC (채널10 전제; 0=무시) 0x0B 1 CountIn Beats (2 or 4) 0x0C 2 PatternCount (N) 0x0E 2 ArrangeCount (M) // (패턴번호, 반복수) 개수 0x10 4*N PatternOffset[i] // 각 패턴 레코드의 파일 오프셋 ... 4*M ArrangePairs[j] // packed: (hi16=patternIndex, lo16=repeats) --- 각 패턴 레코드 --- PattHdr: +0 4 length_ticks (대개 2bar = 8*PPQN) +4 4 event_bytes (아래 이벤트 스트림 길이) +8 ? 이벤트 스트림 (델타-타임 + 미디메시지) Event Stream 인코딩(가볍고 빠르게): [VLQ delta] [Status or 0x00=running] [data1] [data2?] - 메타/시스엑스는 필요 시 스킵 가능 옵션(Flags) - 드럼 전용이면 CH10 메시지 위주로 간소화 가능

포인트: tick→byte 인덱스가 이미 파일 안에 내장되어 있어 패턴 시작 시 즉시 seek만 하면 됩니다.
템포가 바뀌는 패턴은 패턴 이벤트 안에 FF 51 03 메타를 넣어도 되고(Flags로 RAW모드), 대부분의 드럼 패턴은 고정 템포로 충분합니다.

텍스트 디버그 버전(선택): .MADT (사람 읽기용)

MADT, v=1, ppqn=480, bpm=120, kit=26, countin=2 PATTERN 1, len_ticks=3840 dt=0, 90 24 64 dt=120,90 2A 64 ... PATTERN 2, len_ticks=3840 ... ARR: 1x4,2x2,3x4,2x2,1x8

개발 단계에서 가독성↑ / 최종 배포는 .MAD 사용.


장점 요약

  • 무지연 점프/루프: 패턴 오프셋으로 즉시 seek → 카운트-인 동안 준비 끝.

  • 사이드카 정리: .MID + .PAT + .ARR한 파일로 통합.

  • 버스트 감소: 시작·전환부에 필요한 CC/PC/템포 이벤트를 패턴 전에 삽입해 둠.

  • 8.3 안전: FOO.MAD 하나로 끝.

설계를 구체화하기 위해 너무나 많은 문제와 해결책, 그리고 잘 모르던 개념 사이를 방황하고 다녔더니 이렇게라도 문서로 정리하지 않으면 다 잊어버릴 것만 같다.

MIDI와 오픈 사이언스를 연결할 수 있을까? 자동 생성으로 쓴 간단한 글 한편을 소개한다.

MIDI, 오픈 사이언스가 배워야 할 표준의 철학