부제: 혼자서 음악 공장을 세운 한 사내의 이야기
모든 기록은 git log --reverse 에 있다.
줄거리는 첫 줄부터 마지막 줄까지 시간 순으로 흐른다. 삭제된 커밋은 없다. 방향을 바꾼 날도, 실패를 기록한 날도, 자기 자신에게 "이 파이프라인으로는 상업성이 안 된다"고 선고한 날도 전부 이 원장 안에 있다.
이 소설은 그 원장을 그대로 읽은 것이다.
주인공 이름은 dtslib1979. 본명 박씨. 직업 불명. GitHub 프로필에는 "EduArt Engineer"라고 적혀 있다. 공장 경영자를 꿈꾸는 1인 출판사이자 방송국장이자, 근무 사이의 빈 시간에 코드를 짜는 사람이다.
그가 세우려 한 것은 음악 공장이었다. 원자재는 퍼블릭 도메인 클래식 MIDI. 완제품은 YouTube BGM. 공정은 Python 파이프라인. 자동화는 AI.
이 모든 것이 하나의 Git 레포지토리에 들어 있다.
2026년 1월 18일. 하루에 열네 개의 커밋이 올라왔다.
🎵 Initial README for Parksy Audio
📋 Add CLAUDE.md project guide
🙈 Add .gitignore
🌐 Add GitHub Pages landing page
🔐 Add Secret Office with PIN authentication
📦 Add Flutter app pubspec.yaml
...
이모지가 달린 커밋들. 새 프로젝트를 시작하는 사람이 처음 며칠간 쏟아내는, 그 특유의 들뜬 리듬. 플러터 앱, MIDI 변환 서버, FastAPI 백엔드, GitHub Pages 랜딩 페이지, 시크릿 오피스 — PIN 번호는 1126 — 전부 하루 만에 뼈대가 섰다.
야심이 있었다. 커밋 메시지들이 그것을 증명한다.
근데 아직 소리가 없었다. 아직 음악이 없었다.
플러터 앱은 핸드폰에서 녹음한 음성을 MIDI로 변환하는 앱이었다. FastAPI 서버는 그 MIDI를 받아 처리하는 클라우드 엔드포인트였다. GitHub Pages는 그걸 세상에 보여주는 쇼케이스였다. 모든 것이 연결되어 있었고, 아직 아무것도 동작하지 않았다.
이튿날, 사흘 뒤, 일주일 뒤. 커밋들이 이어졌다.
feat: Complete production release with working MIDI API
docs: Add comprehensive user manual
일주일 만에 "완성"이라고 썼다. 이 시기의 커밋들은 모두 그런 분위기였다. 공장의 청사진을 그리는 시간. 실제 소리를 만드는 법은 아직 배우지 않은 상태.
2월 7일. 갑자기 기어가 바뀐다.
feat: Mini-DAW Phase 1 — local-agent (CUT → MIDI pipeline)
"local-agent"라는 폴더가 생겼다. 로컬에서 돌아가는 에이전트. MIDI를 자르고 변환하고 처리하는 Python 도구들. 며칠 만에 문서들이 쏟아졌다.
docs: 렌더 엔진 전략 확정 — Pianoteq + BBC SO + REAPER 듀얼 엔진
처음 잡은 목표는 높았다. Pianoteq, BBC Symphony Orchestra, REAPER — 유료 물리 모델링 엔진들. 돈이 드는 선택지들이었다. 하지만 일단 써 두었다. 방향은 잡혔다.
그러나 먼저 무료인 것을 써봐야 했다. 2월 8일.
Phase 2: FluidSynth config + MIDI clean/merge
FluidSynth. 오픈소스 소프트 신디사이저. MIDI 파일을 넣으면 .wav 파일로 뱉어주는 도구. 그 자체로는 악기가 없고, SoundFont라는 가상악기 파일을 불러서 소리를 낸다. SF2. Software Font 2.
같은 날 버그를 만났다.
fix clean_midi: 2-pass abs/delta timing to prevent FluidSynth hang
fix render: FluidSynth cmd arg order (-F -r before soundfont/midi)
FluidSynth가 멈췄다. 타이밍 처리를 잘못하면 소프트웨어가 무한루프에 빠진다는 것을 알았다. 명령줄 인자 순서가 틀리면 파일이 열리지 않는다는 것을 알았다. MIDI를 두 번 파싱해서 절대시간과 델타시간을 모두 정리해야 한다는 것을 알았다.
하루 만에 두 개의 버그를 수정하고, 첫 음악이 나왔다.
feat: Bruckner Symphony No.9 — 3 movements MP4
브루크너 교향곡 9번. 세 악장. FluidSynth가 렌더링하고 FFmpeg이 영상으로 포장했다. 소리는 좋지 않았다. FluidR3 GM이라는 141MB짜리 SoundFont는 그 이름처럼 범용이었고, 브루크너의 웅장함을 담기에는 역부족이었다. 하지만 나왔다. 소리가 났다. 그것으로 충분했다.
다음날은 라벨의 볼레로였다.
feat: Ravel Bolero 2min MP4
그 다음날에는 다른 SoundFont를 시험했다. SSO, VSCO2 CE. Sonatina Symphonic Orchestra. VSCO Community Edition. 오케스트라 사운드를 위한 SFZ 라이브러리들. 백조의 호수를 오보에와 현악과 하프로 렌더링했다.
Sample: Swan Lake Theme — SSO Auto Render (Oboe+Strings+Harp)
이 무렵의 커밋들을 읽으면 실험실 노트가 생각난다. 매일 다른 재료를 넣고 결과를 기록하는. 어떤 SoundFont가 어떤 음악에 맞는지 계속 시험했다.
그리고 2월 11일, 결정적인 SoundFont를 만났다.
feat: Swan Lake — Timbres of Heaven 4.0 (419MB SF2, 48kHz, AAC 256k)
Timbres of Heaven. TOH4. 419MB. 다른 것들보다 세 배 컸다. 그리고 소리도 달랐다. 어둡고 깊은 저역. 묵직한 서스테인. 브루크너와 말러에 어울리는 소리. 이것이 주력 SoundFont가 되었다.
같은 날 또 하나의 중요한 결정이 내려졌다.
Pivot to Piano Minimal: drop orchestration, keep piano only
방향 전환. 오케스트레이션 드랍. 피아노만.
왜였을까. 커밋 메시지에 이유가 짧게 적혀 있었다.
"Add Audio Production Strategy: lo-fi intentional roughness"
의도적인 거칠음. SF2로 풀 오케스트라를 만드는 것보다 피아노 솔로에 집중하는 것이 더 정직한 선택이었다. 뭔가를 숨기는 것보다 뭔가를 드러내는 것. 도구의 한계를 인정하고, 그 한계 안에서 최선을 찾는 것.
그것이 "Parksy Piano Minimal"의 탄생이었다.
이날 하나만 따로 장을 뽑아야 한다.
2026년 2월 11일. 단 하루에 커밋이 열네 개였다. 이 날은 프로젝트 전체를 통틀어 가장 많은 결정이 내려진 날이었다.
SoundFont 전쟁이 있었다. SGM-V2.01 vs FluidR3 vs TOH4. 같은 MIDI를 세 가지 SoundFont로 렌더링해서 비교했다. 백조의 호수. 사육제 13번. 파베인. 클레르 드 뤼. 비교 비교 비교.
음악 변환 파이프라인이 완성되었다.
MIDI 확보
↓
Piano Solid (prog→0 강제)
↓
humanize_preset.py
↓
FluidSynth + TOH4.sf2
↓
FFmpeg (L1 앰비언트 -18dB + L2 음악 -3dB)
↓
YouTube MP4
그리고 저작권 문서들이 생겼다.
feat: Three-Layer copyright defense — CC stripping + whitepaper v2.0
Add Audio IP Recovery Kit: 5 legal documents
docs: Legal Risk Assessment FINAL v1.0
Legal Risk Assessment. 법적 리스크 평가. 혼자서 이런 문서를 쓴다는 것.
핵심 주장은 이러했다. MIDI는 음반이 아니다. US Copyright Office Compendium §803.4(C)에 따르면 표준 MIDI 파일은 음악적 악보의 구조를 담지만, 특정 음의 연속을 담지 않는다. 한국 저작권법에서도 "음반"의 정의는 음이 유형물에 고정된 것 — MIDI는 음이 아니라 명령어다.
작곡가가 사망한 지 70년이 지난 퍼블릭 도메인 음악. 그 악보를 MIDI로 변환한 것. 그것을 FluidSynth로 다른 소리로 렌더링한 것. 앰비언트 자연음과 믹싱한 것.
5단계가 모두 깨끗하다. 리스크 총평: 극히 낮음.
이날 마지막 커밋.
feat: chopin nocturne op.9 no.1 — 피아노 솔로 풀 사이클
쇼팽 녹턴 9번 1악장. 피아노 솔로. 완전한 파이프라인을 통과한 첫 트랙이었다.
이틀이 더 있었다.
2월 12일. YouTube 업로드 시스템이 생겼다. Production Console. Queue 시스템. Claude Code 없이도 돌아가는 큐 엔진. process_queue.py.
그리고 커밋 하나가 눈에 띈다.
docs: THESIS + README 재설계 — 이건 음악이 아니라 설계서다
"이건 음악이 아니라 설계서다."
이 문장이 이 프로젝트의 본질을 가장 정확하게 요약한다. 음악을 만드는 것이 목적이 아니었다. 음악을 안정적으로 생산하는 시스템을 만드는 것이 목적이었다. 작곡가 포지션이 아니라 엔진/프로듀서 포지션.
2월 13일. 이날도 폭풍 같은 하루였다.
feat: piano_expression.py — 7-Stage 프로 피아노 표현 엔진 (Phase 5)
7단계 표현 엔진. MIDI 파일을 넣으면 프로 피아니스트처럼 연주해주는 알고리즘.
1단계: Parse — 절대시간 기반 노트 리스트
2단계: Phrase Detection — 프레이즈 자동 감지
3단계: Voicing — 멜로디/베이스/내성 음역 차등화
4단계: Dynamic Phrasing — sin 곡선 크레셴도/디크레셴도
5단계: Rubato — 구조적 템포 유연성
6단계: Articulation — 레가토/스타카토/아르페지오
7단계: Sustain Pedal — CC64 자동 삽입
"초딩이 치는 것 같다"는 피드백 이후 만든 도구였다. 기존 humanize_preset이 단순히 무작위 흔들림을 주었다면, piano_expression은 실제 연주 스타일을 알고리즘으로 주입했다.
같은 날, Gate 1 시스템이 설계되었다.
docs: Gate 1 MIDI 품질 사전 평가 시스템 설계
MIDI 파일의 품질을 5개 차원으로 평가하는 시스템. Velocity 분포, Timing 정밀도, Structure, Expression, Integrity. A~F 등급.
그리고 A-grade 배치 프로덕션.
feat: A-grade batch production — 4 tracks full cycle
쇼팽 뱃노래 Op.60. 쇼팽 녹턴 No.7. 리스트 위안 No.3. 쇼팽 녹턴 No.13.
Gate 1 기준으로 모두 A등급이었다. 점수 83~91점. 배치로 처리했다. 4개 트랙. 풀 사이클.
그리고 그 직후에, 가장 짧고 가장 무거운 커밋이 왔다.
docs: Phase 6 A-grade batch 상업성 실패 기록
"못 들어주겠다."
4개 트랙이 전부 상업적 품질 미달이었다. Gate 1 A등급 4개. 93~91점짜리 MIDI. piano_expression 7단계 처리. FluidSynth + TOH4. 그런데 결과가 형편없었다.
이유가 뭐였을까. 프로젝트는 이 질문 앞에서 멈췄다.
조사가 시작되었다.
문제가 발견되었다.
piano_expression.py가 원본 보이싱을 파괴하고 있었다. 9개 트랙을 1개로 강제 병합. velocity +15 voicing 재지정. 원본 CC64 페달 삭제 후 알고리즘 재생성. 모든 프레이즈에 동일한 sin 곡선.
이미 좋은 표현이 있는 MIDI에 알고리즘 표현을 덮어씌운 것이었다. 원본 뉘앙스를 지우고 기계적 패턴을 입힌 것이었다.
그래서 들을 수 없었던 거였다.
해결책은 역설적이었다.
feat: Phase 6.1 — humanize_preset A/B 재처리 (4트랙)
piano_expression 도구를 쓰지 않는 것. 대신 humanize_preset — 원래 훨씬 단순한 도구 — 로 미세 보정만 했다. ±5ms 타이밍 흔들림. ±8 velocity 지터. 그게 전부.
그리고 들을 수 있게 되었다.
docs: 프로덕션 프로세스 확정 — Gate 등급별 처리 분기
이것이 확정 원칙이 되었다.
A/B grade MIDI → humanize_preset (light touch, 원본 표현 보존)
C/D grade MIDI → piano_expression (표현이 없는 것에 표현 주입)
F grade → REJECT
piano_expression.py는 "표현이 없는 MIDI에 표현을 넣는" 도구이지, "이미 좋은 표현을 개선하는" 도구가 아니다.
교훈은 세 글자였다.
좋은 MIDI는 건드리지 마라.
일주일이 지나고, 2월 20일에 거대한 보고서가 올라왔다.
docs: Phase 8 — 마스터링 파이프라인 최적화 실험 개발일지
하루 종일. 6라운드. 22개 MIDI. 42개 파라미터.
Phase 8은 체계적이었다. R1에서 기준선을 잡고, R2에서 SoundFont를 비교했다. R3에서 EQ와 컴프레서의 조합 행렬을 탐색했다. R4에서 Expression 파라미터를 조정했다. R5에서 앰비언트 믹싱 최적점을 찾았다. R6에서 전체 22개 MIDI에 최적 설정을 적용해 검증했다.
가장 중요한 발견이 R2에서 나왔다.
TOH4가 졌다.
SGM-V2.01. 236MB. TOH4의 절반 크기. 평균 점수 96.9. TOH4는 95.1. 차이는 +1.8점이었지만, 방향이 달랐다. SGM은 밝고 균형 잡혀 있었다. TOH4는 어둡고 저역이 강했다.
결론. 하나의 SoundFont가 아니라 스타일별 선택제.
SGM → Warm Classical
TOH4 → Dark Funeral
같은 MIDI로 두 가지 분위기를 낼 수 있게 되었다.
R4에서는 S-curve k값이 가장 큰 변수였다. k=5.0으로 설정했더니 LRA가 19.3까지 폭발했다. 80점대에서 60점대로 떨어졌다. k=3.0으로 낮추자 LRA가 8.6으로 안정되고 100점을 회복했다. 23점의 차이. 숫자 하나가 품질을 바꿨다.
R5에서는 앰비언트 볼륨의 스위트 스팟이 -20dB이라는 것을 발견했다. -18dB은 True Peak을 침범했다. -22dB은 존재감이 없었다. -20dB이 딱 그 경계였다.
6라운드가 끝났을 때, 22개 MIDI 중 15개(68%)가 100.0점이었다. 평균 96.4점.
optimal_config.json — 42개 파라미터가 확정되었다.
Phase 8이 음악의 문제를 해결했다면, 다음 과제는 그것을 세상에 내보내는 것이었다.
feat: 브릿지 인프라 구축 — Google Drive + YouTube Studio CLI
YouTube Studio CLI. youtube-studio.js. Node.js, googleapis. node tools/youtube/youtube-studio.js upload video.mp4 --title "Parksy Piano Minimal #001" --privacy private. 명령줄 한 줄로 YouTube에 영상을 올릴 수 있게 되었다.
Google Drive 동기화. rclone. ./tools/gdrive-sync.sh youtube. 렌더링 결과물을 자동으로 Drive에 올렸다.
같은 날 Gemini Lyria 3 워크플로우도 만들어졌다.
feat: Gemini Lyria 3 워크플로우 전체 구축 — 숏폼 오디오 레이어
Lyria 3는 다른 레이어였다. 30초짜리 AI 생성 음악. CM송, 오프닝 징글, YouTube Shorts BGM. PD 클래식 파이프라인과 분리되어 있었다. lyria3/ 폴더 밖으로 절대 나가지 않는다는 규칙이 있었다. 두 계통이 섞이면 안 된다는.
2월 23일. 채널 구조가 완성되었다.
feat: Musician TV 5-Program 채널 구조 설계 — 음악 발전 퍼널
P1: 큐레이션 [Consumer]
P2: 박씨 오디오 [Producer]
P3: AI 작곡 랩 [Creator]
P4: 가라오케 [Performer]
P5: 완성 음원 [Artist]
소비자에서 예술가까지. 5단계 퍼널. 듣는 사람이 만드는 사람이 되는 과정.
이것은 사업 계획이기도 했고 자기 계획이기도 했다.
2월 24일. 두 개의 커밋.
docs: 헌법 제1조 — 레포지토리는 소설이다
docs: 헌법 제2조 매트릭스 아키텍처 — 전 레포 광역 적용
헌법. 박씨는 자신의 모든 레포지토리에 적용할 헌법을 썼다.
제1조.
**모든 레포지토리는 한 권의 소설책이다.**
**커밋이 문장이고, 브랜치가 챕터이고, git log --reverse가 줄거리다.**
삽질, 실패, 방향 전환 전부 남긴다. squash로 뭉개지 않는다. 기능 구현 과정 = 플롯.
제2조.
**모든 레포지토리는 공장이다.**
**가로축은 재무 원장(ERP)이고, 세로축은 제조 공정(FAB)이다.**
커밋은 전표다. 한번 기표하면 수정이 아니라 반대 분개로 정정한다.
4대 원칙.
1. 삭제는 없다, 반대 분개만 있다 — git revert. reset --hard 금지.
2. 증빙 없는 거래는 없다 — 커밋 메시지에 이유와 맥락.
3. BOM 확인 후 착공한다 — 의존성 명세 먼저.
4. 재공품을 방치하지 않는다 — WIP 브랜치와 큐는 정기적으로 소화한다.
이 헌법이 이 레포를 넘어 전체 28개 레포에 적용되었다. 한 사람이 운영하는 작은 왕국에 법이 생긴 것이었다.
3월. 뭔가 달라지기 시작했다.
docs: WSL2 Claude Code CLI 인증 실패 원인 분석 및 해결 보고서
WSL2. Windows Subsystem for Linux 2. 박씨의 컴퓨터에서 돌아가는 Linux 환경. 이 글이 올라오기 전까지, Claude Code는 핸드폰 Termux에서 SSH로 원격 접속해서 돌렸다. 그런데 WSL2 환경에서 Claude Code CLI 인증이 실패하는 문제가 있었다. credentials.json 파일을 제대로 배치하면 해결된다는 것을 발견했다.
3월 15일. 아키텍처 확정 문서.
docs: 음악 파이프라인 아키텍처 확정 문서 (2026-03-15)
3월 16일. 패러다임 전환을 선언했다.
chore: 전역 컨텍스트 주입 — 특별법 제0조 + SCM 시퀀스
특별법 제0조.
**전환 이유: Claude Code가 메인 드라이버다.**
Claude Code는 에이전트다. 이 에이전트가 가장 잘 돌아가는 환경(WSL2)에 모든 걸 맞춘다.
Windows 환경은 무시한다. WSL2 기준으로 모든 작업을 설계한다.
| Before | After | |||
| 메인 기기 | 핸드폰 (Termux) | 집 PC (WSL2) | ||
|---|---|---|---|---|
| 보조 기기 | PC (원격 서버) | 핸드폰 (SSH 클라이언트) |
죽은 패턴.
❌ headless Chromium 우회
❌ ADB 체인
❌ 핸드폰에서 CDP 흉내
이것은 단순한 환경 변경이 아니었다. 일하는 방식의 철학적 전환이었다. 도구에 맞추는 것이 아니라, 도구가 가장 잘 작동하는 환경에 자신을 맞추는 것.
같은 날, 텔레그램 봇이 생겼다.
feat: telegram bot v1.0 — 오디오 파이프라인 원격 제어 봇 신규
핸드폰에서 텔레그램 메시지를 보내면, WSL2의 PC에서 Claude Code가 파이프라인을 돌린다. 그리고 결과를 텔레그램으로 돌려받는다. 중간 매개가 필요 없어졌다.
텔레그램 봇이 단순한 스크립트가 아니었다.
feat: 83b8682 — telegram audio bot v2.1 — asyncio+스트리밍+슬롯 권한
DraftStreamer 패턴. 같은 메시지를 실시간으로 편집한다. 새 메시지를 보내는 것이 아니라, Claude Code가 생각하는 것을 살아있는 텍스트로 보여준다. Python SDK 오픈소스 프로젝트들에서 가져온 패턴이었다.
SQLite 세션. (chat_id, workdir) → session_id. 대화가 이어진다.
슬롯 권한 시스템. ADMIN, SLOT 1~3, NONE. 어머니도 파일을 드랍할 수 있고, Claude가 처리한다.
3월 16일에 완성된 봇은 3월 19일에 더 나아졌다.
feat: Telegram 봇 실시간 피드백 + M4A 자동 전송 (bot v2.4)
타임아웃 300초에서 1800초로. 음악 파이프라인은 10~20분 걸리기 때문이었다. 30초마다 하트비트: "⏳ 작업 중... (2분 30초 경과)". M4A 파일 자동 감지 후 텔레그램으로 전송. /approve 명령으로 YouTube 비공개 업로드.
파일을 보내면 봇이 물어본다. 어떤 감정으로 처리할까요? 어떤 스타일로? 이터레이션 횟수는?
답을 받으면 파이프라인이 돌아간다.
30분 뒤에 음악이 텔레그램에 도착한다.
3월 22일.
feat: melody_60s_from0s.mp3 → 100.0/100 렌더링 완성
60초짜리 멜로디 파일. 208개 노트. 파이프라인을 통과한 결과 점수가 100.0이었다. 하지만 그냥 된 것은 아니었다.
dynaudnorm이 LRA를 4.4에서 1.1로 오히려 붕괴시켰다. 스파스 소스에 dynaudnorm을 쓰면 안 된다는 것을 배웠다. score_engine이 100MB 이상 파일은 앞 60초만 측정한다는 함정을 발견했다. pcm_s16le -ar 48000 강제 출력으로 44MB를 만들어서 전체 측정이 가능하게 했다.
그리고 핵심 해결책을 발견했다.
volume='max(0.5, 0.75 + 0.25sin(2PI*t/120))':eval=frame
sin파 볼륨 자동화. 120초 주기. 6dB 스윙. LRA 2.9에서 6.1로. 단순 반복 루프가 LRA를 붕괴시키는 것을 sin파로 막는다.
이것은 기술 메모가 아니었다. 이것은 악기 연주의 원리였다. 음악은 반복 안에서도 작은 파동을 가져야 한다. 완전히 동일한 소리는 소리가 아니다.
3월 24일. REAPER.
FluidSynth + SF2의 음질 천장이 명확해졌다. Phase 8을 아무리 최적화해도 100점이 나왔지만, 귀로 듣는 청감 품질은 상업 수준에 미치지 못했다. 점수와 소리 사이의 괴리.
REAPER. 영상 편집으로 치면 DaVinci Resolve 같은 것. 전문가용 DAW. $60이지만 평가판 만료 후에도 5초 스플래시 화면만 뜨고 기능 제한 없이 사용 가능한 소프트웨어. reaper.exe -renderproject file.rpp로 CLI 렌더링이 된다.
0e7ecea feat: REAPER Phase2 렌더링 엔진 전환 + 설치 삽질 이력 기록
REAPER에 sfizz VST를 붙이고, Salamander Grand Piano V3 SFZ 라이브러리를 로드하고, MIDI를 렌더링했다.
feat: Salamander Grand Piano V3 REAPER 템플릿 + genre alias 추가
Salamander. 오픈소스 피아노 샘플 라이브러리. CC BY 3.0. 44.1kHz 16bit. sfizz가 SFZ 포맷을 읽어서 REAPER에서 가상악기로 사용했다.
그리고 VST 설치에 도전했다.
Pianoteq 8. 물리 모델링 피아노. 다이내믹 계단이 없는 피아노. SWAM Bassoon. 물리 모델링 바순. 용량은 600MB 미만. 소리는 최상급.
Playwright로 Pianoteq 설치 페이지를 열고 CDN URL을 캡처했다. 72MB 다운로드 성공. C:\Temp\pianoteq_trial_v912.exe.
그 다음이 문제였다.
bcca671 docs: VST 설치 UAC Hell 삽질 이력 저장 (#017)
UAC. User Account Control. 윈도우 보안 시스템. VST 인스톨러를 실행하면 UAC 프롬프트가 뜬다. 동의하면 설치. 거부하면 종료. 간단하다.
근데 WSL2에서 자동화하려면 불가능이었다.
8가지를 시도했다.
PowerShell Start-Process -Verb RunAs. 에러: The operation was canceled by the user.
NSIS /S 사일런트 설치. 에러: The requested operation requires elevation.
NSIS 사용자 경로 지정. 설치 0MB.
7z로 NSIS 페이로드 추출. 아이콘만 나옴.
VBScript runas. 창이 안 뜸.
Task Scheduler RunLevel Highest. Access is denied (0x80070005).
win-gui MCP. 이 세션에서 연결 안 됨.
Playwright MCP. 다운로드는 됐는데...
그 다음. 치명적인 실수.
chromium lock 파일을 제거하려다 Playwright MCP 서버 자체를 죽였다. 세션 재시작 전까지 브라우저 자동화 전면 불가.
4시간이 날아갔다.
이유가 있었다.
일반 데스크탑 (WinSta0\Default)
└─ 모든 앱, 브라우저, pyautogui 접근 가능
UAC Secure Desktop (WinSta0\Winlogon) ← 별도 윈도우 스테이션
└─ consent.exe 단독 실행
└─ 어떤 프로세스도 접근 불가
└─ 물리적 마우스 클릭만 가능
구조적으로 불가능했다. UAC Secure Desktop은 완전히 격리된 세계다. 어떤 코드도, 어떤 자동화도 거기 들어갈 수 없다. 들어가려면 물리적으로 화면 앞에 앉아서 직접 클릭해야 한다.
30초면 끝나는 일을 자동화하려다 4시간을 날렸다.
개발일지에 이렇게 적혔다.
**교훈:** WSL → Windows admin 자동화 = 구조적으로 불가능.
VST 인스톨러 = 직접 더블클릭이 유일. 자동화 시도 = 시간 낭비.
같은 날, DAW 스터디 결과가 올라왔다.
docs: DAW + 가상악기 스터디 — Reaper + Pianoteq + SWAM Bassoon 최종 조합 확정
비교 분석. Ardour, Zrythm, LMMS, Qtractor, Rosegarden. 모두 검토했다. 결론은 Reaper.
가상악기 비교. 피아노 5개. 바순 4개. 물리 모델링 vs 샘플링. 다이내믹 계단의 존재 여부.
결론. Pianoteq 8 Standard $449 + SWAM Bassoon $149 = $598.
그리고 이 결정이 내려졌다.
기존 FluidSynth SF2 파이프라인은 폐기가 아니라 공존.
대량 생산(SF2) + 프리미엄 단품(VST) 이원 구조.
3월 27일. BBC Symphony Orchestra Discover.
Spitfire Audio의 무료 풀 오케스트라 라이브러리. 등록하면 무료. 설치만 하면 된다. Spitfire Audio 앱을 실행하고, 로그인하고, My Products 탭에서 Install 버튼을 누르면 된다.
문제는 역시 자동화였다.
WSL에서 Playwright로 Spitfire Audio Electron 앱을 조작하려 했다. ShowWindow, FindWindow, SendKeys. 앱 최대화가 안 됐다. My Products 탭을 클릭하려는데 Chrome이 포커스를 가져가 버렸다. File Explorer가 열렸다. SetForegroundWindow 후 클릭해도 탭 전환이 안 됐다.
6시간.
결론.
Spitfire GUI 인증 흐름 = 자동화 불가.
그리고 원칙이 확정되었다.
"설치는 사람 30분, 운용은 AI 영원히."
| 영역 | 담당 | |
| VSTi 설치 + 인증 | 박씨 직접 (1회성, ~30분) | |
|---|---|---|
| .rpp 프로젝트 세팅 | Claude Code | |
| MIDI 생성 | Claude Code | |
| 렌더링 / 믹싱 / 후처리 | Claude Code | |
| 텔레그램 자동 전송 | Claude Code |
이 원칙은 단순한 분업이 아니었다. 무엇이 자동화될 수 있고 무엇이 인간의 손을 필요로 하는지에 대한 인식이었다. UAC는 뚫을 수 없다. GUI 인증은 서버 상태에 종속된다. 이메일 확인은 알 수 없다.
그것들은 사람이 한다. 한 번만. 그 이후는 AI가 한다. 영원히.
3장르 무료 VSTi 5종 플랜이 확정되었다.
BBC SO Discover. Spitfire LABS Soft Nylon Guitar. Ample Guitar M Lite II. Ample Bass P Lite II. MT Power Drum Kit 2. 총 비용 0원. 총 용량 1.7GB.
보사노바. 어쿠스틱 락밴드. 실내악.
같은 날 오후. 다른 커밋.
fb485ca feat: PARKSY Composition Modular v2.0 — 4모듈 완성 + 통합 파이프라인
이것은 전혀 다른 종류의 작업이었다.
핸드폰 로컬에서 박씨가 혼자 생각하고 모델링했던 것. 어느 날 GitHub에 업로드되어 나타났다. Claude Code가 그것을 보았다.
ParksyLog. 핸드폰에서 작성한 문서. React PWA 코드가 포함된 설계 문서. 24개의 감정 상태. 각 감정에 매핑된 16개 음악 파라미터. 3인의 작곡가 스타일.
플루치크 감정의 수레바퀴.
심리학자 로버트 플루치크의 모델. 기쁨, 신뢰, 두려움, 놀라움, 슬픔, 혐오, 분노, 기대. 8개 기본 감정이 3단계 강도를 가진다. 황홀→기쁨→평온. 황금빛 분노→분노→짜증. 이 24개 상태에 8개 이중 감정이 추가되어 총 26~34개 상태가 된다.
이것을 음악 파라미터에 매핑했다. 조성, 모드, 템포 범위, 벨로시티 곡선, 종지 패턴, 화성 진행, 음정 선호, 아티큘레이션, 텍스처, 반음계주의, 전조 빈도.
그리고 3인의 작곡가.
포레. 수평적 이동. 모달 화성. 3도 관계 전조. 도리안 6도. 종지 회피. 40%의 plagal. 조용한 빛.
브루크너. 수직적 블록. 갑작스러운 동적 변화. General Pause. 현악 트레몰로. 묵직한 정지.
말러. 극단적 감정. 인간 목소리를 향한 충동. Ersterbend. 소멸하며 사라짐. 폭발에서 소멸까지.
세 작곡가를 확률 비율로 섞는다. 슬픔이면 Fauré 60%, Bruckner 20%, Mahler 20%. 분노이면 Bruckner 50%, Mahler 40%, Fauré 10%.
SHUFFLE_COMBOS. 6가지 교차 레시피.
A — 모달 고요: 포레 도리안 + 브루크너 현악 + 말러 PPP
B — 결단의 서곡: 브루크너 블록 + 포레 평행 + 말러 팡파르
C — 분열된 서정: 말러 가성 + 포레 반음계 + 브루크너 General Pause
D — 엄숙한 기도: 브루크너 코랄 + 포레 plein-jeu + 말러 Choral
E — 대위법적 소용돌이: 포레 fuga → 브루크너 발전부 + 말러 악기 추가
F — 미끄러짐→정지→소멸: 포레 종지 회피 + 브루크너 General Pause + 말러 Ersterbend
그리고 이 모든 것을 파이썬으로 구현했다.
harmony_library.py — 화성 라이브러리. 데이터만. 3인의 스타일 테이블. Shuffle 조합. Plutchik 매핑. Schubart의 1806년 조성-감정 매핑.
composer_v2.py — 메인 작곡 파이프라인. 감정 → 다이나믹. 26종 벨로시티 곡선. Ersterbend: max(0.05, 1.0 - t_norm**0.7). ppp_then_fff_explosion: 0.75 지점 폭발.
chord_engine.py — 화음 생성. Krumhansl-Kessler 프로파일로 조성 탐지. Roman numeral 파싱. 보이스 리딩. 공통음 최대화.
overture_presets.py — 서곡 프리셋. Tier S 오버처 20개 카탈로그. PARKSY_PRESETS 12개.
PKS-001: 소멸 서곡. Coriolan 템플릿. grief, combo F, through_composed.
PKS-009: 보사노바 서곡.
PKS-010: 락밴드 서곡.
그런데 버그가 있었다.
TypeError: compose() got an unexpected keyword argument 'harmony_prog'
preset_to_compose_params('PKS-001')이 harmony_prog를 반환하는데, compose()가 그것을 받지 못했다. 파라미터 목록에 없었다.
c5300c5 fix: compose() harmony_prog 파라미터 수용 — preset_to_compose_params() 연결 버그 수정
수정 후 테스트.
[composer_v2] emotion=grief combo=F form=through_composed
key=C minor, vel=(15, 60), curve=ersterbend
[composer_v2] 서곡 형식 스캐폴딩: through_composed
[composer_v2] 셔플 조합 F: 미끄러짐 → 정지 → 소멸
[chord_engine] 탐지된 조성: A minor
[chord_engine] harmony_prog: ['i', 'bVI', 'dim7', 'V', 'i', 'iv', 'dim7']
[chord_engine] 화음 트랙 추가 (ch 1, 3565 events)
[chord_engine] 베이스 트랙 추가 (ch 2, 833 events)
[chord_engine] CC 자동화 트랙 추가 (1043 events)
→ /tmp/PKS001_test.mid
출력: 25트랙, 406.3초
25개 트랙. 6분 46초. grief. combo F. 미끄러짐, 정지, 소멸.
PKS-001이 나왔다.
이 소설에는 아직 쓰이지 않은 챕터가 있다.
멜로디 생성기. motif_extractor.py. 실제 포레, 브루크너, 말러의 MIDI에서 모티프를 추출하고, 감정 파라미터에 따라 재조합하는 모듈. 박씨가 "의식적 표절"이라고 불렀던 것.
이것이 전체 파이프라인에서 유일하게 빠진 핵심 모듈이다. 화성 라이브러리가 있고, 화음 엔진이 있고, 서곡 프리셋이 있고, 감정-파라미터 매핑이 있다. 그런데 멜로디를 어디서 가져오는지가 없다.
VSTi 설치도 아직 대기 중이다. BBC SO Discover. LABS Soft Nylon Guitar. Ample Guitar. Ample Bass. MT Power Drum Kit 2. 파일들이 C:\Temp에 있다. 박씨가 더블클릭해서 UAC를 승인하면 된다. 30분이면 된다. 그러면 Claude Code가 이어받는다. 영원히.
Reaper headless 렌더 파이프라인도 미완이다. WSL2에서 Windows REAPER.exe를 CLI로 실행하고, BBC SO VSTi로 렌더링하고, WAV를 받아오는 과정. 이것이 완성되면 SF2 파이프라인의 음질 천장을 넘는다.
그리고 YouTube. @musician-parksy. 채널이 있다. 파이프라인이 있다. 음악이 만들어지고 있다. 아직 올라간 영상은 없다.
[ ] 박씨가 VSTi 5종 직접 설치 (30분)
[ ] 설치 완료 신호 → Claude Code 바톤 터치
[ ] REAPER VST 리스캔
[ ] 3장르 템플릿 .rpp 생성
[ ] motif_extractor.py 구현
[ ] 첫 YouTube 업로드
이 소설의 마지막 문장은 이미 정해져 있다. 각 개발일지의 마지막마다 박씨가 서명처럼 적어두는 말.
Built between shifts. — dtslib1979
근무 사이에 짓는다.
낮에 다른 일을 하고, 그 빈 시간에 공장을 세운다. 핸드폰으로 텔레그램을 보내면 집 컴퓨터가 응답한다. 음악이 만들어진다. 30분 뒤에 핸드폰에 M4A가 도착한다.
이것이 1인 방송국의 생산 방식이다.
이것이 지금도 계속 쓰이고 있는 소설이다.
全 커밋: 150+
全 기간: 2026년 1월 18일 ~ 현재
총 Phase: 1 → 8 → v2.0
총 실패: 기록된 것만 수십 건
총 교훈: 헌법 1조 — 레포지토리는 소설이다