Write · 쓰면 들려요
kick x x x x 처럼 한 줄이 한 트랙이에요. 리듬과 음은 다음 마디 경계에서, 소리는 즉시 바뀌어 박을 놓치지 않아요. 숫자 위에서 Alt+↑↓를 누르면 연주 중에 값을 굴려요.
hat [. x]*4 | gain .45 every 8 ply 2 bass [. 0 0 0]*4 | cut k1(300,2000) pad 0^7 | drop2 verb .6
Tactus는 브라우저에서 바로 여는 라이브 코딩 악기예요. 한 줄이 한 트랙이고, 고치면 다음 마디에 바로 들려요. 코드가 낯설면 블록을 눌러 만들고, 신스 소리를 손으로 빚고, 기타나 마이크를 꽂아 이펙터로 쓰고, 카메라 앞에서 손으로 지휘해요. 설치할 것 없이 폰에서도 열려요. 데모를 틀면 위의 글자 여섯 개가 각자 한 트랙씩 맡아 박자에 맞춰 숨을 쉬어요.
kick x x x x 처럼 한 줄이 한 트랙이에요. 리듬과 음은 다음 마디 경계에서, 소리는 즉시 바뀌어 박을 놓치지 않아요. 숫자 위에서 Alt+↑↓를 누르면 연주 중에 값을 굴려요.
hat [. x]*4 | gain .45 every 8 ply 2 bass [. 0 0 0]*4 | cut k1(300,2000) pad 0^7 | drop2 verb .6
빌드업, 비트 리피트, 게이트, 에코 아웃 같은 DJ 동작 16개가 키보드에 붙어 있어요. 여기서도 눌러 보세요: 누르고 있는 동안 위의 데모 곡에 바로 걸리고, 그 패드를 만든 한 줄이 보여요. 고치거나 새로 쓰면 그대로 패드가 돼요.
스타일과 시드를 고르면 코드 진행, 비트, 베이스, 멜로디까지 코드로 써 줘요. 주사위를 굴려 보세요. 아래 줄은 이 페이지가 지금 실제로 만든 결과예요.
오른손으로 박을 저으면 템포와 셈여림이 따라오고, 왼손으로 가리키면 그 악기가 들어오거나 빠져요. 두 주먹은 페르마타. Chrome에서 Tactus를 열고 손 컨트롤을 켠 뒤 카메라를 허용하면 돼요.
같은 곡이 카드로도 보여요. 드럼은 칸을 누르고, 멜로디는 곡의 음계로 된 피아노 롤에 그려요. 코드 진행, 장면, 곡 순서까지 블록으로 바꾸고, 바꾼 것은 그대로 코드에 써져요. 폰에서는 트랙이 한 줄씩 접혀 작은 스텝 시퀀서처럼 보여요.
kick x . . . x . . . lead [0 _ 2 _ 4 _ _ 2] prog <0 5 3 4>
아날로그, 웨이브테이블, FM 신스가 함께 들어 있어요. 유니즌, 필터 여섯 가지, 모음 필터, 엔벨로프와 곡 박자에 맞춘 LFO까지 한 줄로 써요. 엔벨로프와 필터 곡선은 끌어서 바꾸고, 한 음을 들려주면 가장 비슷한 소리를 찾아 줘요.
bass | analog voices 5 lead | wt table growl keys | fmsynth ratio 3.5
마이크나 오디오 인터페이스에 꽂은 기타를 실시간으로 처리해요. 게이트, 컴프, 앰프와 캐비닛, 와우, 코러스, 플랜저, 페이저, 트레몰로, 딜레이, 리버브, 옥타버, 곡의 키를 따라가는 하모나이저, 튜너. 미리 보는 처리가 없어 지연을 더하지 않고, 딜레이와 트레몰로는 곡의 박자에 맞아요.
input | drive .45 amp crunch delay .3 3/16 pingpong harm 2 .5 verb .3
“둠 츠 칙 츠” 비트박스는 kick, snare, hat 줄이 되고, 흥얼거린 멜로디는 곡의 키에 맞춘 음표가 돼요. 루프 스테이션은 마디에 맞춰 녹음하고, 왕복 지연은 스스로 재서 맞춰요.
kick x . . . x . x . snare . . x . . . x . hum a4 _ c5 . e5 _ d5 .
악기에서 가장 중요한 건 박이에요. Tactus는 120ms 앞을 내다보며 음을 예약하고, 소리를 만드는 보이스와 라이브 이펙터는 할당이 전혀 없는 no_std Rust로 써서 WebAssembly로 AudioWorklet 안에서 돌려요. 오디오 스레드에서 가비지 컬렉션이 일어나지 않아요.
WebAssembly를 쓸 수 없는 곳에서는 같은 계산을 하는 JavaScript가 대신 돌아요. 두 쪽은 샘플 단위로 맞춰 두었고, 신스 엔진과 이펙터는 출력이 똑같아요.
현 16음, 애시드 라인, 모노 베이스, 신스 엔진 화음을 함께 30초 렌더링하면 Rust가 JavaScript보다 약 1.85배 빨라요. 모든 이펙터를 동시에 켠 라이브 체인은 실시간의 약 15배 속도로 돌아요.
오디오 스레드(AudioWorklet)에서는 WebGPU를 쓸 수 없어요. 그래서 Tactus는 GPU에게 음표를 통째로 미리 렌더링시키고, 스케줄러가 정확한 시간에 틀어요. 실시간 입력을 블록마다 처리하는 일엔 맞지 않지만, 미리 준비할 수 있는 무거운 소리와 그림에는 잘 맞아요. GPU가 없는 브라우저에서는 모두 CPU 소리와 기존 시각화로 대신해요.
swarm은 음표 하나에 사인파 최대 4,000개(40개 목소리마다 14kHz까지 배음), choir는 포먼트를 입힌 1,000개 남짓, plate는 금속판의 고유 진동 수백~1,500개를 각자 다른 감쇠로 더해요. JavaScript로는 음표 하나에 수십 초가 걸리는 양이라 실시간으로는 불가능했어요.
P를 누르면 지금 믹스의 FFT에서 가장 센 2,048개 성분을 뽑아 무작위 위상의 사인파로 다시 합성해, 끝없이 이어지는 화음으로 붙잡아요. 드럼은 그대로 흘러가요.
최근 5초의 스펙트럼을 GPU 텍스처에 쌓아 두고 매 프레임 그려요. terrain은 그 스펙트럼을 겹겹의 산 능선으로, contour는 등고선 지도로, dots는 LED 격자로 보여 주고, demo는 90년대 데모신처럼 터널과 사인 스크롤러를 띄워요. 트랙이 칠 때마다 그 코드 줄에서 물결이 퍼져요. 위 데모 화면 아래에서 바꿔 볼 수 있어요.
space cathedral공간을 공진 모드의 합으로 만들어요. 낮은 쪽은 방 크기로 계산한 실제 모드라서 작은 방은 진짜 작은 방처럼 웅웅거리고, 위쪽은 이웃 모드가 겹칠 만큼 촘촘하게 놓아요. 성당은 모드 약 4만 9천 개를 7초 넘게 더해야 해서 JavaScript로는 15분쯤, GPU로는 순식간이에요.
timp 0 . 4 . | membrane북 가죽을 96×96 격자에서 파동 방정식으로 한 샘플씩 풀어요. GPU 워크그룹 하나가 북 하나를 맡아 네 가지 세기를 동시에 치고, 세게 칠수록 가죽이 순간 팽팽해져 음이 살짝 높게 시작해요. 같은 계산을 JavaScript로 하면 음 하나에 10초 넘게 걸려요.
sax ... | nsax키트의 색소폰 녹음 20개로 작은 신경망을 직접 학습시켰어요. 주파수·음높이·세기·시간을 넣으면 그 성분의 크기를 알려 줘서, 녹음에 없는 음도 자연스럽게 만들어요. 학습에서 뺀 음으로 재 보면 배음 오차가 9.5 dB로, 가장 가까운 녹음을 옮겨 쓰는 방식(13~20 dB)보다 정확해요. 추론과 합성 모두 GPU에서 돌아요.
shader glow sin(length(q)*20.-t*4.)*bassviz 줄이 마디에 맞춰 배경을 바꾸고, shader 줄에 쓴 WGSL 식이 그대로 배경이 돼요. bass·kick·스펙트럼·트랙 타격을 변수로 쓸 수 있고, 식을 고치면 바로 다시 컴파일해 오류는 그 줄에 표시해요.
viz sono곡이 흐르는 동안 마디 위치마다 스펙트럼을 GPU 텍스처에 쌓아, 곡 전체를 한 장의 지도로 보여 줘요. 파트 경계와 지금 위치가 함께 그려져서 어디가 비고 어디가 꽉 찼는지 한눈에 보여요.
loop1 | drums 0 rest 1스펙트로그램에서 드럼은 세로줄, 음은 가로줄이에요. 그 차이로 루프를 드럼과 나머지로 나누고(둘을 합치면 원래 루프), 드럼은 kick·snare·hat 줄로 써 줘요. 백그라운드 스레드에서 돌아요. Demucs 같은 신경망 모델은 다음 단계예요.
참고: CPU, GPU, FPGA for modal reverberation (Frontiers, 2025) · Audio Modeling × GPU Audio · Efficient Modal Sound Synthesis on GPUs (RWTH, 2014) · DDSP (Engel et al., 2020) · Demucs
르네상스 음악에서 tactus는 지휘자가 손을 내렸다 올리며 짚던 박을 부르던 말이에요. 악보의 모든 음표가 그 손짓에 맞춰 흘렀어요.
이 악기도 같은 생각에서 시작했어요. 코드를 고치는 손, 패드를 누르는 손, 카메라 앞에서 움직이는 손이 모두 박을 짚어요. 기계가 박을 지키고, 사람은 느낌을 바꿔요.