A small, vanilla JavaScript and TypeScript library meant to easily visualize sound-waves in HTML.
Written in TypeScript and made to be easy for functional programming and general use.
npm install sound-visualizer
This library offers two main forms of visualization: continuous
and current
.
The continuous
version (technically referred to as an oscillogram) is similar to the kind of visualization done by apps like WhatsApp and Audacity, where the wave being displayed reflects what has been recorded so far.
The current
version (a simple soundwave visualization) displays what is being currently recorded as a wave,
moving up and down according to frequency.
The easiest way to see the difference between the two is to visit the codesandbox.
To use one or the other, simply import them:
import { currentVisualizer, continuousVisualizer } from 'sound-visualizer';
Each visualizer takes three arguments, with the third one being different depending on the visualizer.
canvas
(HTMLCanvasElement
): the canvas to display the visualization on.audio
(MediaStream
): the audio to visualize.options
: an optional object containing additional options; see below.
Each visualizer function returns an object with the following properties:
export type VisualizerFunctions = {
start: () => void;
stop: () => void;
reset: () => void;
}
As their names suggest, start
starts the visualization, stop
stops the visualization, and reset
calls stop
and then clears the canvas.
export type DrawContinuousOptions = {
lineWidth?: "thin" | "default" | "thick" | number;
strokeColor?: string;
slices?: number;
barRadius?: number;
}
lineWidth
(number
|string
): the width of the lines that make up the wave; if a thickness string is provided, it will be translated into a percentage of the canvas's width, if a number is provided it will be used apx
value. Default:"default"
.strokeColor
(string
): the color of the wave; Default:"#000"
.slices
(number
): the number of slices drawn onto the canvas to make up the wave; Default:100
.barRadius
(number
): the border radius of each bar, setting0
will draw a normal rectangle; Default:0
.
export type DrawCurrentOptions = {
lineWidth?: "thin" | "default" | "thick" | number;
strokeColor?: string;
heightNorm?: number;
}
lineWidth
(number
|string
): the width of the lines that make up the wave; if a thickness string is provided, it will be translated into a percentage of the canvas's width, if a number is provided it will be used apx
value. Default:"default"
.strokeColor
(string
): the color of the wave; Default:"#000"
.heightNorm
(number
): a number used to normalize the height of the wave; the wave function is multiplied by this number, so a number larger than1
will exaggerate the height of the wave, while a number between0
and1
will minimize it. Default:1
.
This library also exposes a few of the useful functions used internally by the visualizers.They are seperated into pure
and impure
, depending on whether they are pure functions in the functional-programming sense (it was an easy way for me to think about the code 😸).
export function widthFromOption(
lineWidth: number | "thin" | "thick" | "default",
canvasWidth: number
): number;
Used to transform the "thin" | "thick" | "default"
options for lineWidth
into a useable px
value, as a percentage of the canvas' width.
export function calculateLine(canvasHeight: number, value: number): { start: number; end: number };
Used to calculate the coordinates on the canvas that should start and end the line visualized at a certain moment in time.
export function waveForm(array: number[]): number;
Used to calculate the wave-form value for a number array. Equivalent to sound-visualizer
- waveFormUint
is used instead - but it's still exposed for convenience. It can also be acheived by doing:
Math.max(...array) - Math.min(...array)
but waveForm
is simply written to iterate over the array only once.
export function waveFormUint(array: Uint8Array): number;
Identical to waveForm
but utilizes the maximum and minimum sizes of a Uint8.
export function frequencyValue(array: Uint8Array): number;
Takes the result of waveFormUint
and flips it, so that a large waveFormUint
result becomes a small number, and vice versa. This is the function that is actually used by the continuousVisualizer
, because the canvas
coordinates work in such a way that a small number is closer to the edge of the canvas.
export function clearCanvas(canvas: HTMLCanvasElement): void;
Clears a canvas with a 2d context.
export function drawContinuousWave(
canvas: HTMLCanvasElement,
audioHistory: number[],
options: DrawContinuousOptions = defaultOptions
): void;
Function used to draw for every tick
of the continuousVisualizer
. audioHistory
is an array of frequency values for the calculated history of the audio.
export function drawCurrentWave(
canvas: HTMLCanvasElement,
audioData: Uint8Array,
options: DrawCurrentOptions = defaultOptions
): void;
Function used to draw for every tick
of the currentVisualizer
.
export function startAnalysis(audio: MediaStream): { analyse: () => Uint8Array, disconnect: () => void };
Function used to analyse the current audio's byteTimeDomainData
. Abstracts away the pretty unreadable actions required to get the desired Uint8Array
(which is later passed to drawCurrentWave
or calculated with frequencyValue
and added to the audioHistory
array).
The ContinuousVisualizer
and CurrentVisualizer
types are exported from this package, and an additional Visualizer
type is exported for convenience, which is a union type for both.