제보는 짧았습니다. "소리가 나다 말다 해."

순서대로 돌려쓰고 있었습니다

동시에 소리를 낼 수 있는 자리가 정해져 있고, 새 소리가 나면 그 자리를 하나 씁니다. 이걸 순서대로 돌려쓰고 있었습니다. 1번, 2번, 3번… 끝나면 다시 1번.

문제는 옆자리가 비어 있어도 순서가 된 자리를 뺏는다는 것이었습니다. 그 자리에서 아직 총성이 울리고 있어도 그냥 덮어씁니다. 조용한 자리가 열 개 남아 있는데도요.

숫자를 세어 보니 모자랐습니다

여덟 명이 붙으면 분당 600발짜리 총성과 발소리가 겹쳐서 초당 100개 가까이 납니다. 소리 지속 시간을 0.3초로 가정하면 초당 100개 × 0.3초 = 평균 30개 정도의 동시 재생 수요를 예상할 수 있습니다. 순간 최대치는 별도 측정이 필요하며, 모든 소리가 같은 길이라는 뜻은 아닙니다.

자리는 20개였습니다.

0.2초면 한 바퀴를 다 돌고 다시 1번으로 돌아옵니다. 그때부터는 계속 남의 소리를 자르는 겁니다. 이는 초당 100개라는 가정에서의 계산이며, 실제 끊김 주기를 측정한 값은 아닙니다.

두 가지를 고쳤습니다

자리를 20개에서 32개로 늘렸습니다. 예상한 평균 수요보다 조금 큰 값이며 모든 교전에서 충분하다는 보장은 아닙니다.

노는 자리부터 씁니다. 전부 울리는 중일 때만 순환 커서가 가리키는 자리를 교체합니다.

2026-09-15 정정: 로컬 구현의 _take_3d()를 다시 확인했습니다. 재생 시작 시각을 비교하지 않으므로 이전 글의 “가장 오래 울린 자리”라는 설명은 보장되지 않습니다. 빈 슬롯을 건너뛰며 재사용하면 커서 순서와 재생 시작 순서가 달라질 수 있습니다. 정말 가장 오래된 소리를 고르려면 슬롯마다 시작 시각을 별도로 기록해야 합니다.

안 끊긴 것만 보면 알 수 없습니다

당시 기록에 남은 검사 출력입니다. 이번에는 이 20초 실행의 원본 로그를 재확보하지 못했으므로 현재 버전의 재측정 결과로 보지 마세요. 검사에는 숫자를 두 개 같이 찍게 했습니다. 실제로 끊은 횟수와, 예전 방식이었다면 끊겼을 횟수입니다.

[smoke] 소리: 3D 목소리 32개 · 실제로 끊은 횟수 0 · 예전 방식이면 끊겼을 횟수 6

앞 숫자만 보면 "0이니까 됐다"로 끝납니다. 그런데 그 0은 고쳐서 0인지, 원래 안 끊기는 상황이라 0인지 구분이 안 됩니다. 뒤 숫자가 있어야 이 검사가 실제로 무언가를 잡고 있다는 걸 알 수 있습니다.

이 6을 실전의 하한이라고 단정할 수는 없습니다. 입력과 동시 재생 패턴이 다른 교전에서는 결과가 달라집니다. 재검사할 때는 재생 요청 수, 강제 교체 수, 실제 청취 결과를 따로 기록해야 합니다.

이어서 읽을 것

소리가 나다 말다 하는 문제는 소리 자체보다 자리 관리 쪽인 경우가 많습니다. 같은 프로젝트에서 배포본에서만 부서지던 것들은 소스에서는 멀쩡하고 배포본에서만 부서지는 것 세 가지에 모아 두었습니다.