Open Source Code on Github

I’ve recently started releasing a bunch of projects on Github, generally these a bits of code that I find to be very useful in many various projects like Event.js, or just a fun little exercise in code like porting the Inkscape Star tool into Javascript, this is an overview of some of my favorites, and code used in many of my projects:

  • Color-Space.js—Library to convert between color spaces: HEX, RGB, RGBA, HSL, HSLA, CMY, CMYK. This makes it easy to convert from strings into color objects, to be easily modified, apply filters to them, and then convert them back to W3 compatible strings.
  • Event.js—Powerful multi-touch events library, and abstractions—click, dblclick, dbltap, tap, longpress, drag, swipe, pinch, rotate, shake. For pointer events, each listener can handle anywhere from 1 to 12 fingers at a time. This library was used to build Sketch Mobile, a good showcase of multitouch interaction, and honestly every project I’ve been involved with.
  • Loader.js—Simple, customizable, loading indicator to use in HTML5 projects. Handles multiple instances, with multiple progress meters running concurrently. Comes with extra libraries to help with Image, Script, Link, and XMLHttp requests. You can see a simple demo of this working on Sketchpad 2.0.
  • MIDI.js—Making life easier if you’re looking to create a MIDI-app on the web. Package includes scripts to convert soundfonts for Guitar, Bass, Drums, and so on, into code that can be read by the browser. This project was modified to be used in the very cool JellyNote, and then also is what runs Color Piano on my website.
  • Sketch.js—Bare-bones vector drawing application framework with animated replay. Includes a basic eraser & brush with catmull smoothing. Can be tied into other drawing tools, and synced across servers with JSON. Built on Event.js, Color.Picker.js & Color.Space.js. I’ve been meaning to turn this into screencast library, for people to create animated drawings to indicate features on their websites—if that sounds like a fun project for you, then feel free to take the reigns of this project in that direction!

Most all code is licensed under MIT, check individual packages for licensing.

If you end up using any of these projects, leave me a note, and I’ll link you somewhere.

adminOpen Source Code on Github

Color Picker

The latest rendition of the Color Picker “Classic”, themed after Photoshop, GIMP, and other image editors—there are no frills here, it’s a basic Hue, Saturation, Luminance, and Alpha (HSVA) color selector. It works in browsers that support the <canvas> element; Firefox 2+, Safari 3+, Opera 9+, Google Chrome, IE9+.

Configuration:

  • size—how large the saturation/luminance area is.
  • hueWidth—how large the alpha/hue area is.
  • autoclose—makes picker self closing when clicking outside the box.
  • color—input rgba() or #hex.
  • callback—sends your color to your custom function.
  • toggle()—true or false, to display and hide.
  • update()—to change the color externally.
  • eyeDropLayer—layer to grab colors from.
  • eyeDropMouseLayer—layer to get events from when grabbing colors.

Basic implementation:

 picker = new Color.Picker({
	color: "#643263", // accepts rgba(), or #hex
	callback: function(rgba, state, type) {
		document.body.style.background = Color.Space(rgba, "RGBA>W3");
	}
});
picker.element.style.top = 220 + "px";
picker.element.style.left = 270 + "px";

You can find this project on Github.

Licensed under the MIT.

adminColor Picker

MIDI.js

MIDI.js (on github) ties together, and builds upon frameworks that bring MIDI generation to the browser. Combine MIDI.js with jasmid to create a web-radio MIDI stream similar to this demo… or with Three.jsSparks.js, or GLSL to create Audio/visual experiments. Piano/guitar simulations, Drum machines, MIDI recording, and all kinds of certified funkitude are within your grasps (with a little elbow grease)!

Google Chrome is recommended for best listening experience—it has timing perfection. Firefox and Safari can both perform a bit more like the piano has been drinking, arrr.

Carpe beerum, and commandeer yer own copy!

The Jack the Tunafish artwork was graciously provided by Boni Deal; http://bonideal.com/

View a live demo of the github project; http://mudcu.be/midi-js/

Please report issues and bugs on Github or here, many thanks 😀

adminMIDI.js

HTML5: SoundFonts

Color Piano Theory is now available on the Chrome Webstore. There haven’t been any major UI overhauls since last reported, but there has been a lot of work going on the back-end! Most importantly moving from the Java interface to native HTML5 <audio> tag (as Java isn’t supported in the Chrome Webstore). Although this sounds like a simple task, there’s a lot of steps involved; hopefully this will save someone else a bit of trouble!

Generating your own soundfont files;

  • JSMIDI will allow you to generate MIDI files with the MidiWriter package;
	var key = 0x45; // the note A4
	var noteEvents = [];
	Array.prototype.push.apply(noteEvents, MidiEvent.createNote(key));
	var track = new MidiTrack({ events: noteEvents});
	var song  = MidiWriter({ tracks: [track] });
	console.log(song.b64);
  • Saving the MIDI files to disk; File Writer API allows you to save those generated MIDI files to your hard-disk, or, alternatively (and a bit more simple in terms of programming), you could POST the base64 from an embedded <iframe> to .PHP, and write to the file-system;
	var iframe = document.createElement("iframe");
	iframe.src = "index.php?midi=" + (song.b64) + "&key=" + key;
	document.body.appendChild(iframe);

 

if ($_REQUEST['midi']) {
	$myFile = "./midi/".$_REQUEST['key'].".mid";
	$fh = fopen($myFile, "w") or die("can't open file");
	fwrite($fh, base64_decode(str_replace(' ','+',$_REQUEST['midi'])));
	fclose($fh);
	return;
}
  • Getting out of MIDI format; At this point, we have a bunch of MIDI files. We need to eventually get these MIDI’s -> OGG format, by mapping it to a high-quality SoundFont;
    • Older versions of iTunes allows you to batch convert from MIDI’s -> MP4’s. That was very nice feature that seems to have disappeared…
    • Online app, such as SolMire, allow you to convert from MIDI’s -> MP3’s and other formats, one at a time. I especially like that SolMire allows you to choose the desired SoundFont to use on the .MIDI.
    • MIDI2MP3 is a command line application available for Window and Mac OSX that enables you to use specific SoundFonts in your encodings, and allows you to use the command line… and therefore the ability for batch MIDI -> WAV conversion! FluidSynth Soundfont GM is a good .SF2 file to get you started 😉
  • Getting into the OGG format;
    • Switch (for Mac) allows you to convert from WAV’s, MP4’s, and MP3’s -> OGG’s.
    • oggenc from Vorbis, allows you do batch conversion of WAV’s -> OGG’s using a bash script. The calls are like this:
      •  ./oggenc -m 64 -M 128 audio.wav
  • Converting the OGG’s -> base64, and storing them in .js or .jgz file(s):
The following code will allow you to take those MIDI files we created with the JSMIDI package (step #1) and convert them from WAV to OGG to JS to JGZ in seconds! Presenting a solution for the batch conversions of multiple MIDI’s into base64 soundfonts;
#!/bin/bash

# gzip     - http://www.gzip.org/
# base64   - http://www.fourmilab.ch/webtools/base64/
# oggenc   - http://www.rarewares.org/ogg-oggenc.php
# midi2mp3 - http://www.audiosoftstore.com/downloads.html

# from MIDI to WAV to OGG to JS to JGZ, and beyond!

find ./directory -name '*.mid' -print0 | while read -d $'\0' file
	do
		# from MIDI to WAV
		./inc/midi2mp3 $file -sf ./sf2/FluidSynth_1.43.sf2 -e wave
		# from WAV to OGG
		./inc/oggenc -m 64 -M 128 $file.wav
		# from OGG to base64 embedded in Javascript
		echo "if (typeof(Soundfont) === 'undefined') Soundfont = {};" > $file.js
		echo "Soundfont['`basename $file`'] = 'data:audio/mpeg;base64,`base64 -i $file.ogg -o -`';" >> $file.js
		# gzipped version
		gzip $file.js -c > $file.jgz
	done
Now you’re ready to create your own custom Soundfont =)
adminHTML5: SoundFonts

Bitwise Gems and other optimizations

One of my favorite posts in the last few years was Bitwise Gems in AS3 by Polygonal Labs, an article inspired by Bitwise Operations in C on Gamedev. This article is a summery of what I’ve learned, applied to Javascript, plus a few other tricks.

What’s the wisdom in using bitwise?

Bitwise operations can be moderately faster than conventional methods. When processing a lot of data, even a 5% increase in speed can become noticeable. A good example of where you would want to use bitwise operations is in the pixel-manipulation of a <canvas> element, especially when dealing with larger dimensions. When you add up all speed improvements here, and then multiply that by each user that uses your application around the world, we could be talking about years of time saved! (in the collective sense) 😉

Standard operation on the (left) === (right) is bitwise or an alternative method such as replacing Math.max(a, b) with (a > b ? a : b). All speed results are measured in Javascript using Google Chrome 15. Without further ado;

Minimize calls to new Object() and new Array();
+/- 50% faster using flat-variables, not bitwise, but still wise.

var rgb = { R: 255, G: 0, B: 0 }; // slow.
var rgb = [ 255, 0, 0 ]; // faster by 40%
var R = 255, G = 0, B = 0; // faster by 50%
[2-23-2012] Updated as per Closure Compiler group discussion.
Rounding, flooring, and ceiling with bit-shifting;
+/- 20% faster using bitwise operations.

var n = Math.PI;
Math.round(n) === n + (n < 0 ? -0.5 : 0.5)>>0
Math.ceil(n) === n + (n < 0 ? 0 : 1) >> 0;
Math.floor(n) === n + (n < 0 ? -1 : 0) >> 0;

Or, if you’re certain the number will be positive (for example dealing with pixel values):

var n = Math.PI;
Math.round(n) === (n + 0.5) >> 0;
Math.ceil(n) === (n + 1) >> 0;
Math.floor(n) === n >> 0;

Storing mathematic constants in local variables;
+/- 15% faster than not doing it, just a reminder 😉

var E = Math.E;
var PI = Math.PI;
var SQRT2 = Math.SQRT2;
var SQRT1_2 = Math.SQRT1_2;
var LN2 = Math.LN2;
var LN10 = Math.LN10;
var LOG2E = Math.LOG2E;
var LOG10E = Math.LOG10E;

Fast modulo operation using bitwise AND (&);
+/- 15% faster using bitwise operations.

var numerator = 99999;
var divisor = 4; // divisor must be power of 2
(numerator % divisor) === (numerator & (divisor - 1));

Math.max & Math.min;
+/- 15% faster using alternate operations.

Math.max(a, b) === (a > b) ? a : b;
Math.min(a, b) ===  (a < b) ? a : b;

Math.abs;
+/- 10% faster using bitwise, or alternate operations.
The best solution here is not the bitwise operation, nor Math.abs().

var n = 99999;
var n = Math.abs(n);
var n = n > 0 ? n : -n; // +/- 10%
var n = (n ^ (n >> 31)) - (n >> 31); // +/- 3%

Test for even/uneven integers using bitwise AND;
+/- 10% faster using bitwise operations.

var n = 99999;
((n % 2) == 0) === ((n & 1) == 0);

Multiply by any power of two using left bit-shifting;
+/- 5% faster using bitwise operations.

var n = 99999;
(n * 2) === (n << 1);
(n * 64) === (n << 6);

Divide by any power of two using right bit-shifting;
+/- 5% faster using bitwise operations.

var n = 99999;
(n / 2) === (n >> 1);
(n / 64) === (n >> 6);

Swap integers without a temporary variable using XOR (^);
+/- 5% faster using bitwise operations.

var a = 1, b = 2;
// standard
var tmp = a;
a = b;
b = tmp;
// bitwise
a ^= b;
b ^= a;
a ^= b;

Sign flipping using NOT (~) or XOR (^);
+/- 2% faster using bitwise operations.

var n = 99999;
(-n) === (~n + 1);

HEX -> RGB conversion;

// 24-bit
var hex = 0x336699;
var r = hex >> 16;
var g = hex >> 8 & 0xFF;
var b = hex & 0xFF;

// 32-bit
var hex = 0xff336699;
var r = hex >> 24;
var g = hex >> 16 & 0xFF;
var b = hex >> 8 & 0xFF;
var a = hex & 0xFF;

RGB -> HEX conversion;

// 24-bit
var r = 0x33;
var g = 0x66;
var b = 0x99;
var hex = r << 16 | g << 8 | b;

// 32-bit
var r = 0x33;
var g = 0x66;
var b = 0x99;
var a = 0xff;
var hex = a << 24 | r << 16 | g << 8 | b;

Fast color conversion from R5G5B5 to R8G8B8 pixel format;

var R8 = (R5 << 3) | (R5 >> 2);
var G8 = (R5 << 3) | (R5 >> 2);
var B8 = (R5 << 3) | (R5 >> 2);

The speed-tests were done with the following code.

// lets pretend were running it on a image 1000x1000 pixels
var size = 1000 * 1000;
// example code
var bit1 = "Math.round(Math.PI)"; // standard
var bit2 = "(Math.PI + 0.5) >> 0"; // bitwise
// create the speedtest
function createFunction(f) {
	return '(function() { 
	   var t = (new Date()).getTime();
	   for (var n = 0; n < size; n ++) { '+f+' }
	   return t - (new Date()).getTime();
	});';
};
var timeFunctions = {
	a: eval(createFunction(bit1)),
	b: eval(createFunction(bit2))
};
var timeData = { };
//
function getAverage(type) {
	var loops = 10;
	var loopid = 0;
	var average = 0;
	function go() {
		if (loopid ++ == loops) {
			timeData[type] = average/loops;
			if (type == "a") { // get next
				setTimeout(function() { getAverage("b"); }, 1);
			} else { // complete
				var speedGain = ((timeData.a / timeData.b - 1) * 100 + 0.5);
				console.log(speedGain + "%");
			}
			return;
		}
		average += timeFunctions[type]();
		// setTimeout so browser can rest one loop
		setTimeout(function() { go(type); }, 1);
	};
	go();
};
setTimeout(function() { getAverage("a"); }, 1);

There are 10 loops * (1000×1000 pixels) = 10 million iterations are used to get the average execution speed of each function. setTimeout is clear the CPU, and prevent the previous loop from interfering with the next loop.

Further optimizations;

  • Replace Math.random with Park Miller (1988) “minimal standard” linear congruential pseudo-random number generator. This is also handy because the results are replicable by the seed you originally send it.
  • Pre-calculate as much math as possible;
    • var RAD2DEG = 180 / PI;
    • var DEG2RAD =  1 / RAD2DEG;
    • …and so on…
  • When using Color Matrices store the values of the matrix to local-variables (m0, m1, m2, m3… ect) before looping the pixels.
  • Use function calls sparingly; when speed is critical, instead of calling a function, use the contents of the function hard coded into your for() or while() loops. Choose where your line between readability, redundancy, and speed lies.

What optimizations do you use in your graphics or audio applications?

adminBitwise Gems and other optimizations