Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Blockly sound playing and replace with a callback #86

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 17 additions & 19 deletions blockly_compressed_horizontal.js

Large diffs are not rendered by default.

36 changes: 17 additions & 19 deletions blockly_compressed_vertical.js

Large diffs are not rendered by default.

29 changes: 15 additions & 14 deletions blockly_uncompressed_horizontal.js

Large diffs are not rendered by default.

29 changes: 15 additions & 14 deletions blockly_uncompressed_vertical.js

Large diffs are not rendered by default.

30 changes: 0 additions & 30 deletions core/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -442,36 +442,6 @@ Blockly.init_ = function(mainWorkspace) {
mainWorkspace.scrollbar = new Blockly.ScrollbarPair(mainWorkspace);
mainWorkspace.scrollbar.resize();
}

// Load the sounds.
if (options.hasSounds) {
mainWorkspace.loadAudio_(
[options.pathToMedia + 'click.mp3',
options.pathToMedia + 'click.wav',
options.pathToMedia + 'click.ogg'], 'click');
mainWorkspace.loadAudio_(
[options.pathToMedia + 'disconnect.wav',
options.pathToMedia + 'disconnect.mp3',
options.pathToMedia + 'disconnect.ogg'], 'disconnect');
mainWorkspace.loadAudio_(
[options.pathToMedia + 'delete.mp3',
options.pathToMedia + 'delete.ogg',
options.pathToMedia + 'delete.wav'], 'delete');

// Bind temporary hooks that preload the sounds.
var soundBinds = [];
var unbindSounds = function() {
while (soundBinds.length) {
Blockly.unbindEvent_(soundBinds.pop());
}
mainWorkspace.preloadAudio_();
};
// Android ignores any sound not loaded as a result of a user action.
soundBinds.push(
Blockly.bindEvent_(document, 'mousemove', null, unbindSounds));
soundBinds.push(
Blockly.bindEvent_(document, 'touchstart', null, unbindSounds));
}
};

/**
Expand Down
89 changes: 12 additions & 77 deletions core/workspace_svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,10 @@ Blockly.WorkspaceSvg = function(options) {
this.getMetrics = options.getMetrics;
this.setMetrics = options.setMetrics;

Blockly.ConnectionDB.init(this);
/** @type {!Function} */
this.audioCallback_ = null;

/**
* Database of pre-loaded sounds.
* @private
* @const
*/
this.SOUNDS_ = Object.create(null);
Blockly.ConnectionDB.init(this);
};
goog.inherits(Blockly.WorkspaceSvg, Blockly.Workspace);

Expand Down Expand Up @@ -793,82 +789,21 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
};

/**
* Load an audio file. Cache it, ready for instantaneous playing.
* @param {!Array.<string>} filenames List of file types in decreasing order of
* preference (i.e. increasing size). E.g. ['media/go.mp3', 'media/go.wav']
* Filenames include path from Blockly's root. File extensions matter.
* @param {string} name Name of sound.
* @private
*/
Blockly.WorkspaceSvg.prototype.loadAudio_ = function(filenames, name) {
if (!filenames.length) {
return;
}
try {
var audioTest = new window['Audio']();
} catch(e) {
// No browser support for Audio.
// IE can throw an error even if the Audio object exists.
return;
}
var sound;
for (var i = 0; i < filenames.length; i++) {
var filename = filenames[i];
var ext = filename.match(/\.(\w+)$/);
if (ext && audioTest.canPlayType('audio/' + ext[1])) {
// Found an audio format we can play.
sound = new window['Audio'](filename);
break;
}
}
if (sound && sound.play) {
this.SOUNDS_[name] = sound;
}
};

/**
* Preload all the audio files so that they play quickly when asked for.
* @private
* Set the callback for playing audio. The application should provide
* a function that plays the called audio sound.
* @param {!Function} func Function to call.
*/
Blockly.WorkspaceSvg.prototype.preloadAudio_ = function() {
for (var name in this.SOUNDS_) {
var sound = this.SOUNDS_[name];
sound.volume = .01;
sound.play();
sound.pause();
// iOS can only process one sound at a time. Trying to load more than one
// corrupts the earlier ones. Just load one and leave the others uncached.
if (goog.userAgent.IPAD || goog.userAgent.IPHONE) {
break;
}
}
Blockly.Workspace.prototype.setAudioCallback = function(func) {
this.audioCallback_ = func;
};

/**
* Play an audio file at specified value. If volume is not specified,
* use full volume (1).
* Play an audio file at specified value.
* @param {string} name Name of sound.
* @param {number=} opt_volume Volume of sound (0-1).
*/
Blockly.WorkspaceSvg.prototype.playAudio = function(name, opt_volume) {
var sound = this.SOUNDS_[name];
if (sound) {
var mySound;
var ie9 = goog.userAgent.DOCUMENT_MODE &&
goog.userAgent.DOCUMENT_MODE === 9;
if (ie9 || goog.userAgent.IPAD || goog.userAgent.ANDROID) {
// Creating a new audio node causes lag in IE9, Android and iPad. Android
// and IE9 refetch the file from the server, iPad uses a singleton audio
// node which must be deleted and recreated for each new audio tag.
mySound = sound;
} else {
mySound = sound.cloneNode();
}
mySound.volume = (opt_volume === undefined ? 1 : opt_volume);
mySound.play();
} else if (this.options.parentWorkspace) {
// Maybe a workspace on a lower level knows about this sound.
this.options.parentWorkspace.playAudio(name, opt_volume);
Blockly.WorkspaceSvg.prototype.playAudio = function(name) {
if (this.audioCallback_) {
this.audioCallback_(name);
}
};

Expand Down
Binary file added demos/audio/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
146 changes: 146 additions & 0 deletions demos/audio/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Fixed Blockly</title>
<script src="../../blockly_compressed_horizontal.js"></script>
<script src="../../blocks_compressed.js"></script>
<script src="../../msg/js/en.js"></script>
<style>
body {
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Audio</h1>

<p>This demo of using the setAudioCallback workspace method with a simple web-based Audio method to register sounds.
Upstream Blockly embeds the audio-playing code directly into the Workspace. We have split out the functionality to allow
for integration with other audio systems.
</p>

<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>

<xml id="toolbox" style="display: none">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="controls_repeat_ext"></block>
<block type="math_number"></block>
<block type="math_arithmetic"></block>
<block type="text"></block>
<block type="text_print"></block>
</xml>

<script>
// Sound system originally from Blockly, combined with new hooks
// Database of sounds
var SOUNDS_ = Object.create(null);

/**
* Load an audio file. Cache it, ready for instantaneous playing.
* @param {!Array.<string>} filenames List of file types in decreasing order of
* preference (i.e. increasing size). E.g. ['media/go.mp3', 'media/go.wav']
* Filenames include path from Blockly's root. File extensions matter.
* @param {string} name Name of sound.
*/
var loadAudio_ = function(filenames, name) {
if (!filenames.length) {
return;
}
try {
var audioTest = new window['Audio']();
} catch(e) {
// No browser support for Audio.
// IE can throw an error even if the Audio object exists.
return;
}
var sound;
for (var i = 0; i < filenames.length; i++) {
var filename = filenames[i];
var ext = filename.match(/\.(\w+)$/);
if (ext && audioTest.canPlayType('audio/' + ext[1])) {
// Found an audio format we can play.
sound = new window['Audio'](filename);
break;
}
}
if (sound && sound.play) {
SOUNDS_[name] = sound;
}
};

/**
* Preload all the audio files so that they play quickly when asked for.
*/
var preloadAudio_ = function() {
for (var name in SOUNDS_) {
var sound = SOUNDS_[name];
sound.volume = .01;
sound.play();
sound.pause();
// iOS can only process one sound at a time. Trying to load more than one
// corrupts the earlier ones. Just load one and leave the others uncached.
if (goog.userAgent.IPAD || goog.userAgent.IPHONE) {
break;
}
}
};

/**
* Play an audio file at specified value. If volume is not specified,
* use full volume (1).
* @param {string} name Name of sound.
* @param {number=} opt_volume Volume of sound (0-1).
*/
var playAudio = function(name, opt_volume) {
var sound = SOUNDS_[name];
if (sound) {
var mySound;
var ie9 = goog.userAgent.DOCUMENT_MODE &&
goog.userAgent.DOCUMENT_MODE === 9;
if (ie9 || goog.userAgent.IPAD || goog.userAgent.ANDROID) {
// Creating a new audio node causes lag in IE9, Android and iPad. Android
// and IE9 refetch the file from the server, iPad uses a singleton audio
// node which must be deleted and recreated for each new audio tag.
mySound = sound;
} else {
mySound = sound.cloneNode();
}
mySound.volume = (opt_volume === undefined ? 1 : opt_volume);
mySound.play();
} else if (this.options.parentWorkspace) {
// Maybe a workspace on a lower level knows about this sound.
this.options.parentWorkspace.playAudio(name, opt_volume);
}
};

var pathToMedia = '../../media/';
loadAudio_(
[pathToMedia + 'click.mp3',
pathToMedia + 'click.wav',
pathToMedia + 'click.ogg'], 'click');
loadAudio_(
[pathToMedia + 'disconnect.wav',
pathToMedia + 'disconnect.mp3',
pathToMedia + 'disconnect.ogg'], 'disconnect');
loadAudio_(
[pathToMedia + 'delete.mp3',
pathToMedia + 'delete.ogg',
pathToMedia + 'delete.wav'], 'delete');
preloadAudio_();

var workspace = Blockly.inject('blocklyDiv',
{media: pathToMedia,
toolbox: document.getElementById('toolbox')});
workspace.setAudioCallback(playAudio);
</script>

</body>
</html>
11 changes: 11 additions & 0 deletions demos/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,17 @@ <h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt; Demos</h1>
<div>Build custom blocks using Blockly.</div>
</td>
</tr>
<tr>
<td>
<a href="audio/index.html">
<img src="audio/icon.png" height=80 width=100>
</a>
</td>
<td>
<div><a href="audio/index.html">Audio</a></div>
<div>Audio hooks for Blockly.</div>
</td>
</tr>
</table>
</body>
</html>