@waveform-playlist/playout 11.3.0 → 12.0.0

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