Skip to content
Merged
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
339 changes: 339 additions & 0 deletions src/audio/Audio.js

Large diffs are not rendered by default.

59 changes: 58 additions & 1 deletion src/audio/AudioAnalyser.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,69 @@
/**
* This class can be used to analyse audio data.
*
* ```js
* // create an AudioListener and add it to the camera
* const listener = new THREE.AudioListener();
* camera.add( listener );
*
* // create an Audio source
* const sound = new THREE.Audio( listener );
*
* // load a sound and set it as the Audio object's buffer
* const audioLoader = new THREE.AudioLoader();
* audioLoader.load( 'sounds/ambient.ogg', function( buffer ) {
* sound.setBuffer( buffer );
* sound.setLoop(true);
* sound.setVolume(0.5);
* sound.play();
* });
*
* // create an AudioAnalyser, passing in the sound and desired fftSize
* const analyser = new THREE.AudioAnalyser( sound, 32 );
*
* // get the average frequency of the sound
* const data = analyser.getAverageFrequency();
* ```
*/
class AudioAnalyser {

/**
* Constructs a new audio analyzer.
*
* @param {Audio} audio - The audio to analyze.
* @param {Audio} [fftSize=2048] - The window size in samples that is used when performing a Fast Fourier Transform (FFT) to get frequency domain data.
*/
constructor( audio, fftSize = 2048 ) {

/**
* The global audio listener.
*
* @type {AnalyserNode}
*/
this.analyser = audio.context.createAnalyser();
this.analyser.fftSize = fftSize;

/**
* Holds the analyzed data.
*
* @type {Uint8Array}
*/
this.data = new Uint8Array( this.analyser.frequencyBinCount );

audio.getOutput().connect( this.analyser );

}


/**
* Returns an array with frequency data of the audio.
*
* Each item in the array represents the decibel value for a specific frequency.
* The frequencies are spread linearly from 0 to 1/2 of the sample rate.
* For example, for 48000 sample rate, the last item of the array will represent
* the decibel value for 24000 Hz.
*
* @return {Uint8Array} The frequency data.
*/
getFrequencyData() {

this.analyser.getByteFrequencyData( this.data );
Expand All @@ -20,6 +72,11 @@ class AudioAnalyser {

}

/**
* Returns the average of the frequencies returned by {@link AudioAnalyser#getFrequencyData}.
*
* @return {number} The average frequency.
*/
getAverageFrequency() {

let value = 0;
Expand Down
15 changes: 15 additions & 0 deletions src/audio/AudioContext.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
let _context;

/**
* Manages the global audio context in the engine.
*
* @hideconstructor
*/
class AudioContext {

/**
* Returns the global native audio context.
*
* @return {AudioContext} The native audio context.
*/
static getContext() {

if ( _context === undefined ) {
Expand All @@ -14,6 +24,11 @@ class AudioContext {

}

/**
* Allows to set the global native audio context from outside.
*
* @param {AudioContext} value - The native context to set.
*/
static setContext( value ) {

_context = value;
Expand Down
75 changes: 75 additions & 0 deletions src/audio/AudioListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,61 @@ const _quaternion = /*@__PURE__*/ new Quaternion();
const _scale = /*@__PURE__*/ new Vector3();
const _orientation = /*@__PURE__*/ new Vector3();

/**
* The class represents a virtual listern of the all positional and non-positional audio effects
* in the scene. A three.js application usually creates a single listener. It is a mandatory
* constructor parameter for audios entities like {@link Audio} and {@link PositionalAudio}.
*
* In most cases, the listener object is a child of the camera. So the 3D transformation of the
* camera represents the 3D transformation of the listener.
*
* @augments Object3D
*/
class AudioListener extends Object3D {

/**
* Constructs a new audio listener.
*/
constructor() {

super();

this.type = 'AudioListener';

/**
* The native audio context.
*
* @type {AudioContext}
* @readonly
*/
this.context = AudioContext.getContext();

/**
* The gain node used for volume control.
*
* @type {GainNode}
* @readonly
*/
this.gain = this.context.createGain();
this.gain.connect( this.context.destination );

/**
* An optional filter.
*
* Defined via {@AudioListener#setFilter}.
*
* @type {?AudioNode}
* @readonly
*/
this.filter = null;

/**
* Time delta values required for `linearRampToValueAtTime()` usage.
*
* @type {number}
* @default 0
* @readonly
*/
this.timeDelta = 0;

// private
Expand All @@ -32,12 +72,24 @@ class AudioListener extends Object3D {

}

/**
* Returns the listener's input node.
*
* This method is used by other audio nodes to connect to this listener.
*
* @return {GainNode} The input node.
*/
getInput() {

return this.gain;

}

/**
* Removes the current filter from this listener.
*
* @return {AudioListener} A reference to this listener.
*/
removeFilter() {

if ( this.filter !== null ) {
Expand All @@ -53,12 +105,23 @@ class AudioListener extends Object3D {

}

/**
* Returns the current set filter.
*
* @return {AudioNode} The filter.
*/
getFilter() {

return this.filter;

}

/**
* Sets the given filter to this listener.
*
* @param {AudioNode} value - The filter to set.
* @return {AudioListener} A reference to this listener.
*/
setFilter( value ) {

if ( this.filter !== null ) {
Expand All @@ -80,12 +143,24 @@ class AudioListener extends Object3D {

}

/**
* Returns the applications master volume.
*
* @return {number} The master volume.
*/
getMasterVolume() {

return this.gain.gain.value;

}

/**
* Sets the applications master volume. This volume setting affects
* all audio nodes in the scene.
*
* @param {number} value - The master volume to set.
* @return {AudioListener} A reference to this listener.
*/
setMasterVolume( value ) {

this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
Expand Down
Loading
Loading