UNPKG

ez-web-audio

Version:

Making the Web Audio API super EZ since 2024.

268 lines 8.63 kB
import { Beat } from './beat'; import { Connectable } from './interfaces/connectable'; import { Playable } from './interfaces/playable'; import { SamplerOptions, Sampler } from './sampler'; import { BeatTrackEventMap } from './events/event-types'; export interface BeatTrackOptions extends SamplerOptions { numBeats?: number; duration?: number; /** * @method wrapWith * wrapWith allows you to run a function on each beat as it is created * This function must accept a beat and return a beat. An example use-case * appears in the docs site in the "Multisampled Drum Machine" example where * this method is used to wrap each beat in an nx-js observable proxy. * * @param beat * @returns */ wrapWith?: (beat: Beat) => Beat; } /** * Drum machine lane with rhythmic beat patterns. * * BeatTrack manages an array of Beat instances for creating drum patterns. * It extends Sampler for round-robin sample variation and adds tempo-synced * playback with beat events for visual synchronization. * * @example * ```typescript * import { createBeatTrack } from 'ez-web-audio' * * const kick = await createBeatTrack(['kick.mp3'], { numBeats: 8 }) * * // Set a basic 4-on-the-floor pattern * kick.beats[0].active = true // beat 1 * kick.beats[2].active = true // beat 3 * kick.beats[4].active = true // beat 5 * kick.beats[6].active = true // beat 7 * * kick.playBeats(120, 1/4) // Play quarter notes at 120 BPM * * // Listen for beat events * kick.on('beat', (e) => { * console.log(`Beat ${e.detail.beatIndex}`) * }) * ``` */ export declare class BeatTrack extends Sampler { private audioContext; private eventTarget; private scheduleAheadTime; private schedulerInterval; private nextBeatTime; private currentBeatIndex; private timerID; private currentTempo; private noteType; private pausedBeatIndex; private pausedBeatTime; constructor(audioContext: AudioContext, sounds: (Playable & Connectable)[], opts?: BeatTrackOptions); /** * Optional function to wrap each beat as it's created (e.g., with observables). * @internal */ private wrapWith?; /** * Number of beats in this track. * @default 4 */ numBeats: number; /** * How long (in milliseconds) the `isPlaying` flag stays true after a beat plays. * Useful for visual feedback in the UI. * @default 100 */ duration: number; /** * Array of Beat instances in this track. * * The array length always matches `numBeats`. Beats are reused when the * count changes, preserving their `active` state. * * @example * ```typescript * // Toggle individual beats * track.beats[0].active = true * track.beats[1].active = false * * // Check all beat states * track.beats.forEach((beat, i) => { * console.log(`Beat ${i}: ${beat.active ? 'on' : 'off'}`) * }) * ``` */ get beats(): Beat[]; /** * Start playing all beats in the pattern continuously. * * Starts a lookahead scheduler that triggers beats at precise audio times. * Emits 'beat' events for UI synchronization. * * @param bpm - Tempo in beats per minute * @param noteType - Rhythmic length of each beat (e.g., 1/4 for quarter notes, 1/8 for eighths) * * @example * ```typescript * track.playBeats(120, 1/4) // 120 BPM, quarter notes * track.playBeats(140, 1/8) // 140 BPM, eighth notes * ``` */ playBeats(bpm: number, noteType: number): void; /** * Start playing only active beats in the pattern continuously. * * Same as playBeats(), but only plays beats where `active === true`. * Inactive beats become rests (silence), maintaining timing. * * @param bpm - Tempo in beats per minute * @param noteType - Rhythmic length of each beat/rest * * @example * ```typescript * // Set up a pattern with rests * track.beats[0].active = true * track.beats[2].active = true * track.playActiveBeats(120, 1/4) // Only beats 0 and 2 play * ``` */ playActiveBeats(bpm: number, noteType: number): void; /** * Stop playback and reset to the beginning. * * Emits a 'stop' event. Use pause() instead if you want to resume later. * * @example * ```typescript * track.stop() * track.on('stop', () => console.log('Stopped')) * ``` */ stop(): void; /** * Pause playback at the current position. * * Emits a 'pause' event with the current beat index. * Use resume() to continue from where you left off. * * @example * ```typescript * track.pause() * // later... * track.resume() * ``` */ pause(): void; /** * Resume playback from where it was paused. * * Emits a 'resume' event with the beat index where playback resumes. * Has no effect if not paused. * * @example * ```typescript * track.pause() * // ...user clicks play button... * track.resume() // continues from paused position * ``` */ resume(): void; /** * Change the tempo while playing. * * The new tempo takes effect on the next scheduled beat. * * @param bpm - New tempo in beats per minute * * @example * ```typescript * track.playBeats(120, 1/4) * // later, speed up... * track.setTempo(140) * ``` */ setTempo(bpm: number): void; /** * Lookahead scheduler that schedules beats 100ms ahead. * @internal */ private scheduler; /** * Schedule a single beat and emit the beat event. * @internal */ private scheduleBeat; /** * Advance to the next beat in the pattern using current tempo. * @internal */ private advanceToNextBeat; /** * The underlying method for playing beats at calculated intervals. * @internal */ protected callPlayMethodOnBeats(method: 'ifActivePlayIn' | 'playIn', bpm: number, noteType?: number): void; /** * Emit a typed event with the given detail. * @internal */ protected emit<K extends keyof BeatTrackEventMap>(type: K, detail: BeatTrackEventMap[K]['detail']): void; /** * Add a typed event listener for BeatTrack lifecycle events. * * @param type - Event type: 'beat', 'stop', 'pause', 'resume' * @param listener - Handler function * @param options - Standard addEventListener options */ addEventListener<K extends keyof BeatTrackEventMap>(type: K, listener: (event: BeatTrackEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; /** * Remove a typed event listener. * * @param type - Event type to unsubscribe from * @param listener - Handler function to remove * @param options - Standard removeEventListener options */ removeEventListener<K extends keyof BeatTrackEventMap>(type: K, listener: (event: BeatTrackEventMap[K]) => void, options?: boolean | EventListenerOptions): void; /** * Subscribe to an event. Supports chaining. * * @param type - Event type: 'beat', 'stop', 'pause', 'resume' * @param listener - Handler function * @returns this for chaining * * @example * ```typescript * track.on('beat', (e) => { * console.log(`Beat ${e.detail.beatIndex}`) * highlightBeat(e.detail.beatIndex) * }).on('stop', () => { * console.log('Stopped') * }) * ``` */ on<K extends keyof BeatTrackEventMap>(type: K, listener: (event: BeatTrackEventMap[K]) => void): this; /** * Unsubscribe from an event. Supports chaining. * * @param type - Event type to unsubscribe from * @param listener - Handler function to remove * @returns this for chaining */ off<K extends keyof BeatTrackEventMap>(type: K, listener: (event: BeatTrackEventMap[K]) => void): this; /** * Subscribe to an event once. Handler is removed after first invocation. * * @param type - Event type to listen for * @param listener - Handler function (called only once) * @returns this for chaining * * @example * ```typescript * track.once('stop', () => { * console.log('Track stopped for the first time') * }) * ``` */ once<K extends keyof BeatTrackEventMap>(type: K, listener: (event: BeatTrackEventMap[K]) => void): this; } //# sourceMappingURL=beat-track.d.ts.map