Skip to content

loadMIDI() and loadSF2() prepend config path to relative URLs — breaks non-default paths #3

@putersdcat

Description

@putersdcat

Bug

Both loadMIDI(url) and loadSF2(url) prepend a config base path to any URL that doesn't start with http or /. This breaks usage with any relative path other than paths directly under the default config directories.

Affected code (midiocre.js)

// loadSF2 — line ~1721
const url = source.startsWith("http") || source.startsWith("/")
  ? source
  : `${this.config.sf2Path}/${source}`;  // default: "SoundFonts"

// loadMIDI — line ~1757
const url = source.startsWith("http") || source.startsWith("/")
  ? source
  : `${this.config.midiPath}/${source}`; // default: "DemoMidiFiles"

Example

const player = new Midiocre(); // default config

// Intended: fetch ./audio/music/midi/Bach.mid
// Actual URL:  DemoMidiFiles/./audio/music/midi/Bach.mid  (404)
await player.loadMIDI('./audio/music/midi/Bach.mid');

// Same issue for SF2:
// Actual URL:  SoundFonts/./audio/music/MySoundFont.sf2  (404)
await player.loadSF2('./audio/music/MySoundFont.sf2');

The 404 HTML response is then parsed as MIDI/SF2, producing cryptic parse errors like:

Error: Not a Standard MIDI file (missing MThd)

Workarounds

loadSF2 — fetch as ArrayBuffer first, pass buffer directly (accepted as ArrayBuffer):

const resp = await fetch('./audio/music/MySoundFont.sf2');
const buffer = await resp.arrayBuffer();
await player.loadSF2(buffer);

loadMIDI — same pattern (the else branch accepts non-string, non-File as raw buffer):

const resp = await fetch('./audio/music/midi/Bach.mid');
const buffer = await resp.arrayBuffer();
await player.loadMIDI(buffer);

Suggested fix

Accept ./-prefixed paths as absolute (they're relative to the document root and don't need the config path prefix):

const isAbsolute = source.startsWith("http") || source.startsWith("/") || source.startsWith("./") || source.startsWith("../");
const url = isAbsolute ? source : `${this.config.midiPath}/${source}`;

Or alternatively, only prepend when the source is a bare filename (no path separators):

const url = source.includes("/") ? source : `${this.config.midiPath}/${source}`;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions