Skip to content

Commit

Permalink
add stabilizing waveforms
Browse files Browse the repository at this point in the history
off by default
bugfixes
settings rework
  • Loading branch information
spessasus committed Jun 23, 2024
1 parent 69e7fa3 commit a0a88a3
Show file tree
Hide file tree
Showing 21 changed files with 619 additions and 538 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "SpessaSynth",
"version": "3.1.0",
"version": "3.2.1",
"dependencies": {
"@types/webaudioapi": "^0.0.27",
"express": "^4.18.2",
Expand Down
5 changes: 3 additions & 2 deletions src/spessasynth_lib/synthetizer/synthetizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,15 +356,16 @@ export class Synthetizer {
* @param channel {number} usually 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
* @param force {boolean} forces the controller change, even if it's locked or gm system is set and the cc is bank select
*/
controllerChange(channel, controllerNumber, controllerValue)
controllerChange(channel, controllerNumber, controllerValue, force=false)
{
controllerValue = Math.floor(controllerValue);
controllerNumber = Math.floor(controllerNumber);
this.post({
channelNumber: channel,
messageType: workletMessageType.ccChange,
messageData: [controllerNumber, controllerValue]
messageData: [controllerNumber, controllerValue, force]
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import { SYNTHESIZER_GAIN } from '../worklet_utilities/main_processor.js'
* @param channel {number}
* @param controllerNumber {number}
* @param controllerValue {number}
* @param force {boolean}
* @this {SpessaSynthProcessor}
*/
export function controllerChange(channel, controllerNumber, controllerValue)
export function controllerChange(channel, controllerNumber, controllerValue, force = false)
{
/**
* @type {WorkletProcessorChannel}
Expand All @@ -34,45 +35,43 @@ export function controllerChange(channel, controllerNumber, controllerValue)

case midiControllers.bankSelect:
let bankNr = controllerValue;
switch (this.system)
if(!force)
{
case "gm":
// gm ignores bank select
SpessaSynthInfo(`%cIgnoring the Bank Select (${controllerValue}), as the synth is in GM mode.`, consoleColors.info);
return;

case "xg":
// for xg, if msb is 127, then it's drums
if (bankNr === 127)
{
channelObject.drumChannel = true;
this.callEvent("drumchange", {
channel: channel,
isDrumChannel: true
});
}
break;

case "gm2":
if(bankNr === 120)
{
channelObject.drumChannel = true;
this.callEvent("drumchange", {
channel: channel,
isDrumChannel: true
});
}
}
switch (this.system) {
case "gm":
// gm ignores bank select
SpessaSynthInfo(`%cIgnoring the Bank Select (${controllerValue}), as the synth is in GM mode.`, consoleColors.info);
return;

case "xg":
// for xg, if msb is 127, then it's drums
if (bankNr === 127) {
channelObject.drumChannel = true;
this.callEvent("drumchange", {
channel: channel,
isDrumChannel: true
});
}
break;

case "gm2":
if (bankNr === 120) {
channelObject.drumChannel = true;
this.callEvent("drumchange", {
channel: channel,
isDrumChannel: true
});
}
}

if(channelObject.drumChannel)
{
// 128 for percussion channel
bankNr = 128;
}
if(bankNr === 128 && !channelObject.drumChannel)
{
// if channel is not for percussion, default to bank current
bankNr = channelObject.midiControllers[midiControllers.bankSelect];
if (channelObject.drumChannel) {
// 128 for percussion channel
bankNr = 128;
}
if (bankNr === 128 && !channelObject.drumChannel) {
// if channel is not for percussion, default to bank current
bankNr = channelObject.midiControllers[midiControllers.bankSelect];
}
}

channelObject.midiControllers[midiControllers.bankSelect] = bankNr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function handleMessage(message)
break;

case workletMessageType.ccChange:
this.controllerChange(channel, data[0], data[1]);
this.controllerChange(channel, data[0], data[1], data[2]);
break;

case workletMessageType.customcCcChange:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @enum {number}
* @property {number} noteOff - 0 -> midiNote<number>: Every message needs a channel number (if not relevant or all, set to -1)
* @property {number} noteOn - 1 -> [midiNote<number>, velocity<number>, enableDebugging<boolean>]
* @property {number} ccChange - 2 -> [ccNumber<number>, ccValue<number>]
* @property {number} ccChange - 2 -> [ccNumber<number>, ccValue<number>, force<boolean>]
* @property {number} programChange - 3 -> [programNumber<number>, userChange<boolean>]
* @property {number} killNote - 4 -> midiNote<number>
* @property {number} ccReset - 5 -> (no data) note: if channel is -1 then reset all channels
Expand Down
39 changes: 31 additions & 8 deletions src/website/js/renderer/render_waveforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,39 @@ export function renderWaveforms()
this.drawingContext.lineWidth = this.lineThickness;
this.drawingContext.strokeStyle = this.channelColors[channelNumber];
this.drawingContext.beginPath();
if(this.stabilizeWaveforms)
{
const length = waveform.length / 2;
// Oscilloscope triggering
let triggerPoint = 0;
const threshold = 0; // Adjust this if necessary
for (let i = 1; i < waveform.length; i++) {
if (waveform[i - 1] < threshold && waveform[i] >= threshold) {
triggerPoint = i;
break;
}
}
const step = waveWidth / length;

const step = waveWidth / waveform.length;

let xPos = relativeX;
let xPos = relativeX;
for (let i = triggerPoint; i < triggerPoint + length; i++) {
this.drawingContext.lineTo(
xPos,
relativeY + waveform[i] * multiplier);
xPos += step;
}
}
else
{
const step = waveWidth / waveform.length;

for (let i = 0; i < waveform.length; i++) {
this.drawingContext.lineTo(
xPos,
relativeY + waveform[i] * multiplier);
xPos += step;
let xPos = relativeX;
for (let i = 0; i < waveform.length; i++) {
this.drawingContext.lineTo(
xPos,
relativeY + waveform[i] * multiplier);
xPos += step;
}
}

this.drawingContext.stroke();
Expand Down
1 change: 1 addition & 0 deletions src/website/js/renderer/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class Renderer
this.renderNotes = true;
this.drawActiveNotes = true;
this.showVisualPitch = true;
this.stabilizeWaveforms = false;
/**
* @type {boolean[]}
*/
Expand Down
68 changes: 68 additions & 0 deletions src/website/js/settings_ui/handlers/interface_handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @this {Settings}
* @private
*/
export function _toggleDarkMode()
{
if(this.mode === "dark")
{
this.mode = "light";
this.renderer.drawActiveNotes = false;
}
else
{
this.renderer.drawActiveNotes = true;
this.mode = "dark";

}
this.renderer.toggleDarkMode();
this.synthui.toggleDarkMode();
this.sequi.toggleDarkMode()

// top part
document.getElementsByClassName("top_part")[0].classList.toggle("top_part_light");

// settings
this.mainDiv.classList.toggle("settings_menu_light");

// rest
// things get hacky here: change the global (*) --font-color to black:
// find the star rule
const rules = document.styleSheets[0].cssRules;
for(let rule of rules)
{
if(rule.selectorText === "*")
{
rule.style.setProperty("--font-color", this.mode === "dark" ? "#eee" : "#333");
rule.style.setProperty("--top-buttons-color", this.mode === "dark" ? "linear-gradient(201deg, #222, #333)" : "linear-gradient(270deg, #ddd, #fff)");
break;
}
}
document.body.style.background = this.mode === "dark" ? "black" : "white";
}

/**
* @this {Settings}
* @private
*/
export function _createInterfaceSettingsHandler()
{
const button = this.htmlControls.interface.themeSelector;
button.onclick = () => {
this._toggleDarkMode();
this._saveSettings();
}
const select = this.htmlControls.interface.languageSelector;
// load up the languages
for(const [code, locale] of Object.entries(this.locales))
{
const option = document.createElement("option");
option.value = code;
option.textContent = locale.localeName
select.appendChild(option);
}
select.onchange = () => {
this.locale.changeGlobalLocale(this.locales[select.value]);
this._saveSettings();
}
}
55 changes: 55 additions & 0 deletions src/website/js/settings_ui/handlers/keyboard_handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* The channel colors are taken from synthui
* @param keyboard {MidiKeyboard}
* @param synthui {SynthetizerUI}
* @param renderer {Renderer}
* @this {Settings}
* @private
*/
export function _createKeyboardHandler( keyboard, synthui, renderer)
{
let channelNumber = 0;

const keyboardControls = this.htmlControls.keyboard;

const createChannel = () =>
{
const option = document.createElement("option");

option.value = channelNumber.toString();
// Channel: {0} gets formatred to channel number
this.locale.bindObjectProperty(option, "textContent", "locale.settings.keyboardSettings.selectedChannel.channelOption", [channelNumber + 1]);

option.style.background = synthui.channelColors[channelNumber % synthui.channelColors.length];
option.style.color = "rgb(0, 0, 0)";

keyboardControls.channelSelector.appendChild(option);
channelNumber++;
}

// create the initial synth channels+
for (let i = 0; i <synthui.synth.channelsAmount; i++)
{
createChannel();
}
keyboardControls.channelSelector.onchange = () => {
keyboard.selectChannel(parseInt(keyboardControls.channelSelector.value));
}

keyboardControls.sizeSelector.onchange = () => {
keyboard.keyRange = this.keyboardSizes[keyboardControls.sizeSelector.value];
renderer.keyRange = this.keyboardSizes[keyboardControls.sizeSelector.value];
this._saveSettings();
}

// listen for new channels
synthui.synth.eventHandler.addEvent("newchannel", "settings-new-channel", () => {
createChannel();
});

// dark mode toggle
keyboardControls.modeSelector.onclick = () => {
keyboard.toggleMode();
this._saveSettings();
}
}
Loading

0 comments on commit a0a88a3

Please sign in to comment.