@dawcore/components 0.0.18 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3446,6 +3446,108 @@ async function loadFiles(host, files) {
3446
3446
  return { loaded, failed };
3447
3447
  }
3448
3448
 
3449
+ // src/interactions/midi-loader.ts
3450
+ var INSTALL_HINT = "@dawcore/midi is required for loadMidi(). Install with: npm install @dawcore/midi";
3451
+ async function loadMidiImpl(host, source, options = {}) {
3452
+ const startTime = options.startTime ?? 0;
3453
+ if (!Number.isFinite(startTime) || startTime < 0) {
3454
+ throw new RangeError(
3455
+ "loadMidi: startTime must be a non-negative finite number (got " + String(options.startTime) + ")"
3456
+ );
3457
+ }
3458
+ let midiModule;
3459
+ try {
3460
+ midiModule = await import("@dawcore/midi");
3461
+ } catch (originalErr) {
3462
+ console.warn("[dawcore] @dawcore/midi dynamic import failed: " + String(originalErr));
3463
+ throw new Error(INSTALL_HINT);
3464
+ }
3465
+ const { parseMidiUrl, parseMidiFile } = midiModule;
3466
+ let parsed;
3467
+ if (typeof source === "string") {
3468
+ parsed = await parseMidiUrl(source, void 0, options.signal);
3469
+ } else {
3470
+ let buffer;
3471
+ try {
3472
+ buffer = await source.arrayBuffer();
3473
+ } catch (err) {
3474
+ throw new Error(
3475
+ 'loadMidi: failed to read File "' + source.name + '" (' + source.size + " bytes): " + String(err)
3476
+ );
3477
+ }
3478
+ parsed = parseMidiFile(buffer);
3479
+ }
3480
+ const childrenBefore = new Set(host.querySelectorAll("daw-track"));
3481
+ const settlements = await Promise.allSettled(
3482
+ parsed.tracks.map(
3483
+ (t) => host.addTrack({
3484
+ name: t.name,
3485
+ renderMode: "piano-roll",
3486
+ clips: [
3487
+ {
3488
+ midiNotes: t.notes,
3489
+ midiChannel: t.channel,
3490
+ midiProgram: t.programNumber,
3491
+ start: startTime
3492
+ }
3493
+ ]
3494
+ })
3495
+ )
3496
+ );
3497
+ const succeeded = [];
3498
+ const rejections = [];
3499
+ for (const s of settlements) {
3500
+ if (s.status === "fulfilled") {
3501
+ succeeded.push(s.value);
3502
+ } else {
3503
+ rejections.push(s.reason);
3504
+ }
3505
+ }
3506
+ if (rejections.length > 0) {
3507
+ const appendedTracks = Array.from(host.querySelectorAll("daw-track")).filter(
3508
+ (el) => !childrenBefore.has(el)
3509
+ );
3510
+ for (const el of appendedTracks) {
3511
+ try {
3512
+ el.remove();
3513
+ } catch (cleanupErr) {
3514
+ console.warn("[dawcore] loadMidi cleanup failed for a track: " + String(cleanupErr));
3515
+ }
3516
+ }
3517
+ await Promise.resolve();
3518
+ for (let i = 1; i < rejections.length; i++) {
3519
+ console.warn(
3520
+ "[dawcore] loadMidi: additional track failure (" + i + "): " + stringifyReason(rejections[i])
3521
+ );
3522
+ }
3523
+ const first = rejections[0];
3524
+ if (rejections.length > 1) {
3525
+ const message = "loadMidi: " + rejections.length + " of " + settlements.length + " tracks failed; first: " + (first instanceof Error ? first.message : stringifyReason(first));
3526
+ throw new Error(message);
3527
+ }
3528
+ throw first instanceof Error ? first : new Error(stringifyReason(first));
3529
+ }
3530
+ return {
3531
+ trackIds: succeeded.map((el) => el.trackId),
3532
+ bpm: parsed.bpm,
3533
+ timeSignature: parsed.timeSignature,
3534
+ duration: parsed.duration,
3535
+ name: parsed.name
3536
+ };
3537
+ }
3538
+ function stringifyReason(reason) {
3539
+ if (reason === null) return "null";
3540
+ if (reason === void 0) return "undefined";
3541
+ if (typeof reason === "object") {
3542
+ try {
3543
+ return JSON.stringify(reason);
3544
+ } catch {
3545
+ return Object.prototype.toString.call(reason);
3546
+ }
3547
+ }
3548
+ return String(reason);
3549
+ }
3550
+
3449
3551
  // src/interactions/recording-clip.ts
3450
3552
  import { createClip as createClip2 } from "@waveform-playlist/core";
3451
3553
  function addRecordedClip(host, trackId, buf, startSample, durSamples, offsetSamples = 0) {
@@ -5017,6 +5119,22 @@ var DawEditorElement = class extends LitElement10 {
5017
5119
  async loadFiles(files) {
5018
5120
  return loadFiles(this, files);
5019
5121
  }
5122
+ /**
5123
+ * Imperatively load a `.mid` file (URL or File) and create N `<daw-track>`
5124
+ * elements — one per note-bearing MIDI track. On any per-track failure,
5125
+ * every `<daw-track>` appended during the call is removed (both successful
5126
+ * and failed) so the editor returns to its pre-call state.
5127
+ *
5128
+ * `options.signal` is forwarded to `fetch()` only for URL sources; aborting
5129
+ * after parsing does not cancel in-flight `addTrack` calls.
5130
+ *
5131
+ * Requires the optional `@dawcore/midi` peer dep — throws with an install
5132
+ * hint (and `console.warn`s the original error) when the dynamic import
5133
+ * fails for any reason.
5134
+ */
5135
+ async loadMidi(source, options) {
5136
+ return loadMidiImpl(this, source, options);
5137
+ }
5020
5138
  // --- Programmatic Track API ---
5021
5139
  /**
5022
5140
  * Build the engine if it hasn't been built yet. Lets consumers obtain a