addon/classes/oscillator.js
import Ember from 'ember';
import { Connectable, Playable } from 'ember-audio/mixins';
import { Connection } from 'ember-audio';
/**
* Provides classes that are capable of interacting with the Web Audio API's
* AudioContext.
*
* @public
* @module Audio
*/
const {
A,
on,
Object: EmberObject
} = Ember;
/**
* A class that represents an oscillator for a synthesizer. Capable of creating
* and playing a waveform of specified `type` at a specified `frequency`.
*
* All filters from {{#crossLink "BiquadFilterNode"}}{{/crossLink}} are
* available and can be enabled by providing a pojo for a given filter.
*
* // 200Hz sine wave w/highpass at 600Hz and lowpass created but not filtering
* const osc = audioService.createOscillator({
* frequency: 200,
* highpass: { frequency: 600 },
* lowpass: {}
* });
*
* // or
* import { Oscillator } from 'ember-audio';
* const audioContext = audioService.get('audioContext');
* const osc = Oscillator.create({
* audioContext,
* frequency: 200,
* highpass: { frequency: 600 },
* lowpass: {}
* });
*
* @public
* @class Oscillator
* @uses Connectable
* @uses Playable
* @todo figure out why `isPlaying` isn't working for Oscillator
*/
const Oscillator = EmberObject.extend(Connectable, Playable, {
/**
* Determines the type of wave output by the OscillatorNode instance.
* Corresponds directly to `type` from
* {{#crossLink "OscillatorNode"}}{{/crossLink}}
*
* @public
* @property type
* @type {string}
* @default 'sine'
*/
type: 'sine',
/**
* Determines the frequency of the wave output by the OscillatorNode instance.
* Corresponds directly to `frequency.value` from
* {{#crossLink "OscillatorNode"}}{{/crossLink}}
*
* @public
* @property frequency
* @type {number}
*/
frequency: null,
/**
* Determines the `gain.value` of the GainNode instance in the `gain`
* connection instance. Corresponds directly to `gain.value` from
* {{#crossLink "GainNode"}}{{/crossLink}}
*
* @public
* @property gain
* @type {number}
*/
gain: null,
/**
* Lists available filter types.
*
* @private
* @property _filters
* @type {array|string}
*/
_filters: [
'lowpass',
'highpass',
'bandpass',
'lowshelf',
'highshelf',
'peaking',
'notch',
'allpass'
],
/**
* Initializes default connections on Oscillator instantiation. Runs `on('init')`.
*
* @protected
* @method _initConnections
*/
_initConnections: on('init', function() {
const filters = this.get('_filters');
const bufferSource = Connection.create({
name: 'audioSource',
createdOnPlay: true,
source: 'audioContext',
createCommand: 'createOscillator',
onPlaySetAttrsOnNode: [
{
attrNameOnNode: 'frequency.value',
relativePath: 'frequency'
},
{
attrNameOnNode: 'type',
relativePath: 'type'
}
]
});
const gain = Connection.create({
name: 'gain',
source: 'audioContext',
createCommand: 'createGain',
onPlaySetAttrsOnNode: [
{
attrNameOnNode: 'gain.value',
relativePath: 'gain'
}
]
});
const panner = Connection.create({
name: 'panner',
source: 'audioContext',
createCommand: 'createStereoPanner'
});
const destination = Connection.create({
name: 'destination',
path: 'audioContext.destination'
});
// always start with source
const connections = A([ bufferSource ]);
// Add filters if they have been defined
filters.map((filterName) => {
const filterIsDefined = this.get(filterName) !== null;
if (filterIsDefined) {
connections.pushObject(this._createFilter(filterName));
}
});
// add gain, panner, and destination connections
connections.pushObjects([ gain, panner, destination ]);
this.set('connections', connections);
this.wireConnections();
}),
/**
* Creates a Connection instance with a filter of the specified type.
*
* @private
* @method _createFilter
*
* @param {string} type Determines what type of filter will be created.
*
* @return {Connection} A connection with a BiquadFilterNode of the specified
* type.
*/
_createFilter(type) {
return Connection.create({
name: type,
source: 'audioContext',
createCommand: 'createBiquadFilter',
onPlaySetAttrsOnNode: [
{
attrNameOnNode: 'type',
value: type
},
{
attrNameOnNode: 'frequency.value',
relativePath: `${type}.frequency`
},
{
attrNameOnNode: 'q.value',
relativePath: `${type}.q`
},
{
attrNameOnNode: 'gain.value',
relativePath: `${type}.gain`
}
]
});
},
/**
* Settings object for the lowpass filter. The lowpass filter is disabled
* if this is not provided. Accepts `frequency` and `q`.
* https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
*
* @public
* @property lowpass
* @type {object}
*/
lowpass: null,
/**
* Settings object for the highpass filter. The highpass filter is disabled
* if this is not provided. Accepts `frequency` and `q`.
* https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
*
* @public
* @property highpass
* @type {object}
*/
highpass: null,
/**
* Settings object for the bandpass filter. The bandpass filter is disabled
* if this is not provided. Accepts `frequency` and `q`.
* https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
*
* @public
* @property bandpass
* @type {object}
*/
bandpass: null,
/**
* Settings object for the lowshelf filter. The lowshelf filter is disabled
* if this is not provided. Accepts `frequency` and `gain`.
* https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
*
* @public
* @property lowshelf
* @type {object}
*/
lowshelf: null,
/**
* Settings object for the highshelf filter. The highshelf filter is disabled
* if this is not provided. Accepts `frequency` and `gain`.
* https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
*
* @public
* @property highshelf
* @type {object}
*/
highshelf: null,
/**
* Settings object for the peaking filter. The peaking filter is disabled
* if this is not provided. Accepts `frequency`, `q`, and `gain`.
* https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
*
* @public
* @property peaking
* @type {object}
*/
peaking: null,
/**
* Settings object for the notch filter. The notch filter is disabled
* if this is not provided. Accepts `frequency` and `q`.
* https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
*
* @public
* @property notch
* @type {object}
*/
notch: null,
/**
* Settings object for the allpass filter. The allpass filter is disabled
* if this is not provided. Accepts `frequency`, and `q`.
* https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
*
* @public
* @property allpass
* @type {object}
*/
allpass: null
});
export default Oscillator;