Skip to content

Commit

Permalink
The Grand Code Reformat Update
Browse files Browse the repository at this point in the history
I finally figured out how to do it!
  • Loading branch information
spessasus committed Oct 6, 2024
1 parent 7a0278a commit 8035d9d
Show file tree
Hide file tree
Showing 227 changed files with 7,354 additions and 6,025 deletions.
12 changes: 7 additions & 5 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

90 changes: 64 additions & 26 deletions src/spessasynth_lib/README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
# spessasynth_lib

**A powerful soundfont/MIDI JavaScript library for the browsers.**

```shell
npm install --save spessasynth_lib
```

### [Project site (consider giving it a star!)](https://github.com/spessasus/SpessaSynth)

### [Demo](https://spessasus.github.io/SpessaSynth)

### [Complete documentation](https://github.com/spessasus/SpessaSynth/wiki/Usage-As-Library)

#### Basic example: play a single note

```js
import {Synthetizer} from "spessasynth_lib"
import { Synthetizer } from "spessasynth_lib"

const sfont = await (await fetch("soundfont.sf3")).arrayBuffer();
const ctx = new AudioContext();
// make sure you copied the worklet processor!
await ctx.audioWorklet.addModule("./worklet_processor.min.js");
const synth = new Synthetizer(ctx.destination, sfont);
document.getElementById("button").onclick = async () => {
document.getElementById("button").onclick = async () =>
{
await ctx.resume();
synth.programChange(0, 48); // strings ensemble
synth.noteOn(0, 52, 127);
Expand All @@ -28,37 +33,55 @@ document.getElementById("button").onclick = async () => {
## Current Features

### Easy Integration

- **Modular design:** Easy integration into other projects (load what you need)
- **[Detailed documentation:](https://github.com/spessasus/SpessaSynth/wiki/Home)** With [examples!](https://github.com/spessasus/SpessaSynth/wiki/Usage-As-Library#examples)
- **Easy to Use:** basic setup is just [two lines of code!](https://github.com/spessasus/SpessaSynth/wiki/Usage-As-Library#minimal-setup)
- **[Detailed documentation:](https://github.com/spessasus/SpessaSynth/wiki/Home)**
With [examples!](https://github.com/spessasus/SpessaSynth/wiki/Usage-As-Library#examples)
- **Easy to Use:** basic setup is
just [two lines of code!](https://github.com/spessasus/SpessaSynth/wiki/Usage-As-Library#minimal-setup)
- **No dependencies:** _batteries included!_

### Powerful SoundFont Synthesizer

- Suitable for both **real-time** and **offline** synthesis
- **Excellent SoundFont support:**
- **Generator Support**
- **Modulator Support:** *First (to my knowledge) JavaScript SoundFont synth with that feature!*
- **SoundFont3 Support:** Play compressed SoundFonts!
- **Experimental SF2Pack Support:** Play soundfonts compressed with BASSMIDI! (*Note: only works with vorbis compression*)
- **Can load very large SoundFonts:** up to 4GB! *Note: Only Firefox handles this well; Chromium has a hard-coded memory limit*
- **Generator Support**
- **Modulator Support:** *First (to my knowledge) JavaScript SoundFont synth with that feature!*
- **SoundFont3 Support:** Play compressed SoundFonts!
- **Experimental SF2Pack Support:** Play soundfonts compressed with BASSMIDI! (*Note: only works with vorbis
compression*)
- **Can load very large SoundFonts:** up to 4GB! *Note: Only Firefox handles this well; Chromium has a hard-coded
memory limit*
- **Soundfont manager:** Stack multiple soundfonts!
- **DLS Level 1 and 2 Support:** *internally converted to sf2*
- **Reverb and chorus support:** [customizable!](https://github.com/spessasus/SpessaSynth/wiki/Synthetizer-Class#effects-configuration-object)
- **Export audio files** using [OfflineAudioContext](https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext)
- **[Custom modulators for additional controllers](https://github.com/spessasus/SpessaSynth/wiki/Modulator-Class#default-modulators):** Why not?
- **Reverb and chorus support:
** [customizable!](https://github.com/spessasus/SpessaSynth/wiki/Synthetizer-Class#effects-configuration-object)
- **Export audio files**
using [OfflineAudioContext](https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext)
-
*

*[Custom modulators for additional controllers](https://github.com/spessasus/SpessaSynth/wiki/Modulator-Class#default-modulators):
** Why not?

- **Written using AudioWorklets:**
- Runs in a **separate thread** for maximum performance
- Supported by all modern browsers
- Runs in a **separate thread** for maximum performance
- Supported by all modern browsers
- **Unlimited channel count:** Your CPU is the limit!
- **Excellent MIDI Standards Support:**
- **MIDI Controller Support:** Default supported controllers [here](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#supported-controllers)
- **MIDI Tuning Standard Support:** [more info here](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#midi-tuning-standard)
- [Full **RPN** and limited **NRPN** support](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#supported-registered-parameters)
- Supports some [**Roland GS** and **Yamaha XG** system exclusives](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#supported-system-exclusives)
- **MIDI Controller Support:** Default supported
controllers [here](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#supported-controllers)
- **MIDI Tuning Standard Support:
** [more info here](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#midi-tuning-standard)
- [Full **RPN** and limited **NRPN
** support](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#supported-registered-parameters)
- Supports some [**Roland GS** and **Yamaha XG
** system exclusives](https://github.com/spessasus/SpessaSynth/wiki/MIDI-Implementation#supported-system-exclusives)

- **High-performance mode:** Play Rush E! _note: may kill your browser ;)_

### Built-in Powerful and Fast Sequencer

- **Supports MIDI formats 0, 1, and 2:** _note: format 2 support is experimental as it's very, very rare_
- **[Multi-Port MIDI](https://github.com/spessasus/SpessaSynth/wiki/About-Multi-Port) support:** More than 16 channels!
- **Smart preloading:** Only preloads the samples used in the MIDI file for smooth playback (down to key and velocity!)
Expand All @@ -68,54 +91,69 @@ document.getElementById("button").onclick = async () => {
- **Loop points support:** Ensures seamless loops

### Read and Write SoundFont and MIDI Files with Ease

#### Read and write MIDI files

- **Smart name detection:** Handles incorrectly formatted and non-standard track names
- **Raw name available:** Decode in any encoding! *(Kanji? No problem!)*
- **Port detection during load time:** Manage ports and channels easily!
- **Used channels on track:** Quickly determine which channels are used
- **Key range detection:** Detect the key range of the MIDI
- **Easy MIDI editing:** Use [helper functions](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#modifymidi) to modify the song to your needs!
- **Easy MIDI editing:**
Use [helper functions](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#modifymidi) to modify the song
to your needs!
- **Loop detection:** Automatically detects loops in MIDIs (e.g., from _Touhou Project_)
- **First note detection:** Skip unnecessary silence at the start by jumping to the first note!
- **[Write MIDI files from scratch](https://github.com/spessasus/SpessaSynth/wiki/Creating-MIDI-Files)**
- **Easy saving:** Save with just [one function!](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#writemidifile)
- **Easy saving:** Save with
just [one function!](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#writemidifile)

#### Read and write [RMID files with embedded SF2 soundfonts](https://github.com/spessasus/sf2-rmidi-specification#readme)

- **[Level 4](https://github.com/spessasus/sf2-rmidi-specification#level-4) compliance:** Reads and writes *everything!*
- **Compression and trimming support:** Reduce a MIDI file with a 1GB soundfont to **as small as 5MB**!
- **DLS Version support:** The original legacy format with bank offset detection!
- **Automatic bank shifting and validation:** Every soundfont *just works!*
- **Metadata support:** Add title, artist, album name and cover and more! And of course read them too! *(In any encoding!)*
- **Metadata support:** Add title, artist, album name and cover and more! And of course read them too! *(In any
encoding!)*
- **Compatible with [Falcosoft Midi Player 6!](https://falcosoft.hu/softwares.html#midiplayer)**
- **Easy saving:** [As simple as saving a MIDI file!](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#writermidi)
- **Easy saving:
** [As simple as saving a MIDI file!](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#writermidi)

#### Read and write SoundFont2 files
- **Easy info access:** Just an [object of strings!](https://github.com/spessasus/SpessaSynth/wiki/SoundFont2-Class#soundfontinfo)

- **Easy info access:** Just
an [object of strings!](https://github.com/spessasus/SpessaSynth/wiki/SoundFont2-Class#soundfontinfo)
- **Smart trimming:** Trim the SoundFont to only include samples used in the MIDI *(down to key and velocity!)*
- **sf3 conversion:** Compress SoundFont2 files to SoundFont3 with variable quality!
- **Easy saving:** Also just [one function!](https://github.com/spessasus/SpessaSynth/wiki/SoundFont2-Class#write)

#### Read and write SoundFont3 files

- Same features as SoundFont2 but with now with **Ogg Vorbis compression!**
- **Variable compression quality:** You choose between file size and quality!
- **Compression preserving:** Avoid decompressing and recompressing uncompressed samples for minimal quality loss!

#### Read and play DLS Level 1 or 2 files

- Read DLS (DownLoadable Sounds) files as SF2 files!
- **Works like a normal soundfont:** *Saving it as sf2 is still [just one function!](https://github.com/spessasus/SpessaSynth/wiki/SoundFont2-Class#write)*
- **Works like a normal soundfont:** *Saving it as sf2 is
still [just one function!](https://github.com/spessasus/SpessaSynth/wiki/SoundFont2-Class#write)*
- Converts articulators to both **modulators** and **generators**!
- Works with both unsigned 8-bit samples and signed 16-bit samples!
- **Covers special generator cases:** *such as modLfoToPitch*!
- **Correct volume:** *looking at you, Viena and gm.sf2!*
- Support built right into the synthesizer!

### Export MIDI as WAV

- Save the MIDI file as WAV audio!
- **Metadata support:** *Embed metadata such as title, artist, album and more!*
- **Cue points:** *Write MIDI loop points as cue points!*
- **Loop multiple times:** *Render two (or more) loops into the file for seamless transitions!*
- *That's right, saving as WAV is also [just one function!](https://github.com/spessasus/SpessaSynth/wiki/Writing-Wave-Files#audiobuffertowav)*

- *That's right, saving as WAV is
also [just one function!](https://github.com/spessasus/SpessaSynth/wiki/Writing-Wave-Files#audiobuffertowav)*

# License

MIT License, except for the stbvorbis_sync.js in the `externals` folder which is licensed under the Apache-2.0 license.
1 change: 1 addition & 0 deletions src/spessasynth_lib/external_midi/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
## This is the MIDI handling folder.

The code here is respnsible for dealing with MIDI Inputs and outputs
and also for the WebMidiLink functionality.
63 changes: 37 additions & 26 deletions src/spessasynth_lib/external_midi/midi_handler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Synthetizer } from '../synthetizer/synthetizer.js'
import { consoleColors } from '../utils/other.js';
import { SpessaSynthInfo, SpessaSynthWarn } from '../utils/loggin.js'
import { Synthetizer } from "../synthetizer/synthetizer.js";
import { consoleColors } from "../utils/other.js";
import { SpessaSynthInfo, SpessaSynthWarn } from "../utils/loggin.js";

/**
* midi_handler.js
Expand All @@ -12,8 +12,9 @@ const NO_INPUT = null;
export class MIDIDeviceHandler
{
constructor()
{}

{
}

/**
* @returns {Promise<boolean>} if succeded
*/
Expand All @@ -27,7 +28,8 @@ export class MIDIDeviceHandler
* @type {MIDIOutput}
*/
this.selectedOutput = NO_INPUT;
if(navigator.requestMIDIAccess) {
if (navigator.requestMIDIAccess)
{
// prepare the midi access
try
{
Expand All @@ -36,23 +38,23 @@ export class MIDIDeviceHandler
this.outputs = response.outputs;
SpessaSynthInfo("%cMIDI handler created!", consoleColors.recognized);
return true;
}
catch (e) {
} catch (e)
{
SpessaSynthWarn(`Could not get MIDI Devices:`, e);
this.inputs = [];
this.outputs = [];
return false
return false;
}
}
else
{
SpessaSynthWarn("Web MIDI Api not supported!", consoleColors.unrecognized);
this.inputs = [];
this.outputs = [];
return false
return false;
}
}

/**
* Connects the sequencer to a given MIDI output port
* @param output {MIDIOutput}
Expand All @@ -62,11 +64,13 @@ export class MIDIDeviceHandler
{
this.selectedOutput = output;
seq.connectMidiOutput(output);
SpessaSynthInfo(`%cPlaying MIDI to %c${output.name}`,
SpessaSynthInfo(
`%cPlaying MIDI to %c${output.name}`,
consoleColors.info,
consoleColors.recognized);
consoleColors.recognized
);
}

/**
* Disconnects a midi output port from the sequencer
* @param seq {Sequencer}
Expand All @@ -75,10 +79,12 @@ export class MIDIDeviceHandler
{
this.selectedOutput = NO_INPUT;
seq.connectMidiOutput(undefined);
SpessaSynthInfo("%cDisconnected from MIDI out.",
consoleColors.info);
SpessaSynthInfo(
"%cDisconnected from MIDI out.",
consoleColors.info
);
}

/**
* Connects a MIDI input to the synthesizer
* @param input {MIDIInput}
Expand All @@ -87,30 +93,35 @@ export class MIDIDeviceHandler
connectDeviceToSynth(input, synth)
{
this.selectedInput = input;
input.onmidimessage = event => {
input.onmidimessage = event =>
{
synth.sendMessage(event.data);
}
SpessaSynthInfo(`%cListening for messages on %c${input.name}`,
};
SpessaSynthInfo(
`%cListening for messages on %c${input.name}`,
consoleColors.info,
consoleColors.recognized);
consoleColors.recognized
);
}

/**
* @param input {MIDIInput}
*/
disconnectDeviceFromSynth(input)
{
this.selectedInput = NO_INPUT;
input.onmidimessage = undefined;
SpessaSynthInfo(`%cDisconnected from %c${input.name}`,
SpessaSynthInfo(
`%cDisconnected from %c${input.name}`,
consoleColors.info,
consoleColors.recognized);
consoleColors.recognized
);
}

disconnectAllDevicesFromSynth()
{
this.selectedInput = NO_INPUT;
for(const i of this.inputs)
for (const i of this.inputs)
{
i[1].onmidimessage = undefined;
}
Expand Down
Loading

0 comments on commit 8035d9d

Please sign in to comment.