2026년 7월 9일 목요일

Fluid Ardule의 3.5인치 화면에서 리눅스 콘솔을 만나다

Fluid Ardule을 다른 사람도 만들어 쓸 수 있도록 배포하려면 어떻게 해야 할까? 요즘 이런 생각을 조금씩 하고 있다. GitHub에는 소스 코드와 설치 문서를 올려 두었지만, 실제로 Raspberry Pi OS부터 설치해서 시스템을 구성하려면 제법 많은 수고가 필요하다. 특히 Wi-Fi 설정은 사용자마다 다를 수밖에 없다.

현재 Fluid Ardule은 부팅 시간을 줄이기 위해 NetworkManager를 사용하지 않는다. 실제로 systemd-analyze blame으로 확인했을 때 NetworkManager 서비스가 부팅 과정에서 13초 이상을 차지한 적이 있었다. 전원을 켜고 빨리 악기를 사용하고 싶은 시스템에서 13초는 결코 짧은 시간이 아니다.

그래서 Fluid Ardule은 wpa_supplicantdhcpcd를 이용하는 비교적 단순한 네트워크 구성을 사용한다. 문제는 새로운 Wi-Fi를 등록할 때이다. 내가 사용하는 집 Wi-Fi와 휴대전화 핫스팟 정도만 미리 등록해 두면 별 문제가 없지만, 배포판을 사용하는 사람은 자신의 SSID와 비밀번호를 입력해야 한다. 내가 공개한 문서에서는 SSH로 연결한 터미널 창에서 명령어를 넣어서 설정을 입력하는 방법을 소개해 두었다. 그러나 아무래도 불편하지 않을 수 없다.

처음에는 여러 방법을 생각했다.

Fluid Ardule의 인코더를 돌려 ASCII 문자를 선택하게 할까? SSID는 스캔 목록에서 고르고 비밀번호만 입력하면 된다. 그러나 90개가 넘는 printable ASCII 문자를 인코더로 돌려 고르는 장면을 상상하니 썩 내키지 않았다.

Raspberry Pi를 잠시 무선 AP로 만들어 휴대전화에서 접속하게 하는 방법도 있다. 이른바 captive portal 방식이다. 편리하기는 하지만 AP 모드, DHCP, 간단한 웹 서버와 설정 페이지까지 필요하다. Wi-Fi 비밀번호 하나를 입력하기 위해 또 하나의 작은 시스템을 만드는 셈이다.

USB 키보드를 연결하게 할까? 이것도 나쁘지 않다. 하지만 그러려면 Fluid Ardule의 전용 UI 안에 텍스트 입력 기능을 새로 넣어야 한다.

이쯤에서 생각을 바꾸었다.

Fluid Ardule은 상용 전자악기가 아니다. Raspberry Pi에 운영체제를 설치하고 Arduino 펌웨어를 올리며 MIDI 장치를 연결하는 DIY 프로젝트이다. 그렇다면 사용자에게 Raspberry Pi OS와 SSH에 대한 기본적인 숙련을 요구하는 것이 그렇게 부당한 일일까?

최초 Wi-Fi는 Raspberry Pi Imager에서 설정하면 된다. 새로운 네트워크가 필요하면 SSH로 접속하여 설정 파일을 수정할 수 있다. 아무도 요구하지 않은 captive portal을 만들다가 또 며칠을 보내는 것보다는 이 편이 훨씬 낫다.

그래서 설치 문서와 네트워크 문서에 이 원칙을 명시했다. Fluid Ardule은 DIY Raspberry Pi synthesizer project이며, Raspberry Pi OS와 SSH에 대한 기본적인 숙련을 권장한다고 말이다.

여기서 오늘의 이야기가 끝났어야 했다.

그런데 문득 이런 생각이 들었다.

“Fluid Ardule 서비스를 잠시 끄고 3.5인치 TFT를 그냥 리눅스 모니터처럼 쓸 수는 없을까?”

현재 Fluid Ardule의 TFT는 /dev/fb1이라는 framebuffer 장치이다. 운영 스크립트는 Pillow로 화면을 렌더링하고 그 결과를 framebuffer에 직접 출력한다. Raspberry Pi의 Linux 콘솔은 기본적으로 다른 framebuffer를 사용하고 있다.

확인해 보았다.

$ cat /proc/fb
0 vc4drmfb
1 fb_ili9486

framebuffer 0은 HDMI 쪽이고 framebuffer 1은 ILI9486 SPI TFT이다.

Linux console의 framebuffer 연결 상태도 확인했다.

$ con2fbmap 1
console 1 is mapped to framebuffer 0

그렇다면 console 1을 framebuffer 1로 바꾸면 어떻게 될까?

SSH로 접속한 상태에서 Fluid Ardule 서비스를 멈추고 다음 명령을 실행했다.

sudo systemctl stop fluid_ardule.service
sudo con2fbmap 1 1
sudo chvt 1

놀랍게도 3.5인치 TFT에 진짜 Linux console이 나타났다.

Fluid Ardule의 메뉴도 아니고 Pillow로 렌더링한 운영 화면도 아니다. Raspberry Pi의 텍스트 콘솔이다. USB 키보드를 연결하면 명령어를 직접 입력할 수 있다. raspi-config도 실행할 수 있다.

다만 화면은 정확히 180도 뒤집혀 있었다.

사실 당연한 결과였다. Fluid Ardule의 TFT 설정에는 다음과 같은 항목이 있다.

dtoverlay=piscreen,spi0-0,rotate=90,speed=32000000,fps=30

여기서 rotate=90은 ILI9486의 기본 세로 방향 framebuffer를 Fluid Ardule이 사용하는 480×320 가로 화면으로 바꾸기 위한 것이다.

그런데 실제 Fluid Ardule에서는 케이스 내부의 커넥터와 케이블 배치를 편하게 하기 위해 TFT를 반대 방향으로 장착했다. 따라서 가로 화면은 맞지만 실제 사람이 보는 방향에서는 180도 뒤집혀 있다. Fluid Ardule 운영 스크립트는 Pillow로 렌더링한 화면을 다시 180도 회전하여 이를 보정한다.

Linux console은 당연히 이런 사정을 모른다.

그래서 /boot/firmware/cmdline.txt에 다음 커널 파라미터를 추가했다.

fbcon=rotate:2

재부팅 후 다시 console을 TFT에 연결했다.

이번에는 정상 방향이었다.


3.5인치 화면에 raspi-config를 띄워 보았다. 화면이 너무 작지 않을까 걱정했지만 의외로 아무 문제가 없었다. 메뉴를 읽고 조작하기에 충분했다.

그리고 다시 Fluid Ardule로 돌아오는 것도 간단했다.

sudo con2fbmap 1 0
sudo systemctl start fluid_ardule.service

잠시 뒤 익숙한 Fluid Ardule 화면이 다시 나타났다.

오늘은 Wi-Fi 설정 방법을 고민하다가 시작했다. 결론은 “굳이 모든 것을 Fluid Ardule UI 안에서 해결하려 하지 말자”였다.

그런데 그 과정에서 더 재미있는 가능성을 발견했다.

Fluid Ardule의 3.5인치 TFT는 악기 화면으로만 사용할 필요가 없다. 평소에는 Pillow 기반의 전용 악기 UI를 표시하다가, 필요할 때 서비스를 멈추고 Linux console로 전환할 수 있다. 설정이나 진단이 끝나면 다시 악기 UI로 돌아오면 된다.

이제 운영 스크립트에 필요한 것은 Wi-Fi 설정을 위한 복잡한 암호 입력 화면이 아닐지도 모른다. 단지 “Console Mode”로 들어가는 문 하나면 된다.

악기 UI는 악기답게 단순하게 유지하고, 시스템 관리는 Linux에게 맡긴다.

오늘은 기능 하나를 더 만든 날은 아니다. 오히려 만들지 않아도 될 기능을 찾아 헤매다가, 이미 시스템 안에 있던 다른 문 하나를 발견한 날이다.

2026년 7월 7일 화요일

완벽함의 유효기간은 생각보다 짧다

보다 정확히 말하자면 '완벽하다는 믿음의 유효기간은 생각보다 짧다'라고 하는 것이 맞을 것이다.

어제 수정한 Fluid Ardule 운영용 파이썬 스크립트(버전 260706b; 10,725줄)가 정말 완벽하게 작동하는 것 같았다. 

"이만하면 됐다!"

이제는 소개용 영상을 찍어서 유튜브에 올려도 손색이 없겠다고 자신감에 부풀어 있었다. Fluid Ardule의 프로토타입을 소개한 숏 영상은 나의 유튜브 채널에 몇 개 올라가 있지만, 본격적인 소개 영상은 정식으로 인클로저에 넣고 나서 테스트가 어느 정도 되면 그때 찍으려고 잔뜩 벼르고 있었다. 이번 주말에는 영상 작업이 가능하리라! 

하지만 완벽함에 대한 믿음은 단 한 시간도 가지 않았다. 260706b를 GitHub에 commit한 직후 테스트를 해 보다가 미처 점검하지 못한 곳에 오류가 남아 있음을 또 발견한다. 완벽이 아니었던 것이다.

완벽함의 유효기간은 왜 이렇게 짧을까?

때로는 세상이 바뀌어서 나의 완벽함에 대한 바깥의 기대 수준이 훌쩍 올라간 때문이기도 하다. 하지만 세상이 하루 사이에 갑자기 바뀌는 일은 많지 않다. 가장 근본적인 원인은 어제 느꼈던 완벽함이라는 것이 전적으로 나의 착각일 수도 있다는 것이다.

소프트웨어 개발이 막바지에 접어들면서 필요한 기능은 거의 다 구현이 된 상태에 이르렀다. 그러나 소위 fine-tuning에 이렇게 많은 시간이 소요될 것이라고는 미처 생각하지 못했다. 지금은 더욱 매끄럽고 안정적인 작동을 보장하기 위한 미세한 조정 단계이다. 파레토 법칙의 변주라고나 할까? 나머지 20%를 채우기 위해 80%의 노력을 들이고 있다.

조금 더 긍정적으로 말하자면, 그만큼 나도 성장했기에 과거에 완벽하다고 생각했던 것 사이에 숨어 있었던 부족함을 비로소 눈치채게 되었다는 뜻도 된다. 따라서 값진 시행착오를 딛고 조금씩 나아지는 과정을 밟게 된다. 

예를 들어 완벽하다는 믿음의 유효기간이 24시간에 불과하여 매일 고치고 또 부족함을 느끼기를 일주일 동안 반복했다고 치자. 그래서 점진적인 개선을 거쳐서 A->B->C...->H를 만들어 냈다고 가정하자. 일주일 간의 경험은 결코 시간 낭비가 아니다. B에 도달했기 때문에 더 나은 C를 만들기 위한 개선점이 비로소 보이게 되었다. 그러나 타인으로부터 '왜 단번에 H를 만들어내지 못했어? 그러면 완벽했다고 보고한 A는 도대체 뭐야? 그동안 뭐했어?'라고 비판을 받으면 모든 의욕이 꺾인다.

Fluid Ardule의 운영 스크립트는 나 혼자 재미로 하는 일이니 중간 과정에 실수가 좀 있더라도 누구로부터 시간이나 예산을 낭비했다는 말은 듣지 않는다. 점검은 전적으로 나 혼자 한다. 

수시로 현장 점검을 하지 않으면 우리가 하는 일을 믿지 못하겠다는 사람들이 있다. 오늘 오후에도 그 사람이 찾아온다고 한다. 참으로 반갑지 않다.

형편없었던 장마 중 달리기

늦은 장마로 비가 계속 내려서 7월 2일에 이번달의 첫 달리기를 한 뒤 삼일이나 쉰 다음 어제(6일) 다시 밖으로 나갔다. 토요일의 건강검진에서 장을 깨끗이 비우느라 너무 애를 쓴 탓일까, 또는 수면내시경을 위해 투여한 진정제의 부작용인 것일까, 주말 내내 침대를 벗어나지 못했다. 

그렇다면 삼일이나 달리기를 쉬는 동안 꽤 몸이 많이 회복되었을 법도 한데 어제의 5.5km 달리기는 정말 형편없는 수준이었다. 매번 집을 나설 때에는 '아, 이상하게 몸이 무겁네. 오늘은 3km만 뛸까?'하는 유혹에 시달린다. 어제는 더욱 그러하였다.


7.xkm를 달리고는 했던 과거를 돌이켜 보자. 아주 오랜 옛날도 아니고, 불과 1년 정도 전이다. 5km와 7.xkm는 적은 차이가 아니다. 요즘은 달리는 거리도 줄고 쉬는 날도 늘었는데 왜 과거보다 더 힘들다고 느끼는 것일까? 신체의 자연스런 노화 때문인 것인지, 보충 운동을 제대로 하지 않아서 그런 것인지. 

8월이 되면 달리기에 입문한지 딱 2년이 지난다. 무엇이 나아졌는지 아직도 잘 모르겠다. 쉬지 않고 어쨌든 5km는 한번에 뛸 수 있다는(페이스는 신경쓰지 않고) 것에만 만족해서는 안 될 터인데... 

2026년 7월 5일 일요일

정체불명 마이크로SD 카드의 쓸모 없음을 증명하다

명칭 풀네임 규격 용량 표준 파일시스템
microSD Standard Capacity, SDSC 최대 2GB FAT12 / FAT16
microSDHC High Capacity 2GB 초과 ~ 32GB FAT32
microSDXC eXtended Capacity 32GB 초과 ~ 2TB exFAT
microSDUC Ultra Capacity 2TB 초과 ~ 128TB exFAT

라즈베리 파이로 만든 Fluid Ardule은 이제 제법 안정적으로 작동한다. 어제는 소개용 영상을 제대로 찍으려고 배경지까지 구입하여 벽에 걸어 두었다. GitHub에는 지금까지 개발한 소스 코드와 문서가 전부 올라가 있다. 하지만 갑자기 마이크로SD 카드가 망가지면 어떻게 할 것인가? GitHub에 올려둔 설치 문서를 보고 따라서 하면 되지만 매우 번거롭다. 나의 프로젝트에 흥미를 느끼고 따라서 하려는 사람도 이와 같은 절차를 거쳐야 할 것이다. 그러나 개발자인 나 자신은 이보다는 좀 더 편하게 복구를 했으면 한다.

그래서 오늘은 현재 정상 작동 중인 Fluid Ardule 시스템의 비상 복구 이미지를 만들어 보기로 했다. 그리고 사운드폰트 등 내가 2차적 배포를 하면 라이선스상 문제가 될 만한 것은 제외한 이미지를 작은 용량으로 만들어서 배포한다면 Fluid Ardule이 널리 알려지는 데 도움이 될 것이다. 이를 어디에 올릴지는 고민을 해 봐야 되겠지만. 앞으로는 이미지 배포와 설치용 스크립트 개발 사이에서 고민을 하게 될 것 같다.

이를 위해서 주말 외출을 한 김에 오프라인 매장에서 32GB 마이크로SD 카드를 하나 구입했는데(아래 사진의 4번), 그렇게 현명한 구매 행위는 아니었던 것으로 판명되었다. 다음부터는 온라인에서 구입하리라. 1번은 현재 Fluid Ardule에서 사용 중이며, 3번의 카드는 Nano Ardule 드럼 패턴 플레이어(아두이노 나노)에 연결되어 있다.

수 시간 동안의 시행착오를 거친 끝에 내린 결론은 위 사진에서 2번으로 표시한 카드가 표면에 인쇄된 것으로는 '최고급 제품'처럼 보이지만, 실제 성능은 알 수 없다는 것이다. 2번과 4번을 동일한 방법으로 테스트하였으나 오직 4번에 써 넣은 복구용 이미지만 부팅 및 Fluid Ardule 작동에 성공하였다. 이미지를 쓰는 데에도 4번 카드가 훨씬 적은 시간이 걸렸다.

ChatGPT에게 표면의 마킹으로부터 최대한 제품의 성능을 추측해 보라고 하였다.

1번은 Samsung 32 GB EVO microSDHC입니다. 주황색 EVO 디자인의 비교적 구형 세대이고, 전면에 microSDHC / U1 표시가 보입니다. 즉 32 GB이므로 SDHC 계열이며, UHS Speed Class 1(U1) = 최소 지속 쓰기 10 MB/s 보장 등급입니다. 사진에는 UHS 버스의 I 표시(UHS-I)도 확인됩니다. 반면 요즘 카드처럼 A1/A2 또는 V30 표시는 없습니다. 2021년에 Pi 3B와 같이 샀다는 설명을 고려하면 Fluid Ardule의 원본 시스템 카드로 쓰인 이력이 매우 자연스럽습니다. 다만 2021년에 구입했다고 해서 2021년형 제품이라는 뜻은 아닙니다. 디자인상 더 이전 세대 제품일 가능성이 큽니다.

2번 OLEVO 32 GB는 재미있는 카드입니다. 전면에서 V10, A1, U1, UHS-I 표시가 모두 읽힙니다. 따라서 명목상으로는 Video Speed Class V10 = 최소 지속 쓰기 10 MB/s, Application Performance Class A1, U1 카드입니다. A1은 단순 동영상 저장보다 Raspberry Pi 같은 랜덤 I/O 환경에서 의미가 있는데, 규격상 최소 1500 read IOPS / 500 write IOPS 요구 조건을 갖습니다. 네 카드 가운데 표시된 규격만 놓고 보면 Raspberry Pi OS용으로 가장 ‘그럴듯하게 포장된’ 카드입니다. 문제는 말씀하신 대로 카드 소켓 모듈에서 인식 문제가 있었고 세 번 구입했다는 실제 경험이죠. 이것은 인쇄된 속도 등급과 전기적 호환성·컨트롤러 품질·카드 간 편차가 별개의 문제라는 좋은 사례입니다. 사진만으로 OLEVO의 제조사나 NAND/컨트롤러 출처는 판단할 수 없습니다.

3번은 SanDisk 32 GB microSDHC 구형 카드입니다. 검은색 전면이고 microSDHC / UHS-I 표시는 명확합니다. 오른쪽 아래 원형 안의 표시는 사진 해상도상 정확한 판독이 조금 애매합니다(자세히 보면 오른쪽이 열린 원 내부에 4가 기록되어 있어서 4MB/sec의 Speed Class를 의미함). 전면에 U1, A1, V10 등의 현대적인 성능 등급 표시는 보이지 않습니다. 따라서 네 장 중 외관 정보만으로는 성능을 가장 적게 알 수 있는 카드입니다. 아래쪽에 희미한 레이저 각인이 있고 MADE IN CHINA는 읽힙니다. 이 각인을 더 선명하게 접사하면 제품 코드나 제조 로트 일부를 추적할 가능성이 있습니다. 2025년 다이소 구입품이라는 점은 흥미로운데, 판매 시점과 카드 설계 세대가 상당히 다를 수 있음을 보여 줍니다.

4번은 SanDisk Ultra 32 GB microSDHC입니다. 전면에 Class 10의 원 안 10 표시, U1, UHS-I가 모두 보입니다. 따라서 최소 지속 쓰기 등급은 역시 10 MB/s 계열입니다. 최대 100 MB/s는 카드 전면에서는 확인되지 않고 구입 당시 제품 사양에 근거한 것으로 보입니다(포장재에 인쇄되어 있었음). 이 속도는 보통 최대 순차 읽기 속도이며 쓰기 속도 100 MB/s를 의미하지 않습니다. 사진상 A1/A2 표시는 보이지 않습니다.

U1, A1, V10 등은 Speed Class의 성능 등급을 표현하는 것이다. 단, UHS-I은 버스 인터페이스 세대를 뜻한다. Fluid Ardule(라즈베리 파이 3B)에는 삼성이나 샌디스크와 같이 신뢰할 수 있는 제조사의 A1 + UHS-I + 32GB 마이크로SDHC카드면 충분하다. 다나와에서도 SD카드 용어를 잘 정리하여 주었다.

그림 출처: SD Association Speed Class.

많은 시행착오 끝에 응급용 이미지를 만드는 방법을 정립하여 GitHub Fluid Ardule 프로젝트 사이트의 Fluid Ardule Disaster Recovery 문서에 기록해 두었다. 내용을 간단하게 요약해 보겠다.

32 GB 카드 전체를 dd로 복제하면 같은 ‘32 GB’ 카드라도 실제 섹터 수 차이 때문에 이미지가 들어가지 않을 수 있다. 그래서 image-utilsimage-backup을 이용하여 사용 중인 파일시스템만 담은 약 5.5 GB의 compact image를 만들고, image-check와 SHA-256 검증을 거쳤다.

이 이미지를 다른 microSD 카드(SanDisk Ultra 32GB, 위 카드 사진에서 4번)에 기록하여 Raspberry Pi 3B를 실제로 부팅했고, Fluid Ardule 실행과 오디오 출력이 잘 됨을 확인했다. 첫 부팅 뒤 루트 파일시스템도 대상 카드의 약 29 GB 전체 용량으로 자동 확장되었다. 즉 단순히 ‘백업 파일을 만들었다’는 데서 끝나지 않고, 다른 카드에서 실제 부팅까지 확인한 재난복구 이미지를 확보한 것이다.

이 과정에서 microSD 카드의 품질 차이도 직접 경험하였다. 같은 이미지를 기록해도 저가 카드(위 카드 사진의 2번 OLEVO)는 기록과 검증이 매우 느리고 결국 부팅하지 못한 반면, 새 SanDisk 카드에서는 훨씬 빠르게 기록되고 정상적으로 부팅이 되었다. 같은 32 GB라는 표기와 화려한 속도 등급이 카드의 신뢰성까지 보장하는 것은 아니었다.

오늘의 작업은 새로운 기능을 추가하는 개발은 아니었다. 오히려 지금까지 만든 것을 다시 살려낼 수 있는가를 확인하는 것이었다. 중국산 정체불명의 32GB 카드 하나가 자신의 쓸모없음을 증명하는 동안, Fluid Ardule에는 재난복구 절차가 확립되었다.

2026년 7월 4일 토요일

아르페지오의 속도를 조절하려 했는데, 범인은 에코였다

새벽 네 시에 일어나 앉아서 맛없는 음료를 벌컥벌컥 마신다. 몇 시간 뒤에 있을 대장 내시경 검사를 위해 장을 깨끗이 비우기 위함이다. 어젯밤 7시에 먹었던 1차 복용제는 그런대로 먹을 만했는데, 새벽 네 시에 먹어야 하는 2차 복용제는 정말 고역이다. 잠을 깬 김에 어제 퇴근후 벌어졌던 Fluid Ardule 운영 스크립트 개발기를 쓴다. 어차피 속이 그득하고, 잠시 뒤면 또 화장실을 들락거려야 하니 다시 잠자리에 들기는 틀렸다.

Fluid Ardule에서 요즘 흥미를 느끼는 것은 Yoshimi의 아르페지오 계열 음색(preset)이다. 자주 쓰다 보니 한 가지 아쉬움이 생겼다. 현재는 고정된 속도로만 일정 패턴의 note가 발생한다. 실제 곡의 템포에 따라 아르페지오 속도를 바꾸고 싶었다. Yomishi의 프리셋을 전환할 때 발생하는 잡음을 없애는 것이 가장 최근의 도전 과제였었다. 하나를 해결하면, 그 다음 문제에 몰두하게 된다.

아르페지오를 로드한 뒤 건반 하나를 누르면 음이 일정한 패턴으로 반복된다. 음색을 고르는 것만으로도 꽤 그럴듯한 연주가 된다. 그런데 연주 중에 조금 빠르게, 혹은 조금 느리게 바꾸고 싶다는 생각이 드는 것은 당연하다. Fluid Ardule에는 로터리 인코더가 있다. 이것을 돌려 아르페지오의 속도를 조절하면 좋겠다.

말은 간단하다. 문제는 Yoshimi에서 무엇을 건드려야 하는가였다. 당연히 BPM이라고 생각했다. 

AI(ChatGPT)에게 물었다. Yoshimi에는 명령행 인터페이스가 있으니 실행 중인 프로그램에 명령을 보내어 BPM을 바꿀 수 있지 않겠느냐고. 처음에는 AI도 그렇게 생각했다.

나는 Yoshimi 매뉴얼을 AI에게 주었다. AI는 매뉴얼을 읽고 다음과 같은 명령을 찾아냈다.

BPM <n>    default BPM if none from MIDI

좋다. 답을 찾은 것 같았다.

라즈베리 파이에서 Yoshimi를 인터랙티브 모드로 실행했다.

yoshimi -i

아르페지오 프리셋을 불러왔다.

load instrument /home/pi/sf2/yoshimi_links/Arpeggios__0001-Arpeggio1.xiz

그리고 BPM을 바꾸었다.

set bpm 60
set bpm 180

60과 180이면 세 배 차이다. 건반을 눌러 보았다.

똑같다.

나는 말했다.

이상한데요? bpm 바꾸어도 아르페지에이터 속도는 그대로예요.

AI는 매뉴얼을 다시 뒤졌다. 이번에는 LFO 항목에서 BPM 동기화 기능을 찾아냈다.

Bpm <s>    sync frequency to MIDI clock

아마 LFO가 BPM에 동기화되지 않은 상태라서 global BPM을 바꾸어도 소용이 없는 것 같다는 설명이었다. 그럴듯했다.

문제는 Yoshimi의 CLI가 생각보다 만만하지 않았다는 것이다.

set part 1

여기까지는 좋았다.

add

라고 입력했더니,

add what?

이라고 했다. set add라고 해야 했다. LFO로 들어가려고 lfo라고 입력했더니 또 알아듣지 못했다. set lfo라고 해야 했다.

Frequency context에도 들어갔다.

set frequency

마침내 원하는 장소에 도착했다.

@ p1+, A+, LFO freq+

여기에서,

set bpm on

을 실행했다. 다음과 같이 표시된다. 드디어 정확한 명령어 입력 방법을 알아낸 것이다.

Part 1 Kit 1 AddSynth Freq LFO BPM - on

이번에는 정말 되는 줄 알았다. BPM을 바꾸고 건반을 눌렀다.

똑같다. Rate도 바꾸어 보았다. 그러나 달라지는 것이 없었다.

AI는 또 다른 가능성을 제시했다. ADDsynth의 Voice Delay가 반복을 만드는 것이 아닐까? Voice 1과 Voice 2로 들어갔다. Delay라는 명령도 발견했다. 값을 바꾸었다. 나는 건반을 눌렀다.

전혀 안됩니다.

이날 오전 AI와 나의 대화에서 가장 많이 등장한 문장은 아마 이것이었을 것이다.

안 바뀝니다.

AI는 가설을 제시했다. 나는 라즈베리 파이에 명령을 입력했다. 건반을 눌렀다.

안 달라져요.

다시 가설. 다시 명령. 다시 건반.

빠르기와는 무관합니다!

이쯤 되자 매뉴얼에 나오는 일반적인 기능 설명만으로는 답을 찾기 어려워졌다. 나는 이미 분석을 위해 Yoshimi의 아르페지오 프리셋 파일을 AI에게 올려 둔 상태였다. 그래서 말했다.

아까 업로드했으니 다시 살펴봐요.

이번에는 매뉴얼이 아니라 실제 프리셋 파일 자체를 분석하기 시작했다. 대상은 이것이었다.

Arpeggios__0001-Arpeggio1.xiz

이름은 Arpeggio1이다. 나는 당연히 이 파일 어딘가에 아르페지에이터의 속도를 결정하는 파라미터가 있을 것이라고 생각했다. BPM, LFO, Rate, Clock 같은 것 말이다.

그런데 프리셋의 구조를 따라가던 AI가 다른 것을 지목했다.

Part 1. Effect 2. Echo.

에코?

나는 아르페지오의 속도를 바꾸고 싶은데 갑자기 에코라니. 솔직히 처음에는 이것도 별로 믿음이 가지 않았다. 테스트하는 내내 이미 여러 번 틀렸기 때문이다.

그래도 실험은 간단하다. Yoshimi CLI에서 Part 1로 들어갔다.

/
set part 1

Effect 2를 Echo context로 열었다.

set effect 2 echo

프롬프트가 바뀌었다.

@ p1+ eff 2 ECho-3?

Echo의 파라미터 중에는 Delay가 있었다. 값을 바꾸었다. 건반을 눌렀다.

와, 드디어 연주가 달라졌다.

BPM을 바꾸고, LFO를 뒤지고, Voice Delay를 건드려도 꿈쩍하지 않던 반복 속도가 Echo Delay 값을 바꾸자 확연히 달라졌다.

우리가 찾던 아르페지오의 속도는 에코가 만들고 있었다.

물론 엄밀히 말하면 "아르페지에이터가 에코였다"는 표현은 정확하지 않을 것이다. 그러나 적어도 내가 사용하던 Yoshimi의 Arpeggio1 프리셋에서 귀에 들리는 반복 패턴의 속도를 실질적으로 좌우하는 파라미터는 Part 1 Effect 2의 Echo Delay였다.

이제 원인을 찾았다. 다음 문제는 Fluid Ardule의 화면에 무엇을 표시할 것인가였다.

Echo Delay 42

이렇게 표시할 수는 없다. 연주하는 사람이 알고 싶은 것은 Yoshimi 내부의 이펙트 파라미터 값이 아니다. 대략 얼마나 빠르게 반복되는가이다.

처음에는 BPM과 비슷한 숫자를 만들어 Echo Delay에 대응시키는 간단한 식을 만들었다.

echo_delay = round(6000 / raw_speed)

그리고 작은 Python 테스트 프로그램(test_yoshimi_arp_speed_calibrated.py, GitHub에 공개)을 만들었다. 숫자를 넣고 건반을 연주했다. 메트로놈과 비교하여 실제로 어느 정도의 BPM처럼 들리는지 측정했다.

처음 측정값은 조금 들쭉날쭉했다. 그래서 다시 측정했다.

60  → 52
75  → 66
100 → 83
120 → 100
140 → 126
160 → 133
180 → 140
200 → 162
220 → 181
240 → 200

정밀한 계측 장비를 쓴 것은 아니다. 내 귀와 메트로놈이다. 그래도 관계는 꽤 일정했다.

AI에게 계산을 시켰다. 단순 선형 회귀 결과는 다음과 같았다.

apparent_bpm ≈ 0.797 × raw_speed + 5.13

그러면 역으로 원하는 체감 속도에서 내부 값을 계산할 수 있다.

raw_speed ≈ (display_bpm - 5.13) / 0.797

그리고 이것을 다시 Echo Delay 값으로 변환한다.

echo_delay = round(6000 / raw_speed)

첫 번째 테스트 프로그램은 측정을 위한 것이었다. 측정이 끝난 뒤 AI에게 그 결과를 주고 프로그램을 한 번 고쳤다. 보정된 테스트 프로그램으로 다시 확인했다. 괜찮았다.

그제야 Fluid Ardule 본 프로그램에 넣었다.

이 기능의 이름을 BPM이라고 하지는 않았다. 진짜 BPM이 아니기 때문이다. MIDI clock과 동기화된 값도 아니다. 특정 Yoshimi 프리셋의 반복 속도를 귀로 측정하고 경험식으로 보정한 값이다.

그래서 이름은,

Arpeggio Speed.

인코더를 돌리면 1씩 변한다. 연주 중에도 바로 속도가 달라진다. 화면 오른쪽에는 작은 글씨로 이렇게 표시했다.

Rotate Encoder to adjust

기능 하나를 추가하는 데 오전 한나절이 걸렸다.

처음에는 내가 매뉴얼을 AI에게 주었다. AI가 매뉴얼을 분석하여 BPM을 찾았다. 틀렸다. 다시 매뉴얼에서 LFO BPM sync를 찾았다. 틀렸다. Voice Delay를 의심했다. 또 틀렸다.

결국 내가 이미 올려 둔 실제 프리셋 파일을 AI가 분석했다. 그 안에서 Echo를 찾아냈다. 나는 라즈베리 파이에서 CLI 명령을 하나씩 입력하고 건반을 눌러 검증했다. 마지막에는 테스트 프로그램을 만들고, 메트로놈으로 직접 속도를 재고, 측정값을 AI에게 주어 회귀식을 만들었다. 이를 바탕으로 Fluid Ardule 운영 스크립트를 최종적으로 수정하였다. 상세한 기술적인 내용은 GitHub에 Controlling the Apparent Arpeggio Speed of Yoshimi Presets라는 제목으로 따로 정리하였다.

요즘 AI와 하는 개발은 대략 이런 식이다.

실은 이 글도 첫 단락을 제외하면 AI가 써 준 것을 거의 그대로 옮긴 것이다. Fluid Ardule 운영 스크립트 개발을 위해 ChatGPT와 작업한 대화창은 나의 시행착오를 전부 기억하고 있기 때문에, 블로그 작성용 초안을 달라고 명령만 하면 이렇게 뚝딱 만들어 낸다. 처음에는 이런 방식으로 글을 쓰는 것에 대하여 상당한 거부감을 느꼈었는데, 나 역시 편리함과 효율 앞에서는 최신 기술과 적당히 타협하지 않을 수가 없다.

2026년 6월 30일 화요일

개발은 마지막 5분에 끝난다?

Yoshimi synth
그림 출처: Yoshimi synth

어제의 퇴근 후 개발은 Yoshimi를 매끄럽게 작동하기 위한 투쟁이었다. Yoshimi에 대한 ChatGPT의 설명을 인용해 보자.

Yoshimi는 Linux 환경을 위한 오픈소스 소프트웨어 신시사이저로, SoundFont를 재생하는 FluidSynth와 달리 실시간 음색 합성을 통해 소리를 만들어 낸다. Additive, Subtractive, PadSynth 등 다양한 합성 방식을 지원하며, 풍부한 패드, 리드, 베이스, 아르페지오와 같은 신디사이저 음색에 특히 강점을 가진다.

Fluid Ardule에서는 SoundFont(FluidSynth)뿐 아니라 Yoshimi도 하나의 음원 엔진으로 사용할 수 있다. 그런데 악기를 바꿀 때마다 Yoshimi를 다시 시작해야 했고, 그때마다 "붕~" 하는 짧은 소리가 났다. 실사용에는 매우 거북한 상황이었다.

처음에는 당연히 Python 코드의 문제라고 생각했다. 운영 스크립트를 이리저리 고쳐 보았고, 실행 중인 Yoshimi에 명령을 보내 악기만 교체하는 방법도 시도했다. 화면은 정상적으로 바뀌었지만 정작 소리는 바뀌지 않았다. 결국 그 방법은 폐기했다.

여기까지였다면 "Yoshimi는 원래 그런가 보다." 하고 끝냈을지도 모른다. 일단 다른 쪽으로 UI를 안정화한 파이썬 운영 스크립트의 최신 버전을 커밋한 다음 5km 야간 달리기를 하고 돌아왔다.

운동을 하고 돌아오니 정신은 더욱 맑아졌다. 이대로 잠자리에 들기에는 아까웠다. 다시 노트북 컴퓨터 앞에 앉아 커맨드 라인에서 Yoshimi의 프리셋 변경 테스트를 실시해 보았다.

놀랍게도 실행 중인 Yoshimi에서도 다음과 같은 명령으로 악기를 바꿀 수 있었다.

load instrument /path/to/file.xiz

그런데 이상한 점이 있었다. 공백이 없는 파일은 잘 바뀌는데, 공백이 들어 있는 파일 이름만 계속 실패하는 것이다.

한참을 테스트한 끝에 원인을 찾았다. Yoshimi의 CLI는 쉘(shell)이 아니다. 따옴표도, 백슬래시도 일반적인 리눅스 셸처럼 해석하지 않는다. 결국 공백이 없는 심볼릭 링크를 만들어 그 경로를 전달하자 실행 중인 Yoshimi의 패치가 즉시 바뀌었다.

아직 Fluid Ardule에 적용한 것은 아니다. 하지만 오늘 얻은 것은 훨씬 더 중요하다.

"실행 중인 Yoshimi의 패치를 바꾸는 것은 가능하다."

그동안은 재시작이 필수라고 생각했지만, 이제는 부드럽게 전환할 수 있는 길이 보이기 시작했다.

개발을 하다 보면 가끔은 몇 시간 동안 한 발짝도 앞으로 나가지 못하는 것처럼 느껴진다. 그런데 하루를 접고 운동을 하고 돌아와 마지막 5분 동안 결정적인 단서를 발견하는 경우가 있다.

그래서 나는 요즘 이런 생각을 한다.

개발은 하루 종일 하는 것이지만, 진짜 해결은 마지막 5분에 이루어지는 경우가 많다.

더불어서 이런 깨달음도 있다. 어제까지 만든 것이야말로 정말 최선의 안정화 버전이라고 생각했는데, 오늘 다시 돌이켜 보면 "이렇게 부끄러운 것을 어떻게 세상에 내어 놓겠는가" 하는 생각이 든다는 것이다. 운영 스크립트에 거는 기대 수준은 나날이 올라가고 있으며, 개선에 드는 시간도 생각보다 점점 짧아지는 느낌이다.

빨리 소개용 동영상을 찍고 싶은데, 내일 아침 일찍 서울에서 열리는 회의에 참석하기 위해 하루 먼저 올라와 서울역 근처의 허름한 호텔에서 밤을 보내는 내가 조금은 처량하게 느껴진다.


2026년 7월 2일 업데이트

공백을 포함한 Yoshimi의 프리셋 위치를 하이픈으로 대체하여 심볼릭 링크를 만든 뒤 Fluid Ardule 운영 스크립트 내에서 변경을 시도하였으나 소리가 바뀌지 않았다. Yoshimi를 커맨드 라인에서 실행하여 자체 프롬프트에서 load instrument를 실행하는 것과, Fluid Ardule에서 제어하는 것은 약간 다른 것 같다. 일단 이 문제는 다른 방식으로 우회하여 해결하였다. Yoshimi에서 볼륨을 줄여서 붕~ 소리가 거의 나지 않게 만든 뒤 다른 프리셋으로 바꾼 다음 다시 음량을 원상복구하는 간접적인 방식이었다. 일종의 편법이지만 한결 나아졌다.


2026년 7월 3일 업데이트

어제 퇴근 후 작업한 26072f 버전에서 드디어 안정적인 Yoshimi 패치 변경에 성공하였다. 악기 변경 전후에 볼륨을 줄였다가 원상복구하는 편법도 더 이상 필요하지 않다. 작동 안정성도 더욱 좋아진 것 같다.

2026년 6월 29일 월요일

DIYer가 가장 하기 싫은 것은...

사람마다 다르겠지만, 나는 무엇인가를 자르고 뚫는 일이 가장 하기 싫다. 특히 전동 공구를 쓸 때에는 시끄럽고 사고가 나기 쉬우며, 수공구로 톱질이나 줄질을 하다가도 손을 다칠 수 있다. 알루미늄 판에 애써 구멍 위치를 표시하고 타공을 마쳤는데 정작 여기에 고정할 보드의 볼트 구멍 위치가 맞지 않을 때의 그 절망감은 느껴 본 사람만이 안다.

반면 단단하고 창백한 실납이 인두의 열기에 녹으면서 광택과 함께 부드럽게 흐를 때에는 일종의 희열을 느낀다. 하얗게 피어오르는 연기 또한 시각적 즐거움을 더한다. 흡연자의 기분이 이런 것일까? 어쩌면 DIY 작업 중 건강에 가장 해로울 수도 있는 납땜 작업이 나는 가장 즐겁다. 물론 열을 너무 많이 가해서 배선 피복이 녹거나, 만능기판의 동그란 패드가 떨어져 나갈 때 그 난처함은 이루 말할 수 없지만. 간혹 달아오른 인두에 손을 데기도 한다.

드릴 스탠드를 구한 이후로 구멍 뚫기 작업은 한결 수월해졌다. 드릴을 수직으로 움직이는 것이 가능해졌기 때문이다. 작업대에 스탠드를 고정해 두고 작업물까지 물린 바이스까지 있다면 금상첨화일 것이다. 아직은 작업물 + 드릴 방아쇠 + 드릴을 내리누르는 손잡이까지 한꺼번에 붙잡아야 해서 거의 서커스 수준의 요령이 필요하다. 

드릴 작동 및 속도 조절을 발로 할 수 있다면? 조광기를 이용한 드릴 속도 조절기를 만들었던 일이 있다. 이는 R-core 출력트랜스포머(진공관앰프용)의 권선기로 쓰기 위함이었다. 다음은 그 증거 사진(원본 글 링크; 2022년도에 작성)이다. 사진 배경을 보니 광화문 인근 오피스텔에서 파견 근무를 하던 시절 찍은 것이다. 그 좁은 방구석에서도 열심히 납땜을 하고 구멍을 뚫었었다.


혹시 여기에 악기용 익스프레션 페달을 연결하면 발로 속도를 조절하는 것이 가능할까? 조광기는 상용 220V 전기를 사용하는 것이므로, 저전압에서 작동하는 포텐셔미터에 불과한 익스프레션 페달을 그대로 연결할 수는 없다. 안전을 보장할 수 있는 추가 회로를 만들어야 한다.

차라리 드릴 프레스 손잡이에 끈을 달아서 발에 건 뒤 아래로 당기는 것이 더 나을지도 모르겠다. 간단한 것이 최고 아닌가? 

밤 8시가 지난 시각, 아랫집에 미안한 마음을 느끼면서 라즈베리 파이 케이스에 다섯 개의 구멍을 뚫고 줄질을 하였다. RCA 단자를 쇠톱으로 자르는 일은 매우 쉬웠다. 플라스틱이니까.

헤드폰 앰프 만들기. 배선을 완료한 뒤 포맥스 판을 잘라서 위를 덮으면 끝난다. 작업대가 너무 지저분하여 AI로 배경을 약간 정리하였다.

개조한 라즈베리 파이 케이스는 헤드폰 앰프(MAX4410 칩 사용; 데이터시트)의 케이스로 변모하였다. 케이스의 바닥쪽 판은 라즈베리 파이 3B와 함께 Fluid Ardule 안에 영구 장착되었다. 하나의 케이스가 두 개의 작품으로 나뉘어 새 삶을 얻은 셈이다.