@@ -34,6 +34,11 @@ export class Play extends Action {
3434 this . engine . audioContext = new ( window . AudioContext || window . webkitAudioContext ) ( ) ;
3535 }
3636
37+ // Initialize AudioPlayer worklets for the audio context
38+ AudioPlayer . initialize ( this . engine . audioContext ) . catch ( error => {
39+ console . warn ( 'Failed to initialize AudioPlayer worklets:' , error ) ;
40+ } ) ;
41+
3742 this . engine . history ( 'music' ) ;
3843 this . engine . history ( 'sound' ) ;
3944 this . engine . history ( 'voice' ) ;
@@ -171,81 +176,6 @@ export class Play extends Action {
171176 this . engine . state ( { voice : [ ] } ) ;
172177 }
173178
174- /**
175- * Prepare the needed values to run the fade function on the given player
176- *
177- * @param {string } fadeTime - The time it will take the audio to reach it's maximum audio
178- * @param {AudioPlayer } player - The AudioPlayer object to modify
179- *
180- * @return {Promise } - This promise will resolve once the fadeIn has ended
181- */
182- static fadeIn ( fadeTime , player ) {
183- const time = parseFloat ( fadeTime . match ( / \d * ( \. \d * ) ? / ) ) ;
184- const increments = time / 0.1 ;
185-
186- let targetVolume = player . volume ;
187-
188- if ( player . dataset . volumePercentage ) {
189- const percentage = parseInt ( player . dataset . volumePercentage ) ;
190- targetVolume = ( percentage / 100 ) * player . volume ;
191- }
192-
193- const volume = targetVolume / increments ;
194- const interval = ( 1000 * time ) / increments ;
195- const expected = Date . now ( ) + interval ;
196-
197- player . volume = 0 ;
198-
199- player . dataset . fade = 'in' ;
200- player . dataset . maxVolume = targetVolume ;
201-
202- if ( Math . sign ( volume ) === 1 ) {
203- return new Promise ( ( resolve , reject ) => {
204- setTimeout ( ( ) => {
205- Play . fade ( player , volume , targetVolume , interval , expected , resolve ) ;
206- } , interval ) ;
207- } ) ;
208- } else {
209- // If the volume is set to zero or not valid, the fade effect is disabled
210- // to prevent errors
211- return Promise . resolve ( ) ;
212- }
213- }
214-
215- /**
216- * Fade the player's audio on small iterations until it reaches the maximum value for it
217- *
218- * @param {AudioPlayer } player The AudioPlayer to which the audio will fadeIn
219- * @param {number } volume The amount to increase the volume on each iteration
220- * @param {number } interval The time in milliseconds between each iteration
221- * @param {Date } expected The expected time the next iteration will happen
222- * @param {function } resolve The resolve function of the promise returned by the fadeIn function
223- *
224- * @return {void }
225- */
226- static fade ( player , volume , targetVolume , interval , expected , resolve ) {
227- const now = Date . now ( ) - expected ; // the drift (positive for overshooting)
228-
229- if ( now > interval ) {
230- // something really bad happened. Maybe the browser (tab) was inactive?
231- // possibly special handling to avoid futile "catch up" run
232- }
233-
234- if ( player . volume < targetVolume && player . dataset . fade === 'in' ) {
235- if ( player . volume + volume > targetVolume ) {
236- player . volume = targetVolume ;
237- delete player . dataset . fade ;
238- resolve ( ) ;
239- } else {
240- player . volume += volume ;
241- expected += interval ;
242- setTimeout ( ( ) => {
243- Play . fade ( player , volume , targetVolume , interval , expected , resolve ) ;
244- } , Math . max ( 0 , interval - now ) ) ; // take into account drift
245- }
246- }
247- }
248-
249179 constructor ( [ action , type , media , ...props ] ) {
250180 super ( ) ;
251181 this . type = type ;
@@ -279,7 +209,7 @@ export class Play extends Action {
279209 }
280210 }
281211
282- async createAudioPlayer ( ) {
212+ async createAudioPlayer ( paused = false ) {
283213 const audioContext = this . engine . audioContext ;
284214 const gainNode = audioContext . createGain ( ) ;
285215 gainNode . connect ( audioContext . destination ) ;
@@ -290,7 +220,46 @@ export class Play extends Action {
290220 const arrayBuffer = await response . arrayBuffer ( ) ;
291221 const audioBuffer = await audioContext . decodeAudioData ( arrayBuffer ) ;
292222
293- return new AudioPlayer ( audioContext , audioBuffer , gainNode ) ;
223+ // Parse effects from props
224+ const effects = this . parseEffects ( ) ;
225+
226+ return new AudioPlayer ( audioContext , audioBuffer , {
227+ outputNode : gainNode ,
228+ effects : effects ,
229+ paused : paused ,
230+ } ) ;
231+ }
232+
233+ parseEffects ( ) {
234+ const availableEffects = AudioPlayer . effects ( ) ;
235+
236+ const effects = { } ;
237+
238+ for ( const [ id , config ] of Object . entries ( availableEffects ) ) {
239+ const index = this . props . indexOf ( id ) ;
240+
241+ if ( index === - 1 ) {
242+ continue ;
243+ }
244+
245+ const params = { } ;
246+
247+ // Parse parameters based on the effect's parameter list
248+ for ( let i = 0 ; i < config . params . length ; i ++ ) {
249+ const paramName = config . params [ i ] ;
250+ const paramValue = this . props [ index + 1 + i ] ;
251+
252+ if ( paramValue !== undefined ) {
253+ // Try to parse as number first, fallback to string
254+ const numValue = parseFloat ( paramValue ) ;
255+ params [ paramName ] = isNaN ( numValue ) ? paramValue : numValue ;
256+ }
257+ }
258+
259+ effects [ id ] = params ;
260+ }
261+
262+ return effects ;
294263 }
295264
296265 willApply ( ) {
@@ -310,7 +279,7 @@ export class Play extends Action {
310279
311280 // Create player if it doesn't exist yet
312281 if ( this . player === null ) {
313- this . player = await this . createAudioPlayer ( ) ;
282+ this . player = await this . createAudioPlayer ( paused ) ;
314283 this . engine . mediaPlayer ( this . type , this . mediaKey , this . player ) ;
315284 }
316285
@@ -334,25 +303,26 @@ export class Play extends Action {
334303 } ;
335304
336305 if ( fadePosition > - 1 ) {
337- Play . fadeIn ( this . props [ fadePosition + 1 ] , this . player ) ;
306+ const fadeTime = this . props [ fadePosition + 1 ] ;
307+ const duration = parseFloat ( fadeTime . match ( / \d * ( \. \d * ) ? / ) [ 0 ] ) ;
308+ this . player . fadeIn ( duration ) ;
338309 }
339310
340- if ( paused === true ) {
341- // Do not start playback, but set the player as paused
342- this . player . isPaused = true ;
343- this . player . isPlaying = false ;
344- this . player . hasEnded = false ;
311+ if ( paused === true ) {
345312 return Promise . resolve ( ) ;
346- } else {
347- return this . player . play ( ) ;
348313 }
314+
315+ return this . player . play ( ) ;
316+
349317 }
350318 else if ( this . player instanceof Array ) {
351319 const promises = [ ] ;
352320 for ( const player of this . player ) {
353321 if ( player . paused && ! player . ended ) {
354322 if ( fadePosition > - 1 ) {
355- Play . fadeIn ( this . props [ fadePosition + 1 ] , player ) ;
323+ const fadeTime = this . props [ fadePosition + 1 ] ;
324+ const duration = parseFloat ( fadeTime . match ( / \d * ( \. \d * ) ? / ) [ 0 ] ) ;
325+ player . fadeIn ( duration ) ;
356326 }
357327 promises . push ( player . play ( ) ) ;
358328 }
0 commit comments