ez-web-audio
Version:
Making the Web Audio API super EZ since 2024.
268 lines • 8.63 kB
TypeScript
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