forked from google/santa-tracker-web
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsoundcontroller.js
More file actions
214 lines (190 loc) · 6.81 KB
/
Copy pathsoundcontroller.js
File metadata and controls
214 lines (190 loc) · 6.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
/* global Klang */
/**
* @constructor
* @struct
* @param {function(string)} loadCallback Callback to be notified when a set of
* sounds are loaded.
*/
function SoundController(loadCallback) {
// load Klang
var klangScript = document.createElement('script');
klangScript.src = SoundController.klangSrc_;
klangScript.addEventListener('load', this.loadKlangConfig_.bind(this));
document.head.appendChild(klangScript);
/**
* A queue of the sounds to load as soon as Klang is ready to go.
* @private {!Array<string>}
*/
this.loadQueue_ = [];
/**
* A queue of the sounds to play as soon as the currently loading sounds
* finish downloading.
* @private {!Array<SoundController.SoundDetail>}
*/
this.soundQueue_ = [];
/**
* Whether Klang and the config file have finished loading.
* @private {boolean}
*/
this.klangLoaded_ = false;
/**
* The name of the most recently requested set of sounds, or null if the last
* requested set of sounds is loaded.
* @private {?string}
*/
this.loadingSounds_ = null;
/**
* Optional callback to be notified when a set of sounds are loaded.
* @private {function(string)}
*/
this.loadCallback_ = loadCallback;
}
/**
* Sounds can be played by either directly by supplying the name, or as an
* object with the sound name and any optional arguments necessary to play it.
* @typedef {string|{name: string, args: (Array<*>|undefined)}}
*/
SoundController.SoundDetail;
/**
* Klang script source URL.
* @private {string}
*/
SoundController.klangSrc_ = 'third_party/lib/klang/klang.min.js';
/**
* Klang config file URL.
* @private {string}
*/
SoundController.klangConfigSrc_ = 'third_party/lib/klang/config.json';
/**
* Loads the Klang config file; called onload of the Klang library.
* @private
*/
SoundController.prototype.loadKlangConfig_ = function() {
// load config script
Klang.init(SoundController.klangConfigSrc_, function(success) {
if (success) {
console.log('Klang loaded');
this.klangLoaded_ = true;
// Run any queued loads of sound sets. Usually only one set of sounds has
// been queued, but prioritize the most recent in case of more.
for (var i = this.loadQueue_.length - 1; i >= 0; i--) {
this.triggerSoundsLoad_(this.loadQueue_[i]);
}
this.loadQueue_ = [];
} else {
console.log('Klang failed to load');
}
}.bind(this));
};
/**
* Load a set of sounds based on a `sound-preload` event.
* @param {{detail: SoundController.SoundDetail}} loadEvent
*/
SoundController.prototype.loadSounds = function(loadEvent) {
this.loadingSounds_ = /** @type {string} */(loadEvent.detail);
// a new load has been triggered, so cancel any existing queued ambient sounds
this.soundQueue_ = [];
if (!this.klangLoaded_) {
// Sound loads predominantly only happen in onPreload, so will only be
// done once, so if Klang hasn't finished loading, queue sound load calls.
this.loadQueue_.push(this.loadingSounds_);
return;
}
this.triggerSoundsLoad_(this.loadingSounds_);
};
/**
* Actually trigger the sound load via Klang. Should not be called until after
* Klang has finished loading.
* @param {string} soundsName
* @private
*/
SoundController.prototype.triggerSoundsLoad_ = function(soundsName) {
// Klang is already loaded, so attempt to load sound files
Klang.triggerEvent(soundsName,
function success() {
// If this is also the most recently loaded set of sounds, play all queued
// ambient sounds and clear queue.
if (soundsName === this.loadingSounds_) {
for (var i = 0; i < this.soundQueue_.length; i++) {
// Fine to play them all. Klang appears to correctly handle running
// even scene_start and scene_end ambient sounds back to back.
console.log('Klang: playing queued sound ' + this.soundQueue_[i]);
this.triggerSound_(this.soundQueue_[i]);
}
this.loadingSounds_ = null;
this.soundQueue_ = [];
}
// Signal that sounds have loaded (after any queued sounds have begun).
this.loadCallback_(soundsName);
console.log('Klang: loaded sound ' + soundsName);
}.bind(this),
function progress() {
// for now, we don't care about this
},
function failure() {
console.warn('Klang failed to load ' + soundsName);
if (soundsName === this.loadingSounds_) {
this.loadingSounds_ = null;
this.soundQueue_ = [];
}
}.bind(this));
};
/**
* Play a Klang ambient-sound "script" based on a`sound-ambient` event.
* Ambient sounds include the soundtrack and any environmental noises that are
* scripted in a sequence inside of Klang's config file.
* @param {{detail: SoundController.SoundDetail}} loadEvent
*/
SoundController.prototype.playAmbientSounds = function(loadEvent) {
// ambient sounds are important, so queue them up if the last load (or loading
// Klang itself) hasn't finished yet
if (!this.klangLoaded_ || this.loadingSounds_) {
this.soundQueue_.push(loadEvent.detail);
} else {
console.log('Klang: playing sound ' + loadEvent.detail);
this.triggerSound_(loadEvent.detail);
}
};
/**
* Play a transient sound based on a `sound-trigger` event. Transient sounds are
* sounds like an on-click sound, or a missed-objective sound in a game.
* @param {{detail: SoundController.SoundDetail}} loadEvent
*/
SoundController.prototype.playSound = function(loadEvent) {
// transient sounds aren't important, so attempt to play if Klang itself is
// loaded, even if the scene's sounds are not. Some sounds are shared between
// scenes, so it's possible it's already loaded, and if not, this particular
// sound event likely won't be relevant by the time it is loaded.
if (this.klangLoaded_) {
this.triggerSound_(loadEvent.detail);
}
};
/**
* Actually trigger the sound via Klang. Should not be called until after Klang
* has finished loading.
* @param {SoundController.SoundDetail} sound
* @private
*/
SoundController.prototype.triggerSound_ = function(sound) {
var soundName = typeof sound === 'string' ? sound : sound.name;
var args = [soundName];
if (sound.args && Array.isArray(sound.args)) {
[].push.apply(args, sound.args);
}
Klang.triggerEvent.apply(Klang, args);
};