-
Notifications
You must be signed in to change notification settings - Fork 0
/
beepbox_synth.min.js.map
1 lines (1 loc) · 708 KB
/
beepbox_synth.min.js.map
1
{"version":3,"sources":["../synth/SynthConfig.ts","../synth/FFT.ts","../synth/Deque.ts","../synth/filtering.ts","../synth/synth.ts"],"names":["Config","centerWave","wave","sum","i","length","average","performIntegral","push","Float32Array","cumulative","temp","getPulseWidthRatio","pulseWidth","Math","pow","pulseWidthRange","pulseWidthStepPower","getDrumWave","index","inverseRealFourierTransform","scaleElementsByFactor","chipNoises","samples","chipNoiseLength","drumBuffer","newBuffer","random","Error","drawNoiseSpectrum","sqrt","waveLength","lowOctave","highOctave","lowPower","highPower","overallSlope","lowIndex","highIndex","min","retroWave","combinedAmplitude","lerped","log2","amplitude","radians","PI","cos","sin","getArpeggioPitchIndex","pitchCount","rhythm","arpeggio","arpeggioPattern","rhythms","arpeggioPatterns","toNameMap","array","dictionary","value","name","result","effectsIncludeTransition","effects","effectsIncludeChord","effectsIncludePitchShift","effectsIncludeDetune","effectsIncludeVibrato","effectsIncludeNoteFilter","effectsIncludeDistortion","effectsIncludeBitcrusher","effectsIncludePanning","effectsIncludeChorus","effectsIncludeEcho","effectsIncludeReverb","factor","countBits","n","isPowerOf2","round","log","fullArrayLength","totalPasses","pass","subStride","midSubStride","stride","radiansIncrement","cosIncrement","sinIncrement","oscillatorMultiplier","startIndex","startIndexA","midIndexA","startIndexB","midIndexB","stopIndex","realStartA","imagStartB","c","s","cPrev","sPrev","indexA0","indexA1","indexB0","indexB1","real0","real1","imag0","imag1","tempA","tempB","cTemp","sTemp","index1","index2","index3","imag2","imag3","bitCount","finalShift","j","reverseIndexBits","scales","realName","flags","keys","isWhiteKey","basePitch","blackKeyNameParents","tempoMin","tempoMax","echoDelayRange","echoDelayStepTicks","echoSustainRange","echoShelfHz","echoShelfGain","reverbShelfHz","reverbShelfGain","reverbRange","reverbDelayBufferSize","reverbDelayBufferMask","beatsPerBarMin","beatsPerBarMax","barCountMin","barCountMax","instrumentCountMin","layeredInstrumentCountMax","patternInstrumentCountMax","partsPerBeat","ticksPerPart","stepsPerBeat","ticksPerArpeggio","roundUpThresholds","instrumentTypeNames","instrumentTypeHasSpecialInterval","chipBaseExpression","fmBaseExpression","noiseBaseExpression","spectrumBaseExpression","drumsetBaseExpression","harmonicsBaseExpression","pwmBaseExpression","supersawBaseExpression","pickedStringBaseExpression","distortionBaseVolume","bitcrusherBaseVolume","chipWaves","expression","pitchFilterMult","isSoft","filterFreqStep","filterFreqRange","filterFreqReferenceSetting","filterFreqReferenceHz","filterFreqMaxHz","filterFreqMinHz","filterGainRange","filterGainCenter","filterGainStep","filterMaxPoints","filterTypeNames","fadeInRange","fadeOutTicks","fadeOutNeutral","drumsetFadeOutTicks","transitions","isSeamless","continues","slides","slideTicks","includeAdjacentPatterns","vibratos","periodsSeconds","delayTicks","unisons","voices","spread","offset","sign","effectNames","effectOrder","noteSizeMax","volumeRange","volumeLogScale","panCenter","panMax","panDelaySecondsMax","chorusRange","chorusPeriodSeconds","chorusDelayRange","chorusDelayOffsets","chorusPhaseOffsets","chorusMaxDelay","concat","reduce","x","y","max","chords","customInterval","arpeggiates","strumParts","singleTone","maxChordSize","operatorCount","maxPitchOrOperatorCount","algorithms","carrierCount","associatedCarrier","modulatedBy","operatorCarrierInterval","operatorAmplitudeMax","operatorFrequencies","mult","hzOffset","amplitudeSign","envelopes","type","speed","feedbacks","indices","spectrumNoiseLength","spectrumBasePitch","spectrumControlPoints","spectrumControlPointsPerOctave","spectrumControlPointBits","spectrumMax","harmonicsControlPoints","harmonicsRendered","harmonicsRenderedForPickedString","harmonicsControlPointBits","harmonicsMax","harmonicsWavelength","supersawVoiceCount","supersawDynamismMax","supersawSpreadMax","supersawShapeMax","pitchChannelCountMin","pitchChannelCountMax","noiseChannelCountMin","noiseChannelCountMax","noiseInterval","pitchesPerOctave","drumCount","pitchOctaves","maxPitch","maximumTonesPerChannel","justIntonationSemitones","map","pitchShiftRange","pitchShiftCenter","detuneCenter","detuneMax","sineWaveLength","sineWaveMask","sineWave","generateSineWave","pickedStringDispersionCenterFreq","pickedStringDispersionFreqScale","pickedStringDispersionFreqMult","pickedStringShelfHz","stringSustainRange","stringDecayRate","enableAcousticSustain","sustainTypeNames","distortionRange","bitcrusherFreqRange","bitcrusherOctaveStep","bitcrusherQuantizationRange","maxEnvelopeCount","defaultAutomationRange","instrumentAutomationTargets","computeIndex","displayName","interleave","isFilter","maxCount","effect","compatibleInstruments","Deque","constructor","this","_capacity","_buffer","undefined","_mask","_offset","_count","pushFront","element","_expandCapacity","pushBack","popFront","popBack","peakFront","peakBack","count","set","get","remove","oldBuffer","Array","size","FilterCoefficients","a","b","order","linearGain0thOrder","linearGain","lowPass1stOrderButterworth","cornerRadiansPerSample","g","tan","a0","lowPass1stOrderSimplified","highPass1stOrderButterworth","highShelf1stOrder","shelfLinearGain","sqrtGain","allPass1stOrderInvertPhaseAbove","allPass1stOrderFractionalDelay","delay","lowPass2ndOrderButterworth","peakLinearGain","alpha","lowPass2ndOrderSimplified","filterResonance","feedback","highPass2ndOrderButterworth","highShelf2ndOrder","slope","A","Aplus","Aminus","sqrtA2Alpha","peak2ndOrder","bandWidthScale","bandWidth","FrequencyResponse","real","imag","denom","analyze","filter","radiansPerSample","analyzeComplex","realZ1","imagZ1","realNum","imagNum","realDenom","imagDenom","realZ","imagZ","imagTemp","magnitude","angle","atan2","DynamicBiquadFilter","a1","a2","b0","b1","b2","a1Delta","a2Delta","b0Delta","b1Delta","b2Delta","output1","output2","useMultiplicativeInputCoefficients","resetOutput","loadCoefficientsWithGradient","start","end","deltaRate","warpInfinityToNyquist","atan","epsilon","clamp","val","validateRange","base64IntToCharCode","base64CharCodeToInt","BitFieldReader","source","_bits","_readIndex","charCodeAt","read","readLongTail","minValue","minBits","numBits","readPartDuration","readLegacyPartDuration","readPinCount","readPitchInterval","BitFieldWriter","_index","clear","write","writeLongTail","writePartDuration","writePinCount","writePitchInterval","other","encodeBase64","buffer","lengthBase64","ceil","makeNotePin","interval","time","Note","pitch","fadeout","pitches","pins","continuesLastPattern","pickMainInterval","longestFlatIntervalDuration","mainInterval","pinIndex","pinA","pinB","duration","loudestSize","pin","clone","newNote","getEndPinIndex","part","endPinIndex","Pattern","notes","instruments","cloneNotes","note","reset","toJsonObject","song","noteArray","pointArray","tick","pitchBend","volume","noteObject","points","patternObject","patternInstruments","fromJsonObject","channel","importedPartsPerBeat","isNoiseChannel","isArray","instrumentCount","getMaxInstrumentsPerPatternForChannel","maxNoteCount","beatsPerBar","tickClock","k","indexOf","noteClock","startInterval","pointObject","lowestPitch","highestPitch","splice","Operator","frequency","SpectrumWave","spectrum","hash","isHarmonic","markCustomWaveDirty","hashMult","Synth","fittingPowerOfTwo","point","SpectrumWaveState","_hash","getCustomWave","settings","lowestOctave","pitchTweak","controlPointToOctave","floor","value1","value2","octave1","octave2","HarmonicsWave","harmonics","HarmonicsWaveState","instrumentType","_generatedForType","combinedControlPointAmplitude","harmonicIndex","harmonicFreq","controlValue","normalizedValue","FilterControlPoint","freq","gain","freqSetting","gainSetting","getHz","getHzFromSettingValue","static","hz","getSettingValueFromHz","getLinearGain","peakMult","power","neutral","interpolatedPower","toCoefficients","sampleRate","freqMult","getVolumeCompensationMult","octave","gainPow","freqRelativeTo8khz","warpedFreq","warpedOctave","distanceFromCenter","freqLoudness","FilterSettings","controlPoints","controlPointCount","addPoint","controlPoint","filterArray","cutoffHz","filterObject","getRoundedSettingValueFromHz","getRoundedSettingValueFromLinearGain","convertLegacySettings","legacyCutoffSetting","legacyResonanceSetting","legacyEnv","legacyFilterMaxRadians","asin","legacyFilterMax","resonant","firstOrder","cutoffAtMax","legacyFilterCutoffRange","envDecays","standardSampleRate","legacyHz","legacyRadians","extraOctaves","targetRadians","curvedHz","finalHz","finalRadians","legacyFilter","response","legacyFilterGainAtNewRadians","logGain","convertedGain","intendedGain","invertedGain","curvedRadians","legacyFilterGain","EnvelopeSettings","target","envelope","envelopeObject","Instrument","preset","chipWave","chipNoise","eqFilter","noteFilter","envelopeCount","fadeIn","fadeOut","transition","pitchShift","detune","vibrato","unison","chord","pan","supersawDynamism","supersawSpread","supersawShape","stringSustain","stringSustainType","distortion","bitcrusherFreq","bitcrusherQuantization","chorus","reverb","echoSustain","echoDelay","algorithm","feedbackType","feedbackAmplitude","operators","harmonicsWave","drumsetEnvelopes","drumsetSpectrumWaves","spectrumWave","setTypeAndReset","legacySettings","filterCutoff","legacyFilterEnv","filterEnvelope","legacyPulseEnv","pulseEnvelope","legacyOperatorEnvelopes","operatorEnvelopes","legacyFeedbackEnv","feedbackEnvelope","noCarriersControlledByNoteSize","allCarriersControlledByNoteSize","noteSizeControlsSomethingElse","addEnvelope","instrumentObject","getChord","detuneToCents","fadeInSettingToSeconds","fadeOutSettingToTicks","getDrumsetEnvelope","operatorArray","operator","legacyGlobalReverb","legacyEffectsNames","transitionProperty","binary","fadeInSeconds","seamless","sudden","hard","smooth","soft","slide","secondsToFadeInSetting","ticksToFadeOutSetting","chordProperty","legacyChordNames","harmony","unisonProperty","legacyChorusNames","union","fifths","octaves","centsToDetune","vibratoProperty","legacyVibratoNames","isNaN","findIndex","legacyEnvelopeNames","custom","steady","getEnvelope","drum","legacyWaveNames","triangle","square","sawtooth","spiky","plateau","operatorObject","filterCutoffMaxHz","filterCutoffRange","filterResonanceRange","LN2","legacyToCutoff","legacyToEnvelope","filterNames","oldFilterNames","envelopeArray","tempEnvelope","supportsEnvelopeTarget","envelopeSettings","automationTarget","clearInvalidEnvelopeTargets","envelopeIndex","getTransition","getFadeInSeconds","getFadeOutTicks","Channel","patterns","bars","muted","Song","string","channels","fromBase64String","initToDefault","getChannelCount","pitchChannelCount","noiseChannelCount","getMaxInstrumentsPerChannel","layeredInstruments","getMaxInstrumentsPerPattern","channelIndex","getChannelIsNoise","andResetChannels","scale","key","loopStart","loopLength","tempo","barCount","patternsPerChannel","pattern","instrument","bar","toBase64String","bits","_latestVersion","harmonicsBits","o","spectrumBits","neededBits","shapeBits","bitsPerNoteSize","getNeededBits","maxInstrumentsPerPattern","neededInstrumentCountBits","neededInstrumentIndexBits","octaveOffset","lastPitch","recentPitches","recentShapes","curPart","shapePart","startPitch","currentPitch","pitchBends","nextPitch","shapeString","String","fromCharCode","apply","shapeIndex","unshift","pop","allPitches","pitchIndex","pitchIter","stringLength","digits","prototype","maxApplyArgs","slice","legacyIndex","compressed","charIndex","JSON","parse","substring","version","_oldestVersion","beforeThree","beforeFour","beforeFive","beforeSix","beforeSeven","beforeEight","beforeNine","legacySettingsCache","command","instrumentChannelIterator","instrumentIndexIterator","channelCount","instrumentsPerChannel","instrumentIndex","instrumentsFlagBits","presetValue","legacyWaves","originalControlPointCount","_envelopeFromLegacyIndex","sustainValue","legacyEffects","legacyEnvelopes","originalValue","byteCount","subStringLength","bitStringLength","bitStringLengthLength","newPattern","newNotes","noteCount","useOldShape","shape","pinCount","initialSize","bendCount","pinObj","intervalIter","shift","enableIntro","loopCount","enableOutro","channelArray","instrumentArray","patternArray","sequenceArray","l","channelObject","sequence","format","_format","introBars","loopBars","ticksPerBeat","beatsPerMinute","jsonObject","oldScaleNames","enigma","scaleName","letter","charAt","toUpperCase","symbol","toLowerCase","C","D","E","F","G","B","maxInstruments","maxPatterns","maxBars","newPitchChannels","newNoiseChannels","instrumentObjects","getPattern","patternIndex","getBeatsPerMinute","maxValue","clz32","PickedString","delayLine","allPassG","allPassGDelta","sustainFilterA1","sustainFilterA1Delta","sustainFilterA2","sustainFilterA2Delta","sustainFilterB0","sustainFilterB0Delta","sustainFilterB1","sustainFilterB1Delta","sustainFilterB2","sustainFilterB2Delta","delayIndex","allPassSample","allPassPrevInput","sustainFilterSample","sustainFilterPrevOutput2","sustainFilterPrevInput1","sustainFilterPrevInput2","fractionalDelaySample","prevDelayLength","delayResetOffset","update","synth","instrumentState","tone","stringIndex","roundedSamplesPerTick","stringDecayStart","stringDecayEnd","sustainType","allPassCenter","samplesPerSecond","phaseDeltaStart","phaseDeltas","phaseDeltaScale","phaseDeltaScales","phaseDeltaEnd","radiansPerSampleStart","radiansPerSampleEnd","centerHarmonicStart","centerHarmonicEnd","allPassRadiansStart","allPassRadiansEnd","shelfRadians","decayCurveStart","decayCurveEnd","register","registerShelfCenter","registerLowpassCenter","decayRateStart","decayRateEnd","expressionDecayStart","expressionDecayEnd","tempFilterStartCoefficients","tempFrequencyResponse","allPassGStart","allPassPhaseDelayStart","tempFilterEndCoefficients","allPassGEnd","allPassPhaseDelayEnd","brightnessType","shelfGainStart","shelfGainEnd","cornerHardness","lowpass1stOrderCutoffRadiansStart","lowpass1stOrderCutoffRadiansEnd","lowpass2ndOrderCutoffRadiansStart","lowpass2ndOrderCutoffRadiansEnd","lowpass2ndOrderGainStart","lowpass2ndOrderGainEnd","sustainFilterA1Start","sustainFilterA2Start","sustainFilterB0Start","sustainFilterB1Start","sustainFilterB2Start","sustainFilterPhaseDelayStart","sustainFilterA1End","sustainFilterA2End","sustainFilterB0End","sustainFilterB1End","sustainFilterB2End","sustainFilterPhaseDelayEnd","periodLengthStart","periodLengthEnd","minBufferLength","delayLength","delayLengthEnd","delayLengthDelta","pitchChanged","abs","reinitializeImpulse","likelyMaximumLength","frequencyFromPitch","newDelayLine","oldDelayBufferMask","startCopyingFromIndex","delayBufferMask","startImpulseFrom","startZerosFrom","stopZerosAt","impulseWave","impulseWaveLength","impulsePhaseDelta","fadeDuration","startImpulseFromSample","stopImpulseAt","stopImpulseAtSample","impulsePhase","prevWaveIntegral","impulsePhaseInt","nextWaveIntegral","phaseRatio","sample","combinedFade","curvedFade","EnvelopeComputer","noteSecondsStart","noteSecondsEnd","noteTicksStart","noteTicksEnd","noteSizeStart","noteSizeEnd","prevNoteSize","nextNoteSize","_noteSizeFinal","prevNoteSecondsStart","prevNoteSecondsEnd","prevNoteTicksStart","prevNoteTicksEnd","_prevNoteSizeFinal","prevSlideStart","prevSlideEnd","nextSlideStart","nextSlideEnd","prevSlideRatioStart","prevSlideRatioEnd","nextSlideRatioStart","nextSlideRatioEnd","envelopeStarts","envelopeEnds","_modifiedEnvelopeIndices","_modifiedEnvelopeCount","lowpassCutoffDecayVolumeCompensation","computeEnvelopes","currentPart","tickTimeStart","secondsPerTick","atNoteStart","forceContinueAtStart","tickTimeEnd","beatsPerTick","beatTimeStart","beatTimeEnd","passedEndOfNote","startPin","endPin","startPinTick","endPinTick","ratioStart","ratioEnd","noteStartTick","noteStartPart","noteEndTick","noteEndPart","maximumSlideTicks","prevNote","nextNote","forceContinueAtEnd","usedNoteSize","targetIndex","envelopeStart","computeEnvelope","envelopeEnd","filterSettings","getLowpassCutoffDecayVolumeCompensation","clearEnvelopes","beats","noteSize","noteSizeToVolumeMult","attack","Tone","fill","chordSize","drumsetPitch","prevNotePitchIndex","nextNotePitchIndex","freshlyAllocated","isOnLastTick","ticksSinceReleased","liveInputSamplesHeld","lastInterval","noiseSample","phases","expressionDelta","operatorExpressions","operatorExpressionDeltas","prevPitchExpressions","prevVibrato","prevStringDecay","pulseWidthDelta","supersawDynamismDelta","supersawUnisonDetunes","supersawShapeDelta","supersawDelayLength","supersawDelayLengthDelta","supersawDelayLine","supersawDelayIndex","supersawPrevPhaseDelta","pickedStrings","noteFilters","noteFilterCount","initialNoteFilterInput1","initialNoteFilterInput2","specialIntervalExpressionMult","feedbackOutputs","feedbackMult","feedbackDelta","envelopeComputer","pickedString","InstrumentState","awake","computed","tonesAddedInThisTick","flushingDelayLines","deactivateAfterThisTick","attentuationProgress","flushedSamples","activeTones","releasedTones","liveInputTones","synthesizer","noisePitchFilterMult","eqFilterVolume","eqFilterVolumeDelta","mixVolume","mixVolumeDelta","delayInputMult","delayInputMultDelta","distortionDelta","distortionDrive","distortionDriveDelta","distortionFractionalInput1","distortionFractionalInput2","distortionFractionalInput3","distortionPrevInput","distortionNextOutput","bitcrusherPrevInput","bitcrusherCurrentOutput","bitcrusherPhase","bitcrusherPhaseDelta","bitcrusherPhaseDeltaScale","bitcrusherScale","bitcrusherScaleScale","bitcrusherFoldLevel","bitcrusherFoldLevelScale","eqFilters","eqFilterCount","initialEqFilterInput1","initialEqFilterInput2","panningDelayLine","panningDelayPos","panningVolumeL","panningVolumeR","panningVolumeDeltaL","panningVolumeDeltaR","panningOffsetL","panningOffsetR","panningOffsetDeltaL","panningOffsetDeltaR","chorusDelayLineL","chorusDelayLineR","chorusDelayLineDirty","chorusDelayPos","chorusPhase","chorusVoiceMult","chorusVoiceMultDelta","chorusCombinedMult","chorusCombinedMultDelta","echoDelayLineL","echoDelayLineR","echoDelayLineDirty","echoDelayPos","echoDelayOffsetStart","echoDelayOffsetEnd","echoDelayOffsetRatio","echoDelayOffsetRatioDelta","echoMult","echoMultDelta","echoShelfA1","echoShelfB0","echoShelfB1","echoShelfSampleL","echoShelfSampleR","echoShelfPrevInputL","echoShelfPrevInputR","reverbDelayLine","reverbDelayLineDirty","reverbDelayPos","reverbMult","reverbMultDelta","reverbShelfA1","reverbShelfB0","reverbShelfB1","reverbShelfSample0","reverbShelfSample1","reverbShelfSample2","reverbShelfSample3","reverbShelfPrevInput0","reverbShelfPrevInput1","reverbShelfPrevInput2","reverbShelfPrevInput3","allocateNecessaryBuffers","samplesPerTick","panningDelayBufferSize","chorusDelayBufferSize","safeEchoDelaySteps","safeEchoDelayBufferSize","newDelayLineL","newDelayLineR","oldMask","deactivate","resetAllEffects","compute","getInstrumentSynthFunction","updateWaves","usesDistortion","usesBitcrusher","usesPanning","usesChorus","usesEcho","usesReverb","distortionSliderStart","distortionSliderEnd","distortionStart","distortionEnd","distortionDriveStart","distortionDriveEnd","freqSettingStart","freqSettingEnd","quantizationSettingStart","quantizationSettingEnd","freqStart","freqEnd","scaleStart","scaleEnd","foldLevelStart","foldLevelEnd","eqFilterSettings","mainInstrumentVolume","instrumentVolumeToVolumeMult","mixVolumeEnd","eqFilterVolumeStart","eqFilterVolumeEnd","delayInputMultStart","delayInputMultEnd","panStart","panEnd","volumeStartL","volumeStartR","volumeEndL","volumeEndR","maxDelaySamples","delayStart","delayEnd","delayStartL","delayStartR","delayEndL","delayEndR","chorusStart","chorusEnd","chorusCombinedMultStart","chorusCombinedMultEnd","maxEchoMult","averageEchoDelaySeconds","echoMultStart","echoMultEnd","echoDelayOffset","maxReverbMult","reverbStart","reverbEnd","totalDelaySamples","attenuationThreshold","halfLifeMult","delayDuration","attenuationPerSecond","averageMult","averageReverbDelaySeconds","progressInTick","progressAtEndOfTick","_drumsetIndexToSpectrumOctave","getDrumsetWave","drumsetIndexReferenceDelta","ChannelState","singleSeamlessInstrument","preferLowerLatency","anticipatePoorPerformance","liveInputDuration","liveInputStarted","liveInputPitches","liveInputChannel","liveInputInstruments","loopRepeatCount","enableMetronome","countInMetronome","playheadInternal","prevBar","nextBar","beat","isAtStartOfTick","tickSampleCountdown","isPlayingSong","isRecording","liveInputEndTime","browserAutomaticallyClearsAudioBuffer","tempDrumSetControlPoint","tonePool","tempMatchedPitchTones","startedMetronome","metronomeSamplesRemaining","metronomeAmplitude","metronomePrevAmplitude","metronomeFilter","limit","tempMonoInstrumentSampleBuffer","audioCtx","scriptNode","audioProcessCallback","audioProcessingEvent","outputBuffer","outputDataL","getChannelData","outputDataR","performance","now","deactivateAudio","synthesize","computeDelayBufferSizes","setSong","syncSongState","channelState","warmUpSynthesizer","getSamplesPerTick","playing","recording","playhead","remainder","getSamplesPerBar","getTicksIntoBar","getCurrentPart","getTotalBars","panningDelayBufferMask","chorusDelayBufferMask","activateAudio","bufferSize","latencyHint","window","AudioContext","webkitAudioContext","createScriptProcessor","createJavaScriptNode","onaudioprocess","channelCountMode","channelInterpretation","connect","destination","resume","disconnect","close","maintainLiveInput","play","pause","startRecording","snapToStart","snapToBar","goToBar","resetEffects","freeAllTones","jumpIntoLoop","oldBar","goToNextBar","goToPrevBar","getNextBar","outputBufferLength","playSong","ended","limitDecay","limitRise","bufferIndex","samplesLeftInBuffer","samplesLeftInTick","runLength","runEnd","determineCurrentActiveTones","determineLiveInputTones","tonesPlayedInThisInstrument","freeReleasedTone","shouldFadeOutFast","computeTone","playTone","effectsSynth","midBeat","periods","samplesPerPeriod","tempAmplitude","sampleL","sampleR","limitedVolume","Number","isFinite","freeTone","newTone","releaseTone","toneIndex","toneList","toneCount","moveTonesIntoOrderedTempMatchedList","clearTempMatchedPitchTones","adjacentPatternHasCompatibleInstrumentTransition","otherPattern","otherNote","forceContinue","otherInstrument","otherTransition","firstNote","secondNote","firstNoteInterval","notePitches","currentTick","newInstrumentIndex","sourceInstrumentState","destInstrumentState","prevNoteForThisInstrument","nextNoteForThisInstrument","partsPerBar","tonesInPrevNote","tonesInNextNote","prevPattern","lastNote","patternForcesContinueAtStart","adjacentNotesHaveMatchingPitches","chordOfCompatibleInstrument","nextPattern","nextPatternForcesContinueAtStart","oldTone","strumOffsetParts","prevNoteForThisTone","noteForThisTone","nextNoteForThisTone","released","chordExpression","computeChordExpression","intervalScale","secondsPerPart","sampleTime","beatsPerPart","ticksIntoBar","partTimeStart","partTimeEnd","specialIntervalMult","toneIsOnLastTick","intervalStart","intervalEnd","fadeExpressionStart","fadeExpressionEnd","chordExpressionStart","chordExpressionEnd","expressionReferencePitch","baseExpression","pitchDamping","startTicksSinceReleased","endTicksSinceReleased","pinStart","pinEnd","noteTicksPassedTickStart","noteTicksPassedTickEnd","pinRatioStart","pinRatioEnd","noteLengthTicks","intervalDiff","chordSizeDiff","vibratoAmplitude","vibratoStart","getLFOAmplitude","ticksUntilVibratoStart","vibratoEnd","ticksUntilVibratoEnd","noteFilterExpression","noteFilterSettings","noteAllFreqsEnvelopeStart","noteAllFreqsEnvelopeEnd","noteFreqEnvelopeStart","noteFreqEnvelopeEnd","notePeakEnvelopeStart","notePeakEnvelopeEnd","drumsetFilterEnvelope","drumsetFilterEnvelopeStart","drumsetFilterEnvelopeEnd","sineExpressionBoost","totalCarrierExpression","arpeggioInterval","associatedCarrierIndex","pitchStart","pitchEnd","baseFreqStart","baseFreqEnd","targetFreqStart","targetFreqEnd","freqEnvelopeStart","freqEnvelopeEnd","amplitudeCurve","operatorAmplitudeCurve","amplitudeMult","expressionStart","expressionEnd","pitchExpressionStart","pitchExpressionEnd","feedbackStart","feedbackEnd","freqEndRatio","basePhaseDeltaScale","intervalOffset","endPitch","settingsExpressionMult","basePulseWidth","pulseWidthStart","pulseWidthEnd","startFreq","voiceCountExpression","unisonEnvelopeStart","unisonEnvelopeEnd","unisonAStart","unisonAEnd","unisonBStart","unisonBEnd","supersawExpressionStart","supersawExpressionEnd","minFirstVoiceAmplitude","baseDynamismSlider","curvedDynamismStart","curvedDynamismEnd","firstVoiceAmplitudeStart","firstVoiceAmplitudeEnd","dynamismStart","dynamismEnd","initializeSupersaw","accumulator","normalizedPhase","zeroCrossingPhase","prevDrop","nextDrop","phaseDelta","distanceToZeroCrossing","swappedIndex","baseSpreadSlider","averageSpreadSlider","curvedSpread","baseShape","shapeStart","shapeEnd","delayLengthStart","pulseExpressionRatio","sustainEnvelopeStart","sustainEnvelopeEnd","secondsIntoBar","vibratoPeriodSeconds","fingerprint","fmSynthFunctionCache","synthSource","line","fmSourceTemplate","outputs","replace","join","operatorLine","operatorSourceTemplate","modulators","modulatorNumber","feedbackIndices","wrappedFmSynth","Function","chipSynth","harmonicsSynth","pulseWidthSynth","supersawSynth","pickedStringSynth","noiseSynth","spectrumSynth","drumsetSynth","data","unisonSign","phaseDeltaA","phaseDeltaB","phaseDeltaScaleA","phaseDeltaScaleB","phaseA","phaseB","filters","filterCount","initialFilterInput1","initialFilterInput2","applyFilters","phaseAInt","phaseBInt","indexA","indexB","phaseRatioA","phaseRatioB","prevWaveIntegralA","prevWaveIntegralB","sampleIndex","nextWaveIntegralA","nextWaveIntegralB","waveA","waveB","inputSample","output","sanitizeFilters","voiceCount","pickedStringFunction","pickedStringFunctionCache","pickedStringSource","sampleList","voice","lines","usesEqFilter","signature","effectsFunction","effectsFunctionCache","effectsSource","usesDelays","phase","sawPhaseA","sawPhaseB","pulseWave","t","dynamism","dynamismDelta","unisonDetunes","shapeDelta","supersawSample","detunedPhaseDelta","delaySampleTime","lowerIndex","upperIndex","delayRatio","prevDelaySample","phaseMask","pitchRelativefilter","findRandomZeroCrossing","phaseInt","waveSample","referenceDelta","indexPrev","wavePrev","attemptsRemaining","indexNext","waveNext","innerIndexNext","innerWaveNext","instrumentVolume","volumeMult","setting","seconds","ticks","lower","upper","cents","beatsPerSecond","partsPerSecond","tickPerSecond","lastIndex","mask","input1","input2","split"],"mappings":"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","sourcesContent":["/*!\nCopyright (c) 2012-2022 John Nesky and contributing authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of \nthis software and associated documentation files (the \"Software\"), to deal in \nthe Software without restriction, including without limitation the rights to \nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies \nof the Software, and to permit persons to whom the Software is furnished to do \nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all \ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE \nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE \nSOFTWARE.\n*/\n\nexport interface Dictionary<T> {\n\t[K: string]: T;\n}\n\nexport interface DictionaryArray<T> extends ReadonlyArray<T> {\n\tdictionary: Dictionary<T>;\n}\n\nexport const enum FilterType {\n\tlowPass,\n\thighPass,\n\tpeak,\n\tlength,\n}\n\nexport const enum SustainType {\n\tbright,\n\tacoustic,\n\tlength,\n}\n\nexport const enum EnvelopeType {\n\tnoteSize,\n\tnone,\n\tpunch,\n\tflare,\n\ttwang,\n\tswell,\n\ttremolo,\n\ttremolo2,\n\tdecay,\n}\n\nexport const enum InstrumentType {\n\tchip,\n\tfm,\n\tnoise,\n\tspectrum,\n\tdrumset,\n\tharmonics,\n\tpwm,\n\tpickedString,\n\tsupersaw,\n\tlength,\n}\n\nexport const enum EffectType {\n\treverb,\n\tchorus,\n\tpanning,\n\tdistortion,\n\tbitcrusher,\n\tnoteFilter,\n\techo,\n\tpitchShift,\n\tdetune,\n\tvibrato,\n\ttransition,\n\tchord,\n\t// If you add more, you'll also have to extend the bitfield used in Base64 which currently uses two six-bit characters.\n\tlength,\n}\n\nexport const enum EnvelopeComputeIndex {\n\tnoteVolume,\n\tnoteFilterAllFreqs,\n\tpulseWidth,\n\tstringSustain,\n\tunison,\n\toperatorFrequency0, operatorFrequency1, operatorFrequency2, operatorFrequency3,\n\toperatorAmplitude0, operatorAmplitude1, operatorAmplitude2, operatorAmplitude3,\n\tfeedbackAmplitude,\n\tpitchShift,\n\tdetune,\n\tvibratoDepth,\n\tnoteFilterFreq0, noteFilterFreq1, noteFilterFreq2, noteFilterFreq3, noteFilterFreq4, noteFilterFreq5, noteFilterFreq6, noteFilterFreq7,\n\tnoteFilterGain0, noteFilterGain1, noteFilterGain2, noteFilterGain3, noteFilterGain4, noteFilterGain5, noteFilterGain6, noteFilterGain7,\n\tsupersawDynamism,\n\tsupersawSpread,\n\tsupersawShape,\n\tlength,\n}\n\n/*\nexport const enum InstrumentAutomationIndex {\n\tmixVolume,\n\teqFilterAllFreqs,\n\teqFilterFreq0, eqFilterFreq1, eqFilterFreq2, eqFilterFreq3, eqFilterFreq4, eqFilterFreq5, eqFilterFreq6, eqFilterFreq7,\n\teqFilterGain0, eqFilterGain1, eqFilterGain2, eqFilterGain3, eqFilterGain4, eqFilterGain5, eqFilterGain6, eqFilterGain7,\n\tdistortion,\n\tbitcrusherQuantization,\n\tbitcrusherFrequency,\n\tpanning,\n\tchorus,\n\techoSustain,\n\t//echoDelay, // Wait until tick settings can be computed once for multiple run lengths.\n\treverb,\n\tlength,\n}\n*/\n\nexport interface BeepBoxOption {\n\treadonly index: number;\n\treadonly name: string;\n}\n\nexport interface Scale extends BeepBoxOption {\n\treadonly flags: ReadonlyArray<boolean>;\n\treadonly realName: string;\n}\n\nexport interface Key extends BeepBoxOption {\n\treadonly isWhiteKey: boolean;\n\treadonly basePitch: number;\n}\n\nexport interface Rhythm extends BeepBoxOption {\n\treadonly stepsPerBeat: number;\n\treadonly ticksPerArpeggio: number;\n\treadonly arpeggioPatterns: ReadonlyArray<ReadonlyArray<number>>;\n\treadonly roundUpThresholds: number[] | null;\n}\n\nexport interface ChipWave extends BeepBoxOption {\n\treadonly expression: number;\n\treadonly samples: Float32Array;\n}\n\nexport interface ChipNoise extends BeepBoxOption {\n\treadonly expression: number;\n\treadonly basePitch: number;\n\treadonly pitchFilterMult: number;\n\treadonly isSoft: boolean;\n\tsamples: Float32Array | null;\n}\n\nexport interface Transition extends BeepBoxOption {\n\treadonly isSeamless: boolean;\n\treadonly continues: boolean;\n\treadonly slides: boolean;\n\treadonly slideTicks: number;\n\treadonly includeAdjacentPatterns: boolean;\n}\n\nexport interface Vibrato extends BeepBoxOption {\n\treadonly amplitude: number;\n\treadonly periodsSeconds: ReadonlyArray<number>;\n\treadonly delayTicks: number;\n}\n\nexport interface Unison extends BeepBoxOption {\n\treadonly voices: number;\n\treadonly spread: number;\n\treadonly offset: number;\n\treadonly expression: number;\n\treadonly sign: number;\n}\n\nexport interface Chord extends BeepBoxOption {\n\treadonly customInterval: boolean;\n\treadonly arpeggiates: boolean;\n\treadonly strumParts: number;\n\treadonly singleTone: boolean;\n}\n\nexport interface Algorithm extends BeepBoxOption {\n\treadonly carrierCount: number;\n\treadonly associatedCarrier: ReadonlyArray<number>;\n\treadonly modulatedBy: ReadonlyArray<ReadonlyArray<number>>;\n}\n\nexport interface OperatorFrequency extends BeepBoxOption {\n\treadonly mult: number;\n\treadonly hzOffset: number;\n\treadonly amplitudeSign: number;\n}\n\nexport interface Feedback extends BeepBoxOption {\n\treadonly indices: ReadonlyArray<ReadonlyArray<number>>;\n}\n\nexport interface Envelope extends BeepBoxOption {\n\treadonly type: EnvelopeType;\n\treadonly speed: number;\n}\n\nexport interface AutomationTarget extends BeepBoxOption {\n\treadonly computeIndex: EnvelopeComputeIndex /*| InstrumentAutomationIndex*/ | null;\n\treadonly displayName: string;\n\t//readonly perNote: boolean; // Whether to compute envelopes on a per-note basis.\n\treadonly interleave: boolean; // Whether to interleave this target with the next one in the menu (e.g. filter frequency and gain).\n\treadonly isFilter: boolean; // Filters are special because the maxCount depends on other instrument settings.\n\t//readonly range: number | null; // set if automation is allowed.\n\treadonly maxCount: number;\n\treadonly effect: EffectType | null;\n\treadonly compatibleInstruments: InstrumentType[] | null;\n}\n\nexport class Config {\n\tpublic static readonly scales: DictionaryArray<Scale> = toNameMap([\n\t\t{name: \"easy :)\", realName: \"pentatonic major\", flags: [true, false, true, false, true, false, false, true, false, true, false, false]},\n\t\t{name: \"easy :(\", realName: \"pentatonic minor\", flags: [true, false, false, true, false, true, false, true, false, false, true, false]},\n\t\t{name: \"island :)\", realName: \"ryukyu\", flags: [true, false, false, false, true, true, false, true, false, false, false, true]},\n\t\t{name: \"island :(\", realName: \"pelog selisir\", flags: [true, true, false, true, false, false, false, true, true, false, false, false]},\n\t\t{name: \"blues :)\", realName: \"blues major\", flags: [true, false, true, true, true, false, false, true, false, true, false, false]},\n\t\t{name: \"blues :(\", realName: \"blues\", flags: [true, false, false, true, false, true, true, true, false, false, true, false]},\n\t\t{name: \"normal :)\", realName: \"ionian\", flags: [true, false, true, false, true, true, false, true, false, true, false, true]},\n\t\t{name: \"normal :(\", realName: \"aeolian\", flags: [true, false, true, true, false, true, false, true, true, false, true, false]},\n\t\t{name: \"double harmonic :)\", realName: \"double harmonic major\", flags: [true, true, false, false, true, true, false, true, true, false, false, true]},\n\t\t{name: \"double harmonic :(\", realName: \"double harmonic minor\", flags: [true, false, true, true, false, false, true, true, true, false, false, true]},\n\t\t{name: \"strange\", realName: \"whole tone\", flags: [true, false, true, false, true, false, true, false, true, false, true, false]},\n\t\t{name: \"expert\", realName: \"chromatic\", flags: [true, true, true, true, true, true, true, true, true, true, true, true]},\n\t]);\n\tpublic static readonly keys: DictionaryArray<Key> = toNameMap([\n\t\t{name: \"C\", isWhiteKey: true, basePitch: 12}, // C0 has index 12 on the MIDI scale. C7 is 96, and C9 is 120. C10 is barely in the audible range.\n\t\t{name: \"C♯\", isWhiteKey: false, basePitch: 13},\n\t\t{name: \"D\", isWhiteKey: true, basePitch: 14},\n\t\t{name: \"D♯\", isWhiteKey: false, basePitch: 15},\n\t\t{name: \"E\", isWhiteKey: true, basePitch: 16},\n\t\t{name: \"F\", isWhiteKey: true, basePitch: 17},\n\t\t{name: \"F♯\", isWhiteKey: false, basePitch: 18},\n\t\t{name: \"G\", isWhiteKey: true, basePitch: 19},\n\t\t{name: \"G♯\", isWhiteKey: false, basePitch: 20},\n\t\t{name: \"A\", isWhiteKey: true, basePitch: 21},\n\t\t{name: \"A♯\", isWhiteKey: false, basePitch: 22},\n\t\t{name: \"B\", isWhiteKey: true, basePitch: 23},\n\t]);\n\tpublic static readonly blackKeyNameParents: ReadonlyArray<number> = [-1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1];\n\tpublic static readonly tempoMin: number = 30;\n\tpublic static readonly tempoMax: number = 300;\n\tpublic static readonly echoDelayRange: number = 24;\n\tpublic static readonly echoDelayStepTicks: number = 4;\n\tpublic static readonly echoSustainRange: number = 8;\n\tpublic static readonly echoShelfHz: number = 4000.0; // The cutoff freq of the shelf filter that is used to decay echoes.\n\tpublic static readonly echoShelfGain: number = Math.pow(2.0, -0.5);\n\tpublic static readonly reverbShelfHz: number = 8000.0; // The cutoff freq of the shelf filter that is used to decay reverb.\n\tpublic static readonly reverbShelfGain: number = Math.pow(2.0, -1.5);\n\tpublic static readonly reverbRange: number = 4;\n\tpublic static readonly reverbDelayBufferSize: number = 16384; // TODO: Compute a buffer size based on sample rate.\n\tpublic static readonly reverbDelayBufferMask: number = Config.reverbDelayBufferSize - 1; // TODO: Compute a buffer size based on sample rate.\n\tpublic static readonly beatsPerBarMin: number = 3;\n\tpublic static readonly beatsPerBarMax: number = 16;\n\tpublic static readonly barCountMin: number = 1;\n\tpublic static readonly barCountMax: number = 128;\n\tpublic static readonly instrumentCountMin: number = 1;\n\tpublic static readonly layeredInstrumentCountMax: number = 4;\n\tpublic static readonly patternInstrumentCountMax: number = 10;\n\tpublic static readonly partsPerBeat: number = 24;\n\tpublic static readonly ticksPerPart: number = 2;\n\tpublic static readonly rhythms: DictionaryArray<Rhythm> = toNameMap([\n\t\t{name: \"÷3 (triplets)\", stepsPerBeat: 3, ticksPerArpeggio: 4, arpeggioPatterns: [[0], [0, 0, 1, 1], [0, 1, 2, 1]], roundUpThresholds: [/*0*/ 5, /*8*/ 12, /*16*/ 18 /*24*/]},\n\t\t{name: \"÷4 (standard)\", stepsPerBeat: 4, ticksPerArpeggio: 3, arpeggioPatterns: [[0], [0, 0, 1, 1], [0, 1, 2, 1]], roundUpThresholds: [/*0*/ 3, /*6*/ 9, /*12*/ 17, /*18*/ 21 /*24*/]},\n\t\t{name: \"÷6\", stepsPerBeat: 6, ticksPerArpeggio: 4, arpeggioPatterns: [[0], [0, 1], [0, 1, 2, 1]], roundUpThresholds: null},\n\t\t{name: \"÷8\", stepsPerBeat: 8, ticksPerArpeggio: 3, arpeggioPatterns: [[0], [0, 1], [0, 1, 2, 1]], roundUpThresholds: null},\n\t\t{name: \"freehand\", stepsPerBeat:24, ticksPerArpeggio: 3, arpeggioPatterns: [[0], [0, 1], [0, 1, 2, 1]], roundUpThresholds: null},\n\t]);\n\t\n\tpublic static readonly instrumentTypeNames: ReadonlyArray<string> = [\"chip\", \"FM\", \"noise\", \"spectrum\", \"drumset\", \"harmonics\", \"PWM\", \"Picked String\", \"supersaw\"]; // See InstrumentType enum above.\n\tpublic static readonly instrumentTypeHasSpecialInterval: ReadonlyArray<boolean> = [true, true, false, false, false, true, false, false, false];\n\tpublic static readonly chipBaseExpression: number = 0.03375; // Doubled by unison feature, but affected by expression adjustments per unison setting and wave shape.\n\tpublic static readonly fmBaseExpression: number = 0.03;\n\tpublic static readonly noiseBaseExpression: number = 0.19;\n\tpublic static readonly spectrumBaseExpression: number = 0.3; // Spectrum can be in pitch or noise channels, the expression is doubled for noise.\n\tpublic static readonly drumsetBaseExpression: number = 0.45; // Drums tend to be loud but brief!\n\tpublic static readonly harmonicsBaseExpression: number = 0.025;\n\tpublic static readonly pwmBaseExpression: number = 0.04725; // It's actually closer to half of this, the synthesized pulse amplitude range is only .5 to -.5, but also note that the fundamental sine partial amplitude of a square wave is 4/π times the measured square wave amplitude.\n\tpublic static readonly supersawBaseExpression: number = 0.061425; // It's actually closer to half of this, the synthesized sawtooth amplitude range is only .5 to -.5.\n\tpublic static readonly pickedStringBaseExpression: number = 0.025; // Same as harmonics.\n\tpublic static readonly distortionBaseVolume: number = 0.011; // Distortion is not affected by pitchDamping, which otherwise approximately halves expression for notes around the middle of the range.\n\tpublic static readonly bitcrusherBaseVolume: number = 0.010; // Also not affected by pitchDamping, used when bit crushing is maxed out (aka \"1-bit\" output).\n\t\n\tpublic static readonly chipWaves: DictionaryArray<ChipWave> = toNameMap([\n\t\t{name: \"rounded\", expression: 0.94, samples: centerWave([0.0, 0.2, 0.4, 0.5, 0.6, 0.7, 0.8, 0.85, 0.9, 0.95, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.95, 0.9, 0.85, 0.8, 0.7, 0.6, 0.5, 0.4, 0.2, 0.0, -0.2, -0.4, -0.5, -0.6, -0.7, -0.8, -0.85, -0.9, -0.95, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -0.95, -0.9, -0.85, -0.8, -0.7, -0.6, -0.5, -0.4, -0.2])},\n\t\t{name: \"triangle\", expression: 1.0, samples: centerWave([1.0/15.0, 3.0/15.0, 5.0/15.0, 7.0/15.0, 9.0/15.0, 11.0/15.0, 13.0/15.0, 15.0/15.0, 15.0/15.0, 13.0/15.0, 11.0/15.0, 9.0/15.0, 7.0/15.0, 5.0/15.0, 3.0/15.0, 1.0/15.0, -1.0/15.0, -3.0/15.0, -5.0/15.0, -7.0/15.0, -9.0/15.0, -11.0/15.0, -13.0/15.0, -15.0/15.0, -15.0/15.0, -13.0/15.0, -11.0/15.0, -9.0/15.0, -7.0/15.0, -5.0/15.0, -3.0/15.0, -1.0/15.0])},\n\t\t{name: \"square\", expression: 0.5, samples: centerWave([1.0, -1.0])},\n\t\t{name: \"1/4 pulse\", expression: 0.5, samples: centerWave([1.0, -1.0, -1.0, -1.0])},\n\t\t{name: \"1/8 pulse\", expression: 0.5, samples: centerWave([1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0])},\n\t\t{name: \"sawtooth\", expression: 0.65, samples: centerWave([1.0/31.0, 3.0/31.0, 5.0/31.0, 7.0/31.0, 9.0/31.0, 11.0/31.0, 13.0/31.0, 15.0/31.0, 17.0/31.0, 19.0/31.0, 21.0/31.0, 23.0/31.0, 25.0/31.0, 27.0/31.0, 29.0/31.0, 31.0/31.0, -31.0/31.0, -29.0/31.0, -27.0/31.0, -25.0/31.0, -23.0/31.0, -21.0/31.0, -19.0/31.0, -17.0/31.0, -15.0/31.0, -13.0/31.0, -11.0/31.0, -9.0/31.0, -7.0/31.0, -5.0/31.0, -3.0/31.0, -1.0/31.0])},\n\t\t{name: \"double saw\", expression: 0.5, samples: centerWave([0.0, -0.2, -0.4, -0.6, -0.8, -1.0, 1.0, -0.8, -0.6, -0.4, -0.2, 1.0, 0.8, 0.6, 0.4, 0.2])},\n\t\t{name: \"double pulse\", expression: 0.4, samples: centerWave([1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0])},\n\t\t{name: \"spiky\", expression: 0.4, samples: centerWave([1.0, -1.0, 1.0, -1.0, 1.0, 0.0])},\n\t]);\n\t// Noise waves have too many samples to write by hand, they're generated on-demand by getDrumWave instead.\n\tpublic static readonly chipNoises: DictionaryArray<ChipNoise> = toNameMap([\n\t\t{name: \"retro\", expression: 0.25, basePitch: 69, pitchFilterMult: 1024.0, isSoft: false, samples: null},\n\t\t{name: \"white\", expression: 1.0, basePitch: 69, pitchFilterMult: 8.0, isSoft: true, samples: null},\n\t\t// The \"clang\" and \"buzz\" noises are based on similar noises in the modded beepbox! :D\n\t\t{name: \"clang\", expression: 0.4, basePitch: 69, pitchFilterMult: 1024.0, isSoft: false, samples: null},\n\t\t{name: \"buzz\", expression: 0.3, basePitch: 69, pitchFilterMult: 1024.0, isSoft: false, samples: null},\n\t\t{name: \"hollow\", expression: 1.5, basePitch: 96, pitchFilterMult: 1.0, isSoft: true, samples: null},\n\t]);\n\t\n\tpublic static readonly filterFreqStep: number = 1.0/4.0;\n\tpublic static readonly filterFreqRange: number = 34;\n\tpublic static readonly filterFreqReferenceSetting: number = 28;\n\tpublic static readonly filterFreqReferenceHz: number = 8000.0;\n\tpublic static readonly filterFreqMaxHz: number = Config.filterFreqReferenceHz * Math.pow(2.0, Config.filterFreqStep * (Config.filterFreqRange - 1 - Config.filterFreqReferenceSetting)); // ~19khz\n\tpublic static readonly filterFreqMinHz: number = 8.0;\n\tpublic static readonly filterGainRange: number = 15;\n\tpublic static readonly filterGainCenter: number = 7;\n\tpublic static readonly filterGainStep: number = 1.0/2.0;\n\tpublic static readonly filterMaxPoints: number = 8;\n\tpublic static readonly filterTypeNames: ReadonlyArray<string> = [\"low-pass\", \"high-pass\", \"peak\"]; // See FilterType enum above.\n\t\n\tpublic static readonly fadeInRange: number = 10;\n\tpublic static readonly fadeOutTicks: ReadonlyArray<number> = [-24, -12, -6, -3, -1, 6, 12, 24, 48, 72, 96];\n\tpublic static readonly fadeOutNeutral: number = 4;\n\tpublic static readonly drumsetFadeOutTicks: number = 48;\n\tpublic static readonly transitions: DictionaryArray<Transition> = toNameMap([\n\t\t{name: \"normal\", isSeamless: false, continues: false, slides: false, slideTicks: 3, includeAdjacentPatterns: false},\n\t\t{name: \"interrupt\", isSeamless: true, continues: false, slides: false, slideTicks: 3, includeAdjacentPatterns: true},\n\t\t{name: \"continue\", isSeamless: true, continues: true, slides: false, slideTicks: 3, includeAdjacentPatterns: true},\n\t\t{name: \"slide\", isSeamless: true, continues: false, slides: true, slideTicks: 3, includeAdjacentPatterns: true},\n\t\t{name: \"slide in pattern\", isSeamless: true, continues: false, slides: true, slideTicks: 3, includeAdjacentPatterns: false},\n\t]);\n\tpublic static readonly vibratos: DictionaryArray<Vibrato> = toNameMap([\n\t\t{name: \"none\", amplitude: 0.0, periodsSeconds: [0.14], delayTicks: 0},\n\t\t{name: \"light\", amplitude: 0.15, periodsSeconds: [0.14], delayTicks: 0},\n\t\t{name: \"delayed\", amplitude: 0.3, periodsSeconds: [0.14], delayTicks: 37}, // It will fade in over the previous two ticks.\n\t\t{name: \"heavy\", amplitude: 0.45, periodsSeconds: [0.14], delayTicks: 0},\n\t\t{name: \"shaky\", amplitude: 0.1, periodsSeconds: [0.11, 1.618*0.11, 3*0.11], delayTicks: 0},\n\t]);\n\tpublic static readonly unisons: DictionaryArray<Unison> = toNameMap([\n\t\t{name: \"none\", voices: 1, spread: 0.0, offset: 0.0, expression: 1.4, sign: 1.0},\n\t\t{name: \"shimmer\", voices: 2, spread: 0.018,offset: 0.0, expression: 0.8, sign: 1.0},\n\t\t{name: \"hum\", voices: 2, spread: 0.045,offset: 0.0, expression: 1.0, sign: 1.0},\n\t\t{name: \"honky tonk\", voices: 2, spread: 0.09, offset: 0.0, expression: 1.0, sign: 1.0},\n\t\t{name: \"dissonant\", voices: 2, spread: 0.25, offset: 0.0, expression: 0.9, sign: 1.0},\n\t\t{name: \"fifth\", voices: 2, spread: 3.5, offset: 3.5, expression: 0.9, sign: 1.0},\n\t\t{name: \"octave\", voices: 2, spread: 6.0, offset: 6.0, expression: 0.8, sign: 1.0},\n\t\t{name: \"bowed\", voices: 2, spread: 0.02, offset: 0.0, expression: 1.0, sign:-1.0},\n\t\t{name: \"piano\", voices: 2, spread: 0.01, offset: 0.0, expression: 1.0, sign: 0.7},\n\t]);\n\tpublic static readonly effectNames: ReadonlyArray<string> = [\"reverb\", \"chorus\", \"panning\", \"distortion\", \"bitcrusher\", \"note filter\", \"echo\", \"pitch shift\", \"detune\", \"vibrato\", \"transition type\", \"chord type\"];\n\tpublic static readonly effectOrder: ReadonlyArray<EffectType> = [EffectType.transition, EffectType.chord, EffectType.pitchShift, EffectType.detune, EffectType.vibrato, EffectType.noteFilter, EffectType.distortion, EffectType.bitcrusher, EffectType.panning, EffectType.chorus, EffectType.echo, EffectType.reverb];\n\tpublic static readonly noteSizeMax: number = 3;\n\tpublic static readonly volumeRange: number = 8;\n\tpublic static readonly volumeLogScale: number = -0.5;\n\tpublic static readonly panCenter: number = 4;\n\tpublic static readonly panMax: number = Config.panCenter * 2;\n\tpublic static readonly panDelaySecondsMax: number = 0.0005;\n\tpublic static readonly chorusRange: number = 4;\n\tpublic static readonly chorusPeriodSeconds: number = 2.0;\n\tpublic static readonly chorusDelayRange: number = 0.0034;\n\tpublic static readonly chorusDelayOffsets: ReadonlyArray<ReadonlyArray<number>> = [[1.51, 2.10, 3.35], [1.47, 2.15, 3.25]];\n\tpublic static readonly chorusPhaseOffsets: ReadonlyArray<ReadonlyArray<number>> = [[0.0, 2.1, 4.2], [3.2, 5.3, 1.0]];\n\tpublic static readonly chorusMaxDelay: number = Config.chorusDelayRange * (1.0 + Config.chorusDelayOffsets[0].concat(Config.chorusDelayOffsets[1]).reduce((x,y)=>Math.max(x,y)));\n\tpublic static readonly chords: DictionaryArray<Chord> = toNameMap([\n\t\t{name: \"simultaneous\", customInterval: false, arpeggiates: false, strumParts: 0, singleTone: false},\n\t\t{name: \"strum\", customInterval: false, arpeggiates: false, strumParts: 1, singleTone: false},\n\t\t{name: \"arpeggio\", customInterval: false, arpeggiates: true, strumParts: 0, singleTone: true},\n\t\t{name: \"custom interval\", customInterval: true, arpeggiates: false, strumParts: 0, singleTone: true},\n\t]);\n\tpublic static readonly maxChordSize: number = 4;\n\tpublic static readonly operatorCount: number = 4;\n\tpublic static readonly maxPitchOrOperatorCount: number = Math.max(Config.maxChordSize, Config.operatorCount);\n\tpublic static readonly algorithms: DictionaryArray<Algorithm> = toNameMap([\n\t\t{name: \"1←(2 3 4)\", carrierCount: 1, associatedCarrier: [1, 1, 1, 1], modulatedBy: [[2, 3, 4], [], [], []]},\n\t\t{name: \"1←(2 3←4)\", carrierCount: 1, associatedCarrier: [1, 1, 1, 1], modulatedBy: [[2, 3], [], [4], []]},\n\t\t{name: \"1←2←(3 4)\", carrierCount: 1, associatedCarrier: [1, 1, 1, 1], modulatedBy: [[2], [3, 4], [], []]},\n\t\t{name: \"1←(2 3)←4\", carrierCount: 1, associatedCarrier: [1, 1, 1, 1], modulatedBy: [[2, 3], [4], [4], []]},\n\t\t{name: \"1←2←3←4\", carrierCount: 1, associatedCarrier: [1, 1, 1, 1], modulatedBy: [[2], [3], [4], []]},\n\t\t{name: \"1←3 2←4\", carrierCount: 2, associatedCarrier: [1, 2, 1, 2], modulatedBy: [[3], [4], [], []]},\n\t\t{name: \"1 2←(3 4)\", carrierCount: 2, associatedCarrier: [1, 2, 2, 2], modulatedBy: [[], [3, 4], [], []]},\n\t\t{name: \"1 2←3←4\", carrierCount: 2, associatedCarrier: [1, 2, 2, 2], modulatedBy: [[], [3], [4], []]},\n\t\t{name: \"(1 2)←3←4\", carrierCount: 2, associatedCarrier: [1, 2, 2, 2], modulatedBy: [[3], [3], [4], []]},\n\t\t{name: \"(1 2)←(3 4)\", carrierCount: 2, associatedCarrier: [1, 2, 2, 2], modulatedBy: [[3, 4], [3, 4], [], []]},\n\t\t{name: \"1 2 3←4\", carrierCount: 3, associatedCarrier: [1, 2, 3, 3], modulatedBy: [[], [], [4], []]},\n\t\t{name: \"(1 2 3)←4\", carrierCount: 3, associatedCarrier: [1, 2, 3, 3], modulatedBy: [[4], [4], [4], []]},\n\t\t{name: \"1 2 3 4\", carrierCount: 4, associatedCarrier: [1, 2, 3, 4], modulatedBy: [[], [], [], []]},\n\t]);\n\tpublic static readonly operatorCarrierInterval: ReadonlyArray<number> = [0.0, 0.04, -0.073, 0.091];\n\tpublic static readonly operatorAmplitudeMax: number = 15;\n\tpublic static readonly operatorFrequencies: DictionaryArray<OperatorFrequency> = toNameMap([\n\t\t{name: \"1×\", mult: 1.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"~1×\", mult: 1.0, hzOffset: 1.5, amplitudeSign:-1.0},\n\t\t{name: \"2×\", mult: 2.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"~2×\", mult: 2.0, hzOffset:-1.3, amplitudeSign:-1.0},\n\t\t{name: \"3×\", mult: 3.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"4×\", mult: 4.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"5×\", mult: 5.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"6×\", mult: 6.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"7×\", mult: 7.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"8×\", mult: 8.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"9×\", mult: 9.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"11×\", mult: 11.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"13×\", mult: 13.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"16×\", mult: 16.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t\t{name: \"20×\", mult: 20.0, hzOffset: 0.0, amplitudeSign: 1.0},\n\t]);\n\tpublic static readonly envelopes: DictionaryArray<Envelope> = toNameMap([\n\t\t{name: \"none\", type: EnvelopeType.none, speed: 0.0},\n\t\t{name: \"note size\",type: EnvelopeType.noteSize, speed: 0.0},\n\t\t{name: \"punch\", type: EnvelopeType.punch, speed: 0.0},\n\t\t{name: \"flare 1\", type: EnvelopeType.flare, speed: 32.0},\n\t\t{name: \"flare 2\", type: EnvelopeType.flare, speed: 8.0},\n\t\t{name: \"flare 3\", type: EnvelopeType.flare, speed: 2.0},\n\t\t{name: \"twang 1\", type: EnvelopeType.twang, speed: 32.0},\n\t\t{name: \"twang 2\", type: EnvelopeType.twang, speed: 8.0},\n\t\t{name: \"twang 3\", type: EnvelopeType.twang, speed: 2.0},\n\t\t{name: \"swell 1\", type: EnvelopeType.swell, speed: 32.0},\n\t\t{name: \"swell 2\", type: EnvelopeType.swell, speed: 8.0},\n\t\t{name: \"swell 3\", type: EnvelopeType.swell, speed: 2.0},\n\t\t{name: \"tremolo1\", type: EnvelopeType.tremolo, speed: 4.0},\n\t\t{name: \"tremolo2\", type: EnvelopeType.tremolo, speed: 2.0},\n\t\t{name: \"tremolo3\", type: EnvelopeType.tremolo, speed: 1.0},\n\t\t{name: \"tremolo4\", type: EnvelopeType.tremolo2, speed: 4.0},\n\t\t{name: \"tremolo5\", type: EnvelopeType.tremolo2, speed: 2.0},\n\t\t{name: \"tremolo6\", type: EnvelopeType.tremolo2, speed: 1.0},\n\t\t{name: \"decay 1\", type: EnvelopeType.decay, speed: 10.0},\n\t\t{name: \"decay 2\", type: EnvelopeType.decay, speed: 7.0},\n\t\t{name: \"decay 3\", type: EnvelopeType.decay, speed: 4.0},\n\t]);\n\tpublic static readonly feedbacks: DictionaryArray<Feedback> = toNameMap([\n\t\t{name: \"1⟲\", indices: [[1], [], [], []]},\n\t\t{name: \"2⟲\", indices: [ [], [2], [], []]},\n\t\t{name: \"3⟲\", indices: [ [], [], [3], []]},\n\t\t{name: \"4⟲\", indices: [ [], [], [], [4]]},\n\t\t{name: \"1⟲ 2⟲\", indices: [[1], [2], [], []]},\n\t\t{name: \"3⟲ 4⟲\", indices: [ [], [], [3], [4]]},\n\t\t{name: \"1⟲ 2⟲ 3⟲\", indices: [[1], [2], [3], []]},\n\t\t{name: \"2⟲ 3⟲ 4⟲\", indices: [ [], [2], [3], [4]]},\n\t\t{name: \"1⟲ 2⟲ 3⟲ 4⟲\", indices: [[1], [2], [3], [4]]},\n\t\t{name: \"1→2\", indices: [ [], [1], [], []]},\n\t\t{name: \"1→3\", indices: [ [], [], [1], []]},\n\t\t{name: \"1→4\", indices: [ [], [], [], [1]]},\n\t\t{name: \"2→3\", indices: [ [], [], [2], []]},\n\t\t{name: \"2→4\", indices: [ [], [], [], [2]]},\n\t\t{name: \"3→4\", indices: [ [], [], [], [3]]},\n\t\t{name: \"1→3 2→4\", indices: [ [], [], [1], [2]]},\n\t\t{name: \"1→4 2→3\", indices: [ [], [], [2], [1]]},\n\t\t{name: \"1→2→3→4\", indices: [ [], [1], [2], [3]]},\n\t]);\n\tpublic static readonly chipNoiseLength: number = 1 << 15; // 32768\n\tpublic static readonly spectrumNoiseLength: number = 1 << 15; // 32768\n\tpublic static readonly spectrumBasePitch: number = 24;\n\tpublic static readonly spectrumControlPoints: number = 30;\n\tpublic static readonly spectrumControlPointsPerOctave: number = 7;\n\tpublic static readonly spectrumControlPointBits: number = 3;\n\tpublic static readonly spectrumMax: number = (1 << Config.spectrumControlPointBits) - 1;\n\tpublic static readonly harmonicsControlPoints: number = 28;\n\tpublic static readonly harmonicsRendered: number = 64;\n\tpublic static readonly harmonicsRenderedForPickedString: number = 1 << 8; // 256\n\tpublic static readonly harmonicsControlPointBits: number = 3;\n\tpublic static readonly harmonicsMax: number = (1 << Config.harmonicsControlPointBits) - 1;\n\tpublic static readonly harmonicsWavelength: number = 1 << 11; // 2048\n\tpublic static readonly pulseWidthRange: number = 8;\n\tpublic static readonly pulseWidthStepPower: number = 0.5;\n\tpublic static readonly supersawVoiceCount: number = 7;\n\tpublic static readonly supersawDynamismMax: number = 6;\n\tpublic static readonly supersawSpreadMax: number = 12;\n\tpublic static readonly supersawShapeMax: number = 6;\n\tpublic static readonly pitchChannelCountMin: number = 1;\n\tpublic static readonly pitchChannelCountMax: number = 10;\n\tpublic static readonly noiseChannelCountMin: number = 0;\n\tpublic static readonly noiseChannelCountMax: number = 5;\n\tpublic static readonly noiseInterval: number = 6;\n\tpublic static readonly pitchesPerOctave: number = 12; // TODO: Use this for converting pitch to frequency.\n\tpublic static readonly drumCount: number = 12;\n\tpublic static readonly pitchOctaves: number = 7;\n\tpublic static readonly maxPitch: number = Config.pitchOctaves * Config.pitchesPerOctave;\n\tpublic static readonly maximumTonesPerChannel: number = Config.maxChordSize * 2;\n\tpublic static readonly justIntonationSemitones: number[] = [1.0/2.0, 8.0/15.0, 9.0/16.0, 3.0/5.0, 5.0/8.0, 2.0/3.0, 32.0/45.0, 3.0/4.0, 4.0/5.0, 5.0/6.0, 8.0/9.0, 15.0/16.0, 1.0, 16.0/15.0, 9.0/8.0, 6.0/5.0, 5.0/4.0, 4.0/3.0, 45.0/32.0, 3.0/2.0, 8.0/5.0, 5.0/3.0, 16.0/9.0, 15.0/8.0, 2.0].map(x=>Math.log2(x) * Config.pitchesPerOctave);\n\tpublic static readonly pitchShiftRange: number = Config.justIntonationSemitones.length;\n\tpublic static readonly pitchShiftCenter: number = Config.pitchShiftRange >> 1;\n\tpublic static readonly detuneCenter: number = 9;\n\tpublic static readonly detuneMax: number = Config.detuneCenter * 2;\n\tpublic static readonly sineWaveLength: number = 1 << 8; // 256\n\tpublic static readonly sineWaveMask: number = Config.sineWaveLength - 1;\n\tpublic static readonly sineWave: Float32Array = generateSineWave();\n\t\n\t// Picked strings have an all-pass filter with a corner frequency based on the tone fundamental frequency, in order to add a slight inharmonicity. (Which is important for distortion.)\n\tpublic static readonly pickedStringDispersionCenterFreq: number = 6000.0; // The tone fundamental freq is pulled toward this freq for computing the all-pass corner freq.\n\tpublic static readonly pickedStringDispersionFreqScale: number = 0.3; // The tone fundamental freq freq moves this much toward the center freq for computing the all-pass corner freq.\n\tpublic static readonly pickedStringDispersionFreqMult: number = 4.0; // The all-pass corner freq is based on this times the adjusted tone fundamental freq.\n\tpublic static readonly pickedStringShelfHz: number = 4000.0; // The cutoff freq of the shelf filter that is used to decay the high frequency energy in the picked string.\n\tpublic static readonly stringSustainRange: number = 15;\n\tpublic static readonly stringDecayRate: number = 0.12;\n\tpublic static readonly enableAcousticSustain: boolean = false;\n\tpublic static readonly sustainTypeNames: ReadonlyArray<string> = [\"bright\", \"acoustic\"]; // See SustainType enum above.\n\t\n\tpublic static readonly distortionRange: number = 8;\n\tpublic static readonly bitcrusherFreqRange: number = 14;\n\tpublic static readonly bitcrusherOctaveStep: number = 0.5;\n\tpublic static readonly bitcrusherQuantizationRange: number = 8;\n\t\n\tpublic static readonly maxEnvelopeCount: number = 12;\n\tpublic static readonly defaultAutomationRange: number = 13;\n\tpublic static readonly instrumentAutomationTargets: DictionaryArray<AutomationTarget> = toNameMap([\n\t\t{name: \"none\", computeIndex: null, displayName: \"none\", /*perNote: false,*/ interleave: false, isFilter: false, /*range: 0, */ maxCount: 1, effect: null, compatibleInstruments: null},\n\t\t{name: \"noteVolume\", computeIndex: EnvelopeComputeIndex.noteVolume, displayName: \"note volume\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.volumeRange, */ maxCount: 1, effect: null, compatibleInstruments: null},\n\t\t{name: \"pulseWidth\", computeIndex: EnvelopeComputeIndex.pulseWidth, displayName: \"pulse width\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.pulseWidthRange, */ maxCount: 1, effect: null, compatibleInstruments: [InstrumentType.pwm, InstrumentType.supersaw]},\n\t\t{name: \"stringSustain\", computeIndex: EnvelopeComputeIndex.stringSustain, displayName: \"sustain\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.stringSustainRange, */ maxCount: 1, effect: null, compatibleInstruments: [InstrumentType.pickedString]},\n\t\t{name: \"unison\", computeIndex: EnvelopeComputeIndex.unison, displayName: \"unison\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.defaultAutomationRange, */ maxCount: 1, effect: null, compatibleInstruments: [InstrumentType.chip, InstrumentType.harmonics, InstrumentType.pickedString]},\n\t\t{name: \"operatorFrequency\", computeIndex: EnvelopeComputeIndex.operatorFrequency0, displayName: \"fm# freq\", /*perNote: true,*/ interleave: true, isFilter: false, /*range: Config.defaultAutomationRange, */ maxCount: Config.operatorCount, effect: null, compatibleInstruments: [InstrumentType.fm]},\n\t\t{name: \"operatorAmplitude\", computeIndex: EnvelopeComputeIndex.operatorAmplitude0, displayName: \"fm# volume\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.operatorAmplitudeMax + 1,*/ maxCount: Config.operatorCount, effect: null, compatibleInstruments: [InstrumentType.fm]},\n\t\t{name: \"feedbackAmplitude\", computeIndex: EnvelopeComputeIndex.feedbackAmplitude, displayName: \"fm feedback\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.operatorAmplitudeMax + 1,*/ maxCount: 1, effect: null, compatibleInstruments: [InstrumentType.fm]},\n\t\t{name: \"pitchShift\", computeIndex: EnvelopeComputeIndex.pitchShift, displayName: \"pitch shift\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.pitchShiftRange, */ maxCount: 1, effect: EffectType.pitchShift, compatibleInstruments: null},\n\t\t{name: \"detune\", computeIndex: EnvelopeComputeIndex.detune, displayName: \"detune\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.detuneMax + 1, */ maxCount: 1, effect: EffectType.detune, compatibleInstruments: null},\n\t\t{name: \"vibratoDepth\", computeIndex: EnvelopeComputeIndex.vibratoDepth, displayName: \"vibrato range\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.defaultAutomationRange, */ maxCount: 1, effect: EffectType.vibrato, compatibleInstruments: null},\n\t\t{name: \"noteFilterAllFreqs\", computeIndex: EnvelopeComputeIndex.noteFilterAllFreqs, displayName: \"n. filter freqs\", /*perNote: true,*/ interleave: false, isFilter: true, /*range: null, */ maxCount: 1, effect: EffectType.noteFilter, compatibleInstruments: null},\n\t\t{name: \"noteFilterFreq\", computeIndex: EnvelopeComputeIndex.noteFilterFreq0, displayName: \"n. filter # freq\", /*perNote: true,*/ interleave: false/*true*/, isFilter: true, /*range: Config.filterFreqRange, */ maxCount: Config.filterMaxPoints, effect: EffectType.noteFilter, compatibleInstruments: null},\n\t\t// Controlling filter gain is less obvious and intuitive than controlling filter freq, so to avoid confusion I've disabled it for envelopes.\n\t\t{name: \"noteFilterGain\", computeIndex: null, displayName: \"n. filter # vol\", /*perNote: true,*/ interleave: false, isFilter: true, /*range: Config.filterGainRange, */ maxCount: Config.filterMaxPoints, effect: EffectType.noteFilter, compatibleInstruments: null},\n\t\t{name: \"supersawDynamism\", computeIndex: EnvelopeComputeIndex.supersawDynamism, displayName: \"dynamism\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.supersawDynamismMax + 1, */ maxCount: 1, effect: null, compatibleInstruments: [InstrumentType.supersaw]},\n\t\t{name: \"supersawSpread\", computeIndex: EnvelopeComputeIndex.supersawSpread, displayName: \"spread\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.supersawSpreadMax + 1, */ maxCount: 1, effect: null, compatibleInstruments: [InstrumentType.supersaw]},\n\t\t{name: \"supersawShape\", computeIndex: EnvelopeComputeIndex.supersawShape, displayName: \"saw↔pulse\", /*perNote: true,*/ interleave: false, isFilter: false, /*range: Config.supersawShapeMax + 1, */ maxCount: 1, effect: null, compatibleInstruments: [InstrumentType.supersaw]},\n\t\t/*\n\t\t{name: \"distortion\", computeIndex: InstrumentAutomationIndex.distortion, displayName: \"distortion\", perNote: false, interleave: false, isFilter: false, range: Config.distortionRange, maxCount: 1, effect: EffectType.distortion, compatibleInstruments: null},\n\t\t{name: \"bitcrusherQuantization\", computeIndex: InstrumentAutomationIndex.bitcrusherQuantization, displayName: \"bit crush\", perNote: false, interleave: false, isFilter: false, range: Config.bitcrusherQuantizationRange, maxCount: 1, effect: EffectType.bitcrusher, compatibleInstruments: null},\n\t\t{name: \"bitcrusherFrequency\", computeIndex: InstrumentAutomationIndex.bitcrusherFrequency, displayName: \"freq crush\", perNote: false, interleave: false, isFilter: false, range: Config.bitcrusherFreqRange, maxCount: 1, effect: EffectType.bitcrusher, compatibleInstruments: null},\n\t\t{name: \"eqFilterAllFreqs\", computeIndex: InstrumentAutomationIndex.eqFilterAllFreqs, displayName: \"eq filter freqs\", perNote: false, interleave: false, isFilter: true, range: null, maxCount: 1, effect: null, compatibleInstruments: null},\n\t\t{name: \"eqFilterFreq\", computeIndex: InstrumentAutomationIndex.eqFilterFreq0, displayName: \"eq filter # freq\", perNote: false, interleave: true, isFilter: true, range: Config.filterFreqRange, maxCount: Config.filterMaxPoints, effect: null, compatibleInstruments: null},\n\t\t{name: \"eqFilterGain\", computeIndex: InstrumentAutomationIndex.eqFilterGain0, displayName: \"eq filter # vol\", perNote: false, interleave: false, isFilter: true, range: Config.filterGainRange, maxCount: Config.filterMaxPoints, effect: null, compatibleInstruments: null},\n\t\t{name: \"panning\", computeIndex: InstrumentAutomationIndex.panning, displayName: \"panning\", perNote: false, interleave: false, isFilter: false, range: Config.panMax + 1, maxCount: 1, effect: EffectType.panning, compatibleInstruments: null},\n\t\t{name: \"chorus\", computeIndex: InstrumentAutomationIndex.chorus, displayName: \"chorus\", perNote: false, interleave: false, isFilter: false, range: Config.chorusRange, maxCount: 1, effect: EffectType.chorus, compatibleInstruments: null},\n\t\t{name: \"echoSustain\", computeIndex: InstrumentAutomationIndex.echoSustain, displayName: \"echo\", perNote: false, interleave: false, isFilter: false, range: Config.echoSustainRange, maxCount: 1, effect: EffectType.echo, compatibleInstruments: null},\n\t\t{name: \"echoDelay\", computeIndex: InstrumentAutomationIndex.echoDelay, displayName: \"echo delay\", perNote: false, interleave: false, isFilter: false, range: Config.echoDelayRange, maxCount: 1, effect: EffectType.echo, compatibleInstruments: null}, // wait until after we're computing a tick's settings for multiple run lengths.\n\t\t{name: \"reverb\", computeIndex: InstrumentAutomationIndex.reverb, displayName: \"reverb\", perNote: false, interleave: false, isFilter: false, range: Config.reverbRange, maxCount: 1, effect: EffectType.reverb, compatibleInstruments: null},\n\t\t{name: \"mixVolume\", computeIndex: InstrumentAutomationIndex.mixVolume, displayName: \"mix volume\", perNote: false, interleave: false, isFilter: false, range: Config.volumeRange, maxCount: 1, effect: null, compatibleInstruments: null},\n\t\t{name: \"envelope#\", computeIndex: null, displayName: \"envelope\", perNote: false, interleave: false, isFilter: false, range: Config.defaultAutomationRange, maxCount: Config.maxEnvelopeCount, effect: null, compatibleInstruments: null}, // maxCount special case for envelopes to be allowed to target earlier ones.\n\t\t*/\n\t]);\n}\n\nfunction centerWave(wave: Array<number>): Float32Array {\n\tlet sum: number = 0.0;\n\tfor (let i: number = 0; i < wave.length; i++) sum += wave[i];\n\tconst average: number = sum / wave.length;\n\tfor (let i: number = 0; i < wave.length; i++) wave[i] -= average;\n\tperformIntegral(wave);\n\t// The first sample should be zero, and we'll duplicate it at the end for easier interpolation.\n\twave.push(0);\n\treturn new Float32Array(wave);\n}\n\nexport function performIntegral(wave: {length: number, [index: number]: number}): void {\n\t// Perform the integral on the wave. The synth function will perform the derivative to get the original wave back but with antialiasing.\n\tlet cumulative: number = 0.0;\n\tfor (let i: number = 0; i < wave.length; i++) {\n\t\tconst temp = wave[i];\n\t\twave[i] = cumulative;\n\t\tcumulative += temp;\n\t}\n}\n\nexport function getPulseWidthRatio(pulseWidth: number): number {\n\treturn Math.pow(0.5, (Config.pulseWidthRange - 1 - pulseWidth) * Config.pulseWidthStepPower) * 0.5;\n}\n\n// The function arguments will be defined in FFT.ts, but I want\n// SynthConfig.ts to be at the top of the compiled JS so I won't directly\n// depend on FFT here. synth.ts will take care of importing FFT.ts.\n//function inverseRealFourierTransform(array: {length: number, [index: number]: number}, fullArrayLength: number): void;\n//function scaleElementsByFactor(array: {length: number, [index: number]: number}, factor: number): void;\nexport function getDrumWave(index: number, inverseRealFourierTransform: Function | null, scaleElementsByFactor: Function | null): Float32Array {\n\tlet wave: Float32Array | null = Config.chipNoises[index].samples;\n\tif (wave == null) {\n\t\twave = new Float32Array(Config.chipNoiseLength + 1);\n\t\tConfig.chipNoises[index].samples = wave;\n\t\t\n\t\tif (index == 0) {\n\t\t\t// The \"retro\" drum uses a \"Linear Feedback Shift Register\" similar to the NES noise channel.\n\t\t\tlet drumBuffer: number = 1;\n\t\t\tfor (let i: number = 0; i < Config.chipNoiseLength; i++) {\n\t\t\t\twave[i] = (drumBuffer & 1) * 2.0 - 1.0;\n\t\t\t\tlet newBuffer: number = drumBuffer >> 1;\n\t\t\t\tif (((drumBuffer + newBuffer) & 1) == 1) {\n\t\t\t\t\tnewBuffer += 1 << 14;\n\t\t\t\t}\n\t\t\t\tdrumBuffer = newBuffer;\n\t\t\t}\n\t\t} else if (index == 1) {\n\t\t\t// White noise is just random values for each sample.\n\t\t\tfor (let i: number = 0; i < Config.chipNoiseLength; i++) {\n\t\t\t\twave[i] = Math.random() * 2.0 - 1.0;\n\t\t\t}\n\t\t} else if (index == 2) {\n\t\t\t// The \"clang\" noise wave is based on a similar noise wave in the modded beepbox made by DAzombieRE.\n\t\t\tlet drumBuffer: number = 1;\n\t\t\tfor (let i: number = 0; i < Config.chipNoiseLength; i++) {\n\t\t\t\twave[i] = (drumBuffer & 1) * 2.0 - 1.0;\n\t\t\t\tlet newBuffer: number = drumBuffer >> 1;\n\t\t\t\tif (((drumBuffer + newBuffer) & 1) == 1) {\n\t\t\t\t\tnewBuffer += 2 << 14;\n\t\t\t\t}\n\t\t\t\tdrumBuffer = newBuffer;\n\t\t\t}\n\t\t} else if (index == 3) {\n\t\t\t// The \"buzz\" noise wave is based on a similar noise wave in the modded beepbox made by DAzombieRE.\n\t\t\tlet drumBuffer: number = 1;\n\t\t\tfor (let i: number = 0; i < Config.chipNoiseLength; i++) {\n\t\t\t\twave[i] = (drumBuffer & 1) * 2.0 - 1.0;\n\t\t\t\tlet newBuffer: number = drumBuffer >> 1;\n\t\t\t\tif (((drumBuffer + newBuffer) & 1) == 1) {\n\t\t\t\t\tnewBuffer += 10 << 2;\n\t\t\t\t}\n\t\t\t\tdrumBuffer = newBuffer;\n\t\t\t}\n\t\t} else if (index == 4) {\n\t\t\t// \"hollow\" drums, designed in frequency space and then converted via FFT:\n\t\t\tdrawNoiseSpectrum(wave, Config.chipNoiseLength, 10, 11, 1, 1, 0);\n\t\t\tdrawNoiseSpectrum(wave, Config.chipNoiseLength, 11, 14, .6578, .6578, 0);\n\t\t\tinverseRealFourierTransform!(wave, Config.chipNoiseLength);\n\t\t\tscaleElementsByFactor!(wave, 1.0 / Math.sqrt(Config.chipNoiseLength));\n\t\t} else {\n\t\t\tthrow new Error(\"Unrecognized drum index: \" + index);\n\t\t}\n\t\t\n\t\twave[Config.chipNoiseLength] = wave[0];\n\t}\n\t\n\treturn wave;\n}\n\nexport function drawNoiseSpectrum(wave: Float32Array, waveLength: number, lowOctave: number, highOctave: number, lowPower: number, highPower: number, overallSlope: number): number {\n\tconst referenceOctave: number = 11;\n\tconst referenceIndex: number = 1 << referenceOctave;\n\tconst lowIndex: number = Math.pow(2, lowOctave) | 0;\n\tconst highIndex: number = Math.min(waveLength >> 1, Math.pow(2, highOctave) | 0);\n\tconst retroWave: Float32Array = getDrumWave(0, null, null);\n\tlet combinedAmplitude: number = 0.0;\n\tfor (let i: number = lowIndex; i < highIndex; i++) {\n\t\t\n\t\tlet lerped: number = lowPower + (highPower - lowPower) * (Math.log2(i) - lowOctave) / (highOctave - lowOctave);\n\t\tlet amplitude: number = Math.pow(2, (lerped - 1) * 7 + 1) * lerped;\n\t\t\n\t\tamplitude *= Math.pow(i / referenceIndex, overallSlope);\n\t\t\n\t\tcombinedAmplitude += amplitude;\n\t\t\n\t\t// Add two different sources of psuedo-randomness to the noise\n\t\t// (individually they aren't random enough) but in a deterministic\n\t\t// way so that live spectrum editing doesn't result in audible pops.\n\t\t// Multiply all the sine wave amplitudes by 1 or -1 based on the\n\t\t// LFSR retro wave (effectively random), and also rotate the phase\n\t\t// of each sine wave based on the golden angle to disrupt the symmetry.\n\t\tamplitude *= retroWave[i];\n\t\tconst radians: number = 0.61803398875 * i * i * Math.PI * 2.0;\n\t\t\n\t\twave[i] = Math.cos(radians) * amplitude;\n\t\twave[waveLength - i] = Math.sin(radians) * amplitude;\n\t}\n\t\n\treturn combinedAmplitude;\n}\n\nfunction generateSineWave(): Float32Array {\n\tconst wave: Float32Array = new Float32Array(Config.sineWaveLength + 1);\n\tfor (let i: number = 0; i < Config.sineWaveLength + 1; i++) {\n\t\twave[i] = Math.sin(i * Math.PI * 2.0 / Config.sineWaveLength);\n\t}\n\treturn wave;\n}\n\nexport function getArpeggioPitchIndex(pitchCount: number, rhythm: number, arpeggio: number): number {\n\tconst arpeggioPattern: ReadonlyArray<number> = Config.rhythms[rhythm].arpeggioPatterns[pitchCount - 1];\n\tif (arpeggioPattern != null) {\n\t\treturn arpeggioPattern[arpeggio % arpeggioPattern.length];\n\t} else {\n\t\treturn arpeggio % pitchCount;\n\t}\n}\n\n// Pardon the messy type casting. This allows accessing array members by numerical index or string name.\nexport function toNameMap<T extends BeepBoxOption>(array: Array<Pick<T, Exclude<keyof T, \"index\">>>): DictionaryArray<T> {\n\tconst dictionary: Dictionary<T> = {};\n\tfor (let i: number = 0; i < array.length; i++) {\n\t\tconst value: any = array[i];\n\t\tvalue.index = i;\n\t\tdictionary[value.name] = <T> value;\n\t}\n\tconst result: DictionaryArray<T> = <DictionaryArray<T>> <any> array;\n\tresult.dictionary = dictionary;\n\treturn result;\n}\n\nexport function effectsIncludeTransition(effects: number): boolean {\n\treturn (effects & (1 << EffectType.transition)) != 0;\n}\nexport function effectsIncludeChord(effects: number): boolean {\n\treturn (effects & (1 << EffectType.chord)) != 0;\n}\nexport function effectsIncludePitchShift(effects: number): boolean {\n\treturn (effects & (1 << EffectType.pitchShift)) != 0;\n}\nexport function effectsIncludeDetune(effects: number): boolean {\n\treturn (effects & (1 << EffectType.detune)) != 0;\n}\nexport function effectsIncludeVibrato(effects: number): boolean {\n\treturn (effects & (1 << EffectType.vibrato)) != 0;\n}\nexport function effectsIncludeNoteFilter(effects: number): boolean {\n\treturn (effects & (1 << EffectType.noteFilter)) != 0;\n}\nexport function effectsIncludeDistortion(effects: number): boolean {\n\treturn (effects & (1 << EffectType.distortion)) != 0;\n}\nexport function effectsIncludeBitcrusher(effects: number): boolean {\n\treturn (effects & (1 << EffectType.bitcrusher)) != 0;\n}\nexport function effectsIncludePanning(effects: number): boolean {\n\treturn (effects & (1 << EffectType.panning)) != 0;\n}\nexport function effectsIncludeChorus(effects: number): boolean {\n\treturn (effects & (1 << EffectType.chorus)) != 0;\n}\nexport function effectsIncludeEcho(effects: number): boolean {\n\treturn (effects & (1 << EffectType.echo)) != 0;\n}\nexport function effectsIncludeReverb(effects: number): boolean {\n\treturn (effects & (1 << EffectType.reverb)) != 0;\n}\n","// Copyright (c) 2012-2022 John Nesky and contributing authors, distributed under the MIT license, see accompanying the LICENSE.md file.\n\n// interface shared by number[], Float32Array, and other typed arrays in JavaScript.\ninterface NumberArray {\n\tlength: number;\n\t[index: number]: number;\n}\n\n// A basic FFT operation scales the overall magnitude of elements by the\n// square root of the length of the array, √N. Performing a forward FFT and\n// then an inverse FFT results in the original array, but multiplied by N.\n// This helper function can be used to compensate for that. \nexport function scaleElementsByFactor(array: NumberArray, factor: number): void {\n\tfor (let i: number = 0; i < array.length; i++) {\n\t\tarray[i] *= factor;\n\t}\n}\n\nfunction isPowerOf2(n: number): boolean {\n\treturn !!n && !(n & (n - 1));\n}\n\nfunction countBits(n: number): number {\n\tif (!isPowerOf2(n)) throw new Error(\"FFT array length must be a power of 2.\");\n\treturn Math.round(Math.log(n) / Math.log(2));\n}\n\n// Rearranges the elements of the array, swapping the element at an index\n// with an element at an index that is the bitwise reverse of the first\n// index in base 2. Useful for computing the FFT.\nfunction reverseIndexBits(array: NumberArray, fullArrayLength: number): void {\n\tconst bitCount: number = countBits(fullArrayLength);\n\tif (bitCount > 16) throw new Error(\"FFT array length must not be greater than 2^16.\");\n\tconst finalShift: number = 16 - bitCount;\n\tfor (let i: number = 0; i < fullArrayLength; i++) {\n\t\t// Dear Javascript: Please support bit order reversal intrinsics. Thanks! :D\n\t\tlet j: number;\n\t\tj = ((i & 0xaaaa) >> 1) | ((i & 0x5555) << 1);\n\t\tj = ((j & 0xcccc) >> 2) | ((j & 0x3333) << 2);\n\t\tj = ((j & 0xf0f0) >> 4) | ((j & 0x0f0f) << 4);\n\t\tj = ((j >> 8) | ((j & 0xff) << 8)) >> finalShift;\n\t\tif (j > i) {\n\t\t\tlet temp: number = array[i];\n\t\t\tarray[i] = array[j];\n\t\t\tarray[j] = temp;\n\t\t}\n\t}\n}\n\n// Provided for educational purposes. Easier to read than\n// fastFourierTransform(), but computes the same result.\n// Takes two parallel arrays representing the real and imaginary elements,\n// respectively, and returns an array containing two new arrays, which\n// contain the complex result of the transform.\nexport function discreteFourierTransform(realArray: NumberArray, imagArray: NumberArray): number[][] {\n\tconst fullArrayLength: number = realArray.length;\n\tif (fullArrayLength != imagArray.length) throw new Error(\"FFT arrays must be the same length.\");\n\tconst realOut: number[] = [];\n\tconst imagOut: number[] = [];\n\tfor (let i: number = 0; i < fullArrayLength; i++) {\n\t\trealOut[i] = 0.0;\n\t\timagOut[i] = 0.0;\n\t\tfor (let j: number = 0; j < fullArrayLength; j++) {\n\t\t\tconst radians: number = -6.2831853 * j * i / fullArrayLength;\n\t\t\tconst c: number = Math.cos(radians);\n\t\t\tconst s: number = Math.sin(radians);\n\t\t\trealOut[i] += realArray[j] * c - imagArray[j] * s;\n\t\t\timagOut[i] += realArray[j] * s + imagArray[j] * c;\n\t\t}\n\t}\n\treturn [realOut, imagOut];\n}\n\n// Performs a Fourier transform in O(N log(N)) operations. Overwrites the\n// input real and imaginary arrays. Can be used for both forward and inverse\n// transforms: swap the order of the arguments for the inverse.\nexport function fastFourierTransform(realArray: NumberArray, imagArray: NumberArray): void {\n\tconst fullArrayLength: number = realArray.length;\n\tif (!isPowerOf2(fullArrayLength)) throw new Error(\"FFT array length must be a power of 2.\");\n\tif (fullArrayLength < 4) throw new Error(\"FFT array length must be at least 4.\");\n\tif (fullArrayLength != imagArray.length) throw new Error(\"FFT arrays must be the same length.\");\n\t\n\treverseIndexBits(realArray, fullArrayLength);\n\treverseIndexBits(imagArray, fullArrayLength);\n\t\n\t// First two passes, with strides of 2 and 4, can be combined and optimized.\n\tfor (let startIndex: number = 0; startIndex < fullArrayLength; startIndex += 4) {\n\t\tconst startIndex1: number = startIndex + 1;\n\t\tconst startIndex2: number = startIndex + 2;\n\t\tconst startIndex3: number = startIndex + 3;\n\t\tconst real0: number = realArray[startIndex ];\n\t\tconst real1: number = realArray[startIndex1];\n\t\tconst real2: number = realArray[startIndex2];\n\t\tconst real3: number = realArray[startIndex3];\n\t\tconst imag0: number = imagArray[startIndex ];\n\t\tconst imag1: number = imagArray[startIndex1];\n\t\tconst imag2: number = imagArray[startIndex2];\n\t\tconst imag3: number = imagArray[startIndex3];\n\t\tconst realTemp0: number = real0 + real1;\n\t\tconst realTemp1: number = real0 - real1;\n\t\tconst realTemp2: number = real2 + real3;\n\t\tconst realTemp3: number = real2 - real3;\n\t\tconst imagTemp0: number = imag0 + imag1;\n\t\tconst imagTemp1: number = imag0 - imag1;\n\t\tconst imagTemp2: number = imag2 + imag3;\n\t\tconst imagTemp3: number = imag2 - imag3;\n\t\trealArray[startIndex ] = realTemp0 + realTemp2;\n\t\trealArray[startIndex1] = realTemp1 + imagTemp3;\n\t\trealArray[startIndex2] = realTemp0 - realTemp2;\n\t\trealArray[startIndex3] = realTemp1 - imagTemp3;\n\t\timagArray[startIndex ] = imagTemp0 + imagTemp2;\n\t\timagArray[startIndex1] = imagTemp1 - realTemp3;\n\t\timagArray[startIndex2] = imagTemp0 - imagTemp2;\n\t\timagArray[startIndex3] = imagTemp1 + realTemp3;\n\t}\n\t\n\tfor (let stride: number = 8; stride <= fullArrayLength; stride += stride) {\n\t\tconst halfLength: number = stride >>> 1;\n\t\tconst radiansIncrement: number = Math.PI * 2.0 / stride;\n\t\tconst cosIncrement: number = Math.cos(radiansIncrement);\n\t\tconst sinIncrement: number = Math.sin(radiansIncrement);\n\t\tconst oscillatorMultiplier: number = 2.0 * cosIncrement;\n\t\tfor (let startIndex: number = 0; startIndex < fullArrayLength; startIndex += stride) {\n\t\t\tlet c: number = 1.0;\n\t\t\tlet s: number = 0.0;\n\t\t\tlet cPrev: number = cosIncrement;\n\t\t\tlet sPrev: number = sinIncrement;\n\t\t\tconst secondHalf: number = startIndex + halfLength;\n\t\t\tfor (let i: number = startIndex; i < secondHalf; i++) {\n\t\t\t\tconst j: number = i + halfLength;\n\t\t\t\tconst real0: number = realArray[i];\n\t\t\t\tconst imag0: number = imagArray[i];\n\t\t\t\tconst real1: number = realArray[j] * c - imagArray[j] * s;\n\t\t\t\tconst imag1: number = realArray[j] * s + imagArray[j] * c;\n\t\t\t\trealArray[i] = real0 + real1;\n\t\t\t\timagArray[i] = imag0 + imag1;\n\t\t\t\trealArray[j] = real0 - real1;\n\t\t\t\timagArray[j] = imag0 - imag1;\n\t\t\t\tconst cTemp: number = oscillatorMultiplier * c - cPrev;\n\t\t\t\tconst sTemp: number = oscillatorMultiplier * s - sPrev;\n\t\t\t\tcPrev = c;\n\t\t\t\tsPrev = s;\n\t\t\t\tc = cTemp;\n\t\t\t\ts = sTemp;\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Computes the Fourier transform from an array of real-valued time-domain\n// samples. The output is specially formatted for space efficieny: elements\n// 0 through N/2 represent cosine wave amplitudes in ascending frequency,\n// and elements N/2+1 through N-1 represent sine wave amplitudes in\n// descending frequency. Overwrites the input array.\nexport function forwardRealFourierTransform(array: NumberArray): void {\n\tconst fullArrayLength: number = array.length;\n\tconst totalPasses: number = countBits(fullArrayLength);\n\tif (fullArrayLength < 4) throw new Error(\"FFT array length must be at least 4.\");\n\t\n\treverseIndexBits(array, fullArrayLength);\n\t\n\t// First and second pass.\n\tfor (let index: number = 0; index < fullArrayLength; index += 4) {\n\t\tconst index1: number = index + 1;\n\t\tconst index2: number = index + 2;\n\t\tconst index3: number = index + 3;\n\t\tconst real0: number = array[index ];\n\t\tconst real1: number = array[index1];\n\t\tconst real2: number = array[index2];\n\t\tconst real3: number = array[index3];\n\t\t// no imaginary elements yet since the input is fully real.\n\t\tconst tempA: number = real0 + real1;\n\t\tconst tempB: number = real2 + real3;\n\t\tarray[index ] = tempA + tempB;\n\t\tarray[index1] = real0 - real1;\n\t\tarray[index2] = tempA - tempB;\n\t\tarray[index3] = real2 - real3;\n\t}\n\t\n\t// Third pass.\n\tconst sqrt2over2: number = Math.sqrt(2.0) / 2.0;\n\tfor (let index: number = 0; index < fullArrayLength; index += 8) {\n\t\tconst index1: number = index + 1;\n\t\tconst index3: number = index + 3;\n\t\tconst index4: number = index + 4;\n\t\tconst index5: number = index + 5;\n\t\tconst index7: number = index + 7;\n\t\tconst real0: number = array[index ];\n\t\tconst real1: number = array[index1];\n\t\tconst imag3: number = array[index3];\n\t\tconst real4: number = array[index4];\n\t\tconst real5: number = array[index5];\n\t\tconst imag7: number = array[index7];\n\t\tconst tempA: number = (real5 - imag7) * sqrt2over2;\n\t\tconst tempB: number = (real5 + imag7) * sqrt2over2;\n\t\tarray[index ] = real0 + real4;\n\t\tarray[index1] = real1 + tempA;\n\t\tarray[index3] = real1 - tempA;\n\t\tarray[index4] = real0 - real4;\n\t\tarray[index5] = tempB - imag3;\n\t\tarray[index7] = tempB + imag3;\n\t}\n\t\n\t// Handle remaining passes.\n\tfor (let pass: number = 3; pass < totalPasses; pass++) {\n\t\tconst subStride: number = 1 << pass;\n\t\tconst midSubStride: number = subStride >> 1;\n\t\tconst stride: number = subStride << 1;\n\t\tconst radiansIncrement: number = Math.PI * 2.0 / stride;\n\t\tconst cosIncrement: number = Math.cos(radiansIncrement);\n\t\tconst sinIncrement: number = Math.sin(radiansIncrement);\n\t\tconst oscillatorMultiplier: number = 2.0 * cosIncrement;\n\t\tfor (let startIndex: number = 0; startIndex < fullArrayLength; startIndex += stride) {\n\t\t\tconst startIndexA: number = startIndex;\n\t\t\tconst startIndexB: number = startIndexA + subStride;\n\t\t\tconst stopIndex: number = startIndexB + subStride;\n\t\t\tconst realStartA: number = array[startIndexA];\n\t\t\tconst realStartB: number = array[startIndexB];\n\t\t\tarray[startIndexA] = realStartA + realStartB;\n\t\t\tarray[startIndexB] = realStartA - realStartB;\n\t\t\tlet c: number = cosIncrement;\n\t\t\tlet s: number = -sinIncrement;\n\t\t\tlet cPrev: number = 1.0;\n\t\t\tlet sPrev: number = 0.0;\n\t\t\tfor (let index: number = 1; index < midSubStride; index++) {\n\t\t\t\tconst indexA0: number = startIndexA + index;\n\t\t\t\tconst indexA1: number = startIndexB - index;\n\t\t\t\tconst indexB0: number = startIndexB + index;\n\t\t\t\tconst indexB1: number = stopIndex - index;\n\t\t\t\tconst real0: number = array[indexA0];\n\t\t\t\tconst imag0: number = array[indexA1];\n\t\t\t\tconst real1: number = array[indexB0];\n\t\t\t\tconst imag1: number = array[indexB1];\n\t\t\t\tconst tempA: number = real1 * c + imag1 * s;\n\t\t\t\tconst tempB: number = real1 * s - imag1 * c;\n\t\t\t\tarray[indexA0] = real0 + tempA;\n\t\t\t\tarray[indexA1] = real0 - tempA;\n\t\t\t\tarray[indexB0] =-imag0 - tempB;\n\t\t\t\tarray[indexB1] = imag0 - tempB;\n\t\t\t\tconst cTemp: number = oscillatorMultiplier * c - cPrev;\n\t\t\t\tconst sTemp: number = oscillatorMultiplier * s - sPrev;\n\t\t\t\tcPrev = c;\n\t\t\t\tsPrev = s;\n\t\t\t\tc = cTemp;\n\t\t\t\ts = sTemp;\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Computes the inverse Fourier transform from a specially formatted array of\n// scalar values. Elements 0 through N/2 are expected to be the real values of\n// the corresponding complex elements, representing cosine wave amplitudes in\n// ascending frequency, and elements N/2+1 through N-1 correspond to the\n// imaginary values, representing sine wave amplitudes in descending frequency.\n// Generates real-valued time-domain samples. Overwrites the input array.\nexport function inverseRealFourierTransform(array: NumberArray, fullArrayLength: number): void {\n\tconst totalPasses: number = countBits(fullArrayLength);\n\tif (fullArrayLength < 4) throw new Error(\"FFT array length must be at least 4.\");\n\n\t// Perform all but the last few passes in reverse.\n\tfor (let pass: number = totalPasses - 1; pass >= 2; pass--) {\n\t\tconst subStride: number = 1 << pass;\n\t\tconst midSubStride: number = subStride >> 1;\n\t\tconst stride: number = subStride << 1;\n\t\tconst radiansIncrement: number = Math.PI * 2.0 / stride;\n\t\tconst cosIncrement: number = Math.cos(radiansIncrement);\n\t\tconst sinIncrement: number = Math.sin(radiansIncrement);\n\t\tconst oscillatorMultiplier: number = 2.0 * cosIncrement;\n\t\t\n\t\tfor (let startIndex: number = 0; startIndex < fullArrayLength; startIndex += stride) {\n\t\t\tconst startIndexA: number = startIndex;\n\t\t\tconst midIndexA: number = startIndexA + midSubStride;\n\t\t\tconst startIndexB: number = startIndexA + subStride;\n\t\t\tconst midIndexB: number = startIndexB + midSubStride;\n\t\t\tconst stopIndex: number = startIndexB + subStride;\n\t\t\tconst realStartA: number = array[startIndexA];\n\t\t\tconst imagStartB: number = array[startIndexB];\n\t\t\tarray[startIndexA] = realStartA + imagStartB;\n\t\t\tarray[midIndexA] *= 2;\n\t\t\tarray[startIndexB] = realStartA - imagStartB;\n\t\t\tarray[midIndexB] *= 2;\n\t\t\tlet c: number = cosIncrement;\n\t\t\tlet s: number = -sinIncrement;\n\t\t\tlet cPrev: number = 1.0;\n\t\t\tlet sPrev: number = 0.0;\n\t\t\tfor (let index: number = 1; index < midSubStride; index++) {\n\t\t\t\tconst indexA0: number = startIndexA + index;\n\t\t\t\tconst indexA1: number = startIndexB - index;\n\t\t\t\tconst indexB0: number = startIndexB + index;\n\t\t\t\tconst indexB1: number = stopIndex - index;\n\t\t\t\tconst real0: number = array[indexA0];\n\t\t\t\tconst real1: number = array[indexA1];\n\t\t\t\tconst imag0: number = array[indexB0];\n\t\t\t\tconst imag1: number = array[indexB1];\n\t\t\t\tconst tempA: number = real0 - real1;\n\t\t\t\tconst tempB: number = imag0 + imag1;\n\t\t\t\tarray[indexA0] = real0 + real1;\n\t\t\t\tarray[indexA1] = imag1 - imag0;\n\t\t\t\tarray[indexB0] = tempA * c - tempB * s;\n\t\t\t\tarray[indexB1] = tempB * c + tempA * s;\n\t\t\t\tconst cTemp: number = oscillatorMultiplier * c - cPrev;\n\t\t\t\tconst sTemp: number = oscillatorMultiplier * s - sPrev;\n\t\t\t\tcPrev = c;\n\t\t\t\tsPrev = s;\n\t\t\t\tc = cTemp;\n\t\t\t\ts = sTemp;\n\t\t\t}\n\t\t}\n\t}\n\t/*\n\t// Commented out this block (and compensated with an extra pass above)\n\t// because it's slower in my testing so far.\n\t// Pass with stride 8.\n\tconst sqrt2over2: number = Math.sqrt(2.0) / 2.0;\n\tfor (let index: number = 0; index < fullArrayLength; index += 8) {\n\t\tconst index1: number = index + 1;\n\t\tconst index2: number = index + 2;\n\t\tconst index3: number = index + 3;\n\t\tconst index4: number = index + 4;\n\t\tconst index5: number = index + 5;\n\t\tconst index6: number = index + 6;\n\t\tconst index7: number = index + 7;\n\t\tconst real0: number = array[index ];\n\t\tconst real1: number = array[index1];\n\t\tconst real2: number = array[index2];\n\t\tconst real3: number = array[index3];\n\t\tconst imag4: number = array[index4];\n\t\tconst imag5: number = array[index5];\n\t\tconst imag6: number = array[index6];\n\t\tconst imag7: number = array[index7];\n\t\tconst tempA: number = real1 - real3;\n\t\tconst tempB: number = imag5 + imag7;\n\t\tarray[index ] = real0 + imag4;\n\t\tarray[index1] = real1 + real3;\n\t\tarray[index2] = real2 * 2;\n\t\tarray[index3] = imag7 - imag5;\n\t\tarray[index4] = real0 - imag4;\n\t\tarray[index5] = (tempA + tempB) * sqrt2over2;\n\t\tarray[index6] = imag6 * 2;\n\t\tarray[index7] = (tempB - tempA) * sqrt2over2;\n\t}\n\t*/\n\t// The final passes with strides 4 and 2, combined into one loop.\n\tfor (let index: number = 0; index < fullArrayLength; index += 4) {\n\t\tconst index1: number = index + 1;\n\t\tconst index2: number = index + 2;\n\t\tconst index3: number = index + 3;\n\t\tconst real0: number = array[index ];\n\t\tconst real1: number = array[index1] * 2;\n\t\tconst imag2: number = array[index2];\n\t\tconst imag3: number = array[index3] * 2;\n\t\tconst tempA: number = real0 + imag2;\n\t\tconst tempB: number = real0 - imag2;\n\t\tarray[index ] = tempA + real1;\n\t\tarray[index1] = tempA - real1;\n\t\tarray[index2] = tempB + imag3;\n\t\tarray[index3] = tempB - imag3;\n\t}\n\t\n\treverseIndexBits(array, fullArrayLength);\n}\n","// Copyright (c) 2012-2022 John Nesky and contributing authors, distributed under the MIT license, see accompanying the LICENSE.md file.\n\nexport class Deque<T> {\n\tprivate _capacity: number = 1;\n\tprivate _buffer: Array<T | undefined> = [undefined];\n\tprivate _mask: number = 0;\n\tprivate _offset: number = 0;\n\tprivate _count: number = 0;\n\n\tpublic pushFront(element: T): void {\n\t\tif (this._count >= this._capacity) this._expandCapacity();\n\t\tthis._offset = (this._offset - 1) & this._mask;\n\t\tthis._buffer[this._offset] = element;\n\t\tthis._count++;\n\t}\n\tpublic pushBack(element: T): void {\n\t\tif (this._count >= this._capacity) this._expandCapacity();\n\t\tthis._buffer[(this._offset + this._count) & this._mask] = element;\n\t\tthis._count++;\n\t}\n\tpublic popFront(): T {\n\t\tif (this._count <= 0) throw new Error(\"No elements left to pop.\");\n\t\tconst element: T = <T>this._buffer[this._offset];\n\t\tthis._buffer[this._offset] = undefined;\n\t\tthis._offset = (this._offset + 1) & this._mask;\n\t\tthis._count--;\n\t\treturn element;\n\t}\n\tpublic popBack(): T {\n\t\tif (this._count <= 0) throw new Error(\"No elements left to pop.\");\n\t\tthis._count--;\n\t\tconst index: number = (this._offset + this._count) & this._mask;\n\t\tconst element: T = <T>this._buffer[index];\n\t\tthis._buffer[index] = undefined;\n\t\treturn element;\n\t}\n\tpublic peakFront(): T {\n\t\tif (this._count <= 0) throw new Error(\"No elements left to pop.\");\n\t\treturn <T>this._buffer[this._offset];\n\t}\n\tpublic peakBack(): T {\n\t\tif (this._count <= 0) throw new Error(\"No elements left to pop.\");\n\t\treturn <T>this._buffer[(this._offset + this._count - 1) & this._mask];\n\t}\n\tpublic count(): number {\n\t\treturn this._count;\n\t}\n\tpublic set(index: number, element: T): void {\n\t\tif (index < 0 || index >= this._count) throw new Error(\"Invalid index\");\n\t\tthis._buffer[(this._offset + index) & this._mask] = element;\n\t}\n\tpublic get(index: number): T {\n\t\tif (index < 0 || index >= this._count) throw new Error(\"Invalid index\");\n\t\treturn <T>this._buffer[(this._offset + index) & this._mask];\n\t}\n\tpublic remove(index: number): void {\n\t\tif (index < 0 || index >= this._count) throw new Error(\"Invalid index\");\n\t\tif (index <= (this._count >> 1)) {\n\t\t\twhile (index > 0) {\n\t\t\t\tthis.set(index, this.get(index - 1));\n\t\t\t\tindex--;\n\t\t\t}\n\t\t\tthis.popFront();\n\t\t} else {\n\t\t\tindex++;\n\t\t\twhile (index < this._count) {\n\t\t\t\tthis.set(index - 1, this.get(index));\n\t\t\t\tindex++;\n\t\t\t}\n\t\t\tthis.popBack();\n\t\t}\n\t}\n\tprivate _expandCapacity(): void {\n\t\tif (this._capacity >= 0x40000000) throw new Error(\"Capacity too big.\");\n\t\tthis._capacity = this._capacity << 1;\n\t\tconst oldBuffer: Array<T | undefined> = this._buffer;\n\t\tconst newBuffer: Array<T | undefined> = new Array(this._capacity);\n\t\tconst size: number = this._count | 0;\n\t\tconst offset: number = this._offset | 0;\n\t\tfor (let i = 0; i < size; i++) {\n\t\t\tnewBuffer[i] = oldBuffer[(offset + i) & this._mask];\n\t\t}\n\t\tfor (let i = size; i < this._capacity; i++) {\n\t\t\tnewBuffer[i] = undefined;\n\t\t}\n\t\tthis._offset = 0;\n\t\tthis._buffer = newBuffer;\n\t\tthis._mask = this._capacity - 1;\n\t}\n}\n","/*\nThis file contains code to compute digital audio filter coefficients based on\nthe desired type, cutoff frequency, and other parameters. You can use these\ncoefficients to apply the filter to audio samples. It also contains code to\nanalyze these filters, which is useful for graphically displaying their effects.\n\nAll of the filters in this file are known as \"Infinite Impulse Response\" or IIR\nfilters, because older output samples contribute feedback to newer output\nsamples and thus contribute to all future samples, although typically filters\nare design to reduce the contribution of older samples over time.\n\nLow-pass filters aka high-cut filters preserve audio signals below the cutoff\nfrequency, and attenuate audio signals above the cutoff frequency. High-pass\nfilters aka low-cut filters are the reverse. All-pass filters do not affect the\nvolume of the signal at all but induce phase changes above the cutoff frequency.\nPeak/Notch filters maintain the volume on either side of the cutoff frequency,\nbut raise or lower the volume at that frequency. \n\nThe number of old samples used in the filter determines the \"order\" of the\nfilter. First-order filters generally have shallower slopes, and second-order\nfilters generally have steeper slopes and can be configured to \"resonate\",\nmeaning they have a louder peak at the cutoff frequency. This file contains\nfirst-order filters and second-order filters, meaning one or two older samples\nare involved, as well as the current input sample.\n\nThe class FilterCoefficients is defined lower in this file. You can use it to\nset up a first order filter like this:\n\n\tconst cutoffRadiansPerSample: number = 2 * Math.PI * cutoffHz / sampleRate;\n\tconst filter: FilterCoefficients = new FilterCoefficients();\n\tfilter.lowPass1stOrderButterworth(cutoffRadiansPerSample);\n\t// output sample coefficients are conventionally called a0, a1, etc. Note\n\t// that a[0] is typically normalized to 1.0 and need not be used directly.\n\tconst a: number[] = filter.a;\n\t// input sample coefficients are conventionally called b0, b1, etc\n\tconst b: number[] = filter.b;\n\t// filter input samples, x[0] is the most recent, x[1] is the previous one, etc.\n\tconst x: number[] = [0, 0, 0];\n\t// filter output samples, y[0] will be computed by the filter based on input\n\t// samples and older output samples.\n\tconst y: number[] = [0, 0, 0];\n\nThen to apply the first-order filter to samples inside a loop, using the current\ninput sample (x[0]) as well as previous input and output samples, do this:\n\n\t// Compute the next output sample y[0]:\n\ty[0] = b[0] * x[0] + b[1] * x[1] - a[1] * y[1];\n\t// Remember the input and output samples for next time:\n\tx[1] = x[0];\n\ty[1] = y[0];\n\n2nd order filters are similar, but have more parameters and require more old\nsamples:\n\n\t// Compute the next output sample y[0]:\n\ty[0] = b[0] * x[0] + b[1] * x[1] + b[2] * x[2] - a[1] * y[1] - a[2] * y[2];\n\t// Remember the input and output samples for next time:\n\tx[2] = x[1];\n\tx[1] = x[0];\n\ty[2] = y[1];\n\ty[1] = y[0];\n\nYou can compose multiple filters into a higher order filter, although doing so\nreduces the numerical stability of the filter:\n\n\tfilter3.combination(filter1, filter2);\n\t// filter3.order will equal: filter1.order + filter2.order\n\t// The number of coefficients in filter3.a and filter3.b will be: order + 1\n\nThis file also contains a class called FrequencyResponse. You can use it to\ndetermine how much gain or attenuation a filter would apply to sounds at a\nspecific input frequency, as well as the phase offset:\n\n\tconst inputRadians: number = 2 * Math.PI * cutoffHz / sampleRate;\n\tconst response: FrequencyResponse = new FrequencyResponse();\n\tresponse.analyze(filter, inputRadians);\n\tconst gainResponse = response.magnitude();\n\tconst phaseResponse = response.angle();\n\nThat's basically all you need to know to use this code, but I'll also explain\nhow the analysis works.\n\nA first-order digital IIR filter is ordinarily implemented in a form like this:\n\n\toutput = inputCoeff * input + prevInputCoeff * prevInput - prevOutputCoeff * prevOutput;\n\nIf we adopt standard naming conventions for audio filters, this same code would\ninstead look like:\n\n\t// x0 = current input, x1 = prevInput, y0 = current output, y1 = prevOutput\n\ty0 = b0*x0 + b1*x1 - a1*y1;\n\nLeaving behind the world of code for a moment and entering the world of algebra,\nwe can rewrite this equation by moving all the output terms to the left side,\nand we can add a coefficient to the y0 term called a0 (which is typically\nnormalized to 1.0, which is why I didn't bother including it until now):\n\n\ta0*y0 + a1*y1 = b0*x0 + b1*x1\n\nThis is known as the symmetrical form of the filter, and it will help us analyze\nthe impact of the filter on an input audio signal. Here's a lesson that helped\nme understand the symmetrical form:\nhttps://web.archive.org/web/20200626183458/http://123.physics.ucdavis.edu/week_5_files/filters/digital_filter.pdf\n\nThe end of that lesson introduces a concept called the \"delay operator\" which\nlooks like \"z^-1\", which (magically) turns a sample into the previous sample\nwhen you multiply them. For example:\n\n\tx0 * z^-1 = x1\n\nThe lesson doesn't explain how it actually works. Audio signals aren't always\npredictable, which means that you generally can't do math on a single sample to\ncompute what the previous sample was. However, some audio signals ARE\npredictable, such as pure sine waves. Fortunately, all audio signals can be\nbroken down into a sum of independent sine waves. We can pick one sine wave at a\ntime, and use it to analyze the filter's impact on waves at that frequency. In\npractice, this tells us what the filter will do to unpredictable input samples\nthat contain a partial sine wave at that frequency.\n\nTechnically, you can't just use a single sine wave sample to determine the\nprevious sine wave sample, because each possible value is passed going upwards\nand downwards once per period and the direction is ambigous. This is where we\nneed to move into the complex number domain, where the real and imaginary\ncomponents can provide enough information to compute the previous position on\nthe input signal. So now instead of talking about sine waves, we're talking\nabout waves where the imaginary component is a sine wave and the real component\nis a cosine wave at the same frequency. Together, they trace around a unit\ncircle in the complex domain, and each sample is just a consistent rotation\napplied to the previous sample. The \"delay operator\" described above, z^-1, is\nthis same rotation applied in reverse, and it can be computed as:\n\n\tz^-1 = cos(radiansPerSample) - i * sin(radiansPerSample)\n\nMath nerds may be interested to know that \"Euler's formula\" was used here, but\nexplaining what that means is probably beyond the scope of this documentation\naside from noting that a complex number on the unit circle represents a 2D\nrotation that you can apply via multiplication.\n\nNow we can rewrite the symmetrical form using the delay operator and algebra:\n\n\ta0*y0 + a1*y0*z^-1 = b0*x0 + b1*x0*z^-1\n\ty0 * (a0 + a1*z^-1) = x0 * (b0 + b1*z^-1)\n\ty0 = x0 * (b0 + b1*z^-1) / (a0 + a1*z^-1)\n\ty0 / x0 = (b0 + b1*z^-1) / (a0 + a1*z^-1)\n\nThat last equation expresses the relationship between the input and output\nsignals (y0/x0) in terms of the filter coefficients and delay operator. At this\npoint, the specific values of the input and output samples don't even matter!\nThis is called the \"transfer function\", and it's conventionally named \"H(z)\":\n\n\tH(z) = (b0 + b1*z^-1) / (a0 + a1*z^-1)\n\nIf you plug in actual filter coefficients and express the delay operators as\ncomplex numbers with the appropriate trigonometry functions, the transfer\nfunction can be computed and produces a complex number that represents the\nrelationship between the input and output signals, whose magnitude represents\nthe volume gain (or attenuation) of signals at that frequency, and whose angle\nrepresents how much phase shift is applied by the filter to signals at that\nfrequency.\n\n(Note that in order to compute the transfer function, you'll need to do\nsomething about the complex number in the denominator. It turns out you can turn\nthe denominator into a real number by multiplying both the numerator and\ndenominator by the complex conjugate of the denominator, which is just the\ndenominator with the imaginary component negated.)\n\nFinally, I'll list some of the links that helped me understand filters and\nprovided some of the algorithms I that use here.\n\nHere's where I found accurate 2nd order low-pass, high-pass, and high-shelf\ndigital filters:\nhttps://web.archive.org/web/20120531011328/http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt\n\nThis page is how I found a link to the cookbook article above. It claims these\nfilters are Butterworth filters:\nhttp://web.archive.org/web/20191213120120/https://crypto.stanford.edu/~blynn/sound/analog.html\n\nI found the first-order digital Butterworth filter coefficients at:\nhttps://www.researchgate.net/publication/338022014_Digital_Implementation_of_Butterworth_First-Order_Filter_Type_IIR\n\nThis meta-paper helped me understand how to make 2nd order peak/notch filters:\nhttps://web.archive.org/web/20170706085655/https://www.thesounddesign.com/MIO/EQ-Coefficients.pdf\n\nBeepBox originally used simpler low-pass filters that I adapted from SFXR:\nhttps://www.drpetter.se/project_sfxr.html\nFor low cutoff frequencies, the simpler filters and the Butterworth filters are\nnearly identical, but when closer to the nyquist frequency the simpler filters\ncreate extra resonance.\n*/\n\nexport class FilterCoefficients {\n\tpublic readonly a: number[] = [1.0]; // output coefficients (negated, keep a[0]=1)\n\tpublic readonly b: number[] = [1.0]; // input coefficients\n\tpublic order: number = 0;\n\t\n\tpublic linearGain0thOrder(linearGain: number): void {\n\t\t//a[0] = 1.0; // a0 should always be normalized to 1.0, no need to assign it directly.\n\t\tthis.b[0] = linearGain;\n\t\tthis.order = 0;\n\t}\n\t\n\tpublic lowPass1stOrderButterworth(cornerRadiansPerSample: number): void {\n\t\t// First-order Butterworth low-pass filter according to:\n\t\t// https://www.researchgate.net/publication/338022014_Digital_Implementation_of_Butterworth_First-Order_Filter_Type_IIR\n\t\t// A butterworth filter is one where the amplitude response is equal to:\n\t\t// 1 / √(1 + (freq / cutoffFreq)^(2 * order))\n\t\tconst g: number = 1.0 / Math.tan(cornerRadiansPerSample * 0.5);\n\t\tconst a0: number = 1.0 + g;\n\t\tthis.a[1] = (1.0 - g) / a0;\n\t\tthis.b[1] = this.b[0] = 1 / a0;\n\t\tthis.order = 1;\n\t}\n\t\n\tpublic lowPass1stOrderSimplified(cornerRadiansPerSample: number): void {\n\t\t// The output of this filter is nearly identical to the 1st order\n\t\t// Butterworth low-pass above, except if the cutoff is set to nyquist/3,\n\t\t// then the output is the same as the input, and if the cutoff is higher\n\t\t// than that, then the output actually resonates at high frequencies\n\t\t// instead of attenuating.\n\t\t// I'm guessing this filter was converted from analog to digital using\n\t\t// the \"matched z-transform\" method instead of the \"bilinear transform\"\n\t\t// method. The difference is that the bilinear transform warps\n\t\t// frequencies so that the lowpass response of zero at analogue ∞hz maps\n\t\t// to the digital nyquist frequency, whereas the matched z-transform\n\t\t// preserves the frequency of the filter response but also adds the\n\t\t// reflected response from above the nyquist frequency.\n\t\tconst g: number = 2.0 * Math.sin(cornerRadiansPerSample * 0.5);\n\t\tthis.a[1] = g - 1.0;\n\t\tthis.b[0] = g;\n\t\tthis.b[1] = 0.0;\n\t\t/*\n\t\t// Alternatively:\n\t\tconst g: number = 1.0 / (2.0 * Math.sin(cornerRadiansPerSample / 2));\n\t\tconst a0: number = g;\n\t\tthis.a[1] = (1.0 - g) / a0;\n\t\tthis.b[0] = 1.0 / a0;\n\t\tthis.b[1] = 0.0 / a0;\n\t\t*/\n\t\tthis.order = 1;\n\t}\n\t\n\tpublic highPass1stOrderButterworth(cornerRadiansPerSample: number): void {\n\t\t// First-order Butterworth high-pass filter according to:\n\t\t// https://www.researchgate.net/publication/338022014_Digital_Implementation_of_Butterworth_First-Order_Filter_Type_IIR\n\t\tconst g: number = 1.0 / Math.tan(cornerRadiansPerSample * 0.5);\n\t\tconst a0: number = 1.0 + g;\n\t\tthis.a[1] = (1.0 - g) / a0;\n\t\tthis.b[0] = g / a0;\n\t\tthis.b[1] = -g / a0;\n\t\tthis.order = 1;\n\t}\n\t/*\n\tpublic highPass1stOrderSimplified(cornerRadiansPerSample: number): void {\n\t\t// The output of this filter is nearly identical to the 1st order\n\t\t// Butterworth high-pass above, except it resonates when the cutoff\n\t\t// appoaches the nyquist.\n\t\tconst g: number = 2.0 * Math.sin(cornerRadiansPerSample * 0.5);\n\t\tthis.a[1] = g - 1.0;\n\t\tthis.b[0] = 1.0;\n\t\tthis.b[1] = -1.0;\n\t\tthis.order = 1;\n\t}\n\t*/\n\tpublic highShelf1stOrder(cornerRadiansPerSample: number, shelfLinearGain: number): void {\n\t\t// I had trouble figuring this one out because I couldn't find any\n\t\t// online algorithms that I understood. There are 3 degrees of freedom\n\t\t// and I could narrow down a couple of them based on the desired gain at\n\t\t// DC and nyquist, but getting the cutoff frequency correct took a\n\t\t// little bit of trial and error in my attempts to interpret page 53 of\n\t\t// this chapter: http://www.music.mcgill.ca/~ich/classes/FiltersChap2.pdf\n\t\t// Obviously I don't fully understand the bilinear transform yet!\n\t\tconst tan: number = Math.tan(cornerRadiansPerSample * 0.5);\n\t\tconst sqrtGain: number = Math.sqrt(shelfLinearGain);\n\t\tconst g: number = (tan * sqrtGain - 1) / (tan * sqrtGain + 1.0);\n\t\tconst a0: number = 1.0;\n\t\tthis.a[1] = g / a0;\n\t\tthis.b[0] = (1.0 + g + shelfLinearGain * (1.0 - g)) / (2.0 * a0);\n\t\tthis.b[1] = (1.0 + g - shelfLinearGain * (1.0 - g)) / (2.0 * a0);\n\t\tthis.order = 1;\n\t}\n\t\n\tpublic allPass1stOrderInvertPhaseAbove(cornerRadiansPerSample: number): void {\n\t\tconst g: number = (Math.sin(cornerRadiansPerSample) - 1.0) / Math.cos(cornerRadiansPerSample);\n\t\tthis.a[1] = g;\n\t\tthis.b[0] = g;\n\t\tthis.b[1] = 1.0;\n\t\tthis.order = 1;\n\t}\n\t\n\t/*\n\t// I haven't found a practical use for this version of the all pass filter.\n\t// It seems to create a weird subharmonic when used in a delay feedback loop.\n\tpublic allPass1stOrderInvertPhaseBelow(cornerRadiansPerSample: number): void {\n\t\tconst g: number = (Math.sin(cornerRadiansPerSample) - 1.0) / Math.cos(cornerRadiansPerSample);\n\t\tthis.a[1] = g;\n\t\tthis.b[0] = -g;\n\t\tthis.b[1] = -1.0;\n\t\tthis.order = 1;\n\t}\n\t*/\n\t\n\tpublic allPass1stOrderFractionalDelay(delay: number) {\n\t\t// Very similar to allPass1stOrderInvertPhaseAbove, but configured\n\t\t// differently and for a different purpose! Useful for interpolating\n\t\t// between samples in a delay line.\n\t\tconst g: number = (1.0 - delay) / (1.0 + delay);\n\t\tthis.a[1] = g;\n\t\tthis.b[0] = g;\n\t\tthis.b[1] = 1.0;\n\t\tthis.order = 1;\n\t}\n\t\n\tpublic lowPass2ndOrderButterworth(cornerRadiansPerSample: number, peakLinearGain: number): void {\n\t\t// This is Butterworth if peakLinearGain=1/√2 according to:\n\t\t// http://web.archive.org/web/20191213120120/https://crypto.stanford.edu/~blynn/sound/analog.html\n\t\t// An interesting property is that if peakLinearGain=1/16 then the\n\t\t// output resembles a first-order lowpass at a cutoff 4 octaves lower,\n\t\t// although it gets distorted near the nyquist.\n\t\tconst alpha: number = Math.sin(cornerRadiansPerSample) / (2.0 * peakLinearGain);\n\t\tconst cos: number = Math.cos(cornerRadiansPerSample);\n\t\tconst a0: number = 1.0 + alpha;\n\t\tthis.a[1] = -2.0*cos / a0;\n\t\tthis.a[2] = (1 - alpha) / a0;\n\t\tthis.b[2] = this.b[0] = (1 - cos) / (2.0*a0);\n\t\tthis.b[1] = (1 - cos) / a0;\n\t\tthis.order = 2;\n\t}\n\t\n\tpublic lowPass2ndOrderSimplified(cornerRadiansPerSample: number, peakLinearGain: number): void {\n\t\t// This filter is adapted from the one in the SFXR source code:\n\t\t// https://www.drpetter.se/project_sfxr.html\n\t\t// The output is nearly identical to the resonant Butterworth low-pass\n\t\t// above, except it resonates too much when the cutoff appoaches the\n\t\t// nyquist. If the resonance is set to zero and the cutoff is set to\n\t\t// nyquist/3, then the output is the same as the input.\n\t\tconst g: number = 2.0 * Math.sin(cornerRadiansPerSample / 2.0);\n\t\tconst filterResonance: number = 1.0 - 1.0 / (2.0 * peakLinearGain);\n\t\tconst feedback: number = filterResonance + filterResonance / (1.0 - g);\n\t\tthis.a[1] = 2.0*g + (g - 1.0) * g*feedback - 2.0;\n\t\tthis.a[2] = (g - 1.0) * (g - g*feedback - 1.0);\n\t\tthis.b[0] = g*g;\n\t\tthis.b[1] = 0;\n\t\tthis.b[2] = 0;\n\t\tthis.order = 2;\n\t}\n\t\n\tpublic highPass2ndOrderButterworth(cornerRadiansPerSample: number, peakLinearGain: number): void {\n\t\tconst alpha: number = Math.sin(cornerRadiansPerSample) / (2 * peakLinearGain);\n\t\tconst cos: number = Math.cos(cornerRadiansPerSample);\n\t\tconst a0: number = 1.0 + alpha;\n\t\tthis.a[1] = -2.0*cos / a0;\n\t\tthis.a[2] = (1.0 - alpha) / a0;\n\t\tthis.b[2] = this.b[0] = (1.0 + cos) / (2.0*a0);\n\t\tthis.b[1] = -(1.0 + cos) / a0;\n\t\tthis.order = 2;\n\t}\n\t/*\n\tpublic highPass2ndOrderSimplified(cornerRadiansPerSample: number, peakLinearGain: number): void {\n\t\tconst g: number = 2.0 * Math.sin(cornerRadiansPerSample * 0.5);\n\t\tconst filterResonance: number = 1.0 - 1.0 / (2.0 * peakLinearGain);\n\t\tconst feedback: number = filterResonance + filterResonance / (1.0 - g);\n\t\tthis.a[1] = 2.0*g + (g - 1.0) * g*feedback - 2.0;\n\t\tthis.a[2] = (g - 1.0) * (g - g*feedback - 1.0);\n\t\tthis.b[0] = 1.0;\n\t\tthis.b[1] = -2.0;\n\t\tthis.b[2] = 1.0;\n\t\tthis.order = 2;\n\t}\n\t*/\n\t\n\tpublic highShelf2ndOrder(cornerRadiansPerSample: number, shelfLinearGain: number, slope: number): void {\n\t\tconst A: number = Math.sqrt(shelfLinearGain);\n\t\tconst c: number = Math.cos(cornerRadiansPerSample);\n\t\tconst Aplus: number = A + 1.0;\n\t\tconst Aminus: number = A - 1.0;\n\t\tconst alpha: number = Math.sin(cornerRadiansPerSample) * 0.5 * Math.sqrt((Aplus / A) * (1.0 / slope - 1.0) + 2.0);\n\t\tconst sqrtA2Alpha: number = 2.0 * Math.sqrt(A) * alpha;\n\t\tconst a0: number = (Aplus - Aminus * c + sqrtA2Alpha);\n\t\tthis.a[1] = 2 * (Aminus - Aplus * c ) / a0;\n\t\tthis.a[2] = (Aplus - Aminus * c - sqrtA2Alpha) / a0;\n\t\tthis.b[0] = A * (Aplus + Aminus * c + sqrtA2Alpha) / a0;\n\t\tthis.b[1] = -2 * A * (Aminus + Aplus * c ) / a0;\n\t\tthis.b[2] = A * (Aplus + Aminus * c - sqrtA2Alpha) / a0;\n\t\tthis.order = 2;\n\t}\n\t\n\tpublic peak2ndOrder(cornerRadiansPerSample: number, peakLinearGain: number, bandWidthScale: number): void {\n\t\tconst sqrtGain: number = Math.sqrt(peakLinearGain);\n\t\tconst bandWidth: number = bandWidthScale * cornerRadiansPerSample / (sqrtGain >= 1 ? sqrtGain : 1/sqrtGain);\n\t\t//const bandWidth: number = bandWidthScale * cornerRadiansPerSample / Math.max(sqrtGain, 1.0);\n\t\tconst alpha: number = Math.tan(bandWidth * 0.5);\n\t\tconst a0: number = 1.0 + alpha / sqrtGain;\n\t\tthis.b[0] = (1.0 + alpha * sqrtGain) / a0;\n\t\tthis.b[1] = this.a[1] = -2.0 * Math.cos(cornerRadiansPerSample) / a0;\n\t\tthis.b[2] = (1.0 - alpha * sqrtGain) / a0;\n\t\tthis.a[2] = (1.0 - alpha / sqrtGain) / a0;\n\t\tthis.order = 2;\n\t}\n\t/*\n\t// Create a higher order filter by combining two lower order filters.\n\t// However, making high order filters in this manner results in instability.\n\t// It is recommended to apply the 2nd order filters (biquads) in sequence instead.\n\tpublic combination(filter1: FilterCoefficients, filter2: FilterCoefficients): void {\n\t\tthis.order = filter1.order + filter2.order;\n\t\tfor (let i: number = 0; i <= this.order; i++) {\n\t\t\tthis.a[i] = 0.0;\n\t\t\tthis.b[i] = 0.0;\n\t\t}\n\t\tfor (let i: number = 0; i <= filter1.order; i++) {\n\t\t\tfor (let j: number = 0; j <= filter2.order; j++) {\n\t\t\t\tthis.a[i + j] += filter1.a[i] * filter2.a[j];\n\t\t\t\tthis.b[i + j] += filter1.b[i] * filter2.b[j];\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic scaledDifference(other: FilterCoefficients, scale: number): void {\n\t\tif (other.order != this.order) throw new Error();\n\t\tfor (let i: number = 0; i <= this.order; i++) {\n\t\t\tthis.a[i] = (this.a[i] - other.a[i]) * scale;\n\t\t\tthis.b[i] = (this.b[i] - other.b[i]) * scale;\n\t\t}\n\t}\n\t\n\tpublic copy(other: FilterCoefficients): void {\n\t\tthis.order = other.order;\n\t\tfor (let i: number = 0; i <= this.order; i++) {\n\t\t\tthis.a[i] = other.a[i];\n\t\t\tthis.b[i] = other.b[i];\n\t\t}\n\t}\n\t*/\n}\n\nexport class FrequencyResponse {\n\tpublic real: number = 0.0;\n\tpublic imag: number = 0.0;\n\tpublic denom: number = 1.0;\n\t\n\tpublic analyze(filter: FilterCoefficients, radiansPerSample: number): void {\n\t\tthis.analyzeComplex(filter, Math.cos(radiansPerSample), Math.sin(radiansPerSample));\n\t}\n\t\n\tpublic analyzeComplex(filter: FilterCoefficients, real: number, imag: number): void {\n\t\tconst a: number[] = filter.a;\n\t\tconst b: number[] = filter.b;\n\t\tconst realZ1: number = real;\n\t\tconst imagZ1: number = -imag;\n\t\tlet realNum: number = b[0] + b[1] * realZ1;\n\t\tlet imagNum: number = b[1] * imagZ1;\n\t\tlet realDenom: number = 1.0 + a[1] * realZ1;\n\t\tlet imagDenom: number = a[1] * imagZ1;\n\t\tlet realZ: number = realZ1;\n\t\tlet imagZ: number = imagZ1;\n\t\tfor (let i: number = 2; i <= filter.order; i++) {\n\t\t\tconst realTemp: number = realZ * realZ1 - imagZ * imagZ1;\n\t\t\tconst imagTemp: number = realZ * imagZ1 + imagZ * realZ1;\n\t\t\trealZ = realTemp;\n\t\t\timagZ = imagTemp;\n\t\t\trealNum += b[i] * realZ;\n\t\t\timagNum += b[i] * imagZ;\n\t\t\trealDenom += a[i] * realZ;\n\t\t\timagDenom += a[i] * imagZ;\n\t\t}\n\t\tthis.denom = realDenom * realDenom + imagDenom * imagDenom;\n\t\tthis.real = realNum * realDenom + imagNum * imagDenom;\n\t\tthis.imag = imagNum * realDenom - realNum * imagDenom;\n\t}\n\t\n\tpublic magnitude(): number {\n\t\treturn Math.sqrt(this.real * this.real + this.imag * this.imag) / this.denom;\n\t}\n\t\n\tpublic angle(): number {\n\t\treturn Math.atan2(this.imag, this.real);\n\t}\n}\n\nexport class DynamicBiquadFilter {\n\tpublic a1: number = 0.0;\n\tpublic a2: number = 0.0;\n\tpublic b0: number = 1.0;\n\tpublic b1: number = 0.0;\n\tpublic b2: number = 0.0;\n\tpublic a1Delta: number = 0.0;\n\tpublic a2Delta: number = 0.0;\n\tpublic b0Delta: number = 0.0;\n\tpublic b1Delta: number = 0.0;\n\tpublic b2Delta: number = 0.0;\n\tpublic output1: number = 0.0;\n\tpublic output2: number = 0.0;\n\t\n\t// Some filter types are more stable when interpolating between coefficients\n\t// if the \"b\" coefficient interpolation is multiplicative. Don't enable this\n\t// for filter types where the \"b\" coefficients might change sign!\n\tpublic useMultiplicativeInputCoefficients: boolean = false;\n\t\n\tpublic resetOutput(): void {\n\t\tthis.output1 = 0.0;\n\t\tthis.output2 = 0.0;\n\t}\n\t\n\tpublic loadCoefficientsWithGradient(start: FilterCoefficients, end: FilterCoefficients, deltaRate: number, useMultiplicativeInputCoefficients: boolean): void {\n\t\tif (start.order != 2 || end.order != 2) throw new Error();\n\t\tthis.a1 = start.a[1];\n\t\tthis.a2 = start.a[2];\n\t\tthis.b0 = start.b[0];\n\t\tthis.b1 = start.b[1];\n\t\tthis.b2 = start.b[2];\n\t\tthis.a1Delta = (end.a[1] - start.a[1]) * deltaRate;\n\t\tthis.a2Delta = (end.a[2] - start.a[2]) * deltaRate;\n\t\tif (useMultiplicativeInputCoefficients) {\n\t\t\tthis.b0Delta = Math.pow(end.b[0] / start.b[0], deltaRate);\n\t\t\tthis.b1Delta = Math.pow(end.b[1] / start.b[1], deltaRate);\n\t\t\tthis.b2Delta = Math.pow(end.b[2] / start.b[2], deltaRate);\n\t\t} else {\n\t\t\tthis.b0Delta = (end.b[0] - start.b[0]) * deltaRate;\n\t\t\tthis.b1Delta = (end.b[1] - start.b[1]) * deltaRate;\n\t\t\tthis.b2Delta = (end.b[2] - start.b[2]) * deltaRate;\n\t\t}\n\t\tthis.useMultiplicativeInputCoefficients = useMultiplicativeInputCoefficients;\n\t}\n}\n\n// Filters are typically designed as analog filters first, then converted to\n// digital filters using one of two methods: the \"matched z-transform\" or the\n// \"bilinear transform\". The \"bilinear transform\" does a better job of\n// preserving the magnitudes of the frequency response, but warps the frequency\n// range such that the nyquist frequency of the digital filter (π) maps to the\n// infinity frequency of the analog filter. You can use the below functions to\n// manually perform this warping in either direction.\nexport function warpNyquistToInfinity(radians: number): number {\n\treturn 2.0 * Math.tan(radians * 0.5);\n}\nexport function warpInfinityToNyquist(radians: number): number {\n\treturn 2.0 * Math.atan(radians * 0.5);\n}\n","// Copyright (c) 2012-2022 John Nesky and contributing authors, distributed under the MIT license, see accompanying the LICENSE.md file.\n\nimport {Dictionary, DictionaryArray, FilterType, SustainType, EnvelopeType, InstrumentType, EffectType, EnvelopeComputeIndex, Transition, Unison, Chord, Vibrato, Envelope, AutomationTarget, Config, getDrumWave, drawNoiseSpectrum, getArpeggioPitchIndex, performIntegral, getPulseWidthRatio, effectsIncludeTransition, effectsIncludeChord, effectsIncludePitchShift, effectsIncludeDetune, effectsIncludeVibrato, effectsIncludeNoteFilter, effectsIncludeDistortion, effectsIncludeBitcrusher, effectsIncludePanning, effectsIncludeChorus, effectsIncludeEcho, effectsIncludeReverb} from \"./SynthConfig\";\nimport {scaleElementsByFactor, inverseRealFourierTransform} from \"./FFT\";\nimport {Deque} from \"./Deque\";\nimport {FilterCoefficients, FrequencyResponse, DynamicBiquadFilter, warpInfinityToNyquist} from \"./filtering\";\n\ndeclare global {\n\tinterface Window {\n\t\tAudioContext: any;\n\t\twebkitAudioContext: any;\n\t}\n}\n\nconst epsilon: number = (1.0e-24); // For detecting and avoiding float denormals, which have poor performance.\n\n// For performance debugging:\n//let samplesAccumulated: number = 0;\n//let samplePerformance: number = 0;\n\nexport function clamp(min: number, max: number, val: number): number {\n\tmax = max - 1;\n\tif (val <= max) {\n\t\tif (val >= min) return val;\n\t\telse return min;\n\t} else {\n\t\treturn max;\n\t}\n}\n\nfunction validateRange(min: number, max: number, val: number): number {\n\tif (min <= val && val <= max) return val;\n\tthrow new Error(`Value ${val} not in range [${min}, ${max}]`);\n}\n\nconst enum CharCode {\n\tSPACE = 32,\n\tHASH = 35,\n\tPERCENT = 37,\n\tAMPERSAND = 38,\n\tPLUS = 43,\n\tDASH = 45,\n\tDOT = 46,\n\tNUM_0 = 48,\n\tNUM_1 = 49,\n\tNUM_2 = 50,\n\tNUM_3 = 51,\n\tNUM_4 = 52,\n\tNUM_5 = 53,\n\tNUM_6 = 54,\n\tNUM_7 = 55,\n\tNUM_8 = 56,\n\tNUM_9 = 57,\n\tEQUALS = 61,\n\tA = 65,\n\tB = 66,\n\tC = 67,\n\tD = 68,\n\tE = 69,\n\tF = 70,\n\tG = 71,\n\tH = 72,\n\tI = 73,\n\tJ = 74,\n\tK = 75,\n\tL = 76,\n\tM = 77,\n\tN = 78,\n\tO = 79,\n\tP = 80,\n\tQ = 81,\n\tR = 82,\n\tS = 83,\n\tT = 84,\n\tU = 85,\n\tV = 86,\n\tW = 87,\n\tX = 88,\n\tY = 89,\n\tZ = 90,\n\tUNDERSCORE = 95,\n\ta = 97,\n\tb = 98,\n\tc = 99,\n\td = 100,\n\te = 101,\n\tf = 102,\n\tg = 103,\n\th = 104,\n\ti = 105,\n\tj = 106,\n\tk = 107,\n\tl = 108,\n\tm = 109,\n\tn = 110,\n\to = 111,\n\tp = 112,\n\tq = 113,\n\tr = 114,\n\ts = 115,\n\tt = 116,\n\tu = 117,\n\tv = 118,\n\tw = 119,\n\tx = 120,\n\ty = 121,\n\tz = 122,\n\tLEFT_CURLY_BRACE = 123,\n\tRIGHT_CURLY_BRACE = 125,\n}\n\nconst enum SongTagCode {\n\tbeatCount = CharCode.a, // added in BeepBox URL version 2\n\tbars = CharCode.b, // added in BeepBox URL version 2\n\tvibrato = CharCode.c, // added in BeepBox URL version 2, DEPRECATED\n\tfadeInOut = CharCode.d, // added in BeepBox URL version 3 for transition, switched to fadeInOut in 9\n\tloopEnd = CharCode.e, // added in BeepBox URL version 2\n\teqFilter = CharCode.f, // added in BeepBox URL version 3\n\tbarCount = CharCode.g, // added in BeepBox URL version 3\n\tunison = CharCode.h, // added in BeepBox URL version 2\n\tinstrumentCount = CharCode.i, // added in BeepBox URL version 3\n\tpatternCount = CharCode.j, // added in BeepBox URL version 3\n\tkey = CharCode.k, // added in BeepBox URL version 2\n\tloopStart = CharCode.l, // added in BeepBox URL version 2\n\treverb = CharCode.m, // added in BeepBox URL version 5, DEPRECATED\n\tchannelCount = CharCode.n, // added in BeepBox URL version 6\n\tchannelOctave = CharCode.o, // added in BeepBox URL version 3\n\tpatterns = CharCode.p, // added in BeepBox URL version 2\n\teffects = CharCode.q, // added in BeepBox URL version 7\n\trhythm = CharCode.r, // added in BeepBox URL version 2\n\tscale = CharCode.s, // added in BeepBox URL version 2\n\ttempo = CharCode.t, // added in BeepBox URL version 2\n\tpreset = CharCode.u, // added in BeepBox URL version 7\n\tvolume = CharCode.v, // added in BeepBox URL version 2\n\twave = CharCode.w, // added in BeepBox URL version 2\n\tsupersaw = CharCode.x, // added in BeepBox URL version 9\n\tfilterResonance = CharCode.y, // added in BeepBox URL version 7, DEPRECATED\n\tdrumsetEnvelopes = CharCode.z, // added in BeepBox URL version 7 for filter envelopes, still used for drumset envelopes\n\talgorithm = CharCode.A, // added in BeepBox URL version 6\n\tfeedbackAmplitude = CharCode.B, // added in BeepBox URL version 6\n\tchord = CharCode.C, // added in BeepBox URL version 7, DEPRECATED\n//\t = CharCode.D, // added in JummBox URL version 3(?) for detune, DEPRECATED\n\tenvelopes = CharCode.E, // added in BeepBox URL version 6 for FM operator envelopes, repurposed in 9 for general envelopes.\n\tfeedbackType = CharCode.F, // added in BeepBox URL version 6\n//\t = CharCode.G, // added in JummBox URL version 3 for arpeggioSpeed, DEPRECATED\n\tharmonics = CharCode.H, // added in BeepBox URL version 7\n\tstringSustain = CharCode.I, // added in BeepBox URL version 9\n//\t = CharCode.J,\n//\t = CharCode.K,\n\tpan = CharCode.L, // added between 8 and 9, DEPRECATED\n//\t = CharCode.M, // added in JummBox URL version 1(?) for customChipWave\n//\t = CharCode.N, // added in JummBox URL version 1(?) for songTitle\n//\t = CharCode.O, // added in JummBox URL version 3(?) for limiterSettings\n\toperatorAmplitudes = CharCode.P, // added in BeepBox URL version 6\n\toperatorFrequencies = CharCode.Q, // added in BeepBox URL version 6\n//\t = CharCode.R, // added in JummBox URL version 4 for operatorWaves\n\tspectrum = CharCode.S, // added in BeepBox URL version 7\n\tstartInstrument = CharCode.T, // added in BeepBox URL version 6\n//\t = CharCode.U, // added in JummBox URL version 4(?) for channelNames\n\tfeedbackEnvelope = CharCode.V, // added in BeepBox URL version 6, DEPRECATED\n\tpulseWidth = CharCode.W, // added in BeepBox URL version 7\n//\t = CharCode.X, // added in JummBox URL version 4 for aliases, DEPRECATED\n//\t = CharCode.Y,\n//\t = CharCode.Z,\n//\t = CharCode.NUM_0,\n//\t = CharCode.NUM_1,\n//\t = CharCode.NUM_2,\n//\t = CharCode.NUM_3,\n//\t = CharCode.NUM_4,\n//\t = CharCode.NUM_5,\n//\t = CharCode.NUM_6,\n//\t = CharCode.NUM_7,\n//\t = CharCode.NUM_8,\n//\t = CharCode.NUM_9,\n//\t = CharCode.DASH,\n//\t = CharCode.UNDERSCORE,\n}\n\nconst base64IntToCharCode: ReadonlyArray<number> = [48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,45,95];\nconst base64CharCodeToInt: ReadonlyArray<number> = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,62,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,0,0,0,0,63,0,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,0,0,0,0,0]; // 62 could be represented by either \"-\" or \".\" for historical reasons. New songs should use \"-\".\n\nclass BitFieldReader {\n\tprivate _bits: number[] = [];\n\tprivate _readIndex: number = 0;\n\t\n\tconstructor(source: string, startIndex: number, stopIndex: number) {\n\t\tfor (let i: number = startIndex; i < stopIndex; i++) {\n\t\t\tconst value: number = base64CharCodeToInt[source.charCodeAt(i)];\n\t\t\tthis._bits.push((value >> 5) & 0x1);\n\t\t\tthis._bits.push((value >> 4) & 0x1);\n\t\t\tthis._bits.push((value >> 3) & 0x1);\n\t\t\tthis._bits.push((value >> 2) & 0x1);\n\t\t\tthis._bits.push((value >> 1) & 0x1);\n\t\t\tthis._bits.push( value & 0x1);\n\t\t}\n\t}\n\t\n\tpublic read(bitCount: number): number {\n\t\tlet result: number = 0;\n\t\twhile (bitCount > 0) {\n\t\t\tresult = result << 1;\n\t\t\tresult += this._bits[this._readIndex++];\n\t\t\tbitCount--;\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tpublic readLongTail(minValue: number, minBits: number): number {\n\t\tlet result: number = minValue;\n\t\tlet numBits: number = minBits;\n\t\twhile (this._bits[this._readIndex++]) {\n\t\t\tresult += 1 << numBits;\n\t\t\tnumBits++;\n\t\t}\n\t\twhile (numBits > 0) {\n\t\t\tnumBits--;\n\t\t\tif (this._bits[this._readIndex++]) {\n\t\t\t\tresult += 1 << numBits;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tpublic readPartDuration(): number {\n\t\treturn this.readLongTail(1, 3);\n\t}\n\t\n\tpublic readLegacyPartDuration(): number {\n\t\treturn this.readLongTail(1, 2);\n\t}\n\t\n\tpublic readPinCount(): number {\n\t\treturn this.readLongTail(1, 0);\n\t}\n\t\n\tpublic readPitchInterval(): number {\n\t\tif (this.read(1)) {\n\t\t\treturn -this.readLongTail(1, 3);\n\t\t} else {\n\t\t\treturn this.readLongTail(1, 3);\n\t\t}\n\t}\n}\n\nclass BitFieldWriter {\n\tprivate _index: number = 0;\n\tprivate _bits: number[] = [];\n\t\n\tpublic clear() {\n\t\tthis._index = 0;\n\t}\n\t\n\tpublic write(bitCount: number, value: number): void {\n\t\tbitCount--;\n\t\twhile (bitCount >= 0) {\n\t\t\tthis._bits[this._index++] = (value >>> bitCount) & 1;\n\t\t\tbitCount--;\n\t\t}\n\t}\n\t\n\tpublic writeLongTail(minValue: number, minBits: number, value: number): void {\n\t\tif (value < minValue) throw new Error(\"value out of bounds\");\n\t\tvalue -= minValue;\n\t\tlet numBits: number = minBits;\n\t\twhile (value >= (1 << numBits)) {\n\t\t\tthis._bits[this._index++] = 1;\n\t\t\tvalue -= 1 << numBits;\n\t\t\tnumBits++;\n\t\t}\n\t\tthis._bits[this._index++] = 0;\n\t\twhile (numBits > 0) {\n\t\t\tnumBits--;\n\t\t\tthis._bits[this._index++] = (value >>> numBits) & 1;\n\t\t}\n\t}\n\t\n\tpublic writePartDuration(value: number): void {\n\t\tthis.writeLongTail(1, 3, value);\n\t}\n\t\n\tpublic writePinCount(value: number): void {\n\t\tthis.writeLongTail(1, 0, value);\n\t}\n\t\n\tpublic writePitchInterval(value: number): void {\n\t\tif (value < 0) {\n\t\t\tthis.write(1, 1); // sign\n\t\t\tthis.writeLongTail(1, 3, -value);\n\t\t} else {\n\t\t\tthis.write(1, 0); // sign\n\t\t\tthis.writeLongTail(1, 3, value);\n\t\t}\n\t}\n\t\n\tpublic concat(other: BitFieldWriter): void {\n\t\tfor (let i: number = 0; i < other._index; i++) {\n\t\t\tthis._bits[this._index++] = other._bits[i];\n\t\t}\n\t}\n\t\n\tpublic encodeBase64(buffer: number[]): number[] {\n\t\tfor (let i: number = 0; i < this._index; i += 6) {\n\t\t\tconst value: number = (this._bits[i] << 5) | (this._bits[i+1] << 4) | (this._bits[i+2] << 3) | (this._bits[i+3] << 2) | (this._bits[i+4] << 1) | this._bits[i+5];\n\t\t\tbuffer.push(base64IntToCharCode[value]);\n\t\t}\n\t\treturn buffer;\n\t}\n\t\n\tpublic lengthBase64(): number {\n\t\treturn Math.ceil(this._index / 6);\n\t}\n}\n\nexport interface NotePin {\n\tinterval: number;\n\ttime: number;\n\tsize: number;\n}\n\nexport function makeNotePin(interval: number, time: number, size: number): NotePin {\n\treturn {interval: interval, time: time, size: size};\n}\n\nexport class Note {\n\tpublic pitches: number[];\n\tpublic pins: NotePin[];\n\tpublic start: number;\n\tpublic end: number;\n\tpublic continuesLastPattern: boolean;\n\t\n\tpublic constructor(pitch: number, start: number, end: number, size: number, fadeout: boolean = false) {\n\t\tthis.pitches = [pitch];\n\t\tthis.pins = [makeNotePin(0, 0, size), makeNotePin(0, end - start, fadeout ? 0 : size)];\n\t\tthis.start = start;\n\t\tthis.end = end;\n\t\tthis.continuesLastPattern = false;\n\t}\n\t\n\tpublic pickMainInterval(): number {\n\t\tlet longestFlatIntervalDuration: number = 0;\n\t\tlet mainInterval: number = 0;\n\t\tfor (let pinIndex: number = 1; pinIndex < this.pins.length; pinIndex++) {\n\t\t\tconst pinA: NotePin = this.pins[pinIndex - 1];\n\t\t\tconst pinB: NotePin = this.pins[pinIndex];\n\t\t\tif (pinA.interval == pinB.interval) {\n\t\t\t\tconst duration: number = pinB.time - pinA.time;\n\t\t\t\tif (longestFlatIntervalDuration < duration) {\n\t\t\t\t\tlongestFlatIntervalDuration = duration;\n\t\t\t\t\tmainInterval = pinA.interval;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (longestFlatIntervalDuration == 0) {\n\t\t\tlet loudestSize: number = 0;\n\t\t\tfor (let pinIndex: number = 0; pinIndex < this.pins.length; pinIndex++) {\n\t\t\t\tconst pin: NotePin = this.pins[pinIndex];\n\t\t\t\tif (loudestSize < pin.size) {\n\t\t\t\t\tloudestSize = pin.size;\n\t\t\t\t\tmainInterval = pin.interval;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn mainInterval;\n\t}\n\t\n\tpublic clone(): Note {\n\t\tconst newNote: Note = new Note(-1, this.start, this.end, Config.noteSizeMax);\n\t\tnewNote.pitches = this.pitches.concat();\n\t\tnewNote.pins = [];\n\t\tfor (const pin of this.pins) {\n\t\t\tnewNote.pins.push(makeNotePin(pin.interval, pin.time, pin.size));\n\t\t}\n\t\tnewNote.continuesLastPattern = this.continuesLastPattern;\n\t\treturn newNote;\n\t}\n\t\n\tpublic getEndPinIndex(part: number): number {\n\t\tlet endPinIndex: number;\n\t\tfor (endPinIndex = 1; endPinIndex < this.pins.length - 1; endPinIndex++) {\n\t\t\tif (this.pins[endPinIndex].time + this.start > part) break;\n\t\t}\n\t\treturn endPinIndex;\n\t}\n}\n\nexport class Pattern {\n\tpublic notes: Note[] = [];\n\tpublic readonly instruments: number[] = [0];\n\t\n\tpublic cloneNotes(): Note[] {\n\t\tconst result: Note[] = [];\n\t\tfor (const note of this.notes) {\n\t\t\tresult.push(note.clone());\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tpublic reset(): void {\n\t\tthis.notes.length = 0;\n\t\tthis.instruments[0] = 0;\n\t\tthis.instruments.length = 1;\n\t}\n\t\n\tpublic toJsonObject(song: Song): any {\n\t\tconst noteArray: Object[] = [];\n\t\tfor (const note of this.notes) {\n\t\t\tconst pointArray: Object[] = [];\n\t\t\tfor (const pin of note.pins) {\n\t\t\t\tpointArray.push({\n\t\t\t\t\t\"tick\": (pin.time + note.start) * Config.rhythms[song.rhythm].stepsPerBeat / Config.partsPerBeat,\n\t\t\t\t\t\"pitchBend\": pin.interval,\n\t\t\t\t\t\"volume\": Math.round(pin.size * 100 / 3),\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\tconst noteObject: any = {\n\t\t\t\t\"pitches\": note.pitches,\n\t\t\t\t\"points\": pointArray,\n\t\t\t};\n\t\t\tif (note.start == 0) {\n\t\t\t\tnoteObject[\"continuesLastPattern\"] = note.continuesLastPattern;\n\t\t\t}\n\t\t\tnoteArray.push(noteObject);\n\t\t}\n\t\t\n\t\tconst patternObject: any = {\"notes\": noteArray};\n\t\tif (song.patternInstruments) {\n\t\t\tpatternObject[\"instruments\"] = this.instruments.map(i => i + 1);\n\t\t}\n\t\treturn patternObject;\n\t}\n\t\n\tpublic fromJsonObject(patternObject: any, song: Song, channel: Channel, importedPartsPerBeat: number, isNoiseChannel: boolean): void {\n\t\tif (song.patternInstruments) {\n\t\t\tif (Array.isArray(patternObject[\"instruments\"])) {\n\t\t\t\tconst instruments: any[] = patternObject[\"instruments\"];\n\t\t\t\tconst instrumentCount: number = clamp(Config.instrumentCountMin, song.getMaxInstrumentsPerPatternForChannel(channel) + 1, instruments.length);\n\t\t\t\tfor (let j: number = 0; j < instrumentCount; j++) {\n\t\t\t\t\tthis.instruments[j] = clamp(0, channel.instruments.length, (instruments[j] | 0) - 1);\n\t\t\t\t}\n\t\t\t\tthis.instruments.length = instrumentCount;\n\t\t\t} else {\n\t\t\t\tthis.instruments[0] = clamp(0, channel.instruments.length, (patternObject[\"instrument\"] | 0) - 1);\n\t\t\t\tthis.instruments.length = 1;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (patternObject[\"notes\"] && patternObject[\"notes\"].length > 0) {\n\t\t\tconst maxNoteCount: number = Math.min(song.beatsPerBar * Config.partsPerBeat, patternObject[\"notes\"].length >>> 0);\n\t\t\t\n\t\t\t// TODO: Consider supporting notes specified in any timing order, sorting them and truncating as necessary.\n\t\t\tlet tickClock: number = 0;\n\t\t\tfor (let j: number = 0; j < patternObject[\"notes\"].length; j++) {\n\t\t\t\tif (j >= maxNoteCount) break;\n\t\t\t\t\n\t\t\t\tconst noteObject = patternObject[\"notes\"][j];\n\t\t\t\tif (!noteObject || !noteObject[\"pitches\"] || !(noteObject[\"pitches\"].length >= 1) || !noteObject[\"points\"] || !(noteObject[\"points\"].length >= 2)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tconst note: Note = new Note(0, 0, 0, 0);\n\t\t\t\tnote.pitches = [];\n\t\t\t\tnote.pins = [];\n\t\t\t\t\n\t\t\t\tfor (let k: number = 0; k < noteObject[\"pitches\"].length; k++) {\n\t\t\t\t\tconst pitch: number = noteObject[\"pitches\"][k] | 0;\n\t\t\t\t\tif (note.pitches.indexOf(pitch) != -1) continue;\n\t\t\t\t\tnote.pitches.push(pitch);\n\t\t\t\t\tif (note.pitches.length >= Config.maxChordSize) break;\n\t\t\t\t}\n\t\t\t\tif (note.pitches.length < 1) continue;\n\t\t\t\t\n\t\t\t\tlet noteClock: number = tickClock;\n\t\t\t\tlet startInterval: number = 0;\n\t\t\t\tfor (let k: number = 0; k < noteObject[\"points\"].length; k++) {\n\t\t\t\t\tconst pointObject: any = noteObject[\"points\"][k];\n\t\t\t\t\tif (pointObject == undefined || pointObject[\"tick\"] == undefined) continue;\n\t\t\t\t\tconst interval: number = (pointObject[\"pitchBend\"] == undefined) ? 0 : (pointObject[\"pitchBend\"] | 0);\n\t\t\t\t\t\n\t\t\t\t\tconst time: number = Math.round((+pointObject[\"tick\"]) * Config.partsPerBeat / importedPartsPerBeat);\n\t\t\t\t\t\n\t\t\t\t\tconst size: number = (pointObject[\"volume\"] == undefined) ? 3 : Math.max(0, Math.min(3, Math.round((pointObject[\"volume\"] | 0) * 3 / 100)));\n\t\t\t\t\t\n\t\t\t\t\tif (time > song.beatsPerBar * Config.partsPerBeat) continue;\n\t\t\t\t\tif (note.pins.length == 0) {\n\t\t\t\t\t\tif (time < noteClock) continue;\n\t\t\t\t\t\tnote.start = time;\n\t\t\t\t\t\tstartInterval = interval;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (time <= noteClock) continue;\n\t\t\t\t\t}\n\t\t\t\t\tnoteClock = time;\n\t\t\t\t\t\n\t\t\t\t\tnote.pins.push(makeNotePin(interval - startInterval, time - note.start, size));\n\t\t\t\t}\n\t\t\t\tif (note.pins.length < 2) continue;\n\t\t\t\t\n\t\t\t\tnote.end = note.pins[note.pins.length - 1].time + note.start;\n\t\t\t\t\n\t\t\t\tconst maxPitch: number = isNoiseChannel ? Config.drumCount - 1 : Config.maxPitch;\n\t\t\t\tlet lowestPitch: number = maxPitch;\n\t\t\t\tlet highestPitch: number = 0;\n\t\t\t\tfor (let k: number = 0; k < note.pitches.length; k++) {\n\t\t\t\t\tnote.pitches[k] += startInterval;\n\t\t\t\t\tif (note.pitches[k] < 0 || note.pitches[k] > maxPitch) {\n\t\t\t\t\t\tnote.pitches.splice(k, 1);\n\t\t\t\t\t\tk--;\n\t\t\t\t\t}\n\t\t\t\t\tif (note.pitches[k] < lowestPitch) lowestPitch = note.pitches[k];\n\t\t\t\t\tif (note.pitches[k] > highestPitch) highestPitch = note.pitches[k];\n\t\t\t\t}\n\t\t\t\tif (note.pitches.length < 1) continue;\n\t\t\t\t\n\t\t\t\tfor (let k: number = 0; k < note.pins.length; k++) {\n\t\t\t\t\tconst pin: NotePin = note.pins[k];\n\t\t\t\t\tif (pin.interval + lowestPitch < 0) pin.interval = -lowestPitch;\n\t\t\t\t\tif (pin.interval + highestPitch > maxPitch) pin.interval = maxPitch - highestPitch;\n\t\t\t\t\tif (k >= 2) {\n\t\t\t\t\t\tif (pin.interval == note.pins[k-1].interval &&\n\t\t\t\t\t\t\tpin.interval == note.pins[k-2].interval &&\n\t\t\t\t\t\t\tpin.size == note.pins[k-1].size &&\n\t\t\t\t\t\t\tpin.size == note.pins[k-2].size)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnote.pins.splice(k-1, 1);\n\t\t\t\t\t\t\tk--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (note.start == 0) {\n\t\t\t\t\tnote.continuesLastPattern = (noteObject[\"continuesLastPattern\"] === true);\n\t\t\t\t} else {\n\t\t\t\t\tnote.continuesLastPattern = false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tthis.notes.push(note);\n\t\t\t\ttickClock = note.end;\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class Operator {\n\tpublic frequency: number = 0;\n\tpublic amplitude: number = 0;\n\t\n\tconstructor(index: number) {\n\t\tthis.reset(index);\n\t}\n\t\n\tpublic reset(index: number): void {\n\t\tthis.frequency = 0;\n\t\tthis.amplitude = (index <= 1) ? Config.operatorAmplitudeMax : 0;\n\t}\n}\n\nexport class SpectrumWave {\n\tpublic spectrum: number[] = [];\n\tpublic hash: number = -1;\n\t\n\tconstructor(isNoiseChannel: boolean) {\n\t\tthis.reset(isNoiseChannel);\n\t}\n\t\n\tpublic reset(isNoiseChannel: boolean): void {\n\t\tfor (let i: number = 0; i < Config.spectrumControlPoints; i++) {\n\t\t\tif (isNoiseChannel) {\n\t\t\t\tthis.spectrum[i] = Math.round(Config.spectrumMax * (1 / Math.sqrt(1 + i / 3)));\n\t\t\t} else {\n\t\t\t\tconst isHarmonic: boolean = i==0 || i==7 || i==11 || i==14 || i==16 || i==18 || i==21 || i==23 || i>=25;\n\t\t\t\tthis.spectrum[i] = isHarmonic ? Math.max(0, Math.round(Config.spectrumMax * (1 - i / 30))) : 0;\n\t\t\t}\n\t\t}\n\t\tthis.markCustomWaveDirty();\n\t}\n\t\n\tpublic markCustomWaveDirty(): void {\n\t\tconst hashMult: number = Synth.fittingPowerOfTwo(Config.spectrumMax + 2) - 1;\n\t\tlet hash: number = 0;\n\t\tfor (const point of this.spectrum) hash = ((hash * hashMult) + point) >>> 0;\n\t\tthis.hash = hash;\n\t}\n}\n\nclass SpectrumWaveState {\n\tpublic wave: Float32Array | null = null;\n\tprivate _hash: number = -1;\n\t\n\tpublic getCustomWave(settings: SpectrumWave, lowestOctave: number): Float32Array {\n\t\tif (this._hash == settings.hash) return this.wave!;\n\t\tthis._hash = settings.hash;\n\t\t\n\t\tconst waveLength: number = Config.spectrumNoiseLength;\n\t\tif (this.wave == null || this.wave.length != waveLength + 1) {\n\t\t\tthis.wave = new Float32Array(waveLength + 1);\n\t\t}\n\t\tconst wave: Float32Array = this.wave;\n\t\t\n\t\tfor (let i: number = 0; i < waveLength; i++) {\n\t\t\twave[i] = 0;\n\t\t}\n\t\t\n\t\tconst highestOctave: number = 14;\n\t\tconst falloffRatio: number = 0.25;\n\t\t// Nudge the 2/7 and 4/7 control points so that they form harmonic intervals.\n\t\tconst pitchTweak: number[] = [0, 1/7, Math.log2(5/4), 3/7, Math.log2(3/2), 5/7, 6/7];\n\t\tfunction controlPointToOctave(point: number): number {\n\t\t\treturn lowestOctave + Math.floor(point / Config.spectrumControlPointsPerOctave) + pitchTweak[(point + Config.spectrumControlPointsPerOctave) % Config.spectrumControlPointsPerOctave];\n\t\t}\n\t\t\n\t\tlet combinedAmplitude: number = 1;\n\t\tfor (let i: number = 0; i < Config.spectrumControlPoints + 1; i++) {\n\t\t\tconst value1: number = (i <= 0) ? 0 : settings.spectrum[i - 1];\n\t\t\tconst value2: number = (i >= Config.spectrumControlPoints) ? settings.spectrum[Config.spectrumControlPoints - 1] : settings.spectrum[i];\n\t\t\tconst octave1: number = controlPointToOctave(i - 1);\n\t\t\tlet octave2: number = controlPointToOctave(i);\n\t\t\tif (i >= Config.spectrumControlPoints) octave2 = highestOctave + (octave2 - highestOctave) * falloffRatio;\n\t\t\tif (value1 == 0 && value2 == 0) continue;\n\t\t\t\n\t\t\tcombinedAmplitude += 0.02 * drawNoiseSpectrum(wave, waveLength, octave1, octave2, value1 / Config.spectrumMax, value2 / Config.spectrumMax, -0.5);\n\t\t}\n\t\tif (settings.spectrum[Config.spectrumControlPoints - 1] > 0) {\n\t\t\tcombinedAmplitude += 0.02 * drawNoiseSpectrum(wave, waveLength, highestOctave + (controlPointToOctave(Config.spectrumControlPoints) - highestOctave) * falloffRatio, highestOctave, settings.spectrum[Config.spectrumControlPoints - 1] / Config.spectrumMax, 0, -0.5);\n\t\t}\n\t\t\n\t\tinverseRealFourierTransform(wave, waveLength);\n\t\tscaleElementsByFactor(wave, 5.0 / (Math.sqrt(waveLength) * Math.pow(combinedAmplitude, 0.75)));\n\t\t\n\t\t// Duplicate the first sample at the end for easier wrap-around interpolation.\n\t\twave[waveLength] = wave[0];\n\t\t\n\t\treturn wave;\n\t}\n}\n\nexport class HarmonicsWave {\n\tpublic harmonics: number[] = [];\n\tpublic hash: number = -1;\n\t\n\tconstructor() {\n\t\tthis.reset();\n\t}\n\t\n\tpublic reset(): void {\n\t\tfor (let i: number = 0; i < Config.harmonicsControlPoints; i++) {\n\t\t\tthis.harmonics[i] = 0;\n\t\t}\n\t\tthis.harmonics[0] = Config.harmonicsMax;\n\t\tthis.harmonics[3] = Config.harmonicsMax;\n\t\tthis.harmonics[6] = Config.harmonicsMax;\n\t\tthis.markCustomWaveDirty();\n\t}\n\t\n\tpublic markCustomWaveDirty(): void {\n\t\tconst hashMult: number = Synth.fittingPowerOfTwo(Config.harmonicsMax + 2) - 1;\n\t\tlet hash: number = 0;\n\t\tfor (const point of this.harmonics) hash = ((hash * hashMult) + point) >>> 0;\n\t\tthis.hash = hash;\n\t}\n}\n\nclass HarmonicsWaveState {\n\tpublic wave: Float32Array | null = null;\n\tprivate _hash: number = -1;\n\tprivate _generatedForType: InstrumentType;\n\t\n\tpublic getCustomWave(settings: HarmonicsWave, instrumentType: InstrumentType): Float32Array {\n\t\tif (this._hash == settings.hash && this._generatedForType == instrumentType) return this.wave!;\n\t\tthis._hash = settings.hash;\n\t\tthis._generatedForType = instrumentType;\n\t\t\n\t\tconst harmonicsRendered: number = (instrumentType == InstrumentType.pickedString) ? Config.harmonicsRenderedForPickedString : Config.harmonicsRendered;\n\t\t\n\t\tconst waveLength: number = Config.harmonicsWavelength;\n\t\tconst retroWave: Float32Array = getDrumWave(0, null, null);\n\t\t\n\t\tif (this.wave == null || this.wave.length != waveLength + 1) {\n\t\t\tthis.wave = new Float32Array(waveLength + 1);\n\t\t}\n\t\tconst wave: Float32Array = this.wave;\n\t\t\n\t\tfor (let i: number = 0; i < waveLength; i++) {\n\t\t\twave[i] = 0;\n\t\t}\n\t\t\n\t\tconst overallSlope: number = -0.25;\n\t\tlet combinedControlPointAmplitude: number = 1;\n\t\t\n\t\tfor (let harmonicIndex: number = 0; harmonicIndex < harmonicsRendered; harmonicIndex++) {\n\t\t\tconst harmonicFreq: number = harmonicIndex + 1;\n\t\t\tlet controlValue: number = harmonicIndex < Config.harmonicsControlPoints ? settings.harmonics[harmonicIndex] : settings.harmonics[Config.harmonicsControlPoints - 1];\n\t\t\tif (harmonicIndex >= Config.harmonicsControlPoints) {\n\t\t\t\tcontrolValue *= 1 - (harmonicIndex - Config.harmonicsControlPoints) / (harmonicsRendered - Config.harmonicsControlPoints);\n\t\t\t}\n\t\t\tconst normalizedValue: number = controlValue / Config.harmonicsMax;\n\t\t\tlet amplitude: number = Math.pow(2, controlValue - Config.harmonicsMax + 1) * Math.sqrt(normalizedValue);\n\t\t\tif (harmonicIndex < Config.harmonicsControlPoints) {\n\t\t\t\tcombinedControlPointAmplitude += amplitude;\n\t\t\t}\n\t\t\tamplitude *= Math.pow(harmonicFreq, overallSlope);\n\t\t\t\n\t\t\t// Multiply all the sine wave amplitudes by 1 or -1 based on the LFSR\n\t\t\t// retro wave (effectively random) to avoid egregiously tall spikes.\n\t\t\tamplitude *= retroWave[harmonicIndex + 589];\n\t\t\t\n\t\t\twave[waveLength - harmonicFreq] = amplitude;\n\t\t}\n\t\t\n\t\tinverseRealFourierTransform(wave, waveLength);\n\t\t\n\t\t// Limit the maximum wave amplitude.\n\t\tconst mult: number = 1 / Math.pow(combinedControlPointAmplitude, 0.7);\n\t\tfor (let i: number = 0; i < wave.length; i++) wave[i] *= mult;\n\t\t\n\t\tperformIntegral(wave);\n\t\t\n\t\t// The first sample should be zero, and we'll duplicate it at the end for easier interpolation.\n\t\twave[waveLength] = wave[0];\n\t\t\n\t\treturn wave;\n\t}\n}\n\nexport class FilterControlPoint {\n\tpublic freq: number = 0;\n\tpublic gain: number = Config.filterGainCenter;\n\tpublic type: FilterType = FilterType.peak;\n\t\n\tpublic set(freqSetting: number, gainSetting: number): void {\n\t\tthis.freq = freqSetting;\n\t\tthis.gain = gainSetting;\n\t}\n\t\n\tpublic getHz(): number {\n\t\treturn FilterControlPoint.getHzFromSettingValue(this.freq);\n\t}\n\t\n\tpublic static getHzFromSettingValue(value: number): number {\n\t\treturn Config.filterFreqReferenceHz * Math.pow(2.0, (value - Config.filterFreqReferenceSetting) * Config.filterFreqStep);\n\t}\n\tpublic static getSettingValueFromHz(hz: number): number {\n\t\treturn Math.log2(hz / Config.filterFreqReferenceHz) / Config.filterFreqStep + Config.filterFreqReferenceSetting;\n\t}\n\tpublic static getRoundedSettingValueFromHz(hz: number): number {\n\t\treturn Math.max(0, Math.min(Config.filterFreqRange - 1, Math.round(FilterControlPoint.getSettingValueFromHz(hz))));\n\t}\n\t\n\tpublic getLinearGain(peakMult: number = 1.0): number {\n\t\tconst power: number = (this.gain - Config.filterGainCenter) * Config.filterGainStep;\n\t\tconst neutral: number = (this.type == FilterType.peak) ? 0.0 : -0.5;\n\t\tconst interpolatedPower: number = neutral + (power - neutral) * peakMult;\n\t\treturn Math.pow(2.0, interpolatedPower);\n\t}\n\tpublic static getRoundedSettingValueFromLinearGain(linearGain: number): number {\n\t\treturn Math.max(0, Math.min(Config.filterGainRange - 1, Math.round(Math.log2(linearGain) / Config.filterGainStep + Config.filterGainCenter)));\n\t}\n\t\n\tpublic toCoefficients(filter: FilterCoefficients, sampleRate: number, freqMult: number = 1.0, peakMult: number = 1.0): void {\n\t\tconst cornerRadiansPerSample: number = 2.0 * Math.PI * Math.max(Config.filterFreqMinHz, Math.min(Config.filterFreqMaxHz, freqMult * this.getHz())) / sampleRate;\n\t\tconst linearGain: number = this.getLinearGain(peakMult);\n\t\tswitch (this.type) {\n\t\t\tcase FilterType.lowPass:\n\t\t\t\tfilter.lowPass2ndOrderButterworth(cornerRadiansPerSample, linearGain);\n\t\t\t\tbreak;\n\t\t\tcase FilterType.highPass:\n\t\t\t\tfilter.highPass2ndOrderButterworth(cornerRadiansPerSample, linearGain);\n\t\t\t\tbreak;\n\t\t\tcase FilterType.peak:\n\t\t\t\tfilter.peak2ndOrder(cornerRadiansPerSample, linearGain, 1.0);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error();\n\t\t}\n\t}\n\t\n\tpublic getVolumeCompensationMult(): number {\n\t\tconst octave: number = (this.freq - Config.filterFreqReferenceSetting) * Config.filterFreqStep;\n\t\tconst gainPow: number = (this.gain - Config.filterGainCenter) * Config.filterGainStep;\n\t\tswitch (this.type) {\n\t\t\tcase FilterType.lowPass:\n\t\t\t\tconst freqRelativeTo8khz: number = Math.pow(2.0, octave) * Config.filterFreqReferenceHz / 8000.0;\n\t\t\t\t// Reverse the frequency warping from importing legacy simplified filters to imitate how the legacy filter cutoff setting affected volume.\n\t\t\t\tconst warpedFreq: number = (Math.sqrt(1.0 + 4.0 * freqRelativeTo8khz) - 1.0) / 2.0;\n\t\t\t\tconst warpedOctave: number = Math.log2(warpedFreq);\n\t\t\t\treturn Math.pow(0.5, 0.2 * Math.max(0.0, gainPow + 1.0) + Math.min(0.0, Math.max(-3.0, 0.595 * warpedOctave + 0.35 * Math.min(0.0, gainPow + 1.0))));\n\t\t\tcase FilterType.highPass:\n\t\t\t\treturn Math.pow(0.5, 0.125 * Math.max(0.0, gainPow + 1.0) + Math.min(0.0, 0.3 * (-octave - Math.log2(Config.filterFreqReferenceHz / 125.0)) + 0.2 * Math.min(0.0, gainPow + 1.0)));\n\t\t\tcase FilterType.peak:\n\t\t\t\tconst distanceFromCenter: number = octave + Math.log2(Config.filterFreqReferenceHz / 2000.0);\n\t\t\t\tconst freqLoudness: number = Math.pow(1.0 / (1.0 + Math.pow(distanceFromCenter / 3.0, 2.0)), 2.0);\n\t\t\t\treturn Math.pow(0.5, 0.125 * Math.max(0.0, gainPow) + 0.1 * freqLoudness * Math.min(0.0, gainPow));\n\t\t\tdefault:\n\t\t\t\tthrow new Error();\n\t\t}\n\t}\n}\n\nexport class FilterSettings {\n\tpublic readonly controlPoints: FilterControlPoint[] = [];\n\tpublic controlPointCount: number = 0;\n\t\n\tconstructor() {\n\t\tthis.reset();\n\t}\n\t\n\treset(): void {\n\t\tthis.controlPointCount = 0;\n\t}\n\t\n\taddPoint(type: FilterType, freqSetting: number, gainSetting: number): void {\n\t\tlet controlPoint: FilterControlPoint;\n\t\tif (this.controlPoints.length <= this.controlPointCount) {\n\t\t\tcontrolPoint = new FilterControlPoint();\n\t\t\tthis.controlPoints[this.controlPointCount] = controlPoint;\n\t\t} else {\n\t\t\tcontrolPoint = this.controlPoints[this.controlPointCount];\n\t\t}\n\t\tthis.controlPointCount++;\n\t\tcontrolPoint.type = type;\n\t\tcontrolPoint.set(freqSetting, gainSetting);\n\t}\n\t\n\tpublic toJsonObject(): Object {\n\t\tconst filterArray: any[] = [];\n\t\tfor (let i: number = 0; i < this.controlPointCount; i++) {\n\t\t\tconst point: FilterControlPoint = this.controlPoints[i];\n\t\t\tfilterArray.push({\n\t\t\t\t\"type\": Config.filterTypeNames[point.type],\n\t\t\t\t\"cutoffHz\": Math.round(point.getHz() * 100) / 100,\n\t\t\t\t\"linearGain\": Math.round(point.getLinearGain() * 10000) / 10000,\n\t\t\t});\n\t\t}\n\t\treturn filterArray;\n\t}\n\t\n\tpublic fromJsonObject(filterObject: any): void {\n\t\tthis.controlPoints.length = 0;\n\t\tif (filterObject) {\n\t\t\tfor (const pointObject of filterObject) {\n\t\t\t\tconst point: FilterControlPoint = new FilterControlPoint();\n\t\t\t\tpoint.type = Config.filterTypeNames.indexOf(pointObject[\"type\"]);\n\t\t\t\tif (<any>point.type == -1) point.type = FilterType.peak;\n\t\t\t\tif (pointObject[\"cutoffHz\"] != undefined) {\n\t\t\t\t\tpoint.freq = FilterControlPoint.getRoundedSettingValueFromHz(pointObject[\"cutoffHz\"]);\n\t\t\t\t} else {\n\t\t\t\t\tpoint.freq = 0;\n\t\t\t\t}\n\t\t\t\tif (pointObject[\"linearGain\"] != undefined) {\n\t\t\t\t\tpoint.gain = FilterControlPoint.getRoundedSettingValueFromLinearGain(pointObject[\"linearGain\"]);\n\t\t\t\t} else {\n\t\t\t\t\tpoint.gain = Config.filterGainCenter;\n\t\t\t\t}\n\t\t\t\tthis.controlPoints.push(point);\n\t\t\t}\n\t\t}\n\t\tthis.controlPointCount = this.controlPoints.length;\n\t}\n\t\n\tpublic convertLegacySettings(legacyCutoffSetting: number, legacyResonanceSetting: number, legacyEnv: Envelope): void {\n\t\tthis.reset();\n\t\t\n\t\tconst legacyFilterCutoffMaxHz: number = 8000; // This was carefully calculated to correspond to no change in response when filtering at 48000 samples per second... when using the legacy simplified low-pass filter.\n\t\tconst legacyFilterMax: number = 0.95;\n\t\tconst legacyFilterMaxRadians: number = Math.asin(legacyFilterMax / 2.0) * 2.0;\n\t\tconst legacyFilterMaxResonance: number = 0.95;\n\t\tconst legacyFilterCutoffRange: number = 11;\n\t\tconst legacyFilterResonanceRange: number = 8;\n\t\t\n\t\tconst resonant: boolean = (legacyResonanceSetting > 1);\n\t\tconst firstOrder: boolean = (legacyResonanceSetting == 0);\n\t\tconst cutoffAtMax: boolean = (legacyCutoffSetting == legacyFilterCutoffRange - 1);\n\t\tconst envDecays: boolean = (legacyEnv.type == EnvelopeType.flare || legacyEnv.type == EnvelopeType.twang || legacyEnv.type == EnvelopeType.decay || legacyEnv.type == EnvelopeType.noteSize);\n\t\t\n\t\tconst standardSampleRate: number = 48000;\n\t\tconst legacyHz: number = legacyFilterCutoffMaxHz * Math.pow(2.0, (legacyCutoffSetting - (legacyFilterCutoffRange - 1)) * 0.5);\n\t\tconst legacyRadians: number = Math.min(legacyFilterMaxRadians, 2 * Math.PI * legacyHz / standardSampleRate);\n\t\t\n\t\tif (legacyEnv.type == EnvelopeType.none && !resonant && cutoffAtMax) {\n\t\t\t// The response is flat and there's no envelopes, so don't even bother adding any control points.\n\t\t} else if (firstOrder) {\n\t\t\t// In general, a 1st order lowpass can be approximated by a 2nd order lowpass\n\t\t\t// with a cutoff ~4 octaves higher (*16) and a gain of 1/16.\n\t\t\t// However, BeepBox's original lowpass filters behaved oddly as they\n\t\t\t// approach the nyquist frequency, so I've devised this curved conversion\n\t\t\t// to guess at a perceptually appropriate new cutoff frequency and gain.\n\t\t\tconst extraOctaves: number = 3.5;\n\t\t\tconst targetRadians: number = legacyRadians * Math.pow(2.0, extraOctaves);\n\t\t\tconst curvedRadians: number = targetRadians / (1.0 + targetRadians / Math.PI);\n\t\t\tconst curvedHz: number = standardSampleRate * curvedRadians / (2.0 * Math.PI)\n\t\t\tconst freqSetting: number = FilterControlPoint.getRoundedSettingValueFromHz(curvedHz);\n\t\t\tconst finalHz: number = FilterControlPoint.getHzFromSettingValue(freqSetting);\n\t\t\tconst finalRadians: number = 2.0 * Math.PI * finalHz / standardSampleRate;\n\t\t\t\n\t\t\tconst legacyFilter: FilterCoefficients = new FilterCoefficients();\n\t\t\tlegacyFilter.lowPass1stOrderSimplified(legacyRadians);\n\t\t\tconst response: FrequencyResponse = new FrequencyResponse();\n\t\t\tresponse.analyze(legacyFilter, finalRadians);\n\t\t\tconst legacyFilterGainAtNewRadians: number = response.magnitude();\n\t\t\t\n\t\t\tlet logGain: number = Math.log2(legacyFilterGainAtNewRadians);\n\t\t\t// Bias slightly toward 2^(-extraOctaves):\n\t\t\tlogGain = -extraOctaves + (logGain + extraOctaves) * 0.82;\n\t\t\t// Decaying envelopes move the cutoff frequency back into an area where the best approximation of the first order slope requires a lower gain setting.\n\t\t\tif (envDecays) logGain = Math.min(logGain, -1.0);\n\t\t\tconst convertedGain: number = Math.pow(2.0, logGain);\n\t\t\tconst gainSetting: number = FilterControlPoint.getRoundedSettingValueFromLinearGain(convertedGain);\n\t\t\t\n\t\t\tthis.addPoint(FilterType.lowPass, freqSetting, gainSetting);\n\t\t} else {\n\t\t\tconst intendedGain: number = 0.5 / (1.0 - legacyFilterMaxResonance * Math.sqrt(Math.max(0.0, legacyResonanceSetting - 1.0) / (legacyFilterResonanceRange - 2.0)));\n\t\t\tconst invertedGain: number = 0.5 / intendedGain;\n\t\t\tconst maxRadians: number = 2.0 * Math.PI * legacyFilterCutoffMaxHz / standardSampleRate;\n\t\t\tconst freqRatio: number = legacyRadians / maxRadians;\n\t\t\tconst targetRadians: number = legacyRadians * (freqRatio * Math.pow(invertedGain, 0.9) + 1.0);\n\t\t\tconst curvedRadians: number = legacyRadians + (targetRadians - legacyRadians) * invertedGain;\n\t\t\tlet curvedHz: number;\n\t\t\tif (envDecays) {\n\t\t\t\tcurvedHz = standardSampleRate * Math.min(curvedRadians, legacyRadians * Math.pow(2, 0.25)) / (2.0 * Math.PI)\n\t\t\t} else {\n\t\t\t\tcurvedHz = standardSampleRate * curvedRadians / (2.0 * Math.PI)\n\t\t\t}\n\t\t\tconst freqSetting: number = FilterControlPoint.getRoundedSettingValueFromHz(curvedHz);\n\t\t\t\n\t\t\tlet legacyFilterGain: number;\n\t\t\tif (envDecays) {\n\t\t\t\tlegacyFilterGain = intendedGain;\n\t\t\t} else {\n\t\t\t\tconst legacyFilter: FilterCoefficients = new FilterCoefficients();\n\t\t\t\tlegacyFilter.lowPass2ndOrderSimplified(legacyRadians, intendedGain);\n\t\t\t\tconst response: FrequencyResponse = new FrequencyResponse();\n\t\t\t\tresponse.analyze(legacyFilter, curvedRadians);\n\t\t\t\tlegacyFilterGain = response.magnitude();\n\t\t\t}\n\t\t\tif (!resonant) legacyFilterGain = Math.min(legacyFilterGain, Math.sqrt(0.5));\n\t\t\tconst gainSetting: number = FilterControlPoint.getRoundedSettingValueFromLinearGain(legacyFilterGain);\n\t\t\t\n\t\t\tthis.addPoint(FilterType.lowPass, freqSetting, gainSetting);\n\t\t}\n\t}\n}\n\nexport class EnvelopeSettings {\n\tpublic target: number = 0;\n\tpublic index: number = 0;\n\tpublic envelope: number = 0;\n\t\n\tconstructor() {\n\t\tthis.reset();\n\t}\n\t\n\treset(): void {\n\t\tthis.target = 0;\n\t\tthis.index = 0;\n\t\tthis.envelope = 0;\n\t}\n\t\n\tpublic toJsonObject(): Object {\n\t\tconst envelopeObject: any = {\n\t\t\t\"target\": Config.instrumentAutomationTargets[this.target].name,\n\t\t\t\"envelope\": Config.envelopes[this.envelope].name,\n\t\t};\n\t\tif (Config.instrumentAutomationTargets[this.target].maxCount > 1) {\n\t\t\tenvelopeObject[\"index\"] = this.index;\n\t\t}\n\t\treturn envelopeObject;\n\t}\n\t\n\tpublic fromJsonObject(envelopeObject: any): void {\n\t\tthis.reset();\n\t\t\n\t\tlet target: AutomationTarget = Config.instrumentAutomationTargets.dictionary[envelopeObject[\"target\"]];\n\t\tif (target == null) target = Config.instrumentAutomationTargets.dictionary[\"noteVolume\"];\n\t\tthis.target = target.index;\n\t\t\n\t\tlet envelope: Envelope = Config.envelopes.dictionary[envelopeObject[\"envelope\"]];\n\t\tif (envelope == null) envelope = Config.envelopes.dictionary[\"none\"];\n\t\tthis.envelope = envelope.index;\n\t\t\n\t\tif (envelopeObject[\"index\"] != undefined) {\n\t\t\tthis.index = clamp(0, Config.instrumentAutomationTargets[this.target].maxCount, envelopeObject[\"index\"] | 0);\n\t\t} else {\n\t\t\tthis.index = 0;\n\t\t}\n\t}\n}\n\n// Settings that were available to old versions of BeepBox but are no longer available in the\n// current version that need to be reinterpreted as a group to determine the best way to\n// represent them in the current version.\ninterface LegacySettings {\n\tfilterCutoff?: number;\n\tfilterResonance?: number;\n\tfilterEnvelope?: Envelope;\n\tpulseEnvelope?: Envelope;\n\toperatorEnvelopes?: Envelope[];\n\tfeedbackEnvelope?: Envelope;\n}\n\nexport class Instrument {\n\tpublic type: InstrumentType = InstrumentType.chip;\n\tpublic preset: number = 0;\n\tpublic chipWave: number = 2;\n\tpublic chipNoise: number = 1;\n\tpublic eqFilter: FilterSettings = new FilterSettings();\n\tpublic noteFilter: FilterSettings = new FilterSettings();\n\tpublic envelopes: EnvelopeSettings[] = [];\n\tpublic envelopeCount: number = 0;\n\tpublic fadeIn: number = 0;\n\tpublic fadeOut: number = Config.fadeOutNeutral;\n\tpublic transition: number = Config.transitions.dictionary[\"normal\"].index;\n\tpublic pitchShift: number = 0;\n\tpublic detune: number = 0;\n\tpublic vibrato: number = 0;\n\tpublic unison: number = 0;\n\tpublic effects: number = 0;\n\tpublic chord: number = 1;\n\tpublic volume: number = 0;\n\tpublic pan: number = Config.panCenter;\n\tpublic pulseWidth: number = Config.pulseWidthRange - 1;\n\tpublic supersawDynamism: number = Config.supersawDynamismMax;\n\tpublic supersawSpread: number = Math.ceil(Config.supersawSpreadMax / 2.0);\n\tpublic supersawShape: number = 0;\n\tpublic stringSustain: number = 10;\n\tpublic stringSustainType: SustainType = SustainType.acoustic;\n\tpublic distortion: number = 0;\n\tpublic bitcrusherFreq: number = 0;\n\tpublic bitcrusherQuantization: number = 0;\n\tpublic chorus: number = 0;\n\tpublic reverb: number = 0;\n\tpublic echoSustain: number = 0;\n\tpublic echoDelay: number = 0;\n\tpublic algorithm: number = 0;\n\tpublic feedbackType: number = 0;\n\tpublic feedbackAmplitude: number = 0;\n\tpublic readonly operators: Operator[] = [];\n\tpublic readonly spectrumWave: SpectrumWave;\n\tpublic readonly harmonicsWave: HarmonicsWave = new HarmonicsWave();\n\tpublic readonly drumsetEnvelopes: number[] = [];\n\tpublic readonly drumsetSpectrumWaves: SpectrumWave[] = [];\n\t\n\tconstructor(isNoiseChannel: boolean) {\n\t\tthis.spectrumWave = new SpectrumWave(isNoiseChannel);\n\t\tfor (let i: number = 0; i < Config.operatorCount; i++) {\n\t\t\tthis.operators[i] = new Operator(i);\n\t\t}\n\t\tfor (let i: number = 0; i < Config.drumCount; i++) {\n\t\t\tthis.drumsetEnvelopes[i] = Config.envelopes.dictionary[\"twang 2\"].index;\n\t\t\tthis.drumsetSpectrumWaves[i] = new SpectrumWave(true);\n\t\t}\n\t}\n\t\n\tpublic setTypeAndReset(type: InstrumentType, isNoiseChannel: boolean): void {\n\t\tthis.type = type;\n\t\tthis.preset = type;\n\t\tthis.volume = 0;\n\t\tthis.effects = 0;\n\t\tthis.chorus = Config.chorusRange - 1;\n\t\tthis.reverb = 2;\n\t\tthis.echoSustain = Math.floor((Config.echoSustainRange - 1) * 0.5);\n\t\tthis.echoDelay = Math.floor((Config.echoDelayRange - 1) * 0.5);\n\t\tthis.eqFilter.reset();\n\t\tthis.noteFilter.reset();\n\t\tthis.distortion = Math.floor((Config.distortionRange - 1) * 0.75);\n\t\tthis.bitcrusherFreq = Math.floor((Config.bitcrusherFreqRange - 1) * 0.5)\n\t\tthis.bitcrusherQuantization = Math.floor((Config.bitcrusherQuantizationRange - 1) * 0.5);\n\t\tthis.pan = Config.panCenter;\n\t\tthis.pitchShift = Config.pitchShiftCenter;\n\t\tthis.detune = Config.detuneCenter;\n\t\tthis.vibrato = 0;\n\t\tthis.unison = 0;\n\t\tthis.stringSustain = 10;\n\t\tthis.stringSustainType = Config.enableAcousticSustain ? SustainType.acoustic : SustainType.bright;\n\t\tthis.fadeIn = 0;\n\t\tthis.fadeOut = Config.fadeOutNeutral;\n\t\tthis.transition = Config.transitions.dictionary[\"normal\"].index;\n\t\tthis.envelopeCount = 0;\n\t\tswitch (type) {\n\t\t\tcase InstrumentType.chip:\n\t\t\t\tthis.chipWave = 2;\n\t\t\t\t// TODO: enable the chord effect?\n\t\t\t\tthis.chord = Config.chords.dictionary[\"arpeggio\"].index;\n\t\t\t\tbreak;\n\t\t\tcase InstrumentType.fm:\n\t\t\t\tthis.chord = Config.chords.dictionary[\"custom interval\"].index;\n\t\t\t\tthis.algorithm = 0;\n\t\t\t\tthis.feedbackType = 0;\n\t\t\t\tthis.feedbackAmplitude = 0;\n\t\t\t\tfor (let i: number = 0; i < this.operators.length; i++) {\n\t\t\t\t\tthis.operators[i].reset(i);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase InstrumentType.noise:\n\t\t\t\tthis.chipNoise = 1;\n\t\t\t\tthis.chord = Config.chords.dictionary[\"arpeggio\"].index;\n\t\t\t\tbreak;\n\t\t\tcase InstrumentType.spectrum:\n\t\t\t\tthis.chord = Config.chords.dictionary[\"simultaneous\"].index;\n\t\t\t\tthis.spectrumWave.reset(isNoiseChannel);\n\t\t\t\tbreak;\n\t\t\tcase InstrumentType.drumset:\n\t\t\t\tthis.chord = Config.chords.dictionary[\"simultaneous\"].index;\n\t\t\t\tfor (let i: number = 0; i < Config.drumCount; i++) {\n\t\t\t\t\tthis.drumsetEnvelopes[i] = Config.envelopes.dictionary[\"twang 2\"].index;\n\t\t\t\t\tthis.drumsetSpectrumWaves[i].reset(isNoiseChannel);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase InstrumentType.harmonics:\n\t\t\t\tthis.chord = Config.chords.dictionary[\"simultaneous\"].index;\n\t\t\t\tthis.harmonicsWave.reset();\n\t\t\t\tbreak;\n\t\t\tcase InstrumentType.pwm:\n\t\t\t\tthis.chord = Config.chords.dictionary[\"arpeggio\"].index;\n\t\t\t\tthis.pulseWidth = Config.pulseWidthRange - 1;\n\t\t\t\tbreak;\n\t\t\tcase InstrumentType.pickedString:\n\t\t\t\tthis.chord = Config.chords.dictionary[\"strum\"].index;\n\t\t\t\tthis.harmonicsWave.reset();\n\t\t\t\tbreak;\n\t\t\tcase InstrumentType.supersaw:\n\t\t\t\tthis.chord = Config.chords.dictionary[\"arpeggio\"].index;\n\t\t\t\tthis.supersawDynamism = Config.supersawDynamismMax;\n\t\t\t\tthis.supersawSpread = Math.ceil(Config.supersawSpreadMax / 2.0);\n\t\t\t\tthis.supersawShape = 0;\n\t\t\t\tthis.pulseWidth = Config.pulseWidthRange - 1;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(\"Unrecognized instrument type: \" + type);\n\t\t}\n\t\t// Chip/noise instruments had arpeggio and FM had custom interval but neither\n\t\t// explicitly saved the chorus setting beforeSeven so enable it here. The effects\n\t\t// will otherwise get overridden when reading SongTagCode.startInstrument.\n\t\tif (this.chord != Config.chords.dictionary[\"simultaneous\"].index) {\n\t\t\t// Enable chord if it was used.\n\t\t\tthis.effects = (this.effects | (1 << EffectType.chord));\n\t\t}\n\t}\n\t\n\tpublic convertLegacySettings(legacySettings: LegacySettings): void {\n\t\tlet legacyCutoffSetting: number | undefined = legacySettings.filterCutoff;\n\t\tlet legacyResonanceSetting: number | undefined = legacySettings.filterResonance;\n\t\tlet legacyFilterEnv: Envelope | undefined = legacySettings.filterEnvelope;\n\t\tlet legacyPulseEnv: Envelope | undefined = legacySettings.pulseEnvelope;\n\t\tlet legacyOperatorEnvelopes: Envelope[] | undefined = legacySettings.operatorEnvelopes;\n\t\tlet legacyFeedbackEnv: Envelope | undefined = legacySettings.feedbackEnvelope;\n\t\t\n\t\t// legacy defaults:\n\t\tif (legacyCutoffSetting == undefined) legacyCutoffSetting = (this.type == InstrumentType.chip) ? 6 : 10;\n\t\tif (legacyResonanceSetting == undefined) legacyResonanceSetting = 0;\n\t\tif (legacyFilterEnv == undefined) legacyFilterEnv = Config.envelopes.dictionary[\"none\"];\n\t\tif (legacyPulseEnv == undefined) legacyPulseEnv = Config.envelopes.dictionary[(this.type == InstrumentType.pwm) ? \"twang 2\" : \"none\"];\n\t\tif (legacyOperatorEnvelopes == undefined) legacyOperatorEnvelopes = [Config.envelopes.dictionary[(this.type == InstrumentType.fm) ? \"note size\" : \"none\"], Config.envelopes.dictionary[\"none\"], Config.envelopes.dictionary[\"none\"], Config.envelopes.dictionary[\"none\"]];\n\t\tif (legacyFeedbackEnv == undefined) legacyFeedbackEnv = Config.envelopes.dictionary[\"none\"];\n\t\t\n\t\t// The \"punch\" envelope is special: it goes *above* the chosen cutoff. But if the cutoff was already at the max, it couldn't go any higher... except in the current version of BeepBox I raised the max cutoff so it *can* but then it sounds different, so to preserve the original sound let's just remove the punch envelope.\n\t\tconst legacyFilterCutoffRange: number = 11;\n\t\tconst cutoffAtMax: boolean = (legacyCutoffSetting == legacyFilterCutoffRange - 1);\n\t\tif (cutoffAtMax && legacyFilterEnv.type == EnvelopeType.punch) legacyFilterEnv = Config.envelopes.dictionary[\"none\"];\n\t\t\n\t\tconst carrierCount: number = Config.algorithms[this.algorithm].carrierCount;\n\t\tlet noCarriersControlledByNoteSize: boolean = true;\n\t\tlet allCarriersControlledByNoteSize: boolean = true;\n\t\tlet noteSizeControlsSomethingElse: boolean = (legacyFilterEnv.type == EnvelopeType.noteSize) || (legacyPulseEnv.type == EnvelopeType.noteSize);\n\t\tif (this.type == InstrumentType.fm) {\n\t\t\tnoteSizeControlsSomethingElse = noteSizeControlsSomethingElse || (legacyFeedbackEnv.type == EnvelopeType.noteSize);\n\t\t\tfor (let i: number = 0; i < legacyOperatorEnvelopes.length; i++) {\n\t\t\t\tif (i < carrierCount) {\n\t\t\t\t\tif (legacyOperatorEnvelopes[i].type != EnvelopeType.noteSize) {\n\t\t\t\t\t\tallCarriersControlledByNoteSize = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnoCarriersControlledByNoteSize = false;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tnoteSizeControlsSomethingElse = noteSizeControlsSomethingElse || (legacyOperatorEnvelopes[i].type == EnvelopeType.noteSize);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tthis.envelopeCount = 0;\n\t\t\n\t\tif (this.type == InstrumentType.fm) {\n\t\t\tif (allCarriersControlledByNoteSize && noteSizeControlsSomethingElse) {\n\t\t\t\tthis.addEnvelope(Config.instrumentAutomationTargets.dictionary[\"noteVolume\"].index, 0, Config.envelopes.dictionary[\"note size\"].index);\n\t\t\t} else if (noCarriersControlledByNoteSize && !noteSizeControlsSomethingElse) {\n\t\t\t\tthis.addEnvelope(Config.instrumentAutomationTargets.dictionary[\"none\"].index, 0, Config.envelopes.dictionary[\"note size\"].index);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (legacyFilterEnv.type == EnvelopeType.none) {\n\t\t\tthis.noteFilter.reset();\n\t\t\tthis.eqFilter.convertLegacySettings(legacyCutoffSetting, legacyResonanceSetting, legacyFilterEnv);\n\t\t\tthis.effects &= ~(1 << EffectType.noteFilter);\n\t\t} else {\n\t\t\tthis.eqFilter.reset();\n\t\t\tthis.noteFilter.convertLegacySettings(legacyCutoffSetting, legacyResonanceSetting, legacyFilterEnv);\n\t\t\tthis.effects |= 1 << EffectType.noteFilter;\n\t\t\tthis.addEnvelope(Config.instrumentAutomationTargets.dictionary[\"noteFilterAllFreqs\"].index, 0, legacyFilterEnv.index);\n\t\t}\n\t\t\n\t\tif (legacyPulseEnv.type != EnvelopeType.none) {\n\t\t\tthis.addEnvelope(Config.instrumentAutomationTargets.dictionary[\"pulseWidth\"].index, 0, legacyPulseEnv.index);\n\t\t}\n\t\t\n\t\tfor (let i: number = 0; i < legacyOperatorEnvelopes.length; i++) {\n\t\t\tif (i < carrierCount && allCarriersControlledByNoteSize) continue;\n\t\t\tif (legacyOperatorEnvelopes[i].type != EnvelopeType.none) {\n\t\t\t\tthis.addEnvelope(Config.instrumentAutomationTargets.dictionary[\"operatorAmplitude\"].index, i, legacyOperatorEnvelopes[i].index);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (legacyFeedbackEnv.type != EnvelopeType.none) {\n\t\t\tthis.addEnvelope(Config.instrumentAutomationTargets.dictionary[\"feedbackAmplitude\"].index, 0, legacyFeedbackEnv.index);\n\t\t}\n\t}\n\t\n\tpublic toJsonObject(): Object {\n\t\tconst instrumentObject: any = {\n\t\t\t\"type\": Config.instrumentTypeNames[this.type],\n\t\t\t\"volume\": (5 - this.volume) * 20,\n\t\t\t\"eqFilter\": this.eqFilter.toJsonObject(),\n\t\t};\n\t\t\n\t\tif (this.preset != this.type) {\n\t\t\tinstrumentObject[\"preset\"] = this.preset;\n\t\t}\n\t\t\n\t\tconst effects: string[] = [];\n\t\tfor (const effect of Config.effectOrder) {\n\t\t\tif (this.effects & (1 << effect)) {\n\t\t\t\teffects.push(Config.effectNames[effect]);\n\t\t\t}\n\t\t}\n\t\tinstrumentObject[\"effects\"] = effects;\n\t\t\n\t\t\n\t\tif (effectsIncludeTransition(this.effects)) {\n\t\t\tinstrumentObject[\"transition\"] = Config.transitions[this.transition].name;\n\t\t}\n\t\tif (effectsIncludeChord(this.effects)) {\n\t\t\tinstrumentObject[\"chord\"] = this.getChord().name;\n\t\t}\n\t\tif (effectsIncludePitchShift(this.effects)) {\n\t\t\tinstrumentObject[\"pitchShiftSemitones\"] = this.pitchShift;\n\t\t}\n\t\tif (effectsIncludeDetune(this.effects)) {\n\t\t\tinstrumentObject[\"detuneCents\"] = Synth.detuneToCents(this.detune - Config.detuneCenter);\n\t\t}\n\t\tif (effectsIncludeVibrato(this.effects)) {\n\t\t\tinstrumentObject[\"vibrato\"] = Config.vibratos[this.vibrato].name;\n\t\t}\n\t\tif (effectsIncludeNoteFilter(this.effects)) {\n\t\t\tinstrumentObject[\"noteFilter\"] = this.noteFilter.toJsonObject();\n\t\t}\n\t\tif (effectsIncludeDistortion(this.effects)) {\n\t\t\tinstrumentObject[\"distortion\"] = Math.round(100 * this.distortion / (Config.distortionRange - 1));\n\t\t}\n\t\tif (effectsIncludeBitcrusher(this.effects)) {\n\t\t\tinstrumentObject[\"bitcrusherOctave\"] = (Config.bitcrusherFreqRange - 1 - this.bitcrusherFreq) * Config.bitcrusherOctaveStep;\n\t\t\tinstrumentObject[\"bitcrusherQuantization\"] = Math.round(100 * this.bitcrusherQuantization / (Config.bitcrusherQuantizationRange - 1));\n\t\t}\n\t\tif (effectsIncludePanning(this.effects)) {\n\t\t\tinstrumentObject[\"pan\"] = Math.round(100 * (this.pan - Config.panCenter) / Config.panCenter);\n\t\t}\n\t\tif (effectsIncludeChorus(this.effects)) {\n\t\t\tinstrumentObject[\"chorus\"] = Math.round(100 * this.chorus / (Config.chorusRange - 1));\n\t\t}\n\t\tif (effectsIncludeEcho(this.effects)) {\n\t\t\tinstrumentObject[\"echoSustain\"] = Math.round(100 * this.echoSustain / (Config.echoSustainRange - 1));\n\t\t\tinstrumentObject[\"echoDelayBeats\"] = Math.round(1000 * (this.echoDelay + 1) * Config.echoDelayStepTicks / (Config.ticksPerPart * Config.partsPerBeat)) / 1000;\n\t\t}\n\t\tif (effectsIncludeReverb(this.effects)) {\n\t\t\tinstrumentObject[\"reverb\"] = Math.round(100 * this.reverb / (Config.reverbRange - 1));\n\t\t}\n\t\t\n\t\tif (this.type != InstrumentType.drumset) {\n\t\t\tinstrumentObject[\"fadeInSeconds\"] = Math.round(10000 * Synth.fadeInSettingToSeconds(this.fadeIn)) / 10000;\n\t\t\tinstrumentObject[\"fadeOutTicks\"] = Synth.fadeOutSettingToTicks(this.fadeOut);\n\t\t}\n\t\t\n\t\tif (this.type == InstrumentType.harmonics || this.type == InstrumentType.pickedString) {\n\t\t\tinstrumentObject[\"harmonics\"] = [];\n\t\t\tfor (let i: number = 0; i < Config.harmonicsControlPoints; i++) {\n\t\t\t\tinstrumentObject[\"harmonics\"][i] = Math.round(100 * this.harmonicsWave.harmonics[i] / Config.harmonicsMax);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (this.type == InstrumentType.noise) {\n\t\t\tinstrumentObject[\"wave\"] = Config.chipNoises[this.chipNoise].name;\n\t\t} else if (this.type == InstrumentType.spectrum) {\n\t\t\tinstrumentObject[\"spectrum\"] = [];\n\t\t\tfor (let i: number = 0; i < Config.spectrumControlPoints; i++) {\n\t\t\t\tinstrumentObject[\"spectrum\"][i] = Math.round(100 * this.spectrumWave.spectrum[i] / Config.spectrumMax);\n\t\t\t}\n\t\t} else if (this.type == InstrumentType.drumset) {\n\t\t\tinstrumentObject[\"drums\"] = [];\n\t\t\tfor (let j: number = 0; j < Config.drumCount; j++) {\n\t\t\t\tconst spectrum: number[] = [];\n\t\t\t\tfor (let i: number = 0; i < Config.spectrumControlPoints; i++) {\n\t\t\t\t\tspectrum[i] = Math.round(100 * this.drumsetSpectrumWaves[j].spectrum[i] / Config.spectrumMax);\n\t\t\t\t}\n\t\t\t\tinstrumentObject[\"drums\"][j] = {\n\t\t\t\t\t\"filterEnvelope\": this.getDrumsetEnvelope(j).name,\n\t\t\t\t\t\"spectrum\": spectrum,\n\t\t\t\t};\n\t\t\t}\n\t\t} else if (this.type == InstrumentType.chip) {\n\t\t\tinstrumentObject[\"wave\"] = Config.chipWaves[this.chipWave].name;\n\t\t\tinstrumentObject[\"unison\"] = Config.unisons[this.unison].name;\n\t\t} else if (this.type == InstrumentType.pwm) {\n\t\t\tinstrumentObject[\"pulseWidth\"] = Math.round(getPulseWidthRatio(this.pulseWidth) * 100 * 100000) / 100000;\n\t\t} else if (this.type == InstrumentType.supersaw) {\n\t\t\tinstrumentObject[\"pulseWidth\"] = Math.round(getPulseWidthRatio(this.pulseWidth) * 100 * 100000) / 100000;\n\t\t\tinstrumentObject[\"dynamism\"] = Math.round(100 * this.supersawDynamism / Config.supersawDynamismMax);\n\t\t\tinstrumentObject[\"spread\"] = Math.round(100 * this.supersawSpread / Config.supersawSpreadMax);\n\t\t\tinstrumentObject[\"shape\"] = Math.round(100 * this.supersawShape / Config.supersawShapeMax);\n\t\t} else if (this.type == InstrumentType.pickedString) {\n\t\t\tinstrumentObject[\"unison\"] = Config.unisons[this.unison].name;\n\t\t\tinstrumentObject[\"stringSustain\"] = Math.round(100 * this.stringSustain / (Config.stringSustainRange - 1));\n\t\t\tif (Config.enableAcousticSustain) {\n\t\t\t\tinstrumentObject[\"stringSustainType\"] = Config.sustainTypeNames[this.stringSustainType];\n\t\t\t}\n\t\t} else if (this.type == InstrumentType.harmonics) {\n\t\t\tinstrumentObject[\"unison\"] = Config.unisons[this.unison].name;\n\t\t} else if (this.type == InstrumentType.fm) {\n\t\t\tconst operatorArray: Object[] = [];\n\t\t\tfor (const operator of this.operators) {\n\t\t\t\toperatorArray.push({\n\t\t\t\t\t\"frequency\": Config.operatorFrequencies[operator.frequency].name,\n\t\t\t\t\t\"amplitude\": operator.amplitude,\n\t\t\t\t});\n\t\t\t}\n\t\t\tinstrumentObject[\"algorithm\"] = Config.algorithms[this.algorithm].name;\n\t\t\tinstrumentObject[\"feedbackType\"] = Config.feedbacks[this.feedbackType].name;\n\t\t\tinstrumentObject[\"feedbackAmplitude\"] = this.feedbackAmplitude;\n\t\t\tinstrumentObject[\"operators\"] = operatorArray;\n\t\t} else {\n\t\t\tthrow new Error(\"Unrecognized instrument type\");\n\t\t}\n\t\t\n\t\tconst envelopes: any[] = [];\n\t\tfor (let i = 0; i < this.envelopeCount; i++) {\n\t\t\tenvelopes.push(this.envelopes[i].toJsonObject());\n\t\t}\n\t\tinstrumentObject[\"envelopes\"] = envelopes;\n\t\t\n\t\treturn instrumentObject;\n\t}\n\t\n\tpublic fromJsonObject(instrumentObject: any, isNoiseChannel: boolean, legacyGlobalReverb: number = 0): void {\n\t\tif (instrumentObject == undefined) instrumentObject = {};\n\t\t\n\t\tlet type: InstrumentType = Config.instrumentTypeNames.indexOf(instrumentObject[\"type\"]);\n\t\tif (<any>type == -1) type = isNoiseChannel ? InstrumentType.noise : InstrumentType.chip;\n\t\tthis.setTypeAndReset(type, isNoiseChannel);\n\t\t\n\t\tif (instrumentObject[\"preset\"] != undefined) {\n\t\t\tthis.preset = instrumentObject[\"preset\"] >>> 0;\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"volume\"] != undefined) {\n\t\t\tthis.volume = clamp(0, Config.volumeRange, Math.round(5 - (instrumentObject[\"volume\"] | 0) / 20));\n\t\t} else {\n\t\t\tthis.volume = 0;\n\t\t}\n\t\t\n\t\tif (Array.isArray(instrumentObject[\"effects\"])) {\n\t\t\tlet effects: number = 0;\n\t\t\tfor (let i: number = 0; i < instrumentObject[\"effects\"].length; i++) {\n\t\t\t\teffects = effects | (1 << Config.effectNames.indexOf(instrumentObject[\"effects\"][i]));\n\t\t\t}\n\t\t\tthis.effects = (effects & ((1 << EffectType.length) - 1));\n\t\t} else {\n\t\t\t// The index of these names is reinterpreted as a bitfield, which relies on reverb and chorus being the first effects!\n\t\t\tconst legacyEffectsNames: string[] = [\"none\", \"reverb\", \"chorus\", \"chorus & reverb\"];\n\t\t\tthis.effects = legacyEffectsNames.indexOf(instrumentObject[\"effects\"]);\n\t\t\tif (this.effects == -1) this.effects = (this.type == InstrumentType.noise) ? 0 : 1;\n\t\t}\n\t\t\n\t\tthis.transition = Config.transitions.dictionary[\"normal\"].index; // default value.\n\t\tconst transitionProperty: any = instrumentObject[\"transition\"] || instrumentObject[\"envelope\"]; // the transition property used to be called envelope, so check that too.\n\t\tif (transitionProperty != undefined) {\n\t\t\tlet transition: Transition | undefined = Config.transitions.dictionary[transitionProperty];\n\t\t\tif (instrumentObject[\"fadeInSeconds\"] == undefined || instrumentObject[\"fadeOutTicks\"] == undefined) {\n\t\t\t\tconst legacySettings = (<any>{\n\t\t\t\t\t\"binary\": {transition: \"interrupt\", fadeInSeconds: 0.0, fadeOutTicks: -1},\n\t\t\t\t\t\"seamless\": {transition: \"interrupt\", fadeInSeconds: 0.0, fadeOutTicks: -1},\n\t\t\t\t\t\"sudden\": {transition: \"normal\", fadeInSeconds: 0.0, fadeOutTicks: -3},\n\t\t\t\t\t\"hard\": {transition: \"normal\", fadeInSeconds: 0.0, fadeOutTicks: -3},\n\t\t\t\t\t\"smooth\": {transition: \"normal\", fadeInSeconds: 0.025, fadeOutTicks: -3},\n\t\t\t\t\t\"soft\": {transition: \"normal\", fadeInSeconds: 0.025, fadeOutTicks: -3},\n\t\t\t\t\t// Note that the old slide transition has the same name as a new slide transition that is different.\n\t\t\t\t\t// Only apply legacy settings if the instrument JSON was created before, based on the presence\n\t\t\t\t\t// of the fade in/out fields.\n\t\t\t\t\t\"slide\": {transition: \"slide in pattern\", fadeInSeconds: 0.025, fadeOutTicks: -3},\n\t\t\t\t\t\"cross fade\": {transition: \"normal\", fadeInSeconds: 0.04, fadeOutTicks: 6},\n\t\t\t\t\t\"hard fade\": {transition: \"normal\", fadeInSeconds: 0.0, fadeOutTicks: 48},\n\t\t\t\t\t\"medium fade\": {transition: \"normal\", fadeInSeconds: 0.0125, fadeOutTicks: 72},\n\t\t\t\t\t\"soft fade\": {transition: \"normal\", fadeInSeconds: 0.06, fadeOutTicks: 96},\n\t\t\t\t})[transitionProperty];\n\t\t\t\tif (legacySettings != undefined) {\n\t\t\t\t\ttransition = Config.transitions.dictionary[legacySettings.transition];\n\t\t\t\t\t// These may be overridden below.\n\t\t\t\t\tthis.fadeIn = Synth.secondsToFadeInSetting(legacySettings.fadeInSeconds);\n\t\t\t\t\tthis.fadeOut = Synth.ticksToFadeOutSetting(legacySettings.fadeOutTicks);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (transition != undefined) this.transition = transition.index;\n\t\t\t\n\t\t\tif (this.transition != Config.transitions.dictionary[\"normal\"].index) {\n\t\t\t\t// Enable transition if it was used.\n\t\t\t\tthis.effects = (this.effects | (1 << EffectType.transition));\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Overrides legacy settings in transition above.\n\t\tif (instrumentObject[\"fadeInSeconds\"] != undefined) {\n\t\t\tthis.fadeIn = Synth.secondsToFadeInSetting(+instrumentObject[\"fadeInSeconds\"]);\n\t\t}\n\t\tif (instrumentObject[\"fadeOutTicks\"] != undefined) {\n\t\t\tthis.fadeOut = Synth.ticksToFadeOutSetting(+instrumentObject[\"fadeOutTicks\"]);\n\t\t}\n\t\t\n\t\t{\n\t\t\t// Note that the chord setting may be overridden by instrumentObject[\"chorus\"] below.\n\t\t\tconst chordProperty: any = instrumentObject[\"chord\"];\n\t\t\tconst legacyChordNames: Dictionary<string> = {\"harmony\": \"simultaneous\"};\n\t\t\tconst chord: Chord | undefined = Config.chords.dictionary[legacyChordNames[chordProperty]] || Config.chords.dictionary[chordProperty];\n\t\t\tif (chord != undefined) {\n\t\t\t\tthis.chord = chord.index;\n\t\t\t} else {\n\t\t\t\t// Different instruments have different default chord types based on historical behaviour.\n\t\t\t\tif (this.type == InstrumentType.noise) {\n\t\t\t\t\tthis.chord = Config.chords.dictionary[\"arpeggio\"].index;\n\t\t\t\t} else if (this.type == InstrumentType.pickedString) {\n\t\t\t\t\tthis.chord = Config.chords.dictionary[\"strum\"].index;\n\t\t\t\t} else if (this.type == InstrumentType.chip) {\n\t\t\t\t\tthis.chord = Config.chords.dictionary[\"arpeggio\"].index;\n\t\t\t\t} else if (this.type == InstrumentType.fm) {\n\t\t\t\t\tthis.chord = Config.chords.dictionary[\"custom interval\"].index;\n\t\t\t\t} else {\n\t\t\t\t\tthis.chord = Config.chords.dictionary[\"simultaneous\"].index;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tthis.unison = Config.unisons.dictionary[\"none\"].index; // default value.\n\t\tconst unisonProperty: any = instrumentObject[\"unison\"] || instrumentObject[\"interval\"] || instrumentObject[\"chorus\"]; // The unison property has gone by various names in the past.\n\t\tif (unisonProperty != undefined) {\n\t\t\tconst legacyChorusNames: Dictionary<string> = {\"union\": \"none\", \"fifths\": \"fifth\", \"octaves\": \"octave\"};\n\t\t\tconst unison: Unison | undefined = Config.unisons.dictionary[legacyChorusNames[unisonProperty]] || Config.unisons.dictionary[unisonProperty];\n\t\t\tif (unison != undefined) this.unison = unison.index;\n\t\t}\n\t\tif (instrumentObject[\"chorus\"] == \"custom harmony\") {\n\t\t\t// The original chorus setting had an option that now maps to two different settings. Override those if necessary.\n\t\t\tthis.unison = Config.unisons.dictionary[\"hum\"].index;\n\t\t\tthis.chord = Config.chords.dictionary[\"custom interval\"].index;\n\t\t}\n\t\tif (this.chord != Config.chords.dictionary[\"simultaneous\"].index && !Array.isArray(instrumentObject[\"effects\"])) {\n\t\t\t// Enable chord if it was used.\n\t\t\tthis.effects = (this.effects | (1 << EffectType.chord));\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"pitchShiftSemitones\"] != undefined) {\n\t\t\tthis.pitchShift = clamp(0, Config.pitchShiftRange, Math.round(+instrumentObject[\"pitchShiftSemitones\"]));\n\t\t}\n\t\tif (instrumentObject[\"detuneCents\"] != undefined) {\n\t\t\tthis.detune = clamp(0, Config.detuneMax + 1, Math.round(Config.detuneCenter + Synth.centsToDetune(+instrumentObject[\"detuneCents\"])));\n\t\t}\n\t\t\n\t\tthis.vibrato = Config.vibratos.dictionary[\"none\"].index; // default value.\n\t\tconst vibratoProperty: any = instrumentObject[\"vibrato\"] || instrumentObject[\"effect\"]; // The vibrato property was previously called \"effect\", not to be confused with the current \"effects\".\n\t\tif (vibratoProperty != undefined) {\n\t\t\tconst legacyVibratoNames: Dictionary<string> = {\"vibrato light\": \"light\", \"vibrato delayed\": \"delayed\", \"vibrato heavy\": \"heavy\"};\n\t\t\tconst vibrato: Vibrato | undefined = Config.vibratos.dictionary[legacyVibratoNames[unisonProperty]] || Config.vibratos.dictionary[vibratoProperty];\n\t\t\tif (vibrato != undefined) this.vibrato = vibrato.index;\n\t\t\t\n\t\t\t// Old songs may have a vibrato effect without explicitly enabling it.\n\t\t\tif (vibrato != Config.vibratos.dictionary[\"none\"]) {\n\t\t\t\tthis.effects = (this.effects | (1 << EffectType.vibrato));\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"pan\"] != undefined) {\n\t\t\tthis.pan = clamp(0, Config.panMax + 1, Math.round(Config.panCenter + (instrumentObject[\"pan\"] | 0) * Config.panCenter / 100));\n\t\t\t\n\t\t\t// Old songs may have a panning effect without explicitly enabling it.\n\t\t\tif (this.pan != Config.panCenter) {\n\t\t\t\tthis.effects = (this.effects | (1 << EffectType.panning));\n\t\t\t}\n\t\t} else {\n\t\t\tthis.pan = Config.panCenter;\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"distortion\"] != undefined) {\n\t\t\tthis.distortion = clamp(0, Config.distortionRange, Math.round((Config.distortionRange - 1) * (instrumentObject[\"distortion\"] | 0) / 100));\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"bitcrusherOctave\"] != undefined) {\n\t\t\tthis.bitcrusherFreq = Config.bitcrusherFreqRange - 1 - (+instrumentObject[\"bitcrusherOctave\"]) / Config.bitcrusherOctaveStep;\n\t\t}\n\t\tif (instrumentObject[\"bitcrusherQuantization\"] != undefined) {\n\t\t\tthis.bitcrusherQuantization = clamp(0, Config.bitcrusherQuantizationRange, Math.round((Config.bitcrusherQuantizationRange - 1) * (instrumentObject[\"bitcrusherQuantization\"] | 0) / 100));\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"echoSustain\"] != undefined) {\n\t\t\tthis.echoSustain = clamp(0, Config.echoSustainRange, Math.round((Config.echoSustainRange - 1) * (instrumentObject[\"echoSustain\"] | 0) / 100));\n\t\t}\n\t\tif (instrumentObject[\"echoDelayBeats\"] != undefined) {\n\t\t\tthis.echoDelay = clamp(0, Config.echoDelayRange, Math.round((+instrumentObject[\"echoDelayBeats\"]) * (Config.ticksPerPart * Config.partsPerBeat) / Config.echoDelayStepTicks - 1.0));\n\t\t}\n\t\t\n\t\tif (!isNaN(instrumentObject[\"chorus\"])) {\n\t\t\tthis.chorus = clamp(0, Config.chorusRange, Math.round((Config.chorusRange - 1) * (instrumentObject[\"chorus\"] | 0) / 100));\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"reverb\"] != undefined) {\n\t\t\tthis.reverb = clamp(0, Config.reverbRange, Math.round((Config.reverbRange - 1) * (instrumentObject[\"reverb\"] | 0) / 100));\n\t\t} else {\n\t\t\tif (legacyGlobalReverb == 0) {\n\t\t\t\t// If the original song reverb was zero, just disable the instrument reverb effect entirely.\n\t\t\t\tthis.effects = (this.effects & (~(1 << EffectType.reverb)));\n\t\t\t} else {\n\t\t\t\tthis.reverb = legacyGlobalReverb;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"pulseWidth\"] != undefined) {\n\t\t\tthis.pulseWidth = clamp(0, Config.pulseWidthRange, Math.round(Math.log2((+instrumentObject[\"pulseWidth\"]) / 50) / 0.5 - 1 + 8));\n\t\t} else {\n\t\t\tthis.pulseWidth = Config.pulseWidthRange - 1;\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"dynamism\"] != undefined) {\n\t\t\tthis.supersawDynamism = clamp(0, Config.supersawDynamismMax + 1, Math.round(Config.supersawDynamismMax * (instrumentObject[\"dynamism\"] | 0) / 100));\n\t\t} else {\n\t\t\tthis.supersawDynamism = Config.supersawDynamismMax;\n\t\t}\n\t\tif (instrumentObject[\"spread\"] != undefined) {\n\t\t\tthis.supersawSpread = clamp(0, Config.supersawSpreadMax + 1, Math.round(Config.supersawSpreadMax * (instrumentObject[\"spread\"] | 0) / 100));\n\t\t} else {\n\t\t\tthis.supersawSpread = Math.ceil(Config.supersawSpreadMax / 2.0);\n\t\t}\n\t\tif (instrumentObject[\"shape\"] != undefined) {\n\t\t\tthis.supersawShape = clamp(0, Config.supersawShapeMax + 1, Math.round(Config.supersawShapeMax * (instrumentObject[\"shape\"] | 0) / 100));\n\t\t} else {\n\t\t\tthis.supersawShape = 0;\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"harmonics\"] != undefined) {\n\t\t\tfor (let i: number = 0; i < Config.harmonicsControlPoints; i++) {\n\t\t\t\tthis.harmonicsWave.harmonics[i] = Math.max(0, Math.min(Config.harmonicsMax, Math.round(Config.harmonicsMax * (+instrumentObject[\"harmonics\"][i]) / 100)));\n\t\t\t}\n\t\t\tthis.harmonicsWave.markCustomWaveDirty();\n\t\t} else {\n\t\t\tthis.harmonicsWave.reset();\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"spectrum\"] != undefined) {\n\t\t\tfor (let i: number = 0; i < Config.spectrumControlPoints; i++) {\n\t\t\t\tthis.spectrumWave.spectrum[i] = Math.max(0, Math.min(Config.spectrumMax, Math.round(Config.spectrumMax * (+instrumentObject[\"spectrum\"][i]) / 100)));\n\t\t\t}\n\t\t\tthis.spectrumWave.markCustomWaveDirty();\n\t\t} else {\n\t\t\tthis.spectrumWave.reset(isNoiseChannel);\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"stringSustain\"] != undefined) {\n\t\t\tthis.stringSustain = clamp(0, Config.stringSustainRange, Math.round((Config.stringSustainRange - 1) * (instrumentObject[\"stringSustain\"] | 0) / 100));\n\t\t} else {\n\t\t\tthis.stringSustain = 10;\n\t\t}\n\t\tthis.stringSustainType = Config.enableAcousticSustain ? Config.sustainTypeNames.indexOf(instrumentObject[\"stringSustainType\"]) : SustainType.bright;\n\t\tif (<any>this.stringSustainType == -1) this.stringSustainType = SustainType.bright;\n\t\t\n\t\tif (this.type == InstrumentType.noise) {\n\t\t\tthis.chipNoise = Config.chipNoises.findIndex(wave=>wave.name==instrumentObject[\"wave\"]);\n\t\t\tif (this.chipNoise == -1) this.chipNoise = 1;\n\t\t}\n\t\t\n\t\tconst legacyEnvelopeNames: Dictionary<string> = {\"custom\": \"note size\", \"steady\": \"none\", \"pluck 1\": \"twang 1\", \"pluck 2\": \"twang 2\", \"pluck 3\": \"twang 3\"};\n\t\tconst getEnvelope = (name: any): Envelope | undefined => (legacyEnvelopeNames[name] != undefined) ? Config.envelopes.dictionary[legacyEnvelopeNames[name]] : Config.envelopes.dictionary[name];\n\t\t\n\t\tif (this.type == InstrumentType.drumset) {\n\t\t\tif (instrumentObject[\"drums\"] != undefined) {\n\t\t\t\tfor (let j: number = 0; j < Config.drumCount; j++) {\n\t\t\t\t\tconst drum: any = instrumentObject[\"drums\"][j];\n\t\t\t\t\tif (drum == undefined) continue;\n\t\t\t\t\t\n\t\t\t\t\tthis.drumsetEnvelopes[j] = Config.envelopes.dictionary[\"twang 2\"].index; // default value.\n\t\t\t\t\tif (drum[\"filterEnvelope\"] != undefined) {\n\t\t\t\t\t\tconst envelope: Envelope | undefined = getEnvelope(drum[\"filterEnvelope\"]);\n\t\t\t\t\t\tif (envelope != undefined) this.drumsetEnvelopes[j] = envelope.index;\n\t\t\t\t\t}\n\t\t\t\t\tif (drum[\"spectrum\"] != undefined) {\n\t\t\t\t\t\tfor (let i: number = 0; i < Config.spectrumControlPoints; i++) {\n\t\t\t\t\t\t\tthis.drumsetSpectrumWaves[j].spectrum[i] = Math.max(0, Math.min(Config.spectrumMax, Math.round(Config.spectrumMax * (+drum[\"spectrum\"][i]) / 100)));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (this.type == InstrumentType.chip) {\n\t\t\tconst legacyWaveNames: Dictionary<number> = {\"triangle\": 1, \"square\": 2, \"pulse wide\": 3, \"pulse narrow\": 4, \"sawtooth\": 5, \"double saw\": 6, \"double pulse\": 7, \"spiky\": 8, \"plateau\": 0};\n\t\t\tthis.chipWave = legacyWaveNames[instrumentObject[\"wave\"]] != undefined ? legacyWaveNames[instrumentObject[\"wave\"]] : Config.chipWaves.findIndex(wave=>wave.name==instrumentObject[\"wave\"]);\n\t\t\tif (this.chipWave == -1) this.chipWave = 1;\n\t\t}\n\t\t\n\t\tif (this.type == InstrumentType.fm) {\n\t\t\tthis.algorithm = Config.algorithms.findIndex(algorithm=>algorithm.name==instrumentObject[\"algorithm\"]);\n\t\t\tif (this.algorithm == -1) this.algorithm = 0;\n\t\t\tthis.feedbackType = Config.feedbacks.findIndex(feedback=>feedback.name==instrumentObject[\"feedbackType\"]);\n\t\t\tif (this.feedbackType == -1) this.feedbackType = 0;\n\t\t\tif (instrumentObject[\"feedbackAmplitude\"] != undefined) {\n\t\t\t\tthis.feedbackAmplitude = clamp(0, Config.operatorAmplitudeMax + 1, instrumentObject[\"feedbackAmplitude\"] | 0);\n\t\t\t} else {\n\t\t\t\tthis.feedbackAmplitude = 0;\n\t\t\t}\n\t\t\t\n\t\t\tfor (let j: number = 0; j < Config.operatorCount; j++) {\n\t\t\t\tconst operator: Operator = this.operators[j];\n\t\t\t\tlet operatorObject: any = undefined;\n\t\t\t\tif (instrumentObject[\"operators\"] != undefined) operatorObject = instrumentObject[\"operators\"][j];\n\t\t\t\tif (operatorObject == undefined) operatorObject = {};\n\t\t\t\t\n\t\t\t\toperator.frequency = Config.operatorFrequencies.findIndex(freq=>freq.name==operatorObject[\"frequency\"]);\n\t\t\t\tif (operator.frequency == -1) operator.frequency = 0;\n\t\t\t\tif (operatorObject[\"amplitude\"] != undefined) {\n\t\t\t\t\toperator.amplitude = clamp(0, Config.operatorAmplitudeMax + 1, operatorObject[\"amplitude\"] | 0);\n\t\t\t\t} else {\n\t\t\t\t\toperator.amplitude = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (instrumentObject[\"noteFilter\"] != undefined) {\n\t\t\tthis.noteFilter.fromJsonObject(instrumentObject[\"noteFilter\"]);\n\t\t} else {\n\t\t\tthis.noteFilter.reset();\n\t\t}\n\t\tif (Array.isArray(instrumentObject[\"eqFilter\"])) {\n\t\t\tthis.eqFilter.fromJsonObject(instrumentObject[\"eqFilter\"]);\n\t\t} else {\n\t\t\tthis.eqFilter.reset();\n\t\t\t\n\t\t\tconst legacySettings: LegacySettings = {};\n\t\t\t\n\t\t\t// Try converting from legacy filter settings.\n\t\t\tconst filterCutoffMaxHz: number = 8000;\n\t\t\tconst filterCutoffRange: number = 11;\n\t\t\tconst filterResonanceRange: number = 8;\n\t\t\tif (instrumentObject[\"filterCutoffHz\"] != undefined) {\n\t\t\t\tlegacySettings.filterCutoff = clamp(0, filterCutoffRange, Math.round((filterCutoffRange - 1) + 2.0 * Math.log((instrumentObject[\"filterCutoffHz\"] | 0) / filterCutoffMaxHz) / Math.LN2));\n\t\t\t} else {\n\t\t\t\tlegacySettings.filterCutoff = (this.type == InstrumentType.chip) ? 6 : 10;\n\t\t\t}\n\t\t\tif (instrumentObject[\"filterResonance\"] != undefined) {\n\t\t\t\tlegacySettings.filterResonance = clamp(0, filterResonanceRange, Math.round((filterResonanceRange - 1) * (instrumentObject[\"filterResonance\"] | 0) / 100));\n\t\t\t} else {\n\t\t\t\tlegacySettings.filterResonance = 0;\n\t\t\t}\n\t\t\t\n\t\t\tlegacySettings.filterEnvelope = getEnvelope(instrumentObject[\"filterEnvelope\"]);\n\t\t\tlegacySettings.pulseEnvelope = getEnvelope(instrumentObject[\"pulseEnvelope\"]);\n\t\t\tlegacySettings.feedbackEnvelope = getEnvelope(instrumentObject[\"feedbackEnvelope\"]);\n\t\t\tif (Array.isArray(instrumentObject[\"operators\"])) {\n\t\t\t\tlegacySettings.operatorEnvelopes = [];\n\t\t\t\tfor (let j: number = 0; j < Config.operatorCount; j++) {\n\t\t\t\t\tlet envelope: Envelope | undefined;\n\t\t\t\t\tif (instrumentObject[\"operators\"][j] != undefined) {\n\t\t\t\t\t\tenvelope = getEnvelope(instrumentObject[\"operators\"][j][\"envelope\"]);\n\t\t\t\t\t}\n\t\t\t\t\tlegacySettings.operatorEnvelopes[j] = (envelope != undefined) ? envelope : Config.envelopes.dictionary[\"none\"];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Try converting from even older legacy filter settings.\n\t\t\tif (instrumentObject[\"filter\"] != undefined) {\n\t\t\t\tconst legacyToCutoff: number[] = [10, 6, 3, 0, 8, 5, 2];\n\t\t\t\tconst legacyToEnvelope: string[] = [\"none\", \"none\", \"none\", \"none\", \"decay 1\", \"decay 2\", \"decay 3\"];\n\t\t\t\tconst filterNames: string[] = [\"none\", \"bright\", \"medium\", \"soft\", \"decay bright\", \"decay medium\", \"decay soft\"];\n\t\t\t\tconst oldFilterNames: Dictionary<number> = {\"sustain sharp\": 1, \"sustain medium\": 2, \"sustain soft\": 3, \"decay sharp\": 4};\n\t\t\t\tlet legacyFilter: number = oldFilterNames[instrumentObject[\"filter\"]] != undefined ? oldFilterNames[instrumentObject[\"filter\"]] : filterNames.indexOf(instrumentObject[\"filter\"]);\n\t\t\t\tif (legacyFilter == -1) legacyFilter = 0;\n\t\t\t\tlegacySettings.filterCutoff = legacyToCutoff[legacyFilter];\n\t\t\t\tlegacySettings.filterEnvelope = getEnvelope(legacyToEnvelope[legacyFilter]);\n\t\t\t\tlegacySettings.filterResonance = 0;\n\t\t\t}\n\t\t\t\n\t\t\tthis.convertLegacySettings(legacySettings);\n\t\t}\n\t\t\n\t\tif (Array.isArray(instrumentObject[\"envelopes\"])) {\n\t\t\tconst envelopeArray: any[] = instrumentObject[\"envelopes\"];\n\t\t\tfor (let i = 0; i < envelopeArray.length; i++) {\n\t\t\t\tif (this.envelopeCount >= Config.maxEnvelopeCount) break;\n\t\t\t\tconst tempEnvelope: EnvelopeSettings = new EnvelopeSettings();\n\t\t\t\ttempEnvelope.fromJsonObject(envelopeArray[i]);\n\t\t\t\tthis.addEnvelope(tempEnvelope.target, tempEnvelope.index, tempEnvelope.envelope);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic static frequencyFromPitch(pitch: number): number {\n\t\treturn 440.0 * Math.pow(2.0, (pitch - 69.0) / 12.0);\n\t}\n\t\n\tpublic addEnvelope(target: number, index: number, envelope: number): void {\n\t\tif (!this.supportsEnvelopeTarget(target, index)) throw new Error();\n\t\tif (this.envelopeCount >= Config.maxEnvelopeCount) throw new Error();\n\t\twhile (this.envelopes.length <= this.envelopeCount) this.envelopes[this.envelopes.length] = new EnvelopeSettings();\n\t\tconst envelopeSettings: EnvelopeSettings = this.envelopes[this.envelopeCount];\n\t\tenvelopeSettings.target = target;\n\t\tenvelopeSettings.index = index;\n\t\tenvelopeSettings.envelope = envelope;\n\t\tthis.envelopeCount++;\n\t}\n\t\n\tpublic supportsEnvelopeTarget(target: number, index: number): boolean {\n\t\tconst automationTarget: AutomationTarget = Config.instrumentAutomationTargets[target];\n\t\tif (automationTarget.computeIndex == null && automationTarget.name != \"none\") {\n\t\t\treturn false;\n\t\t}\n\t\tif (index >= automationTarget.maxCount) {\n\t\t\treturn false;\n\t\t}\n\t\tif (automationTarget.compatibleInstruments != null && automationTarget.compatibleInstruments.indexOf(this.type) == -1) {\n\t\t\treturn false;\n\t\t}\n\t\tif (automationTarget.effect != null && (this.effects & (1 << automationTarget.effect)) == 0) {\n\t\t\treturn false;\n\t\t}\n\t\tif (automationTarget.isFilter) {\n\t\t\t//if (automationTarget.perNote) {\n\t\t\t\tif (index >= this.noteFilter.controlPointCount) return false;\n\t\t\t//} else {\n\t\t\t//\tif (index >= this.eqFilter.controlPointCount) return false;\n\t\t\t//}\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tpublic clearInvalidEnvelopeTargets(): void {\n\t\tfor (let envelopeIndex: number = 0; envelopeIndex < this.envelopeCount; envelopeIndex++) {\n\t\t\tconst target: number = this.envelopes[envelopeIndex].target;\n\t\t\tconst index: number = this.envelopes[envelopeIndex].index;\n\t\t\tif (!this.supportsEnvelopeTarget(target, index)) {\n\t\t\t\tthis.envelopes[envelopeIndex].target = Config.instrumentAutomationTargets.dictionary[\"none\"].index;\n\t\t\t\tthis.envelopes[envelopeIndex].index = 0;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic getTransition(): Transition {\n\t\treturn effectsIncludeTransition(this.effects) ? Config.transitions[this.transition] : Config.transitions.dictionary[\"normal\"];\n\t}\n\t\n\tpublic getFadeInSeconds(): number {\n\t\treturn (this.type == InstrumentType.drumset) ? 0.0 : Synth.fadeInSettingToSeconds(this.fadeIn);\n\t}\n\t\n\tpublic getFadeOutTicks(): number {\n\t\treturn (this.type == InstrumentType.drumset) ? Config.drumsetFadeOutTicks : Synth.fadeOutSettingToTicks(this.fadeOut)\n\t}\n\t\n\tpublic getChord(): Chord {\n\t\treturn effectsIncludeChord(this.effects) ? Config.chords[this.chord] : Config.chords.dictionary[\"simultaneous\"];\n\t}\n\t\n\tpublic getDrumsetEnvelope(pitch: number): Envelope {\n\t\tif (this.type != InstrumentType.drumset) throw new Error(\"Can't getDrumsetEnvelope() for non-drumset.\");\n\t\treturn Config.envelopes[this.drumsetEnvelopes[pitch]];\n\t}\n}\n\nexport class Channel {\n\tpublic octave: number = 0;\n\tpublic readonly instruments: Instrument[] = [];\n\tpublic readonly patterns: Pattern[] = [];\n\tpublic readonly bars: number[] = [];\n\tpublic muted: boolean = false;\n}\n\nexport class Song {\n\tprivate static readonly _format: string = \"BeepBox\";\n\tprivate static readonly _oldestVersion: number = 2;\n\tprivate static readonly _latestVersion: number = 9;\n\t\n\tpublic scale: number;\n\tpublic key: number;\n\tpublic tempo: number;\n\tpublic beatsPerBar: number;\n\tpublic barCount: number;\n\tpublic patternsPerChannel: number;\n\tpublic rhythm: number;\n\tpublic layeredInstruments: boolean;\n\tpublic patternInstruments: boolean;\n\tpublic loopStart: number;\n\tpublic loopLength: number;\n\tpublic pitchChannelCount: number;\n\tpublic noiseChannelCount: number;\n\tpublic readonly channels: Channel[] = [];\n\t\n\tconstructor(string?: string) {\n\t\tif (string != undefined) {\n\t\t\tthis.fromBase64String(string);\n\t\t} else {\n\t\t\tthis.initToDefault(true);\n\t\t}\n\t}\n\t\n\tpublic getChannelCount(): number {\n\t\treturn this.pitchChannelCount + this.noiseChannelCount;\n\t}\n\t\n\tpublic getMaxInstrumentsPerChannel(): number {\n\t\treturn Math.max(\n\t\t\tthis.layeredInstruments ? Config.layeredInstrumentCountMax : Config.instrumentCountMin,\n\t\t\tthis.patternInstruments ? Config.patternInstrumentCountMax : Config.instrumentCountMin);\n\t}\n\t\n\tpublic getMaxInstrumentsPerPattern(channelIndex: number): number {\n\t\treturn this.getMaxInstrumentsPerPatternForChannel(this.channels[channelIndex]);\n\t}\n\t\n\tpublic getMaxInstrumentsPerPatternForChannel(channel: Channel): number {\n\t\treturn this.layeredInstruments\n\t\t\t? Math.min(Config.layeredInstrumentCountMax, channel.instruments.length)\n\t\t\t: 1;\n\t}\n\t\n\tpublic getChannelIsNoise(channelIndex: number): boolean {\n\t\treturn (channelIndex >= this.pitchChannelCount);\n\t}\n\t\n\tpublic initToDefault(andResetChannels: boolean = true): void {\n\t\tthis.scale = 0;\n\t\tthis.key = 0;\n\t\tthis.loopStart = 0;\n\t\tthis.loopLength = 4;\n\t\tthis.tempo = 150;\n\t\tthis.beatsPerBar = 8;\n\t\tthis.barCount = 16;\n\t\tthis.patternsPerChannel = 8;\n\t\tthis.rhythm = 1;\n\t\tthis.layeredInstruments = false;\n\t\tthis.patternInstruments = false;\n\t\t\n\t\tif (andResetChannels) {\n\t\t\tthis.pitchChannelCount = 3;\n\t\t\tthis.noiseChannelCount = 1;\n\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\tconst isNoiseChannel: boolean = channelIndex >= this.pitchChannelCount;\n\t\t\t\tif (this.channels.length <= channelIndex) {\n\t\t\t\t\tthis.channels[channelIndex] = new Channel();\n\t\t\t\t}\n\t\t\t\tconst channel: Channel = this.channels[channelIndex];\n\t\t\t\tchannel.octave = isNoiseChannel ? 0 : 4 - channelIndex; // [4, 3, 2, 0]: Descending octaves with drums at zero in last channel.\n\t\t\t\n\t\t\t\tfor (let pattern: number = 0; pattern < this.patternsPerChannel; pattern++) {\n\t\t\t\t\tif (channel.patterns.length <= pattern) {\n\t\t\t\t\t\tchannel.patterns[pattern] = new Pattern();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchannel.patterns[pattern].reset();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tchannel.patterns.length = this.patternsPerChannel;\n\t\t\t\n\t\t\t\tfor (let instrument: number = 0; instrument < Config.instrumentCountMin; instrument++) {\n\t\t\t\t\tif (channel.instruments.length <= instrument) {\n\t\t\t\t\t\tchannel.instruments[instrument] = new Instrument(isNoiseChannel);\n\t\t\t\t\t}\n\t\t\t\t\tchannel.instruments[instrument].setTypeAndReset(isNoiseChannel ? InstrumentType.noise : InstrumentType.chip, isNoiseChannel);\n\t\t\t\t}\n\t\t\t\tchannel.instruments.length = Config.instrumentCountMin;\n\t\t\t\n\t\t\t\tfor (let bar: number = 0; bar < this.barCount; bar++) {\n\t\t\t\t\tchannel.bars[bar] = bar < 4 ? 1 : 0;\n\t\t\t\t}\n\t\t\t\tchannel.bars.length = this.barCount;\n\t\t\t}\n\t\t\tthis.channels.length = this.getChannelCount();\n\t\t}\n\t}\n\t\n\tpublic toBase64String(): string {\n\t\tlet bits: BitFieldWriter;\n\t\tlet buffer: number[] = [];\n\t\t\n\t\tbuffer.push(base64IntToCharCode[Song._latestVersion]);\n\t\tbuffer.push(SongTagCode.channelCount, base64IntToCharCode[this.pitchChannelCount], base64IntToCharCode[this.noiseChannelCount]);\n\t\tbuffer.push(SongTagCode.scale, base64IntToCharCode[this.scale]);\n\t\tbuffer.push(SongTagCode.key, base64IntToCharCode[this.key]);\n\t\tbuffer.push(SongTagCode.loopStart, base64IntToCharCode[this.loopStart >> 6], base64IntToCharCode[this.loopStart & 0x3f]);\n\t\tbuffer.push(SongTagCode.loopEnd, base64IntToCharCode[(this.loopLength - 1) >> 6], base64IntToCharCode[(this.loopLength - 1) & 0x3f]);\n\t\tbuffer.push(SongTagCode.tempo, base64IntToCharCode[this.tempo >> 6], base64IntToCharCode[this.tempo & 63]);\n\t\tbuffer.push(SongTagCode.beatCount, base64IntToCharCode[this.beatsPerBar - 1]);\n\t\tbuffer.push(SongTagCode.barCount, base64IntToCharCode[(this.barCount - 1) >> 6], base64IntToCharCode[(this.barCount - 1) & 0x3f]);\n\t\tbuffer.push(SongTagCode.patternCount, base64IntToCharCode[(this.patternsPerChannel - 1) >> 6], base64IntToCharCode[(this.patternsPerChannel - 1) & 0x3f]);\n\t\tbuffer.push(SongTagCode.rhythm, base64IntToCharCode[this.rhythm]);\n\t\t\n\t\tbuffer.push(SongTagCode.instrumentCount, base64IntToCharCode[(<any>this.layeredInstruments << 1) | <any>this.patternInstruments]);\n\t\tif (this.layeredInstruments || this.patternInstruments) {\n\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\tbuffer.push(base64IntToCharCode[this.channels[channelIndex].instruments.length - Config.instrumentCountMin]);\n\t\t\t}\n\t\t}\n\t\t\n\t\tbuffer.push(SongTagCode.channelOctave);\n\t\tfor (let channelIndex: number = 0; channelIndex < this.pitchChannelCount; channelIndex++) {\n\t\t\tbuffer.push(base64IntToCharCode[this.channels[channelIndex].octave]);\n\t\t}\n\t\t\n\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\tfor (let i: number = 0; i < this.channels[channelIndex].instruments.length; i++) {\n\t\t\t\tconst instrument: Instrument = this.channels[channelIndex].instruments[i];\n\t\t\t\tbuffer.push(SongTagCode.startInstrument, base64IntToCharCode[instrument.type]);\n\t\t\t\tbuffer.push(SongTagCode.volume, base64IntToCharCode[instrument.volume]);\n\t\t\t\tbuffer.push(SongTagCode.preset, base64IntToCharCode[instrument.preset >> 6], base64IntToCharCode[instrument.preset & 63]);\n\t\t\t\t\n\t\t\t\tbuffer.push(SongTagCode.eqFilter, base64IntToCharCode[instrument.eqFilter.controlPointCount]);\n\t\t\t\tfor (let j: number = 0; j < instrument.eqFilter.controlPointCount; j++) {\n\t\t\t\t\tconst point: FilterControlPoint = instrument.eqFilter.controlPoints[j];\n\t\t\t\t\tbuffer.push(base64IntToCharCode[point.type], base64IntToCharCode[point.freq], base64IntToCharCode[point.gain]);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// The list of enabled effects is represented as a 12-bit bitfield using two six-bit characters.\n\t\t\t\tbuffer.push(SongTagCode.effects, base64IntToCharCode[instrument.effects >> 6], base64IntToCharCode[instrument.effects & 63]);\n\t\t\t\tif (effectsIncludeNoteFilter(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.noteFilter.controlPointCount]);\n\t\t\t\t\tfor (let j: number = 0; j < instrument.noteFilter.controlPointCount; j++) {\n\t\t\t\t\t\tconst point: FilterControlPoint = instrument.noteFilter.controlPoints[j];\n\t\t\t\t\t\tbuffer.push(base64IntToCharCode[point.type], base64IntToCharCode[point.freq], base64IntToCharCode[point.gain]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (effectsIncludeTransition(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.transition]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludeChord(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.chord]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludePitchShift(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.pitchShift]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludeDetune(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.detune]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludeVibrato(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.vibrato]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludeDistortion(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.distortion]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludeBitcrusher(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.bitcrusherFreq], base64IntToCharCode[instrument.bitcrusherQuantization]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludePanning(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.pan]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludeChorus(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.chorus]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludeEcho(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.echoSustain], base64IntToCharCode[instrument.echoDelay]);\n\t\t\t\t}\n\t\t\t\tif (effectsIncludeReverb(instrument.effects)) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.reverb]);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (instrument.type != InstrumentType.drumset) {\n\t\t\t\t\tbuffer.push(SongTagCode.fadeInOut, base64IntToCharCode[instrument.fadeIn], base64IntToCharCode[instrument.fadeOut]);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (instrument.type == InstrumentType.harmonics || instrument.type == InstrumentType.pickedString) {\n\t\t\t\t\tbuffer.push(SongTagCode.harmonics);\n\t\t\t\t\tconst harmonicsBits: BitFieldWriter = new BitFieldWriter();\n\t\t\t\t\tfor (let i: number = 0; i < Config.harmonicsControlPoints; i++) {\n\t\t\t\t\t\tharmonicsBits.write(Config.harmonicsControlPointBits, instrument.harmonicsWave.harmonics[i]);\n\t\t\t\t\t}\n\t\t\t\t\tharmonicsBits.encodeBase64(buffer);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (instrument.type == InstrumentType.chip) {\n\t\t\t\t\tbuffer.push(SongTagCode.wave, base64IntToCharCode[instrument.chipWave]);\n\t\t\t\t\tbuffer.push(SongTagCode.unison, base64IntToCharCode[instrument.unison]);\n\t\t\t\t} else if (instrument.type == InstrumentType.fm) {\n\t\t\t\t\tbuffer.push(SongTagCode.algorithm, base64IntToCharCode[instrument.algorithm]);\n\t\t\t\t\tbuffer.push(SongTagCode.feedbackType, base64IntToCharCode[instrument.feedbackType]);\n\t\t\t\t\tbuffer.push(SongTagCode.feedbackAmplitude, base64IntToCharCode[instrument.feedbackAmplitude]);\n\t\t\t\t\t\n\t\t\t\t\tbuffer.push(SongTagCode.operatorFrequencies);\n\t\t\t\t\tfor (let o: number = 0; o < Config.operatorCount; o++) {\n\t\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.operators[o].frequency]);\n\t\t\t\t\t}\n\t\t\t\t\tbuffer.push(SongTagCode.operatorAmplitudes);\n\t\t\t\t\tfor (let o: number = 0; o < Config.operatorCount; o++) {\n\t\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.operators[o].amplitude]);\n\t\t\t\t\t}\n\t\t\t\t} else if (instrument.type == InstrumentType.noise) {\n\t\t\t\t\tbuffer.push(SongTagCode.wave, base64IntToCharCode[instrument.chipNoise]);\n\t\t\t\t} else if (instrument.type == InstrumentType.spectrum) {\n\t\t\t\t\tbuffer.push(SongTagCode.spectrum);\n\t\t\t\t\tconst spectrumBits: BitFieldWriter = new BitFieldWriter();\n\t\t\t\t\tfor (let i: number = 0; i < Config.spectrumControlPoints; i++) {\n\t\t\t\t\t\tspectrumBits.write(Config.spectrumControlPointBits, instrument.spectrumWave.spectrum[i]);\n\t\t\t\t\t}\n\t\t\t\t\tspectrumBits.encodeBase64(buffer);\n\t\t\t\t} else if (instrument.type == InstrumentType.drumset) {\n\t\t\t\t\tbuffer.push(SongTagCode.drumsetEnvelopes);\n\t\t\t\t\tfor (let j: number = 0; j < Config.drumCount; j++) {\n\t\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.drumsetEnvelopes[j]]);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tbuffer.push(SongTagCode.spectrum);\n\t\t\t\t\tconst spectrumBits: BitFieldWriter = new BitFieldWriter();\n\t\t\t\t\tfor (let j: number = 0; j < Config.drumCount; j++) {\n\t\t\t\t\t\tfor (let i: number = 0; i < Config.spectrumControlPoints; i++) {\n\t\t\t\t\t\t\tspectrumBits.write(Config.spectrumControlPointBits, instrument.drumsetSpectrumWaves[j].spectrum[i]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tspectrumBits.encodeBase64(buffer);\n\t\t\t\t} else if (instrument.type == InstrumentType.harmonics) {\n\t\t\t\t\tbuffer.push(SongTagCode.unison, base64IntToCharCode[instrument.unison]);\n\t\t\t\t} else if (instrument.type == InstrumentType.pwm) {\n\t\t\t\t\tbuffer.push(SongTagCode.pulseWidth, base64IntToCharCode[instrument.pulseWidth]);\n\t\t\t\t} else if (instrument.type == InstrumentType.supersaw) {\n\t\t\t\t\tbuffer.push(SongTagCode.supersaw, base64IntToCharCode[instrument.supersawDynamism], base64IntToCharCode[instrument.supersawSpread], base64IntToCharCode[instrument.supersawShape]);\n\t\t\t\t\tbuffer.push(SongTagCode.pulseWidth, base64IntToCharCode[instrument.pulseWidth]);\n\t\t\t\t} else if (instrument.type == InstrumentType.pickedString) {\n\t\t\t\t\tbuffer.push(SongTagCode.unison, base64IntToCharCode[instrument.unison]);\n\t\t\t\t\tif (Config.stringSustainRange > 0x20 || SustainType.length > 2) {\n\t\t\t\t\t\tthrow new Error(\"Not enough bits to represent sustain value and type in same base64 character.\");\n\t\t\t\t\t}\n\t\t\t\t\tbuffer.push(SongTagCode.stringSustain, base64IntToCharCode[instrument.stringSustain | (instrument.stringSustainType << 5)]);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\"Unknown instrument type.\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbuffer.push(SongTagCode.envelopes, base64IntToCharCode[instrument.envelopeCount]);\n\t\t\t\tfor (let envelopeIndex: number = 0; envelopeIndex < instrument.envelopeCount; envelopeIndex++) {\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.envelopes[envelopeIndex].target]);\n\t\t\t\t\tif (Config.instrumentAutomationTargets[instrument.envelopes[envelopeIndex].target].maxCount > 1) {\n\t\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.envelopes[envelopeIndex].index]);\n\t\t\t\t\t}\n\t\t\t\t\tbuffer.push(base64IntToCharCode[instrument.envelopes[envelopeIndex].envelope]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tbuffer.push(SongTagCode.bars);\n\t\tbits = new BitFieldWriter();\n\t\tlet neededBits: number = 0;\n\t\twhile ((1 << neededBits) < this.patternsPerChannel + 1) neededBits++;\n\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) for (let i: number = 0; i < this.barCount; i++) {\n\t\t\tbits.write(neededBits, this.channels[channelIndex].bars[i]);\n\t\t}\n\t\tbits.encodeBase64(buffer);\n\t\t\n\t\tbuffer.push(SongTagCode.patterns);\n\t\tbits = new BitFieldWriter();\n\t\tconst shapeBits: BitFieldWriter = new BitFieldWriter();\n\t\tconst bitsPerNoteSize: number = Song.getNeededBits(Config.noteSizeMax);\n\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\tconst channel: Channel = this.channels[channelIndex];\n\t\t\tconst maxInstrumentsPerPattern: number = this.getMaxInstrumentsPerPattern(channelIndex);\n\t\t\tconst neededInstrumentCountBits: number = Song.getNeededBits(maxInstrumentsPerPattern - Config.instrumentCountMin);\n\t\t\tconst neededInstrumentIndexBits: number = Song.getNeededBits(channel.instruments.length - 1);\n\t\t\tconst isNoiseChannel: boolean = this.getChannelIsNoise(channelIndex);\n\t\t\tconst octaveOffset: number = isNoiseChannel ? 0 : channel.octave * Config.pitchesPerOctave;\n\t\t\tlet lastPitch: number = (isNoiseChannel ? 4 : octaveOffset);\n\t\t\tconst recentPitches: number[] = isNoiseChannel ? [4,6,7,2,3,8,0,10] : [0, 7, 12, 19, 24, -5, -12];\n\t\t\tconst recentShapes: string[] = [];\n\t\t\tfor (let i: number = 0; i < recentPitches.length; i++) {\n\t\t\t\trecentPitches[i] += octaveOffset;\n\t\t\t}\n\t\t\tfor (const pattern of channel.patterns) {\n\t\t\t\tif (this.patternInstruments) {\n\t\t\t\t\tconst instrumentCount: number = validateRange(Config.instrumentCountMin, maxInstrumentsPerPattern, pattern.instruments.length);\n\t\t\t\t\tbits.write(neededInstrumentCountBits, instrumentCount - Config.instrumentCountMin);\n\t\t\t\t\tfor (let i: number = 0; i < instrumentCount; i++) {\n\t\t\t\t\t\tbits.write(neededInstrumentIndexBits, pattern.instruments[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (pattern.notes.length > 0) {\n\t\t\t\t\tbits.write(1, 1);\n\t\t\t\t\t\n\t\t\t\t\tlet curPart: number = 0;\n\t\t\t\t\tfor (const note of pattern.notes) {\n\t\t\t\t\t\tif (note.start > curPart) {\n\t\t\t\t\t\t\tbits.write(2, 0); // rest\n\t\t\t\t\t\t\tbits.writePartDuration(note.start - curPart);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tshapeBits.clear();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// 0: 1 pitch, 10: 2 pitches, 110: 3 pitches, 111: 4 pitches\n\t\t\t\t\t\tfor (let i: number = 1; i < note.pitches.length; i++) shapeBits.write(1,1);\n\t\t\t\t\t\tif (note.pitches.length < Config.maxChordSize) shapeBits.write(1,0);\n\t\t\t\t\t\t\n\t\t\t\t\t\tshapeBits.writePinCount(note.pins.length - 1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tshapeBits.write(bitsPerNoteSize, note.pins[0].size);\n\t\t\t\t\t\t\n\t\t\t\t\t\tlet shapePart: number = 0;\n\t\t\t\t\t\tlet startPitch: number = note.pitches[0];\n\t\t\t\t\t\tlet currentPitch: number = startPitch;\n\t\t\t\t\t\tconst pitchBends: number[] = [];\n\t\t\t\t\t\tfor (let i: number = 1; i < note.pins.length; i++) {\n\t\t\t\t\t\t\tconst pin: NotePin = note.pins[i];\n\t\t\t\t\t\t\tconst nextPitch: number = startPitch + pin.interval;\n\t\t\t\t\t\t\tif (currentPitch != nextPitch) {\n\t\t\t\t\t\t\t\tshapeBits.write(1, 1);\n\t\t\t\t\t\t\t\tpitchBends.push(nextPitch);\n\t\t\t\t\t\t\t\tcurrentPitch = nextPitch;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tshapeBits.write(1, 0);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tshapeBits.writePartDuration(pin.time - shapePart);\n\t\t\t\t\t\t\tshapePart = pin.time;\n\t\t\t\t\t\t\tshapeBits.write(bitsPerNoteSize, pin.size);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst shapeString: string = String.fromCharCode.apply(null, shapeBits.encodeBase64([]));\n\t\t\t\t\t\tconst shapeIndex: number = recentShapes.indexOf(shapeString);\n\t\t\t\t\t\tif (shapeIndex == -1) {\n\t\t\t\t\t\t\tbits.write(2, 1); // new shape\n\t\t\t\t\t\t\tbits.concat(shapeBits);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbits.write(1, 1); // old shape\n\t\t\t\t\t\t\tbits.writeLongTail(0, 0, shapeIndex);\n\t\t\t\t\t\t\trecentShapes.splice(shapeIndex, 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\trecentShapes.unshift(shapeString);\n\t\t\t\t\t\tif (recentShapes.length > 10) recentShapes.pop();\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst allPitches: number[] = note.pitches.concat(pitchBends);\n\t\t\t\t\t\tfor (let i: number = 0; i < allPitches.length; i++) {\n\t\t\t\t\t\t\tconst pitch: number = allPitches[i];\n\t\t\t\t\t\t\tconst pitchIndex: number = recentPitches.indexOf(pitch);\n\t\t\t\t\t\t\tif (pitchIndex == -1) {\n\t\t\t\t\t\t\t\tlet interval: number = 0;\n\t\t\t\t\t\t\t\tlet pitchIter: number = lastPitch;\n\t\t\t\t\t\t\t\tif (pitchIter < pitch) {\n\t\t\t\t\t\t\t\t\twhile (pitchIter != pitch) {\n\t\t\t\t\t\t\t\t\t\tpitchIter++;\n\t\t\t\t\t\t\t\t\t\tif (recentPitches.indexOf(pitchIter) == -1) interval++;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\twhile (pitchIter != pitch) {\n\t\t\t\t\t\t\t\t\t\tpitchIter--;\n\t\t\t\t\t\t\t\t\t\tif (recentPitches.indexOf(pitchIter) == -1) interval--;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbits.write(1, 0);\n\t\t\t\t\t\t\t\tbits.writePitchInterval(interval);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tbits.write(1, 1);\n\t\t\t\t\t\t\t\tbits.write(3, pitchIndex);\n\t\t\t\t\t\t\t\trecentPitches.splice(pitchIndex, 1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\trecentPitches.unshift(pitch);\n\t\t\t\t\t\t\tif (recentPitches.length > 8) recentPitches.pop();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (i == note.pitches.length - 1) {\n\t\t\t\t\t\t\t\tlastPitch = note.pitches[0];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tlastPitch = pitch;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (note.start == 0) {\n\t\t\t\t\t\t\tbits.write(1, note.continuesLastPattern ? 1 : 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcurPart = note.end;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (curPart < this.beatsPerBar * Config.partsPerBeat) {\n\t\t\t\t\t\tbits.write(2, 0); // rest\n\t\t\t\t\t\tbits.writePartDuration(this.beatsPerBar * Config.partsPerBeat - curPart);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tbits.write(1, 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tlet stringLength: number = bits.lengthBase64();\n\t\tlet digits: number[] = [];\n\t\twhile (stringLength > 0) {\n\t\t\tdigits.unshift(base64IntToCharCode[stringLength & 0x3f]);\n\t\t\tstringLength = stringLength >> 6;\n\t\t}\n\t\tbuffer.push(base64IntToCharCode[digits.length]);\n\t\tArray.prototype.push.apply(buffer, digits); // append digits to buffer.\n\t\tbits.encodeBase64(buffer);\n\t\t\n\t\tconst maxApplyArgs: number = 64000;\n\t\tif (buffer.length < maxApplyArgs) {\n\t\t\t// Note: Function.apply may break for long argument lists. \n\t\t\treturn String.fromCharCode.apply(null, buffer);\n\t\t} else {\n\t\t\tlet result: string = \"\";\n\t\t\tfor (let i: number = 0; i < buffer.length; i += maxApplyArgs) {\n\t\t\t\tresult += String.fromCharCode.apply(null, buffer.slice(i, i + maxApplyArgs));\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\t\n\tprivate static _envelopeFromLegacyIndex(legacyIndex: number): Envelope {\n\t\t// I swapped the order of \"custom\"/\"steady\", now \"none\"/\"note size\".\n\t\tif (legacyIndex == 0) legacyIndex = 1; else if (legacyIndex == 1) legacyIndex = 0;\n\t\treturn Config.envelopes[clamp(0, Config.envelopes.length, legacyIndex)];\n\t}\n\t\n\tpublic fromBase64String(compressed: string): void {\n\t\tif (compressed == null || compressed == \"\") {\n\t\t\tthis.initToDefault(true);\n\t\t\treturn;\n\t\t}\n\t\tlet charIndex: number = 0;\n\t\t// skip whitespace.\n\t\twhile (compressed.charCodeAt(charIndex) <= CharCode.SPACE) charIndex++;\n\t\t// skip hash mark.\n\t\tif (compressed.charCodeAt(charIndex) == CharCode.HASH) charIndex++;\n\t\t// if it starts with curly brace, treat it as JSON.\n\t\tif (compressed.charCodeAt(charIndex) == CharCode.LEFT_CURLY_BRACE) {\n\t\t\tthis.fromJsonObject(JSON.parse(charIndex == 0 ? compressed : compressed.substring(charIndex)));\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tconst version: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\tif (version == -1 || version > Song._latestVersion || version < Song._oldestVersion) return;\n\t\tconst beforeThree: boolean = version < 3;\n\t\tconst beforeFour: boolean = version < 4;\n\t\tconst beforeFive: boolean = version < 5;\n\t\tconst beforeSix: boolean = version < 6;\n\t\tconst beforeSeven: boolean = version < 7;\n\t\tconst beforeEight: boolean = version < 8;\n\t\tconst beforeNine: boolean = version < 9;\n\t\tthis.initToDefault(beforeNine);\n\t\t\n\t\tif (beforeThree) {\n\t\t\t// Originally, the only instrument transition was \"instant\" and the only drum wave was \"retro\".\n\t\t\tfor (const channel of this.channels) {\n\t\t\t\tchannel.instruments[0].transition = Config.transitions.dictionary[\"interrupt\"].index;\n\t\t\t\tchannel.instruments[0].effects |= 1 << EffectType.transition;\n\t\t\t}\n\t\t\tthis.channels[3].instruments[0].chipNoise = 0;\n\t\t}\n\t\t\n\t\tlet legacySettingsCache: LegacySettings[][] | null = null;\n\t\tif (beforeNine) {\n\t\t\t// Unfortunately, old versions of BeepBox had a variety of different ways of saving\n\t\t\t// filter-and-envelope-related parameters in the URL, and none of them directly\n\t\t\t// correspond to the new way of saving these parameters. We can approximate the old\n\t\t\t// settings by collecting all the old settings for an instrument and passing them to\n\t\t\t// convertLegacySettings(), so I use this data structure to collect the settings\n\t\t\t// for each instrument if necessary.\n\t\t\tlegacySettingsCache = [];\n\t\t\tfor (let i: number = legacySettingsCache.length; i < this.getChannelCount(); i++) {\n\t\t\t\tlegacySettingsCache[i] = [];\n\t\t\t\tfor (let j: number = 0; j < Config.instrumentCountMin; j++) legacySettingsCache[i][j] = {};\n\t\t\t}\n\t\t}\n\t\t\n\t\tlet legacyGlobalReverb: number = 0; // beforeNine reverb was song-global, record that reverb here and adapt it to instruments as needed.\n\t\t\n\t\tlet instrumentChannelIterator: number = 0;\n\t\tlet instrumentIndexIterator: number = -1;\n\t\tlet command: SongTagCode;\n\t\twhile (charIndex < compressed.length) switch(command = compressed.charCodeAt(charIndex++)) {\n\t\t\tcase SongTagCode.channelCount: {\n\t\t\t\tthis.pitchChannelCount = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\tthis.noiseChannelCount = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\tthis.pitchChannelCount = validateRange(Config.pitchChannelCountMin, Config.pitchChannelCountMax, this.pitchChannelCount);\n\t\t\t\tthis.noiseChannelCount = validateRange(Config.noiseChannelCountMin, Config.noiseChannelCountMax, this.noiseChannelCount);\n\t\t\t\tfor (let channelIndex = this.channels.length; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\tthis.channels[channelIndex] = new Channel();\n\t\t\t\t}\n\t\t\t\tthis.channels.length = this.getChannelCount();\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tfor (let i: number = legacySettingsCache!.length; i < this.getChannelCount(); i++) {\n\t\t\t\t\t\tlegacySettingsCache![i] = [];\n\t\t\t\t\t\tfor (let j: number = 0; j < Config.instrumentCountMin; j++) legacySettingsCache![i][j] = {};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.scale: {\n\t\t\t\tthis.scale = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\tif (beforeThree && this.scale == 10) this.scale = 11;\n\t\t\t} break;\n\t\t\tcase SongTagCode.key: {\n\t\t\t\tif (beforeSeven) {\n\t\t\t\t\tthis.key = clamp(0, Config.keys.length, 11 - base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t} else {\n\t\t\t\t\tthis.key = clamp(0, Config.keys.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.loopStart: {\n\t\t\t\tif (beforeFive) {\n\t\t\t\t\tthis.loopStart = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t} else {\n\t\t\t\t\tthis.loopStart = (base64CharCodeToInt[compressed.charCodeAt(charIndex++)] << 6) + base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.loopEnd: {\n\t\t\t\tif (beforeFive) {\n\t\t\t\t\tthis.loopLength = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t} else {\n\t\t\t\t\tthis.loopLength = (base64CharCodeToInt[compressed.charCodeAt(charIndex++)] << 6) + base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + 1;\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.tempo: {\n\t\t\t\tif (beforeFour) {\n\t\t\t\t\tthis.tempo = [95, 120, 151, 190][base64CharCodeToInt[compressed.charCodeAt(charIndex++)]];\n\t\t\t\t} else if (beforeSeven) {\n\t\t\t\t\tthis.tempo = [88, 95, 103, 111, 120, 130, 140, 151, 163, 176, 190, 206, 222, 240, 259][base64CharCodeToInt[compressed.charCodeAt(charIndex++)]];\n\t\t\t\t} else {\n\t\t\t\t\tthis.tempo = (base64CharCodeToInt[compressed.charCodeAt(charIndex++)] << 6) | (base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t}\n\t\t\t\tthis.tempo = clamp(Config.tempoMin, Config.tempoMax + 1, this.tempo);\n\t\t\t} break;\n\t\t\tcase SongTagCode.reverb: {\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tlegacyGlobalReverb = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tlegacyGlobalReverb = clamp(0, 4, legacyGlobalReverb);\n\t\t\t\t} else {\n\t\t\t\t\t// Do nothing? This song tag code is deprecated for now.\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.beatCount: {\n\t\t\t\tif (beforeThree) {\n\t\t\t\t\tthis.beatsPerBar = [6, 7, 8, 9, 10][base64CharCodeToInt[compressed.charCodeAt(charIndex++)]];\n\t\t\t\t} else {\n\t\t\t\t\tthis.beatsPerBar = base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + 1;\n\t\t\t\t}\n\t\t\t\tthis.beatsPerBar = Math.max(Config.beatsPerBarMin, Math.min(Config.beatsPerBarMax, this.beatsPerBar));\n\t\t\t} break;\n\t\t\tcase SongTagCode.barCount: {\n\t\t\t\tconst barCount: number = (base64CharCodeToInt[compressed.charCodeAt(charIndex++)] << 6) + base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + 1;\n\t\t\t\tthis.barCount = validateRange(Config.barCountMin, Config.barCountMax, barCount);\n\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\tfor (let bar = this.channels[channelIndex].bars.length; bar < this.barCount; bar++) {\n\t\t\t\t\t\tthis.channels[channelIndex].bars[bar] = 1;\n\t\t\t\t\t}\n\t\t\t\t\tthis.channels[channelIndex].bars.length = this.barCount;\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.patternCount: {\n\t\t\t\tlet patternsPerChannel: number;\n\t\t\t\tif (beforeEight) {\n\t\t\t\t\tpatternsPerChannel = base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + 1;\n\t\t\t\t} else {\n\t\t\t\t\tpatternsPerChannel = (base64CharCodeToInt[compressed.charCodeAt(charIndex++)] << 6) + base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + 1;\n\t\t\t\t}\n\t\t\t\tthis.patternsPerChannel = validateRange(1, Config.barCountMax, patternsPerChannel);\n\t\t\t\tconst channelCount: number = this.getChannelCount();\n\t\t\t\tfor (let channelIndex: number = 0; channelIndex < channelCount; channelIndex++) {\n\t\t\t\t\tconst patterns: Pattern[] = this.channels[channelIndex].patterns;\n\t\t\t\t\tfor (let pattern = patterns.length; pattern < this.patternsPerChannel; pattern++) {\n\t\t\t\t\t\tpatterns[pattern] = new Pattern();\n\t\t\t\t\t}\n\t\t\t\t\tpatterns.length = this.patternsPerChannel;\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.instrumentCount: {\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tconst instrumentsPerChannel: number = validateRange(Config.instrumentCountMin, Config.patternInstrumentCountMax, base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + Config.instrumentCountMin);\n\t\t\t\t\tthis.layeredInstruments = false;\n\t\t\t\t\tthis.patternInstruments = (instrumentsPerChannel > 1);\n\t\t\t\t\t\n\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\tconst isNoiseChannel: boolean = channelIndex >= this.pitchChannelCount;\n\t\t\t\t\t\tfor (let instrumentIndex: number = this.channels[channelIndex].instruments.length; instrumentIndex < instrumentsPerChannel; instrumentIndex++) {\n\t\t\t\t\t\t\tthis.channels[channelIndex].instruments[instrumentIndex] = new Instrument(isNoiseChannel);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.channels[channelIndex].instruments.length = instrumentsPerChannel;\n\t\t\t\t\t\tif (beforeSix) {\n\t\t\t\t\t\t\tfor (let instrumentIndex: number = 0; instrumentIndex < instrumentsPerChannel; instrumentIndex++) {\n\t\t\t\t\t\t\t\tthis.channels[channelIndex].instruments[instrumentIndex].setTypeAndReset(isNoiseChannel ? InstrumentType.noise : InstrumentType.chip, isNoiseChannel);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (let j: number = legacySettingsCache![channelIndex].length; j < instrumentsPerChannel; j++) {\n\t\t\t\t\t\t\tlegacySettingsCache![channelIndex][j] = {};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst instrumentsFlagBits: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tthis.layeredInstruments = (instrumentsFlagBits & (1 << 1)) != 0;\n\t\t\t\t\tthis.patternInstruments = (instrumentsFlagBits & (1 << 0)) != 0;\n\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\tlet instrumentCount: number = 1;\n\t\t\t\t\t\tif (this.layeredInstruments || this.patternInstruments) {\n\t\t\t\t\t\t\tinstrumentCount = validateRange(Config.instrumentCountMin, this.getMaxInstrumentsPerChannel(), base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + Config.instrumentCountMin);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst channel: Channel = this.channels[channelIndex];\n\t\t\t\t\t\tconst isNoiseChannel: boolean = this.getChannelIsNoise(channelIndex);\n\t\t\t\t\t\tfor (let i: number = channel.instruments.length; i < instrumentCount; i++) {\n\t\t\t\t\t\t\tchannel.instruments[i] = new Instrument(isNoiseChannel);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tchannel.instruments.length = instrumentCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.rhythm: {\n\t\t\t\tthis.rhythm = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t} break;\n\t\t\tcase SongTagCode.channelOctave: {\n\t\t\t\tif (beforeThree) {\n\t\t\t\t\tconst channelIndex: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tthis.channels[channelIndex].octave = clamp(0, Config.pitchOctaves, base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + 1);\n\t\t\t\t\tif (channelIndex >= this.pitchChannelCount) this.channels[channelIndex].octave = 0;\n\t\t\t\t} else if (beforeNine) {\n\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\tthis.channels[channelIndex].octave = clamp(0, Config.pitchOctaves, base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + 1);\n\t\t\t\t\t\tif (channelIndex >= this.pitchChannelCount) this.channels[channelIndex].octave = 0;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.pitchChannelCount; channelIndex++) {\n\t\t\t\t\t\tthis.channels[channelIndex].octave = clamp(0, Config.pitchOctaves, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tfor (let channelIndex: number = this.pitchChannelCount; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\tthis.channels[channelIndex].octave = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.startInstrument: {\n\t\t\t\tinstrumentIndexIterator++;\n\t\t\t\tif (instrumentIndexIterator >= this.channels[instrumentChannelIterator].instruments.length) {\n\t\t\t\t\tinstrumentChannelIterator++;\n\t\t\t\t\tinstrumentIndexIterator = 0;\n\t\t\t\t}\n\t\t\t\tvalidateRange(0, this.channels.length - 1, instrumentChannelIterator);\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tconst instrumentType: number = validateRange(0, InstrumentType.length - 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\tinstrument.setTypeAndReset(instrumentType, instrumentChannelIterator >= this.pitchChannelCount);\n\t\t\t\t\n\t\t\t\tif (beforeSeven) {\n\t\t\t\t\tinstrument.effects = 0;\n\t\t\t\t\t// the reverb effect was applied to all pitched instruments if nonzero but never explicitly enabled if beforeSeven, so enable it here.\n\t\t\t\t\tif (legacyGlobalReverb > 0 && !this.getChannelIsNoise(instrumentChannelIterator)) {\n\t\t\t\t\t\tinstrument.reverb = legacyGlobalReverb;\n\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.reverb;\n\t\t\t\t\t}\n\t\t\t\t\t// Chip/noise instruments had arpeggio and FM had custom interval but neither\n\t\t\t\t\t// explicitly saved the chorus setting beforeSeven so enable it here.\n\t\t\t\t\tif (instrument.chord != Config.chords.dictionary[\"simultaneous\"].index) {\n\t\t\t\t\t\t// Enable chord if it was used.\n\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.chord;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.preset: {\n\t\t\t\tconst presetValue: number = (base64CharCodeToInt[compressed.charCodeAt(charIndex++)] << 6) | (base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].preset = presetValue;\n\t\t\t} break;\n\t\t\tcase SongTagCode.wave: {\n\t\t\t\tif (beforeThree) {\n\t\t\t\t\tconst legacyWaves: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 0];\n\t\t\t\t\tconst channelIndex: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tconst instrument: Instrument = this.channels[channelIndex].instruments[0];\n\t\t\t\t\tinstrument.chipWave = clamp(0, Config.chipWaves.length, legacyWaves[base64CharCodeToInt[compressed.charCodeAt(charIndex++)]] | 0);\n\t\t\t\t\t\n\t\t\t\t\t// Version 2 didn't save any settings for settings for filters, or envelopes,\n\t\t\t\t\t// just waves, so initialize them here I guess.\n\t\t\t\t\tinstrument.convertLegacySettings(legacySettingsCache![channelIndex][0]);\n\t\t\t\t\t\n\t\t\t\t} else if (beforeSix) {\n\t\t\t\t\tconst legacyWaves: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 0];\n\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\tfor (const instrument of this.channels[channelIndex].instruments) {\n\t\t\t\t\t\t\tif (channelIndex >= this.pitchChannelCount) {\n\t\t\t\t\t\t\t\tinstrument.chipNoise = clamp(0, Config.chipNoises.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tinstrument.chipWave = clamp(0, Config.chipWaves.length, legacyWaves[base64CharCodeToInt[compressed.charCodeAt(charIndex++)]] | 0);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (beforeSeven) {\n\t\t\t\t\tconst legacyWaves: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 0];\n\t\t\t\t\tif (instrumentChannelIterator >= this.pitchChannelCount) {\n\t\t\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].chipNoise = clamp(0, Config.chipNoises.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].chipWave = clamp(0, Config.chipWaves.length, legacyWaves[base64CharCodeToInt[compressed.charCodeAt(charIndex++)]] | 0);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (instrumentChannelIterator >= this.pitchChannelCount) {\n\t\t\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].chipNoise = clamp(0, Config.chipNoises.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].chipWave = clamp(0, Config.chipWaves.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.eqFilter: {\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tif (beforeSeven) {\n\t\t\t\t\t\tconst legacyToCutoff: number[] = [10, 6, 3, 0, 8, 5, 2];\n\t\t\t\t\t\tconst legacyToEnvelope: string[] = [\"none\", \"none\", \"none\", \"none\", \"decay 1\", \"decay 2\", \"decay 3\"];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (beforeThree) {\n\t\t\t\t\t\t\tconst channelIndex: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\t\t\tconst instrument: Instrument = this.channels[channelIndex].instruments[0];\n\t\t\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![channelIndex][0];\n\t\t\t\t\t\t\tconst legacyFilter: number = [1, 3, 4, 5][clamp(0, legacyToCutoff.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)])];\n\t\t\t\t\t\t\tlegacySettings.filterCutoff = legacyToCutoff[legacyFilter];\n\t\t\t\t\t\t\tlegacySettings.filterResonance = 0;\n\t\t\t\t\t\t\tlegacySettings.filterEnvelope = Config.envelopes.dictionary[legacyToEnvelope[legacyFilter]];\n\t\t\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t\t\t} else if (beforeSix) {\n\t\t\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\t\t\tfor (let i: number = 0; i < this.channels[channelIndex].instruments.length; i++) {\n\t\t\t\t\t\t\t\t\tconst instrument: Instrument = this.channels[channelIndex].instruments[i];\n\t\t\t\t\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![channelIndex][i];\n\t\t\t\t\t\t\t\t\tconst legacyFilter: number = clamp(0, legacyToCutoff.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)] + 1);\n\t\t\t\t\t\t\t\t\tif (channelIndex < this.pitchChannelCount) {\n\t\t\t\t\t\t\t\t\t\tlegacySettings.filterCutoff = legacyToCutoff[legacyFilter];\n\t\t\t\t\t\t\t\t\t\tlegacySettings.filterResonance = 0;\n\t\t\t\t\t\t\t\t\t\tlegacySettings.filterEnvelope = Config.envelopes.dictionary[legacyToEnvelope[legacyFilter]];\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tlegacySettings.filterCutoff = 10;\n\t\t\t\t\t\t\t\t\t\tlegacySettings.filterResonance = 0;\n\t\t\t\t\t\t\t\t\t\tlegacySettings.filterEnvelope = Config.envelopes.dictionary[\"none\"];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst legacyFilter: number = clamp(0, legacyToCutoff.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\t\t\tlegacySettings.filterCutoff = legacyToCutoff[legacyFilter];\n\t\t\t\t\t\t\tlegacySettings.filterResonance = 0;\n\t\t\t\t\t\t\tlegacySettings.filterEnvelope = Config.envelopes.dictionary[legacyToEnvelope[legacyFilter]];\n\t\t\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst filterCutoffRange: number = 11;\n\t\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\t\tlegacySettings.filterCutoff = clamp(0, filterCutoffRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\tconst originalControlPointCount: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tinstrument.eqFilter.controlPointCount = clamp(0, Config.filterMaxPoints + 1, originalControlPointCount);\n\t\t\t\t\tfor (let i: number = instrument.eqFilter.controlPoints.length; i < instrument.eqFilter.controlPointCount; i++) {\n\t\t\t\t\t\tinstrument.eqFilter.controlPoints[i] = new FilterControlPoint();\n\t\t\t\t\t}\n\t\t\t\t\tfor (let i: number = 0; i < instrument.eqFilter.controlPointCount; i++) {\n\t\t\t\t\t\tconst point: FilterControlPoint = instrument.eqFilter.controlPoints[i];\n\t\t\t\t\t\tpoint.type = clamp(0, FilterType.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\tpoint.freq = clamp(0, Config.filterFreqRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\tpoint.gain = clamp(0, Config.filterGainRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tfor (let i: number = instrument.eqFilter.controlPointCount; i < originalControlPointCount; i++) {\n\t\t\t\t\t\tcharIndex += 3;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.filterResonance: {\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tconst filterResonanceRange: number = 8;\n\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\tlegacySettings.filterResonance = clamp(0, filterResonanceRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t} else {\n\t\t\t\t\t// Do nothing? This song tag code is deprecated for now.\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.drumsetEnvelopes: {\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tif (instrument.type == InstrumentType.drumset) {\n\t\t\t\t\t\tfor (let i: number = 0; i < Config.drumCount; i++) {\n\t\t\t\t\t\t\tinstrument.drumsetEnvelopes[i] = Song._envelopeFromLegacyIndex(base64CharCodeToInt[compressed.charCodeAt(charIndex++)]).index;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// This used to be used for general filter envelopes.\n\t\t\t\t\t\t// The presence of an envelope affects how convertLegacySettings\n\t\t\t\t\t\t// decides the closest possible approximation, so update it.\n\t\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\t\tlegacySettings.filterEnvelope = Song._envelopeFromLegacyIndex(base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// This tag is now only used for drumset filter envelopes.\n\t\t\t\t\tfor (let i: number = 0; i < Config.drumCount; i++) {\n\t\t\t\t\t\tinstrument.drumsetEnvelopes[i] = clamp(0, Config.envelopes.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.pulseWidth: {\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tinstrument.pulseWidth = clamp(0, Config.pulseWidthRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\tlegacySettings.pulseEnvelope = Song._envelopeFromLegacyIndex(base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.supersaw: {\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tinstrument.supersawDynamism = clamp(0, Config.supersawDynamismMax + 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\tinstrument.supersawSpread = clamp(0, Config.supersawSpreadMax + 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\tinstrument.supersawShape = clamp(0, Config.supersawShapeMax + 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t} break;\n\t\t\tcase SongTagCode.stringSustain: {\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tconst sustainValue: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\tinstrument.stringSustain = clamp(0, Config.stringSustainRange, sustainValue & 0x1F);\n\t\t\t\tinstrument.stringSustainType = Config.enableAcousticSustain ? clamp(0, SustainType.length, sustainValue >> 5) : SustainType.bright;\n\t\t\t} break;\n\t\t\tcase SongTagCode.fadeInOut: {\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\t// this tag was used for a combination of transition and fade in/out.\n\t\t\t\t\tconst legacySettings = [\n\t\t\t\t\t\t{transition: \"interrupt\", fadeInSeconds: 0.0, fadeOutTicks: -1},\n\t\t\t\t\t\t{transition: \"normal\", fadeInSeconds: 0.0, fadeOutTicks: -3},\n\t\t\t\t\t\t{transition: \"normal\", fadeInSeconds: 0.025, fadeOutTicks: -3},\n\t\t\t\t\t\t{transition: \"slide in pattern\", fadeInSeconds: 0.025, fadeOutTicks: -3},\n\t\t\t\t\t\t{transition: \"normal\", fadeInSeconds: 0.04, fadeOutTicks: 6},\n\t\t\t\t\t\t{transition: \"normal\", fadeInSeconds: 0.0, fadeOutTicks: 48},\n\t\t\t\t\t\t{transition: \"normal\", fadeInSeconds: 0.0125, fadeOutTicks: 72},\n\t\t\t\t\t\t{transition: \"normal\", fadeInSeconds: 0.06, fadeOutTicks: 96},\n\t\t\t\t\t];\n\t\t\t\t\tif (beforeThree) {\n\t\t\t\t\t\tconst channelIndex: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\t\tconst settings = legacySettings[clamp(0, legacySettings.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)])];\n\t\t\t\t\t\tconst instrument: Instrument = this.channels[channelIndex].instruments[0];\n\t\t\t\t\t\tinstrument.fadeIn = Synth.secondsToFadeInSetting(settings.fadeInSeconds);\n\t\t\t\t\t\tinstrument.fadeOut = Synth.ticksToFadeOutSetting(settings.fadeOutTicks);\n\t\t\t\t\t\tinstrument.transition = Config.transitions.dictionary[settings.transition].index;\n\t\t\t\t\t\tif (instrument.transition != Config.transitions.dictionary[\"normal\"].index) {\n\t\t\t\t\t\t\t// Enable transition if it was used.\n\t\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.transition;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (beforeSix) {\n\t\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\t\tfor (const instrument of this.channels[channelIndex].instruments) {\n\t\t\t\t\t\t\t\tconst settings = legacySettings[clamp(0, legacySettings.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)])];\n\t\t\t\t\t\t\t\tinstrument.fadeIn = Synth.secondsToFadeInSetting(settings.fadeInSeconds);\n\t\t\t\t\t\t\t\tinstrument.fadeOut = Synth.ticksToFadeOutSetting(settings.fadeOutTicks);\n\t\t\t\t\t\t\t\tinstrument.transition = Config.transitions.dictionary[settings.transition].index;\n\t\t\t\t\t\t\t\tif (instrument.transition != Config.transitions.dictionary[\"normal\"].index) {\n\t\t\t\t\t\t\t\t\t// Enable transition if it was used.\n\t\t\t\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.transition;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst settings = legacySettings[clamp(0, legacySettings.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)])];\n\t\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\t\tinstrument.fadeIn = Synth.secondsToFadeInSetting(settings.fadeInSeconds);\n\t\t\t\t\t\tinstrument.fadeOut = Synth.ticksToFadeOutSetting(settings.fadeOutTicks);\n\t\t\t\t\t\tinstrument.transition = Config.transitions.dictionary[settings.transition].index;\n\t\t\t\t\t\tif (instrument.transition != Config.transitions.dictionary[\"normal\"].index) {\n\t\t\t\t\t\t\t// Enable transition if it was used.\n\t\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.transition;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\tinstrument.fadeIn = clamp(0, Config.fadeInRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\tinstrument.fadeOut = clamp(0, Config.fadeOutTicks.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.vibrato: {\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tif (beforeSeven) {\n\t\t\t\t\t\tif (beforeThree) {\n\t\t\t\t\t\t\tconst legacyEffects: number[] = [0, 3, 2, 0];\n\t\t\t\t\t\t\tconst legacyEnvelopes: string[] = [\"none\", \"none\", \"none\", \"tremolo2\"];\n\t\t\t\t\t\t\tconst channelIndex: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\t\t\tconst effect: number = clamp(0, legacyEffects.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t\tconst instrument: Instrument = this.channels[channelIndex].instruments[0];\n\t\t\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![channelIndex][0];\n\t\t\t\t\t\t\tinstrument.vibrato = legacyEffects[effect];\n\t\t\t\t\t\t\tif (legacySettings.filterEnvelope == undefined || legacySettings.filterEnvelope.type == EnvelopeType.none) {\n\t\t\t\t\t\t\t\t// Imitate the legacy tremolo with a filter envelope.\n\t\t\t\t\t\t\t\tlegacySettings.filterEnvelope = Config.envelopes.dictionary[legacyEnvelopes[effect]];\n\t\t\t\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (instrument.vibrato != Config.vibratos.dictionary[\"none\"].index) {\n\t\t\t\t\t\t\t\t// Enable vibrato if it was used.\n\t\t\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.vibrato;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (beforeSix) {\n\t\t\t\t\t\t\tconst legacyEffects: number[] = [0, 1, 2, 3, 0, 0];\n\t\t\t\t\t\t\tconst legacyEnvelopes: string[] = [\"none\", \"none\", \"none\", \"none\", \"tremolo5\", \"tremolo2\"];\n\t\t\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\t\t\tfor (let i: number = 0; i < this.channels[channelIndex].instruments.length; i++) {\n\t\t\t\t\t\t\t\t\tconst effect: number = clamp(0, legacyEffects.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t\t\t\tconst instrument: Instrument = this.channels[channelIndex].instruments[i];\n\t\t\t\t\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![channelIndex][i];\n\t\t\t\t\t\t\t\t\tinstrument.vibrato = legacyEffects[effect];\n\t\t\t\t\t\t\t\t\tif (legacySettings.filterEnvelope == undefined || legacySettings.filterEnvelope.type == EnvelopeType.none) {\n\t\t\t\t\t\t\t\t\t\t// Imitate the legacy tremolo with a filter envelope.\n\t\t\t\t\t\t\t\t\t\tlegacySettings.filterEnvelope = Config.envelopes.dictionary[legacyEnvelopes[effect]];\n\t\t\t\t\t\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (instrument.vibrato != Config.vibratos.dictionary[\"none\"].index) {\n\t\t\t\t\t\t\t\t\t\t// Enable vibrato if it was used.\n\t\t\t\t\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.vibrato;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (legacyGlobalReverb != 0 && !this.getChannelIsNoise(channelIndex)) {\n\t\t\t\t\t\t\t\t\t\t// Enable reverb if it was used globaly before. (Global reverb was added before the effects option so I need to pick somewhere else to initialize instrument reverb, and I picked the vibrato command.)\n\t\t\t\t\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.reverb;\n\t\t\t\t\t\t\t\t\t\tinstrument.reverb = legacyGlobalReverb;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst legacyEffects: number[] = [0, 1, 2, 3, 0, 0];\n\t\t\t\t\t\t\tconst legacyEnvelopes: string[] = [\"none\", \"none\", \"none\", \"none\", \"tremolo5\", \"tremolo2\"];\n\t\t\t\t\t\t\tconst effect: number = clamp(0, legacyEffects.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\t\t\tinstrument.vibrato = legacyEffects[effect];\n\t\t\t\t\t\t\tif (legacySettings.filterEnvelope == undefined || legacySettings.filterEnvelope.type == EnvelopeType.none) {\n\t\t\t\t\t\t\t\t// Imitate the legacy tremolo with a filter envelope.\n\t\t\t\t\t\t\t\tlegacySettings.filterEnvelope = Config.envelopes.dictionary[legacyEnvelopes[effect]];\n\t\t\t\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (instrument.vibrato != Config.vibratos.dictionary[\"none\"].index) {\n\t\t\t\t\t\t\t\t// Enable vibrato if it was used.\n\t\t\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.vibrato;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (legacyGlobalReverb != 0) {\n\t\t\t\t\t\t\t\t// Enable reverb if it was used globaly before. (Global reverb was added before the effects option so I need to pick somewhere else to initialize instrument reverb, and I picked the vibrato command.)\n\t\t\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.reverb;\n\t\t\t\t\t\t\t\tinstrument.reverb = legacyGlobalReverb;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\t\tconst vibrato: number = clamp(0, Config.vibratos.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\tinstrument.vibrato = vibrato;\n\t\t\t\t\t\tif (instrument.vibrato != Config.vibratos.dictionary[\"none\"].index) {\n\t\t\t\t\t\t\t// Enable vibrato if it was used.\n\t\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.vibrato;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Do nothing? This song tag code is deprecated for now.\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.unison: {\n\t\t\t\tif (beforeThree) {\n\t\t\t\t\tconst channelIndex: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tthis.channels[channelIndex].instruments[0].unison = clamp(0, Config.unisons.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t} else if (beforeSix) {\n\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\tfor (const instrument of this.channels[channelIndex].instruments) {\n\t\t\t\t\t\t\tconst originalValue: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\t\t\tlet unison: number = clamp(0, Config.unisons.length, originalValue);\n\t\t\t\t\t\t\tif (originalValue == 8) {\n\t\t\t\t\t\t\t\t// original \"custom harmony\" now maps to \"hum\" and \"custom interval\".\n\t\t\t\t\t\t\t\tunison = 2;\n\t\t\t\t\t\t\t\tinstrument.chord = 3;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tinstrument.unison = unison;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (beforeSeven) {\n\t\t\t\t\tconst originalValue: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tlet unison: number = clamp(0, Config.unisons.length, originalValue);\n\t\t\t\t\tif (originalValue == 8) {\n\t\t\t\t\t\t// original \"custom harmony\" now maps to \"hum\" and \"custom interval\".\n\t\t\t\t\t\tunison = 2;\n\t\t\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].chord = 3;\n\t\t\t\t\t}\n\t\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].unison = unison;\n\t\t\t\t} else {\n\t\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].unison = clamp(0, Config.unisons.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.chord: {\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\tinstrument.chord = clamp(0, Config.chords.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\tif (instrument.chord != Config.chords.dictionary[\"simultaneous\"].index) {\n\t\t\t\t\t\t// Enable chord if it was used.\n\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.chord;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Do nothing? This song tag code is deprecated for now.\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.effects: {\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tinstrument.effects = (base64CharCodeToInt[compressed.charCodeAt(charIndex++)] & ((1 << EffectType.length) - 1));\n\t\t\t\t\tif (legacyGlobalReverb == 0) {\n\t\t\t\t\t\t// Disable reverb if legacy song reverb was zero.\n\t\t\t\t\t\tinstrument.effects &= ~(1 << EffectType.reverb);\n\t\t\t\t\t} else if (effectsIncludeReverb(instrument.effects)) {\n\t\t\t\t\t\tinstrument.reverb = legacyGlobalReverb;\n\t\t\t\t\t}\n\t\t\t\t\tif (instrument.pan != Config.panCenter) {\n\t\t\t\t\t\t// Enable panning if panning slider isn't centered.\n\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.panning;\n\t\t\t\t\t}\n\t\t\t\t\tif (instrument.vibrato != Config.vibratos.dictionary[\"none\"].index) {\n\t\t\t\t\t\t// Enable vibrato if it was used.\n\t\t\t\t\t\tinstrument.effects |= 1 << EffectType.panning;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// convertLegacySettings may need to force-enable note filter, call\n\t\t\t\t\t// it again here to make sure that this override takes precedence.\n\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t} else {\n\t\t\t\t\t// BeepBox currently uses two base64 characters at 6 bits each for a bitfield representing all the enabled effects.\n\t\t\t\t\tif (EffectType.length > 12) throw new Error();\n\t\t\t\t\tinstrument.effects = (base64CharCodeToInt[compressed.charCodeAt(charIndex++)] << 6) | (base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\n\t\t\t\t\tif (effectsIncludeNoteFilter(instrument.effects)) {\n\t\t\t\t\t\tconst originalControlPointCount: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\t\tinstrument.noteFilter.controlPointCount = clamp(0, Config.filterMaxPoints + 1, originalControlPointCount);\n\t\t\t\t\t\tfor (let i: number = instrument.noteFilter.controlPoints.length; i < instrument.noteFilter.controlPointCount; i++) {\n\t\t\t\t\t\t\tinstrument.noteFilter.controlPoints[i] = new FilterControlPoint();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (let i: number = 0; i < instrument.noteFilter.controlPointCount; i++) {\n\t\t\t\t\t\t\tconst point: FilterControlPoint = instrument.noteFilter.controlPoints[i];\n\t\t\t\t\t\t\tpoint.type = clamp(0, FilterType.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t\tpoint.freq = clamp(0, Config.filterFreqRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t\tpoint.gain = clamp(0, Config.filterGainRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (let i: number = instrument.noteFilter.controlPointCount; i < originalControlPointCount; i++) {\n\t\t\t\t\t\t\tcharIndex += 3;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludeTransition(instrument.effects)) {\n\t\t\t\t\t\tinstrument.transition = clamp(0, Config.transitions.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludeChord(instrument.effects)) {\n\t\t\t\t\t\tinstrument.chord = clamp(0, Config.chords.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludePitchShift(instrument.effects)) {\n\t\t\t\t\t\tinstrument.pitchShift = clamp(0, Config.pitchShiftRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludeDetune(instrument.effects)) {\n\t\t\t\t\t\tinstrument.detune = clamp(0, Config.detuneMax + 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludeVibrato(instrument.effects)) {\n\t\t\t\t\t\tinstrument.vibrato = clamp(0, Config.vibratos.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludeDistortion(instrument.effects)) {\n\t\t\t\t\t\tinstrument.distortion = clamp(0, Config.distortionRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludeBitcrusher(instrument.effects)) {\n\t\t\t\t\t\tinstrument.bitcrusherFreq = clamp(0, Config.bitcrusherFreqRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\tinstrument.bitcrusherQuantization = clamp(0, Config.bitcrusherQuantizationRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludePanning(instrument.effects)) {\n\t\t\t\t\t\tinstrument.pan = clamp(0, Config.panMax + 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludeChorus(instrument.effects)) {\n\t\t\t\t\t\tinstrument.chorus = clamp(0, Config.chorusRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludeEcho(instrument.effects)) {\n\t\t\t\t\t\tinstrument.echoSustain = clamp(0, Config.echoSustainRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\tinstrument.echoDelay = clamp(0, Config.echoDelayRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tif (effectsIncludeReverb(instrument.effects)) {\n\t\t\t\t\t\tinstrument.reverb = clamp(0, Config.reverbRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Clamp the range.\n\t\t\t\tinstrument.effects &= (1 << EffectType.length) - 1;\n\t\t\t} break;\n\t\t\tcase SongTagCode.volume: {\n\t\t\t\tif (beforeThree) {\n\t\t\t\t\tconst channelIndex: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tconst instrument: Instrument = this.channels[channelIndex].instruments[0];\n\t\t\t\t\tinstrument.volume = clamp(0, Config.volumeRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t// legacy mute value:\n\t\t\t\t\tif (instrument.volume == 5) instrument.volume = Config.volumeRange - 1;\n\t\t\t\t} else if (beforeSix) {\n\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\tfor (const instrument of this.channels[channelIndex].instruments) {\n\t\t\t\t\t\t\tinstrument.volume = clamp(0, Config.volumeRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t\t// legacy mute value:\n\t\t\t\t\t\t\tif (instrument.volume == 5) instrument.volume = Config.volumeRange - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (beforeSeven) {\n\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\tinstrument.volume = clamp(0, Config.volumeRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t// legacy mute value:\n\t\t\t\t\tif (instrument.volume == 5) instrument.volume = Config.volumeRange - 1;\n\t\t\t\t} else {\n\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\tinstrument.volume = clamp(0, Config.volumeRange, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.pan: {\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\tinstrument.pan = clamp(0, Config.panMax + 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t} else {\n\t\t\t\t\t// Do nothing? This song tag code is deprecated for now.\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.algorithm: {\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tinstrument.algorithm = clamp(0, Config.algorithms.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\t// The algorithm determines the carrier count, which affects how legacy settings are imported.\n\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.feedbackType: {\n\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].feedbackType = clamp(0, Config.feedbacks.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t} break;\n\t\t\tcase SongTagCode.feedbackAmplitude: {\n\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].feedbackAmplitude = clamp(0, Config.operatorAmplitudeMax + 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t} break;\n\t\t\tcase SongTagCode.feedbackEnvelope: {\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\tlegacySettings.feedbackEnvelope = Song._envelopeFromLegacyIndex(base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t} else {\n\t\t\t\t\t// Do nothing? This song tag code is deprecated for now.\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.operatorFrequencies: {\n\t\t\t\tfor (let o: number = 0; o < Config.operatorCount; o++) {\n\t\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].operators[o].frequency = clamp(0, Config.operatorFrequencies.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.operatorAmplitudes: {\n\t\t\t\tfor (let o: number = 0; o < Config.operatorCount; o++) {\n\t\t\t\t\tthis.channels[instrumentChannelIterator].instruments[instrumentIndexIterator].operators[o].amplitude = clamp(0, Config.operatorAmplitudeMax + 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.envelopes: {\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tif (beforeNine) {\n\t\t\t\t\tconst legacySettings: LegacySettings = legacySettingsCache![instrumentChannelIterator][instrumentIndexIterator];\n\t\t\t\t\tlegacySettings.operatorEnvelopes = [];\n\t\t\t\t\tfor (let o: number = 0; o < Config.operatorCount; o++) {\n\t\t\t\t\t\tlegacySettings.operatorEnvelopes[o] = Song._envelopeFromLegacyIndex(base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t}\n\t\t\t\t\tinstrument.convertLegacySettings(legacySettings);\n\t\t\t\t} else {\n\t\t\t\t\tconst envelopeCount: number = clamp(0, Config.maxEnvelopeCount + 1, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\tfor (let i: number = 0; i < envelopeCount; i++) {\n\t\t\t\t\t\tconst target: number = clamp(0, Config.instrumentAutomationTargets.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\tlet index: number = 0;\n\t\t\t\t\t\tconst maxCount: number = Config.instrumentAutomationTargets[target].maxCount;\n\t\t\t\t\t\tif (maxCount > 1) {\n\t\t\t\t\t\t\tindex = clamp(0, maxCount, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst envelope: number = clamp(0, Config.envelopes.length, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\t\tinstrument.addEnvelope(target, index, envelope);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.spectrum: {\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tif (instrument.type == InstrumentType.spectrum) {\n\t\t\t\t\tconst byteCount: number = Math.ceil(Config.spectrumControlPoints * Config.spectrumControlPointBits / 6)\n\t\t\t\t\tconst bits: BitFieldReader = new BitFieldReader(compressed, charIndex, charIndex + byteCount);\n\t\t\t\t\tfor (let i: number = 0; i < Config.spectrumControlPoints; i++) {\n\t\t\t\t\t\tinstrument.spectrumWave.spectrum[i] = bits.read(Config.spectrumControlPointBits);\n\t\t\t\t\t}\n\t\t\t\t\tinstrument.spectrumWave.markCustomWaveDirty();\n\t\t\t\t\tcharIndex += byteCount;\n\t\t\t\t} else if (instrument.type == InstrumentType.drumset) {\n\t\t\t\t\tconst byteCount: number = Math.ceil(Config.drumCount * Config.spectrumControlPoints * Config.spectrumControlPointBits / 6)\n\t\t\t\t\tconst bits: BitFieldReader = new BitFieldReader(compressed, charIndex, charIndex + byteCount);\n\t\t\t\t\tfor (let j: number = 0; j < Config.drumCount; j++) {\n\t\t\t\t\t\tfor (let i: number = 0; i < Config.spectrumControlPoints; i++) {\n\t\t\t\t\t\t\tinstrument.drumsetSpectrumWaves[j].spectrum[i] = bits.read(Config.spectrumControlPointBits);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinstrument.drumsetSpectrumWaves[j].markCustomWaveDirty();\n\t\t\t\t\t}\n\t\t\t\t\tcharIndex += byteCount;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\"Unhandled instrument type for spectrum song tag code.\");\n\t\t\t\t}\n\t\t\t} break;\n\t\t\tcase SongTagCode.harmonics: {\n\t\t\t\tconst instrument: Instrument = this.channels[instrumentChannelIterator].instruments[instrumentIndexIterator];\n\t\t\t\tconst byteCount: number = Math.ceil(Config.harmonicsControlPoints * Config.harmonicsControlPointBits / 6)\n\t\t\t\tconst bits: BitFieldReader = new BitFieldReader(compressed, charIndex, charIndex + byteCount);\n\t\t\t\tfor (let i: number = 0; i < Config.harmonicsControlPoints; i++) {\n\t\t\t\t\tinstrument.harmonicsWave.harmonics[i] = bits.read(Config.harmonicsControlPointBits);\n\t\t\t\t}\n\t\t\t\tinstrument.harmonicsWave.markCustomWaveDirty();\n\t\t\t\tcharIndex += byteCount;\n\t\t\t} break;\n\t\t\tcase SongTagCode.bars: {\n\t\t\t\tlet subStringLength: number;\n\t\t\t\tif (beforeThree) {\n\t\t\t\t\tconst channelIndex: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tconst barCount: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tsubStringLength = Math.ceil(barCount * 0.5);\n\t\t\t\t\tconst bits: BitFieldReader = new BitFieldReader(compressed, charIndex, charIndex + subStringLength);\n\t\t\t\t\tfor (let i: number = 0; i < barCount; i++) {\n\t\t\t\t\t\tthis.channels[channelIndex].bars[i] = bits.read(3) + 1;\n\t\t\t\t\t}\n\t\t\t\t} else if (beforeFive) {\n\t\t\t\t\tlet neededBits: number = 0;\n\t\t\t\t\twhile ((1 << neededBits) < this.patternsPerChannel) neededBits++;\n\t\t\t\t\tsubStringLength = Math.ceil(this.getChannelCount() * this.barCount * neededBits / 6);\n\t\t\t\t\tconst bits: BitFieldReader = new BitFieldReader(compressed, charIndex, charIndex + subStringLength);\n\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\tfor (let i: number = 0; i < this.barCount; i++) {\n\t\t\t\t\t\t\tthis.channels[channelIndex].bars[i] = bits.read(neededBits) + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlet neededBits: number = 0;\n\t\t\t\t\twhile ((1 << neededBits) < this.patternsPerChannel + 1) neededBits++;\n\t\t\t\t\tsubStringLength = Math.ceil(this.getChannelCount() * this.barCount * neededBits / 6);\n\t\t\t\t\tconst bits: BitFieldReader = new BitFieldReader(compressed, charIndex, charIndex + subStringLength);\n\t\t\t\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\t\t\t\tfor (let i: number = 0; i < this.barCount; i++) {\n\t\t\t\t\t\t\tthis.channels[channelIndex].bars[i] = bits.read(neededBits);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcharIndex += subStringLength;\n\t\t\t} break;\n\t\t\tcase SongTagCode.patterns: {\n\t\t\t\tlet bitStringLength: number = 0;\n\t\t\t\tlet channelIndex: number;\n\t\t\t\tif (beforeThree) {\n\t\t\t\t\tchannelIndex = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\t\n\t\t\t\t\t// The old format used the next character to represent the number of patterns in the channel, which is usually eight, the default. \n\t\t\t\t\tcharIndex++; //let patternCount: number = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\t\n\t\t\t\t\tbitStringLength = base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\tbitStringLength = bitStringLength << 6;\n\t\t\t\t\tbitStringLength += base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t} else {\n\t\t\t\t\tchannelIndex = 0;\n\t\t\t\t\tlet bitStringLengthLength: number = validateRange(1, 4, base64CharCodeToInt[compressed.charCodeAt(charIndex++)]);\n\t\t\t\t\twhile (bitStringLengthLength > 0) {\n\t\t\t\t\t\tbitStringLength = bitStringLength << 6;\n\t\t\t\t\t\tbitStringLength += base64CharCodeToInt[compressed.charCodeAt(charIndex++)];\n\t\t\t\t\t\tbitStringLengthLength--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tconst bits: BitFieldReader = new BitFieldReader(compressed, charIndex, charIndex + bitStringLength);\n\t\t\t\tcharIndex += bitStringLength;\n\t\t\t\t\n\t\t\t\tconst bitsPerNoteSize: number = Song.getNeededBits(Config.noteSizeMax);\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst channel: Channel = this.channels[channelIndex];\n\t\t\t\t\tconst isNoiseChannel: boolean = this.getChannelIsNoise(channelIndex);\n\t\t\t\t\tconst maxInstrumentsPerPattern: number = this.getMaxInstrumentsPerPattern(channelIndex);\n\t\t\t\t\tconst neededInstrumentCountBits: number = Song.getNeededBits(maxInstrumentsPerPattern - Config.instrumentCountMin);\n\t\t\t\t\tconst neededInstrumentIndexBits: number = Song.getNeededBits(channel.instruments.length - 1);\n\t\t\t\t\t\n\t\t\t\t\tconst octaveOffset: number = isNoiseChannel ? 0 : channel.octave * 12;\n\t\t\t\t\tlet lastPitch: number = (isNoiseChannel ? 4 : octaveOffset);\n\t\t\t\t\tconst recentPitches: number[] = isNoiseChannel ? [4,6,7,2,3,8,0,10] : [0, 7, 12, 19, 24, -5, -12];\n\t\t\t\t\tconst recentShapes: any[] = [];\n\t\t\t\t\tfor (let i: number = 0; i < recentPitches.length; i++) {\n\t\t\t\t\t\trecentPitches[i] += octaveOffset;\n\t\t\t\t\t}\n\t\t\t\t\tfor (let i: number = 0; i < this.patternsPerChannel; i++) {\n\t\t\t\t\t\tconst newPattern: Pattern = channel.patterns[i];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (beforeNine) {\n\t\t\t\t\t\t\tnewPattern.instruments[0] = validateRange(0, channel.instruments.length - 1, bits.read(neededInstrumentIndexBits));\n\t\t\t\t\t\t\tnewPattern.instruments.length = 1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (this.patternInstruments) {\n\t\t\t\t\t\t\t\tconst instrumentCount: number = validateRange(Config.instrumentCountMin, maxInstrumentsPerPattern, bits.read(neededInstrumentCountBits) + Config.instrumentCountMin);\n\t\t\t\t\t\t\t\tfor (let j: number = 0; j < instrumentCount; j++) {\n\t\t\t\t\t\t\t\t\tnewPattern.instruments[j] = validateRange(0, channel.instruments.length - 1, bits.read(neededInstrumentIndexBits));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tnewPattern.instruments.length = instrumentCount;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnewPattern.instruments[0] = 0;\n\t\t\t\t\t\t\t\tnewPattern.instruments.length = Config.instrumentCountMin;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!beforeThree && bits.read(1) == 0) {\n\t\t\t\t\t\t\tnewPattern.notes.length = 0;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tlet curPart: number = 0;\n\t\t\t\t\t\tconst newNotes: Note[] = newPattern.notes;\n\t\t\t\t\t\tlet noteCount: number = 0;\n\t\t\t\t\t\twhile (curPart < this.beatsPerBar * Config.partsPerBeat) {\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tconst useOldShape: boolean = bits.read(1) == 1;\n\t\t\t\t\t\t\tlet newNote: boolean = false;\n\t\t\t\t\t\t\tlet shapeIndex: number = 0;\n\t\t\t\t\t\t\tif (useOldShape) {\n\t\t\t\t\t\t\t\tshapeIndex = validateRange(0, recentShapes.length - 1, bits.readLongTail(0, 0));\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnewNote = bits.read(1) == 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (!useOldShape && !newNote) {\n\t\t\t\t\t\t\t\tconst restLength: number = beforeSeven\n\t\t\t\t\t\t\t\t\t? bits.readLegacyPartDuration() * Config.partsPerBeat / Config.rhythms[this.rhythm].stepsPerBeat\n\t\t\t\t\t\t\t\t\t: bits.readPartDuration();\n\t\t\t\t\t\t\t\tcurPart += restLength;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tlet shape: any;\n\t\t\t\t\t\t\t\tif (useOldShape) {\n\t\t\t\t\t\t\t\t\tshape = recentShapes[shapeIndex];\n\t\t\t\t\t\t\t\t\trecentShapes.splice(shapeIndex, 1);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tshape = {};\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tshape.pitchCount = 1;\n\t\t\t\t\t\t\t\t\twhile (shape.pitchCount < Config.maxChordSize && bits.read(1) == 1) shape.pitchCount++;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tshape.pinCount = bits.readPinCount();\n\t\t\t\t\t\t\t\t\tshape.initialSize = bits.read(bitsPerNoteSize);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tshape.pins = [];\n\t\t\t\t\t\t\t\t\tshape.length = 0;\n\t\t\t\t\t\t\t\t\tshape.bendCount = 0;\n\t\t\t\t\t\t\t\t\tfor (let j: number = 0; j < shape.pinCount; j++) {\n\t\t\t\t\t\t\t\t\t\tlet pinObj: any = {};\n\t\t\t\t\t\t\t\t\t\tpinObj.pitchBend = bits.read(1) == 1;\n\t\t\t\t\t\t\t\t\t\tif (pinObj.pitchBend) shape.bendCount++;\n\t\t\t\t\t\t\t\t\t\tshape.length += beforeSeven\n\t\t\t\t\t\t\t\t\t\t\t? bits.readLegacyPartDuration() * Config.partsPerBeat / Config.rhythms[this.rhythm].stepsPerBeat\n\t\t\t\t\t\t\t\t\t\t\t: bits.readPartDuration();\n\t\t\t\t\t\t\t\t\t\tpinObj.time = shape.length;\n\t\t\t\t\t\t\t\t\t\tpinObj.size = bits.read(bitsPerNoteSize);\n\t\t\t\t\t\t\t\t\t\tshape.pins.push(pinObj);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\trecentShapes.unshift(shape);\n\t\t\t\t\t\t\t\tif (recentShapes.length > 10) recentShapes.pop(); // TODO: Use Deque?\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tlet note: Note;\n\t\t\t\t\t\t\t\tif (newNotes.length <= noteCount) {\n\t\t\t\t\t\t\t\t\tnote = new Note(0, curPart, curPart + shape.length, shape.initialSize);\n\t\t\t\t\t\t\t\t\tnewNotes[noteCount++] = note;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnote = newNotes[noteCount++];\n\t\t\t\t\t\t\t\t\tnote.start = curPart;\n\t\t\t\t\t\t\t\t\tnote.end = curPart + shape.length;\n\t\t\t\t\t\t\t\t\tnote.pins[0].size = shape.initialSize;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tlet pitch: number;\n\t\t\t\t\t\t\t\tlet pitchCount: number = 0;\n\t\t\t\t\t\t\t\tconst pitchBends: number[] = []; // TODO: allocate this array only once! keep separate length and iterator index. Use Deque?\n\t\t\t\t\t\t\t\tfor (let j: number = 0; j < shape.pitchCount + shape.bendCount; j++) {\n\t\t\t\t\t\t\t\t\tconst useOldPitch: boolean = bits.read(1) == 1;\n\t\t\t\t\t\t\t\t\tif (!useOldPitch) {\n\t\t\t\t\t\t\t\t\t\tconst interval: number = bits.readPitchInterval();\n\t\t\t\t\t\t\t\t\t\tpitch = lastPitch;\n\t\t\t\t\t\t\t\t\t\tlet intervalIter: number = interval;\n\t\t\t\t\t\t\t\t\t\twhile (intervalIter > 0) {\n\t\t\t\t\t\t\t\t\t\t\tpitch++;\n\t\t\t\t\t\t\t\t\t\t\twhile (recentPitches.indexOf(pitch) != -1) pitch++;\n\t\t\t\t\t\t\t\t\t\t\tintervalIter--;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\twhile (intervalIter < 0) {\n\t\t\t\t\t\t\t\t\t\t\tpitch--;\n\t\t\t\t\t\t\t\t\t\t\twhile (recentPitches.indexOf(pitch) != -1) pitch--;\n\t\t\t\t\t\t\t\t\t\t\tintervalIter++;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tconst pitchIndex: number = validateRange(0, recentPitches.length - 1, bits.read(3));\n\t\t\t\t\t\t\t\t\t\tpitch = recentPitches[pitchIndex];\n\t\t\t\t\t\t\t\t\t\trecentPitches.splice(pitchIndex, 1);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\trecentPitches.unshift(pitch);\n\t\t\t\t\t\t\t\t\tif (recentPitches.length > 8) recentPitches.pop();\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (j < shape.pitchCount) {\n\t\t\t\t\t\t\t\t\t\tnote.pitches[pitchCount++] = pitch;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tpitchBends.push(pitch);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (j == shape.pitchCount - 1) {\n\t\t\t\t\t\t\t\t\t\tlastPitch = note.pitches[0];\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tlastPitch = pitch;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tnote.pitches.length = pitchCount;\n\t\t\t\t\t\t\t\tpitchBends.unshift(note.pitches[0]); // TODO: Use Deque?\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tlet pinCount: number = 1;\n\t\t\t\t\t\t\t\tfor (const pinObj of shape.pins) {\n\t\t\t\t\t\t\t\t\tif (pinObj.pitchBend) pitchBends.shift();\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tconst interval: number = pitchBends[0] - note.pitches[0];\n\t\t\t\t\t\t\t\t\tif (note.pins.length <= pinCount) {\n\t\t\t\t\t\t\t\t\t\tnote.pins[pinCount++] = makeNotePin(interval, pinObj.time, pinObj.size);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tconst pin: NotePin = note.pins[pinCount++];\n\t\t\t\t\t\t\t\t\t\tpin.interval = interval;\n\t\t\t\t\t\t\t\t\t\tpin.time = pinObj.time;\n\t\t\t\t\t\t\t\t\t\tpin.size = pinObj.size;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tnote.pins.length = pinCount;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (note.start == 0 && !beforeNine) {\n\t\t\t\t\t\t\t\t\tnote.continuesLastPattern = (bits.read(1) == 1);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnote.continuesLastPattern = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcurPart = validateRange(0, this.beatsPerBar * Config.partsPerBeat, note.end);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnewNotes.length = noteCount;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (beforeThree) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchannelIndex++;\n\t\t\t\t\t\tif (channelIndex >= this.getChannelCount()) break;\n\t\t\t\t\t}\n\t\t\t\t} // while (true)\n\t\t\t} break;\n\t\t\tdefault: {\n\t\t\t\tthrow new Error(\"Unrecognized song tag code \" + String.fromCharCode(command) + \" at index \" + (charIndex - 1));\n\t\t\t} break;\n\t\t}\n\t}\n\t\n\tpublic toJsonObject(enableIntro: boolean = true, loopCount: number = 1, enableOutro: boolean = true): Object {\n\t\tconst channelArray: Object[] = [];\n\t\tfor (let channelIndex: number = 0; channelIndex < this.getChannelCount(); channelIndex++) {\n\t\t\tconst channel: Channel = this.channels[channelIndex];\n\t\t\tconst instrumentArray: Object[] = [];\n\t\t\tconst isNoiseChannel: boolean = this.getChannelIsNoise(channelIndex);\n\t\t\tfor (const instrument of channel.instruments) {\n\t\t\t\tinstrumentArray.push(instrument.toJsonObject());\n\t\t\t}\n\t\t\t\n\t\t\tconst patternArray: Object[] = [];\n\t\t\tfor (const pattern of channel.patterns) {\n\t\t\t\tpatternArray.push(pattern.toJsonObject(this));\n\t\t\t}\n\t\t\t\n\t\t\tconst sequenceArray: number[] = [];\n\t\t\tif (enableIntro) for (let i: number = 0; i < this.loopStart; i++) {\n\t\t\t\tsequenceArray.push(channel.bars[i]);\n\t\t\t}\n\t\t\tfor (let l: number = 0; l < loopCount; l++) for (let i: number = this.loopStart; i < this.loopStart + this.loopLength; i++) {\n\t\t\t\tsequenceArray.push(channel.bars[i]);\n\t\t\t}\n\t\t\tif (enableOutro) for (let i: number = this.loopStart + this.loopLength; i < this.barCount; i++) {\n\t\t\t\tsequenceArray.push(channel.bars[i]);\n\t\t\t}\n\t\t\t\n\t\t\tconst channelObject: any = {\n\t\t\t\t\"type\": isNoiseChannel ? \"drum\" : \"pitch\",\n\t\t\t\t\"instruments\": instrumentArray,\n\t\t\t\t\"patterns\": patternArray,\n\t\t\t\t\"sequence\": sequenceArray,\n\t\t\t};\n\t\t\tif (!isNoiseChannel) {\n\t\t\t\t// For compatibility with old versions the octave is offset by one.\n\t\t\t\tchannelObject[\"octaveScrollBar\"] = channel.octave - 1;\n\t\t\t}\n\t\t\tchannelArray.push(channelObject);\n\t\t}\n\t\t\n\t\treturn {\n\t\t\t\"format\": Song._format,\n\t\t\t\"version\": Song._latestVersion,\n\t\t\t\"scale\": Config.scales[this.scale].name,\n\t\t\t\"key\": Config.keys[this.key].name,\n\t\t\t\"introBars\": this.loopStart,\n\t\t\t\"loopBars\": this.loopLength,\n\t\t\t\"beatsPerBar\": this.beatsPerBar,\n\t\t\t\"ticksPerBeat\": Config.rhythms[this.rhythm].stepsPerBeat,\n\t\t\t\"beatsPerMinute\": this.tempo,\n\t\t\t//\"patternCount\": this.patternsPerChannel, // derive this from pattern arrays.\n\t\t\t\"layeredInstruments\": this.layeredInstruments,\n\t\t\t\"patternInstruments\": this.patternInstruments,\n\t\t\t\"channels\": channelArray,\n\t\t};\n\t}\n\t\n\tpublic fromJsonObject(jsonObject: any): void {\n\t\tthis.initToDefault(true);\n\t\tif (!jsonObject) return;\n\t\t\n\t\t//const version: number = jsonObject[\"version\"] | 0;\n\t\t//if (version > Song._latestVersion) return; // Go ahead and try to parse something from the future I guess? JSON is pretty easy-going!\n\t\t\n\t\tthis.scale = 11; // default to expert.\n\t\tif (jsonObject[\"scale\"] != undefined) {\n\t\t\tconst oldScaleNames: Dictionary<string> = {\n\t\t\t\t\"romani :)\": \"double harmonic :)\",\n\t\t\t\t\"romani :(\": \"double harmonic :(\",\n\t\t\t\t\"dbl harmonic :)\": \"double harmonic :)\",\n\t\t\t\t\"dbl harmonic :(\": \"double harmonic :(\",\n\t\t\t\t\"enigma\": \"strange\",\n\t\t\t};\n\t\t\tconst scaleName: string = (oldScaleNames[jsonObject[\"scale\"]] != undefined) ? oldScaleNames[jsonObject[\"scale\"]] : jsonObject[\"scale\"];\n\t\t\tconst scale: number = Config.scales.findIndex(scale => scale.name == scaleName);\n\t\t\tif (scale != -1) this.scale = scale;\n\t\t}\n\t\t\n\t\tif (jsonObject[\"key\"] != undefined) {\n\t\t\tif (typeof(jsonObject[\"key\"]) == \"number\") {\n\t\t\t\tthis.key = ((jsonObject[\"key\"] + 1200) >>> 0) % Config.keys.length;\n\t\t\t} else if (typeof(jsonObject[\"key\"]) == \"string\") {\n\t\t\t\tconst key: string = jsonObject[\"key\"];\n\t\t\t\tconst letter: string = key.charAt(0).toUpperCase();\n\t\t\t\tconst symbol: string = key.charAt(1).toLowerCase();\n\t\t\t\tconst letterMap: Readonly<Dictionary<number>> = {\"C\": 0, \"D\": 2, \"E\": 4, \"F\": 5, \"G\": 7, \"A\": 9, \"B\": 11};\n\t\t\t\tconst accidentalMap: Readonly<Dictionary<number>> = {\"#\": 1, \"♯\": 1, \"b\": -1, \"♭\": -1};\n\t\t\t\tlet index: number | undefined = letterMap[letter];\n\t\t\t\tconst offset: number | undefined = accidentalMap[symbol];\n\t\t\t\tif (index != undefined) {\n\t\t\t\t\tif (offset != undefined) index += offset;\n\t\t\t\t\tif (index < 0) index += 12;\n\t\t\t\t\tindex = index % 12;\n\t\t\t\t\tthis.key = index;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (jsonObject[\"beatsPerMinute\"] != undefined) {\n\t\t\tthis.tempo = clamp(Config.tempoMin, Config.tempoMax + 1, jsonObject[\"beatsPerMinute\"] | 0);\n\t\t}\n\t\t\n\t\tlet legacyGlobalReverb: number = 0; // In older songs, reverb was song-global, record that here and pass it to Instrument.fromJsonObject() for context.\n\t\tif (jsonObject[\"reverb\"] != undefined) {\n\t\t\tlegacyGlobalReverb = clamp(0, 4, jsonObject[\"reverb\"] | 0);\n\t\t}\n\t\t\n\t\tif (jsonObject[\"beatsPerBar\"] != undefined) {\n\t\t\tthis.beatsPerBar = Math.max(Config.beatsPerBarMin, Math.min(Config.beatsPerBarMax, jsonObject[\"beatsPerBar\"] | 0));\n\t\t}\n\t\t\n\t\tlet importedPartsPerBeat: number = 4;\n\t\tif (jsonObject[\"ticksPerBeat\"] != undefined) {\n\t\t\timportedPartsPerBeat = (jsonObject[\"ticksPerBeat\"] | 0) || 4;\n\t\t\tthis.rhythm = Config.rhythms.findIndex(rhythm=>rhythm.stepsPerBeat==importedPartsPerBeat);\n\t\t\tif (this.rhythm == -1) {\n\t\t\t\tthis.rhythm = 1;\n\t\t\t}\n\t\t}\n\t\t\n\t\tlet maxInstruments: number = 1;\n\t\tlet maxPatterns: number = 1;\n\t\tlet maxBars: number = 1;\n\t\tif (jsonObject[\"channels\"] != undefined) {\n\t\t\tfor (const channelObject of jsonObject[\"channels\"]) {\n\t\t\t\tif (channelObject[\"instruments\"]) maxInstruments = Math.max(maxInstruments, channelObject[\"instruments\"].length | 0);\n\t\t\t\tif (channelObject[\"patterns\"]) maxPatterns = Math.max(maxPatterns, channelObject[\"patterns\"].length | 0);\n\t\t\t\tif (channelObject[\"sequence\"]) maxBars = Math.max(maxBars, channelObject[\"sequence\"].length | 0);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (jsonObject[\"layeredInstruments\"] != undefined) {\n\t\t\tthis.layeredInstruments = !!jsonObject[\"layeredInstruments\"];\n\t\t} else {\n\t\t\tthis.layeredInstruments = false;\n\t\t}\n\t\tif (jsonObject[\"patternInstruments\"] != undefined) {\n\t\t\tthis.patternInstruments = !!jsonObject[\"patternInstruments\"];\n\t\t} else {\n\t\t\tthis.patternInstruments = (maxInstruments > 1);\n\t\t}\n\t\tthis.patternsPerChannel = Math.min(maxPatterns, Config.barCountMax);\n\t\tthis.barCount = Math.min(maxBars, Config.barCountMax);\n\t\t\n\t\tif (jsonObject[\"introBars\"] != undefined) {\n\t\t\tthis.loopStart = clamp(0, this.barCount, jsonObject[\"introBars\"] | 0);\n\t\t}\n\t\tif (jsonObject[\"loopBars\"] != undefined) {\n\t\t\tthis.loopLength = clamp(1, this.barCount - this.loopStart + 1, jsonObject[\"loopBars\"] | 0);\n\t\t}\n\t\t\n\t\tconst newPitchChannels: Channel[] = [];\n\t\tconst newNoiseChannels: Channel[] = [];\n\t\tif (jsonObject[\"channels\"] != undefined) {\n\t\t\tfor (let channelIndex: number = 0; channelIndex < jsonObject[\"channels\"].length; channelIndex++) {\n\t\t\t\tlet channelObject: any = jsonObject[\"channels\"][channelIndex];\n\t\t\t\t\n\t\t\t\tconst channel: Channel = new Channel();\n\t\t\t\t\n\t\t\t\tlet isNoiseChannel: boolean = false;\n\t\t\t\tif (channelObject[\"type\"] != undefined) {\n\t\t\t\t\tisNoiseChannel = (channelObject[\"type\"] == \"drum\");\n\t\t\t\t} else {\n\t\t\t\t\t// for older files, assume drums are channel 3.\n\t\t\t\t\tisNoiseChannel = (channelIndex >= 3);\n\t\t\t\t}\n\t\t\t\tif (isNoiseChannel) {\n\t\t\t\t\tnewNoiseChannels.push(channel);\n\t\t\t\t} else {\n\t\t\t\t\tnewPitchChannels.push(channel);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (channelObject[\"octaveScrollBar\"] != undefined) {\n\t\t\t\t\tchannel.octave = clamp(0, Config.pitchOctaves, (channelObject[\"octaveScrollBar\"] | 0) + 1);\n\t\t\t\t\tif (isNoiseChannel) channel.octave = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Array.isArray(channelObject[\"instruments\"])) {\n\t\t\t\t\tconst instrumentObjects: any[] = channelObject[\"instruments\"];\n\t\t\t\t\tfor (let i: number = 0; i < instrumentObjects.length; i++) {\n\t\t\t\t\t\tif (i >= this.getMaxInstrumentsPerChannel()) break;\n\t\t\t\t\t\tconst instrument: Instrument = new Instrument(isNoiseChannel);\n\t\t\t\t\t\tchannel.instruments[i] = instrument;\n\t\t\t\t\t\tinstrument.fromJsonObject(instrumentObjects[i], isNoiseChannel, legacyGlobalReverb);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (let i: number = 0; i < this.patternsPerChannel; i++) {\n\t\t\t\t\tconst pattern: Pattern = new Pattern();\n\t\t\t\t\tchannel.patterns[i] = pattern;\n\t\t\t\t\t\n\t\t\t\t\tlet patternObject: any = undefined;\n\t\t\t\t\tif (channelObject[\"patterns\"]) patternObject = channelObject[\"patterns\"][i];\n\t\t\t\t\tif (patternObject == undefined) continue;\n\t\t\t\t\t\n\t\t\t\t\tpattern.fromJsonObject(patternObject, this, channel, importedPartsPerBeat, isNoiseChannel);\n\t\t\t\t}\n\t\t\t\tchannel.patterns.length = this.patternsPerChannel;\n\t\t\t\t\n\t\t\t\tfor (let i: number = 0; i < this.barCount; i++) {\n\t\t\t\t\tchannel.bars[i] = (channelObject[\"sequence\"] != undefined) ? Math.min(this.patternsPerChannel, channelObject[\"sequence\"][i] >>> 0) : 0;\n\t\t\t\t}\n\t\t\t\tchannel.bars.length = this.barCount;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (newPitchChannels.length > Config.pitchChannelCountMax) newPitchChannels.length = Config.pitchChannelCountMax;\n\t\tif (newNoiseChannels.length > Config.noiseChannelCountMax) newNoiseChannels.length = Config.noiseChannelCountMax;\n\t\tthis.pitchChannelCount = newPitchChannels.length;\n\t\tthis.noiseChannelCount = newNoiseChannels.length;\n\t\tthis.channels.length = 0;\n\t\tArray.prototype.push.apply(this.channels, newPitchChannels);\n\t\tArray.prototype.push.apply(this.channels, newNoiseChannels);\n\t}\n\t\n\tpublic getPattern(channelIndex: number, bar: number): Pattern | null {\n\t\tif (bar < 0 || bar >= this.barCount) return null;\n\t\tconst patternIndex: number = this.channels[channelIndex].bars[bar];\n\t\tif (patternIndex == 0) return null;\n\t\treturn this.channels[channelIndex].patterns[patternIndex - 1];\n\t}\n\t\n\tpublic getBeatsPerMinute(): number {\n\t\treturn this.tempo;\n\t}\n\t\n\tpublic static getNeededBits(maxValue: number): number {\n\t\treturn 32 - Math.clz32(Math.ceil(maxValue + 1) - 1);\n\t}\n}\n\nclass PickedString {\n\tpublic delayLine: Float32Array | null = null;\n\tpublic delayIndex: number;\n\tpublic allPassSample: number;\n\tpublic allPassPrevInput: number;\n\tpublic sustainFilterSample: number;\n\tpublic sustainFilterPrevOutput2: number;\n\tpublic sustainFilterPrevInput1: number;\n\tpublic sustainFilterPrevInput2: number;\n\tpublic fractionalDelaySample: number;\n\tpublic prevDelayLength: number;\n\tpublic delayLengthDelta: number;\n\tpublic delayResetOffset: number;\n\t\n\tpublic allPassG: number = 0.0;\n\tpublic allPassGDelta: number = 0.0;\n\tpublic sustainFilterA1: number = 0.0;\n\tpublic sustainFilterA1Delta: number = 0.0;\n\tpublic sustainFilterA2: number = 0.0;\n\tpublic sustainFilterA2Delta: number = 0.0;\n\tpublic sustainFilterB0: number = 0.0;\n\tpublic sustainFilterB0Delta: number = 0.0;\n\tpublic sustainFilterB1: number = 0.0;\n\tpublic sustainFilterB1Delta: number = 0.0;\n\tpublic sustainFilterB2: number = 0.0;\n\tpublic sustainFilterB2Delta: number = 0.0;\n\t\n\tconstructor() {\n\t\tthis.reset();\n\t}\n\t\n\tpublic reset(): void {\n\t\tthis.delayIndex = -1;\n\t\tthis.allPassSample = 0.0;\n\t\tthis.allPassPrevInput = 0.0;\n\t\tthis.sustainFilterSample = 0.0;\n\t\tthis.sustainFilterPrevOutput2 = 0.0;\n\t\tthis.sustainFilterPrevInput1 = 0.0;\n\t\tthis.sustainFilterPrevInput2 = 0.0;\n\t\tthis.fractionalDelaySample = 0.0;\n\t\tthis.prevDelayLength = -1.0;\n\t\tthis.delayResetOffset = 0;\n\t}\n\t\n\tpublic update(synth: Synth, instrumentState: InstrumentState, tone: Tone, stringIndex: number, roundedSamplesPerTick: number, stringDecayStart: number, stringDecayEnd: number, sustainType: SustainType): void {\n\t\tconst allPassCenter: number = 2.0 * Math.PI * Config.pickedStringDispersionCenterFreq / synth.samplesPerSecond;\n\t\t\n\t\tconst prevDelayLength: number = this.prevDelayLength;\n\t\t\n\t\tconst phaseDeltaStart: number = tone.phaseDeltas[stringIndex];\n\t\tconst phaseDeltaScale: number = tone.phaseDeltaScales[stringIndex];\n\t\tconst phaseDeltaEnd: number = phaseDeltaStart * Math.pow(phaseDeltaScale, roundedSamplesPerTick);\n\t\t\n\t\tconst radiansPerSampleStart: number = Math.PI * 2.0 * phaseDeltaStart;\n\t\tconst radiansPerSampleEnd: number = Math.PI * 2.0 * phaseDeltaEnd;\n\t\t\n\t\tconst centerHarmonicStart: number = radiansPerSampleStart * 2.0;\n\t\tconst centerHarmonicEnd: number = radiansPerSampleEnd * 2.0;\n\t\t\n\t\tconst allPassRadiansStart: number = Math.min(Math.PI, radiansPerSampleStart * Config.pickedStringDispersionFreqMult * Math.pow(allPassCenter / radiansPerSampleStart, Config.pickedStringDispersionFreqScale));\n\t\tconst allPassRadiansEnd: number = Math.min(Math.PI, radiansPerSampleEnd * Config.pickedStringDispersionFreqMult * Math.pow(allPassCenter / radiansPerSampleEnd, Config.pickedStringDispersionFreqScale));\n\t\t\n\t\tconst shelfRadians: number = 2.0 * Math.PI * Config.pickedStringShelfHz / synth.samplesPerSecond;\n\t\tconst decayCurveStart: number = (Math.pow(100.0, stringDecayStart) - 1.0) / 99.0;\n\t\tconst decayCurveEnd: number = (Math.pow(100.0, stringDecayEnd ) - 1.0) / 99.0;\n\t\tconst register: number = sustainType == SustainType.acoustic ? 0.25 : 0.0;\n\t\tconst registerShelfCenter: number = 15.6;\n\t\tconst registerLowpassCenter: number = 3.0 * synth.samplesPerSecond / 48000;\n\t\t//const decayRateStart: number = Math.pow(0.5, decayCurveStart * shelfRadians / radiansPerSampleStart);\n\t\t//const decayRateEnd: number = Math.pow(0.5, decayCurveEnd * shelfRadians / radiansPerSampleEnd);\n\t\tconst decayRateStart: number = Math.pow(0.5, decayCurveStart * Math.pow(shelfRadians / (radiansPerSampleStart * registerShelfCenter), (1.0 + 2.0 * register)) * registerShelfCenter);\n\t\tconst decayRateEnd: number = Math.pow(0.5, decayCurveEnd * Math.pow(shelfRadians / (radiansPerSampleEnd * registerShelfCenter), (1.0 + 2.0 * register)) * registerShelfCenter);\n\t\t\n\t\tconst expressionDecayStart: number = Math.pow(decayRateStart, 0.002);\n\t\tconst expressionDecayEnd: number = Math.pow(decayRateEnd, 0.002);\n\t\t\n\t\tSynth.tempFilterStartCoefficients.allPass1stOrderInvertPhaseAbove(allPassRadiansStart);\n\t\tsynth.tempFrequencyResponse.analyze(Synth.tempFilterStartCoefficients, centerHarmonicStart);\n\t\tconst allPassGStart: number = Synth.tempFilterStartCoefficients.b[0]; /* same as a[1] */\n\t\tconst allPassPhaseDelayStart: number = -synth.tempFrequencyResponse.angle() / centerHarmonicStart;\n\t\t\n\t\tSynth.tempFilterEndCoefficients.allPass1stOrderInvertPhaseAbove(allPassRadiansEnd);\n\t\tsynth.tempFrequencyResponse.analyze(Synth.tempFilterEndCoefficients, centerHarmonicEnd);\n\t\tconst allPassGEnd: number = Synth.tempFilterEndCoefficients.b[0]; /* same as a[1] */\n\t\tconst allPassPhaseDelayEnd: number = -synth.tempFrequencyResponse.angle() / centerHarmonicEnd;\n\t\t\n\t\t// 1st order shelf filters and 2nd order lowpass filters have differently shaped frequency\n\t\t// responses, as well as adjustable shapes. I originally picked a 1st order shelf filter,\n\t\t// but I kinda prefer 2nd order lowpass filters now and I designed a couple settings:\n\t\tconst enum PickedStringBrightnessType {\n\t\t\tbright, // 1st order shelf\n\t\t\tnormal, // 2nd order lowpass, rounded corner\n\t\t\tresonant, // 3rd order lowpass, harder corner\n\t\t}\n\t\tconst brightnessType: PickedStringBrightnessType = <any> sustainType == SustainType.bright ? PickedStringBrightnessType.bright : PickedStringBrightnessType.normal;\n\t\tif (brightnessType == PickedStringBrightnessType.bright) {\n\t\t\tconst shelfGainStart: number = Math.pow(decayRateStart, Config.stringDecayRate);\n\t\t\tconst shelfGainEnd: number = Math.pow(decayRateEnd, Config.stringDecayRate);\n\t\t\tSynth.tempFilterStartCoefficients.highShelf2ndOrder(shelfRadians, shelfGainStart, 0.5);\n\t\t\tSynth.tempFilterEndCoefficients.highShelf2ndOrder(shelfRadians, shelfGainEnd, 0.5);\n\t\t} else {\n\t\t\tconst cornerHardness: number = Math.pow(brightnessType == PickedStringBrightnessType.normal ? 0.0 : 1.0, 0.25);\n\t\t\tconst lowpass1stOrderCutoffRadiansStart: number = Math.pow(registerLowpassCenter * registerLowpassCenter * radiansPerSampleStart * 3.3 * 48000 / synth.samplesPerSecond, 0.5 + register) / registerLowpassCenter / Math.pow(decayCurveStart, .5);\n\t\t\tconst lowpass1stOrderCutoffRadiansEnd: number = Math.pow(registerLowpassCenter * registerLowpassCenter * radiansPerSampleEnd * 3.3 * 48000 / synth.samplesPerSecond, 0.5 + register) / registerLowpassCenter / Math.pow(decayCurveEnd, .5);\n\t\t\tconst lowpass2ndOrderCutoffRadiansStart: number = lowpass1stOrderCutoffRadiansStart * Math.pow(2.0, 0.5 - 1.75 * (1.0 - Math.pow(1.0 - cornerHardness, 0.85)));\n\t\t\tconst lowpass2ndOrderCutoffRadiansEnd: number = lowpass1stOrderCutoffRadiansEnd * Math.pow(2.0, 0.5 - 1.75 * (1.0 - Math.pow(1.0 - cornerHardness, 0.85)));\n\t\t\tconst lowpass2ndOrderGainStart: number = Math.pow(2.0, -Math.pow(2.0, -Math.pow(cornerHardness, 0.9)));\n\t\t\tconst lowpass2ndOrderGainEnd: number = Math.pow(2.0, -Math.pow(2.0, -Math.pow(cornerHardness, 0.9)));\n\t\t\tSynth.tempFilterStartCoefficients.lowPass2ndOrderButterworth(warpInfinityToNyquist(lowpass2ndOrderCutoffRadiansStart), lowpass2ndOrderGainStart);\n\t\t\tSynth.tempFilterEndCoefficients .lowPass2ndOrderButterworth(warpInfinityToNyquist(lowpass2ndOrderCutoffRadiansEnd), lowpass2ndOrderGainEnd);\n\t\t}\n\t\t\n\t\tsynth.tempFrequencyResponse.analyze(Synth.tempFilterStartCoefficients, centerHarmonicStart);\n\t\tconst sustainFilterA1Start: number = Synth.tempFilterStartCoefficients.a[1];\n\t\tconst sustainFilterA2Start: number = Synth.tempFilterStartCoefficients.a[2];\n\t\tconst sustainFilterB0Start: number = Synth.tempFilterStartCoefficients.b[0] * expressionDecayStart;\n\t\tconst sustainFilterB1Start: number = Synth.tempFilterStartCoefficients.b[1] * expressionDecayStart;\n\t\tconst sustainFilterB2Start: number = Synth.tempFilterStartCoefficients.b[2] * expressionDecayStart;\n\t\tconst sustainFilterPhaseDelayStart: number = -synth.tempFrequencyResponse.angle() / centerHarmonicStart;\n\t\t\n\t\tsynth.tempFrequencyResponse.analyze(Synth.tempFilterEndCoefficients, centerHarmonicEnd);\n\t\tconst sustainFilterA1End: number = Synth.tempFilterEndCoefficients.a[1];\n\t\tconst sustainFilterA2End: number = Synth.tempFilterEndCoefficients.a[2];\n\t\tconst sustainFilterB0End: number = Synth.tempFilterEndCoefficients.b[0] * expressionDecayEnd;\n\t\tconst sustainFilterB1End: number = Synth.tempFilterEndCoefficients.b[1] * expressionDecayEnd;\n\t\tconst sustainFilterB2End: number = Synth.tempFilterEndCoefficients.b[2] * expressionDecayEnd;\n\t\tconst sustainFilterPhaseDelayEnd: number = -synth.tempFrequencyResponse.angle() / centerHarmonicEnd;\n\t\t\n\t\tconst periodLengthStart: number = 1.0 / phaseDeltaStart;\n\t\tconst periodLengthEnd: number = 1.0 / phaseDeltaEnd;\n\t\tconst minBufferLength: number = Math.ceil(Math.max(periodLengthStart, periodLengthEnd) * 2);\n\t\tconst delayLength: number = periodLengthStart - allPassPhaseDelayStart - sustainFilterPhaseDelayStart;\n\t\tconst delayLengthEnd: number = periodLengthEnd - allPassPhaseDelayEnd - sustainFilterPhaseDelayEnd;\n\t\t\n\t\tthis.prevDelayLength = delayLength;\n\t\tthis.delayLengthDelta = (delayLengthEnd - delayLength) / roundedSamplesPerTick;\n\t\tthis.allPassG = allPassGStart;\n\t\tthis.sustainFilterA1 = sustainFilterA1Start;\n\t\tthis.sustainFilterA2 = sustainFilterA2Start;\n\t\tthis.sustainFilterB0 = sustainFilterB0Start;\n\t\tthis.sustainFilterB1 = sustainFilterB1Start;\n\t\tthis.sustainFilterB2 = sustainFilterB2Start;\n\t\tthis.allPassGDelta = (allPassGEnd - allPassGStart) / roundedSamplesPerTick;\n\t\tthis.sustainFilterA1Delta = (sustainFilterA1End - sustainFilterA1Start) / roundedSamplesPerTick;\n\t\tthis.sustainFilterA2Delta = (sustainFilterA2End - sustainFilterA2Start) / roundedSamplesPerTick;\n\t\tthis.sustainFilterB0Delta = (sustainFilterB0End - sustainFilterB0Start) / roundedSamplesPerTick;\n\t\tthis.sustainFilterB1Delta = (sustainFilterB1End - sustainFilterB1Start) / roundedSamplesPerTick;\n\t\tthis.sustainFilterB2Delta = (sustainFilterB2End - sustainFilterB2Start) / roundedSamplesPerTick;\n\t\t\n\t\tconst pitchChanged: boolean = Math.abs(Math.log2(delayLength / prevDelayLength)) > 0.01;\n\t\t\n\t\tconst reinitializeImpulse: boolean = (this.delayIndex == -1 || pitchChanged);\n\t\tif (this.delayLine == null || this.delayLine.length <= minBufferLength) {\n\t\t\t// The delay line buffer will get reused for other tones so might as well\n\t\t\t// start off with a buffer size that is big enough for most notes.\n\t\t\tconst likelyMaximumLength: number = Math.ceil(2 * synth.samplesPerSecond / Instrument.frequencyFromPitch(12));\n\t\t\tconst newDelayLine: Float32Array = new Float32Array(Synth.fittingPowerOfTwo(Math.max(likelyMaximumLength, minBufferLength)));\n\t\t\tif (!reinitializeImpulse && this.delayLine != null) {\n\t\t\t\t// If the tone has already started but the buffer needs to be reallocated,\n\t\t\t\t// transfer the old data to the new buffer.\n\t\t\t\tconst oldDelayBufferMask: number = (this.delayLine.length - 1) >> 0;\n\t\t\t\tconst startCopyingFromIndex: number = this.delayIndex + this.delayResetOffset;\n\t\t\t\tthis.delayIndex = this.delayLine.length - this.delayResetOffset;\n\t\t\t\tfor (let i: number = 0; i < this.delayLine.length; i++) {\n\t\t\t\t\tnewDelayLine[i] = this.delayLine[(startCopyingFromIndex + i) & oldDelayBufferMask];\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.delayLine = newDelayLine;\n\t\t}\n\t\tconst delayLine: Float32Array = this.delayLine;\n\t\tconst delayBufferMask: number = (delayLine.length - 1) >> 0;\n\t\t\n\t\tif (reinitializeImpulse) {\n\t\t\t// -1 delay index means the tone was reset.\n\t\t\t// Also, if the pitch changed suddenly (e.g. from seamless or arpeggio) then reset the wave.\n\t\t\t\n\t\t\tthis.delayIndex = 0;\n\t\t\tthis.allPassSample = 0.0;\n\t\t\tthis.allPassPrevInput = 0.0;\n\t\t\tthis.sustainFilterSample = 0.0;\n\t\t\tthis.sustainFilterPrevOutput2 = 0.0;\n\t\t\tthis.sustainFilterPrevInput1 = 0.0;\n\t\t\tthis.sustainFilterPrevInput2 = 0.0;\n\t\t\tthis.fractionalDelaySample = 0.0;\n\t\t\t\n\t\t\t// Clear away a region of the delay buffer for the new impulse.\n\t\t\tconst startImpulseFrom: number = -delayLength;\n\t\t\tconst startZerosFrom: number = Math.floor(startImpulseFrom - periodLengthStart / 2);\n\t\t\tconst stopZerosAt: number = Math.ceil(startZerosFrom + periodLengthStart * 2);\n\t\t\tthis.delayResetOffset = stopZerosAt; // And continue clearing the area in front of the delay line.\n\t\t\tfor (let i: number = startZerosFrom; i <= stopZerosAt; i++) {\n\t\t\t\tdelayLine[i & delayBufferMask] = 0.0;\n\t\t\t}\n\t\t\t\n\t\t\tconst impulseWave: Float32Array = instrumentState.wave!;\n\t\t\tconst impulseWaveLength: number = impulseWave.length - 1; // The first sample is duplicated at the end, don't double-count it.\n\t\t\tconst impulsePhaseDelta: number = impulseWaveLength / periodLengthStart;\n\t\t\t\n\t\t\tconst fadeDuration: number = Math.min(periodLengthStart * 0.2, synth.samplesPerSecond * 0.003);\n\t\t\tconst startImpulseFromSample: number = Math.ceil(startImpulseFrom);\n\t\t\tconst stopImpulseAt: number = startImpulseFrom + periodLengthStart + fadeDuration;\n\t\t\tconst stopImpulseAtSample: number = stopImpulseAt;\n\t\t\tlet impulsePhase: number = (startImpulseFromSample - startImpulseFrom) * impulsePhaseDelta;\n\t\t\tlet prevWaveIntegral: number = 0.0;\n\t\t\tfor (let i: number = startImpulseFromSample; i <= stopImpulseAtSample; i++) {\n\t\t\t\tconst impulsePhaseInt: number = impulsePhase|0;\n\t\t\t\tconst index: number = impulsePhaseInt % impulseWaveLength;\n\t\t\t\tlet nextWaveIntegral: number = impulseWave[index];\n\t\t\t\tconst phaseRatio: number = impulsePhase - impulsePhaseInt;\n\t\t\t\tnextWaveIntegral += (impulseWave[index+1] - nextWaveIntegral) * phaseRatio;\n\t\t\t\tconst sample: number = (nextWaveIntegral - prevWaveIntegral) / impulsePhaseDelta;\n\t\t\t\tconst fadeIn: number = Math.min(1.0, (i - startImpulseFrom) / fadeDuration);\n\t\t\t\tconst fadeOut: number = Math.min(1.0, (stopImpulseAt - i) / fadeDuration);\n\t\t\t\tconst combinedFade: number = fadeIn * fadeOut;\n\t\t\t\tconst curvedFade: number = combinedFade * combinedFade * (3.0 - 2.0 * combinedFade); // A cubic sigmoid from 0 to 1.\n\t\t\t\tdelayLine[i & delayBufferMask] += sample * curvedFade;\n\t\t\t\tprevWaveIntegral = nextWaveIntegral;\n\t\t\t\timpulsePhase += impulsePhaseDelta;\n\t\t\t}\n\t\t}\n\t}\n}\n\nclass EnvelopeComputer {\n\tpublic noteSecondsStart: number = 0.0;\n\tpublic noteSecondsEnd: number = 0.0;\n\tpublic noteTicksStart: number = 0.0;\n\tpublic noteTicksEnd: number = 0.0;\n\tpublic noteSizeStart: number = Config.noteSizeMax;\n\tpublic noteSizeEnd: number = Config.noteSizeMax;\n\tpublic prevNoteSize: number = Config.noteSizeMax;\n\tpublic nextNoteSize: number = Config.noteSizeMax;\n\tprivate _noteSizeFinal: number = Config.noteSizeMax;\n\tpublic prevNoteSecondsStart: number = 0.0;\n\tpublic prevNoteSecondsEnd: number = 0.0;\n\tpublic prevNoteTicksStart: number = 0.0;\n\tpublic prevNoteTicksEnd: number = 0.0;\n\tprivate _prevNoteSizeFinal: number = Config.noteSizeMax;\n\t\n\tpublic prevSlideStart: boolean = false;\n\tpublic prevSlideEnd: boolean = false;\n\tpublic nextSlideStart: boolean = false;\n\tpublic nextSlideEnd: boolean = false;\n\tpublic prevSlideRatioStart: number = 0.0;\n\tpublic prevSlideRatioEnd: number = 0.0;\n\tpublic nextSlideRatioStart: number = 0.0;\n\tpublic nextSlideRatioEnd: number = 0.0;\n\t\n\tpublic readonly envelopeStarts: number[] = [];\n\tpublic readonly envelopeEnds: number[] = [];\n\tprivate readonly _modifiedEnvelopeIndices: number[] = [];\n\tprivate _modifiedEnvelopeCount: number = 0;\n\tpublic lowpassCutoffDecayVolumeCompensation: number = 1.0;\n\t\n\tconstructor(/*private _perNote: boolean*/) {\n\t\t//const length: number = this._perNote ? EnvelopeComputeIndex.length : InstrumentAutomationIndex.length;\n\t\tconst length: number = EnvelopeComputeIndex.length;\n\t\tfor (let i: number = 0; i < length; i++) {\n\t\t\tthis.envelopeStarts[i] = 1.0;\n\t\t\tthis.envelopeEnds[i] = 1.0;\n\t\t}\n\t\t\n\t\tthis.reset();\n\t}\n\t\n\tpublic reset(): void {\n\t\tthis.noteSecondsEnd = 0.0;\n\t\tthis.noteTicksEnd = 0.0;\n\t\tthis._noteSizeFinal = Config.noteSizeMax;\n\t\tthis.prevNoteSecondsEnd = 0.0;\n\t\tthis.prevNoteTicksEnd = 0.0;\n\t\tthis._prevNoteSizeFinal = Config.noteSizeMax;\n\t\tthis._modifiedEnvelopeCount = 0;\n\t}\n\t\n\tpublic computeEnvelopes(instrument: Instrument, currentPart: number, tickTimeStart: number, secondsPerTick: number, tone: Tone | null): void {\n\t\tconst transition: Transition = instrument.getTransition();\n\t\tif (tone != null && tone.atNoteStart && !transition.continues && !tone.forceContinueAtStart) {\n\t\t\tthis.prevNoteSecondsEnd = this.noteSecondsEnd;\n\t\t\tthis.prevNoteTicksEnd = this.noteTicksEnd;\n\t\t\tthis._prevNoteSizeFinal = this._noteSizeFinal;\n\t\t\tthis.noteSecondsEnd = 0.0;\n\t\t\tthis.noteTicksEnd = 0.0;\n\t\t}\n\t\tif (tone != null) {\n\t\t\tif (tone.note != null) {\n\t\t\t\tthis._noteSizeFinal = tone.note.pins[tone.note.pins.length - 1].size;\n\t\t\t} else {\n\t\t\t\tthis._noteSizeFinal = Config.noteSizeMax;\n\t\t\t}\n\t\t}\n\t\t\n\t\tconst tickTimeEnd: number = tickTimeStart + 1.0;\n\t\tconst noteSecondsStart: number = this.noteSecondsEnd;\n\t\tconst noteSecondsEnd: number = noteSecondsStart + secondsPerTick;\n\t\tconst noteTicksStart: number = this.noteTicksEnd;\n\t\tconst noteTicksEnd: number = noteTicksStart + 1.0;\n\t\tconst prevNoteSecondsStart: number = this.prevNoteSecondsEnd;\n\t\tconst prevNoteSecondsEnd: number = prevNoteSecondsStart + secondsPerTick;\n\t\tconst prevNoteTicksStart: number = this.prevNoteTicksEnd;\n\t\tconst prevNoteTicksEnd: number = prevNoteTicksStart + 1.0;\n\t\t\n\t\tconst beatsPerTick: number = 1.0 / (Config.ticksPerPart * Config.partsPerBeat);\n\t\tconst beatTimeStart: number = beatsPerTick * tickTimeStart;\n\t\tconst beatTimeEnd: number = beatsPerTick * tickTimeEnd;\n\t\t\n\t\tlet noteSizeStart: number = this._noteSizeFinal;\n\t\tlet noteSizeEnd: number = this._noteSizeFinal;\n\t\tlet prevNoteSize: number = this._prevNoteSizeFinal;\n\t\tlet nextNoteSize: number = 0;\n\t\tlet prevSlideStart: boolean = false;\n\t\tlet prevSlideEnd: boolean = false;\n\t\tlet nextSlideStart: boolean = false;\n\t\tlet nextSlideEnd: boolean = false;\n\t\tlet prevSlideRatioStart: number = 0.0;\n\t\tlet prevSlideRatioEnd: number = 0.0;\n\t\tlet nextSlideRatioStart: number = 0.0;\n\t\tlet nextSlideRatioEnd: number = 0.0;\n\t\tif (tone != null && tone.note != null && !tone.passedEndOfNote) {\n\t\t\tconst endPinIndex: number = tone.note.getEndPinIndex(currentPart);\n\t\t\tconst startPin: NotePin = tone.note.pins[endPinIndex-1];\n\t\t\tconst endPin: NotePin = tone.note.pins[endPinIndex];\n\t\t\tconst startPinTick: number = (tone.note.start + startPin.time) * Config.ticksPerPart;\n\t\t\tconst endPinTick: number = (tone.note.start + endPin.time) * Config.ticksPerPart;\n\t\t\tconst ratioStart: number = (tickTimeStart - startPinTick) / (endPinTick - startPinTick);\n\t\t\tconst ratioEnd: number = (tickTimeEnd - startPinTick) / (endPinTick - startPinTick);\n\t\t\tnoteSizeStart = startPin.size + (endPin.size - startPin.size) * ratioStart;\n\t\t\tnoteSizeEnd = startPin.size + (endPin.size - startPin.size) * ratioEnd;\n\t\t\t\n\t\t\tif (transition.slides) {\n\t\t\t\tconst noteStartTick: number = tone.noteStartPart * Config.ticksPerPart;\n\t\t\t\tconst noteEndTick: number = tone.noteEndPart * Config.ticksPerPart;\n\t\t\t\tconst noteLengthTicks: number = noteEndTick - noteStartTick;\n\t\t\t\tconst maximumSlideTicks: number = noteLengthTicks * 0.5;\n\t\t\t\tconst slideTicks: number = Math.min(maximumSlideTicks, transition.slideTicks);\n\t\t\t\tif (tone.prevNote != null && !tone.forceContinueAtStart) {\n\t\t\t\t\tif (tickTimeStart - noteStartTick < slideTicks) {\n\t\t\t\t\t\tprevSlideStart = true;\n\t\t\t\t\t\tprevSlideRatioStart = 0.5 * (1.0 - (tickTimeStart - noteStartTick) / slideTicks);\n\t\t\t\t\t}\n\t\t\t\t\tif (tickTimeEnd - noteStartTick < slideTicks) {\n\t\t\t\t\t\tprevSlideEnd = true;\n\t\t\t\t\t\tprevSlideRatioEnd = 0.5 * (1.0 - (tickTimeEnd - noteStartTick) / slideTicks);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (tone.nextNote != null && !tone.forceContinueAtEnd) {\n\t\t\t\t\tnextNoteSize = tone.nextNote.pins[0].size\n\t\t\t\t\tif (noteEndTick - tickTimeStart < slideTicks) {\n\t\t\t\t\t\tnextSlideStart = true;\n\t\t\t\t\t\tnextSlideRatioStart = 0.5 * (1.0 - (noteEndTick - tickTimeStart) / slideTicks);\n\t\t\t\t\t}\n\t\t\t\t\tif (noteEndTick - tickTimeEnd < slideTicks) {\n\t\t\t\t\t\tnextSlideEnd = true;\n\t\t\t\t\t\tnextSlideRatioEnd = 0.5 * (1.0 - (noteEndTick - tickTimeEnd) / slideTicks);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tlet lowpassCutoffDecayVolumeCompensation: number = 1.0;\n\t\tlet usedNoteSize: boolean = false;\n\t\tfor (let envelopeIndex: number = 0; envelopeIndex <= instrument.envelopeCount; envelopeIndex++) {\n\t\t\tlet automationTarget: AutomationTarget;\n\t\t\tlet targetIndex: number;\n\t\t\tlet envelope: Envelope;\n\t\t\tif (envelopeIndex == instrument.envelopeCount) {\n\t\t\t\tif (usedNoteSize /*|| !this._perNote*/) break;\n\t\t\t\t// Special case: if no other envelopes used note size, default to applying it to note volume.\n\t\t\t\tautomationTarget = Config.instrumentAutomationTargets.dictionary[\"noteVolume\"];\n\t\t\t\ttargetIndex = 0;\n\t\t\t\tenvelope = Config.envelopes.dictionary[\"note size\"];\n\t\t\t} else {\n\t\t\t\tlet envelopeSettings: EnvelopeSettings = instrument.envelopes[envelopeIndex];\n\t\t\t\tautomationTarget = Config.instrumentAutomationTargets[envelopeSettings.target];\n\t\t\t\ttargetIndex = envelopeSettings.index;\n\t\t\t\tenvelope = Config.envelopes[envelopeSettings.envelope];\n\t\t\t\tif (envelope.type == EnvelopeType.noteSize) usedNoteSize = true;\n\t\t\t}\n\t\t\tif (/*automationTarget.perNote == this._perNote &&*/ automationTarget.computeIndex != null) {\n\t\t\t\tconst computeIndex: number = automationTarget.computeIndex + targetIndex;\n\t\t\t\tlet envelopeStart: number = EnvelopeComputer.computeEnvelope(envelope, noteSecondsStart, beatTimeStart, noteSizeStart);\n\t\t\t\tlet envelopeEnd: number = EnvelopeComputer.computeEnvelope(envelope, noteSecondsEnd, beatTimeEnd, noteSizeEnd);\n\t\t\t\t\n\t\t\t\tif (prevSlideStart) {\n\t\t\t\t\tconst other: number = EnvelopeComputer.computeEnvelope(envelope, prevNoteSecondsStart, beatTimeStart, prevNoteSize);\n\t\t\t\t\tenvelopeStart += (other - envelopeStart) * prevSlideRatioStart;\n\t\t\t\t}\n\t\t\t\tif (prevSlideEnd) {\n\t\t\t\t\tconst other: number = EnvelopeComputer.computeEnvelope(envelope, prevNoteSecondsEnd, beatTimeEnd, prevNoteSize);\n\t\t\t\t\tenvelopeEnd += (other - envelopeEnd) * prevSlideRatioEnd;\n\t\t\t\t}\n\t\t\t\tif (nextSlideStart) {\n\t\t\t\t\tconst other: number = EnvelopeComputer.computeEnvelope(envelope, 0.0, beatTimeStart, nextNoteSize);\n\t\t\t\t\tenvelopeStart += (other - envelopeStart) * nextSlideRatioStart;\n\t\t\t\t}\n\t\t\t\tif (nextSlideEnd) {\n\t\t\t\t\tconst other: number = EnvelopeComputer.computeEnvelope(envelope, 0.0, beatTimeEnd, nextNoteSize);\n\t\t\t\t\tenvelopeEnd += (other - envelopeEnd) * nextSlideRatioEnd;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tthis.envelopeStarts[computeIndex] *= envelopeStart;\n\t\t\t\tthis.envelopeEnds[computeIndex] *= envelopeEnd;\n\t\t\t\tthis._modifiedEnvelopeIndices[this._modifiedEnvelopeCount++] = computeIndex;\n\t\t\t\t\n\t\t\t\tif (automationTarget.isFilter) {\n\t\t\t\t\tconst filterSettings: FilterSettings = /*this._perNote ?*/ instrument.noteFilter /*: instrument.eqFilter*/;\n\t\t\t\t\tif (filterSettings.controlPointCount > targetIndex && filterSettings.controlPoints[targetIndex].type == FilterType.lowPass) {\n\t\t\t\t\t\tlowpassCutoffDecayVolumeCompensation = Math.max(lowpassCutoffDecayVolumeCompensation, EnvelopeComputer.getLowpassCutoffDecayVolumeCompensation(envelope));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tthis.noteSecondsStart = noteSecondsStart;\n\t\tthis.noteSecondsEnd = noteSecondsEnd;\n\t\tthis.noteTicksStart = noteTicksStart;\n\t\tthis.noteTicksEnd = noteTicksEnd;\n\t\tthis.prevNoteSecondsStart = prevNoteSecondsStart;\n\t\tthis.prevNoteSecondsEnd = prevNoteSecondsEnd;\n\t\tthis.prevNoteTicksStart = prevNoteTicksStart;\n\t\tthis.prevNoteTicksEnd = prevNoteTicksEnd;\n\t\tthis.prevNoteSize = prevNoteSize;\n\t\tthis.nextNoteSize = nextNoteSize;\n\t\tthis.noteSizeStart = noteSizeStart;\n\t\tthis.noteSizeEnd = noteSizeEnd;\n\t\tthis.prevSlideStart = prevSlideStart;\n\t\tthis.prevSlideEnd = prevSlideEnd;\n\t\tthis.nextSlideStart = nextSlideStart;\n\t\tthis.nextSlideEnd = nextSlideEnd;\n\t\tthis.prevSlideRatioStart = prevSlideRatioStart;\n\t\tthis.prevSlideRatioEnd = prevSlideRatioEnd;\n\t\tthis.nextSlideRatioStart = nextSlideRatioStart;\n\t\tthis.nextSlideRatioEnd = nextSlideRatioEnd;\n\t\tthis.lowpassCutoffDecayVolumeCompensation = lowpassCutoffDecayVolumeCompensation;\n\t}\n\t\n\tpublic clearEnvelopes(): void {\n\t\tfor (let envelopeIndex: number = 0; envelopeIndex < this._modifiedEnvelopeCount; envelopeIndex++) {\n\t\t\tconst computeIndex: number = this._modifiedEnvelopeIndices[envelopeIndex];\n\t\t\tthis.envelopeStarts[computeIndex] = 1.0;\n\t\t\tthis.envelopeEnds[computeIndex] = 1.0;\n\t\t}\n\t\tthis._modifiedEnvelopeCount = 0;\n\t}\n\t\n\tpublic static computeEnvelope(envelope: Envelope, time: number, beats: number, noteSize: number): number {\n\t\tswitch(envelope.type) {\n\t\t\tcase EnvelopeType.noteSize: return Synth.noteSizeToVolumeMult(noteSize);\n\t\t\tcase EnvelopeType.none: return 1.0;\n\t\t\tcase EnvelopeType.twang: return 1.0 / (1.0 + time * envelope.speed);\n\t\t\tcase EnvelopeType.swell: return 1.0 - 1.0 / (1.0 + time * envelope.speed);\n\t\t\tcase EnvelopeType.tremolo: return 0.5 - Math.cos(beats * 2.0 * Math.PI * envelope.speed) * 0.5;\n\t\t\tcase EnvelopeType.tremolo2: return 0.75 - Math.cos(beats * 2.0 * Math.PI * envelope.speed) * 0.25;\n\t\t\tcase EnvelopeType.punch: return Math.max(1.0, 2.0 - time * 10.0);\n\t\t\tcase EnvelopeType.flare: const attack: number = 0.25 / Math.sqrt(envelope.speed); return time < attack ? time / attack : 1.0 / (1.0 + (time - attack) * envelope.speed);\n\t\t\tcase EnvelopeType.decay: return Math.pow(2, -envelope.speed * time);\n\t\t\tdefault: throw new Error(\"Unrecognized operator envelope type.\");\n\t\t}\n\t}\n\t\n\tpublic static getLowpassCutoffDecayVolumeCompensation(envelope: Envelope): number {\n\t\t// This is a little hokey in the details, but I designed it a while ago and keep it \n\t\t// around for compatibility. This decides how much to increase the volume (or\n\t\t// expression) to compensate for a decaying lowpass cutoff to maintain perceived\n\t\t// volume overall.\n\t\tif (envelope.type == EnvelopeType.decay) return 1.25 + 0.025 * envelope.speed;\n\t\tif (envelope.type == EnvelopeType.twang) return 1.0 + 0.02 * envelope.speed;\n\t\treturn 1.0;\n\t}\n}\n\nclass Tone {\n\tpublic instrumentIndex: number;\n\tpublic readonly pitches: number[] = Array(Config.maxChordSize).fill(0);\n\tpublic pitchCount: number = 0;\n\tpublic chordSize: number = 0;\n\tpublic drumsetPitch: number | null = null;\n\tpublic note: Note | null = null;\n\tpublic prevNote: Note | null = null;\n\tpublic nextNote: Note | null = null;\n\tpublic prevNotePitchIndex: number = 0;\n\tpublic nextNotePitchIndex: number = 0;\n\tpublic freshlyAllocated: boolean = true;\n\tpublic atNoteStart: boolean = false;\n\tpublic isOnLastTick: boolean = false; // Whether the tone is finished fading out and ready to be freed.\n\tpublic passedEndOfNote: boolean = false;\n\tpublic forceContinueAtStart: boolean = false;\n\tpublic forceContinueAtEnd: boolean = false;\n\tpublic noteStartPart: number = 0;\n\tpublic noteEndPart: number = 0;\n\tpublic ticksSinceReleased: number = 0;\n\tpublic liveInputSamplesHeld: number = 0;\n\tpublic lastInterval: number = 0;\n\tpublic noiseSample: number = 0.0;\n\tpublic readonly phases: number[] = [];\n\tpublic readonly phaseDeltas: number[] = [];\n\tpublic readonly phaseDeltaScales: number[] = [];\n\tpublic expression: number = 0.0;\n\tpublic expressionDelta: number = 0.0;\n\tpublic readonly operatorExpressions: number[] = [];\n\tpublic readonly operatorExpressionDeltas: number[] = [];\n\tpublic readonly prevPitchExpressions: Array<number | null> = Array(Config.maxPitchOrOperatorCount).fill(null);\n\tpublic prevVibrato: number | null = null;\n\tpublic prevStringDecay: number | null = null;\n\tpublic pulseWidth: number = 0.0;\n\tpublic pulseWidthDelta: number = 0.0;\n\tpublic supersawDynamism: number = 0.0;\n\tpublic supersawDynamismDelta: number = 0.0;\n\tpublic supersawUnisonDetunes: number[] = []; // These can change over time, but slowly enough that I'm not including corresponding delta values within a tick run.\n\tpublic supersawShape: number = 0.0;\n\tpublic supersawShapeDelta: number = 0.0;\n\tpublic supersawDelayLength: number = 0.0;\n\tpublic supersawDelayLengthDelta: number = 0.0;\n\tpublic supersawDelayLine: Float32Array | null = null;\n\tpublic supersawDelayIndex: number = -1;\n\tpublic supersawPrevPhaseDelta: number | null = null;\n\tpublic readonly pickedStrings: PickedString[] = [];\n\t\n\tpublic readonly noteFilters: DynamicBiquadFilter[] = [];\n\tpublic noteFilterCount: number = 0;\n\tpublic initialNoteFilterInput1: number = 0.0;\n\tpublic initialNoteFilterInput2: number = 0.0;\n\t\n\tpublic specialIntervalExpressionMult: number = 1.0;\n\tpublic readonly feedbackOutputs: number[] = [];\n\tpublic feedbackMult: number = 0.0;\n\tpublic feedbackDelta: number = 0.0;\n\t\n\tpublic readonly envelopeComputer: EnvelopeComputer = new EnvelopeComputer(/*true*/);\n\t\n\tconstructor() {\n\t\tthis.reset();\n\t}\n\t\n\tpublic reset(): void {\n\t\tthis.noiseSample = 0.0;\n\t\tfor (let i: number = 0; i < Config.maxPitchOrOperatorCount; i++) {\n\t\t\tthis.phases[i] = 0.0;\n\t\t\tthis.feedbackOutputs[i] = 0.0;\n\t\t\tthis.prevPitchExpressions[i] = null;\n\t\t}\n\t\tfor (let i: number = 0; i < this.noteFilterCount; i++) {\n\t\t\tthis.noteFilters[i].resetOutput();\n\t\t}\n\t\tthis.noteFilterCount = 0;\n\t\tthis.initialNoteFilterInput1 = 0.0;\n\t\tthis.initialNoteFilterInput2 = 0.0;\n\t\tthis.liveInputSamplesHeld = 0;\n\t\tthis.supersawDelayIndex = -1;\n\t\tfor (const pickedString of this.pickedStrings) {\n\t\t\tpickedString.reset();\n\t\t}\n\t\tthis.envelopeComputer.reset();\n\t\tthis.prevVibrato = null;\n\t\tthis.prevStringDecay = null;\n\t\tthis.supersawPrevPhaseDelta = null;\n\t\tthis.drumsetPitch = null;\n\t}\n}\n\nclass InstrumentState {\n\tpublic awake: boolean = false; // Whether the instrument's effects-processing loop should continue.\n\tpublic computed: boolean = false; // Whether the effects-processing parameters are up-to-date for the current synth run.\n\tpublic tonesAddedInThisTick: boolean = false; // Whether any instrument tones are currently active.\n\tpublic flushingDelayLines: boolean = false; // If no tones were active recently, enter a mode where the delay lines are filled with zeros to reset them for later use.\n\tpublic deactivateAfterThisTick: boolean = false; // Whether the instrument is ready to be deactivated because the delay lines, if any, are fully zeroed.\n\tpublic attentuationProgress: number = 0.0; // How long since an active tone introduced an input signal to the delay lines, normalized from 0 to 1 based on how long to wait until the delay lines signal will have audibly dissapated.\n\tpublic flushedSamples: number = 0; // How many delay line samples have been flushed to zero.\n\tpublic readonly activeTones: Deque<Tone> = new Deque<Tone>();\n\tpublic readonly releasedTones: Deque<Tone> = new Deque<Tone>(); // Tones that are in the process of fading out after the corresponding notes ended.\n\tpublic readonly liveInputTones: Deque<Tone> = new Deque<Tone>(); // Tones that are initiated by a source external to the loaded song data.\n\t\n\tpublic type: InstrumentType = InstrumentType.chip;\n\tpublic synthesizer: Function | null = null;\n\tpublic wave: Float32Array | null = null;\n\tpublic noisePitchFilterMult: number = 1.0;\n\tpublic unison: Unison | null = null;\n\tpublic chord: Chord | null = null;\n\tpublic effects: number = 0;\n\t\n\tpublic eqFilterVolume: number = 1.0;\n\tpublic eqFilterVolumeDelta: number = 0.0;\n\tpublic mixVolume: number = 1.0;\n\tpublic mixVolumeDelta: number = 0.0;\n\tpublic delayInputMult: number = 0.0;\n\tpublic delayInputMultDelta: number = 0.0;\n\t\n\tpublic distortion: number = 0.0;\n\tpublic distortionDelta: number = 0.0;\n\tpublic distortionDrive: number = 0.0;\n\tpublic distortionDriveDelta: number = 0.0;\n\tpublic distortionFractionalInput1: number = 0.0;\n\tpublic distortionFractionalInput2: number = 0.0;\n\tpublic distortionFractionalInput3: number = 0.0;\n\tpublic distortionPrevInput: number = 0.0;\n\tpublic distortionNextOutput: number = 0.0;\n\t\n\tpublic bitcrusherPrevInput: number = 0.0;\n\tpublic bitcrusherCurrentOutput: number = 0.0;\n\tpublic bitcrusherPhase: number = 1.0;\n\tpublic bitcrusherPhaseDelta: number = 0.0;\n\tpublic bitcrusherPhaseDeltaScale: number = 1.0;\n\tpublic bitcrusherScale: number = 1.0;\n\tpublic bitcrusherScaleScale: number = 1.0;\n\tpublic bitcrusherFoldLevel: number = 1.0;\n\tpublic bitcrusherFoldLevelScale: number = 1.0;\n\t\n\tpublic readonly eqFilters: DynamicBiquadFilter[] = [];\n\tpublic eqFilterCount: number = 0;\n\tpublic initialEqFilterInput1: number = 0.0;\n\tpublic initialEqFilterInput2: number = 0.0;\n\t\n\tpublic panningDelayLine: Float32Array | null = null;\n\tpublic panningDelayPos: number = 0;\n\tpublic panningVolumeL: number = 0.0;\n\tpublic panningVolumeR: number = 0.0;\n\tpublic panningVolumeDeltaL: number = 0.0;\n\tpublic panningVolumeDeltaR: number = 0.0;\n\tpublic panningOffsetL: number = 0.0;\n\tpublic panningOffsetR: number = 0.0;\n\tpublic panningOffsetDeltaL: number = 0.0;\n\tpublic panningOffsetDeltaR: number = 0.0;\n\t\n\tpublic chorusDelayLineL: Float32Array | null = null;\n\tpublic chorusDelayLineR: Float32Array | null = null;\n\tpublic chorusDelayLineDirty: boolean = false;\n\tpublic chorusDelayPos: number = 0;\n\tpublic chorusPhase: number = 0;\n\tpublic chorusVoiceMult: number = 0;\n\tpublic chorusVoiceMultDelta: number = 0;\n\tpublic chorusCombinedMult: number = 0;\n\tpublic chorusCombinedMultDelta: number = 0;\n\t\n\tpublic echoDelayLineL: Float32Array | null = null;\n\tpublic echoDelayLineR: Float32Array | null = null;\n\tpublic echoDelayLineDirty: boolean = false;\n\tpublic echoDelayPos: number = 0;\n\tpublic echoDelayOffsetStart: number = 0;\n\tpublic echoDelayOffsetEnd: number | null = null;\n\tpublic echoDelayOffsetRatio: number = 0.0;\n\tpublic echoDelayOffsetRatioDelta: number = 0.0;\n\tpublic echoMult: number = 0.0;\n\tpublic echoMultDelta: number = 0.0;\n\tpublic echoShelfA1: number = 0.0;\n\tpublic echoShelfB0: number = 0.0;\n\tpublic echoShelfB1: number = 0.0;\n\tpublic echoShelfSampleL: number = 0.0;\n\tpublic echoShelfSampleR: number = 0.0;\n\tpublic echoShelfPrevInputL: number = 0.0;\n\tpublic echoShelfPrevInputR: number = 0.0;\n\t\n\tpublic reverbDelayLine: Float32Array | null = null;\n\tpublic reverbDelayLineDirty: boolean = false;\n\tpublic reverbDelayPos: number = 0;\n\tpublic reverbMult: number = 0.0;\n\tpublic reverbMultDelta: number = 0.0;\n\tpublic reverbShelfA1: number = 0.0;\n\tpublic reverbShelfB0: number = 0.0;\n\tpublic reverbShelfB1: number = 0.0;\n\tpublic reverbShelfSample0: number = 0.0;\n\tpublic reverbShelfSample1: number = 0.0;\n\tpublic reverbShelfSample2: number = 0.0;\n\tpublic reverbShelfSample3: number = 0.0;\n\tpublic reverbShelfPrevInput0: number = 0.0;\n\tpublic reverbShelfPrevInput1: number = 0.0;\n\tpublic reverbShelfPrevInput2: number = 0.0;\n\tpublic reverbShelfPrevInput3: number = 0.0;\n\t\n\t//public readonly envelopeComputer: EnvelopeComputer = new EnvelopeComputer(false);\n\t\n\tpublic readonly spectrumWave: SpectrumWaveState = new SpectrumWaveState();\n\tpublic readonly harmonicsWave: HarmonicsWaveState = new HarmonicsWaveState();\n\tpublic readonly drumsetSpectrumWaves: SpectrumWaveState[] = [];\n\t\n\tconstructor() {\n\t\tfor (let i: number = 0; i < Config.drumCount; i++) {\n\t\t\tthis.drumsetSpectrumWaves[i] = new SpectrumWaveState();\n\t\t}\n\t}\n\t\n\tpublic allocateNecessaryBuffers(synth: Synth, instrument: Instrument, samplesPerTick: number): void {\n\t\tif (effectsIncludePanning(instrument.effects)) {\n\t\t\tif (this.panningDelayLine == null || this.panningDelayLine.length < synth.panningDelayBufferSize) {\n\t\t\t\tthis.panningDelayLine = new Float32Array(synth.panningDelayBufferSize);\n\t\t\t}\n\t\t}\n\t\tif (effectsIncludeChorus(instrument.effects)) {\n\t\t\tif (this.chorusDelayLineL == null || this.chorusDelayLineL.length < synth.chorusDelayBufferSize) {\n\t\t\t\tthis.chorusDelayLineL = new Float32Array(synth.chorusDelayBufferSize);\n\t\t\t}\n\t\t\tif (this.chorusDelayLineR == null || this.chorusDelayLineR.length < synth.chorusDelayBufferSize) {\n\t\t\t\tthis.chorusDelayLineR = new Float32Array(synth.chorusDelayBufferSize);\n\t\t\t}\n\t\t}\n\t\tif (effectsIncludeEcho(instrument.effects)) {\n\t\t\t// account for tempo and delay automation changing delay length during a tick?\n\t\t\tconst safeEchoDelaySteps: number = Math.max(Config.echoDelayRange >> 1, (instrument.echoDelay + 1)); // The delay may be very short now, but if it increases later make sure we have enough sample history.\n\t\t\tconst baseEchoDelayBufferSize: number = Synth.fittingPowerOfTwo(safeEchoDelaySteps * Config.echoDelayStepTicks * samplesPerTick);\n\t\t\tconst safeEchoDelayBufferSize: number = baseEchoDelayBufferSize * 2; // If the tempo or delay changes and we suddenly need a longer delay, make sure that we have enough sample history to accomodate the longer delay.\n\t\t\t\n\t\t\tif (this.echoDelayLineL == null || this.echoDelayLineR == null) {\n\t\t\t\tthis.echoDelayLineL = new Float32Array(safeEchoDelayBufferSize);\n\t\t\t\tthis.echoDelayLineR = new Float32Array(safeEchoDelayBufferSize);\n\t\t\t} else if (this.echoDelayLineL.length < safeEchoDelayBufferSize || this.echoDelayLineR.length < safeEchoDelayBufferSize) {\n\t\t\t\t// The echo delay length may change whlie the song is playing if tempo changes,\n\t\t\t\t// so buffers may need to be reallocated, but we don't want to lose any echoes\n\t\t\t\t// so we need to copy the contents of the old buffer to the new one.\n\t\t\t\tconst newDelayLineL: Float32Array = new Float32Array(safeEchoDelayBufferSize);\n\t\t\t\tconst newDelayLineR: Float32Array = new Float32Array(safeEchoDelayBufferSize);\n\t\t\t\tconst oldMask: number = this.echoDelayLineL.length - 1;\n\t\t\t\t\n\t\t\t\tfor (let i = 0; i < this.echoDelayLineL.length; i++) {\n\t\t\t\t\tnewDelayLineL[i] = this.echoDelayLineL[(this.echoDelayPos + i) & oldMask];\n\t\t\t\t\tnewDelayLineR[i] = this.echoDelayLineL[(this.echoDelayPos + i) & oldMask];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tthis.echoDelayPos = this.echoDelayLineL.length;\n\t\t\t\tthis.echoDelayLineL = newDelayLineL;\n\t\t\t\tthis.echoDelayLineR = newDelayLineR;\n\t\t\t}\n\t\t}\n\t\tif (effectsIncludeReverb(instrument.effects)) {\n\t\t\t// TODO: Make reverb delay line sample rate agnostic. Maybe just double buffer size for 96KHz? Adjust attenuation and shelf cutoff appropriately?\n\t\t\tif (this.reverbDelayLine == null) {\n\t\t\t\tthis.reverbDelayLine = new Float32Array(Config.reverbDelayBufferSize);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic deactivate(): void {\n\t\tthis.bitcrusherPrevInput = 0.0;\n\t\tthis.bitcrusherCurrentOutput = 0.0;\n\t\tthis.bitcrusherPhase = 1.0;\n\t\tfor (let i: number = 0; i < this.eqFilterCount; i++) {\n\t\t\tthis.eqFilters[i].resetOutput();\n\t\t}\n\t\tthis.eqFilterCount = 0;\n\t\tthis.initialEqFilterInput1 = 0.0;\n\t\tthis.initialEqFilterInput2 = 0.0;\n\t\tthis.distortionFractionalInput1 = 0.0;\n\t\tthis.distortionFractionalInput2 = 0.0;\n\t\tthis.distortionFractionalInput3 = 0.0;\n\t\tthis.distortionPrevInput = 0.0;\n\t\tthis.distortionNextOutput = 0.0;\n\t\tthis.panningDelayPos = 0;\n\t\tif (this.panningDelayLine != null) for (let i: number = 0; i < this.panningDelayLine.length; i++) this.panningDelayLine[i] = 0.0;\n\t\tthis.echoDelayOffsetEnd = null;\n\t\tthis.echoShelfSampleL = 0.0;\n\t\tthis.echoShelfSampleR = 0.0;\n\t\tthis.echoShelfPrevInputL = 0.0;\n\t\tthis.echoShelfPrevInputR = 0.0;\n\t\tthis.reverbShelfSample0 = 0.0;\n\t\tthis.reverbShelfSample1 = 0.0;\n\t\tthis.reverbShelfSample2 = 0.0;\n\t\tthis.reverbShelfSample3 = 0.0;\n\t\tthis.reverbShelfPrevInput0 = 0.0;\n\t\tthis.reverbShelfPrevInput1 = 0.0;\n\t\tthis.reverbShelfPrevInput2 = 0.0;\n\t\tthis.reverbShelfPrevInput3 = 0.0;\n\t\t\n\t\tthis.awake = false;\n\t\tthis.flushingDelayLines = false;\n\t\tthis.deactivateAfterThisTick = false;\n\t\tthis.attentuationProgress = 0.0;\n\t\tthis.flushedSamples = 0;\n\t}\n\t\n\tpublic resetAllEffects(): void {\n\t\tthis.deactivate();\n\t\t\n\t\tif (this.chorusDelayLineDirty) {\n\t\t\tfor (let i: number = 0; i < this.chorusDelayLineL!.length; i++) this.chorusDelayLineL![i] = 0.0;\n\t\t\tfor (let i: number = 0; i < this.chorusDelayLineR!.length; i++) this.chorusDelayLineR![i] = 0.0;\n\t\t}\n\t\tif (this.echoDelayLineDirty) {\n\t\t\tfor (let i: number = 0; i < this.echoDelayLineL!.length; i++) this.echoDelayLineL![i] = 0.0;\n\t\t\tfor (let i: number = 0; i < this.echoDelayLineR!.length; i++) this.echoDelayLineR![i] = 0.0;\n\t\t}\n\t\tif (this.reverbDelayLineDirty) {\n\t\t\tfor (let i: number = 0; i < this.reverbDelayLine!.length; i++) this.reverbDelayLine![i] = 0.0;\n\t\t}\n\t\t\n\t\tthis.chorusPhase = 0.0;\n\t}\n\t\n\tpublic compute(synth: Synth, instrument: Instrument, samplesPerTick: number, roundedSamplesPerTick: number, tone: Tone | null): void {\n\t\tthis.computed = true;\n\t\t\n\t\tthis.type = instrument.type;\n\t\tthis.synthesizer = Synth.getInstrumentSynthFunction(instrument);\n\t\tthis.unison = Config.unisons[instrument.unison];\n\t\tthis.chord = instrument.getChord();\n\t\tthis.noisePitchFilterMult = Config.chipNoises[instrument.chipNoise].pitchFilterMult;\n\t\t\n\t\t// Force effects to be disabled if the corresponding slider is at zero (and automation isn't involved).\n\t\tlet effects: number = instrument.effects;\n\t\tif (instrument.distortion == 0) effects &= ~(1 << EffectType.distortion);\n\t\tif (instrument.pan == Config.panCenter) effects &= ~(1 << EffectType.panning);\n\t\tif (instrument.chorus == 0) effects &= ~(1 << EffectType.chorus);\n\t\tif (instrument.echoSustain == 0) effects &= ~(1 << EffectType.echo);\n\t\tif (instrument.reverb == 0) effects &= ~(1 << EffectType.reverb);\n\t\tthis.effects = effects;\n\t\t\n\t\tthis.allocateNecessaryBuffers(synth, instrument, samplesPerTick);\n\t\t\n\t\tconst samplesPerSecond: number = synth.samplesPerSecond;\n\t\t\n\t\tthis.updateWaves(instrument, samplesPerSecond);\n\t\t\n\t\t//const ticksIntoBar: number = synth.getTicksIntoBar();\n\t\t//const tickTimeStart: number = ticksIntoBar;\n\t\t//const tickTimeEnd: number = ticksIntoBar + 1.0;\n\t\t//const secondsPerTick: number = samplesPerTick / synth.samplesPerSecond;\n\t\t//const currentPart: number = synth.getCurrentPart();\n\t\t//this.envelopeComputer.computeEnvelopes(instrument, currentPart, tickTimeStart, secondsPerTick, tone);\n\t\t//const envelopeStarts: number[] = this.envelopeComputer.envelopeStarts;\n\t\t//const envelopeEnds: number[] = this.envelopeComputer.envelopeEnds;\n\t\t\n\t\tconst usesDistortion: boolean = effectsIncludeDistortion(effects);\n\t\tconst usesBitcrusher: boolean = effectsIncludeBitcrusher(effects);\n\t\tconst usesPanning: boolean = effectsIncludePanning(effects);\n\t\tconst usesChorus: boolean = effectsIncludeChorus(effects);\n\t\tconst usesEcho: boolean = effectsIncludeEcho(effects);\n\t\tconst usesReverb: boolean = effectsIncludeReverb(effects);\n\t\t\n\t\tif (usesDistortion) {\n\t\t\tconst distortionSliderStart: number = Math.min(1.0, /*envelopeStarts[InstrumentAutomationIndex.distortion] **/ instrument.distortion / (Config.distortionRange - 1));\n\t\t\tconst distortionSliderEnd: number = Math.min(1.0, /*envelopeEnds[ InstrumentAutomationIndex.distortion] **/ instrument.distortion / (Config.distortionRange - 1));\n\t\t\tconst distortionStart: number = Math.pow(1.0 - 0.895 * (Math.pow(20.0, distortionSliderStart) - 1.0) / 19.0, 2.0);\n\t\t\tconst distortionEnd: number = Math.pow(1.0 - 0.895 * (Math.pow(20.0, distortionSliderEnd ) - 1.0) / 19.0, 2.0);\n\t\t\tconst distortionDriveStart: number = (1.0 + 2.0 * distortionSliderStart) / Config.distortionBaseVolume;\n\t\t\tconst distortionDriveEnd: number = (1.0 + 2.0 * distortionSliderEnd) / Config.distortionBaseVolume;\n\t\t\tthis.distortion = distortionStart;\n\t\t\tthis.distortionDelta = (distortionEnd - distortionStart) / roundedSamplesPerTick;\n\t\t\tthis.distortionDrive = distortionDriveStart;\n\t\t\tthis.distortionDriveDelta = (distortionDriveEnd - distortionDriveStart) / roundedSamplesPerTick;\n\t\t}\n\t\t\n\t\tif (usesBitcrusher) {\n\t\t\tconst freqSettingStart: number = instrument.bitcrusherFreq /** Math.sqrt(envelopeStarts[InstrumentAutomationIndex.bitcrusherFrequency])*/;\n\t\t\tconst freqSettingEnd: number = instrument.bitcrusherFreq /** Math.sqrt(envelopeEnds[ InstrumentAutomationIndex.bitcrusherFrequency])*/;\n\t\t\tconst quantizationSettingStart: number = instrument.bitcrusherQuantization /** Math.sqrt(envelopeStarts[InstrumentAutomationIndex.bitcrusherQuantization])*/;\n\t\t\tconst quantizationSettingEnd: number = instrument.bitcrusherQuantization /** Math.sqrt(envelopeEnds[ InstrumentAutomationIndex.bitcrusherQuantization])*/;\n\t\t\t\n\t\t\tconst basePitch: number = Config.keys[synth.song!.key].basePitch; // TODO: What if there's a key change mid-song?\n\t\t\tconst freqStart: number = Instrument.frequencyFromPitch(basePitch + 60) * Math.pow(2.0, (Config.bitcrusherFreqRange - 1 - freqSettingStart) * Config.bitcrusherOctaveStep);\n\t\t\tconst freqEnd: number = Instrument.frequencyFromPitch(basePitch + 60) * Math.pow(2.0, (Config.bitcrusherFreqRange - 1 - freqSettingEnd) * Config.bitcrusherOctaveStep);\n\t\t\tconst phaseDeltaStart: number = Math.min(1.0, freqStart / samplesPerSecond);\n\t\t\tconst phaseDeltaEnd: number = Math.min(1.0, freqEnd / samplesPerSecond);\n\t\t\tthis.bitcrusherPhaseDelta = phaseDeltaStart;\n\t\t\tthis.bitcrusherPhaseDeltaScale = Math.pow(phaseDeltaEnd / phaseDeltaStart, 1.0 / roundedSamplesPerTick);\n\t\t\t\n\t\t\tconst scaleStart: number = 2.0 * Config.bitcrusherBaseVolume * Math.pow(2.0, 1.0 - Math.pow(2.0, (Config.bitcrusherQuantizationRange - 1 - quantizationSettingStart) * 0.5));\n\t\t\tconst scaleEnd: number = 2.0 * Config.bitcrusherBaseVolume * Math.pow(2.0, 1.0 - Math.pow(2.0, (Config.bitcrusherQuantizationRange - 1 - quantizationSettingEnd) * 0.5));\n\t\t\tthis.bitcrusherScale = scaleStart;\n\t\t\tthis.bitcrusherScaleScale = Math.pow(scaleEnd / scaleStart, 1.0 / roundedSamplesPerTick);\n\t\t\t\n\t\t\tconst foldLevelStart: number = 2.0 * Config.bitcrusherBaseVolume * Math.pow(1.5, Config.bitcrusherQuantizationRange - 1 - quantizationSettingStart);\n\t\t\tconst foldLevelEnd: number = 2.0 * Config.bitcrusherBaseVolume * Math.pow(1.5, Config.bitcrusherQuantizationRange - 1 - quantizationSettingEnd);\n\t\t\tthis.bitcrusherFoldLevel = foldLevelStart;\n\t\t\tthis.bitcrusherFoldLevelScale = Math.pow(foldLevelEnd / foldLevelStart, 1.0 / roundedSamplesPerTick);\n\t\t}\n\t\t\n\t\tlet eqFilterVolume: number = 1.0; //this.envelopeComputer.lowpassCutoffDecayVolumeCompensation;\n\t\tconst eqFilterSettings: FilterSettings = instrument.eqFilter;\n\t\t//const eqAllFreqsEnvelopeStart: number = envelopeStarts[InstrumentAutomationIndex.eqFilterAllFreqs];\n\t\t//const eqAllFreqsEnvelopeEnd: number = envelopeEnds[ InstrumentAutomationIndex.eqFilterAllFreqs];\n\t\tfor (let i: number = 0; i < eqFilterSettings.controlPointCount; i++) {\n\t\t\t//const eqFreqEnvelopeStart: number = envelopeStarts[InstrumentAutomationIndex.eqFilterFreq0 + i];\n\t\t\t//const eqFreqEnvelopeEnd: number = envelopeEnds[ InstrumentAutomationIndex.eqFilterFreq0 + i];\n\t\t\t//const eqPeakEnvelopeStart: number = envelopeStarts[InstrumentAutomationIndex.eqFilterGain0 + i];\n\t\t\t//const eqPeakEnvelopeEnd: number = envelopeEnds[ InstrumentAutomationIndex.eqFilterGain0 + i];\n\t\t\tconst point: FilterControlPoint = eqFilterSettings.controlPoints[i];\n\t\t\tpoint.toCoefficients(Synth.tempFilterStartCoefficients, samplesPerSecond, /*eqAllFreqsEnvelopeStart * eqFreqEnvelopeStart*/ 1.0, /*eqPeakEnvelopeStart*/ 1.0);\n\t\t\tpoint.toCoefficients(Synth.tempFilterEndCoefficients, samplesPerSecond, /*eqAllFreqsEnvelopeEnd * eqFreqEnvelopeEnd*/ 1.0, /*eqPeakEnvelopeEnd*/ 1.0);\n\t\t\tif (this.eqFilters.length <= i) this.eqFilters[i] = new DynamicBiquadFilter();\n\t\t\tthis.eqFilters[i].loadCoefficientsWithGradient(Synth.tempFilterStartCoefficients, Synth.tempFilterEndCoefficients, 1.0 / roundedSamplesPerTick, point.type == FilterType.lowPass);\n\t\t\teqFilterVolume *= point.getVolumeCompensationMult();\n\t\t}\n\t\tthis.eqFilterCount = eqFilterSettings.controlPointCount;\n\t\teqFilterVolume = Math.min(3.0, eqFilterVolume);\n\t\t\n\t\tconst mainInstrumentVolume: number = Synth.instrumentVolumeToVolumeMult(instrument.volume);\n\t\tthis.mixVolume = mainInstrumentVolume /** envelopeStarts[InstrumentAutomationIndex.mixVolume]*/;\n\t\tconst mixVolumeEnd = mainInstrumentVolume /** envelopeEnds[ InstrumentAutomationIndex.mixVolume]*/;\n\t\tthis.mixVolumeDelta = (mixVolumeEnd - this.mixVolume) / roundedSamplesPerTick;\n\t\t\n\t\tlet eqFilterVolumeStart: number = eqFilterVolume;\n\t\tlet eqFilterVolumeEnd: number = eqFilterVolume;\n\t\tlet delayInputMultStart: number = 1.0;\n\t\tlet delayInputMultEnd: number = 1.0;\n\t\t\n\t\tif (usesPanning) {\n\t\t\t//const panEnvelopeStart: number = envelopeStarts[InstrumentAutomationIndex.panning] * 2.0 - 1.0;\n\t\t\t//const panEnvelopeEnd: number = envelopeEnds[ InstrumentAutomationIndex.panning] * 2.0 - 1.0;\n\t\t\tconst pan: number = (instrument.pan - Config.panCenter) / Config.panCenter;\n\t\t\tconst panStart: number = Math.max(-1.0, Math.min(1.0, pan /** panEnvelopeStart*/));\n\t\t\tconst panEnd: number = Math.max(-1.0, Math.min(1.0, pan /** panEnvelopeEnd */));\n\t\t\tconst volumeStartL: number = Math.cos((1 + panStart) * Math.PI * 0.25) * 1.414;\n\t\t\tconst volumeStartR: number = Math.cos((1 - panStart) * Math.PI * 0.25) * 1.414;\n\t\t\tconst volumeEndL: number = Math.cos((1 + panEnd) * Math.PI * 0.25) * 1.414;\n\t\t\tconst volumeEndR: number = Math.cos((1 - panEnd) * Math.PI * 0.25) * 1.414;\n\t\t\tconst maxDelaySamples: number = samplesPerSecond * Config.panDelaySecondsMax;\n\t\t\tconst delayStart: number = panStart * maxDelaySamples;\n\t\t\tconst delayEnd: number = panEnd * maxDelaySamples;\n\t\t\tconst delayStartL: number = Math.max(0.0, delayStart);\n\t\t\tconst delayStartR: number = Math.max(0.0, -delayStart);\n\t\t\tconst delayEndL: number = Math.max(0.0, delayEnd);\n\t\t\tconst delayEndR: number = Math.max(0.0, -delayEnd);\n\t\t\t\n\t\t\tthis.panningVolumeL = volumeStartL;\n\t\t\tthis.panningVolumeR = volumeStartR;\n\t\t\tthis.panningVolumeDeltaL = (volumeEndL - volumeStartL) / roundedSamplesPerTick;\n\t\t\tthis.panningVolumeDeltaR = (volumeEndR - volumeStartR) / roundedSamplesPerTick;\n\t\t\tthis.panningOffsetL = this.panningDelayPos - delayStartL + synth.panningDelayBufferSize;\n\t\t\tthis.panningOffsetR = this.panningDelayPos - delayStartR + synth.panningDelayBufferSize;\n\t\t\tthis.panningOffsetDeltaL = (delayEndL - delayStartL) / roundedSamplesPerTick;\n\t\t\tthis.panningOffsetDeltaR = (delayEndR - delayStartR) / roundedSamplesPerTick;\n\t\t}\n\t\t\n\t\tif (usesChorus) {\n\t\t\t//const chorusEnvelopeStart: number = envelopeStarts[InstrumentAutomationIndex.chorus];\n\t\t\t//const chorusEnvelopeEnd: number = envelopeEnds[ InstrumentAutomationIndex.chorus];\n\t\t\tlet chorusStart: number = Math.min(1.0, /*chorusEnvelopeStart **/ instrument.chorus / (Config.chorusRange - 1));\n\t\t\tlet chorusEnd: number = Math.min(1.0, /*chorusEnvelopeEnd **/ instrument.chorus / (Config.chorusRange - 1));\n\t\t\tchorusStart = chorusStart * 0.6 + (Math.pow(chorusStart, 6.0)) * 0.4;\n\t\t\tchorusEnd = chorusEnd * 0.6 + (Math.pow(chorusEnd, 6.0)) * 0.4;\n\t\t\tconst chorusCombinedMultStart = 1.0 / Math.sqrt(3.0 * chorusStart * chorusStart + 1.0);\n\t\t\tconst chorusCombinedMultEnd = 1.0 / Math.sqrt(3.0 * chorusEnd * chorusEnd + 1.0);\n\t\t\tthis.chorusVoiceMult = chorusStart;\n\t\t\tthis.chorusVoiceMultDelta = (chorusEnd - chorusStart) / roundedSamplesPerTick;\n\t\t\tthis.chorusCombinedMult = chorusCombinedMultStart;\n\t\t\tthis.chorusCombinedMultDelta = (chorusCombinedMultEnd - chorusCombinedMultStart) / roundedSamplesPerTick;\n\t\t}\n\t\t\n\t\tlet maxEchoMult = 0.0;\n\t\tlet averageEchoDelaySeconds: number = 0.0;\n\t\tif (usesEcho) {\n\t\t\t//const echoSustainEnvelopeStart: number = envelopeStarts[InstrumentAutomationIndex.echoSustain];\n\t\t\t//const echoSustainEnvelopeEnd: number = envelopeEnds[ InstrumentAutomationIndex.echoSustain];\n\t\t\tconst echoMultStart: number = Math.min(1.0, Math.pow(/*echoSustainEnvelopeStart **/ instrument.echoSustain / Config.echoSustainRange, 1.1)) * 0.9;\n\t\t\tconst echoMultEnd: number = Math.min(1.0, Math.pow(/*echoSustainEnvelopeEnd **/ instrument.echoSustain / Config.echoSustainRange, 1.1)) * 0.9;\n\t\t\tthis.echoMult = echoMultStart;\n\t\t\tthis.echoMultDelta = (echoMultEnd - echoMultStart) / roundedSamplesPerTick;\n\t\t\tmaxEchoMult = Math.max(echoMultStart, echoMultEnd);\n\t\t\t\n\t\t\t// TODO: After computing a tick's settings once for multiple run lengths (which is\n\t\t\t// good for audio worklet threads), compute the echo delay envelopes at tick (or\n\t\t\t// part) boundaries to interpolate between two delay taps.\n\t\t\t//const echoDelayEnvelopeStart: number = envelopeStarts[InstrumentAutomationIndex.echoDelay];\n\t\t\t//const echoDelayEnvelopeEnd: number = envelopeEnds[ InstrumentAutomationIndex.echoDelay];\n\t\t\tconst echoDelayOffset: number = Math.round((instrument.echoDelay + 1) * Config.echoDelayStepTicks * samplesPerTick);\n\t\t\tif (this.echoDelayOffsetEnd != null) {\n\t\t\t\tthis.echoDelayOffsetStart = this.echoDelayOffsetEnd;\n\t\t\t} else {\n\t\t\t\tthis.echoDelayOffsetStart = echoDelayOffset;\n\t\t\t}\n\t\t\tthis.echoDelayOffsetEnd = echoDelayOffset;\n\t\t\taverageEchoDelaySeconds = (this.echoDelayOffsetStart + this.echoDelayOffsetEnd) * 0.5 / samplesPerSecond;\n\t\t\t\n\t\t\tthis.echoDelayOffsetRatio = 0.0;\n\t\t\tthis.echoDelayOffsetRatioDelta = 1.0 / roundedSamplesPerTick;\n\t\t\t\n\t\t\tconst shelfRadians: number = 2.0 * Math.PI * Config.echoShelfHz / synth.samplesPerSecond;\n\t\t\tSynth.tempFilterStartCoefficients.highShelf1stOrder(shelfRadians, Config.echoShelfGain);\n\t\t\tthis.echoShelfA1 = Synth.tempFilterStartCoefficients.a[1];\n\t\t\tthis.echoShelfB0 = Synth.tempFilterStartCoefficients.b[0];\n\t\t\tthis.echoShelfB1 = Synth.tempFilterStartCoefficients.b[1];\n\t\t}\n\t\t\n\t\tlet maxReverbMult = 0.0;\n\t\tif (usesReverb) {\n\t\t\t//const reverbEnvelopeStart: number = envelopeStarts[InstrumentAutomationIndex.reverb];\n\t\t\t//const reverbEnvelopeEnd: number = envelopeEnds[ InstrumentAutomationIndex.reverb];\n\t\t\tconst reverbStart: number = Math.min(1.0, Math.pow(/*reverbEnvelopeStart **/ instrument.reverb / Config.reverbRange, 0.667)) * 0.425;\n\t\t\tconst reverbEnd: number = Math.min(1.0, Math.pow(/*reverbEnvelopeEnd **/ instrument.reverb / Config.reverbRange, 0.667)) * 0.425;\n\t\t\tthis.reverbMult = reverbStart;\n\t\t\tthis.reverbMultDelta = (reverbEnd - reverbStart) / roundedSamplesPerTick;\n\t\t\tmaxReverbMult = Math.max(reverbStart, reverbEnd);\n\t\t\t\n\t\t\tconst shelfRadians: number = 2.0 * Math.PI * Config.reverbShelfHz / synth.samplesPerSecond;\n\t\t\tSynth.tempFilterStartCoefficients.highShelf1stOrder(shelfRadians, Config.reverbShelfGain);\n\t\t\tthis.reverbShelfA1 = Synth.tempFilterStartCoefficients.a[1];\n\t\t\tthis.reverbShelfB0 = Synth.tempFilterStartCoefficients.b[0];\n\t\t\tthis.reverbShelfB1 = Synth.tempFilterStartCoefficients.b[1];\n\t\t}\n\t\t\n\t\tif (this.tonesAddedInThisTick) {\n\t\t\tthis.attentuationProgress = 0.0;\n\t\t\tthis.flushedSamples = 0;\n\t\t\tthis.flushingDelayLines = false;\n\t\t} else if (!this.flushingDelayLines) {\n\t\t\t// If this instrument isn't playing tones anymore, the volume can fade out by the\n\t\t\t// end of the first tick. It's possible for filters and the panning delay line to\n\t\t\t// continue past the end of the tone but they should have mostly dissipated by the\n\t\t\t// end of the tick anyway.\n\t\t\tif (this.attentuationProgress == 0.0) {\n\t\t\t\teqFilterVolumeEnd = 0.0;\n\t\t\t} else {\n\t\t\t\teqFilterVolumeStart = 0.0;\n\t\t\t\teqFilterVolumeEnd = 0.0;\n\t\t\t}\n\t\t\t\n\t\t\tconst attenuationThreshold: number = 1.0 / 256.0; // when the delay line signal has attenuated this much, it should be inaudible and should be flushed to zero.\n\t\t\tconst halfLifeMult: number = -Math.log2(attenuationThreshold);\n\t\t\tlet delayDuration: number = 0.0;\n\t\t\t\n\t\t\tif (usesChorus) {\n\t\t\t\tdelayDuration += Config.chorusMaxDelay;\n\t\t\t}\n\t\t\t\n\t\t\tif (usesEcho) {\n\t\t\t\tconst attenuationPerSecond: number = Math.pow(maxEchoMult, 1.0 / averageEchoDelaySeconds);\n\t\t\t\tconst halfLife: number = -1.0 / Math.log2(attenuationPerSecond);\n\t\t\t\tconst echoDuration: number = halfLife * halfLifeMult;\n\t\t\t\tdelayDuration += echoDuration;\n\t\t\t}\n\t\t\t\n\t\t\tif (usesReverb) {\n\t\t\t\tconst averageMult: number = maxReverbMult * 2.0;\n\t\t\t\tconst averageReverbDelaySeconds: number = (Config.reverbDelayBufferSize / 4.0) / samplesPerSecond;\n\t\t\t\tconst attenuationPerSecond: number = Math.pow(averageMult, 1.0 / averageReverbDelaySeconds);\n\t\t\t\tconst halfLife: number = -1.0 / Math.log2(attenuationPerSecond);\n\t\t\t\tconst reverbDuration: number = halfLife * halfLifeMult;\n\t\t\t\tdelayDuration += reverbDuration;\n\t\t\t}\n\t\t\t\n\t\t\tconst secondsInTick: number = samplesPerTick / samplesPerSecond;\n\t\t\tconst progressInTick: number = secondsInTick / delayDuration;\n\t\t\tconst progressAtEndOfTick: number = this.attentuationProgress + progressInTick;\n\t\t\tif (progressAtEndOfTick >= 1.0) {\n\t\t\t\tdelayInputMultEnd = 0.0;\n\t\t\t}\n\t\t\tthis.attentuationProgress = progressAtEndOfTick;\n\t\t\tif (this.attentuationProgress >= 1.0) {\n\t\t\t\tthis.flushingDelayLines = true;\n\t\t\t}\n\t\t} else {\n\t\t\t// Flushing delay lines to zero since the signal has mostly dissipated.\n\t\t\teqFilterVolumeStart = 0.0;\n\t\t\teqFilterVolumeEnd = 0.0;\n\t\t\tdelayInputMultStart = 0.0;\n\t\t\tdelayInputMultEnd = 0.0;\n\t\t\t\n\t\t\tlet totalDelaySamples: number = 0;\n\t\t\tif (usesChorus) totalDelaySamples += synth.chorusDelayBufferSize;\n\t\t\tif (usesEcho) totalDelaySamples += this.echoDelayLineL!.length;\n\t\t\tif (usesReverb) totalDelaySamples += Config.reverbDelayBufferSize;\n\t\t\t\n\t\t\tthis.flushedSamples += roundedSamplesPerTick;\n\t\t\tif (this.flushedSamples >= totalDelaySamples) {\n\t\t\t\tthis.deactivateAfterThisTick = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tthis.eqFilterVolume = eqFilterVolumeStart;\n\t\tthis.eqFilterVolumeDelta = (eqFilterVolumeEnd - eqFilterVolumeStart) / roundedSamplesPerTick;\n\t\tthis.delayInputMult = delayInputMultStart;\n\t\tthis.delayInputMultDelta = (delayInputMultEnd - delayInputMultStart) / roundedSamplesPerTick;\n\t}\n\t\n\tpublic updateWaves(instrument: Instrument, samplesPerSecond: number): void {\n\t\tif (instrument.type == InstrumentType.chip) {\n\t\t\tthis.wave = Config.chipWaves[instrument.chipWave].samples;\n\t\t} else if (instrument.type == InstrumentType.noise) {\n\t\t\tthis.wave = getDrumWave(instrument.chipNoise, inverseRealFourierTransform, scaleElementsByFactor);\n\t\t} else if (instrument.type == InstrumentType.harmonics) {\n\t\t\tthis.wave = this.harmonicsWave.getCustomWave(instrument.harmonicsWave, instrument.type);\n\t\t} else if (instrument.type == InstrumentType.pickedString) {\n\t\t\tthis.wave = this.harmonicsWave.getCustomWave(instrument.harmonicsWave, instrument.type);\n\t\t} else if (instrument.type == InstrumentType.spectrum) {\n\t\t\tthis.wave = this.spectrumWave.getCustomWave(instrument.spectrumWave, 8);\n\t\t} else if (instrument.type == InstrumentType.drumset) {\n\t\t\tfor (let i: number = 0; i < Config.drumCount; i++) {\n\t\t\t\tthis.drumsetSpectrumWaves[i].getCustomWave(instrument.drumsetSpectrumWaves[i], InstrumentState._drumsetIndexToSpectrumOctave(i));\n\t\t\t}\n\t\t\tthis.wave = null;\n\t\t} else {\n\t\t\tthis.wave = null;\n\t\t}\n\t}\n\t\n\tpublic getDrumsetWave(pitch: number): Float32Array {\n\t\tif (this.type == InstrumentType.drumset) {\n\t\t\treturn this.drumsetSpectrumWaves[pitch].wave!;\n\t\t} else {\n\t\t\tthrow new Error(\"Unhandled instrument type in getDrumsetWave\");\n\t\t}\n\t}\n\t\n\tpublic static drumsetIndexReferenceDelta(index: number): number {\n\t\treturn Instrument.frequencyFromPitch(Config.spectrumBasePitch + index * 6) / 44100;\n\t}\n\t\n\tprivate static _drumsetIndexToSpectrumOctave(index: number): number {\n\t\treturn 15 + Math.log2(InstrumentState.drumsetIndexReferenceDelta(index));\n\t}\n}\n\nclass ChannelState {\n\tpublic readonly instruments: InstrumentState[] = [];\n\tpublic muted: boolean = false;\n\tpublic singleSeamlessInstrument: number | null = null; // Seamless tones from a pattern with a single instrument can be transferred to a different single seamless instrument in the next pattern.\n}\n\nexport class Synth {\n\n\tprivate syncSongState(): void {\n\t\tconst channelCount: number = this.song!.getChannelCount();\n\t\tfor (let i: number = this.channels.length; i < channelCount; i++) {\n\t\t\tthis.channels[i] = new ChannelState();\n\t\t}\n\t\tthis.channels.length = channelCount;\n\t\tfor (let i: number = 0; i < channelCount; i++) {\n\t\t\tconst channel: Channel = this.song!.channels[i];\n\t\t\tconst channelState: ChannelState = this.channels[i];\n\t\t\tfor (let j: number = channelState.instruments.length; j < channel.instruments.length; j++) {\n\t\t\t\tchannelState.instruments[j] = new InstrumentState();\n\t\t\t}\n\t\t\tchannelState.instruments.length = channel.instruments.length;\n\t\t\t\n\t\t\tif (channelState.muted != channel.muted) {\n\t\t\t\tchannelState.muted = channel.muted;\n\t\t\t\tif (channelState.muted) {\n\t\t\t\t\tfor (const instrumentState of channelState.instruments) {\n\t\t\t\t\t\tinstrumentState.resetAllEffects();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tprivate warmUpSynthesizer(song: Song | null): void {\n\t\tif (song != null) {\n\t\t\tthis.syncSongState();\n\t\t\tconst samplesPerTick: number = this.getSamplesPerTick();\n\t\t\tfor (let j: number = 0; j < song.getChannelCount(); j++) {\n\t\t\t\tfor (let i: number = 0; i < song.channels[j].instruments.length; i++) {\n\t\t\t\t\tconst instrument: Instrument = song.channels[j].instruments[i];\n\t\t\t\t\tconst instrumentState: InstrumentState = this.channels[j].instruments[i];\n\t\t\t\t\tSynth.getInstrumentSynthFunction(instrument);\n\t\t\t\t\tinstrumentState.updateWaves(instrument, this.samplesPerSecond);\n\t\t\t\t\tinstrumentState.allocateNecessaryBuffers(this, instrument, samplesPerTick);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t/*\n\t\t// JummBox needed to run synth functions for at least one sample (for JIT purposes)\n\t\t// before starting audio callbacks to avoid skipping the initial output.\n\t\tvar dummyArray = new Float32Array(1);\n\t\tthis.synthesize(dummyArray, dummyArray, 1, true);\n\t\t*/\n\t}\n\t\n\tprivate static operatorAmplitudeCurve(amplitude: number): number {\n\t\treturn (Math.pow(16.0, amplitude / 15.0) - 1.0) / 15.0;\n\t}\n\t\n\tpublic samplesPerSecond: number = 44100;\n\tpublic panningDelayBufferSize: number;\n\tpublic panningDelayBufferMask: number;\n\tpublic chorusDelayBufferSize: number;\n\tpublic chorusDelayBufferMask: number;\n\t// TODO: reverb\n\t\n\tpublic song: Song | null = null;\n\tpublic preferLowerLatency: boolean = false; // enable when recording performances from keyboard or MIDI. Takes effect next time you activate audio.\n\tpublic anticipatePoorPerformance: boolean = false; // enable on mobile devices to reduce audio stutter glitches. Takes effect next time you activate audio.\n\tpublic liveInputDuration: number = 0;\n\tpublic liveInputStarted: boolean = false;\n\tpublic liveInputPitches: number[] = [];\n\tpublic liveInputChannel: number = 0;\n\tpublic liveInputInstruments: number[] = [];\n\tpublic loopRepeatCount: number = -1;\n\tpublic volume: number = 1.0;\n\tpublic enableMetronome: boolean = false;\n\tpublic countInMetronome: boolean = false;\n\t\n\tprivate playheadInternal: number = 0.0;\n\tprivate bar: number = 0;\n\tprivate prevBar: number | null = null;\n\tprivate nextBar: number | null = null;\n\tprivate beat: number = 0;\n\tprivate part: number = 0;\n\tprivate tick: number = 0;\n\tpublic isAtStartOfTick: boolean = true;\n\tpublic tickSampleCountdown: number = 0;\n\tprivate isPlayingSong: boolean = false;\n\tprivate isRecording: boolean = false;\n\tprivate liveInputEndTime: number = 0.0;\n\tprivate browserAutomaticallyClearsAudioBuffer: boolean = true; // Assume true until proven otherwise. Older Chrome does not clear the buffer so it needs to be cleared manually.\n\t\n\tpublic static readonly tempFilterStartCoefficients: FilterCoefficients = new FilterCoefficients();\n\tpublic static readonly tempFilterEndCoefficients: FilterCoefficients = new FilterCoefficients();\n\tprivate tempDrumSetControlPoint: FilterControlPoint = new FilterControlPoint();\n\tpublic tempFrequencyResponse: FrequencyResponse = new FrequencyResponse();\n\t\n\tprivate static readonly fmSynthFunctionCache: Dictionary<Function> = {};\n\tprivate static readonly effectsFunctionCache: Function[] = Array(1 << 7).fill(undefined); // keep in sync with the number of post-process effects.\n\tprivate static readonly pickedStringFunctionCache: Function[] = Array(3).fill(undefined); // keep in sync with the number of unison voices.\n\t\n\tprivate readonly channels: ChannelState[] = [];\n\tprivate readonly tonePool: Deque<Tone> = new Deque<Tone>();\n\tprivate readonly tempMatchedPitchTones: Array<Tone | null> = Array(Config.maxChordSize).fill(null);\n\t\n\tprivate startedMetronome: boolean = false;\n\tprivate metronomeSamplesRemaining: number = -1;\n\tprivate metronomeAmplitude: number = 0.0;\n\tprivate metronomePrevAmplitude: number = 0.0;\n\tprivate metronomeFilter: number = 0.0;\n\tprivate limit: number = 0.0;\n\t\n\tprivate tempMonoInstrumentSampleBuffer: Float32Array | null = null;\n\t\n\tprivate audioCtx: any | null = null;\n\tprivate scriptNode: any | null = null;\n\t\n\tpublic get playing(): boolean {\n\t\treturn this.isPlayingSong;\n\t}\n\t\n\tpublic get recording(): boolean {\n\t\treturn this.isRecording;\n\t}\n\t\n\tpublic get playhead(): number {\n\t\treturn this.playheadInternal;\n\t}\n\t\n\tpublic set playhead(value: number) {\n\t\tif (this.song != null) {\n\t\t\tthis.playheadInternal = Math.max(0, Math.min(this.song.barCount, value));\n\t\t\tlet remainder: number = this.playheadInternal;\n\t\t\tthis.bar = Math.floor(remainder);\n\t\t\tremainder = this.song.beatsPerBar * (remainder - this.bar);\n\t\t\tthis.beat = Math.floor(remainder);\n\t\t\tremainder = Config.partsPerBeat * (remainder - this.beat);\n\t\t\tthis.part = Math.floor(remainder);\n\t\t\tremainder = Config.ticksPerPart * (remainder - this.part);\n\t\t\tthis.tick = Math.floor(remainder);\n\t\t\tthis.tickSampleCountdown = 0;\n\t\t\tthis.isAtStartOfTick = true;\n\t\t\tthis.prevBar = null;\n\t\t}\n\t}\n\t\n\tpublic getSamplesPerBar(): number {\n\t\tif (this.song == null) throw new Error();\n\t\treturn this.getSamplesPerTick() * Config.ticksPerPart * Config.partsPerBeat * this.song.beatsPerBar;\n\t}\n\t\n\tpublic getTicksIntoBar(): number {\n\t\treturn (this.beat * Config.partsPerBeat + this.part) * Config.ticksPerPart + this.tick;\n\t}\n\tpublic getCurrentPart(): number {\n\t\treturn (this.beat * Config.partsPerBeat + this.part);\n\t}\n\t\n\tpublic getTotalBars(enableIntro: boolean, enableOutro: boolean): number {\n\t\tif (this.song == null) throw new Error();\n\t\tlet bars: number = this.song.loopLength * (this.loopRepeatCount + 1);\n\t\tif (enableIntro) bars += this.song.loopStart;\n\t\tif (enableOutro) bars += this.song.barCount - (this.song.loopStart + this.song.loopLength);\n\t\treturn bars;\n\t}\n\t\n\tconstructor(song: Song | string | null = null) {\n\t\tthis.computeDelayBufferSizes();\n\t\tif (song != null) this.setSong(song);\n\t}\n\t\n\tpublic setSong(song: Song | string): void {\n\t\tif (typeof(song) == \"string\") {\n\t\t\tthis.song = new Song(song);\n\t\t} else if (song instanceof Song) {\n\t\t\tthis.song = song;\n\t\t}\n\t\tthis.prevBar = null;\n\t}\n\t\n\tprivate computeDelayBufferSizes(): void {\n\t\tthis.panningDelayBufferSize = Synth.fittingPowerOfTwo(this.samplesPerSecond * Config.panDelaySecondsMax);\n\t\tthis.panningDelayBufferMask = this.panningDelayBufferSize - 1;\n\t\tthis.chorusDelayBufferSize = Synth.fittingPowerOfTwo(this.samplesPerSecond * Config.chorusMaxDelay);\n\t\tthis.chorusDelayBufferMask = this.chorusDelayBufferSize - 1;\n\t}\n\t\n\tprivate activateAudio(): void {\n\t\tconst bufferSize: number = this.anticipatePoorPerformance ? (this.preferLowerLatency ? 2048 : 4096) : (this.preferLowerLatency ? 512 : 2048);\n\t\tif (this.audioCtx == null || this.scriptNode == null || this.scriptNode.bufferSize != bufferSize) {\n\t\t\tif (this.scriptNode != null) this.deactivateAudio();\n\t\t\tconst latencyHint: string = this.anticipatePoorPerformance ? (this.preferLowerLatency ? \"balanced\" : \"playback\") : (this.preferLowerLatency ? \"interactive\" : \"balanced\");\n\t\t\tthis.audioCtx = this.audioCtx || new (window.AudioContext || window.webkitAudioContext)({latencyHint: latencyHint});\n\t\t\tthis.samplesPerSecond = this.audioCtx.sampleRate;\n\t\t\tthis.scriptNode = this.audioCtx.createScriptProcessor ? this.audioCtx.createScriptProcessor(bufferSize, 0, 2) : this.audioCtx.createJavaScriptNode(bufferSize, 0, 2); // bufferSize samples per callback buffer, 0 input channels, 2 output channels (left/right)\n\t\t\tthis.scriptNode.onaudioprocess = this.audioProcessCallback;\n\t\t\tthis.scriptNode.channelCountMode = 'explicit';\n\t\t\tthis.scriptNode.channelInterpretation = 'speakers';\n\t\t\tthis.scriptNode.connect(this.audioCtx.destination);\n\t\t\t\n\t\t\tthis.computeDelayBufferSizes();\n\t\t}\n\t\tthis.audioCtx.resume();\n\t}\n\t\n\tprivate deactivateAudio(): void {\n\t\tif (this.audioCtx != null && this.scriptNode != null) {\n\t\t\tthis.scriptNode.disconnect(this.audioCtx.destination);\n\t\t\tthis.scriptNode = null;\n\t\t\tif (this.audioCtx.close) this.audioCtx.close(); // firefox is missing this function?\n\t\t\tthis.audioCtx = null;\n\t\t}\n\t}\n\t\n\tpublic maintainLiveInput(): void {\n\t\tthis.activateAudio();\n\t\tthis.liveInputEndTime = performance.now() + 10000.0;\n\t}\n\t\n\tpublic play(): void {\n\t\tif (this.isPlayingSong) return;\n\t\tthis.isPlayingSong = true;\n\t\tthis.warmUpSynthesizer(this.song);\n\t\tthis.activateAudio();\n\t}\n\t\n\tpublic pause(): void {\n\t\tif (!this.isPlayingSong) return;\n\t\tthis.isPlayingSong = false;\n\t\tthis.isRecording = false;\n\t}\n\t\n\tpublic startRecording(): void {\n\t\tthis.preferLowerLatency = true;\n\t\tthis.isRecording = true;\n\t\tthis.play();\n\t}\n\t\n\tpublic snapToStart(): void {\n\t\tthis.bar = 0;\n\t\tthis.snapToBar();\n\t}\n\t\n\tpublic goToBar(bar: number): void {\n\t\tthis.bar = bar;\n\t\tthis.playheadInternal = this.bar;\n\t\tthis.prevBar = null;\n\t}\n\t\n\tpublic snapToBar(): void {\n\t\tthis.playheadInternal = this.bar;\n\t\tthis.beat = 0;\n\t\tthis.part = 0;\n\t\tthis.tick = 0;\n\t\tthis.tickSampleCountdown = 0;\n\t\tthis.isAtStartOfTick = true;\n\t\tthis.prevBar = null;\n\t}\n\t\n\tpublic resetEffects(): void {\n\t\tthis.limit = 0.0;\n\t\tthis.freeAllTones();\n\t\tif (this.song != null) {\n\t\t\tfor (const channelState of this.channels) {\n\t\t\t\tfor (const instrumentState of channelState.instruments) {\n\t\t\t\t\tinstrumentState.resetAllEffects();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic jumpIntoLoop(): void {\n\t\tif (!this.song) return;\n\t\tif (this.bar < this.song.loopStart || this.bar >= this.song.loopStart + this.song.loopLength) {\n\t\t\tconst oldBar: number = this.bar;\n\t\t\tthis.bar = this.song.loopStart;\n\t\t\tthis.playheadInternal += this.bar - oldBar;\n\t\t\tthis.prevBar = null;\n\t\t}\n\t}\n\t\n\tpublic goToNextBar(): void {\n\t\tif (!this.song) return;\n\t\tthis.prevBar = this.bar;\n\t\tconst oldBar: number = this.bar;\n\t\tthis.bar++;\n\t\tif (this.bar >= this.song.barCount) {\n\t\t\tthis.bar = 0;\n\t\t}\n\t\tthis.playheadInternal += this.bar - oldBar;\n\t}\n\t\n\tpublic goToPrevBar(): void {\n\t\tif (!this.song) return;\n\t\tthis.prevBar = null;\n\t\tconst oldBar: number = this.bar;\n\t\tthis.bar--;\n\t\tif (this.bar < 0 || this.bar >= this.song.barCount) {\n\t\t\tthis.bar = this.song.barCount - 1;\n\t\t}\n\t\tthis.playheadInternal += this.bar - oldBar;\n\t}\n\t\n\tprivate getNextBar(): number {\n\t\tlet nextBar: number = this.bar + 1;\n\t\tif (this.isRecording) {\n\t\t\tif (nextBar >= this.song!.barCount) {\n\t\t\t\tnextBar = this.song!.barCount - 1;\n\t\t\t}\n\t\t} else if (this.loopRepeatCount != 0 && nextBar == this.song!.loopStart + this.song!.loopLength) {\n\t\t\tnextBar = this.song!.loopStart;\n\t\t}\n\t\treturn nextBar;\n\t}\n\t\n\tprivate audioProcessCallback = (audioProcessingEvent: any): void => {\n\t\tconst outputBuffer = audioProcessingEvent.outputBuffer;\n\t\tconst outputDataL: Float32Array = outputBuffer.getChannelData(0);\n\t\tconst outputDataR: Float32Array = outputBuffer.getChannelData(1);\n\t\t\n\t\tif (this.browserAutomaticallyClearsAudioBuffer && (outputDataL[0] != 0.0 || outputDataR[0] != 0.0 || outputDataL[outputBuffer.length-1] != 0.0 || outputDataR[outputBuffer.length-1] != 0.0)) {\n\t\t\t// If the buffer is ever initially nonzero, then this must be an older browser that doesn't automatically clear the audio buffer.\n\t\t\tthis.browserAutomaticallyClearsAudioBuffer = false;\n\t\t}\n\t\tif (!this.browserAutomaticallyClearsAudioBuffer) {\n\t\t\t// If this browser does not clear the buffer automatically, do so manually before continuing.\n\t\t\tconst length: number = outputBuffer.length;\n\t\t\tfor (let i: number = 0; i < length; i++) {\n\t\t\t\toutputDataL[i] = 0.0;\n\t\t\t\toutputDataR[i] = 0.0;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (!this.isPlayingSong && performance.now() >= this.liveInputEndTime) {\n\t\t\tthis.deactivateAudio();\n\t\t} else {\n\t\t\tthis.synthesize(outputDataL, outputDataR, outputBuffer.length, this.isPlayingSong);\n\t\t}\n\t}\n\t\n\tpublic synthesize(outputDataL: Float32Array, outputDataR: Float32Array, outputBufferLength: number, playSong: boolean = true): void {\n\t\tif (this.song == null) {\n\t\t\tfor (let i: number = 0; i < outputBufferLength; i++) {\n\t\t\t\toutputDataL[i] = 0.0;\n\t\t\t\toutputDataR[i] = 0.0;\n\t\t\t}\n\t\t\tthis.deactivateAudio();\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tconst song: Song = this.song;\n\t\tconst samplesPerTick: number = this.getSamplesPerTick();\n\t\tlet ended: boolean = false;\n\t\t\n\t\t// Check the bounds of the playhead:\n\t\tif (this.tickSampleCountdown <= 0 || this.tickSampleCountdown > samplesPerTick) {\n\t\t\tthis.tickSampleCountdown = samplesPerTick;\n\t\t\tthis.isAtStartOfTick = true;\n\t\t}\n\t\tif (playSong) {\n\t\t\tif (this.beat >= song.beatsPerBar) {\n\t\t\t\tthis.beat = 0;\n\t\t\t\tthis.part = 0;\n\t\t\t\tthis.tick = 0;\n\t\t\t\tthis.tickSampleCountdown = samplesPerTick;\n\t\t\t\tthis.isAtStartOfTick = true;\n\t\t\t\t\n\t\t\t\tthis.prevBar = this.bar;\n\t\t\t\tthis.bar = this.getNextBar();\n\t\t\t\tif (this.bar <= this.prevBar && this.loopRepeatCount > 0) this.loopRepeatCount--;\n\t\t\t}\n\t\t\tif (this.bar >= song.barCount) {\n\t\t\t\tthis.bar = 0;\n\t\t\t\tif (this.loopRepeatCount != -1) {\n\t\t\t\t\tended = true;\n\t\t\t\t\tthis.pause();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t//const synthStartTime: number = performance.now();\n\t\t\n\t\tthis.syncSongState();\n\t\t\n\t\tif (this.tempMonoInstrumentSampleBuffer == null || this.tempMonoInstrumentSampleBuffer.length < outputBufferLength) {\n\t\t\tthis.tempMonoInstrumentSampleBuffer = new Float32Array(outputBufferLength);\n\t\t}\n\t\t\n\t\t// Post processing parameters:\n\t\tconst volume: number = +this.volume;\n\t\tconst limitDecay: number = 1.0 - Math.pow(0.5, 4.0 / this.samplesPerSecond);\n\t\tconst limitRise: number = 1.0 - Math.pow(0.5, 4000.0 / this.samplesPerSecond);\n\t\tlet limit: number = +this.limit;\n\t\t\n\t\tlet bufferIndex: number = 0;\n\t\twhile (bufferIndex < outputBufferLength && !ended) {\n\t\t\t\n\t\t\tthis.nextBar = this.getNextBar();\n\t\t\tif (this.nextBar >= song.barCount) this.nextBar = null;\n\t\t\t\n\t\t\tconst samplesLeftInBuffer: number = outputBufferLength - bufferIndex;\n\t\t\tconst samplesLeftInTick: number = Math.ceil(this.tickSampleCountdown);\n\t\t\tconst runLength: number = Math.min(samplesLeftInTick, samplesLeftInBuffer);\n\t\t\tconst runEnd: number = bufferIndex + runLength;\n\t\t\tfor (let channelIndex: number = 0; channelIndex < song.getChannelCount(); channelIndex++) {\n\t\t\t\tconst channel: Channel = song.channels[channelIndex];\n\t\t\t\tconst channelState: ChannelState = this.channels[channelIndex];\n\t\t\t\t\n\t\t\t\tif (this.isAtStartOfTick) {\n\t\t\t\t\tthis.determineCurrentActiveTones(song, channelIndex, samplesPerTick, playSong && !this.countInMetronome);\n\t\t\t\t\tthis.determineLiveInputTones(song, channelIndex, samplesPerTick);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (let instrumentIndex: number = 0; instrumentIndex < channel.instruments.length; instrumentIndex++) {\n\t\t\t\t\tconst instrument: Instrument = channel.instruments[instrumentIndex];\n\t\t\t\t\tconst instrumentState: InstrumentState = channelState.instruments[instrumentIndex];\n\t\t\t\t\t\n\t\t\t\t\tif (this.isAtStartOfTick) {\n\t\t\t\t\t\tlet tonesPlayedInThisInstrument: number = instrumentState.activeTones.count() + instrumentState.liveInputTones.count();\n\t\t\t\t\t\tfor (let i: number = 0; i < instrumentState.releasedTones.count(); i++) {\n\t\t\t\t\t\t\tconst tone: Tone = instrumentState.releasedTones.get(i);\n\t\t\t\t\t\t\tif (tone.ticksSinceReleased >= Math.abs(instrument.getFadeOutTicks())) {\n\t\t\t\t\t\t\t\tthis.freeReleasedTone(instrumentState, i);\n\t\t\t\t\t\t\t\ti--;\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst shouldFadeOutFast: boolean = (tonesPlayedInThisInstrument >= Config.maximumTonesPerChannel);\n\t\t\t\t\t\t\tthis.computeTone(song, channelIndex, samplesPerTick, tone, true, shouldFadeOutFast);\n\t\t\t\t\t\t\ttonesPlayedInThisInstrument++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (instrumentState.awake) {\n\t\t\t\t\t\t\tif (!instrumentState.computed) {\n\t\t\t\t\t\t\t\tinstrumentState.compute(this, instrument, samplesPerTick, Math.ceil(samplesPerTick), null);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tinstrumentState.computed = false;\n\t\t\t\t\t\t\t//instrumentState.envelopeComputer.clearEnvelopes();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor (let i: number = 0; i < instrumentState.activeTones.count(); i++) {\n\t\t\t\t\t\tconst tone: Tone = instrumentState.activeTones.get(i);\n\t\t\t\t\t\tthis.playTone(channelIndex, bufferIndex, runLength, tone);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor (let i: number = 0; i < instrumentState.liveInputTones.count(); i++) {\n\t\t\t\t\t\tconst tone: Tone = instrumentState.liveInputTones.get(i);\n\t\t\t\t\t\tthis.playTone(channelIndex, bufferIndex, runLength, tone);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor (let i: number = 0; i < instrumentState.releasedTones.count(); i++) {\n\t\t\t\t\t\tconst tone: Tone = instrumentState.releasedTones.get(i);\n\t\t\t\t\t\tthis.playTone(channelIndex, bufferIndex, runLength, tone);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (instrumentState.awake) {\n\t\t\t\t\t\tSynth.effectsSynth(this, outputDataL, outputDataR, bufferIndex, runLength, instrumentState);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (this.enableMetronome || this.countInMetronome) {\n\t\t\t\tif (this.part == 0) {\n\t\t\t\t\tif (!this.startedMetronome) {\n\t\t\t\t\t\tconst midBeat: boolean = (song.beatsPerBar > 4 && (song.beatsPerBar % 2 == 0) && this.beat == song.beatsPerBar / 2);\n\t\t\t\t\t\tconst periods: number = (this.beat == 0) ? 8 : midBeat ? 6 : 4;\n\t\t\t\t\t\tconst hz: number = (this.beat == 0) ? 1600 : midBeat ? 1200 : 800;\n\t\t\t\t\t\tconst amplitude: number = (this.beat == 0) ? 0.06 : midBeat ? 0.05 : 0.04;\n\t\t\t\t\t\tconst samplesPerPeriod: number = this.samplesPerSecond / hz;\n\t\t\t\t\t\tconst radiansPerSample: number = Math.PI * 2.0 / samplesPerPeriod;\n\t\t\t\t\t\tthis.metronomeSamplesRemaining = Math.floor(samplesPerPeriod * periods);\n\t\t\t\t\t\tthis.metronomeFilter = 2.0 * Math.cos(radiansPerSample);\n\t\t\t\t\t\tthis.metronomeAmplitude = amplitude * Math.sin(radiansPerSample);\n\t\t\t\t\t\tthis.metronomePrevAmplitude = 0.0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tthis.startedMetronome = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (this.metronomeSamplesRemaining > 0) {\n\t\t\t\t\t\tconst stopIndex: number = Math.min(runEnd, bufferIndex + this.metronomeSamplesRemaining);\n\t\t\t\t\t\tthis.metronomeSamplesRemaining -= stopIndex - bufferIndex;\n\t\t\t\t\t\tfor (let i: number = bufferIndex; i < stopIndex; i++) {\n\t\t\t\t\t\t\toutputDataL[i] += this.metronomeAmplitude;\n\t\t\t\t\t\t\toutputDataR[i] += this.metronomeAmplitude;\n\t\t\t\t\t\t\tconst tempAmplitude: number = this.metronomeFilter * this.metronomeAmplitude - this.metronomePrevAmplitude;\n\t\t\t\t\t\t\tthis.metronomePrevAmplitude = this.metronomeAmplitude;\n\t\t\t\t\t\t\tthis.metronomeAmplitude = tempAmplitude;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.startedMetronome = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Post processing:\n\t\t\tfor (let i: number = bufferIndex; i < runEnd; i++) {\n\t\t\t\t// A compressor/limiter.\n\t\t\t\tconst sampleL = outputDataL[i];\n\t\t\t\tconst sampleR = outputDataR[i];\n\t\t\t\tconst abs: number = Math.max(Math.abs(sampleL), Math.abs(sampleR));\n\t\t\t\tlimit += (abs - limit) * (limit < abs ? limitRise : limitDecay * (1.0 + limit));\n\t\t\t\tconst limitedVolume = volume / (limit >= 1 ? limit * 1.05 : limit * 0.8 + 0.25);\n\t\t\t\toutputDataL[i] = sampleL * limitedVolume;\n\t\t\t\toutputDataR[i] = sampleR * limitedVolume;\n\t\t\t}\n\t\t\t\n\t\t\tbufferIndex += runLength;\n\t\t\t\n\t\t\tthis.isAtStartOfTick = false;\n\t\t\tthis.tickSampleCountdown -= runLength;\n\t\t\tif (this.tickSampleCountdown <= 0) {\n\t\t\t\tthis.isAtStartOfTick = true;\n\t\t\t\t\n\t\t\t\t// Track how long tones have been released, and free ones that are marked as ending.\n\t\t\t\t// Also reset awake InstrumentStates that didn't have any Tones during this tick.\n\t\t\t\tfor (const channelState of this.channels) {\n\t\t\t\t\tfor (const instrumentState of channelState.instruments) {\n\t\t\t\t\t\tfor (let i: number = 0; i < instrumentState.releasedTones.count(); i++) {\n\t\t\t\t\t\t\tconst tone: Tone = instrumentState.releasedTones.get(i);\n\t\t\t\t\t\t\tif (tone.isOnLastTick) {\n\t\t\t\t\t\t\t\tthis.freeReleasedTone(instrumentState, i);\n\t\t\t\t\t\t\t\ti--;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\ttone.ticksSinceReleased++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (instrumentState.deactivateAfterThisTick) {\n\t\t\t\t\t\t\tinstrumentState.deactivate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinstrumentState.tonesAddedInThisTick = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tthis.tick++;\n\t\t\t\tthis.tickSampleCountdown += samplesPerTick;\n\t\t\t\tif (this.tick == Config.ticksPerPart) {\n\t\t\t\t\tthis.tick = 0;\n\t\t\t\t\tthis.part++;\n\t\t\t\t\tthis.liveInputDuration--;\n\t\t\t\t\t\n\t\t\t\t\tif (this.part == Config.partsPerBeat) {\n\t\t\t\t\t\tthis.part = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (playSong) {\n\t\t\t\t\t\t\tthis.beat++;\n\t\t\t\t\t\t\tif (this.beat == song.beatsPerBar) {\n\t\t\t\t\t\t\t\t// bar changed, reset for next bar:\n\t\t\t\t\t\t\t\tthis.beat = 0;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (this.countInMetronome) {\n\t\t\t\t\t\t\t\t\tthis.countInMetronome = false;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tthis.prevBar = this.bar;\n\t\t\t\t\t\t\t\t\tthis.bar = this.getNextBar();\n\t\t\t\t\t\t\t\t\tif (this.bar <= this.prevBar && this.loopRepeatCount > 0) this.loopRepeatCount--;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (this.bar >= song.barCount) {\n\t\t\t\t\t\t\t\t\t\tthis.bar = 0;\n\t\t\t\t\t\t\t\t\t\tif (this.loopRepeatCount != -1) {\n\t\t\t\t\t\t\t\t\t\t\tended = true;\n\t\t\t\t\t\t\t\t\t\t\tthis.resetEffects();\n\t\t\t\t\t\t\t\t\t\t\tthis.pause();\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Avoid persistent denormal or NaN values.\n\t\tif (!Number.isFinite(limit) || Math.abs(limit) < epsilon) limit = 0.0;\n\t\tthis.limit = limit;\n\t\t\n\t\tif (playSong && !this.countInMetronome) {\n\t\t\tthis.playheadInternal = (((this.tick + 1.0 - this.tickSampleCountdown / samplesPerTick) / 2.0 + this.part) / Config.partsPerBeat + this.beat) / song.beatsPerBar + this.bar;\n\t\t}\n\t\t\n\t\t/*\n\t\tconst synthDuration: number = performance.now() - synthStartTime;\n\t\t// Performance measurements:\n\t\tsamplesAccumulated += outputBufferLength;\n\t\tsamplePerformance += synthDuration;\n\t\t\n\t\tif (samplesAccumulated >= 44100 * 4) {\n\t\t\tconst secondsGenerated = samplesAccumulated / 44100;\n\t\t\tconst secondsRequired = samplePerformance / 1000;\n\t\t\tconst ratio = secondsRequired / secondsGenerated;\n\t\t\tconsole.log(ratio);\n\t\t\tsamplePerformance = 0;\n\t\t\tsamplesAccumulated = 0;\n\t\t}\n\t\t*/\n\t}\n\t\n\tprivate freeTone(tone: Tone): void {\n\t\tthis.tonePool.pushBack(tone);\n\t}\n\t\n\tprivate newTone(): Tone {\n\t\tif (this.tonePool.count() > 0) {\n\t\t\tconst tone: Tone = this.tonePool.popBack();\n\t\t\ttone.freshlyAllocated = true;\n\t\t\treturn tone;\n\t\t}\n\t\treturn new Tone();\n\t}\n\t\n\tprivate releaseTone(instrumentState: InstrumentState, tone: Tone): void {\n\t\tinstrumentState.releasedTones.pushFront(tone);\n\t\ttone.atNoteStart = false;\n\t\ttone.passedEndOfNote = true;\n\t}\n\t\n\tprivate freeReleasedTone(instrumentState: InstrumentState, toneIndex: number): void {\n\t\tthis.freeTone(instrumentState.releasedTones.get(toneIndex));\n\t\tinstrumentState.releasedTones.remove(toneIndex);\n\t}\n\t\n\tpublic freeAllTones(): void {\n\t\tfor (const channelState of this.channels) {\n\t\t\tfor (const instrumentState of channelState.instruments) {\n\t\t\t\twhile (instrumentState.activeTones.count() > 0) this.freeTone(instrumentState.activeTones.popBack());\n\t\t\t\twhile (instrumentState.releasedTones.count() > 0) this.freeTone(instrumentState.releasedTones.popBack());\n\t\t\t\twhile (instrumentState.liveInputTones.count() > 0) this.freeTone(instrumentState.liveInputTones.popBack());\n\t\t\t}\n\t\t}\n\t}\n\t\n\tprivate determineLiveInputTones(song: Song, channelIndex: number, samplesPerTick: number): void {\n\t\tconst channel: Channel = song.channels[channelIndex];\n\t\tconst channelState: ChannelState = this.channels[channelIndex];\n\t\tconst pitches: number[] = this.liveInputPitches;\n\t\t\n\t\tfor (let instrumentIndex: number = 0; instrumentIndex < channel.instruments.length; instrumentIndex++) {\n\t\t\tconst instrumentState: InstrumentState = channelState.instruments[instrumentIndex];\n\t\t\tconst toneList: Deque<Tone> = instrumentState.liveInputTones;\n\t\t\tlet toneCount: number = 0;\n\t\t\tif (this.liveInputDuration > 0 && channelIndex == this.liveInputChannel && pitches.length > 0 && this.liveInputInstruments.indexOf(instrumentIndex) != -1) {\n\t\t\t\tconst instrument: Instrument = channel.instruments[instrumentIndex];\n\t\t\t\t\n\t\t\t\tif (instrument.getChord().singleTone) {\n\t\t\t\t\tlet tone: Tone;\n\t\t\t\t\tif (toneList.count() <= toneCount) {\n\t\t\t\t\t\ttone = this.newTone();\n\t\t\t\t\t\ttoneList.pushBack(tone);\n\t\t\t\t\t} else if (!instrument.getTransition().isSeamless && this.liveInputStarted) {\n\t\t\t\t\t\tthis.releaseTone(instrumentState, toneList.get(toneCount));\n\t\t\t\t\t\ttone = this.newTone();\n\t\t\t\t\t\ttoneList.set(toneCount, tone);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttone = toneList.get(toneCount);\n\t\t\t\t\t}\n\t\t\t\t\ttoneCount++;\n\t\t\t\t\t\n\t\t\t\t\tfor (let i: number = 0; i < pitches.length; i++) {\n\t\t\t\t\t\ttone.pitches[i] = pitches[i];\n\t\t\t\t\t}\n\t\t\t\t\ttone.pitchCount = pitches.length;\n\t\t\t\t\ttone.chordSize = 1;\n\t\t\t\t\ttone.instrumentIndex = instrumentIndex;\n\t\t\t\t\ttone.note = tone.prevNote = tone.nextNote = null;\n\t\t\t\t\ttone.atNoteStart = this.liveInputStarted;\n\t\t\t\t\ttone.forceContinueAtStart = false;\n\t\t\t\t\ttone.forceContinueAtEnd = false;\n\t\t\t\t\tthis.computeTone(song, channelIndex, samplesPerTick, tone, false, false);\n\t\t\t\t} else {\n\t\t\t\t\t//const transition: Transition = instrument.getTransition();\n\t\t\t\t\t\n\t\t\t\t\tthis.moveTonesIntoOrderedTempMatchedList(toneList, pitches);\n\t\t\t\t\t\n\t\t\t\t\tfor (let i: number = 0; i < pitches.length; i++) {\n\t\t\t\t\t\t//const strumOffsetParts: number = i * instrument.getChord().strumParts;\n\t\t\t\t\t\t\n\t\t\t\t\t\tlet tone: Tone;\n\t\t\t\t\t\tif (this.tempMatchedPitchTones[toneCount] != null) {\n\t\t\t\t\t\t\ttone = this.tempMatchedPitchTones[toneCount]!;\n\t\t\t\t\t\t\tthis.tempMatchedPitchTones[toneCount] = null;\n\t\t\t\t\t\t\tif (tone.pitchCount != 1 || tone.pitches[0] != pitches[i]) {\n\t\t\t\t\t\t\t\tthis.releaseTone(instrumentState, tone);\n\t\t\t\t\t\t\t\ttone = this.newTone();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttoneList.pushBack(tone);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttone = this.newTone();\n\t\t\t\t\t\t\ttoneList.pushBack(tone);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttoneCount++;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttone.pitches[0] = pitches[i];\n\t\t\t\t\t\ttone.pitchCount = 1;\n\t\t\t\t\t\ttone.chordSize = pitches.length;\n\t\t\t\t\t\ttone.instrumentIndex = instrumentIndex;\n\t\t\t\t\t\ttone.note = tone.prevNote = tone.nextNote = null;\n\t\t\t\t\t\ttone.atNoteStart = this.liveInputStarted;\n\t\t\t\t\t\ttone.forceContinueAtStart = false;\n\t\t\t\t\t\ttone.forceContinueAtEnd = false;\n\t\t\t\t\t\tthis.computeTone(song, channelIndex, samplesPerTick, tone, false, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\twhile (toneList.count() > toneCount) {\n\t\t\t\tthis.releaseTone(instrumentState, toneList.popBack());\n\t\t\t}\n\t\t\t\n\t\t\tthis.clearTempMatchedPitchTones(toneCount, instrumentState);\n\t\t}\n\t\t\n\t\tthis.liveInputStarted = false;\n\t}\n\t\n\t// Returns the chord type of the instrument in the adjacent pattern if it is compatible for a\n\t// seamless transition across patterns, otherwise returns null.\n\tprivate adjacentPatternHasCompatibleInstrumentTransition(song: Song, channel: Channel, pattern: Pattern, otherPattern: Pattern, instrumentIndex: number, transition: Transition, chord: Chord, note: Note, otherNote: Note, forceContinue: boolean): Chord | null {\n\t\tif (song.patternInstruments && otherPattern.instruments.indexOf(instrumentIndex) == -1) {\n\t\t\t// The adjacent pattern does not contain the same instrument as the current pattern.\n\t\t\t\n\t\t\tif (pattern.instruments.length > 1 || otherPattern.instruments.length > 1) {\n\t\t\t\t// The current or adjacent pattern contains more than one instrument, don't bother\n\t\t\t\t// trying to connect them.\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// Otherwise, the two patterns each contain one instrument, but not the same instrument.\n\t\t\t// Try to connect them.\n\t\t\tconst otherInstrument: Instrument = channel.instruments[otherPattern.instruments[0]];\n\t\t\t\n\t\t\tif (forceContinue) {\n\t\t\t\t// Even non-seamless instruments can be connected across patterns if forced.\n\t\t\t\treturn otherInstrument.getChord();\n\t\t\t}\n\t\t\t\n\t\t\t// Otherwise, check that both instruments are seamless across patterns.\n\t\t\tconst otherTransition: Transition = otherInstrument.getTransition();\n\t\t\tif (transition.includeAdjacentPatterns && otherTransition.includeAdjacentPatterns && otherTransition.slides == transition.slides) {\n\t\t\t\treturn otherInstrument.getChord();\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else {\n\t\t\t// If both patterns contain the same instrument, check that it is seamless across patterns.\n\t\t\treturn (forceContinue || transition.includeAdjacentPatterns) ? chord : null;\n\t\t}\n\t}\n\t\n\tpublic static adjacentNotesHaveMatchingPitches(firstNote: Note, secondNote: Note): boolean {\n\t\tif (firstNote.pitches.length != secondNote.pitches.length) return false;\n\t\tconst firstNoteInterval: number = firstNote.pins[firstNote.pins.length - 1].interval;\n\t\tfor (const pitch of firstNote.pitches) {\n\t\t\tif (secondNote.pitches.indexOf(pitch + firstNoteInterval) == -1) return false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate moveTonesIntoOrderedTempMatchedList(toneList: Deque<Tone>, notePitches: number[]): void {\n\t\t// The tones are about to seamlessly transition to a new note. The pitches\n\t\t// from the old note may or may not match any of the pitches in the new\n\t\t// note, and not necessarily in order, but if any do match, they'll sound\n\t\t// better if those tones continue to have the same pitch. Attempt to find\n\t\t// the right spot for each old tone in the new chord if possible.\n\t\t\n\t\tfor (let i: number = 0; i < toneList.count(); i++) {\n\t\t\tconst tone: Tone = toneList.get(i);\n\t\t\tconst pitch: number = tone.pitches[0] + tone.lastInterval;\n\t\t\tfor (let j: number = 0; j < notePitches.length; j++) {\n\t\t\t\tif (notePitches[j] == pitch) {\n\t\t\t\t\tthis.tempMatchedPitchTones[j] = tone;\n\t\t\t\t\ttoneList.remove(i);\n\t\t\t\t\ti--;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Any tones that didn't get matched should just fill in the gaps.\n\t\twhile (toneList.count() > 0) {\n\t\t\tconst tone: Tone = toneList.popFront();\n\t\t\tfor (let j: number = 0; j < this.tempMatchedPitchTones.length; j++) {\n\t\t\t\tif (this.tempMatchedPitchTones[j] == null) {\n\t\t\t\t\tthis.tempMatchedPitchTones[j] = tone;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tprivate determineCurrentActiveTones(song: Song, channelIndex: number, samplesPerTick: number, playSong: boolean): void {\n\t\tconst channel: Channel = song.channels[channelIndex];\n\t\tconst channelState: ChannelState = this.channels[channelIndex];\n\t\tconst pattern: Pattern | null = song.getPattern(channelIndex, this.bar);\n\t\tconst currentPart: number = this.getCurrentPart();\n\t\tconst currentTick: number = this.tick + Config.ticksPerPart * currentPart;\n\t\tlet note: Note | null = null;\n\t\tlet prevNote: Note | null = null;\n\t\tlet nextNote: Note | null = null;\n\t\t\n\t\tif (playSong && pattern != null && !channel.muted && (!this.isRecording || this.liveInputChannel != channelIndex)) {\n\t\t\tfor (let i: number = 0; i < pattern.notes.length; i++) {\n\t\t\t\tif (pattern.notes[i].end <= currentPart) {\n\t\t\t\t\tprevNote = pattern.notes[i];\n\t\t\t\t} else if (pattern.notes[i].start <= currentPart && pattern.notes[i].end > currentPart) {\n\t\t\t\t\tnote = pattern.notes[i];\n\t\t\t\t} else if (pattern.notes[i].start > currentPart) {\n\t\t\t\t\tnextNote = pattern.notes[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (note != null) {\n\t\t\t\tif (prevNote != null && prevNote.end != note.start) prevNote = null;\n\t\t\t\tif (nextNote != null && nextNote.start != note.end) nextNote = null;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Seamless tones from a pattern with a single instrument can be transferred to a different single seamless instrument in the next pattern.\n\t\tif (pattern != null && (!song.layeredInstruments || channel.instruments.length == 1 || (song.patternInstruments && pattern.instruments.length == 1))) {\n\t\t\tconst newInstrumentIndex: number = song.patternInstruments ? pattern.instruments[0] : 0;\n\t\t\tif (channelState.singleSeamlessInstrument != null && channelState.singleSeamlessInstrument != newInstrumentIndex && channelState.singleSeamlessInstrument < channelState.instruments.length) {\n\t\t\t\tconst sourceInstrumentState: InstrumentState = channelState.instruments[channelState.singleSeamlessInstrument];\n\t\t\t\tconst destInstrumentState: InstrumentState = channelState.instruments[newInstrumentIndex];\n\t\t\t\twhile (sourceInstrumentState.activeTones.count() > 0) {\n\t\t\t\t\tdestInstrumentState.activeTones.pushFront(sourceInstrumentState.activeTones.popBack());\n\t\t\t\t}\n\t\t\t}\n\t\t\tchannelState.singleSeamlessInstrument = newInstrumentIndex;\n\t\t} else {\n\t\t\tchannelState.singleSeamlessInstrument = null;\n\t\t}\n\t\t\n\t\tfor (let instrumentIndex: number = 0; instrumentIndex < channel.instruments.length; instrumentIndex++) {\n\t\t\tconst instrumentState: InstrumentState = channelState.instruments[instrumentIndex];\n\t\t\tconst toneList: Deque<Tone> = instrumentState.activeTones;\n\t\t\tlet toneCount: number = 0;\n\t\t\tif ((note != null) && (!song.patternInstruments || (pattern!.instruments.indexOf(instrumentIndex) != -1))) {\n\t\t\t\tconst instrument: Instrument = channel.instruments[instrumentIndex];\n\t\t\t\tlet prevNoteForThisInstrument: Note | null = prevNote;\n\t\t\t\tlet nextNoteForThisInstrument: Note | null = nextNote;\n\t\t\t\t\n\t\t\t\tconst partsPerBar: Number = Config.partsPerBeat * song.beatsPerBar;\n\t\t\t\tconst transition: Transition = instrument.getTransition();\n\t\t\t\tconst chord: Chord = instrument.getChord();\n\t\t\t\tlet forceContinueAtStart: boolean = false;\n\t\t\t\tlet forceContinueAtEnd: boolean = false;\n\t\t\t\tlet tonesInPrevNote: number = 0;\n\t\t\t\tlet tonesInNextNote: number = 0;\n\t\t\t\tif (note.start == 0) {\n\t\t\t\t\t// If the beginning of the note coincides with the beginning of the pattern,\n\t\t\t\t\t// look for an adjacent note at the end of the previous pattern.\n\t\t\t\t\tlet prevPattern: Pattern | null = (this.prevBar == null) ? null : song.getPattern(channelIndex, this.prevBar);\n\t\t\t\t\tif (prevPattern != null) {\n\t\t\t\t\t\tconst lastNote: Note | null = (prevPattern.notes.length <= 0) ? null : prevPattern.notes[prevPattern.notes.length - 1];\n\t\t\t\t\t\tif (lastNote != null && lastNote.end == partsPerBar) {\n\t\t\t\t\t\t\tconst patternForcesContinueAtStart: boolean = note.continuesLastPattern && Synth.adjacentNotesHaveMatchingPitches(lastNote, note);\n\t\t\t\t\t\t\tconst chordOfCompatibleInstrument: Chord | null = this.adjacentPatternHasCompatibleInstrumentTransition(song, channel, pattern!, prevPattern, instrumentIndex, transition, chord, note, lastNote, patternForcesContinueAtStart);\n\t\t\t\t\t\t\tif (chordOfCompatibleInstrument != null) {\n\t\t\t\t\t\t\t\tprevNoteForThisInstrument = lastNote;\n\t\t\t\t\t\t\t\ttonesInPrevNote = chordOfCompatibleInstrument.singleTone ? 1 : prevNoteForThisInstrument.pitches.length\n\t\t\t\t\t\t\t\tforceContinueAtStart = patternForcesContinueAtStart;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (prevNoteForThisInstrument != null) {\n\t\t\t\t\ttonesInPrevNote = chord.singleTone ? 1 : prevNoteForThisInstrument.pitches.length\n\t\t\t\t}\n\t\t\t\tif (note.end == partsPerBar) {\n\t\t\t\t\t// If the end of the note coincides with the end of the pattern, look for an\n\t\t\t\t\t// adjacent note at the beginning of the next pattern.\n\t\t\t\t\tlet nextPattern: Pattern | null = (this.nextBar == null) ? null : song.getPattern(channelIndex, this.nextBar);\n\t\t\t\t\tif (nextPattern != null) {\n\t\t\t\t\t\tconst firstNote: Note | null = (nextPattern.notes.length <= 0) ? null : nextPattern.notes[0];\n\t\t\t\t\t\tif (firstNote != null && firstNote.start == 0) {\n\t\t\t\t\t\t\tconst nextPatternForcesContinueAtStart: boolean = firstNote.continuesLastPattern && Synth.adjacentNotesHaveMatchingPitches(note, firstNote);\n\t\t\t\t\t\t\tconst chordOfCompatibleInstrument: Chord | null = this.adjacentPatternHasCompatibleInstrumentTransition(song, channel, pattern!, nextPattern, instrumentIndex, transition, chord, note, firstNote, nextPatternForcesContinueAtStart);\n\t\t\t\t\t\t\tif (chordOfCompatibleInstrument != null) {\n\t\t\t\t\t\t\t\tnextNoteForThisInstrument = firstNote;\n\t\t\t\t\t\t\t\ttonesInNextNote = chordOfCompatibleInstrument.singleTone ? 1 : nextNoteForThisInstrument.pitches.length\n\t\t\t\t\t\t\t\tforceContinueAtEnd = nextPatternForcesContinueAtStart;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (nextNoteForThisInstrument != null) {\n\t\t\t\t\ttonesInNextNote = chord.singleTone ? 1 : nextNoteForThisInstrument.pitches.length\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (chord.singleTone) {\n\t\t\t\t\tconst atNoteStart: boolean = (Config.ticksPerPart * note.start == currentTick);\n\t\t\t\t\tlet tone: Tone;\n\t\t\t\t\tif (toneList.count() <= toneCount) {\n\t\t\t\t\t\ttone = this.newTone();\n\t\t\t\t\t\ttoneList.pushBack(tone);\n\t\t\t\t\t} else if (atNoteStart && ((!transition.isSeamless && !forceContinueAtStart) || prevNoteForThisInstrument == null)) {\n\t\t\t\t\t\tconst oldTone: Tone = toneList.get(toneCount);\n\t\t\t\t\t\tif (oldTone.isOnLastTick) {\n\t\t\t\t\t\t\tthis.freeTone(oldTone);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.releaseTone(instrumentState, oldTone);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttone = this.newTone();\n\t\t\t\t\t\ttoneList.set(toneCount, tone);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttone = toneList.get(toneCount);\n\t\t\t\t\t}\n\t\t\t\t\ttoneCount++;\n\t\t\t\t\t\n\t\t\t\t\tfor (let i: number = 0; i < note.pitches.length; i++) {\n\t\t\t\t\t\ttone.pitches[i] = note.pitches[i];\n\t\t\t\t\t}\n\t\t\t\t\ttone.pitchCount = note.pitches.length;\n\t\t\t\t\ttone.chordSize = 1;\n\t\t\t\t\ttone.instrumentIndex = instrumentIndex;\n\t\t\t\t\ttone.note = note;\n\t\t\t\t\ttone.noteStartPart = note.start;\n\t\t\t\t\ttone.noteEndPart = note.end;\n\t\t\t\t\ttone.prevNote = prevNoteForThisInstrument;\n\t\t\t\t\ttone.nextNote = nextNoteForThisInstrument;\n\t\t\t\t\ttone.prevNotePitchIndex = 0;\n\t\t\t\t\ttone.nextNotePitchIndex = 0;\n\t\t\t\t\ttone.atNoteStart = atNoteStart;\n\t\t\t\t\ttone.passedEndOfNote = false;\n\t\t\t\t\ttone.forceContinueAtStart = forceContinueAtStart;\n\t\t\t\t\ttone.forceContinueAtEnd = forceContinueAtEnd;\n\t\t\t\t\tthis.computeTone(song, channelIndex, samplesPerTick, tone, false, false);\n\t\t\t\t} else {\n\t\t\t\t\tconst transition: Transition = instrument.getTransition();\n\t\t\t\t\t\n\t\t\t\t\tif (((transition.isSeamless && !transition.slides && chord.strumParts == 0) || forceContinueAtStart) && (Config.ticksPerPart * note.start == currentTick) && prevNoteForThisInstrument != null) {\n\t\t\t\t\t\tthis.moveTonesIntoOrderedTempMatchedList(toneList, note.pitches);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlet strumOffsetParts: number = 0;\n\t\t\t\t\tfor (let i: number = 0; i < note.pitches.length; i++) {\n\t\t\t\t\t\t\n\t\t\t\t\t\tlet prevNoteForThisTone: Note | null = (tonesInPrevNote > i) ? prevNoteForThisInstrument : null;\n\t\t\t\t\t\tlet noteForThisTone: Note = note;\n\t\t\t\t\t\tlet nextNoteForThisTone: Note | null = (tonesInNextNote > i) ? nextNoteForThisInstrument : null;\n\t\t\t\t\t\tlet noteStartPart: number = noteForThisTone.start + strumOffsetParts;\n\t\t\t\t\t\tlet passedEndOfNote: boolean = false;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Strumming may mean that a note's actual start time may be after the\n\t\t\t\t\t\t// note's displayed start time. If the note start hasn't been reached yet,\n\t\t\t\t\t\t// carry over the previous tone if available and seamless, otherwise skip\n\t\t\t\t\t\t// the new tone until it is ready to start.\n\t\t\t\t\t\tif (noteStartPart > currentPart) {\n\t\t\t\t\t\t\tif (toneList.count() > i && (transition.isSeamless || forceContinueAtStart) && prevNoteForThisTone != null) {\n\t\t\t\t\t\t\t\t// Continue the previous note's chord until the current one takes over.\n\t\t\t\t\t\t\t\tnextNoteForThisTone = noteForThisTone;\n\t\t\t\t\t\t\t\tnoteForThisTone = prevNoteForThisTone;\n\t\t\t\t\t\t\t\tprevNoteForThisTone = null;\n\t\t\t\t\t\t\t\tnoteStartPart = noteForThisTone.start + strumOffsetParts;\n\t\t\t\t\t\t\t\tpassedEndOfNote = true;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// This and the rest of the tones in the chord shouldn't start yet.\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tlet noteEndPart: number = noteForThisTone.end;\n\t\t\t\t\t\tif ((transition.isSeamless || forceContinueAtStart) && nextNoteForThisTone != null) {\n\t\t\t\t\t\t\tnoteEndPart = Math.min(Config.partsPerBeat * this.song!.beatsPerBar, noteEndPart + strumOffsetParts);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ((!transition.continues && !forceContinueAtStart) || prevNoteForThisTone == null) {\n\t\t\t\t\t\t\tstrumOffsetParts += chord.strumParts;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst atNoteStart: boolean = (Config.ticksPerPart * noteStartPart == currentTick);\n\t\t\t\t\t\tlet tone: Tone;\n\t\t\t\t\t\tif (this.tempMatchedPitchTones[toneCount] != null) {\n\t\t\t\t\t\t\ttone = this.tempMatchedPitchTones[toneCount]!;\n\t\t\t\t\t\t\tthis.tempMatchedPitchTones[toneCount] = null;\n\t\t\t\t\t\t\ttoneList.pushBack(tone);\n\t\t\t\t\t\t} else if (toneList.count() <= toneCount) {\n\t\t\t\t\t\t\ttone = this.newTone();\n\t\t\t\t\t\t\ttoneList.pushBack(tone);\n\t\t\t\t\t\t} else if (atNoteStart && ((!transition.isSeamless && !forceContinueAtStart) || prevNoteForThisTone == null)) {\n\t\t\t\t\t\t\tconst oldTone: Tone = toneList.get(toneCount);\n\t\t\t\t\t\t\tif (oldTone.isOnLastTick) {\n\t\t\t\t\t\t\t\tthis.freeTone(oldTone);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.releaseTone(instrumentState, oldTone);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttone = this.newTone();\n\t\t\t\t\t\t\ttoneList.set(toneCount, tone);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttone = toneList.get(toneCount);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttoneCount++;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttone.pitches[0] = noteForThisTone.pitches[i];\n\t\t\t\t\t\ttone.pitchCount = 1;\n\t\t\t\t\t\ttone.chordSize = noteForThisTone.pitches.length;\n\t\t\t\t\t\ttone.instrumentIndex = instrumentIndex;\n\t\t\t\t\t\ttone.note = noteForThisTone;\n\t\t\t\t\t\ttone.noteStartPart = noteStartPart;\n\t\t\t\t\t\ttone.noteEndPart = noteEndPart;\n\t\t\t\t\t\ttone.prevNote = prevNoteForThisTone;\n\t\t\t\t\t\ttone.nextNote = nextNoteForThisTone;\n\t\t\t\t\t\ttone.prevNotePitchIndex = i;\n\t\t\t\t\t\ttone.nextNotePitchIndex = i;\n\t\t\t\t\t\ttone.atNoteStart = atNoteStart;\n\t\t\t\t\t\ttone.passedEndOfNote = passedEndOfNote;\n\t\t\t\t\t\ttone.forceContinueAtStart = forceContinueAtStart && prevNoteForThisTone != null;\n\t\t\t\t\t\ttone.forceContinueAtEnd = forceContinueAtEnd && nextNoteForThisTone != null;\n\t\t\t\t\t\tthis.computeTone(song, channelIndex, samplesPerTick, tone, false, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Automatically free or release seamless tones if there's no new note to take over.\n\t\t\twhile (toneList.count() > toneCount) {\n\t\t\t\tconst tone: Tone = toneList.popBack();\n\t\t\t\tconst channel: Channel = song.channels[channelIndex];\n\t\t\t\tif (tone.instrumentIndex < channel.instruments.length && !tone.isOnLastTick) {\n\t\t\t\t\tconst instrumentState: InstrumentState = channelState.instruments[tone.instrumentIndex];\n\t\t\t\t\tthis.releaseTone(instrumentState, tone);\n\t\t\t\t} else {\n\t\t\t\t\tthis.freeTone(tone);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tthis.clearTempMatchedPitchTones(toneCount, instrumentState);\n\t\t}\n\t}\n\t\n\tprivate clearTempMatchedPitchTones(toneCount: number, instrumentState: InstrumentState): void {\n\t\tfor (let i: number = toneCount; i < this.tempMatchedPitchTones.length; i++) {\n\t\t\tconst oldTone: Tone | null = this.tempMatchedPitchTones[i];\n\t\t\tif (oldTone != null) {\n\t\t\t\tif (oldTone.isOnLastTick) {\n\t\t\t\t\tthis.freeTone(oldTone);\n\t\t\t\t} else {\n\t\t\t\t\tthis.releaseTone(instrumentState, oldTone);\n\t\t\t\t}\n\t\t\t\tthis.tempMatchedPitchTones[i] = null;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tprivate playTone(channelIndex: number, bufferIndex: number, runLength: number, tone: Tone): void {\n\t\tconst channelState: ChannelState = this.channels[channelIndex];\n\t\tconst instrumentState: InstrumentState = channelState.instruments[tone.instrumentIndex];\n\t\t\n\t\tinstrumentState.synthesizer!(this, bufferIndex, runLength, tone, instrumentState);\n\t\ttone.envelopeComputer.clearEnvelopes();\n\t}\n\t\n\tprivate static computeChordExpression(chordSize: number): number {\n\t\treturn 1.0 / ((chordSize - 1) * 0.25 + 1.0);\n\t}\n\t\n\tprivate computeTone(song: Song, channelIndex: number, samplesPerTick: number, tone: Tone, released: boolean, shouldFadeOutFast: boolean): void {\n\t\tconst roundedSamplesPerTick: number = Math.ceil(samplesPerTick);\n\t\tconst channel: Channel = song.channels[channelIndex];\n\t\tconst channelState: ChannelState = this.channels[channelIndex];\n\t\tconst instrument: Instrument = channel.instruments[tone.instrumentIndex];\n\t\tconst instrumentState: InstrumentState = channelState.instruments[tone.instrumentIndex];\n\t\tinstrumentState.awake = true;\n\t\tinstrumentState.tonesAddedInThisTick = true;\n\t\tif (!instrumentState.computed) {\n\t\t\tinstrumentState.compute(this, instrument, samplesPerTick, roundedSamplesPerTick, tone);\n\t\t}\n\t\tconst isNoiseChannel: boolean = song.getChannelIsNoise(channelIndex);\n\t\tconst transition: Transition = instrument.getTransition();\n\t\tconst chord: Chord = instrument.getChord();\n\t\tconst chordExpression: number = chord.singleTone ? 1.0 : Synth.computeChordExpression(tone.chordSize);\n\t\tconst intervalScale: number = isNoiseChannel ? Config.noiseInterval : 1;\n\t\tconst secondsPerPart: number = Config.ticksPerPart * samplesPerTick / this.samplesPerSecond;\n\t\tconst sampleTime: number = 1.0 / this.samplesPerSecond;\n\t\tconst beatsPerPart: number = 1.0 / Config.partsPerBeat;\n\t\tconst ticksIntoBar: number = this.getTicksIntoBar();\n\t\tconst partTimeStart: number = (ticksIntoBar ) / Config.ticksPerPart;\n\t\tconst partTimeEnd: number = (ticksIntoBar + 1.0) / Config.ticksPerPart;\n\t\tconst currentPart: number = this.getCurrentPart();\n\t\t\n\t\tlet specialIntervalMult: number = 1.0;\n\t\ttone.specialIntervalExpressionMult = 1.0;\n\t\t\n\t\tlet toneIsOnLastTick: boolean = shouldFadeOutFast;\n\t\tlet intervalStart: number = 0.0;\n\t\tlet intervalEnd: number = 0.0;\n\t\tlet fadeExpressionStart: number = 1.0;\n\t\tlet fadeExpressionEnd: number = 1.0;\n\t\tlet chordExpressionStart: number = chordExpression;\n\t\tlet chordExpressionEnd: number = chordExpression;\n\t\t\n\t\tlet expressionReferencePitch: number = 16; // A low \"E\" as a MIDI pitch.\n\t\tlet basePitch: number = Config.keys[song.key].basePitch;\n\t\tlet baseExpression: number = 1.0;\n\t\tlet pitchDamping: number = 48;\n\t\tif (instrument.type == InstrumentType.spectrum) {\n\t\t\tbaseExpression = Config.spectrumBaseExpression;\n\t\t\tif (isNoiseChannel) {\n\t\t\t\tbasePitch = Config.spectrumBasePitch;\n\t\t\t\tbaseExpression *= 2.0; // Note: spectrum is louder for drum channels than pitch channels!\n\t\t\t}\n\t\t\texpressionReferencePitch = Config.spectrumBasePitch;\n\t\t\tpitchDamping = 28;\n\t\t} else if (instrument.type == InstrumentType.drumset) {\n\t\t\tbasePitch = Config.spectrumBasePitch;\n\t\t\tbaseExpression = Config.drumsetBaseExpression;\n\t\t\texpressionReferencePitch = basePitch;\n\t\t} else if (instrument.type == InstrumentType.noise) {\n\t\t\tbasePitch = Config.chipNoises[instrument.chipNoise].basePitch;\n\t\t\tbaseExpression = Config.noiseBaseExpression;\n\t\t\texpressionReferencePitch = basePitch;\n\t\t\tpitchDamping = Config.chipNoises[instrument.chipNoise].isSoft ? 24.0 : 60.0;\n\t\t} else if (instrument.type == InstrumentType.fm) {\n\t\t\tbaseExpression = Config.fmBaseExpression;\n\t\t} else if (instrument.type == InstrumentType.chip) {\n\t\t\tbaseExpression = Config.chipBaseExpression;\n\t\t} else if (instrument.type == InstrumentType.harmonics) {\n\t\t\tbaseExpression = Config.harmonicsBaseExpression;\n\t\t} else if (instrument.type == InstrumentType.pwm) {\n\t\t\tbaseExpression = Config.pwmBaseExpression;\n\t\t} else if (instrument.type == InstrumentType.supersaw) {\n\t\t\tbaseExpression = Config.supersawBaseExpression;\n\t\t} else if (instrument.type == InstrumentType.pickedString) {\n\t\t\tbaseExpression = Config.pickedStringBaseExpression;\n\t\t} else {\n\t\t\tthrow new Error(\"Unknown instrument type in computeTone.\");\n\t\t}\n\t\t\n\t\tif ((tone.atNoteStart && !transition.isSeamless && !tone.forceContinueAtStart) || tone.freshlyAllocated) {\n\t\t\ttone.reset();\n\t\t}\n\t\ttone.freshlyAllocated = false;\n\t\t\n\t\tfor (let i: number = 0; i < Config.maxPitchOrOperatorCount; i++) {\n\t\t\ttone.phaseDeltas[i] = 0.0;\n\t\t\ttone.phaseDeltaScales[i] = 0.0;\n\t\t\ttone.operatorExpressions[i] = 0.0;\n\t\t\ttone.operatorExpressionDeltas[i] = 0.0;\n\t\t}\n\t\ttone.expression = 0.0;\n\t\ttone.expressionDelta = 0.0;\n\n\t\tif (released) {\n\t\t\tconst startTicksSinceReleased: number = tone.ticksSinceReleased;\n\t\t\tconst endTicksSinceReleased: number = tone.ticksSinceReleased + 1.0;\n\t\t\tintervalStart = intervalEnd = tone.lastInterval;\n\t\t\tconst fadeOutTicks: number = Math.abs(instrument.getFadeOutTicks());\n\t\t\tfadeExpressionStart = Synth.noteSizeToVolumeMult((1.0 - startTicksSinceReleased / fadeOutTicks) * Config.noteSizeMax);\n\t\t\tfadeExpressionEnd = Synth.noteSizeToVolumeMult((1.0 - endTicksSinceReleased / fadeOutTicks) * Config.noteSizeMax);\n\t\t\t\n\t\t\tif (shouldFadeOutFast) {\n\t\t\t\tfadeExpressionEnd = 0.0;\n\t\t\t}\n\t\t\t\n\t\t\tif (tone.ticksSinceReleased + 1 >= fadeOutTicks) toneIsOnLastTick = true;\n\t\t} else if (tone.note == null) {\n\t\t\tfadeExpressionStart = fadeExpressionEnd = 1.0;\n\t\t\ttone.lastInterval = 0;\n\t\t\ttone.ticksSinceReleased = 0;\n\t\t\ttone.liveInputSamplesHeld += roundedSamplesPerTick;\n\t\t} else {\n\t\t\tconst note: Note = tone.note;\n\t\t\tconst nextNote: Note | null = tone.nextNote;\n\n\t\t\tconst noteStartPart: number = tone.noteStartPart;\n\t\t\tconst noteEndPart: number = tone.noteEndPart;\n\t\t\t\n\t\t\tconst endPinIndex: number = note.getEndPinIndex(currentPart);\n\t\t\tconst startPin: NotePin = note.pins[endPinIndex-1];\n\t\t\tconst endPin: NotePin = note.pins[endPinIndex];\n\t\t\tconst noteStartTick: number = noteStartPart * Config.ticksPerPart;\n\t\t\tconst noteEndTick: number = noteEndPart * Config.ticksPerPart;\n\t\t\tconst pinStart: number = (note.start + startPin.time) * Config.ticksPerPart;\n\t\t\tconst pinEnd: number = (note.start + endPin.time) * Config.ticksPerPart;\n\t\t\t\n\t\t\ttone.ticksSinceReleased = 0;\n\t\t\t\n\t\t\tconst tickTimeStart: number = currentPart * Config.ticksPerPart + this.tick;\n\t\t\tconst tickTimeEnd: number = tickTimeStart + 1.0;\n\t\t\tconst noteTicksPassedTickStart: number = tickTimeStart - noteStartTick;\n\t\t\tconst noteTicksPassedTickEnd: number = tickTimeEnd - noteStartTick;\n\t\t\tconst pinRatioStart: number = Math.min(1.0, (tickTimeStart - pinStart) / (pinEnd - pinStart));\n\t\t\tconst pinRatioEnd: number = Math.min(1.0, (tickTimeEnd - pinStart) / (pinEnd - pinStart));\n\t\t\tfadeExpressionStart = 1.0;\n\t\t\tfadeExpressionEnd = 1.0;\n\t\t\tintervalStart = startPin.interval + (endPin.interval - startPin.interval) * pinRatioStart;\n\t\t\tintervalEnd = startPin.interval + (endPin.interval - startPin.interval) * pinRatioEnd;\n\t\t\ttone.lastInterval = intervalEnd;\n\t\t\t\n\t\t\tif ((!transition.isSeamless && !tone.forceContinueAtEnd) || nextNote == null) {\n\t\t\t\tconst fadeOutTicks: number = -instrument.getFadeOutTicks();\n\t\t\t\tif (fadeOutTicks > 0.0) {\n\t\t\t\t\t// If the tone should fade out before the end of the note, do so here.\n\t\t\t\t\tconst noteLengthTicks: number = noteEndTick - noteStartTick;\n\t\t\t\t\tfadeExpressionStart *= Math.min(1.0, (noteLengthTicks - noteTicksPassedTickStart) / fadeOutTicks);\n\t\t\t\t\tfadeExpressionEnd *= Math.min(1.0, (noteLengthTicks - noteTicksPassedTickEnd) / fadeOutTicks);\n\t\t\t\t\tif (tickTimeEnd >= noteStartTick + noteLengthTicks) toneIsOnLastTick = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\ttone.isOnLastTick = toneIsOnLastTick;\n\t\t\n\t\t// Compute envelopes *after* resetting the tone, otherwise the envelope computer gets reset too!\n\t\tconst envelopeComputer: EnvelopeComputer = tone.envelopeComputer;\n\t\tenvelopeComputer.computeEnvelopes(instrument, currentPart, Config.ticksPerPart * partTimeStart, samplesPerTick / this.samplesPerSecond, tone);\n\t\tconst envelopeStarts: number[] = tone.envelopeComputer.envelopeStarts;\n\t\tconst envelopeEnds: number[] = tone.envelopeComputer.envelopeEnds;\n\t\t\n\t\tif (tone.note != null && transition.slides) {\n\t\t\t// Slide interval and chordExpression at the start and/or end of the note if necessary.\n\t\t\tconst prevNote: Note | null = tone.prevNote;\n\t\t\tconst nextNote: Note | null = tone.nextNote;\n\t\t\tif (prevNote != null) {\n\t\t\t\tconst intervalDiff: number = prevNote.pitches[tone.prevNotePitchIndex] + prevNote.pins[prevNote.pins.length-1].interval - tone.pitches[0];\n\t\t\t\tif (envelopeComputer.prevSlideStart) intervalStart += intervalDiff * envelopeComputer.prevSlideRatioStart;\n\t\t\t\tif (envelopeComputer.prevSlideEnd) intervalEnd += intervalDiff * envelopeComputer.prevSlideRatioEnd;\n\t\t\t\tif (!chord.singleTone) {\n\t\t\t\t\tconst chordSizeDiff: number = prevNote.pitches.length - tone.chordSize;\n\t\t\t\t\tif (envelopeComputer.prevSlideStart) chordExpressionStart = Synth.computeChordExpression(tone.chordSize + chordSizeDiff * envelopeComputer.prevSlideRatioStart);\n\t\t\t\t\tif (envelopeComputer.prevSlideEnd) chordExpressionEnd = Synth.computeChordExpression(tone.chordSize + chordSizeDiff * envelopeComputer.prevSlideRatioEnd);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (nextNote != null) {\n\t\t\t\tconst intervalDiff: number = nextNote.pitches[tone.nextNotePitchIndex] - (tone.pitches[0] + tone.note.pins[tone.note.pins.length-1].interval);\n\t\t\t\tif (envelopeComputer.nextSlideStart) intervalStart += intervalDiff * envelopeComputer.nextSlideRatioStart;\n\t\t\t\tif (envelopeComputer.nextSlideEnd) intervalEnd += intervalDiff * envelopeComputer.nextSlideRatioEnd;\n\t\t\t\tif (!chord.singleTone) {\n\t\t\t\t\tconst chordSizeDiff: number = nextNote.pitches.length - tone.chordSize;\n\t\t\t\t\tif (envelopeComputer.nextSlideStart) chordExpressionStart = Synth.computeChordExpression(tone.chordSize + chordSizeDiff * envelopeComputer.nextSlideRatioStart);\n\t\t\t\t\tif (envelopeComputer.nextSlideEnd) chordExpressionEnd = Synth.computeChordExpression(tone.chordSize + chordSizeDiff * envelopeComputer.nextSlideRatioEnd);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (effectsIncludePitchShift(instrument.effects)) {\n\t\t\tconst pitchShift: number = Config.justIntonationSemitones[instrument.pitchShift] / intervalScale;\n\t\t\tconst envelopeStart: number = envelopeStarts[EnvelopeComputeIndex.pitchShift];\n\t\t\tconst envelopeEnd: number = envelopeEnds[ EnvelopeComputeIndex.pitchShift];\n\t\t\tintervalStart += pitchShift * envelopeStart;\n\t\t\tintervalEnd += pitchShift * envelopeEnd;\n\t\t}\n\t\tif (effectsIncludeDetune(instrument.effects)) {\n\t\t\tconst envelopeStart: number = envelopeStarts[EnvelopeComputeIndex.detune];\n\t\t\tconst envelopeEnd: number = envelopeEnds[ EnvelopeComputeIndex.detune];\n\t\t\tintervalStart += Synth.detuneToCents((instrument.detune - Config.detuneCenter) * envelopeStart) * Config.pitchesPerOctave / (12.0 * 100.0);\n\t\t\tintervalEnd += Synth.detuneToCents((instrument.detune - Config.detuneCenter) * envelopeEnd ) * Config.pitchesPerOctave / (12.0 * 100.0);\n\t\t}\n\t\t\n\t\tif (effectsIncludeVibrato(instrument.effects)) {\n\t\t\tconst delayTicks: number = Config.vibratos[instrument.vibrato].delayTicks;\n\t\t\tconst vibratoAmplitude: number = Config.vibratos[instrument.vibrato].amplitude;\n\t\t\t\n\t\t\t// To maintain pitch continuity, (mostly for picked string which retriggers impulse\n\t\t\t// otherwise) remember the vibrato at the end of this run and reuse it at the start\n\t\t\t// of the next run if available.\n\t\t\tlet vibratoStart: number;\n\t\t\tif (tone.prevVibrato != null) {\n\t\t\t\tvibratoStart = tone.prevVibrato;\n\t\t\t} else {\n\t\t\t\tlet lfoStart: number = Synth.getLFOAmplitude(instrument, secondsPerPart * partTimeStart);\n\t\t\t\tconst vibratoDepthEnvelopeStart: number = envelopeStarts[EnvelopeComputeIndex.vibratoDepth];\n\t\t\t\tvibratoStart = vibratoAmplitude * lfoStart * vibratoDepthEnvelopeStart;\n\t\t\t\tif (delayTicks > 0.0) {\n\t\t\t\t\tconst ticksUntilVibratoStart: number = delayTicks - envelopeComputer.noteTicksStart;\n\t\t\t\t\tvibratoStart *= Math.max(0.0, Math.min(1.0, 1.0 - ticksUntilVibratoStart / 2.0));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tlet lfoEnd: number = Synth.getLFOAmplitude(instrument, secondsPerPart * partTimeEnd);\n\t\t\tconst vibratoDepthEnvelopeEnd: number = envelopeEnds[ EnvelopeComputeIndex.vibratoDepth];\n\t\t\tlet vibratoEnd: number = vibratoAmplitude * lfoEnd * vibratoDepthEnvelopeEnd;\n\t\t\tif (delayTicks > 0.0) {\n\t\t\t\tconst ticksUntilVibratoEnd: number = delayTicks - envelopeComputer.noteTicksEnd;\n\t\t\t\tvibratoEnd *= Math.max(0.0, Math.min(1.0, 1.0 - ticksUntilVibratoEnd / 2.0));\n\t\t\t}\n\t\t\ttone.prevVibrato = vibratoEnd;\n\t\t\t\n\t\t\tintervalStart += vibratoStart;\n\t\t\tintervalEnd += vibratoEnd;\n\t\t}\n\t\t\n\t\tif ((!transition.isSeamless && !tone.forceContinueAtStart) || tone.prevNote == null) {\n\t\t\t// Fade in the beginning of the note.\n\t\t\tconst fadeInSeconds: number = instrument.getFadeInSeconds();\n\t\t\tif (fadeInSeconds > 0.0) {\n\t\t\t\tfadeExpressionStart *= Math.min(1.0, envelopeComputer.noteSecondsStart / fadeInSeconds);\n\t\t\t\tfadeExpressionEnd *= Math.min(1.0, envelopeComputer.noteSecondsEnd / fadeInSeconds);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (instrument.type == InstrumentType.drumset && tone.drumsetPitch == null) {\n\t\t\t// It's possible that the note will change while the user is editing it,\n\t\t\t// but the tone's pitches don't get updated because the tone has already\n\t\t\t// ended and is fading out. To avoid an array index out of bounds error, clamp the pitch.\n\t\t\ttone.drumsetPitch = tone.pitches[0];\n\t\t\tif (tone.note != null) tone.drumsetPitch += tone.note.pickMainInterval();\n\t\t\ttone.drumsetPitch = Math.max(0, Math.min(Config.drumCount - 1, tone.drumsetPitch));\n\t\t}\n\t\t\n\t\tlet noteFilterExpression: number = envelopeComputer.lowpassCutoffDecayVolumeCompensation;\n\t\tif (!effectsIncludeNoteFilter(instrument.effects)) {\n\t\t\ttone.noteFilterCount = 0;\n\t\t} else {\n\t\t\tconst noteFilterSettings: FilterSettings = instrument.noteFilter;\n\t\t\t\n\t\t\tconst noteAllFreqsEnvelopeStart: number = envelopeStarts[EnvelopeComputeIndex.noteFilterAllFreqs];\n\t\t\tconst noteAllFreqsEnvelopeEnd: number = envelopeEnds[ EnvelopeComputeIndex.noteFilterAllFreqs];\n\t\t\tfor (let i: number = 0; i < noteFilterSettings.controlPointCount; i++) {\n\t\t\t\tconst noteFreqEnvelopeStart: number = envelopeStarts[EnvelopeComputeIndex.noteFilterFreq0 + i];\n\t\t\t\tconst noteFreqEnvelopeEnd: number = envelopeEnds[ EnvelopeComputeIndex.noteFilterFreq0 + i];\n\t\t\t\tconst notePeakEnvelopeStart: number = envelopeStarts[EnvelopeComputeIndex.noteFilterGain0 + i];\n\t\t\t\tconst notePeakEnvelopeEnd: number = envelopeEnds[ EnvelopeComputeIndex.noteFilterGain0 + i];\n\t\t\t\tconst point: FilterControlPoint = noteFilterSettings.controlPoints[i];\n\t\t\t\tpoint.toCoefficients(Synth.tempFilterStartCoefficients, this.samplesPerSecond, noteAllFreqsEnvelopeStart * noteFreqEnvelopeStart, notePeakEnvelopeStart);\n\t\t\t\tpoint.toCoefficients(Synth.tempFilterEndCoefficients, this.samplesPerSecond, noteAllFreqsEnvelopeEnd * noteFreqEnvelopeEnd, notePeakEnvelopeEnd);\n\t\t\t\tif (tone.noteFilters.length <= i) tone.noteFilters[i] = new DynamicBiquadFilter();\n\t\t\t\ttone.noteFilters[i].loadCoefficientsWithGradient(Synth.tempFilterStartCoefficients, Synth.tempFilterEndCoefficients, 1.0 / roundedSamplesPerTick, point.type == FilterType.lowPass);\n\t\t\t\tnoteFilterExpression *= point.getVolumeCompensationMult();\n\t\t\t}\n\t\t\ttone.noteFilterCount = noteFilterSettings.controlPointCount;\n\t\t}\n\t\t\n\t\tif (instrument.type == InstrumentType.drumset) {\n\t\t\tconst drumsetFilterEnvelope: Envelope = instrument.getDrumsetEnvelope(tone.drumsetPitch!);\n\t\t\t// If the drumset lowpass cutoff decays, compensate by increasing expression.\n\t\t\tnoteFilterExpression *= EnvelopeComputer.getLowpassCutoffDecayVolumeCompensation(drumsetFilterEnvelope)\n\t\t\t\n\t\t\t// Drumset filters use the same envelope timing as the rest of the envelopes, but do not include support for slide transitions.\n\t\t\tlet drumsetFilterEnvelopeStart: number = EnvelopeComputer.computeEnvelope(drumsetFilterEnvelope, envelopeComputer.noteSecondsStart, beatsPerPart * partTimeStart, envelopeComputer.noteSizeStart);\n\t\t\tlet drumsetFilterEnvelopeEnd: number = EnvelopeComputer.computeEnvelope(drumsetFilterEnvelope, envelopeComputer.noteSecondsEnd, beatsPerPart * partTimeEnd, envelopeComputer.noteSizeEnd);\n\t\t\t\n\t\t\t// Apply slide interpolation to drumset envelope.\n\t\t\tif (envelopeComputer.prevSlideStart) {\n\t\t\t\tconst other: number = EnvelopeComputer.computeEnvelope(drumsetFilterEnvelope, envelopeComputer.prevNoteSecondsStart, beatsPerPart * partTimeStart, envelopeComputer.prevNoteSize);\n\t\t\t\tdrumsetFilterEnvelopeStart += (other - drumsetFilterEnvelopeStart) * envelopeComputer.prevSlideRatioStart;\n\t\t\t}\n\t\t\tif (envelopeComputer.prevSlideEnd) {\n\t\t\t\tconst other: number = EnvelopeComputer.computeEnvelope(drumsetFilterEnvelope, envelopeComputer.prevNoteSecondsEnd, beatsPerPart * partTimeEnd, envelopeComputer.prevNoteSize);\n\t\t\t\tdrumsetFilterEnvelopeEnd += (other - drumsetFilterEnvelopeEnd) * envelopeComputer.prevSlideRatioEnd;\n\t\t\t}\n\t\t\tif (envelopeComputer.nextSlideStart) {\n\t\t\t\tconst other: number = EnvelopeComputer.computeEnvelope(drumsetFilterEnvelope, 0.0, beatsPerPart * partTimeStart, envelopeComputer.nextNoteSize);\n\t\t\t\tdrumsetFilterEnvelopeStart += (other - drumsetFilterEnvelopeStart) * envelopeComputer.nextSlideRatioStart;\n\t\t\t}\n\t\t\tif (envelopeComputer.nextSlideEnd) {\n\t\t\t\tconst other: number = EnvelopeComputer.computeEnvelope(drumsetFilterEnvelope, 0.0, beatsPerPart * partTimeEnd, envelopeComputer.nextNoteSize);\n\t\t\t\tdrumsetFilterEnvelopeEnd += (other - drumsetFilterEnvelopeEnd) * envelopeComputer.nextSlideRatioEnd;\n\t\t\t}\n\t\t\t\n\t\t\tconst point: FilterControlPoint = this.tempDrumSetControlPoint;\n\t\t\tpoint.type = FilterType.lowPass;\n\t\t\tpoint.gain = FilterControlPoint.getRoundedSettingValueFromLinearGain(0.5);\n\t\t\tpoint.freq = FilterControlPoint.getRoundedSettingValueFromHz(8000.0);\n\t\t\t// Drumset envelopes are warped to better imitate the legacy simplified 2nd order lowpass at ~48000Hz that I used to use.\n\t\t\tpoint.toCoefficients(Synth.tempFilterStartCoefficients, this.samplesPerSecond, drumsetFilterEnvelopeStart * (1.0 + drumsetFilterEnvelopeStart), 1.0);\n\t\t\tpoint.toCoefficients(Synth.tempFilterEndCoefficients, this.samplesPerSecond, drumsetFilterEnvelopeEnd * (1.0 + drumsetFilterEnvelopeEnd), 1.0);\n\t\t\tif (tone.noteFilters.length == tone.noteFilterCount) tone.noteFilters[tone.noteFilterCount] = new DynamicBiquadFilter();\n\t\t\ttone.noteFilters[tone.noteFilterCount].loadCoefficientsWithGradient(Synth.tempFilterStartCoefficients, Synth.tempFilterEndCoefficients, 1.0 / roundedSamplesPerTick, true);\n\t\t\ttone.noteFilterCount++;\n\t\t}\n\t\t\n\t\tnoteFilterExpression = Math.min(3.0, noteFilterExpression);\n\t\t\n\t\tif (instrument.type == InstrumentType.fm) {\n\t\t\t// phase modulation!\n\t\t\t\n\t\t\tlet sineExpressionBoost: number = 1.0;\n\t\t\tlet totalCarrierExpression: number = 0.0;\n\n\t\t\tlet arpeggioInterval: number = 0;\n\t\t\tconst arpeggiates: boolean = chord.arpeggiates;\n\t\t\tif (tone.pitchCount > 1 && arpeggiates) {\n\t\t\t\tconst arpeggio: number = Math.floor((this.tick + this.part * Config.ticksPerPart) / Config.rhythms[song.rhythm].ticksPerArpeggio);\n\t\t\t\tarpeggioInterval = tone.pitches[getArpeggioPitchIndex(tone.pitchCount, song.rhythm, arpeggio)] - tone.pitches[0];\n\t\t\t}\n\t\t\t\n\t\t\tconst carrierCount: number = Config.algorithms[instrument.algorithm].carrierCount;\n\t\t\tfor (let i: number = 0; i < Config.operatorCount; i++) {\n\t\t\t\tconst associatedCarrierIndex: number = Config.algorithms[instrument.algorithm].associatedCarrier[i] - 1;\n\t\t\t\tconst pitch: number = tone.pitches[arpeggiates ? 0 : ((i < tone.pitchCount) ? i : ((associatedCarrierIndex < tone.pitchCount) ? associatedCarrierIndex : 0))];\n\t\t\t\tconst freqMult = Config.operatorFrequencies[instrument.operators[i].frequency].mult;\n\t\t\t\tconst interval = Config.operatorCarrierInterval[associatedCarrierIndex] + arpeggioInterval;\n\t\t\t\tconst pitchStart: number = basePitch + (pitch + intervalStart) * intervalScale + interval;\n\t\t\t\tconst pitchEnd: number = basePitch + (pitch + intervalEnd) * intervalScale + interval;\n\t\t\t\tconst baseFreqStart: number = Instrument.frequencyFromPitch(pitchStart);\n\t\t\t\tconst baseFreqEnd: number = Instrument.frequencyFromPitch(pitchEnd);\n\t\t\t\tconst hzOffset: number = Config.operatorFrequencies[instrument.operators[i].frequency].hzOffset;\n\t\t\t\tconst targetFreqStart: number = freqMult * baseFreqStart + hzOffset;\n\t\t\t\tconst targetFreqEnd: number = freqMult * baseFreqEnd + hzOffset;\n\t\t\t\t\n\t\t\t\tconst freqEnvelopeStart: number = envelopeStarts[EnvelopeComputeIndex.operatorFrequency0 + i];\n\t\t\t\tconst freqEnvelopeEnd: number = envelopeEnds[ EnvelopeComputeIndex.operatorFrequency0 + i];\n\t\t\t\tlet freqStart: number;\n\t\t\t\tlet freqEnd: number;\n\t\t\t\tif (freqEnvelopeStart != 1.0 || freqEnvelopeEnd != 1.0) {\n\t\t\t\t\tfreqStart = Math.pow(2.0, Math.log2(targetFreqStart / baseFreqStart) * freqEnvelopeStart) * baseFreqStart;\n\t\t\t\t\tfreqEnd = Math.pow(2.0, Math.log2(targetFreqEnd / baseFreqEnd) * freqEnvelopeEnd) * baseFreqEnd;\n\t\t\t\t} else {\n\t\t\t\t\tfreqStart = targetFreqStart;\n\t\t\t\t\tfreqEnd = targetFreqEnd;\n\t\t\t\t}\n\t\t\t\ttone.phaseDeltas[i] = freqStart * sampleTime;\n\t\t\t\ttone.phaseDeltaScales[i] = Math.pow(freqEnd / freqStart, 1.0 / roundedSamplesPerTick);\n\t\t\t\t\n\t\t\t\tconst amplitudeCurve: number = Synth.operatorAmplitudeCurve(instrument.operators[i].amplitude);\n\t\t\t\tconst amplitudeMult: number = amplitudeCurve * Config.operatorFrequencies[instrument.operators[i].frequency].amplitudeSign;\n\t\t\t\tlet expressionStart: number = amplitudeMult;\n\t\t\t\tlet expressionEnd: number = amplitudeMult;\n\t\t\t\tif (i < carrierCount) {\n\t\t\t\t\t// carrier\n\t\t\t\t\tlet pitchExpressionStart: number;\n\t\t\t\t\tif (tone.prevPitchExpressions[i] != null) {\n\t\t\t\t\t\tpitchExpressionStart = tone.prevPitchExpressions[i]!;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpitchExpressionStart = Math.pow(2.0, -(pitchStart - expressionReferencePitch) / pitchDamping);\n\t\t\t\t\t}\n\t\t\t\t\tconst pitchExpressionEnd: number = Math.pow(2.0, -(pitchEnd - expressionReferencePitch) / pitchDamping);\n\t\t\t\t\ttone.prevPitchExpressions[i] = pitchExpressionEnd;\n\t\t\t\t\texpressionStart *= pitchExpressionStart;\n\t\t\t\t\texpressionEnd *= pitchExpressionEnd;\n\t\t\t\t\t\n\t\t\t\t\ttotalCarrierExpression += amplitudeCurve;\n\t\t\t\t} else {\n\t\t\t\t\t// modulator\n\t\t\t\t\texpressionStart *= Config.sineWaveLength * 1.5;\n\t\t\t\t\texpressionEnd *= Config.sineWaveLength * 1.5;\n\t\t\t\t\t\n\t\t\t\t\tsineExpressionBoost *= 1.0 - Math.min(1.0, instrument.operators[i].amplitude / 15);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\texpressionStart *= envelopeStarts[EnvelopeComputeIndex.operatorAmplitude0 + i];\n\t\t\t\texpressionEnd *= envelopeEnds[ EnvelopeComputeIndex.operatorAmplitude0 + i];\n\t\t\t\t\n\t\t\t\ttone.operatorExpressions[i] = expressionStart;\n\t\t\t\ttone.operatorExpressionDeltas[i] = (expressionEnd - expressionStart) / roundedSamplesPerTick;\n\t\t\t}\n\t\t\t\n\t\t\tsineExpressionBoost *= (Math.pow(2.0, (2.0 - 1.4 * instrument.feedbackAmplitude / 15.0)) - 1.0) / 3.0;\n\t\t\tsineExpressionBoost *= 1.0 - Math.min(1.0, Math.max(0.0, totalCarrierExpression - 1) / 2.0);\n\t\t\tsineExpressionBoost = 1.0 + sineExpressionBoost * 3.0;\n\t\t\tconst expressionStart: number = baseExpression * sineExpressionBoost * noteFilterExpression * fadeExpressionStart * chordExpressionStart * envelopeStarts[EnvelopeComputeIndex.noteVolume];\n\t\t\tconst expressionEnd: number = baseExpression * sineExpressionBoost * noteFilterExpression * fadeExpressionEnd * chordExpressionEnd * envelopeEnds[ EnvelopeComputeIndex.noteVolume];\n\t\t\ttone.expression = expressionStart;\n\t\t\ttone.expressionDelta = (expressionEnd - expressionStart) / roundedSamplesPerTick;\n\t\t\t\n\t\t\tconst feedbackAmplitude: number = Config.sineWaveLength * 0.3 * instrument.feedbackAmplitude / 15.0;\n\t\t\tlet feedbackStart: number = feedbackAmplitude * envelopeStarts[EnvelopeComputeIndex.feedbackAmplitude];\n\t\t\tlet feedbackEnd: number = feedbackAmplitude * envelopeEnds[ EnvelopeComputeIndex.feedbackAmplitude];\n\t\t\ttone.feedbackMult = feedbackStart;\n\t\t\ttone.feedbackDelta = (feedbackEnd - feedbackStart) / roundedSamplesPerTick;\n\t\t} else {\n\t\t\tconst freqEndRatio: number = Math.pow(2.0, (intervalEnd - intervalStart) * intervalScale / 12.0);\n\t\t\tconst basePhaseDeltaScale: number = Math.pow(freqEndRatio, 1.0 / roundedSamplesPerTick);\n\t\t\t\n\t\t\tlet pitch: number = tone.pitches[0];\n\t\t\tif (tone.pitchCount > 1 && (chord.arpeggiates || chord.customInterval)) {\n\t\t\t\tconst arpeggio: number = Math.floor((this.tick + this.part * Config.ticksPerPart) / Config.rhythms[song.rhythm].ticksPerArpeggio);\n\t\t\t\tif (chord.customInterval) {\n\t\t\t\t\tconst intervalOffset: number = tone.pitches[1 + getArpeggioPitchIndex(tone.pitchCount - 1, song.rhythm, arpeggio)] - tone.pitches[0];\n\t\t\t\t\tspecialIntervalMult = Math.pow(2.0, intervalOffset / 12.0);\n\t\t\t\t\ttone.specialIntervalExpressionMult = Math.pow(2.0, -intervalOffset / pitchDamping);\n\t\t\t\t} else {\n\t\t\t\t\tpitch = tone.pitches[getArpeggioPitchIndex(tone.pitchCount, song.rhythm, arpeggio)];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tconst startPitch: number = basePitch + (pitch + intervalStart) * intervalScale;\n\t\t\tconst endPitch: number = basePitch + (pitch + intervalEnd) * intervalScale;\n\t\t\tlet pitchExpressionStart: number;\n\t\t\t// TODO: use the second element of prevPitchExpressions for the unison voice, compute a separate expression delta for it.\n\t\t\tif (tone.prevPitchExpressions[0] != null) {\n\t\t\t\tpitchExpressionStart = tone.prevPitchExpressions[0]!;\n\t\t\t} else {\n\t\t\t\tpitchExpressionStart = Math.pow(2.0, -(startPitch - expressionReferencePitch) / pitchDamping);\n\t\t\t}\n\t\t\tconst pitchExpressionEnd: number = Math.pow(2.0, -(endPitch - expressionReferencePitch) / pitchDamping);\n\t\t\ttone.prevPitchExpressions[0] = pitchExpressionEnd;\n\t\t\tlet settingsExpressionMult: number = baseExpression * noteFilterExpression;\n\t\t\t\n\t\t\tif (instrument.type == InstrumentType.noise) {\n\t\t\t\tsettingsExpressionMult *= Config.chipNoises[instrument.chipNoise].expression;\n\t\t\t}\n\t\t\tif (instrument.type == InstrumentType.chip) {\n\t\t\t\tsettingsExpressionMult *= Config.chipWaves[instrument.chipWave].expression;\n\t\t\t}\n\t\t\tif (instrument.type == InstrumentType.pwm) {\n\t\t\t\tconst basePulseWidth: number = getPulseWidthRatio(instrument.pulseWidth);\n\t\t\t\tconst pulseWidthStart: number = basePulseWidth * envelopeStarts[EnvelopeComputeIndex.pulseWidth];\n\t\t\t\tconst pulseWidthEnd: number = basePulseWidth * envelopeEnds[ EnvelopeComputeIndex.pulseWidth];\n\t\t\t\ttone.pulseWidth = pulseWidthStart;\n\t\t\t\ttone.pulseWidthDelta = (pulseWidthEnd - pulseWidthStart) / roundedSamplesPerTick;\n\t\t\t}\n\t\t\t\n\t\t\tif (instrument.type == InstrumentType.pickedString) {\n\t\t\t\t// Increase expression to compensate for string decay.\n\t\t\t\tsettingsExpressionMult *= Math.pow(2.0, 0.7 * (1.0 - instrument.stringSustain / (Config.stringSustainRange - 1)));\n\t\t\t}\n\t\t\t\n\t\t\tconst startFreq: number = Instrument.frequencyFromPitch(startPitch);\n\t\t\tif (instrument.type == InstrumentType.chip || instrument.type == InstrumentType.harmonics || instrument.type == InstrumentType.pickedString) {\n\t\t\t\t// These instruments have two waves at different frequencies for the unison feature.\n\t\t\t\tconst unison: Unison = Config.unisons[instrument.unison];\n\t\t\t\tconst voiceCountExpression: number = (instrument.type == InstrumentType.pickedString) ? 1 : unison.voices / 2.0;\n\t\t\t\tsettingsExpressionMult *= unison.expression * voiceCountExpression;\n\t\t\t\tconst unisonEnvelopeStart = envelopeStarts[EnvelopeComputeIndex.unison];\n\t\t\t\tconst unisonEnvelopeEnd = envelopeEnds[ EnvelopeComputeIndex.unison];\n\t\t\t\tconst unisonAStart: number = Math.pow(2.0, (unison.offset + unison.spread) * unisonEnvelopeStart / 12.0);\n\t\t\t\tconst unisonAEnd: number = Math.pow(2.0, (unison.offset + unison.spread) * unisonEnvelopeEnd / 12.0);\n\t\t\t\tconst unisonBStart: number = Math.pow(2.0, (unison.offset - unison.spread) * unisonEnvelopeStart / 12.0) * specialIntervalMult;\n\t\t\t\tconst unisonBEnd: number = Math.pow(2.0, (unison.offset - unison.spread) * unisonEnvelopeEnd / 12.0) * specialIntervalMult;\n\t\t\t\ttone.phaseDeltas[0] = startFreq * sampleTime * unisonAStart;\n\t\t\t\ttone.phaseDeltas[1] = startFreq * sampleTime * unisonBStart;\n\t\t\t\ttone.phaseDeltaScales[0] = basePhaseDeltaScale * Math.pow(unisonAEnd / unisonAStart, 1.0 / roundedSamplesPerTick);\n\t\t\t\ttone.phaseDeltaScales[1] = basePhaseDeltaScale * Math.pow(unisonBEnd / unisonBStart, 1.0 / roundedSamplesPerTick);\n\t\t\t} else {\n\t\t\t\ttone.phaseDeltas[0] = startFreq * sampleTime;\n\t\t\t\ttone.phaseDeltaScales[0] = basePhaseDeltaScale;\n\t\t\t}\n\t\t\t\n\t\t\t// TODO: make expressionStart and expressionEnd variables earlier and modify those\n\t\t\t// instead of these supersawExpression variables.\n\t\t\tlet supersawExpressionStart: number = 1.0;\n\t\t\tlet supersawExpressionEnd: number = 1.0;\n\t\t\tif (instrument.type == InstrumentType.supersaw) {\n\t\t\t\tconst minFirstVoiceAmplitude: number = 1.0 / Math.sqrt(Config.supersawVoiceCount);\n\t\t\t\tconst baseDynamismSlider: number = instrument.supersawDynamism / Config.supersawDynamismMax;\n\t\t\t\tconst curvedDynamismStart: number = 1.0 - Math.pow(Math.max(0.0, 1.0 - baseDynamismSlider * envelopeStarts[EnvelopeComputeIndex.supersawDynamism]), 0.2);\n\t\t\t\tconst curvedDynamismEnd: number = 1.0 - Math.pow(Math.max(0.0, 1.0 - baseDynamismSlider * envelopeEnds[ EnvelopeComputeIndex.supersawDynamism]), 0.2);\n\t\t\t\tconst firstVoiceAmplitudeStart: number = Math.pow(2.0, Math.log2(minFirstVoiceAmplitude) * curvedDynamismStart);\n\t\t\t\tconst firstVoiceAmplitudeEnd: number = Math.pow(2.0, Math.log2(minFirstVoiceAmplitude) * curvedDynamismEnd);\n\t\t\t\t// TODO: automation\n\t\t\t\tconst dynamismStart: number = Math.sqrt((1.0 / Math.pow(firstVoiceAmplitudeStart, 2.0) - 1.0) / (Config.supersawVoiceCount - 1.0));\n\t\t\t\tconst dynamismEnd: number = Math.sqrt((1.0 / Math.pow(firstVoiceAmplitudeEnd, 2.0) - 1.0) / (Config.supersawVoiceCount - 1.0));\n\t\t\t\ttone.supersawDynamism = dynamismStart;\n\t\t\t\ttone.supersawDynamismDelta = (dynamismEnd - dynamismStart) / roundedSamplesPerTick;\n\t\t\t\t\n\t\t\t\tconst initializeSupersaw: boolean = (tone.supersawDelayIndex == -1);\n\t\t\t\tif (initializeSupersaw) {\n\t\t\t\t\t// Goal: generate sawtooth phases such that the combined initial amplitude\n\t\t\t\t\t// cancel out to minimize pop. Algorithm: generate sorted phases, iterate over\n\t\t\t\t\t// their sawtooth drop points to find a combined zero crossing, then offset the\n\t\t\t\t\t// phases so they start there.\n\t\t\t\t\t\n\t\t\t\t\t// Generate random phases in ascending order by adding positive randomly\n\t\t\t\t\t// sized gaps between adjacent phases. For a proper distribution of random\n\t\t\t\t\t// events, the gaps sizes should be an \"exponential distribution\", which is\n\t\t\t\t\t// just: -Math.log(Math.random()). At the end, normalize the phases to a 0-1\n\t\t\t\t\t// range by dividing by the final value of the accumulator.\n\t\t\t\t\tlet accumulator: number = 0.0;\n\t\t\t\t\tfor (let i: number = 0; i < Config.supersawVoiceCount; i++) {\n\t\t\t\t\t\ttone.phases[i] = accumulator;\n\t\t\t\t\t\taccumulator += -Math.log(Math.random());\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tconst amplitudeSum: number = 1.0 + (Config.supersawVoiceCount - 1.0) * dynamismStart;\n\t\t\t\t\tconst slope: number = amplitudeSum;\n\t\t\t\t\t\n\t\t\t\t\t// Find the initial amplitude of the sum of sawtooths with the normalized\n\t\t\t\t\t// set of phases.\n\t\t\t\t\tlet sample: number = 0.0;\n\t\t\t\t\tfor (let i: number = 0; i < Config.supersawVoiceCount; i++) {\n\t\t\t\t\t\tconst amplitude: number = (i == 0) ? 1.0 : dynamismStart;\n\t\t\t\t\t\tconst normalizedPhase: number = tone.phases[i] / accumulator;\n\t\t\t\t\t\ttone.phases[i] = normalizedPhase;\n\t\t\t\t\t\tsample += (normalizedPhase - 0.5) * amplitude;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Find the phase of the zero crossing of the sum of the sawtooths. You can\n\t\t\t\t\t// use a constant slope and the distance between sawtooth drops to determine if\n\t\t\t\t\t// the zero crossing occurs between them. Note that a small phase means that\n\t\t\t\t\t// the corresponding drop for that wave is far away, and a big phase means the\n\t\t\t\t\t// drop is nearby, so to iterate forward through the drops we iterate backward\n\t\t\t\t\t// through the phases.\n\t\t\t\t\tlet zeroCrossingPhase: number = 1.0;\n\t\t\t\t\tlet prevDrop: number = 0.0;\n\t\t\t\t\tfor (let i: number = Config.supersawVoiceCount - 1; i >= 0; i--) {\n\t\t\t\t\t\tconst nextDrop: number = 1.0 - tone.phases[i];\n\t\t\t\t\t\tconst phaseDelta: number = nextDrop - prevDrop;\n\t\t\t\t\t\tif (sample < 0.0) {\n\t\t\t\t\t\t\tconst distanceToZeroCrossing: number = -sample / slope;\n\t\t\t\t\t\t\tif (distanceToZeroCrossing < phaseDelta) {\n\t\t\t\t\t\t\t\tzeroCrossingPhase = prevDrop + distanceToZeroCrossing;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst amplitude: number = (i == 0) ? 1.0 : dynamismStart;\n\t\t\t\t\t\tsample += phaseDelta * slope - amplitude;\n\t\t\t\t\t\tprevDrop = nextDrop;\n\t\t\t\t\t}\n\t\t\t\t\tfor (let i: number = 0; i < Config.supersawVoiceCount; i++) {\n\t\t\t\t\t\ttone.phases[i] += zeroCrossingPhase;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Randomize the (initially sorted) order of the phases (aside from the\n\t\t\t\t\t// first one) so that they don't correlate to the detunes that are also\n\t\t\t\t\t// based on index.\n\t\t\t\t\tfor (let i: number = 1; i < Config.supersawVoiceCount - 1; i++) {\n\t\t\t\t\t\tconst swappedIndex: number = i + Math.floor(Math.random() * (Config.supersawVoiceCount - i));\n\t\t\t\t\t\tconst temp: number = tone.phases[i];\n\t\t\t\t\t\ttone.phases[i] = tone.phases[swappedIndex];\n\t\t\t\t\t\ttone.phases[swappedIndex] = temp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tconst baseSpreadSlider: number = instrument.supersawSpread / Config.supersawSpreadMax;\n\t\t\t\t// TODO: automation\n\t\t\t\tconst spreadSliderStart: number = baseSpreadSlider * envelopeStarts[EnvelopeComputeIndex.supersawSpread];\n\t\t\t\tconst spreadSliderEnd: number = baseSpreadSlider * envelopeEnds[ EnvelopeComputeIndex.supersawSpread];\n\t\t\t\t// Just use the average detune for the current tick in the below loop.\n\t\t\t\tconst averageSpreadSlider: number = (spreadSliderStart + spreadSliderEnd) * 0.5;\n\t\t\t\tconst curvedSpread: number = Math.pow(1.0 - Math.sqrt(Math.max(0.0, 1.0 - averageSpreadSlider)), 1.75);\n\t\t\t\tfor (let i = 0; i < Config.supersawVoiceCount; i++) {\n\t\t\t\t\t// Spread out the detunes around the center;\n\t\t\t\t\tconst offset: number = (i == 0) ? 0.0 : Math.pow((((i + 1) >> 1) - 0.5 + 0.025 * ((i & 2) - 1)) / (Config.supersawVoiceCount >> 1), 1.1) * ((i & 1) * 2 - 1);\n\t\t\t\t\ttone.supersawUnisonDetunes[i] = Math.pow(2.0, curvedSpread * offset / 12.0);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tconst baseShape: number = instrument.supersawShape / Config.supersawShapeMax;\n\t\t\t\t// TODO: automation\n\t\t\t\tconst shapeStart: number = baseShape * envelopeStarts[EnvelopeComputeIndex.supersawShape];\n\t\t\t\tconst shapeEnd: number = baseShape * envelopeEnds[ EnvelopeComputeIndex.supersawShape];\n\t\t\t\ttone.supersawShape = shapeStart;\n\t\t\t\ttone.supersawShapeDelta = (shapeEnd - shapeStart) / roundedSamplesPerTick;\n\t\t\t\t\n\t\t\t\tconst basePulseWidth: number = getPulseWidthRatio(instrument.pulseWidth);\n\t\t\t\t// TODO: automation\n\t\t\t\tconst pulseWidthStart: number = basePulseWidth * envelopeStarts[EnvelopeComputeIndex.pulseWidth];\n\t\t\t\tconst pulseWidthEnd: number = basePulseWidth * envelopeEnds[ EnvelopeComputeIndex.pulseWidth];\n\t\t\t\tconst phaseDeltaStart: number = (tone.supersawPrevPhaseDelta != null) ? tone.supersawPrevPhaseDelta : startFreq * sampleTime;\n\t\t\t\tconst phaseDeltaEnd: number = startFreq * sampleTime * freqEndRatio;\n\t\t\t\ttone.supersawPrevPhaseDelta = phaseDeltaEnd;\n\t\t\t\tconst delayLengthStart = pulseWidthStart / phaseDeltaStart;\n\t\t\t\tconst delayLengthEnd = pulseWidthEnd / phaseDeltaEnd;\n\t\t\t\ttone.supersawDelayLength = delayLengthStart;\n\t\t\t\ttone.supersawDelayLengthDelta = (delayLengthEnd - delayLengthStart) / roundedSamplesPerTick;\n\t\t\t\tconst minBufferLength: number = Math.ceil(Math.max(delayLengthStart, delayLengthEnd)) + 2;\n\t\t\t\t\n\t\t\t\tif (tone.supersawDelayLine == null || tone.supersawDelayLine.length <= minBufferLength) {\n\t\t\t\t\t// The delay line buffer will get reused for other tones so might as well\n\t\t\t\t\t// start off with a buffer size that is big enough for most notes.\n\t\t\t\t\tconst likelyMaximumLength: number = Math.ceil(0.5 * this.samplesPerSecond / Instrument.frequencyFromPitch(24));\n\t\t\t\t\tconst newDelayLine: Float32Array = new Float32Array(Synth.fittingPowerOfTwo(Math.max(likelyMaximumLength, minBufferLength)));\n\t\t\t\t\tif (!initializeSupersaw && tone.supersawDelayLine != null) {\n\t\t\t\t\t\t// If the tone has already started but the buffer needs to be reallocated,\n\t\t\t\t\t\t// transfer the old data to the new buffer.\n\t\t\t\t\t\tconst oldDelayBufferMask: number = (tone.supersawDelayLine.length - 1) >> 0;\n\t\t\t\t\t\tconst startCopyingFromIndex: number = tone.supersawDelayIndex;\n\t\t\t\t\t\tfor (let i: number = 0; i < tone.supersawDelayLine.length; i++) {\n\t\t\t\t\t\t\tnewDelayLine[i] = tone.supersawDelayLine[(startCopyingFromIndex + i) & oldDelayBufferMask];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttone.supersawDelayLine = newDelayLine;\n\t\t\t\t\ttone.supersawDelayIndex = tone.supersawDelayLine.length;\n\t\t\t\t} else if (initializeSupersaw) {\n\t\t\t\t\ttone.supersawDelayLine.fill(0.0);\n\t\t\t\t\ttone.supersawDelayIndex = tone.supersawDelayLine.length;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tconst pulseExpressionRatio: number = Config.pwmBaseExpression / Config.supersawBaseExpression;\n\t\t\t\tsupersawExpressionStart *= (1.0 + (pulseExpressionRatio - 1.0) * shapeStart) / Math.sqrt(1.0 + (Config.supersawVoiceCount - 1.0) * dynamismStart * dynamismStart);\n\t\t\t\tsupersawExpressionEnd *= (1.0 + (pulseExpressionRatio - 1.0) * shapeEnd) / Math.sqrt(1.0 + (Config.supersawVoiceCount - 1.0) * dynamismEnd * dynamismEnd);\n\t\t\t}\n\t\t\t\n\t\t\tconst expressionStart: number = settingsExpressionMult * fadeExpressionStart * chordExpressionStart * pitchExpressionStart * envelopeStarts[EnvelopeComputeIndex.noteVolume] * supersawExpressionStart;\n\t\t\tconst expressionEnd: number = settingsExpressionMult * fadeExpressionEnd * chordExpressionEnd * pitchExpressionEnd * envelopeEnds[ EnvelopeComputeIndex.noteVolume] * supersawExpressionEnd;\n\t\t\ttone.expression = expressionStart;\n\t\t\ttone.expressionDelta = (expressionEnd - expressionStart) / roundedSamplesPerTick;\n\t\t\t\n\t\t\tif (instrument.type == InstrumentType.pickedString) {\n\t\t\t\tlet stringDecayStart: number;\n\t\t\t\tif (tone.prevStringDecay != null) {\n\t\t\t\t\tstringDecayStart = tone.prevStringDecay;\n\t\t\t\t} else {\n\t\t\t\t\tconst sustainEnvelopeStart: number = tone.envelopeComputer.envelopeStarts[EnvelopeComputeIndex.stringSustain];\n\t\t\t\t\tstringDecayStart = 1.0 - Math.min(1.0, sustainEnvelopeStart * instrument.stringSustain / (Config.stringSustainRange - 1));\n\t\t\t\t}\n\t\t\t\tconst sustainEnvelopeEnd: number = tone.envelopeComputer.envelopeEnds[ EnvelopeComputeIndex.stringSustain];\n\t\t\t\tlet stringDecayEnd: number = 1.0 - Math.min(1.0, sustainEnvelopeEnd * instrument.stringSustain / (Config.stringSustainRange - 1));\n\t\t\t\ttone.prevStringDecay = stringDecayEnd;\n\t\t\t\t\n\t\t\t\tconst unison: Unison = Config.unisons[instrument.unison];\n\t\t\t\tfor (let i: number = tone.pickedStrings.length; i < unison.voices; i++) {\n\t\t\t\t\ttone.pickedStrings[i] = new PickedString();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (tone.atNoteStart && !transition.continues && !tone.forceContinueAtStart) {\n\t\t\t\t\tfor (const pickedString of tone.pickedStrings) {\n\t\t\t\t\t\t// Force the picked string to retrigger the attack impulse at the start of the note.\n\t\t\t\t\t\tpickedString.delayIndex = -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (let i: number = 0; i < unison.voices; i++) {\n\t\t\t\t\ttone.pickedStrings[i].update(this, instrumentState, tone, i, roundedSamplesPerTick, stringDecayStart, stringDecayEnd, instrument.stringSustainType);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic static getLFOAmplitude(instrument: Instrument, secondsIntoBar: number): number {\n\t\tlet effect: number = 0.0;\n\t\tfor (const vibratoPeriodSeconds of Config.vibratos[instrument.vibrato].periodsSeconds) {\n\t\t\teffect += Math.sin(Math.PI * 2.0 * secondsIntoBar / vibratoPeriodSeconds);\n\t\t}\n\t\treturn effect;\n\t}\n\t\n\tpublic static getInstrumentSynthFunction(instrument: Instrument): Function {\n\t\tif (instrument.type == InstrumentType.fm) {\n\t\t\tconst fingerprint: string = instrument.algorithm + \"_\" + instrument.feedbackType;\n\t\t\tif (Synth.fmSynthFunctionCache[fingerprint] == undefined) {\n\t\t\t\tconst synthSource: string[] = [];\n\t\t\t\t\n\t\t\t\tfor (const line of Synth.fmSourceTemplate) {\n\t\t\t\t\tif (line.indexOf(\"// CARRIER OUTPUTS\") != -1) {\n\t\t\t\t\t\tconst outputs: string[] = [];\n\t\t\t\t\t\tfor (let j: number = 0; j < Config.algorithms[instrument.algorithm].carrierCount; j++) {\n\t\t\t\t\t\t\toutputs.push(\"operator\" + j + \"Scaled\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsynthSource.push(line.replace(\"/*operator#Scaled*/\", outputs.join(\" + \")));\n\t\t\t\t\t} else if (line.indexOf(\"// INSERT OPERATOR COMPUTATION HERE\") != -1) {\n\t\t\t\t\t\tfor (let j: number = Config.operatorCount - 1; j >= 0; j--) {\n\t\t\t\t\t\t\tfor (const operatorLine of Synth.operatorSourceTemplate) {\n\t\t\t\t\t\t\t\tif (operatorLine.indexOf(\"/* + operator@Scaled*/\") != -1) {\n\t\t\t\t\t\t\t\t\tlet modulators = \"\";\n\t\t\t\t\t\t\t\t\tfor (const modulatorNumber of Config.algorithms[instrument.algorithm].modulatedBy[j]) {\n\t\t\t\t\t\t\t\t\t\tmodulators += \" + operator\" + (modulatorNumber - 1) + \"Scaled\";\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tconst feedbackIndices: ReadonlyArray<number> = Config.feedbacks[instrument.feedbackType].indices[j];\n\t\t\t\t\t\t\t\t\tif (feedbackIndices.length > 0) {\n\t\t\t\t\t\t\t\t\t\tmodulators += \" + feedbackMult * (\";\n\t\t\t\t\t\t\t\t\t\tconst feedbacks: string[] = [];\n\t\t\t\t\t\t\t\t\t\tfor (const modulatorNumber of feedbackIndices) {\n\t\t\t\t\t\t\t\t\t\t\tfeedbacks.push(\"operator\" + (modulatorNumber - 1) + \"Output\");\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tmodulators += feedbacks.join(\" + \") + \")\";\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tsynthSource.push(operatorLine.replace(/\\#/g, j + \"\").replace(\"/* + operator@Scaled*/\", modulators));\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tsynthSource.push(operatorLine.replace(/\\#/g, j + \"\"));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (line.indexOf(\"#\") != -1) {\n\t\t\t\t\t\tfor (let j: number = 0; j < Config.operatorCount; j++) {\n\t\t\t\t\t\t\tsynthSource.push(line.replace(/\\#/g, j + \"\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsynthSource.push(line);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t//console.log(synthSource.join(\"\\n\"));\n\t\t\t\t\n\t\t\t\tconst wrappedFmSynth: string = \"return (synth, bufferIndex, runLength, tone, instrument) => {\" + synthSource.join(\"\\n\") + \"}\";\n\t\t\t\t\n\t\t\t\tSynth.fmSynthFunctionCache[fingerprint] = new Function(\"Config\", \"Synth\", wrappedFmSynth)(Config, Synth);\n\t\t\t}\n\t\t\treturn Synth.fmSynthFunctionCache[fingerprint];\n\t\t} else if (instrument.type == InstrumentType.chip) {\n\t\t\treturn Synth.chipSynth;\n\t\t} else if (instrument.type == InstrumentType.harmonics) {\n\t\t\treturn Synth.harmonicsSynth;\n\t\t} else if (instrument.type == InstrumentType.pwm) {\n\t\t\treturn Synth.pulseWidthSynth;\n\t\t} else if (instrument.type == InstrumentType.supersaw) {\n\t\t\treturn Synth.supersawSynth;\n\t\t} else if (instrument.type == InstrumentType.pickedString) {\n\t\t\treturn Synth.pickedStringSynth;\n\t\t} else if (instrument.type == InstrumentType.noise) {\n\t\t\treturn Synth.noiseSynth;\n\t\t} else if (instrument.type == InstrumentType.spectrum) {\n\t\t\treturn Synth.spectrumSynth;\n\t\t} else if (instrument.type == InstrumentType.drumset) {\n\t\t\treturn Synth.drumsetSynth;\n\t\t} else {\n\t\t\tthrow new Error(\"Unrecognized instrument type: \" + instrument.type);\n\t\t}\n\t}\n\t\n\tprivate static chipSynth(synth: Synth, bufferIndex: number, runLength: number, tone: Tone, instrumentState: InstrumentState): void {\n\t\tconst data: Float32Array = synth.tempMonoInstrumentSampleBuffer!;\n\t\tconst wave: Float32Array = instrumentState.wave!;\n\t\tconst waveLength: number = wave.length - 1; // The first sample is duplicated at the end, don't double-count it.\n\t\t\n\t\tconst unisonSign: number = tone.specialIntervalExpressionMult * instrumentState.unison!.sign;\n\t\tif (instrumentState.unison!.voices == 1 && !instrumentState.chord!.customInterval) tone.phases[1] = tone.phases[0];\n\t\tlet phaseDeltaA: number = tone.phaseDeltas[0] * waveLength;\n\t\tlet phaseDeltaB: number = tone.phaseDeltas[1] * waveLength;\n\t\tconst phaseDeltaScaleA: number = +tone.phaseDeltaScales[0];\n\t\tconst phaseDeltaScaleB: number = +tone.phaseDeltaScales[1];\n\t\tlet expression: number = +tone.expression;\n\t\tconst expressionDelta: number = +tone.expressionDelta;\n\t\tlet phaseA: number = (tone.phases[0] % 1) * waveLength;\n\t\tlet phaseB: number = (tone.phases[1] % 1) * waveLength;\n\t\t\n\t\tconst filters: DynamicBiquadFilter[] = tone.noteFilters;\n\t\tconst filterCount: number = tone.noteFilterCount|0;\n\t\tlet initialFilterInput1: number = +tone.initialNoteFilterInput1;\n\t\tlet initialFilterInput2: number = +tone.initialNoteFilterInput2;\n\t\tconst applyFilters: Function = Synth.applyFilters;\n\t\t\n\t\tconst phaseAInt: number = phaseA|0;\n\t\tconst phaseBInt: number = phaseB|0;\n\t\tconst indexA: number = phaseAInt % waveLength;\n\t\tconst indexB: number = phaseBInt % waveLength;\n\t\tconst phaseRatioA: number = phaseA - phaseAInt;\n\t\tconst phaseRatioB: number = phaseB - phaseBInt;\n\t\tlet prevWaveIntegralA: number = +wave[indexA];\n\t\tlet prevWaveIntegralB: number = +wave[indexB];\n\t\tprevWaveIntegralA += (wave[indexA+1] - prevWaveIntegralA) * phaseRatioA;\n\t\tprevWaveIntegralB += (wave[indexB+1] - prevWaveIntegralB) * phaseRatioB;\n\t\t\n\t\tconst stopIndex: number = bufferIndex + runLength;\n\t\tfor (let sampleIndex: number = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\t\n\t\t\tphaseA += phaseDeltaA;\n\t\t\tphaseB += phaseDeltaB;\n\t\t\t\n\t\t\tconst phaseAInt: number = phaseA|0;\n\t\t\tconst phaseBInt: number = phaseB|0;\n\t\t\tconst indexA: number = phaseAInt % waveLength;\n\t\t\tconst indexB: number = phaseBInt % waveLength;\n\t\t\tlet nextWaveIntegralA: number = wave[indexA];\n\t\t\tlet nextWaveIntegralB: number = wave[indexB];\n\t\t\tconst phaseRatioA: number = phaseA - phaseAInt;\n\t\t\tconst phaseRatioB: number = phaseB - phaseBInt;\n\t\t\tnextWaveIntegralA += (wave[indexA+1] - nextWaveIntegralA) * phaseRatioA;\n\t\t\tnextWaveIntegralB += (wave[indexB+1] - nextWaveIntegralB) * phaseRatioB;\n\t\t\tconst waveA: number = (nextWaveIntegralA - prevWaveIntegralA) / phaseDeltaA;\n\t\t\tconst waveB: number = (nextWaveIntegralB - prevWaveIntegralB) / phaseDeltaB;\n\t\t\tprevWaveIntegralA = nextWaveIntegralA;\n\t\t\tprevWaveIntegralB = nextWaveIntegralB;\n\t\t\t\n\t\t\tconst inputSample: number = waveA + waveB * unisonSign;\n\t\t\tconst sample: number = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\tinitialFilterInput1 = inputSample;\n\t\t\t\n\t\t\tphaseDeltaA *= phaseDeltaScaleA;\n\t\t\tphaseDeltaB *= phaseDeltaScaleB;\n\t\t\t\n\t\t\tconst output: number = sample * expression;\n\t\t\texpression += expressionDelta;\n\t\t\t\n\t\t\tdata[sampleIndex] += output;\n\t\t}\n\t\t\n\t\ttone.phases[0] = phaseA / waveLength;\n\t\ttone.phases[1] = phaseB / waveLength;\n\t\ttone.phaseDeltas[0] = phaseDeltaA / waveLength;\n\t\ttone.phaseDeltas[1] = phaseDeltaB / waveLength;\n\t\ttone.expression = expression;\n\t\t\n\t\tsynth.sanitizeFilters(filters);\n\t\ttone.initialNoteFilterInput1 = initialFilterInput1;\n\t\ttone.initialNoteFilterInput2 = initialFilterInput2;\n\t}\n\t\n\tprivate static harmonicsSynth(synth: Synth, bufferIndex: number, runLength: number, tone: Tone, instrumentState: InstrumentState): void {\n\t\tconst data: Float32Array = synth.tempMonoInstrumentSampleBuffer!;\n\t\tconst wave: Float32Array = instrumentState.wave!;\n\t\tconst waveLength: number = wave.length - 1; // The first sample is duplicated at the end, don't double-count it.\n\t\t\n\t\tconst unisonSign: number = tone.specialIntervalExpressionMult * instrumentState.unison!.sign;\n\t\tif (instrumentState.unison!.voices == 1 && !instrumentState.chord!.customInterval) tone.phases[1] = tone.phases[0];\n\t\tlet phaseDeltaA: number = tone.phaseDeltas[0] * waveLength;\n\t\tlet phaseDeltaB: number = tone.phaseDeltas[1] * waveLength;\n\t\tconst phaseDeltaScaleA: number = +tone.phaseDeltaScales[0];\n\t\tconst phaseDeltaScaleB: number = +tone.phaseDeltaScales[1];\n\t\tlet expression: number = +tone.expression;\n\t\tconst expressionDelta: number = +tone.expressionDelta;\n\t\tlet phaseA: number = (tone.phases[0] % 1) * waveLength;\n\t\tlet phaseB: number = (tone.phases[1] % 1) * waveLength;\n\t\t\n\t\tconst filters: DynamicBiquadFilter[] = tone.noteFilters;\n\t\tconst filterCount: number = tone.noteFilterCount|0;\n\t\tlet initialFilterInput1: number = +tone.initialNoteFilterInput1;\n\t\tlet initialFilterInput2: number = +tone.initialNoteFilterInput2;\n\t\tconst applyFilters: Function = Synth.applyFilters;\n\t\t\n\t\tconst phaseAInt: number = phaseA|0;\n\t\tconst phaseBInt: number = phaseB|0;\n\t\tconst indexA: number = phaseAInt % waveLength;\n\t\tconst indexB: number = phaseBInt % waveLength;\n\t\tconst phaseRatioA: number = phaseA - phaseAInt;\n\t\tconst phaseRatioB: number = phaseB - phaseBInt;\n\t\tlet prevWaveIntegralA: number = +wave[indexA];\n\t\tlet prevWaveIntegralB: number = +wave[indexB];\n\t\tprevWaveIntegralA += (wave[indexA+1] - prevWaveIntegralA) * phaseRatioA;\n\t\tprevWaveIntegralB += (wave[indexB+1] - prevWaveIntegralB) * phaseRatioB;\n\t\t\n\t\tconst stopIndex: number = bufferIndex + runLength;\n\t\tfor (let sampleIndex: number = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\t\n\t\t\tphaseA += phaseDeltaA;\n\t\t\tphaseB += phaseDeltaB;\n\t\t\t\n\t\t\tconst phaseAInt: number = phaseA|0;\n\t\t\tconst phaseBInt: number = phaseB|0;\n\t\t\tconst indexA: number = phaseAInt % waveLength;\n\t\t\tconst indexB: number = phaseBInt % waveLength;\n\t\t\tlet nextWaveIntegralA: number = wave[indexA];\n\t\t\tlet nextWaveIntegralB: number = wave[indexB];\n\t\t\tconst phaseRatioA: number = phaseA - phaseAInt;\n\t\t\tconst phaseRatioB: number = phaseB - phaseBInt;\n\t\t\tnextWaveIntegralA += (wave[indexA+1] - nextWaveIntegralA) * phaseRatioA;\n\t\t\tnextWaveIntegralB += (wave[indexB+1] - nextWaveIntegralB) * phaseRatioB;\n\t\t\tconst waveA: number = (nextWaveIntegralA - prevWaveIntegralA) / phaseDeltaA;\n\t\t\tconst waveB: number = (nextWaveIntegralB - prevWaveIntegralB) / phaseDeltaB;\n\t\t\tprevWaveIntegralA = nextWaveIntegralA;\n\t\t\tprevWaveIntegralB = nextWaveIntegralB;\n\t\t\t\n\t\t\tconst inputSample: number = waveA + waveB * unisonSign;\n\t\t\tconst sample: number = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\tinitialFilterInput1 = inputSample;\n\t\t\t\n\t\t\tphaseDeltaA *= phaseDeltaScaleA;\n\t\t\tphaseDeltaB *= phaseDeltaScaleB;\n\t\t\t\n\t\t\tconst output: number = sample * expression;\n\t\t\texpression += expressionDelta;\n\t\t\t\n\t\t\tdata[sampleIndex] += output;\n\t\t}\n\t\t\n\t\ttone.phases[0] = phaseA / waveLength;\n\t\ttone.phases[1] = phaseB / waveLength;\n\t\ttone.phaseDeltas[0] = phaseDeltaA / waveLength;\n\t\ttone.phaseDeltas[1] = phaseDeltaB / waveLength;\n\t\ttone.expression = expression;\n\t\t\n\t\tsynth.sanitizeFilters(filters);\n\t\ttone.initialNoteFilterInput1 = initialFilterInput1;\n\t\ttone.initialNoteFilterInput2 = initialFilterInput2;\n\t}\n\t\n\tprivate static pickedStringSynth(synth: Synth, bufferIndex: number, runLength: number, tone: Tone, instrumentState: InstrumentState): void {\n\t\t// This algorithm is similar to the Karpluss-Strong algorithm in principle, but with an\n\t\t// all-pass filter for dispersion and with more control over the impulse harmonics.\n\t\t// The source code is processed as a string before being compiled, in order to\n\t\t// handle the unison feature. If unison is disabled or set to none, then only one\n\t\t// string voice is required, otherwise two string voices are required. We only want\n\t\t// to compute the minimum possible number of string voices, so omit the code for\n\t\t// processing extra ones if possible. Any line containing a \"#\" is duplicated for\n\t\t// each required voice, replacing the \"#\" with the voice index.\n\t\t\n\t\tconst voiceCount: number = instrumentState.unison!.voices;\n\t\tlet pickedStringFunction: Function = Synth.pickedStringFunctionCache[voiceCount];\n\t\tif (pickedStringFunction == undefined) {\n\t\t\tlet pickedStringSource: string = \"return (synth, bufferIndex, runLength, tone, instrumentState) => {\";\n\t\t\t\n\t\t\tpickedStringSource += `\n\t\t\t\tconst data = synth.tempMonoInstrumentSampleBuffer;\n\t\t\t\t\n\t\t\t\tlet pickedString# = tone.pickedStrings[#];\n\t\t\t\tlet allPassSample# = +pickedString#.allPassSample;\n\t\t\t\tlet allPassPrevInput# = +pickedString#.allPassPrevInput;\n\t\t\t\tlet sustainFilterSample# = +pickedString#.sustainFilterSample;\n\t\t\t\tlet sustainFilterPrevOutput2# = +pickedString#.sustainFilterPrevOutput2;\n\t\t\t\tlet sustainFilterPrevInput1# = +pickedString#.sustainFilterPrevInput1;\n\t\t\t\tlet sustainFilterPrevInput2# = +pickedString#.sustainFilterPrevInput2;\n\t\t\t\tlet fractionalDelaySample# = +pickedString#.fractionalDelaySample;\n\t\t\t\tconst delayLine# = pickedString#.delayLine;\n\t\t\t\tconst delayBufferMask# = (delayLine#.length - 1) >> 0;\n\t\t\t\tlet delayIndex# = pickedString#.delayIndex|0;\n\t\t\t\tdelayIndex# = (delayIndex# & delayBufferMask#) + delayLine#.length;\n\t\t\t\tlet delayLength# = +pickedString#.prevDelayLength;\n\t\t\t\tconst delayLengthDelta# = +pickedString#.delayLengthDelta;\n\t\t\t\tlet allPassG# = +pickedString#.allPassG;\n\t\t\t\tlet sustainFilterA1# = +pickedString#.sustainFilterA1;\n\t\t\t\tlet sustainFilterA2# = +pickedString#.sustainFilterA2;\n\t\t\t\tlet sustainFilterB0# = +pickedString#.sustainFilterB0;\n\t\t\t\tlet sustainFilterB1# = +pickedString#.sustainFilterB1;\n\t\t\t\tlet sustainFilterB2# = +pickedString#.sustainFilterB2;\n\t\t\t\tconst allPassGDelta# = +pickedString#.allPassGDelta;\n\t\t\t\tconst sustainFilterA1Delta# = +pickedString#.sustainFilterA1Delta;\n\t\t\t\tconst sustainFilterA2Delta# = +pickedString#.sustainFilterA2Delta;\n\t\t\t\tconst sustainFilterB0Delta# = +pickedString#.sustainFilterB0Delta;\n\t\t\t\tconst sustainFilterB1Delta# = +pickedString#.sustainFilterB1Delta;\n\t\t\t\tconst sustainFilterB2Delta# = +pickedString#.sustainFilterB2Delta;\n\t\t\t\t\n\t\t\t\tlet expression = +tone.expression;\n\t\t\t\tconst expressionDelta = +tone.expressionDelta;\n\t\t\t\t\n\t\t\t\tconst unisonSign = tone.specialIntervalExpressionMult * instrumentState.unison.sign;\n\t\t\t\tconst delayResetOffset# = pickedString#.delayResetOffset|0;\n\t\t\t\t\n\t\t\t\tconst filters = tone.noteFilters;\n\t\t\t\tconst filterCount = tone.noteFilterCount|0;\n\t\t\t\tlet initialFilterInput1 = +tone.initialNoteFilterInput1;\n\t\t\t\tlet initialFilterInput2 = +tone.initialNoteFilterInput2;\n\t\t\t\tconst applyFilters = Synth.applyFilters;\n\t\t\t\t\n\t\t\t\tconst stopIndex = bufferIndex + runLength;\n\t\t\t\tfor (let sampleIndex = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\t\t\tconst targetSampleTime# = delayIndex# - delayLength#;\n\t\t\t\t\tconst lowerIndex# = (targetSampleTime# + 0.125) | 0; // Offset to improve stability of all-pass filter.\n\t\t\t\t\tconst upperIndex# = lowerIndex# + 1;\n\t\t\t\t\tconst fractionalDelay# = upperIndex# - targetSampleTime#;\n\t\t\t\t\tconst fractionalDelayG# = (1.0 - fractionalDelay#) / (1.0 + fractionalDelay#); // Inlined version of FilterCoefficients.prototype.allPass1stOrderFractionalDelay\n\t\t\t\t\tconst prevInput# = delayLine#[lowerIndex# & delayBufferMask#];\n\t\t\t\t\tconst input# = delayLine#[upperIndex# & delayBufferMask#];\n\t\t\t\t\tfractionalDelaySample# = fractionalDelayG# * input# + prevInput# - fractionalDelayG# * fractionalDelaySample#;\n\t\t\t\t\t\n\t\t\t\t\tallPassSample# = fractionalDelaySample# * allPassG# + allPassPrevInput# - allPassG# * allPassSample#;\n\t\t\t\t\tallPassPrevInput# = fractionalDelaySample#;\n\t\t\t\t\t\n\t\t\t\t\tconst sustainFilterPrevOutput1# = sustainFilterSample#;\n\t\t\t\t\tsustainFilterSample# = sustainFilterB0# * allPassSample# + sustainFilterB1# * sustainFilterPrevInput1# + sustainFilterB2# * sustainFilterPrevInput2# - sustainFilterA1# * sustainFilterSample# - sustainFilterA2# * sustainFilterPrevOutput2#;\n\t\t\t\t\tsustainFilterPrevOutput2# = sustainFilterPrevOutput1#;\n\t\t\t\t\tsustainFilterPrevInput2# = sustainFilterPrevInput1#;\n\t\t\t\t\tsustainFilterPrevInput1# = allPassSample#;\n\t\t\t\t\t\n\t\t\t\t\tdelayLine#[delayIndex# & delayBufferMask#] += sustainFilterSample#;\n\t\t\t\t\tdelayLine#[(delayIndex# + delayResetOffset#) & delayBufferMask#] = 0.0;\n\t\t\t\t\tdelayIndex#++;\n\t\t\t\t\t\n\t\t\t\t\tconst inputSample = (`\n\t\t\t\n\t\t\tconst sampleList: string[] = [];\n\t\t\tfor (let voice: number = 0; voice < voiceCount; voice++) {\n\t\t\t\tsampleList.push(\"fractionalDelaySample\" + voice + (voice == 1 ? \" * unisonSign\" : \"\"));\n\t\t\t}\n\t\t\t\n\t\t\tpickedStringSource += sampleList.join(\" + \");\n\t\t\t\n\t\t\tpickedStringSource += `) * expression;\n\t\t\t\t\tconst sample = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\t\t\tinitialFilterInput1 = inputSample;\n\t\t\t\t\tdata[sampleIndex] += sample;\n\t\t\t\t\t\n\t\t\t\t\texpression += expressionDelta;\n\t\t\t\t\tdelayLength# += delayLengthDelta#;\n\t\t\t\t\tallPassG# += allPassGDelta#;\n\t\t\t\t\tsustainFilterA1# += sustainFilterA1Delta#;\n\t\t\t\t\tsustainFilterA2# += sustainFilterA2Delta#;\n\t\t\t\t\tsustainFilterB0# += sustainFilterB0Delta#;\n\t\t\t\t\tsustainFilterB1# += sustainFilterB1Delta#;\n\t\t\t\t\tsustainFilterB2# += sustainFilterB2Delta#;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Avoid persistent denormal or NaN values in the delay buffers and filter history.\n\t\t\t\tconst epsilon = (1.0e-24);\n\t\t\t\tif (!Number.isFinite(allPassSample#) || Math.abs(allPassSample#) < epsilon) allPassSample# = 0.0;\n\t\t\t\tif (!Number.isFinite(allPassPrevInput#) || Math.abs(allPassPrevInput#) < epsilon) allPassPrevInput# = 0.0;\n\t\t\t\tif (!Number.isFinite(sustainFilterSample#) || Math.abs(sustainFilterSample#) < epsilon) sustainFilterSample# = 0.0;\n\t\t\t\tif (!Number.isFinite(sustainFilterPrevOutput2#) || Math.abs(sustainFilterPrevOutput2#) < epsilon) sustainFilterPrevOutput2# = 0.0;\n\t\t\t\tif (!Number.isFinite(sustainFilterPrevInput1#) || Math.abs(sustainFilterPrevInput1#) < epsilon) sustainFilterPrevInput1# = 0.0;\n\t\t\t\tif (!Number.isFinite(sustainFilterPrevInput2#) || Math.abs(sustainFilterPrevInput2#) < epsilon) sustainFilterPrevInput2# = 0.0;\n\t\t\t\tif (!Number.isFinite(fractionalDelaySample#) || Math.abs(fractionalDelaySample#) < epsilon) fractionalDelaySample# = 0.0;\n\t\t\t\tpickedString#.allPassSample = allPassSample#;\n\t\t\t\tpickedString#.allPassPrevInput = allPassPrevInput#;\n\t\t\t\tpickedString#.sustainFilterSample = sustainFilterSample#;\n\t\t\t\tpickedString#.sustainFilterPrevOutput2 = sustainFilterPrevOutput2#;\n\t\t\t\tpickedString#.sustainFilterPrevInput1 = sustainFilterPrevInput1#;\n\t\t\t\tpickedString#.sustainFilterPrevInput2 = sustainFilterPrevInput2#;\n\t\t\t\tpickedString#.fractionalDelaySample = fractionalDelaySample#;\n\t\t\t\tpickedString#.delayIndex = delayIndex#;\n\t\t\t\tpickedString#.prevDelayLength = delayLength#;\n\t\t\t\tpickedString#.allPassG = allPassG#;\n\t\t\t\tpickedString#.sustainFilterA1 = sustainFilterA1#;\n\t\t\t\tpickedString#.sustainFilterA2 = sustainFilterA2#;\n\t\t\t\tpickedString#.sustainFilterB0 = sustainFilterB0#;\n\t\t\t\tpickedString#.sustainFilterB1 = sustainFilterB1#;\n\t\t\t\tpickedString#.sustainFilterB2 = sustainFilterB2#;\n\t\t\t\t\n\t\t\t\ttone.expression = expression;\n\t\t\t\t\n\t\t\t\tsynth.sanitizeFilters(filters);\n\t\t\t\ttone.initialNoteFilterInput1 = initialFilterInput1;\n\t\t\t\ttone.initialNoteFilterInput2 = initialFilterInput2;\n\t\t\t}`\n\t\t\t\n\t\t\t// Duplicate lines containing \"#\" for each voice and replace the \"#\" with the voice index.\n\t\t\tpickedStringSource = pickedStringSource.replace(/^.*\\#.*$/mg, line => {\n\t\t\t\tconst lines = [];\n\t\t\t\tfor (let voice: number = 0; voice < voiceCount; voice++) {\n\t\t\t\t\tlines.push(line.replace(/\\#/g, String(voice)));\n\t\t\t\t}\n\t\t\t\treturn lines.join(\"\\n\");\n\t\t\t});\n\t\t\t\n\t\t\t//console.log(pickedStringSource);\n\t\t\tpickedStringFunction = new Function(\"Config\", \"Synth\", pickedStringSource)(Config, Synth);\n\t\t\tSynth.pickedStringFunctionCache[voiceCount] = pickedStringFunction;\n\t\t}\n\t\t\n\t\tpickedStringFunction(synth, bufferIndex, runLength, tone, instrumentState);\n\t}\n\t\n\tprivate static effectsSynth(synth: Synth, outputDataL: Float32Array, outputDataR: Float32Array, bufferIndex: number, runLength: number, instrumentState: InstrumentState): void {\n\t\t// TODO: If automation is involved, don't assume sliders will stay at zero.\n\t\tconst usesDistortion: boolean = effectsIncludeDistortion(instrumentState.effects);\n\t\tconst usesBitcrusher: boolean = effectsIncludeBitcrusher(instrumentState.effects);\n\t\tconst usesEqFilter: boolean = instrumentState.eqFilterCount > 0;\n\t\tconst usesPanning: boolean = effectsIncludePanning(instrumentState.effects);\n\t\tconst usesChorus: boolean = effectsIncludeChorus(instrumentState.effects);\n\t\tconst usesEcho: boolean = effectsIncludeEcho(instrumentState.effects);\n\t\tconst usesReverb: boolean = effectsIncludeReverb(instrumentState.effects);\n\t\tlet signature: number = 0; if (usesDistortion) signature = signature | 1;\n\t\tsignature = signature << 1; if (usesBitcrusher) signature = signature | 1;\n\t\tsignature = signature << 1; if (usesEqFilter) signature = signature | 1;\n\t\tsignature = signature << 1; if (usesPanning) signature = signature | 1;\n\t\tsignature = signature << 1; if (usesChorus) signature = signature | 1;\n\t\tsignature = signature << 1; if (usesEcho) signature = signature | 1;\n\t\tsignature = signature << 1; if (usesReverb) signature = signature | 1;\n\t\t\n\t\tlet effectsFunction: Function = Synth.effectsFunctionCache[signature];\n\t\tif (effectsFunction == undefined) {\n\t\t\tlet effectsSource: string = \"return (synth, outputDataL, outputDataR, bufferIndex, runLength, instrumentState) => {\";\n\t\t\t\n\t\t\tconst usesDelays: boolean = usesChorus || usesReverb || usesEcho;\n\t\t\t\n\t\t\teffectsSource += `\n\t\t\t\tconst tempMonoInstrumentSampleBuffer = synth.tempMonoInstrumentSampleBuffer;\n\t\t\t\t\n\t\t\t\tlet mixVolume = +instrumentState.mixVolume;\n\t\t\t\tconst mixVolumeDelta = +instrumentState.mixVolumeDelta;`\n\t\t\t\n\t\t\tif (usesDelays) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tlet delayInputMult = +instrumentState.delayInputMult;\n\t\t\t\tconst delayInputMultDelta = +instrumentState.delayInputMultDelta;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesDistortion) {\n\t\t\t\t// Distortion can sometimes create noticeable aliasing.\n\t\t\t\t// It seems the established industry best practice for distortion antialiasing\n\t\t\t\t// is to upsample the inputs (\"zero stuffing\" followed by a brick wall lowpass\n\t\t\t\t// at the original nyquist frequency), perform the distortion, then downsample\n\t\t\t\t// (the lowpass again followed by dropping in-between samples). This is\n\t\t\t\t// \"mathematically correct\" in that it preserves only the intended frequencies,\n\t\t\t\t// but it has several unfortunate tradeoffs depending on the choice of filter,\n\t\t\t\t// introducing latency and/or time smearing, since no true brick wall filter\n\t\t\t\t// exists. For the time being, I've opted to instead generate in-between input\n\t\t\t\t// samples using fractional delay all-pass filters, and after distorting them,\n\t\t\t\t// I \"downsample\" these with a simple weighted sum.\n\t\t\t\t\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tconst distortionBaseVolume = +Config.distortionBaseVolume;\n\t\t\t\tlet distortion = instrumentState.distortion;\n\t\t\t\tconst distortionDelta = instrumentState.distortionDelta;\n\t\t\t\tlet distortionDrive = instrumentState.distortionDrive;\n\t\t\t\tconst distortionDriveDelta = instrumentState.distortionDriveDelta;\n\t\t\t\tconst distortionFractionalResolution = 4.0;\n\t\t\t\tconst distortionOversampleCompensation = distortionBaseVolume / distortionFractionalResolution;\n\t\t\t\tconst distortionFractionalDelay1 = 1.0 / distortionFractionalResolution;\n\t\t\t\tconst distortionFractionalDelay2 = 2.0 / distortionFractionalResolution;\n\t\t\t\tconst distortionFractionalDelay3 = 3.0 / distortionFractionalResolution;\n\t\t\t\tconst distortionFractionalDelayG1 = (1.0 - distortionFractionalDelay1) / (1.0 + distortionFractionalDelay1); // Inlined version of FilterCoefficients.prototype.allPass1stOrderFractionalDelay\n\t\t\t\tconst distortionFractionalDelayG2 = (1.0 - distortionFractionalDelay2) / (1.0 + distortionFractionalDelay2); // Inlined version of FilterCoefficients.prototype.allPass1stOrderFractionalDelay\n\t\t\t\tconst distortionFractionalDelayG3 = (1.0 - distortionFractionalDelay3) / (1.0 + distortionFractionalDelay3); // Inlined version of FilterCoefficients.prototype.allPass1stOrderFractionalDelay\n\t\t\t\tconst distortionNextOutputWeight1 = Math.cos(Math.PI * distortionFractionalDelay1) * 0.5 + 0.5;\n\t\t\t\tconst distortionNextOutputWeight2 = Math.cos(Math.PI * distortionFractionalDelay2) * 0.5 + 0.5;\n\t\t\t\tconst distortionNextOutputWeight3 = Math.cos(Math.PI * distortionFractionalDelay3) * 0.5 + 0.5;\n\t\t\t\tconst distortionPrevOutputWeight1 = 1.0 - distortionNextOutputWeight1;\n\t\t\t\tconst distortionPrevOutputWeight2 = 1.0 - distortionNextOutputWeight2;\n\t\t\t\tconst distortionPrevOutputWeight3 = 1.0 - distortionNextOutputWeight3;\n\t\t\t\t\n\t\t\t\tlet distortionFractionalInput1 = +instrumentState.distortionFractionalInput1;\n\t\t\t\tlet distortionFractionalInput2 = +instrumentState.distortionFractionalInput2;\n\t\t\t\tlet distortionFractionalInput3 = +instrumentState.distortionFractionalInput3;\n\t\t\t\tlet distortionPrevInput = +instrumentState.distortionPrevInput;\n\t\t\t\tlet distortionNextOutput = +instrumentState.distortionNextOutput;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesBitcrusher) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tlet bitcrusherPrevInput = +instrumentState.bitcrusherPrevInput;\n\t\t\t\tlet bitcrusherCurrentOutput = +instrumentState.bitcrusherCurrentOutput;\n\t\t\t\tlet bitcrusherPhase = +instrumentState.bitcrusherPhase;\n\t\t\t\tlet bitcrusherPhaseDelta = +instrumentState.bitcrusherPhaseDelta;\n\t\t\t\tconst bitcrusherPhaseDeltaScale = +instrumentState.bitcrusherPhaseDeltaScale;\n\t\t\t\tlet bitcrusherScale = +instrumentState.bitcrusherScale;\n\t\t\t\tconst bitcrusherScaleScale = +instrumentState.bitcrusherScaleScale;\n\t\t\t\tlet bitcrusherFoldLevel = +instrumentState.bitcrusherFoldLevel;\n\t\t\t\tconst bitcrusherFoldLevelScale = +instrumentState.bitcrusherFoldLevelScale;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesEqFilter) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tlet filters = instrumentState.eqFilters;\n\t\t\t\tconst filterCount = instrumentState.eqFilterCount|0;\n\t\t\t\tlet initialFilterInput1 = +instrumentState.initialEqFilterInput1;\n\t\t\t\tlet initialFilterInput2 = +instrumentState.initialEqFilterInput2;\n\t\t\t\tconst applyFilters = Synth.applyFilters;`\n\t\t\t}\n\t\t\t\n\t\t\t// The eq filter volume is also used to fade out the instrument state, so always include it.\n\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tlet eqFilterVolume = +instrumentState.eqFilterVolume;\n\t\t\t\tconst eqFilterVolumeDelta = +instrumentState.eqFilterVolumeDelta;`\n\t\t\t\n\t\t\tif (usesPanning) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tconst panningMask = synth.panningDelayBufferMask >>> 0;\n\t\t\t\tconst panningDelayLine = instrumentState.panningDelayLine;\n\t\t\t\tlet panningDelayPos = instrumentState.panningDelayPos & panningMask;\n\t\t\t\tlet panningVolumeL = +instrumentState.panningVolumeL;\n\t\t\t\tlet panningVolumeR = +instrumentState.panningVolumeR;\n\t\t\t\tconst panningVolumeDeltaL = +instrumentState.panningVolumeDeltaL;\n\t\t\t\tconst panningVolumeDeltaR = +instrumentState.panningVolumeDeltaR;\n\t\t\t\tlet panningOffsetL = +instrumentState.panningOffsetL;\n\t\t\t\tlet panningOffsetR = +instrumentState.panningOffsetR;\n\t\t\t\tconst panningOffsetDeltaL = 1.0 - instrumentState.panningOffsetDeltaL;\n\t\t\t\tconst panningOffsetDeltaR = 1.0 - instrumentState.panningOffsetDeltaR;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesChorus) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tconst chorusMask = synth.chorusDelayBufferMask >>> 0;\n\t\t\t\tconst chorusDelayLineL = instrumentState.chorusDelayLineL;\n\t\t\t\tconst chorusDelayLineR = instrumentState.chorusDelayLineR;\n\t\t\t\tinstrumentState.chorusDelayLineDirty = true;\n\t\t\t\tlet chorusDelayPos = instrumentState.chorusDelayPos & chorusMask;\n\t\t\t\t\n\t\t\t\tlet chorusVoiceMult = +instrumentState.chorusVoiceMult;\n\t\t\t\tconst chorusVoiceMultDelta = +instrumentState.chorusVoiceMultDelta;\n\t\t\t\tlet chorusCombinedMult = +instrumentState.chorusCombinedMult;\n\t\t\t\tconst chorusCombinedMultDelta = +instrumentState.chorusCombinedMultDelta;\n\t\t\t\t\n\t\t\t\tconst chorusDuration = +Config.chorusPeriodSeconds;\n\t\t\t\tconst chorusAngle = Math.PI * 2.0 / (chorusDuration * synth.samplesPerSecond);\n\t\t\t\tconst chorusRange = synth.samplesPerSecond * Config.chorusDelayRange;\n\t\t\t\tconst chorusOffset0 = synth.chorusDelayBufferSize - Config.chorusDelayOffsets[0][0] * chorusRange;\n\t\t\t\tconst chorusOffset1 = synth.chorusDelayBufferSize - Config.chorusDelayOffsets[0][1] * chorusRange;\n\t\t\t\tconst chorusOffset2 = synth.chorusDelayBufferSize - Config.chorusDelayOffsets[0][2] * chorusRange;\n\t\t\t\tconst chorusOffset3 = synth.chorusDelayBufferSize - Config.chorusDelayOffsets[1][0] * chorusRange;\n\t\t\t\tconst chorusOffset4 = synth.chorusDelayBufferSize - Config.chorusDelayOffsets[1][1] * chorusRange;\n\t\t\t\tconst chorusOffset5 = synth.chorusDelayBufferSize - Config.chorusDelayOffsets[1][2] * chorusRange;\n\t\t\t\tlet chorusPhase = instrumentState.chorusPhase % (Math.PI * 2.0);\n\t\t\t\tlet chorusTap0Index = chorusDelayPos + chorusOffset0 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[0][0]);\n\t\t\t\tlet chorusTap1Index = chorusDelayPos + chorusOffset1 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[0][1]);\n\t\t\t\tlet chorusTap2Index = chorusDelayPos + chorusOffset2 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[0][2]);\n\t\t\t\tlet chorusTap3Index = chorusDelayPos + chorusOffset3 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[1][0]);\n\t\t\t\tlet chorusTap4Index = chorusDelayPos + chorusOffset4 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[1][1]);\n\t\t\t\tlet chorusTap5Index = chorusDelayPos + chorusOffset5 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[1][2]);\n\t\t\t\tchorusPhase += chorusAngle * runLength;\n\t\t\t\tconst chorusTap0End = chorusDelayPos + chorusOffset0 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[0][0]) + runLength;\n\t\t\t\tconst chorusTap1End = chorusDelayPos + chorusOffset1 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[0][1]) + runLength;\n\t\t\t\tconst chorusTap2End = chorusDelayPos + chorusOffset2 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[0][2]) + runLength;\n\t\t\t\tconst chorusTap3End = chorusDelayPos + chorusOffset3 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[1][0]) + runLength;\n\t\t\t\tconst chorusTap4End = chorusDelayPos + chorusOffset4 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[1][1]) + runLength;\n\t\t\t\tconst chorusTap5End = chorusDelayPos + chorusOffset5 - chorusRange * Math.sin(chorusPhase + Config.chorusPhaseOffsets[1][2]) + runLength;\n\t\t\t\tconst chorusTap0Delta = (chorusTap0End - chorusTap0Index) / runLength;\n\t\t\t\tconst chorusTap1Delta = (chorusTap1End - chorusTap1Index) / runLength;\n\t\t\t\tconst chorusTap2Delta = (chorusTap2End - chorusTap2Index) / runLength;\n\t\t\t\tconst chorusTap3Delta = (chorusTap3End - chorusTap3Index) / runLength;\n\t\t\t\tconst chorusTap4Delta = (chorusTap4End - chorusTap4Index) / runLength;\n\t\t\t\tconst chorusTap5Delta = (chorusTap5End - chorusTap5Index) / runLength;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesEcho) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tlet echoMult = +instrumentState.echoMult;\n\t\t\t\tconst echoMultDelta = +instrumentState.echoMultDelta;\n\t\t\t\t\n\t\t\t\tconst echoDelayLineL = instrumentState.echoDelayLineL;\n\t\t\t\tconst echoDelayLineR = instrumentState.echoDelayLineR;\n\t\t\t\tconst echoMask = (echoDelayLineL.length - 1) >>> 0;\n\t\t\t\tinstrumentState.echoDelayLineDirty = true;\n\t\t\t\t\n\t\t\t\tlet echoDelayPos = instrumentState.echoDelayPos & echoMask;\n\t\t\t\tconst echoDelayOffsetStart = (echoDelayLineL.length - instrumentState.echoDelayOffsetStart) & echoMask;\n\t\t\t\tconst echoDelayOffsetEnd = (echoDelayLineL.length - instrumentState.echoDelayOffsetEnd) & echoMask;\n\t\t\t\tlet echoDelayOffsetRatio = +instrumentState.echoDelayOffsetRatio;\n\t\t\t\tconst echoDelayOffsetRatioDelta = +instrumentState.echoDelayOffsetRatioDelta;\n\t\t\t\t\n\t\t\t\tconst echoShelfA1 = +instrumentState.echoShelfA1;\n\t\t\t\tconst echoShelfB0 = +instrumentState.echoShelfB0;\n\t\t\t\tconst echoShelfB1 = +instrumentState.echoShelfB1;\n\t\t\t\tlet echoShelfSampleL = +instrumentState.echoShelfSampleL;\n\t\t\t\tlet echoShelfSampleR = +instrumentState.echoShelfSampleR;\n\t\t\t\tlet echoShelfPrevInputL = +instrumentState.echoShelfPrevInputL;\n\t\t\t\tlet echoShelfPrevInputR = +instrumentState.echoShelfPrevInputR;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesReverb) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tconst reverbMask = Config.reverbDelayBufferMask >>> 0; //TODO: Dynamic reverb buffer size.\n\t\t\t\tconst reverbDelayLine = instrumentState.reverbDelayLine;\n\t\t\t\tinstrumentState.reverbDelayLineDirty = true;\n\t\t\t\tlet reverbDelayPos = instrumentState.reverbDelayPos & reverbMask;\n\t\t\t\t\n\t\t\t\tlet reverb = +instrumentState.reverbMult;\n\t\t\t\tconst reverbDelta = +instrumentState.reverbMultDelta;\n\t\t\t\t\n\t\t\t\tconst reverbShelfA1 = +instrumentState.reverbShelfA1;\n\t\t\t\tconst reverbShelfB0 = +instrumentState.reverbShelfB0;\n\t\t\t\tconst reverbShelfB1 = +instrumentState.reverbShelfB1;\n\t\t\t\tlet reverbShelfSample0 = +instrumentState.reverbShelfSample0;\n\t\t\t\tlet reverbShelfSample1 = +instrumentState.reverbShelfSample1;\n\t\t\t\tlet reverbShelfSample2 = +instrumentState.reverbShelfSample2;\n\t\t\t\tlet reverbShelfSample3 = +instrumentState.reverbShelfSample3;\n\t\t\t\tlet reverbShelfPrevInput0 = +instrumentState.reverbShelfPrevInput0;\n\t\t\t\tlet reverbShelfPrevInput1 = +instrumentState.reverbShelfPrevInput1;\n\t\t\t\tlet reverbShelfPrevInput2 = +instrumentState.reverbShelfPrevInput2;\n\t\t\t\tlet reverbShelfPrevInput3 = +instrumentState.reverbShelfPrevInput3;`\n\t\t\t}\n\t\t\t\n\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tconst stopIndex = bufferIndex + runLength;\n\t\t\t\tfor (let sampleIndex = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\t\t\tlet sample = tempMonoInstrumentSampleBuffer[sampleIndex];\n\t\t\t\t\ttempMonoInstrumentSampleBuffer[sampleIndex] = 0.0;`\n\t\t\t\n\t\t\tif (usesDistortion) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\tconst distortionReverse = 1.0 - distortion;\n\t\t\t\t\tconst distortionNextInput = sample * distortionDrive;\n\t\t\t\t\tsample = distortionNextOutput;\n\t\t\t\t\tdistortionNextOutput = distortionNextInput / (distortionReverse * Math.abs(distortionNextInput) + distortion);\n\t\t\t\t\tdistortionFractionalInput1 = distortionFractionalDelayG1 * distortionNextInput + distortionPrevInput - distortionFractionalDelayG1 * distortionFractionalInput1;\n\t\t\t\t\tdistortionFractionalInput2 = distortionFractionalDelayG2 * distortionNextInput + distortionPrevInput - distortionFractionalDelayG2 * distortionFractionalInput2;\n\t\t\t\t\tdistortionFractionalInput3 = distortionFractionalDelayG3 * distortionNextInput + distortionPrevInput - distortionFractionalDelayG3 * distortionFractionalInput3;\n\t\t\t\t\tconst distortionOutput1 = distortionFractionalInput1 / (distortionReverse * Math.abs(distortionFractionalInput1) + distortion);\n\t\t\t\t\tconst distortionOutput2 = distortionFractionalInput2 / (distortionReverse * Math.abs(distortionFractionalInput2) + distortion);\n\t\t\t\t\tconst distortionOutput3 = distortionFractionalInput3 / (distortionReverse * Math.abs(distortionFractionalInput3) + distortion);\n\t\t\t\t\tdistortionNextOutput += distortionOutput1 * distortionNextOutputWeight1 + distortionOutput2 * distortionNextOutputWeight2 + distortionOutput3 * distortionNextOutputWeight3;\n\t\t\t\t\tsample += distortionOutput1 * distortionPrevOutputWeight1 + distortionOutput2 * distortionPrevOutputWeight2 + distortionOutput3 * distortionPrevOutputWeight3;\n\t\t\t\t\tsample *= distortionOversampleCompensation;\n\t\t\t\t\tdistortionPrevInput = distortionNextInput;\n\t\t\t\t\tdistortion += distortionDelta;\n\t\t\t\t\tdistortionDrive += distortionDriveDelta;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesBitcrusher) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\tbitcrusherPhase += bitcrusherPhaseDelta;\n\t\t\t\t\tif (bitcrusherPhase < 1.0) {\n\t\t\t\t\t\tbitcrusherPrevInput = sample;\n\t\t\t\t\t\tsample = bitcrusherCurrentOutput;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbitcrusherPhase = bitcrusherPhase % 1.0;\n\t\t\t\t\t\tconst ratio = bitcrusherPhase / bitcrusherPhaseDelta;\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst lerpedInput = sample + (bitcrusherPrevInput - sample) * ratio;\n\t\t\t\t\t\tbitcrusherPrevInput = sample;\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst bitcrusherWrapLevel = bitcrusherFoldLevel * 4.0;\n\t\t\t\t\t\tconst wrappedSample = (((lerpedInput + bitcrusherFoldLevel) % bitcrusherWrapLevel) + bitcrusherWrapLevel) % bitcrusherWrapLevel;\n\t\t\t\t\t\tconst foldedSample = bitcrusherFoldLevel - Math.abs(bitcrusherFoldLevel * 2.0 - wrappedSample);\n\t\t\t\t\t\tconst scaledSample = foldedSample / bitcrusherScale;\n\t\t\t\t\t\tconst oldValue = bitcrusherCurrentOutput;\n\t\t\t\t\t\tconst newValue = (((scaledSample > 0 ? scaledSample + 1 : scaledSample)|0)-.5) * bitcrusherScale;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsample = oldValue + (newValue - oldValue) * ratio;\n\t\t\t\t\t\tbitcrusherCurrentOutput = newValue;\n\t\t\t\t\t}\n\t\t\t\t\tbitcrusherPhaseDelta *= bitcrusherPhaseDeltaScale;\n\t\t\t\t\tbitcrusherScale *= bitcrusherScaleScale;\n\t\t\t\t\tbitcrusherFoldLevel *= bitcrusherFoldLevelScale;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesEqFilter) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\tconst inputSample = sample;\n\t\t\t\t\tsample = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\t\t\tinitialFilterInput1 = inputSample;`\n\t\t\t}\n\t\t\t\n\t\t\t// The eq filter volume is also used to fade out the instrument state, so always include it.\n\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\tsample *= eqFilterVolume;\n\t\t\t\t\teqFilterVolume += eqFilterVolumeDelta;`\n\t\t\t\n\t\t\tif (usesPanning) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\tpanningDelayLine[panningDelayPos] = sample;\n\t\t\t\t\tconst panningRatioL = panningOffsetL % 1;\n\t\t\t\t\tconst panningRatioR = panningOffsetR % 1;\n\t\t\t\t\tconst panningTapLA = panningDelayLine[(panningOffsetL) & panningMask];\n\t\t\t\t\tconst panningTapLB = panningDelayLine[(panningOffsetL + 1) & panningMask];\n\t\t\t\t\tconst panningTapRA = panningDelayLine[(panningOffsetR) & panningMask];\n\t\t\t\t\tconst panningTapRB = panningDelayLine[(panningOffsetR + 1) & panningMask];\n\t\t\t\t\tconst panningTapL = panningTapLA + (panningTapLB - panningTapLA) * panningRatioL;\n\t\t\t\t\tconst panningTapR = panningTapRA + (panningTapRB - panningTapRA) * panningRatioR;\n\t\t\t\t\tlet sampleL = panningTapL * panningVolumeL;\n\t\t\t\t\tlet sampleR = panningTapR * panningVolumeR;\n\t\t\t\t\tpanningDelayPos = (panningDelayPos + 1) & panningMask;\n\t\t\t\t\tpanningVolumeL += panningVolumeDeltaL;\n\t\t\t\t\tpanningVolumeR += panningVolumeDeltaR;\n\t\t\t\t\tpanningOffsetL += panningOffsetDeltaL;\n\t\t\t\t\tpanningOffsetR += panningOffsetDeltaR;`\n\t\t\t} else {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\tlet sampleL = sample;\n\t\t\t\t\tlet sampleR = sample;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesChorus) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\tconst chorusTap0Ratio = chorusTap0Index % 1;\n\t\t\t\t\tconst chorusTap1Ratio = chorusTap1Index % 1;\n\t\t\t\t\tconst chorusTap2Ratio = chorusTap2Index % 1;\n\t\t\t\t\tconst chorusTap3Ratio = chorusTap3Index % 1;\n\t\t\t\t\tconst chorusTap4Ratio = chorusTap4Index % 1;\n\t\t\t\t\tconst chorusTap5Ratio = chorusTap5Index % 1;\n\t\t\t\t\tconst chorusTap0A = chorusDelayLineL[(chorusTap0Index) & chorusMask];\n\t\t\t\t\tconst chorusTap0B = chorusDelayLineL[(chorusTap0Index + 1) & chorusMask];\n\t\t\t\t\tconst chorusTap1A = chorusDelayLineL[(chorusTap1Index) & chorusMask];\n\t\t\t\t\tconst chorusTap1B = chorusDelayLineL[(chorusTap1Index + 1) & chorusMask];\n\t\t\t\t\tconst chorusTap2A = chorusDelayLineL[(chorusTap2Index) & chorusMask];\n\t\t\t\t\tconst chorusTap2B = chorusDelayLineL[(chorusTap2Index + 1) & chorusMask];\n\t\t\t\t\tconst chorusTap3A = chorusDelayLineR[(chorusTap3Index) & chorusMask];\n\t\t\t\t\tconst chorusTap3B = chorusDelayLineR[(chorusTap3Index + 1) & chorusMask];\n\t\t\t\t\tconst chorusTap4A = chorusDelayLineR[(chorusTap4Index) & chorusMask];\n\t\t\t\t\tconst chorusTap4B = chorusDelayLineR[(chorusTap4Index + 1) & chorusMask];\n\t\t\t\t\tconst chorusTap5A = chorusDelayLineR[(chorusTap5Index) & chorusMask];\n\t\t\t\t\tconst chorusTap5B = chorusDelayLineR[(chorusTap5Index + 1) & chorusMask];\n\t\t\t\t\tconst chorusTap0 = chorusTap0A + (chorusTap0B - chorusTap0A) * chorusTap0Ratio;\n\t\t\t\t\tconst chorusTap1 = chorusTap1A + (chorusTap1B - chorusTap1A) * chorusTap1Ratio;\n\t\t\t\t\tconst chorusTap2 = chorusTap2A + (chorusTap2B - chorusTap2A) * chorusTap2Ratio;\n\t\t\t\t\tconst chorusTap3 = chorusTap3A + (chorusTap3B - chorusTap3A) * chorusTap3Ratio;\n\t\t\t\t\tconst chorusTap4 = chorusTap4A + (chorusTap4B - chorusTap4A) * chorusTap4Ratio;\n\t\t\t\t\tconst chorusTap5 = chorusTap5A + (chorusTap5B - chorusTap5A) * chorusTap5Ratio;\n\t\t\t\t\tchorusDelayLineL[chorusDelayPos] = sampleL * delayInputMult;\n\t\t\t\t\tchorusDelayLineR[chorusDelayPos] = sampleR * delayInputMult;\n\t\t\t\t\tsampleL = chorusCombinedMult * (sampleL + chorusVoiceMult * (chorusTap1 - chorusTap0 - chorusTap2));\n\t\t\t\t\tsampleR = chorusCombinedMult * (sampleR + chorusVoiceMult * (chorusTap4 - chorusTap3 - chorusTap5));\n\t\t\t\t\tchorusDelayPos = (chorusDelayPos + 1) & chorusMask;\n\t\t\t\t\tchorusTap0Index += chorusTap0Delta;\n\t\t\t\t\tchorusTap1Index += chorusTap1Delta;\n\t\t\t\t\tchorusTap2Index += chorusTap2Delta;\n\t\t\t\t\tchorusTap3Index += chorusTap3Delta;\n\t\t\t\t\tchorusTap4Index += chorusTap4Delta;\n\t\t\t\t\tchorusTap5Index += chorusTap5Delta;\n\t\t\t\t\tchorusVoiceMult += chorusVoiceMultDelta;\n\t\t\t\t\tchorusCombinedMult += chorusCombinedMultDelta;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesEcho) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\tconst echoTapStartIndex = (echoDelayPos + echoDelayOffsetStart) & echoMask;\n\t\t\t\t\tconst echoTapEndIndex = (echoDelayPos + echoDelayOffsetEnd ) & echoMask;\n\t\t\t\t\tconst echoTapStartL = echoDelayLineL[echoTapStartIndex];\n\t\t\t\t\tconst echoTapEndL = echoDelayLineL[echoTapEndIndex];\n\t\t\t\t\tconst echoTapStartR = echoDelayLineR[echoTapStartIndex];\n\t\t\t\t\tconst echoTapEndR = echoDelayLineR[echoTapEndIndex];\n\t\t\t\t\tconst echoTapL = (echoTapStartL + (echoTapEndL - echoTapStartL) * echoDelayOffsetRatio) * echoMult;\n\t\t\t\t\tconst echoTapR = (echoTapStartR + (echoTapEndR - echoTapStartR) * echoDelayOffsetRatio) * echoMult;\n\t\t\t\t\t\n\t\t\t\t\techoShelfSampleL = echoShelfB0 * echoTapL + echoShelfB1 * echoShelfPrevInputL - echoShelfA1 * echoShelfSampleL;\n\t\t\t\t\techoShelfSampleR = echoShelfB0 * echoTapR + echoShelfB1 * echoShelfPrevInputR - echoShelfA1 * echoShelfSampleR;\n\t\t\t\t\techoShelfPrevInputL = echoTapL;\n\t\t\t\t\techoShelfPrevInputR = echoTapR;\n\t\t\t\t\tsampleL += echoShelfSampleL;\n\t\t\t\t\tsampleR += echoShelfSampleR;\n\t\t\t\t\t\n\t\t\t\t\techoDelayLineL[echoDelayPos] = sampleL * delayInputMult;\n\t\t\t\t\techoDelayLineR[echoDelayPos] = sampleR * delayInputMult;\n\t\t\t\t\techoDelayPos = (echoDelayPos + 1) & echoMask;\n\t\t\t\t\techoDelayOffsetRatio += echoDelayOffsetRatioDelta;\n\t\t\t\t\techoMult += echoMultDelta;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesReverb) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\t// Reverb, implemented using a feedback delay network with a Hadamard matrix and lowpass filters.\n\t\t\t\t\t// good ratios: 0.555235 + 0.618033 + 0.818 + 1.0 = 2.991268\n\t\t\t\t\t// Delay lengths: 3041 + 3385 + 4481 + 5477 = 16384 = 2^14\n\t\t\t\t\t// Buffer offsets: 3041 -> 6426 -> 10907 -> 16384\n\t\t\t\t\tconst reverbDelayPos1 = (reverbDelayPos + 3041) & reverbMask;\n\t\t\t\t\tconst reverbDelayPos2 = (reverbDelayPos + 6426) & reverbMask;\n\t\t\t\t\tconst reverbDelayPos3 = (reverbDelayPos + 10907) & reverbMask;\n\t\t\t\t\tconst reverbSample0 = (reverbDelayLine[reverbDelayPos]);\n\t\t\t\t\tconst reverbSample1 = reverbDelayLine[reverbDelayPos1];\n\t\t\t\t\tconst reverbSample2 = reverbDelayLine[reverbDelayPos2];\n\t\t\t\t\tconst reverbSample3 = reverbDelayLine[reverbDelayPos3];\n\t\t\t\t\tconst reverbTemp0 = -(reverbSample0 + sampleL) + reverbSample1;\n\t\t\t\t\tconst reverbTemp1 = -(reverbSample0 + sampleR) - reverbSample1;\n\t\t\t\t\tconst reverbTemp2 = -reverbSample2 + reverbSample3;\n\t\t\t\t\tconst reverbTemp3 = -reverbSample2 - reverbSample3;\n\t\t\t\t\tconst reverbShelfInput0 = (reverbTemp0 + reverbTemp2) * reverb;\n\t\t\t\t\tconst reverbShelfInput1 = (reverbTemp1 + reverbTemp3) * reverb;\n\t\t\t\t\tconst reverbShelfInput2 = (reverbTemp0 - reverbTemp2) * reverb;\n\t\t\t\t\tconst reverbShelfInput3 = (reverbTemp1 - reverbTemp3) * reverb;\n\t\t\t\t\treverbShelfSample0 = reverbShelfB0 * reverbShelfInput0 + reverbShelfB1 * reverbShelfPrevInput0 - reverbShelfA1 * reverbShelfSample0;\n\t\t\t\t\treverbShelfSample1 = reverbShelfB0 * reverbShelfInput1 + reverbShelfB1 * reverbShelfPrevInput1 - reverbShelfA1 * reverbShelfSample1;\n\t\t\t\t\treverbShelfSample2 = reverbShelfB0 * reverbShelfInput2 + reverbShelfB1 * reverbShelfPrevInput2 - reverbShelfA1 * reverbShelfSample2;\n\t\t\t\t\treverbShelfSample3 = reverbShelfB0 * reverbShelfInput3 + reverbShelfB1 * reverbShelfPrevInput3 - reverbShelfA1 * reverbShelfSample3;\n\t\t\t\t\treverbShelfPrevInput0 = reverbShelfInput0;\n\t\t\t\t\treverbShelfPrevInput1 = reverbShelfInput1;\n\t\t\t\t\treverbShelfPrevInput2 = reverbShelfInput2;\n\t\t\t\t\treverbShelfPrevInput3 = reverbShelfInput3;\n\t\t\t\t\treverbDelayLine[reverbDelayPos1] = reverbShelfSample0 * delayInputMult;\n\t\t\t\t\treverbDelayLine[reverbDelayPos2] = reverbShelfSample1 * delayInputMult;\n\t\t\t\t\treverbDelayLine[reverbDelayPos3] = reverbShelfSample2 * delayInputMult;\n\t\t\t\t\treverbDelayLine[reverbDelayPos ] = reverbShelfSample3 * delayInputMult;\n\t\t\t\t\treverbDelayPos = (reverbDelayPos + 1) & reverbMask;\n\t\t\t\t\tsampleL += reverbSample1 + reverbSample2 + reverbSample3;\n\t\t\t\t\tsampleR += reverbSample0 + reverbSample2 - reverbSample3;\n\t\t\t\t\treverb += reverbDelta;`\n\t\t\t}\n\t\t\t\n\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\toutputDataL[sampleIndex] += sampleL * mixVolume;\n\t\t\t\t\toutputDataR[sampleIndex] += sampleR * mixVolume;\n\t\t\t\t\tmixVolume += mixVolumeDelta;`\n\t\t\t\n\t\t\tif (usesDelays) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\t\tdelayInputMult += delayInputMultDelta;`\n\t\t\t}\n\t\t\t\n\t\t\teffectsSource += `\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tinstrumentState.mixVolume = mixVolume;\n\t\t\t\tinstrumentState.eqFilterVolume = eqFilterVolume;\n\t\t\t\t\n\t\t\t\t// Avoid persistent denormal or NaN values in the delay buffers and filter history.\n\t\t\t\tconst epsilon = (1.0e-24);`\n\t\t\t\n\t\t\tif (usesDelays) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tinstrumentState.delayInputMult = delayInputMult;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesDistortion) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tinstrumentState.distortion = distortion;\n\t\t\t\tinstrumentState.distortionDrive = distortionDrive;\n\t\t\t\t\n\t\t\t\tif (!Number.isFinite(distortionFractionalInput1) || Math.abs(distortionFractionalInput1) < epsilon) distortionFractionalInput1 = 0.0;\n\t\t\t\tif (!Number.isFinite(distortionFractionalInput2) || Math.abs(distortionFractionalInput2) < epsilon) distortionFractionalInput2 = 0.0;\n\t\t\t\tif (!Number.isFinite(distortionFractionalInput3) || Math.abs(distortionFractionalInput3) < epsilon) distortionFractionalInput3 = 0.0;\n\t\t\t\tif (!Number.isFinite(distortionPrevInput) || Math.abs(distortionPrevInput) < epsilon) distortionPrevInput = 0.0;\n\t\t\t\tif (!Number.isFinite(distortionNextOutput) || Math.abs(distortionNextOutput) < epsilon) distortionNextOutput = 0.0;\n\t\t\t\t\n\t\t\t\tinstrumentState.distortionFractionalInput1 = distortionFractionalInput1;\n\t\t\t\tinstrumentState.distortionFractionalInput2 = distortionFractionalInput2;\n\t\t\t\tinstrumentState.distortionFractionalInput3 = distortionFractionalInput3;\n\t\t\t\tinstrumentState.distortionPrevInput = distortionPrevInput;\n\t\t\t\tinstrumentState.distortionNextOutput = distortionNextOutput;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesBitcrusher) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\tif (Math.abs(bitcrusherPrevInput) < epsilon) bitcrusherPrevInput = 0.0;\n\t\t\t\tif (Math.abs(bitcrusherCurrentOutput) < epsilon) bitcrusherCurrentOutput = 0.0;\n\t\t\t\tinstrumentState.bitcrusherPrevInput = bitcrusherPrevInput;\n\t\t\t\tinstrumentState.bitcrusherCurrentOutput = bitcrusherCurrentOutput;\n\t\t\t\tinstrumentState.bitcrusherPhase = bitcrusherPhase;\n\t\t\t\tinstrumentState.bitcrusherPhaseDelta = bitcrusherPhaseDelta;\n\t\t\t\tinstrumentState.bitcrusherScale = bitcrusherScale;\n\t\t\t\tinstrumentState.bitcrusherFoldLevel = bitcrusherFoldLevel;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesEqFilter) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\t\n\t\t\t\tsynth.sanitizeFilters(filters);\n\t\t\t\t// The filter input here is downstream from another filter so we\n\t\t\t\t// better make sure it's safe too.\n\t\t\t\tif (!(initialFilterInput1 < 100) || !(initialFilterInput2 < 100)) {\n\t\t\t\t\tinitialFilterInput1 = 0.0;\n\t\t\t\t\tinitialFilterInput2 = 0.0;\n\t\t\t\t}\n\t\t\t\tif (Math.abs(initialFilterInput1) < epsilon) initialFilterInput1 = 0.0;\n\t\t\t\tif (Math.abs(initialFilterInput2) < epsilon) initialFilterInput2 = 0.0;\n\t\t\t\tinstrumentState.initialEqFilterInput1 = initialFilterInput1;\n\t\t\t\tinstrumentState.initialEqFilterInput2 = initialFilterInput2;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesPanning) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tSynth.sanitizeDelayLine(panningDelayLine, panningDelayPos, panningMask);\n\t\t\t\tinstrumentState.panningDelayPos = panningDelayPos;\n\t\t\t\tinstrumentState.panningVolumeL = panningVolumeL;\n\t\t\t\tinstrumentState.panningVolumeR = panningVolumeR;\n\t\t\t\tinstrumentState.panningOffsetL = panningOffsetL;\n\t\t\t\tinstrumentState.panningOffsetR = panningOffsetR;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesChorus) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tSynth.sanitizeDelayLine(chorusDelayLineL, chorusDelayPos, chorusMask);\n\t\t\t\tSynth.sanitizeDelayLine(chorusDelayLineR, chorusDelayPos, chorusMask);\n\t\t\t\tinstrumentState.chorusPhase = chorusPhase;\n\t\t\t\tinstrumentState.chorusDelayPos = chorusDelayPos;\n\t\t\t\tinstrumentState.chorusVoiceMult = chorusVoiceMult;\n\t\t\t\tinstrumentState.chorusCombinedMult = chorusCombinedMult;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesEcho) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tSynth.sanitizeDelayLine(echoDelayLineL, echoDelayPos, echoMask);\n\t\t\t\tSynth.sanitizeDelayLine(echoDelayLineR, echoDelayPos, echoMask);\n\t\t\t\tinstrumentState.echoDelayPos = echoDelayPos;\n\t\t\t\tinstrumentState.echoMult = echoMult;\n\t\t\t\tinstrumentState.echoDelayOffsetRatio = echoDelayOffsetRatio;\n\t\t\t\t\n\t\t\t\tif (!Number.isFinite(echoShelfSampleL) || Math.abs(echoShelfSampleL) < epsilon) echoShelfSampleL = 0.0;\n\t\t\t\tif (!Number.isFinite(echoShelfSampleR) || Math.abs(echoShelfSampleR) < epsilon) echoShelfSampleR = 0.0;\n\t\t\t\tif (!Number.isFinite(echoShelfPrevInputL) || Math.abs(echoShelfPrevInputL) < epsilon) echoShelfPrevInputL = 0.0;\n\t\t\t\tif (!Number.isFinite(echoShelfPrevInputR) || Math.abs(echoShelfPrevInputR) < epsilon) echoShelfPrevInputR = 0.0;\n\t\t\t\tinstrumentState.echoShelfSampleL = echoShelfSampleL;\n\t\t\t\tinstrumentState.echoShelfSampleR = echoShelfSampleR;\n\t\t\t\tinstrumentState.echoShelfPrevInputL = echoShelfPrevInputL;\n\t\t\t\tinstrumentState.echoShelfPrevInputR = echoShelfPrevInputR;`\n\t\t\t}\n\t\t\t\n\t\t\tif (usesReverb) {\n\t\t\t\teffectsSource += `\n\t\t\t\t\n\t\t\t\tSynth.sanitizeDelayLine(reverbDelayLine, reverbDelayPos , reverbMask);\n\t\t\t\tSynth.sanitizeDelayLine(reverbDelayLine, reverbDelayPos + 3041, reverbMask);\n\t\t\t\tSynth.sanitizeDelayLine(reverbDelayLine, reverbDelayPos + 6426, reverbMask);\n\t\t\t\tSynth.sanitizeDelayLine(reverbDelayLine, reverbDelayPos + 10907, reverbMask);\n\t\t\t\tinstrumentState.reverbDelayPos = reverbDelayPos;\n\t\t\t\tinstrumentState.reverbMult = reverb;\n\t\t\t\t\n\t\t\t\tif (!Number.isFinite(reverbShelfSample0) || Math.abs(reverbShelfSample0) < epsilon) reverbShelfSample0 = 0.0;\n\t\t\t\tif (!Number.isFinite(reverbShelfSample1) || Math.abs(reverbShelfSample1) < epsilon) reverbShelfSample1 = 0.0;\n\t\t\t\tif (!Number.isFinite(reverbShelfSample2) || Math.abs(reverbShelfSample2) < epsilon) reverbShelfSample2 = 0.0;\n\t\t\t\tif (!Number.isFinite(reverbShelfSample3) || Math.abs(reverbShelfSample3) < epsilon) reverbShelfSample3 = 0.0;\n\t\t\t\tif (!Number.isFinite(reverbShelfPrevInput0) || Math.abs(reverbShelfPrevInput0) < epsilon) reverbShelfPrevInput0 = 0.0;\n\t\t\t\tif (!Number.isFinite(reverbShelfPrevInput1) || Math.abs(reverbShelfPrevInput1) < epsilon) reverbShelfPrevInput1 = 0.0;\n\t\t\t\tif (!Number.isFinite(reverbShelfPrevInput2) || Math.abs(reverbShelfPrevInput2) < epsilon) reverbShelfPrevInput2 = 0.0;\n\t\t\t\tif (!Number.isFinite(reverbShelfPrevInput3) || Math.abs(reverbShelfPrevInput3) < epsilon) reverbShelfPrevInput3 = 0.0;\n\t\t\t\tinstrumentState.reverbShelfSample0 = reverbShelfSample0;\n\t\t\t\tinstrumentState.reverbShelfSample1 = reverbShelfSample1;\n\t\t\t\tinstrumentState.reverbShelfSample2 = reverbShelfSample2;\n\t\t\t\tinstrumentState.reverbShelfSample3 = reverbShelfSample3;\n\t\t\t\tinstrumentState.reverbShelfPrevInput0 = reverbShelfPrevInput0;\n\t\t\t\tinstrumentState.reverbShelfPrevInput1 = reverbShelfPrevInput1;\n\t\t\t\tinstrumentState.reverbShelfPrevInput2 = reverbShelfPrevInput2;\n\t\t\t\tinstrumentState.reverbShelfPrevInput3 = reverbShelfPrevInput3;`\n\t\t\t}\n\t\t\t\n\t\t\teffectsSource += \"}\";\n\t\t\t\n\t\t\t//console.log(effectsSource);\n\t\t\teffectsFunction = new Function(\"Config\", \"Synth\", effectsSource)(Config, Synth);\n\t\t\tSynth.effectsFunctionCache[signature] = effectsFunction;\n\t\t}\n\t\t\n\t\teffectsFunction(synth, outputDataL, outputDataR, bufferIndex, runLength, instrumentState);\n\t}\n\t\n\tprivate static pulseWidthSynth(synth: Synth, bufferIndex: number, runLength: number, tone: Tone, instrumentState: InstrumentState): void {\n\t\tconst data: Float32Array = synth.tempMonoInstrumentSampleBuffer!;\n\t\t\n\t\tlet phaseDelta: number = tone.phaseDeltas[0];\n\t\tconst phaseDeltaScale: number = +tone.phaseDeltaScales[0];\n\t\tlet expression: number = +tone.expression;\n\t\tconst expressionDelta: number = +tone.expressionDelta;\n\t\tlet phase: number = (tone.phases[0] % 1);\n\t\t\n\t\tlet pulseWidth: number = tone.pulseWidth;\n\t\tconst pulseWidthDelta: number = tone.pulseWidthDelta;\n\t\t\n\t\tconst filters: DynamicBiquadFilter[] = tone.noteFilters;\n\t\tconst filterCount: number = tone.noteFilterCount|0;\n\t\tlet initialFilterInput1: number = +tone.initialNoteFilterInput1;\n\t\tlet initialFilterInput2: number = +tone.initialNoteFilterInput2;\n\t\tconst applyFilters: Function = Synth.applyFilters;\n\t\t\n\t\tconst stopIndex: number = bufferIndex + runLength;\n\t\tfor (let sampleIndex: number = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\t\n\t\t\tconst sawPhaseA: number = phase % 1;\n\t\t\tconst sawPhaseB: number = (phase + pulseWidth) % 1;\n\t\t\t\n\t\t\tlet pulseWave: number = sawPhaseB - sawPhaseA;\n\t\t\t\n\t\t\t// This is a PolyBLEP, which smooths out discontinuities at any frequency to reduce aliasing. \n\t\t\tif (sawPhaseA < phaseDelta) {\n\t\t\t\tvar t = sawPhaseA / phaseDelta;\n\t\t\t\tpulseWave += (t+t-t*t-1) * 0.5;\n\t\t\t} else if (sawPhaseA > 1.0 - phaseDelta) {\n\t\t\t\tvar t = (sawPhaseA - 1.0) / phaseDelta;\n\t\t\t\tpulseWave += (t+t+t*t+1) * 0.5;\n\t\t\t}\n\t\t\tif (sawPhaseB < phaseDelta) {\n\t\t\t\tvar t = sawPhaseB / phaseDelta;\n\t\t\t\tpulseWave -= (t+t-t*t-1) * 0.5;\n\t\t\t} else if (sawPhaseB > 1.0 - phaseDelta) {\n\t\t\t\tvar t = (sawPhaseB - 1.0) / phaseDelta;\n\t\t\t\tpulseWave -= (t+t+t*t+1) * 0.5;\n\t\t\t}\n\t\t\t\n\t\t\tconst inputSample: number = pulseWave;\n\t\t\tconst sample: number = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\tinitialFilterInput1 = inputSample;\n\t\t\t\n\t\t\tphase += phaseDelta;\n\t\t\tphaseDelta *= phaseDeltaScale;\n\t\t\tpulseWidth += pulseWidthDelta;\n\t\t\t\n\t\t\tconst output: number = sample * expression;\n\t\t\texpression += expressionDelta;\n\t\t\t\n\t\t\tdata[sampleIndex] += output;\n\t\t}\n\t\t\n\t\ttone.phases[0] = phase;\n\t\ttone.phaseDeltas[0] = phaseDelta;\n\t\ttone.expression = expression;\n\t\ttone.pulseWidth = pulseWidth;\n\t\t\n\t\tsynth.sanitizeFilters(filters);\n\t\ttone.initialNoteFilterInput1 = initialFilterInput1;\n\t\ttone.initialNoteFilterInput2 = initialFilterInput2;\n\t}\n\t\n\tprivate static supersawSynth(synth: Synth, bufferIndex: number, runLength: number, tone: Tone, instrumentState: InstrumentState): void {\n\t\tconst data: Float32Array = synth.tempMonoInstrumentSampleBuffer!;\n\t\tconst voiceCount: number = Config.supersawVoiceCount|0;\n\t\t\n\t\tlet phaseDelta: number = tone.phaseDeltas[0];\n\t\tconst phaseDeltaScale: number = +tone.phaseDeltaScales[0];\n\t\tlet expression: number = +tone.expression;\n\t\tconst expressionDelta: number = +tone.expressionDelta;\n\t\tlet phases: number[] = tone.phases;\n\t\t\n\t\tlet dynamism: number = +tone.supersawDynamism;\n\t\tconst dynamismDelta: number = +tone.supersawDynamismDelta;\n\t\tconst unisonDetunes: number[] = tone.supersawUnisonDetunes;\n\t\tlet shape: number = +tone.supersawShape;\n\t\tconst shapeDelta: number = +tone.supersawShapeDelta;\n\t\tlet delayLength: number = +tone.supersawDelayLength;\n\t\tconst delayLengthDelta: number = +tone.supersawDelayLengthDelta;\n\t\tconst delayLine: Float32Array = tone.supersawDelayLine!;\n\t\tconst delayBufferMask: number = (delayLine.length - 1) >> 0;\n\t\tlet delayIndex: number = tone.supersawDelayIndex|0;\n\t\tdelayIndex = (delayIndex & delayBufferMask) + delayLine.length;\n\t\t\n\t\tconst filters: DynamicBiquadFilter[] = tone.noteFilters;\n\t\tconst filterCount: number = tone.noteFilterCount|0;\n\t\tlet initialFilterInput1: number = +tone.initialNoteFilterInput1;\n\t\tlet initialFilterInput2: number = +tone.initialNoteFilterInput2;\n\t\tconst applyFilters: Function = Synth.applyFilters;\n\t\t\n\t\tconst stopIndex: number = bufferIndex + runLength;\n\t\tfor (let sampleIndex: number = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\t// The phase initially starts at a zero crossing so apply\n\t\t\t// the delta before first sample to get a nonzero value.\n\t\t\tlet phase: number = (phases[0] + phaseDelta) % 1.0;\n\t\t\tlet supersawSample: number = phase - 0.5 * (1.0 + (voiceCount - 1.0) * dynamism);\n\t\t\t\n\t\t\t// This is a PolyBLEP, which smooths out discontinuities at any frequency to reduce aliasing. \n\t\t\tif (phase < phaseDelta) {\n\t\t\t\tvar t: number = phase / phaseDelta;\n\t\t\t\tsupersawSample -= (t+t-t*t-1) * 0.5;\n\t\t\t} else if (phase > 1.0 - phaseDelta) {\n\t\t\t\tvar t: number = (phase - 1.0) / phaseDelta;\n\t\t\t\tsupersawSample -= (t+t+t*t+1) * 0.5;\n\t\t\t}\n\t\t\t\n\t\t\tphases[0] = phase;\n\t\t\t\n\t\t\tfor (let i: number = 1; i < voiceCount; i++) {\n\t\t\t\tconst detunedPhaseDelta: number = phaseDelta * unisonDetunes[i];\n\t\t\t\t// The phase initially starts at a zero crossing so apply\n\t\t\t\t// the delta before first sample to get a nonzero value.\n\t\t\t\tlet phase: number = (phases[i] + detunedPhaseDelta) % 1.0;\n\t\t\t\tsupersawSample += phase * dynamism;\n\t\t\t\t\n\t\t\t\t// This is a PolyBLEP, which smooths out discontinuities at any frequency to reduce aliasing. \n\t\t\t\tif (phase < detunedPhaseDelta) {\n\t\t\t\t\tconst t: number = phase / detunedPhaseDelta;\n\t\t\t\t\tsupersawSample -= (t+t-t*t-1) * 0.5 * dynamism;\n\t\t\t\t} else if (phase > 1.0 - detunedPhaseDelta) {\n\t\t\t\t\tconst t: number = (phase - 1.0) / detunedPhaseDelta;\n\t\t\t\t\tsupersawSample -= (t+t+t*t+1) * 0.5 * dynamism;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tphases[i] = phase;\n\t\t\t}\n\t\t\t\n\t\t\tdelayLine[delayIndex & delayBufferMask] = supersawSample;\n\t\t\tconst delaySampleTime: number = delayIndex - delayLength;\n\t\t\tconst lowerIndex: number = delaySampleTime | 0;\n\t\t\tconst upperIndex: number = lowerIndex + 1;\n\t\t\tconst delayRatio: number = delaySampleTime - lowerIndex;\n\t\t\tconst prevDelaySample: number = delayLine[lowerIndex & delayBufferMask];\n\t\t\tconst nextDelaySample: number = delayLine[upperIndex & delayBufferMask];\n\t\t\tconst delaySample: number = prevDelaySample + (nextDelaySample - prevDelaySample) * delayRatio;\n\t\t\tdelayIndex++;\n\t\t\t\n\t\t\tconst inputSample: number = supersawSample - delaySample * shape;\n\t\t\tconst sample: number = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\tinitialFilterInput1 = inputSample;\n\t\t\t\n\t\t\tphaseDelta *= phaseDeltaScale;\n\t\t\tdynamism += dynamismDelta;\n\t\t\tshape += shapeDelta;\n\t\t\tdelayLength += delayLengthDelta;\n\t\t\t\n\t\t\tconst output: number = sample * expression;\n\t\t\texpression += expressionDelta;\n\t\t\t\n\t\t\tdata[sampleIndex] += output;\n\t\t}\n\t\t\n\t\ttone.phaseDeltas[0] = phaseDelta;\n\t\ttone.expression = expression;\n\t\ttone.supersawDynamism = dynamism;\n\t\ttone.supersawShape = shape;\n\t\ttone.supersawDelayLength = delayLength;\n\t\ttone.supersawDelayIndex = delayIndex;\n\t\t\n\t\tsynth.sanitizeFilters(filters);\n\t\ttone.initialNoteFilterInput1 = initialFilterInput1;\n\t\ttone.initialNoteFilterInput2 = initialFilterInput2;\n\t}\n\t\n\tprivate static fmSourceTemplate: string[] = (`\n\t\tconst data = synth.tempMonoInstrumentSampleBuffer;\n\t\tconst sineWave = Config.sineWave;\n\t\t\n\t\t// I'm adding 1000 to the phase to ensure that it's never negative even when modulated by other waves because negative numbers don't work with the modulus operator very well.\n\t\tlet operator#Phase = +((tone.phases[#] % 1) + 1000) * ` + Config.sineWaveLength + `;\n\t\tlet operator#PhaseDelta = +tone.phaseDeltas[#] * ` + Config.sineWaveLength + `;\n\t\tlet operator#PhaseDeltaScale = +tone.phaseDeltaScales[#];\n\t\tlet operator#OutputMult = +tone.operatorExpressions[#];\n\t\tconst operator#OutputDelta = +tone.operatorExpressionDeltas[#];\n\t\tlet operator#Output = +tone.feedbackOutputs[#];\n\t\tlet feedbackMult = +tone.feedbackMult;\n\t\tconst feedbackDelta = +tone.feedbackDelta;\n\t\tlet expression = +tone.expression;\n\t\tconst expressionDelta = +tone.expressionDelta;\n\t\t\n\t\tconst filters = tone.noteFilters;\n\t\tconst filterCount = tone.noteFilterCount|0;\n\t\tlet initialFilterInput1 = +tone.initialNoteFilterInput1;\n\t\tlet initialFilterInput2 = +tone.initialNoteFilterInput2;\n\t\tconst applyFilters = Synth.applyFilters;\n\t\t\n\t\tconst stopIndex = bufferIndex + runLength;\n\t\tfor (let sampleIndex = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\t// INSERT OPERATOR COMPUTATION HERE\n\t\t\tconst fmOutput = (/*operator#Scaled*/); // CARRIER OUTPUTS\n\t\t\t\n\t\t\tconst inputSample = fmOutput;\n\t\t\tconst sample = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\tinitialFilterInput1 = inputSample;\n\t\t\t\n\t\t\tfeedbackMult += feedbackDelta;\n\t\t\toperator#OutputMult += operator#OutputDelta;\n\t\t\toperator#Phase += operator#PhaseDelta;\n\t\t\toperator#PhaseDelta *= operator#PhaseDeltaScale;\n\t\t\t\n\t\t\tconst output = sample * expression;\n\t\t\texpression += expressionDelta;\n\t\t\t\n\t\t\tdata[sampleIndex] += output;\n\t\t}\n\t\t\n\t\ttone.phases[#] = operator#Phase / ` + Config.sineWaveLength + `;\n\t\ttone.phaseDeltas[#] = operator#PhaseDelta / ` + Config.sineWaveLength + `;\n\t\ttone.operatorExpressions[#] = operator#OutputMult;\n\t\ttone.feedbackOutputs[#] = operator#Output;\n\t\ttone.feedbackMult = feedbackMult;\n\t\ttone.expression = expression;\n\t\t\n\t\tsynth.sanitizeFilters(filters);\n\t\ttone.initialNoteFilterInput1 = initialFilterInput1;\n\t\ttone.initialNoteFilterInput2 = initialFilterInput2;\n\t`).split(\"\\n\");\n\t\n\tprivate static operatorSourceTemplate: string[] = (`\n\t\t\tconst operator#PhaseMix = operator#Phase/* + operator@Scaled*/;\n\t\t\tconst operator#PhaseInt = operator#PhaseMix|0;\n\t\t\tconst operator#Index = operator#PhaseInt & ` + Config.sineWaveMask + `;\n\t\t\tconst operator#Sample = sineWave[operator#Index];\n\t\t\toperator#Output = operator#Sample + (sineWave[operator#Index + 1] - operator#Sample) * (operator#PhaseMix - operator#PhaseInt);\n\t\t\tconst operator#Scaled = operator#OutputMult * operator#Output;\n\t`).split(\"\\n\");\n\t\n\tprivate static noiseSynth(synth: Synth, bufferIndex: number, runLength: number, tone: Tone, instrumentState: InstrumentState): void {\n\t\tconst data: Float32Array = synth.tempMonoInstrumentSampleBuffer!;\n\t\tconst wave: Float32Array = instrumentState.wave!;\n\t\tlet phaseDelta: number = +tone.phaseDeltas[0];\n\t\tconst phaseDeltaScale: number = +tone.phaseDeltaScales[0];\n\t\tlet expression: number = +tone.expression;\n\t\tconst expressionDelta: number = +tone.expressionDelta;\n\t\tlet phase: number = (tone.phases[0] % 1) * Config.chipNoiseLength;\n\t\tif (tone.phases[0] == 0.0) {\n\t\t\t// Zero phase means the tone was reset, just give noise a random start phase instead.\n\t\t\tphase = Math.random() * Config.chipNoiseLength;\n\t\t}\n\t\tconst phaseMask: number = Config.chipNoiseLength - 1;\n\t\tlet noiseSample: number = +tone.noiseSample;\n\t\t\n\t\tconst filters: DynamicBiquadFilter[] = tone.noteFilters;\n\t\tconst filterCount: number = tone.noteFilterCount|0;\n\t\tlet initialFilterInput1: number = +tone.initialNoteFilterInput1;\n\t\tlet initialFilterInput2: number = +tone.initialNoteFilterInput2;\n\t\tconst applyFilters: Function = Synth.applyFilters;\n\t\t\n\t\t// This is for a \"legacy\" style simplified 1st order lowpass filter with\n\t\t// a cutoff frequency that is relative to the tone's fundamental frequency.\n\t\tconst pitchRelativefilter: number = Math.min(1.0, phaseDelta * instrumentState.noisePitchFilterMult);\n\t\t\n\t\tconst stopIndex: number = bufferIndex + runLength;\n\t\tfor (let sampleIndex: number = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\tconst waveSample: number = wave[phase & phaseMask];\n\t\t\t\n\t\t\tnoiseSample += (waveSample - noiseSample) * pitchRelativefilter;\n\t\t\t\n\t\t\tconst inputSample: number = noiseSample;\n\t\t\tconst sample: number = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\tinitialFilterInput1 = inputSample;\n\t\t\t\n\t\t\tphase += phaseDelta;\n\t\t\tphaseDelta *= phaseDeltaScale;\n\t\t\t\n\t\t\tconst output: number = sample * expression;\n\t\t\texpression += expressionDelta;\n\t\t\t\n\t\t\tdata[sampleIndex] += output;\n\t\t}\n\t\t\n\t\ttone.phases[0] = phase / Config.chipNoiseLength;\n\t\ttone.phaseDeltas[0] = phaseDelta;\n\t\ttone.expression = expression;\n\t\ttone.noiseSample = noiseSample;\n\t\t\n\t\tsynth.sanitizeFilters(filters);\n\t\ttone.initialNoteFilterInput1 = initialFilterInput1;\n\t\ttone.initialNoteFilterInput2 = initialFilterInput2;\n\t}\n\t\n\tprivate static spectrumSynth(synth: Synth, bufferIndex: number, runLength: number, tone: Tone, instrumentState: InstrumentState): void {\n\t\tconst data: Float32Array = synth.tempMonoInstrumentSampleBuffer!;\n\t\tconst wave: Float32Array = instrumentState.wave!;\n\t\tconst samplesInPeriod: number = (1 << 7);\n\t\tlet phaseDelta: number = tone.phaseDeltas[0] * samplesInPeriod;\n\t\tconst phaseDeltaScale: number = +tone.phaseDeltaScales[0];\n\t\tlet expression: number = +tone.expression;\n\t\tconst expressionDelta: number = +tone.expressionDelta;\n\t\tlet noiseSample: number = +tone.noiseSample;\n\t\t\n\t\tconst filters: DynamicBiquadFilter[] = tone.noteFilters;\n\t\tconst filterCount: number = tone.noteFilterCount|0;\n\t\tlet initialFilterInput1: number = +tone.initialNoteFilterInput1;\n\t\tlet initialFilterInput2: number = +tone.initialNoteFilterInput2;\n\t\tconst applyFilters: Function = Synth.applyFilters;\n\t\t\n\t\tlet phase: number = (tone.phases[0] % 1) * Config.spectrumNoiseLength;\n\t\t// Zero phase means the tone was reset, just give noise a random start phase instead.\n\t\tif (tone.phases[0] == 0.0) phase = Synth.findRandomZeroCrossing(wave, Config.spectrumNoiseLength) + phaseDelta;\n\t\tconst phaseMask: number = Config.spectrumNoiseLength - 1;\n\t\t\n\t\t// This is for a \"legacy\" style simplified 1st order lowpass filter with\n\t\t// a cutoff frequency that is relative to the tone's fundamental frequency.\n\t\tconst pitchRelativefilter: number = Math.min(1.0, phaseDelta);\n\t\t\n\t\tconst stopIndex: number = bufferIndex + runLength;\n\t\tfor (let sampleIndex: number = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\tconst phaseInt: number = phase|0;\n\t\t\tconst index: number = phaseInt & phaseMask;\n\t\t\tlet waveSample: number = wave[index];\n\t\t\tconst phaseRatio: number = phase - phaseInt;\n\t\t\twaveSample += (wave[index + 1] - waveSample) * phaseRatio;\n\t\t\t\n\t\t\tnoiseSample += (waveSample - noiseSample) * pitchRelativefilter;\n\t\t\t\n\t\t\tconst inputSample: number = noiseSample;\n\t\t\tconst sample: number = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\tinitialFilterInput1 = inputSample;\n\t\t\n\t\t\tphase += phaseDelta;\n\t\t\tphaseDelta *= phaseDeltaScale;\n\t\t\t\n\t\t\tconst output: number = sample * expression;\n\t\t\texpression += expressionDelta;\n\t\t\t\n\t\t\tdata[sampleIndex] += output;\n\t\t}\n\t\t\n\t\ttone.phases[0] = phase / Config.spectrumNoiseLength;\n\t\ttone.phaseDeltas[0] = phaseDelta / samplesInPeriod;\n\t\ttone.expression = expression;\n\t\ttone.noiseSample = noiseSample;\n\t\t\n\t\tsynth.sanitizeFilters(filters);\n\t\ttone.initialNoteFilterInput1 = initialFilterInput1;\n\t\ttone.initialNoteFilterInput2 = initialFilterInput2;\n\t}\n\t\n\tprivate static drumsetSynth(synth: Synth, bufferIndex: number, runLength: number, tone: Tone, instrumentState: InstrumentState): void {\n\t\tconst data: Float32Array = synth.tempMonoInstrumentSampleBuffer!;\n\t\tlet wave: Float32Array = instrumentState.getDrumsetWave(tone.drumsetPitch!);\n\t\tconst referenceDelta: number = InstrumentState.drumsetIndexReferenceDelta(tone.drumsetPitch!);\n\t\tlet phaseDelta: number = tone.phaseDeltas[0] / referenceDelta;\n\t\tconst phaseDeltaScale: number = +tone.phaseDeltaScales[0];\n\t\tlet expression: number = +tone.expression;\n\t\tconst expressionDelta: number = +tone.expressionDelta;\n\t\t\n\t\tconst filters: DynamicBiquadFilter[] = tone.noteFilters;\n\t\tconst filterCount: number = tone.noteFilterCount|0;\n\t\tlet initialFilterInput1: number = +tone.initialNoteFilterInput1;\n\t\tlet initialFilterInput2: number = +tone.initialNoteFilterInput2;\n\t\tconst applyFilters: Function = Synth.applyFilters;\n\t\t\n\t\tlet phase: number = (tone.phases[0] % 1) * Config.spectrumNoiseLength;\n\t\t// Zero phase means the tone was reset, just give noise a random start phase instead.\n\t\tif (tone.phases[0] == 0.0) phase = Synth.findRandomZeroCrossing(wave, Config.spectrumNoiseLength) + phaseDelta;\n\t\tconst phaseMask: number = Config.spectrumNoiseLength - 1;\n\t\t\n\t\tconst stopIndex: number = bufferIndex + runLength;\n\t\tfor (let sampleIndex: number = bufferIndex; sampleIndex < stopIndex; sampleIndex++) {\n\t\t\tconst phaseInt: number = phase|0;\n\t\t\tconst index: number = phaseInt & phaseMask;\n\t\t\tlet noiseSample: number = wave[index];\n\t\t\tconst phaseRatio: number = phase - phaseInt;\n\t\t\tnoiseSample += (wave[index + 1] - noiseSample) * phaseRatio;\n\t\t\t\n\t\t\tconst inputSample: number = noiseSample;\n\t\t\tconst sample: number = applyFilters(inputSample, initialFilterInput1, initialFilterInput2, filterCount, filters);\n\t\t\tinitialFilterInput2 = initialFilterInput1;\n\t\t\tinitialFilterInput1 = inputSample;\n\t\t\n\t\t\tphase += phaseDelta;\n\t\t\tphaseDelta *= phaseDeltaScale;\n\t\t\t\n\t\t\tconst output: number = sample * expression;\n\t\t\texpression += expressionDelta;\n\t\t\t\n\t\t\tdata[sampleIndex] += output;\n\t\t}\n\t\t\n\t\ttone.phases[0] = phase / Config.spectrumNoiseLength;\n\t\ttone.phaseDeltas[0] = phaseDelta * referenceDelta;\n\t\ttone.expression = expression;\n\t\t\n\t\tsynth.sanitizeFilters(filters);\n\t\ttone.initialNoteFilterInput1 = initialFilterInput1;\n\t\ttone.initialNoteFilterInput2 = initialFilterInput2;\n\t}\n\t\n\tprivate static findRandomZeroCrossing(wave: Float32Array, waveLength: number): number {\n\t\tlet phase: number = Math.random() * waveLength;\n\t\tconst phaseMask: number = waveLength - 1;\n\t\t\n\t\t// Spectrum and drumset waves sounds best when they start at a zero crossing,\n\t\t// otherwise they pop. Try to find a zero crossing.\n\t\tlet indexPrev: number = phase & phaseMask;\n\t\tlet wavePrev: number = wave[indexPrev];\n\t\tconst stride: number = 16;\n\t\tfor (let attemptsRemaining: number = 128; attemptsRemaining > 0; attemptsRemaining--) {\n\t\t\tconst indexNext: number = (indexPrev + stride) & phaseMask;\n\t\t\tconst waveNext: number = wave[indexNext];\n\t\t\tif (wavePrev * waveNext <= 0.0) {\n\t\t\t\t// Found a zero crossing! Now let's narrow it down to two adjacent sample indices.\n\t\t\t\tfor (let i: number = 0; i < stride; i++) {\n\t\t\t\t\tconst innerIndexNext: number = (indexPrev + 1) & phaseMask;\n\t\t\t\t\tconst innerWaveNext: number = wave[innerIndexNext];\n\t\t\t\t\tif (wavePrev * innerWaveNext <= 0.0) {\n\t\t\t\t\t\t// Found the zero crossing again! Now let's find the exact intersection.\n\t\t\t\t\t\tconst slope: number = innerWaveNext - wavePrev;\n\t\t\t\t\t\tphase = indexPrev;\n\t\t\t\t\t\tif (Math.abs(slope) > 0.00000001) {\n\t\t\t\t\t\t\tphase += -wavePrev / slope;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tphase = Math.max(0, phase) % waveLength;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tindexPrev = innerIndexNext;\n\t\t\t\t\t\twavePrev = innerWaveNext;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tindexPrev = indexNext;\n\t\t\t\twavePrev = waveNext;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn phase;\n\t}\n\t\n\tpublic static instrumentVolumeToVolumeMult(instrumentVolume: number): number {\n\t\treturn (instrumentVolume == Config.volumeRange - 1) ? 0.0 : Math.pow(2, Config.volumeLogScale * instrumentVolume);\n\t}\n\tpublic static volumeMultToInstrumentVolume(volumeMult: number): number {\n\t\treturn (volumeMult <= 0.0) ? Config.volumeRange - 1 : Math.min(Config.volumeRange - 2, Math.log2(volumeMult) / Config.volumeLogScale);\n\t}\n\tpublic static noteSizeToVolumeMult(size: number): number {\n\t\treturn Math.pow(Math.max(0.0, size) / Config.noteSizeMax, 1.5);\n\t}\n\tpublic static volumeMultToNoteSize(volumeMult: number): number {\n\t\treturn Math.pow(Math.max(0.0, volumeMult), 1/1.5) * Config.noteSizeMax;\n\t}\n\t\n\tpublic static fadeInSettingToSeconds(setting: number): number {\n\t\treturn 0.0125 * (0.95 * setting + 0.05 * setting * setting);\n\t}\n\tpublic static secondsToFadeInSetting(seconds: number): number {\n\t\treturn clamp(0, Config.fadeInRange, Math.round((-0.95 + Math.sqrt(0.9025 + 0.2 * seconds / 0.0125)) / 0.1));\n\t}\n\tpublic static fadeOutSettingToTicks(setting: number): number {\n\t\treturn Config.fadeOutTicks[setting];\n\t}\n\tpublic static ticksToFadeOutSetting(ticks: number): number {\n\t\tlet lower: number = Config.fadeOutTicks[0];\n\t\tif (ticks <= lower) return 0;\n\t\tfor (let i: number = 1; i < Config.fadeOutTicks.length; i++) {\n\t\t\tlet upper: number = Config.fadeOutTicks[i];\n\t\t\tif (ticks <= upper) return (ticks < (lower + upper) / 2) ? i - 1 : i;\n\t\t\tlower = upper;\n\t\t}\n\t\treturn Config.fadeOutTicks.length - 1;\n\t}\n\t\n\tpublic static detuneToCents(detune: number): number {\n\t\treturn detune * (Math.abs(detune)+1) / 2;\n\t}\n\tpublic static centsToDetune(cents: number): number {\n\t\treturn Math.sign(cents) * (Math.sqrt(1 + 8 * Math.abs(cents)) - 1) / 2.0;\n\t}\n\t\n\tprivate getSamplesPerTick(): number {\n\t\tif (this.song == null) return 0;\n\t\tconst beatsPerMinute: number = this.song.getBeatsPerMinute();\n\t\tconst beatsPerSecond: number = beatsPerMinute / 60.0;\n\t\tconst partsPerSecond: number = Config.partsPerBeat * beatsPerSecond;\n\t\tconst tickPerSecond: number = Config.ticksPerPart * partsPerSecond;\n\t\treturn this.samplesPerSecond / tickPerSecond;\n\t}\n\t\n\tpublic static fittingPowerOfTwo(x: number): number {\n\t\treturn 1 << (32 - Math.clz32(Math.ceil(x) - 1));\n\t}\n\t\n\tprivate sanitizeFilters(filters: DynamicBiquadFilter[]): void {\n\t\tlet reset: boolean = false;\n\t\tfor (const filter of filters) {\n\t\t\tconst output1: number = Math.abs(filter.output1);\n\t\t\tconst output2: number = Math.abs(filter.output2);\n\t\t\t// If either is a large value, Infinity, or NaN, then just reset all filter history.\n\t\t\tif (!(output1 < 100) || !(output2 < 100)) {\n\t\t\t\treset = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (output1 < epsilon) filter.output1 = 0.0;\n\t\t\tif (output2 < epsilon) filter.output2 = 0.0;\n\t\t}\n\t\tif (reset) {\n\t\t\tfor (const filter of filters) {\n\t\t\t\tfilter.output1 = 0.0;\n\t\t\t\tfilter.output2 = 0.0;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic static sanitizeDelayLine(delayLine: Float32Array, lastIndex: number, mask: number): void {\n\t\twhile (true) {\n\t\t\tlastIndex--;\n\t\t\tconst index: number = lastIndex & mask;\n\t\t\tconst sample: number = Math.abs(delayLine[index]);\n\t\t\tif (Number.isFinite(sample) && (sample == 0.0 || sample >= epsilon)) break;\n\t\t\tdelayLine[index] = 0.0;\n\t\t}\n\t}\n\t\n\tpublic static applyFilters(sample: number, input1: number, input2: number, filterCount: number, filters: DynamicBiquadFilter[]): number {\n\t\tfor (let i: number = 0; i < filterCount; i++) {\n\t\t\tconst filter: DynamicBiquadFilter = filters[i];\n\t\t\tconst output1: number = filter.output1;\n\t\t\tconst output2: number = filter.output2;\n\t\t\tconst a1: number = filter.a1;\n\t\t\tconst a2: number = filter.a2;\n\t\t\tconst b0: number = filter.b0;\n\t\t\tconst b1: number = filter.b1;\n\t\t\tconst b2: number = filter.b2;\n\t\t\tsample = b0 * sample + b1 * input1 + b2 * input2 - a1 * output1 - a2 * output2;\n\t\t\tfilter.a1 = a1 + filter.a1Delta;\n\t\t\tfilter.a2 = a2 + filter.a2Delta;\n\t\t\tif (filter.useMultiplicativeInputCoefficients) {\n\t\t\t\tfilter.b0 = b0 * filter.b0Delta;\n\t\t\t\tfilter.b1 = b1 * filter.b1Delta;\n\t\t\t\tfilter.b2 = b2 * filter.b2Delta;\n\t\t\t} else {\n\t\t\t\tfilter.b0 = b0 + filter.b0Delta;\n\t\t\t\tfilter.b1 = b1 + filter.b1Delta;\n\t\t\t\tfilter.b2 = b2 + filter.b2Delta;\n\t\t\t}\n\t\t\tfilter.output2 = output1;\n\t\t\tfilter.output1 = sample;\n\t\t\t// Updating the input values is waste if the next filter doesn't exist...\n\t\t\tinput2 = output2;\n\t\t\tinput1 = output1;\n\t\t}\n\t\treturn sample;\n\t}\n}\n\n// When compiling synth.ts as a standalone module named \"beepbox\", expose these imported classes as members to JavaScript:\nexport {Dictionary, DictionaryArray, FilterType, EnvelopeType, InstrumentType, Transition, Chord, Envelope, Config};\n"]}