@kidlib/web-audio 0.1.1 → 0.1.3

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.
package/dist/index.d.ts CHANGED
@@ -12,9 +12,9 @@ declare const AudioRecorderState: {
12
12
 
13
13
  declare type AudioRecorderState = (typeof AudioRecorderState)[keyof typeof AudioRecorderState];
14
14
 
15
- declare type BaseNodeType = 'instrument' | 'voice' | 'fx' | 'param' | 'container' | 'recorder' | 'audiograph';
15
+ declare type BaseNodeType = "instrument" | "voice" | "fx" | "param" | "container" | "recorder" | "audiograph";
16
16
 
17
- declare type BusNodeName = 'input' | 'output' | 'dryMix' | 'wetMix' | 'hpf' | 'lpf' | 'distortion' | 'feedback' | 'reverb' | 'compressor' | 'limiter' | 'delay';
17
+ declare type BusNodeName = "input" | "output" | "dryMix" | "wetMix" | "hpf" | "lpf" | "distortion" | "feedback" | "reverb" | "compressor" | "limiter" | "delay";
18
18
 
19
19
  declare type BusNodeTypeMap = {
20
20
  input: ILibAudioNode<GainNode>;
@@ -36,7 +36,7 @@ declare type BusSendName = `${BusNodeName}_send`;
36
36
  /** False in Safari — AudioContext.setSinkId is Chromium/Firefox only */
37
37
  export declare function canSetOutputDevice(): boolean;
38
38
 
39
- declare type ContainerType = 'pool' | 'chain' | 'audiolib';
39
+ declare type ContainerType = "pool" | "chain" | "audiolib";
40
40
 
41
41
  /**
42
42
  * Creates and initializes a new audio recorder
@@ -144,7 +144,7 @@ export declare class CustomEnvelope implements LibNode {
144
144
  dispose(): void;
145
145
  }
146
146
 
147
- declare type CustomFxType = 'feedback-delay' | 'harmonic-feedback' | 'distortion' | 'dattorro-reverb';
147
+ declare type CustomFxType = "feedback-delay" | "harmonic-feedback" | "distortion" | "dattorro-reverb";
148
148
 
149
149
  declare type CustomLibWaveform = (typeof CUSTOM_WAVEFORMS)[number];
150
150
 
@@ -222,7 +222,7 @@ declare class DattorroReverb implements ILibAudioNode {
222
222
  setParam(name: string, value: number, time?: number): void;
223
223
  getAudioParam(name: string): AudioParam | null;
224
224
  setAmountMacro(amount: number): void;
225
- setPreset(preset?: 'room' | 'church' | 'freeze' | 'ether' | 'default', rampTime?: number): void;
225
+ setPreset(preset?: "room" | "church" | "freeze" | "ether" | "default", rampTime?: number): void;
226
226
  /**
227
227
  DIFFUSION PARAMETER (0.0 - 1.0, default: 0.7)
228
228
  Controls reverb density and scatter. Higher = more complex tail.
@@ -273,7 +273,7 @@ declare interface DefaultWorkletConfig extends WorkletConfig {
273
273
  message: WorkletMessage;
274
274
  }
275
275
 
276
- declare type DelayCharacter = 'clean' | 'bitCrushed' | 'filtered';
276
+ declare type DelayCharacter = "clean" | "bitCrushed" | "filtered";
277
277
 
278
278
  declare type DelayConfig = {
279
279
  params: DelayParams;
@@ -297,8 +297,8 @@ declare type DistortionConfig = {
297
297
  };
298
298
 
299
299
  declare type DistortionMsg = {
300
- type: 'setLimitingMode';
301
- mode: 'soft-clipping' | 'hard-clipping';
300
+ type: "setLimitingMode";
301
+ mode: "soft-clipping" | "hard-clipping";
302
302
  };
303
303
 
304
304
  declare type DistortionParams = {
@@ -315,7 +315,7 @@ export declare class EnvelopeData {
315
315
  #private;
316
316
  points: EnvelopePoint[];
317
317
  constructor(points: EnvelopePoint[] | undefined, valueRange: [number, number] | undefined, durationSeconds: number, sustainIdx?: number, releaseIdx?: number);
318
- addPoint(time: number, value: number, curve?: 'linear' | 'exponential'): void;
318
+ addPoint(time: number, value: number, curve?: "linear" | "exponential"): void;
319
319
  updatePoint(index: number, time?: number, value?: number): void;
320
320
  updateStartPoint: (time?: number, value?: number) => void;
321
321
  updateEndPoint: (time?: number, value?: number) => void;
@@ -339,10 +339,10 @@ export declare class EnvelopeData {
339
339
  export declare type EnvelopePoint = {
340
340
  time: number;
341
341
  value: number;
342
- curve?: 'linear' | 'exponential';
342
+ curve?: "linear" | "exponential";
343
343
  };
344
344
 
345
- export declare type EnvelopeType = 'amp-env' | 'pitch-env' | 'filter-env' | 'loop-env' | 'default-env';
345
+ export declare type EnvelopeType = "amp-env" | "pitch-env" | "filter-env" | "loop-env" | "default-env";
346
346
 
347
347
  declare type FbDelayConfig = {
348
348
  params: FbDelayParams;
@@ -350,14 +350,14 @@ declare type FbDelayConfig = {
350
350
  };
351
351
 
352
352
  declare type FbDelayMsg = {
353
- type: 'setAutoGain';
353
+ type: "setAutoGain";
354
354
  enabled: boolean;
355
355
  amount: number;
356
356
  } | {
357
- type: 'triggerDecay';
357
+ type: "triggerDecay";
358
358
  baseFeedbackAmount: number;
359
359
  } | {
360
- type: 'stopDecay';
360
+ type: "stopDecay";
361
361
  };
362
362
 
363
363
  declare type FbDelayParams = {
@@ -495,13 +495,13 @@ declare class InstrumentBus implements ILibAudioNode {
495
495
  /**
496
496
  * Set the character modes for the delay processor, in the order in which to process (e.g. ['filtered', 'bitCrushed'])
497
497
  */
498
- setDelayCharacter(modes: Array<'clean' | 'bitCrushed' | 'filtered'>): this;
498
+ setDelayCharacter(modes: Array<"clean" | "bitCrushed" | "filtered">): this;
499
499
  setReverbSize(amount: number): this;
500
500
  setReverbDecay(decay: number): this;
501
501
  setDistortionMacro(amount: number): void;
502
502
  setDrive(amount: number): this;
503
503
  setClippingMacro(amount: number): this;
504
- setClippingMode(mode: 'soft-clipping' | 'hard-clipping'): void;
504
+ setClippingMode(mode: "soft-clipping" | "hard-clipping"): void;
505
505
  setFeedbackAmount(amount: number): this;
506
506
  setFeedbackPitchScale(value: number): this;
507
507
  setFeedbackDecay(amount: number): this;
@@ -551,11 +551,11 @@ declare class InstrumentBus implements ILibAudioNode {
551
551
  onMessage(type: string, handler: MessageHandler<Message>): () => void;
552
552
  }
553
553
 
554
- declare type InstrumentType = 'sample-player' | 'synth';
554
+ declare type InstrumentType = "sample-player" | "synth";
555
555
 
556
556
  export declare type KeyMap = Record<string, number>;
557
557
 
558
- export declare type KeymapKey = 'piano' | 'major' | 'minor' | 'pentatonic' | 'chromatic';
558
+ export declare type KeymapKey = "piano" | "major" | "minor" | "pentatonic" | "chromatic";
559
559
 
560
560
  export declare const keymaps: Record<KeymapKey, KeyMap>;
561
561
 
@@ -629,7 +629,7 @@ declare class MacroParam {
629
629
  init(): Promise<void>;
630
630
  addTarget(targetParam: AudioParam, paramType: string, scaleFactor?: number): this;
631
631
  ramp(targetValue: number, duration: number, constant: number, options?: {
632
- method?: 'exponential' | 'linear';
632
+ method?: "exponential" | "linear";
633
633
  debounceMs?: number;
634
634
  onComplete?: () => void;
635
635
  onCompleteDelayMs?: number;
@@ -678,7 +678,7 @@ declare interface Message {
678
678
 
679
679
  declare type MessageHandler<T> = (data: T) => void;
680
680
 
681
- declare type NativeAudioNode = 'AudioWorkletNode' | 'GainNode' | 'BiquadFilterNode' | 'AudioBufferSourceNode' | 'DynamicsCompressorNode';
681
+ declare type NativeAudioNode = "AudioWorkletNode" | "GainNode" | "BiquadFilterNode" | "AudioBufferSourceNode" | "DynamicsCompressorNode";
682
682
 
683
683
  declare type NodeID_2 = string;
684
684
 
@@ -772,12 +772,12 @@ export declare class Recorder implements LibNode {
772
772
  }
773
773
 
774
774
  export declare type RecorderInput = {
775
- type: 'microphone';
775
+ type: "microphone";
776
776
  deviceId?: string;
777
777
  } | {
778
- type: 'display';
778
+ type: "display";
779
779
  } | {
780
- type: 'audio-node';
780
+ type: "audio-node";
781
781
  node: AudioNode;
782
782
  };
783
783
 
@@ -788,8 +788,6 @@ declare type RecorderOptions = {
788
788
  autoStop: boolean;
789
789
  stopThreshold: number;
790
790
  silenceTimeoutMs: number;
791
- preprocess: boolean;
792
- preprocessOptions: object;
793
791
  };
794
792
 
795
793
  export declare type RecorderStartOptions = Partial<RecorderOptions> & {
@@ -798,20 +796,20 @@ export declare type RecorderStartOptions = Partial<RecorderOptions> & {
798
796
 
799
797
  declare const ROOT_NOTES: {
800
798
  readonly C: 0;
801
- readonly 'C#': 1;
799
+ readonly "C#": 1;
802
800
  readonly Db: 1;
803
801
  readonly D: 2;
804
- readonly 'D#': 3;
802
+ readonly "D#": 3;
805
803
  readonly Eb: 3;
806
804
  readonly E: 4;
807
805
  readonly F: 5;
808
- readonly 'F#': 6;
806
+ readonly "F#": 6;
809
807
  readonly Gb: 6;
810
808
  readonly G: 7;
811
- readonly 'G#': 8;
809
+ readonly "G#": 8;
812
810
  readonly Ab: 8;
813
811
  readonly A: 9;
814
- readonly 'A#': 10;
812
+ readonly "A#": 10;
815
813
  readonly Bb: 10;
816
814
  readonly B: 11;
817
815
  };
@@ -825,6 +823,7 @@ export declare class SamplePlayer implements ILibInstrumentNode {
825
823
  readonly nodeId: NodeID_2;
826
824
  readonly nodeType: "sample-player";
827
825
  readonly context: AudioContext;
826
+ static readonly MAX_LAYERS = 4;
828
827
  randomizeVelocity: boolean;
829
828
  voicePool: SampleVoicePool;
830
829
  outBus: InstrumentBus;
@@ -845,13 +844,24 @@ export declare class SamplePlayer implements ILibInstrumentNode {
845
844
  get output(): GainNode;
846
845
  get now(): number;
847
846
  get initialized(): boolean;
848
- getMacrosAudioParam(paramName: 'loopStart' | 'loopEnd'): AudioParam;
849
- getMacro(paramName: 'loopStart' | 'loopEnd'): MacroParam;
847
+ getMacrosAudioParam(paramName: "loopStart" | "loopEnd"): AudioParam;
848
+ getMacro(paramName: "loopStart" | "loopEnd"): MacroParam;
850
849
  setModulationAmount: (modType: "AM" | "FM", amount: number) => void;
851
- setModulationWaveform(modType?: 'AM' | 'FM', waveform?: CustomLibWaveform | OscillatorType | PeriodicWave, customWaveOptions?: WaveformOptions): void;
852
- syncLFOsToNoteFreq(lfoId: 'gain-lfo' | 'pitch-lfo', enabled: boolean): void;
850
+ setModulationWaveform(modType?: "AM" | "FM", waveform?: CustomLibWaveform | OscillatorType | PeriodicWave, customWaveOptions?: WaveformOptions): void;
851
+ syncLFOsToNoteFreq(lfoId: "gain-lfo" | "pitch-lfo", enabled: boolean): void;
853
852
  freezeActiveVoices(freeze: boolean): this;
853
+ /**
854
+ * Load a single sample. Equivalent to `loadLayers([buffer])`: any previously
855
+ * loaded extra layers are cleared.
856
+ */
854
857
  loadSample(buffer: AudioBuffer | ArrayBuffer, modSampleRate?: number, preprocessOptions?: Partial<PreProcessOptions>): Promise<AudioBuffer | null>;
858
+ /**
859
+ * Replace the whole layer set. Layers are summed inside the voice worklet at
860
+ * one shared playhead, so they play in unison and layer 0 is the authority
861
+ * for duration, loop points, start/end and zero crossings. Layers shorter
862
+ * than layer 0 fall silent at their own end; longer ones are truncated.
863
+ */
864
+ loadLayers(buffers: (AudioBuffer | ArrayBuffer)[], modSampleRate?: number, preprocessOptions?: Partial<PreProcessOptions>): Promise<AudioBuffer[] | null>;
855
865
  cropSample(startSeconds?: number, endSeconds?: number, fadeMs?: number): Promise<AudioBuffer | null>;
856
866
  detectPitch(buffer: AudioBuffer): Promise<{
857
867
  frequency: number;
@@ -888,7 +898,7 @@ export declare class SamplePlayer implements ILibInstrumentNode {
888
898
  setSustainPedal(pressed: boolean): this;
889
899
  sustainPedalOn: () => this;
890
900
  sustainPedalOff: () => this;
891
- setPlaybackDirection(direction: 'forward' | 'reverse'): this;
901
+ setPlaybackDirection(direction: "forward" | "reverse"): this;
892
902
  setLoopDurationDriftAmount(amount: number): this;
893
903
  setPanDriftEnabled: (enabled: boolean) => this;
894
904
  setTimestretchEnabled: (enabled: boolean) => this;
@@ -903,7 +913,7 @@ export declare class SamplePlayer implements ILibInstrumentNode {
903
913
  setKeytrackLoopAmount(amount: number): this;
904
914
  getKeytrackLoopAmount: () => number;
905
915
  get tempo(): number;
906
- setLoopPoint(loopPoint: 'start' | 'end', loopStartSeconds: number, loopEndSeconds: number, rampDuration?: number): this;
916
+ setLoopPoint(loopPoint: "start" | "end", loopStartSeconds: number, loopEndSeconds: number, rampDuration?: number): this;
907
917
  scrollLoopPoints(loopStart: number, loopEnd: number): this;
908
918
  setParam(name: string, value: number): this;
909
919
  applyParams(params: SamplerParamPatch): this;
@@ -941,7 +951,7 @@ export declare class SamplePlayer implements ILibInstrumentNode {
941
951
  setFeedbackDecay(value: number): void;
942
952
  setFeedbackLowpassCutoff(freqHz: number): void;
943
953
  setFeedbackAmount: (amount: number) => void;
944
- setFeedbackMode(mode: 'monophonic' | 'polyphonic' | 'double-trouble'): void;
954
+ setFeedbackMode(mode: "monophonic" | "polyphonic" | "double-trouble"): void;
945
955
  setFeedbackPitchScale(value: number): void;
946
956
  get mainOut(): GainNode;
947
957
  get outputBus(): InstrumentBus;
@@ -956,6 +966,8 @@ export declare class SamplePlayer implements ILibInstrumentNode {
956
966
  get loopEnd(): number;
957
967
  get isLoaded(): boolean;
958
968
  get audiobuffer(): AudioBuffer | null;
969
+ /** All loaded layers. Index 0 is the authority layer (=== `audiobuffer`). */
970
+ get layers(): readonly AudioBuffer[];
959
971
  dispose(): void;
960
972
  }
961
973
 
@@ -1035,6 +1047,13 @@ declare class SampleVoice {
1035
1047
  });
1036
1048
  init(): Promise<void>;
1037
1049
  loadBuffer(buffer: AudioBuffer, zeroCrossings?: number[]): Promise<boolean>;
1050
+ /**
1051
+ * Replace the whole layer set. Layers are summed at one shared playhead, so
1052
+ * layer 0 is the authority for duration and all range math; the rest only
1053
+ * add samples. A layer at the wrong sample rate is dropped on its own,
1054
+ * leaving the others playable, except layer 0: losing it fails the load.
1055
+ */
1056
+ loadLayers(buffers: AudioBuffer[], zeroCrossings?: number[]): Promise<boolean>;
1038
1057
  freeze(freeze: boolean): this;
1039
1058
  setGlideTime(seconds: number): void;
1040
1059
  trigger(options: {
@@ -1052,8 +1071,8 @@ declare class SampleVoice {
1052
1071
  secondsFromNow?: number | undefined;
1053
1072
  }): this;
1054
1073
  stop(timestamp?: number): this;
1055
- setModulationAmount(modType: 'AM' | 'FM', amount: number): this;
1056
- setModulationWaveform(modType?: 'AM' | 'FM', waveform?: CustomLibWaveform | OscillatorType | PeriodicWave, customWaveOptions?: WaveformOptions): this;
1074
+ setModulationAmount(modType: "AM" | "FM", amount: number): this;
1075
+ setModulationWaveform(modType?: "AM" | "FM", waveform?: CustomLibWaveform | OscillatorType | PeriodicWave, customWaveOptions?: WaveformOptions): this;
1057
1076
  enableEnvelope: (envType: EnvelopeType) => void;
1058
1077
  disableEnvelope: (envType: EnvelopeType) => void;
1059
1078
  setEnvelopeTimeScale: (envType: EnvelopeType, timeScale: number) => void;
@@ -1125,7 +1144,7 @@ declare class SampleVoice {
1125
1144
  glideTime?: number;
1126
1145
  cancelPrevious?: boolean;
1127
1146
  }): this;
1128
- setPlaybackDirection(direction: 'forward' | 'reverse'): this;
1147
+ setPlaybackDirection(direction: "forward" | "reverse"): this;
1129
1148
  setLoopDurationDriftAmount(amount: number): this;
1130
1149
  setPanDriftEnabled: (enabled: boolean) => this;
1131
1150
  setTimestretchEnabled: (enabled: boolean) => this;
@@ -1144,7 +1163,7 @@ declare class SampleVoicePool implements LibNode {
1144
1163
  disconnect(): void;
1145
1164
  onMessage(type: string, handler: MessageHandler<Message>): () => void;
1146
1165
  sendUpstreamMessage(type: string, data: any): this;
1147
- setBuffer(buffer: AudioBuffer, zeroCrossings?: number[]): this;
1166
+ setLayers(buffers: AudioBuffer[], zeroCrossings?: number[]): this;
1148
1167
  allocate(available?: Set<SampleVoice>, releasing?: Set<SampleVoice>): SampleVoice | undefined;
1149
1168
  prevMidiNote: number;
1150
1169
  noteOn(midiNote: MidiValue, velocity?: MidiValue, secondsFromNow?: number, glideTime?: number): MidiValue | null;
@@ -1190,7 +1209,7 @@ declare const SCALE_PATTERNS: {
1190
1209
  export declare function setAudioOutputDevice(deviceId: string): Promise<void>;
1191
1210
 
1192
1211
  declare type SetDelayCharacterMsg = {
1193
- type: 'setCharacter';
1212
+ type: "setCharacter";
1194
1213
  modes: DelayCharacter[];
1195
1214
  };
1196
1215
 
@@ -1198,10 +1217,10 @@ declare type SetDelayCharacterMsg = {
1198
1217
  export declare const SUPPORTED_WAVEFORMS: readonly SupportedWaveform[];
1199
1218
 
1200
1219
  /** Union type of all supported waveforms */
1201
- export declare type SupportedWaveform = 'sine' | 'sawtooth' | 'square' | 'triangle' | CustomLibWaveform;
1220
+ export declare type SupportedWaveform = "sine" | "sawtooth" | "square" | "triangle" | CustomLibWaveform;
1202
1221
 
1203
1222
  declare type TriggerDelayMsg = {
1204
- type: 'trigger';
1223
+ type: "trigger";
1205
1224
  };
1206
1225
 
1207
1226
  declare class ValueSnapper {
@@ -1210,8 +1229,8 @@ declare class ValueSnapper {
1210
1229
  setScale(rootNote: keyof typeof ROOT_NOTES, scalePattern: readonly number[] | number[], tuningOffset: number | undefined, // in semitones
1211
1230
  lowestOctave: number | undefined, highestOctave: number | undefined, normalize: NormalizeOptions | false, snapToZeroCrossings?: number[] | false): number[];
1212
1231
  setRootNote(rootNote: keyof typeof ROOT_NOTES): void;
1213
- setAllowedPeriods(periods: number[], normalize: NormalizeOptions | false, snapToZeroCrossings?: number[] | false, direction?: 'left' | 'right' | 'any'): number[];
1214
- snapToValue(target: number, allowedValues?: number[], tolerance?: number, preferDirection?: 'left' | 'right' | 'any'): number;
1232
+ setAllowedPeriods(periods: number[], normalize: NormalizeOptions | false, snapToZeroCrossings?: number[] | false, direction?: "left" | "right" | "any"): number[];
1233
+ snapToValue(target: number, allowedValues?: number[], tolerance?: number, preferDirection?: "left" | "right" | "any"): number;
1215
1234
  snapToMusicalPeriod(targetPeriod: number, allowedPeriods?: number[]): number;
1216
1235
  setAllowedValues(values: number[], normalize: NormalizeOptions | false): number[];
1217
1236
  get rootNote(): "C" | "C#" | "Db" | "D" | "D#" | "Eb" | "E" | "F" | "F#" | "Gb" | "G" | "G#" | "Ab" | "A" | "A#" | "Bb" | "B";
@@ -1234,7 +1253,7 @@ declare const VoiceState: {
1234
1253
 
1235
1254
  declare type VoiceState = (typeof VoiceState)[keyof typeof VoiceState];
1236
1255
 
1237
- declare type VoiceType = 'sample-voice' | 'karplus-strong-voice' | 'osc-voice' | 'noise-voice';
1256
+ declare type VoiceType = "sample-voice" | "karplus-strong-voice" | "osc-voice" | "noise-voice";
1238
1257
 
1239
1258
  /**
1240
1259
  * Generic options interface that can be used with any CustomLibWaveform type
@@ -1268,11 +1287,11 @@ declare class WorkletNode<TConfig extends WorkletConfig = DefaultWorkletConfig>
1268
1287
  private _processorReady;
1269
1288
  private _messageQueue;
1270
1289
  constructor(audioContext: AudioContext, processorName: string, options?: AudioWorkletNodeOptions);
1271
- setParam<K extends keyof TConfig['params']>(name: K, value: TConfig['params'][K]): this;
1272
- getParam<K extends keyof TConfig['params']>(name: K): AudioParam | undefined;
1273
- sendProcessorMessage(message: TConfig['message']): this;
1290
+ setParam<K extends keyof TConfig["params"]>(name: K, value: TConfig["params"][K]): this;
1291
+ getParam<K extends keyof TConfig["params"]>(name: K): AudioParam | undefined;
1292
+ sendProcessorMessage(message: TConfig["message"]): this;
1274
1293
  private _onProcessorMessage?;
1275
- onProcessorMessage(callback: (event: MessageEvent<TConfig['message']>) => void): this;
1294
+ onProcessorMessage(callback: (event: MessageEvent<TConfig["message"]>) => void): this;
1276
1295
  dispose(): void;
1277
1296
  }
1278
1297