« Box of Chocolates Marathon | Main | What's Up With CNN's Website? »

November 09, 2005

Monad Audibleizer

I really am not trying to come up with a "crazy Monad script of the week"...but this is one I thought of. It's inspired by the "visualizers" you see on car stereos now, which generate abstract visuals in sync with the music they are playing. I never could understand the point of those. My script (which I can't understand the point of either) uses the Windows system sounds to generate random audio in sync with a file it is...well basically in sync with a file it is using to generate the sounds.

So here it is:

$files = resolve-path $args[0] | where-object { $_.Provider.Name -eq "FileSystem" }

$s = ( [System.Media.SystemSounds]::Beep,
       [System.Media.SystemSounds]::Exclamation )

foreach ($f in $files) {
    $c = 0
    foreach ($b in [System.IO.File]::ReadAllBytes($f.Path)) {
        $k = $b -band 3
        if ($c -lt 4) {
            start-sleep -milliseconds 200
        } else {
            $c = 0
            start-sleep -milliseconds 800

(Interesting, CodeHTMLer didn't pick up the resolve-path in the first line as a cmdlet).

A few points, to give this script some redeeming social value:

  1. The script is written to take a filename as an argument, but I use resolve-path on it. This gets me globbing for free. Plus, it allows me to use ~ to refer to th $home directory. Most importantly, it fixes up the fact that the Monad current location (which is what the user visually thinks of as the "current directory") is not necessarily the current process's current directory, which is what the System.IO.File APIs use. Meaning if you run msh.exe with c:\foo as your current directory, and then inside of Monad you set-location somewhere else, the process's current directory is still c:\foo, so System.IO.File methods would look in c:\foo if you passed in a filename that wasn't path-qualified (we do set the process current directory to a reasonable value in any child processes we launch (setting it to the current location in the filesystem provider, even if your current Monad location is in another provider), but in this case we are just invoking .NET methods and we don't know that the particular ones we call are sensitive to the process current directory). Calling resolve-path ensures we get a fully-qualified path that takes into account the current Monad location. I run the output of resolve-path through where-object to filter out any locations that are not in the filesystem.
  2. I use ReadAllBytes() to read in the data. This puts it in a byte array which makes it easy to walk through one byte at a time.
  3. -band is the Monad "bitwise and" operator (yes we have -bor and -bnot also).
  4. To give the thing some rhythm, it pauses for two beats after each fourth note--that's what the futzing with the start-sleep parameter is for.

As usual, any hallucinations or angry co-workers caused by running scripts posted here are your own responsibility.

Posted by AdamBa at November 9, 2005 09:13 PM

Trackback Pings

TrackBack URL for this entry:


I actually haven't colorized all the cmdlets. That would sort of be eqivalent to highlighting the entire baseclass library in C#/VB which I'm not sure is worth it.

It is interesting that where-object gets highlighted. It happens because where and object themselves are listed as keywords. What do you think? Is it worth while to highlight all the builtin cmdlets? If so then what about all the builtin alias? Where would it stop? That is why I typically only highlight the language specific stuff. However I am open for dicussion on this.

Posted by: Wes Haggard at November 10, 2005 08:18 AM