{
  "version": 3,
  "sources": ["../../../plugins/sound/sound.js", "../../../plugins/sound/play.js", "../../../plugins/sound/index.js"],
  "sourcesContent": ["/**\n * Pi.js - Sound Module (Plugin)\n * \n * Sound effects, audio files, and volume control using Web Audio API.\n * \n * @module plugins/sound/sound\n */\n\n\"use strict\";\n\nlet m_audioContext = null;\nlet m_audioPools = {};\nlet m_nextAudioId = 0;\nlet m_soundPool = {};\nlet m_nextSoundId = 0;\nlet m_volume = 0.75;\n\n\n/***************************************************************************************************\n * Internal Functions\n **************************************************************************************************/\n\n\n/**\n * Load an audio element and add to pool when ready\n * \n * @param {Object} pluginApi - Plugin API\n * @param {Object} audioItem - Audio pool item\n * @param {HTMLAudioElement} audio - Audio element\n * @param {number} retryCount - Number of retries remaining\n */\nfunction loadAudioItem( pluginApi, audioItem, audio, retryCount = 3 ) {\n\n\t// Audio ready callback\n\tfunction audioReady() {\n\t\taudioItem.pool.push( {\n\t\t\t\"audio\": audio,\n\t\t\t\"timeout\": 0,\n\t\t\t\"volume\": 1\n\t\t} );\n\t\taudio.removeEventListener( \"canplay\", audioReady );\n\t\tpluginApi.done();\n\t}\n\n\t// Audio error callback\n\tfunction audioError() {\n\t\tconst errors = [\n\t\t\t\"MEDIA_ERR_ABORTED - fetching process aborted by user\",\n\t\t\t\"MEDIA_ERR_NETWORK - error occurred when downloading\",\n\t\t\t\"MEDIA_ERR_DECODE - error occurred when decoding\",\n\t\t\t\"MEDIA_ERR_SRC_NOT_SUPPORTED - audio/video not supported\"\n\t\t];\n\n\t\tconst errorCode = audio.error.code;\n\t\tconst index = errorCode - 1;\n\n\t\tif( index >= 0 && index < errors.length ) {\n\t\t\tconsole.error( \"loadAudio: \" + errors[ index ] );\n\n\t\t\t// Retry loading if retries remain\n\t\t\tif( retryCount > 0 ) {\n\t\t\t\tsetTimeout( () => {\n\t\t\t\t\taudio.removeEventListener( \"canplay\", audioReady );\n\t\t\t\t\taudio.removeEventListener( \"error\", audioError );\n\t\t\t\t\tconst newAudio = new Audio( audio.src );\n\t\t\t\t\tloadAudioItem( pluginApi, audioItem, newAudio, retryCount - 1 );\n\t\t\t\t}, 100 );\n\t\t\t} else {\n\t\t\t\tconsole.error( \"loadAudio: Max retries exceeded for \" + audio.src );\n\t\t\t\tpluginApi.done();\n\t\t\t}\n\t\t} else {\n\t\t\tconsole.error( \"loadAudio: Unknown error - \" + errorCode );\n\t\t\tpluginApi.done();\n\t\t}\n\t}\n\n\t// Wait for audio to load (only on first attempt)\n\tif( retryCount === 3 ) {\n\t\tpluginApi.wait();\n\t}\n\n\t// Set up event listeners\n\taudio.addEventListener( \"canplay\", audioReady );\n\taudio.addEventListener( \"error\", audioError );\n}\n\n\n/***************************************************************************************************\n * Exported Functions (for play.js)\n **************************************************************************************************/\n\n\n/**\n * Stop a sound by ID (internal function for play module)\n * \n * @param {string} soundId - Sound ID to stop\n */\nexport function stopSoundById( soundId ) {\n\tif( m_soundPool[ soundId ] ) {\n\t\tm_soundPool[ soundId ].oscillator.stop( 0 );\n\t}\n}\n\n/**\n * Create a sound using Web Audio API (internal function exported for play module)\n * \n * @param {AudioContext} audioContext - Audio context\n * @param {number} frequency - Frequency in Hz\n * @param {number} volume - Volume (0-1)\n * @param {number} attackTime - Attack time in seconds\n * @param {number} sustainTime - Sustain time in seconds\n * @param {number} decayTime - Decay time in seconds\n * @param {number} stopTime - Total sound duration\n * @param {string} oType - Oscillator type\n * @param {Array} waveTables - Custom wave tables (if oType is \"custom\")\n * @param {number} delay - Delay before playing\n * @returns {string} Sound ID\n */\nexport function createSound(\n\taudioContext, frequency, volume, attackTime, sustainTime,\n\tdecayTime, stopTime, oType, waveTables, delay\n) {\n\tconst oscillator = audioContext.createOscillator();\n\tconst envelope = audioContext.createGain();\n\tconst master = audioContext.createGain();\n\n\tmaster.gain.value = m_volume;\n\toscillator.frequency.value = frequency;\n\n\t// Set oscillator type\n\tif( oType === \"custom\" ) {\n\t\tconst real = waveTables[ 0 ];\n\t\tconst imag = waveTables[ 1 ];\n\t\tconst wave = audioContext.createPeriodicWave( real, imag );\n\t\toscillator.setPeriodicWave( wave );\n\t} else {\n\t\toscillator.type = oType;\n\t}\n\n\t// Set initial envelope gain\n\tif( attackTime === 0 ) {\n\t\tenvelope.gain.value = volume;\n\t} else {\n\t\tenvelope.gain.value = 0;\n\t}\n\n\t// Connect audio nodes\n\toscillator.connect( envelope );\n\tenvelope.connect( master );\n\tmaster.connect( audioContext.destination );\n\n\tconst currentTime = audioContext.currentTime + delay;\n\n\t// Set attack envelope\n\tif( attackTime > 0 ) {\n\t\tenvelope.gain.setValueCurveAtTime(\n\t\t\tnew Float32Array( [ 0, volume ] ),\n\t\t\tcurrentTime,\n\t\t\tattackTime\n\t\t);\n\t}\n\n\t// Set sustain envelope\n\tif( sustainTime > 0 ) {\n\t\tenvelope.gain.setValueCurveAtTime(\n\t\t\tnew Float32Array( [ volume, 0.8 * volume ] ),\n\t\t\tcurrentTime + attackTime,\n\t\t\tsustainTime\n\t\t);\n\t}\n\n\t// Set decay envelope\n\tif( decayTime > 0 ) {\n\t\tenvelope.gain.setValueCurveAtTime(\n\t\t\tnew Float32Array( [ 0.8 * volume, 0.1 * volume, 0 ] ),\n\t\t\tcurrentTime + attackTime + sustainTime,\n\t\t\tdecayTime\n\t\t);\n\t}\n\n\t// Start and stop oscillator\n\toscillator.start( currentTime );\n\toscillator.stop( currentTime + stopTime );\n\n\t// Add to sound pool\n\tconst soundId = \"sound_\" + m_nextSoundId;\n\tm_nextSoundId += 1;\n\tm_soundPool[ soundId ] = {\n\t\t\"oscillator\": oscillator,\n\t\t\"master\": master,\n\t\t\"audioContext\": audioContext\n\t};\n\n\t// Auto-cleanup when done\n\tsetTimeout( () => {\n\t\tdelete m_soundPool[ soundId ];\n\t}, ( currentTime + stopTime ) * 1000 );\n\n\treturn soundId;\n}\n\n\n/***************************************************************************************************\n * Plugin Registration\n **************************************************************************************************/\n\n\n/**\n * Register sound module commands\n * \n * @param {Object} pluginApi - Plugin API\n */\nexport function registerSound( pluginApi ) {\n\tconst utils = pluginApi.utils;\n\n\t/**\n\t * Create an audio pool for playing multiple instances of the same sound file\n\t * \n\t * @param {Object} options - Command options\n\t * @param {string} options.src - Audio file URL\n\t * @param {number} options.poolSize - Number of audio instances (default: 1)\n\t * @returns {string} Audio ID for use with playAudio\n\t */\n\tpluginApi.addCommand( \"loadAudio\", loadAudio, false, [ \"src\", \"name\", \"poolSize\" ] );\n\tfunction loadAudio( options ) {\n\t\tconst src = options.src;\n\t\tlet poolSize = utils.getInt( options.poolSize, 1 );\n\t\tlet audioName = options.name;\n\n\t\t// Validate src\n\t\tif( !src || typeof src !== \"string\" ) {\n\t\t\tconst error = new TypeError( \"loadAudio: Parameter src must be a non-empty string.\" );\n\t\t\terror.code = \"INVALID_SRC\";\n\t\t\tthrow error;\n\t\t}\n\n\t\tlet audioId = \"audioPool_\" + m_nextAudioId;\n\t\tif( audioName ) {\n\n\t\t\t// Name must be unique\n\t\t\tif( m_audioPools[ audioName ] ) {\n\t\t\t\tconst error = new Error(\n\t\t\t\t\t`loadAudio: Audio pool name \"${audioName}\" is already in use.`\n\t\t\t\t);\n\t\t\t\terror.code = \"DUPLICATE_AUDIO_NAME\";\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\taudioId = audioName;\n\t\t} else {\n\t\t\tm_nextAudioId += 1;\n\t\t}\n\n\t\t// Validate poolSize\n\t\tif( poolSize < 1 ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t\"loadAudio: Parameter poolSize must be an integer greater than 0.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_POOL_SIZE\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Create the audio pool item\n\t\tconst audioItem = {\n\t\t\t\"pool\": [],\n\t\t\t\"index\": 0\n\t\t};\n\n\t\t// Create each audio instance in the pool\n\t\tfor( let i = 0; i < poolSize; i++ ) {\n\t\t\tconst audio = new Audio( src );\n\t\t\tloadAudioItem( pluginApi, audioItem, audio );\n\t\t}\n\n\t\t// Save audioId to global array\n\t\tm_audioPools[ audioId ] = audioItem;\n\n\t\treturn audioId;\n\t}\n\n\t/**\n\t * Delete an audio pool and free its resources\n\t * \n\t * @param {Object} options - Command options\n\t * @param {string} options.audioId - Audio pool ID returned from loadAudio\n\t */\n\tpluginApi.addCommand( \"removeAudio\", removeAudio, false, [ \"audioId\" ] );\n\tfunction removeAudio( options ) {\n\t\tconst audioId = options.audioId;\n\n\t\t// Validate audioId\n\t\tif( !m_audioPools[ audioId ] ) {\n\t\t\tconst error = new Error( `removeAudio: Audio pool \"${audioId}\" not found.` );\n\t\t\terror.code = \"AUDIO_POOL_NOT_FOUND\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Stop all audio and clear timeouts in the pool\n\t\tfor( let i = 0; i < m_audioPools[ audioId ].pool.length; i++ ) {\n\t\t\tconst poolItem = m_audioPools[ audioId ].pool[ i ];\n\t\t\tpoolItem.audio.pause();\n\t\t\tclearTimeout( poolItem.timeout );\n\t\t}\n\n\t\t// Delete the pool\n\t\tdelete m_audioPools[ audioId ];\n\t}\n\n\t/**\n\t * Play audio from an audio pool\n\t * \n\t * @param {Object} options - Command options\n\t * @param {string} options.audioId - Audio pool ID\n\t * @param {number} options.volume - Volume (0-1, default: 1)\n\t * @param {number} options.startTime - Start time in seconds (default: 0)\n\t * @param {number} options.duration - Play duration in seconds (default: 0 = play full)\n\t */\n\tpluginApi.addCommand(\n\t\t\"playAudio\", playAudio, false, [ \"audioId\", \"volume\", \"startTime\", \"duration\" ]\n\t);\n\tfunction playAudio( options ) {\n\t\tconst audioId = options.audioId;\n\t\tconst volume = utils.getFloat( options.volume, 1 );\n\t\tconst startTime = utils.getFloat( options.startTime, 0 );\n\t\tconst duration = utils.getFloat( options.duration, 0 );\n\n\t\t// Validate audioId\n\t\tif( !m_audioPools[ audioId ] ) {\n\t\t\tconst error = new Error( `playAudio: Audio pool \"${audioId}\" not found.` );\n\t\t\terror.code = \"AUDIO_POOL_NOT_FOUND\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Validate volume\n\t\tif( volume < 0 || volume > 1 ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t\"playAudio: Parameter volume must be a number between 0 and 1.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_VOLUME\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Validate startTime\n\t\tif( startTime < 0 ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t\"playAudio: Parameter startTime must be a number greater than or equal to 0.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_START_TIME\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Validate duration\n\t\tif( duration < 0 ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t\"playAudio: Parameter duration must be a number greater than or equal to 0.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_DURATION\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Get the audio pool\n\t\tconst audioItem = m_audioPools[ audioId ];\n\n\t\t// Make sure pool has sounds loaded\n\t\tif( audioItem.pool.length === 0 ) {\n\t\t\tconst error = new Error( \"playAudio: Audio pool has no sounds loaded.\" );\n\t\t\terror.code = \"EMPTY_POOL\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Get the next audio player from the pool\n\t\tconst poolItem = audioItem.pool[ audioItem.index ];\n\t\tconst audio = poolItem.audio;\n\n\t\t// Set volume and start time\n\t\taudio.volume = m_volume * volume;\n\t\tpoolItem.volume = volume;\n\t\taudio.currentTime = startTime;\n\n\t\t// Set duration if specified\n\t\tif( duration > 0 ) {\n\t\t\tclearTimeout( poolItem.timeout );\n\t\t\tpoolItem.timeout = setTimeout( () => {\n\t\t\t\taudio.pause();\n\t\t\t\taudio.currentTime = 0;\n\t\t\t}, duration * 1000 );\n\t\t}\n\n\t\t// Play the sound\n\t\t// Note: audio.play() returns a promise that may be rejected due to browser autoplay policies\n\t\tconst playPromise = audio.play();\n\t\tif( playPromise !== undefined ) {\n\t\t\tplayPromise.catch( ( error ) => {\n\t\t\t\tconsole.warn( \"playAudio: Audio playback failed:\", error.message );\n\t\t\t} );\n\t\t}\n\n\t\t// Move to next sound in pool (round-robin)\n\t\taudioItem.index += 1;\n\t\tif( audioItem.index >= audioItem.pool.length ) {\n\t\t\taudioItem.index = 0;\n\t\t}\n\t}\n\n\t/**\n\t * Stop audio from an audio pool or all audio pools\n\t * \n\t * @param {Object} options - Command options\n\t * @param {string} options.audioId - Audio pool ID (null to stop all pools)\n\t */\n\tpluginApi.addCommand( \"stopAudio\", stopAudio, false, [ \"audioId\" ] );\n\tfunction stopAudio( options ) {\n\t\tconst audioId = options.audioId;\n\n\t\t// If no audioId, stop all audio pools\n\t\tif( audioId == null ) {\n\t\t\tfor( const poolId in m_audioPools ) {\n\t\t\t\tfor( let j = 0; j < m_audioPools[ poolId ].pool.length; j++ ) {\n\t\t\t\t\tconst poolItem = m_audioPools[ poolId ].pool[ j ];\n\t\t\t\t\tpoolItem.audio.pause();\n\t\t\t\t\tclearTimeout( poolItem.timeout );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Validate audioId\n\t\tif( !m_audioPools[ audioId ] ) {\n\t\t\tconst error = new Error( `stopAudio: Audio pool \"${audioId}\" not found.` );\n\t\t\terror.code = \"AUDIO_POOL_NOT_FOUND\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Stop all audio and clear timeouts in the specified pool\n\t\tfor( let i = 0; i < m_audioPools[ audioId ].pool.length; i++ ) {\n\t\t\tconst poolItem = m_audioPools[ audioId ].pool[ i ];\n\t\t\tpoolItem.audio.pause();\n\t\t\tclearTimeout( poolItem.timeout );\n\t\t}\n\t}\n\n\t/**\n\t * Play a sound by frequency using Web Audio API\n\t * \n\t * @param {Object} options - Command options\n\t * @param {number} options.frequency - Frequency in Hz\n\t * @param {number} options.duration - Duration in seconds (default: 1)\n\t * @param {number} options.volume - Volume 0-1 (default: 1)\n\t * @param {string|Array} options.oType - Oscillator type or custom wave table (default: \"triangle\")\n\t * @param {number} options.delay - Delay before playing in seconds (default: 0)\n\t * @param {number} options.attack - Attack time in seconds (default: 0)\n\t * @param {number} options.decay - Decay time in seconds (default: 0.1)\n\t * @returns {string} Sound ID for use with stopSound\n\t */\n\tpluginApi.addCommand( \"sound\", sound, false, [\n\t\t\"frequency\", \"duration\", \"volume\", \"oType\", \"delay\", \"attack\", \"decay\"\n\t] );\n\tfunction sound( options ) {\n\t\tconst frequency = Math.round( utils.getFloat( options.frequency, 440 ) );\n\t\tconst duration = utils.getFloat( options.duration, 1 );\n\t\tconst volume = utils.getFloat( options.volume, 1 );\n\t\tlet oType = options.oType != null ? options.oType : \"triangle\";\n\t\tconst delay = utils.getFloat( options.delay, 0 );\n\t\tconst attack = utils.getFloat( options.attack, 0 );\n\t\tconst decay = utils.getFloat( options.decay, 0.1 );\n\n\t\t// Validate duration\n\t\tif( duration < 0 ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t\"sound: Parameter duration must be a number greater than or equal to 0.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_DURATION\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Validate volume\n\t\tif( volume < 0 || volume > 1 ) {\n\t\t\tconst error = new RangeError( \"sound: Parameter volume must be a number between 0 and 1.\" );\n\t\t\terror.code = \"INVALID_VOLUME\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Validate attack\n\t\tif( attack < 0 ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t\"sound: Parameter attack must be a number greater than or equal to 0.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_ATTACK\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Validate delay\n\t\tif( delay < 0 ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t\"sound: Parameter delay must be a number greater than or equal to 0.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_DELAY\";\n\t\t\tthrow error;\n\t\t}\n\n\t\tlet waveTables = null;\n\n\t\t// Check for custom waveform (array)\n\t\tif( Array.isArray( oType ) ) {\n\t\t\tif(\n\t\t\t\toType.length !== 2 ||\n\t\t\t\toType[ 0 ].length === 0 ||\n\t\t\t\toType[ 1 ].length === 0 ||\n\t\t\t\toType[ 0 ].length !== oType[ 1 ].length\n\t\t\t) {\n\t\t\t\tconst error = new TypeError(\n\t\t\t\t\t\"sound: Parameter oType array must contain two non-empty arrays of equal length.\"\n\t\t\t\t);\n\t\t\t\terror.code = \"INVALID_WAVE_TABLE\";\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\twaveTables = [];\n\n\t\t\t// Validate all values are numbers\n\t\t\tfor( let i = 0; i < oType.length; i++ ) {\n\t\t\t\tfor( let j = 0; j < oType[ i ].length; j++ ) {\n\t\t\t\t\tif( isNaN( oType[ i ][ j ] ) ) {\n\t\t\t\t\t\tconst error = new TypeError(\n\t\t\t\t\t\t\t\"sound: Parameter oType array must only contain numbers.\"\n\t\t\t\t\t\t);\n\t\t\t\t\t\terror.code = \"INVALID_WAVE_TABLE_VALUE\";\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twaveTables.push( new Float32Array( oType[ i ] ) );\n\t\t\t}\n\n\t\t\toType = \"custom\";\n\t\t} else if( typeof oType !== \"string\" ) {\n\t\t\tconst error = new TypeError( \"sound: Parameter oType must be a string or an array.\" );\n\t\t\terror.code = \"INVALID_OTYPE\";\n\t\t\tthrow error;\n\t\t} else {\n\n\t\t\t// Validate oType string\n\t\t\tconst validTypes = [ \"triangle\", \"sine\", \"square\", \"sawtooth\" ];\n\t\t\tif( validTypes.indexOf( oType ) === -1 ) {\n\t\t\t\tconst error = new Error(\n\t\t\t\t\t\"sound: Parameter oType must be one of: triangle, sine, square, sawtooth.\"\n\t\t\t\t);\n\t\t\t\terror.code = \"INVALID_OTYPE\";\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\t// Create audio context if needed\n\t\tif( !m_audioContext ) {\n\t\t\tconst AudioContextClass = window.AudioContext || window.webkitAudioContext;\n\t\t\tm_audioContext = new AudioContextClass();\n\t\t}\n\n\t\t// Calculate stop time\n\t\tconst stopTime = attack + duration + decay;\n\n\t\treturn createSound(\n\t\t\tm_audioContext, frequency, volume, attack, duration,\n\t\t\tdecay, stopTime, oType, waveTables, delay\n\t\t);\n\t}\n\n\t/**\n\t * Stop a playing sound or all sounds\n\t * \n\t * @param {Object} options - Command options\n\t * @param {string} options.soundId - Sound ID (null to stop all sounds)\n\t */\n\tpluginApi.addCommand( \"stopSound\", stopSound, false, [ \"soundId\" ] );\n\tfunction stopSound( options ) {\n\t\tconst soundId = options.soundId;\n\n\t\t// If no soundId, stop all sounds\n\t\tif( soundId == null ) {\n\t\t\tfor( const id in m_soundPool ) {\n\t\t\t\tm_soundPool[ id ].oscillator.stop( 0 );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Validate soundId exists\n\t\tif( !m_soundPool[ soundId ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Stop the sound\n\t\tm_soundPool[ soundId ].oscillator.stop( 0 );\n\t}\n\n\t/**\n\t * Set global volume for all sounds\n\t * \n\t * @param {Object} options - Command options\n\t * @param {number} options.volume - Volume (0-1)\n\t */\n\tpluginApi.addCommand( \"setVolume\", setVolume, false, [ \"volume\" ] );\n\tfunction setVolume( options ) {\n\t\tconst volume = utils.getFloat( options.volume, 0.75 );\n\n\t\t// Validate volume\n\t\tif( volume < 0 || volume > 1 ) {\n\t\t\tconst error = new RangeError(\n\t\t\t\t\"setVolume: Parameter volume must be a number between 0 and 1.\"\n\t\t\t);\n\t\t\terror.code = \"INVALID_VOLUME\";\n\t\t\tthrow error;\n\t\t}\n\n\t\tm_volume = volume;\n\n\t\t// Update all active sounds\n\t\tfor( const soundId in m_soundPool ) {\n\t\t\tconst sound = m_soundPool[ soundId ];\n\t\t\tif( volume === 0 ) {\n\n\t\t\t\t// Use exponential ramp to near-zero, then set to zero\n\t\t\t\tsound.master.gain.exponentialRampToValueAtTime(\n\t\t\t\t\t0.01, sound.audioContext.currentTime + 0.1\n\t\t\t\t);\n\t\t\t\tsound.master.gain.setValueAtTime(\n\t\t\t\t\t0, sound.audioContext.currentTime + 0.11\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tsound.master.gain.exponentialRampToValueAtTime(\n\t\t\t\t\tvolume, sound.audioContext.currentTime + 0.1\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Update all audio pools\n\t\tfor( const poolId in m_audioPools ) {\n\t\t\tfor( let j = 0; j < m_audioPools[ poolId ].pool.length; j++ ) {\n\t\t\t\tconst poolItem = m_audioPools[ poolId ].pool[ j ];\n\t\t\t\tpoolItem.audio.volume = m_volume * poolItem.volume;\n\t\t\t}\n\t\t}\n\t}\n}\n\n", "/**\n * Pi.js - Play Module (Plugin)\n * \n * BASIC-style music notation playback (inspired by QBasic PLAY command).\n * \n * @module plugins/sound/play\n */\n\n\"use strict\";\n\nimport { createSound, stopSoundById } from \"./sound.js\";\n\nconst m_tracks = {};\nconst m_allTracks = [];\nlet m_lastTrackId = 0;\nlet m_playData = [];\nlet m_utils = null;\n\n// Note frequency data (in Hz) by note name and octave\nconst m_notesData = {\n\t\"A\": [ 27.50, 55.00, 110, 220, 440, 880, 1760, 3520, 7040, 14080 ],\n\t\"A#\": [ 29.14, 58.27, 116.541, 233.082, 466.164, 932.328, 1864.655, 3729.31, 7458.62, 14917.24 ],\n\t\"B\": [ 30.87, 61.74, 123.471, 246.942, 493.883, 987.767, 1975.533, 3951.066, 7902.132, 15804.264 ],\n\t\"C\": [ 16.35, 32.70, 65.41, 130.813, 261.626, 523.251, 1046.502, 2093.005, 4186.009, 8372.018 ],\n\t\"C#\": [ 17.32, 34.65, 69.296, 138.591, 277.183, 554.365, 1108.731, 2217.461, 4434.922, 8869.844 ],\n\t\"D\": [ 18.35, 36.71, 73.416, 146.832, 293.665, 587.33, 1174.659, 2349.318, 4698.636, 9397.272 ],\n\t\"D#\": [ 19.45, 38.89, 77.782, 155.563, 311.127, 622.254, 1244.508, 2489.016, 4978.032, 9956.064 ],\n\t\"E\": [ 20.60, 41.20, 82.407, 164.814, 329.628, 659.255, 1318.51, 2637.021, 5274.042, 10548.084 ],\n\t\"F\": [ 21.83, 43.65, 87.307, 174.614, 349.228, 698.456, 1396.913, 2793.826, 5587.652, 11175.304 ],\n\t\"F#\": [ 23.12, 46.25, 92.499, 184.997, 369.994, 739.989, 1479.978, 2959.955, 5919.91, 11839.82 ],\n\t\"G\": [ 24.50, 49.00, 97.999, 195.998, 391.995, 783.991, 1567.982, 3135.964, 6271.928, 12543.856 ],\n\t\"G#\": [ 25.96, 51.91, 103.826, 207.652, 415.305, 830.609, 1661.219, 3322.438, 6644.876, 13289.752 ]\n};\n\n// All notes by number (for N command)\nconst m_allNotes = [\n\t0, 16.35, 17.32, 18.35, 19.45, 20.60, 21.83, 23.12, 24.50, 25.96, 27.50, 29.14, 30.87, 32.70,\n\t34.65, 36.71, 38.89, 41.20, 43.65, 46.25, 49.00, 51.91, 55.00, 58.27, 61.74, 65.406, 69.296,\n\t73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813,\n\t138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942,\n\t261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164,\n\t493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880,\n\t932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982,\n\t1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.021, 2793.826,\n\t2959.955, 3135.964, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032,\n\t5274.042, 5587.652, 5919.91, 6271.928, 6644.876, 7040, 7458.62, 7902.132, 8372.018, 8869.844,\n\t9397.272, 9956.064, 10548.084, 11175.304, 11839.82, 13289.752, 14080, 14917.24, 15804.264\n];\n\n\n/***************************************************************************************************\n * Internal Functions\n **************************************************************************************************/\n\n\n/**\n * Create a track from a play string\n * \n * @param {string} playString - Music notation string\n * @returns {number} First track ID\n */\nfunction createTrack( playString ) {\n\tlet firstTrackId;\n\n\t// Convert to uppercase and remove spaces\n\tplayString = playString.split( /\\s+/ ).join( \"\" ).toUpperCase();\n\n\t// Find and extract wavetables\n\tconst waveTables = [];\n\tlet start = 0;\n\twhile( start > -1 ) {\n\t\tstart = playString.indexOf( \"[[\" );\n\t\tif( start > -1 ) {\n\t\t\tconst end = playString.indexOf( \"]]\", start );\n\t\t\twaveTables.push( playString.substring( start, end + 2 ) );\n\t\t\tconst i = waveTables.length - 1;\n\t\t\tplayString = playString.replace( waveTables[ i ], \"W\" + i );\n\t\t}\n\t}\n\n\t// Convert wavetables to arrays\n\tfor( let i = 0; i < waveTables.length; i++ ) {\n\t\twaveTables[ i ] = JSON.parse( waveTables[ i ] );\n\n\t\t// Validate wavetable\n\t\tif(\n\t\t\twaveTables[ i ].length !== 2 ||\n\t\t\twaveTables[ i ][ 0 ].length !== waveTables[ i ][ 1 ].length\n\t\t) {\n\t\t\tconsole.error(\n\t\t\t\t\"play: Wavetables must have 2 arrays of same length. Defaulting to triangle wave.\"\n\t\t\t);\n\t\t\twaveTables[ i ] = \"triangle\";\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Validate all values are numbers\n\t\tfor( let j = 0; j < 2; j++ ) {\n\t\t\tfor( let k = 0; k < waveTables[ i ][ j ].length; k++ ) {\n\t\t\t\twaveTables[ i ][ j ][ k ] = parseFloat( waveTables[ i ][ j ][ k ] );\n\t\t\t\tif( isNaN( waveTables[ i ][ j ][ k ] ) ) {\n\t\t\t\t\twaveTables[ i ][ j ][ k ] = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\twaveTables[ i ][ j ] = new Float32Array( waveTables[ i ][ j ] );\n\t\t}\n\t}\n\n\t// Split tracks by commas\n\tconst trackStrings = playString.split( \",\" );\n\tconst trackIds = [];\n\n\t// Regular expression for parsing play commands\n\tconst regString =\n\t\t\"(?=WS|WQ|WW|WT|W\\\\d[\\\\d]?|V\\\\d|Q\\\\d|O\\\\d|\\\\<|\\\\>|N\\\\d\\\\d?|\" +\n\t\t\"L\\\\d\\\\d?|MS|MN|ML|MU\\\\d|MU\\\\-\\\\d|MK\\\\d[\\\\d]?[\\\\d]?|\" +\n\t\t\"MZ\\\\d[\\\\d]?[\\\\d]?|MX\\\\d[\\\\d]?[\\\\d]?|MY\\\\d[\\\\d]?[\\\\d]?|\" +\n\t\t\"MW|P[\\\\d]?|T\\\\d|\" +\n\t\t\"[[A|B|C|D|E|F|G][\\\\d]?[\\\\+|\\\\-|\\\\#|\\\\.\\\\.?]?)\";\n\tconst reg = new RegExp( regString );\n\n\tlet lastNote;\n\n\tfor( let i = 0; i < trackStrings.length; i++ ) {\n\n\t\t// Replace complex keywords with short symbols\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /SINE/g, \"WS\" );\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /SQUARE/g, \"WQ\" );\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /SAWTOOTH/g, \"WW\" );\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /TRIANGLE/g, \"WT\" );\n\n\t\t// Replace conflicting symbols\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /MD/g, \"MZ\" );\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /MA/g, \"MY\" );\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /MT/g, \"MX\" );\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /MO/g, \"MU\" );\n\n\t\t// Remove deprecated symbols\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /MB/g, \"\" );\n\t\ttrackStrings[ i ] = trackStrings[ i ].replace( /MF/g, \"\" );\n\n\t\t// Create track\n\t\tconst trackId = m_lastTrackId;\n\t\tif( firstTrackId === undefined ) {\n\t\t\tfirstTrackId = trackId;\n\t\t}\n\t\tm_lastTrackId += 1;\n\n\t\tm_tracks[ trackId ] = {\n\t\t\t\"id\": trackId,\n\t\t\t\"notes\": [],\n\t\t\t\"noteId\": 0,\n\t\t\t\"decayRate\": 0.20,\n\t\t\t\"attackRate\": 0.15,\n\t\t\t\"sustainRate\": 0.65,\n\t\t\t\"fullNote\": false,\n\t\t\t\"extra\": 1,\n\t\t\t\"space\": \"normal\",\n\t\t\t\"interval\": 0,\n\t\t\t\"time\": 0,\n\t\t\t\"simultaneousPlay\": i > 0,\n\t\t\t\"tempo\": 60 / 120,\n\t\t\t\"noteLength\": 0.25,\n\t\t\t\"pace\": 0.875,\n\t\t\t\"octave\": 4,\n\t\t\t\"octaveExtra\": 0,\n\t\t\t\"volume\": 1,\n\t\t\t\"trackIds\": trackIds,\n\t\t\t\"type\": \"triangle\",\n\t\t\t\"waveTables\": waveTables,\n\t\t\t\"sounds\": []\n\t\t};\n\t\tm_allTracks.push( trackId );\n\t\ttrackIds.push( trackId );\n\n\t\t// Mark previous note for simultaneous play\n\t\tif( i > 0 ) {\n\t\t\tlastNote.simultaneousPlay = trackId;\n\t\t}\n\n\t\t// Split track into command parts\n\t\tconst trackParts = trackStrings[ i ].split( reg );\n\n\t\tfor( let j = 0; j < trackParts.length; j++ ) {\n\t\t\tconst index = trackParts[ j ].indexOf( \"-\" );\n\n\t\t\t// Split minus symbol (only if not a music note)\n\t\t\tif( index > -1 && \"ABCDEFG\".indexOf( trackParts[ j ][ 0 ] ) === -1 ) {\n\t\t\t\tconst noteData = {\n\t\t\t\t\t\"name\": trackParts[ j ].substring( 0, index ),\n\t\t\t\t\t\"val\": trackParts[ j ].substring( index )\n\t\t\t\t};\n\t\t\t\tm_tracks[ trackId ].notes.push( noteData );\n\t\t\t\tlastNote = noteData;\n\t\t\t} else {\n\t\t\t\tconst noteParts = trackParts[ j ].split( /(\\d+)/ );\n\t\t\t\tconst noteData = {\n\t\t\t\t\t\"name\": noteParts[ 0 ]\n\t\t\t\t};\n\t\t\t\tif( noteParts.length > 1 ) {\n\t\t\t\t\tnoteData.val = noteParts[ 1 ];\n\t\t\t\t}\n\t\t\t\tm_tracks[ trackId ].notes.push( noteData );\n\t\t\t\tlastNote = noteData;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn firstTrackId;\n}\n\n/**\n * Play a track recursively\n * \n * @param {number} trackId - Track ID to play\n */\nfunction playTrack( trackId ) {\n\tconst track = m_tracks[ trackId ];\n\tif( track.noteId >= track.notes.length ) {\n\t\treturn;\n\t}\n\n\tconst cmd = track.notes[ track.noteId ];\n\tlet frequency = 0;\n\tlet val;\n\tlet wait = false;\n\ttrack.extra = 0;\n\n\tswitch( cmd.name.charAt( 0 ) ) {\n\t\tcase \"A\":\n\t\tcase \"B\":\n\t\tcase \"C\":\n\t\tcase \"D\":\n\t\tcase \"E\":\n\t\tcase \"F\":\n\t\tcase \"G\":\n\t\t\tfrequency = processNote( track, cmd );\n\t\t\twait = true;\n\t\t\tbreak;\n\t\tcase \"N\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\t\t\t\tval = m_utils.getInt( cmd.val, 0 );\n\t\t\t\tif( val >= 0 && val < m_allNotes.length ) {\n\t\t\t\t\tfrequency = m_allNotes[ val ];\n\t\t\t\t}\n\t\t\t\twait = true;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"O\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\t\t\t\tval = m_utils.getInt( cmd.val, 4 );\n\t\t\t\tif( val >= 0 && val < m_notesData[ \"A\" ].length ) {\n\t\t\t\t\ttrack.octave = val;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \">\":\n\t\t\ttrack.octave += 1;\n\t\t\tif( track.octave >= m_notesData[ \"A\" ].length ) {\n\t\t\t\ttrack.octave = m_notesData[ \"A\" ].length - 1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"<\":\n\t\t\ttrack.octave -= 1;\n\t\t\tif( track.octave < 0 ) {\n\t\t\t\ttrack.octave = 0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"L\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\t\t\t\tval = m_utils.getInt( cmd.val, 1 );\n\t\t\t\ttrack.noteLength = getNoteLength( val );\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"T\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\t\t\t\tval = m_utils.getInt( cmd.val, 120 );\n\t\t\t\tif( val >= 32 && val < 256 ) {\n\t\t\t\t\ttrack.tempo = 60 / val;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"M\":\n\t\t\tprocessMusic( track, cmd );\n\t\t\tbreak;\n\t\tcase \"P\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\t\t\t\twait = true;\n\t\t\t\tval = m_utils.getInt( cmd.val, 1 );\n\t\t\t\ttrack.extra = getNoteLength( val );\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"V\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\t\t\t\tval = m_utils.getInt( cmd.val, 50 );\n\t\t\t\tif( val < 0 ) {\n\t\t\t\t\tval = 0;\n\t\t\t\t} else if( val > 100 ) {\n\t\t\t\t\tval = 100;\n\t\t\t\t}\n\t\t\t\ttrack.volume = val / 100;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"W\":\n\t\t\tprocessWaveform( track, cmd );\n\t\t\tbreak;\n\t}\n\n\t// Calculate interval for next note\n\tif( track.extra > 0 ) {\n\t\ttrack.interval = track.tempo * track.extra * track.pace * 4;\n\t} else {\n\t\ttrack.interval = track.tempo * track.noteLength * track.pace * 4;\n\t}\n\n\t// Play simultaneous track\n\tif( m_tracks[ cmd.simultaneousPlay ] ) {\n\t\tm_tracks[ cmd.simultaneousPlay ].time = track.time;\n\t\tcopyTrackData( m_tracks[ cmd.simultaneousPlay ].id, trackId );\n\t\tplayTrack( m_tracks[ cmd.simultaneousPlay ].id );\n\t}\n\n\t// Play note if frequency > 0\n\tif( frequency > 0 ) {\n\t\tplayNote( track, frequency );\n\t}\n\n\t// Move to next instruction\n\ttrack.noteId += 1;\n\n\t// Continue playing track\n\tif( track.noteId < track.notes.length ) {\n\t\tif( wait ) {\n\t\t\ttrack.time += track.interval;\n\t\t}\n\t\tplayTrack( trackId );\n\t} else {\n\n\t\t// Schedule track removal after completion\n\t\tsetTimeout( () => {\n\t\t\tif( m_tracks[ trackId ] ) {\n\t\t\t\tremoveTrack( trackId );\n\t\t\t}\n\t\t}, ( track.time + track.interval ) * 1000 );\n\t}\n}\n\n/**\n * Process a note command (A-G)\n * \n * @param {Object} track - Track object\n * @param {Object} cmd - Command object\n * @returns {number} Frequency in Hz\n */\nfunction processNote( track, cmd ) {\n\tlet note = cmd.name;\n\n\t// Convert + to sharp\n\tnote = note.replace( /\\+/g, \"#\" );\n\n\t// Convert flats to equivalent sharps\n\tnote = note.replace( \"C-\", \"B\" );\n\tnote = note.replace( \"D-\", \"C#\" );\n\tnote = note.replace( \"E-\", \"D#\" );\n\tnote = note.replace( \"G-\", \"F#\" );\n\tnote = note.replace( \"A-\", \"G#\" );\n\tnote = note.replace( \"B-\", \"A#\" );\n\n\t// Convert enharmonic equivalents\n\tnote = note.replace( \"E#\", \"F\" );\n\tnote = note.replace( \"B#\", \"C\" );\n\n\t// Check for extra note length (dotted notes)\n\tif( cmd.name.indexOf( \"..\" ) > 0 ) {\n\t\ttrack.extra = 1.75 * track.noteLength;\n\t} else if( cmd.name.indexOf( \".\" ) > 0 ) {\n\t\ttrack.extra = 1.5 * track.noteLength;\n\t}\n\n\t// Remove dots from note\n\tnote = note.replace( /\\./g, \"\" );\n\n\t// Get note frequency\n\tlet frequency = 0;\n\tif( m_notesData[ note ] ) {\n\t\tconst octave = track.octave + track.octaveExtra;\n\t\tif( octave < m_notesData[ note ].length ) {\n\t\t\tfrequency = m_notesData[ note ][ octave ];\n\t\t}\n\t}\n\n\t// Check if note length included\n\tif( !isNaN( Number( cmd.val ) ) ) {\n\t\tconst val = m_utils.getInt( cmd.val, 1 );\n\t\ttrack.extra = getNoteLength( val );\n\t}\n\n\treturn frequency;\n}\n\n/**\n * Process music style commands (M...)\n * \n * @param {Object} track - Track object\n * @param {Object} cmd - Command object\n */\nfunction processMusic( track, cmd ) {\n\tswitch( cmd.name ) {\n\t\tcase \"MS\":\n\n\t\t\t// Staccato\n\t\t\ttrack.pace = 0.75;\n\t\t\tbreak;\n\t\tcase \"MN\":\n\n\t\t\t// Normal\n\t\t\ttrack.pace = 0.875;\n\t\t\tbreak;\n\t\tcase \"ML\":\n\n\t\t\t// Legato\n\t\t\ttrack.pace = 1;\n\t\t\tbreak;\n\t\tcase \"MU\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\n\t\t\t\t// Modify octave\n\t\t\t\tconst val = m_utils.getInt( cmd.val, 0 );\n\t\t\t\ttrack.octaveExtra = val;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"MY\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\n\t\t\t\t// Modify attack rate\n\t\t\t\tconst val = m_utils.getInt( cmd.val, 25 );\n\t\t\t\ttrack.attackRate = val / 100;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"MX\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\n\t\t\t\t// Modify sustain rate\n\t\t\t\tconst val = m_utils.getInt( cmd.val, 25 );\n\t\t\t\ttrack.sustainRate = val / 100;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"MZ\":\n\t\t\tif( !isNaN( Number( cmd.val ) ) ) {\n\n\t\t\t\t// Modify decay rate\n\t\t\t\tconst val = m_utils.getInt( cmd.val, 25 );\n\t\t\t\ttrack.decayRate = val / 100;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"MW\":\n\n\t\t\t// Toggle full note\n\t\t\ttrack.fullNote = !track.fullNote;\n\t\t\tbreak;\n\t}\n}\n\n/**\n * Process waveform commands (W...)\n * \n * @param {Object} track - Track object\n * @param {Object} cmd - Command object\n */\nfunction processWaveform( track, cmd ) {\n\tif( cmd.name === \"WS\" ) {\n\t\ttrack.type = \"sine\";\n\t} else if( cmd.name === \"WQ\" ) {\n\t\ttrack.type = \"square\";\n\t} else if( cmd.name === \"WW\" ) {\n\t\ttrack.type = \"sawtooth\";\n\t} else if( cmd.name === \"WT\" ) {\n\t\ttrack.type = \"triangle\";\n\t} else if( !isNaN( Number( cmd.val ) ) ) {\n\n\t\t// Custom wavetable\n\t\tconst val = m_utils.getInt( cmd.val, -1 );\n\t\tif( track.waveTables[ val ] ) {\n\t\t\ttrack.type = val;\n\t\t}\n\t}\n}\n\n/**\n * Play a single note\n * \n * @param {Object} track - Track object\n * @param {number} frequency - Frequency in Hz\n */\nfunction playNote( track, frequency ) {\n\tconst volume = track.volume;\n\tconst attackTime = track.interval * track.attackRate;\n\tconst sustainTime = track.interval * track.sustainRate;\n\tconst decayTime = track.interval * track.decayRate;\n\n\tlet stopTime;\n\tif( track.fullNote && attackTime + sustainTime + decayTime > track.interval ) {\n\t\tstopTime = track.interval;\n\t} else {\n\t\tstopTime = attackTime + sustainTime + decayTime;\n\t}\n\n\tlet oType;\n\tlet waveTables = null;\n\tif( typeof track.type === \"string\" ) {\n\t\toType = track.type;\n\t} else {\n\t\twaveTables = track.waveTables[ track.type ];\n\t\tif( Array.isArray( waveTables ) ) {\n\t\t\toType = \"custom\";\n\t\t} else {\n\t\t\toType = waveTables;\n\t\t\twaveTables = null;\n\t\t}\n\t}\n\n\tconst soundData = {\n\t\t\"frequency\": frequency,\n\t\t\"volume\": volume,\n\t\t\"attackTime\": attackTime,\n\t\t\"sustainTime\": sustainTime,\n\t\t\"decayTime\": decayTime,\n\t\t\"stopTime\": stopTime,\n\t\t\"oType\": oType,\n\t\t\"waveTables\": waveTables,\n\t\t\"time\": track.time,\n\t\t\"track\": track\n\t};\n\n\tm_playData.push( soundData );\n}\n\n/**\n * Copy track data from source to destination\n * \n * @param {number} trackDestId - Destination track ID\n * @param {number} trackSourceId - Source track ID\n */\nfunction copyTrackData( trackDestId, trackSourceId ) {\n\tconst trackDest = m_tracks[ trackDestId ];\n\tconst trackSource = m_tracks[ trackSourceId ];\n\n\ttrackDest.decayRate = trackSource.decayRate;\n\ttrackDest.attackRate = trackSource.attackRate;\n\ttrackDest.sustainRate = trackSource.sustainRate;\n\ttrackDest.fullNote = trackSource.fullNote;\n\ttrackDest.extra = trackSource.extra;\n\ttrackDest.space = trackSource.space;\n\ttrackDest.interval = trackSource.interval;\n\ttrackDest.tempo = trackSource.tempo;\n\ttrackDest.noteLength = trackSource.noteLength;\n\ttrackDest.pace = trackSource.pace;\n\ttrackDest.octave = trackSource.octave;\n\ttrackDest.octaveExtra = trackSource.octaveExtra;\n\ttrackDest.volume = trackSource.volume;\n\ttrackDest.type = trackSource.type;\n}\n\n/**\n * Remove a track and all its sub-tracks\n * \n * @param {number} trackId - Track ID to remove\n */\nfunction removeTrack( trackId ) {\n\n\t// Delete all sub-tracks as well as main track\n\tconst trackIds = m_tracks[ trackId ].trackIds;\n\tfor( let i = trackIds.length; i >= 0; i-- ) {\n\t\tdelete m_tracks[ trackIds[ i ] ];\n\t}\n\n\t// Remove track from all tracks array\n\tfor( let i = m_allTracks.length - 1; i >= 0; i-- ) {\n\t\tif( !m_tracks[ m_allTracks[ i ] ] ) {\n\t\t\tm_allTracks.splice( i, 1 );\n\t\t}\n\t}\n}\n\n/**\n * Get note length from note value\n * \n * @param {number} val - Note value (1-64)\n * @returns {number} Note length\n */\nfunction getNoteLength( val ) {\n\tif( val >= 1 && val < 65 ) {\n\t\treturn 1 / val;\n\t}\n\treturn 0.875;\n}\n\n\n/***************************************************************************************************\n * Plugin Registration\n **************************************************************************************************/\n\n\n/**\n * Register play module commands\n * \n * @param {Object} pluginApi - Plugin API\n */\nexport function registerPlay( pluginApi ) {\n\tm_utils = pluginApi.utils;\n\n\t/**\n\t * Play music using BASIC-style notation\n\t * \n\t * Format: \"NOTE[length][.][#|+|-] ...\"\n\t * - Notes: A-G (can include sharps # or +, flats -)\n\t * - Length: 1-64 (1=whole, 4=quarter, etc.)\n\t * - Dot modifiers: . (1.5x), .. (1.75x)\n\t * - Multiple tracks: separated by commas\n\t * \n\t * Commands:\n\t * - O[n]: Set octave (0-9)\n\t * - L[n]: Set default note length\n\t * - T[n]: Set tempo (32-255 BPM)\n\t * - V[n]: Set volume (0-100)\n\t * - P[n]: Pause for note length\n\t * - N[n]: Play note by number (0-127)\n\t * - W[type]: Set waveform (SINE, SQUARE, SAWTOOTH, TRIANGLE)\n\t * - MS: Staccato (75% of note length)\n\t * - MN: Normal (87.5% of note length)\n\t * - ML: Legato (100% of note length)\n\t * - MW: Toggle full note mode\n\t * - MO[n]: Modify octave offset\n\t * - MA[n]: Modify attack rate (0-100)\n\t * - MT[n]: Modify sustain rate (0-100)\n\t * - MD[n]: Modify decay rate (0-100)\n\t * - <: Decrease octave\n\t * - >: Increase octave\n\t * \n\t * @param {Object} options - Command options\n\t * @param {string} options.playString - Music notation string\n\t */\n\tpluginApi.addCommand( \"play\", play, false, [ \"playString\" ] );\n\tfunction play( options ) {\n\t\tlet playString = options.playString;\n\n\t\t// Validate playString\n\t\tif( typeof playString !== \"string\" ) {\n\t\t\tconst error = new TypeError( \"play: Parameter playString must be a string.\" );\n\t\t\terror.code = \"INVALID_PLAY_STRING\";\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Create track from play string\n\t\tconst trackId = createTrack( playString );\n\n\t\t// Generate all play data\n\t\tm_playData = [];\n\t\tplayTrack( trackId );\n\n\t\t// Sort by time\n\t\tm_playData.sort( ( a, b ) => a.time - b.time );\n\n\t\t// Create audio context\n\t\tconst AudioContextClass = window.AudioContext || window.webkitAudioContext;\n\t\tconst audioContext = new AudioContextClass();\n\n\t\t// Create all sounds\n\t\tfor( let i = 0; i < m_playData.length; i++ ) {\n\t\t\tconst playData = m_playData[ i ];\n\t\t\tplayData.track.sounds.push(\n\t\t\t\tcreateSound(\n\t\t\t\t\taudioContext, playData.frequency, playData.volume, playData.attackTime,\n\t\t\t\t\tplayData.sustainTime, playData.decayTime, playData.stopTime, playData.oType,\n\t\t\t\t\tplayData.waveTables, playData.time\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Stop playing music\n\t * \n\t * @param {Object} options - Command options\n\t * @param {number} options.trackId - Track ID to stop (null to stop all tracks)\n\t */\n\tpluginApi.addCommand( \"stopPlay\", stopPlay, false, [ \"trackId\" ] );\n\tfunction stopPlay( options ) {\n\t\tconst trackId = options.trackId;\n\n\t\t// Stop all tracks\n\t\tif( trackId === null ) {\n\t\t\tfor( let i = 0; i < m_allTracks.length; i++ ) {\n\t\t\t\tconst track = m_tracks[ m_allTracks[ i ] ];\n\t\t\t\tif( track ) {\n\t\t\t\t\tfor( let j = 0; j < track.sounds.length; j++ ) {\n\t\t\t\t\t\tstopSoundById( track.sounds[ j ] );\n\t\t\t\t\t}\n\t\t\t\t\tdelete m_tracks[ m_allTracks[ i ] ];\n\t\t\t\t}\n\t\t\t}\n\t\t\tm_allTracks.length = 0;\n\t\t\treturn;\n\t\t}\n\n\t\t// Stop specific track\n\t\tif( m_tracks[ trackId ] ) {\n\t\t\tconst track = m_tracks[ trackId ];\n\t\t\tfor( let j = 0; j < track.sounds.length; j++ ) {\n\t\t\t\tstopSoundById( track.sounds[ j ] );\n\t\t\t}\n\t\t\tremoveTrack( trackId );\n\t\t}\n\t}\n}\n\n", "/**\n * Pi.js - Play-Sound Plugin\n * \n * Music playback and sound effects using Web Audio API.\n * Combines play.js (BASIC-style music notation) and sound.js (sound effects).\n * \n * @module plugins/sound\n * @version 1.0.0\n */\n\n\"use strict\";\n\nimport { registerSound } from \"./sound.js\";\nimport { registerPlay } from \"./play.js\";\n\n\n/***************************************************************************************************\n * Plugin Initialization\n **************************************************************************************************/\n\n\n/**\n * Play-sound plugin initialization\n * \n * @param {Object} pluginApi - Plugin API provided by Pi.js\n */\nexport default function playSoundPlugin( pluginApi ) {\n\n\t// Register sound module commands\n\tregisterSound( pluginApi );\n\n\t// Register play module commands\n\tregisterPlay( pluginApi );\n}\n\n\n// Auto-register in IIFE mode (when loaded via <script> tag)\nif( typeof window !== \"undefined\" && window.pi ) {\n\twindow.pi.registerPlugin( {\n\t\t\"name\": \"sound\",\n\t\t\"version\": \"1.0.0\",\n\t\t\"description\": \"Music playback and sound effects using Web Audio API\",\n\t\t\"init\": playSoundPlugin\n\t} );\n}\n\n"],
  "mappings": "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",
  "names": ["sound"]
}
