Skip to content

Commit

Permalink
More controls
Browse files Browse the repository at this point in the history
- fixed release time
- added System Reset button
- added Recording button (to create music if you want to)
  • Loading branch information
spessasus committed Sep 22, 2023
1 parent 80b04c9 commit 0cc8a50
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export class GeneratorTranslator {

// releaseVolEnv (timecents) defaults to 5s
this.releaseTime = this.sumGeneratorValue(generatorTypes.releaseVolEnv,
-7200,
-12000,
-7200, // shorter to prevent clicks
8000);

Expand Down Expand Up @@ -176,7 +176,6 @@ export class GeneratorTranslator {
const val = gen.generatorValue + preset;
return this.limitValue(val, minAllowed, maxAllowed)
}

return this.limitValue(preset + defaultValue, minAllowed, maxAllowed);
}

Expand Down
70 changes: 43 additions & 27 deletions src/spessasynth_lib/synthetizer/synthetizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ export class Synthetizer {

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

Expand All @@ -117,7 +117,7 @@ export class Synthetizer {
return;
}
if(this.onNoteOff) {
this.onNoteOff(midiNote);
this.callEvent(this.onNoteOff, [midiNote, channel]);
}
if(this.highPerformanceMode)
{
Expand All @@ -127,21 +127,33 @@ 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;
onNoteOn = [];

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

/**
* Stops all notes
Expand All @@ -154,7 +166,7 @@ export class Synthetizer {
{
for(const note of channel.notes)
{
this.onNoteOff(note);
this.callEvent(this.onNoteOff, [note, channel.channelNumber - 1]);
}
}
channel.stopAll(force);
Expand Down Expand Up @@ -216,7 +228,7 @@ export class Synthetizer {
}
if(this.onControllerChange)
{
this.onControllerChange(channel, controllerNumber, controllerValue);
this.callEvent(this.onControllerChange, [channel, controllerNumber, controllerValue]);
}
}

Expand All @@ -236,21 +248,22 @@ export class Synthetizer {

// call all the event listeners
const chNr = ch.channelNumber - 1;
if(this.onProgramChange)
if(this.onProgramChange.length)
{
this.onProgramChange(chNr, chNr === DEFAULT_PERCUSSION ? this.percussionPreset : this.defaultPreset);
this.callEvent(this.onProgramChange, [chNr, chNr === DEFAULT_PERCUSSION ? this.percussionPreset : this.defaultPreset]);
}
if(this.onControllerChange)
if(this.onControllerChange.length)
{
this.onControllerChange(chNr, midiControllers.mainVolume, 100);
this.onControllerChange(chNr, midiControllers.pan, 64);
this.onControllerChange(chNr, midiControllers.expressionController, 127);
this.onControllerChange(chNr, midiControllers.modulationWheel, 0);
this.onControllerChange(chNr, midiControllers.effects3Depth, 0);
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]);

}
if(this.onPitchWheel)
if(this.onPitchWheel.length)
{
this.onPitchWheel(ch.channelNumber - 1, 64, 0);
this.callEvent(this.onPitchWheel, [chNr, 64, 0]);
}
}

Expand All @@ -270,9 +283,9 @@ export class Synthetizer {
pitchWheel(channel, MSB, LSB)
{
this.midiChannels[channel].setPitchBend(MSB, LSB);
if(this.onPitchWheel)
if(this.onPitchWheel.length)
{
this.onPitchWheel(channel, MSB, LSB);
this.callEvent(this.onPitchWheel, [channel, MSB, LSB]);
}
}

Expand All @@ -296,21 +309,24 @@ export class Synthetizer {

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

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

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

/**
* Changes the patch for a given channel
Expand All @@ -329,7 +345,7 @@ export class Synthetizer {
// console.log("changing channel", channel, "to bank:", channelObj.bank,
// "preset:", programNumber, preset.presetName);
if(this.onProgramChange) {
this.onProgramChange(channel, preset);
this.callEvent(this.onProgramChange, [channel, preset]);
}
}

Expand Down Expand Up @@ -508,6 +524,6 @@ export class Synthetizer {

get voicesAmount()
{
return this.midiChannels.reduce((amt, chan) => amt += chan.voicesAmount, 0);
return this.midiChannels.reduce((amt, chan) => amt + chan.voicesAmount, 0);
}
}
7 changes: 2 additions & 5 deletions src/website/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class Manager {
*/
constructor(context, soundFont) {
this.context = context;
this.initializeContext(context, soundFont);
this.initializeContext(context, soundFont).then();

}

Expand Down Expand Up @@ -77,13 +77,10 @@ export class Manager {
this.renderer = new Renderer(this.channelColors, this.synth, canvas);
this.renderer.render(true);

// connect the synth to keyboard
this.synth.onNoteOn = (note, chan, vel, vol, exp) => this.keyboard.pressNote(note, chan, vel, vol, exp);
this.synth.onNoteOff = note => this.keyboard.releaseNote(note);

// set up synth UI
this.synthUI = new SynthetizerUI(this.channelColors);
this.synthUI.connectSynth(this.synth);
this.synthUI.connectKeyboard(this.keyboard);

// create an UI for sequencer
this.seqUI = new SequencerUI();
Expand Down
14 changes: 14 additions & 0 deletions src/website/sequence_recorder/sequence_event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export class SequenceEvent
{
/**
* @param time {number}
* @param eventType {number}
* @param eventData {ShiftableByteArray}
*/
constructor(time, eventType, eventData)
{
this.absoluteTime = time;
this.eventStatusByte = eventType;
this.eventData = eventData;
}
}
46 changes: 46 additions & 0 deletions src/website/sequence_recorder/sequence_player.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { MIDIDeviceHandler } from '../../spessasynth_lib/midi_handler/midi_handler.js'

export class SequencePlayer
{
/**
* @param synth {Synthetizer}
* @param recorder {SequenceRecorder}
*/
constructor(synth, recorder) {
this.synth = synth;
this.recorder = recorder;
this.startTime = 0;
this.eventIndex = 0;
}

play() {
if(this.recorder.events.length < 1)
{
return
}
this.startTime = this.synth.currentTime;
this.timeout = setInterval(this.processTick.bind(this));
}

processTick()
{
let event = this.recorder.events[this.eventIndex];

while(event.absoluteTime < this.currentTime)
{
MIDIDeviceHandler.decodeMidiMessage([event.eventStatusByte, ...event.eventData], this.synth);
this.eventIndex++;
if(this.eventIndex >= this.recorder.events.length)
{
this.eventIndex = 0;
this.startTime = this.synth.currentTime;
}
event = this.recorder.events[this.eventIndex];
}
}

get currentTime()
{
return this.synth.currentTime - this.startTime;
}
}
Loading

0 comments on commit 0cc8a50

Please sign in to comment.