Skip to content

Commit

Permalink
refactoring and changes to the worklet system
Browse files Browse the repository at this point in the history
  • Loading branch information
spessasus committed Sep 27, 2023
1 parent 291fce7 commit b6d00dc
Show file tree
Hide file tree
Showing 28 changed files with 597 additions and 499 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,11 @@ The program is divided into parts:
- Vibrato LFO (freq, depth and delay) **Including the Mod wheel support!**
- Scale tuning, fine tune and coarse tune
- exclusive class (although sometimes broken)
- pan
- pan

#### todo
- make the worklet system work
- make the worklet system perform good
- implement the worklet system
- port the worklet system to emscripten (maybe)
- reverb that actually runs well
78 changes: 5 additions & 73 deletions src/spessasynth_lib/soundfont/chunk/modulators.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import {signedInt16, readByte, readBytesAsUintLittleEndian} from "../../utils/byte_functions.js";
import { ShiftableByteArray } from '../../utils/shiftable_array.js';
import {
getModulatorValue,
MOD_PRECOMPUTED_LENGTH,
} from '../../synthetizer/worklet_channel/worklet_utilities/modulator_curves.js'
import { generatorTypes } from './generators.js'
import { consoleColors } from '../../utils/other.js'

Expand Down Expand Up @@ -47,13 +43,13 @@ export class Modulator{
this.modulatorSource = dataArray.srcEnum;
this.modulatorDestination = dataArray.dest;
this.modulationSecondarySrc = dataArray.secSrcEnum;
this.modulationAmount = dataArray.amt;
this.transformAmount = dataArray.amt;
this.transformType = dataArray.transform;
}
else {
this.modulatorSource = readBytesAsUintLittleEndian(dataArray, 2);
this.modulatorDestination = readBytesAsUintLittleEndian(dataArray, 2);
this.modulationAmount = signedInt16(readByte(dataArray), readByte(dataArray));
this.transformAmount = signedInt16(readByte(dataArray), readByte(dataArray));
this.modulationSecondarySrc = readBytesAsUintLittleEndian(dataArray, 2);
this.transformType = readBytesAsUintLittleEndian(dataArray, 2);
}
Expand All @@ -64,84 +60,20 @@ export class Modulator{
}

// decode the source
this.sourceIsBipolar = this.modulatorSource >> 9 & 1;
this.sourcePolarity = this.modulatorSource >> 9 & 1;
this.sourceDirection = this.modulatorSource >> 8 & 1;
this.sourceUsesCC = this.modulatorSource >> 7 & 1;
this.sourceIndex = this.modulatorSource & 127;
this.sourceCurveType = this.modulatorSource >> 10 & 3;

// decode the secondary source
this.secSrcIsBipolar = this.modulationSecondarySrc >> 9 & 1;
this.secSrcPolarity = this.modulationSecondarySrc >> 9 & 1;
this.secSrcDirection = this.modulationSecondarySrc >> 8 & 1;
this.secSrcUsesCC = this.modulationSecondarySrc >> 7 & 1;
this.secSrcIndex = this.modulationSecondarySrc & 127;
this.secSrcCurveType = this.modulationSecondarySrc >> 10 & 3;

this.precomputeModulatorTransform();
}

// precompute the values on sf load
precomputeModulatorTransform()
{
this.sourceTransformed = new Float32Array(MOD_PRECOMPUTED_LENGTH);
this.secondarySrcTransformed = new Float32Array(MOD_PRECOMPUTED_LENGTH);

if(this.modulationAmount < 1)
{
return;
}


// read the cached table
let sourceCached = false;
if(precomputedTransforms[this.sourceCurveType][this.sourceIsBipolar][this.sourceDirection])
{
this.sourceTransformed = new Float32Array(precomputedTransforms[this.sourceCurveType][this.sourceIsBipolar][this.sourceDirection]);
sourceCached = true;
}

let secondarySourceCached = false;
if(precomputedTransforms[this.secSrcCurveType][this.secSrcIsBipolar][this.secSrcDirection])
{
this.secondarySrcTransformed = new Float32Array(precomputedTransforms[this.secSrcCurveType][this.secSrcIsBipolar][this.secSrcDirection]);
secondarySourceCached = true;
}

if(!secondarySourceCached || !sourceCached) {
for (let i = 0; i < MOD_PRECOMPUTED_LENGTH; i++) {
if (!sourceCached) {
this.sourceTransformed[i] = getModulatorValue(
this.sourceDirection,
this.sourceCurveType,
i / MOD_PRECOMPUTED_LENGTH,
this.sourceIsBipolar);
if (isNaN(this.sourceTransformed[i])) {
this.sourceTransformed[i] = 1;
}
}

if (!secondarySourceCached) {
this.secondarySrcTransformed[i] = getModulatorValue(
this.secSrcDirection,
this.secSrcCurveType,
i / MOD_PRECOMPUTED_LENGTH,
this.secSrcIsBipolar);
if (isNaN(this.secondarySrcTransformed[i])) {
this.secondarySrcTransformed[i] = 1;
}
}
}
}

if(!sourceCached)
{
precomputedTransforms[this.sourceCurveType][this.sourceIsBipolar][this.sourceDirection] = this.sourceTransformed;
}

if(!secondarySourceCached)
{
precomputedTransforms[this.secSrcCurveType][this.secSrcIsBipolar][this.secSrcDirection] = this.secondarySrcTransformed;
}
//this.precomputeModulatorTransform();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/spessasynth_lib/soundfont/chunk/presets.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export class Preset {
if(identicalInstrumentModulator)
{
// sum the amounts
identicalInstrumentModulator.modulationAmount += mod.modulationAmount;
identicalInstrumentModulator.modulationAmount += mod.transformAmount;
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Voice} from "./voice.js";
import {VoiceGroup} from "./voice_group.js";
import {Preset} from "../../soundfont/chunk/presets.js";
import { consoleColors } from '../../utils/other.js'
import { midiControllers } from '../../midi_parser/midi_message.js'
Expand Down Expand Up @@ -71,12 +71,12 @@ export class MidiChannel {

/**
* Current playing notes
* @type {Voice[]}
* @type {VoiceGroup[]}
*/
this.playingNotes = [];
/**
* Notes that are stopping and are about to get deleted
* @type {Voice[]}
* @type {VoiceGroup[]}
*/
this.stoppingNotes = [];

Expand Down Expand Up @@ -250,7 +250,7 @@ export class MidiChannel {

this.notes.add(midiNote);
this.receivedNotes.add(midiNote);
let note = new Voice(midiNote, velocity, this.panner, this.preset, this.vibrato, this.channelTuningRatio, this.modulation);
let note = new VoiceGroup(midiNote, velocity, this.panner, this.preset, this.vibrato, this.channelTuningRatio, this.modulation);

let exclusives = note.startNote(debugInfo);
const bendRatio = (this.pitchBend / 8192) * this.channelPitchBendRange;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GeneratorTranslator } from './generator_translator.js';

export class SynthesisModel
export class Voice
{
/**
* Creates a new instance of a single sample
Expand Down Expand Up @@ -240,7 +240,7 @@ export class SynthesisModel
if(!this.wavetableOscillator.loop)
{
// if not looping, return the sample length
return this.synthesisOptions.sample.sampleLengthSeconds;
return Math.min(this.synthesisOptions.sample.sampleLengthSeconds, this.volEnv.releaseTime);
}
return this.volEnv.releaseTime;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {Preset} from "../../soundfont/chunk/presets.js";
import { SynthesisModel } from './synthesis_model.js';
import { Voice } from './voice.js';

export class Voice
export class VoiceGroup
{
/**
* Create a note
* Create a note (a group of voices)
* @param midiNote {number}
* @param targetVelocity {number}
* @param node {AudioNode}
Expand Down Expand Up @@ -43,10 +43,10 @@ export class Voice
this.exclusives = new Set();

/**
* @type {SynthesisModel[]}
* @type {Voice[]}
*/
this.sampleNodes = samples.map(samAndGen => {
const sm = new SynthesisModel(
const sm = new Voice(
samAndGen,
midiNote,
node,
Expand Down
21 changes: 9 additions & 12 deletions src/spessasynth_lib/synthetizer/synthetizer.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {MidiChannel} from "./buffer_voice/midi_channel.js";
import {MidiChannel} from "./native_system/midi_channel.js";
import {SoundFont2} from "../soundfont/soundfont_parser.js";
import {ShiftableByteArray} from "../utils/shiftable_array.js";
import { arrayToHexString, consoleColors } from '../utils/other.js';
import { midiControllers } from '../midi_parser/midi_message.js'
import { WorkletChannel } from './worklet_channel/worklet_channel.js'
import { WorkletChannel } from './worklet_system/worklet_channel.js'
import { EventHandler } from '../utils/event_handler.js'

// i mean come on
Expand Down Expand Up @@ -105,11 +105,14 @@ export class Synthetizer {
}

/*
* Prevents any further changes to the vibrato via NRPN messages
* Prevents any further changes to the vibrato via NRPN messages and resets it to none
*/
lockChannelVibrato()
lockAndResetChannelVibrato()
{
this.midiChannels.forEach(c => c.lockVibrato = true);
this.midiChannels.forEach(c => {
c.lockVibrato = true;
c.vibrato = {depth: 0, rate: 0, delay: 0};
});
}

/**
Expand Down Expand Up @@ -142,15 +145,9 @@ export class Synthetizer {
stopAll(force=false) {
console.log("%cStop all received!", consoleColors.info);
for (let channel of this.midiChannels) {
for(const note of channel.notes)
{
this.eventHandler.callEvent("noteoff", {
midiNote: note,
channel: channel.channelNumber - 1
});
}
channel.stopAll(force);
}
this.eventHandler.callEvent("stopall", {});
}

/**
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit b6d00dc

Please sign in to comment.