@waveform-playlist/playout 11.2.0 → 11.3.1

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.d.mts CHANGED
@@ -20,6 +20,8 @@ interface ToneTrackOptions {
20
20
  track: Track;
21
21
  effects?: TrackEffectsFunction;
22
22
  destination?: ToneAudioNode;
23
+ /** Max channel count across clips — sets Panner channelCount. Default: 1 */
24
+ channelCount?: number;
23
25
  }
24
26
  /** Per-clip scheduling info and audio nodes */
25
27
  interface ScheduledClip {
@@ -98,7 +100,6 @@ declare class ToneTrack {
98
100
  * Called on pause/stop to prevent stale fade envelopes.
99
101
  */
100
102
  cancelFades(): void;
101
- private gainToDb;
102
103
  setVolume(gain: number): void;
103
104
  setPan(pan: number): void;
104
105
  setMute(muted: boolean): void;
@@ -169,7 +170,6 @@ declare class MidiToneTrack implements PlayableTrack {
169
170
  * Routes per-note: channel 9 → percussion synths, others → melodic PolySynth.
170
171
  */
171
172
  private triggerNote;
172
- private gainToDb;
173
173
  /**
174
174
  * No-op for MIDI — schedule guard is for AudioBufferSourceNode ghost tick prevention.
175
175
  * Tone.Part handles its own scheduling relative to Transport.
@@ -390,7 +390,6 @@ declare class SoundFontToneTrack implements PlayableTrack {
390
390
  * Per-note routing: channel 9 → bank 128 (drums), others → bank 0 with programNumber.
391
391
  */
392
392
  private triggerNote;
393
- private gainToDb;
394
393
  /**
395
394
  * No-op — Tone.Part handles scheduling internally, no ghost tick guard needed.
396
395
  */
@@ -438,7 +437,6 @@ declare class TonePlayout {
438
437
  private _loopStart;
439
438
  private _loopEnd;
440
439
  constructor(options?: TonePlayoutOptions);
441
- private gainToDb;
442
440
  private clearCompletionEvent;
443
441
  init(): Promise<void>;
444
442
  addTrack(trackOptions: ToneTrackOptions): ToneTrack;
package/dist/index.d.ts CHANGED
@@ -20,6 +20,8 @@ interface ToneTrackOptions {
20
20
  track: Track;
21
21
  effects?: TrackEffectsFunction;
22
22
  destination?: ToneAudioNode;
23
+ /** Max channel count across clips — sets Panner channelCount. Default: 1 */
24
+ channelCount?: number;
23
25
  }
24
26
  /** Per-clip scheduling info and audio nodes */
25
27
  interface ScheduledClip {
@@ -98,7 +100,6 @@ declare class ToneTrack {
98
100
  * Called on pause/stop to prevent stale fade envelopes.
99
101
  */
100
102
  cancelFades(): void;
101
- private gainToDb;
102
103
  setVolume(gain: number): void;
103
104
  setPan(pan: number): void;
104
105
  setMute(muted: boolean): void;
@@ -169,7 +170,6 @@ declare class MidiToneTrack implements PlayableTrack {
169
170
  * Routes per-note: channel 9 → percussion synths, others → melodic PolySynth.
170
171
  */
171
172
  private triggerNote;
172
- private gainToDb;
173
173
  /**
174
174
  * No-op for MIDI — schedule guard is for AudioBufferSourceNode ghost tick prevention.
175
175
  * Tone.Part handles its own scheduling relative to Transport.
@@ -390,7 +390,6 @@ declare class SoundFontToneTrack implements PlayableTrack {
390
390
  * Per-note routing: channel 9 → bank 128 (drums), others → bank 0 with programNumber.
391
391
  */
392
392
  private triggerNote;
393
- private gainToDb;
394
393
  /**
395
394
  * No-op — Tone.Part handles scheduling internally, no ghost tick guard needed.
396
395
  */
@@ -438,7 +437,6 @@ declare class TonePlayout {
438
437
  private _loopStart;
439
438
  private _loopEnd;
440
439
  constructor(options?: TonePlayoutOptions);
441
- private gainToDb;
442
440
  private clearCompletionEvent;
443
441
  init(): Promise<void>;
444
442
  addTrack(trackOptions: ToneTrackOptions): ToneTrack;
package/dist/index.js CHANGED
@@ -49,9 +49,11 @@ module.exports = __toCommonJS(index_exports);
49
49
 
50
50
  // src/TonePlayout.ts
51
51
  var import_tone4 = require("tone");
52
+ var import_core5 = require("@waveform-playlist/core");
52
53
 
53
54
  // src/ToneTrack.ts
54
55
  var import_tone = require("tone");
56
+ var import_core2 = require("@waveform-playlist/core");
55
57
 
56
58
  // src/fades.ts
57
59
  var import_core = require("@waveform-playlist/core");
@@ -79,8 +81,11 @@ var ToneTrack = class {
79
81
  // clips at/after this offset.
80
82
  this._scheduleGuardOffset = 0;
81
83
  this.track = options.track;
82
- this.volumeNode = new import_tone.Volume(this.gainToDb(options.track.gain));
83
- this.panNode = new import_tone.Panner({ pan: options.track.stereoPan, channelCount: 2 });
84
+ this.volumeNode = new import_tone.Volume((0, import_core2.gainToDb)(options.track.gain));
85
+ this.panNode = new import_tone.Panner({
86
+ pan: options.track.stereoPan,
87
+ channelCount: options.channelCount ?? 1
88
+ });
84
89
  this.muteGain = new import_tone.Gain(options.track.muted ? 0 : 1);
85
90
  this.volumeNode.chain(this.panNode, this.muteGain);
86
91
  const destination = options.destination || (0, import_tone.getDestination)();
@@ -412,12 +417,9 @@ var ToneTrack = class {
412
417
  audioParam.setValueAtTime(clipInfo.gain, 0);
413
418
  });
414
419
  }
415
- gainToDb(gain) {
416
- return 20 * Math.log10(gain);
417
- }
418
420
  setVolume(gain) {
419
421
  this.track.gain = gain;
420
- this.volumeNode.volume.value = this.gainToDb(gain);
422
+ this.volumeNode.volume.value = (0, import_core2.gainToDb)(gain);
421
423
  }
422
424
  setPan(pan) {
423
425
  this.track.stereoPan = pan;
@@ -498,6 +500,7 @@ var ToneTrack = class {
498
500
 
499
501
  // src/MidiToneTrack.ts
500
502
  var import_tone2 = require("tone");
503
+ var import_core3 = require("@waveform-playlist/core");
501
504
  function getDrumCategory(midiNote) {
502
505
  if (midiNote === 35 || midiNote === 36) return "kick";
503
506
  if (midiNote >= 37 && midiNote <= 40) return "snare";
@@ -508,7 +511,7 @@ function getDrumCategory(midiNote) {
508
511
  var MidiToneTrack = class {
509
512
  constructor(options) {
510
513
  this.track = options.track;
511
- this.volumeNode = new import_tone2.Volume(this.gainToDb(options.track.gain));
514
+ this.volumeNode = new import_tone2.Volume((0, import_core3.gainToDb)(options.track.gain));
512
515
  this.panNode = new import_tone2.Panner(options.track.stereoPan);
513
516
  this.muteGain = new import_tone2.Gain(options.track.muted ? 0 : 1);
514
517
  this.volumeNode.chain(this.panNode, this.muteGain);
@@ -641,9 +644,6 @@ var MidiToneTrack = class {
641
644
  this.synth.triggerAttackRelease(noteName, duration, time, velocity);
642
645
  }
643
646
  }
644
- gainToDb(gain) {
645
- return 20 * Math.log10(gain);
646
- }
647
647
  /**
648
648
  * No-op for MIDI — schedule guard is for AudioBufferSourceNode ghost tick prevention.
649
649
  * Tone.Part handles its own scheduling relative to Transport.
@@ -711,7 +711,7 @@ var MidiToneTrack = class {
711
711
  }
712
712
  setVolume(gain) {
713
713
  this.track.gain = gain;
714
- this.volumeNode.volume.value = this.gainToDb(gain);
714
+ this.volumeNode.volume.value = (0, import_core3.gainToDb)(gain);
715
715
  }
716
716
  setPan(pan) {
717
717
  this.track.stereoPan = pan;
@@ -800,6 +800,7 @@ var MidiToneTrack = class {
800
800
 
801
801
  // src/SoundFontToneTrack.ts
802
802
  var import_tone3 = require("tone");
803
+ var import_core4 = require("@waveform-playlist/core");
803
804
  var _SoundFontToneTrack = class _SoundFontToneTrack {
804
805
  constructor(options) {
805
806
  this.activeSources = /* @__PURE__ */ new Set();
@@ -807,7 +808,7 @@ var _SoundFontToneTrack = class _SoundFontToneTrack {
807
808
  this.soundFontCache = options.soundFontCache;
808
809
  this.programNumber = options.programNumber ?? 0;
809
810
  this.bankNumber = options.isPercussion ? 128 : 0;
810
- this.volumeNode = new import_tone3.Volume(this.gainToDb(options.track.gain));
811
+ this.volumeNode = new import_tone3.Volume((0, import_core4.gainToDb)(options.track.gain));
811
812
  this.panNode = new import_tone3.Panner(options.track.stereoPan);
812
813
  this.muteGain = new import_tone3.Gain(options.track.muted ? 0 : 1);
813
814
  this.volumeNode.chain(this.panNode, this.muteGain);
@@ -907,9 +908,6 @@ var _SoundFontToneTrack = class _SoundFontToneTrack {
907
908
  source.start(time);
908
909
  source.stop(time + effectiveDuration + releaseVolEnv);
909
910
  }
910
- gainToDb(gain) {
911
- return 20 * Math.log10(gain);
912
- }
913
911
  /**
914
912
  * No-op — Tone.Part handles scheduling internally, no ghost tick guard needed.
915
913
  */
@@ -969,7 +967,7 @@ var _SoundFontToneTrack = class _SoundFontToneTrack {
969
967
  }
970
968
  setVolume(gain) {
971
969
  this.track.gain = gain;
972
- this.volumeNode.volume.value = this.gainToDb(gain);
970
+ this.volumeNode.volume.value = (0, import_core4.gainToDb)(gain);
973
971
  }
974
972
  setPan(pan) {
975
973
  this.track.stereoPan = pan;
@@ -1063,7 +1061,7 @@ var TonePlayout = class {
1063
1061
  this._loopEnabled = false;
1064
1062
  this._loopStart = 0;
1065
1063
  this._loopEnd = 0;
1066
- this.masterVolume = new import_tone4.Volume(this.gainToDb(options.masterGain ?? 1));
1064
+ this.masterVolume = new import_tone4.Volume((0, import_core5.gainToDb)(options.masterGain ?? 1));
1067
1065
  if (options.effects) {
1068
1066
  const cleanup = options.effects(this.masterVolume, (0, import_tone4.getDestination)(), false);
1069
1067
  if (cleanup) {
@@ -1079,9 +1077,6 @@ var TonePlayout = class {
1079
1077
  });
1080
1078
  }
1081
1079
  }
1082
- gainToDb(gain) {
1083
- return 20 * Math.log10(gain);
1084
- }
1085
1080
  clearCompletionEvent() {
1086
1081
  if (this._completionEventId !== null) {
1087
1082
  try {
@@ -1276,7 +1271,7 @@ var TonePlayout = class {
1276
1271
  this.clearCompletionEvent();
1277
1272
  }
1278
1273
  setMasterGain(gain) {
1279
- this.masterVolume.volume.value = this.gainToDb(gain);
1274
+ this.masterVolume.volume.value = (0, import_core5.gainToDb)(gain);
1280
1275
  }
1281
1276
  setSolo(trackId, soloed) {
1282
1277
  const track = this.tracks.get(trackId);
@@ -1630,7 +1625,7 @@ function hasMediaStreamSource(stream) {
1630
1625
  }
1631
1626
 
1632
1627
  // src/TonePlayoutAdapter.ts
1633
- var import_core2 = require("@waveform-playlist/core");
1628
+ var import_core6 = require("@waveform-playlist/core");
1634
1629
  var import_tone7 = require("tone");
1635
1630
  function createToneAdapter(options) {
1636
1631
  let playout = null;
@@ -1645,8 +1640,8 @@ function createToneAdapter(options) {
1645
1640
  const audioClips = track.clips.filter((c) => c.audioBuffer && !c.midiNotes);
1646
1641
  const midiClips = track.clips.filter((c) => c.midiNotes && c.midiNotes.length > 0);
1647
1642
  if (audioClips.length > 0) {
1648
- const startTime = Math.min(...audioClips.map(import_core2.clipStartTime));
1649
- const endTime = Math.max(...audioClips.map(import_core2.clipEndTime));
1643
+ const startTime = Math.min(...audioClips.map(import_core6.clipStartTime));
1644
+ const endTime = Math.max(...audioClips.map(import_core6.clipEndTime));
1650
1645
  const trackObj = {
1651
1646
  id: track.id,
1652
1647
  name: track.name,
@@ -1659,9 +1654,9 @@ function createToneAdapter(options) {
1659
1654
  };
1660
1655
  const clipInfos = audioClips.map((clip) => ({
1661
1656
  buffer: clip.audioBuffer,
1662
- startTime: (0, import_core2.clipStartTime)(clip) - startTime,
1663
- duration: (0, import_core2.clipDurationTime)(clip),
1664
- offset: (0, import_core2.clipOffsetTime)(clip),
1657
+ startTime: (0, import_core6.clipStartTime)(clip) - startTime,
1658
+ duration: (0, import_core6.clipDurationTime)(clip),
1659
+ offset: (0, import_core6.clipOffsetTime)(clip),
1665
1660
  fadeIn: clip.fadeIn,
1666
1661
  fadeOut: clip.fadeOut,
1667
1662
  gain: clip.gain
@@ -1669,12 +1664,13 @@ function createToneAdapter(options) {
1669
1664
  p.addTrack({
1670
1665
  clips: clipInfos,
1671
1666
  track: trackObj,
1672
- effects: track.effects
1667
+ effects: track.effects,
1668
+ channelCount: (0, import_core6.trackChannelCount)(track)
1673
1669
  });
1674
1670
  }
1675
1671
  if (midiClips.length > 0) {
1676
- const startTime = Math.min(...midiClips.map(import_core2.clipStartTime));
1677
- const endTime = Math.max(...midiClips.map(import_core2.clipEndTime));
1672
+ const startTime = Math.min(...midiClips.map(import_core6.clipStartTime));
1673
+ const endTime = Math.max(...midiClips.map(import_core6.clipEndTime));
1678
1674
  const trackId = audioClips.length > 0 ? `${track.id}:midi` : track.id;
1679
1675
  const trackObj = {
1680
1676
  id: trackId,
@@ -1688,9 +1684,9 @@ function createToneAdapter(options) {
1688
1684
  };
1689
1685
  const midiClipInfos = midiClips.map((clip) => ({
1690
1686
  notes: clip.midiNotes,
1691
- startTime: (0, import_core2.clipStartTime)(clip) - startTime,
1692
- duration: (0, import_core2.clipDurationTime)(clip),
1693
- offset: (0, import_core2.clipOffsetTime)(clip)
1687
+ startTime: (0, import_core6.clipStartTime)(clip) - startTime,
1688
+ duration: (0, import_core6.clipDurationTime)(clip),
1689
+ offset: (0, import_core6.clipOffsetTime)(clip)
1694
1690
  }));
1695
1691
  if (options?.soundFontCache?.isLoaded) {
1696
1692
  const firstClip = midiClips[0];
@@ -1796,12 +1792,12 @@ function createToneAdapter(options) {
1796
1792
  if (!playout) return;
1797
1793
  const audioClips = track.clips.filter((c) => c.audioBuffer && !c.midiNotes);
1798
1794
  if (audioClips.length > 0) {
1799
- const startTime = Math.min(...audioClips.map(import_core2.clipStartTime));
1795
+ const startTime = Math.min(...audioClips.map(import_core6.clipStartTime));
1800
1796
  const clipInfos = audioClips.map((clip) => ({
1801
1797
  buffer: clip.audioBuffer,
1802
- startTime: (0, import_core2.clipStartTime)(clip) - startTime,
1803
- duration: (0, import_core2.clipDurationTime)(clip),
1804
- offset: (0, import_core2.clipOffsetTime)(clip),
1798
+ startTime: (0, import_core6.clipStartTime)(clip) - startTime,
1799
+ duration: (0, import_core6.clipDurationTime)(clip),
1800
+ offset: (0, import_core6.clipOffsetTime)(clip),
1805
1801
  fadeIn: clip.fadeIn,
1806
1802
  fadeOut: clip.fadeOut,
1807
1803
  gain: clip.gain