·
musicdsp

Archetype: Coda #2 — 소리가 숫자가 되기까지

앰프 뚜껑을 열기 전에 더 밑바닥의 질문 하나. 기타 줄을 튕긴 떨림은 대체 어떤 과정을 거쳐 컴퓨터 안의 숫자가 되는가.

지난 편을 “이제 진짜로 앰프 뚜껑을 열어보자”로 닫았다. 그런데 막상 뚜껑에 손을 대려다 멈췄다. 그 전에 더 밑바닥의 질문 하나가 빠져 있었기 때문이다.

내 기타 소리는 대체 어떻게 컴퓨터 안으로 들어오는가?

이게 사소한 질문이 아니다. 앞으로 우리가 만들 모든 부품 — 디스토션이든 필터든 캐비닛이든 — 은 결국 컴퓨터 안의 무언가를 주무르는 코드다. 그런데 그 “무언가”가 정확히 뭔지 모르면, 코드는 영원히 공중에 뜬 채로 남는다. 그래서 이번 편은 코드도, 앰프 블록도 잠시 미뤄두고, 줄의 떨림이 숫자가 되기까지의 여정만 따라간다. 이 여정을 이해하고 나면, 그 뒤의 모든 게 “숫자 배열 주무르기”라는 한 문장으로 정리된다.

모든 건 떨림에서 시작한다

기타 줄을 튕긴다. 줄이 떨린다. 끝.

너무 당연해서 그냥 지나치기 쉬운데, 여기에 이미 핵심이 다 들어 있다. 줄은 하나의 깔끔한 주파수(frequency)로만 떨지 않는다. 줄 전체가 출렁이는 가장 낮은 진동인 fundamental, 그 절반 길이로 떠는 진동, 1/3 길이로 떠는 진동… 이런 harmonics가 동시에 겹쳐서 운다. 이 harmonics가 섞이는 비율이 바로 “기타다움”의 정체다. 똑같은 ‘라’ 음을 쳐도 기타와 피아노가 다르게 들리는 이유가 여기 있다.

이걸 식으로 쓰면 이렇게 된다. 줄의 움직임 x(t)x(t) 는 fundamental 주파수 f0f_0 의 정수배(kk)로 진동하는 사인파들이, 각자의 크기 aka_k 로 겹쳐 쌓인 합이다.

x(t)=k=1aksin(2πkf0t)x(t) = \sum_{k=1}^{\infty} a_k \sin(2\pi k f_0 t)

겁먹을 것 없다. “여러 사인파를 더하면 하나의 복잡한 소리가 된다” — 식이 말하는 건 딱 이것뿐이다. 그리고 이 덧셈을 거꾸로 풀어 “어떤 사인파가 얼마씩 섞였나”를 알아내는 게, 뒤에서 잠깐 언급할 Fourier 변환이다.

즉 줄에서 나오는 건 단순한 진동이 아니라, 여러 떨림이 겹쳐진 복잡한 출렁임 하나다. 이 출렁임의 모양을 우리는 파형(waveform) 이라 부른다. 시간에 따라 위아래로 일렁이는 곡선.

떨림이 전기가 되는 순간 — 픽업

문제는, 줄의 떨림은 공기와 쇠붙이의 물리 현상일 뿐 컴퓨터가 만질 수 있는 게 아니라는 거다. 누군가 이걸 전기 신호로 번역해줘야 한다. 그 번역기가 픽업이다.

일렉기타 픽업은 의외로 단순하다. 자석 위에 가느다란 구리선을 수천 번 감아놓은 코일. 그 위로 쇠로 된 기타 줄이 지나간다. 줄이 가만히 있으면 아무 일도 없지만, 줄이 떨리는 순간 자기장이 출렁이고, 그 출렁임이 코일에 미세한 전압을 만들어낸다. 고등학교 물리에서 배운 전자기 유도, 바로 그거다.

여기서 결정적인 사실. 이렇게 만들어진 전압의 출렁임은, 줄이 떨리는 모양을 그대로 닮아 있다. 줄이 빠르게 떨리면 전압도 빠르게 출렁이고, 줄이 크게 떨리면 전압도 크게 출렁인다. 신호의 모양이 원본을 “닮았다(analogous)“고 해서, 이걸 아날로그 신호라고 부른다. 케이블을 타고 흐르는 건 이 끊김 없이 연속적인 전압의 곡선이다. 다만 아주 약하다 — 고작 몇 밀리볼트짜리, 가늘고 깨끗한 파형.

컴퓨터는 연속을 못 읽는다

이제 이 아날로그 신호를 컴퓨터에 넣어야 한다. 그런데 여기서 근본적인 충돌이 생긴다.

아날로그 파형은 연속적이다. 1초를 아무리 잘게 쪼개도 그 사이엔 무한히 많은 순간이 있고, 매 순간 전압 값이 정해져 있다. 반면 컴퓨터는 연속을 모른다. 컴퓨터가 다룰 수 있는 건 딱 떨어지는 숫자들, 그것도 유한한 개수뿐이다. 무한히 매끄러운 곡선을, 유한한 숫자 목록으로 바꿔야 한다.

이 번역을 담당하는 칩이 ADC(Analog-to-Digital Converter) 다. 오디오 인터페이스 안에 들어 있는 그 작은 칩. ADC가 하는 일은 딱 두 가지로 쪼개진다. 샘플링양자화.

찰칵, 찰칵, 찰칵 — 샘플링

샘플링은 시간을 쪼개는 일이다.

연속적인 파형을 통째로 들고 갈 수 없으니, ADC는 아주 빠른 간격으로 파형의 높이를 사진 찍듯 떠낸다. 찰칵 — 지금 전압 0.3. 찰칵 — 0.7. 찰칵 — 0.5. 이렇게 떠낸 점 하나하나를 샘플(sample) 이라 하고, 1초에 몇 번 찍는지를 샘플링 레이트(sampling rate) 라 한다.

연속 신호 (아날로그)샘플 (디지털)
ADC는 연속적인 아날로그 파형(회색 곡선)을 일정 간격으로 떠내어 숫자의 나열(teal 점)로 바꾼다. 점과 점 사이의 정보는 버려진다 — 그래서 충분히 촘촘히 떠야 원래 파형을 복원할 수 있다.

음악에서 흔히 보는 그 숫자, 44,100Hz(44.1kHz)48,000Hz. 1초에 4만 4천 번씩 파형의 높이를 떠낸다는 뜻이다. 살벌하게 들리지만 컴퓨터한텐 가벼운 일이다.

그런데 왜 하필 4만 번대일까? 더 적게 찍으면 안 되나? 여기엔 나이퀴스트(Nyquist) 라는 칼같은 규칙이 있다. 어떤 파형을 제대로 복원하려면, 그 파형이 가진 가장 높은 주파수의 최소 2배로 떠내야 한다.

fs2fmaxf_s \geq 2 f_{max}

(fsf_s 가 샘플링 레이트, fmaxf_{max} 가 담고 싶은 가장 높은 주파수.)

사람 귀가 듣는 한계가 대략 20kHz니까, 그 2배인 40kHz보다 살짝 여유를 둔 44.1kHz면 우리가 들을 수 있는 소리는 다 담긴다. 이게 CD 음질의 그 44.1kHz가 나온 이유다.

너무 띄엄띄엄 찍으면 어떻게 될까? 에일리어싱(aliasing) 이라는 사고가 난다. 영화에서 빠르게 도는 자동차 바퀴가 거꾸로 도는 것처럼 보이는 그 현상 — 프레임을 너무 드물게 찍어서 진짜 움직임이 가짜로 둔갑하는 것. 소리에서도 똑같이, 너무 적게 샘플링하면 원래 없던 가짜 주파수가 끼어들어 신호를 망친다. 나중에 디스토션을 코딩할 때 이 에일리어싱이 다시 골칫거리로 돌아온다. 일단 이름만 기억해두자.

눈금을 얼마나 잘게 — 양자화

샘플링이 시간을 쪼갰다면, 양자화(quantization) 는 높이를 쪼갠다.

찰칵 찍은 그 순간의 전압 값이 0.3173628…처럼 무한히 정밀할 수 있는데, 컴퓨터는 이걸 유한한 눈금에 반올림해 적어야 한다. 자를 떠올리면 된다. 눈금이 촘촘한 자일수록 더 정밀하게 길이를 잴 수 있는 것처럼, 눈금이 촘촘할수록 소리를 더 정밀하게 기록한다. 이 눈금의 개수를 정하는 게 비트 뎁스(bit depth) 다.

  • 16비트 — 65,536단계. CD가 쓰는 해상도.
  • 24비트 — 약 1,670만 단계. 녹음 작업에서 흔히 쓰는 해상도.

눈금이 촘촘할수록 가장 작은 소리와 가장 큰 소리 사이의 폭, 즉 다이내믹 레인지를 더 넓고 곱게 담을 수 있다. 반대로 눈금이 성기면 그 사이를 반올림하면서 미세한 오차가 끼는데, 이걸 양자화 노이즈라 부른다. 자를 너무 굵은 눈금으로 재면 생기는 그 어쩔 수 없는 오차다.

그래서, 소리는 결국 숫자의 긴 줄이다

샘플링으로 시간을 쪼개고, 양자화로 높이를 적었다. 그 결과물은?

그냥 숫자가 줄줄이 늘어선 배열 하나다. 1초에 48,000개씩, 보통 -1.0에서 +1.0 사이의 값으로 정규화된 숫자들. 우리가 화면에서 보는 그 매끈한 파형은, 사실 이 숫자들을 점으로 찍어 이은 그림일 뿐이다.

[0.00, 0.21, 0.39, 0.52, 0.55, 0.48, 0.31, 0.08, -0.18, ...]

이게 이번 연재 전체를 떠받치는 한 줄이다. 컴퓨터 안에서 소리는 숫자 배열이다. 그리고 앞으로 우리가 만들 모든 부품은 결국 —

이 숫자 배열을 입력으로 받아서, 어떤 규칙으로 주물러서, 새로운 숫자 배열을 뱉어내는 함수다.

게이트는 작은 숫자들을 0으로 눌러버리는 함수. 디스토션은 큰 숫자의 끝을 곡선으로 깎아내는 함수. 필터는 특정 패턴의 출렁임만 키우거나 줄이는 함수. 전부 다 숫자 배열 in, 숫자 배열 out. 이게 DSP(Digital Signal Processing) — 숫자가 된 신호를 처리하는 일의 전부다. 거창한 이름 뒤에 숨은 실체는 의외로 이렇게 담백하다.

그리고 우리가 모든 처리를 끝내고 나면, 반대편 끝에서 DAC(Digital-to-Analog Converter) 가 이 숫자 배열을 다시 연속적인 전압으로 되돌려 스피커를 울린다. 들어올 때 ADC, 나갈 때 DAC. 그 사이의 모든 일이 우리가 짤 코드다.

잠깐, 겹친 harmonics는 어떻게 풀까

여기서 한 가지 미끼만 던져두고 넘어가자. 글 첫머리에서 줄은 fundamental과 여러 harmonics가 동시에 겹쳐서 운다고 했다. 그렇게 겹친 결과가 지금 우리 손에 든 이 숫자 배열이다. 그런데 — 거꾸로, 이 한 줄짜리 배열을 보고 “어떤 주파수들이 얼마씩 섞여 있는지” 를 도로 풀어낼 수 있을까?

놀랍게도 된다. 시간 축으로 출렁이는 숫자 배열을, “각 주파수가 얼마나 들어 있나”라는 주파수 축의 그림으로 바꾸는 변환이 있다. 그 그림을 스펙트럼(spectrum), 그걸 만들어내는 연산을 푸리에 변환(Fourier Transform) 이라 부른다. 디지털 신호 처리의 절반은 이 “시간 ↔ 주파수” 두 세계를 오가는 일이라고 해도 과언이 아니다. 뒤에 나올 톤 스택(필터)이나 캐비닛(컨볼루션)도 결국 이 주파수 세계의 언어로 이해할 때 가장 깨끗하게 풀린다.

다만 이 연재에서는 그 수학적 바닥까지 파고들지는 않을 생각이다. Coda의 약속은 “일단 동작하는 앰프를 만든다” 니까, 필터든 컨볼루션이든 일단 도구로 갖다 쓰고 소리를 낸다. 푸리에 변환이 왜 그렇게 작동하는지, 컨볼루션 정리가 무슨 마법인지, 필터를 떠받치는 LTI 시스템이 뭔지 — 그 진짜 바닥은 따로 떼어 별도의 DSP 스터디 연재에서 차근차근 다루려 한다. 고전 DSP부터 요즘의 DDSP까지, 디지털로 신호를 주무르는 이야기 전반을 Think DSP 같은 교재를 출발점 삼아 정리해갈 생각이다. 그러니 이 글에서 스펙트럼·푸리에 같은 단어가 스쳐 지나가더라도, “아 저건 저쪽 연재에서 제대로 판다” 정도로만 기억해두면 된다.

다음 편

이제 우리는 손에 숫자 배열을 쥐고 있다. 그리고 그 배열을 주무르는 게 DSP라는 것도 안다.

다음 편은 드디어 앰프 뚜껑을 연다. 이 숫자 배열이 우리가 아는 그 일렉기타 소리가 되기까지, 안에서 어떤 부품들을 어떤 순서로 통과하는지 — 신호 체인 전체를 한 블록씩 해부한다. 코드는 그 지도를 다 그린 다음, 그다음 편부터다.

댓글