wave-roll
Version:
JavaScript Library for Comparative MIDI Piano-Roll Visualization
167 lines • 5.35 kB
TypeScript
/**
* Sampler Manager for MIDI playback
* Handles Tone.js sampler creation, loading, and playback
*/
import * as Tone from "tone";
import { NoteData } from "@/lib/midi/types";
export interface SamplerTrack {
sampler: Tone.Sampler;
delay: Tone.Delay | null;
gate: Tone.Gain;
panner: Tone.Panner;
muted: boolean;
}
export declare class SamplerManager {
/** Legacy single sampler (used for single-file players) */
private sampler;
/** Global panner for legacy single-sampler path */
private panner;
/** Hard gate for legacy single-sampler path */
private gate;
/** Map of fileId -> {sampler, panner, muted} for multi-file playback */
private trackSamplers;
/** Current Tone.Part for scheduling note events */
private part;
/** Notes to be played */
private notes;
/** MIDI manager reference */
private midiManager;
/** Alignment delay in seconds to compensate downstream (e.g., WAV PitchShift) latency */
private alignmentDelaySec;
constructor(notes: NoteData[], midiManager?: any);
private getTrack;
private applySamplerVolume;
private applyPannerPan;
/** Return notes filtered to intersect the [loopStart, loopEnd) window, or all if window inactive. */
private filterNotesByLoopWindow;
/** Compute visual->transport scale factor. */
private computeScaleToTransport;
/** Map notes to Part events without fileId. */
private notesToEvents;
/** Map notes to Part events with fileId. */
private notesToEventsWithFileId;
/** Build Tone.Part from events and callback, configure loop settings. */
private buildPart;
/**
* Initialize samplers - either multi-track or legacy single sampler
*/
initialize(options: {
soundFont?: string;
volume?: number;
}): Promise<void>;
/**
* Set up per-track samplers for multi-file playback
* @returns true if multi-file setup succeeded, false for fallback
*/
private setupTrackSamplers;
/**
* Fallback: Set up legacy single sampler
*/
private setupLegacySampler;
/**
* Create note part for Tone.js scheduling
*/
setupNotePart(loopStartVisual?: number | null, loopEndVisual?: number | null, options?: {
repeat?: boolean;
duration?: number;
tempo?: number;
originalTempo?: number;
}): void;
private setupMultiTrackPart;
private setupLegacyPart;
/**
* Start the part at specified offset
*/
startPart(time: string | number, offset?: number): void;
/**
* Stop and cancel the part
*/
stopPart(): void;
/**
* Restart the part for seamless looping
* This avoids recreating the Part which can cause gaps
*/
restartPartAtLoop(): void;
/**
* Set volume for all samplers
*/
setVolume(volume: number): void;
/**
* Set pan for all samplers
*/
setPan(pan: number): void;
/**
* Set alignment delay in seconds for all sampler outputs (compensate external FX latency).
*/
setAlignmentDelaySec(delaySec: number): void;
/**
* Set pan for a specific file
*/
setFilePan(fileId: string, pan: number): void;
/**
* Set mute state for a specific file
*/
setFileMute(fileId: string, mute: boolean): void;
/**
* Ensure the specified track is audible. If its sampler volume is effectively
* silent (<= SILENT_DB), lift it to the provided masterVolume.
*/
ensureTrackAudible(fileId: string, masterVolume: number): void;
/**
* Retrigger any notes that are currently sustaining at `currentTime` for the given file.
* Useful when a track is unmuted while the transport is already running so that
* long-held notes become audible immediately without waiting for the next onset.
*/
retriggerHeldNotes(fileId: string, currentTime: number): void;
/**
* Retrigger held notes for all unmuted tracks at the current time
* Useful after seeking to ensure long notes are audible at the new position
*/
retriggerAllUnmutedHeldNotes(currentTime: number): void;
/**
* Set volume for a specific file
*/
setFileVolume(fileId: string, volume: number, masterVolume: number): void;
/**
* Get file mute states
*/
getFileMuteStates(): Map<string, boolean>;
/**
* Get file volume states
*/
getFileVolumeStates(): Map<string, number>;
/**
* Check if all tracks have zero volume
*/
areAllTracksZeroVolume(): boolean;
/**
* Check if all tracks are muted
*/
areAllTracksMuted(): boolean;
/**
* Clean up resources
*/
destroy(): void;
/**
* Immediately stop/kill any currently sounding voices to prevent tail/bleed.
* Best-effort: tries Sampler/PolySynth-specific release helpers if available.
*/
stopAllVoicesImmediate(): void;
/**
* Get the current part instance
*/
getPart(): Tone.Part | null;
/**
* Hard mute all track gates to instantly silence any residual sound.
*/
hardMuteAllGates(): void;
/**
* Unmute all track gates.
*/
hardUnmuteAllGates(): void;
/**
* Check if samplers are initialized
*/
isInitialized(): boolean;
}
//# sourceMappingURL=sampler-manager.d.ts.map