@dawcore/transport 0.0.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.
@@ -0,0 +1,306 @@
1
+ import { ClipTrack } from '@waveform-playlist/core';
2
+ import { PlayoutAdapter } from '@waveform-playlist/engine';
3
+
4
+ interface SchedulerEvent {
5
+ /** Transport time (elapsed seconds from timeline start) when this event should be realized */
6
+ transportTime: number;
7
+ }
8
+ interface SchedulerListener<T extends SchedulerEvent> {
9
+ /** Generate events in the time window [fromTime, toTime) */
10
+ generate(fromTime: number, toTime: number): T[];
11
+ /** Realize an event (create audio nodes, start sources) */
12
+ consume(event: T): void;
13
+ /** Position jumped (loop/seek) — stop active sources, re-schedule */
14
+ onPositionJump(newTime: number): void;
15
+ /** Stop all active audio immediately */
16
+ silence(): void;
17
+ }
18
+ interface TransportOptions {
19
+ /** Sample rate for SampleTimeline. Default: audioContext.sampleRate */
20
+ sampleRate?: number;
21
+ /** Ticks per quarter note. Default: 960 */
22
+ ppqn?: number;
23
+ /** Initial tempo in BPM. Default: 120 */
24
+ tempo?: number;
25
+ /** Beats per bar. Default: 4 */
26
+ beatsPerBar?: number;
27
+ /** How far ahead to schedule audio, in seconds. Default: 0.2 */
28
+ schedulerLookahead?: number;
29
+ }
30
+ interface TempoEntry {
31
+ /** Tick position where this tempo starts */
32
+ tick: number;
33
+ /** Beats per minute */
34
+ bpm: number;
35
+ /** Cached cumulative seconds up to this tick (for O(log n) lookup). Derived — do not set manually. */
36
+ readonly secondsAtTick: number;
37
+ }
38
+ interface TransportPosition {
39
+ /** 1-indexed bar number */
40
+ bar: number;
41
+ /** 1-indexed beat within bar */
42
+ beat: number;
43
+ /** Sub-beat tick (0 to ppqn-1) */
44
+ tick: number;
45
+ }
46
+
47
+ declare class Clock {
48
+ private _audioContext;
49
+ private _running;
50
+ private _audioTimeAtStart;
51
+ private _clockTimeAtStart;
52
+ constructor(audioContext: AudioContext);
53
+ start(): void;
54
+ stop(): void;
55
+ reset(): void;
56
+ getTime(): number;
57
+ seekTo(time: number): void;
58
+ /**
59
+ * Convert transport time to AudioContext.currentTime space.
60
+ * Used by players to schedule AudioBufferSourceNode.start(when).
61
+ */
62
+ toAudioTime(transportTime: number): number;
63
+ isRunning(): boolean;
64
+ }
65
+
66
+ interface SchedulerOptions {
67
+ lookahead?: number;
68
+ /** Called when the scheduler wraps at loopEnd — Transport uses this to seek the clock */
69
+ onLoop?: (loopStartTime: number) => void;
70
+ }
71
+ declare class Scheduler<T extends SchedulerEvent> {
72
+ private _lookahead;
73
+ private _rightEdge;
74
+ private _listeners;
75
+ private _loopEnabled;
76
+ private _loopStart;
77
+ private _loopEnd;
78
+ private _onLoop;
79
+ constructor(options?: SchedulerOptions);
80
+ addListener(listener: SchedulerListener<T>): void;
81
+ removeListener(listener: SchedulerListener<T>): void;
82
+ setLoop(enabled: boolean, start: number, end: number): void;
83
+ reset(time: number): void;
84
+ advance(currentTime: number): void;
85
+ private _generateAndConsume;
86
+ }
87
+
88
+ declare class Timer {
89
+ private _onTick;
90
+ private _rafId;
91
+ private _running;
92
+ constructor(onTick: () => void);
93
+ start(): void;
94
+ stop(): void;
95
+ private _scheduleFrame;
96
+ }
97
+
98
+ declare class SampleTimeline {
99
+ private _sampleRate;
100
+ constructor(sampleRate: number);
101
+ get sampleRate(): number;
102
+ samplesToSeconds(samples: number): number;
103
+ secondsToSamples(seconds: number): number;
104
+ }
105
+
106
+ declare class TickTimeline {
107
+ private _ppqn;
108
+ constructor(ppqn?: number);
109
+ get ppqn(): number;
110
+ ticksPerBeat(): number;
111
+ ticksPerBar(beatsPerBar: number): number;
112
+ toPosition(ticks: number, beatsPerBar: number): TransportPosition;
113
+ fromPosition(bar: number, beat: number, tick: number, beatsPerBar: number): number;
114
+ }
115
+
116
+ declare class TempoMap {
117
+ private _ppqn;
118
+ private _entries;
119
+ constructor(ppqn?: number, initialBpm?: number);
120
+ getTempo(atTick?: number): number;
121
+ setTempo(bpm: number, atTick?: number): void;
122
+ ticksToSeconds(ticks: number): number;
123
+ secondsToTicks(seconds: number): number;
124
+ beatsToSeconds(beats: number): number;
125
+ secondsToBeats(seconds: number): number;
126
+ private _ticksToSecondsInternal;
127
+ private _entryAt;
128
+ private _recomputeCache;
129
+ }
130
+
131
+ declare class MasterNode {
132
+ private _gainNode;
133
+ constructor(audioContext: AudioContext);
134
+ get input(): AudioNode;
135
+ get output(): AudioNode;
136
+ setVolume(value: number): void;
137
+ dispose(): void;
138
+ }
139
+
140
+ declare class TrackNode {
141
+ readonly id: string;
142
+ private _volumeNode;
143
+ private _panNode;
144
+ private _muteNode;
145
+ private _destination;
146
+ private _effectsInput;
147
+ constructor(id: string, audioContext: AudioContext);
148
+ /** Where clip sources connect */
149
+ get input(): GainNode;
150
+ /** Connect this track's output to a destination (master node) */
151
+ connectOutput(destination: AudioNode): void;
152
+ setVolume(value: number): void;
153
+ setPan(value: number): void;
154
+ setMute(muted: boolean): void;
155
+ connectEffects(effectsInput: AudioNode): void;
156
+ disconnectEffects(): void;
157
+ dispose(): void;
158
+ }
159
+
160
+ interface ClipEvent extends SchedulerEvent {
161
+ trackId: string;
162
+ clipId: string;
163
+ audioBuffer: AudioBuffer;
164
+ /** Offset into the audioBuffer (seconds) */
165
+ offset: number;
166
+ /** Duration to play (seconds) */
167
+ duration: number;
168
+ /** Clip gain multiplier */
169
+ gain: number;
170
+ /** Fade in duration in seconds */
171
+ fadeInDuration: number;
172
+ /** Fade out duration in seconds */
173
+ fadeOutDuration: number;
174
+ }
175
+ declare class ClipPlayer implements SchedulerListener<ClipEvent> {
176
+ private _audioContext;
177
+ private _sampleTimeline;
178
+ private _toAudioTime;
179
+ private _tracks;
180
+ private _trackNodes;
181
+ private _activeSources;
182
+ private _loopEnabled;
183
+ private _loopEnd;
184
+ constructor(audioContext: AudioContext, sampleTimeline: SampleTimeline, toAudioTime: (transportTime: number) => number);
185
+ setTracks(tracks: ClipTrack[], trackNodes: Map<string, TrackNode>): void;
186
+ setLoop(enabled: boolean, _start: number, end: number): void;
187
+ updateTrack(trackId: string, track: ClipTrack): void;
188
+ generate(fromTime: number, toTime: number): ClipEvent[];
189
+ consume(event: ClipEvent): void;
190
+ onPositionJump(newTime: number): void;
191
+ silence(): void;
192
+ private _silenceTrack;
193
+ }
194
+
195
+ interface MetronomeEvent extends SchedulerEvent {
196
+ isAccent: boolean;
197
+ buffer: AudioBuffer;
198
+ }
199
+ declare class MetronomePlayer implements SchedulerListener<MetronomeEvent> {
200
+ private _audioContext;
201
+ private _tempoMap;
202
+ private _tickTimeline;
203
+ private _destination;
204
+ private _toAudioTime;
205
+ private _enabled;
206
+ private _beatsPerBar;
207
+ private _accentBuffer;
208
+ private _normalBuffer;
209
+ private _activeSources;
210
+ constructor(audioContext: AudioContext, tempoMap: TempoMap, tickTimeline: TickTimeline, destination: AudioNode, toAudioTime: (transportTime: number) => number);
211
+ setEnabled(enabled: boolean): void;
212
+ setBeatsPerBar(beats: number): void;
213
+ setClickSounds(accent: AudioBuffer, normal: AudioBuffer): void;
214
+ generate(fromTime: number, toTime: number): MetronomeEvent[];
215
+ consume(event: MetronomeEvent): void;
216
+ onPositionJump(_newTime: number): void;
217
+ silence(): void;
218
+ }
219
+
220
+ interface TransportEvents {
221
+ play: () => void;
222
+ pause: () => void;
223
+ stop: () => void;
224
+ loop: () => void;
225
+ tempochange: () => void;
226
+ }
227
+ type TransportEventType = keyof TransportEvents;
228
+ declare class Transport {
229
+ private _audioContext;
230
+ private _clock;
231
+ private _scheduler;
232
+ private _timer;
233
+ private _sampleTimeline;
234
+ private _tickTimeline;
235
+ private _tempoMap;
236
+ private _clipPlayer;
237
+ private _metronomePlayer;
238
+ private _masterNode;
239
+ private _trackNodes;
240
+ private _tracks;
241
+ private _soloedTrackIds;
242
+ private _mutedTrackIds;
243
+ private _playing;
244
+ private _endTime;
245
+ private _listeners;
246
+ constructor(audioContext: AudioContext, options?: TransportOptions);
247
+ get audioContext(): AudioContext;
248
+ play(startTime?: number, endTime?: number): void;
249
+ pause(): void;
250
+ stop(): void;
251
+ seek(time: number): void;
252
+ getCurrentTime(): number;
253
+ isPlaying(): boolean;
254
+ setTracks(tracks: ClipTrack[]): void;
255
+ addTrack(track: ClipTrack): void;
256
+ removeTrack(trackId: string): void;
257
+ updateTrack(trackId: string, track: ClipTrack): void;
258
+ setTrackVolume(trackId: string, volume: number): void;
259
+ setTrackPan(trackId: string, pan: number): void;
260
+ setTrackMute(trackId: string, muted: boolean): void;
261
+ setTrackSolo(trackId: string, soloed: boolean): void;
262
+ setMasterVolume(volume: number): void;
263
+ setLoop(enabled: boolean, start: number, end: number): void;
264
+ setTempo(bpm: number): void;
265
+ getTempo(): number;
266
+ setBeatsPerBar(beats: number): void;
267
+ setMetronomeEnabled(enabled: boolean): void;
268
+ setMetronomeClickSounds(accent: AudioBuffer, normal: AudioBuffer): void;
269
+ connectTrackOutput(trackId: string, node: AudioNode): void;
270
+ disconnectTrackOutput(trackId: string): void;
271
+ on<K extends TransportEventType>(event: K, cb: TransportEvents[K]): void;
272
+ off<K extends TransportEventType>(event: K, cb: TransportEvents[K]): void;
273
+ dispose(): void;
274
+ private static _validateOptions;
275
+ private _initAudioGraph;
276
+ private _silenceAll;
277
+ private _applyMuteState;
278
+ private _emit;
279
+ }
280
+
281
+ declare class NativePlayoutAdapter implements PlayoutAdapter {
282
+ private _transport;
283
+ private _audioContext;
284
+ constructor(audioContext: AudioContext, options?: TransportOptions);
285
+ get transport(): Transport;
286
+ init(): Promise<void>;
287
+ setTracks(tracks: ClipTrack[]): void;
288
+ addTrack(track: ClipTrack): void;
289
+ removeTrack(trackId: string): void;
290
+ updateTrack(trackId: string, track: ClipTrack): void;
291
+ play(startTime: number, endTime?: number): void;
292
+ pause(): void;
293
+ stop(): void;
294
+ seek(time: number): void;
295
+ getCurrentTime(): number;
296
+ isPlaying(): boolean;
297
+ setMasterVolume(volume: number): void;
298
+ setTrackVolume(trackId: string, volume: number): void;
299
+ setTrackMute(trackId: string, muted: boolean): void;
300
+ setTrackSolo(trackId: string, soloed: boolean): void;
301
+ setTrackPan(trackId: string, pan: number): void;
302
+ setLoop(enabled: boolean, start: number, end: number): void;
303
+ dispose(): void;
304
+ }
305
+
306
+ export { type ClipEvent, ClipPlayer, Clock, MasterNode, type MetronomeEvent, MetronomePlayer, NativePlayoutAdapter, SampleTimeline, Scheduler, type SchedulerEvent, type SchedulerListener, type SchedulerOptions, type TempoEntry, TempoMap, TickTimeline, Timer, TrackNode, Transport, type TransportEvents, type TransportOptions, type TransportPosition };