@@ -467,6 +467,7 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
467467 public harmonics : number [ ] = [ ] ;
468468 private _wave : Float32Array | null = null ;
469469 private _waveIsReady : boolean = false ;
470+ private _generatedForType : InstrumentType ;
470471
471472 constructor ( ) {
472473 this . reset ( ) ;
@@ -486,7 +487,13 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
486487 this . _waveIsReady = false ;
487488 }
488489
489- public getCustomWave ( ) : Float32Array {
490+ public getCustomWave ( instrumentType : InstrumentType ) : Float32Array {
491+ if ( this . _generatedForType != instrumentType ) {
492+ this . _generatedForType = instrumentType ;
493+ this . _waveIsReady = false ;
494+ }
495+ const harmonicsRendered : number = ( instrumentType == InstrumentType . pickedString ) ? Config . harmonicsRenderedForPickedString : Config . harmonicsRendered ;
496+
490497 if ( this . _waveIsReady ) return this . _wave ! ;
491498
492499 const waveLength : number = Config . harmonicsWavelength ;
@@ -504,11 +511,11 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
504511 const overallSlope : number = - 0.25 ;
505512 let combinedControlPointAmplitude : number = 1 ;
506513
507- for ( let harmonicIndex : number = 0 ; harmonicIndex < Config . harmonicsRendered ; harmonicIndex ++ ) {
514+ for ( let harmonicIndex : number = 0 ; harmonicIndex < harmonicsRendered ; harmonicIndex ++ ) {
508515 const harmonicFreq : number = harmonicIndex + 1 ;
509516 let controlValue : number = harmonicIndex < Config . harmonicsControlPoints ? this . harmonics [ harmonicIndex ] : this . harmonics [ Config . harmonicsControlPoints - 1 ] ;
510517 if ( harmonicIndex >= Config . harmonicsControlPoints ) {
511- controlValue *= 1 - ( harmonicIndex - Config . harmonicsControlPoints ) / ( Config . harmonicsRendered - Config . harmonicsControlPoints ) ;
518+ controlValue *= 1 - ( harmonicIndex - Config . harmonicsControlPoints ) / ( harmonicsRendered - Config . harmonicsControlPoints ) ;
512519 }
513520 const normalizedValue : number = controlValue / Config . harmonicsMax ;
514521 let amplitude : number = Math . pow ( 2 , controlValue - Config . harmonicsMax + 1 ) * Math . sqrt ( normalizedValue ) ;
@@ -540,42 +547,6 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
540547 }
541548 }
542549
543- export class PickedStringImpulseWave {
544- private static _wave : Float32Array | null = null ;
545-
546- private constructor ( ) { throw new Error ( ) ; } // Don't instantiate.
547-
548- public static getWave ( ) : Float32Array {
549- if ( PickedStringImpulseWave . _wave != null ) return PickedStringImpulseWave . _wave ;
550-
551- const waveLength : number = Config . harmonicsWavelength ;
552- PickedStringImpulseWave . _wave = new Float32Array ( waveLength + 1 ) ;
553- const wave : Float32Array = PickedStringImpulseWave . _wave ;
554- const retroWave : Float32Array = getDrumWave ( 0 , null , null ) ;
555-
556- for ( let harmonicFreq : number = 1 ; harmonicFreq < ( waveLength >> 1 ) ; harmonicFreq ++ ) {
557- let amplitude : number = 0.5 / harmonicFreq ; // The symmetric inverse FFT doubles amplitudes, compensating for that here.
558-
559- // Multiply all the sine wave amplitudes by 1 or -1 based on the LFSR
560- // retro wave (effectively random) to avoid egregiously tall spikes.
561- amplitude *= retroWave [ harmonicFreq + 588 ] ;
562-
563- /*
564- const radians: number = 0.61803398875 * harmonicFreq * harmonicFreq * Math.PI * 2.0;
565- wave[harmonicFreq] = Math.sin(radians) * amplitude;
566- wave[waveLength - harmonicFreq] = Math.cos(radians) * amplitude;
567- */
568- wave [ waveLength - harmonicFreq ] = amplitude ;
569- }
570-
571- inverseRealFourierTransform ( wave , waveLength ) ;
572- performIntegral ( wave ) ;
573- // The first sample should be zero, and we'll duplicate it at the end for easier interpolation.
574- wave [ waveLength ] = wave [ 0 ] ;
575- return wave ;
576- }
577- }
578-
579550 export class FilterControlPoint {
580551 public freq : number = 0 ;
581552 public gain : number = Config . filterGainCenter ;
@@ -894,7 +865,7 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
894865 break ;
895866 case InstrumentType . pickedString :
896867 this . chord = Config . chords . dictionary [ "strum" ] . index ;
897- this . pulseWidth = Config . pulseWidthRange - 3 ;
868+ this . harmonicsWave . reset ( ) ;
898869 this . stringSustain = 6 ;
899870 break ;
900871 default :
@@ -966,6 +937,13 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
966937 instrumentObject [ "filterEnvelope" ] = this . getFilterEnvelope ( ) . name ; // DEPRECATED
967938 }
968939
940+ if ( this . type == InstrumentType . harmonics || this . type == InstrumentType . pickedString ) {
941+ instrumentObject [ "harmonics" ] = [ ] ;
942+ for ( let i : number = 0 ; i < Config . harmonicsControlPoints ; i ++ ) {
943+ instrumentObject [ "harmonics" ] [ i ] = Math . round ( 100 * this . harmonicsWave . harmonics [ i ] / Config . harmonicsMax ) ;
944+ }
945+ }
946+
969947 if ( this . type == InstrumentType . noise ) {
970948 instrumentObject [ "wave" ] = Config . chipNoises [ this . chipNoise ] . name ;
971949 } else if ( this . type == InstrumentType . spectrum ) {
@@ -1000,10 +978,6 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
1000978 } else if ( this . type == InstrumentType . harmonics ) {
1001979 instrumentObject [ "interval" ] = Config . intervals [ this . interval ] . name ;
1002980 instrumentObject [ "vibrato" ] = Config . vibratos [ this . vibrato ] . name ;
1003- instrumentObject [ "harmonics" ] = [ ] ;
1004- for ( let i : number = 0 ; i < Config . harmonicsControlPoints ; i ++ ) {
1005- instrumentObject [ "harmonics" ] [ i ] = Math . round ( 100 * this . harmonicsWave . harmonics [ i ] / Config . harmonicsMax ) ;
1006- }
1007981 } else if ( this . type == InstrumentType . fm ) {
1008982 const operatorArray : Object [ ] = [ ] ;
1009983 for ( const operator of this . operators ) {
@@ -1305,9 +1279,9 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
13051279 if ( this . type == InstrumentType . noise ) {
13061280 getDrumWave ( this . chipNoise , inverseRealFourierTransform , scaleElementsByFactor ) ;
13071281 } else if ( this . type == InstrumentType . harmonics ) {
1308- this . harmonicsWave . getCustomWave ( ) ;
1282+ this . harmonicsWave . getCustomWave ( this . type ) ;
13091283 } else if ( this . type == InstrumentType . pickedString ) {
1310- PickedStringImpulseWave . getWave ( ) ;
1284+ this . harmonicsWave . getCustomWave ( this . type ) ;
13111285 } else if ( this . type == InstrumentType . spectrum ) {
13121286 this . spectrumWave . getCustomWave ( 8 ) ;
13131287 } else if ( this . type == InstrumentType . drumset ) {
@@ -1509,6 +1483,15 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
15091483 buffer . push ( SongTagCode . chord , base64IntToCharCode [ instrument . chord ] ) ;
15101484 }
15111485
1486+ if ( instrument . type == InstrumentType . harmonics || instrument . type == InstrumentType . pickedString ) {
1487+ buffer . push ( SongTagCode . harmonics ) ;
1488+ const harmonicsBits : BitFieldWriter = new BitFieldWriter ( ) ;
1489+ for ( let i : number = 0 ; i < Config . harmonicsControlPoints ; i ++ ) {
1490+ harmonicsBits . write ( Config . harmonicsControlPointBits , instrument . harmonicsWave . harmonics [ i ] ) ;
1491+ }
1492+ harmonicsBits . encodeBase64 ( buffer ) ;
1493+ }
1494+
15121495 if ( instrument . type == InstrumentType . chip ) {
15131496 buffer . push ( SongTagCode . wave , base64IntToCharCode [ instrument . chipWave ] ) ;
15141497 buffer . push ( SongTagCode . vibrato , base64IntToCharCode [ instrument . vibrato ] ) ;
@@ -1558,19 +1541,11 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
15581541 } else if ( instrument . type == InstrumentType . harmonics ) {
15591542 buffer . push ( SongTagCode . vibrato , base64IntToCharCode [ instrument . vibrato ] ) ;
15601543 buffer . push ( SongTagCode . interval , base64IntToCharCode [ instrument . interval ] ) ;
1561-
1562- buffer . push ( SongTagCode . harmonics ) ;
1563- const harmonicsBits : BitFieldWriter = new BitFieldWriter ( ) ;
1564- for ( let i : number = 0 ; i < Config . harmonicsControlPoints ; i ++ ) {
1565- harmonicsBits . write ( Config . harmonicsControlPointBits , instrument . harmonicsWave . harmonics [ i ] ) ;
1566- }
1567- harmonicsBits . encodeBase64 ( buffer ) ;
15681544 } else if ( instrument . type == InstrumentType . pwm ) {
15691545 buffer . push ( SongTagCode . vibrato , base64IntToCharCode [ instrument . vibrato ] ) ;
15701546 // TODO: The envelope should be saved separately.
15711547 buffer . push ( SongTagCode . pulseWidth , base64IntToCharCode [ instrument . pulseWidth ] , base64IntToCharCode [ instrument . pulseEnvelope ] ) ;
15721548 } else if ( instrument . type == InstrumentType . pickedString ) {
1573- buffer . push ( SongTagCode . pulseWidth , base64IntToCharCode [ instrument . pulseWidth ] ) ;
15741549 buffer . push ( SongTagCode . vibrato , base64IntToCharCode [ instrument . vibrato ] ) ;
15751550 buffer . push ( SongTagCode . stringSustain , base64IntToCharCode [ instrument . stringSustain ] ) ;
15761551 } else {
@@ -4757,7 +4732,7 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
47574732
47584733 private static harmonicsSynth ( synth : Synth , bufferIndex : number , runLength : number , tone : Tone , instrument : Instrument ) : void {
47594734 const data : Float32Array = synth . tempMonoInstrumentSampleBuffer ! ;
4760- const wave : Float32Array = instrument . harmonicsWave . getCustomWave ( ) ;
4735+ const wave : Float32Array = instrument . harmonicsWave . getCustomWave ( instrument . type ) ;
47614736 const waveLength : number = wave . length - 1 ; // The first sample is duplicated at the end, don't double-count it.
47624737
47634738 const intervalA : number = + Math . pow ( 2.0 , ( Config . intervals [ instrument . interval ] . offset + Config . intervals [ instrument . interval ] . spread ) / 12.0 ) ;
@@ -4932,6 +4907,12 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
49324907 // Also, if the pitch changed suddenly (e.g. from seamless or arpeggio) then reset the wave.
49334908
49344909 delayIndex = 0 ;
4910+ allPassSample = 0.0 ;
4911+ allPassPrevInput = 0.0 ;
4912+ shelfSample = 0.0 ;
4913+ shelfPrevInput = 0.0 ;
4914+ fractionalDelaySample = 0.0 ;
4915+
49354916 // Clear away a region of the delay buffer for the new impulse.
49364917 const startImpulseFrom : number = - delayLength ;
49374918 const startZerosFrom : number = Math . floor ( startImpulseFrom - periodLengthStart / 2 ) ;
@@ -4941,51 +4922,27 @@ const epsilon: number = (1.0e-24); // For detecting and avoiding float denormals
49414922 delayLine [ i & delayBufferMask ] = 0.0 ;
49424923 }
49434924
4944- allPassSample = 0.0 ;
4945- allPassPrevInput = 0.0 ;
4946- shelfSample = 0.0 ;
4947- shelfPrevInput = 0.0 ;
4948- fractionalDelaySample = 0.0 ;
4949-
4950- const impulseWave : Float32Array = PickedStringImpulseWave . getWave ( ) ;
4951- const impulseWaveLength : number = + impulseWave . length - 1 ; // The first sample is duplicated at the end, don't double-count it.
4925+ const impulseWave : Float32Array = instrument . harmonicsWave . getCustomWave ( instrument . type ) ;
4926+ const impulseWaveLength : number = impulseWave . length - 1 ; // The first sample is duplicated at the end, don't double-count it.
49524927 const impulsePhaseDelta : number = impulseWaveLength / periodLengthStart ;
4953- const pulseOffset : number = periodLengthStart * ( tone . pulseWidth * ( 1.0 + ( Math . random ( ) - 0.5 ) * Config . pickedStringPulseWidthRandomness ) ) ;
4954- const impulseExpressionMult : number = 0.5 ; // Compensate for adding two copies of the wave.
4955-
4956- const startFirstWaveFrom : number = startImpulseFrom ;
4957- const startFirstWaveFromSample : number = Math . ceil ( startFirstWaveFrom ) ;
4958- const stopFirstWaveAtSample : number = Math . floor ( startImpulseFrom + periodLengthStart ) ;
4959- const startFirstWavePhase : number = ( startFirstWaveFromSample - startFirstWaveFrom ) * impulsePhaseDelta ;
4960- const startSecondWaveFrom : number = startFirstWaveFrom + pulseOffset ;
4961- const startSecondWaveFromSample : number = Math . ceil ( startSecondWaveFrom ) ;
4962- const stopSecondWaveAtSample : number = Math . floor ( startSecondWaveFrom + periodLengthStart ) ;
4963- const startSecondWavePhase : number = ( startSecondWaveFromSample - startSecondWaveFrom ) * impulsePhaseDelta ;
4964-
4965- let impulsePhase : number = startFirstWavePhase ;
4966- let prevWaveIntegral : number = 0.0 ;
4967- for ( let i : number = startFirstWaveFromSample ; i <= stopFirstWaveAtSample ; i ++ ) {
4968- const impulsePhaseInt : number = impulsePhase | 0 ;
4969- const index : number = impulsePhaseInt % impulseWaveLength ;
4970- let nextWaveIntegral : number = impulseWave [ index ] ;
4971- const phaseRatio : number = impulsePhase - impulsePhaseInt ;
4972- nextWaveIntegral += ( impulseWave [ index + 1 ] - nextWaveIntegral ) * phaseRatio ;
4973- const sample : number = ( nextWaveIntegral - prevWaveIntegral ) / impulsePhaseDelta ;
4974- delayLine [ i & delayBufferMask ] += sample * impulseExpressionMult ;
4975- prevWaveIntegral = nextWaveIntegral ;
4976- impulsePhase += impulsePhaseDelta ;
4928+ if ( impulseWaveLength <= Math . ceil ( periodLengthStart ) ) {
4929+ throw new Error ( "Picked string delay buffer too small to contain wave, buffer: " + impulseWaveLength + ", period: " + periodLengthStart ) ;
49774930 }
4931+
4932+ const startImpulseFromSample : number = Math . ceil ( startImpulseFrom ) ;
4933+ const stopImpulseAtSample : number = Math . floor ( startImpulseFrom + periodLengthStart ) ;
4934+ const startImpulsePhase : number = ( startImpulseFromSample - startImpulseFrom ) * impulsePhaseDelta ;
49784935
4979- impulsePhase = startSecondWavePhase ;
4980- prevWaveIntegral = 0.0 ;
4981- for ( let i : number = startSecondWaveFromSample ; i <= stopSecondWaveAtSample ; i ++ ) {
4936+ let impulsePhase : number = startImpulsePhase ;
4937+ let prevWaveIntegral : number = 0.0 ;
4938+ for ( let i : number = startImpulseFromSample ; i <= stopImpulseAtSample ; i ++ ) {
49824939 const impulsePhaseInt : number = impulsePhase | 0 ;
49834940 const index : number = impulsePhaseInt % impulseWaveLength ;
49844941 let nextWaveIntegral : number = impulseWave [ index ] ;
49854942 const phaseRatio : number = impulsePhase - impulsePhaseInt ;
49864943 nextWaveIntegral += ( impulseWave [ index + 1 ] - nextWaveIntegral ) * phaseRatio ;
49874944 const sample : number = ( nextWaveIntegral - prevWaveIntegral ) / impulsePhaseDelta ;
4988- delayLine [ i & delayBufferMask ] - = sample * impulseExpressionMult ;
4945+ delayLine [ i & delayBufferMask ] + = sample ;
49894946 prevWaveIntegral = nextWaveIntegral ;
49904947 impulsePhase += impulsePhaseDelta ;
49914948 }
0 commit comments