Web Audio API: 코딩할 수 있는데 왜 작곡을 합니까?

게시 됨: 2022-03-11

웹 오디오 API의 첫 번째 초안은 2011년 W3C에 나타났습니다. 웹 페이지의 오디오는 오랫동안 지원되었지만 웹 브라우저에서 오디오를 생성하는 적절한 방법은 최근까지 사용할 수 없었습니다. 저는 개인적으로 이것을 구글 크롬 덕분이라고 생각합니다. 구글의 관심사에 관해서는 브라우저가 컴퓨터의 가장 중요한 부분이 되기 시작했기 때문입니다. 웹 브라우저의 영역은 Google 크롬이 나타날 때까지 크게 바뀌지 않았다는 것을 기억할 것입니다. 이때 웹페이지에서 사운드를 사용했다면 잘못된 디자인 결정이 되었을 것입니다. 그러나 웹 실험이라는 아이디어가 나온 이후로 웹 오디오가 다시 이해되기 시작했습니다. 오늘날 웹 브라우저는 예술적 표현을 위한 또 다른 도구이며 웹 브라우저의 비디오 및 오디오는 중요한 역할을 합니다.

Web Audio API: 코딩할 수 있는데 왜 작곡을 합니까?

Web Audio API: 코딩할 수 있는데 왜 작곡을 합니까?
트위터

Web Audio API는 아직 개발 중이기 때문에 어떤 목적에서는 사용하기가 상당히 어려울 수 있지만 작업을 더 쉽게 하기 위해 많은 JavaScript 라이브러리가 이미 존재합니다. 이 경우 Tone.js라는 라이브러리를 사용하여 Web Audio API를 시작하는 방법을 보여 드리겠습니다. 이를 통해 기본 사항만 배우면 대부분의 브라우저 사운드 요구 사항을 충족할 수 있습니다.

안녕하세요 웹 오디오 API

시작하기

라이브러리를 사용하지 않고 시작합니다. 첫 번째 실험은 3개의 사인파를 만드는 것입니다. 이것은 간단한 예이므로 소량의 마크업이 있는 베어 HTML 파일인 hello.html이라는 파일 하나만 생성합니다.

 <!DOCTYPE html> <html> <head> <meta charset="utf‐8"> <title> Hello web audio </title> </head> <body> </body> <script> </script> </html>

Web Audio API의 핵심은 오디오 컨텍스트입니다. 오디오 컨텍스트는 웹 오디오와 관련된 모든 것을 포함하는 객체입니다. 단일 프로젝트에 둘 이상의 오디오 컨텍스트를 갖는 것은 좋은 습관으로 간주되지 않습니다. Mozilla의 Web Audio API 문서에서 제공하는 권장 사항에 따라 오디오 컨텍스트를 인스턴스화하는 것으로 시작하겠습니다.

 var audioCtx = new (window.AudioContext || window.webkitAudioContext);

오실레이터 만들기

오디오 컨텍스트가 인스턴스화되면 이미 오디오 구성 요소인 audioCtx.destination이 있습니다. 이것은 당신의 스피커와 같습니다. 소리를 내려면 audioCtx.destination에 연결해야 합니다. 이제 사운드를 생성하기 위해 오실레이터를 생성해 보겠습니다.

 var sine = audioCtx.createOscillator();

훌륭하지만 충분하지 않습니다. 또한 audioCtx.destination을 시작하고 연결해야 합니다.

 sine.start(); sine.connect(audioCtx.destination);

이 네 줄을 사용하면 사인 사운드를 재생하는 꽤 성가신 웹 페이지를 갖게 되지만 이제 모듈이 서로 연결할 수 있는 방법을 이해하게 됩니다. 다음 스크립트에는 출력에 연결된 3개의 사인 모양 톤이 있으며 각각 다른 톤이 있습니다. 코드는 매우 자명합니다.

 //create the context for the web audio var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); //create, tune, start and connect each oscillator sinea, sineb and sinec var sinea = audioCtx.createOscillator(); sinea.frequency.value = 440; sinea.type = "sine"; sinea.start(); sinea.connect(audioCtx.destination); var sineb = audioCtx.createOscillator(); sineb.frequency.value = 523.25; sineb.type = "sine"; sineb.start(); sineb.connect(audioCtx.destination); var sinec = audioCtx.createOscillator(); sinec.frequency.value = 698.46; sinec.type = "sine"; sinec.start(); sinec.connect(audioCtx.destination);

오실레이터는 사인파에 국한되지 않고 MDN에 명시된 바와 같이 삼각형, 톱니, 정사각형 및 사용자 정의 모양도 될 수 있습니다.

웹 오디오의 패치 로직

다음으로 Web Audio 구성 요소의 오케스트라에 게인 모듈을 추가합니다. 이 모듈을 사용하면 소리의 진폭을 변경할 수 있습니다. 볼륨 노브와 유사합니다. 우리는 이미 연결 기능을 사용하여 오실레이터를 오디오 출력에 연결했습니다. 동일한 연결 기능을 사용하여 모든 오디오 구성 요소를 연결할 수 있습니다. Firefox를 사용 중이고 웹 오디오 콘솔을 보면 다음이 표시됩니다.

볼륨을 변경하려면 패치가 다음과 같아야 합니다.

이는 오실레이터가 더 이상 오디오 대상에 연결되지 않고 대신 게인 모듈에 연결되고 해당 게인 모듈이 대상에 연결된다는 것을 의미합니다. 기타 페달과 케이블로 이 작업을 수행한다고 항상 상상하는 것이 좋습니다. 코드는 다음과 같습니다.

 var audioCtx = new (window.AudioContext || window.webkitAudioContext) // we create the gain module, named as volume, and connect it to our var volume = audioCtx.createGain(); volume.connect(audioCtx.destination); //these sines are the same, exept for the last connect statement. //Now they are connected to the volume gain module and not to the au var sinea = audioCtx.createOscillator(); sinea.frequency.value = 440; sinea.type = "sine"; sinea.start(); sinea.connect(volume); var sineb = audioCtx.createOscillator(); sineb.frequency.value = 523.25; sineb.type = "sine"; sineb.start(); sineb.connect(volume); var sinec = audioCtx.createOscillator(); sinec.frequency.value = 698.46; sinec.type = "sine"; sinec.start(); sinec.connect(volume); volume.gain.value=0.2;

https://github.com/autotel/simple-webaudioapi/에서 솔루션을 찾을 수 있습니다.

GainNode는 가장 기본적인 효과 단위이지만 지연, convolver, biquadratic 필터, 스테레오 패너, 웨이브 셰이퍼 등이 있습니다. Tone.js와 같은 라이브러리에서 새로운 효과를 얻을 수 있습니다.

이러한 사운드 패치 중 하나를 자체 개체에 저장하면 필요에 따라 이를 재사용하고 더 적은 코드로 더 복잡한 오케스트레이션을 생성할 수 있습니다. 이것은 향후 게시물의 주제가 될 수 있습니다.

Tone.js로 더 쉽게 만들기

바닐라 웹 오디오 모듈이 어떻게 작동하는지 간략하게 살펴보았으므로 이제 멋진 웹 오디오 프레임워크인 Tone.js를 살펴보겠습니다. 이것(및 사용자 인터페이스 구성 요소를 위한 NexusUI)을 사용하면 더 흥미로운 신디사이저와 사운드를 매우 쉽게 구축할 수 있습니다. 시험해 보기 위해 샘플러를 만들고 여기에 사용자 대화형 효과를 적용한 다음 이 샘플에 대한 몇 가지 간단한 컨트롤을 추가합니다.

Tone.js 샘플러

간단한 프로젝트 구조를 만드는 것으로 시작할 수 있습니다.

 simpleSampler |-- js |-- nexusUI.js |-- Tone.js |-- noisecollector_hit4.wav |-- sampler.html

JavaScript 라이브러리는 js 디렉토리에 있습니다. 이 데모의 목적을 위해 Freesound.org에서 다운로드할 수 있는 NoiseCollector의 hit4.wav 파일을 사용할 수 있습니다.

Tone.js는 Player 개체를 통해 기능을 제공합니다. 개체의 기본 기능은 샘플을 로드하고 루프에서 또는 한 번 재생하는 것입니다. 여기서 첫 번째 단계는 sampler.html 파일 내부의 "샘플러" 변수에 플레이어 개체를 만드는 것입니다.

 <!doctype html> <html> <head> <title> Sampler </title> <script type="text/javascript" src="js/nexusUI.js" ></script> <script type="text/javascript" src="js/Tone.js" ></script> <script> var sampler = new Tone.Player("noisecollector_hit4.wav", function() { console.log("samples loaded"); }); </script> </head> <body> </body> </html>

플레이어 생성자의 첫 번째 매개변수는 WAV 파일의 이름이고 두 번째 매개변수는 콜백 함수입니다. WAV가 유일하게 지원되는 파일 형식은 아니며 호환성은 라이브러리보다 웹 브라우저에 더 많이 의존합니다. 플레이어가 샘플을 버퍼에 로드하는 것을 완료하면 콜백 함수가 실행됩니다.

또한 샘플러를 출력에 연결해야 합니다. 이를 수행하는 Tone.js 방법은 다음과 같습니다.

 sampler.toMaster();

... 여기서 sampler는 10행 이후의 Tone.Player 객체입니다. toMaster 함수는 connect(Tone.Master)의 약어입니다.

개발자 콘솔이 열린 상태에서 웹 브라우저를 열면 플레이어가 올바르게 생성되었음을 나타내는 "샘플 로드됨" 메시지가 표시되어야 합니다. 이 시점에서 샘플을 듣고 싶을 수 있습니다. 그렇게 하려면 웹 페이지에 버튼을 추가하고 한번 누르면 샘플이 재생되도록 프로그래밍해야 합니다. 본문에서 NexusUI 버튼을 사용할 것입니다.

 <canvas nx="button"></canvas>

이제 문서에서 렌더링되는 둥근 버튼을 볼 수 있습니다. 샘플을 재생하도록 프로그래밍하기 위해 다음과 같은 NexusUI 리스너를 추가합니다.

 button1.on('*',function(data) { console.log("button pressed!"); })

NexusUI의 뛰어난 점은 각 NexusUI 요소에 대한 전역 변수를 생성한다는 것입니다. NexusUI가 그렇게 하지 않도록 설정할 수 있으며, 대신 nx.globalWidgets를 false로 설정하여 이러한 변수를 nx.widgets[]에만 사용할 수 있습니다. 여기서 우리는 몇 가지 요소만 만들 것이므로 이 동작을 고수할 것입니다.

jQuery에서와 같이 이러한 .on 이벤트를 넣을 수 있으며 첫 번째 인수는 이벤트 이름이 됩니다. 여기에서는 버튼에 수행되는 모든 작업에 기능을 할당합니다. 이것은 "*"로 쓰여진 것입니다. NexusUI API의 각 요소에 대한 이벤트에 대해 자세히 알아볼 수 있습니다. 버튼을 누를 때 메시지를 기록하는 대신 샘플을 재생하려면 샘플러의 시작 기능을 실행해야 합니다.

 nx.onload = function() { button1.on('*',function(data) { console.log("button pressed!"); sampler.start(); }); }

또한 리스너는 onload 콜백 내부로 이동합니다. NexusUI 요소는 캔버스에 그려지며 nx가 onload 함수를 호출할 때까지 참조할 수 없습니다. jQuery의 DOM 요소와 마찬가지로.

이벤트는 마우스를 누르고 놓을 때 트리거됩니다. 누를 때만 트리거되도록 하려면 event.press가 1인지 평가해야 합니다.

이를 통해 누를 때마다 샘플을 재생하는 버튼이 있어야 합니다. sampler.retrigger를 true로 설정하면 재생 여부에 관계없이 샘플을 재생할 수 있습니다. 그렇지 않으면 샘플이 다시 트리거될 때까지 기다려야 합니다.

효과 적용

Tone.js를 사용하면 지연을 쉽게 생성할 수 있습니다.

 var delay= new Tone.FeedbackDelay("16n",0.5).toMaster();

첫 번째 인수는 지연 시간이며 여기에 표시된 대로 음악 표기법으로 작성할 수 있습니다. 두 번째는 Wet Level로, 원래의 소리와 그것에 영향을 주는 소리의 혼합을 의미합니다. 딜레이의 경우 일반적으로 100% 웨트를 원하지 않습니다. 딜레이는 원래 사운드와 관련하여 흥미롭고 웨트 단독은 둘 다 함께 그다지 매력적이지 않기 때문입니다.

다음 단계는 마스터에서 샘플러를 뽑고 대신 딜레이에 연결하는 것입니다. 샘플러가 마스터에 연결된 라인을 조정합니다.

 sampler.connect(delay);

이제 버튼을 다시 시도하고 차이점을 확인하십시오.

다음으로 문서 본문에 두 개의 다이얼을 추가합니다.

 <canvas nx="dial"></canvas> <canvas nx="dial"></canvas>

그리고 NexusUIlistener를 사용하여 지연 효과에 다이얼 값을 적용합니다.

 dial1.on('*',function(data) { delay.delayTime.value=data.value; }) dial2.on('*',function(data) { delay.feedback.value=data.value; })

각 이벤트에서 조정할 수 있는 매개변수는 Tone.js 문서에서 찾을 수 있습니다. 지연을 위해 여기에 있습니다. 이제 예제를 시도하고 NexusUI 다이얼로 지연 매개변수를 조정할 준비가 되었습니다. 이 과정은 효과에만 국한되지 않고 각 NexusUI 요소로 쉽게 수행할 수 있습니다. 예를 들어, 다른 다이얼을 추가하고 다음과 같이 리스너를 추가해 보십시오.

 dial3.on('*',function(data) { sampler.playbackRate=data.value; })

이 파일은 github.com/autotel/simpleSampler에서 찾을 수 있습니다.

결론

이 API들을 살펴보았을 때, 저는 제 마음에 떠오르기 시작한 모든 가능성과 아이디어에 압도되기 시작했습니다. 이러한 오디오 구현과 디지털 오디오의 기존 구현 간의 큰 차이점은 오디오 자체가 아니라 컨텍스트에 있습니다. 여기에 합성을 만드는 새로운 방법은 없습니다. 오히려 혁신은 오디오와 음악 제작이 이제 웹 기술을 만나고 있다는 것입니다.

저는 개인적으로 전자 음악 제작에 참여하고 있으며, 이 분야는 실제로 음악을 연주하는 것과 녹음된 트랙을 재생하는 것 사이의 모호함이라는 역설이 항상 있었습니다. 실제로 라이브 전자 음악을 만들고 싶다면 라이브 즉흥 연주를 위한 자신만의 연주 도구 또는 "음악 제작 로봇"을 만들 수 있어야 합니다. 그러나 전자 음악의 연주가 미리 준비된 음악 제작 알고리즘의 매개변수를 단순히 조정하면 청중도 이 과정에 참여할 수 있습니다. 저는 크라우드소싱 음악을 위한 웹과 오디오의 통합과 관련하여 약간의 실험을 하고 있으며 아마도 곧 스마트폰을 통해 청중으로부터 음악이 나오는 파티에 참석하게 될 것입니다. 결국 우리가 동굴시대에 즐겼던 리듬감 있는 잼과 별반 다르지 않다.


Toptal 엔지니어링 블로그에 대한 추가 정보:

  • WebAssembly/Rust 튜토리얼: 완벽한 피치 오디오 처리
  • MIDI 튜토리얼: MIDI 하드웨어로 제어되는 브라우저 기반 오디오 애플리케이션 만들기