Skip to content

Commit

Permalink
read gain from sample level WSMP in DLS
Browse files Browse the repository at this point in the history
fix volenv recalculation being called twice on note on
  • Loading branch information
spessasus committed Oct 2, 2024
1 parent bff129d commit 8936170
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 74 deletions.
11 changes: 10 additions & 1 deletion src/spessasynth_lib/soundfont/dls/dls_sample.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export class DLSSample extends BasicSample
* @param loopStart {number} sample data points
* @param loopEnd {number} sample data points
* @param data {Float32Array}
* @param sampleDbAttenuation {number} in db
*/
constructor(
name,
Expand All @@ -18,7 +19,8 @@ export class DLSSample extends BasicSample
pitchCorrection,
loopStart,
loopEnd,
data
data,
sampleDbAttenuation
)
{
super(
Expand All @@ -32,13 +34,20 @@ export class DLSSample extends BasicSample
(loopEnd - 1) * 2 // -1 sample because soundfont end is last sample and dls end is next sample
);
this.sampleData = data;
this.sampleDbAttenuation = sampleDbAttenuation;
}

getAudioData()
{
return this.sampleData;
}

/**
* in decibels of attenuation, WITHOUT EMU CORRECTION
* @type {number}
*/
sampleDbAttenuation;

/**
* @type {Float32Array}
*/
Expand Down
12 changes: 10 additions & 2 deletions src/spessasynth_lib/soundfont/dls/read_region.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ export function readRegion(chunk)
);

// gain correction: Each unit of gain represents 1/655360 dB
// it is set after linking the sample
const gainCorrection = readLittleEndian(waveSampleChunk.chunkData, 4);
// convert to signed and turn into attenuation (invert)
const dbCorrection = (gainCorrection | 0) / -655360;
// convert to centibels
const attenuation = (dbCorrection * 10) / 0.4; // make sure to apply EMU correction

// skip options
readLittleEndian(waveSampleChunk.chunkData, 4);
Expand Down Expand Up @@ -118,11 +117,20 @@ export function readRegion(chunk)
readLittleEndian(waveLinkChunk.chunkData, 4);
// sampleID
const sampleID = readLittleEndian(waveLinkChunk.chunkData, 4);
/**
* @type {DLSSample}
*/
const sample = this.samples[sampleID];
if(sample === undefined)
{
throw new Error("Invalid sample ID!");
}

// this correction overrides the sample gain correction
const actualDbCorrection = dbCorrection || sample.sampleDbAttenuation;
// convert to centibels
const attenuation = (actualDbCorrection * 10) / 0.4; // make sure to apply EMU correction

zone.setWavesample(
attenuation, loopingMode,
loop,
Expand Down
10 changes: 7 additions & 3 deletions src/spessasynth_lib/soundfont/dls/read_samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export function readDLSSamples(waveListChunk)
let samplePitch = 0;
let sampleLoopStart = 0;
let sampleLoopEnd = sampleData.length - 1;
let sampleDbAttenuation = 0;

// read wsmp
const wsmpChunk = waveChunks.find(c => c.header === "wsmp")
Expand All @@ -120,8 +121,10 @@ export function readDLSSamples(waveListChunk)
wsmpChunk.chunkData[wsmpChunk.chunkData.currentIndex++],
wsmpChunk.chunkData[wsmpChunk.chunkData.currentIndex++]
);
// gain is handled in regions as initialAttenuation
readLittleEndian(wsmpChunk.chunkData, 4);
// gain is applied it manually here (literally multiplying the samples)
const gainCorrection = readLittleEndian(wsmpChunk.chunkData, 4);
// convert to signed and turn into decibels
sampleDbAttenuation = (gainCorrection | 0) / -655360;
// no idea about ful options
readLittleEndian(wsmpChunk.chunkData, 4);
const loopsAmount = readLittleEndian(wsmpChunk.chunkData, 4);
Expand Down Expand Up @@ -162,7 +165,8 @@ export function readDLSSamples(waveListChunk)
samplePitch,
sampleLoopStart,
sampleLength,
sampleData
sampleData,
sampleDbAttenuation
));

sampleID++;
Expand Down
22 changes: 11 additions & 11 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 @@ -82,6 +82,7 @@ class SpessaSynthProcessor extends AudioWorkletProcessor

/**
* Interpolation type used
* TODO: cubic interpolation?
* @type {interpolationTypes}
*/
this.interpolationType = interpolationTypes.linear;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export function noteOn(channel, midiNote, velocity, enableDebugging = false, sen
const exclusive = voice.generators[generatorTypes.exclusiveClass];
if(exclusive !== 0)
{
// kill all voices with the same exclusive class
channelVoices.forEach(v => {
if(v.generators[generatorTypes.exclusiveClass] === exclusive)
{
Expand All @@ -72,7 +73,9 @@ export function noteOn(channel, midiNote, velocity, enableDebugging = false, sen
}
// compute all modulators
computeModulators(voice, channelObject.midiControllers);
WorkletVolumeEnvelope.intialize(voice);
// 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;
// set initial pan to avoid split second changing from middle to the correct value
voice.currentPan = ((Math.max(-500, Math.min(500, voice.modulatedGenerators[generatorTypes.pan] )) + 500) / 1000) // 0 to 1
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,22 +147,11 @@ export class WorkletVolumeEnvelope
WorkletVolumeEnvelope.recalculate(voice);
}

/**
* Initializes a volume envelope
* @param voice {WorkletVoice}
*/
static intialize(voice)
{
WorkletVolumeEnvelope.recalculate(voice, true);
voice.volumeEnvelope.attenuation = voice.volumeEnvelope.attenuationTarget;
}

/**
* Recalculates the envelope
* @param voice {WorkletVoice} the voice this envelope belongs to
* @param setupInterpolated {boolean} if we should initialize the interpolated values (attenuation and sustain)
*/
static recalculate(voice, setupInterpolated = false)
static recalculate(voice)
{
const env = voice.volumeEnvelope;
const timecentsToSamples = tc =>
Expand All @@ -172,10 +161,6 @@ export class WorkletVolumeEnvelope
// calculate absolute times (they can change so we have to recalculate every time
env.attenuationTarget = Math.max(0, Math.min(voice.modulatedGenerators[generatorTypes.initialAttenuation], 1440)) / 10; // divide by ten to get decibels
env.sustainDbRelative = Math.min(DB_SILENCE, voice.modulatedGenerators[generatorTypes.sustainVolEnv] / 10);
if(setupInterpolated)
{
env.attenuation = env.attenuationTarget;
}
const sustainDb = Math.min(DB_SILENCE, env.sustainDbRelative);

// calculate durations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ export function computeModulators(voice, controllerTable, sourceUsesCC = -1, sou
const { modulators, generators, modulatedGenerators } = voice;

// Modulation envelope is cheap to recalculate
// why here and not at the bottom?
// I dunno, seems to work fine
WorkletModulationEnvelope.recalculate(voice);

if (sourceUsesCC === -1)
Expand Down
4 changes: 2 additions & 2 deletions src/website/js/dls_to_sf2.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ document.getElementById("dls_upload").oninput = e => {
return;
}
document.getElementById("sf_info").classList.remove("hidden");
document.getElementById("dls_name").innerText = sfont.soundFontInfo["INAM"];
document.getElementById("dls_description").innerText = sfont.soundFontInfo["ICMT"].replace("\nConverted from DLS to SF2 with SpessaSynth", "");
document.getElementById("dls_name").innerText = sfont.soundFontInfo["INAM"] || "Unnamed" ;
document.getElementById("dls_description").innerText = (sfont.soundFontInfo["ICMT"] || "No description").replace("\nConverted from DLS to SF2 with SpessaSynth", "");
document.getElementById("dls_presets").innerText = sfont.presets.length;
document.getElementById("dls_samples").innerText = sfont.samples.length;
message.innerText = "Loaded!";
Expand Down
38 changes: 19 additions & 19 deletions src/website/minified/demo_main.min.js

Large diffs are not rendered by default.

38 changes: 19 additions & 19 deletions src/website/minified/local_main.min.js

Large diffs are not rendered by default.

0 comments on commit 8936170

Please sign in to comment.