Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/demo/src/app/pages/audio/audio-page.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ <h2>Source</h2>
[fftSize]="fftSize"
(timeByte$)="onTimeDomain($event)"
>
<ng-container [waOutput]="chain || fallback" />
<ng-container [waOutput]="chain() || fallback" />
</ng-container>
</button>
}
Expand All @@ -90,7 +90,7 @@ <h2>Source</h2>
[fftSize]="fftSize"
(timeByte$)="onTimeDomain($event)"
>
<ng-container [waOutput]="chain || fallback" />
<ng-container [waOutput]="chain() || fallback" />
</ng-container>
</audio>
}
Expand All @@ -112,7 +112,7 @@ <h2>Source</h2>
[fftSize]="fftSize"
(timeByte$)="onTimeDomain($event)"
>
<ng-container [waOutput]="chain || fallback" />
<ng-container [waOutput]="chain() || fallback" />
</ng-container>
</button>
}
Expand Down
5 changes: 2 additions & 3 deletions apps/demo/src/app/pages/audio/audio-page.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {CommonModule} from '@angular/common';
import {ChangeDetectionStrategy, Component, inject, ViewChild} from '@angular/core';
import {ChangeDetectionStrategy, Component, inject, viewChild} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {AUDIO_CONTEXT, WaWebAudio} from '@ng-web-apis/audio';
import {CanvasModule} from '@ng-web-apis/canvas';
Expand Down Expand Up @@ -30,8 +30,7 @@ import {TuiSelectModule, TuiTextfieldControllerModule} from '@taiga-ui/legacy';
export default class AudioPage {
private readonly context = inject<AudioContext>(AUDIO_CONTEXT);

@ViewChild('chain')
protected readonly chain?: AudioNode;
protected readonly chain = viewChild<AudioNode>('chain');

protected buffers = [Date.now()];

Expand Down
1 change: 0 additions & 1 deletion libs/audio/src/nodes/analyser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {parse} from '../utils/parse';
exportAs: 'AudioNode',
})
export class WebAudioAnalyser extends AnalyserNode implements OnDestroy {
// '!' because it is actually set in constructor
@Output()
public frequencyByte$!: Observable<Uint8Array>;

Expand Down
8 changes: 5 additions & 3 deletions libs/audio/src/nodes/script-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
EventEmitter,
inject,
type OnDestroy,
Output,
output,
type OutputEmitterRef,
} from '@angular/core';

import {AUDIO_CONTEXT} from '../tokens/audio-context';
Expand All @@ -20,8 +21,9 @@ import {connect} from '../utils/connect';
exportAs: 'AudioNode',
})
export class WebAudioScriptProcessor extends ScriptProcessorNode implements OnDestroy {
@Output()
public audioprocess?: EventEmitter<AudioProcessingEvent>;
public audioprocess:
| EventEmitter<AudioProcessingEvent>
| OutputEmitterRef<AudioProcessingEvent> = output<AudioProcessingEvent>();

constructor(
@Attribute('bufferSize') bufferSize: string | null,
Expand Down
26 changes: 14 additions & 12 deletions libs/audio/src/nodes/stereo-panner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// eslint-disable-next-line no-restricted-imports
import {Attribute, Directive, inject, Input, type OnDestroy} from '@angular/core';
import {Attribute, Directive, inject, input, type OnDestroy} from '@angular/core';

import {AUDIO_CONTEXT} from '../tokens/audio-context';
import {asAudioNode, AUDIO_NODE} from '../tokens/audio-node';
Expand All @@ -17,6 +17,19 @@ import {processAudioParam} from '../utils/process-audio-param';
exportAs: 'AudioNode',
})
export class WebAudioStereoPanner extends StereoPannerNode implements OnDestroy {
public readonly panParam = input(undefined, {
alias: 'pan',
transform: (pan: AudioParamInput) => {
if ('setPosition' in this) {
/** fallback for browsers not supporting {@link StereoPannerNode} */
// @ts-ignore
this.fallbackToPannerNode(fallbackAudioParam(pan));
} else {
processAudioParam(this.pan, pan, this.context.currentTime);
}
},
});

constructor(@Attribute('pan') panArg: string | null) {
const context = inject(AUDIO_CONTEXT);
const node = inject(AUDIO_NODE, {skipSelf: true});
Expand All @@ -38,17 +51,6 @@ export class WebAudioStereoPanner extends StereoPannerNode implements OnDestroy
connect(node, this);
}

@Input('pan')
public set panParam(pan: AudioParamInput) {
if ('setPosition' in this) {
/** fallback for browsers not supporting {@link StereoPannerNode} */
// @ts-ignore
this.fallbackToPannerNode(fallbackAudioParam(pan));
} else {
processAudioParam(this.pan, pan, this.context.currentTime);
}
}

public ngOnDestroy(): void {
this.disconnect();
}
Expand Down
6 changes: 2 additions & 4 deletions libs/audio/src/nodes/worklet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import {
// eslint-disable-next-line no-restricted-imports
Attribute,
Directive,
EventEmitter,
inject,
type OnDestroy,
Output,
output,
} from '@angular/core';

import {AUDIO_CONTEXT} from '../tokens/audio-context';
Expand All @@ -20,8 +19,7 @@ import {connect} from '../utils/connect';
exportAs: 'AudioNode',
})
export class WebAudioWorklet extends AudioWorkletNode implements OnDestroy {
@Output()
public processorerror = new EventEmitter<void>();
public readonly processorerror = output();

constructor(@Attribute('name') name: string) {
const context = inject(AUDIO_CONTEXT);
Expand Down
15 changes: 3 additions & 12 deletions libs/audio/src/sources/constant-source.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
import {
// eslint-disable-next-line no-restricted-imports
Attribute,
Directive,
EventEmitter,
inject,
Input,
type OnDestroy,
Output,
} from '@angular/core';
// eslint-disable-next-line no-restricted-imports
import {Attribute, Directive, inject, Input, type OnDestroy, output} from '@angular/core';

import {audioParam} from '../decorators/audio-param';
import {AUDIO_CONTEXT} from '../tokens/audio-context';
Expand All @@ -27,8 +19,7 @@ export class WebAudioConstantSource extends ConstantSourceNode implements OnDest
@audioParam('offset')
public offsetParam?: AudioParamInput;

@Output()
public ended = new EventEmitter<void>();
public readonly ended = output();

constructor(
@Attribute('autoplay') autoplay: string | null,
Expand Down
64 changes: 37 additions & 27 deletions libs/audio/tests/analyser.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ChangeDetectionStrategy, Component, ViewChild} from '@angular/core';
import {ChangeDetectionStrategy, Component, viewChild} from '@angular/core';
import {type ComponentFixture, TestBed} from '@angular/core/testing';
import {providers, WaWebAudio, WebAudioAnalyser} from '@ng-web-apis/audio';
import {take} from 'rxjs';
Expand All @@ -16,8 +16,7 @@ describe('Analyser', () => {
changeDetection: ChangeDetectionStrategy.OnPush,
})
class Test {
@ViewChild(WebAudioAnalyser)
public node!: WebAudioAnalyser;
public readonly node = viewChild.required(WebAudioAnalyser);
}

let fixture: ComponentFixture<Test>;
Expand All @@ -34,39 +33,51 @@ describe('Analyser', () => {
});

it('creates node', () => {
expect(testComponent.node instanceof AnalyserNode).toBe(true);
expect(testComponent.node() instanceof AnalyserNode).toBe(true);
});

it('emits frequency byte array', (done) => {
testComponent.node.frequencyByte$.pipe(take(1)).subscribe((array) => {
expect(array instanceof Uint8Array).toBe(true);

done();
});
testComponent
.node()
.frequencyByte$.pipe(take(1))
.subscribe((array) => {
expect(array instanceof Uint8Array).toBe(true);

done();
});
});

it('emits frequency float array', (done) => {
testComponent.node.frequencyFloat$.pipe(take(1)).subscribe((array) => {
expect(array instanceof Float32Array).toBe(true);

done();
});
testComponent
.node()
.frequencyFloat$.pipe(take(1))
.subscribe((array) => {
expect(array instanceof Float32Array).toBe(true);

done();
});
});

it('emits time byte array', (done) => {
testComponent.node.timeByte$.pipe(take(1)).subscribe((array) => {
expect(array instanceof Uint8Array).toBe(true);

done();
});
testComponent
.node()
.timeByte$.pipe(take(1))
.subscribe((array) => {
expect(array instanceof Uint8Array).toBe(true);

done();
});
});

it('emits time float array', (done) => {
testComponent.node.timeFloat$.pipe(take(1)).subscribe((array) => {
expect(array instanceof Float32Array).toBe(true);

done();
});
testComponent
.node()
.timeFloat$.pipe(take(1))
.subscribe((array) => {
expect(array instanceof Float32Array).toBe(true);

done();
});
});
});

Expand All @@ -80,8 +91,7 @@ describe('Analyser', () => {
changeDetection: ChangeDetectionStrategy.OnPush,
})
class Test {
@ViewChild(WebAudioAnalyser)
public node!: WebAudioAnalyser;
public readonly node = viewChild.required(WebAudioAnalyser);
}

let fixture: ComponentFixture<Test>;
Expand All @@ -99,7 +109,7 @@ describe('Analyser', () => {
});

it('creates node', () => {
expect(testComponent.node instanceof AnalyserNode).toBe(true);
expect(testComponent.node() instanceof AnalyserNode).toBe(true);
});
});
});
7 changes: 3 additions & 4 deletions libs/audio/tests/audio-context.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ChangeDetectionStrategy, Component, ViewChild} from '@angular/core';
import {ChangeDetectionStrategy, Component, viewChild} from '@angular/core';
import {type ComponentFixture, TestBed} from '@angular/core/testing';
import {WaWebAudio, WebAudioContext} from '@ng-web-apis/audio';

Expand All @@ -17,8 +17,7 @@ describe('AudioContext', () => {
changeDetection: ChangeDetectionStrategy.OnPush,
})
class Test {
@ViewChild(WebAudioContext)
public audioContext!: AudioContext;
public readonly audioContext = viewChild.required(WebAudioContext);
}

let fixture: ComponentFixture<Test>;
Expand All @@ -35,6 +34,6 @@ describe('AudioContext', () => {
});

it('creates context', () => {
expect(testComponent.audioContext instanceof AudioContext).toBe(true);
expect(testComponent.audioContext() instanceof AudioContext).toBe(true);
});
});
12 changes: 5 additions & 7 deletions libs/audio/tests/biquad-filter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ChangeDetectionStrategy, Component, ViewChild} from '@angular/core';
import {ChangeDetectionStrategy, Component, viewChild} from '@angular/core';
import {type ComponentFixture, TestBed} from '@angular/core/testing';
import {providers, WaWebAudio, WebAudioBiquadFilter} from '@ng-web-apis/audio';

Expand All @@ -15,8 +15,7 @@ describe('BiquadFilter', () => {
changeDetection: ChangeDetectionStrategy.OnPush,
})
class Test {
@ViewChild(WebAudioBiquadFilter)
public node!: AudioNode;
public readonly node = viewChild.required(WebAudioBiquadFilter);
}

let fixture: ComponentFixture<Test>;
Expand All @@ -33,7 +32,7 @@ describe('BiquadFilter', () => {
});

it('creates node', () => {
expect(testComponent.node instanceof BiquadFilterNode).toBe(true);
expect(testComponent.node() instanceof BiquadFilterNode).toBe(true);
});
});

Expand All @@ -47,8 +46,7 @@ describe('BiquadFilter', () => {
changeDetection: ChangeDetectionStrategy.OnPush,
})
class Test {
@ViewChild(WebAudioBiquadFilter)
public node!: AudioNode;
public readonly node = viewChild.required(WebAudioBiquadFilter);
}

let fixture: ComponentFixture<Test>;
Expand All @@ -66,7 +64,7 @@ describe('BiquadFilter', () => {
});

it('creates node', () => {
expect(testComponent.node instanceof BiquadFilterNode).toBe(true);
expect(testComponent.node() instanceof BiquadFilterNode).toBe(true);
});
});
});
12 changes: 5 additions & 7 deletions libs/audio/tests/buffer-source.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ChangeDetectionStrategy, Component, ViewChild} from '@angular/core';
import {ChangeDetectionStrategy, Component, viewChild} from '@angular/core';
import {type ComponentFixture, TestBed} from '@angular/core/testing';
import {providers, WaWebAudio, WebAudioBufferSource} from '@ng-web-apis/audio';

Expand All @@ -15,8 +15,7 @@ describe('BufferSource', () => {
changeDetection: ChangeDetectionStrategy.OnPush,
})
class Test {
@ViewChild(WebAudioBufferSource)
public node!: AudioNode;
public readonly node = viewChild.required(WebAudioBufferSource);
}

let fixture: ComponentFixture<Test>;
Expand All @@ -33,7 +32,7 @@ describe('BufferSource', () => {
});

it('creates node', () => {
expect(testComponent.node instanceof AudioBufferSourceNode).toBe(true);
expect(testComponent.node() instanceof AudioBufferSourceNode).toBe(true);
});
});

Expand All @@ -47,8 +46,7 @@ describe('BufferSource', () => {
changeDetection: ChangeDetectionStrategy.OnPush,
})
class Test {
@ViewChild(WebAudioBufferSource)
public node!: AudioNode;
public readonly node = viewChild.required(WebAudioBufferSource);
}

let fixture: ComponentFixture<Test>;
Expand All @@ -66,7 +64,7 @@ describe('BufferSource', () => {
});

it('creates node', () => {
expect(testComponent.node instanceof AudioBufferSourceNode).toBe(true);
expect(testComponent.node() instanceof AudioBufferSourceNode).toBe(true);
});
});
});
Loading