우선 결과물부터.
오디오 전체의 파형 데이터를 가져온 뒤 현재 감지되는 소리의 주파수를 이용해서 움직이게 만들었습니다.
(무료 플러그인들을 주워담다가 이렇게 움직이는 플레이어를 봤는데 너무 이쁘더군요. 그래서 비슷하게 만들어봤습니다.)
1. 오디오 데이터
먼저 사운드를 다룰려면 어떤 식으로 이루어져 있는지 확인해야겠죠. 제 전공은 아니기에 깊이있는 내용을 다루진 않을 겁니다.
오디오 데이터는 수백수만 개의 여러 샘플로 구성되어 있습니다.
샘플링된 데이터가 연속적으로 붙어있는 형태죠. (44,100hz 또는 48,000hz 단어를 보셨을 겁니다. 이게 초당 44100번 또는 48000번의 샘플링이 이루어졌다는 의미입니다.)
여기서 중요한 것이 이 샘플에는 어떠한 데이터가 들어있냐는 것입니다.
바로 특정 시점에서의 오디오 파형입니다. 이 파형은 여러 정현파들의 합으로 이루어져 있죠.
(정현파의 주파수는 음의 높이를, 진폭은 음의 세기를 담당합니다.)
이게 무슨 뜻인가..?
소리에는 낮은 음역대, 중간 음역대, 높은 음역대 별로 다양한 음이 포함되어 있습니다.
즉, 가지각색의 다양한 정현파들이 존재한다는 의미입니다.
낮은 주파수에 높은 진폭을 가진 음이라던가, 높은 주파수에 낮은 진폭을 가지는 음이라던가... 말이죠.
이 음들이 모두 합쳐져서 소리가 만들어집니다.
2. 데이터 처리
이제 이 정현파들을 분리시켜서 각 주파수 별로 진폭 값을 알아내야 합니다.
하나로 만들어져 있는 곡선을 여러 개의 정현파들로 분리시키는 과정이 필요합니다.
여기서 푸리에 변환(Fourier Transform)이란 것을 이용합니다. 정현파의 진폭 또는 위상을 구할 수 있죠.
(더 상세히 이야기하자면 복잡한 모양의 주기 함수를 푸리에 급수로 분해시키고, 여러 sin, cos들을 뽑아내는 과정입니다.)
다행히도 Web API에 AnalyserNode 인터페이스를 제공해주는데 여기서 '고속 푸리에 변환' 기능을 제공해줍니다. fft 사이즈만 잘 조절하면 쉽게 계산할 수 있습니다.
// AudioContext 생성
// 모든 Web Audio API 작업의 기반이 됨
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// AudioContext를 사용하여 AnalyserNode 인스턴스를 생성
// 그리고 FFT 사이즈 설정
var analyser = audioCtx.createAnalyser();
analyser.fftSize = 2048;
// 데이터 배열 생성 - 푸리에 변환을 거친 결과 값을 저장하기 위함
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
// audio 태그로부터 소스를 생성
var source = audioCtx.createMediaElementSource(audio);
// 분석될 소스에 연결
source.connect(analyser);
// 마지막으로 데이터 수집
// getByteFrequencyData 메소드도 있음!
analyser.getByteTimeDomainData(dataArray);
이런 과정을 거치고 나면 파형의 데이터나 주파수 영역 데이터를 얻어올 수 있습니다.
3. 주파수 스펙트럼
계산된 데이터를 이쁘게 보여주려면 또 보기 편하게 조정해야겠죠.
주파수 영역 데이터를 선형 그래프로 보여주면 저음역대가 아주 좁게 나오는 것을 볼 수 있습니다.
하지만 로그 스케일로 표현한다면 낮은 주파수 성분을 더 넓고 세밀하게 표현시킬 수 있습니다.
로그 스케일로 축을 계산하는 방법입니다.
logspace(start, stop, n, max){
return start * Math.pow(stop/start, n/(max-1));
}
>>> logspace(20, 20000, 0, 1000)
20.0
>>> logspace(20, 20000, 100, 1000)
39.93284900219588
>>> logspace(20, 20000, 999, 1000)
20000.0
이렇게 보정된 데이터로 자신의 입맛대로 이쁘게 오디오 트랙을 그려주면 완성입니다 :)