SoundFX Singleton

Basic Sound Controller Singleton

by Noncho Savov

HTML

<div>
	<input type="button" id="start" value="SoundFX.start();" style="margin-top: 4px; margin-right: 4px;">
</div>
<div id="ui" style="opacity:.5;pointer-events:none">
	<div id="volumeUI" style="display:none">
		Master SoundFX.volume:<input id="masterVolume" type="text" style="width:50px" value="1">
	</div>
	<br/>
	<div id="buttons">
		<b>SoundFX sounds and effects:</b><br/>
	</div>
	<div id="custom">
		<br/><b>Create your own sound:</b><br/>
		Starting Frequency:<br/><input type="text" id="frequency"><br/>
		Frequency Change value (+/-):<br/><input type="text" id="change"><br/>
		Duration (animation frames):<br/><input type="text" id="duration"><br/>
		Type (0-3 int):<br/><input type="text" id="type"><br/>
		Volume (0-1 float):<br/><input type="text" id="volume"><br/>
		Delay (frames):<br/><input type="text" id="delay"><br/>
		Pitch (0-Duration/4 int):<br/><input type="text" id="pitch"><br/>
		<input style="margin-top:8px;" type="button" id="play" value="Play Sound" disabled>
	</div>
</div>

JavaScript

var SoundFX = (function() {
	// Note: The Web Audio API will be included in the Chrome autoplay policy with M71 (December 2018).
	// Audio Context needs to be initialized after some sort of user interaction has been occured first, otherwise
	// it will be created in the "suspended" state and you will need to call resume() after a user gesture is received.
	// To prevent that and to avoid seeing warnings in the console, use the method SoundFX.start()
	
	var audioContext;
	var oscTypes = ["square", "sawtooth", "triangle", "sine"];
	var initialized;
	var volume = 1;
	
	function start(_volume){
		try {
			audioContext = new (
				window.AudioContext ||
				window.webkitAudioContext ||
				window.mozAudioContext ||
				window.msAudioContext ||
				window.oAudioContext
			)();
			if(_volume) setVolume(_volume);
			initialized = true;
			console.log("[Event] AudioContext initialized");
		} catch(e){
			console.log("[Warning] AudioContext not found",e);
		}
	}
	
	
	// start frequency HZ
	// frequency change in time + / -
	// length (number of frames taking to play the sound)
	// volume of the current sound: 0.0 - 1.0 (multiplied by SoundFX.volume)
	// oscillator type 0 - 3 ("square", "sawtooth", "triangle", "sine")
	// starting delay (frames  of silence before the sound starts)
	// gradually ramp up the volume by a few frames: 0 - _duration/5
	
	function playSound(_frequency, _change, _duration, _volume, _type, _delay, _pitch){
		
		// validation
		if(!audioContext || !_duration || !_volume) return;
		if(_pitch > _duration/4|0) _pitch = _duration/4|0;
		
		// instantiate oscillator
		var oscillator = audioContext.createOscillator();
		oscillator.type = oscTypes[_type%4|0];
		
		// instantiate modulation for sound volume control
		var modulationGain = audioContext.createGain();
		
		// set the volume to 0 at the beginning to prevent sound glitches
		modulationGain.gain.value = 0;
		
		// frame counter, using requestAnimationFrame - all measures are in frames
		var i =...