4

I am trying to draw the waveform of my audio using tone.js

// setup
const wave = new Tone.Waveform()
Tone.Master.connect(wave)

// later
wave.getValue() // returns an array (length 1024) of numbers between -1 and 1

This works fine, except that I'm having trouble understanding what these number represent, excatly. I assume they are the amplitude of the wave over time, but if that's the case, how far into the past do they go?

Or maybe I'm misunderstanding something entirely, in either case, I would appreciate if you could shed some light on this!

The documentation is very short and can be found here, it reads:

Gets the waveform of the audio source. Returns the waveform data of length size as a Float32Array with values between -1 and 1.

Hoff
  • 38,776
  • 17
  • 74
  • 99
  • It's a Float32Array, not a regular array, which is a ***B I G*** difference. Also, how long is your audio source? Does the length of the array change when the source length changes? – – kelsny Oct 24 '22 at 19:28
  • @caTS What is the difference, except that the precision is defined to be exaclty 32 bits in a Float32Array? The source is continuous, I can for example attach an oscillator to it, or any other source of audio... – Hoff Oct 24 '22 at 20:21
  • @Hoff in this [youtube tutorial](https://youtu.be/hgg3ZBLRH58?t=1505) it says that the `getValues()` targets the left, both or right speaker. So it will return the buffer of a specific sample. – wittgenstein Jan 26 '23 at 15:51

1 Answers1

4

This is really interesting! Since I am not too much familiar with audio APIs, I've followed the source code of Tone.js to reveal what does it mean.

The Tone.Waveform property, which is new Tone().Waveform in the code does include the implementation of .getValue().

// https://github.com/Tonejs/Tone.js/blob/053b5d4397b595ea804b5d6baf6108158c8e0696/Tone/component/analysis/Waveform.ts#L43-L45
// Waveform.ts
class Waveform extends MeterBase {
  // ...
  /**
   * Return the waveform for the current time as a Float32Array where each value in the array
   * represents a sample in the waveform.
   */
  getValue(): Float32Array {
    return this._analyser.getValue() as Float32Array;
  }
}

Waveform._analyser property is coming from MeterBase. It implements ._analyser property with Analyser

// https://github.com/Tonejs/Tone.js/blob/053b5d4397b595ea804b5d6baf6108158c8e0696/Tone/component/analysis/MeterBase.ts
// MeterBase.ts
class MeterBase {
  // ...
  protected _analyser: Analyser;
}

looking at the Analyser.ts, it is revealed that getValue() is coming from analysers[x].getFloatTimeDomainData(). Now we have one lead, that getValue() seems like a time series data of some float signal.

// https://github.com/Tonejs/Tone.js/blob/b1526c357854d8017765328bd1278a91d1e14e50/Tone/component/analysis/Analyser.ts#L17-L21
// Analyser.ts
/**
* Wrapper around the native Web Audio's [AnalyserNode](http://webaudio.github.io/web-audio-api/#idl-def-AnalyserNode).
* Extracts FFT or Waveform data from the incoming signal.
* @category Component
*/
class Analyser {
  // ...
  private _analysers: AnalyserNode[] = [];
}

analysers is a wrapper around array of AnalyserNode, as stated in the comment.

The linked official W3C document of AnalyserNode reveals that .getFloatTimeDomainData() is a result of blackman window and fourier transform over time series data of frequency in decibel(dB). This document has better details. Please check it if it interests you.

To simply put, this is a normalized data of how decibels(dB) change over time. I believe it uses normalized timeframe of 1024 and -1 ~ 1 for dB to save memory. In nature, waveforms have curve forms which can be gracefully compressed with mathematical expressions. So in theory it does not have clear limit since everything can be normalized but it may lose some quality by normalization rate(smoothness).

I personally think the document author of Tone.js did a great job of simplifying the meaning of getValues(). It just explains what it is and what it can be in a short sentence, instead of giving unnecessary lectures. It may need more elaboration for some but I think anyone who fiddled with WebAudio probably understood what it is.

Thanks to @Hoff for bringing in such awesome question.

sungryeol
  • 3,677
  • 7
  • 20