Skip to content

Commit

Permalink
Update demos in Sound guide
Browse files Browse the repository at this point in the history
  • Loading branch information
williamngan committed Apr 10, 2019
1 parent c9b33f0 commit 2f71247
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 41 deletions.
53 changes: 53 additions & 0 deletions guide/audio_test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<html>

<body>

<h3>Click on the canvas to play</h3>>
<canvas id="canvas" style="background:black;width:512px;height:255px;"></canvas>
<p>If this works in iOS, then we can assume MediaElementAudioSourceNode is now supported.</p>

<script>
var canvas = document.getElementById('canvas');

canvas.addEventListener("click", function () {

var canvasCtx = canvas.getContext("2d");
var audioContext = new (window.AudioContext || window.webkitAudioContext)();
if (audioContext === 'suspended') audioContext.resume();
var analyser = audioContext.createAnalyser();
var data = new Uint8Array(analyser.frequencyBinCount);

function render() {
analyser.getByteTimeDomainData(data);
canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0, l = data.length; i < l; i++) {
canvasCtx.fillStyle = "#ffffff";
canvasCtx.fillRect(i, -(canvas.height / 255) * data[i], 1, canvas.height);
}
requestAnimationFrame(render);
}

requestAnimationFrame(render);

var audio = new Audio("/assets/spacetravel.mp3");
audio.crossOrigin = "anonymous";

audio.addEventListener('error', function (e) {
console.log(e);
});



audio.addEventListener('canplay', function () {
var audioSourceNode = audioContext.createMediaElementSource(audio);

audioSourceNode.connect(analyser);
analyser.connect(audioContext.destination);
if (audioContext === 'suspended') audioContext.resume();
audio.play();
});
});
</script>
</body>

</html>
36 changes: 23 additions & 13 deletions guide/js/examples/sound_frequency.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,31 @@
var files = ["/assets/flute.mp3", "/assets/drum.mp3", "/assets/tambourine.mp3"];
var currFile = 0;
var sound;

// Load next sound file
function nextSound() {
sound = Sound.load( files[currFile] ).analyze(32);
currFile = (currFile + 1) % files.length;
function nextSound( play=true ) {
Sound.load( files[currFile] ).then( (result) => {
sound = result;
sound.analyze(32);
currFile = (currFile + 1) % files.length;
if (play) {
sound.start();
space.replay();
} else {
space.playOnce(50);
}
}).catch( e => console.error(e) );
}

nextSound(false);

// Draw play button
function playButton() {
if (!sound.playing) {
if (!sound || !sound.playing) {
form.fillOnly('rgba(0,0,0,.2)').circle( Circle.fromCenter( space.center, 30 ) );
form.fillOnly('#fff').polygon( Triangle.fromCenter( space.center, 15 ).rotate2D( Const.half_pi, space.center ) );
}
}

nextSound();

// animation
space.add({
Expand All @@ -49,9 +58,10 @@
},

action: (type, x, y) => {
if (type === "up") {
if (!sound.playing) nextSound();
sound.toggle();
if (type === "up" && Geom.withinBound( [x,y], space.center.$subtract( 25 ), space.center.$add( 25 ) )) {
if (!sound || !sound.playing) {
nextSound();
}
}
}
});
Expand All @@ -61,9 +71,9 @@
space.playOnce(200).bindMouse().bindTouch();

// For use in demo page only
if (window.registerDemo) window.registerDemo(demoID, space, null, stopFn);
function stopFn() {
if (sound && sound.playing) sound.stop();
if (window.registerDemo) window.registerDemo(demoID, space, startFn, null, true);
function startFn() {
if (sound && !sound.playing) space.replay();
}


Expand Down
41 changes: 24 additions & 17 deletions guide/js/examples/sound_time.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,38 @@
var sound;

// Load next sound file
function nextSound() {
sound = Sound.load( files[currFile] ).analyze(512);
currFile = (currFile + 1) % files.length;
function nextSound( play=true ) {
Sound.load( files[currFile] ).then( (result) => {
sound = result;
sound.analyze(256);
currFile = (currFile + 1) % files.length;
if (play) {
sound.start();
space.replay();
} else {
space.playOnce(50);
}
}).catch( e => console.error(e) );
}

nextSound(false);

// Draw play button
function playButton() {
if (!sound) return;
if (!sound.playing) {
if (!sound || !sound.playing) {
form.fillOnly('rgba(0,0,0,.2)').circle( Circle.fromCenter( space.center, 30 ) );
form.fillOnly('#fff').polygon( Triangle.fromCenter( space.center, 15 ).rotate2D( Const.half_pi, space.center ) );
}
}

nextSound();

// animation
space.add({

animate: (time, ftime) => {
if (sound && sound.playable) {

// map time domain data to lines drawing two half circles
let tdata = sound.timeDomainTo( [Const.two_pi, 1] ).map( (t, i) => {
let ln = Line.fromAngle( [ (i>256 ? space.size.x : 0), space.center.y ], t.x-Const.half_pi, space.size.y/0.9 );
let ln = Line.fromAngle( [ (i>128 ? space.size.x : 0), space.center.y ], t.x-Const.half_pi, space.size.y/0.9 );
return [ ln.p1, ln.interpolate( t.y ) ]
});

Expand All @@ -45,14 +52,14 @@
form.stroke( `rgba( ${255-c}, 20, ${c}, .7 )`, 1 ).line( tdata[i] );
}
}

playButton();
},

action: (type, x, y) => {
if (type === "up") {
if (!sound.playing) nextSound();
sound.toggle();
if (type === "up" && Geom.withinBound( [x,y], space.center.$subtract( 25 ), space.center.$add( 25 ) )) {
if (!sound || !sound.playing) {
nextSound();
}
}
}
});
Expand All @@ -62,10 +69,10 @@
space.playOnce(200).bindMouse().bindTouch();

// For use in demo page only
if (window.registerDemo) window.registerDemo(demoID, space, null, stopFn);
function stopFn() {
if (sound && sound.playing) sound.stop();
if (window.registerDemo) window.registerDemo(demoID, space, startFn, null, true);
function startFn() {
if (sound && !sound.playing) space.replay();
}


})();
20 changes: 10 additions & 10 deletions guide/js/examples/sound_visual.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,23 @@
var space = new CanvasSpace("#"+demoID).setup({ retina: true, bgcolor: "#e2e6ef", resize: true });
var form = space.getForm();

var sound = Sound.load( "/assets/spacetravel.mp3" ).analyze(bins);
var sound;
var bins = 256;
var ctrls, radius;
var colors = ["#f06", "#62e", "#fff", "#fe3", "#0c9"];

Sound.load( "/assets/spacetravel.mp3" ).then( s => {
sound = s;
sound.analyze(bins);
}).catch( e => console.error(e) );

// Draw play button
function playButton() {
form.fillOnly( sound.playing ? "rgba(0,0,0,.2)" : "#f06").rect( [[0,0], [50,50]] );
if (!sound.playing) {
if (!sound || !sound.playing) {
form.fillOnly("#f06").rect( [[0,0], [50,50]] );
form.fillOnly('#fff').polygon( Triangle.fromCenter( [25,25], 10 ).rotate2D( Const.half_pi, [25,25] ) );
} else {
form.fillOnly("rgba(0,0,0,.2)").rect( [[0,0], [50,50]] );
form.fillOnly("#fff").rect( [[18, 18], [32,32]] );
}
}
Expand Down Expand Up @@ -142,13 +148,7 @@
space.playOnce(200).bindMouse().bindTouch();

// For use in demo page only
if (window.registerDemo) window.registerDemo(demoID, space, null, stopFn);
function stopFn() {
if (sound && sound.playing) {
// shouldStop = true;
// sound.stop();
}
}
if (window.registerDemo) window.registerDemo(demoID, space);


})();
28 changes: 27 additions & 1 deletion src/Play.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,11 @@ export class Sound {
/**
* Create a `Sound` by loading from a sound file or an audio element.
* @param source either an url string to load a sound file, or an audio element.
* @param crossOrigin whether to support loading cross-origin. Default is "anonymous".
* @returns a `Sound` instance
* @example `Sound.load( '/path/to/file.mp3' )`
*/
static load( source:HTMLMediaElement|string ):Promise<Sound> {
static load( source:HTMLMediaElement|string, crossOrigin:string="anonymous" ):Promise<Sound> {
return new Promise( (resolve, reject) => {
let s = new Sound("file");
if (!s) {
Expand All @@ -212,13 +213,38 @@ export class Sound {
}
s.source = (typeof source === 'string') ? new Audio(source) : source;
s.source.autoplay = false;
(s.source as HTMLMediaElement).crossOrigin = crossOrigin;
s.source.addEventListener("ended", function () { s._playing = false; } );
s.source.addEventListener('error', function () { reject("Error loading sound"); });
s.source.addEventListener('canplaythrough', function () {
s.node = s.ctx.createMediaElementSource( s.source );
resolve( s );
});
});

/*
// Sample code of using AudioBufferSourceNode instead of MediaElementAudioSourceNode
// AudioBufferSourceNode can work with iOS and Safari currently. But it's very cumbersome and cannot stream playthrough.
// Not implementing for now.
let request = new XMLHttpRequest();
request.open('GET', source as string, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
s.ctx.decodeAudioData(request.response, function(buffer) {
s.node = s.ctx.createBufferSource();
(s.node as AudioBufferSourceNode ).buffer = buffer;
(s.node as AudioBufferSourceNode ).onended = function (evt) {
console.log( "ended" );
s._playing = false;
};
resolve( s );
}, (err) => reject("Error decoding audio") );
};
request.send();
*/
}


Expand Down

0 comments on commit 2f71247

Please sign in to comment.