tone
Version:
A Web Audio framework for making interactive music in the browser.
230 lines • 8.29 kB
JavaScript
import * as tslib_1 from "tslib";
import { connect } from "../../core/context/ToneAudioNode";
import { Param } from "../../core/context/Param";
import { ToneAudioBuffer } from "../../core/context/ToneAudioBuffer";
import { defaultArg, optionsFromArguments } from "../../core/util/Defaults";
import { noOp } from "../../core/util/Interface";
import { isDefined } from "../../core/util/TypeCheck";
import { assert } from "../../core/util/Debug";
import { OneShotSource } from "../OneShotSource";
import { EQ, GTE, LT } from "../../core/util/Math";
/**
* Wrapper around the native BufferSourceNode.
* @category Source
*/
var ToneBufferSource = /** @class */ (function (_super) {
tslib_1.__extends(ToneBufferSource, _super);
function ToneBufferSource() {
var _this = _super.call(this, optionsFromArguments(ToneBufferSource.getDefaults(), arguments, ["url", "onload"])) || this;
_this.name = "ToneBufferSource";
/**
* The oscillator
*/
_this._source = _this.context.createBufferSource();
_this._internalChannels = [_this._source];
/**
* indicators if the source has started/stopped
*/
_this._sourceStarted = false;
_this._sourceStopped = false;
var options = optionsFromArguments(ToneBufferSource.getDefaults(), arguments, ["url", "onload"]);
connect(_this._source, _this._gainNode);
_this._source.onended = function () { return _this._stopSource(); };
/**
* The playbackRate of the buffer
*/
_this.playbackRate = new Param({
context: _this.context,
param: _this._source.playbackRate,
units: "positive",
value: options.playbackRate,
});
// set some values initially
_this.loop = options.loop;
_this.loopStart = options.loopStart;
_this.loopEnd = options.loopEnd;
_this._buffer = new ToneAudioBuffer(options.url, options.onload, options.onerror);
_this._internalChannels.push(_this._source);
return _this;
}
ToneBufferSource.getDefaults = function () {
return Object.assign(OneShotSource.getDefaults(), {
url: new ToneAudioBuffer(),
loop: false,
loopEnd: 0,
loopStart: 0,
onload: noOp,
onerror: noOp,
playbackRate: 1,
});
};
Object.defineProperty(ToneBufferSource.prototype, "fadeIn", {
/**
* The fadeIn time of the amplitude envelope.
*/
get: function () {
return this._fadeIn;
},
set: function (t) {
this._fadeIn = t;
},
enumerable: true,
configurable: true
});
Object.defineProperty(ToneBufferSource.prototype, "fadeOut", {
/**
* The fadeOut time of the amplitude envelope.
*/
get: function () {
return this._fadeOut;
},
set: function (t) {
this._fadeOut = t;
},
enumerable: true,
configurable: true
});
Object.defineProperty(ToneBufferSource.prototype, "curve", {
/**
* The curve applied to the fades, either "linear" or "exponential"
*/
get: function () {
return this._curve;
},
set: function (t) {
this._curve = t;
},
enumerable: true,
configurable: true
});
/**
* Start the buffer
* @param time When the player should start.
* @param offset The offset from the beginning of the sample to start at.
* @param duration How long the sample should play. If no duration is given, it will default to the full length of the sample (minus any offset)
* @param gain The gain to play the buffer back at.
*/
ToneBufferSource.prototype.start = function (time, offset, duration, gain) {
if (gain === void 0) { gain = 1; }
assert(this.buffer.loaded, "buffer is either not set or not loaded");
var computedTime = this.toSeconds(time);
// apply the gain envelope
this._startGain(computedTime, gain);
// if it's a loop the default offset is the loopstart point
if (this.loop) {
offset = defaultArg(offset, this.loopStart);
}
else {
// otherwise the default offset is 0
offset = defaultArg(offset, 0);
}
// make sure the offset is not less than 0
var computedOffset = Math.max(this.toSeconds(offset), 0);
// start the buffer source
if (this.loop) {
// modify the offset if it's greater than the loop time
var loopEnd = this.toSeconds(this.loopEnd) || this.buffer.duration;
var loopStart = this.toSeconds(this.loopStart);
var loopDuration = loopEnd - loopStart;
// move the offset back
if (GTE(computedOffset, loopEnd)) {
computedOffset = ((computedOffset - loopStart) % loopDuration) + loopStart;
}
// when the offset is very close to the duration, set it to 0
if (EQ(computedOffset, this.buffer.duration)) {
computedOffset = 0;
}
}
// this.buffer.loaded would have return false if the AudioBuffer was undefined
this._source.buffer = this.buffer.get();
this._source.loopEnd = this.toSeconds(this.loopEnd) || this.buffer.duration;
if (LT(computedOffset, this.buffer.duration)) {
this._sourceStarted = true;
this._source.start(computedTime, computedOffset);
}
// if a duration is given, schedule a stop
if (isDefined(duration)) {
var computedDur = this.toSeconds(duration);
// make sure it's never negative
computedDur = Math.max(computedDur, 0);
this.stop(computedTime + computedDur);
}
return this;
};
ToneBufferSource.prototype._stopSource = function (time) {
if (!this._sourceStopped && this._sourceStarted) {
this._sourceStopped = true;
this._source.stop(this.toSeconds(time));
this._onended();
}
};
Object.defineProperty(ToneBufferSource.prototype, "loopStart", {
/**
* If loop is true, the loop will start at this position.
*/
get: function () {
return this._source.loopStart;
},
set: function (loopStart) {
this._source.loopStart = this.toSeconds(loopStart);
},
enumerable: true,
configurable: true
});
Object.defineProperty(ToneBufferSource.prototype, "loopEnd", {
/**
* If loop is true, the loop will end at this position.
*/
get: function () {
return this._source.loopEnd;
},
set: function (loopEnd) {
this._source.loopEnd = this.toSeconds(loopEnd);
},
enumerable: true,
configurable: true
});
Object.defineProperty(ToneBufferSource.prototype, "buffer", {
/**
* The audio buffer belonging to the player.
*/
get: function () {
return this._buffer;
},
set: function (buffer) {
this._buffer.set(buffer);
},
enumerable: true,
configurable: true
});
Object.defineProperty(ToneBufferSource.prototype, "loop", {
/**
* If the buffer should loop once it's over.
*/
get: function () {
return this._source.loop;
},
set: function (loop) {
this._source.loop = loop;
if (this._sourceStarted) {
this.cancelStop();
}
},
enumerable: true,
configurable: true
});
/**
* Clean up.
*/
ToneBufferSource.prototype.dispose = function () {
_super.prototype.dispose.call(this);
this._source.onended = null;
this._source.disconnect();
this._buffer.dispose();
this.playbackRate.dispose();
return this;
};
return ToneBufferSource;
}(OneShotSource));
export { ToneBufferSource };
//# sourceMappingURL=ToneBufferSource.js.map