@ng-web-apis/audio
Version:
This is a library for declarative use of Web Audio API with Angular
833 lines (802 loc) • 64.3 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, input, inject, HostAttributeToken, Directive, booleanAttribute, output, contentChildren, effect, Injectable, Pipe, ElementRef } from '@angular/core';
import { outputFromObservable } from '@angular/core/rxjs-interop';
import { interval, map, tap, distinctUntilChanged, skipWhile, debounceTime, filter, animationFrameScheduler } from 'rxjs';
const WA_AUDIO_CONTEXT = new InjectionToken(ngDevMode ? '[WA_AUDIO_CONTEXT]' : '', { factory: () => new AudioContext() });
function latencyHintFactory(latencyHint) {
return latencyHint === null
? undefined
: Number.parseFloat(latencyHint) || latencyHint;
}
class WaAudioContext extends AudioContext {
rate = input('', ...(ngDevMode ? [{ debugName: "rate", alias: 'sampleRate' }] : [{ alias: 'sampleRate' }]));
latencyHint = input(...(ngDevMode ? [undefined, { debugName: "latencyHint" }] : []));
constructor() {
const sampleRate = inject(new HostAttributeToken('sampleRate'), { optional: true });
const latencyHint = inject(new HostAttributeToken('latencyHint'), {
optional: true,
});
super({
latencyHint: latencyHintFactory(latencyHint),
sampleRate: Number.parseInt(sampleRate ?? '', 10) || undefined,
});
}
ngOnDestroy() {
void this.close();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaAudioContext, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.19", type: WaAudioContext, isStandalone: true, selector: "[waAudioContext]", inputs: { rate: { classPropertyName: "rate", publicName: "sampleRate", isSignal: true, isRequired: false, transformFunction: null }, latencyHint: { classPropertyName: "latencyHint", publicName: "latencyHint", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: WA_AUDIO_CONTEXT, useExisting: WaAudioContext }], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaAudioContext, decorators: [{
type: Directive,
args: [{
selector: '[waAudioContext]',
providers: [{ provide: WA_AUDIO_CONTEXT, useExisting: WaAudioContext }],
}]
}], ctorParameters: () => [], propDecorators: { rate: [{ type: i0.Input, args: [{ isSignal: true, alias: "sampleRate", required: false }] }], latencyHint: [{ type: i0.Input, args: [{ isSignal: true, alias: "latencyHint", required: false }] }] } });
class WaChannel extends GainNode {
constructor() {
super(inject(WA_AUDIO_CONTEXT));
}
ngOnDestroy() {
this.disconnect();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaChannel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaChannel, isStandalone: true, selector: "[waChannel]", exportAs: ["AudioNode"], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaChannel, decorators: [{
type: Directive,
args: [{
selector: '[waChannel]',
exportAs: 'AudioNode',
}]
}], ctorParameters: () => [] });
const WA_AUDIO_NODE = new InjectionToken(ngDevMode ? '[WA_AUDIO_NODE]' : '', { factory: () => null });
function asAudioNode(useExisting) {
return { provide: WA_AUDIO_NODE, useExisting };
}
function connect(source, destination) {
if (source && destination) {
// @ts-ignore TS does not have a union override for connect method
source.connect(destination);
}
}
class WaDestination extends AnalyserNode {
quiet = outputFromObservable(interval(100).pipe(map(() => new Float32Array(this.fftSize)), tap((array) => this.getFloatTimeDomainData(array)), map((array) => this.isSilent(array)), distinctUntilChanged(), skipWhile((isSilent) => isSilent), debounceTime(5000), filter((isSilent) => isSilent)));
constructor() {
super(inject(WA_AUDIO_CONTEXT), { fftSize: 256 });
connect(inject(WA_AUDIO_NODE), this);
this.connect(this.context.destination);
}
ngOnDestroy() {
this.disconnect();
}
isSilent(array) {
return Math.abs(array.reduce((acc, cur) => acc + cur, 0)) < 0.001;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaDestination, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaDestination, isStandalone: true, selector: "[waAudioDestinationNode]", outputs: { quiet: "quiet" }, exportAs: ["AudioNode"], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaDestination, decorators: [{
type: Directive,
args: [{
selector: '[waAudioDestinationNode]',
exportAs: 'AudioNode',
}]
}], ctorParameters: () => [], propDecorators: { quiet: [{ type: i0.Output, args: ["quiet"] }] } });
function audioParam(param, value, currentTime = 0) {
value = typeof value === 'string' ? Number.parseFloat(value) : value;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (param.cancelAndHoldAtTime) {
param.cancelAndHoldAtTime(currentTime);
}
else {
param.cancelScheduledValues(currentTime);
param.setValueAtTime(guard(param.value), currentTime);
}
if (typeof value === 'number') {
param.setValueAtTime(guard(value), currentTime);
return;
}
if (value instanceof Array) {
processSchedule(param, value, currentTime);
return;
}
if (!('mode' in value)) {
param.setValueCurveAtTime(value.value, currentTime, value.duration);
return;
}
param.setValueAtTime(guard(param.value), currentTime);
processAutomation(param, value, currentTime);
}
function processSchedule(param, value, currentTime) {
value.forEach((automation) => {
if ('mode' in automation) {
processAutomation(param, automation, currentTime);
}
else {
param.setValueCurveAtTime(automation.value, currentTime, automation.duration);
}
currentTime += automation.duration;
});
}
function processAutomation(param, { value, mode, duration }, currentTime) {
switch (mode) {
case 'exponential':
if (value < 0 || value * param.value < 0) {
param.linearRampToValueAtTime(guard(value), currentTime + duration);
}
else {
param.exponentialRampToValueAtTime(guard(value), currentTime + duration);
}
param.setValueAtTime(guard(value), currentTime + duration);
break;
case 'instant':
param.setValueAtTime(guard(value), currentTime);
param.setValueAtTime(guard(value), currentTime + duration);
break;
case 'linear':
param.linearRampToValueAtTime(guard(value), currentTime + duration);
break;
}
}
function guard(v) {
return v || 0.00000001;
}
class WaListener extends GainNode {
constructor() {
super(inject(WA_AUDIO_CONTEXT, { self: true }));
}
set forwardXSetter(value) {
audioParam(this.context.listener.forwardX, value, this.context.currentTime);
}
set forwardYSetter(value) {
audioParam(this.context.listener.forwardY, value, this.context.currentTime);
}
set forwardZSetter(value) {
audioParam(this.context.listener.forwardZ, value, this.context.currentTime);
}
set positionXSetter(value) {
audioParam(this.context.listener.positionX, value, this.context.currentTime);
}
set positionYSetter(value) {
audioParam(this.context.listener.positionY, value, this.context.currentTime);
}
set positionZSetter(value) {
audioParam(this.context.listener.positionZ, value, this.context.currentTime);
}
set upXSetter(value) {
audioParam(this.context.listener.upX, value, this.context.currentTime);
}
set upYSetter(value) {
audioParam(this.context.listener.upX, value, this.context.currentTime);
}
set upZSetter(value) {
audioParam(this.context.listener.upX, value, this.context.currentTime);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaListener, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaListener, isStandalone: true, selector: "[waAudioContext],[waOfflineAudioContext][length][sampleRate]", inputs: { forwardXSetter: ["forwardX", "forwardXSetter"], forwardYSetter: ["forwardY", "forwardYSetter"], forwardZSetter: ["forwardZ", "forwardZSetter"], positionXSetter: ["positionX", "positionXSetter"], positionYSetter: ["positionY", "positionYSetter"], positionZSetter: ["positionZ", "positionZSetter"], upXSetter: ["upX", "upXSetter"], upYSetter: ["upY", "upYSetter"], upZSetter: ["upZ", "upZSetter"] }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaListener, decorators: [{
type: Directive,
args: [{
selector: '[waAudioContext],[waOfflineAudioContext][length][sampleRate]',
inputs: [
'forwardXSetter: forwardX',
'forwardYSetter: forwardY',
'forwardZSetter: forwardZ',
'positionXSetter: positionX',
'positionYSetter: positionY',
'positionZSetter: positionZ',
'upXSetter: upX',
'upYSetter: upY',
'upZSetter: upZ',
],
}]
}], ctorParameters: () => [] });
class WaNode {
node = inject(WA_AUDIO_NODE, { self: true });
parent = inject(WA_AUDIO_NODE, { skipSelf: true });
ngOnInit() {
connect(this.parent, this.node);
}
ngOnDestroy() {
this.node?.disconnect();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaNode, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaNode, isStandalone: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaNode, decorators: [{
type: Directive
}] });
class WaOfflineContext extends OfflineAudioContext {
lngth = input('', ...(ngDevMode ? [{ debugName: "lngth", alias: 'length' }] : [{ alias: 'length' }]));
rate = input('', ...(ngDevMode ? [{ debugName: "rate", alias: 'sampleRate' }] : [{ alias: 'sampleRate' }]));
channels = input('', ...(ngDevMode ? [{ debugName: "channels", alias: 'numberOfChannels' }] : [{ alias: 'numberOfChannels' }]));
autoplay = input(false, ...(ngDevMode ? [{ debugName: "autoplay", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
complete = output();
constructor() {
const length = inject(new HostAttributeToken('length'));
const sampleRate = inject(new HostAttributeToken('sampleRate'));
const channels = inject(new HostAttributeToken('numberOfChannels'), {
optional: true,
});
super(Number.parseInt(channels ?? '', 10) || 1, Number.parseInt(length, 10), Number.parseInt(sampleRate, 10));
}
oncomplete = (e) => this.complete.emit(e.renderedBuffer);
ngOnInit() {
if (this.autoplay()) {
this.startRendering();
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaOfflineContext, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.19", type: WaOfflineContext, isStandalone: true, selector: "[waOfflineAudioContext][length][sampleRate]", inputs: { lngth: { classPropertyName: "lngth", publicName: "length", isSignal: true, isRequired: false, transformFunction: null }, rate: { classPropertyName: "rate", publicName: "sampleRate", isSignal: true, isRequired: false, transformFunction: null }, channels: { classPropertyName: "channels", publicName: "numberOfChannels", isSignal: true, isRequired: false, transformFunction: null }, autoplay: { classPropertyName: "autoplay", publicName: "autoplay", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { complete: "complete" }, providers: [{ provide: WA_AUDIO_CONTEXT, useExisting: WaOfflineContext }], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaOfflineContext, decorators: [{
type: Directive,
args: [{
selector: '[waOfflineAudioContext][length][sampleRate]',
providers: [{ provide: WA_AUDIO_CONTEXT, useExisting: WaOfflineContext }],
}]
}], ctorParameters: () => [], propDecorators: { lngth: [{ type: i0.Input, args: [{ isSignal: true, alias: "length", required: false }] }], rate: [{ type: i0.Input, args: [{ isSignal: true, alias: "sampleRate", required: false }] }], channels: [{ type: i0.Input, args: [{ isSignal: true, alias: "numberOfChannels", required: false }] }], autoplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoplay", required: false }] }], complete: [{ type: i0.Output, args: ["complete"] }] } });
class WaOutput extends GainNode {
constructor() {
super(inject(WA_AUDIO_CONTEXT));
connect(inject(WA_AUDIO_NODE), this);
}
set waOutput(destination) {
this.disconnect();
connect(this, destination);
}
ngOnDestroy() {
this.disconnect();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaOutput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaOutput, isStandalone: true, selector: "[waOutput]", inputs: { waOutput: "waOutput" }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaOutput, decorators: [{
type: Directive,
args: [{
selector: '[waOutput]',
inputs: ['waOutput'],
}]
}], ctorParameters: () => [] });
class WaScheduledSource {
node = inject(WA_AUDIO_NODE, { self: true });
autoplay = input(false, ...(ngDevMode ? [{ debugName: "autoplay", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
ended = output();
ngOnInit() {
this.node.onended = () => this.ended.emit();
if (this.autoplay()) {
this.node.start();
}
}
ngOnDestroy() {
try {
this.node.stop();
}
catch {
// noop
}
this.node.disconnect();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaScheduledSource, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.19", type: WaScheduledSource, isStandalone: true, inputs: { autoplay: { classPropertyName: "autoplay", publicName: "autoplay", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { ended: "ended" }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaScheduledSource, decorators: [{
type: Directive
}], propDecorators: { autoplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoplay", required: false }] }], ended: [{ type: i0.Output, args: ["ended"] }] } });
class WaSource {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaSource, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaSource, isStandalone: true, hostDirectives: [{ directive: WaScheduledSource, inputs: ["autoplay", "autoplay"], outputs: ["ended", "ended"] }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaSource, decorators: [{
type: Directive,
args: [{
hostDirectives: [
{
directive: WaScheduledSource,
inputs: ['autoplay'],
outputs: ['ended'],
},
],
}]
}] });
class WaMediaStreamDestination extends MediaStreamAudioDestinationNode {
constructor() {
super(inject(WA_AUDIO_CONTEXT));
connect(inject(WA_AUDIO_NODE), this);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaMediaStreamDestination, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaMediaStreamDestination, isStandalone: true, selector: "[waMediaStreamAudioDestinationNode]", exportAs: ["AudioNode"], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaMediaStreamDestination, decorators: [{
type: Directive,
args: [{
selector: '[waMediaStreamAudioDestinationNode]',
exportAs: 'AudioNode',
}]
}], ctorParameters: () => [] });
function parse(value, fallback) {
const parsed = Number.parseFloat(value || '');
return Number.isNaN(parsed) ? fallback : parsed;
}
class WaAnalyser extends AnalyserNode {
fByte = new Uint8Array(this.frequencyBinCount);
fFloat = new Float32Array(this.frequencyBinCount);
tByte = new Uint8Array(this.fftSize);
tFloat = new Float32Array(this.fftSize);
frequencyByte = outputFromObservable(interval(0, animationFrameScheduler).pipe(map(() => {
if (this.fByte.length !== this.frequencyBinCount) {
this.fByte = new Uint8Array(this.frequencyBinCount);
}
this.getByteFrequencyData(this.fByte);
return this.fByte;
})));
frequencyFloat = outputFromObservable(interval(0, animationFrameScheduler).pipe(map(() => {
if (this.fFloat.length !== this.frequencyBinCount) {
this.fFloat = new Float32Array(this.frequencyBinCount);
}
this.getFloatFrequencyData(this.fFloat);
return this.fFloat;
})));
timeByte = outputFromObservable(interval(0, animationFrameScheduler).pipe(map(() => {
if (this.tByte.length !== this.fftSize) {
this.tByte = new Uint8Array(this.frequencyBinCount);
}
this.getByteTimeDomainData(this.tByte);
return this.tByte;
})));
timeFloat = outputFromObservable(interval(0, animationFrameScheduler).pipe(map(() => {
if (this.tFloat.length !== this.fftSize) {
this.tFloat = new Float32Array(this.frequencyBinCount);
}
this.getFloatTimeDomainData(this.tFloat);
return this.tFloat;
})));
constructor() {
const O = { optional: true };
const fftSize = inject(new HostAttributeToken('fftSize'), O);
const minDecibels = inject(new HostAttributeToken('minDecibels'), O);
const maxDecibels = inject(new HostAttributeToken('maxDecibels'), O);
const time = inject(new HostAttributeToken('smoothingTimeConstant'), O);
super(inject(WA_AUDIO_CONTEXT), {
fftSize: parse(fftSize, 2048),
maxDecibels: parse(maxDecibels, -30),
minDecibels: parse(minDecibels, -100),
smoothingTimeConstant: parse(time, 0.8),
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaAnalyser, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaAnalyser, isStandalone: true, selector: "[waAnalyserNode]", inputs: { fftSize: "fftSize", minDecibels: "minDecibels", maxDecibels: "maxDecibels", smoothingTimeConstant: "smoothingTimeConstant", channelCount: "channelCount", channelCountMode: "channelCountMode", channelInterpretation: "channelInterpretation" }, outputs: { frequencyByte: "frequencyByte", frequencyFloat: "frequencyFloat", timeByte: "timeByte", timeFloat: "timeFloat" }, providers: [asAudioNode(WaAnalyser)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaAnalyser, decorators: [{
type: Directive,
args: [{
selector: '[waAnalyserNode]',
inputs: [
'fftSize',
'minDecibels',
'maxDecibels',
'smoothingTimeConstant',
'channelCount',
'channelCountMode',
'channelInterpretation',
],
providers: [asAudioNode(WaAnalyser)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [], propDecorators: { frequencyByte: [{ type: i0.Output, args: ["frequencyByte"] }], frequencyFloat: [{ type: i0.Output, args: ["frequencyFloat"] }], timeByte: [{ type: i0.Output, args: ["timeByte"] }], timeFloat: [{ type: i0.Output, args: ["timeFloat"] }] } });
class WaBiquadFilter extends BiquadFilterNode {
constructor() {
const detune = inject(new HostAttributeToken('detune'), { optional: true });
const frequency = inject(new HostAttributeToken('frequency'), { optional: true });
const gain = inject(new HostAttributeToken('gain'), { optional: true });
const Q = inject(new HostAttributeToken('Q'), { optional: true });
super(inject(WA_AUDIO_CONTEXT), {
detune: parse(detune, 0),
frequency: parse(frequency, 350),
gain: parse(gain, 0),
Q: parse(Q, 1),
});
}
set detuneSetter(value) {
audioParam(this.detune, value, this.context.currentTime);
}
set frequencySetter(value) {
audioParam(this.frequency, value, this.context.currentTime);
}
set gainSetter(value) {
audioParam(this.gain, value, this.context.currentTime);
}
set qSetter(value) {
audioParam(this.Q, value, this.context.currentTime);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaBiquadFilter, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaBiquadFilter, isStandalone: true, selector: "[waBiquadFilterNode]", inputs: { detuneSetter: ["detune", "detuneSetter"], frequencySetter: ["frequency", "frequencySetter"], gainSetter: ["gain", "gainSetter"], qSetter: ["Q", "qSetter"], type: "type", channelCount: "channelCount", channelCountMode: "channelCountMode", channelInterpretation: "channelInterpretation" }, providers: [asAudioNode(WaBiquadFilter)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaBiquadFilter, decorators: [{
type: Directive,
args: [{
selector: '[waBiquadFilterNode]',
inputs: [
'detuneSetter: detune',
'frequencySetter: frequency',
'gainSetter: gain',
'qSetter: Q',
'type',
'channelCount',
'channelCountMode',
'channelInterpretation',
],
providers: [asAudioNode(WaBiquadFilter)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [] });
class WaChannelMerger extends ChannelMergerNode {
channels = contentChildren(WaChannel, ...(ngDevMode ? [{ debugName: "channels", descendants: false }] : [{ descendants: false }]));
inputs = input('', ...(ngDevMode ? [{ debugName: "inputs", alias: 'numberOfInputs' }] : [{ alias: 'numberOfInputs' }]));
constructor() {
const attr = inject(new HostAttributeToken('numberOfInputs'), { optional: true });
const numberOfInputs = Number.parseInt(attr || '', 10) || 6;
super(inject(WA_AUDIO_CONTEXT), { numberOfInputs });
effect(() => {
this.channels().forEach((node, index) => {
node.connect(this, 0, index);
});
});
}
ngOnDestroy() {
this.disconnect();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaChannelMerger, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.3.19", type: WaChannelMerger, isStandalone: true, selector: "[waChannelMergerNode]", inputs: { channelCount: { classPropertyName: "channelCount", publicName: "channelCount", isSignal: false, isRequired: false, transformFunction: null }, channelCountMode: { classPropertyName: "channelCountMode", publicName: "channelCountMode", isSignal: false, isRequired: false, transformFunction: null }, channelInterpretation: { classPropertyName: "channelInterpretation", publicName: "channelInterpretation", isSignal: false, isRequired: false, transformFunction: null }, inputs: { classPropertyName: "inputs", publicName: "numberOfInputs", isSignal: true, isRequired: false, transformFunction: null } }, providers: [asAudioNode(WaChannelMerger)], queries: [{ propertyName: "channels", predicate: WaChannel, isSignal: true }], exportAs: ["AudioNode"], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaChannelMerger, decorators: [{
type: Directive,
args: [{
selector: '[waChannelMergerNode]',
inputs: ['channelCount', 'channelCountMode', 'channelInterpretation'],
providers: [asAudioNode(WaChannelMerger)],
exportAs: 'AudioNode',
}]
}], ctorParameters: () => [], propDecorators: { channels: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => WaChannel), { ...{ descendants: false }, isSignal: true }] }], inputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "numberOfInputs", required: false }] }] } });
class WaChannelSplitter extends ChannelSplitterNode {
channels = contentChildren(WA_AUDIO_NODE, ...(ngDevMode ? [{ debugName: "channels", descendants: false }] : [{ descendants: false }]));
outputs = input('', ...(ngDevMode ? [{ debugName: "outputs", alias: 'numberOfOutputs' }] : [{ alias: 'numberOfOutputs' }]));
constructor() {
const attr = inject(new HostAttributeToken('numberOfOutputs'), { optional: true });
const numberOfOutputs = Number.parseInt(attr || '', 10) || 6;
super(inject(WA_AUDIO_CONTEXT), { numberOfOutputs });
effect(() => {
this.disconnect();
this.channels()
.filter((node) => !!node)
.forEach((node, index) => {
this.connect(node, index);
});
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaChannelSplitter, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.3.19", type: WaChannelSplitter, isStandalone: true, selector: "[waChannelSplitterNode]", inputs: { channelCount: { classPropertyName: "channelCount", publicName: "channelCount", isSignal: false, isRequired: false, transformFunction: null }, channelCountMode: { classPropertyName: "channelCountMode", publicName: "channelCountMode", isSignal: false, isRequired: false, transformFunction: null }, channelInterpretation: { classPropertyName: "channelInterpretation", publicName: "channelInterpretation", isSignal: false, isRequired: false, transformFunction: null }, outputs: { classPropertyName: "outputs", publicName: "numberOfOutputs", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: WA_AUDIO_NODE, useValue: null }], queries: [{ propertyName: "channels", predicate: WA_AUDIO_NODE, isSignal: true }], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaChannelSplitter, decorators: [{
type: Directive,
args: [{
selector: '[waChannelSplitterNode]',
inputs: ['channelCount', 'channelCountMode', 'channelInterpretation'],
providers: [{ provide: WA_AUDIO_NODE, useValue: null }],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [], propDecorators: { channels: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => WA_AUDIO_NODE), { ...{ descendants: false }, isSignal: true }] }], outputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "numberOfOutputs", required: false }] }] } });
class WaAudioBufferService {
context = inject(WA_AUDIO_CONTEXT);
cache = new Map();
async fetch(url) {
return new Promise((resolve, reject) => {
if (this.cache.has(url)) {
resolve(this.cache.get(url));
return;
}
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onerror = reject;
request.onabort = reject;
request.onload = () => {
void this.context.decodeAudioData(request.response, (buffer) => {
this.cache.set(url, buffer);
resolve(buffer);
}, reject);
};
request.send();
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaAudioBufferService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaAudioBufferService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaAudioBufferService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class WaConvolver extends ConvolverNode {
service = inject(WaAudioBufferService);
constructor() {
super(inject(WA_AUDIO_CONTEXT));
}
set bufferSetter(source) {
if (typeof source === 'string') {
this.service.fetch(source).then((result) => {
this.buffer = result;
});
}
else {
this.buffer = source;
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaConvolver, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaConvolver, isStandalone: true, selector: "[waConvolverNode]", inputs: { bufferSetter: ["buffer", "bufferSetter"], normalize: "normalize", channelCount: "channelCount", channelCountMode: "channelCountMode", channelInterpretation: "channelInterpretation" }, providers: [asAudioNode(WaConvolver)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaConvolver, decorators: [{
type: Directive,
args: [{
selector: '[waConvolverNode]',
inputs: [
'bufferSetter: buffer',
'normalize',
'channelCount',
'channelCountMode',
'channelInterpretation',
],
providers: [asAudioNode(WaConvolver)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [] });
class WaDelay extends DelayNode {
maxDelayTime = input('', ...(ngDevMode ? [{ debugName: "maxDelayTime" }] : []));
constructor() {
const delayTime = inject(new HostAttributeToken('delayTime'), { optional: true });
const maxDelayTime = inject(new HostAttributeToken('maxDelayTime'), {
optional: true,
});
super(inject(WA_AUDIO_CONTEXT), {
delayTime: parse(delayTime, 0),
maxDelayTime: parse(maxDelayTime, 1),
});
}
set delayTimeSetter(value) {
audioParam(this.delayTime, value, this.context.currentTime);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaDelay, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.19", type: WaDelay, isStandalone: true, selector: "[waDelayNode]", inputs: { delayTimeSetter: { classPropertyName: "delayTimeSetter", publicName: "delayTime", isSignal: false, isRequired: false, transformFunction: null }, channelCount: { classPropertyName: "channelCount", publicName: "channelCount", isSignal: false, isRequired: false, transformFunction: null }, channelCountMode: { classPropertyName: "channelCountMode", publicName: "channelCountMode", isSignal: false, isRequired: false, transformFunction: null }, channelInterpretation: { classPropertyName: "channelInterpretation", publicName: "channelInterpretation", isSignal: false, isRequired: false, transformFunction: null }, maxDelayTime: { classPropertyName: "maxDelayTime", publicName: "maxDelayTime", isSignal: true, isRequired: false, transformFunction: null } }, providers: [asAudioNode(WaDelay)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaDelay, decorators: [{
type: Directive,
args: [{
selector: '[waDelayNode]',
inputs: [
'delayTimeSetter: delayTime',
'channelCount',
'channelCountMode',
'channelInterpretation',
],
providers: [asAudioNode(WaDelay)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [], propDecorators: { maxDelayTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDelayTime", required: false }] }] } });
class WaDynamicsCompressor extends DynamicsCompressorNode {
constructor() {
const attack = inject(new HostAttributeToken('attack'), { optional: true });
const knee = inject(new HostAttributeToken('knee'), { optional: true });
const ratio = inject(new HostAttributeToken('ratio'), { optional: true });
const release = inject(new HostAttributeToken('release'), { optional: true });
const threshold = inject(new HostAttributeToken('threshold'), { optional: true });
super(inject(WA_AUDIO_CONTEXT), {
attack: parse(attack, 0.003),
knee: parse(knee, 30),
ratio: parse(ratio, 12),
release: parse(release, 0.25),
threshold: parse(threshold, -24),
});
}
set attackSetter(value) {
audioParam(this.attack, value, this.context.currentTime);
}
set kneeSetter(value) {
audioParam(this.knee, value, this.context.currentTime);
}
set ratioSetter(value) {
audioParam(this.ratio, value, this.context.currentTime);
}
set releaseSetter(value) {
audioParam(this.release, value, this.context.currentTime);
}
set thresholdSetter(value) {
audioParam(this.threshold, value, this.context.currentTime);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaDynamicsCompressor, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaDynamicsCompressor, isStandalone: true, selector: "[waDynamicsCompressorNode]", inputs: { attackSetter: ["attack", "attackSetter"], kneeSetter: ["knee", "kneeSetter"], ratioSetter: ["ratio", "ratioSetter"], releaseSetter: ["release", "releaseSetter"], thresholdSetter: ["threshold", "thresholdSetter"], channelCount: "channelCount", channelCountMode: "channelCountMode", channelInterpretation: "channelInterpretation" }, providers: [asAudioNode(WaDynamicsCompressor)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaDynamicsCompressor, decorators: [{
type: Directive,
args: [{
selector: '[waDynamicsCompressorNode]',
inputs: [
'attackSetter: attack',
'kneeSetter: knee',
'ratioSetter: ratio',
'releaseSetter: release',
'thresholdSetter: threshold',
'channelCount',
'channelCountMode',
'channelInterpretation',
],
providers: [asAudioNode(WaDynamicsCompressor)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [] });
class WaGain extends GainNode {
constructor() {
const gain = inject(new HostAttributeToken('gain'), { optional: true });
super(inject(WA_AUDIO_CONTEXT), { gain: parse(gain, 1) });
}
set gainSetter(value) {
audioParam(this.gain, value, this.context.currentTime);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaGain, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaGain, isStandalone: true, selector: "[waGainNode]", inputs: { gainSetter: ["gain", "gainSetter"], channelCount: "channelCount", channelCountMode: "channelCountMode", channelInterpretation: "channelInterpretation" }, providers: [asAudioNode(WaGain)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaGain, decorators: [{
type: Directive,
args: [{
selector: '[waGainNode]',
inputs: [
'gainSetter: gain',
'channelCount',
'channelCountMode',
'channelInterpretation',
],
providers: [asAudioNode(WaGain)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [] });
const WA_FEEDBACK_COEFFICIENTS = new InjectionToken(ngDevMode ? '[WA_FEEDBACK_COEFFICIENTS]' : '');
const WA_FEEDFORWARD_COEFFICIENTS = new InjectionToken(ngDevMode ? '[WA_FEEDFORWARD_COEFFICIENTS]' : '');
class WaIIRFilter extends IIRFilterNode {
constructor() {
const feedback = inject(WA_FEEDBACK_COEFFICIENTS);
const feedforward = inject(WA_FEEDFORWARD_COEFFICIENTS);
super(inject(WA_AUDIO_CONTEXT), { feedback, feedforward });
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaIIRFilter, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaIIRFilter, isStandalone: true, selector: "[waIIRFilterNode]", inputs: { channelCount: "channelCount", channelCountMode: "channelCountMode", channelInterpretation: "channelInterpretation" }, providers: [asAudioNode(WaIIRFilter)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaIIRFilter, decorators: [{
type: Directive,
args: [{
selector: '[waIIRFilterNode]',
inputs: ['channelCount', 'channelCountMode', 'channelInterpretation'],
providers: [asAudioNode(WaIIRFilter)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [] });
class WaPanner extends PannerNode {
constructor() {
super(inject(WA_AUDIO_CONTEXT));
}
set orientationXSetter(value) {
audioParam(this.orientationX, value, this.context.currentTime);
}
set orientationYSetter(value) {
audioParam(this.orientationY, value, this.context.currentTime);
}
set orientationZSetter(value) {
audioParam(this.orientationZ, value, this.context.currentTime);
}
set positionXSetter(value) {
audioParam(this.positionX, value, this.context.currentTime);
}
set positionYSetter(value) {
audioParam(this.positionY, value, this.context.currentTime);
}
set positionZSetter(value) {
audioParam(this.positionZ, value, this.context.currentTime);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaPanner, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaPanner, isStandalone: true, selector: "[waPannerNode]", inputs: { orientationXSetter: ["orientationX", "orientationXSetter"], orientationYSetter: ["orientationY", "orientationYSetter"], orientationZSetter: ["orientationZ", "orientationZSetter"], positionXSetter: ["positionX", "positionXSetter"], positionYSetter: ["positionY", "positionYSetter"], positionZSetter: ["positionZ", "positionZSetter"], coneInnerAngle: "coneInnerAngle", coneOuterAngle: "coneOuterAngle", coneOuterGain: "coneOuterGain", distanceModel: "distanceModel", maxDistance: "maxDistance", panningModel: "panningModel", refDistance: "refDistance", rolloffFactor: "rolloffFactor", channelCount: "channelCount", channelCountMode: "channelCountMode", channelInterpretation: "channelInterpretation" }, providers: [asAudioNode(WaPanner)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaPanner, decorators: [{
type: Directive,
args: [{
selector: '[waPannerNode]',
inputs: [
'orientationXSetter: orientationX',
'orientationYSetter: orientationY',
'orientationZSetter: orientationZ',
'positionXSetter: positionX',
'positionYSetter: positionY',
'positionZSetter: positionZ',
'coneInnerAngle',
'coneOuterAngle',
'coneOuterGain',
'distanceModel',
'maxDistance',
'panningModel',
'refDistance',
'rolloffFactor',
'channelCount',
'channelCountMode',
'channelInterpretation',
],
providers: [asAudioNode(WaPanner)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [] });
class WaStereoPanner extends StereoPannerNode {
constructor() {
const pan = inject(new HostAttributeToken('pan'), { optional: true });
super(inject(WA_AUDIO_CONTEXT), { pan: parse(pan, 0) });
}
set panSetter(value) {
audioParam(this.pan, value, this.context.currentTime);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaStereoPanner, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaStereoPanner, isStandalone: true, selector: "[waStereoPannerNode]", inputs: { panSetter: ["pan", "panSetter"], channelCount: "channelCount", channelCountMode: "channelCountMode", channelInterpretation: "channelInterpretation" }, providers: [asAudioNode(WaStereoPanner)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaStereoPanner, decorators: [{
type: Directive,
args: [{
selector: '[waStereoPannerNode]',
inputs: [
'panSetter: pan',
'channelCount',
'channelCountMode',
'channelInterpretation',
],
providers: [asAudioNode(WaStereoPanner)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [] });
class WaWaveShaper extends WaveShaperNode {
constructor() {
super(inject(WA_AUDIO_CONTEXT));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaWaveShaper, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: WaWaveShaper, isStandalone: true, selector: "[waWaveShaperNode]", inputs: { oversample: "oversample", curve: "curve", channelCount: "channelCount", channelCountMode: "channelCountMode", channelInterpretation: "channelInterpretation" }, providers: [asAudioNode(WaWaveShaper)], exportAs: ["AudioNode"], usesInheritance: true, hostDirectives: [{ directive: WaNode }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaWaveShaper, decorators: [{
type: Directive,
args: [{
selector: '[waWaveShaperNode]',
inputs: [
'oversample',
'curve',
'channelCount',
'channelCountMode',
'channelInterpretation',
],
providers: [asAudioNode(WaWaveShaper)],
exportAs: 'AudioNode',
hostDirectives: [WaNode],
}]
}], ctorParameters: () => [] });
// TODO: Add AudioWorkletNodeOptions
class WaWorklet extends AudioWorkletNode {
name = input('', ...(ngDevMode ? [{ debugName: "name" }] : []));
processorerror = output();
constructor() {
super(inject(WA_AUDIO_CONTEXT), inject(new HostAttributeToken('name')));
}
onprocessorerror = () => this.processorerror.emit();
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WaWorklet, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.19", type: WaWorklet, isStandalone: true, selector: "[waAudioWorkletNode][name]", inputs: { channelCount: { classPropertyName: "channelCount", publicName: "channelCount", isSignal: false, isRequired: false, transformFunction: null }, channelCountMode: { classPropertyName: "channelCountMode", publicName: "channelCountMode", isSignal: false, isRequired: false, transformFunction: null }, channelInterpretation: { classPropertyName: "channelInterpretation", publicName: "channelInterpretation", isSignal: false, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: