Skip to content

Commit

Permalink
Merge pull request #10 from cstoquer/getUri
Browse files Browse the repository at this point in the history
Remove wizAssets dependency
  • Loading branch information
Cedric Stoquer committed Sep 9, 2015
2 parents 9236a29 + 3545a79 commit 543fae8
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 45 deletions.
19 changes: 6 additions & 13 deletions ISound.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@ function ISound() {

// the following properties are public but should NOT be assigned directly.
// instead, use the setter functions: setId, setVolume, setPan, setLoop, setPitch.
this.id = 0;
this.id = null;
this.volume = 1.0;
this.pan = 0.0;
this.loop = false;
this.pitch = 0.0;

// private properties
this._src = '';
this._loaded = false;
this._loading = false;
this._unloading = false;
Expand All @@ -38,9 +37,7 @@ ISound.prototype.init = function () { /* virtual function */ };

//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
ISound.prototype.setId = function (value) {
var audioPath = this.audioManager.settings.audioPath;
this.id = value;
this._src = audioPath + value + '.mp3';
this._loaded = false;
};

Expand All @@ -67,11 +64,9 @@ ISound.prototype.setPitch = function (pitch) {
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
/** Load sound. Abstract method to be overwritten
* @private
*
* @param {String} filePath - audio file to be loaded
*/
ISound.prototype._load = function (filePath) {
console.log('ISound load call: ' + filePath);
ISound.prototype._load = function () {
console.log('ISound load call: ' + this.id);
return this._finalizeLoad(null);
};

Expand All @@ -88,8 +83,7 @@ ISound.prototype.load = function (cb) {
if (this._loading) return;
this._loading = true;

var filePath = this.audioManager.settings.assetSeverUrl + this._src;
return this._load(filePath, this);
return this._load();
};

//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
Expand Down Expand Up @@ -137,8 +131,7 @@ ISound.prototype.unload = function () {
this.audioManager.usedMemory -= this.usedMemory;
this.setVolume(1.0);
this.setPan(0.0);
this.id = 0;
this._src = '';
this.id = null;
this._loaded = false;
this.usedMemory = 0;

Expand Down Expand Up @@ -176,7 +169,7 @@ ISound.prototype.play = function (vol, pan, pitch) {
/** Play sound. Abstract method to be overwritten */
ISound.prototype._play = function () {
this.playing = true;
console.log('ISound play call: "' + this._src + '"');
console.log('ISound play call: "' + this.id + '"');
};

//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
Expand Down
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Play sounds using Web Audio, fallback on HTML5 Audio.
`AudioManager` is specifically designed to works for games that have a big
quantity of audio assets. Loading and unloading is made easy and transparent.
If available, WizAsset is used for downloading files to disc.

# API

Expand Down Expand Up @@ -151,3 +150,41 @@ audioManager.settings.crossFade = true; // default is false
```javascript
audioManager.release();
```

### Custom loader function
`audioManager.settings.getFileUri` can be overriden if you want more control on how to
resolve files uri from sound id. The function have one on the following synchronous or
asynchronous profile:

```javascript
function getFileUriSync(audioPath, id) {
var uri;
// ...
return uri;
}
```

```javascript
function getFileUriAsync(audioPath, id, callback) {
var uri;
var error = null;
// ...
return callback(error, uri);
}
```

For instance, here's how you can add [wizAssets](https://github.com/Wizcorp/phonegap-plugin-wizAssets)
to cache files on disc in a PhoneGap application:
```javascript
if (window.wizAssets) {
audioManager.settings.getFileUri = function wizAssetsGetUri(audioPath, id, cb) {
window.wizAssets.downloadFile(audioPath + id + '.mp3', 'audio/' + id + '.mp3',
function onSuccess(uri) {
cb(null, uri)
},
cb // onFail callback
);
}
}
```

32 changes: 22 additions & 10 deletions Sound.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,13 @@ Sound.prototype.setLoop = function (value) {
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
/** Load sound
* @private
*
* @param {String} filePath - audio file to be loaded
*/
Sound.prototype._load = function (filePath) {
Sound.prototype._load = function () {
var self = this;

function loadFail() {
function loadFail(error) {
// TODO: keep track that loading has failed to not retry to loading it
self._finalizeLoad('Sound could not be loaded.');
self._finalizeLoad(error);
}

function onAudioLoaded() {
Expand All @@ -58,10 +56,10 @@ Sound.prototype._load = function (filePath) {
self._finalizeLoad(null);
}

function onAudioError() {
function onAudioError(error) {
this.removeEventListener('canplaythrough', onAudioLoaded);
this.removeEventListener('error', onAudioError);
loadFail();
loadFail(error);
}

function loadAudio(uri) {
Expand All @@ -72,10 +70,24 @@ Sound.prototype._load = function (filePath) {
self._audio.load();
}

if (window.wizAssets) {
window.wizAssets.downloadFile(filePath, this._src, loadAudio, loadFail);
var getFileUri = this.audioManager.settings.getFileUri;
var audioPath = this.audioManager.settings.audioPath;

if (getFileUri.length > 2) {
// asynchronous
getFileUri(audioPath, this.id, function onUri(error, uri) {
if (error) return loadFail(error);
loadAudio(uri);
});
} else {
loadAudio(filePath);
// synchronous
try {
var uri = getFileUri(audioPath, this.id);
if (!uri) return loadFail('emptyUri');
loadAudio(uri);
} catch (error) {
loadFail(error);
}
}
};

Expand Down
47 changes: 32 additions & 15 deletions SoundBuffered.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,17 +156,15 @@ SoundBuffered.prototype._setPlaybackRate = function (portamento) {
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
/** Load sound
* @private
*
* @param {String} filePath - audio file to be loaded
*/
SoundBuffered.prototype._load = function (filePath) {
SoundBuffered.prototype._load = function () {
var self = this;

this._createAudioNodes();

function loadFail() {
function loadFail(error) {
// TODO: keep track that loading has failed so we don't retry to load it ?
self._finalizeLoad('Sound could not be loaded.');
self._finalizeLoad(error);
}

function onAudioLoaded(buffer) {
Expand All @@ -183,7 +181,7 @@ SoundBuffered.prototype._load = function (filePath) {
xobj.onreadystatechange = function onXhrStateChange() {
if (~~xobj.readyState !== 4) return;
if (~~xobj.status !== 200 && ~~xobj.status !== 0) {
return loadFail();
return loadFail('xhrError:' + xobj.status);
}
if (self.audioContext) {
self.audioContext.decodeAudioData(xobj.response, onAudioLoaded, loadFail);
Expand All @@ -192,14 +190,29 @@ SoundBuffered.prototype._load = function (filePath) {
self._finalizeLoad(null);
}
};

xobj.open('GET', uri, true);
xobj.send();
}

if (window.wizAssets) {
window.wizAssets.downloadFile(filePath, this._src, loadAudio, loadFail);
var getFileUri = this.audioManager.settings.getFileUri;
var audioPath = this.audioManager.settings.audioPath;

if (getFileUri.length > 2) {
// asynchronous
getFileUri(audioPath, this.id, function onUri(error, uri) {
if (error) return loadFail(error);
loadAudio(uri);
});
} else {
loadAudio(filePath);
// synchronous
try {
var uri = getFileUri(audioPath, this.id);
if (!uri) return loadFail('emptyUri');
loadAudio(uri);
} catch (error) {
loadFail(error);
}
}
};

Expand Down Expand Up @@ -233,8 +246,8 @@ SoundBuffered.prototype._play = function (pitch) {
}

// prevent a looped sound to play twice
// TODO: add a flag to allow force restart
if (this.loop && this.playing) {
// TODO: restart sound from beginning
// update pitch if needed
if ((pitch || pitch === 0) && pitch !== this._playPitch) {
this._playPitch = pitch;
Expand All @@ -243,15 +256,19 @@ SoundBuffered.prototype._play = function (pitch) {
return;
}

// if sound is still fading out, we stop and clear it before restarting it
this.playing = true;
this.gain.setTargetAtTime(this.volume, this.audioContext.currentTime, this.fade);

// if sound is still fading out, clear all onStop callback
if (this._fadeTimeout) {
this._onStopCallback = null;
this._stopAndClear();
this.stopping = false;
this.source.onended = null;
window.clearTimeout(this._fadeTimeout);
this._fadeTimeout = null;
return;
}

this.playing = true;
this.gain.setTargetAtTime(this.volume, this.audioContext.currentTime, this.fade);

var sourceNode = this.source = this.audioContext.createBufferSource();
sourceNode.connect(this.sourceConnector);

Expand Down
2 changes: 1 addition & 1 deletion component.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "AudioManager",
"repo": "Wizcorp/AudioManager",
"version": "0.1.5",
"version": "0.1.6",
"description": "Play sounds using Web Audio, fallback to HTML5 Audio",
"dependencies": {
"Wizcorp/util": "0.1.0"
Expand Down
8 changes: 4 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ function AudioManager(channels) {
// settings
this.settings = {
audioPath: '', // path to audio assets folder
assetSeverUrl: '', // asset server url
maxSoundGroup: 500,
maxUsedMemory: 300, // seconds
defaultFade: 2, // seconds
maxPlayLatency: 1000, // milliseconds
fadeOutRatio: 0.4,
crossFading: false
crossFading: false,
getFileUri: function getFileUri(audioPath, id) { return audioPath + id + '.mp3'; }
};

// create channels
Expand Down Expand Up @@ -268,8 +268,8 @@ AudioManager.prototype.playLoopSound = function (channelId, soundId, volume, pan
var defaultFade = this.settings.defaultFade;
var crossFading = this.settings.crossFading;
var channel = this.channels[channelId];
var currentSoundId = channel.loopId;
var currentSound = channel.loopSound;
var currentSoundId = currentSound && currentSound.id;

volume = Math.max(0, Math.min(1, volume || 1));

Expand All @@ -280,7 +280,7 @@ AudioManager.prototype.playLoopSound = function (channelId, soundId, volume, pan
if (channel.muted) return;

// if requested sound is already playing, update volume, pan and pitch
if (soundId === currentSoundId && currentSound && currentSound.playing) {
if (soundId === currentSoundId && currentSound && (currentSound.playing || currentSound.stopping)) {
currentSound.play(volume * channel.volume, pan, pitch);
if (channel.nextLoop) {
channel.nextLoop.cancelOnLoadCallbacks();
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "audio-manager",
"version": "0.1.5",
"version": "0.1.6",
"description": "Play sounds using Web Audio, fallback to HTML5 Audio",
"main": "index.js",
"scripts": {
Expand Down

0 comments on commit 543fae8

Please sign in to comment.