PHP2Shell 공지를 보고 점검했더니 PHP가 하나도 없었습니다

이미지
10월 21일에 PHP와 Node.js가 같은 날 보안 패치를 냈습니다. PHP 쪽은 사람들이 PHP2Shell이라고 부르고 있고, Node 쪽은 Node2Shell이라는 이름이 붙었습니다. 이름부터가 좀 무섭습니다. 뒤에 Shell이 붙으면 대개 남의 서버에서 명령을 실행할 수 있다는 뜻이니까요. 회사에서도 바로 지시가 내려왔습니다. 전 프로젝트 점검하고, 외부 IP 붙은 서버는 전수조사하라는 내용이었습니다. 회사 쪽 일은 회사 쪽대로 하고, 저는 퇴근하고 개인 프로젝트랑 예전에 알바로 했던 것들을 한번 열어 봤습니다. 그런데 열어 보고 나니 이번 글은 패치 이야기가 아니라 7년 전 이야기가 됐습니다. PHP2Shell과 Node2Shell, 둘이 같은 무게는 아닌 것 같습니다 찾아오신 분들은 아마 이게 뭔지, 내 서버가 해당되는지부터 궁금하실 것 같아서 그것부터 적습니다. PHP2Shell은 CVE 두 건입니다. CVE-2026-109618 과 CVE-2026-109619이고, 둘 다 인증 없이 원격에서 코드를 실행할 수 있는 취약점입니다. CVSS 4.0 기준 9.2점입니다. 하나는 메모리가 부족할 때 PHP가 요청 데이터를 반쯤 만든 상태에서 멈추고, 정리 단계에서 그 망가진 데이터를 멀쩡한 걸로 취급하는 문제입니다. 다른 하나는 요청이 끝난 뒤에도 그 요청이 쓰던 상태가 남아 있다가 같은 워커가 받은 다음 요청에서 다시 쓰이는 문제입니다. PHP 공식 공지 기준으로 고쳐진 버전은 8.5.12, 8.4.27, 8.3.36, 8.2.35입니다. 그보다 낮은 버전은 전부 해당됩니다. 8.1 이하는 PHP 프로젝트가 더 이상 정규 릴리스를 내지 않습니다. 대신 보안팀이 7.4, 8.0, 8.1용으로 최소한의 소스 백포트를 따로 공개해 뒀고, 배포판이나 LTS 벤더 중에도 백포트를 내는 곳이 있다고 합니다. 직접 빌드하거나 벤더 패키지를 쓰는 게 아니면 사실상 버전을 올리는 수밖에 없어 보입니다. 공지에도 설정을 바꾸는 건 부분적인 완화일 뿐이고...

Claude에게 음악까지 맡기려다 하루 늦게 안 것

밤에 스탠드 불빛만 켜진 나무 책상 위에 작은 건반과 닫힌 노트북, 그 앞에 놓인 헤드폰과 머그컵

설정 화면에서 커넥터 목록을 내리다가 ElevenLabs 가 보였습니다.

처음 든 생각은 드디어, 였습니다. 저한테는 반가운 이름이었습니다. 범용 AI 쪽에 음악 도구가 들어왔다는 건 제가 몇 달 동안 돌아가는 길만 찾고 있던 문제에 정식 경로가 생겼다는 뜻으로 읽혔습니다.

언제부터 있었는지 찾아봤더니 어제였습니다. 그게 좀 묘했습니다. 같은 달 초에 정반대 방향의 일이 있었거든요. 음악 생성 전용 도구 쪽은 다운로드 횟수를 제한했는데, 범용 도구 쪽은 만드는 기능을 추가했습니다. 3주 사이에 일어난 일입니다. 그리고 그걸 확인하다가 저는 한 번 틀렸습니다.

두 군데서 멈췄던 일

작년부터 취미로 게임을 만들고 있습니다. 그중 하나가 아이가 만들고 싶다고 한 미연시인데, 사이드 프로젝트 네 개를 동시에 붙들고 있던 때에 같이 시작한 겁니다. 엔진은 Ren'Py 를 썼습니다. Python 기반 비주얼 노벨 도구인데 대화랑 선택지랑 분기가 이미 다 들어 있어서 스크립트 파일 하나만 고치면 돌아갑니다.

여기서 AI 가 해주는 건 꽤 분명했습니다. 기획은 됩니다. 캐릭터 설정을 주고 분기 구조를 짜달라고 하면 루트가 몇 갈래로 나뉘는 설계가 나옵니다. 개발도 됩니다. 스크립트 문법이 단순해서 대화 200줄 붙이는 건 정말 30분입니다. 테스트도 됩니다. 분기를 다 타보고 도달할 수 없는 라벨을 찾아달라고 하면 찾아줍니다.

그런데 게임은 텍스트만 있으면 되는 게 아니었고, 딱 두 군데서 멈췄습니다. 하나는 화면에 띄울 그림입니다. 캐릭터 그림, 배경, 표정이 바뀔 때마다 갈아 끼울 컷, UI 아이콘. 다른 하나는 들려줄 소리입니다. 배경음악이 있어야 장면 분위기가 잡히고, 선택지를 누를 때 딸깍하는 소리가 있어야 뭔가 조작하는 느낌이 납니다.

검은 화면 버전을 아이한테 한 번 보여준 적이 있습니다. 대사가 올라가고 선택지가 뜨고 분기가 나뉘는 것까지 다 되는 상태였습니다. 아이가 몇 줄 읽다가 물었습니다. "얘 얼굴은 언제 나와?" 그다음에 "노래 없어?"

그게 좀 뼈아팠습니다. 저는 그때까지 분기 설계랑 라벨 정리를 붙들고 있었는데, 정작 하는 쪽에서 제일 먼저 찾은 건 얼굴이랑 노래였습니다. 만드는 사람이 어려워하는 거랑 하는 사람이 먼저 보는 게 이렇게 다를 수 있구나 싶었습니다. 생각해보면 당연한 얘기입니다. 분기가 몇 갈래인지는 끝까지 해봐야 알지만 얼굴이 없다는 건 첫 화면에서 바로 보이니까요. 저는 안 보이는 쪽을 열심히 만들고 있었고 아이는 보이는 쪽부터 찾았습니다.

저는 개발이 제일 오래 걸릴 줄 알았는데 개발은 제일 빨리 끝났고 그림이랑 소리에서 멈췄습니다. 창작이 마지막 병목일 거라던 예측이 실제로는 빗나갔다는 얘기를 쓴 적이 있는데, 제 작업에서는 그게 좀 다르게 나타났습니다. 창작이 안 되는 게 아니라 창작 도구를 제가 쓰는 환경에 이어 붙이는 데서 멈췄습니다. 만드는 능력보다 연결이 문제였던 겁니다.

그림 쪽은 방법을 찾았습니다. Codex CLI 에 이미지 생성 도구가 있어서 Claude 가 지시를 내리고 Codex 가 실제로 그리게 했습니다. 매번 손으로 하기 싫어서 codex-image 라는 스킬로 정리해뒀습니다. Claude 가 영문 프롬프트를 만들어서 codex exec 로 넘기면, Codex 가 자기 도구로 이미지를 만들어서 정해둔 경로에 저장하고, Claude 가 그 파일을 받아서 뒤처리를 합니다. Claude 는 지시하고 판단하고 Codex 는 만듭니다.

만들면서 알게 된 게 두 가지 있었습니다. 하나는 성공했는지를 모델 말로 판단하면 안 된다는 겁니다. Codex 가 이미지를 만들어서 저장했다고 보고했는데 그 경로에 파일이 없는 경우가 있었습니다. 실행 로그에 캐시 갱신 실패 오류가 섞여 나오는데 생성은 성공하기도 하고, 반대로 보고는 깔끔한데 결과물이 없기도 했습니다. 그래서 스킬에 아예 적어뒀습니다. 성공은 Codex 말이 아니라 실제 파일이 있는지와 크기로 본다고요. 파일이 있고, 0바이트가 아니고, file 명령이 이미지 형식으로 읽어주면 성공입니다.

다른 하나는 빼달라는 걸 프롬프트에 분명히 적어야 한다는 겁니다. 히어로 이미지를 만들면 화면이나 글자가 자꾸 섞여 들어왔습니다. 아무 말 안 하면 AI 코딩 작업 환경이라는 프롬프트를 받고 모니터에 코드가 떠 있는 장면을 그립니다. 그 코드는 진짜 코드가 아니라 코드처럼 생긴 무늬고, 글자도 읽어보면 뜻이 없습니다. 글자가 들어간 이미지는 그냥 다시 만들어야 해서, 프롬프트 뒤에 글자와 로고와 화면과 UI 를 다 빼라는 문구를 늘 붙여두게 됐습니다.

시간을 제일 많이 쓴 건 사실 생성이 아니라 변환이었습니다. Codex 가 주는 건 PNG 1536×1024인데 블로그 규약은 WebP 가로 1200픽셀에 200KB 이하입니다. 변환 도구를 찾았는데 이 맥에는 cwebp 도 ffmpeg 도 magick 도 없었습니다. macOS 기본 도구인 sips 가 WebP 옵션을 받아주긴 하는데 파일을 안 만듭니다. 오류도 안 냅니다. 성공한 것처럼 끝나고 결과 파일만 없습니다.

그때 진짜 든 생각은 아니 왜 조용히 실패하지, 였습니다. 오류를 던져주면 다른 방법을 찾을 텐데 성공한 척하면 제가 뭘 잘못했는지부터 의심하게 됩니다. 결국 Pillow 로 돌아왔고 그걸로 한 번에 됐습니다. 처음부터 Pillow 를 썼으면 됐을 걸, 기본 도구로 해보겠다고 한참 돌아간 겁니다. 그래도 그 덕에 조용히 실패하는 도구가 있다는 건 확실히 기억하게 됐습니다.

Codex 가 저장했다고 해놓고 파일이 없던 것과 sips 가 성공한 척 끝난 게 저한테는 같은 종류로 느껴졌습니다. 하나는 모델이고 하나는 운영체제 기본 도구인데, 둘 다 끝났다는 말과 실제 결과가 따로 놀았습니다. 모델이라서 이상한 게 아니라 도구라는 게 원래 이런 데가 있는 것 같기도 합니다. 그러면 모델한테만 의심을 걸어둘 게 아니라, 결과를 파일로 확인하는 습관을 도구 전체에 걸어두는 게 맞겠다 싶었습니다. 다 됐다는 말은 일단 듣기만 하고, 믿는 건 파일을 보고 나서 하는 쪽이요.

해보고 나서 보니 생성은 전체 과정의 한 토막일 뿐이었습니다. 앞뒤로 붙은 게 더 많았습니다. 프롬프트를 규약대로 맞추고, 호출하고, 파일이 실제로 생겼는지 보고, 포맷이랑 해상도를 바꾸고, 용량을 넘는지 보고, 저장할 곳에 올리고, 본문에 넣을 때 화면을 못 보는 사람을 위한 설명까지 씁니다. 손이 많이 가는 건 앞이 아니라 뒤였습니다.

그림이 그렇게 정리되고 나니 소리가 남았습니다. 그래서 커넥터 목록에서 ElevenLabs 를 봤을 때 그렇게 반가웠던 겁니다. 같은 방식으로 풀 수 있는 게 하나 더 생긴 줄 알았습니다.

매뉴얼을 읽고 안 된다고 생각했는데

확인은 매뉴얼부터 했습니다. 목록에 올라간 ElevenLabs 가 무슨 도구를 내보내는지 보려고 MCP 서버 매뉴얼을 열었는데 이렇게 적혀 있었습니다.

exposes agent management tools to AI assistants

접근 범위도 ElevenAgents 읽기와 쓰기, 그리고 텍스트 음성 변환이라고 되어 있었습니다. 예로 든 것도 다 그쪽이었습니다. 최근 대화에서 주제를 뽑아 분석하기, 새 시장에 맞춰 에이전트를 복제하기, 에이전트끼리 설정 비교하기, 언어 모델 사용량이랑 비용 추정하기.

음악 생성은 없었습니다. 효과음 생성도 없었습니다. 그래서 목록에 있는 ElevenLabs 는 음성 에이전트를 운영하는 사람을 위한 관리 도구고 제 미연시에 들어갈 피아노 트랙은 여기서 안 나온다고 생각했습니다. 이름은 반가운데 내용은 아니었네 하고 글까지 쓰기 시작했습니다.

그게 틀렸습니다. 하마터면 이름만 반가운 커넥터였다는 글을 그대로 올릴 뻔했습니다.

일레븐랩스가 ElevenCreative 를 MCP 서버에 합친 게 바로 어제였습니다. 음성 합성이랑 음성 복제만이 아니라 효과음, 음악, 음성 디자인, 긴 편집, 이미지랑 비디오 생성까지 들어갔고, 클로드에서는 커넥터 디렉터리에서 몇 번 클릭하면 깔 수 있다고 되어 있었습니다. MCP 안내 페이지에도 같은 커넥터로 수십 개 모델을 쓸 수 있다고 적혀 있었습니다. 제가 읽은 매뉴얼은 에이전트 쪽 거였고 9월 초에 마지막으로 고친 거였습니다. 합치기 전 상태로 남아 있던 페이지를 지금 상태로 읽은 겁니다.

그때 든 생각은 아, 매뉴얼을 믿었네, 였습니다. 매뉴얼을 안 읽고 판단한 게 아니라 읽고 판단했는데, 그게 더 확실해 보여서 더 크게 틀렸습니다. 이름만 보고 기능을 짐작하면 위험하다고 생각해서 매뉴얼까지 봤는데 매뉴얼에도 날짜가 있었습니다. 공식이라고 해서 최신인 건 아니었습니다.

그래서 확인하는 방법을 하나 바꿨습니다. 커넥터를 붙이고 나서 실제로 무슨 도구가 들어왔는지 물어보는 겁니다. 이름이랑 설명이 그대로 나오니까 제가 쓰려는 게 그 안에 있는지 보면 됩니다.

이게 매뉴얼보다 정확한 건 프로토콜이 그렇게 생겨서입니다. 커넥터는 연결될 때 서버한테 도구 목록을 물어보고, 서버는 지금 가진 도구를 이름이랑 설명이랑 입력 형식까지 붙여서 돌려줍니다. 클라이언트 쪽에 목록이 미리 적혀 있는 게 아닙니다. 그러니까 서버에 기능이 추가되면 다음 연결에서 바로 목록이 늘어납니다. 매뉴얼은 사람이 따로 고쳐야 하고 도구 목록은 고칠 필요가 없습니다.

제가 어제 한 건 지도를 보고 길이 없다고 생각한 거였습니다. 길은 이미 나 있었고 지도가 아직 안 그려져 있었습니다. 그냥 가봤으면 3분이면 알았을 텐데 매뉴얼 읽는 게 더 꼼꼼한 확인이라고 생각했습니다. 도구가 빠르게 붙는 곳에서는 그 순서가 반대인 것 같습니다. 예전에는 문서를 먼저 읽고 써보는 게 맞는 순서라고 생각했는데, 지금처럼 하루 만에 기능이 들어오고 문서는 그다음에 따라오는 곳에서는 써보고 나서 문서를 읽는 게 덜 틀리는 것 같습니다. 써보면 지금 상태가 나오고 문서는 누가 마지막으로 고친 때의 상태가 나오니까요.

문서가 틀렸다는 걸 알게 되는 건 대개 써보다가 막혔을 때입니다. 그런데 그때 문서를 고쳐두는 사람은 별로 없는 것 같습니다. 막힌 걸 풀고 나면 다들 그냥 다음 일로 넘어가니까요. 그러면 다음 사람이 같은 문서를 읽고 같은 데서 막힙니다. 제가 이번에 읽은 매뉴얼도 누군가는 이미 지금 상태와 다르다는 걸 알았을지 모릅니다. 그 사람이 한 줄만 남겨줬으면 저는 하루를 덜 헤맸을 텐데, 저도 그 한 줄을 남기는 쪽은 아니었던 것 같아서 뭐라고 하기가 어렵습니다.

이름이랑 하는 일이 다른 경우가 많다는 건 여전한 것 같습니다. 커넥터 목록에서 음악 관련으로 올라온 걸 보면 하는 일이 다 다릅니다. Spotify 커넥터는 검색하고 추천하고 재생하는 정도였고, 같은 달 들어온 Splice 커넥터는 로열티 프리 샘플을 찾아주는 거고, Ableton 커넥터는 Live 와 Push 공식 문서를 근거로 질문에 답해주는 거였습니다. 셋 다 음악이랑 관련 있는데 셋 다 음악을 만들지는 않습니다. 거기에 어제부로 만드는 쪽이 하나 붙은 겁니다.

Suno 는 받는 횟수를 제한했고

이 소식이 더 크게 느껴진 건 3주 전에 반대 방향 일이 있었기 때문입니다. Suno 가 다운로드 정책과 이용약관을 바꿨습니다. 바뀐 건 만드는 쪽이 아니라 받는 쪽입니다. 곡을 만드는 크레딧은 그대로 두고 다운로드 횟수에 한도를 걸었습니다. 무료는 평생 7회, Pro 는 월 20회, Premier 는 월 60회이고, Premier 에서 Suno Studio 를 쓰면 제한이 없습니다. 바뀌기 전에 만들어둔 곡에도 적용되고, 안 쓴 한도는 다음 달로 안 넘어갑니다. 넘으면 추가로 살 수 있다는데 가격은 안 나와 있습니다.

Suno 쪽 사정도 아예 모르겠는 건 아닙니다. 만드는 데도 돈이 들 텐데 만든 걸 무한정 받아 가게 두면 그 곡들이 어디로 가는지 관리가 안 될 겁니다. 받는 걸 세기 시작하면 적어도 어떤 곡이 밖으로 나갔는지는 알 수 있게 됩니다. 권리를 다운로드에 붙인 것도 그런 쪽으로 읽힙니다. 다만 그건 Suno 입장이고 제 입장에서는 고르는 일이 비싸졌다는 게 먼저입니다.

상업적으로 쓸 권리가 다운로드에 붙는다는 것도 같이 바뀌었습니다. 받아둔 곡에만 권리가 따라온다는 겁니다. 계정에 만든 기록이 남아 있는 거랑 권리를 가진 게 다르다는 얘기입니다. 만들어둔 곡이 백 개여도 받은 게 스무 개면 스무 개에만 권리가 있고, 예전에 만든 걸 꺼내 쓰려고 해도 그달 한도를 써야 합니다.

제 게임에 대보면 Pro 의 월 20회인데, 미연시 한 편에 필요한 소리를 세어보면 배경음악이 타이틀, 일상, 무거워지는 장면, 고백, 엔딩 정도로 다섯에서 열 곡이고 효과음이 누르고 넘기고 열고 닫고 저장하는 것만 해도 스무 개 가까이 됩니다. 한도 안에 안 들어갑니다. 고르는 것까지 생각하면 한참 모자랍니다.

그런데 더 걸리는 건 개수보다 방식이었습니다. 에셋 작업은 한 번에 맞는 게 안 나옵니다. 열 개를 뽑아서 세 개를 쓰고 일곱 개를 버립니다. 버리는 일곱 개가 나빠서 버리는 게 아니라 옆에 놓고 들어봐야 어느 게 장면에 맞는지 알 수 있어서 버리는 겁니다. 받아보기 전에는 판단이 안 되고, 판단하려면 받아야 하고, 받으면 횟수가 줄어듭니다. 고르는 데 돈이 붙으면 안 고르게 됩니다.

안 고르게 된다는 게 생각보다 큰 차이일 것 같습니다. 고르지 않으면 처음 나온 걸 그냥 쓰게 되고, 처음 나온 걸 쓰면 다른 걸 들어봤으면 알았을 차이를 모른 채로 넘어갑니다. 장면에 조금 안 맞는 곡이 들어가도 만든 사람은 그걸 모르고, 하는 사람은 왠지 어색하다고만 느낄 겁니다. 하는 쪽은 이유를 설명하지 않고 그냥 느끼니까요. 아이가 노래 없냐고 물었을 때도 그랬습니다.

이미지 쪽 스킬을 딱 그 방식으로 짜뒀기 때문에 이게 더 눈에 들어왔습니다. codex-image 는 한 장씩 만드는 것보다 여러 장을 한꺼번에 띄우는 걸 기본으로 잡았습니다. 프롬프트를 조금씩 바꾼 걸 다섯 개까지 동시에 돌리고 나온 걸 나란히 놓고 고릅니다. 다섯 개를 넘기면 한 번에 띄우지 말고 나눠서 돌리라고 적어뒀는데, 그건 한도 때문이 아니라 한꺼번에 실패하면 원인 찾기가 어려워서입니다. 실패한 것만 새 파일명으로 다시 돌립니다. 이미 성공한 파일을 덮어쓰지 않으려고요.

이게 되는 건 버리는 데 돈이 안 들어서입니다. 다섯 개를 만들어서 하나를 쓰면 네 개는 그냥 지웁니다. 지운 만큼 다음에 만들 수 있는 개수가 줄지 않습니다. 그래서 마음 편하게 여러 개를 뽑습니다. 받는 횟수에 한도가 걸리면 이게 안 되고 스킬을 다시 짜야 합니다. 한 번에 맞히는 프롬프트를 고민하는 쪽으로 가야 하는데, 그건 에셋 작업에서 잘 안 됩니다. 맞는지 아닌지는 만들어보기 전에는 모르니까요.

한 곡을 끝까지 다듬는 데는 Suno 가 여전히 앞서 있다고 봅니다. 도구가 겨냥하는 일이 제 일이랑 다른 겁니다. 저는 완성도 높은 한 곡이 아니라 쓸 만한 여러 개가 필요합니다. Studio 를 쓰면 제한이 없다는 것도 결국 Suno 안에서 끝까지 다듬으라는 얘기로 들립니다. 밖으로 가져가서 다른 데 붙이는 사람보다 Suno 안에서 작업을 마치는 사람을 더 반기는 거죠. 저처럼 받아서 Ren'Py 에 넣어야 하는 사람은 그 반대쪽에 서 있는 겁니다.

루프는 여전히 제 몫

그럼 어제 생긴 쪽이 제 문제를 다 풀어주느냐 하면 그건 아니었습니다.

Eleven Music 은 짧게는 몇 초부터 길게는 5분까지 만들고, MP3 나 WAV 로 내보내고, 보컬을 빼는 인스트루멘털 옵션이 있고, 구간별로 소리랑 가사를 따로 고칠 수 있습니다. 루프 얘기는 공식 문서에 없었습니다.

인스트루멘털 옵션은 중요합니다. 게임 배경음악에 가사가 붙으면 대사 읽는 데 방해가 됩니다. 노래가 나오는데 밑에서 누가 말을 걸면 둘 다 안 들립니다.

문제는 루프입니다. Ren'Py 는 채널을 나눠 쓰는데 play music 은 music 채널로 가고 이 채널은 반복 재생이 기본입니다. play sound 는 sound 채널로 가고 이쪽은 반복을 안 하는 게 기본입니다. 공식 문서에 sound 채널은 "default to not looping" 이라고 적혀 있습니다. 배경음악은 계속 돌아야 하고 효과음은 한 번만 나야 하니 맞는 기본값입니다. 포맷은 넉넉하게 받아서 MP3 면 그냥 넣으면 되고, WAV 는 압축 안 한 16비트 signed PCM 만 됩니다.

그런데 Eleven Music 은 5분짜리 완결된 곡을 만듭니다. 시작이 있고 전개가 있고 끝이 있는 음악입니다. 그걸 music 채널에 넣으면 5분마다 끝에서 처음으로 돌아갑니다. 마지막 마디는 끝나는 소리로 만들어져 있고 첫 마디는 시작하는 소리로 만들어져 있으니 그 이음새에서 튑니다.

게임 배경음악을 루프용으로 따로 만드는 게 그래서입니다. 마지막 마디가 첫 마디로 자연스럽게 이어지게 만들고, 끝나는 느낌을 일부러 안 주고, 잔향이 다음 바퀴 첫 박이랑 겹쳐도 어색하지 않게 만듭니다. 작곡할 때 정해지는 거라 다 만든 곡을 잘라서 해결하기는 어렵습니다.

Ren'Py 에 마침 쓸 만한 문법이 있었습니다. 파일 이름 앞에 꺾쇠 괄호를 붙여서 재생 구간을 정할 수 있습니다.

play music "<loop 6.333>song.opus"

이러면 전곡을 한 번 틀고 두 번째 바퀴부터는 6.333초 지점에서 시작합니다. 도입부는 한 번만 들려주고 그다음엔 본 구간만 반복하는 겁니다. 게임 음악이 원래 이렇게 만들어집니다. 처음 한 번 나오는 도입부가 따로 있고 계속 도는 구간이 따로 있습니다. <from 5 to 15.5> 처럼 시작이랑 끝을 같이 정하는 것도 있어서, 5분짜리 트랙에서 이음새가 그럴듯한 30초를 찾아 거기만 돌리는 방법도 됩니다.

이걸 보고 해결됐다 싶었는데 다시 보니 그 6.333이라는 숫자가 문제였습니다. 그건 곡을 들으면서 소절이 시작되는 지점을 찾아 적은 값입니다. 파일이 있는지는 기계가 봐주지만 몇 초에서 이어야 자연스러운지는 기계가 대신 들어주지 않습니다. 결국 다시 사람 귀로 돌아옵니다. 이미지는 파일 크기랑 해상도를 숫자로 재면 끝났는데 소리는 마지막에 꼭 누가 들어봐야 합니다. 들어보는 건 자동으로 돌릴 수가 없어서, 여러 개를 뽑아서 고르는 방식이 소리에서는 이미지만큼 가볍지 않을 것 같기도 합니다. 열 곡을 뽑으면 열 곡을 다 들어야 하니까요.

그리고 소리는 됐다는 걸 확인하는 기준부터 애매합니다. 이미지는 파일이 있고 크기가 맞으면 일단 됐다고 볼 수 있었는데, 소리는 파일이 있고 길이가 맞아도 이음새에서 튀면 안 된 겁니다. 다 됐다는 보고를 받았을 때 그걸 어디까지 믿어야 하는지가 소리 쪽에서는 더 흐릿해질 것 같습니다. 파일 확인까지는 스킬에 넣을 수 있는데, 들어보고 괜찮다는 판단은 넣을 방법이 없습니다. 아마 마지막 단계는 그냥 제가 듣는 걸로 남겨둘 것 같습니다. 그걸 자동으로 만들 수 있다고 누가 말하면 저는 일단 의심부터 할 것 같고요.

효과음은 더 까다로울 것 같습니다. 선택지 누르는 소리는 0.2초 안에 딸깍 하고 끝나야 합니다. 그보다 길면 다음 대사가 올라오는 데 걸립니다. 그리고 하나만 있으면 되는 게 아닙니다. 누르는 소리, 넘기는 소리, 창이 열리는 소리, 닫히는 소리, 저장되는 소리가 다 있어야 합니다.

이게 다 같은 세계에서 나온 소리처럼 들려야 한다는 게 어렵습니다. 누를 때는 나무 두드리는 소리가 나고 창이 열릴 때는 유리 스치는 소리가 나면, 하나하나는 잘 만들었어도 같이 쓰면 이상합니다. 잔향도 맞아야 합니다. 하나는 좁은 방에서 녹음한 것처럼 건조하고 다른 하나는 강당처럼 울리면, 같은 화면에서 번갈아 나올 때 공간이 계속 바뀌는 느낌이 납니다.

사람이 만들 때도 신경 쓰는 부분이긴 한데, 사람은 같은 라이브러리에서 같은 계열을 골라서 해결합니다. 효과음 패키지를 하나 사면 그 안의 소리들이 이미 같은 환경에서 만들어져 있습니다. 생성으로 하면 매번 새로 만들어지니 계열이라는 게 없습니다. 프롬프트에 악기랑 공간감을 고정해서 넣어야 할 것 같은데 그게 얼마나 재현될지는 해봐야 알 것 같습니다. 이미지에서 같은 캐릭터 얼굴을 여러 장 뽑을 때 생기는 문제랑 비슷하지 않을까 짐작만 하고 있습니다.

Ren'Py 쪽 제약도 하나 더 있습니다. 한 채널은 한 번에 한 파일만 틉니다. 배경음악이랑 효과음은 채널이 다르니 같이 나지만, 효과음 두 개를 동시에 내려면 채널을 따로 만들어야 합니다. 선택지를 누르는 순간 딸깍 소리랑 화면 전환 소리를 겹치고 싶으면 처음부터 채널을 나눠둬야 한다는 얘기입니다. 이건 생성 도구가 풀어주는 게 아니라 제가 미리 정해야 합니다. 이런 건 만들다가 뒤늦게 알면 앞에 짜둔 걸 다 다시 봐야 해서, 소리를 뽑기 전에 먼저 정해두려고 합니다.

음량도 남습니다. 만들 때마다 결과물 크기가 조금씩 다르게 나옵니다. 배경음악이 대사를 덮으면 안 되고 효과음이 배경음악보다 크게 튀면 깜짝 놀랍니다. 이미지에서 가로 1200픽셀에 200KB 이하라는 기준을 정해두고 거기 맞춘 것처럼 소리도 기준 음량을 정해두고 다 거기로 맞춰야 할 것 같습니다. 안 하면 곡마다 볼륨을 따로 적어주는 식으로 땜질하게 되고, 곡 하나 바꿀 때마다 그 값을 또 만지게 됩니다.

이미지에서 글자가 섞여 들어왔던 거랑 같은 종류의 문제라고 봅니다. 모델은 시킨 걸 만듭니다. 그런데 만든 게 제 작업에 그대로 들어갈 수 있는 모양인지는 또 다른 얘기입니다. 이미지는 글자를 빼달라고 해야 했고 해상도랑 포맷을 규약에 맞춰 바꿔야 했습니다. 소리는 길이를 맞추고, 이음새를 맞추고, 여러 개 사이 톤을 맞추고, 음량을 맞춰야 합니다. 맞출 게 소리 쪽이 더 많아 보입니다.

라이선스

취미로 하는 동안은 안 걸리지만 미리 알아두면 좋을 것 같은 게 있었습니다. Eleven Music 으로 만든 곡은 유료 플랜에서 상업적으로 쓸 수 있고, 문서에 게임도 분명히 들어가 있습니다. 그런데 영화랑 TV, 그리고 대형 스튜디오 게임은 Enterprise 플랜이 필요하다고 되어 있습니다. 혼자 만드는 인디 게임이나 취미 프로젝트는 일반 유료 플랜으로 되지만 규모가 커지면 다시 봐야 하는 선이 있다는 겁니다.

이걸 미리 봐두는 게 나은 건 작업 순서 때문입니다. 에셋은 게임에 한 번 들어가면 빼기가 어렵습니다. 배경음악에 맞춰 장면 길이를 정하고 전환 타이밍을 잡아두면 곡을 바꾸는 순간 그 장면들을 다 다시 손봐야 합니다. 효과음 세트면 더합니다. 나중에 권리 문제로 전부 바꾸게 되는 게 제일 나쁩니다. 그래서 취미로 시작해도 어디까지 쓸 생각인지는 처음에 정해두는 게 나은 것 같습니다.

Suno 에서 상업적 권리가 다운로드에 붙게 바뀐 것도 같은 얘기 같습니다. 만들어둔 거랑 권리를 가진 게 다를 수 있습니다. 그 선이 어디인지 숫자로 적혀 있지 않아서 팀으로 상용 게임을 만들 거라면 약관을 직접 읽어봐야 할 것 같습니다. 제 경우는 아이랑 만드는 미연시라 한참 먼 얘기입니다. 그래도 AI 로 만든 음악이 유통 단계에서 어떤 벽을 만나는지 전에 한 번 본 적이 있어서 이런 건 일단 알아두려고 합니다. 만들 때는 아무 문제가 없다가 내보낼 때 걸리는 일이 이쪽에 꽤 있었습니다.

하나냐 세트냐

두 변화가 방향은 반대인데 저한테는 같은 얘기가 됐습니다. 여러 개를 뽑아보고 버리는 작업을 어디서 할 수 있느냐가 바뀐 겁니다.

둘이 겨냥하는 일이 애초에 다르다는 것도 이번에 좀 보였습니다. 전용 도구는 하나를 작품으로 만드는 쪽을 봅니다. 그러니 받아 가는 결과물에 권리를 붙이고 개수를 세는 게 그쪽 논리로는 맞습니다. 곡 하나가 결과물이고 그 결과물에 값을 매기는 겁니다. 범용 도구는 반대입니다. 한 대화 안에서 여러 도구를 번갈아 부르는 게 목적이니 부르는 한 번 한 번이 가벼워야 합니다. 결과물 하나마다 값을 매기면 그게 안 됩니다.

게임 에셋은 뒤쪽에 가깝습니다. 그림 스무 장이랑 소리 스무 개가 필요한데 하나하나가 작품일 필요는 없습니다. 오히려 스무 개가 서로 안 튀는 게 중요합니다. 캐릭터 얼굴 하나를 아주 잘 그려도 옆에 놓인 배경이랑 그림체가 다르면 못 씁니다. 작품 하나를 뽑는 도구보다 세트를 맞추는 도구가 맞고, 제가 이미지 쪽에서 스킬을 만들어 붙인 것도 그래서였습니다.

도구를 고를 때 내가 만들려는 게 작품 하나인지 세트인지를 먼저 물어보게 될 것 같습니다. 플레이리스트를 만드는 사람도 게임 에셋을 붙이는 사람도 세트 쪽이고, 곡 하나를 끝까지 다듬을 사람은 전용 도구가 맞을 겁니다. 같은 기능처럼 보여도 값을 매기는 방식이 다르면 다른 도구인 것 같습니다.

그렇다고 이제 다 된다고 하기엔 이릅니다. 만들 수 있게 된 거고, 만든 걸 게임에 넣을 수 있는 모양으로 바꾸는 일은 그대로 남아 있습니다. 이미지 때도 그랬습니다. 그림을 얻는 게 어려웠던 게 아니라 얻은 그림을 규약에 맞추는 게 오래 걸렸습니다.

소리 쪽도 아마 비슷할 겁니다. 만드는 버튼이 생긴 건 반가운데, 그 버튼을 누른 다음부터가 제 일입니다. 버튼이 생겼다는 소식은 크게 들리고, 그 뒤에 남는 일은 소식에 잘 안 나옵니다. 그래서 새 기능 소식을 보면 저는 그다음에 누가 무슨 일을 하게 되는지부터 떠올리게 되는 것 같습니다. 이번에도 커넥터를 보자마자 반가웠는데, 그다음 일을 하나씩 세어보니 반가움이 조금 줄었습니다.

달라진 건 연결할 상대가 어디 있는지는 확인할 수 있게 됐다는 겁니다. 이미지 때는 그것도 없었습니다. Codex 에 이미지 생성 도구가 있다는 것도 플래그를 조회해보고 알았고, 되는지 안 되는지 직접 불러서 확인했고, 그 결과를 스킬 문서에 날짜랑 같이 적어뒀습니다. 어디에도 정리돼 있지 않았으니까요.

이제 남은 건 만들어보는 겁니다. 미연시에 들어갈 배경음악 한 곡을 뽑아서 music 채널에 넣어보면 루프 이음새가 얼마나 튀는지 알게 될 것 같습니다. 튀면 구간 편집으로 끝부분을 고쳐보고, 소절이 시작되는 지점을 찾아서 <loop> 값으로 넣어보는 것도 같이 해볼 생각입니다. 그 숫자를 몇 번이나 고치게 될지는 감이 안 옵니다. 효과음 스무 개 톤을 맞추는 건 아직 어떻게 할지 모르겠습니다. 프롬프트에 악기랑 공간감을 고정해서 넣으면 될 것 같은데, 이미지에서 글자 빼는 문구를 찾는 데도 몇 번 걸렸으니 여기서도 몇 번은 걸릴 겁니다.

codex-image 옆에 비슷한 스킬이 하나 더 생길 것 같기는 합니다. 이름은 아직 안 정했는데 그건 만들어보고 나서 생각해도 될 것 같습니다.

댓글

이 블로그의 인기 게시물

봉제인형 사진 한 장, ChatGPT와 Gemini의 다른 대답

AI 부업으로 3개월에 2달러 벌고 50달러를 썼다는 증언을 봤습니다. 그 위에 광고가 네 겹입니다

구글은 서울에서 모델이 아니라 에이전트를 판다