Skip to content

Commit

Permalink
Glow and new event system
Browse files Browse the repository at this point in the history
  • Loading branch information
spessasus committed Sep 26, 2023
1 parent dba57f4 commit c133572
Show file tree
Hide file tree
Showing 15 changed files with 399 additions and 170 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ <h1 id="title">SpessaSynth: Online Demo</h1>
}
else
{
title = midiFiles[i].name;
title = midiFiles[i].name.replace(".mid", "");
}
titles.push(title);
}
Expand Down
11 changes: 10 additions & 1 deletion src/spessasynth_lib/synthetizer/buffer_voice/voice.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
/**
* @typedef {{}}
*/

import {Preset} from "../../soundfont/chunk/presets.js";
import { SynthesisModel } from './synthesis_model.js'
import { SynthesisModel } from './synthesis_model.js';

export class Voice
{
Expand Down Expand Up @@ -64,6 +68,11 @@ export class Voice
});
}

/**
* @type {[]}
*/
static cachedVoices = [];


/**
* @param debug {boolean}
Expand Down
167 changes: 72 additions & 95 deletions src/spessasynth_lib/synthetizer/synthetizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ 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 { EventHandler } from '../utils/event_handler.js'

// i mean come on
const VOICES_CAP = 2137;
const VOICES_CAP = 800;

export const DEFAULT_GAIN = 0.5;
export const DEFAULT_PERCUSSION = 9;
Expand All @@ -23,6 +24,8 @@ export class Synthetizer {
this.soundFont = soundFont;
this.context = targetNode.context;

this.eventHandler = new EventHandler();

this.volumeController = new GainNode(targetNode.context, {
gain: DEFAULT_GAIN
});
Expand Down Expand Up @@ -92,9 +95,13 @@ export class Synthetizer {

let chan = this.midiChannels[channel];
chan.playNote(midiNote, velocity, enableDebugging);
if(this.onNoteOn.length) {
this.callEvent(this.onNoteOn, [midiNote, channel, velocity, chan.channelVolume, chan.channelExpression]);
}
this.eventHandler.callEvent("noteon", {
midiNote: midiNote,
channel: channel,
velocity: velocity,
channelVolume: chan.channelVolume,
channelExpression: chan.channelExpression,
});
}

/*
Expand All @@ -116,9 +123,10 @@ export class Synthetizer {
console.warn(`Received a noteOn for note`, midiNote, "Ignoring.");
return;
}
if(this.onNoteOff) {
this.callEvent(this.onNoteOff, [midiNote, channel]);
}
this.eventHandler.callEvent("noteoff", {
midiNote: midiNote,
channel: channel
});
if(this.highPerformanceMode)
{
this.midiChannels[channel].stopNote(midiNote, true);
Expand All @@ -127,47 +135,19 @@ export class Synthetizer {
this.midiChannels[channel].stopNote(midiNote);
}

/**
* @param event {function[]}
* @param args {number[]}
*/
callEvent(event, args)
{
event.forEach(f => f(...args))
}

/**
* Plays when the midi note goes on
* @type {function[]}
* @param midiNote {number} 0-127
* @param channel {number} 0-15
* @param velocity {number} 0-127
* @param volume {number} 0-1
* @param expression {number} 0-1
*/
onNoteOn = [];

/**
* Plays when the midi note goes off
* @type {function[]}
* @param midiNote {number} 0-127
* @param channel {number} 0-15
*/
onNoteOff = [];

/**
* Stops all notes
* @param force {boolean} if we should instantly kill the note, defaults to false
*/
stopAll(force=false) {
console.log("%cStop all received!", consoleColors.info);
for (let channel of this.midiChannels) {
if(this.onNoteOff)
for(const note of channel.notes)
{
for(const note of channel.notes)
{
this.callEvent(this.onNoteOff, [note, channel.channelNumber - 1]);
}
this.eventHandler.callEvent("noteoff", {
midiNote: note,
channel: channel.channelNumber - 1
});
}
channel.stopAll(force);
}
Expand Down Expand Up @@ -216,8 +196,16 @@ export class Synthetizer {
if(this.midiChannels[channel].bank === 127)
{
this.midiChannels[channel].percussionChannel = true;
this.eventHandler.callEvent("drumchange",{
channel: channel,
isDrumChannel: true
});
}
this.midiChannels[channel].bank = controllerValue;
this.eventHandler.callEvent("drumchange",{
channel: channel,
isDrumChannel: false
});
}
break;

Expand All @@ -226,10 +214,11 @@ export class Synthetizer {
this.midiChannels[channel].controllerChange(controllerNumber, controllerValue);
break;
}
if(this.onControllerChange)
{
this.callEvent(this.onControllerChange, [channel, controllerNumber, controllerValue]);
}
this.eventHandler.callEvent("controllerchange", {
channel: channel,
controllerNumber: controllerNumber,
controllerValue: controllerValue
});
}

/**
Expand All @@ -242,33 +231,37 @@ export class Synthetizer {
{
// reset
ch.resetControllers();
ch.percussionChannel = false;
ch.bank = 0;
ch.setPreset(this.defaultPreset);
if(ch.channelNumber - 1 === DEFAULT_PERCUSSION) {
ch.setPreset(this.percussionPreset);
ch.percussionChannel = true;
this.eventHandler.callEvent("drumchange",{
channel: ch.channelNumber - 1,
isDrumChannel: true
});
}
else
{
ch.percussionChannel = false;
ch.setPreset(this.defaultPreset);
this.eventHandler.callEvent("drumchange",{
channel: ch.channelNumber - 1,
isDrumChannel: false
});
}

// call all the event listeners
const chNr = ch.channelNumber - 1;
if(this.onProgramChange.length)
{
this.callEvent(this.onProgramChange, [chNr, chNr === DEFAULT_PERCUSSION ? this.percussionPreset : this.defaultPreset]);
}
if(this.onControllerChange.length)
{
this.callEvent(this.onControllerChange, [chNr, midiControllers.mainVolume, 100]);
this.callEvent(this.onControllerChange, [chNr, midiControllers.pan, 64]);
this.callEvent(this.onControllerChange, [chNr, midiControllers.expressionController, 127]);
this.callEvent(this.onControllerChange, [chNr, midiControllers.modulationWheel, 0]);
this.callEvent(this.onControllerChange, [chNr, midiControllers.effects3Depth, 0]);
this.eventHandler.callEvent("programchange", {channel: chNr, preset: ch.preset})

}
if(this.onPitchWheel.length)
{
this.callEvent(this.onPitchWheel, [chNr, 64, 0]);
}
}
this.eventHandler.callEvent("controllerchange", {channel: chNr, controllerNumber: midiControllers.mainVolume, controllerValue: 100});
this.eventHandler.callEvent("controllerchange", {channel: chNr, controllerNumber: midiControllers.pan, controllerValue: 64});
this.eventHandler.callEvent("controllerchange", {channel: chNr, controllerNumber: midiControllers.expressionController, controllerValue: 127});
this.eventHandler.callEvent("controllerchange", {channel: chNr, controllerNumber: midiControllers.modulationWheel, controllerValue: 0});
this.eventHandler.callEvent("controllerchange", {channel: chNr, controllerNumber: midiControllers.effects3Depth, controllerValue: 0});

this.midiChannels[DEFAULT_PERCUSSION].percussionChannel = true;
this.midiChannels[DEFAULT_PERCUSSION].setPreset(this.percussionPreset);
this.eventHandler.callEvent("pitchwheel", {channel: chNr, MSB: 64, LSB: 0})
}
this.system = "gm2";
this.volumeController.gain.value = DEFAULT_GAIN;
this.panController.pan.value = 0;
Expand All @@ -283,10 +276,11 @@ export class Synthetizer {
pitchWheel(channel, MSB, LSB)
{
this.midiChannels[channel].setPitchBend(MSB, LSB);
if(this.onPitchWheel.length)
{
this.callEvent(this.onPitchWheel, [channel, MSB, LSB]);
}
this.eventHandler.callEvent("pitchwheel", {
channel: channel,
MSB: MSB,
LSB: LSB
});
}

/**
Expand All @@ -307,27 +301,6 @@ export class Synthetizer {
this.volumeController.gain.value = volume * DEFAULT_GAIN;
}

/**
* Calls on program change(channel number, preset)
* @type {function(number, Preset)[]}
*/
onProgramChange = [];

/**
* Calls on controller change(channel number, cc, controller value)
* @param channel {number} 0-16
* @param controllerNumber {number} 0-127
* @param controllerValue {number} 0-127
* @type {function[]}
*/
onControllerChange = [];

/**
* Calls on pitch wheel change (channel, msb, lsb)
* @type {function(number, number, number)[]}
*/
onPitchWheel = [];

/**
* Changes the patch for a given channel
* @param channel {number} 0-15 the channel to change
Expand All @@ -342,11 +315,10 @@ export class Synthetizer {
// find the preset
let preset = this.soundFont.getPreset(bank, programNumber);
channelObj.setPreset(preset);
// console.log("changing channel", channel, "to bank:", channelObj.bank,
// "preset:", programNumber, preset.presetName);
if(this.onProgramChange) {
this.callEvent(this.onProgramChange, [channel, preset]);
}
this.eventHandler.callEvent("programchange", {
channel: channel,
preset: preset
});
}

/**
Expand Down Expand Up @@ -452,6 +424,11 @@ export class Synthetizer {
consoleColors.recognized,
consoleColors.info,
consoleColors.value);

this.eventHandler.callEvent("drumchange",{
channel: channel,
isDrumChannel: this.midiChannels[channel].percussionChannel
});
}
else
if(messageData[4] === 0x40 && messageData[6] === 0x06 && messageData[5] === 0x00)
Expand Down
62 changes: 62 additions & 0 deletions src/spessasynth_lib/utils/event_handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @typedef {
* "noteon"|
* "noteoff"|
* "pitchwheel"|
* "controllerchange"|
* "programchange"|
* "drumchange"} EventTypes
*/
export class EventHandler
{
/**
* A new synthesizer event handler
*/
constructor() {
/**
* The main list of events
* @type {Object<EventTypes, function(Object)[]>}
*/
this.events = {};
}

/**
* Adds a new event listener
* @param name {EventTypes}
* @param callback {function(Object)}
*/
addEvent(name, callback)
{
if(this.events[name])
{
this.events[name].push(callback);
}
else
{
this.events[name] = [callback];
}
}

/**
* Removes an event listener
* @param name {EventTypes}
* @param callback {function(Object)}
*/
removeEvent(name, callback)
{
this.events[name].splice(this.events[name].findIndex(c => c === callback), 1);
}

/**
* Calls the given event
* @param name {EventTypes}
* @param eventData {Object}
*/
callEvent(name, eventData)
{
if(this.events[name])
{
this.events[name].forEach(ev => ev(eventData));
}
}
}
4 changes: 4 additions & 0 deletions src/website/css/keyboard.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
--flat-half-translate: 18%;
}

#keyboard .flat_dark_key{
background: linear-gradient(262deg, #111, #000);
}

#keyboard .sharp_key{
--sharp-transform: scale(1, 0.7);
transform: var(--sharp-transform);
Expand Down
Loading

0 comments on commit c133572

Please sign in to comment.