spessasynth_lib 3.20.11 → 3.20.15

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.
@@ -1,3 +1,5 @@
1
+ // noinspection JSUnresolvedReference
2
+
1
3
  import { DEFAULT_PERCUSSION, DEFAULT_SYNTH_MODE, VOICE_CAP } from '../synthetizer.js'
2
4
  import { WorkletSequencer } from '../../sequencer/worklet_sequencer/worklet_sequencer.js'
3
5
  import { SpessaSynthInfo } from '../../utils/loggin.js'
@@ -32,13 +34,14 @@ import {
32
34
  clearSoundFont,
33
35
  getPreset,
34
36
  programChange,
35
- reloadSoundFont, sampleDump, sendPresetList,
36
- setDrums,
37
+ reloadSoundFont, sendPresetList,
38
+ setDrums, setEmbeddedSoundFont,
37
39
  setPreset,
38
40
  } from './worklet_methods/program_control.js'
39
41
  import { applySynthesizerSnapshot, sendSynthesizerSnapshot } from './worklet_methods/snapshot.js'
40
42
  import { WorkletSoundfontManager } from './worklet_methods/worklet_soundfont_manager/worklet_soundfont_manager.js'
41
43
  import { interpolationTypes } from './worklet_utilities/wavetable_oscillator.js'
44
+ import { getWorkletVoices } from './worklet_utilities/worklet_voice.js'
42
45
 
43
46
 
44
47
  /**
@@ -50,6 +53,7 @@ export const MIN_NOTE_LENGTH = 0.07; // if the note is released faster than that
50
53
 
51
54
  export const SYNTHESIZER_GAIN = 1.0;
52
55
 
56
+
53
57
  class SpessaSynthProcessor extends AudioWorkletProcessor
54
58
  {
55
59
  /**
@@ -169,10 +173,6 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
169
173
  this.defaultPreset = this.getPreset(0, 0);
170
174
  this.drumPreset = this.getPreset(128, 0);
171
175
 
172
- /**
173
- * @type {Float32Array[]}
174
- */
175
- this.workletDumpedSamplesList = [];
176
176
  /**
177
177
  * contains all the channels with their voices on the processor size
178
178
  * @type {WorkletProcessorChannel[]}
@@ -186,9 +186,6 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
186
186
  this.workletProcessorChannels[DEFAULT_PERCUSSION].preset = this.drumPreset;
187
187
  this.workletProcessorChannels[DEFAULT_PERCUSSION].drumChannel = true;
188
188
 
189
- // in seconds, time between two samples (very, very short)
190
- this.sampleTime = 1 / sampleRate;
191
-
192
189
  // these smoothing factors were tested on 44100Hz, adjust them here
193
190
  this.volumeEnvelopeSmoothingFactor = VOLUME_ENVELOPE_SMOOTHING_FACTOR * (sampleRate / 44100);
194
191
  this.panSmoothingFactor = PAN_SMOOTHING_FACTOR * (sampleRate / 44100);
@@ -204,14 +201,21 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
204
201
 
205
202
  this.totalVoicesAmount = 0;
206
203
 
204
+ /**
205
+ * The snapshot that synth was restored from
206
+ * @type {SynthesizerSnapshot|undefined}
207
+ * @private
208
+ */
209
+ this._snapshot = options.processorOptions?.startRenderingData?.snapshot;
210
+
207
211
  this.port.onmessage = e => this.handleMessage(e.data);
208
212
 
209
213
  // if sent, start rendering
210
214
  if(options.processorOptions.startRenderingData)
211
215
  {
212
- if (options.processorOptions.startRenderingData.snapshot)
216
+ if (this._snapshot !== undefined)
213
217
  {
214
- this.applySynthesizerSnapshot(options.processorOptions.startRenderingData.snapshot);
218
+ this.applySynthesizerSnapshot(this._snapshot);
215
219
  this.resetAllControllers();
216
220
  }
217
221
 
@@ -271,6 +275,7 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
271
275
  });
272
276
  }
273
277
 
278
+ // noinspection JSUnusedGlobalSymbols
274
279
  /**
275
280
  * Syntesizes the voice to buffers
276
281
  * @param inputs {Float32Array[][]} required by WebAudioAPI
@@ -355,6 +360,7 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
355
360
  SpessaSynthProcessor.prototype.renderVoice = renderVoice;
356
361
  SpessaSynthProcessor.prototype.releaseVoice = releaseVoice;
357
362
  SpessaSynthProcessor.prototype.voiceKilling = voiceKilling;
363
+ SpessaSynthProcessor.prototype.getWorkletVoices = getWorkletVoices;
358
364
 
359
365
  // message port related
360
366
  SpessaSynthProcessor.prototype.handleMessage = handleMessage;
@@ -411,7 +417,7 @@ SpessaSynthProcessor.prototype.setPreset = setPreset;
411
417
  SpessaSynthProcessor.prototype.setDrums = setDrums;
412
418
  SpessaSynthProcessor.prototype.reloadSoundFont = reloadSoundFont;
413
419
  SpessaSynthProcessor.prototype.clearSoundFont = clearSoundFont;
414
- SpessaSynthProcessor.prototype.sampleDump = sampleDump;
420
+ SpessaSynthProcessor.prototype.setEmbeddedSoundFont = setEmbeddedSoundFont;
415
421
  SpessaSynthProcessor.prototype.sendPresetList = sendPresetList;
416
422
 
417
423
  // snapshot related
@@ -1,4 +1,3 @@
1
- import { getWorkletVoices } from '../worklet_utilities/worklet_voice.js'
2
1
  import { generatorTypes } from '../../../soundfont/read_sf2/generators.js'
3
2
  import { computeModulators } from '../worklet_utilities/worklet_modulator.js'
4
3
  import { WorkletVolumeEnvelope } from '../worklet_utilities/volume_envelope.js'
@@ -45,19 +44,12 @@ export function noteOn(channel, midiNote, velocity, enableDebugging = false, sen
45
44
  }
46
45
 
47
46
  // get voices
48
- const voices = getWorkletVoices(
47
+ const voices = this.getWorkletVoices(
49
48
  channel,
50
49
  sentMidiNote,
51
50
  velocity,
52
- channelObject.preset,
51
+ channelObject,
53
52
  startTime,
54
- sampleRate,
55
- data => this.sampleDump(
56
- data.channel,
57
- data.sampleID,
58
- data.sampleData
59
- ),
60
- channelObject.cachedVoices,
61
53
  enableDebugging
62
54
  );
63
55
 
@@ -1,6 +1,4 @@
1
1
  import { midiControllers } from '../../../midi_parser/midi_message.js'
2
- import { clearSamplesList } from '../worklet_utilities/worklet_voice.js'
3
- import { generatorTypes } from '../../../soundfont/read_sf2/generators.js'
4
2
  import { returnMessageType } from '../message_protocol/worklet_message.js'
5
3
  import { SpessaSynthInfo, SpessaSynthWarn } from '../../../utils/loggin.js'
6
4
  import { consoleColors } from '../../../utils/other.js'
@@ -183,13 +181,10 @@ export function sendPresetList()
183
181
  export function clearSoundFont(sendPresets = true, clearOverride = true)
184
182
  {
185
183
  this.stopAllChannels(true);
186
- clearSamplesList();
187
184
  if(clearOverride)
188
185
  {
189
186
  delete this.overrideSoundfont;
190
187
  }
191
- delete this.workletDumpedSamplesList;
192
- this.workletDumpedSamplesList = [];
193
188
  this.defaultPreset = this.getPreset(0, 0);
194
189
  this.drumPreset = this.getPreset(128, 0);
195
190
 
@@ -253,44 +248,23 @@ export function reloadSoundFont(buffer, isOverride = false)
253
248
  }
254
249
 
255
250
  /**
256
- * saves a sample
257
- * @param channel {number}
258
- * @param sampleID {number}
259
- * @param sampleData {Float32Array}
251
+ * Sets the embedded (RMI soundfont)
252
+ * @param font {ArrayBuffer}
253
+ * @param offset {number}
260
254
  * @this {SpessaSynthProcessor}
261
255
  */
262
- export function sampleDump(channel, sampleID, sampleData)
256
+ export function setEmbeddedSoundFont(font, offset)
263
257
  {
264
- this.workletDumpedSamplesList[sampleID] = sampleData;
265
- // the sample maybe was loaded after the voice was sent... adjust the end position!
266
-
267
- // not for all channels because the system tells us for what channel this voice was dumped! yay!
268
- this.workletProcessorChannels[channel].voices.forEach(v => {
269
- if(v.sample.sampleID !== sampleID)
270
- {
271
- return;
272
- }
273
- v.sample.end = sampleData.length - 1 + v.generators[generatorTypes.endAddrOffset] + (v.generators[generatorTypes.endAddrsCoarseOffset] * 32768);
274
- // calculate for how long the sample has been playing and move the cursor there
275
- v.sample.cursor = (v.sample.playbackStep * sampleRate) * (currentTime - v.startTime);
276
- if(v.sample.loopingMode === 0) // no loop
277
- {
278
- if (v.sample.cursor >= v.sample.end)
279
- {
280
- v.finished = true;
281
- return;
282
- }
283
- }
284
- else
285
- {
286
- // go through modulo (adjust cursor if the sample has looped
287
- if(v.sample.cursor > v.sample.loopEnd)
288
- {
289
- v.sample.cursor = v.sample.cursor % (v.sample.loopEnd - v.sample.loopStart) + v.sample.loopStart - 1;
290
- }
291
- }
292
- // set start time to current!
293
- v.startTime = currentTime;
294
- })
258
+ // set offet
259
+ this.soundfontBankOffset = offset;
260
+ this.reloadSoundFont(font, true);
261
+ // preload all samples
262
+ this.overrideSoundfont.samples.forEach(s => s.getAudioData());
295
263
 
264
+ // apply snapshot again if applicable
265
+ if(this._snapshot !== undefined)
266
+ {
267
+ this.applySynthesizerSnapshot(this._snapshot);
268
+ this.resetAllControllers();
269
+ }
296
270
  }
@@ -5,7 +5,7 @@ import { customControllers } from '../worklet_utilities/worklet_processor_channe
5
5
  import { WorkletModulationEnvelope } from '../worklet_utilities/modulation_envelope.js'
6
6
  import { getSampleLinear, getSampleNearest, interpolationTypes } from '../worklet_utilities/wavetable_oscillator.js'
7
7
  import { panVoice } from '../worklet_utilities/stereo_panner.js'
8
- import { applyLowpassFilter } from '../worklet_utilities/lowpass_filter.js'
8
+ import { WorkletLowpassFilter } from '../worklet_utilities/lowpass_filter.js'
9
9
  import { MIN_NOTE_LENGTH } from '../main_processor.js'
10
10
  import { WorkletVolumeEnvelope } from '../worklet_utilities/volume_envelope.js'
11
11
 
@@ -150,15 +150,15 @@ export function renderVoice(
150
150
  // wavetable oscillator
151
151
  if(this.interpolationType === interpolationTypes.linear)
152
152
  {
153
- getSampleLinear(voice, this.workletDumpedSamplesList[voice.sample.sampleID], bufferOut);
153
+ getSampleLinear(voice, bufferOut);
154
154
  }
155
155
  else
156
156
  {
157
- getSampleNearest(voice, this.workletDumpedSamplesList[voice.sample.sampleID], bufferOut);
157
+ getSampleNearest(voice, bufferOut);
158
158
  }
159
159
 
160
160
  // lowpass filter
161
- applyLowpassFilter(voice, bufferOut, lowpassCents);
161
+ WorkletLowpassFilter.apply(voice, bufferOut, lowpassCents);
162
162
 
163
163
  // volenv
164
164
  WorkletVolumeEnvelope.apply(voice, bufferOut, modLfoCentibels, this.volumeEnvelopeSmoothingFactor);
@@ -9,122 +9,166 @@ import { absCentsToHz, decibelAttenuationToGain } from './unit_converter.js'
9
9
  * Shoutout to them!
10
10
  */
11
11
 
12
-
13
- /**
14
- * @typedef {Object} WorkletLowpassFilter
15
- * @property {number} a0 - filter coefficient 1
16
- * @property {number} a1 - filter coefficient 2
17
- * @property {number} a2 - filter coefficient 3
18
- * @property {number} a3 - filter coefficient 4
19
- * @property {number} a4 - filter coefficient 5
20
- * @property {number} x1 - input history 1
21
- * @property {number} x2 - input history 2
22
- * @property {number} y1 - output history 1
23
- * @property {number} y2 - output history 2
24
- * @property {number} reasonanceCb - reasonance in centibels
25
- * @property {number} reasonanceGain - resonance gain
26
- * @property {number} cutoffCents - cutoff frequency in cents
27
- * @property {number} cutoffHz - cutoff frequency in Hz
28
- */
29
-
30
- /**
31
- * @type {WorkletLowpassFilter}
32
- */
33
- export const DEFAULT_WORKLET_LOWPASS_FILTER = {
34
- a0: 0,
35
- a1: 0,
36
- a2: 0,
37
- a3: 0,
38
- a4: 0,
39
-
40
- x1: 0,
41
- x2: 0,
42
- y1: 0,
43
- y2: 0,
44
-
45
- reasonanceCb: 0,
46
- reasonanceGain: 1,
47
- cutoffCents: 13500,
48
- cutoffHz: 20000
49
- }
50
-
51
- /**
52
- * Applies a low-pass filter to the given buffer
53
- * @param voice {WorkletVoice} the voice we're working on
54
- * @param outputBuffer {Float32Array} the buffer to apply the filter to
55
- * @param cutoffCents {number} cutoff frequency in cents
56
- */
57
- export function applyLowpassFilter(voice, outputBuffer, cutoffCents)
12
+ export class WorkletLowpassFilter
58
13
  {
59
- if(cutoffCents > 13499)
60
- {
61
- return; // filter is open
62
- }
63
-
64
- // check if the frequency has changed. if so, calculate new coefficients
65
- if(voice.filter.cutoffCents !== cutoffCents || voice.filter.reasonanceCb !== voice.modulatedGenerators[generatorTypes.initialFilterQ])
14
+ /**
15
+ * Filter coefficient 1
16
+ * @type {number}
17
+ */
18
+ a0 = 0;
19
+
20
+ /**
21
+ * Filter coefficient 2
22
+ * @type {number}
23
+ */
24
+ a1 = 0;
25
+
26
+ /**
27
+ * Filter coefficient 3
28
+ * @type {number}
29
+ */
30
+ a2 = 0;
31
+
32
+ /**
33
+ * Filter coefficient 4
34
+ * @type {number}
35
+ */
36
+ a3 = 0;
37
+
38
+ /**
39
+ * Filter coefficient 5
40
+ * @type {number}
41
+ */
42
+ a4 = 0;
43
+
44
+ /**
45
+ * Input history 1
46
+ * @type {number}
47
+ */
48
+ x1 = 0;
49
+
50
+ /**
51
+ * Input history 2
52
+ * @type {number}
53
+ */
54
+ x2 = 0;
55
+
56
+ /**
57
+ * Output history 1
58
+ * @type {number}
59
+ */
60
+ y1 = 0;
61
+
62
+ /**
63
+ * Output history 2
64
+ * @type {number}
65
+ */
66
+ y2 = 0;
67
+
68
+ /**
69
+ * Resonance in centibels
70
+ * @type {number}
71
+ */
72
+ reasonanceCb = 0;
73
+
74
+ /**
75
+ * Resonance gain
76
+ * @type {number}
77
+ */
78
+ reasonanceGain = 1;
79
+
80
+ /**
81
+ * Cutoff frequency in cents
82
+ * @type {number}
83
+ */
84
+ cutoffCents = 13500;
85
+
86
+ /**
87
+ * Cutoff frequency in Hz
88
+ * @type {number}
89
+ */
90
+ cutoffHz = 20000;
91
+
92
+ /**
93
+ * Applies a low-pass filter to the given buffer
94
+ * @param voice {WorkletVoice} the voice we're working on
95
+ * @param outputBuffer {Float32Array} the buffer to apply the filter to
96
+ * @param cutoffCents {number} cutoff frequency in cents
97
+ */
98
+ static apply(voice, outputBuffer, cutoffCents)
66
99
  {
67
- voice.filter.cutoffCents = cutoffCents;
68
- voice.filter.reasonanceCb = voice.modulatedGenerators[generatorTypes.initialFilterQ];
69
- calculateCoefficients(voice);
100
+ if(cutoffCents > 13499)
101
+ {
102
+ return; // filter is open
103
+ }
104
+
105
+ // check if the frequency has changed. if so, calculate new coefficients
106
+ if(voice.filter.cutoffCents !== cutoffCents || voice.filter.reasonanceCb !== voice.modulatedGenerators[generatorTypes.initialFilterQ])
107
+ {
108
+ voice.filter.cutoffCents = cutoffCents;
109
+ voice.filter.reasonanceCb = voice.modulatedGenerators[generatorTypes.initialFilterQ];
110
+ WorkletLowpassFilter.calculateCoefficients(voice);
111
+ }
112
+
113
+ // filter the input
114
+ for (let i = 0; i < outputBuffer.length; i++)
115
+ {
116
+ let input = outputBuffer[i];
117
+ let filtered = voice.filter.a0 * input
118
+ + voice.filter.a1 * voice.filter.x1
119
+ + voice.filter.a2 * voice.filter.x2
120
+ - voice.filter.a3 * voice.filter.y1
121
+ - voice.filter.a4 * voice.filter.y2;
122
+
123
+ // set buffer
124
+ voice.filter.x2 = voice.filter.x1;
125
+ voice.filter.x1 = input;
126
+ voice.filter.y2 = voice.filter.y1;
127
+ voice.filter.y1 = filtered;
128
+
129
+ outputBuffer[i] = filtered;
130
+ }
70
131
  }
71
132
 
72
- // filter the input
73
- for (let i = 0; i < outputBuffer.length; i++) {
74
- let input = outputBuffer[i];
75
- let filtered = voice.filter.a0 * input
76
- + voice.filter.a1 * voice.filter.x1
77
- + voice.filter.a2 * voice.filter.x2
78
- - voice.filter.a3 * voice.filter.y1
79
- - voice.filter.a4 * voice.filter.y2;
80
-
81
- // set buffer
82
- voice.filter.x2 = voice.filter.x1;
83
- voice.filter.x1 = input;
84
- voice.filter.y2 = voice.filter.y1;
85
- voice.filter.y1 = filtered;
86
-
87
- outputBuffer[i] = filtered;
88
- }
89
- }
90
-
91
- /**
92
- * @param voice {WorkletVoice}
93
- */
94
- function calculateCoefficients(voice)
95
- {
96
- voice.filter.cutoffHz = absCentsToHz(voice.filter.cutoffCents);
97
-
98
- // fix cutoff on low frequencies (fluid_iir_filter.c line 392)
99
- if(voice.filter.cutoffHz > 0.45 * sampleRate)
133
+ /**
134
+ * @param voice {WorkletVoice}
135
+ */
136
+ static calculateCoefficients(voice)
100
137
  {
101
- voice.filter.cutoffHz = 0.45 * sampleRate;
138
+ voice.filter.cutoffHz = absCentsToHz(voice.filter.cutoffCents);
139
+
140
+ // fix cutoff on low frequencies (fluid_iir_filter.c line 392)
141
+ if(voice.filter.cutoffHz > 0.45 * sampleRate)
142
+ {
143
+ voice.filter.cutoffHz = 0.45 * sampleRate;
144
+ }
145
+
146
+ // adjust the filterQ (fluid_iir_filter.c line 204)
147
+ const qDb = (voice.filter.reasonanceCb / 10) - 3.01;
148
+ voice.filter.reasonanceGain = decibelAttenuationToGain(-1 * qDb); // -1 because it's attenuation and we don't want attenuation
149
+
150
+ // reduce the gain by the Q factor (fluid_iir_filter.c line 250)
151
+ const qGain = 1 / Math.sqrt(voice.filter.reasonanceGain);
152
+
153
+
154
+ // code is ported from https://github.com/sinshu/meltysynth/ to work with js.
155
+ // I'm too dumb to understand the math behind this...
156
+ let w = 2 * Math.PI * voice.filter.cutoffHz / sampleRate; // we're in the audioworkletglobalscope so we can use sampleRate
157
+ let cosw = Math.cos(w);
158
+ let alpha = Math.sin(w) / (2 * voice.filter.reasonanceGain);
159
+
160
+ let b1 = (1 - cosw) * qGain;
161
+ let b0 = b1 / 2;
162
+ let b2 = b0;
163
+ let a0 = 1 + alpha;
164
+ let a1 = -2 * cosw;
165
+ let a2 = 1 - alpha;
166
+
167
+ // set coefficients
168
+ voice.filter.a0 = b0 / a0;
169
+ voice.filter.a1 = b1 / a0;
170
+ voice.filter.a2 = b2 / a0;
171
+ voice.filter.a3 = a1 / a0;
172
+ voice.filter.a4 = a2 / a0;
102
173
  }
103
-
104
- // adjust the filterQ (fluid_iir_filter.c line 204)
105
- const qDb = (voice.filter.reasonanceCb / 10) - 3.01;
106
- voice.filter.reasonanceGain = decibelAttenuationToGain(-1 * qDb); // -1 because it's attenuation and we don't want attenuation
107
-
108
- // reduce the gain by the Q factor (fluid_iir_filter.c line 250)
109
- const qGain = 1 / Math.sqrt(voice.filter.reasonanceGain);
110
-
111
-
112
- // code is ported from https://github.com/sinshu/meltysynth/ to work with js. I'm too dumb to understand the math behind this...
113
- let w = 2 * Math.PI * voice.filter.cutoffHz / sampleRate; // we're in the audioworkletglobalscope so we can use sampleRate
114
- let cosw = Math.cos(w);
115
- let alpha = Math.sin(w) / (2 * voice.filter.reasonanceGain);
116
-
117
- let b1 = (1 - cosw) * qGain;
118
- let b0 = b1 / 2;
119
- let b2 = b0;
120
- let a0 = 1 + alpha;
121
- let a1 = -2 * cosw;
122
- let a2 = 1 - alpha;
123
-
124
- // set coefficients
125
- voice.filter.a0 = b0 / a0;
126
- voice.filter.a1 = b1 / a0;
127
- voice.filter.a2 = b2 / a0;
128
- voice.filter.a3 = a1 / a0;
129
- voice.filter.a4 = a2 / a0;
130
174
  }
@@ -16,17 +16,17 @@ export const interpolationTypes = {
16
16
  /**
17
17
  * Fills the output buffer with raw sample data using linear interpolation
18
18
  * @param voice {WorkletVoice} the voice we're working on
19
- * @param sampleData {Float32Array} the sample data to write with
20
19
  * @param outputBuffer {Float32Array} the output buffer to write to
21
20
  */
22
- export function getSampleLinear(voice, sampleData, outputBuffer)
21
+ export function getSampleLinear(voice, outputBuffer)
23
22
  {
24
23
  let cur = voice.sample.cursor;
25
24
  const loop = (voice.sample.loopingMode === 1) || (voice.sample.loopingMode === 3 && !voice.isInRelease);
26
- const loopLength = voice.sample.loopEnd - voice.sample.loopStart;
25
+ const sampleData = voice.sample.sampleData;
27
26
 
28
27
  if(loop)
29
28
  {
29
+ const loopLength = voice.sample.loopEnd - voice.sample.loopStart;
30
30
  for (let i = 0; i < outputBuffer.length; i++)
31
31
  {
32
32
  // check for loop
@@ -44,11 +44,6 @@ export function getSampleLinear(voice, sampleData, outputBuffer)
44
44
  ceil -= loopLength;
45
45
  }
46
46
 
47
- // nearest neighbor (uncomment to use)
48
- // outputBuffer[i] = sampleData[ceil];
49
- // cur += voice.sample.playbackStep * voice.currentTuningCalculated;
50
- // continue;
51
-
52
47
  const fraction = cur - floor;
53
48
 
54
49
  // grab the samples and interpolate
@@ -73,7 +68,8 @@ export function getSampleLinear(voice, sampleData, outputBuffer)
73
68
  {
74
69
  voice.sample.end = sampleData.length - 1;
75
70
  }
76
- for (let i = 0; i < outputBuffer.length; i++) {
71
+ for (let i = 0; i < outputBuffer.length; i++)
72
+ {
77
73
 
78
74
  // linear interpolation
79
75
  const floor = ~~cur;
@@ -86,11 +82,6 @@ export function getSampleLinear(voice, sampleData, outputBuffer)
86
82
  return;
87
83
  }
88
84
 
89
- // nearest neighbor (uncomment to use)
90
- // outputBuffer[i] = sampleData[ceil];
91
- // cur += voice.sample.playbackStep * voice.currentTuningCalculated;
92
- // continue;
93
-
94
85
  const fraction = cur - floor;
95
86
 
96
87
  // grab the samples and interpolate
@@ -107,15 +98,14 @@ export function getSampleLinear(voice, sampleData, outputBuffer)
107
98
  /**
108
99
  * Fills the output buffer with raw sample data using no interpolation (nearest neighbor)
109
100
  * @param voice {WorkletVoice} the voice we're working on
110
- * @param sampleData {Float32Array} the sample data to write with
111
101
  * @param outputBuffer {Float32Array} the output buffer to write to
112
102
  */
113
- export function getSampleNearest(voice, sampleData, outputBuffer)
103
+ export function getSampleNearest(voice, outputBuffer)
114
104
  {
115
105
  let cur = voice.sample.cursor;
116
106
  const loop = (voice.sample.loopingMode === 1) || (voice.sample.loopingMode === 3 && !voice.isInRelease);
117
107
  const loopLength = voice.sample.loopEnd - voice.sample.loopStart;
118
-
108
+ const sampleData = voice.sample.sampleData;
119
109
  if(loop)
120
110
  {
121
111
  for (let i = 0; i < outputBuffer.length; i++)