Skip to content

Commit

Permalink
The Global Scope Update 2.0: The End
Browse files Browse the repository at this point in the history
completed the sequencer
added audio exporting
  • Loading branch information
spessasus committed Jun 16, 2024
1 parent 6113855 commit b7f9e38
Show file tree
Hide file tree
Showing 37 changed files with 1,139 additions and 920 deletions.
3 changes: 3 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ <h1 id="title" translate-path='locale.demoTitleMessage'>SpessaSynth: Online Demo
<label id="file_upload" for='midi_file_input' translate-path='locale.midiUploadButton'>Upload your MIDI files</label>
<input type="file" accept=".mid" id="midi_file_input" multiple><br/>

<label for='export_file_input' translate-path='locale.midiRenderButton'>Export audio</label>
<input type='file' accept='.mid' id='export_file_input'>

<label id="sf_upload"> <p translate-path='locale.demoSoundfontUploadButton'>Upload the soundfont</p>
<input type="file" accept=".sf2,.sf3" id="sf_file_input"><br/>
</label>
Expand Down
13 changes: 7 additions & 6 deletions src/spessasynth_lib/midi_handler/midi_handler.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Synthetizer } from '../synthetizer/synthetizer.js'
import { consoleColors } from '../utils/other.js';
import { SpessaSynthInfo, SpessaSynthWarn } from '../utils/loggin.js'

/**
* midi_handler.js
Expand Down Expand Up @@ -29,10 +30,10 @@ export class MIDIDeviceHandler
const response = await navigator.requestMIDIAccess({ sysex: true, software: true });
this.inputs = response.inputs;
this.outputs = response.outputs;
console.log("%cMIDI handler created!", consoleColors.recognized);
SpessaSynthInfo("%cMIDI handler created!", consoleColors.recognized);
}
catch (e) {
console.warn(`Could not get MIDI Devices:`, e);
SpessaSynthWarn(`Could not get MIDI Devices:`, e);
this.inputs = [];
this.outputs = [];
}
Expand All @@ -53,7 +54,7 @@ export class MIDIDeviceHandler
{
this.selectedOutput = output;
seq.connectMidiOutput(output);
console.log(`%cPlaying MIDI to %c${output.name}`,
SpessaSynthInfo(`%cPlaying MIDI to %c${output.name}`,
consoleColors.info,
consoleColors.recognized);
}
Expand All @@ -66,7 +67,7 @@ export class MIDIDeviceHandler
{
this.selectedOutput = NO_INPUT;
seq.connectMidiOutput(undefined);
console.log("%cDisconnected from MIDI out.",
SpessaSynthInfo("%cDisconnected from MIDI out.",
consoleColors.info);
}

Expand All @@ -81,7 +82,7 @@ export class MIDIDeviceHandler
input.onmidimessage = event => {
synth.sendMessage(event.data);
}
console.log(`%cListening for messages on %c${input.name}`,
SpessaSynthInfo(`%cListening for messages on %c${input.name}`,
consoleColors.info,
consoleColors.recognized);
}
Expand All @@ -93,7 +94,7 @@ export class MIDIDeviceHandler
{
this.selectedInput = NO_INPUT;
input.onmidimessage = undefined;
console.log(`%cDisconnected from %c${input.name}`,
SpessaSynthInfo(`%cDisconnected from %c${input.name}`,
consoleColors.info,
consoleColors.recognized);
}
Expand Down
3 changes: 2 additions & 1 deletion src/spessasynth_lib/midi_handler/web_midi_link.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Synthetizer } from '../synthetizer/synthetizer.js'
import { consoleColors } from '../utils/other.js'
import { SpessaSynthInfo } from '../utils/loggin.js'

/**
* web_midi_link.js
Expand Down Expand Up @@ -35,6 +36,6 @@ export class WebMidiLinkHandler
synth.sendMessage(midiData);
});

console.log("%cWeb MIDI Link handler created!", consoleColors.recognized);
SpessaSynthInfo("%cWeb MIDI Link handler created!", consoleColors.recognized);
}
}
37 changes: 32 additions & 5 deletions src/spessasynth_lib/midi_parser/midi_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
readVariableLengthQuantity
} from "../utils/byte_functions.js";
import { arrayToHexString, consoleColors, formatTitle } from '../utils/other.js'
import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd, SpessaSynthInfo } from '../utils/loggin.js'

/**
* midi_loader.js
Expand All @@ -19,7 +20,7 @@ export class MIDI{
* @param fileName {string} optional, replaces the decoded title if empty
*/
constructor(arrayBuffer, fileName="") {
console.groupCollapsed(`%cParsing MIDI File...`, consoleColors.info);
SpessaSynthGroupCollapsed(`%cParsing MIDI File...`, consoleColors.info);

const fileByteArray = new ShiftableByteArray(arrayBuffer);
const headerChunk = this.readMIDIChunk(fileByteArray);
Expand Down Expand Up @@ -233,14 +234,14 @@ export class MIDI{
{
const decoded = decoder.decode(messageData.slice(7, messageData.length - 3)) + "\n";
this.copyright += decoded;
console.info(`%cDecoded Roland SC message! %c${decoded}`,
SpessaSynthInfo(`%cDecoded Roland SC message! %c${decoded}`,
consoleColors.recognized,
consoleColors.value)
}
}
}
this.tracks.push(track);
console.info(`%cParsed %c${this.tracks.length}%c / %c${this.tracksAmount}`,
SpessaSynthInfo(`%cParsed %c${this.tracks.length}%c / %c${this.tracksAmount}`,
consoleColors.info,
consoleColors.value,
consoleColors.info,
Expand All @@ -260,10 +261,10 @@ export class MIDI{
}
this.firstNoteOn = Math.min(...firstNoteOns);

console.info(`%cMIDI file parsed. Total tick time: %c${this.lastVoiceEventTick}`,
SpessaSynthInfo(`%cMIDI file parsed. Total tick time: %c${this.lastVoiceEventTick}`,
consoleColors.info,
consoleColors.recognized);
console.groupEnd();
SpessaSynthGroupEnd();

if(loopStart !== null && loopEnd === null)
{
Expand Down Expand Up @@ -327,6 +328,12 @@ export class MIDI{

// reverse the tempo changes
this.tempoChanges.reverse();

/**
* The total playback time, in seconds
* @type {number}
*/
this.duration = this._ticksToSeconds(this.lastVoiceEventTick);
}

/**
Expand All @@ -347,4 +354,24 @@ export class MIDI{
fileByteArray.currentIndex += chunk.size;
return chunk;
}


/**
* Coverts ticks to time in seconds
* @param ticks {number}
* @returns {number}
* @private
*/
_ticksToSeconds(ticks)
{
if (ticks <= 0) {
return 0;
}

// find the last tempo change that has occured
let tempo = this.tempoChanges.find(v => v.ticks < ticks);

let timeSinceLastTempo = ticks - tempo.ticks;
return this._ticksToSeconds(ticks - timeSinceLastTempo) + (timeSinceLastTempo * 60) / (tempo.tempo * this.timeDivision);
}
}
23 changes: 22 additions & 1 deletion src/spessasynth_lib/sequencer/README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,23 @@
## This is the sequencer's folder.
The code here is responsible for playing back the parsed MIDI sequence with the synthesizer.
The code here is responsible for playing back the parsed MIDI sequence with the synthesizer.

### Message protocol:
#### Message structure
```js
const message = {
messageType: number, // WorkletSequencerMessageType
messageData: any // any
}
```

#### To worklet
Sequencer uses `Synthetizer`'s `post` method to post a message with `messageData` set to `workletMessageType.sequencerSpecific`.
The `messageData` is set to the sequencer's message.

#### From worklet
`WorkletSequencer` uses `SpessaSynthProcessor`'s post to send a message with `messageData` set to `returnMessageType.sequencerSpecific`.
The `messageData` is set to the sequencer's return message.


### Process tick
`processTick` is called every time the `process` method is called via `SpessaSynthProcessor.processTickCallback`.
Loading

0 comments on commit b7f9e38

Please sign in to comment.