Archive for the 'Music' Category

Deck the Halls 2012

Monday, December 24th, 2012

wineguitar

Traditions are traditions. Marry Christmas with a new cover, this time it's Deck the Halls:

Deck the halls (part one)

(It's only part one because I didn't find the time to properly record what I had in mind - another 7/8th cover like last year. But you can hear the idea at the end)

Here are the previous years for your entertainment.

Here's to a happy new 2013!


Gear: Ovation wine-colored guitar (depicted above) plugged in one channel of M-Audio box. AKG C452 microphone ponited at 12th fret and plugged in the other channel of the M-Audio box. Out of the box and into Garageband.

 

WebAudio: live input

Sunday, October 28th, 2012

Live input, aka getUserMedia: it exists in Chrome Canary for audio too. Great times to be a web developer, right?

Let's check it out.

Here's the demo, but first a prerequisite: go chrome://flags, search for "Web Audio Input" and enable it. Restart Chrome Canary.

With a guitar

I wanted to have a little trickier setup and capture guitar sound not just voice with a microphone.

As always, it was bigger hurdle to get guitar sound to the computer, than anything else JavaScript-wise.

I have a guitar amp that has a mini-USB out. This goes to the USB of the computer. Wrestle, system settings, garage band to the rescue.... eventually the computer makes sound.

Capturing

I was assuming the stream you get from getuserMedia can go directly to an HTML <audio> src. No such luck. Works for video but not yet for audio.

So... WebAudio API saves the day.

Setting up audio context (like in the previous post), shimming getUserMedia and setting up callbacks for it:

  // for logging
  function fire(e, data) {    
    log.innerHTML += "\n" + e + " " + (data || '');
  }
 
  // globals
  var audio_context;
  var volume;
 
  // one-off initialization
  (function init(g){
    try {
      audio_context = new (g.AudioContext || g.webkitAudioContext);
      fire('Audio context OK');
      // shim
      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
      fire('navigator.getUserMedia ' + (navigator.getUserMedia ? 'OK' : 'fail'));
      // use
      navigator.getUserMedia(
        {audio:true},
        iCanHazUserMedia, 
        function(e){fire('No live audio input ' + e);}
      );
    } catch (e) {
      alert('No web audio support in this browser');
    }
  }(window));

When the user loads the page, here's what they see:

In my case I select the guitar amp and click "Allow" button.

This little window informs me the page is using the audio input:

Playing back

Now that the user has allowed audio access, let's play back the audio we receive, but pass it through a volume control.

All this work happens in the iCanhazUserMedia(), the success callback to getUserMedia.

  function iCanHazUserMedia(stream) {
    
    fire('I haz live stream');
    
    var input = audio_context.createMediaStreamSource(stream);
    volume = audio_context.createGainNode();
    volume.gain.value = 0.8;
    input.connect(volume);
    volume.connect(audio_context.destination);
    
    fire('input connected to destination');
  }

What we have here (ignoring fire()):

  1. setup an input stream from the user stream, this is the first node in the audio chain
  2. setup a volume (Gain) node with initial volume 0.8 out of 1
  3. connect input to volume to output/speakers

And this is it!

Additionally an input type=range max=1 step=0.1 can change the volume via volume.gain.value = value;

Go play! Isn't it amazing that you can now grab microphone or any other audio input and play around with it? All in JavaScript, all in the browser without any plugins.

Moar!

This was a very basic exploratory/primer example. For more:

 

WebAudio: oscillator in JS

Saturday, October 27th, 2012

How about generating some noise in JavaScript?

Demo is here: oscillator.

How does this work?

Using HTML Web Audio you can synthesize audio with a given frequency. E.g. 440Hz is A ("la" in solfège)

This means you don't need an <audio> element or any mp3, ogg, wav, etc, no external files.

Let's see how.

Capable browser?

You need a browser that supports AudioContext. No such (major) browser at the time of writing, afaik. But there's webkitAudioContext supported in stable iOS Safari, Safari, Chrome. Also there could be browsers that support AudioContext but not the oscillator part. So starting off:

  // globals
  var audio_context, oscillator;
 
  // hello audio world
  (function init(g){
    try {
      audio_context = new (g.AudioContext || g.webkitAudioContext);
      oscillator = audio_context.createOscillator();
    } catch (e) {
      alert('No web audio oscillator support in this browser');
    }
  }(window));

Start/stop playing

Alright, next is a play(frequency /*number*/) function which makes noise with a given frequency.

  function play(freq) {
    oscillator = audio_context.createOscillator();
    oscillator.frequency.value = freq;
    oscillator.connect(audio_context.destination);
    oscillator.noteOn(0);
    fire('play', oscillator.frequency.value);
  }

(Don't mind fire(), it's just a poor man's event utility for logging what's going on)

The audio context provides a createOscillator(). You assign the frequency you need and connect this oscillator node to the audio destination (speaker).

There is a nice analogy going on in the Web Audio: you start with some input noise, say coming from microphone or an audio file, or, in this case, you generate the noise yourself. Then you connect that initial input to the output (destination) which is the system speaker/phones. In between though you can pass the noise through a bunch of nodes that can modify the noise.

In this simple example I only have an oscillator node which is connected directly to the audio destination.

noteOn(0) starts playing the noise we just generated.

Implementing stop() to silence the noise is just a question of calling noteOff(0) on the same oscillator node.

  function stop() {
    oscillator.noteOff(0);
    fire('stop');
  }

That's it, go play with the demo.

The demo plays 440Hz (A on 4th octave of the piano) and 880Hz (A on 5th octave) and also lets you punch in a number and see what happens. Probably nice to play with your dog and with sounds at frequencies you cannot hear.

A chord

Finally, an attempt to play a chord: three frequencies at the same time. C major is C, E and G tones. We have an array of the three frequencies, so loop over the array and create and noteOn three oscillator nodes.

  var cmajor = {};
  cmajor.yo = function () {
    var oscs = [], o, i, freqs = [261.63, 329.63, 392];
    freqs.forEach(function(freq) {
      o = audio_context.createOscillator();
      o.frequency.value = freq;
      o.connect(audio_context.destination);
      o.noteOn(0);
      oscs.push(o);
    });
    this.oscs = oscs;
    fire('play', '\n - ' + freqs.join('Hz\n - '));
  };
  
  cmajor.no = function () {
    this.oscs.forEach(function(o) {
      o.noteOff(0);
    });
    fire('stop');
  };

Thanks

Some links for learning more

Once again the demo is here: oscillator.

Intro: html5rocks.com

Educational demos: webaudiodemos.appspot.com/

 

Anaconda Limousine: the guitar parts

Sunday, June 17th, 2012

I'm part of a band that has an album out now. I know, right? (links: excuse-for-a-site, amazon, itunes).

I wanted to put up all the songs on the site, but seems like there's a little dissonance in the band whether this is a good idea. Plan B: 30s samples. Like the bigwigs do on Amazon and iTunes.

But while their samples are random, a band can do a better job in picking parts that are representative of the overall sound. I though - let me pick my solo stuff only as an exercise. So there: Anaconda Limousine: the guitar parts.

I wanted to use command-line ffmpeg, of course, because all music software is like Photoshop to me, just can't figure out what's going on with so much UI. Turned out I needed sox too.

And then I want to use HTML5 Audio to play the samples.

I thought: an audio sprite would be a good idea, put all samples in one file, then JS can update the UI depending on which sample is playing. And I thought might be neat to have the JS turn the volume up and down to fade in/out the samples, like iTunes does. Turns out sox is doing this so nicely, that I let it do it.

Samples

I started by listening to the songs and taking notes with song #, start and end.

var slices = [
  {song: 1,  start:   8, end:  21},
  {song: 1,  start: 301, end: 323}, // from 3:01 to 3:23
  {song: 1,  start: 405, end:   0}, // 0 means till the end
  {song: 2,  start:   0, end:  30},
  {song: 2,  start: 305, end: 318},
  {song: 2,  start: 330, end:   0},
  {song: 3,  start:   0, end:  20},
  {song: 3,  start: 333, end:   0},
  {song: 4,  start: 303, end:   0},
  {song: 5,  start:   0, end:  20},
  {song: 5,  start: 300, end: 333},
  {song: 7,  start:   0, end:  20},
  {song: 7,  start: 340, end:   0},
  {song: 8,  start:   0, end:  25},
  {song: 8,  start: 313, end:   0},
  {song: 9,  start: 155, end: 239},
  {song: 9,  start: 350, end:   0}
];

Start 0 means start from the beginning of the song, end 0 means go to the end.

The time format is optimized for easy typing (I was walking, typing in Notes app on the iPhone). Turned out I need to convert the times to seconds:

function secs(num) {
  if (num <= 60) {
    return 1 * num
  }
  num += '';
  return num[0] * 60 + num[1] * 10 + num[2] * 1;
}

And I need album meta data too, with name of the song, filename and duration:

 
var songs = [
  {name: "Virus",     fname: "01-virus",     duration: 436},
  {name: "Yesterday", fname: "02-yesterday", duration: 346},
  {name: "All for you", fname: "03-all4u",   duration: 404},
  {name: "Damage",    fname: "04-damage",    duration: 333},
  {name: "Everyday",  fname: "05-everyday",  duration: 444},
  {name: "Girl of mine", fname: "06-girlomine", duration: 338},
  {name: "Fool on the hill", fname: "07-fool",  duration: 413},
  {name: "Faultline", fname: "08-faultline", duration: 347},
  {name: "Parting is such sweet sorrow", 
                      fname: "09-parting",   duration: 420}
];

Ripping the album

In the interest of quality I wanted to work with WAV and then encode in m4a, ogg and mp3.

On TuneCore.com there's a nice step-by-step instruction how to rip a CD to WAV in iTunes, because it uses mp3 by default.

So then I had the files:

01-virus.wav
02-yesterday.wav
03-all4u.wav
04-damage.wav
05-everyday.wav
06-girl.wav
07-fool.wav
08-faultline.wav
09-parting.wav

Slicing and fading

I used ffmpeg to do the slicing, like for example the first sample:

$ ffmpeg -i 01-virus.wav -ss 5 -t 20 ff-0.wav

-ss is start time and -t is duration. As you see instead of starting at 8 seconds (as described in the samples array) I start earlier. This is to give some more music for fade in/out.

For fade in/out I used sox. I didn't know this awesome command line tool existed, but found out while searching how to combine wav files (I know for mp3 you can just `cat`)

I don't want to fade in when the sample starts at the beginning. Or fade out then the sample happens to end at the end of the song. sox takes fade-in duration (or 0 for no fade in), stop time (0 for till the end of the file/sample) and fade out duration (again 0 is no fade out)

I used 3 secods fade in, 4 fade out. The sox commands are one of:

$ sox in.wav out.wav fade 3 0 0
$ sox in.wav out.wav fade 3 0 4
$ sox in.wav out.wav fade 0 0 4

And since I have all the configs in JS, JS makes perfect sense to generate the commands. Hope you can make sense of the comments:

var fadein = 3;
var fadeout = 4;
var merge = ['sox'];
slices.forEach(function(s, index){
  var ff = ['ffmpeg -i'];
  ff.push(songs[s.song - 1].fname  + '.wav'); // in file
  ff.push('-ss');
  ff.push(s.start ? secs(s.start) - fadein : 0); // start of the slice
  ff.push('-t');
  ff.push(!s.end ? 
      1000 : 
      secs(s.end) - secs(s.start) + fadein + fadeout); // end slice
  ff.push('ff-' + index  + '.wav'); // out file
  
  var sox = ['sox'];
  sox.push('ff-' + index  + '.wav'); // in file
  sox.push('s-' + index  + '.wav'); // out file
  sox.push('fade');
  sox.push(s.start ? fadein : 0); // fade in, unless it;s the beginning of the song
  sox.push(0); // till the end of the slice
  sox.push(s.end ? fadeout : 0); // fade out unless it's The End
    
  console.log(ff.join(' '));
  console.log(sox.join(' '));
  
  merge.push('s-' + index  + '.wav');
});
 
merge.push('_.wav');
console.log(merge.join(' '));

Running this gives me a bunch of commands:

ffmpeg -i 01-virus.wav -ss 5 -t 20 ff-0.wav
sox ff-0.wav s-0.wav fade 3 0 4
ffmpeg -i 01-virus.wav -ss 178 -t 29 ff-1.wav
sox ff-1.wav s-1.wav fade 3 0 4
[....]

sox s-0.wav s-1.wav s-2.wav s-3.wav [...] s-16.wav _.wav

2 for each sample (slice and fade) and one last one to merge all faded results. Nothing left to do but run the generated commands.

Save for Web

Final step is to convert the result _.wav to a web-ready format: m4a, ogg or mp3:

$ ffmpeg -i _.wav _.m4a
$ ffmpeg -i _.wav _.mp3
$ ffmpeg -i _.wav -acodec vorbis -aq 60 -strict experimental _.ogg

Turn it up!

Enjoy Anaconda Limousine: The Guitar Parts (ogg, m4a or mp3) with all samples in one file.

And come back later for the JS player part.

See you!

 

Simple music player

Wednesday, April 18th, 2012

I put up a few MP3s on http://anacondalimousine.com, in simple a hrefs. While modern browsers will let you click and display some sort of player in a new page, why not play them in-page without a refresh? Simple enough. Plus we have HTML5 audio. Problem is, old IEs don't support HTML5 audio and you need flash or, god forbid, a Java applet to play them.

What's a webmaster to do? All I need is a simple PLAY button next to each link

While I was aware of SoundManager, I accidentally stumbled across sound.js yesterday and thought I should give it a chance. Tiny (3K), it should give me an easy way to do x-browser playing with the help of some SWF for IE, I assume. Dropped the JS from their CDN (nice), but then what? "Online documentation" points to API docs which I don't feel like reading. Demos don't give you the code. Next.

Sound manager has a nice "basic template". Awesome. Replace the sound.js js with SoundManager's. Load in FF. It's looking for an swf. In FF. Why? Because FF doesn't play mp3. Well, I'd rather convert the MP3 than have the user load SWF. But anyway, I drop the swf. For whatever reason (like you need a reason!) I've disabled flash in FF and forgot about it. So no sound in FF. And maybe I'm not the one. Requiring SWF in FF feels unnecessary, although I'm sure Sound Manager probably has way around it. I'm sure. I've met the author, he's brilliant. But... I still need to write some JS to initialize the playing. And if I'm to write code, might as well go solo.

Here's what I came up with, hope it helps.

Disclaimer: I haven't tested in IE, and I mean at all. Should probably work in newer IEs

Demo

http://anacondalimousine.com

Codez, how they work

Everything in an immediate function. Unobtrusive. Bail if (IE) browser doesn't know about Audio.

(function () {
  if (!Audio) return;
  
  // ...
 
}());

Codes for play and stop:

var playsym = "&#9654;", stopsym = "&#9632;";

Some browsers play mp3, some OGG, so let's just change the extension and have both .mp3 and .ogg on the server

var extension = new Audio().canPlayType('audio/mpeg') === '' ? 'ogg' : 'mp3';

Loop though all links on the page, find the ones that point to .mp3

var dl = document.links;
for (var i = 0; i < dl.length; i++) {
  if (dl[i].href.split('.').slice(-1)[0] !== "mp3") {
    continue;
  }
  var p = document.createElement('button');
  p.innerHTML = playsym;
  p.onclick = play;
  dl[i].parentNode.insertBefore(p, dl[i]);
}

Forgot to mention, my markup is as simple as it gets:

  <p><a href="virus.mp3">Virus</a></p>
  <p><a href="yesterday.mp3">Yesterday</a></p>
  <p><a href="parting.mp3">Parting</a></p>
  <p><a href="faultline.mp3">Faultline</a></p>

So all I'm doing is insert a PLAY button right before the link. Onclick it should play.

The play() function initializes Audio with the appropriate extension, based on what the browser supports:

  function play(e) {
    var button = e ? e.target : window.event.srcElement;
    button.innerHTML = stopsym;
    var a = new Audio(button.nextSibling.href.replace('mp3', extension));
    a.play();

And if you click the same button as the music plays, you stop it and reset the button click handler:

    button.onclick = function() {
      a.pause();
      button.innerHTML = playsym;
      button.onclick = play;
    };
  }

That's it

So simple and tiny, it's all inline, no extra requests, not a SWF in sight. Support for 72.3% of all browsers. The other 30% can still download the file and play it with a separate program.

SoundManager and, I assume, sound.js have more features, events and other shiny, but for my simple purpose I'm so happy with the result I'll even blog about it :)

For full source - view source at http://anacondalimousine.com

Moarr info:

p.s. about the mp3 to ogg conversion... ffmpeg ftw:

$ ffmpeg -i in.mp3 -acodec vorbis -aq 60 -strict experimental out.ogg
 

Wish You a Merry Christmas 2011

Saturday, December 24th, 2011

Here's a cover of We Wish You a Merry Christmas I just did. It's in a Bulgarian (and other Balkan countries) style in 7/8 tempo (and 9/8th at one place). This is me channeling my inner Goran Bregovich :)

We Wish You a Merry Christmas (7/8th and 9/8th)

Continuing the tradition (why did I skip last year?! oh I know, because 7/8 is damn confusing and I failed last year), here are the others:

It's amazing to look back over the years and see how little I have grown as a musician and recording technician :P

 

Sultans of Speed

Monday, June 13th, 2011

#2 This post is part of the Velocity countdown series. Stay tuned for the last one tomorrow.

With only 2 days to Velocity, it's time to drop in the quality of these posts (but the one tomorrow will be great, I promise) with today's announcement of the immediate availability of the project called http://sultansofspeed.com.

I think we've had enough of experts, gurus, ninjas, jedis, pirates and overloards. Time for the sultans to step in!

So there: a slideshow of bios and photos of a number of Web Performance Sultans.

The background music is my heavy metal cover (sorry!) of "Sultans of Swing" by Dire Straits.

The Sultans you see there are the people who have written for the Perfplanet Calendar. But this is just the initial seed. (And because these are the bios/photos I have easy access to.)

Are you a sultan? Add/delete/edit your bio in the Github repo in the sultans.js file.

Want to change something - better slideshow maybe? Yes, the repository is still there.

In the immortal words of Mark Knopfler:

And he makes it fast with one more thing:
"We are the sultans, yeah the sultans of speed"

 

Silicon Valley (roughest place I’ve ever been)

Saturday, April 16th, 2011

Excuse me, my dearest reader for subjecting you to this (*cough vogon poetry*). My only excuse is it's Friday.

So here comes another one of those. This time a coverlet (a whatlet?) of Stevie Ray Vaughan's Tin Pan Alley (The Roughest Place in Town). Tin Pan Alley sounds almost like Silicon (Silly Con?) Valley :)

Went down to Silicon Valley
To see what was goin' on
Things was too weird down there
Couldn't stay very long
  Hey hey hey hey,
  Valley's the roughest place I've ever been
  All the people down there
  Livin' for their stock options, perks and dental care

I heard a woman scream
When she saw her team
"It's just a bunch of nerds out there
and no one cares to wash their hair"
  Hey hey hey hey,
  Valley's the roughest place I've ever been
  All the people down there
  Call them CEOs and next dotcom millionaire

I heard a pistol shoot
Yeah and it was a .44
Oh wait - just some engineers killing time
on their PlayStation 4
  Hey hey hey hey,
  Valley's the roughest place I've ever been
  All the people down there
  Killin' for their options, perks and dental care
 

Audio sprites

Wednesday, April 13th, 2011

Another "brilliant" idea that I had recently - how about combining audio files into a single file to reduce HTTP requests, just like we do with CSS sprites? Then use the audio APIs to play only selected parts of the audio. Unlike pretty much all brilliant ideas I have, I decided to search for this one before I dive in. Turned out Remy Sharp has already talked about this. So I knew it was possible and wanted to check the server-side or things. (Remy is amazing, by the way, and I was happy to have him as a reviewer of "JavaScript Patterns")

Here's the demo - parts of Voodoo Chile covered by yours truly.

Playing separate files

Markup is a few audio elements:

<audio id="in">
  <source src="in.mp3">
  <source src="in.ogg" type="video/ogg">
</audio>
<audio id="1">
  <source src="1.mp3">
  <source src="1.ogg" type="video/ogg">
</audio>
<audio>
  ...

I have the files:

  1. in.mp3 - intro
  2. 1.mp3 - figure 1
  3. 2.mp3 - figure 2
  4. out.mp3 - the end

1 and 2 repeat a few times.

I play these files in JavaScript using a next() iterator function, which contains (in a private closure) the melody (which file after which) and a pointer to the current file being played. After play()-ing each audio, I subscribe to the "ended" event and play the next() file.

var thing = 'the thing';
var next = (function() {  
    //log('#: file');
    //log('-------');
    var these = ['in', '1', '2', '1', '2', '1', '2', '1', 'out'],
        current = 0;
    return function() {
        thing = document.getElementById(these[current]);
        //log(current + ': ' + these[current] + ' ' + thing.currentSrc);
        thing.play();
        
        if (current < these.length - 1) {
            thing.addEventListener('ended', next, false);
            current++;
        } else {
            current = 0;
        }        
    }
}());

That was easy enough. And worked (except on iPhone, see later). But we should be able to do better with sprites.

Sprite

For the sprite I have this audio:

<audio id="sprite">
  <source src="combo.mp3">
  <source src="combo.ogg" type="video/ogg">
</audio>

There's only one file - combo.mp3 which contains all the other four files played one after the other.

So we need to know the start and the length of each piece of audio. There are two parts to playing the sprite. First is knowing the lenghts and the "song" (meaning the succession of audios) and starting to play:

var sprites = {
      // id: [start, length]
       'in': [0, 3.07],
        '1': [3.07,  2.68],
        '2': [3.07 + 2.68,  2.68],
        out: [3.07 + 2.68 + 2.68, 11.79]
    },
    song = ['in', '1', '2', '1', '2', '1', '2', '1', 'out'],
    current = 0,
    id = song[current],
    start = 0,
    end = sprites[id][1],
    interval;
 
thing = document.getElementById('sprite');
thing.play();

Next is "listening" and stopping when one audio should be stopped, then seeking through the file and playing another part of it. This is done with a setInterval(), I couldn't find a better audio event to listen to.

// change
interval = setInterval(function() {
    if (thing.currentTime > end) {
        thing.pause();
        if (current === song.length - 1) {
            clearInterval(interval);
            return;
        }
        current++;
        
        id = song[current];
        start = sprites[id][0];
        end = start + sprites[id][1]
        thing.currentTime = start;
        thing.play();
        log(id + ': start: ' + sprites[id].join(', length: '));
    }
}, 10);

And this is it. The property currentTime is read/write - you can figure out where we are and also fast-forward or rewind to where you want to go.

Results

  • Sprites play fine in FF, Chrome, O, Safari, iPhone's mobile webkit.
  • I haven't tested IE9.
  • All the browsers played y stuff off by a few milliseconds, I think some early, some late. This is probably due to unreliable setTimeout(). Also I didn't cut the audio pieces very well, so that might have someting to do. Also adding a few milliseconds of silence between the sprites may help. A follow up experiment will be to have a piano of sorts and see how timely the audio is played after a click/button press.
  • iPhone didn't play properly the non-sprited verison - I believe because it won't let you autoplay unless there's a user action. There might be a workaround, but I only cared about the sprites and they are fine!

Server side

I was imagining the whole thing as a combo service like YUI's JS/CSS combo handler. The browser says: i need these 5 files, the server then creates a new audio file and sends it back. In this case it should also somehow send the data about start/length of each audio, so maybe a JSONP thing. I was mostly curious about those file formats and how the stitching would work.

In terms of file formats, it's not that bad, turns out all I need is MP3 and OGG in order to support all these browsers (I was prepared for worse).

(I could also probably support IE3? and above with a <bgsound> and a WAV, but the WAV is too big to be practical. So any IE (before 9) enthusiasm should probably end up in Flash.)

I recorded my audio pieces in Garage Band and exported as MP3.

ffmpeg is teh tool! It's like imagemagick for audio/video.

Cutting out extra 4-5 seconds Garage Band adds to each file you export:

$ ffmpeg -i in.mp3 -ss 0 -t 2.43 in-ok.mp3

(I didn't do that very precisely I think)

Converting MP3 to OGG is like:

$ ffmpeg -i in.mp3 -acodec vorbis -aq 60 -strict experimental in.ogg

Then the stitching.

MP3 files can actually be concatenated together just like JS/CSS, provided they have the same bitrate. I've done it in the past.

You can also combine by reading the files and piping them into ffmpeg. That somehow feels better:

$ cat in.mp3 1.mp3 2.mp3 out.mp3 | ffmpeg -i - combo.mp3

You can also consider putting a bit of silence between the separate audios.

In order to get the length info to return it to the client, you can use ffmpeg -i filename.mp3 (I haven't done that part)

OGGs cannot be concatenated like MP3, so the combo service should `cat` the mp3s as shown above, then convert to OGG (also shown :) )

Voila

You can now roll your own on-demand audio combo handler and use audio sprites to have fewer HTTP requests a more responsive app/game/html5 thing.

 

Another LOC

Friday, February 11th, 2011
We don't need no docum'ntation
We don't need no source control
No dark sarcasm on the mail(ing) list
Ninjas leave them kids alone

No comments - code should speak alone!
All in all it's just another LOC

We don't need no code conventions
We don't need no (js)lint control
No YSlow rules, no validation
And who needs stinking unit tests?

Hey, guru, leave them kids alone!
All in all it's just another kick in balls

Alternatives:

Hey Crockford, leave them kids alone!

No dark sarcasm in the board room

Many thanks to contributions from @ltackmann, @lucidlifedream, @jalbertbowdenii, @jasonfry, @getify, @skilldrick, @marceloOrigoni, @jdbartlett, @pixsym, @jLix, @joedevon, @leopyc, @cramforce, Carlos!

 

Feliz Navidad Merry Christmas 2009

Friday, December 25th, 2009

Disregarding my dear wife's opinion that the best present to my blog readers would be to *not* publish my new recording.... I'll just go ahead and do it:

Feliz Navidad

'tis a heavy metal sort of cover of Jose Feliciano's Feliz Navidad. I hope you like Iron Maiden and Helloween (there's a special treat between 02:44 to 03:05) and I hope you would be kind enough to tolerate this show-off type of guitar heroism :) Another thing you may notice is at 03:54 - I played a part (a mashup if you will) of Slash's Sweet Child o' Mine solo (splic'd).

psst, here's my last year's Christmas cover - Jingle Bells. You can clearly see where I'm going with this - an album of Christmas songs within the next 10 years. Watch out Mariah Carey :P

 

Help write the lyrics to “Give PNG a chance”

Thursday, September 3rd, 2009

As you know yours truly is a guitar hero wannabe. So I'm playing with the idea of recording a song/video called "Give PiNG a Chance", cover of "Give peace a chance". Hopefully whoever hears it will then think twice before saving a GIF instead of PNG. Imagine. And the web will be as one... :D

Here's the lyrics so far, it's a work-in-progress. If anyone can think of rhyming Web 2.0 buzzwords, please comment.

Give PNG a Chance

#1
Everybody's talking about

Web 2
YouTube
WordPress
CMS
    Highrise
    Enterprise
    Crowd sourcing
    Open sourcing
Phone texting
Unit testing 
Foo bars
Avatars

All we are saying is: give PNG a chance

#2
Everybody's talking 'bout

Long Tail
Junk Mail
Fail Whale
Ruby Rail
    Webcasting
    Screencasting
    Podcasting
    Vodcasting
Cloud computing
Tele commuting
Trackbacks
Pingbacks
    Less is More
    Apple store
    Link whore
    Browser war

All we are saying is: give PNG a chance


#3
Everybody's talking about
RSS, CSS
HTML, XML
    SOA, RIA
    API, CGI
REST-POST, GET-HEAD
SOAP? Nope!
    SEO, SMO
    CPM, CRM
SQL, YQL
SMS, MMS

All we are saying is: give PNG a chance
All we are saying is: give PNG a chance
All we are saying is: give PNG a chance
All we are saying is: give PNG a chance
Yup, no more GIFs
All we are saying is: give PNG a chance
All we are saying is: give PNG a chance...

Unused buzzwords

Here's my laundry list of buzzwords I thought of but didn't use so far in the lyrics. If you think of good rhymes as you look through the list, please comment.

  • flickr
  • blog
  • blogging
  • wiki
  • twitter
  • facebook
  • outlook
  • ajax
  • comet
  • firefox
  • chrome
  • ie6.. ie8
  • explorer
  • navigator
  • digg
  • blogger
  • safari
  • opera
  • RoR
  • PHP
  • CDN
  • SMS, MMS
  • WTF
  • FTW
  • web service
  • Perl, cURL
  • Ruby
  • Python
  • social
  • social media
  • social tagging
  • click-through
  • agile
  • photoshop
  • rounded corners
  • fluid layout
  • iPhone
  • Air, PEAR
  • Sliverlight,
  • mobile
  • JavaScript
  • flash
  • buzzwords
  • keywords
  • microblogging
  • microformats
  • micropayment
  • semantic web
  • validators
  • web standards
  • folksonomy
  • taxonomy
  • tagging
  • phishing scam
  • spam
  • widget
  • gadget
  • geotagging
  • linkbait
  • bookmarking
  • viral
  • tag clouds
  • view source
  • torrents
  • bit torrent
  • github
  • blog
  • mashup
  • pagerank
  • social network
 

Blog-to-podcast with ffmpeg

Monday, February 16th, 2009

ffmpeg is such an amazing tool, looks like it's for video what ImageMagick is for images. An all-powerful all-formats wicked cool command-line tool.

This blog post is an introduction to some of the MP3 capabilities of ffmpeg. I'll use ffmpeg to transform a blog post into a podcast-ready mp3 file. If you continue to read this longish post, here's what you can expect to see:

  • using PHP DOM
  • ffmpeg to convert to MP3
  • ffmpeg to crop (slice) an MP3
  • glue together several MP3s
  • Mac's say command for TTS (text-to-speech)

PHP DOM to get some blog content

This blog's feed is at http://phpied.com/feed. Let's create a small PHP script to extract the title, date and content of the last blog post. We'll feed these to Mac's say command to read then aloud.

Location of the feed:

$file = 'http://phpied.com/feed/';

Load the feed into a DOM instance:

$dom = new DOMDocument;
$dom->loadXML(file_get_contents($file));

Access the node that contains the first item, i.e. the last blog post

$post = $dom->getElementsByTagName('item')->item(0);

The title and a friendly-formatted date:

$title = $post->getElementsByTagName('title')->item(0)->textContent;
$date = $post->getElementsByTagName('pubDate')->item(0)->textContent;
$date = strtotime($date);
$date = date('F jS, Y', $date);

Get the content:

$ns = 'http://purl.org/rss/1.0/modules/content/';
$content = $post->getElementsByTagNameNS($ns,'encoded')->item(0)->textContent;

Strip out HTML tags and entities:

$content = strip_tags($content);
$content = html_entity_decode($content);

(Since this content will be read aloud, HTML tags and entities will make no sense. Here we cound've done better job by doing something more special for list, using ALT tags to replace images and so on...)

echo $title, "\n\n", $date, "\n\n", $content;

OK, so now let's call the script from the command line and write the output to a file:

$ php feed.php > thepost.txt

Here's the result - thepost.txt

Using Mac's say for text-to-speech

You can make your Mac talk on the command line, like:

$ say test

and it will say the word "test"

The say command can also read text from text files and write to AIFF audio files. Let's read thepost.txt into an audio file.

$ say -f thepost.txt -o thepost.aiff

Since I'll make this look like it's a part of an ongoing series of podcasts, I'll add some music and I also need a greeting and goodbye spoken text. So:
$ say -o welcome.aiff Welcome to phpied.com podcast
$ say -o thatsallfolks.aiff That was all for today, join us next time on... phpied.com

OK, so now I have three AIFF files:

Now I want to add some music before/after the podcast. I took four loops from Garage Band's library. Here they are:

Next?

Now I have a bunch of audio files. All I need to do is merge them, glue them together into one MP3. Glueing MP3 will be as easy as simply concatenating the files, using cat for example and them making a final pass through ffmpeg to correct dates and other meta data, so that the result looks like one single file, and not like a Frankenstein :)

In order for the concatenation to work, you only need to make sure all files are the same format, bitrate, etc.

Let's choose 22050 Hz, mono for the result. This means always add the options:

-ar 22050 -ac 1

to all calls to ffmpeg.

Let's get cracking.

ffmpeg to convert just about anything

The simplest use of ffmpeg is to convert from one file format to another, for example AVI to MPEG, WMV to FLV and what not. This is done like this for example:

$ ffmpeg -i input.avi output.flv

ffmpeg to get file information

It's useful to know what type of file we're dealing with, you can do this simply by omitting the output file:

$ ffmpeg -i input.avi

Let's check out one of the Garage Band loops:

$ ffmpeg -i opener.mp3 
FFmpeg version..... (more ffmpeg information)
Input #0, mp3, from 'opener.mp3':
  Duration: 00:00:12.6, start: 0.000000, bitrate: 191 kb/s
  Stream #0.0: Audio: mp3, 44100 Hz, stereo, 192 kb/s
Must supply at least one output file

Pretty good quality, more than I need. Plus, for some reason Garage Band added silence at the end of the files I exported, so let's cut it off.

ffmpeg to crop files

I want to remove trailing 5 seconds or so of each Garage Band loop. Here goes:

$ ffmpeg -i breaking-news.mp3 -ac 1 -ar 22050 -ss 0 -t 6 breaking-news-ok.mp3
$ ffmpeg -i opener.mp3 -ac 1 -ar 22050 -ss 0 -t 8 opener-ok.mp3
$ ffmpeg -i closer.mp3 -ac 1 -ar 22050 -ss 0 -t 33 closer-ok.mp3
$ ffmpeg -i squeeze-toy.mp3 -ac 1 -ar 22050 -ss 0 -t 2 squeeze-toy-ok.mp3

-i is the input file -ac is the number of channels (1 for mono) -ar is the rate, -ss is start, -t is length.

Now you can see how the meta information for the opener.mp3 has changed:

$ ffmpeg -i opener-ok.mp3 
Input #0, mp3, from 'opener-ok.mp3':
  Duration: 00:00:08.1, start: 0.000000, bitrate: 63 kb/s
  Stream #0.0: Audio: mp3, 22050 Hz, mono, 64 kb/s

Convert AIFF to MP3

Now let's convert the AIFF files from our TTS say command to MP3, keeping the same 22050 mono rate:

$ ffmpeg -i thepost.aiff -ac 1 -ar 22050 thepost.mp3
$ ffmpeg -i welcome.aiff -ac 1 -ar 22050 welcome.mp3
$ ffmpeg -i thatsallfolks.aiff -ac 1 -ar 22050 thatsallfolks.mp3

Here are the new MP3s:

Glue the pieces with cat and ffmpeg

Now, last stage, let's glue all the pieces with cat which simply means append the next file at the end of the previous.

$ cat breaking-news-ok.mp3 welcome.mp3 opener-ok.mp3 thepost.mp3 
            squeeze-toy-ok.mp3 thatsallfolks.mp3 closer-ok.mp3 > pieces.together

Then make these pieces a proper MP3 file

$ ffmpeg -i pieces.together final.mp3

Well, that's all folks, here's the final result:
final.mp3

 

Merry Christmas 2008!

Thursday, December 25th, 2008

Best wishes to everyone!

Here's a rendition of Jingle Bells I recorded today (kinda punky and heavily inspired by Pearl Jam's 2007 Christmas single). Enjoy.

» Jingle-Bells.mp3

 

Start wearing purple

Tuesday, December 2nd, 2008

Today was officially my first day at my new job at in Yahoo! Search. In the spirit of less-is-more I'm stepping out of the position of improving the performance of all Yahoo's sites worldwide to improving the performance of just one Yahoo! Search - in the US first, then maybe helping globally. I'm excited by the new opportunity and I'm not just saying it. Having in mind how smart I am (muhaha) and how committed YSearch is to performance, can't help but give a friendly warning to all the dear readers of my blog: if you own GOOG stock, now is the time to consider a second look at your portfolio :P

Anyway, I felt like doing something silly and here's what I came up - my first online video (videos of my kids don't count). I decided to play a rendition of "Start Wearing Purple" by Gogol Bordello on my acoustic and video tape it. This song (here's a vid of the original) is something of a hymn for Y!

So here's the video, enjoy!


start wearing purple @ Yahoo! Video
 

Seeing stars

Friday, August 8th, 2008

It's been interesting few days lately for me, celebrity-wise.

Agassi/Graff

First, last Thursday, Andre Agassi and his wife Steffi Graff came to the Yahoo! center in Santa Monica (my workplace) and played with our kids and signed tennis balls. This was fun, check out: vid, vid, vid, pics.

Here's my daughter almost hitting the ball:
Steffi:Zlatina

Craig Ferguson

Then I became part of the audience at a taping of Craig Ferguson's late night talk show. I find him funny and he was even funnier live. The audience environment is nice and small - 113 people. A nice surprise was that when there are supposed to be commercial breaks in the TV, Craig kept making fun and be there although there was no camera rolling. I always though that during those breaks, the host hides in a dressing room or something.

This was all good.

But the warm up guy and the whole warm up procedure was just awful. There's this guy telling stupid and mostly nasty adult jokes, who's not even remotely funny compared to Craig and he's supposed to warm up the audience so we can be prepared when the main dude arrives. He kept repeating how we should laugh, LOL, etc, even when we don't find something funny (who are we to judge ;) ), it made me feel uncomfortable as if I was on an exam or something. A friend told me he used to be a big Letterman fan, until he went to a show tapping in NY. Well, didn't happen to me, I still like Craig, but the whole event felt a little weird.

Buddy Guy

The last "seeing stars" experience was the best - this Tuesday I went to see Buddy Guy, the blues legend, live. The show was another taping but much more fun and natural then the Ferguson one. The show was part of the "live sets" by Nissan and Yahoo! Music which means a very intimate show, maybe about 200 people, mostly fan club members and "VIP". I was part of the VIP, which meant feeling uncomfortable bypassing a line of people and also not being able to be right in front of the stage. Whatever. The show was great, Buddy Guy is 70+ years old but you can never tell. At some point he was all around the audience and playing a meter or so from me, to the guy next to me. He mostly played songs from his latest "Skin deep" album, but he also did what is probably his usual routine playing Strange Brew like Eric Clapton and Voodoo Child like Hendrix. Can't wait to see the recording on Yahoo music, they said it should be ready somewhere in October. There was also a Q&A session with him, the whole event was so natural, human and anti-celebrity.

You can see how much fun is going on on these shows if you see how Weezer play Radiohead's Creep together with the fans.

 

Yahoo Music API

Thursday, August 7th, 2008

This was meant to be a longer posts with examples and such, but Jim Bumgardner said it and coded it better than I could :) He's been with Y!Music way longer than me and has done way cooler stuff.

As a front-end engineer for Yahoo! Music, I've always thought it would great if the web services we use to create the Y! Music pages were available to developers outside of Yahoo!, and, as of today, due to the herculean labors of our web services team, they are!

Full blog post and code examples are on the YDN (Yahoo! Developer Network) blog and the Music API docs are there too.

Could you come up with an idea of a mashup using music data like artists, songs, similarities? The APIs are here.

 

first book review and a new instrumental piece

Tuesday, August 5th, 2008

The first review for OOJS is posted on Amazon - 5 stars, yeey! (My copies still hasn't arrived, talk about weird, eh?). If anyone is interested in reading my book and posting a review on Amazon or some other site, let me know, my publisher might be willing to send you a copy.

Here's another song I just recorded today, a sort of metal/grunge thing with a melody of some sort even :) Enjoy loud!
» melody.mp3 (< 3 min)

 

Steppn

Tuesday, July 1st, 2008

So I got one year older last week, no, the week before and I got a gift: a guitar processor. A DigiTech RP250 Guitar Multi Effects Pedal, to be precise. Yeey! The thing has so many pre-build effects, some of them really weird as you can hear. And can be plugged into the PC via USB, so cool.

I recorded a sort of a piece today, using one of the pre-builds, the display says the name is of the effect is STEPPN, hence the name of my new song :D

Steppn

It's a long piece, actually, believe or not, I plugged the guitar 20 seconds after the start of my creation. Before that I'm just playing with the cable jack and enjoying the noises. There's also a drum machine that comes (absolutely free ;) ) with the guitar processor. There's no mixing going on (it takes so much time), just plug and play, one guitar and this is it. I eventually turn on the drums at some point. If you listen carefully you can hear Jimi Hendrix and Pearl Jam in there. Also something that resembles the fly of the bumblebee. And yeah, the whole thing is very Jimmy Pagelicious, Zeppelinicious and Dazedilicious and Confusedilicious.

 

Kiss alive

Saturday, May 17th, 2008

I've never been a Kiss fan, but went to see them while in Bulgaria. The show was excellent, lots of fireworks, fire breathing and all kinds of effects. More theatre than music, but fun nevertheless. It's a whole different experience than for example Pearl Jam, which is my kind of show, because it's all about the music and being simple, honest and non-celebrity. I was looking to recognize a piece that Mike McCready from Pearl Jam says he stole from Kiss, in turn stolen from The Doors. The piece in question is the beginning of the Alive (Pearl Jam) solo, which is like the beginning of Five To One (Doors) and the middle of the She (Kiss) solo, at least I think She was the song.

Tried to do a few photos with a camera phone.

cinderroad.jpg
The opening band, Cinder Road, apparently something like a post-glam band, inspired by bands (from one of the worst periods in pop music ;) ) like Poison, Motley Crue and obviously Cinderella.

cinderroad2.jpg
In fact I think Cinder Road sounded better than Kiss, maybe because they couldn't rely on effects but had to actually play.

kiss-gene.jpg
Gene Simmons

kiss-gene-paul2.jpg
Gene Simmons, Paul Stanley

kiss-gene-paul.jpg
Yep, I was close to the stage, although I moved away eventually. The sound from the back was better.

kiss-guitar.jpg
Starchild, I think was the nick name of this dude.

kiss-snow.jpg
At some point there were lots of flying little pieces of paper, lots and lots of them, much like snow.

kiss-moon.jpg
The moon

sister.jpg
My sister in the foreground, yet another explosion of sound and light on the stage in the background.

 

Crowes and Crows

Friday, March 28th, 2008

The Black CrowesCounting Crows

Currently enjoying two new albums by two older bands:

Cool stuff, especially the first one.

Can't help but be a little worried about the fact that I seem to have stopped my musical development somewhere in the nineties, and just keep listening to the same bands. Luckily some of them sometimes release new albums.

 

Sharpenning those flamenco skillz

Wednesday, February 6th, 2008

What's new today? Let me see.

[x] Wrote the first sentence of chapter 6 of the new book. Goes like this "After encapsulation, inheritance is probably the most important feature of the object-oriented programming". Promising, but not exactly progress. Good news is I already wrote all the code for the chapter.
[x] My teammate Nicole posted an interesting entry on developer.yahoo.com blog. Especially interesting if you happen to care about web page performance and you're also a US voter. I haven't voted in yeeeaars. Wasn't allowed to vote in Canada initially and just when I became Canadian I moved to US where I'm also not allowed to vote. Oh, well. Don't like any candidate anyway.
[x] Christian Heilmann posted on Ajaxian about the canvas Pie I published last night

... and ...

[x] I recorded again!!

It's a piece loosely based on a Paco De Lucia song I tried to figure out for myself long ago. For this recording I used a microphone specially designed for acoustic guitars (gift from my best-men) but the problem is I plugged it into the microphone jack on the laptop, so there is some nasty amplification. I tried to de-amplify in Audacity.

Here goes: Paco. Hope ya like it! :D

 

Audacity + Starcaster

Wednesday, January 30th, 2008

(if you see this in a RSS reader, come to the page to hear the music)

(Now that I got this Starcaster and also completed the first 5 chapters of the new book) Yesterday, I was wondering how I can record some music, so I searched for open-source sound recorder and came across this beautiful application called Audacity (French word for "courage", didn't know it existed in English).

Anyway, last time I've tried music editing software was yeeeears ago and they looked pretty intimidating. Audacity is nothing like this, it's so easy to get started. I just started the program, hit the big red "record" button and recorded away. Just as easy as Windows Sound Recorder. But! When I wasn't happy with what I recorder and hit "record" again, it played my previous junk but was recording on another track. How cool is that?! So easy to mix. Now I record something, then record again while listening with headphones to the previous thing.

I don't have any special equipment, so I just use the laptop's built-in microphone. Since those microphones amplify and therefore distort, I do a little trick. I play load (take that, neighbors!) and set the microphone level in Audacity to almost zero. The result is not too shabby for an amateur recording if you ask me. I do have an amp, no bigger than any average self-respected Java book, it was in the same package with the guitar.

So here goes. My take on Stevie Ray Vaughan's take on Jimi Hendrix' Little Wing intro - about 40 seconds.

Little Wing

Now if you feel brave, try the next piece. The theme is somewhat distantly loosely based on what I remember of a song called "Que Que Ha?" by Joe Pass. In this case I recorder the rhythm first then tried improvising some sort of a - for a lack of a better word, let's call it - solo on top. Didn't like the result, so tried again. Thought first time was definitely better. At this point the kids were finishing their bath so I had to forget about further recordings. Later on I tried playing both solos together - horrible, horrible idea. But then I moved (it's trivial with Audacity) the first solo to the left speaker and the second to the right. And here's the result. I suggest that if, for whatever unhealthy reason, you decide to listen to the next piece, do use the headphones. Otherwise it really is a handful, er, earful. Plus people around you will appreciate it, I assure you. Good luck!

Que Que Ha?

Ah, yeah and the nice player you use to hear these MP3s is the Yahoo! Media Player, which you can integrate on every page.

 

MP3 player from Yahoo! – bookmarklet

Wednesday, January 23rd, 2008

Update Jan 30, 2008: updated code based on comments and code from Carl
Update Dec 11, 2008: updated the code thanks to the comment from Nolan

Here's the scenario: you have a page that links to some .mp3 files. You add a line of code in your page and lo and behold, there's a nice media player embedded into the page. Your visitors no longer have to download the MP3s, they can just stream it right there. All the mp3s on the page become part of a playlist.

The line in question you need to add to your page is:

<script src = "http://mediaplayer.yahoo.com/js"></script>

More about the player here - yahoomediaplayer.wikia.com

For examples of sites using this player in the wild, try aurgasm.us

A bookmarklet

Now, here's what you can do if you want to use the player, but the web site owner haven't incorporated it yet. Take the player with you. Run my bookmarklet that will simply insert the required javascript into the page.

So here goes in two easy steps:

  1. Grab the bookmarklet:

    Right-click, add to favorites

  2. Go to any page that links to MP3s and click your new shiny bookmarklet

    Enjoy!

Source

The readable source code of the bookmarklet:

javascript:(function(){
 
  var start = function(){YAHOO.mediaplayer.loadPlayerScript()};
 
  var script = document.createElement('script');
  script.src = 'http://mediaplayer.yahoo.com/js';
 
 
  if(script.addEventListener){
    script.addEventListener("load", start, false);
  } else{
    script.onreadystatechange = function(){
      if(this.readyState=="complete"){ 
        start(); 
        script = null;
      } 
    }
  }
  script.type="text/javascript";
  document.getElementsByTagName('head')[0].appendChild(script);
  
})();
 

Starcaster

Tuesday, January 8th, 2008

Look what Santa brought this year:

starcaster.png

A Starcaster by Fender! (Not to be confused with Stratocaster.) Packed with an amp and everything.

Looking forward to posting some recordings in 2008!