Skip to content

Commit

Permalink
allow sample offset modulation
Browse files Browse the repository at this point in the history
fixes #51
  • Loading branch information
spessasus committed Oct 3, 2024
1 parent 1a8fcf4 commit 13c6f49
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 21 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "SpessaSynth",
"version": "3.20.36.1",
"version": "3.20.36.2",
"type": "module",
"scripts": {
"start": "node src/website/server/server.js"
Expand Down
8 changes: 4 additions & 4 deletions src/spessasynth_lib/soundfont/read_sf2/generators.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ export const generatorTypes = {
endAddrOffset: 1, // sample control - moves sample end point
startloopAddrsOffset: 2, // loop control - moves loop start point
endloopAddrsOffset: 3, // loop control - moves loop end point
startAddrsCoarseOffset: 4, // sample control - moves sample start point in 32767 increments
startAddrsCoarseOffset: 4, // sample control - moves sample start point in 32768 increments
modLfoToPitch: 5, // pitch modulation - modulation lfo pitch modulation in cents
vibLfoToPitch: 6, // pitch modulation - vibrato lfo pitch modulation in cents
modEnvToPitch: 7, // pitch modulation - modulation envelope pitch modulation in cents
initialFilterFc: 8, // filter - lowpass filter cutoff in cents
initialFilterQ: 9, // filter - lowpass filter resonance
modLfoToFilterFc: 10, // filter modulation - modulation lfo lowpass filter cutoff in cents
modEnvToFilterFc: 11, // filter modulation - modulation envelope lowpass filter cutoff in cents
endAddrsCoarseOffset: 12, // ample control - moves sample end point in 32767 increments
endAddrsCoarseOffset: 12, // ample control - moves sample end point in 32768 increments
modLfoToVolume: 13, // modulation lfo - volume (tremolo), where 100 = 10dB
unused1: 14,
chorusEffectsSend: 15, // effect send - how much is sent to chorus 0 - 1000
Expand Down Expand Up @@ -57,12 +57,12 @@ export const generatorTypes = {
reserved1: 42,
keyRange: 43, // zone - key range for which preset / instrument zone is active
velRange: 44, // zone - velocity range for which preset / instrument zone is active
startloopAddrsCoarseOffset: 45, // ample control - moves sample loop start point in 32767 increments
startloopAddrsCoarseOffset: 45, // sample control - moves sample loop start point in 32768 increments
keyNum: 46, // zone - instrument only: always use this midi number (ignore what's pressed)
velocity: 47, // zone - instrument only: always use this velocity (ignore what's pressed)
initialAttenuation: 48, // zone - allows turning down the volume, 10 = -1dB
reserved2: 49,
endloopAddrsCoarseOffset: 50, // ample control - moves sample loop end point in 32767 increments
endloopAddrsCoarseOffset: 50, // sample control - moves sample loop end point in 32768 increments
coarseTune: 51, // tune - pitch offset in semitones
fineTune: 52, // tune - pitch offset in cents
sampleID: 53, // sample - instrument zone only: which sample to use
Expand Down
18 changes: 9 additions & 9 deletions src/spessasynth_lib/synthetizer/worklet_processor.min.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,30 @@ export function noteOn(channel, midiNote, velocity, enableDebugging = false, sen
}
// compute all modulators
computeModulators(voice, channelObject.midiControllers);
// modulate sample offsets (these are not real time)
const cursorStartOffset = voice.modulatedGenerators[generatorTypes.startAddrsOffset] + voice.modulatedGenerators[generatorTypes.startAddrsCoarseOffset] * 32768;
const endOffset = voice.modulatedGenerators[generatorTypes.endAddrOffset] + voice.modulatedGenerators[generatorTypes.endAddrsCoarseOffset] * 32768;
const loopStartOffset = voice.modulatedGenerators[generatorTypes.startloopAddrsOffset] + voice.modulatedGenerators[generatorTypes.startloopAddrsCoarseOffset] * 32768;
const loopEndOffset = voice.modulatedGenerators[generatorTypes.endloopAddrsOffset] + voice.modulatedGenerators[generatorTypes.endloopAddrsCoarseOffset] * 32768;
const sm = voice.sample;
// apply them
const clamp = num => Math.max(0, Math.min(sm.sampleData.length, num));
sm.cursor = clamp( sm.cursor + cursorStartOffset);
sm.end = clamp(sm.end + endOffset);
sm.loopStart = clamp(sm.loopStart + loopStartOffset);
sm.loopEnd = clamp(sm.loopEnd + loopEndOffset);
// swap loops if needed
if(sm.loopEnd < sm.loopStart)
{
const temp = sm.loopStart;
sm.loopStart = sm.loopEnd;
sm.loopEnd = temp;
}
if (sm.loopEnd - sm.loopStart < 1)
{
sm.loopingMode = 0;
sm.isLooping = false;
}
// set the current attenuation to target,
// as it's interpolated (we don't want 0 attenuation for even a split second)
voice.volumeEnvelope.attenuation = voice.volumeEnvelope.attenuationTarget;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,8 @@ export function getWorkletVoices(channel,
}

// determine looping mode now. if the loop is too small, disable
let loopStart = (sampleAndGenerators.sample.sampleLoopStartIndex / 2) + (generators[generatorTypes.startloopAddrsOffset] + (generators[generatorTypes.startloopAddrsCoarseOffset] * 32768));
let loopEnd = (sampleAndGenerators.sample.sampleLoopEndIndex / 2) + (generators[generatorTypes.endloopAddrsOffset] + (generators[generatorTypes.endloopAddrsCoarseOffset] * 32768));
let loopStart = (sampleAndGenerators.sample.sampleLoopStartIndex / 2);
let loopEnd = (sampleAndGenerators.sample.sampleLoopEndIndex / 2);
let loopingMode = generators[generatorTypes.sampleModes];
const sampleLength = sampleAndGenerators.sample.getAudioData().length;
// clamp loop
Expand All @@ -381,17 +381,18 @@ export function getWorkletVoices(channel,
loopingMode = 0;
}
/**
* create the worklet sample and calculate offsets
* create the worklet sample
* offsets are calculated at note on time (to allow for modulation of them)
* @type {WorkletSample}
*/
const workletSample = new WorkletSample(
sampleAndGenerators.sample.getAudioData(),
(sampleAndGenerators.sample.sampleRate / sampleRate) * Math.pow(2, sampleAndGenerators.sample.samplePitchCorrection / 1200), // cent tuning
generators[generatorTypes.startAddrsOffset] + (generators[generatorTypes.startAddrsCoarseOffset] * 32768),
0,
rootKey,
loopStart,
loopEnd,
Math.floor( sampleAndGenerators.sample.sampleData.length) - 1 + (generators[generatorTypes.endAddrOffset] + (generators[generatorTypes.endAddrsCoarseOffset] * 32768)),
Math.floor( sampleAndGenerators.sample.sampleData.length) - 1,
loopingMode
)
// velocity override
Expand Down
2 changes: 1 addition & 1 deletion src/website/js/main/demo_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ demoInit(initLocale).then(() => {
window.manager.sfError = e => {
loadingMessage.innerHTML = `Error parsing soundfont: <pre style='font-family: monospace; font-weight: bold'>${e}</pre>`;
changeIcon(getExclamationSvg(256));
console.log(e);
console.error(e);
}
loadingMessage.textContent = window.manager.localeManager.getLocaleString("locale.synthInit.startingSynthesizer");
await window.manager.reloadSf(soundFontBuffer);
Expand Down
Loading

0 comments on commit 13c6f49

Please sign in to comment.