mirror of
https://github.com/doublespeakgames/adarkroom.git
synced 2026-05-28 00:01:54 +08:00
refactor audio engine: simplified gain channels, improve fading between audio, rename functions
This commit is contained in:
+106
-115
@@ -4,158 +4,157 @@
|
||||
var AudioEngine = {
|
||||
FADE_TIME: 1,
|
||||
AUDIO_BUFFER_CACHE: {},
|
||||
_audioPreloaded: false,
|
||||
audioContext: null,
|
||||
master: null,
|
||||
tracks: {
|
||||
'bg1': null,
|
||||
'bg2': null,
|
||||
'events': null,
|
||||
'sfx': null
|
||||
_audioContext: null,
|
||||
_master: null,
|
||||
_currentBackgroundMusic: null,
|
||||
_currentEventAudio: null,
|
||||
_currentSoundEffectAudio: null,
|
||||
init: function () {
|
||||
AudioEngine._initAudioContext();
|
||||
},
|
||||
currentBackgroundChannel: 'bg1',
|
||||
currentBackgroundAudio: null,
|
||||
currentEventAudio: null,
|
||||
init: function (options) {
|
||||
AudioEngine.initAudioContext();
|
||||
},
|
||||
initAudioContext: function () {
|
||||
_initAudioContext: function () {
|
||||
// for legacy browsers
|
||||
AudioEngine.audioContext = new (window.AudioContext || window.webkitAudioContext);
|
||||
|
||||
if (AudioEngine.audioContext.state === 'suspended') {
|
||||
AudioEngine.audioContext.resume().then(function () {
|
||||
AudioEngine.createChannels();
|
||||
AudioEngine._audioContext = new (window.AudioContext || window.webkitAudioContext);
|
||||
if (AudioEngine._audioContext.state === 'suspended') {
|
||||
AudioEngine._audioContext.resume().then(function () {
|
||||
AudioEngine._createMasterChannel();
|
||||
});
|
||||
} else {
|
||||
AudioEngine.createChannels();
|
||||
AudioEngine._createMasterChannel();
|
||||
}
|
||||
},
|
||||
createChannels: function () {
|
||||
_createMasterChannel: function () {
|
||||
// create master
|
||||
AudioEngine.master = AudioEngine.audioContext.createGain();
|
||||
AudioEngine.master.gain.setValueAtTime(1.0, AudioEngine.audioContext.currentTime);
|
||||
AudioEngine.master.connect(AudioEngine.audioContext.destination);
|
||||
|
||||
// create 4 tracks to output to master
|
||||
AudioEngine.tracks['bg1'] = AudioEngine.audioContext.createGain();
|
||||
AudioEngine.tracks['bg1'].connect(AudioEngine.master);
|
||||
AudioEngine.tracks['bg1'].gain.setValueAtTime(1.0, AudioEngine.audioContext.currentTime);
|
||||
AudioEngine.tracks['bg2'] = AudioEngine.audioContext.createGain();
|
||||
AudioEngine.tracks['bg2'].connect(AudioEngine.master);
|
||||
AudioEngine.tracks['bg2'].gain.setValueAtTime(1.0, AudioEngine.audioContext.currentTime);
|
||||
AudioEngine.tracks['events'] = AudioEngine.audioContext.createGain();
|
||||
AudioEngine.tracks['events'].connect(AudioEngine.master);
|
||||
AudioEngine.tracks['events'].gain.setValueAtTime(1.0, AudioEngine.audioContext.currentTime);
|
||||
AudioEngine.tracks['sfx'] = AudioEngine.audioContext.createGain();
|
||||
AudioEngine.tracks['sfx'].connect(AudioEngine.master);
|
||||
AudioEngine.tracks['sfx'].gain.setValueAtTime(1.0, AudioEngine.audioContext.currentTime);
|
||||
AudioEngine._master = AudioEngine._audioContext.createGain();
|
||||
AudioEngine._master.gain.setValueAtTime(1.0, AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._master.connect(AudioEngine._audioContext.destination);
|
||||
},
|
||||
options: {}, // Nothing for now,
|
||||
_canPlayAudio: function () {
|
||||
if (AudioEngine.audioContext.state === 'suspended') {
|
||||
if (AudioEngine._audioContext.state === 'suspended') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
_getMissingAudioBuffer: function () {
|
||||
var buffer = AudioEngine.audioContext.createBuffer(
|
||||
// plays beeping sound to indicate missing audio
|
||||
var buffer = AudioEngine._audioContext.createBuffer(
|
||||
1,
|
||||
AudioEngine.audioContext.sampleRate,
|
||||
AudioEngine.audioContext.sampleRate
|
||||
AudioEngine._audioContext.sampleRate,
|
||||
AudioEngine._audioContext.sampleRate
|
||||
);
|
||||
// Fill the buffer
|
||||
var bufferData = buffer.getChannelData(0);
|
||||
for (var i = 0; i < buffer.length / 2; i++) {
|
||||
bufferData[i] = Math.sin(i * .05) / 2;
|
||||
bufferData[i] = Math.sin(i * .05) / 4; // max .25 gain value
|
||||
}
|
||||
return buffer;
|
||||
},
|
||||
_playSound: function (buffer) {
|
||||
if (!AudioEngine._canPlayAudio()) return;
|
||||
|
||||
var source = AudioEngine.audioContext.createBufferSource();
|
||||
var source = AudioEngine._audioContext.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.connect(AudioEngine.tracks['sfx']);
|
||||
source.start(AudioEngine.audioContext.currentTime);
|
||||
source.connect(AudioEngine._master);
|
||||
source.start();
|
||||
|
||||
AudioEngine._currentSoundEffectAudio = {
|
||||
source: source
|
||||
};
|
||||
},
|
||||
_fadeTrack: function (buffer) {
|
||||
_playBackgroundMusic: function (buffer) {
|
||||
if (!AudioEngine._canPlayAudio()) return;
|
||||
|
||||
var bufferSource = AudioEngine.audioContext.createBufferSource();
|
||||
bufferSource.buffer = buffer;
|
||||
bufferSource.loop = true;
|
||||
var source = AudioEngine._audioContext.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.loop = true;
|
||||
|
||||
// figure out which background track to start on
|
||||
// in order to do crossfade
|
||||
var nextBackgroundChannel;
|
||||
if (AudioEngine.currentBackgroundChannel === 'bg1') {
|
||||
nextBackgroundChannel = 'bg2';
|
||||
} else {
|
||||
nextBackgroundChannel = 'bg1';
|
||||
var envelope = AudioEngine._audioContext.createGain();
|
||||
envelope.gain.setValueAtTime(0.0, AudioEngine._audioContext.currentTime);
|
||||
|
||||
var fadeTime = AudioEngine._audioContext.currentTime + AudioEngine.FADE_TIME;
|
||||
|
||||
// fade out current background music
|
||||
if (AudioEngine._currentBackgroundMusic) {
|
||||
var currentBackgroundGainValue = AudioEngine._currentBackgroundMusic.envelope.gain.value;
|
||||
AudioEngine._currentBackgroundMusic.envelope.gain.cancelScheduledValues(AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._currentBackgroundMusic.envelope.gain.setValueAtTime(currentBackgroundGainValue, AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._currentBackgroundMusic.envelope.gain.linearRampToValueAtTime(0.0, fadeTime);
|
||||
AudioEngine._currentBackgroundMusic.source.stop(fadeTime + 0.3); // make sure fade has completed
|
||||
}
|
||||
|
||||
// fade in new track
|
||||
var fadeTime = AudioEngine.audioContext.currentTime + AudioEngine.FADE_TIME;
|
||||
bufferSource.connect(AudioEngine.tracks[nextBackgroundChannel]);
|
||||
bufferSource.start(AudioEngine.audioContext.currentTime);
|
||||
AudioEngine.tracks[nextBackgroundChannel].gain.setValueAtTime(0.0, AudioEngine.audioContext.currentTime);
|
||||
AudioEngine.tracks[nextBackgroundChannel].gain.linearRampToValueAtTime(1.0, fadeTime);
|
||||
// fade in new backgorund music
|
||||
source.connect(envelope);
|
||||
envelope.connect(AudioEngine._master);
|
||||
source.start();
|
||||
envelope.gain.linearRampToValueAtTime(1.0, fadeTime);
|
||||
|
||||
// fade out old track
|
||||
AudioEngine.tracks[AudioEngine.currentBackgroundChannel].gain.linearRampToValueAtTime(0.0, fadeTime);
|
||||
if (AudioEngine.currentBackgroundAudio) {
|
||||
AudioEngine.currentBackgroundAudio.stop(fadeTime + 0.3); // make sure fade has completed
|
||||
}
|
||||
|
||||
// switch background track
|
||||
AudioEngine.currentBackgroundChannel = nextBackgroundChannel;
|
||||
AudioEngine.currentBackgroundAudio = bufferSource;
|
||||
// update current background music
|
||||
AudioEngine._currentBackgroundMusic = {
|
||||
source: source,
|
||||
envelope: envelope
|
||||
};
|
||||
},
|
||||
_playEvent: function (buffer) {
|
||||
_playEventMusic: function (buffer) {
|
||||
if (!AudioEngine._canPlayAudio()) return;
|
||||
|
||||
var bufferSource = AudioEngine.audioContext.createBufferSource();
|
||||
bufferSource.buffer = buffer;
|
||||
bufferSource.loop = true;
|
||||
var source = AudioEngine._audioContext.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.loop = true;
|
||||
|
||||
var fadeTime = AudioEngine.audioContext.currentTime + AudioEngine.FADE_TIME * 2;
|
||||
var envelope = AudioEngine._audioContext.createGain();
|
||||
envelope.gain.setValueAtTime(0.0, AudioEngine._audioContext.currentTime);
|
||||
|
||||
// turn down background music
|
||||
AudioEngine.tracks['bg1'].gain.linearRampToValueAtTime(0.2, fadeTime);
|
||||
AudioEngine.tracks['bg2'].gain.linearRampToValueAtTime(0.2, fadeTime);
|
||||
var fadeTime = AudioEngine._audioContext.currentTime + AudioEngine.FADE_TIME * 2;
|
||||
|
||||
// turn down current background music
|
||||
if (AudioEngine._currentBackgroundMusic != null) {
|
||||
var currentBackgroundGainValue = AudioEngine._currentBackgroundMusic.envelope.gain.value;
|
||||
AudioEngine._currentBackgroundMusic.envelope.gain.cancelScheduledValues(AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._currentBackgroundMusic.envelope.gain.setValueAtTime(currentBackgroundGainValue, AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._currentBackgroundMusic.envelope.gain.linearRampToValueAtTime(0.2, fadeTime);
|
||||
}
|
||||
|
||||
// fade in event music
|
||||
bufferSource.connect(AudioEngine.tracks['events']);
|
||||
bufferSource.start(0);
|
||||
AudioEngine.currentEventAudio = bufferSource;
|
||||
source.connect(envelope);
|
||||
envelope.connect(AudioEngine._master);
|
||||
source.start();
|
||||
envelope.gain.linearRampToValueAtTime(1.0, fadeTime);
|
||||
|
||||
AudioEngine.tracks['events'].gain.setValueAtTime(0.0, AudioEngine.audioContext.currentTime);
|
||||
AudioEngine.tracks['events'].gain.linearRampToValueAtTime(1.0, fadeTime);
|
||||
// update reference
|
||||
AudioEngine._currentEventAudio = {
|
||||
source: source,
|
||||
envelope: envelope
|
||||
};
|
||||
},
|
||||
_stopEventMusic: function () {
|
||||
var fadeTime = AudioEngine.audioContext.currentTime + AudioEngine.FADE_TIME * 2;
|
||||
var fadeTime = AudioEngine._audioContext.currentTime + AudioEngine.FADE_TIME * 2;
|
||||
|
||||
// fade out event music and stop
|
||||
AudioEngine.tracks['events'].gain.linearRampToValueAtTime(0.0, fadeTime);
|
||||
if (AudioEngine.currentEventAudio) {
|
||||
AudioEngine.currentEventAudio.stop(fadeTime + 1); // make sure fade has completed
|
||||
AudioEngine.currentEventAudio = null;
|
||||
if (AudioEngine._currentEventAudio) {
|
||||
var currentEventGainValue = AudioEngine._currentEventAudio.envelope.gain.value;
|
||||
AudioEngine._currentEventAudio.envelope.gain.cancelScheduledValues(AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._currentEventAudio.envelope.gain.setValueAtTime(currentEventGainValue, AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._currentEventAudio.envelope.gain.linearRampToValueAtTime(0.0, fadeTime);
|
||||
AudioEngine._currentEventAudio.source.stop(fadeTime + 1); // make sure fade has completed
|
||||
AudioEngine._currentEventAudio = null;
|
||||
}
|
||||
|
||||
// turn up background music
|
||||
AudioEngine.tracks[AudioEngine.currentBackgroundChannel].gain.linearRampToValueAtTime(1.0, fadeTime);
|
||||
var currentBackgroundGainValue = AudioEngine._currentBackgroundMusic.envelope.gain.value;
|
||||
AudioEngine._currentBackgroundMusic.envelope.gain.cancelScheduledValues(AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._currentBackgroundMusic.envelope.gain.setValueAtTime(currentBackgroundGainValue, AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._currentBackgroundMusic.envelope.gain.linearRampToValueAtTime(1.0, fadeTime);
|
||||
},
|
||||
changeMusic: function (src) {
|
||||
playBackgroundMusic: function (src) {
|
||||
AudioEngine.loadAudioFile(src)
|
||||
.then(function (buffer) {
|
||||
AudioEngine._fadeTrack(buffer);
|
||||
AudioEngine._playBackgroundMusic(buffer);
|
||||
});
|
||||
},
|
||||
playEventMusic: function (src) {
|
||||
AudioEngine.loadAudioFile(src)
|
||||
.then(function (buffer) {
|
||||
AudioEngine._playEvent(buffer);
|
||||
AudioEngine._playEventMusic(buffer);
|
||||
});
|
||||
},
|
||||
stopEventMusic: function () {
|
||||
@@ -185,37 +184,29 @@ var AudioEngine = {
|
||||
return AudioEngine._getMissingAudioBuffer();
|
||||
}
|
||||
|
||||
return AudioEngine.audioContext.decodeAudioData(buffer, function (decodedData) {
|
||||
return AudioEngine._audioContext.decodeAudioData(buffer, function (decodedData) {
|
||||
AudioEngine.AUDIO_BUFFER_CACHE[src] = decodedData;
|
||||
return AudioEngine.AUDIO_BUFFER_CACHE[src];
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
mute: function () {
|
||||
AudioEngine.master.gain.linearRampToValueAtTime(
|
||||
0.0,
|
||||
AudioEngine.audioContext.currentTime + AudioEngine.FADE_TIME
|
||||
);
|
||||
},
|
||||
getVolume: function () {
|
||||
return AudioEngine.master.gain.value;
|
||||
},
|
||||
setVolume: function (volume, s) {
|
||||
if (!AudioEngine.master) return; // master may not be ready yet
|
||||
if (!volume) {
|
||||
if (AudioEngine._master == null) return; // master may not be ready yet
|
||||
if (volume === undefined) {
|
||||
volume = 1.0;
|
||||
}
|
||||
if (!s) {
|
||||
if (s === undefined) {
|
||||
s = 1.0;
|
||||
}
|
||||
AudioEngine.master.gain.setValueAtTime(
|
||||
AudioEngine.master.gain.value,
|
||||
AudioEngine.audioContext.currentTime
|
||||
);
|
||||
AudioEngine.master.gain.linearRampToValueAtTime(
|
||||
|
||||
// cancel any current schedules and then ramp
|
||||
var currentGainValue = AudioEngine._master.gain.value;
|
||||
AudioEngine._master.gain.cancelScheduledValues(AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._master.gain.setValueAtTime(currentGainValue, AudioEngine._audioContext.currentTime);
|
||||
AudioEngine._master.gain.linearRampToValueAtTime(
|
||||
volume,
|
||||
AudioEngine.audioContext.currentTime + s
|
||||
AudioEngine._audioContext.currentTime + s
|
||||
);
|
||||
}
|
||||
};
|
||||
+1
-1
@@ -805,7 +805,7 @@
|
||||
if ($SM.get('config.soundOn')) {
|
||||
$('.volume').text(_('sound on.'));
|
||||
$SM.set('config.soundOn', false);
|
||||
AudioEngine.mute();
|
||||
AudioEngine.setVolume(0.0);
|
||||
} else {
|
||||
$('.volume').text(_('sound off.'));
|
||||
$SM.set('config.soundOn', true);
|
||||
|
||||
+6
-6
@@ -591,17 +591,17 @@ var Outside = {
|
||||
// set music
|
||||
var numberOfHuts = $SM.get('game.buildings["hut"]', true);
|
||||
if(numberOfHuts === 0) {
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_SILENT_FOREST);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_SILENT_FOREST);
|
||||
} else if(numberOfHuts == 1) {
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_LONELY_HUT);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_LONELY_HUT);
|
||||
} else if(numberOfHuts <= 4) {
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_TINY_VILLAGE);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_TINY_VILLAGE);
|
||||
} else if(numberOfHuts <= 8) {
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_MODEST_VILLAGE);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_MODEST_VILLAGE);
|
||||
} else if(numberOfHuts <= 14) {
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_LARGE_VILLAGE);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_LARGE_VILLAGE);
|
||||
} else {
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_RAUCOUS_VILLAGE);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_RAUCOUS_VILLAGE);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
+1
-1
@@ -304,7 +304,7 @@ var Path = {
|
||||
Path.updateOutfitting();
|
||||
Path.updatePerks(true);
|
||||
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_DUSTY_PATH);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_DUSTY_PATH);
|
||||
|
||||
Engine.moveStoresView($('#perks'), transition_diff);
|
||||
},
|
||||
|
||||
+5
-5
@@ -1232,19 +1232,19 @@ var Room = {
|
||||
var fireValue = $SM.get('game.fire.value');
|
||||
switch (fireValue) {
|
||||
case 0:
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_FIRE_DEAD);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_FIRE_DEAD);
|
||||
break;
|
||||
case 1:
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_FIRE_SMOLDERING);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_FIRE_SMOLDERING);
|
||||
break;
|
||||
case 2:
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_FIRE_FLICKERING);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_FIRE_FLICKERING);
|
||||
break;
|
||||
case 3:
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_FIRE_BURNING);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_FIRE_BURNING);
|
||||
break;
|
||||
case 4:
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_FIRE_ROARING);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_FIRE_ROARING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ var Ship = {
|
||||
Notifications.notify(Ship, _('somewhere above the debris cloud, the wanderer fleet hovers. been on this rock too long.'));
|
||||
$SM.set('game.spaceShip.seenShip', true);
|
||||
}
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_SHIP);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_SHIP);
|
||||
|
||||
Engine.moveStoresView(null, transition_diff);
|
||||
},
|
||||
|
||||
+3
-3
@@ -53,7 +53,7 @@ var Space = {
|
||||
Space.hull = Ship.getMaxHull();
|
||||
Space.altitude = 0;
|
||||
Space.setTitle();
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_SPACE);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_SPACE);
|
||||
Space.updateHull();
|
||||
|
||||
Space.up =
|
||||
@@ -68,7 +68,7 @@ var Space = {
|
||||
Space.startAscent();
|
||||
Space._shipTimer = setInterval(Space.moveShip, 33);
|
||||
Space._volumeTimer = setInterval(Space.lowerVolume, 1000);
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_SPACE);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_SPACE);
|
||||
},
|
||||
|
||||
setTitle: function() {
|
||||
@@ -401,7 +401,7 @@ var Space = {
|
||||
delete Outside._popTimeout;
|
||||
|
||||
AudioEngine.setVolume(1.0);
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_ENDING);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_ENDING);
|
||||
$('#hullRemaining', Space.panel).animate({opacity: 0}, 500, 'linear');
|
||||
Space.ship.animate({
|
||||
top: '350px',
|
||||
|
||||
+1
-1
@@ -1012,7 +1012,7 @@ var World = {
|
||||
World.curPos = World.copyPos(World.VILLAGE_POS);
|
||||
World.drawMap();
|
||||
World.setTitle();
|
||||
AudioEngine.changeMusic(AudioLibrary.MUSIC_WORLD);
|
||||
AudioEngine.playBackgroundMusic(AudioLibrary.MUSIC_WORLD);
|
||||
World.dead = false;
|
||||
$('div#bagspace-world > div').empty();
|
||||
World.updateSupplies();
|
||||
|
||||
Reference in New Issue
Block a user