audioworklet-audioparam-iterable.https.html (6639B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <title> 6 Test get parameterDescriptor as various iterables 7 </title> 8 <script src="/resources/testharness.js"></script> 9 <script src="/resources/testharnessreport.js"></script> 10 <script src="/webaudio/js/helpers.js"></script> 11 </head> 12 13 <body> 14 <script id="params"> 15 // A series of AudioParamDescriptors, copied one by one into various iterable 16 // data structures. This is used by both the processor side and the main 17 // thread side, so is in a different script tag. 18 const PARAMS = [ 19 { 20 name: "a control-rate parameter", 21 defaultValue: 0.5, 22 minValue: 0, 23 maxValue: 1, 24 automationRate: "a-rate", 25 }, 26 { 27 name: "你好", 28 defaultValue: 2.5, 29 minValue: 0, 30 maxValue: 7, 31 automationRate: "a-rate", 32 }, 33 { 34 name: "🎶", 35 defaultValue: 8.5, 36 minValue: 0, 37 maxValue: 11115, 38 automationRate: "k-rate", 39 }, 40 ]; 41 </script> 42 <script id="processors" type="worklet"> 43 registerProcessor("set", 44 class SetParamProcessor extends AudioWorkletProcessor { 45 static get parameterDescriptors() { 46 var s = new Set(); 47 s.add(PARAMS[0]); 48 s.add(PARAMS[1]); 49 s.add(PARAMS[2]); 50 return s; 51 } 52 constructor() { super(); } 53 process() { 54 } 55 }); 56 57 registerProcessor("array", 58 class ArrayParamProcessor extends AudioWorkletProcessor { 59 static get parameterDescriptors() { 60 return PARAMS; 61 } 62 constructor() { super(); } 63 process() { } 64 }); 65 66 function* gen() { 67 yield PARAMS[0]; 68 yield PARAMS[1]; 69 yield PARAMS[2]; 70 } 71 registerProcessor("generator", 72 class GeneratorParamProcessor extends AudioWorkletProcessor { 73 static get parameterDescriptors() { 74 return gen(); 75 } 76 constructor() { super(); } 77 process() { } 78 }); 79 // Test a processor that has a get parameterDescriptors, but it returns 80 // something that is not iterable. 81 try { 82 registerProcessor("invalid", 83 class InvalidParamProcessor extends AudioWorkletProcessor { 84 static get parameterDescriptors() { 85 return 4; 86 } 87 constructor() { super(); } 88 process() { } 89 }); 90 throw "This should not have been reached."; 91 } catch (e) { 92 // unclear how to signal success here, but we can signal failure in the 93 // developer console 94 if (e.name != "TypeError") { 95 throw "This should be TypeError"; 96 } 97 } 98 // Test a processor that has a get parameterDescriptors, with a duplicate 99 // param name something that is not iterable. 100 try { 101 registerProcessor("duplicate-param-name", 102 class DuplicateParamProcessor extends AudioWorkletProcessor { 103 static get parameterDescriptors() { 104 var p = { 105 name: "a", 106 defaultValue: 1, 107 minValue: 0, 108 maxValue: 1, 109 automationRate: "k-rate", 110 }; 111 return [p,p]; 112 } 113 constructor() { super(); } 114 process() { } 115 }); 116 throw "This should not have been reached."; 117 } catch (e) { 118 // unclear how to signal success here, but we can signal failure in the 119 // developer console 120 if (e.name != "NotSupportedError") { 121 throw "This should be NotSupportedError"; 122 } 123 } 124 // Test a processor that has a no get parameterDescriptors. 125 try { 126 registerProcessor("no-params", 127 class NoParamProcessor extends AudioWorkletProcessor { 128 constructor() { super(); } 129 process() { } 130 }); 131 } catch (e) { 132 throw "Construction should have worked."; 133 } 134 </script> 135 <script> 136 setup({ explicit_done: true }); 137 // Mangle the PARAMS object into a map that has the same shape as what an 138 // AudioWorkletNode.parameter property would 139 var PARAMS_MAP = new Map(); 140 for (var param of PARAMS) { 141 var o = param; 142 var name = o.name; 143 delete o.name; 144 PARAMS_MAP.set(name, o); 145 } 146 147 // This compares `lhs` and `rhs`, that are two maplike with the same shape 148 // as PARAMS_MAP. 149 function compare(testname, lhs, rhs) { 150 equals(lhs.size, rhs.size, "Map match in size for " + testname); 151 var i = 0; 152 for (var [k, v] of lhs) { 153 is_true(rhs.has(k), testname + ": " + k + " exists in both maps"); 154 var vrhs = rhs.get(k); 155 ["defaultValue", "minValue", "maxValue", "automationRate"].forEach( 156 paramKey => { 157 equals( 158 v[paramKey], 159 vrhs[paramKey], 160 `Values for ${k}.${paramKey} match for ${testname}` 161 ); 162 } 163 ); 164 } 165 } 166 var ac = new AudioContext(); 167 var url = URLFromScriptsElements(["params", "processors"]); 168 ac.audioWorklet 169 .addModule(url) 170 .then(() => { 171 ["set", "array", "generator"].forEach(iterable => { 172 test(() => { 173 var node = new AudioWorkletNode(ac, iterable); 174 compare(iterable, node.parameters, PARAMS_MAP); 175 }, `Creating an AudioWorkletNode with a ${iterable} for 176 parameter descriptor worked`); 177 }); 178 }) 179 .then(function() { 180 test(function() { 181 assert_throws_dom("InvalidStateError", function() { 182 new AudioWorkletNode(ac, "invalid"); 183 }); 184 }, `Attempting to create an AudioWorkletNode with an non 185 iterable for parameter descriptor should not work`); 186 }) 187 .then(function() { 188 test(() => { 189 new AudioWorkletNode(ac, "no-params"); 190 }, `Attempting to create an AudioWorkletNode from a processor 191 that does not have a parameterDescriptors getter should work`); 192 }) 193 .then(function() { 194 test(function() { 195 assert_throws_dom("InvalidStateError", function() { 196 new AudioWorkletNode(ac, "duplicate-param-name"); 197 }); 198 }, `Attempting to create an AudioWorkletNode with two parameter 199 descriptor with the same name should not work`); 200 }).then(function() { 201 done(); 202 }); 203 </script> 204 </body> 205 </html>