There are 1424 possible deltas given 89 steps and 16 codes. We can
quickly compute those and reuse them to save time.
Knowing the exact size of the waveform we can re-author the
decompression loop to take advantage of that. We can place the block
header decompression first in the outer while loop and then place an
inner loop with the 2 samples per block decompression unwrapped. The
first sample reads from the stream and the second uses the other 4 bits.
The number of samples in the ADPCM can be known once the data chunk is
extracted and the block size is known. From there the audio buffer can
be created and its channel data passed to the decompress method. A lot
of time is saved by writing to the channel data directly instead of
writing to one array, copying that to another array, and then finally
copying to the channel data. A surprising amount of time is saved by
using one getChannelData call instead of calling to store each sample.
The extracted children can refer to their parent typed array views and
buffer to keep from needing to make memory copies that take a lot of
time to create and memory to use. As well some time can be saved by
using the same Uint8Array for reading Uint8 values and strings.
Firefox at this time cannot smoothly schedule audio parameter changes
to happen immediately. Immediately scheduled changes clip when firefox
tries to catch up. Smoothly fading out a sound immediately instead of
clipping the end of the sound, in firefox at this time clips the sound
between where the fade out starts and where firefox catches up and
finishes the scheduled fade.
- EffectChain knows of audioEngine so it can create Effects
- EffectChain connects to the target specified by .connect(target)
- EffectChain can connect to other Effects or EffectChains
- EffectChain can clone itself and connect to the original's target
- Add EffectChain.update to mirror Effects API
- Use deepest setting first in setEffectsFromTarget
Debounce when the sound starts to keep from playing many copies of the
same sound layered on itself. Use AudioEngine's currentTime in seconds
plus some value in milliseconds to make sure the sound has a chance to
start before starting a second playback.
Self-resolving promise removes itself once it resolves. While it is on
a player the player may consider itself to not yet have the time to
actually start sound playback. While playback has not started, the
player can shortcut out of starting playback.
- Add GreenPlayer as SoundPlayer replacement
- Standalone playback separate from an AudioPlayer
- Each GreenPlayer has their own VolumeEffect for fading out
- play() while already isPlaying fades out the last copy
- stop() fades the sound out
- stopImmediate() hard stops the sound