spessasynth_lib 3.24.15 → 3.24.18

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.
@@ -47,6 +47,10 @@ export function controllerChange(controllerNumber, controllerValue, force = fals
47
47
  this.midiControllers[actualCCNum] = (this.midiControllers[actualCCNum] & 0x3F80) | (controllerValue & 0x7F);
48
48
  this.voices.forEach(v => computeModulators(v, this.midiControllers, 1, actualCCNum));
49
49
  }
50
+ if (this.lockedControllers[controllerNumber])
51
+ {
52
+ return;
53
+ }
50
54
  switch (controllerNumber)
51
55
  {
52
56
  case midiControllers.allNotesOff:
@@ -180,10 +184,6 @@ export function controllerChange(controllerNumber, controllerValue, force = fals
180
184
 
181
185
  // default: apply the controller to the table
182
186
  default:
183
- if (this.lockedControllers[controllerNumber])
184
- {
185
- return;
186
- }
187
187
  this.midiControllers[controllerNumber] = controllerValue << 7;
188
188
  this.voices.forEach(v => computeModulators(v, this.midiControllers, 1, controllerNumber));
189
189
  break;
@@ -124,7 +124,7 @@ export function resetControllers()
124
124
  {
125
125
  if (this.lockedControllers[i])
126
126
  {
127
- return;
127
+ continue;
128
128
  }
129
129
  const resetValue = resetArray[i];
130
130
  if (this.midiControllers[i] !== resetValue && i < 127)
@@ -3,9 +3,10 @@ import { generatorTypes } from "../../../../soundfont/basic_soundfont/generator.
3
3
  /**
4
4
  * Stops a note nearly instantly
5
5
  * @param midiNote {number}
6
+ * @param releaseTime {number} ticks
6
7
  * @this {WorkletProcessorChannel}
7
8
  */
8
- export function killNote(midiNote)
9
+ export function killNote(midiNote, releaseTime = -12000)
9
10
  {
10
11
  this.voices.forEach(v =>
11
12
  {
@@ -13,7 +14,7 @@ export function killNote(midiNote)
13
14
  {
14
15
  return;
15
16
  }
16
- v.modulatedGenerators[generatorTypes.releaseVolEnv] = -12000; // set release to be very short
17
+ v.modulatedGenerators[generatorTypes.releaseVolEnv] = releaseTime; // set release to be very short
17
18
  v.release();
18
19
  });
19
20
  }
@@ -21,7 +21,11 @@ export function noteOff(midiNote)
21
21
  // if the channel is percussion channel, do not kill the notes
22
22
  if (!this.drumChannel)
23
23
  {
24
- this.killNote(realKey);
24
+ this.killNote(realKey, -6950);
25
+ this.synth.callEvent("noteoff", {
26
+ midiNote: midiNote,
27
+ channel: this.channelNumber
28
+ });
25
29
  return;
26
30
  }
27
31
  }
@@ -146,55 +146,63 @@ export class WorkletLowpassFilter
146
146
  const cutoffCents = ~~filter.cutoffCents; // Math.floor
147
147
  const qCb = filter.reasonanceCb;
148
148
  // check if these coefficients were already cached
149
- if (WorkletLowpassFilter.cachedCoefficients?.[qCb]?.[cutoffCents] === undefined)
149
+ const cached = WorkletLowpassFilter.cachedCoefficients?.[qCb]?.[cutoffCents];
150
+ if (cached !== undefined)
150
151
  {
151
- let cutoffHz = absCentsToHz(cutoffCents);
152
-
153
- // fix cutoff on low frequencies (fluid_iir_filter.c line 392)
154
- cutoffHz = Math.min(cutoffHz, 0.45 * sampleRate);
155
-
156
- const qDb = qCb / 10;
157
- // correct the filter gain, like fluid does
158
- const reasonanceGain = decibelAttenuationToGain(-1 * (qDb - 3.01)); // -1 because it's attenuation, and we don't want attenuation
159
-
160
- // reduce the gain by the Q factor (fluid_iir_filter.c line 250)
161
- const qGain = 1 / Math.sqrt(decibelAttenuationToGain(-qDb));
162
-
163
-
164
- // initial filtering code was ported from meltysynth created by sinshu.
165
- let w = 2 * Math.PI * cutoffHz / sampleRate; // we're in the AudioWorkletGlobalScope so we can use sampleRate
166
- let cosw = Math.cos(w);
167
- let alpha = Math.sin(w) / (2 * reasonanceGain);
168
-
169
- let b1 = (1 - cosw) * qGain;
170
- let b0 = b1 / 2;
171
- let b2 = b0;
172
- let a0 = 1 + alpha;
173
- let a1 = -2 * cosw;
174
- let a2 = 1 - alpha;
175
-
176
- /**
177
- * set coefficients
178
- * @type {CachedCoefficient}
179
- */
180
- const toCache = {};
181
- toCache.a0 = b0 / a0;
182
- toCache.a1 = b1 / a0;
183
- toCache.a2 = b2 / a0;
184
- toCache.a3 = a1 / a0;
185
- toCache.a4 = a2 / a0;
186
-
187
- if (WorkletLowpassFilter.cachedCoefficients[qCb] === undefined)
188
- {
189
- WorkletLowpassFilter.cachedCoefficients[qCb] = [];
190
- }
191
- WorkletLowpassFilter.cachedCoefficients[qCb][cutoffCents] = toCache;
152
+ filter.a0 = cached.a0;
153
+ filter.a1 = cached.a1;
154
+ filter.a2 = cached.a2;
155
+ filter.a3 = cached.a3;
156
+ filter.a4 = cached.a4;
157
+ return;
158
+ }
159
+ let cutoffHz = absCentsToHz(cutoffCents);
160
+
161
+ // fix cutoff on low frequencies (fluid_iir_filter.c line 392)
162
+ cutoffHz = Math.min(cutoffHz, 0.45 * sampleRate);
163
+
164
+ const qDb = qCb / 10;
165
+ // correct the filter gain, like fluid does
166
+ const reasonanceGain = decibelAttenuationToGain(-1 * (qDb - 3.01)); // -1 because it's attenuation, and we don't want attenuation
167
+
168
+ // reduce the gain by the Q factor (fluid_iir_filter.c line 250)
169
+ const qGain = 1 / Math.sqrt(decibelAttenuationToGain(-qDb));
170
+
171
+
172
+ // initial filtering code was ported from meltysynth created by sinshu.
173
+ let w = 2 * Math.PI * cutoffHz / sampleRate; // we're in the AudioWorkletGlobalScope so we can use sampleRate
174
+ let cosw = Math.cos(w);
175
+ let alpha = Math.sin(w) / (2 * reasonanceGain);
176
+
177
+ let b1 = (1 - cosw) * qGain;
178
+ let b0 = b1 / 2;
179
+ let b2 = b0;
180
+ let a0 = 1 + alpha;
181
+ let a1 = -2 * cosw;
182
+ let a2 = 1 - alpha;
183
+
184
+ /**
185
+ * set coefficients
186
+ * @type {CachedCoefficient}
187
+ */
188
+ const toCache = {};
189
+ toCache.a0 = b0 / a0;
190
+ toCache.a1 = b1 / a0;
191
+ toCache.a2 = b2 / a0;
192
+ toCache.a3 = a1 / a0;
193
+ toCache.a4 = a2 / a0;
194
+ filter.a0 = toCache.a0;
195
+ filter.a1 = toCache.a1;
196
+ filter.a2 = toCache.a2;
197
+ filter.a3 = toCache.a3;
198
+ filter.a4 = toCache.a4;
199
+
200
+ if (WorkletLowpassFilter.cachedCoefficients[qCb] === undefined)
201
+ {
202
+ WorkletLowpassFilter.cachedCoefficients[qCb] = [];
192
203
  }
193
- const cached = WorkletLowpassFilter.cachedCoefficients[qCb][cutoffCents];
194
- filter.a0 = cached.a0;
195
- filter.a1 = cached.a1;
196
- filter.a2 = cached.a2;
197
- filter.a3 = cached.a3;
198
- filter.a4 = cached.a4;
204
+ WorkletLowpassFilter.cachedCoefficients[qCb][cutoffCents] = toCache;
205
+
206
+
199
207
  }
200
208
  }