Web Audio API for Angular
Part of Web APIs for Angular
This is a library for declarative use of
Web Audio API with Angular 7+.
It is a complete conversion to declarative Angular directives, if you find any inconsistencies
or errors, please file an issue. Watch out
for 💡 emoji in this README for additional features and special use cases.
How to use
After you installed the package, you must add @ng-web-apis/audio/polyfill
to your polyfills.ts
.
It is required to normalize things like webkitAudioContext
, otherwise your code would fail.
You can build audio graph with directives. For example, here's a typical echo feedback loop:
<audio src="/demo.wav" waMediaElementAudioSourceNode>
<ng-container #node="AudioNode" waDelayNode [delayTime]="delayTime">
<ng-container waGainNode [gain]="gain">
<ng-container [waOutput]="node"></ng-container>
<ng-container waAudioDestinationNode></ng-container>
</ng-container>
</ng-container>
<ng-container waAudioDestinationNode></ng-container>
</audio>
💡 AudioBufferService
This library has AudioBufferService
with fetch
method, returning
Promise
which allows you to easily turn your hosted audio file into
AudioBuffer through GET requests.
Result is stored in service's cache so same file is not requested again while application is running.
This service is also used within directives that have
AudioBuffer inputs (such as
AudioBufferSourceNode or
ConvolverNode) so you can just
pass string URL, as well as an actual
AudioBuffer. For example:
<button
#source="AudioNode"
buffer="/demo.wav"
waAudioBufferSourceNode
(click)="source.start()"
>
Play
<ng-container waAudioDestinationNode></ng-container>
</button>
Supported nodes
You can use following audio nodes through directives of the same name
(prefixed with wa
standing for Web API):
Terminal nodes
Sources
Processors
You can use AudioWorkletNode
in supporting browsers. To register your
AudioWorkletProcessors
in a global default AudioContext
you can use tokens:
@NgModule({
bootstrap: [AppComponent],
declarations: [AppComponent],
providers: [
{
provide: AUDIO_WORKLET_PROCESSORS,
useValue: 'assets/my-processor.js',
multi: true,
},
],
})
export class AppModule {}
@Component({
selector: 'app',
templateUrl: './app.component.html',
})
export class AppComponent {
constructor(
@Inject(AUDIO_WORKLET_PROCESSORS_READY) readonly processorsReady: Promise<boolean>,
) {}
}
You can then instantiate your
AudioWorkletNode:
<ng-container *ngIf="processorsReady | async" waAudioWorkletNode name="my-processor">
<ng-container waAudioDestinationNode></ng-container>
</ng-container>
If you need to create your own node with custom
AudioParam
and control it declaratively you can extend WebAudioWorklet
class
and add audioParam
decorator to new component's inputs:
@Directive({
selector: '[my-worklet-node]',
exportAs: 'AudioNode',
providers: [
{
provide: AUDIO_NODE,
useExisting: forwardRef(() => MyWorklet),
},
],
})
export class MyWorklet extends WebAudioWorklet {
@Input()
@audioParam()
customParam?: AudioParamInput;
constructor(
@Inject(AUDIO_CONTEXT) context: BaseAudioContext,
@SkipSelf() @Inject(AUDIO_NODE) node: AudioNode | null,
) {
super(context, node, 'my-processor');
}
}
Since work with AudioParam
is imperative in its nature, there are difference to native API when working with
declarative inputs and directives.
NOTE: You can always access directives through
template reference variables /
@ViewChild and since they extend native nodes
work with AudioParam
in traditional Web Audio fashion
AudioParam inputs
for directives accept following arguments:
-
number
to set in instantly, equivalent to setting
AudioParam.value
-
AudioParamCurve
to set array of values over given duration, equivalent to
AudioParam.setValueCurveAtTime
called with
AudioContext.currentTime
export type AudioParamCurve = {
readonly value: number[];
readonly duration: number;
}
-
AudioParamAutomation
to linearly or exponentially ramp to given value starting from
AudioContext.currentTime
export type AudioParamAutomation = {
readonly value: number;
readonly duration: number;
readonly mode: 'instant' | 'linear' | 'exponential';
};
-
AudioParamAutomation[]
to schedule multiple changes in value, stacking one after another
You can use waAudioParam
pipe to turn your number values into AudioParamAutomation
(default mode is exponential
, so last argument can be omitted)
or number arrays to AudioParamCurve
(second argument duration
is in seconds):
<ng-container
waGainNode
gain="0"
[gain]="gain | waAudioParam : 0.1 : 'linear'"
></ng-container>
This way values would change smoothly rather than abruptly, causing audio artifacts.
NOTE: You can set initial value for AudioParam
through argument binding combined with dynamic property binding as seen above.
To schedule an audio envelope looking something like this:
You would need to pass the following array of AudioParamAutomation
items:
envelope = [
{
value: 0,
duration: 0,
mode: 'instant',
},
{
value: 1,
duration: ATTACK_TIME,
mode: 'linear',
},
{
value: SUS,
duration: DECAY_TIME,
mode: 'linear',
},
{
value: SUS,
duration: SUSTAIN_TIME,
mode: 'instant',
},
{
value: 0,
duration: RELEASE_TIME,
mode: 'exponential',
},
];
💡 Special cases
<audio src="/demo.wav" waMediaElementAudioSourceNode>
<ng-container waChannelSplitterNode>
<ng-container [waOutput]="right"></ng-container>
<ng-container [waOutput]="left"></ng-container>
</ng-container>
<ng-container waChannelMergerNode>
<ng-container #left="AudioNode" waChannel></ng-container>
<ng-container #right="AudioNode" waChannel></ng-container>
<ng-container waAudioDestinationNode></ng-container>
</ng-container>
</audio>
💡 Tokens
Browser support
Note that some features
(AudioWorklet etc.)
were added later and are supported only by more recent versions
IMPORTANT: You must add @ng-web-apis/audio/polyfill
to your polyfills.ts
,
otherwise you will get ReferenceError: X is not defined
in browsers for entities
they do not support
💡 StereoPannerNode
is emulated with PannerNode
in browsers that do not support it yet
💡 positionX
(orientationX) and
other similar properties of AudioListener
and PannerNode fall back to
setPosition
(setOrientation)
method if browser does not support it
Angular Universal
If you want to use this package with SSR, you need to mock native Web Audio API classes on the server.
You can use our Universal package for this, see this example.
Demo
You can try online demo here
See also
Other Web APIs for Angular by @ng-web-apis
Open-source
Do you also want to open-source something, but hate the collateral work?
Check out this Angular Open-source Library Starter
we’ve created for our projects. It got you covered on continuous integration,
pre-commit checks, linting, versioning + changelog, code coverage and all that jazz.