@grame/faustwasm 0.18.1 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1099,6 +1099,8 @@ export declare class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implement
1099
1099
  private fAudioMixing;
1100
1100
  private fAudioMixingHalf;
1101
1101
  private fMixingBase;
1102
+ /** Float view of the memory, kept from `initMemory` like `fHEAP32`. */
1103
+ private fHEAPF;
1102
1104
  private fVoiceTable;
1103
1105
  private fSampleRate;
1104
1106
  /** Voices whose crossfade this block already rendered in full. */
@@ -1123,14 +1125,29 @@ export declare class FaustPolyWebAudioDsp extends FaustBaseWebAudioDsp implement
1123
1125
  /**
1124
1126
  * Render the stolen voices, each across the whole block.
1125
1127
  *
1126
- * A steal is a crossfade: the voice plays the note it is losing over the
1128
+ * A steal is a hand-over: the voice plays the note it is losing over the
1127
1129
  * first half of the buffer, that half fades out, and the new note plays
1128
- * the second half. The fade has to be half a block -- 64 frames -- rather
1129
- * than half a slice, which late in the block would be a frame or two, or
1130
- * nothing at all. So this runs before the slicing, and `fRenderSlice`
1131
- * skips these voices.
1130
+ * the second half, faded in. Both fades are needed. `fadeOut` scales the
1131
+ * buffer, not the voice: after `keyOn` the DSP carries on from its live
1132
+ * state -- an envelope that never reached silence is still up -- so
1133
+ * without the fade-in the second half started at full level, a step on
1134
+ * every stolen note. On a monophonic patch whose voice never falls
1135
+ * silent that is a click on every note after the first (measured on a
1136
+ * long-release bass: 0, 0, 0, 0.1485, 0.2618 across the split).
1137
+ *
1138
+ * The fades have to be half a block -- 64 frames -- rather than half a
1139
+ * slice, which late in the block would be a frame or two, or nothing at
1140
+ * all. So this runs before the slicing, and `fRenderSlice` skips these
1141
+ * voices.
1132
1142
  */
1133
1143
  private renderStolenVoices;
1144
+ /**
1145
+ * Scale `count` frames of each channel at `$tables` from 1/count up to 1.
1146
+ *
1147
+ * The mixer has `fadeOut` in wasm; this is its counterpart on the JS
1148
+ * side, over the channel-pointer table the same way the mixer reads it.
1149
+ */
1150
+ private fadeIn;
1134
1151
  /**
1135
1152
  * Move the mixing tables along with the input and output ones.
1136
1153
  *
package/dist/cjs/index.js CHANGED
@@ -3989,12 +3989,20 @@ export default ${(_b = jsCode.match(jsCodeHead)) == null ? void 0 : _b[1]};
3989
3989
  /**
3990
3990
  * Render the stolen voices, each across the whole block.
3991
3991
  *
3992
- * A steal is a crossfade: the voice plays the note it is losing over the
3992
+ * A steal is a hand-over: the voice plays the note it is losing over the
3993
3993
  * first half of the buffer, that half fades out, and the new note plays
3994
- * the second half. The fade has to be half a block -- 64 frames -- rather
3995
- * than half a slice, which late in the block would be a frame or two, or
3996
- * nothing at all. So this runs before the slicing, and `fRenderSlice`
3997
- * skips these voices.
3994
+ * the second half, faded in. Both fades are needed. `fadeOut` scales the
3995
+ * buffer, not the voice: after `keyOn` the DSP carries on from its live
3996
+ * state -- an envelope that never reached silence is still up -- so
3997
+ * without the fade-in the second half started at full level, a step on
3998
+ * every stolen note. On a monophonic patch whose voice never falls
3999
+ * silent that is a click on every note after the first (measured on a
4000
+ * long-release bass: 0, 0, 0, 0.1485, 0.2618 across the split).
4001
+ *
4002
+ * The fades have to be half a block -- 64 frames -- rather than half a
4003
+ * slice, which late in the block would be a frame or two, or nothing at
4004
+ * all. So this runs before the slicing, and `fRenderSlice` skips these
4005
+ * voices.
3998
4006
  */
3999
4007
  renderStolenVoices() {
4000
4008
  const stolen = this.fStolen;
@@ -4013,6 +4021,11 @@ export default ${(_b = jsCode.match(jsCodeHead)) == null ? void 0 : _b[1]};
4013
4021
  this.getNumOutputs(),
4014
4022
  this.fAudioMixing
4015
4023
  );
4024
+ this.fadeIn(
4025
+ this.fBufferSize - (this.fBufferSize >> 1),
4026
+ this.getNumOutputs(),
4027
+ this.fAudioMixingHalf
4028
+ );
4016
4029
  voice.fLevel = this.fInstance.mixerAPI.mixCheckVoice(
4017
4030
  this.fBufferSize,
4018
4031
  this.getNumOutputs(),
@@ -4021,6 +4034,22 @@ export default ${(_b = jsCode.match(jsCodeHead)) == null ? void 0 : _b[1]};
4021
4034
  );
4022
4035
  });
4023
4036
  }
4037
+ /**
4038
+ * Scale `count` frames of each channel at `$tables` from 1/count up to 1.
4039
+ *
4040
+ * The mixer has `fadeOut` in wasm; this is its counterpart on the JS
4041
+ * side, over the channel-pointer table the same way the mixer reads it.
4042
+ */
4043
+ fadeIn(count, chans, $tables) {
4044
+ const shift = Math.log2(this.fSampleSize);
4045
+ const HEAPF = this.fHEAPF;
4046
+ for (let chan = 0; chan < chans; chan++) {
4047
+ const start = this.fHEAP32[($tables >> 2) + chan] >> shift;
4048
+ for (let i = 0; i < count; i++) {
4049
+ HEAPF[start + i] *= (i + 1) / count;
4050
+ }
4051
+ }
4052
+ }
4024
4053
  /**
4025
4054
  * Move the mixing tables along with the input and output ones.
4026
4055
  *
@@ -4119,6 +4148,7 @@ export default ${(_b = jsCode.match(jsCodeHead)) == null ? void 0 : _b[1]};
4119
4148
  for (let chan = 0; chan < this.getNumInputs(); chan++) {
4120
4149
  this.fInBase[chan] = HEAP32[(this.fAudioInputs >> 2) + chan];
4121
4150
  }
4151
+ this.fHEAPF = HEAPF;
4122
4152
  this.fOutBase = [];
4123
4153
  this.fMixingBase = [];
4124
4154
  for (let chan = 0; chan < this.getNumOutputs(); chan++) {