| import { WorkletSequencerReturnMessageType } from "./sequencer_message.js"; |
| import { consoleColors, formatTime } from "../../utils/other.js"; |
| import { |
| SpessaSynthGroupCollapsed, |
| SpessaSynthGroupEnd, |
| SpessaSynthInfo, |
| SpessaSynthWarn |
| } from "../../utils/loggin.js"; |
| import { MIDIData } from "../../midi_parser/midi_data.js"; |
| import { MIDI } from "../../midi_parser/midi_loader.js"; |
| import { BasicMIDI } from "../../midi_parser/basic_midi.js"; |
|
|
|
|
| |
| |
| |
| |
| |
| export function assignMIDIPort(trackNum, port) |
| { |
| |
| if (this.midiData.usedChannelsOnTrack[trackNum].size === 0) |
| { |
| return; |
| } |
| |
| |
| if (this.midiPortChannelOffset === 0) |
| { |
| this.midiPortChannelOffset += 16; |
| this.midiPortChannelOffsets[port] = 0; |
| } |
| |
| if (this.midiPortChannelOffsets[port] === undefined) |
| { |
| if (this.synth.workletProcessorChannels.length < this.midiPortChannelOffset + 15) |
| { |
| this._addNewMidiPort(); |
| } |
| this.midiPortChannelOffsets[port] = this.midiPortChannelOffset; |
| this.midiPortChannelOffset += 16; |
| } |
| |
| this.midiPorts[trackNum] = port; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function loadNewSequence(parsedMidi, autoPlay = true) |
| { |
| this.stop(); |
| if (!parsedMidi.tracks) |
| { |
| throw new Error("This MIDI has no tracks!"); |
| } |
| |
| this.oneTickToSeconds = 60 / (120 * parsedMidi.timeDivision); |
| |
| |
| |
| |
| this.midiData = parsedMidi; |
| |
| |
| if (this.midiData.embeddedSoundFont !== undefined) |
| { |
| SpessaSynthInfo("%cEmbedded soundfont detected! Using it.", consoleColors.recognized); |
| this.synth.setEmbeddedSoundFont(this.midiData.embeddedSoundFont, this.midiData.bankOffset); |
| } |
| else |
| { |
| if (this.synth.overrideSoundfont) |
| { |
| |
| this.synth.clearSoundFont(true, true); |
| } |
| SpessaSynthGroupCollapsed("%cPreloading samples...", consoleColors.info); |
| |
| const used = this.midiData.getUsedProgramsAndKeys(this.synth.soundfontManager); |
| for (const [programBank, combos] of Object.entries(used)) |
| { |
| const bank = parseInt(programBank.split(":")[0]); |
| const program = parseInt(programBank.split(":")[1]); |
| const preset = this.synth.getPreset(bank, program); |
| SpessaSynthInfo( |
| `%cPreloading used samples on %c${preset.presetName}%c...`, |
| consoleColors.info, |
| consoleColors.recognized, |
| consoleColors.info |
| ); |
| for (const combo of combos) |
| { |
| const split = combo.split("-"); |
| preset.preloadSpecific(parseInt(split[0]), parseInt(split[1])); |
| } |
| } |
| SpessaSynthGroupEnd(); |
| } |
| |
| |
| |
| |
| |
| this.tracks = this.midiData.tracks; |
| |
| |
| this.midiPorts = this.midiData.midiPorts.slice(); |
| |
| |
| this.midiPortChannelOffset = 0; |
| this.midiPortChannelOffsets = {}; |
| |
| this.midiData.midiPorts.forEach((port, trackIndex) => |
| { |
| this.assignMIDIPort(trackIndex, port); |
| }); |
| |
| |
| |
| |
| |
| this.duration = this.midiData.duration; |
| this.firstNoteTime = this.midiData.MIDIticksToSeconds(this.midiData.firstNoteOn); |
| SpessaSynthInfo(`%cTotal song time: ${formatTime(Math.ceil(this.duration)).time}`, consoleColors.recognized); |
| |
| this.post(WorkletSequencerReturnMessageType.songChange, [this.songIndex, autoPlay]); |
| |
| if (this.duration <= 1) |
| { |
| SpessaSynthWarn( |
| `%cVery short song: (${formatTime(Math.round(this.duration)).time}). Disabling loop!`, |
| consoleColors.warn |
| ); |
| this.loop = false; |
| } |
| if (autoPlay) |
| { |
| this.play(true); |
| } |
| else |
| { |
| |
| const targetTime = this.skipToFirstNoteOn ? this.midiData.firstNoteOn - 1 : 0; |
| this.setTimeTicks(targetTime); |
| this.pause(); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| export function loadNewSongList(midiBuffers, autoPlay = true) |
| { |
| |
| |
| |
| |
| this.songs = midiBuffers.reduce((mids, b) => |
| { |
| if (b.duration) |
| { |
| mids.push(BasicMIDI.copyFrom(b)); |
| return mids; |
| } |
| try |
| { |
| mids.push(new MIDI(b.binary, b.altName || "")); |
| } |
| catch (e) |
| { |
| console.error(e); |
| this.post(WorkletSequencerReturnMessageType.midiError, e); |
| return mids; |
| } |
| return mids; |
| }, []); |
| if (this.songs.length < 1) |
| { |
| return; |
| } |
| this.songIndex = 0; |
| if (this.songs.length > 1) |
| { |
| this.loop = false; |
| } |
| this.shuffleSongIndexes(); |
| const midiDatas = this.songs.map(s => new MIDIData(s)); |
| this.post(WorkletSequencerReturnMessageType.songListChange, midiDatas); |
| this.loadCurrentSong(autoPlay); |
| } |
|
|
| |
| |
| |
| export function nextSong() |
| { |
| if (this.songs.length === 1) |
| { |
| this.currentTime = 0; |
| return; |
| } |
| this.songIndex++; |
| this.songIndex %= this.songs.length; |
| this.loadCurrentSong(); |
| } |
|
|
| |
| |
| |
| export function previousSong() |
| { |
| if (this.songs.length === 1) |
| { |
| this.currentTime = 0; |
| return; |
| } |
| this.songIndex--; |
| if (this.songIndex < 0) |
| { |
| this.songIndex = this.songs.length - 1; |
| } |
| this.loadCurrentSong(); |
| } |