@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 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/core/clock.ts","../src/core/scheduler.ts","../src/core/timer.ts","../src/timeline/sample-timeline.ts","../src/timeline/tick-timeline.ts","../src/timeline/tempo-map.ts","../src/audio/master-node.ts","../src/audio/track-node.ts","../src/audio/clip-player.ts","../src/audio/metronome-player.ts","../src/transport.ts","../src/adapter.ts"],"sourcesContent":["// packages/transport/src/index.ts\nexport type {\n SchedulerEvent,\n SchedulerListener,\n TransportOptions,\n TempoEntry,\n TransportPosition,\n} from './types';\n\nexport { Clock } from './core/clock';\nexport { Scheduler, type SchedulerOptions } from './core/scheduler';\nexport { Timer } from './core/timer';\nexport { SampleTimeline } from './timeline/sample-timeline';\nexport { TickTimeline } from './timeline/tick-timeline';\nexport { TempoMap } from './timeline/tempo-map';\nexport { MasterNode } from './audio/master-node';\nexport { TrackNode } from './audio/track-node';\nexport { ClipPlayer, type ClipEvent } from './audio/clip-player';\nexport { MetronomePlayer, type MetronomeEvent } from './audio/metronome-player';\nexport { Transport, type TransportEvents } from './transport';\nexport { NativePlayoutAdapter } from './adapter';\n","export class Clock {\n private _audioContext: AudioContext;\n private _running = false;\n private _audioTimeAtStart = 0;\n private _clockTimeAtStart = 0;\n\n constructor(audioContext: AudioContext) {\n this._audioContext = audioContext;\n }\n\n start(): void {\n if (this._running) return;\n this._audioTimeAtStart = this._audioContext.currentTime;\n this._running = true;\n }\n\n stop(): void {\n if (!this._running) return;\n this._clockTimeAtStart = this.getTime();\n this._running = false;\n }\n\n reset(): void {\n this._running = false;\n this._clockTimeAtStart = 0;\n this._audioTimeAtStart = 0;\n }\n\n getTime(): number {\n if (this._running) {\n return this._clockTimeAtStart + (this._audioContext.currentTime - this._audioTimeAtStart);\n }\n return this._clockTimeAtStart;\n }\n\n seekTo(time: number): void {\n if (this._running) {\n this._clockTimeAtStart = time;\n this._audioTimeAtStart = this._audioContext.currentTime;\n } else {\n this._clockTimeAtStart = time;\n }\n }\n\n /**\n * Convert transport time to AudioContext.currentTime space.\n * Used by players to schedule AudioBufferSourceNode.start(when).\n */\n toAudioTime(transportTime: number): number {\n return this._audioContext.currentTime + (transportTime - this.getTime());\n }\n\n isRunning(): boolean {\n return this._running;\n }\n}\n","import type { SchedulerEvent, SchedulerListener } from '../types';\n\nexport interface SchedulerOptions {\n lookahead?: number;\n /** Called when the scheduler wraps at loopEnd — Transport uses this to seek the clock */\n onLoop?: (loopStartTime: number) => void;\n}\n\nexport class Scheduler<T extends SchedulerEvent> {\n private _lookahead: number;\n private _rightEdge = 0;\n private _listeners: Set<SchedulerListener<T>> = new Set();\n private _loopEnabled = false;\n private _loopStart = 0;\n private _loopEnd = 0;\n private _onLoop: ((loopStartTime: number) => void) | undefined;\n\n constructor(options: SchedulerOptions = {}) {\n this._lookahead = options.lookahead ?? 0.2;\n this._onLoop = options.onLoop;\n }\n\n addListener(listener: SchedulerListener<T>): void {\n this._listeners.add(listener);\n }\n\n removeListener(listener: SchedulerListener<T>): void {\n this._listeners.delete(listener);\n }\n\n setLoop(enabled: boolean, start: number, end: number): void {\n if (enabled && start >= end) {\n console.warn(\n '[waveform-playlist] Scheduler.setLoop: start (' +\n start +\n ') must be less than end (' +\n end +\n ')'\n );\n return;\n }\n this._loopEnabled = enabled;\n this._loopStart = start;\n this._loopEnd = end;\n }\n\n reset(time: number): void {\n this._rightEdge = time;\n }\n\n advance(currentTime: number): void {\n const targetEdge = currentTime + this._lookahead;\n\n if (this._loopEnabled && this._loopEnd > this._loopStart) {\n const loopDuration = this._loopEnd - this._loopStart;\n let remaining = targetEdge - this._rightEdge;\n\n // Handle multiple loop wraps (loop region shorter than lookahead)\n while (remaining > 0) {\n const distToEnd = this._loopEnd - this._rightEdge;\n if (distToEnd <= 0 || distToEnd > remaining) {\n // No wrap needed — generate remaining window\n this._generateAndConsume(this._rightEdge, this._rightEdge + remaining);\n this._rightEdge += remaining;\n break;\n }\n // Generate up to loopEnd\n this._generateAndConsume(this._rightEdge, this._loopEnd);\n remaining -= distToEnd;\n // Notify listeners of position jump\n for (const listener of this._listeners) {\n listener.onPositionJump(this._loopStart);\n }\n // Seek clock back to loopStart\n this._onLoop?.(this._loopStart);\n this._rightEdge = this._loopStart;\n\n // Guard against infinite loop from zero-length loop regions\n if (loopDuration <= 0) break;\n }\n return;\n }\n\n if (targetEdge > this._rightEdge) {\n this._generateAndConsume(this._rightEdge, targetEdge);\n this._rightEdge = targetEdge;\n }\n }\n\n private _generateAndConsume(from: number, to: number): void {\n for (const listener of this._listeners) {\n try {\n const events = listener.generate(from, to);\n for (const event of events) {\n try {\n listener.consume(event);\n } catch (err) {\n console.warn('[waveform-playlist] Scheduler: error consuming event:', String(err));\n }\n }\n } catch (err) {\n console.warn('[waveform-playlist] Scheduler: error generating events:', String(err));\n }\n }\n }\n}\n","export class Timer {\n private _onTick: () => void;\n private _rafId: number | null = null;\n private _running = false;\n\n constructor(onTick: () => void) {\n this._onTick = onTick;\n }\n\n start(): void {\n if (this._running) return;\n this._running = true;\n this._scheduleFrame();\n }\n\n stop(): void {\n this._running = false;\n if (this._rafId !== null) {\n cancelAnimationFrame(this._rafId);\n this._rafId = null;\n }\n }\n\n private _scheduleFrame(): void {\n this._rafId = requestAnimationFrame(() => {\n if (!this._running) return;\n try {\n this._onTick();\n } catch (err) {\n console.warn('[waveform-playlist] Timer tick error:', String(err));\n }\n this._scheduleFrame();\n });\n }\n}\n","export class SampleTimeline {\n private _sampleRate: number;\n\n constructor(sampleRate: number) {\n this._sampleRate = sampleRate;\n }\n\n get sampleRate(): number {\n return this._sampleRate;\n }\n\n samplesToSeconds(samples: number): number {\n return samples / this._sampleRate;\n }\n\n secondsToSamples(seconds: number): number {\n return Math.round(seconds * this._sampleRate);\n }\n}\n","import type { TransportPosition } from '../types';\n\nexport class TickTimeline {\n private _ppqn: number;\n\n constructor(ppqn: number = 960) {\n this._ppqn = ppqn;\n }\n\n get ppqn(): number {\n return this._ppqn;\n }\n\n ticksPerBeat(): number {\n return this._ppqn;\n }\n\n ticksPerBar(beatsPerBar: number): number {\n return this._ppqn * beatsPerBar;\n }\n\n toPosition(ticks: number, beatsPerBar: number): TransportPosition {\n const ticksPerBar = this.ticksPerBar(beatsPerBar);\n const bar = Math.floor(ticks / ticksPerBar) + 1;\n const remaining = ticks % ticksPerBar;\n const beat = Math.floor(remaining / this._ppqn) + 1;\n const tick = remaining % this._ppqn;\n return { bar, beat, tick };\n }\n\n fromPosition(bar: number, beat: number, tick: number, beatsPerBar: number): number {\n const ticksPerBar = this.ticksPerBar(beatsPerBar);\n return (bar - 1) * ticksPerBar + (beat - 1) * this._ppqn + tick;\n }\n}\n","import type { TempoEntry } from '../types';\n\n/** Mutable internal version of TempoEntry (exported interface has readonly secondsAtTick) */\ninterface MutableTempoEntry {\n tick: number;\n bpm: number;\n secondsAtTick: number;\n}\n\nexport class TempoMap {\n private _ppqn: number;\n private _entries: MutableTempoEntry[];\n\n constructor(ppqn: number = 960, initialBpm: number = 120) {\n this._ppqn = ppqn;\n this._entries = [{ tick: 0, bpm: initialBpm, secondsAtTick: 0 }];\n }\n\n getTempo(atTick: number = 0): number {\n const entry = this._entryAt(atTick);\n return entry.bpm;\n }\n\n setTempo(bpm: number, atTick: number = 0): void {\n if (atTick === 0) {\n this._entries[0] = { ...this._entries[0], bpm };\n this._recomputeCache(0);\n return;\n }\n // Find insertion point\n let i = this._entries.length - 1;\n while (i > 0 && this._entries[i].tick > atTick) i--;\n\n if (this._entries[i].tick === atTick) {\n this._entries[i] = { ...this._entries[i], bpm };\n } else {\n const secondsAtTick = this._ticksToSecondsInternal(atTick);\n this._entries.splice(i + 1, 0, { tick: atTick, bpm, secondsAtTick });\n i = i + 1;\n }\n this._recomputeCache(i);\n }\n\n ticksToSeconds(ticks: number): number {\n return this._ticksToSecondsInternal(ticks);\n }\n\n secondsToTicks(seconds: number): number {\n let lo = 0;\n let hi = this._entries.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (this._entries[mid].secondsAtTick <= seconds) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n const entry = this._entries[lo];\n const secondsIntoSegment = seconds - entry.secondsAtTick;\n const ticksPerSecond = (entry.bpm / 60) * this._ppqn;\n return entry.tick + secondsIntoSegment * ticksPerSecond;\n }\n\n beatsToSeconds(beats: number): number {\n return this.ticksToSeconds(beats * this._ppqn);\n }\n\n secondsToBeats(seconds: number): number {\n return this.secondsToTicks(seconds) / this._ppqn;\n }\n\n private _ticksToSecondsInternal(ticks: number): number {\n const entry = this._entryAt(ticks);\n const ticksIntoSegment = ticks - entry.tick;\n const secondsPerTick = 60 / (entry.bpm * this._ppqn);\n return entry.secondsAtTick + ticksIntoSegment * secondsPerTick;\n }\n\n private _entryAt(tick: number): TempoEntry {\n let lo = 0;\n let hi = this._entries.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (this._entries[mid].tick <= tick) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n return this._entries[lo];\n }\n\n private _recomputeCache(fromIndex: number): void {\n for (let i = Math.max(1, fromIndex); i < this._entries.length; i++) {\n const prev = this._entries[i - 1];\n const tickDelta = this._entries[i].tick - prev.tick;\n const secondsPerTick = 60 / (prev.bpm * this._ppqn);\n this._entries[i] = {\n ...this._entries[i],\n secondsAtTick: prev.secondsAtTick + tickDelta * secondsPerTick,\n };\n }\n }\n}\n","export class MasterNode {\n private _gainNode: GainNode;\n\n constructor(audioContext: AudioContext) {\n this._gainNode = audioContext.createGain();\n }\n\n get input(): AudioNode {\n return this._gainNode;\n }\n\n get output(): AudioNode {\n return this._gainNode;\n }\n\n setVolume(value: number): void {\n this._gainNode.gain.value = value;\n }\n\n dispose(): void {\n try {\n this._gainNode.disconnect();\n } catch (err) {\n console.warn('[waveform-playlist] MasterNode.dispose: error disconnecting:', String(err));\n }\n }\n}\n","export class TrackNode {\n readonly id: string;\n private _volumeNode: GainNode;\n private _panNode: StereoPannerNode;\n private _muteNode: GainNode;\n private _destination: AudioNode | null = null;\n private _effectsInput: AudioNode | null = null;\n\n constructor(id: string, audioContext: AudioContext) {\n this.id = id;\n this._volumeNode = audioContext.createGain();\n this._panNode = audioContext.createStereoPanner();\n this._panNode.channelCount = 2;\n this._muteNode = audioContext.createGain();\n\n // Wire: volume → pan → mute (caller connects output via connectOutput)\n this._volumeNode.connect(this._panNode);\n this._panNode.connect(this._muteNode);\n }\n\n /** Where clip sources connect */\n get input(): GainNode {\n return this._volumeNode;\n }\n\n /** Connect this track's output to a destination (master node) */\n connectOutput(destination: AudioNode): void {\n this._destination = destination;\n this._muteNode.connect(destination);\n }\n\n setVolume(value: number): void {\n this._volumeNode.gain.value = value;\n }\n\n setPan(value: number): void {\n this._panNode.pan.value = value;\n }\n\n setMute(muted: boolean): void {\n this._muteNode.gain.value = muted ? 0 : 1;\n }\n\n connectEffects(effectsInput: AudioNode): void {\n // Clean up previous effects connection first\n if (this._effectsInput) {\n this.disconnectEffects();\n }\n // Disconnect mute from destination\n this._muteNode.disconnect();\n // Route mute → effects input\n this._muteNode.connect(effectsInput);\n this._effectsInput = effectsInput;\n }\n\n disconnectEffects(): void {\n if (this._effectsInput && this._destination) {\n this._muteNode.disconnect();\n // Restore direct routing: mute → destination\n this._muteNode.connect(this._destination);\n this._effectsInput = null;\n }\n }\n\n dispose(): void {\n for (const node of [this._volumeNode, this._panNode, this._muteNode]) {\n try {\n node.disconnect();\n } catch (err) {\n console.warn(\n '[waveform-playlist] TrackNode.dispose: error disconnecting node:',\n String(err)\n );\n }\n }\n }\n}\n","import type { ClipTrack, AudioClip } from '@waveform-playlist/core';\nimport type { SchedulerEvent, SchedulerListener } from '../types';\nimport type { SampleTimeline } from '../timeline/sample-timeline';\nimport type { TrackNode } from './track-node';\n\nexport interface ClipEvent extends SchedulerEvent {\n trackId: string;\n clipId: string;\n audioBuffer: AudioBuffer;\n /** Offset into the audioBuffer (seconds) */\n offset: number;\n /** Duration to play (seconds) */\n duration: number;\n /** Clip gain multiplier */\n gain: number;\n /** Fade in duration in seconds */\n fadeInDuration: number;\n /** Fade out duration in seconds */\n fadeOutDuration: number;\n}\n\ninterface TrackClipState {\n track: ClipTrack;\n clips: AudioClip[];\n}\n\nexport class ClipPlayer implements SchedulerListener<ClipEvent> {\n private _audioContext: AudioContext;\n private _sampleTimeline: SampleTimeline;\n private _toAudioTime: (transportTime: number) => number;\n private _tracks: Map<string, TrackClipState> = new Map();\n private _trackNodes: Map<string, TrackNode> = new Map();\n private _activeSources: Map<AudioBufferSourceNode, { trackId: string; gainNode: GainNode }> =\n new Map();\n private _loopEnabled = false;\n private _loopEnd = 0;\n\n constructor(\n audioContext: AudioContext,\n sampleTimeline: SampleTimeline,\n toAudioTime: (transportTime: number) => number\n ) {\n this._audioContext = audioContext;\n this._sampleTimeline = sampleTimeline;\n this._toAudioTime = toAudioTime;\n }\n\n setTracks(tracks: ClipTrack[], trackNodes: Map<string, TrackNode>): void {\n this._tracks.clear();\n this._trackNodes = trackNodes;\n for (const track of tracks) {\n this._tracks.set(track.id, { track, clips: track.clips });\n }\n }\n\n setLoop(enabled: boolean, _start: number, end: number): void {\n this._loopEnabled = enabled;\n this._loopEnd = end;\n }\n\n updateTrack(trackId: string, track: ClipTrack): void {\n this._tracks.set(trackId, { track, clips: track.clips });\n this._silenceTrack(trackId);\n }\n\n generate(fromTime: number, toTime: number): ClipEvent[] {\n const events: ClipEvent[] = [];\n\n for (const [trackId, state] of this._tracks) {\n for (const clip of state.clips) {\n if (clip.durationSamples === 0) continue;\n if (!clip.audioBuffer) continue;\n\n const clipStartTime = this._sampleTimeline.samplesToSeconds(clip.startSample);\n const clipDuration = this._sampleTimeline.samplesToSeconds(clip.durationSamples);\n const clipOffsetTime = this._sampleTimeline.samplesToSeconds(clip.offsetSamples);\n\n // Only schedule when the clip START falls within this window.\n // Clips that started in a previous window are already playing\n // (AudioBufferSourceNode runs for its full duration).\n // Mid-clip starts (seek, loop wrap) are handled by onPositionJump().\n if (clipStartTime < fromTime) continue;\n if (clipStartTime >= toTime) continue;\n\n const fadeInDuration = clip.fadeIn\n ? this._sampleTimeline.samplesToSeconds(clip.fadeIn.duration ?? 0)\n : 0;\n const fadeOutDuration = clip.fadeOut\n ? this._sampleTimeline.samplesToSeconds(clip.fadeOut.duration ?? 0)\n : 0;\n\n // Clamp duration at loopEnd so the source stops exactly at the\n // loop boundary. onPositionJump handles the mid-clip restart.\n let duration = clipDuration;\n if (this._loopEnabled && clipStartTime + duration > this._loopEnd) {\n duration = this._loopEnd - clipStartTime;\n }\n\n events.push({\n trackId,\n clipId: clip.id,\n audioBuffer: clip.audioBuffer,\n transportTime: clipStartTime,\n offset: clipOffsetTime,\n duration,\n gain: clip.gain,\n fadeInDuration,\n fadeOutDuration,\n });\n }\n }\n\n return events;\n }\n\n consume(event: ClipEvent): void {\n const trackNode = this._trackNodes.get(event.trackId);\n if (!trackNode) {\n console.warn(\n '[waveform-playlist] ClipPlayer.consume: no TrackNode for trackId \"' +\n event.trackId +\n '\", clipId \"' +\n event.clipId +\n '\" — clip will not play'\n );\n return;\n }\n\n // Guard against invalid offset\n if (event.offset >= event.audioBuffer.duration) {\n return;\n }\n\n const source = this._audioContext.createBufferSource();\n source.buffer = event.audioBuffer;\n\n // Convert transport time → AudioContext.currentTime for scheduling\n const when = this._toAudioTime(event.transportTime);\n\n // Create a gain node for per-clip gain and fades\n const gainNode = this._audioContext.createGain();\n gainNode.gain.value = event.gain;\n\n // Apply fades (AudioParam scheduling uses AudioContext time)\n // Clamp fades so they don't overlap (split duration evenly if they would)\n let fadeIn = event.fadeInDuration;\n let fadeOut = event.fadeOutDuration;\n if (fadeIn + fadeOut > event.duration) {\n const ratio = event.duration / (fadeIn + fadeOut);\n fadeIn *= ratio;\n fadeOut *= ratio;\n }\n\n if (fadeIn > 0) {\n gainNode.gain.setValueAtTime(0, when);\n gainNode.gain.linearRampToValueAtTime(event.gain, when + fadeIn);\n }\n if (fadeOut > 0) {\n const fadeOutStart = when + event.duration - fadeOut;\n gainNode.gain.setValueAtTime(event.gain, fadeOutStart);\n gainNode.gain.linearRampToValueAtTime(0, when + event.duration);\n }\n\n source.connect(gainNode);\n gainNode.connect(trackNode.input);\n\n this._activeSources.set(source, {\n trackId: event.trackId,\n gainNode,\n });\n\n // Clean up when source finishes\n source.addEventListener('ended', () => {\n this._activeSources.delete(source);\n try {\n gainNode.disconnect();\n } catch (err) {\n console.warn('[waveform-playlist] ClipPlayer: error disconnecting gain node:', String(err));\n }\n });\n\n source.start(when, event.offset, event.duration);\n }\n\n onPositionJump(newTime: number): void {\n this.silence();\n\n // Re-schedule mid-clip sources for clips that span the new position\n for (const [trackId, state] of this._tracks) {\n for (const clip of state.clips) {\n if (clip.durationSamples === 0) continue;\n if (!clip.audioBuffer) continue;\n\n const clipStartTime = this._sampleTimeline.samplesToSeconds(clip.startSample);\n const clipDuration = this._sampleTimeline.samplesToSeconds(clip.durationSamples);\n const clipEndTime = clipStartTime + clipDuration;\n const clipOffsetTime = this._sampleTimeline.samplesToSeconds(clip.offsetSamples);\n\n // Check if clip spans the new position\n if (clipStartTime <= newTime && clipEndTime > newTime) {\n const offsetIntoClip = newTime - clipStartTime;\n const offset = clipOffsetTime + offsetIntoClip;\n const duration = clipEndTime - newTime;\n\n const fadeOutDuration = clip.fadeOut\n ? this._sampleTimeline.samplesToSeconds(clip.fadeOut.duration ?? 0)\n : 0;\n\n this.consume({\n trackId,\n clipId: clip.id,\n audioBuffer: clip.audioBuffer,\n transportTime: newTime,\n offset,\n duration,\n gain: clip.gain,\n fadeInDuration: 0,\n fadeOutDuration,\n });\n }\n }\n }\n }\n\n silence(): void {\n for (const [source, { gainNode }] of this._activeSources) {\n try {\n source.stop();\n } catch (err) {\n console.warn('[waveform-playlist] ClipPlayer.silence: error stopping source:', String(err));\n }\n try {\n gainNode.disconnect();\n } catch (err) {\n console.warn('[waveform-playlist] ClipPlayer.silence: error disconnecting:', String(err));\n }\n }\n this._activeSources.clear();\n }\n\n private _silenceTrack(trackId: string): void {\n const toDelete: AudioBufferSourceNode[] = [];\n for (const [source, info] of this._activeSources) {\n if (info.trackId === trackId) {\n try {\n source.stop();\n } catch (err) {\n console.warn(\n '[waveform-playlist] ClipPlayer._silenceTrack: error stopping source:',\n String(err)\n );\n }\n try {\n info.gainNode.disconnect();\n } catch (err) {\n console.warn(\n '[waveform-playlist] ClipPlayer._silenceTrack: error disconnecting:',\n String(err)\n );\n }\n toDelete.push(source);\n }\n }\n for (const source of toDelete) {\n this._activeSources.delete(source);\n }\n }\n}\n","import type { SchedulerEvent, SchedulerListener } from '../types';\nimport type { TempoMap } from '../timeline/tempo-map';\nimport type { TickTimeline } from '../timeline/tick-timeline';\n\nexport interface MetronomeEvent extends SchedulerEvent {\n isAccent: boolean;\n buffer: AudioBuffer;\n}\n\nexport class MetronomePlayer implements SchedulerListener<MetronomeEvent> {\n private _audioContext: AudioContext;\n private _tempoMap: TempoMap;\n private _tickTimeline: TickTimeline;\n private _destination: AudioNode;\n private _toAudioTime: (transportTime: number) => number;\n private _enabled = false;\n private _beatsPerBar = 4;\n private _accentBuffer: AudioBuffer | null = null;\n private _normalBuffer: AudioBuffer | null = null;\n private _activeSources: Set<AudioBufferSourceNode> = new Set();\n\n constructor(\n audioContext: AudioContext,\n tempoMap: TempoMap,\n tickTimeline: TickTimeline,\n destination: AudioNode,\n toAudioTime: (transportTime: number) => number\n ) {\n this._audioContext = audioContext;\n this._tempoMap = tempoMap;\n this._tickTimeline = tickTimeline;\n this._destination = destination;\n this._toAudioTime = toAudioTime;\n }\n\n setEnabled(enabled: boolean): void {\n this._enabled = enabled;\n if (!enabled) {\n this.silence();\n }\n }\n\n setBeatsPerBar(beats: number): void {\n this._beatsPerBar = beats;\n }\n\n setClickSounds(accent: AudioBuffer, normal: AudioBuffer): void {\n this._accentBuffer = accent;\n this._normalBuffer = normal;\n }\n\n generate(fromTime: number, toTime: number): MetronomeEvent[] {\n if (!this._enabled || !this._accentBuffer || !this._normalBuffer) {\n return [];\n }\n\n const events: MetronomeEvent[] = [];\n const ppqn = this._tickTimeline.ppqn;\n\n // Convert time window to ticks\n const fromTicks = this._tempoMap.secondsToTicks(fromTime);\n const toTicks = this._tempoMap.secondsToTicks(toTime);\n\n // Find first beat at or after fromTicks\n const firstBeatTick = Math.ceil(fromTicks / ppqn) * ppqn;\n\n for (let tick = firstBeatTick; tick < toTicks; tick += ppqn) {\n const transportTime = this._tempoMap.ticksToSeconds(tick);\n const ticksPerBar = this._tickTimeline.ticksPerBar(this._beatsPerBar);\n const isAccent = tick % ticksPerBar === 0;\n\n events.push({\n transportTime,\n isAccent,\n buffer: isAccent ? this._accentBuffer : this._normalBuffer,\n });\n }\n\n return events;\n }\n\n consume(event: MetronomeEvent): void {\n const source = this._audioContext.createBufferSource();\n source.buffer = event.buffer;\n source.connect(this._destination);\n\n this._activeSources.add(source);\n source.addEventListener('ended', () => {\n this._activeSources.delete(source);\n try {\n source.disconnect();\n } catch (err) {\n console.warn(\n '[waveform-playlist] MetronomePlayer: error disconnecting source:',\n String(err)\n );\n }\n });\n\n source.start(this._toAudioTime(event.transportTime));\n }\n\n onPositionJump(_newTime: number): void {\n this.silence();\n }\n\n silence(): void {\n for (const source of this._activeSources) {\n try {\n source.stop();\n } catch (err) {\n console.warn(\n '[waveform-playlist] MetronomePlayer.silence: error stopping source:',\n String(err)\n );\n }\n try {\n source.disconnect();\n } catch (err) {\n console.warn(\n '[waveform-playlist] MetronomePlayer.silence: error disconnecting:',\n String(err)\n );\n }\n }\n this._activeSources.clear();\n }\n}\n","import type { ClipTrack } from '@waveform-playlist/core';\nimport type { TransportOptions } from './types';\nimport { Clock } from './core/clock';\nimport { Scheduler } from './core/scheduler';\nimport { Timer } from './core/timer';\nimport { SampleTimeline } from './timeline/sample-timeline';\nimport { TickTimeline } from './timeline/tick-timeline';\nimport { TempoMap } from './timeline/tempo-map';\nimport { ClipPlayer } from './audio/clip-player';\nimport { MetronomePlayer } from './audio/metronome-player';\nimport { MasterNode } from './audio/master-node';\nimport { TrackNode } from './audio/track-node';\n\nexport interface TransportEvents {\n play: () => void;\n pause: () => void;\n stop: () => void;\n loop: () => void;\n tempochange: () => void;\n}\n\ntype TransportEventType = keyof TransportEvents;\n\nexport class Transport {\n private _audioContext: AudioContext;\n private _clock: Clock;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private _scheduler: Scheduler<any>;\n private _timer: Timer;\n private _sampleTimeline: SampleTimeline;\n private _tickTimeline: TickTimeline;\n private _tempoMap: TempoMap;\n private _clipPlayer!: ClipPlayer;\n private _metronomePlayer!: MetronomePlayer;\n private _masterNode!: MasterNode;\n private _trackNodes: Map<string, TrackNode> = new Map();\n private _tracks: ClipTrack[] = [];\n private _soloedTrackIds: Set<string> = new Set();\n private _mutedTrackIds: Set<string> = new Set();\n private _playing = false;\n private _endTime: number | undefined;\n private _listeners: Map<TransportEventType, Set<TransportEvents[TransportEventType]>> = new Map();\n\n constructor(audioContext: AudioContext, options: TransportOptions = {}) {\n this._audioContext = audioContext;\n\n const sampleRate = options.sampleRate ?? audioContext.sampleRate;\n const ppqn = options.ppqn ?? 960;\n const tempo = options.tempo ?? 120;\n const beatsPerBar = options.beatsPerBar ?? 4;\n const lookahead = options.schedulerLookahead ?? 0.2;\n\n Transport._validateOptions(sampleRate, ppqn, tempo, beatsPerBar, lookahead);\n\n this._clock = new Clock(audioContext);\n this._scheduler = new Scheduler({\n lookahead,\n onLoop: (loopStartTime: number) => {\n this._clock.seekTo(loopStartTime);\n },\n });\n this._sampleTimeline = new SampleTimeline(sampleRate);\n this._tickTimeline = new TickTimeline(ppqn);\n this._tempoMap = new TempoMap(ppqn, tempo);\n\n this._initAudioGraph(audioContext, beatsPerBar);\n\n this._timer = new Timer(() => {\n const time = this._clock.getTime();\n if (this._endTime !== undefined && time >= this._endTime) {\n this.stop();\n return;\n }\n this._scheduler.advance(time);\n });\n }\n\n get audioContext(): AudioContext {\n return this._audioContext;\n }\n\n // --- Playback ---\n\n play(startTime?: number, endTime?: number): void {\n if (this._playing) return;\n\n if (startTime !== undefined) {\n this._clock.seekTo(startTime);\n }\n\n // Always reset scheduler to current position — after pause, the old\n // rightEdge is stale and clips whose startTime is before it won't\n // be picked up by generate().\n const currentTime = this._clock.getTime();\n this._scheduler.reset(currentTime);\n\n this._endTime = endTime;\n this._clock.start();\n\n // Re-create sources for clips spanning the current position.\n // After pause, silence() killed all active sources. generate() only\n // picks up clips whose startTime falls in the window, so clips that\n // started before the current position need mid-clip sources.\n this._clipPlayer.onPositionJump(currentTime);\n\n this._timer.start();\n this._playing = true;\n this._emit('play');\n }\n\n pause(): void {\n if (!this._playing) return;\n\n this._timer.stop();\n this._clock.stop();\n this._silenceAll();\n this._playing = false;\n this._emit('pause');\n }\n\n stop(): void {\n const wasPlaying = this._playing;\n this._timer.stop();\n this._clock.reset();\n this._scheduler.reset(0);\n this._silenceAll();\n this._playing = false;\n this._endTime = undefined;\n if (wasPlaying) {\n this._emit('stop');\n }\n }\n\n seek(time: number): void {\n const wasPlaying = this._playing;\n\n if (wasPlaying) {\n this._timer.stop();\n }\n\n this._silenceAll();\n this._clock.seekTo(time);\n this._scheduler.reset(time);\n // Clear stale endTime — seeking past a previous endTime shouldn't\n // cause immediate stop on the next play()\n this._endTime = undefined;\n\n if (wasPlaying) {\n this._clock.start();\n // Re-create sources for clips spanning the seek position\n this._clipPlayer.onPositionJump(time);\n this._timer.start();\n }\n }\n\n getCurrentTime(): number {\n return this._clock.getTime();\n }\n\n isPlaying(): boolean {\n return this._playing;\n }\n\n // --- Tracks ---\n\n setTracks(tracks: ClipTrack[]): void {\n // Dispose existing track nodes\n for (const node of this._trackNodes.values()) {\n node.dispose();\n }\n this._trackNodes.clear();\n this._soloedTrackIds.clear();\n this._mutedTrackIds.clear();\n\n this._tracks = tracks;\n\n // Create track nodes\n for (const track of tracks) {\n const trackNode = new TrackNode(track.id, this._audioContext);\n trackNode.setVolume(track.volume);\n trackNode.setPan(track.pan);\n trackNode.connectOutput(this._masterNode.input);\n this._trackNodes.set(track.id, trackNode);\n\n if (track.muted) {\n this._mutedTrackIds.add(track.id);\n }\n if (track.soloed) {\n this._soloedTrackIds.add(track.id);\n }\n }\n\n this._applyMuteState();\n this._clipPlayer.setTracks(tracks, this._trackNodes);\n }\n\n addTrack(track: ClipTrack): void {\n const trackNode = new TrackNode(track.id, this._audioContext);\n trackNode.setVolume(track.volume);\n trackNode.setPan(track.pan);\n trackNode.connectOutput(this._masterNode.input);\n this._trackNodes.set(track.id, trackNode);\n\n if (track.muted) {\n this._mutedTrackIds.add(track.id);\n }\n if (track.soloed) {\n this._soloedTrackIds.add(track.id);\n }\n\n this._tracks = [...this._tracks, track];\n this._applyMuteState();\n this._clipPlayer.setTracks(this._tracks, this._trackNodes);\n }\n\n removeTrack(trackId: string): void {\n const node = this._trackNodes.get(trackId);\n if (node) {\n node.dispose();\n this._trackNodes.delete(trackId);\n }\n this._soloedTrackIds.delete(trackId);\n this._mutedTrackIds.delete(trackId);\n this._tracks = this._tracks.filter((t) => t.id !== trackId);\n this._applyMuteState();\n this._clipPlayer.setTracks(this._tracks, this._trackNodes);\n }\n\n updateTrack(trackId: string, track: ClipTrack): void {\n this._tracks = this._tracks.map((t) => (t.id === trackId ? track : t));\n\n const node = this._trackNodes.get(trackId);\n if (node) {\n node.setVolume(track.volume);\n node.setPan(track.pan);\n }\n\n // Update mute/solo\n if (track.muted) {\n this._mutedTrackIds.add(trackId);\n } else {\n this._mutedTrackIds.delete(trackId);\n }\n if (track.soloed) {\n this._soloedTrackIds.add(trackId);\n } else {\n this._soloedTrackIds.delete(trackId);\n }\n\n this._applyMuteState();\n this._clipPlayer.updateTrack(trackId, track);\n }\n\n // --- Track Controls ---\n\n setTrackVolume(trackId: string, volume: number): void {\n const node = this._trackNodes.get(trackId);\n if (!node) {\n console.warn('[waveform-playlist] setTrackVolume: unknown trackId \"' + trackId + '\"');\n return;\n }\n node.setVolume(volume);\n }\n\n setTrackPan(trackId: string, pan: number): void {\n const node = this._trackNodes.get(trackId);\n if (!node) {\n console.warn('[waveform-playlist] setTrackPan: unknown trackId \"' + trackId + '\"');\n return;\n }\n node.setPan(pan);\n }\n\n setTrackMute(trackId: string, muted: boolean): void {\n if (muted) {\n this._mutedTrackIds.add(trackId);\n } else {\n this._mutedTrackIds.delete(trackId);\n }\n this._applyMuteState();\n }\n\n setTrackSolo(trackId: string, soloed: boolean): void {\n if (soloed) {\n this._soloedTrackIds.add(trackId);\n } else {\n this._soloedTrackIds.delete(trackId);\n }\n this._applyMuteState();\n }\n\n // --- Master ---\n\n setMasterVolume(volume: number): void {\n this._masterNode.setVolume(volume);\n }\n\n // --- Loop ---\n\n setLoop(enabled: boolean, start: number, end: number): void {\n if (enabled && start >= end) {\n console.warn(\n '[waveform-playlist] Transport.setLoop: start (' +\n start +\n ') must be less than end (' +\n end +\n ')'\n );\n return;\n }\n this._scheduler.setLoop(enabled, start, end);\n this._clipPlayer.setLoop(enabled, start, end);\n this._emit('loop');\n }\n\n // --- Tempo ---\n\n setTempo(bpm: number): void {\n this._tempoMap.setTempo(bpm);\n this._emit('tempochange');\n }\n\n getTempo(): number {\n return this._tempoMap.getTempo();\n }\n\n setBeatsPerBar(beats: number): void {\n this._metronomePlayer.setBeatsPerBar(beats);\n }\n\n // --- Metronome ---\n\n setMetronomeEnabled(enabled: boolean): void {\n this._metronomePlayer.setEnabled(enabled);\n }\n\n setMetronomeClickSounds(accent: AudioBuffer, normal: AudioBuffer): void {\n this._metronomePlayer.setClickSounds(accent, normal);\n }\n\n // --- Effects Hook ---\n\n connectTrackOutput(trackId: string, node: AudioNode): void {\n const trackNode = this._trackNodes.get(trackId);\n if (!trackNode) {\n console.warn('[waveform-playlist] connectTrackOutput: unknown trackId \"' + trackId + '\"');\n return;\n }\n trackNode.connectEffects(node);\n }\n\n disconnectTrackOutput(trackId: string): void {\n const trackNode = this._trackNodes.get(trackId);\n if (!trackNode) {\n console.warn('[waveform-playlist] disconnectTrackOutput: unknown trackId \"' + trackId + '\"');\n return;\n }\n trackNode.disconnectEffects();\n }\n\n // --- Events ---\n\n on<K extends TransportEventType>(event: K, cb: TransportEvents[K]): void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set());\n }\n this._listeners.get(event)!.add(cb);\n }\n\n off<K extends TransportEventType>(event: K, cb: TransportEvents[K]): void {\n this._listeners.get(event)?.delete(cb);\n }\n\n // --- Dispose ---\n\n dispose(): void {\n this.stop();\n for (const node of this._trackNodes.values()) {\n node.dispose();\n }\n this._trackNodes.clear();\n this._masterNode.dispose();\n this._listeners.clear();\n }\n\n // --- Private ---\n\n private static _validateOptions(\n sampleRate: number,\n ppqn: number,\n tempo: number,\n beatsPerBar: number,\n lookahead: number\n ): void {\n if (sampleRate <= 0) {\n throw new Error(\n '[waveform-playlist] Transport: sampleRate must be positive, got ' + sampleRate\n );\n }\n if (ppqn <= 0 || !Number.isInteger(ppqn)) {\n throw new Error(\n '[waveform-playlist] Transport: ppqn must be a positive integer, got ' + ppqn\n );\n }\n if (tempo <= 0) {\n throw new Error('[waveform-playlist] Transport: tempo must be positive, got ' + tempo);\n }\n if (beatsPerBar <= 0 || !Number.isInteger(beatsPerBar)) {\n throw new Error(\n '[waveform-playlist] Transport: beatsPerBar must be a positive integer, got ' + beatsPerBar\n );\n }\n if (lookahead <= 0) {\n throw new Error(\n '[waveform-playlist] Transport: schedulerLookahead must be positive, got ' + lookahead\n );\n }\n }\n\n private _initAudioGraph(audioContext: AudioContext, beatsPerBar: number): void {\n this._masterNode = new MasterNode(audioContext);\n this._masterNode.output.connect(audioContext.destination);\n\n const toAudioTime = (transportTime: number) => this._clock.toAudioTime(transportTime);\n\n this._clipPlayer = new ClipPlayer(audioContext, this._sampleTimeline, toAudioTime);\n this._metronomePlayer = new MetronomePlayer(\n audioContext,\n this._tempoMap,\n this._tickTimeline,\n this._masterNode.input,\n toAudioTime\n );\n this._metronomePlayer.setBeatsPerBar(beatsPerBar);\n\n this._scheduler.addListener(this._clipPlayer);\n this._scheduler.addListener(this._metronomePlayer);\n }\n\n private _silenceAll(): void {\n this._clipPlayer.silence();\n this._metronomePlayer.silence();\n }\n\n private _applyMuteState(): void {\n const hasSolo = this._soloedTrackIds.size > 0;\n\n for (const [trackId, node] of this._trackNodes) {\n const isExplicitlyMuted = this._mutedTrackIds.has(trackId);\n const isSoloMuted = hasSolo && !this._soloedTrackIds.has(trackId);\n\n // Explicit mute takes precedence — a track that is both soloed AND muted stays muted\n node.setMute(isExplicitlyMuted || isSoloMuted);\n }\n }\n\n private _emit(event: TransportEventType): void {\n const listeners = this._listeners.get(event);\n if (listeners) {\n for (const cb of listeners) {\n try {\n cb();\n } catch (err) {\n console.warn(\n '[waveform-playlist] Transport \"' + event + '\" listener threw:',\n String(err)\n );\n }\n }\n }\n }\n}\n","import type { ClipTrack } from '@waveform-playlist/core';\nimport type { PlayoutAdapter } from '@waveform-playlist/engine';\nimport { Transport } from './transport';\nimport type { TransportOptions } from './types';\n\nexport class NativePlayoutAdapter implements PlayoutAdapter {\n private _transport: Transport;\n private _audioContext: AudioContext;\n\n constructor(audioContext: AudioContext, options?: TransportOptions) {\n this._audioContext = audioContext;\n this._transport = new Transport(audioContext, options);\n }\n\n get transport(): Transport {\n return this._transport;\n }\n\n async init(): Promise<void> {\n if (this._audioContext.state === 'closed') {\n throw new Error('[waveform-playlist] Cannot init: AudioContext is closed');\n }\n if (this._audioContext.state === 'suspended') {\n await this._audioContext.resume();\n }\n }\n\n setTracks(tracks: ClipTrack[]): void {\n this._transport.setTracks(tracks);\n }\n\n addTrack(track: ClipTrack): void {\n this._transport.addTrack(track);\n }\n\n removeTrack(trackId: string): void {\n this._transport.removeTrack(trackId);\n }\n\n updateTrack(trackId: string, track: ClipTrack): void {\n this._transport.updateTrack(trackId, track);\n }\n\n play(startTime: number, endTime?: number): void {\n this._transport.play(startTime, endTime);\n }\n\n pause(): void {\n this._transport.pause();\n }\n\n stop(): void {\n this._transport.stop();\n }\n\n seek(time: number): void {\n this._transport.seek(time);\n }\n\n getCurrentTime(): number {\n return this._transport.getCurrentTime();\n }\n\n isPlaying(): boolean {\n return this._transport.isPlaying();\n }\n\n setMasterVolume(volume: number): void {\n this._transport.setMasterVolume(volume);\n }\n\n setTrackVolume(trackId: string, volume: number): void {\n this._transport.setTrackVolume(trackId, volume);\n }\n\n setTrackMute(trackId: string, muted: boolean): void {\n this._transport.setTrackMute(trackId, muted);\n }\n\n setTrackSolo(trackId: string, soloed: boolean): void {\n this._transport.setTrackSolo(trackId, soloed);\n }\n\n setTrackPan(trackId: string, pan: number): void {\n this._transport.setTrackPan(trackId, pan);\n }\n\n setLoop(enabled: boolean, start: number, end: number): void {\n this._transport.setLoop(enabled, start, end);\n }\n\n dispose(): void {\n this._transport.dispose();\n }\n}\n"],"mappings":"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","names":[]}