2026년 10월 27일 화요일

이것이 1978년도 미슐랭 가이드(레드가이드) 실물이다

파주 헤이리 예술마을의 한 베이커리 카페(좋은날 189)에 갔다가 장식용으로 놓인 미슐랭 가이드 《MICHELIN Great Britain and Ireland 1978》를 발견하였다. 당시 미슐랭은 대략 France, Italia, Deutschland, Benelux, Suisse, España/Portugal, Great Britain & Ireland 같은 식으로 국가·권역별 Red Guide를 냈다고 한다. 좋은날 189는 치아바타를 주력으로 하고 있는 것 같았다.



한국 지사에서 사명을 '미쉐린'으로 정함에 따라서 공식 명칭도 미쉐린 가이드로 바뀌었다고 한다. 온라인 시대가 되었으니 이제는 이렇게 두꺼운 책을 찍어서 배포하지는 않을 것이다. 한국어판 온라인 가이드는 여기에 있다. 훌륭한 호텔이나 맛집을 찾아다닐 정도로 내가 여유로운 것은 아니지만, 어쩌다 한번은 사치를 부려도 되지 않을까?

EO1-Museum v0.3에서 비로소 웹브라우저의 굴레를 벗어나다

 


며칠 동안 붙들고 있던 Electric Objects EO1 되살리기 프로젝트가 어제 상당히 큰 고비를 넘었다. 처음에는 서비스가 종료되어 더 이상 쓸 수 없게 된 전자액자에 웹브라우저를 띄우고, PC에서 웹서버를 돌려 그림을 보내는 정도가 목표였다. 그런데 작업을 계속하다 보니 이제는 EO1 안에서 직접 돌아가는 전용 앱까지 만들게 되었다. 이름은 EO1-Museum이다.

처음 만든 방식은 매우 단순했다. PC에서 뉴욕 메트로폴리탄 미술관의 Open Access 작품을 내려받아 EO1 화면 크기에 맞게 가공하고, 웹페이지로 만든 뒤 HTTP 서버를 실행한다. EO1에서는 Firefox를 띄워 그 페이지를 보여주었다. 기본 웹브라우저에서는 시작 웹페이지를 지정하는 것이 어려웠다. 제조사가 서비스를 종료한 기기를 다시 그림 액자로 쓰는 데에는 이것만으로도 충분했다.

하지만 이 방식에는 분명한 한계가 있었다. PC가 계속 켜져 있어야 하고, 웹서버도 돌아가야 한다. 무엇보다 EO1이라는 기기가 스스로 그림을 보여주는 것이 아니라 사실상 PC가 만들어 주는 웹페이지를 원격 화면처럼 표시하는 셈이었다.

그래서 Android용 native gallery를 만들기 시작했다.

v0.1 — EO1 안에 그림을 넣다

JPEG와 PNG 파일을 EO1 내부 저장공간에 넣고 앱이 직접 읽어서 보여주는 것을 목표로 하였다. 미디어 파일은 다음 위치에 저장한다.

/sdcard/EO1-Museum/images/

앱은 이 디렉터리를 검색하여 그림 목록을 만들고 순서를 섞은 뒤 일정 시간마다 다음 작품으로 넘어간다. 이것이 성공하면서 EO1은 처음으로 PC와 완전히 분리된 상태에서도 다시 전자액자로 기능하게 되었다.

v0.2 — 동영상과 소리

다음 단계에서는 MP4 동영상도 같은 미디어 목록에 넣었다. 이미지가 나오다가 동영상 차례가 되면 전체 동영상을 재생하고, 끝나면 다시 다음 작품으로 넘어간다.

Bluetooth 오디오도 정상적으로 작동했다. 한번 페어링한 Bluetooth 장치는 재부팅 뒤에도 다시 연결되었다. 덕분에 EO1은 단순한 그림 액자를 넘어 이미지와 동영상을 함께 보여주는 미디어 디스플레이가 되었다. 오디오 기능은 겉으로 드러나지 않았던 것을 재확인한 것이라서 새로운 개발이 필요하지는 않았다. 소리가 포함된 동영상 재생에 매우 유용할 것이다.

v0.3 — 하나의 앱으로 합치다

어제 가장 큰 변화가 이루어졌다. 기존의 Local Gallery와 PC 기반 Gallery를 하나의 앱 안에 통합했기 때문이다.

PC Gallery를 선택하면 더 이상 Firefox를 실행하지 않는다. EO1-Museum 자체에 WebView를 넣어 PC에서 제공하는 gallery를 앱 안에서 직접 보여준다. 반대로 Local Gallery를 선택하면 EO1 내부에 저장된 이미지와 동영상을 표시한다.

마우스 오른쪽 버튼을 누르면 제어 메뉴가 열린다. 여기에서는 Local Gallery, PC Gallery, Next, Rescan Media, Clock On/Off를 제어할 수 있다. 현재 어떤 Gallery를 사용하고 있는지도 메뉴에서 확인할 수 있다.

이미지 사이에는 cross-fade 효과를 넣었고 화면에는 시계를 표시할 수 있게 했다. 새 파일을 ADB로 전송한 뒤에는 앱을 다시 시작하지 않고 Rescan Media만 선택하면 된다.

그리고 EO1-Museum을 Android의 HOME application으로 지정했다. 이제 전원을 넣으면 Android 바탕화면이나 원래 Electric Objects 프로그램을 거치지 않고 바로 EO1-Museum의 Local Gallery가 시작된다.

이 변화가 가장 마음에 든다. 전원을 넣고 잠시 기다리면 알아서 그림이나 동영상이 나온다. 전자액자는 원래 그래야 한다.

ADB를 여는 작은 열쇠

여기까지 오는 과정에서 의외로 중요한 역할을 한 것이 ADBApprovalHelper.apk였다.

EO1에 새 프로그램을 넣으려면 ADB를 사용하는 것이 가장 편하지만, 최초 USB 연결에서는 Android의 RSA debugging authorization을 통과해야 한다. EO1에서는 이런 시스템 대화상자를 다루는 것이 꽤 불편하다.

그래서 먼저 EO1의 내장 웹브라우저를 이용하여 ADBApprovalHelper.apk를 설치한다. 이때 PC에서는 APK가 Android application package임을 브라우저가 제대로 알아볼 수 있도록 MIME type을 설정한 server.py를 실행한다. ADBApprovalHelper.apk는 EO1 화면에 나타나는 인증 관련 화면에 자동으로 클릭을 해 준다. 이 화면은 ADB를 통해 PC가 연결된 상태에서만 나온다. PC가 host로 잡히기 때문에 중간에 USB hub를 끼운다 해도 마우스 포인터를 EO1에 나타나게 할 수 없다. 그래서 별도의 앱을 만드는 편법을 이용한 것이다.

Helper가 설치되고 USB ADB 연결이 확보되면 그다음부터는 일이 훨씬 쉬워진다. EO1-Museum APK 설치도, 이미지와 동영상 전송도 모두 ADB로 처리할 수 있다.

무선 ADB도 시험해 보았지만 정식 사용 방법에서는 제외하기로 했다. 연결 상태가 한번 꼬이면 오히려 복구하기가 번거롭다. 케이블을 꽂았다 빼야 하는 불편함이 있더라도 유지보수에는 USB ADB가 훨씬 명확하다.

버려진 기기에서 다시 하나의 제품으로

EO1-Museum v0.3까지 오면서 처음의 구조는 상당히 달라졌다.

예전에는

PC → HTTP server → Firefox → EO1 display

였다면 이제 기본 동작은

EO1-Museum → Local media → EO1 display

이다.

PC는 더 이상 필수가 아니다. 필요할 때만 PC Gallery를 선택해서 사용한다.

물론 아직 할 일이 조금 남아 있다. 현재 PC Gallery의 서버 주소는 프로그램에 들어 있으므로, 다음 버전에서는 화면에서 주소를 수정하고 저장할 수 있게 만들 생각이다. 설치 절차와 GitHub repository도 새 구조에 맞게 정리하고 있다.

그러나 기능적으로는 v0.3에서 이미 중요한 선을 넘었다고 생각한다.

2019년 무렵 우연히 얻었다가 제조사의 서비스 종료와 함께 사실상 쓸모를 잃었던 23인치 화면이 이제는 특정 회사의 서버도, 전용 앱도, 심지어 PC도 필요 없이 스스로 그림과 동영상을 보여준다.

처음에는 그저 고장 아닌 고장이 난 전자액자를 다시 켜 보자는 생각이었다.

그런데 어느새 전자액자에 새 프로그램을 만들어 넣고 있다. 이쯤 되면 '되살렸다'고 해도 되지 않을까.

2026년 10월 22일 목요일

긴급 PHP 취약점, 내 DokuWiki 웹사이트는 안전한가?


바로 어제, PHP 보안취약점(PHP2Shell)이 발견되어 웹사이트를 다루는 사람들은 바짝 긴장하지 않을 수 없게 되었다. 로그인 없이 외부에서 서버에 원하는 명령을 실행할 수 있는 매우 치명적인 취약점이라 한다.

PHP 보안취약점(PHP2Shell) 관련 기업 보안 대응 수칙 - KISA 보호나라

나는 호스팅어에서 DokuWiki를 설치하여 공식 웹사이트로 사용하고 있다. DokuWiki 자체는 꾸준히 업데이트를 해 왔었다. PHP 8.2.34는 업데이트 대상이라고 하던데...


직접 PHP를 업데이트해야 하는가? 호스팅어에 접속하여 에이전트 창에 다음과 같이 물어 보았다. 어쩌면 호스팅 업체의 기술진이 다 해 놓았을지도 모르는 일이니까 말이다.

I understand that the PHP 8.2.34 version currently running on my hosting account was built yesterday. However, I would like to confirm whether this build is vulnerable to the critical PHP security vulnerabilities disclosed recently. Could you please confirm whether your PHP 8.2.34 build includes the necessary security patches, even though the displayed version is still 8.2.34? If not, when will the patched version be deployed?

이에 대한 답변은 다음과 같다.

PHP 8.2.34 can already include the required security fix even though the displayed version remains 8.2.34. Hostinger added the protection to the existing PHP builds, and the managed-hosting rollout is complete; if your PHP Info → Build Date is October 21, 2026, or later, that build includes the fix for these vulnerabilities.

You do not need to wait for a newer version number or change PHP versions for this issue. Hostinger’s Security team could not reproduce the vulnerabilities in its managed hosting environment, and firewall protections block attack attempts across all PHP versions.

Read Hostinger’s official PHP2Shell update.

빌드 데이트가 2026년 10월 21일 이후라면 이번 취약점 패치가 적용된 것이고, PHP 버전은 8.2.34를 유지한다고 한다. 이번 보안 이슈에 대해서 상당히 발빠르게 대처함 셈이다. 다만 PHP 8.2는 올해 연말에 보안지원 종료이니, 해가 바뀌기 전에 8.3으로 올릴 것을 권장하고 있다.

만약 집에서 데스크톱 컴퓨터에 적당히 리눅스와 PHP를 설치해 서버를 운영하고 있었다면, 이번 사태에 어떻게 대처했어야 할까? 인터넷에 공개하지 않은 서버라면 그나마 느긋하게 대응할 수 있겠지만, 외부에 공개된 웹 서버라면 이야기가 완전히 달라진다. 취약점의 영향을 확인하고, 보안 패치가 나온 배포판 패키지를 찾아 업데이트하고, PHP와 웹 서버를 재시작하고, 혹시 그사이에 침입 흔적은 없었는지 로그까지 살펴야 한다. 실제 공격 시도가 패치 공개 전부터 나타난 이번 사태 같은 경우라면 정말 진땀나는 일이다. 이런 순간에는 약간의 비용을 들이더라도 서버의 보안과 업데이트를 전문가가 관리해 주는 상용 호스팅 서비스의 진가가 드러난다.

상황 종료!

2026년 10월 21일 수요일

EO1-Museum: USB 메모리를 포기하고 내부 저장공간으로

Electric Objects EO1을 다시 살려 미술 작품을 보여주는 디지털 액자로 쓰는 작업을 계속하고 있다. 지금까지는 PC에서 메트로폴리탄 미술관의 공개 작품 이미지를 내려받아 EO1 화면에 맞게 가공한 뒤, 로컬 웹 서버를 통해 Firefox에서 슬라이드쇼로 보여주는 방식을 사용했다. 이 방법은 이미 꽤 안정적으로 작동한다. 두 기기는 서로 동일한 Wi-Fi 네트워크 안에 있어야 한다.

휴~ 힘들구나. 오늘 나의 기분을 잘 보여주는 그림.


그러나 가능하면 EO1이 PC의 도움 없이 독립적으로 작동하게 만들고 싶었다. 그래서 USB 메모리에서 Linux를 부팅하는 방법도 시험해 보았고, 이번에는 원래 설치되어 있는 Android 4.4에서 USB 메모리를 직접 사용할 수 있는지도 조사해 보았다.

이 과정에서 먼저 해결해야 했던 것이 ADB(Android Debug Bridge)였다. EO1의 micro-USB 단자는 하나뿐이므로 PC와 ADB로 연결하면 OTG 마우스나 USB 메모리를 동시에 사용할 수 없다. 더구나 처음 ADB를 연결하면 다음 사진과 같이 Android가 RSA 인증을 요구하는데, 화면을 터치할 수도 없고 USB 포트는 이미 PC가 차지하고 있으니 OK 버튼을 누를 방법이 마땅치 않았다. USB 허브는 소용이 없다. 왜냐하면 PC가 호스트로 잡히기 때문이다. 여기에서 인증을 완료하지 못하면 ADB shell을 열거나 파일을 전송할 수 없고, ADB를 TCP 모드로 전환하여 Wi-Fi로 접속하는 것도 불가능하다.

무슨 수로 체크박스를 표시하고 OK를 클릭한단 말인가?

결국 이 문제를 해결하기 위해 작은 Android 앱을 하나 만들었다. Accessibility Service를 이용하여 USB debugging 승인 창이 나타났을 때 'Always allow from this computer'를 선택하고 OK 버튼을 눌러 주는 앱이다. Android Studio에서 APK를 빌드하여 EO1에 설치한 뒤 실제로 시험해 보니 제대로 작동했다.

그 결과 ADB 연결에 성공했고, 이어서 ADB를 TCP 5555 포트로 전환하여 Wi-Fi를 통한 접속도 가능하게 만들었다. USB 케이블을 뽑은 뒤에도 PC에서 EO1에 접속하여 shell을 사용할 수 있게 된 것이다. 다만 이 설정은 재부팅 후에는 유지되지 않아, 다시 무선 ADB를 사용하려면 USB로 연결하여 TCP 모드로 전환해야 한다.

여기서 뜻밖의 사실도 하나 발견했다.

uid=0(root) gid=0(root) context=u:r:shell:s0

EO1의 ADB shell이 처음부터 root 권한으로 실행되고 있었다. 별도의 rooting 작업이나 su 명령도 필요하지 않았다. 덕분에 시스템을 변경하지 않고도 커널과 USB 장치의 상태를 상당히 자세히 조사할 수 있게 되었다.

 Shell을 열어서 EO1의 정체를 확인해 보았다.

이제 무선 ADB를 유지한 채 EO1의 micro-USB 포트에 OTG 어댑터와 USB 메모리를 연결해 보았다. USB 메모리는 전혀 인식되지 않는 것처럼 보였지만 실제로는 그렇지 않았다. 커널 메시지를 확인해 보니 USB 장치 자체는 정상적으로 발견되고 있었다.

usb 1-1: new high speed USB device number 7 using fsl-ehci
usb 1-1: device v23a9 pef18 is not supported

더 조사해 보니 이 장치는 class 08, subclass 06, protocol 50으로 인식되고 있었다. 즉 흔히 사용하는 표준 USB Mass Storage 장치임을 EO1이 정확히 알고 있었다. 문제는 그 다음 단계였다. USB 메모리를 block device로 취급하기 위해 필요한 SCSI 계층과 USB mass-storage 지원이 커널에 포함되어 있지 않았고, 따라서 /dev/sda와 같은 block device가 만들어지지 않았다.

마지막으로 실행 중인 EO1 커널의 /proc/config.gz를 꺼내 조사했다. 결정적인 설정은 다음과 같았다.

# CONFIG_SCSI is not set

즉 포맷이나 Android의 자동 마운트 기능에 문제가 있었던 것이 아니다. EO1의 기본 커널 자체가 일반적인 USB mass storage를 디스크로 사용하기 위해 필요한 SCSI 계층 없이 만들어져 있었다. 키보드와 마우스가 USB OTG에서 잘 작동하면서 USB 메모리만 사용할 수 없었던 이유도 이것으로 설명된다.

물론 커널을 다시 컴파일하는 방법도 있을 것이다. EO1은 i.MX6 계열의 ARM 프로세서를 사용하므로 PC의 Linux 환경에서 적절한 소스와 cross compiler를 이용하여 커널을 만들 수 있다. 그러나 단순히 미술 작품을 보여주기 위해 커널까지 교체하는 것은 일이 너무 커진다. 잘못된 커널을 내부 eMMC에 기록하면 멀쩡하게 작동하는 EO1을 부팅하지 못하게 만들 위험도 있다.

그런데 여기까지 조사하고 나니 훨씬 간단한 길이 보였다.

EO1에는 약 2.38 GB의 Android 사용자 저장공간이 있고, 현재 약 960 MB가 비어 있다. PC에 USB 케이블로 연결하면 이 공간을 볼 수 있으며, ADB를 이용해서도 파일을 복사할 수 있다. 그렇다면 굳이 USB 메모리가 필요할 이유가 없다.

PC
 |
 |  adb push
 v
EO1 내부 저장공간
 |
 +-- images/
 +-- metadata.json
 +-- exhibition.json
 |
 v
EO1-Museum Android app
 |
 v
1080 x 1920 fullscreen display

현재 EO1-Museum은 MetBoot가 부팅 완료를 감지하여 Firefox를 실행하고, Firefox가 PC의 로컬 웹 서버에 접속하여 작품을 보여주는 구조이다. 이것도 잘 작동하지만 PC와 Wi-Fi가 항상 필요하다.

다음 단계에서는 아주 작은 Android 디스플레이 앱을 직접 만들어 볼 생각이다. 내부 저장공간의 특정 디렉터리에 있는 JPEG 이미지를 읽어 전체 화면으로 보여주고, 예를 들어 15초마다 다음 작품으로 넘어가게 하면 된다. 처음에는 그것만으로 충분하다.

잘 작동한다면 나중에 부팅 후 자동 실행, 작품 순서의 무작위화, 메타데이터 표시, 밝기 조절, 가로로 긴 작품의 천천히 움직이는 화면 같은 기능을 하나씩 더할 수 있다. 예전에 EO1을 위해 만들어진 오픈소스 Android 앱(spalt/EO1)의 코드도 참고할 수 있을 것이다.

재미있는 것은 여러 방향을 돌아본 끝에 오히려 구조가 단순해졌다는 점이다. Linux를 설치할 필요도 없고, USB 메모리를 인식시키기 위해 커널을 고칠 필요도 없다. 완성된 상태에서는 Firefox도, PC의 웹 서버도, 심지어 Wi-Fi도 필요하지 않을 수 있다.

그림을 내부 저장공간에 넣고 그것을 전체 화면으로 보여주는 Android 앱 하나.

어쩌면 그것이 내가 개발하는 EO1-Museum의 가장 자연스러운 모습일지도 모르겠다.


2026년 10월 23일 업데이트

EO1의 내부 저장공간에 이미지 파일을 복사한 뒤 이를 순차적으로 재생하는 앱(v0.1)을 개발하였다. 이제는 웹브라우저를 쓰지 않기 때문에 테두리가 나타나지 않는다.


2026년 10월 26일 업데이트

EO1 내부 저장공간 모드(Local Gallery)와 PC에서 서비스하는 것을 보여주는 모드(PC Gallery)를 선택할 수 있게 하였다. PC Gallery는 웹브라우저에 의존하지 않으며, 메인 앱에 일체화하였다. 더불어서 오른쪽 위에 시계를 표시하게 하였다. 이러한 설정은 마우스를 통해 제어할 수 있다. 이제 더 이상 다음을 것이 없는 상태로 발전하였으므로, 공식적은 배포판이라 해도 무방하다. 문서만 조금 더 구조화시키면 이번 프로젝트는 종료를 선언해도 된다.

2026년 10월 20일 화요일

Electric Objects EO1 되살리기: EO1-Museum, 그리고 신조어 '미술정보학'

이로써 GitHub의 여덟 번째 리포지토리가 만들어졌다. 먼지만 뒤집어쓰고 있던 전자액자 EO1을 어떻게 해서든 활용해 보자고 마음을 먹고 조사에 착수한 것이 지난 토요일. 오늘이 화요일이니 정말 최단 시간에 실제 활용 가능한 형태의 '해킹' 결과물이 나왔다.

EO1-Museum - Repurposing an Electric Objects EO1 as an open-access museum display.

이 모든 것은 바닥부터 시작한 것은 물론 아니다. 인터넷에 성공담을 올려 준 여러 선구자와 인공지능 덕분이었다.


아직 몇 가지 개선 아이디어가 남아있다. EO1의 웹브라우저 테두리를 없앤다든가, 종횡비가 맞지 않는 경우 이미지의 높이를 디스플레이에 딱 맞게 한 뒤 옆으로 흐르게 한다는가.

'오늘은 어떤 그림을 다운로드하여 표현해 볼까?' 지금은 이 질문에 대하여 간단한 키워드 조합으로만 작품을 선택하게 되어 있다. 예를 들어 '피카소의 청색 시대 작품을 보여줘'라는 지시에 맞게 작동하려면 약간의 인공지능 기술을 넣어야 한다. 물론 피카소는 1973년에 사망했으니 아직 사후 70년이 지나지 않았기 때문에 그의 작품은 2044년이나 되어야 저작권이 만료되어 퍼블릭 도메인이 될 수 있다. 검색 기술보다 박물관이 제공하는 디지털 이미지의 이용조건을 명확히 알야 하는 것이 더 큰 문제이다. 결국 미래의 EO1-Museum에는 “무엇을 보여줄 것인가”를 이해하는 지능뿐 아니라, “무엇을 보여주어도 되는가”를 판단하는 능력도 필요하다.

해외 미술관만 바라볼 필요도 없다. 우리나라의 국공립 박물관과 미술관에도 방대한 소장품과 디지털 이미지가 축적되어 있다. 일부 기관은 이미 공공누리 등의 조건에 따라 소장품 이미지를 내려받아 활용할 수 있도록 하고 있다. 다만 기관마다, 그리고 작품마다 이용 조건이 다르고 현대미술 작품에는 아직 저작권이 살아 있는 경우도 많다. 앞으로 이러한 이미지와 메타데이터가 기계가 읽을 수 있는 형태로 더 많이 공개되고 이용 조건까지 명확하게 표시된다면, EO1-Museum에서도 ‘오늘은 조선 후기의 산수화를 보여줘’와 같은 말 한마디로 우리 미술을 찾아 작은 전시를 구성하는 일이 가능할 것이다. 결국 필요한 것은 이미지의 공개뿐만 아니라 작품 정보와 이용 권리를 함께 알 수 있는 데이터의 공개이다.

생명정보학(bioinformatics)이 있고 음악정보학(music informatics)이 있다면, 이런 일을 ‘미술정보학’이라고 불러도 되지 않을까? 궁금해서 찾아보니 영어권에는 Art Informatics라는 표현이 간헐적으로 쓰인 사례가 있었다. 그러나 영어의 art는 우리말 ‘미술’보다 범위가 넓어 문학이나 공연예술까지 아우를 수 있으므로 이를 곧바로 미술정보학이라고 옮기기는 어렵다. 내가 말하는 ‘미술’의 범위를 좀 더 정확하게 영어로 표현한다면 Fine Arts Informatics 또는 Visual Arts Informatics 정도가 될 것이다. 적어도 내가 찾아본 범위에서는 ‘미술정보학’이라는 우리말이나 이와 정확히 대응하는 영어 표현이 독립된 학문 분야의 이름으로 널리 자리 잡은 흔적은 발견하지 못했다.

그렇다면 한번 써 보자. 내가 생각하는 미술정보학은 작품을 단순히 디지털 이미지로 만드는 일이 아니다. 미술 작품과 작가에 관한 데이터를 수집하고, 메타데이터로 기술하고, 컴퓨터로 검색하고 분류하며, 인공지능을 이용하여 작품의 맥락을 이해하고, 저작권과 이용 조건을 판단하고, 그 결과를 이용하여 새로운 방식으로 작품을 발견하고 감상하게 만드는 일까지를 포함한다. 우리나라 공공 미술관과 박물관이 소장품 이미지와 메타데이터, 그리고 각각의 이용 조건을 기계가 읽을 수 있는 형태로 더욱 적극적으로 공개한다면 할 수 있는 일은 훨씬 많아질 것이다. 

낡은 EO1 하나를 되살려 세계의 미술관을 연결해 보려던 작은 프로젝트가 뜻밖에도 미술과 데이터, 정보기술이 만나는 지점까지 나를 데려왔다. 돌이켜보면 그 출발점에는 생명과학 데이터를 다루는 나의 업무가 있었고, 취미로 즐겨 온 음악과 정보기술의 결합도 있었다. 생명정보학에서 출발하여 음악정보학을 기웃거리다가 이제 미술에까지 왔다. 나는 일단 이 새로운 활동을 ‘미술정보학’이라고 불러 보기로 했다.

2026년 10월에 MP3 플레이어를 구입하다

휴대폰으로 못 하는 일이 없게 된 요즘, 여전히 MP3 플레이어를 사는 사람들이 있다. 음원을 준비하여 기기에 넣는 과정이 번거롭지만, 오로지 감상 자체에만 집중할 수 있기 때문이다. 정신을 어지럽히는 소셜 미디어도, 자꾸 들여다보게 되는 비생산적인 화면도 없다. 음악이면 음악, 라디오면 라디오. 

나도 그런 이유로 MP3 플레이어를 구입한 사람 중의 하나가 되었다. 가격도 무척 싸다. 단, 메모리 가격이 요즘 너무 올라서 따로 갖고 있는 microSD 카드를 넣어야 했던 것은 함정이다. 광고에서는 마치 16GB의 기본 메모리가 포함된 것처럼 오해를 불러일으키게 만들어 두었다.



이번에 MP3 플레이어를 사게 된 것은 실은 어학 공부(영어) 때문이다. 사실 귀에다 뭔가를 꽂은 상태에서 뭔가를 중얼거리면서 살게 될 것이라고는 생각하지 못했다. 지금까지 단 한 번도 그래 본 적은 없었다. 학교에 다니던 시절부터 진작에 영어 회화 공부에 관심을 가졌더라면 얼마나 좋았을까? 그랬다면 지금 더 넓은 세상을 만날 수 있었을텐데.

지금 어떤 온라인 강좌를 듣고 있는지 여기에 밝히기는 부끄럽다. 강좌를 학습하고, 유튜브로 제공되는 녹음본을 다운로드하여 MP3 플레이어에서 반복하여 들음과 동시에 승용차로 출퇴근하는 동안에는 ChatGPT를 이용한 연습도 지속적으로 실시하고 있다. 유튜브 다운로드에는 명령행 도구인 yt-dlp를 사용한다.

요즘 젊은 세대의 어학 실력은 우리 세대보다 훨씬 나은 것 같다. 인터넷이나 '미드' 등을 통해 영어 환경에 자연스럽게 노출되고, 영어 학습도 문법이나 어휘 및 지필시험 중심에서 실제 활용을 중시하는 방향으로 많이 바뀌었기 때문이다. 이러한 변화에 따라 대학원 입시나 졸업 요건 등에서 일정 수준 이상의 공인영어시험 성적을 요구하게 된 것으로 보인다.

내가 마지막으로 본 영어 시험은 대학원 졸업 자격 획득을 위한 자체 지필고사가 전부였다. 이것이 TOEIC, TOEFL, 그리고 나중에 등장한 TEPS 등의 공인영어시험으로 대체된 것은 훨씬 뒤의 일이었다. 내가 지금까지 커리어를 유지하면서 공인영어시험 성적은 전혀 필요하지 않았다. 더군다나 국외 연수 경험이 없는 순수 국내파였던 나는, 문서로서 영어를 읽거나 이따금 쓰는 것 말고는 실제 영어 활용 능력을 기르려는 동기 자체가 부족하였음을 고백하지 않을 수 없다.

커리어 차원에서 이제 내려갈 일만 남은 지금, 오히려 영어에 대한 필요성을 더욱 강하게 느끼는 이 역설적인 현상을 어떻게 설명할 수 있을까? 생각해 보면 그렇게 이상한 일도 아니다. 젊었을 때는 영어가 시험을 통과하고 지식을 얻기 위한 도구였다면, 지금의 영어는 사람을 만나고 내가 가진 생각을 전하기 위한 도구이기 때문이다.

더 이상 영어 점수로 증명해야 할 것도 없고, 영어를 잘한다고 해서 승진할 일도 없다. 그런데 바로 그렇기 때문에 지금의 영어 공부가 더 절실하게 느껴지는지도 모르겠다.


2026년 10월 19일 월요일

Electric Objects EO1을 다시 살리는 사람들

Electric Objects EO1을 원래 서비스와 관계없이 활용하려는 시도는 이미 오래전부터 있었다. 이번에 EO1을 다시 사용해 보면서 특히 도움이 된 자료는 두 가지였다. 시간 순서로 보면 Darius Kazemi의 Hack Your EO1이 먼저이고, 그 뒤에 Christian Boyle의 eo1-workaround가 이어진다.

Hack Your EO1 — Darius Kazemi

먼저 참고한 것은 Darius Kazemi가 Feel Train 블로그에 2015년 9월 공개한 Hack Your EO1이다. 이 글은 EO1을 단순한 디지털 액자가 아니라 Android 4.4.2 KitKat이 돌아가는 하나의 컴퓨터로 바라본다.

EO1 뒷면의 micro-USB 단자에 OTG 어댑터와 USB 허브를 연결하여 키보드와 마우스를 사용할 수 있고, Windows 키와 B를 함께 누르면 Android의 기본 웹 브라우저를 실행할 수 있다는 매우 중요한 정보도 이 글에서 소개한다. 브라우저에서 APK를 내려받아 직접 설치하거나, Startup Manager를 이용하여 특정 앱을 부팅할 때 실행시키는 방법도 다룬다.

엊그제 EO1을 만지면서 OTG 허브에 키보드와 마우스를 연결하고 Win+B를 눌러 브라우저를 띄웠던 것도 바로 이 방법을 따른 것이다. 오래된 전자액자 안에 멀쩡한 Android 컴퓨터가 숨어 있다는 사실을 알려 준, 이번 작업의 출발점과 같은 글이었다.

참고: Darius Kazemi / Feel Train — Hack Your EO1

이 글은 Electric Objects의 서비스가 살아있던 시절 작성되었다. 당시에는 이를 이용하여 임의의 URL을 EO1으로 내보내는 것이 가능하였다. 그러나 지금은 다른 방법을 찾아야 하고, 몇 시간의 노력 끝에 같은 Wi-Fi 네트워크 내에 있는 PC 서버에서 제공하는 웹사이트를 EO1에서 디스플레이하는데 성공하였다.

eo1-workaround — Christian Boyle

그 다음으로 직접적인 도움이 된 것은 Christian Boyle의 eo1-workaround이다. GitHub에 공개된 이 프로젝트는 제목 그대로 서비스가 중단된 EO1을 다시 사용할 수 있도록 하는 우회 방법을 제시한다.

여기에서도 EO1에 USB 허브와 키보드·마우스를 연결하고 Win+B로 기본 브라우저를 여는 방법을 사용한다. 그 다음 Firefox를 APK 형태로 내려받아 설치하고, 웹페이지를 이용하여 사진이나 이미지를 EO1 화면에 표시한다.

특히 흥미로웠던 것은 Firefox를 사용하는 이유였다. EO1에 들어 있는 오래된 Android 기본 브라우저보다는 Firefox가 Fullscreen API를 지원하기 때문에 브라우저의 메뉴나 주소창이 없는 디지털 액자다운 화면을 만들기에 유리하다.

실제로 이번 작업에서도 이 아이디어를 따라 구형 Android에서 동작하는 Firefox 68을 설치했다. Firefox의 홈페이지를 PC에서 실행하는 로컬 웹 서버 주소로 지정했더니 EO1을 껐다 켜도 그 설정이 유지되었다. 결국 Firefox는 이번 시스템의 실제 디스플레이 역할을 맡게 되었다.

Firefox 앱을 설치하는 과정에서 한 가지 작은 장애물도 있었다. EO1의 브라우저에서 http://PC주소:8000/something.apk처럼 APK 파일의 주소를 직접 열면 파일 자체는 다운로드되지만, Android가 이를 설치 가능한 APK로 제대로 인식하지 못해 “Can’t open file”과 같은 문제가 발생했다. 원인은 Python의 기본 python -m http.server 8000이 이 환경에서 .apk 파일을 Android가 기대하는 MIME 형식으로 전달하지 못했기 때문이었다. 그래서 작은 server.py를 만들어 .apk 확장자에 application/vnd.android.package-archive라는 MIME type을 명시하고, 이 서버를 대신 실행하였다. 그 뒤에는 같은 주소에서 APK를 내려받아 정상적으로 설치할 수 있었다. 결국 server.py는 별도의 복잡한 웹 서버가 아니라, 오래된 Android가 APK 파일을 올바른 설치 패키지로 알아보도록 HTTP 응답의 파일 형식을 정확히 알려 주기 위한 작은 보완책이었다.

참고: Christian Boyle / GitHub — eo1-workaround

두 프로젝트에서 나의 MetBoot까지

두 자료를 시간 순서와 역할로 놓고 보면 꽤 자연스럽게 연결된다. Darius Kazemi의 글이 EO1의 Android 내부로 들어가서 키보드, 마우스, 브라우저와 APK를 사용하는 기본적인 방법을 보여 주었다면, eo1-workaround는 그 방법을 이용하여 원래 Electric Objects 서비스가 사라진 뒤에도 EO1을 웹 기반 디지털 디스플레이로 사용하는 구체적인 방법을 보여 주었다.

이번에 내가 한 작업도 처음에는 거의 같은 길을 따라갔다. OTG 키보드와 마우스로 EO1에 접근하고, Win+B로 브라우저를 열고, APK를 sideload하고 Firefox를 설치했다.

다만 마지막 단계는 조금 달라졌다. The Metropolitan Museum of Art의 공개 작품을 PC에서 자동으로 내려받아 로컬 웹 서버로 제공하고, EO1에서는 Firefox로 그 페이지를 표시하도록 만들었다. 그리고 EO1이 켜지면 Firefox를 자동으로 실행시키기 위해 Android 4.4(API 19)에서 작동하는 아주 작은 앱인 MetBoot까지 직접 만들었다. 여기까지 오게 될 줄 누가 알았겠는가?

따라서 이 작은 프로젝트의 계보를 한 줄로 적는다면 다음과 같다.

Hack Your EO1 → eo1-workaround → MetBoot + The Met local gallery

처음에는 오래된 전자액자 하나를 다시 써 보자는 생각이었는데, 결국 OTG, Android 4.4, APK sideload, Firefox, Python 웹 서버, Android Studio까지 건드리게 되었다. 하지만 앞서 이런 기기를 열어 보고 기록을 남긴 사람들이 있었기에 가능한 일이었다.

주소창이 드러나지 않도록 이미지를 스크린 전체에 표시하거나 설명을 보여주는 것, 그리고 가로 형태의 사진은 옆으로 흐르듯이 보여주는 것 등 추가할 기능이 더 있다.


다음의 목표는 Wi-Fi가 없는 환경에서도 쓸 수 있도록 USB 메모리에 사진을 담아서 이를 표시하게 만드는 일이다. 쉽게 될 것이라고는 생각하지 않는다.

2026년 10월 17일 토요일

Electric Objects EO1 전자액자를 되살려 보자

Electric Objects EO1이라는 전자액자를 우연한 기회에 구하여 잠깐 사용해 보았던 것이 2019년이다. 휴대폰 앱을 통해서 서버로 사진을 업로드하면 이를 와이파이로 접속한 상태에서 1080x1920의 세로 포맷의 이미지를 보여주던 물건이었다.


사진 출처는 내 블로그이다(링크). 잠깐 사용했던 초소형 푸시풀 진공관 앰프가 보인다. 

그 후 EO1에 대한 관심이 떨어져서 몇 년을 방치해 두었다가 다시 활용 가능성을 알아보기로 하였다. 이미 앱은 서비스가 되지 않는 상태였다. 전원을 넣어 보니 다음과 같이 접속 시도만 하는 상태이다.


2016년에 이를 용감하게 분해하여 정체를 알아 본 사람이 있었다(Electric Objects EO1 Digital Art Display Teardown). Freescale i.MX 6Dual SoC with two ARM Cortex A9 cores(싱글보드 컴퓨터)에 안드로이드가 설치되어 있으며, LCD 패널은 삼성전자 제품이고, 뒷면의 전원 어댑터 잭 바로 곁에 위치한 micro-USB가 USB OTG를 지원한다는 것까지를 확인하였다고 한다. Freescale은 2015년에 NXP에 인수되었다.

ChatGPT에게 물어보니 OTG를 꽂아서 키보드를 연결한 뒤 Windows + B 버튼을 누르면 웹브라우저가 뜬다고 하였다. 서랍 속을 뒤지면 micro-USB OTG가 있지 않을까?


그렇다. 용케 필요한 물건을 이미 갖고 있는 것을 확인하였다. 그러나... 이것을 꽂으면 어댑터를 꽂을 수가 없다! 그래서 늦은 밤에 다이소에 가서 micro-USB <-> USB-C 젠더를 사 가지고 돌아왔다. USB type-C의 OTG는 갖고 있었기 때문. 하지만 이것으로는 키보드가 작동하지 않았다. 너무 여러 단계의 접속을 거쳐서 문제가 되는 것 같았다. NumLock, CapsLock을 아무리 눌러도 LED가 들어오지 않았다.

결국 위 사진의 것을 칼로 가공하여 커넥터 가까운 쪽에서 케이블을 꺾을 수 있게 만든 뒤 전원 어댑터를 꽂았다.


USB 키보드를 연결하니 CapsLock 키를 눌렀을 때 불이 들어온다. 그러면 키보드는 인식이 잘 된다는 뜻이다. Windows + B 키를 눌러 보았다. 



오! 가능성이 있다. 와이파이도 잘 인식된 상태였다. Ctrl + L을 눌러서 주소창에 네이버를 입력해 보았으나 보안 경고가 나왔다. 브라우저가 너무 오래된 것이 문제이다. HTTPS를 사용하지 않도록 만들어진 테스트용 사이트인 http://neverssl.com을 접속해 보니 다음과 같이 창이 열렸다. HTTPS가 아니라 HTTP여야 한다. USB 허브를 중간에 꽂으니 마우스 포인터도 나타났다.


세상을 향하여 창은 열려 있지만, EO1을 돌리는 구형 Android 브라우저가 현대 HTTPS/TLS와 호환되지 않는 것이 문제이다. 

자, 이 전자액자를 2026년 현재 어떻게 활용할 것인가? EO1의 LCD(삼성 LTM230HL07, 23인치, 1920x1080 PLS)에 맞는 컨트롤러를 구해서 LCD를 HDMI 모니터로 사용하는 것이 가능하다고 한다. 그러나 그렇게까지 침습적인 방법까지는 쓰고 싶지 않다. 

또 다른 가능성은 휴대폰이나 PC에서 웹서버를 띄운 뒤 EO1에서 접속하여 사진 디스플레이 등의 용도로 사용하는 것이다. 바이브 코딩으로 index.html과 이미지 일괄 리사이즈용 파이썬 스크립트를 만든 뒤, PC에서 로컬 웹서버를 실행하였다. 집 안의 동일한 와이파이 네트워크에서만 사용하는 것이므로 여기서는 HTTPS가 아닌 HTTP로 접속하도록 하였다. 다음은 EO1의 웹브라우저에서 PC의 웹서버에 정상적으로 접속이 됨을 확인한 화면이다.



구글 포토에서 최근에 찍은 사진을 몇 장 다운로드한 뒤 일괄 리사이즈 명령을 실행한 후 EO1에서 접속해 보았다. 성공이다!


좀 더 적극적인 활용 방법은 EO1에서 Linux를 구동하는 것이다. EO1은 ARM 기반의 i.MX6 프로세서를 사용하므로 적절한 Linux 이미지를 USB 메모리에 기록한 뒤, micro-USB OTG 허브를 통해 USB 메모리와 키보드 등을 연결하여 Linux로 부팅에 성공하였다는 경험담이 존재한다. 

이는 내장 Android를 지우지 않고 외부 USB에서 Linux를 실행할 수 있다는 점이 장점이다. Linux가 정상적으로 부팅되면 EO1은 더 이상 단순한 디지털 액자에 머물지 않고 SSH 접속, Python 프로그램 실행, 웹서버나 정보 대시보드 운영 등에 사용할 수 있는 작은 ARM Linux 컴퓨터가 된다. 다만 아무 ARM Linux 이미지나 사용할 수 있는 것은 아니며 EO1의 i.MX6 하드웨어에 맞는 부트로더와 커널을 갖춘 이미지가 필요하다. 이는 또 별도의 프로젝트가 될 것이다. 

2015년 빌드된 EO1의 커널.


메트로폴리탄 미술관 소장품 다운로드하여 디스플레이하기

EO1에 내가 찍은 사진만 띄우는 것도 좋지만, 디지털 액자라는 물건의 성격을 생각하면 미술관 소장품을 전시하는 용도로도 잘 어울린다. 뉴욕 메트로폴리탄 미술관(The Metropolitan Museum of Art, The Met)은 Public Domain에 해당하는 소장품 이미지와 메타데이터를 Open Access 정책에 따라 공개하고 있다.

The Met은 소장품 메타데이터 전체를 CSV 파일로도 제공한다. 이를 이용하여 Public Domain으로 표시된 회화 작품을 골라낸 뒤, 이미지가 제공되는 작품 중 100점을 무작위로 선택하여 다운로드하는 Python 스크립트를 만들었다.

처음에는 The Met의 Collection API를 이용하여 작품을 검색하려 했으나 검색 API가 HTTP 410(Gone)을 반환하였다. 그래서 Open Access 데이터셋인 MetObjects.csv를 내려받아 작품을 선별하고, 개별 작품의 이미지 주소를 얻는 데에만 API를 이용하는 방식으로 바꾸었다. CSV 파일은 처음 한 번만 내려받으면 된다.

다운로드한 이미지는 EO1 화면에 맞추어 1080 × 1920 픽셀로 변환하였다. 원본의 종횡비는 그대로 유지하고 남는 부분에는 검은 여백을 넣었다. 이렇게 만든 이미지 목록을 images.js에 기록하고, index.html에서 일정 시간 간격으로 무작위로 바뀌어 표시되도록 하였다.

마지막으로 이미지가 들어 있는 디렉터리에서 다음과 같이 간단한 웹서버를 실행하였다.

python -m http.server 8000

EO1과 PC가 같은 Wi-Fi에 연결되어 있다면 EO1의 웹브라우저에서 http://PC의-IP주소:8000으로 접속하면 된다. 집 안의 로컬 네트워크에서만 사용하는 것이므로 여기서는 HTTPS를 사용하지 않았다. 오히려 오래된 Android를 사용하는 EO1에서는 최신 HTTPS 사이트 접속에 문제가 있기 때문에 단순한 HTTP 서버가 편리하다.

결과적으로 별도의 앱을 설치하거나 EO1의 운영체제를 개조하지 않고도, 원래의 웹브라우저만 이용하여 The Met의 회화 작품을 차례로 보여주는 디지털 액자로 다시 사용할 수 있게 되었다. 서버 쪽의 이미지와 HTML을 바꾸면 EO1에서는 페이지를 다시 불러오는 것만으로 새로운 내용을 표시할 수 있다.

여가를 위한 프로젝트가 하나 더 늘어났다.

2026년 10월 11일 일요일

물건은 남는데 정보는 먼저 사라진다

이 글은 GitHub에 추가한 SyX2ool 프로젝트의 Background and Modification(BACKGROUND.md)을 국문으로 옮긴 것이다.

ChatGPT 자동 생성 이미지.

Korg X2와 SyX2ool을 만들게 된 이야기

Korg X2와 X3가 출시된 1990년대에는 3.5인치 플로피 디스크가 신시사이저와 컴퓨터 사이에서 데이터를 주고받는 평범한 수단이었다. 특히 내장 시퀀서를 갖춘 워크스테이션급 신시사이저에서 플로피 디스크 드라이브는 단순한 부가 기능이 아니었다. 곡과 시퀀스, 음색을 비롯한 사용자 데이터를 저장하고 다시 불러오는 중요한 장치였다.

30여 년이 지난 지금은 상황이 달라졌다. 신시사이저 본체는 여전히 멀쩡하게 작동하는데 플로피 디스크 드라이브가 먼저 고장 나는 일이 생긴다. 드라이브가 살아 있다고 해도 요즘 컴퓨터에서 플로피 디스크를 사용하는 것 자체가 매우 번거롭다.

한 가지 해결 방법은 원래의 플로피 디스크 드라이브를 Gotek 같은 플로피 에뮬레이터로 교체하는 것이다. 과거의 디스크 기반 작업 방식을 그대로 유지하려면 아마 이것이 가장 간단한 방법일 것이다. 그러나 나는 플로피 디스크 드라이브를 교체하지 않고 어디까지 할 수 있는지가 궁금했다.

플로피 디스크라는 통로를 제외하면 X2/X3와 현대의 컴퓨터를 이어 주는 가장 중요한 통로는 MIDI 포트가 된다. 일반 MIDI 메시지로 연주 정보를 주고받을 수 있고, System Exclusive(SysEx) 메시지를 이용하면 해당 신시사이저에 고유한 데이터까지 주고받을 수 있다.

이 과정에서 오래전에 만들어진 Java 프로그램인 X3File2Sysex가 큰 도움이 되었다. 다행히 예전에 보관해 둔 Korg 디스크 파일도 있었다. X3File2Sysex를 이용하면 디스크의 데이터(.PCG, .SNG)를 SysEx 형태로 바꾸어 MIDI를 통해 신시사이저로 전송할 수 있었다.

이것이 특히 중요했던 것은 X2의 내장 백업 배터리를 교체했을 때였다. 배터리를 교체한 뒤 X2를 다시 제대로 사용할 수 있는 상태로 만들려면 Preload Data 디스크의 데이터를 다시 올려야 했다. 그런데 플로피 디스크 드라이브가 고장 난 상태에서는 원래의 복구 방법을 사용할 수 없었다. X3File2Sysex와 MIDI 연결을 이용하니 필요한 디스크 데이터를 SysEx로 바꾸어 X2에 전송하는 방법으로 이 문제를 해결할 수 있었다.

이 경험을 통해 고장 난 플로피 디스크 드라이브를 우회하는 통로로 SysEx를 충분히 활용할 수 있다는 것을 알게 되었다. 그러나 기존 도구에는 한계도 있었다. 이미 준비된 데이터를 복원하는 것은 가능했지만, X2에서 덤프한 시퀀서 데이터를 자유롭게 들여다보고 수정하거나 다른 형식으로 바꾸어 다시 이용하는 것은 또 다른 문제였다.

오래전에 받아 둔 파일이 다시 귀중한 자료가 되다

지금 생각하면 정말 운이 좋았다. 아주 오래전에 어느 웹사이트에서 Korg X2/X3용 디스크 파일을 모아 놓은 ZIP 파일을 발견하여 받아 두었기 때문이다. 지금은 그 자료가 있던 웹사이트의 흔적조차 찾기가 쉽지 않다.

당시에는 그 파일을 보관해 둔 것이 특별히 중요하다고 생각하지 않았다. 그러나 수십 년이 지난 뒤 그것은 매우 귀중한 시험 자료가 되었다.

그 안에는 실제 Song과 User Pattern, Program, Drum 데이터 등 X2/X3에서 사용하던 여러 종류의 데이터가 들어 있었다. 이 파일들을 실제 X2에서 덤프한 SysEx 데이터와 비교하면서 막연한 추측이 아니라 실제 데이터를 바탕으로 내부 구조를 조사할 수 있었다.

또 하나 결정적으로 중요했던 자료는 Korg X2/X3 Reference Guide였다.

신시사이저를 단순히 연주하는 데에는 별로 눈에 띄지 않는 내용이 이 매뉴얼에는 상당히 자세하게 기록되어 있다. SysEx 명령, 시퀀서 파라미터, 이벤트의 종류, Pattern 관련 기능, MIDI 동작 등 내부 데이터 구조를 이해하는 데 필요한 기술적인 정보가 들어 있다.

물론 Reference Guide만 읽는다고 해서 시퀀서 덤프의 모든 바이트가 저절로 해석되는 것은 아니었다. 하지만 실제 SysEx 파일에서 발견되는 데이터를 이해하는 데 필요한 용어와 구조적인 단서를 제공했다.

결국 Reference Guide, 오래전에 보관해 둔 디스크 파일, X3File2Sysex, 그리고 실제 X2에서 얻은 덤프 데이터를 서로 비교하는 것이 X2/X3 시퀀서 형식을 분석하는 기반이 되었다.

그래서 SyX2ool을 만들기 시작했다

X2에서 시퀀서 데이터를 덤프하고, 기존 SysEx 데이터를 다시 X2로 보내는 것까지는 가능했다. 하지만 나는 덤프 파일을 정체를 알 수 없는 하나의 거대한 바이트 덩어리로 취급하는 데서 그치고 싶지 않았다.

그 안에 무엇이 들어 있는지를 알고 싶었다.

10개의 Song은 어디에 저장되어 있는가? 100개의 User Pattern은 어떤 구조로 들어 있는가? 각 Track과 Event는 어떻게 표현되는가? 그리고 X2/X3의 시퀀서 데이터와 오늘날에도 널리 사용하는 Standard MIDI File(SMF)을 서로 변환할 수는 없을까?

무엇보다도 플로피 디스크 드라이브에 의존하지 않고 현대의 컴퓨터에서 X2/X3의 내장 시퀀서에 좀 더 자유롭게 접근하고 싶었다.

그것이 SyX2ool을 만들게 된 동기였다.

SyX2ool이라는 이름은 SysEx + X2 + Tool을 합쳐 만든 것이다. 처음에는 X2/X3의 ALL SEQUENCE DATA 덤프를 해석해 보는 작은 실험으로 시작했다. 그러나 작업을 계속하면서 Song을 가져오고 내보내고, User Pattern을 추출하고, SysEx 데이터를 분석하고, MIDI와 Pattern 데이터를 실시간으로 신시사이저에서 연주하는 기능까지 갖춘 명령행 도구로 조금씩 발전하게 되었다.

그런 의미에서 SyX2ool은 X2/X3를 대신하기 위해 만든 프로그램이 아니다. 오히려 그 반대다.

오래된 X2/X3에서 원래 가지고 있던 기능을 오늘날에도 조금 더 자유롭게 사용할 수 있게 만드는 것이 목적이다.

하드웨어만 보존한다고 끝나는 것이 아니다

이번 작업을 하면서 또 하나 느낀 점이 있다.

오래된 신시사이저는 그것을 둘러싸고 있던 정보와 소프트웨어 생태계보다 오히려 더 오래 살아남을 수 있다는 것이다.

개인이 운영하던 웹사이트는 사라진다. 다운로드 링크는 끊어진다. 한때 유용했던 작은 프로그램은 더 이상 구하기 어려워진다. 사용자들 사이에서 공유되던 사용법과 기술적인 지식도 조금씩 사라진다.

내 컴퓨터 한구석에 별 생각 없이 보관해 두었던 오래된 파일들이 수십 년이 지난 뒤 X2/X3를 이해하는 데 매우 귀중한 자료가 되었다.

물건은 남는데, 정보는 먼저 사라진다.

SyX2ool 개발에는 이러한 정보의 일부라도 다시 기록하여 남겨 두려는 의미도 있다.


이 '덧붙임' 단락은 GitHub의 문서에는 포함되지 않았다.

덧붙임.1: 이 글을 쓰면서 X3File2Sysex를 지금도 인터넷에서 구할 수 있는지 찾아보았다. 한참 찾다 보니 뜻밖에도 내 오래된 홈페이지(My old synth and MIDI)에 x3file2sysex.zip을 올려 둔 흔적이 검색되었다. 올려 놓은 나 자신도 까맣게 잊고 있었다. 물건뿐 아니라 정보도, 때로는 어디에 보관했는지조차 잊은 채 살아남는다. 😄 


덧붙임.2: 한 시대를 풍미했던 MIDI 관련 MIDI-OX가 최신 Windows 컴퓨터에서 제대로 전송하지 못하는 SysEx를 놓고 얼마나 고민을 하였던가? 그러나 바이브 코딩으로 만든 Syx2ool 파이썬 스크립트는 X2의 설정 상태를 전부 덤프한 꽤 큰 용량의 SysEx 파일을 구렁이 담 넘어가듯 잘만 전송하였다. 

웹 서핑을 하다가 우연히 MIDI-OX의 개발자인 Jamie O'Connell의 자기 소개 정보를 접하였다(링크). 8년 동안 고단하고 힘든 밴드 생활을 하다가 소프트웨어 엔지니어가 되었다는 진솔한 이야기가 실려 있다. 이 웹사이트는 마지막 갱신일이 2003년 7월이다. 그의 GitHub 프로젝트 사이트에도 약간의 활동 내역이 있지만, 시간이 흐를수록 이런 역사적 자료는 점점 사라질 것이다.

2026년 10월 10일 토요일

X2 Piano는 살리고 X3DRUMS(시퀀스 및 패턴)는 제대로 올리기 — SysEx 파일을 AI로 고쳐 쓰다

Korg X2는 90년대의 Pop & Rock의 표준적인 음색과 나쁘지 않은 이펙터를 내장하고 있다. 내가 특별히 관심을 두고 있는 것은 내장 시퀀서와 드럼 패턴이다. 인터넷에서 구한 XSD-15 Power Disk라는 프리셋 디스크의 내용물 중에 X3DRUMS.SNG에는 음악 제작이나 라이브에서 재사용 가능한 패턴 100개가 장르별로 10개의 곡에 채워져서 제공된다. 실제 소리가 궁금하다면 내가 1년 전에 올린 다음 영상을 확인하면 된다.



하지만 X2 기본 설정 상태에서 이 SNG 데이터만 로드하면 제 소리가 나지 않는다. 실제로는 플로피 디스크 드라이브가 망가진 상태라서 SNG 파일을 직접 로드할 수는 없고, 이를 SysEx로 전환한 것을 사용하고 있다. 제 소리를 내려면 Song/Pattern 데이터뿐 아니라 X3DRUMS에 맞는 Program과 Drum Kit 데이터도 함께 로드해야 한다. 내가 사용하는 SysEx 파일로 말하면 X3DRUMS_Prog.syx와 X3DRUMS_Drums.syx가 그것이다. 이렇게 하였을 때 가장 큰 불편함은 X2의 최대 장점인 Program A01 "X2 Piano"가 사라진다는 것이다. 매뉴얼을 참고하여 A01을 X2의 것으로 고쳐 놓으면 되지만 여간 불편한 것이 아니다. Multisound를 340번 피아노로 맞추는 것 외에도 이펙터를 비롯한 여러 설정을 손봐야 하니 여간 번거로운 일이 아니다. 이러한 불편함은 인공지능 덕분에 크게 줄어들게 되었다. 매뉴얼과 샘플 파일을 밀어 넣고 원하는 사항을 지시하면 되기 때문이다.

  • X2: A01 = X2 Piano, B01 = Piano 16' 
  • X3: A01 = Piano 8', B02 = ExpressoPF

X2/X3에는 편집 가능한 4개의 드럼킷(A1/A2/B1/B2)과 8개의 ROM 드럼킷이 있다. 이 4개의 드럼킷에서 각 키(건반)에 어떤 Drum Sound를 배치하고 어떻게 소리 나게 할 것인지는 Drums.syx에 저장된다. 반면 각 Drum Program이 이들 가운데 어느 Drum Kit을 사용할 것인지는 Prog.syx에 저장된다. 따라서 X3DRUMS의 song 및 사용자 패턴을 제작자가 의도한 음색으로 재생하려면 X3DRUMS_Prog.syx와 X3DRUMS_Drums.syx를 모두 로드해야 한다. 

놀랍게도 X2/X3의 기본 설정에서 B1은 프로그램에 할당되어 있지 않다. 

  • Program A09 (Total Kit) => A1 (Total Kit)
  • Program A69 (ProdcrKit) => A2 (Producer Kit)
  • Program B09 (Rave Kit) => B2 (Rave Kit)
  • Program B69 (VeloGated) => B2 (Rave Kit)

처음에는 이 결과가 잘 이해되지 않았다. 혹시 설정이 변형된 장비에서 덤프한 SysEx 파일을 표준 데이터처럼 사용하고 있는 것은 아닐까 하는 의심도 들었다. 그러나 X2에 Preload 데이터를 다시 로드한 뒤 실제 Program Edit 화면에서 확인해도 B09와 B69는 모두 B2를 사용하고 있었고, 별도로 살펴본 X3 Preload의 Program 데이터에서도 같은 관계가 확인되었다. 따라서 B1이 기본 Drum Program에서 사용되지 않는 것은 단순한 덤프 오류라기보다는 원래 그렇게 설계된 것으로 보인다.

그러나 X3DRUMS의 Program 데이터를 그대로 로드하면 X2의 Piano인 Program A01도 X3DRUMS의 A01로 덮어써진다. X2 Piano를 계속 사용하고 싶었기 때문에, X3DRUMS의 Program 데이터는 그대로 유지하면서 A01만 X2 Preload의 Piano 설정으로 교체하도록 ChatGPT에 지시하였다. 이렇게 만든 수정 SysEx를 사용하면 X3DRUMS에 필요한 Drum Program 설정을 유지하면서 X2의 A01 Piano도 함께 사용할 수 있다.

X3DRUMS User Pattern 목록
Song 제목 Pattern 길이 프리뷰용 Program / Drum Kit
S6 Rock&Roll! P00–P19 모두 2 bar A09 Total Kit / A1
S0 16 Beat P20–P29 모두 2 bar A09 Total Kit / A1
S9 Waltz1,2,3 P30–P35 모두 2 bar A09 Total Kit / A1
S7 Shuffels P36–P43 모두 2 bar A09 Total Kit / A1
S3* Latin&Perc P44–P59 모두 1 bar B69 Percussion / B1
S1* CntryPolka P60–P69 모두 1 bar B69 Percussion / B1
S2* Dance !!! P70–P79 모두 1 bar B09 Rave Kit / B2
S5* Rap!!! P80–P89 P80–85: 2 bar / P86–89: 1 bar B09 Rave Kit / B2
S4* Rap Filler P90–P94 모두 1 bar B09 Rave Kit / B2
S8 Slow Jams P95–P99 모두 1 bar A09 Total Kit / A1

* X2/X3 Preload 상태에서 X3DRUMS의 Song/Pattern 데이터만 로드하면 원래 의도한 음색으로 재생되지 않는 곡.

X3DRUMS에서 확인한 중요한 변경은 다음과 같다.

  • 기본 Preload에서는 사용되지 않던 B1 (Percussion Kit)을 Program B69가 사용하도록 변경하였다. B1 자체의 내용은 Preload와 동일하며, B69의 이름은 VeloGated에서 Percussion으로 바뀌었다.
  • B2 (Rave Kit)는 X3DRUMS에서 Drum Kit 자체의 내용이 대폭 변경되었다.

결론적으로 X2의 장점인 X2 Piano를 유지하면서 X3DRUMS의 드럼 패턴과 시퀀스를 원래 의도된 소리로 사용하는 방법은 다음과 같다.

  1. X2 Preload를 기본 상태로 삼는다.
  2. X3DRUMS_Drums.syx와 X3DRUMS의 Song/Pattern 데이터를 전송한다.
  3. X3DRUMS_Prog.syx에서 Program A01만 X2 Preload의 X2 Piano로 치환한 수정 SysEx를 전송한다. 이 파일은 두 Program dump를 ChatGPT에 주고 A01 데이터만 교체하도록 지시하여 만들었다.

X3DRUMS의 시퀀스 덤프에서 패턴 데이터를 풀어낸다고 해서 곧바로 표준 MIDI처럼 사용할 수 있는 것은 아니다. PC에서 MIDI 케이블을 통해 X2로 드럼 연주 정보를 보내려면 패턴 내부의 이벤트와 시간 정보가 실제 MIDI 메시지로 어떻게 대응되는지를 더 알아내야 한다. 특히 라이브 드럼머신처럼 PC에서 다음 패턴을 즉석에서 예약하고, 현재 패턴이 끝나는 다음 bar부터 정확히 전환하여 연주하려면 PC 쪽에서 패턴의 재생과 타이밍을 직접 관리해야 한다. X2에 저장된 User Pattern을 외부 MIDI에서 이런 방식으로 선택하고 전환하는 기능은 매뉴얼에서는 확인되지 않기 때문이다.

어휴, 차라리 이런 물건 갖고 노는 것이 정신 건강에 더 이롭지 않을까?


정신 건강에는 이런 물건이 낫고, 지적 유희에는 X2가 낫다. Ardule 드럼 패턴학 생태계까지 X2를 이어 보려는 것이 나의 장기적 목표이다.

신시사이저 역사에서 Korg X2/X3가 갖는 의미

Korg X2/X3는 신시사이저 역사에서 M1이나 Trinity, Triton처럼 새로운 시대를 연 기종은 아니다. 그러나 1980년대 말부터 1990년대 중반까지 이어진 Korg 워크스테이션의 발전 과정을 이해하기에는 꽤 흥미로운 악기이다.

요즘 두 기기의 '케미'가 아주 좋다. USB 케이블 형태의 MIDI 인터페이스는 '대용량' SysEx 전송에서 동작 불안정으로 인해 서랍 속으로 들어가 버렸다.

1988년에 등장한 M1은 PCM 기반 음원, 디지털 이펙트, 드럼과 시퀀서를 한 악기에 통합하면서 이른바 ‘뮤직 워크스테이션’이라는 악기 유형을 대중화했다. Korg 역시 M1이 워크스테이션이라는 새로운 악기 범주를 정의한 제품이라고 평가한다. 이후 T 시리즈를 거쳐 1991년에는 AI² 음원과 waveshaping을 채택한 01/W 시리즈가 등장했다.

X3는 1993년에 출시되었다. 내가 보유한 X2는 그 이듬해 등장한 76건반 모델(피아노 음색이 강화됨)이며, 2004년 3월에 천안 백석대학교 근처까지 가서 중고품을 구입하였다. 이들은 앞선 Korg 워크스테이션에서 발전해 온 AI² 계열의 PCM 음원 기술을 계승했다. X3의 경우 340개의 PCM multisound, 32음 동시발음, 두 개의 디지털 multi-effect processor, 16트랙 시퀀서와 32,000 event의 기록 용량을 갖추었다. 시퀀서에는 10개의 Song과 100개의 Pattern을 저장할 수 있었으며, 3.5인치 플로피디스크와 Standard MIDI File(SMF), General MIDI도 지원했다.

그러나 X2/X3가 기술적으로 새로운 시대를 연 것은 아니었다. 오히려 이미 상당히 성숙한 Korg의 PCM 워크스테이션 기술을 보다 실용적인 형태로 정리한 제품에 가까웠다. 01/W에 있었던 waveshaping도 X3에서는 사라졌다. 당시의 평가에서도 X3는 획기적인 신기술을 선보인 악기라기보다 기존 AI² 기술을 이용하여 가격과 기능의 균형을 맞춘 워크스테이션으로 받아들여졌다.

이 점은 전후의 Korg 제품을 함께 보면 더욱 분명해진다. X3보다 5년 앞선 1988년에는 역사적인 M1이 있었고, 1990년에는 독특한 Wave Sequencing과 Vector Synthesis를 내세운 Wavestation이 등장했다. 그리고 X2가 나온 바로 다음 해인 1995년에는 Trinity가 등장했다. Trinity는 터치스크린 기반의 TouchView 인터페이스와 당시로서는 고품질·대용량인 PCM, 다양한 확장 기능을 갖춘 새로운 세대의 플래그십 워크스테이션이었다. 1999년에는 그 계보를 이어 Triton이 등장했다.

따라서 Korg 워크스테이션의 역사를 아주 단순화한다면 다음과 같은 두 시대를 생각해 볼 수 있다.

M1 → T series → 01/W → X2/X3
      ↓
Trinity → Triton → 이후 세대

물론 이것은 엄밀한 제품 계보도가 아니라 기술과 제품 성격의 변화를 이해하기 위한 단순화이다. X2/X3 이후에도 AI² 계열 제품은 계속 출시되었다.

그렇다면 X2/X3의 역사적 가치는 무엇일까?

이 악기에는 1990년대 초반의 ‘워크스테이션’이라는 개념이 매우 전형적인 형태로 남아 있다. 컴퓨터를 사용하지 않고도 한 대의 건반악기에서 음색을 고르고 Combination을 만들고, 드럼 Pattern을 구성하고, 16트랙 Sequencer에 곡을 녹음한 뒤 플로피디스크에 저장한다. MIDI와 SysEx를 이용해 외부 기기와 데이터를 주고받고, GM/SMF를 통해 다른 환경에서 만들어진 곡을 재생할 수도 있다.

오늘날의 DAW 중심 작업 환경에서 보면 번거로운 방식이다. 하지만 바로 그렇기 때문에 X2/X3를 직접 사용해 보는 것은 1990년대 초반의 전자악기가 지향했던 ‘컴퓨터 없이 한 대에서 곡 전체를 만드는 작업 환경’을 경험하는 일이기도 하다.

X2/X3는 Korg 역사에서 가장 유명하거나 가장 혁신적인 신시사이저는 아니다. 오히려 M1에서 시작된 초기 PCM 워크스테이션 시대가 충분히 성숙한 시점에 등장한 실용적인 제품이라고 보는 편이 적절하다. 그리고 바로 다음 해 Trinity가 등장하면서 Korg의 워크스테이션은 새로운 세대로 넘어가기 시작했다.

그런 의미에서 X2는 ‘명기’라는 하기 어렵다. 그러나 한 시대의 기술과 음악 제작 방식을 잘 보존하고 있는 흥미로운 악기라고 부르는 편이 더 어울린다.

그러면 나는 2026년에 이르러 왜 이렇게 낡은 신시사이저인 X2에 집착하는가? 가장 큰 출발점은 아마도 일종의 ‘죄책감’이었을 것이다. 22년 전 결코 적지 않은 돈을 주고 중고로 구입했으면서도 제대로 활용하지 못한 채 오랫동안 방치해 두었다. 그동안 피아노 대용의 연습 악기로라도 꾸준히 사용했다면 지금쯤 내 연주 실력이 훨씬 나아졌으리라는 것은 자명하다.

두 번째 이유는 X2가 나의 DIY적 호기심을 자극하기 때문이다. 오래된 전자악기인 만큼 유지보수와 수리가 필요하고, 때로는 직접 개선해 볼 여지도 있다. 뜯어보고, 고치고, 데이터를 들여다보고, 원하는 기능을 만들어 보기에 아주 적당한 대상이다. 더구나 인공지능의 발전으로 과거의 나로서는 엄두를 내기 어려웠던 SysEx 분석이나 프로그래밍까지 직접 시도할 수 있게 되었다.

처음 다시 X2를 만지기 시작했을 때는 첫 번째 이유가 더 컸는지도 모르겠다. 하지만 지금은 분명히 두 번째 이유가 더 크다. X2는 이제 연주해야 할 오래된 악기인 동시에, 가지고 놀기에 아주 재미있는 오래된 기계가 되었다.

2026년 10월 6일 화요일

[KORG X2] 30년 된 신시사이저의 시퀀서 포맷을 파헤치다

집에 있는 Korg X2는 1990년대 초에 나온 신시사이저이다. USB 같은 것은 당연히 없고 데이터를 주고받으려면 플로피디스크나 MIDI를 이용해야 한다. 최근 고장 난 플로피 드라이브를 Gotek(USB 메모리를 이용하는 에뮬레이터)으로 바꿀까 고민하다가 엉뚱한 생각이 들었다. PC에 있는 MIDI 파일을 X2의 내장 시퀀서에 직접 집어넣을 수는 없을까?

PC에서 MIDI 파일을 재생하면서 X2를 음원으로 사용하는 것은 간단하다. 내가 해 보려는 것은 그것이 아니라 Standard MIDI File(SMF)을 X2의 시퀀서 데이터로 변환하여 SysEx로 보내는 것이었다.

다행히 X2/X3 Reference Guide에는 MIDI implementation이 꽤 자세히 나와 있다. X2의 시퀀서는 10개의 Song(S0~S9)과 100개의 User Pattern(P00~P99)을 저장할 수 있으며, 이것을 ALL SEQUENCE DATA라는 하나의 SysEx로 덤프할 수 있다. 실제 덤프를 풀어 보니 control data 뒤에 4 byte 단위의 Note, Program Change, Control Change, Pitch Bend 등의 event가 이어진다. 그렇다면 MIDI 파일의 event를 이것으로 바꾸어 SysEx로 전환하여 주면 될 것 같았다. GM 전용으로 할당된 S9를 목적지로 해야 한다.

시험곡은 Olivia Newton-John의 Physical이었다. 결코 쉽지는 않았다. 특히 velocity를 잘못 해석한 버전에서는 음이 거의 나오지 않고 틱틱 강하게 튀는 소리만 났다. 매뉴얼과 실제 dump를 다시 비교하여 고친 뒤 전송하니 드디어 X2의 S9에서 Physical이 제대로 연주되었다. 124 BPM도 정확했다. tempo를 달리 설정하여 받은 dump들을 비교해 보니 실제 저장값은 BPM - 30이라는 것도 알게 되었다. 다음은 MIDI 파일을 SysEx로 전환하여 X2로 전송하여 시퀀서의 S9 영역에 넣은 다음 재생하는 모습을 촬영하는 것이다. 오디오와 비디오를 따로 기록한 뒤 합치는 바람에 싱크가 썩 잘 맞지는 않는다.



처음에는 변환할 때 X2에서 받아 놓은 기존 sequence dump를 template으로 사용했다. 그런데 생각해 보니 굳이 그럴 필요가 없었다. X2에는 전원을 켤 때 S0~S9과 P00~P99를 모두 지우는 기능이 있다. 그렇게 완전히 비운 뒤 바로 dump를 받으니 4,240 byte짜리 아주 작은 SysEx가 생겼다. X2 자신이 만들어 준 빈 시퀀서인 셈이다. 이것을 converter 안에 넣어 버렸다. 이제 MIDI 파일 하나만 주면 빈 X2 시퀀서를 만들고 S9에 곡을 채워 넣을 수 있다. 기존 dump를 template으로 주면 S0~S8과 Pattern은 그대로 두고 S9만 바꾸어 준다.

중간에 MIDI 전송 때문에 엉뚱한 곳에서 고생하기도 했다. 싸구려 USB-MIDI 케이블로 큰 SysEx를 보내면 MIDI-OX에서는 끝났다고 하는데 X2는 계속 Processing... 상태에 머물렀다. Mackie Onyx Producer 2•2의 MIDI 인터페이스 기능을 사용하자 문제가 사라졌다. 현재 MIDI-OX에서는 input buffer 256 bytes × 32, output buffer 1024 bytes × 128, Auto-adjust Buffer Delays를 켜 놓고 사용한다.



SysEx의 크기가 40KB 정도 넘어가면 버퍼가 부족하다는 에러 메시지가 자꾸 나와서 애를 먹었다. 그 원인으로서 Windows의 새로운 MIDI Server 기능도 의심했다. 그래서 관리자 권한으로 PowerShell을 열고 다음 명령을 실행하여 기존 Legacy MIDI 방식을 사용하도록 설정한 뒤 Windows를 재부팅했다.

reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32" /v UseLegacyMidi /t REG_DWORD /d 1 /f

재부팅 뒤에는 다음 명령으로 MidiSrv.exe가 실행되고 있는지 확인했다. 단, 재부팅 직후에는 보이지 않을 수 있다. 새 MIDI 서비스를 사용하는 프로그램이나 장치가 서비스를 요청하였을 때에만 tasklist에 보이는 것이 기본이라 한다. 

tasklist | findstr /I MidiSrv 

아무것도 출력되지 않는 것을 확인했다. 적어도 이 상태에서는 MidiSrv.exe가 실행되고 있지 않았다. 원래 설정으로 되돌리려면 같은 레지스트리 값을 0으로 바꾸고 다시 재부팅하면 된다.

reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32" /v UseLegacyMidi /t REG_DWORD /d 0 /f

다만 이것이 SysEx 전송 문제를 해결한 결정적인 조치였다고 보기는 어렵다. 나중에 USB-MIDI 케이블 대신 Mackie Onyx Producer 2•2의 MIDI 단자를 사용하자 전송이 안정되었기 때문이다. 따라서 당시 문제의 원인은 Windows MIDI Services보다는 사용하던 USB-MIDI 인터페이스였을 가능성이 더 크다.

지금 프로그램 이름은 midi_to_korg_x2_s9_v6_1.py이다. 너무 길다. 앞으로는 이름을 SyX2ool이라고 바꾸어 볼 생각이다. 이는 SYX + X2 + Tool의 합성어이자 말장난이다. 향후 다음과 같은 subcommand 방식으로 개발을 완결할 것이다.

예:

syx2ool import
syx2ool export
syx2ool analyze
syx2ool compare

아직 할 일이 있다. 지금은 MIDI 파일을 X2의 S9으로 보내는 방향이 중심인데, 다음에는 반대로 X2에서 받은 sequence dump의 S0~S8을 각각 SMF Format 1으로 변환해 보려고 한다. User Pattern을 사용한 부분은 실제 MIDI event로 풀어내야 하므로 조금 더 분석이 필요하다. 이것까지 되면 MIDI → X2 SysEx → MIDI의 왕복 변환도 시험할 수 있다.

이 정도면 리버스 엔지니어링이라고 거창하게 부를 일은 아니다. Korg가 옛날 매뉴얼에 자료를 상당히 잘 남겨 놓았다. 매뉴얼을 읽고, X2가 내놓는 byte를 비교하고, 프로그램을 고쳐서 다시 집어넣어 보는 일을 반복했을 뿐이다. 이 과정에서 ChatGPT의 도움을 많이 받았다.

그래도 30년 넘은 신시사이저가 내가 만든 데이터로 Physical을 연주하기 시작했을 때는 꽤 재미있었다. 이래서 오래된 기계를 쉽게 버리지 못한다.


2026년 10월 5일 월요일

[KORG X2] 오후 내내 RAG를 만지작거리다가 원래 자리로 돌아왔다

오늘 오전에는 Korg X2/X3 매뉴얼을 좀 더 편하게 찾아보기 위한 작은 프로그램을 만들었다(원본 글). 가지고 있는 매뉴얼 PDF는 오래된 스캔 자료라서 텍스트를 직접 검색할 수 없다. 우선 OCR을 거쳐 각 페이지의 글자를 추출하고, 어느 매뉴얼의 몇 번째 PDF 페이지에서 나온 글인지 알 수 있도록 JSON 파일로 정리하였다. 여기에 Ollama에서 로컬로 실행하는 qwen3:1.7b를 이용하여 한국어 질문을 검색에 적합한 영어 표현으로 바꾸고, 관련성이 높은 매뉴얼 페이지를 찾아주는 기능을 붙였다. 검색된 페이지는 원래 PDF의 모습 그대로 화면에서 볼 수 있게 하였다.

처음에는 검색된 내용을 다시 언어모델에 넘겨 질문에 대한 답까지 만들어 보기도 했다. 그런데 여기에서 작은 문제가 발견되었다. 검색된 원문에는 없는 용어나 수치를 언어모델이 그럴듯하게 만들어 답에 섞는 일이 있었다. 오래된 신시사이저의 사용법을 알아보려고 매뉴얼을 찾는 것인데, 없는 기능을 AI가 만들어내면 곤란하다. 그래서 AI가 답을 대신 써 주게 하는 것보다 관련된 원문 페이지를 잘 찾아서 내가 직접 읽는 것이 이 용도에는 더 안전하겠다는 생각이 들었다.

그렇게 해서 오전 작업의 결과물은 거창한 AI 챗봇이라기보다는 일종의 지능형 매뉴얼 검색기에 가까워졌다. 한국어로 질문하면 관련성이 높은 페이지 몇 개를 제시하고, 그중 하나를 선택하면 실제 매뉴얼 페이지를 보여준다. Basic Guide와 Reference Guide의 목차를 이용해서 직접 찾아 들어갈 수도 있다. 인터넷 연결도 필요 없고 API 사용료도 들지 않는다. 드럼 키트의 편집 위치나 snare drum의 pitch 조정처럼 구체적인 질문에는 꽤 쓸 만한 페이지를 찾아 주었다. 여기까지만 해도 처음 원했던 것은 거의 이루어진 셈이었다.

그런데 오후가 되자 욕심이 생겼다. 예를 들어 “왼손으로는 베이스, 오른손으로는 피아노를 연주하려면 어떻게 하나?”와 같은 질문을 생각해 보았다. 사람이라면 이것이 건반을 두 영역으로 나누는 split 설정에 관한 질문이라는 것을 쉽게 알아듣는다. Korg X2의 구조를 조금 아는 사람이라면 Combination에서 각 Timbre의 Key Window를 설정하는 부분을 찾아야 한다는 것도 짐작할 수 있다. 그러나 작은 언어모델과 단순한 검색의 조합은 반드시 그렇게 생각하지 않았다.

여기에서 오후의 삽질이 시작되었다. 요즘 문서 기반 AI를 이야기하면 빠지지 않고 등장하는 것이 RAG(Retrieval-Augmented Generation), 즉 검색 증강 생성이다. 오전에 만든 프로그램도 넓게 보면 검색한 원문을 언어모델과 연결한다는 점에서 아주 단순한 RAG라고 할 수 있다. 그렇다면 조금 더 제대로 된 RAG 방식을 적용하면 검색 성능이 좋아지지 않을까 하는 생각이 들었다.

우선 페이지 전체를 검색 단위로 삼는 것이 문제일 수 있다고 생각하여 매뉴얼의 OCR 텍스트를 작은 덩어리, 즉 chunk로 나누었다. Basic Guide와 Reference Guide를 합쳐 모두 609개의 chunk가 만들어졌다. 결과를 직접 살펴보니 나누어진 모양 자체는 제법 괜찮았다. Split과 관련된 Key Window 설명도 적절한 덩어리로 잡혔고, snare drum의 Tune이나 tempo 설정에 관한 설명도 잘 나뉘어 있었다.

다음에는 각 chunk의 의미를 숫자로 표현하는 embedding을 만들었다. Ollama에서 nomic-embed-text 모델을 사용하였다. 609개의 chunk를 모두 embedding하는 데 내 노트북에서 약 249초가 걸렸다. 질문도 같은 방법으로 벡터로 만들면 단어가 정확하게 일치하지 않더라도 의미가 비슷한 설명을 찾을 수 있을 것이라고 기대하였다.

여기에 CrossEncoder라는 것도 동원하였다. embedding 검색으로 우선 후보를 뽑고, 질문과 각각의 후보를 다시 함께 비교하여 관련성을 좀 더 정밀하게 평가하는 reranking 방식이다. 문서 검색에서는 이미 널리 사용되는 전형적인 2단계 구조라고 한다. 처음에는 609개 chunk를 전부 CrossEncoder로 비교해 보았는데 너무 느렸고, 그래서 embedding으로 상위 20개 후보를 먼저 고른 뒤 그 후보만 다시 순위를 매기는 방식으로 바꾸었다. 어느새 오래된 신시사이저 매뉴얼을 좀 편하게 읽겠다는 일이 작은 정보검색 실험으로 변하고 있었다.

결과는 흥미로웠다. Snare pitch나 tempo처럼 질문과 매뉴얼의 용어가 비교적 잘 대응하는 경우에는 아주 잘 작동하였다. 정답에 해당하는 chunk가 embedding 검색에서 처음부터 1위에 들어왔고 reranking을 거친 뒤에도 1위를 유지하였다. 하지만 정작 개선하고 싶었던 split 질문은 그렇지 않았다. 관련된 Key Window chunk 하나가 embedding 검색 후보 16위에 겨우 들어왔고 reranking 뒤에는 5위가 되었다. 더 직접적으로 관련된 다른 chunk는 상위 20개 후보에도 들어오지 못했다. 엉뚱한 effect 관련 설명이 최종 1위를 차지하는 경우도 있었다.

검색 한 번에는 3초 남짓이 걸렸다. 오전에 만든 단순한 검색보다 구조는 훨씬 복잡해졌지만 결과가 그만큼 좋아졌다고 하기는 어려웠다. “왼손은 베이스, 오른손은 피아노”라는 일상적인 표현과 “Combination mode의 Timbre별 Key Window”라는 Korg X2의 전문 용어 사이에는 상당한 의미의 간격이 있다. 문서를 잘게 나누고 벡터를 만들고 순위를 다시 매긴다고 해서 그 간격이 저절로 사라지는 것은 아니었다.

그러다 문득 내가 왜 이 일을 하고 있는지를 다시 생각하게 되었다. 내가 필요한 것은 Korg X2에 관한 질문이라면 무엇이든 대답하는 인공지능이 아니다. 오래된 매뉴얼 두 권에서 내가 읽어야 할 페이지를 빨리 찾아주는 도구가 필요했을 뿐이다. 그렇게 생각하고 나니 오전에 만든 단순한 프로그램이 다시 달리 보였다.

질문을 입력하면 관련성이 높은 페이지 세 개 정도가 나온다. 그중 하나를 선택하여 원본 매뉴얼을 읽고, 설명이 앞뒤로 이어진다면 화살표를 눌러 한 페이지씩 넘겨 보면 된다. 결국 오후 늦게 프로그램에 추가한 가장 유용한 기능은 복잡한 RAG 기법이 아니라 PDF 페이지를 앞뒤로 넘기는 좌우 화살표였다. PDF를 작게 만드는 별도의 버튼도 처음에는 만들어 보았지만 그것조차 필요 없었다. 브라우저 창의 폭을 조절하면 PDF도 선명한 상태로 따라서 줄어든다. 몇 시간 동안 embedding, chunking, reranking을 돌아다닌 뒤 도착한 곳은 결국 책에서 관련 페이지를 찾아 앞뒤로 넘겨 읽는 방식이었다.

오늘 오후의 경험에서 얻은 교훈은 RAG나 embedding의 원리를 조금 더 알게 되었다는 것만은 아니다. 오히려 이미 잘 알려진 문제를 너무 처음부터 다시 풀려고 했다는 생각이 들었다. 문서 검색에는 오랫동안 사용되어 온 방법이 있고, embedding 검색과 reranking 역시 각각 어디에서 유용하고 어떤 한계를 갖는지 많은 사람이 이미 경험하였다. 그런데 AI가 코드를 척척 만들어 주니 “이것이 잘 안 되면 이것도 붙여 보자”는 식으로 하나씩 직접 시험하게 되었고, 어느 순간 남들이 이미 겪은 시행착오를 작은 Korg 매뉴얼 두 권을 가지고 다시 재현하고 있었다.

생각해 보면 AI를 이용한 프로그래밍에서 이것은 꽤 조심해야 할 점이다. 예전에는 새로운 방법을 시험하려면 코드를 작성하는 비용이 컸기 때문에 시작하기 전에 방법을 충분히 조사할 수밖에 없었다. 지금은 AI에게 부탁하면 몇 분 안에 다음 실험을 위한 코드가 나온다. 구현 비용이 낮아진 덕분에 오히려 충분히 조사하지 않고 여러 방법을 차례로 시험해 보는 일이 쉬워졌다. 코드를 빨리 만들 수 있다는 것과 문제를 빨리 해결한다는 것은 같은 뜻이 아니다.

다음에는 순서를 조금 바꾸어야겠다. 먼저 내가 풀려는 문제가 이미 어떤 이름으로 불리는지 알아보고, 그 문제에 널리 쓰이는 가장 단순한 방법이 무엇인지 찾아보는 것이 먼저다. 그것을 구현하여 실제로 써 본 뒤 부족한 점이 확인되었을 때에만 다음 단계를 추가하면 된다. AI 시대에는 코드를 만드는 비용이 크게 낮아졌다. 그래서 역설적으로 무엇을 더 만들 것인가보다 무엇을 만들지 않을 것인가를 판단하는 일이 더 중요해졌는지도 모르겠다.

609개의 chunk를 embedding하느라 노트북이 249초 동안 열심히 일한 것은 아마 그것을 배우기 위한 수업료였을 것이다. 다행히 API 사용료는 들지 않았다. 전기료는 조금 들었겠지만.

[KORG X2] 거창한 RAG 챗봇을 만들려다가 소박한 매뉴얼 검색기 구현으로 끝내다

며칠 전 오래된 Korg X2/X3 신시사이저의 매뉴얼을 뒤적이다가 한 가지 생각을 했다. Basic Guide와 Reference Guide를 AI에게 모두 읽혀 놓고 한국어로 질문하면 매뉴얼을 근거로 답해 주는 개인용 챗봇을 만들 수 있지 않을까? 요즘 흔히 말하는 RAG(Retrieval-Augmented Generation)를 로컬 PC에서 구현하면 될 것 같았다. 매뉴얼에서 질문과 관련된 내용을 검색하고, 그것을 로컬에서 실행되는 LLM에 넘겨 답을 만들게 하는 것이다. 별도의 API 사용료 없이 내 노트북에서 모든 것을 처리한다는 것도 매력적으로 느껴졌다.

처음 기대한 것은 제법 그럴듯했다. “드럼 키트는 어디에서 편집하지?”, “패턴을 트랙에 넣으려면?”, “MIDI로 Program을 선택하는 방법은?”과 같이 한국어로 물어보면 AI가 매뉴얼에서 근거를 찾아 답해 주는 시스템을 생각했다. 그러나 며칠 동안 작은 모델과 임베딩, OCR, 여러 단계의 답변 생성 방법을 시험해 본 끝에 결과물은 처음 구상과 상당히 달라졌다. 내 노트북의 제한된 자원으로 무엇을 할 수 있고, 무엇을 굳이 하지 않는 편이 나은지를 알아 가면서 목표 자체가 바뀌었기 때문이다. 내가 쓰는 노트북은 2022년 여름 용산에서 구입한 ThinkPad E14 Gen3이다(구입 당시 쓴 글).

Python 작업 환경부터 만들기

Windows에서 프로젝트 폴더를 하나 만들고 Python 가상환경(venv)을 만들었다. Python은 3.11을 사용했다. PowerShell에서 프로젝트 디렉터리로 이동한 다음 다음과 같이 가상환경을 만들고 활성화하였다.

python -m venv .venv
.\.venv\Scripts\Activate.ps1

PowerShell의 실행 정책 때문에 활성화가 막힌다면 현재 세션에 한해서 다음과 같이 허용할 수 있다.

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\.venv\Scripts\Activate.ps1

필요한 Python 패키지도 설치하였다. 최종적으로 남은 프로그램만 생각한다면 다음 정도면 된다.

python -m pip install --upgrade pip
pip install streamlit pymupdf requests pillow pytesseract

PDF가 스캔 이미지이므로 OCR을 위해 Tesseract도 별도로 설치했다. 여기에서 처음 접하는 사람이라면 조금 헷갈릴 수 있는데, pip install pytesseract로 설치되는 것은 OCR 프로그램 자체가 아니다. pytesseract는 Python에서 Tesseract를 호출하기 위한 인터페이스이고, 실제 Tesseract OCR 프로그램은 Windows에 따로 설치해야 한다.

처음에는 임베딩을 이용한 검색도 시도했기 때문에 다음 패키지도 설치하였다.

pip install sentence-transformers numpy

그러나 이것들은 최종 프로그램에서는 사용하지 않게 되었다. 시행착오를 그대로 재현하려는 것이 아니라면 설치할 필요가 없다.

스캔한 매뉴얼을 검색할 수 있게 만들기

내가 가지고 있는 Korg X2/X3 매뉴얼은 텍스트가 포함된 PDF가 아니라 스캔한 문서다. 따라서 PDF 파일을 열었다고 해서 Drum Kit나 Pattern 같은 단어를 곧바로 검색할 수 있는 것은 아니었다. PyMuPDF로 PDF의 각 페이지를 읽어 이미지로 만들고 Tesseract로 OCR을 수행한 뒤, 페이지별로 추출된 텍스트를 manual_index.json이라는 파일에 저장했다.

구조를 단순하게 표현하면 다음과 같다.

Basic Guide
  PDF page 1 → OCR text
  PDF page 2 → OCR text
  ...

Reference Guide
  PDF page 1 → OCR text
  PDF page 2 → OCR text
  ...

OCR 결과는 물론 완벽하지 않았다. 오래된 영문 매뉴얼을 읽히다 보니 170을 17O로 읽거나 171이 전혀 엉뚱한 문자로 변하는 일도 있었다. 그래도 내가 원하는 것은 완벽한 전자책을 만드는 것이 아니라 관련 페이지를 찾는 것이므로, Drum Kit, Pattern, MIDI Data Dump, Program Change 같은 기술 용어가 대체로 제대로 인식되는 정도면 충분했다.

RAG라면 임베딩부터 해야 하는 줄 알았다

RAG라는 말을 처음 접하면 문서를 잘게 나누고 임베딩(IBM의 짧은 설명)을 만들어 벡터 검색을 해야 할 것 같은 생각부터 든다. 나도 그렇게 시작했다. paraphrase-multilingual-MiniLM-L12-v2를 사용하여 288페이지의 매뉴얼을 384차원의 벡터로 만들고 manual_embeddings.npy라는 파일로 저장하였다. 한국어로 질문해도 의미가 비슷한 영문 매뉴얼 페이지를 찾아줄 것이라고 기대했다.

여기서 ‘문서를 잘게 나눈다’는 것은 긴 문서 전체를 한꺼번에 검색 대상으로 삼지 않고, 몇 문단이나 한 페이지 정도의 작은 단위로 쪼개는 것을 뜻한다. 그리고 ‘임베딩(embedding)’은 각각의 작은 문서 조각을 그 내용의 특징을 나타내는 여러 개의 숫자로 바꾸는 과정이다. 이렇게 만들어진 숫자의 묶음을 벡터(vector)라고 한다. 질문도 같은 방법으로 벡터로 바꾼 뒤, 질문 벡터와 가까운 문서 벡터를 찾으면 단어가 정확히 일치하지 않아도 의미가 비슷한 내용을 찾을 수 있다. 이것이 여기서 말하는 벡터 검색이다.

그런데 실제로 시험해 보니 이 매뉴얼에서는 생각만큼 만족스럽지 않았다. 내가 찾고 싶은 것은 문장의 추상적인 의미가 비슷한 페이지라기보다 Drum Kit Setup, Put to Track, Program Change, MIDI Data Dump처럼 매뉴얼에 실제로 쓰인 기술 용어가 등장하는 곳이었다. 그렇다면 굳이 모든 페이지를 벡터로 바꾸어 의미상의 거리를 계산하기보다, 한국어 질문을 매뉴얼에서 사용될 법한 영어 검색어로 잘 바꾼 다음 전통적인 문자열 검색을 하는 편이 나을 수도 있었다.

이것은 이번 작업에서 처음으로 목표를 크게 줄인 지점이었다. 임베딩 검색이 나쁜 기술이라는 뜻은 아니다. 내가 가진 자료의 양과 성격, 그리고 찾으려는 정보의 종류에는 더 단순한 방법이 잘 맞았다는 뜻이다.

작은 로컬 LLM에게 너무 많은 일을 시켰다

로컬 LLM은 Ollama를 통해 실행했다. 처음에는 Qwen 모델에게 질문을 영어 검색어로 바꾸는 일뿐 아니라 검색된 매뉴얼 내용을 읽고, 적절한 근거인지 판단하고, 마지막에는 한국어 답변까지 작성하도록 했다. 관련 없는 질문을 걸러 내는 relevance gate도 붙여 보고, 한 번의 호출로 잘 안 되면 두 번, 세 번에 나누어 일을 시키는 방법도 시험했다.

Qwen은 중국의 Alibaba Cloud가 개발하는 AI 언어 모델 계열이고, Ollama는 미국의 Ollama가 개발하는 로컬 AI 모델 실행 소프트웨어다. Qwen 자체는 일반 응용 프로그램이라기보다 문장을 이해하고 생성하도록 학습된 AI 모델이며, Ollama는 Qwen을 비롯한 여러 언어 모델을 내 컴퓨터에 내려받아 쉽게 실행하고 다른 프로그램에서 호출할 수 있게 해 준다. 이번 작업에서는 Ollama를 설치하고, 이를 통해 비교적 작은 Qwen 3 계열의 1.7B 모델(qwen3:1.7b)을 내 노트북에서 실행하였다.

문제는 내 노트북에 별도의 GPU가 없다는 것이다. Qwen 1.7B 정도의 작은 모델은 CPU만으로도 비교적 부담 없이 실행되었지만, 매뉴얼을 정확하게 해석하여 답을 만드는 일에서는 신뢰하기 어려운 경우가 있었다. 원문에는 분명히 Global Mode라고 적혀 있는데 답을 만드는 과정에서 다른 모드로 바꾸어 말하는 식의 오류가 생겼다. 더 큰 4B급 모델도 시험했지만 이번에는 기다리는 시간이 현실적인 문제가 되었다. 좋은 답 하나를 얻기 위해 매번 오래 기다려야 한다면 매뉴얼을 직접 펼쳐 보는 것보다 나을 것이 없다.

그렇다고 작은 모델이 쓸모없는 것은 아니었다. 오히려 일을 하나만 시키니 제법 잘했다. “답하지 말고, 한국어 질문을 이 영문 매뉴얼에서 검색하기 좋은 영어 단어로 바꾸어라”라고 역할을 제한한 것이다. 예를 들어 “드럼 키트를 편집하려면?”이라는 질문을 넣으면 drum kit edit setup global mode와 같은 검색어를 만들어 주고, “패턴을 트랙에 넣으려면?”이라고 하면 pattern put to track assign pattern track과 같은 결과를 내놓았다. 이 정도의 일은 1.7B 모델도 빠르고 제법 안정적으로 해냈다.

결국 검색 알고리즘은 아주 단순해졌다

LLM이 영어 검색어를 만들어 주고 나면 그다음부터는 AI라고 부를 만한 것도 별로 없다. OCR한 각 페이지에서 검색어가 얼마나 많이 등장하는지를 세고 점수를 주었다. 검색어 전체가 그대로 등장하면 추가 점수를 주는 정도의 단순한 방식이다.

핵심 아이디어를 단순화하면 다음과 같다.

def score_page(text, query):
    text = text.lower()
    query = query.lower()

    score = 0

    if query in text:
        score += 100

    for term in query.split():
        score += text.count(term) * 5

    return score

이렇게 해도 의외로 결과가 괜찮았다. 예를 들어 GM Song을 재생하는 방법을 묻는 질문에서 LLM이 gm song play라는 검색어를 만들면 Basic Guide의 Playing GM Songs가 있는 페이지가 상위에 나온다. 드럼 키트 편집을 물으면 Reference Guide의 Global Mode에 있는 Drum Kit Setup 페이지가 잘 검색된다. 기술 매뉴얼에서는 용어 자체가 상당한 정보를 가지고 있기 때문에 가능한 일일 것이다.

AI에게 답을 쓰게 하지 말고 원본 페이지를 보여 주자

여기에서 다시 한 번 방향을 바꾸었다. 검색된 OCR 텍스트를 작은 LLM에게 넘겨 답을 작성하게 하는 대신, 검색된 원본 PDF 페이지를 그대로 브라우저에 보여 주기로 했다. OCR은 어디까지나 검색용으로만 사용하고, 사람이 실제로 읽는 것은 스캔된 원래 매뉴얼이다.

이렇게 하니 여러 문제가 한꺼번에 사라졌다. OCR이 일부 문자를 잘못 인식하더라도 검색만 성공하면 원본 페이지에서 정확한 내용을 확인할 수 있다. 작은 LLM이 근거 문장을 잘못 해석하거나 그럴듯한 설명을 덧붙이는 문제도 없다. 무엇보다 내가 원하는 것은 Korg X2에 대해 유창하게 설명하는 AI가 아니라, 200쪽이 넘는 Reference Guide에서 필요한 페이지를 빨리 찾는 도구라는 사실이 분명해졌다.

결국 현재 프로그램의 처리 과정은 다음과 같이 단순해졌다.

한국어 질문
    ↓
Qwen 1.7B
    ↓
영문 매뉴얼용 검색어
    ↓
OCR 텍스트 검색
    ↓
관련 페이지 선정
    ↓
원본 PDF 페이지 표시

전형적인 RAG라면 마지막 단계에서 검색된 문서를 LLM에 다시 넣고 답변을 생성할 것이다. 내 프로그램은 그 단계를 아예 없애 버렸다. 따라서 이제 이것을 RAG 챗봇이라고 부르는 것은 적절하지 않다. “자연어로 매뉴얼 검색” 정도가 지금 하는 일을 가장 정확하게 표현한다.

Streamlit으로 검색 화면 만들기

사용자 인터페이스는 Streamlit으로 만들었다. 프로그램을 실행하는 방법은 간단하다.

streamlit run app.py

브라우저에는 Search, Basic Guide, Reference Guide의 세 탭이 나타난다. Search 탭에서 한국어나 영어로 궁금한 내용을 입력하면 관련도가 높은 Basic Guide와 Reference Guide 페이지를 각각 찾아 준다. 검색 결과 가운데 하나를 선택하면 바로 아래에 원본 PDF 페이지가 표시되고, 필요하면 앞뒤 페이지도 함께 볼 수 있게 하였다.

Basic Guide와 Reference Guide 탭은 전자 목차처럼 만들었다. 원래 매뉴얼의 Table of Contents를 OCR한 뒤 오류가 난 페이지 번호를 확인하여 별도의 toc.json으로 정리했다. Chapter와 Section을 선택하면 해당 원본 페이지로 바로 이동한다. 오래된 종이 매뉴얼을 스캔한 PDF가 이제는 검색과 목차 이동이 가능한 작은 웹 애플리케이션이 된 셈이다.

시행착오가 사라지고 남은 파일들

개발 중에는 여러 방법을 시험하느라 ask_manual_2call.py, ask_manual_3call_gate.py, ask_manual_grounded.py, search_embedding.py, build_embeddings.py 같은 파일이 계속 생겨났다. 이름만 보아도 작은 LLM에게 어떻게든 정확한 답을 만들어 내게 하려고 애쓴 흔적이 남아 있었다. 최종 방향을 정한 뒤에는 이런 실험용 파일과 임베딩 데이터도 모두 지웠다.

현재 남아 있는 것은 다음 정도다.

x2-assistant/
│
├─ .venv/
├─ manuals/
│  ├─ basic.pdf
│  └─ reference.pdf
│
├─ app.py
├─ build_index.py
├─ manual_index.json
└─ toc.json

app.py가 Streamlit 애플리케이션이고, manual_index.json에는 검색용 OCR 텍스트가 들어 있다. toc.json은 두 매뉴얼의 목차 이동에 사용하며, build_index.py는 나중에 PDF에서 OCR 인덱스를 다시 만들어야 할 경우를 대비해 남겨 두었다. 처음 생각했던 시스템에 비하면 놀랄 만큼 단출하다.

API, 로컬 LLM, RAG를 직접 만져 보면서

이번 일을 시작하기 전에는 API를 이용하는 AI와 내 컴퓨터에서 직접 돌리는 LLM의 차이, RAG에서 retrieval과 generation이 각각 무슨 역할을 하는지, 임베딩 검색이 왜 필요한지 같은 개념을 막연하게만 알고 있었다. 직접 만들어 보니 이런 용어들이 조금씩 구체적으로 느껴졌다. 특히 LLM을 사용한다고 해서 모든 단계를 LLM에게 맡길 필요는 없다는 점이 인상적이었다.

성능 좋은 외부 AI의 API를 사용했다면 검색된 몇 페이지를 넘겨서 꽤 훌륭한 답을 만들 수도 있었을 것이다. 그러나 이번에는 별도의 API 비용 없이 내 노트북 안에서 해결하는 것이 조건이었다. 그렇다면 CPU에서 작은 모델이 잘할 수 있는 일과 기존 프로그램이 훨씬 잘할 수 있는 일을 나누는 것이 합리적이다. 한국어 질문을 영어 기술 용어로 바꾸는 것은 작은 LLM에게 맡기고, 단어를 세어 페이지를 찾는 일은 평범한 Python 코드에 맡기며, 최종 판단은 원본 문서를 읽는 사람이 하도록 했다.

거창하게 시작했지만 이 정도가 오히려 쓸 만하다

처음에는 “내 노트북에서 돌아가는 Korg X2 전용 RAG 챗봇”을 생각했다. 임베딩을 만들고, 관련 문장을 추출하고, relevance gate를 붙이고, LLM을 여러 번 호출하면서 어떻게든 그럴듯한 답을 만들어 보려고 했다. 그러나 CPU만 사용하는 노트북에서 큰 모델을 돌리는 데에는 한계가 있었고, 작은 모델에게 복잡한 판단까지 맡기면 정확도가 마음에 들지 않았다. 결국 많은 기능을 하나씩 걷어 내고 작은 LLM, 단순한 문자열 검색, OCR 인덱스와 PDF 뷰어만 남겼다.

결과적으로 목표는 상당히 작아졌지만 실제 용도에는 오히려 더 잘 맞는다. 내가 필요한 것은 30년 된 신시사이저에 대해 AI와 대화를 나누는 것이 아니라, “Put to Track이 어디에 있었지?”라고 물었을 때 Reference Guide의 해당 페이지를 바로 펼쳐 주는 도구이기 때문이다. 제한된 컴퓨터 자원 때문에 타협했다고 생각할 수도 있지만, 며칠 동안 이것저것 만들어 보고 지우면서 느낀 것은 조금 다르다. AI를 얼마나 많이 사용하는가보다, AI에게 무슨 일을 맡기고 무슨 일은 맡기지 않을지를 정하는 것이 더 중요했다.

'자연어로 매뉴얼 찾기'는 약간 과장이다.

이번 작업은 거창한 AI 개발 프로젝트라기보다 AI를 직접 만져 본 나의 첫 작은 실험에 가까웠다. 그동안 AI를 이용하거나 관련 이야기를 접할 기회는 많았지만, 로컬 LLM을 직접 설치하고 임베딩을 만들어 검색해 보고, 작은 모델에게 답변을 시키면서 그 한계를 확인해 본 것은 이번이 처음이었다. 그런데 그 첫 경험이 업무에서가 아니라, 30년 된 신시사이저의 매뉴얼을 좀 더 편하게 찾아보겠다는 취미 프로젝트에서 이루어졌다는 점도 재미있다. 모든 일을 AI에게 맡기기보다 AI가 잘하는 작은 역할만 맡기고 나머지는 기존의 단순한 프로그램으로 처리하는 편이 더 나을 때가 있다는 것도 직접 확인했다. RAG나 임베딩, 로컬 LLM 같은 용어 역시 글로 읽을 때보다 직접 만들고 실패해 보니 훨씬 구체적으로 이해할 수 있었다.

이제 X2를 Ardule에서 어떻게 써먹을까?

이렇게 매뉴얼을 다시 들여다보고 SysEx와 MIDI 구조까지 조금씩 이해하게 된 이유는 결국 하나다. 30년이나 된 Korg X2를 지금 내가 만들고 있는 Ardule 생태계에서 어떻게 활용할 수 있을까? X2의 시퀀서나 패턴 기능을 오늘날의 소프트웨어로 그대로 흉내 낼 필요는 없을 것이다. 그런 일은 Raspberry Pi와 소프트웨어가 훨씬 자유롭게 할 수 있다. 대신 X2에는 지금도 쓸 만한 고유한 음색과 드럼 키트, Program과 Combination이 있고, MIDI와 SysEx를 이용하면 외부에서 이들을 꽤 세밀하게 제어할 수 있다.

따라서 Ardule에서는 FluidSynth와 SoundFont를 주된 음원으로 사용하면서 X2를 선택적으로 불러 쓰는 외부 하드웨어 음원으로 두는 것이 재미있을 것 같다. Ardule이 곡이나 연주 상황에 따라 MIDI 채널을 배분하고 Program이나 Combination을 선택하며, 필요한 경우 미리 준비한 SysEx를 보내 X2의 상태를 설정하는 식이다. 오래된 X2의 패턴을 분석하여 유용한 리듬은 Ardule 쪽의 패턴 라이브러리로 가져올 수도 있다. 그렇게 하면 X2의 낡은 시퀀서를 억지로 중심에 놓지 않으면서도 그 안에 들어 있는 소리와 데이터는 계속 활용할 수 있다.

어쩌면 이번 매뉴얼 검색기 만들기도 그 과정의 일부였던 셈이다. 1990년대의 신시사이저와 Raspberry Pi, Arduino, SoundFont, 그리고 이제는 로컬 LLM까지 한데 섞이기 시작했다. 서로 만들어진 시대도 다르고 원래 함께 쓰라고 만들어진 물건들도 아니지만, 필요한 부분만 골라 연결하는 것이 내가 생각하는 Ardule의 재미다. X2가 언제까지 정상적으로 작동할지는 모르겠지만, 적어도 당분간은 창고로 들어갈 이유가 하나 더 줄었다.

다음은 X2 하판을 고정하는 screw boss를 보강한 어제의 작업 결과를 사진으로 남긴 것이다. 


분해 조립을 자주 하면서 플라스틱으로 만들어진 나사산도 많이 뭉개지고, 몇 개의 보스는 갈라져 버렸다. 여기에 알리익스프레스에서 구입한 내경 8mm 스틸 무나사 스페이서를 끼워서 더 이상 갈라지지 않게 보강한 것이 주요 내용이다. 내경 9mm짜리를 구입했더라면 보스의 바깥을 갈아내느라 고생을 하지 않아도 되었을 것이다. 들어가다 만 것을 빼느라 플라이어로 이 금속 부품을 꽉 잡고 좌우로 돌려서 비틀었더니 보스 하나가 부러지는 사고를 치는 바람에 응급 수술도 하였다.


아직 뭉개진 나사산에 대한 보수 작업은 하지 않은 상태이다. 망가진 X2의 플로피 드라이브를 대신할 에뮬레이터를 구입할지도 아직 결정하지 못하였다. 이것이 있다면 USB 메모리를 이용하여 설정 상태를 백업하고 복원하는 일이 매우 편해진다. 모든 것을 SysEx 전송으로 해결할 수도 있지만 MIDI 자체의 전송 속도가 느리기 때문이다. 그나마 ChatGPT의 도움을 받아 KORG X2/X3의 SysEx 데이터와 SNG 파일 구조를 분석하는 리버스 엔지니어링 작업을 훨씬 수월하게 할 수 있다는 것이 다행이다.

2026년 9월 29일 화요일

회의는 AI가 다시 정리해 준다



부제: 게으른 국외출장자를 위한 영어 녹음·전사·요약 워크플로

생물학자에게 전사(transcription)라는 단어는 아주 특별한 의미로 각인되어 있다. 바로 DNA를 주형으로 RNA를 만드는 과정을 뜻한다. 중심원리(central dogma)를 처음 배울 때부터 DNA → RNA → Protein이라는 도식과 함께 전사와 번역(transcription and translation)을 수도 없이 외웠으니 그럴 만도 하다.

그래서 요즘 AI 서비스를 이야기하면서 “회의를 녹음해서 전사한다”라는 표현을 접하면 처음에는 조금 묘한 기분이 든다. 나에게 전사란 RNA polymerase가 하는 일이었으니까.

그러나 전사(轉寫)라는 말의 본래 의미를 생각하면 이상할 것이 없다. 영어 transcribe는 라틴어 transcribere에서 왔으며, trans-는 ‘건너서, 다른 쪽으로’, scribere는 ‘쓰다’를 뜻한다. 즉 본래 의미는 어떤 것을 다른 형태로 옮겨 적는 것이다. 한자어 轉寫도 말 그대로 ‘옮겨 쓴다’는 뜻이다.

DNA의 염기서열 정보를 RNA라는 다른 매체에 옮겨 적는 것도 transcription이고, 회의실에서 사람이 한 말을 문자로 옮겨 적는 것도 transcription이다. 생물학자에게 익숙한 전사가 오히려 이 넓은 의미의 한 사례인 셈이다.

그리고 이번 국외출장에서 새삼 깨달은 것이 있다.

AI-assisted transcription, 즉 AI를 이용한 전사는 출장 기록의 방식을 꽤 크게 바꿀 수 있다.

요즘 업무 회의를 마친 뒤 젊은 연구원들이 녹음 파일과 함께 AI가 자동으로 요약해 준 문서를 전달해 줄 때가 많다. 이처럼 AI를 이용하여 업무 효율화를 이루고 있는데, 나도 여기에 동참해야 하지 않겠는가. 그래서 이번에 싱가포르에서 열린 제14회 GA4GH Plenary에 참석하면서 수립한 워크플로를 글로 정리해 보았다. 미리 계획을 세우거나 조사한 것은 아니다. 회의장 테이블에서 발표내용을 기록하던 도중에 이리저리 검색하고 테스트하여 완성하였다. 따라서 이보다 더욱 효율적이면서도 정확한 기록 방법이 얼마든지 있을 수 있음을 미리 일러 둔다. 


출장보고서를 위해 회의 내용을 받아 적을 필요가 있을까

국외출장을 다녀오면 마지막에 남는 숙제가 있다. 출장보고서다.

회의 중에는 발표를 듣고, 슬라이드를 보고, 메모도 하고, 발표가 끝나면 사람들과 이야기도 해야 한다. 영어 발표라면 집중력도 더 필요하다. 그런데 이 모든 일을 하면서 동시에 “이 내용은 나중에 보고서에 써야 하니 적어놓자”고 생각하는 것은 상당히 피곤한 일이다.

이번 출장에서는 조금 다른 방법을 시험했다.

회의는 녹음한다. 슬라이드는 사진으로 남긴다. 그리고 나중에 AI에게 회의를 다시 정리하게 한다.

이때 가장 중요한 중간 단계가 바로 전사였다.

음성 녹음만 잔뜩 가지고 있어서는 활용하기 어렵다. 한 시간짜리 녹음을 다시 한 시간 동안 들으면서 필요한 내용을 찾는다면 AI를 사용하는 의미가 별로 없다. 음성을 검색하고 분석할 수 있는 텍스트로 바꾸어 놓아야 한다.

음성 → 전사된 텍스트 → 슬라이드와 결합 → AI에 의한 재구성

Otter와 Subtitle Edit는 쓰임새가 조금 다르다

영어 회의를 녹음하고 전사한다고 하면 먼저 떠오르는 서비스 중 하나가 Otter.ai다. 회의 녹음과 전사를 중심으로 만들어진 서비스라서 전사 결과를 확인하고 화자를 구분하며 회의 내용을 정리하는 데 편리하다. 온라인 회의나 협업 환경에서 쓰기에도 좋다. 나도 2년 전 워싱턴 DC 출장(AI-바이오과학 협력회의)에서는 Otter를 꽤 요긴하게 사용했었다.

그런데 이번 출장에서 내가 원했던 것은 조금 달랐다.

이미 녹음해 둔 한두 시간짜리 영어 음성 파일이 여러 개 있고, 이것을 인터넷 연결 상태에 크게 구애받지 않고 내 노트북에서 처리하고 싶었다.

여기에는 오픈소스 프로그램인 Subtitle Edit가 의외로 아주 잘 맞았다. 이름 그대로 원래 동영상 자막을 만들고 편집하는 프로그램이다. 하지만 이 프로그램 안에 Whisper 계열 음성인식 엔진을 이용하면 동영상뿐 아니라 녹음 파일을 자동으로 전사하는 데도 사용할 수 있다.

그리고 결과물로 SRT 자막 파일을 얻을 수 있다는 것이 이번 용도에는 아주 좋았다.

00:23:14 → 00:23:21
발표자가 이 시간에 한 말...

SRT에는 이렇게 시간 정보가 붙는다. 처음에는 그저 자막을 위한 시간표시라고 생각했지만, 나중에는 이것이 출장 기록에서 대단히 유용한 정보가 되었다.

Whisper 모델이란 무엇인가

Subtitle Edit 자체가 사람 말을 알아듣는 것은 아니다. 실제 음성인식을 담당하는 것이 Whisper다.

Whisper는 OpenAI가 공개한 음성인식 모델이다. 사람의 음성을 입력받아 문자로 변환하는 speech-to-text 모델이며, 여러 언어와 다양한 녹음 환경을 처리할 수 있다.

Subtitle Edit 프로그램에서 녹음 파일(MP3, M4A, WAV 등)을 연 뒤 Video → Audio to text (Whisper) 메뉴로 들어가 음성 인식 엔진으로 whisper.cpp를 선택한다. 처음 사용하는 경우 필요한 Whisper 실행 파일과 음성 인식 모델을 내려받아야 하는데, 나는 영어 회의 전사를 위해 **medium 모델(약 1.5GB)**을 사용했다. 모델이 클수록 일반적으로 인식 정확도는 좋아지지만 처리 시간과 메모리 사용량도 늘어나므로, 노트북에서 빠르게 처리하려면 small이나 medium 정도가 현실적이다. 언어는 회의가 영어라면 English로 명시해 주는 편이 좋고, 자동 감지에 맡길 수도 있다. 설정을 마치고 Generate를 누르면 Subtitle Edit가 녹음 파일을 구간별로 분석하여 자막을 만들며, 결과는 화면에서 바로 수정할 수 있고 SRT 파일로 저장할 수 있다. SRT에는 각 발화의 시간 정보가 함께 들어 있으므로, 나중에 AI에게 회의 내용을 요약시키면서 특정 발언이 녹음의 어느 부분에 해당하는지 추적하기에도 편리하다.

Whisper에는 크기가 다른 여러 모델이 있다. 일반적으로 작은 모델은 계산이 빠르고 필요한 컴퓨터 자원이 적은 대신 인식 정확도에서 손해를 볼 수 있고, 큰 모델은 처리 시간이 길어지는 대신 좀 더 나은 결과를 기대할 수 있다.

이번에는 Subtitle Edit에서 whisper.cpp와 medium 모델을 사용했다. 내가 선택한 모델의 용량은 약 1.5GB였다. 8GB의 데이터 로밍을 준비해 왔는데, 노트북을 휴대폰의 모바일 핫스팟에 연결해 이 모델을 다운로드하는 바람에 로밍 데이터를 상당히 소진하였다. 

2021년에 구입한 Dell XPS 노트북에서도 별도의 고성능 GPU 없이 처리할 수 있었다. 전사 시간이 실제 녹음 시간보다 조금 더 걸리기는 했다. 그러나 회의가 끝난 뒤 호텔에서 돌려놓는 작업이라면 큰 문제가 아니었다.

무엇보다 마음에 들었던 것은 일단 프로그램과 모델을 준비해 놓으면 인터넷에 연결하지 않고도 긴 녹음을 전사할 수 있다는 점이었다.

국내에서라면 클로바노트도 아주 편리한 선택이다. 한국어 회의뿐 아니라 외국어 음성도 처리할 수 있다. 영어 회의라면 노트를 만들 때 음성 인식 언어를 영어로 지정해서 사용하면 된다.

꼭 클로바노트 자체에서 녹음할 필요도 없다. 휴대폰의 기본 녹음기로 회의를 녹음한 다음 파일을 가져와 전사하는 방법도 있다.

문제는 이번과 같은 국외출장 환경이다.

클로바노트 같은 클라우드 기반 서비스를 이용하려면 결국 녹음 데이터를 서버로 보내야 한다. 짧은 음성이라면 별 문제가 아니지만 한두 시간짜리 회의를 하루에 몇 개씩 녹음하면 이야기가 달라진다. 호텔 Wi-Fi가 불안정하거나 로밍 데이터를 사용하고 있다면 대용량 음성 파일을 클라우드로 올리는 것 자체가 부담스럽다.

반면 Subtitle Edit + Whisper에서는 녹음 파일만 노트북에 가져오면 이후의 전사 작업은 로컬에서 이루어진다.

인터넷 연결이 충분하고 편리한 회의 관리가 중요하다면 클로바노트나 Otter,
긴 녹음 파일을 인터넷 연결 없이 내 컴퓨터에서 처리하고 싶다면 Subtitle Edit + Whisper.

녹음은 휴대폰이 가장 편했다

실제로 회의를 녹음해 보니 휴대폰이 가장 편했다. 별도의 녹음 장비를 가지고 다닐 필요가 없다. 테이블 위에 휴대폰을 놓고 녹음 버튼만 누르면 된다. 요즘 휴대폰의 마이크 성능이면 일반적인 회의실에서 발표 내용을 전사하기 위한 음질로는 충분했다.

문제는 녹음이 끝난 다음이다.

Whisper를 노트북에서 돌리려면 녹음 파일을 PC로 옮겨야 한다. USB 케이블을 연결하고 휴대폰 저장소를 찾아 들어가도 되지만 매번 그렇게 하는 것은 귀찮다.

이번에 써보니 이 문제의 답은 Quick Share였다.

Android 휴대폰과 Windows PC 사이에서 Quick Share를 이용하면 녹음 파일과 사진을 무선으로 바로 넘길 수 있다. 일반 Windows PC에서는 Google이 배포하는 Windows용 Quick Share를 사용할 수 있다.

휴대폰 녹음 → Quick Share → 노트북 → Subtitle Edit/Whisper → SRT

노트북 자체의 녹음기도 시험해 보았다. 이것도 생각보다 나쁘지 않았다. 어차피 회의장에서 노트북을 펼쳐 놓고 있다면 녹음이 끝나는 순간 파일이 이미 PC에 있으므로 Quick Share 과정조차 필요 없다.

그래도 휴대폰은 위치를 자유롭게 잡을 수 있고 녹음을 시작하고 끝내기도 편하다. 개인적으로는 휴대폰을 주 녹음기로 쓰는 쪽이 마음에 들었다.

게으른 출장자도 슬라이드 사진은 부지런히 찍어야 한다

여기에서 약간의 모순이 생긴다.

제목은 ‘게으른 국외출장자를 위한 워크플로’인데, 슬라이드 사진만큼은 부지런히 찍어야 한다.

슬라이드가 바뀔 때마다 가능하면 고해상도로 찍는다. 그렇다고 현장에서 사진 이름을 바꾸고 발표자별 폴더를 만들 필요까지는 없다. 중요한 것은 순서와 촬영 시각을 보존하는 것이다.

사진에는 촬영 시각이 기록되어 있다. SRT에는 녹음 시작점을 기준으로 각 발언의 시간이 기록되어 있다.

예를 들어 오전 9시 30분에 녹음을 시작했고 SRT의 00:27:30에 어떤 발언이 있다면 실제 시각은 대략 오전 9시 57분 30초다. 그 무렵 촬영한 사진을 찾아보면 당시 화면에 떠 있던 슬라이드를 찾을 수 있다. SRT의 타임코드와 사진의 촬영시각이 연결고리가 되는 것이다.

Subtitle Edit의 결과 화면.


Whisper가 틀린 것은 슬라이드가 고쳐 준다

Whisper의 영문 전사 결과는 놀라울 정도로 쓸 만했지만 당연히 완벽하지 않았다.

특히 국제학회는 음성인식 프로그램에 꽤 가혹한 환경이다. 여러 나라 사람들의 억양이 섞이고, 생소한 사람 이름과 기관명, 프로젝트명, 약어가 끊임없이 등장한다.

이때 슬라이드 사진이 위력을 발휘한다.

Whisper가 발표자의 이름을 엉뚱하게 받아썼더라도 첫 슬라이드에는 정확한 이름과 소속이 적혀 있다. 프로젝트명이나 전문용어, 숫자도 마찬가지다.

반대로 슬라이드에는 제목과 몇 개의 불릿만 있고 발표자가 그것을 어떻게 설명했는지는 나타나 있지 않다. 그 부분은 SRT가 채워준다.

슬라이드는 ‘무엇을 보여주었는가’를 기록한다.
SRT는 ‘무엇을 말했는가’를 기록한다.
손으로 쓴 메모는 ‘그중 무엇이 나에게 중요했는가’를 기록한다.

마지막으로 ChatGPT에 밀어 넣는다

이번에는 하루 동안 촬영한 슬라이드 사진이 200장을 넘었다. 여기에 여러 시간 분량의 SRT 파일도 생겼다.

예전 같으면 이 자료를 보는 순간 출장보고서를 쓸 의욕부터 사라졌을 것이다.

이번에는 사진을 시간 순서대로 묶고 SRT와 함께 ChatGPT에 넣었다. 그리고 세션을 구분하고, 발표자와 발표 제목을 확인하고, 슬라이드와 전사 내용을 대응시키면서 출장보고서 형태로 정리하도록 했다.

여기서 중요한 점이 있다. AI에게 아무 자료 없이 “오늘 학회에 다녀왔으니 출장보고서를 써줘”라고 하는 것이 아니다.

오히려 그 반대다.

가능한 한 충실한 원자료를 남기고, 그 원자료를 AI에게 다시 읽히는 것이 핵심이다.

음성에는 발표자의 설명이 있다. SRT에는 그것을 검색하고 분석할 수 있는 텍스트와 시간 정보가 있다. 사진에는 정확한 제목, 사람 이름, 기관명, 수치와 그림이 있다.

AI에게 맡기는 것은 기억이 아니라 재구성이다.

녹음 + SRT + 슬라이드 사진 → 발표 흐름의 재구성 → 요약 → 출장보고서

찍을 수 있는 것과 공개할 수 있는 것은 다르다

여기에는 중요한 전제가 하나 있다.

프로젝터에 보인다고 해서 모든 슬라이드를 촬영해도 되는 것은 아니다.

학회나 회의에 따라서는 발표 자료의 촬영이나 녹음을 금지하기도 한다. 미공개 연구 결과, 아직 출판되지 않은 데이터, 환자 또는 연구참여자와 관련된 정보, 기업의 기밀 자료 등이 포함될 수도 있다. 발표자가 특정 슬라이드에 대해 촬영하지 말아 달라고 요청하는 경우도 있다.

따라서 여기서 말하는 ‘슬라이드가 바뀔 때마다 찍는다’는 방법은 촬영이 허용된 범위 안에서만 적용되는 원칙이다. 녹음 역시 마찬가지다. 회의 성격과 주최 측의 규정을 먼저 확인해야 한다.

또 하나 중요한 것은 촬영과 공개는 전혀 다른 문제라는 점이다.

출장보고서를 작성하기 위해 개인적으로 촬영이 허용된 자료라고 해도 그 사진을 블로그나 SNS에 그대로 공개해도 된다는 뜻은 아니다. 발표 자료에는 저작권이 있고, 발표 당시에는 공개되었지만 온라인 재배포까지 의도하지 않은 내용도 있을 수 있다.

이번 워크플로에서 슬라이드 사진의 일차적인 목적은 공개가 아니라 기록과 확인이다. Whisper가 틀리게 인식한 이름이나 프로젝트명을 확인하고, 발표 순서를 복원하고, 발표자의 설명과 화면의 내용을 대응시키기 위한 원자료에 가깝다.

AI 서비스에 자료를 올리는 행위 역시 외부 서비스에 데이터를 제공하는 것이므로, 기밀자료나 개인정보처럼 외부 처리가 허용되지 않은 자료라면 업로드해서도 안 된다.

기록할 수 있는 것만 기록하고,
AI에 제공할 수 있는 것만 제공하며,
공개해도 되는 것만 공개한다.

그래서 이제 회의를 안 들어도 되는가?

물론 그렇지는 않다.

녹음에는 회의장의 모든 맥락이 담기지 않는다. 어떤 발표에서 사람들이 유난히 관심을 보였는지, 어떤 질문에서 분위기가 달라졌는지, 쉬는 시간에 누구와 무슨 이야기를 나누었는지는 직접 그 자리에 있었던 사람만 안다.

AI가 만들어 준 결과도 확인할 필요가 있다. Whisper가 고유명사를 틀릴 수 있고, 사진이 빠졌을 수도 있으며, AI가 서로 다른 발표의 내용을 잘못 연결할 수도 있다. 중요한 이름, 숫자, 발표 제목 정도는 원자료와 다시 맞춰보는 것이 좋다.

하지만 한 가지는 분명했다.

“출장보고서를 써야 하니까 지금 이 문장을 받아 적어야 한다”는 부담에서는 상당히 자유로워질 수 있다.

그 시간에 발표 자체에 더 집중하면 된다.

그리고 저녁이 되면 AI가 회의를 다시 정리해 준다.

정확히 말하면 AI가 나 대신 회의에 참석한 것이 아니다. 내가 남겨놓은 여러 종류의 기록을 시간축 위에서 다시 조립해 주는 것이다.

이번에 실제로 해보니 이 방법은 앞으로 국외출장에서도 계속 써먹을 만하다.

나의 새로운 출장 준비물은 별것 없다.

휴대폰, 노트북, Quick Share,
Subtitle Edit + Whisper, 그리고 ChatGPT.

아, 하나 더 있다.

슬라이드가 바뀔 때 사진 찍는 것을 잊지 않을 정도의 성실함.

그리고 그보다 더 중요한 것 하나.

찍어도 되는 것과 공개해도 되는 것을 구별하는 상식.

게으른 출장자에게 요구되는 성실함은 딱 그 정도면 될 것 같다. 

이 글을 마무리하면서 많은 고민을 하였다. 너무나 쉽게 출장 보고서를 쓰는 꼼수를 공개하는 부도덕한 일은 아닐까? 혹은 AI를 업무에 활용하여 자동화할 것은 최대로 자동화한다. 반면 회의장에서 듣고, 질문하고, 판단하고, 중요한 것을 알아채는 일은 사람이 한다. 이때 AI는 훌륭한 도구가 된다.

출장보고서 작성에 두 시간을 썼느냐 이틀을 썼느냐가 보고서의 성실성을 결정하는 것은 아니다. 중요한 것은 실제로 무엇을 보고 들었는지를 얼마나 충실하게 남기고, 그것을 왜곡하지 않고 전달하느냐일 것이다. AI 덕분에 그 과정이 쉬워졌다면, 그것은 요령이라기보다 도구의 발전에 가깝다.

2026년 9월 26일 토요일

브리츠 BR-1800 Classic 스피커에 파일럿 램프를 달다

당장 폐가전제품 수거통에 넣어도 아깝지 않을 고물 액티브 스피커에 너무 정성을 들이는 것은 아닐까. 가벼우면서도 출력이 높고(대부분 Class D일 것이므로) 블루투스까지 연결되는 현대적인 PC용 스피커를 몇 만원만 주면 살 수 있는 요즘에 2005년 11월 제조일자가 찍힌 구형 스피커를 부품까지 바꾸어 가면서 쓰는 정성이란...

이 액티브 스피커는 전원이 들어왔는지 표시해 주는 파일럿 램프가 없다. 손가락으로 더듬어서 뒷면에 위치한 스위치를 확실히 내리는 것으로 만족스럽지 못하다. 시각적으로 작동 상태를 확실히 보여주기 위하여 파일럿 램프를 달아 주기로 하였다. 이틀 전 MAX4410 헤드폰 앰프에 케이스를 달면서 LED 파일럿을 달아 주었던 일(링크)이 '자작심(心)'을 자극한 것일게다.

이는 아날로그 아날로그 리니어 파워 앰프 IC인 LM1875T를 써서 Class AB로 동작한다. 무거운 전원 트랜스포머가 들어 있고, 으며, 18-0-18V AC를 정류·평활하여 대략 ±24 V의 DC 전원을 앰프 회로에 공급하는 전형적인 구성이다.

LM1875T는 한 시대를 풍미했던 이른바 ‘게인클론(Gainclone)’ 계열의 리니어 파워 앰프 IC이기도 하다. 정확히 말하면 원조 게인클론에 사용된 칩은 아니지만, LM1875를 비롯하여 LM3875, LM3886 같은 칩 하나로 간결한 Class AB 파워 앰프를 만드는 방식은 한때 오디오 DIY에서 상당한 인기를 누렸다. 이제는 작고 가볍고 효율까지 높은 Class D 앰프가 그 자리를 거의 차지해 버렸다. 무거운 전원 트랜스포머까지 품고 있는 이 BR-1800 Classic은 그런 의미에서도 제법 옛날 물건이 되었다.

전원 레일 한쪽에 저항과 LED를 달면 파일럿 램프 대용으로 쓸 수 있다. 그러나 저항값을 계산하기가 귀찮다. 부품통에 샤시용 네온램프(AC 220V 연결용)가 하나쯤 남아 있을텐데... 찾았다! 뒷면 패널 아래쪽 전원스위치와 왼쪽 스피커 출력선을 연결하는 RCA 단자 중간 부분에 적당히 구멍을 뚫고 램프를 고정하였다. 



LED를 썼다면 저항을 적당히 조합하여 더 밝게 만들 수도 있었을 것이다. 기기 뒷면에 있으니 밝은 것이 여러모로 유리하겠지만 손이 덜 가는 방법을 택했다. 납땜조차 하지 않은 채 압착 커넥터로 아주 간단하게 처리하였다.

새로 산다면 4인치 우퍼를 장착한 에디파이어 MR4 정도면 충분할 것이다. 가끔 음악 작업도 하니 조금 사치를 부려 전문적인 냄새가 물씬 나는 제네렉 8020D 한 조를 책상 위에 올려놓는 것도 좋겠다.

그런데도 나는 BR-1800 Classic을 버리지 않고 또 케이스에 구멍을 뚫어 작은 네온램프 하나를 달았다. 소리가 더 좋아진 것도 아니고 수명이 늘어난 것도 아니다. 그저 전원이 들어왔다는 것을 눈으로 확인할 수 있게 되었을 뿐이다.

몇 만원이면 새 스피커를 살 수 있는 시대에 이런 수고가 경제적으로 합리적일 리는 없다. 그래도 멀쩡히 소리가 나는 오래된 물건에 작은 불 하나를 밝혀 주는 일은 제법 즐겁다. 아마 그래서 아직도 이런 짓을 하나 보다.