Web Audio APIê° ì²ì ë¸ë¼ì°ì ì ìê°ëìì ë, ì´ê²ì ì¤ìê°ì¼ë¡ ì¤ëì¤ë¥¼ ì¡°ìíë ì¬ì©ì ì ì ì¤ëì¤ íë¡ì¸ì를 ìì±í기 ìí´ JavaScript ì½ë를 ì¬ì©íê³ ìììµëë¤. ScriptProcessorNode
ì 문ì ì ì ë¨ìíìµëë¤: ì´ê²ì ë©ì¸ ì¤ë ëìì ì¤íë기 ë문ì ì¤íì ë§ì¹ê¸° ì ê¹ì§ ë¤ë¥¸ 모ë ëìì ë§ììµëë¤. ì´ë¬í ë°©ìì ì´ìì ì´ì§ ìììµëë¤. í¹í ì¤ëì¤ íë¡ì¸ì±ê°ì´ ê³ì°ì ì¼ë¡ ë¹ì©ì´ ë§ì´ ë¤ ì ìë 무ì¸ê°ì ëí´ì ë§ì
ëë¤.
AudioWorklet
ì´ ëì
ëììµëë¤. ì¤ëì¤ ì»¨í
ì¤í¸ì ì¤ëì¤ workletì ë©ì¸ ì¤ë ëìì ë¨ì´ì ¸ ì¤íëë Worklet
ì¸ë°, ì´ë 컨í
ì¤í¸ì audioWorklet.addModule()
ë©ìë를 í¸ì¶í¨ì¼ë¡ì¨ ì´ workletì ì¶ê°ë ì¤ëì¤ íë¡ì¸ì± ì½ë를 ì¤íí©ëë¤. addModule()
ì í¸ì¶íë©´ ëª
ìë JavaScript íì¼ì ë¡ëíëë°, ì´ íì¼ì ì¤ëì¤ íë¡ì¸ìì 구íì í¬í¨íê³ ìì´ì¼ í©ëë¤. íë¡ì¸ìê° ë±ë¡ëìë¤ë©´ ì¬ë¬ë¶ì ìë¡ì´ AudioWorkletNode
를 ìì±í ì ìê³ , ì´ ë
¸ëê° ë¤ë¥¸ ì¤ëì¤ ë
¸ëë¤ê³¼ í¨ê² ì¤ëì¤ ë
¸ëì ì²´ì¸ì ì°ê²°ëìì ë ì´ ë
¸ëë íë¡ì¸ìì ì½ë를 íµí´ ì¤ëì¤ë¥¼ ì ë¬í©ëë¤.
JavaScript를 ì¬ì©í´ ì¤ëì¤ íë¡ì¸ì를 ìì±íê³ , ì¤ëì¤ worklet íë¡ì¸ìë¡ì ê·¸ê²ì ë±ë¡íê³ , ê·¸ë¦¬ê³ ëì Web Audio ì í리ì¼ì´ì ë´ìì ê·¸ íë¡ì¸ì를 ì¬ì©íë ê³¼ì ì´ ì´ ê¸ì 주ì ì ëë¤.
ì¤ëì¤ íë¡ì¸ì±ì´ ì¢ ì¢ ìë¹í ê³ì°ëì ìë°í기 ë문ì, ì¬ë¬ë¶ì íë¡ì¸ìê° WebAssembly를 ì¬ì©íì¬ ê°ë°ëë¤ë©´ í° ì´ì ì ì·¨í ìë ìì ê²ì ëë¤. ê·¸ë¦¬ê³ ì´ë ê² íë ê²ì ì¹ ì±ì ë¤ì´í°ë¸ì ê°ê¹ê±°ë ìì í ë¤ì´í°ë¸ì¸ ì±ë¥ì ê°ì ¸ë¤ ì¤ë¤ë ê²ì 주목í ê°ì¹ê° ììµëë¤. WebAssembly를 ì¬ì©íì¬ ì¤ëì¤ íë¡ì¸ì± ìê³ ë¦¬ì¦ì 구ííë©´ ì¤ëì¤ íë¡ì¸ì±ì´ ëë¨í ë°ì´ëê² ìíë ì ìê² ë§ë¤ ì ììµëë¤.
ë©ë¦¬ì ë°ë¼ë³¸ ê°ìë¨ê³ë³ 기ì´ë¥¼ ë°ìê°ë©° AudioWorkletì ì¬ì©ë²ì ìì보기 ì ì, ì¬ê¸°ì 무ìì´ ê´ë ¨ëì´ ìëì§ ê°ëµí ê³ ìì¤ì ê°ì를 ì´í´ë³´ë©° ììí©ìë¤.
AudioWorkletProcessor
를 ììë°ë ì¤ëì¤ worklet íë¡ì¸ì í´ëì¤ë¥¼ ì ìíë 모ëì ë§ëëë¤.audioWorklet
ìì±ì íµí´ ì¤ëì¤ ì»¨í
ì¤í¸ì AudioWorklet
ì ì ê·¼íê³ , ì¤ëì¤ workletì addModule()
ë©ìë를 í¸ì¶íì¬ ì¤ëì¤ worklet íë¡ì¸ì 모ëì ì¤ì¹í©ëë¤.AudioWorkletNode()
ìì±ìì ì ë¬í¨ì¼ë¡ì¨ ì¤ëì¤ íë¡ì¸ì± ë
¸ë를 ìì±í©ëë¤.AudioWorkletNode
ê° íìë¡ íë, ëë ì¬ë¬ë¶ì´ ì¤ì í기를 ìíë ì¤ëì¤ íë¼ë¯¸í°ë¤ì ì¤ì í©ëë¤. ì´ íë¼ë¯¸í°ë¤ì ì¤ëì¤ worklet íë¡ì¸ì 모ë ë´ì ì ìëì´ ììµëë¤.AudioWorkletNode
를 ì¤ëì¤ íë¡ì¸ì± íì´íë¼ì¸ì ì°ê²°íê³ , ì¤ëì¤ íì´íë¼ì¸ì íììì²ë¼ ì¬ì©í©ëë¤.ì´ ê¸ì ë§ì§ë§ê¹ì§ ì°ë¦¬ë ì´ ê³¼ì ë¤ì ìì ì í¨ê» ëì± ìì¸íê² ì´í´ë³¼ ê²ì ëë¤ (ì§ì ìëí´ë³¼ ì ìë ìëíë ìì 를 í¬í¨í©ëë¤).
ì´ íì´ì§ìì ì°¾ì ì ìë ìì ì½ëë MDNì Web Audio ìì ì GitHub ë í¬ì§í 리ì ì¼ë¶ì¸ ì´ ìì ìì ììµëë¤. ì´ ìì ë ì¤ì¤ë ì´í° ë
¸ë를 ìì±íê³ ê²°ê³¼ë¡ ë°ìë ì¬ì´ë를 ì¬ìí기 ì ì AudioWorkletNode
를 ì¬ì©íì¬ ì´ ì리ì ë°±ìììì ì¶ê°í©ëë¤. ëí, ì¬ë¼ì´ë를 ì¬ì©í´ ì¤ì¤ë ì´í°ì ì¤ëì¤ workletì ì¶ë ¥ gainì ì ì´í ì ììµëë¤.
기본ì ì¼ë¡, ì¤ëì¤ worklet íë¡ì¸ìë JavaScript 모ëì ì¬ì©íì¬ êµ¬íëê³ , ì´ JavaScript 모ëì ì¬ì©ì ì ì ì¤ëì¤ íë¡ì¸ì í´ëì¤ë¥¼ ì ìíê³ ë±ë¡í©ëë¤ (ì°¸ê³ ë¡, ì°ë¦¬ë ì´ ê¸ìì ì¤ëì¤ worklet íë¡ì¸ì를 "ì¤ëì¤ íë¡ì¸ì" ëë "íë¡ì¸ì"ë¡ ëíë¼ ê²ì ëë¤. ìëíë©´ ê·¸ë ì§ ìì ê²½ì° ì´ ê¸ì ë ë°° ê°ë 길ì´ì§ ê²ì´ê¸° ë문ì ëë¤).
ì¤ëì¤ worklet íë¡ì¸ìì 구조ì¤ëì¤ worklet íë¡ì¸ìë ë¤ìì í¬í¨íë JavaScript 모ëì ëë¤:
AudioWorkletProcessor
í´ëì¤ë¥¼ ììë°ìµëë¤(extends).process()
ë©ìë를 구íí´ì¼ íëë°, ì´ ë©ìëë ë¤ì´ì¤ë ì¤ëì¤ ë°ì´í°ë¥¼ ë°ê³ íë¡ì¸ìì ìí´ ì¡°ìë ë°ì´í°ë¥¼ ì¶ë ¥ì ë£ìµëë¤.registerProcessor()
를 í¸ì¶í¨ì¼ë¡ì¨ ìë¡ì´ ì¤ëì¤ worklet íë¡ì¸ì를 ë±ë¡íëë°, ë±ë¡í ë ì¤ëì¤ íë¡ì¸ìì ì´ë¦ê³¼ íë¡ì¸ì를 ì ìíë í´ëì¤ë¥¼ ì¸ìë¡ ì ë¬í©ëë¤.í ê°ì ì¤ëì¤ worklet íë¡ì¸ì 모ëì´ ë¤ìì íë¡ì¸ì í´ëì¤ë¥¼ ì ìíê³ ê° í´ëì¤ì ëí´ registerProcessor()
를 í¸ì¶í´ í´ëì¤ë¤ì ë±ë¡í ìë ìì ê²ì
ëë¤. ê° í´ëì¤ê° ê³ ì í ì´ë¦ì ê°ì§ê³ ìë í, ì´ê²ì 문ì ìë ë°©ë²ì
ëë¤. ì´ ë°©ë²ì ëí ë¤ìì 모ëì ë¤í¸ìí¬ë ì¬ì§ì´ ì¬ì©ìì ë¡ì»¬ ëì¤í¬ë¡ë¶í° ë¡ë©íë ê²ë³´ë¤ ëì± í¨ì¨ì ì
ëë¤.
ì¤ëì¤ íë¡ì¸ì í´ëì¤ì ê°ì¥ 기본ì ì¸ íë ììí¬ë ë¤ìê³¼ ê°ìµëë¤:
class MyAudioProcessor extends AudioWorkletProcessor {
constructor() {
super();
}
process(inputList, outputList, parameters) {
/* inputs를 ì¬ì©íì¬ (í¹ì íìíì§ ìë¤ë©´ ì¬ì©íì§ ìì ìë ìì),
ê° outputsì ë´ë¶ì ìë ì¶ë ¥ì ìì±í©ëë¤ */
return true;
}
}
registerProcessor("my-audio-processor", MyAudioProcessor);
íë¡ì¸ìì 구í ì´íì ì ì í¨ì registerProcessor()
를 í¸ì¶íëë°, ì´ í¨ìë ì¤ì§ ì¤ëì¤ ì»¨í
ì¤í¸ì AudioWorklet
ì ì¤ì½í ë´ë¶ììë§ ì¬ì© ê°ë¥íê³ , ì´ AudioWorkletì ì¬ë¬ë¶ì´ í¸ì¶í audioWorklet.addModule()
ì ê²°ê³¼ë¡ì¨ í¸ì¶ìê° ë©ëë¤. ì´ registerProcessor()
í¸ì¶ì AudioWorkletNode
ë¤ì´ ì¤ì ëìì ë, ìì±ë 모ë AudioWorkletProcessor
ì ëí 기ì´ë¡ì¨ ì¬ë¬ë¶ì í´ëì¤ë¥¼ ë±ë¡í©ëë¤.
ì´ê²ì´ ê°ì¥ 기본ì ì¸ íë ììí¬ì´ê³ ì½ëê° process()
ì ì¶ê°ëì´ ì
ë ¥ê³¼ ì¶ë ¥ì ê°ì§ê³ 무ì¸ê°ë¥¼ í기 ì ê¹ì§ë ì¤ì ë¡ë ìë¬´ë° í¨ê³¼ë ììµëë¤. ê·¸ë¦¬ê³ ì´ì ì°ë¦¬ë ì
ë ¥ê³¼ ì¶ë ¥ì ëí´ ì´í´ë³¼ ì¤ë¹ê° ëììµëë¤.
ì ë ¥ê³¼ ì¶ë ¥ 리ì¤í¸ê° ì´ë»ê² ìëíëì§ í ë² ê¹¨ë«ê³ ëë©´ ì´ê²ë¤ì ì¤ì ë¡ ë§¤ì° ë¨ìí긴 íì§ë§, ì²ììë ì¡°ê¸ í¼ëì¤ë¬ì¸ ì ììµëë¤.
ììì ììí´ì ë°ì¼ë¡ ëê°ë ì ëµì ì·¨í´ ë´
ìë¤. 기본ì ì¼ë¡, (ì를 ë¤ìë©´ ì¢ì¸¡ ì¤í¼ì»¤ë ìë¸ì°í¼ê°ì) íëì ì¤ëì¤ ì±ëì ëí ì¤ëì¤ë Float32Array
ë¡ ííëëë° ì´ê²ì ê°ì ê°ê°ì ì¤ëì¤ ìíì
ëë¤. ëª
ì¸ì ë°ë¥´ë©´, process()
í¨ìê° ë°ë ê° ì¤ëì¤ ë¸ëì 128ê°ì íë ìì í¬í¨íê³ ìì§ë§ (ì¦, ê° ì±ëì ëí´ 128ê°ì ìí), ì´ ê°ì´ 미ëì ë°ë ê²ì´ë¼ë ê±´ ìì ëì´ ìê³ , ì¬ì¤ì ìí©ì ë°ë¼ ë¤ìí ì ìì ê²ì´ë¯ë¡, ì¬ë¬ë¶ì í¹ì í í¬ê¸°ë¥¼ ì¶ì í기보ë¤ë íì ë°°ì´ì length
를 íì¸í´ì¼ í ê²ì
ëë¤. ê·¸ë¬ë, ì
ë ¥ê³¼ ì¶ë ¥ì´ ê°ì ë¸ë 길ì´ë¥¼ ê°ì§ ê²ì´ë¼ë ê±´ ë³´ì¥ë©ëë¤.
ê°ê°ì ì
ë ¥ì ì¼ë§ê°ì ì±ëì ê°ì§ê³ ììµëë¤. 모ë
¸ ì
ë ¥ì íëì ì±ëì ê°ì§ê³ ìê³ , ì¤í
ë ì¤ ì
ë ¥ì ë ê°ì ì±ëì ê°ì§ê³ ììµëë¤. ìë¼ì´ë ì¬ì´ëë ì¬ì¯ ê° í¹ì ê·¸ ì´ìì ì±ëì ê°ì§ê³ ìì ì§ë 모ë¦
ëë¤. ê·¸ëì ê° ì
ë ¥ì, ê²°êµì, ì±ëì ë°°ì´ì
ëë¤. ì¦, Float32Array
ê°ì²´ì ë°°ì´ì
ëë¤.
ê·¸ë ë¤ë©´, ë¤ìì ì
ë ¥ì´ ìì ì ìì¼ë¯ë¡, inputList
ë Float32Array
ê°ì²´ì ë°°ì´ì ë°°ì´ì
ëë¤. ê°ê°ì ì
ë ¥ì ê°ê¸° ë¤ë¥¸ ìì ì±ëì ê°ì§ê³ ìì ì§ë ëª¨ë¥´ê³ , ê° ì±ëì ì±ëë§ë¤ì ìí ë°°ì´ì ê°ì§ê³ ììµëë¤.
ë°ë¼ì, ì
ë ¥ 리ì¤í¸ inputList
ê° ì£¼ì´ì§ë©´:
const numberOfInputs = inputList.length;
const firstInput = inputList[0];
const firstInputChannelCount = firstInput.length;
const firstInputFirstChannel = firstInput[0]; // (ëë inputList[0][0])
const firstChannelByteCount = firstInputFirstChannel.length;
const firstByteOfFirstChannel = firstInputFirstChannel[0]; // (ëë inputList[0][0][0])
ì¶ë ¥ 리ì¤í¸ë ì íí ê°ì ë°©ìì¼ë¡ 구ì±ë©ëë¤; ì´ê²ì ì¶ë ¥ë¤ì ë°°ì´ì¸ë°, ì´ê²ì ê°ê°ì ì±ëë¤ì ë°°ì´ì´ê³ , ì´ê²ì ê°ê°ì Float32Array
ê°ì²´ì ë°°ì´ì¸ë°, ì´ë ê·¸ ì±ëì ëí ìíì í¬í¨í©ëë¤.
ì¬ë¬ë¶ì´ ì´ë»ê² ì ë ¥ì ì¬ì©íê³ ì´ë»ê² ì¶ë ¥ì ìì±í ê²ì¸ê°ë ì¬ë¬ë¶ì íë¡ì¸ìì ì주 ë¬ë ¤ ììµëë¤. ë§ì½ ì¬ë¬ë¶ì íë¡ì¸ìê° ë¨ì§ ìì±ê¸°ë¼ë©´, ì´ê²ì ì ë ¥ì 무ìíê³ ë¨ì§ ìì±ë ë°ì´í°ë¡ ì¶ë ¥ì ë´ì©ì ëì²´í ì ììµëë¤. ëë ì¬ë¬ë¶ì ê° ì ë ¥ì ê° ì±ëì ë¤ì´ì¤ë ë°ì´í°ì ìê³ ë¦¬ì¦ì ì ì©íê³ ê·¸ 결과를 í´ë¹íë ì¶ë ¥ì ì±ëì ìì±íë©° (ì ë ¥ê³¼ ì¶ë ¥ì ìë ë¤ë¥¼ì§ë ëª¨ë¥´ê³ , ì±ëì ëí ë¤ë¥¼ì§ë 모르ë ì´ ì ë ¥ê³¼ ì¶ë ¥ì 기ëê³ ìë¤ë ê²ì ëª ì¬íììì¤), ê°ê°ì ì ë ¥ì ë 립ì ì¼ë¡ ì²ë¦¬í ì ììµëë¤. ëë ì¬ë¬ë¶ì 모ë ì ë ¥ì ì·¨í´ì 믹ì±ì´ë ë°ì´í°ë¡ ì±ìì§ íëì ì¶ë ¥ (ëë ê°ì ë°ì´í°ë¡ ì±ìì§ ëª¨ë ì¶ë ¥) ì ìì±íë ë¤ë¥¸ ê³ì°ì ìíí ì ììµëë¤.
ì´ê²ì ì ì ì¼ë¡ ì¬ë¬ë¶ìê² ë¬ë ¤ ììµëë¤. ì´ê²ì ì¤ëì¤ íë¡ê·¸ëë° í´í·ìì ë§¤ì° ê°ë ¥í ë구ì ëë¤.
ë¤ìì ì ë ¥ ì²ë¦¬í기í´ë¹íë ì¶ë ¥ì ìì±í기 ìí´ ì¬ì©ëë ê° ì
ë ¥ì ê°ì§ê³ , ë¤ìì ì
ë ¥ì ì²ë¦¬í ì ìë process()
ì 구íì ì´í´ë´
ìë¤. ì´ê³¼ëë ì
ë ¥ì 무ìë©ëë¤.
process(inputList, outputList, parameters) {
const sourceLimit = Math.min(inputList.length, outputList.length);
for (let inputNum = 0; inputNum < sourceLimit; inputNum++) {
let input = inputList[inputNum];
let output = outputList[inputNum];
let channelCount = Math.min(input.length, output.length);
for (let channelNum = 0; channelNum < channelCount; channelNum++) {
let sampleCount = input[channelNum].length;
for (let i = 0; i < sampleCount; i++) {
let sample = input[channelNum][i];
/* ìí ì¡°ìí기 */
output[channelNum][i] = sample;
}
}
};
return true;
}
í´ë¹íë ì¶ë ¥ì ë³´ë´ê³ ì²ë¦¬í ìì¤ì ì를 ê²°ì í ë, ì°ë¦¬ë Math.min()
ì ì¬ì©í´ ì¤ì§ ì¶ë ¥ 리ì¤í¸ì ìë ê³µê°ë§í¼ì ì±ëë§ì ì²ë¦¬íë¤ë ê²ì íì¤í í©ëë¤. ì´ê²ê³¼ ê°ì íì¸ì íì¬ ì
ë ¥ìì ì¼ë§ë ë§ì ì±ëì ì²ë¦¬í ì§ ê²°ì í ë ìíë©ëë¤; ì°ë¦¬ë ì¤ì§ destination ì¶ë ¥ì ìë ê³µê°ë§í¼ë§ ì²ë¦¬í©ëë¤. ì´ë ê² í¨ì¼ë¡ì¨ ì°ë¦¬ë ì´ ë°°ì´ì ì´ê³¼ ë문ì ë°ìíë ì¤ë¥ë¤ì ë°©ì§í ì ììµëë¤.
ë§ì ë ¸ëë¤ì ì ë ¥ë¤ì´ ì´ë¤ ë°©ë²ì¼ë¡ íëì ì¶ë ¥ì¼ë¡ ê²°í©ëë ë¯¹ì± ìì ì ìíí©ëë¤. ì´ë ìëì ìì ìì ìì°ë©ëë¤.
process(inputList, outputList, parameters) {
const sourceLimit = Math.min(inputList.length, outputList.length);
for (let inputNum = 0; inputNum < sourceLimit; inputNum++) {
let input = inputList[inputNum];
let output = outputList[0];
let channelCount = Math.min(input.length, output.length);
for (let channelNum = 0; channelNum < channelCount; channelNum++) {
let sampleCount = input[channelNum].length;
for (let i = 0; i < sampleCount; i++) {
let sample = output[channelNum][i] + input[channelNum][i];
if (sample > 1.0) {
sample = 1.0;
} else if (sample < -1.0) {
sample = -1.0;
}
output[channelNum][i] = sample;
}
}
};
return true;
}
ì´ê²ì ë§ì ì ìì ì´ì ìì ì ë¹ì·í ì½ëì´ì§ë§, ì¤ì§ 첫ë²ì§¸ ì¶ë ¥âoutputList[0]
âì´ ë³ê²½ëììµëë¤. ê°ì ì íì ëì´ì ìíë¤ì´ -1.0ìì 1.0 ì¬ì´ì ì¬ë°ë¥¸ ë²ì를 ì´ê³¼íë ê²ì ë°©ì§í기 ìí´ ìëíë ê°ë¨í ì½ë ì¡°ê°ê³¼ í¨ê», ê°ê°ì ìíì´ ì¶ë ¥ ë²í¼ì í´ë¹íë ìíì ì¶ê°ëììµëë¤; í´ë¦¬íì ë°©ì§í ìë§ë ë ì곡ë ê²½í¥ì´ ìë ë¤ë¥¸ ë°©ë²ë¤ì´ ìê² ì§ë§, ì´ê²ì ì무ê²ë ìë ê² ë³´ë¤ë ëì ê°ë¨í ìì를 ë³´ì¬ì¤ëë¤.
ì¬ë¬ë¶ì´ ì¤ëì¤ worklet íë¡ì¸ìì ìì 주기ì ìí¥ì ì¤ ì ì¼í ìë¨ì process()
ì ìí´ ë°íë ê°ì íµí´ìì¸ë°, ì´ë ë
¸ëê° ì¬ì í ì¬ì©ëê³ ìëì§ ìëì§ì ëí user agentì ìì¬ ê²°ì ì 무ìí ì§ ë§ì§ë¥¼ ëíë´ë Boolean ê°ì´ì´ì¼ë§ í©ëë¤.
ì¼ë°ì ì¼ë¡, 모ë ì¤ëì¤ ë
¸ëì ìì ì ì±
ì ë¨ìí©ëë¤: ë§ì½ ë
¸ëê° ì¬ì í íë°í ì¤ëì¤ë¥¼ íë¡ì¸ì±íê³ ìë ê²ì¼ë¡ ì¬ê²¨ì§ë¤ë©´, ë
¸ëë ê³ì ì¬ì©ë ê²ì
ëë¤. AudioWorkletNode
ì ê²½ì°, ë§ì½ ì´ ë
¸ëì process()
í¨ìê° true
를 ë°ííê³ ëí ì´ ë
¸ëê° ì¤ëì¤ ë°ì´í°ì ëí´ ìì¤ë¡ì 컨í
ì¸ ë¥¼ ìì±íê±°ë íë ì´ìì ì
ë ¥ì¼ë¡ë¶í° ë°ì´í°ë¥¼ ë°ê³ ìë¤ë©´ ì´ ë
¸ëë ìë ì¤ì¸ ê²ì¼ë¡ ì¬ê²¨ì§ëë¤.
본ì§ì ì¼ë¡ process()
í¨ìë¡ë¶í°ì ê²°ê³¼ë¡ì¨ true
ì ê°ì ëª
ìíë¤ë ê²ì Web Audio APIìê² ì¬ì§ì´ APIê° ì¬ë¬ë¶ì ìí´ í 무ì¸ê°ê° ë¨ììì§ ìë¤ê³ ìê°íë¤ í ì§ë¼ë ì¬ë¬ë¶ì íë¡ì¸ìê° ê³ì í¸ì¶ë íìê° ìë¤ê³ ë§í´ì£¼ë ê²ì
ëë¤. ë¤ë¥¸ ë§ë¡ íìë©´, true
ë APIì ë¡ì§ì 무ìíê³ ì¬ë¬ë¶ì íë¡ì¸ìì ìì 주기 ì ì±
ì ëí ì ì´ë¥¼ ì ê³µí©ëë¤. ì¦, APIê° ì´ ë
¸ë를 ëê¸°ë¡ ê²°ì íì ëì¼ì§ë¼ë íë¡ì¸ìê° ìì ì¤ì¸ AudioWorkletNode
ì ì¤íì ì ì§í©ëë¤.
process()
ë©ìëë¡ë¶í° false
를 ë°ííë ê²ì APIìê² ë³´íµì ë¡ì§ì ë°ë¥´ê³ ë§ì½ íë¡ì¸ì ë
¸ë를 ì¢
ë£íë ê²ì´ ì ì íë¤ê³ ì¬ê²¨ì§ë©´ ê·¸ë ê² í´ì¼ íë¤ê³ ë§í´ì£¼ë ê²ì
ëë¤. ë§ì½ APIê° ì¬ë¬ë¶ì ë
¸ëê° ë ì´ì íììë¤ê³ ê²°ì íë¤ë©´, process()
ë ë¤ì í¸ì¶ëì§ ìì ê²ì
ëë¤.
ì°¸ê³ : ì´ ìì ìì, ë¶ííê²ë, Chromeì ì´ë¤ ì미ë¡ë íì¬ íì¤ì ì¼ì¹íë ì´ ìê³ ë¦¬ì¦ì 구ííì§ ìììµëë¤. ëì , Chromeì ë§ì½ ì¬ë¬ë¶ì´ true
를 ë°ííë©´ ë
¸ë를 ì´ë ¤ëê³ false
를 ë°ííë©´ ëëë¤. ë°ë¼ì í¸íì±ì ì´ì ë¡ ì ì´ë Chromeììë ì¬ë¬ë¶ì íì ë°ëì process()
ìì true
를 ë°íí´ì¼ í©ëë¤. ê·¸ë¬ë, ì´ Chrome ì´ìê° ìì ëê³ ëë©´, ì´ê²ì ì±ë¥ì ì½ê° ë¶ì ì ì¸ ìí¥ì ê°ì§ì§ë 모르ë¯ë¡ ì¬ë¬ë¶ì ë§ì½ ê°ë¥íë¤ë©´ ì´ ëìì ë³ê²½íê³ ì í ê²ì
ëë¤.
AudioWorkletProcessor
를 íµí´ ì¤ëì¤ ë°ì´í° ë¸ëì ì±ì°ë ì¤ëì¤ ë
¸ë를 ìì±íë ¤ë©´, ì¬ë¬ë¶ì ë¤ìì ê°ë¨í ë¨ê³ë¥¼ ë°ë¥¼ íìê° ììµëë¤:
AudioWorkletNode
ìì±í기AudioWorkletNode
ì ì
ë ¥ì ì°ê²°íê³ ì´ ë
¸ëì ì¶ë ¥ì ì ì í destinationì ì°ê²°í기 (ì´ë ë¤ë¥¸ ë
¸ëê±°ë AudioContext
ê°ì²´ì destination
ìì±ì
ëë¤).ì¤ëì¤ worklet íë¡ì¸ì를 ì¬ì©í기 ìí´ì, ì¬ë¬ë¶ì ë¤ìê³¼ ì ì¬í ì½ë를 ì¬ì©í ì ììµëë¤:
let audioContext = null;
async function createMyAudioProcessor() {
if (!audioContext) {
try {
audioContext = new AudioContext();
await audioContext.resume();
await audioContext.audioWorklet.addModule("module-url/module.js");
} catch (e) {
return null;
}
}
return new AudioWorkletNode(audioContext, "processor-name");
}
ì´ createMyAudioProcessor()
í¨ìë ì¬ë¬ë¶ì ì¤ëì¤ íë¡ì¸ì를 ì¬ì©í기 ìí´ ì¤ì ë AudioWorkletNode
ì ìë¡ì´ ì¸ì¤í´ì¤ë¥¼ ìì±íê³ ë°íí©ëë¤. ì´ í¨ìë ëí ë§ì½ ì¤ëì¤ ì»¨í
ì¤í¸ ìì±ì´ ì´ë¯¸ ìë£ëì§ ììë¤ë©´ ì¤ëì¤ ì»¨í
ì¤í¸ ìì±ì ë¤ë£¹ëë¤.
컨í
ì¤í¸ê° ì¬ì© ê°ë¥í¨ì íì¤í í기 ìí´ì, ì´ í¨ìë 컨í
ì¤í¸ê° ì´ë¯¸ ì¬ì© ê°ë¥íì§ ìë¤ë©´ 컨í
ì¤í¸ë¥¼ ìì±í¨ì¼ë¡ì¨ ììíê³ , ê·¸ë¦¬ê³ ëì íë¡ì¸ì를 í¬í¨íë 모ëì workletì ì¶ê°í©ëë¤. ì´ ìì
ì´ ìë£ëê³ ëë©´, ì´ í¨ìë ìë¡ì´ AudioWorkletNode
를 ì¸ì¤í´ì¤ííê³ ë°íí©ëë¤. ë°íë ë
¸ë를 ì»ìë¤ë©´, ì¬ë¬ë¶ì ì´ ë
¸ë를 ë¤ë¥¸ ë
¸ëë¤ì ì°ê²°í ì ìê³ ê·¸ê² ìëë¼ë©´ ì¬í ë¤ë¥¸ ë
¸ëì²ë¼ ì¬ì©í ì ììµëë¤.
ë¤ìì ì½ë를 íµí´ ì¬ë¬ë¶ì ìë¡ì´ ì¤ëì¤ íë¡ì¸ì ë ¸ë를 ìì±í ì ììµëë¤:
let newProcessorNode = createMyAudioProcessor();
ë§ì½ ë°íë ê° newProcessorNode
ê° null
ì´ ìëë¼ë©´, ì°ë¦¬ë ìëíê³ ì¬ì©ë ì¤ë¹ê° ë ë°±ììì íë¡ì¸ì ë
¸ëì í¨ê» ì í¨í ì¤ëì¤ ì»¨í
ì¤í¸ë¥¼ ê°ì§ê³ ìë ê²ì
ëë¤.
ë¤ë¥¸ Web Audio ë
¸ëë¤ì²ë¼, AudioWorkletNode
ì íë¼ë¯¸í°ë¥¼ ì§ìíëë°, ì´ë ì¤ì ìì
ì íë AudioWorkletProcessor
ì ê³µì ë©ëë¤.
AudioWorkletNode
ì íë¼ë¯¸í°ë¥¼ ì¶ê°í기 ìí´ì, ì¬ë¬ë¶ì 모ë ë´ì AudioWorkletProcessor
기ë°ì íë¡ì¸ì í´ëì¤ ë´ìì íë¼ë¯¸í°ë¤ì ì ìí íìê° ììµëë¤. ì´ ìì
ì static getter parameterDescriptors
를 í´ëì¤ì ì¶ê°í¨ì¼ë¡ì¨ ì´ë£¨ì´ì§ ì ììµëë¤. ì´ í¨ìë AudioParam
ê°ì²´ë¤ì ë°°ì´ì ë°íí´ì¼ íëë°, ì´ ê°ì²´ë íë¡ì¸ìì ìí´ ì§ìëë ê° íë¼ë¯¸í°ì ëí´ íëì©ì
ëë¤.
ë¤ìì parameterDescriptors()
구íìì, ë°íë ë°°ì´ì ë ê°ì AudioParam
ê°ì²´ë¥¼ ê°ì§ê³ ììµëë¤. 첫ë²ì§¸ íë¼ë¯¸í°ë gain
ì 기본ê°ì´ 0.5ì¸ 0ê³¼ 1 ì¬ì´ì ê°ì¼ë¡ ì ìíìµëë¤. ëë²ì§¸ íë¼ë¯¸í°ì ì´ë¦ì frequency
ì´ê³ 기본ê°ì 440.0ì¸ë°, ê·¸ ë²ìë ì ë¶ íµíì´ 27.5ìì 4186.009ê¹ì§ì
ëë¤.
static get parameterDescriptors() {
return [
{
name: "gain",
defaultValue: 0.5,
minValue: 0,
maxValue: 1
},
{
name: "frequency",
defaultValue: 440.0;
minValue: 27.5,
maxValue: 4186.009
}
];
}
íë¡ì¸ì ë
¸ëì íë¼ë¯¸í°ë¤ì ì ê·¼íë ê²ì ê·¸ê²ë¤ì process()
ì 구íì ì ë¬ë parameters
ê°ì²´ìì ì°¾ë ê²ë§í¼ì´ë ê°ë¨í©ëë¤. parameters
ê°ì²´ ë´ë¶ì ìë ê²ì ë°°ì´ë¤ì¸ë°, ê° íë¼ë¯¸í° ë¹ íëì´ê³ , íë¼ë¯¸í°ë¡ì ê°ì ì´ë¦ì ê³µì í©ëë¤.
a-rate íë¼ë¯¸í°ì ëí´ìâìê°ì ë°ë¼ ê°ì´ ìëì ì¼ë¡ ë³íë íë¼ë¯¸í°âparameters
ê°ì²´ìì íë¼ë¯¸í°ì ìí¸ë¦¬ë AudioParam
ê°ì²´ë¤ì ë°°ì´ì¸ë°, ì²ë¦¬ëê³ ìë ë¸ë¡ì ê° íë ì ë¹ íëì
ëë¤. ì´ ê°ë¤ì í´ë¹íë íë ìë¤ì ì ì©ë ê²ì
ëë¤.
ë°ë©´ì K-rate íë¼ë¯¸í°ë, ë¸ëë¹ í ë²ë§ ë³í ì ìì´ì, íë¼ë¯¸í°ì ë°°ì´ì ì¤ì§ íëì ìí¸ë¦¬ë¥¼ ê°ì§ëë¤. ë¸ëì 모ë íë ìì ëí´ ì´ ê°ì ì¬ì©íììì¤.
ìëì ì½ëìì, ì°ë¦¬ë a-rate ëë k-rate íë¼ë¯¸í°ë¡ ì°ì¼ ì ìë gain
íë¼ë¯¸í°ë¥¼ ë¤ë£¨ë process()
í¨ì를 ë³¼ ì ììµëë¤. ì°ë¦¬ì ë
¸ëë ì¤ì§ íëì ì
ë ¥ë§ì ì§ìíë¯ë¡, ì´ ë
¸ëë ë¨ì§ 리ì¤í¸ì 첫ë²ì§¸ ì
ë ¥ë§ì ì·¨íê³ , gainì ì´ ì
ë ¥ì ì ì©íê³ , ê²°ê³¼ë¡ ìì±ë ë°ì´í°ë¥¼ 첫ë²ì§¸ ì¶ë ¥ì ë²í¼ì ìì±í©ëë¤.
process(inputList, outputList, parameters) {
const input = inputList[0];
const output = outputList[0];
const gain = parameters.gain;
for (let channelNum = 0; channelNum < input.length; channel++) {
const inputChannel = input[channel];
const outputChannel = output[channel];
// ë§ì½ gain.lengthê° 1ì´ë©´, ì´ê²ì k-rate íë¼ë¯¸í°ì´ë¯ë¡,
// 첫ë²ì§¸ ìí¸ë¦¬ë¥¼ 모ë íë ìì ì ì©í©ëë¤.
// ê·¸ë ì§ ìì¼ë©´, ê° ìí¸ë¦¬ë¥¼ í´ë¹íë íë ìì ì ì©í©ëë¤.
if (gain.length === 1) {
for (let i = 0; i < inputChannel.length; i++) {
outputChannel[i] = inputChannel[i] * gain[0];
}
} else {
for (let i = 0; i < inputChannel.length; i++) {
outputChannel[i] = inputChannel[i] * gain[i];
}
}
}
return true;
}
ì¬ê¸°ì, ë§ì½ gain.length
ê° gain
íë¼ë¯¸í°ì ê°ë¤ì ë°°ì´ì ì¤ì§ íëì ê°ë§ì´ ìë¤ë ê²ì ëíë´ë©´, ë°°ì´ì ìë 첫ë²ì§¸ ìí¸ë¦¬ê° ë¸ëì 모ë íë ìì ì ì©ë©ëë¤. ê·¸ë ì§ ìì¼ë©´, ë¸ëì ê° íë ìì ëí´, gain[]
ì ìë í´ë¹íë ìí¸ë¦¬ê° ì ì©ë©ëë¤.
ì¬ë¬ë¶ì ë©ì¸ ì¤ë ë ì¤í¬ë¦½í¸ë ë¤ë¥¸ ë
¸ëë¤ì´ í ì ìë ê²ê³¼ ë§ì°¬ê°ì§ë¡ íë¼ë¯¸í°ì ì ê·¼í ì ììµëë¤. ì´ë ê² í기 ìí´ìë, ì²«ì§¸ë¡ ì¬ë¬ë¶ì AudioWorkletNode
ì parameters
ìì±ì get()
ë©ìë를 í¸ì¶í¨ì¼ë¡ì¨ íë¼ë¯¸í°ì ëí 참조를 ì»ì íìê° ììµëë¤.
let gainParam = myAudioWorkletNode.parameters.get("gain");
gainParam
ì ë°íëê³ ì ì¥ë ê°ì gain
íë¼ë¯¸í°ë¥¼ ì ì¥í기 ìí´ ì¬ì©ë AudioParam
ì
ëë¤. ì¬ë¬ë¶ì ê·¸ë¦¬ê³ ëì AudioParam
ë©ìë setValueAtTime()
ì ì¬ì©íì¬ ì£¼ì´ì§ ìê°ì ê°ì í¨ê³¼ì ì¼ë¡ ë°ê¿ ì ììµëë¤.
ì를 ë¤ì´, ì¬ê¸°ì, ì°ë¦¬ë ê°ì newValue
ë¡, í¨ê³¼ì ì¼ë¡ ì¦ì ì¤ì íìµëë¤.
gainParam.setValueAtTime(newValue, audioContext.currentTime);
ì¬ë¬ë¶ì ì ì¬íê² AudioParam
ì¸í°íì´ì¤ì ìë ë¤ë¥¸ 모ë ë©ìë를 ìê°ì ë°ë¥¸ ë³í를 ì ì©í기 ìí´, ìì ë ë³í를 ì·¨ìí기 ìí´, ê·¸ë¦¬ê³ ë±ë±ì ìí´ ì¬ì©í ì ììµëë¤.
íë¼ë¯¸í°ì ê°ì ì½ë ê²ì value
ìì±ì ë³´ë ê² ë§í¼ì´ë ê°ë¨í©ëë¤:
let currentGain = gainParam.value;
ê°ì´ 보기
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4