1
1
<!doctype html>
2
2
< html >
3
3
< head >
4
- < title > k-rate AudioParams with inputs for DelayNode </ title >
4
+ < title > DelayNode delayTime with k-rate input should match automation </ title >
5
5
< script src ="/resources/testharness.js "> </ script >
6
6
< script src ="/resources/testharnessreport.js "> </ script >
7
- < script src ="/webaudio/resources/audit.js "> </ script >
8
7
< script src ="/webaudio/resources/audit-util.js "> </ script >
9
8
</ head >
10
9
11
10
< body >
12
11
< script >
13
- let audit = Audit . createTaskRunner ( ) ;
14
-
15
- // Power-of-two to eliminate round-off in computing time and frames, but
16
- // is otherwise arbitrary.
12
+ // Power-of-two sample rate to eliminate round-off errors.
17
13
const sampleRate = 8192 ;
18
14
19
- // Arbitrary duration except it must be greater than or equal to 1.
20
- const testDuration = 1.5 ;
21
-
22
- audit . define (
23
- { label : 'delayTime' , description : `DelayNode delayTime k-rate input` } ,
24
- async ( task , should ) => {
25
- // Two channels: 0 = test result, 1 = expected result.
26
- let context = new OfflineAudioContext ( {
27
- numberOfChannels : 2 ,
28
- sampleRate : sampleRate ,
29
- length : testDuration * sampleRate
30
- } ) ;
31
-
32
- let merger = new ChannelMergerNode (
33
- context , { numberOfInputs : context . destination . channelCount } ) ;
34
- merger . connect ( context . destination ) ;
35
-
36
- // Test the DelayNode by having a reference node (refNode) that uses
37
- // k-rate automations of delayTime. The test node (testNode) sets
38
- // delayTime to k-rate with a connected input that has the same
39
- // automation vlaues as the reference node. The test passes if the
40
- // output from each node is identical to each other.
41
-
42
- // Just some non-constant source.
43
- let src = new OscillatorNode ( context ) ;
44
-
45
- // The end value and time for the linear ramp. These values are
46
- // chosen so that the delay advances faster than real time.
47
- let endValue = 1.125 ;
48
- let endTime = 1 ;
49
-
50
- let refNode ;
51
-
52
- should (
53
- ( ) => refNode = new DelayNode ( context ) ,
54
- `refNode = new DelayNode(context)` )
55
- . notThrow ( ) ;
56
-
57
- should (
58
- ( ) => refNode . delayTime . automationRate = 'k-rate' ,
59
- `refNode.delayTime.automationRate = 'k-rate'` )
60
- . notThrow ( ) ;
61
-
62
- should (
63
- ( ) => refNode . delayTime . setValueAtTime ( 0 , 0 ) ,
64
- `refNode.delayTime.setValueAtTime(0, 0)` )
65
- . notThrow ( ) ;
66
-
67
- should (
68
- ( ) => refNode . delayTime . linearRampToValueAtTime (
69
- endValue , endTime ) ,
70
- `refNode.delayTime.linearRampToValueAtTime(${ endValue } , ${
71
- endTime } )`)
72
- . notThrow ( ) ;
73
-
74
- let testNode ;
75
-
76
- should (
77
- ( ) => testNode = new DelayNode ( context ) ,
78
- `testNode = new DelayNode(context)` )
79
- . notThrow ( ) ;
80
-
81
- should (
82
- ( ) => testNode . delayTime . automationRate = 'k-rate' ,
83
- `testNode.delayTime.automationRate = 'k-rate'` )
84
- . notThrow ( ) ;
85
-
86
- let testMod ;
87
-
88
- should (
89
- ( ) => testMod = new ConstantSourceNode ( context ) ,
90
- `testMod = new ConstantSourceNode(context)` )
91
- . notThrow ( ) ;
92
-
93
- should (
94
- ( ) => testMod . offset . setValueAtTime ( 0 , 0 ) ,
95
- `testMod.offset.setValueAtTime(0, 0)` )
96
- . notThrow ( ) ;
97
-
98
- should (
99
- ( ) => testMod . offset . linearRampToValueAtTime ( endValue , endTime ) ,
100
- `testMod.offset.linearRampToValueAtTime(${ endValue } , ${
101
- endTime } )`)
102
- . notThrow ( ) ;
103
-
104
- should (
105
- ( ) => testMod . connect ( testNode . delayTime ) ,
106
- `testMod.connect(testNode.delayTime)` )
107
- . notThrow ( ) ;
108
-
109
- // Connect up everything and go!
110
- src . connect ( testNode ) . connect ( merger , 0 , 0 ) ;
111
- src . connect ( refNode ) . connect ( merger , 0 , 1 ) ;
112
-
113
- src . start ( ) ;
114
- testMod . start ( ) ;
115
-
116
- const buffer = await context . startRendering ( ) ;
117
- let expected = buffer . getChannelData ( 0 ) ;
118
- let actual = buffer . getChannelData ( 1 ) ;
119
-
120
- // Quick sanity check that output isn't zero. This means we messed
121
- // up the connections or automations or the buffer source.
122
- should ( expected , `Expected k-rate delayTime AudioParam with input` )
123
- . notBeConstantValueOf ( 0 ) ;
124
- should ( actual , `Actual k-rate delayTime AudioParam with input` )
125
- . notBeConstantValueOf ( 0 ) ;
126
-
127
- // Quick sanity check. The amount of delay after one render is
128
- // endValue * 128 / sampleRate. But after 1 render, time has
129
- // advanced 128/sampleRate. Hence, the delay exceeds the time by
130
- // (endValue - 1)*128/sampleRate sec or (endValue - 1)*128 frames.
131
- // This means the output must be EXACTLY zero for this many frames
132
- // in the second render.
133
- let zeroFrames = ( endValue - 1 ) * RENDER_QUANTUM_FRAMES ;
134
- should (
135
- actual . slice (
136
- RENDER_QUANTUM_FRAMES , RENDER_QUANTUM_FRAMES + zeroFrames ) ,
137
- `output[${ RENDER_QUANTUM_FRAMES } , ${
138
- RENDER_QUANTUM_FRAMES + zeroFrames - 1 } ]`)
139
- . beConstantValueOf ( 0 ) ;
140
- should (
141
- actual . slice (
142
- RENDER_QUANTUM_FRAMES + zeroFrames ,
143
- 2 * RENDER_QUANTUM_FRAMES ) ,
144
- `output[${ RENDER_QUANTUM_FRAMES + zeroFrames } , ${
145
- 2 * RENDER_QUANTUM_FRAMES - 1 } ]`)
146
- . notBeConstantValueOf ( 0 ) ;
147
-
148
- // The expected and actual results must be EXACTLY the same.
149
- should ( actual , `k-rate delayTime AudioParam with input` )
150
- . beCloseToArray ( expected , { absoluteThreshold : 0 } ) ;
151
- } ) ;
152
-
153
- audit . run ( ) ;
15
+ // Arbitrary test duration (must be ≥ 1s).
16
+ const testDurationSeconds = 1.5 ;
17
+
18
+ // Total number of frames based on sample rate and duration.
19
+ const totalFrames = sampleRate * testDurationSeconds ;
20
+
21
+ promise_test ( async t => {
22
+ // Two channels: 0 = test result, 1 = expected result.
23
+ const context = new OfflineAudioContext ( {
24
+ numberOfChannels : 2 ,
25
+ sampleRate : sampleRate ,
26
+ length : totalFrames
27
+ } ) ;
28
+
29
+ const merger = new ChannelMergerNode ( context , {
30
+ numberOfInputs : context . destination . channelCount
31
+ } ) ;
32
+ merger . connect ( context . destination ) ;
33
+
34
+ // Test the DelayNode by having a reference node (refNode) that uses
35
+ // k-rate automations of delayTime. The test node (testNode) sets
36
+ // delayTime to k-rate with a connected input that has the same
37
+ // automation vlaues as the reference node. The test passes if the
38
+ // output from each node is identical to each other.
39
+
40
+ const oscillator = new OscillatorNode ( context ) ;
41
+
42
+ // The end value and time for the linear ramp. These values are
43
+ // chosen so that the delay advances faster than real time.
44
+ const rampEndValue = 1.125 ;
45
+ const rampEndTime = 1 ;
46
+
47
+ const refNode = new DelayNode ( context ) ;
48
+ refNode . delayTime . automationRate = 'k-rate' ;
49
+ refNode . delayTime . setValueAtTime ( 0 , 0 ) ;
50
+ refNode . delayTime . linearRampToValueAtTime ( rampEndValue , rampEndTime ) ;
51
+
52
+ const testNode = new DelayNode ( context ) ;
53
+ testNode . delayTime . automationRate = 'k-rate' ;
54
+
55
+ const modulator = new ConstantSourceNode ( context ) ;
56
+ modulator . offset . setValueAtTime ( 0 , 0 ) ;
57
+ modulator . offset . linearRampToValueAtTime ( rampEndValue , rampEndTime ) ;
58
+ modulator . connect ( testNode . delayTime ) ;
59
+
60
+ oscillator . connect ( testNode ) . connect ( merger , 0 , 0 ) ;
61
+ oscillator . connect ( refNode ) . connect ( merger , 0 , 1 ) ;
62
+
63
+ oscillator . start ( ) ;
64
+ modulator . start ( ) ;
65
+
66
+ const renderedBuffer = await context . startRendering ( ) ;
67
+ const actual = renderedBuffer . getChannelData ( 0 ) ;
68
+ const expected = renderedBuffer . getChannelData ( 1 ) ;
69
+
70
+ // Quick sanity check that output isn't zero. This means we messed
71
+ // up the connections or automations or the buffer source.
72
+ assert_not_constant_value (
73
+ expected , 0 , 'Expected output should not be constant zero' ) ;
74
+ assert_not_constant_value (
75
+ actual , 0 , 'Actual output should not be constant zero' ) ;
76
+
77
+ // Quick sanity check. The amount of delay after one render is
78
+ // endValue * 128 / sampleRate. But after 1 render, time has
79
+ // advanced 128/sampleRate. Hence, the delay exceeds the time by
80
+ // (endValue - 1)*128/sampleRate sec or (endValue - 1)*128 frames.
81
+ // This means the output must be EXACTLY zero for this many frames
82
+ // in the second render.
83
+ const silentFrames = ( rampEndValue - 1 ) * RENDER_QUANTUM_FRAMES ;
84
+
85
+ assert_strict_constant_value (
86
+ actual . slice (
87
+ RENDER_QUANTUM_FRAMES , RENDER_QUANTUM_FRAMES + silentFrames ) ,
88
+ 0 ,
89
+ `output[${ RENDER_QUANTUM_FRAMES } ` +
90
+ `..${ RENDER_QUANTUM_FRAMES + silentFrames - 1 } ] must be silent`
91
+ ) ;
92
+
93
+ // Next quantum should NOT be silent
94
+ assert_not_constant_value (
95
+ actual . slice (
96
+ RENDER_QUANTUM_FRAMES + silentFrames ,
97
+ 2 * RENDER_QUANTUM_FRAMES ) ,
98
+ 0 ,
99
+ `output[${ RENDER_QUANTUM_FRAMES + silentFrames } ` +
100
+ `..${ 2 * RENDER_QUANTUM_FRAMES - 1 } ] must have signal`
101
+ ) ;
102
+
103
+ // Compare actual vs expected output
104
+ assert_array_equals_exact (
105
+ actual ,
106
+ expected ,
107
+ 'Output from testNode should exactly match reference' ) ;
108
+ } , 'k-rate DelayNode.delayTime with input matches automation behavior' ) ;
154
109
</ script >
155
110
</ body >
156
- </ html >
111
+ </ html >
0 commit comments