웹 오디오 프로그래밍

[Web Audio API #7] 음량 조절

영바이트 2021. 7. 4. 11:00

음원 신호를 재생할 때 기본적으로 따라오는 기능 중 하나가 음량 조절이다. 음원에 적용되는 다양한 효과와 기능들을 개발자 관점에서 어떻게 다룰 수 있는지 가장 기본이 되는 음량조절 기능을 예로 다루면서 살펴보자.

 

웹 오디오 표준에서 신호의 음량을 다루기 위해 사용하는 기본적인 노드는 gain node와 dynamic compressor node가 있다. 이 중 gain node는 쉽게 볼륨을 조절하는 기능을 제공하는 오디오 노드이다. dynamic compressor 노드는 음향 신호의 가장 시끄러운 구간의 신호를 일정 크기보다 작게 만들어 주는 기능(dynamic range compression이라고 부른다)을 제공한다.

너무 큰 크기의 소리는 스피커가 정상적으로 재생할 수 없다. 큰 크기의 신호를 스피커가 정상적으로 재생할 수 없는 현상을 clipping이라고 하는데 dynamic compression을 사용하면 크기가 일정 수준 이상인 신호를 줄여주어 clipping이 일어나지 않도록 해 준다.

 

웹 오디오 표준에서 gain 노드와 dynamic compressor 노드는 아래와 같이 생성하고 서로 연결되어 오디오 그래프로 만들어진다.

//	오디오 노드 생성
var source = audioContext.createBufferSource();
var compressor = audioContext.createDynamicsCompressor();
var gainNode = audioContext.createGain();

//	오디오 그래프 구성
source.connect(compressor);
compressor.connect(gainNode);
gainNode.connect(audioContext.destination);

 

위 코드는 아래와 같은 오디오 그래프를 생성한다.

 

Dynamic compressor 노드는 오디오 그래프에 포함되면 언제나 활성화되어 항상 기능이 적용된다. Gain 노드는 아래와 같이 gain 값을 설정해 줄 수 있다.

gainNode.gain.setValueAtTime(gainControl.value, audioContext.currentTime);

 

기본적으로 아래와 같이 코드를 구성하면 위 그림과 같은 오디오 그래프를 구성하고 동작시킬 수 있다.

//	오디오 노드 생성
var source = audioContext.createBufferSource();
source.buffer = audioBuffer;
source.loop = true;

var gainNode = audioContext.createGain();
var compressor = audioContext.createDynamicsCompressor();

//	오디오 그래프 구성
source.connect(compressor);
compressor.connect(gainNode);
gainNode.connect(audioContext.destination);

//	볼륨(gain) 조정 - 설정은 재생 이후에도 가능하다
gainNode.gain.setValueAtTime(2.0, audioContext.currentTime);    //  2.0 = X2

//	재생 시작
source.start(0);

 

서버로 부터 오디오 데이터를 다운로드하는 부분은 fetch API, XMLHttpRequest 등을 사용하여 AJAX 형태로 구성할 수 있다. 이 부분은 이전 블로그들에서 몇 번 예제로 다루었기 때문에 생략하였다.

 


 

Dynamic compressor 노드는 주로 기본 값을 사용하지만 노드를 생성할 때 아래와 같이 값을 설정해 줄 수 있다.

 

· attack: 음향 신호의 크기가 커져 압축의 대상이 되었을 때 attack 인자에 지정한 시간 동안 압축비를 천천히 증가시킨다. 단위는 초(second)이고 기본 값은 0.003초이다.
· knee: threshold 에서 신호를 급격하게 압축할 지(hard knee) 완만하게 압축할 지(soft knee) 결정한다. 기본 값은 30으로 설정되어 있다.
· ratio: 음향 신호의 가장 시끄러운 지점과 가장 조용한 지점의 크기 차이를 얼마나 감소시킬지 설정한다. 기본 값은 12이고 12:1 압축비를 의미한다. 입력 신호의 가장 큰 지점과 가장 조용한 지점의 차이가 12dB 였다면 이를 압축하여 그 차이를 1dB로 줄여준다. 12dB 기본 설정에서 그 단위가 dB이기 때문에 실제 음향 신호의 크기(amplitude) 차이로 보면 2배 보다 작다.
· release: attack의 반대 개념이다. 음향 신호의 크기가 작아져 압축의 대상이 아닐 때 이 release 인자에 지정한 시간 동안 압축비를 천천히 감소시킨다. 단위는 초(second)다. 기본 값으로 0.25초가 설정되어 있다.
· threshold: 이 값보다 큰 음향 신호는 압축의 대상이 된다. 기본으로 설정되어 있는 값은 -24dB이다.

 

아래 그림들을 보면 위 내용들을 이해하는데 도움이 될 것이다.

knee
ratio
threshold, attack, release

※ 그림 출처: https://www.uaudio.com/blog/audio-compression-basics/

 

값을 설정할 때는 audioContext의 createDynamicsCompressor() 메서드를 사용하는 대신 DynamicsCompressorNode 객체를 직접 생성한다. 예를 들면 아래와 같다.

//	new DynamicsCompressorNode(오디오 컨텍스트, [설정 값들])
var compressor = new DynamicsCompressorNode(audioContext, [0.003, 30, 12, 0.25, -24]);

 

이번 글의 내용을 좀 더 잘 이해하기 위해서, 더 나아가 웹 오디오를 다루기 위해서 오디오 신호에 대한 약간의 배경지식이 있으면 좋다. 다음 블로그에서는 오디오 신호를 이해하기 위한 배경이 되는 정보들을 잠시 살펴볼까 한다.