Skip to content

Commit

Permalink
Added mute functionality
Browse files Browse the repository at this point in the history
and some small imrovements
  • Loading branch information
spessasus committed Sep 20, 2023
1 parent eb41c7f commit d99ccee
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 73 deletions.
42 changes: 30 additions & 12 deletions src/spessasynth_lib/synthetizer/buffer_voice/midi_channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class MidiChannel {
this.outputNode = targetNode;
this.channelNumber = channelNumber
this.percussionChannel = percussionChannel;
this.defaultGain = CHANNEL_LOUDNESS;

this.preset = defaultPreset;
this.bank = this.preset.bank;
Expand Down Expand Up @@ -101,6 +102,7 @@ export class MidiChannel {
* @type {boolean}
*/
this.lockPreset = false;
this.lockVibrato = false;
}

/**
Expand Down Expand Up @@ -233,7 +235,7 @@ export class MidiChannel {
{
val = Math.min(1, val);
this.channelExpression = val;
this.gainController.gain.value = this.getGain();
this.updateGain();
}

/**
Expand All @@ -242,16 +244,17 @@ export class MidiChannel {
* @param debugInfo {boolean} for debugging set to true
*/
playNote(midiNote, velocity, debugInfo = false) {
if(!velocity)
{
throw "No velocity given!";
}
if (velocity === 0) {
// stop if velocity 0
this.stopNote(midiNote);
return;
}

if(this.defaultGain === 0)
{
return;
}

this.notes.add(midiNote);
this.receivedNotes.add(midiNote);
let note = new Voice(midiNote, velocity, this.panner, this.preset, this.vibrato, this.channelTuningRatio, this.modulation);
Expand Down Expand Up @@ -330,7 +333,7 @@ export class MidiChannel {
setVolume(volume) {
volume = Math.min(127, volume);
this.channelVolume = volume / 127;
this.gainController.gain.value = this.getGain();
this.updateGain();
}

setRPCoarse(value)
Expand Down Expand Up @@ -387,6 +390,10 @@ export class MidiChannel {
break;

case 1:
if(this.lockVibrato)
{
return;
}
switch(this.NRPFine)
{
default:
Expand Down Expand Up @@ -472,12 +479,20 @@ export class MidiChannel {

}
}
updateGain(){
this.gainController.gain.value = this.defaultGain * this.channelVolume * this.channelExpression;
}

/**
* @returns {number}
*/
getGain(){
return CHANNEL_LOUDNESS * this.channelVolume * this.channelExpression;
muteChannel()
{
this.defaultGain = 0;
this.updateGain();
}

unmuteChannel()
{
this.defaultGain = CHANNEL_LOUDNESS;
this.updateGain();
}

/**
Expand Down Expand Up @@ -533,6 +548,9 @@ export class MidiChannel {
{
this.stopNote(midiNote);
}
this.playingNotes.forEach(n => {
this.stopNote(n.midiNote);
});
if(force)
{
this.stoppingNotes.forEach(n => {
Expand All @@ -549,7 +567,7 @@ export class MidiChannel {
this.channelTuningRatio = 1;
this.channelPitchBendRange = 2;
this.holdPedal = false;
this.gainController.gain.value = this.getGain();
this.updateGain();
this.chorusController.gain.value = 0;
this.panner.pan.value = 0;
this.pitchBend = 0;
Expand Down
57 changes: 35 additions & 22 deletions src/spessasynth_lib/synthetizer/synthetizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const DEFAULT_PERCUSSION = 9;

export class Synthetizer {
/**
* Creates a new instance of the SpessaSynth synthesizer
* @param targetNode {AudioNode}
* @param soundFont {SoundFont2}
*/
Expand Down Expand Up @@ -68,10 +69,10 @@ export class Synthetizer {
}

/**
* MIDI noteOn Event
* @param channel {number} 0-15
* @param midiNote {number} 0-127
* @param velocity {number} 0-127
* Starts playing a note
* @param channel {number} 0-15 the channel to play the note
* @param midiNote {number} 0-127 the key number of the note
* @param velocity {number} 0-127 the velocity of the note (generally controls loudness)
* @param enableDebugging {boolean} set to true to log stuff to console
*/
noteOn(channel, midiNote, velocity, enableDebugging = false) {
Expand Down Expand Up @@ -103,10 +104,18 @@ export class Synthetizer {
}
}

/*
* Prevents any further changes to the vibrato via NRPN messages
*/
lockChannelVibrato()
{
this.midiChannels.forEach(c => c.lockVibrato = true);
}

/**
* MIDI noteOff event
* @param channel {number} 0-15
* @param midiNote {number} 0-127
* Stops playing a note
* @param channel {number} 0-15 the channel of the note
* @param midiNote {number} 0-127 the key number of the note
*/
noteOff(channel, midiNote) {
if(midiNote > 127 || midiNote < 0)
Expand Down Expand Up @@ -161,9 +170,9 @@ export class Synthetizer {

/**
* Changes the given controller
* @param channel {number} 0-15
* @param controllerNumber {number} 0-127
* @param controllerValue {number} 0-127
* @param channel {number} 0-15 the channel to change the controller
* @param controllerNumber {number} 0-127 the MIDI CC number
* @param controllerValue {number} 0-127 the controller value
*/
controllerChange(channel, controllerNumber, controllerValue)
{
Expand Down Expand Up @@ -219,7 +228,7 @@ export class Synthetizer {
}

/**
* Resets all controllers
* Resets all controllers (for every channel)
*/
resetControllers()
{
Expand Down Expand Up @@ -260,10 +269,10 @@ export class Synthetizer {
}

/**
* Sets the pitch
* @param channel {number} 0-16
* @param MSB {number} SECOND byte
* @param LSB {number} FIRST byte
* Sets the pitch of the given channel
* @param channel {number} 0-16 the channel to change pitch
* @param MSB {number} SECOND byte of the MIDI pitchWheel message
* @param LSB {number} FIRST byte of the MIDI pitchWheel message
*/
pitchWheel(channel, MSB, LSB)
{
Expand All @@ -276,7 +285,7 @@ export class Synthetizer {

/**
* Transposes the synthetizer's pitch by given semitones amount (percussion channels do not get affected)
* @param semitones {number}
* @param semitones {number} the semitones to transpose by. Can be a floating point number for more precision
*/
transpose(semitones)
{
Expand All @@ -285,7 +294,7 @@ export class Synthetizer {

/**
* Sets the main volume
* @param volume {number} 0-1
* @param volume {number} 0-1 the volume
*/
setMainVolume(volume)
{
Expand All @@ -311,8 +320,9 @@ export class Synthetizer {
onPitchWheel;

/**
* @param channel {number} 0-15
* @param programNumber {number} 0-127
* Changes the patch for a given channel
* @param channel {number} 0-15 the channel to change
* @param programNumber {number} 0-127 the MIDI patch number
*/
programChange(channel, programNumber)
{
Expand All @@ -330,6 +340,9 @@ export class Synthetizer {
}
}

/**
* Call after replacing synth.soundFont
*/
reloadSoundFont()
{
this.defaultPreset = this.soundFont.getPreset(0, 0);
Expand All @@ -346,8 +359,8 @@ export class Synthetizer {
}

/**
* Sends a sysex
* @param messageData {ShiftableByteArray} the message's data (after F0)
* Sends a MIDI Sysex message
* @param messageData {ShiftableByteArray} the message's data (excluding the F0 byte, but including the F7 at the end)
*/
systemExclusive(messageData)
{
Expand Down Expand Up @@ -493,7 +506,7 @@ export class Synthetizer {
}

/**
* @returns {number}
* @returns {number} the audioContext's current time
*/
get currentTime()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,42 +211,42 @@ class ChannelProcessor extends AudioWorkletProcessor {


// LOWPASS
const filterQ = getModulated(voice, generatorTypes.initialFilterQ, this.midiControllers) - 3.01; // polyphone????
const filterQgain = Math.pow(10, filterQ / 20);
const filterFcHz = absCentsToHz(getModulated(voice, generatorTypes.initialFilterFc, this.midiControllers));
// calculate coefficients
const theta = 2 * Math.PI * filterFcHz / sampleRate;
let a0, a1, a2, b1, b2;
if (filterQgain <= 0)
{
a0 = 1;
a1 = 0;
a2 = 0;
b1 = 0;
b2 = 0;
}
else
{
const dTmp = Math.sin(theta) / (2 * filterQgain);
if (dTmp <= -1.0)
{
a0 = 1;
a1 = 0;
a2 = 0;
b1 = 0;
b2 = 0;
}
else
{
const beta = 0.5 * (1 - dTmp) / (1 + dTmp);
const gamma = (0.5 + beta) * Math.cos(theta);
a0 = (0.5 + beta - gamma) / 2;
a1 = 2 * a0;
a2 = a0;
b1 = -2 * gamma;
b2 = 2 * beta;
}
}
// const filterQ = getModulated(voice, generatorTypes.initialFilterQ, this.midiControllers) - 3.01; // polyphone????
// const filterQgain = Math.pow(10, filterQ / 20);
// const filterFcHz = absCentsToHz(getModulated(voice, generatorTypes.initialFilterFc, this.midiControllers));
// // calculate coefficients
// const theta = 2 * Math.PI * filterFcHz / sampleRate;
// let a0, a1, a2, b1, b2;
// if (filterQgain <= 0)
// {
// a0 = 1;
// a1 = 0;
// a2 = 0;
// b1 = 0;
// b2 = 0;
// }
// else
// {
// const dTmp = Math.sin(theta) / (2 * filterQgain);
// if (dTmp <= -1.0)
// {
// a0 = 1;
// a1 = 0;
// a2 = 0;
// b1 = 0;
// b2 = 0;
// }
// else
// {
// const beta = 0.5 * (1 - dTmp) / (1 + dTmp);
// const gamma = (0.5 + beta) * Math.cos(theta);
// a0 = (0.5 + beta - gamma) / 2;
// a1 = 2 * a0;
// a2 = a0;
// b1 = -2 * gamma;
// b2 = 2 * beta;
// }
// }

// SYNTHESIS
let actualTime = currentTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import { consoleColors } from '../../utils/other.js'
import { modulatorSources } from '../../soundfont/chunk/modulators.js'
import { midiControllers } from '../../midi_parser/midi_message.js'
import { addAndClampGenerator, generatorTypes } from '../../soundfont/chunk/generators.js'

const CHANNEL_GAIN = 0.5;

export const NON_CC_INDEX_OFFSET = 128;
Expand Down Expand Up @@ -160,6 +159,7 @@ export class WorkletChannel {
* @type {boolean}
*/
this.lockPreset = false;
this.lockVibrato = false;
}

/**
Expand All @@ -170,6 +170,16 @@ export class WorkletChannel {
this.worklet.port.postMessage(data);
}

muteChannel()
{
this.gainController.gain.value = 0;
}

unmuteChannel()
{
this.gainController.gain.value = CHANNEL_GAIN;
}

/**
* @param cc {number}
* @param val {number}
Expand Down Expand Up @@ -493,6 +503,10 @@ export class WorkletChannel {

// vibrato rate
case 8:
if(this.lockVibrato)
{
return;
}
if(dataValue === 64)
{
return;
Expand Down
14 changes: 14 additions & 0 deletions src/website/css/synthesizer_ui.css
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,20 @@
display: block;
}

.mute_button
{
flex: 0;
display: flex;
justify-content: center;
align-items: center;
border: #777 1px solid;
min-width: var(--voice-meter-height);
}

.mute_button:hover{
cursor: pointer;
}

.voice_reset{
flex: 0;
min-width: 0;
Expand Down
Loading

0 comments on commit d99ccee

Please sign in to comment.