Monday, December 3, 2012

Automating iTunes

In order to train my kids to go to sleep with ambient noise and without I wanted to setup a way to have music play in their room on some nights and no music playing on other nights.  Given that the holiday season is here, I decided to go ahead and document how I did this.

First of all, I put a small form factor PC in their room on one of the bookshelves behind the books.  I hooked up some cheap speakers to it and installed iTunes.  This was enough to get started.  Since iTunes on that PC was joined to my home share, it was easy to control the music using my iPhone.  There were several problems with this: 1) I had to remember to turn it off or it would be going all night, 2) I had to carve out a section of my iTunes library that would not wake the boys up, and 3) I sometimes had to turn on the music while I was holding a sleeping baby (not easy).  So, I decided to automate things.  A quick Google search led me to Maximize Software's collection of Windows iTunes scripts.  After unpacking the scripts and familiarizing myself with the various options, I started building a batch file that would automate things.

Let's define the objectives:
  1. I want the music to come on and turn off by itself - this should be pretty easy to do using a scheduled task.
  2. I don't want the music to start off at full blast in case we've put the boys down early.    
  3. I want the music to play whenever we put the boys to sleep, which could be as early as 7pm but as late as 9pm.
  4. I want to be able to rotate playlists so it's not the same thing every night.
  5. I want to be able to kick off the music any time.
  6. I want to be able to manually override either the current song or the current volume level.
So, the first thing I did was copy all the music I wanted to play into that computer's iTunes library.  I wanted to be able to use my computer independently of the nursery music, so that meant all the music needed to be local.  The next thing I did was setup a couple of playlists.  The first is called AllMusic and is a smart list with the following criteria: Media Kind = Music & Playlist is not 'Waves' & Playlist is not 'Christmas' & Location = 'on this computer'.  Waves and Christmas are the other two playlists.  Christmas is also a smart play list with the following criteria: Media Kind = Music & Genre = Christmas & Location = 'on this computer'.  Waves is a manual list that contains a single 1 hour 8 minute MP3 of waves crashing on a beach.  The idea behind the playlists is that each playlist gets a night and there would also be one quiet night, setting up a rotation of 4 nights.

The next thing to do was to setup the batch file to play any given playlist, ramp the music up, and ramp the music down.  Here's the batch file:

@echo off
SetVolume.vbs 0
PlayPlaylist.vbs "%1"
for /L %%A IN (0,1,100) DO (
 echo.Increasing volume by 1/sec.
 call:WAITER 1
 SetVolume.vbs +1
)
call:WAITER 7200
for /L %%A IN (100,-1,0) DO (
 echo.Decreasing volume by 1/10 sec.
 call:WAITER 10
 SetVolume.vbs -1
)
Stop.vbs
SetVolume.vbs 100
GOTO:EOF

:WAITER
echo.Waiting for %~1 second(s).
choice /C x /N /T %~1 /D x > NUL
goto:eof

Let me break it down:

@echo off
SetVolume.vbs 0
PlayPlaylist.vbs "%1"
This section starts things off by turning off screen echo, setting the starting volume to 0, then starting to play the playlist provided as the first parameter when calling the batch file.

for /L %%A IN (0,1,100) DO (
 echo.Increasing volume by 1/sec.
 call:WAITER 1
 SetVolume.vbs +1
)
This section ramps up the volume over 100 seconds.  It increases the volume by 1% every 1 second.  This section makes the first use of the WAITER function shown next.  I chose to increment the volume instead of setting the volume to a specific level so that I could manually override the volume.  This means I could use my phone to increase the volume to 100 immediately instead of waiting 100 seconds.  If the script tries to increase the volume to something past 100, the volume just stays at 100.  If this for loop were in its 20th iteration and I had set it to increase to a specific level each time, then if I immediately pushed it up to 100, the next second would push it back to 21.  Not desirable, especially when ramping down the volume.

:WAITER
echo.Waiting for %~1 second(s).
choice /C x /N /T %~1 /D x > NUL
goto:eof
The waiter function simply waits a predetermined number of seconds.  So, if I wanted to wait X seconds, I would just call waiter like this: call:WAITER X.

call:WAITER 7200
This section waits for 7200 seconds which is 2 hours.  This is my 2 hour window; if I start the music at 6:45, it'll still be playing even if we put the boys to bed late.

for /L %%A IN (100,-1,0) DO (
 echo.Decreasing volume by 1/10 sec.
 call:WAITER 10
 SetVolume.vbs -1
)
This section uses the waiter function again to ramp down the volume over 1000 seconds (or 16 minutes and 40 seconds).

Stop.vbs
SetVolume.vbs 100
GOTO:EOF
This section cleans up after everything is over, making the whole thing ready to manually play music during the day if I wanted to.

I put this patch file into the same directory as the scripts and setup 3 scheduled tasks, each starting on a different day and repeating every 4 days:

  1. sleepitunes.bat AllMusic
  2. sleepitunes.bat Christmas
  3. sleepitunes.bat Waves
This has worked pretty well for us.  I've toyed around with doing something like this as an alarm clock, but since the boys were born, I haven't really needed an alarm clock.  However, it wouldn't be very difficult.  The ramp up rate could be changed simply by changing the first call to the waiter function from 'call:WAITER 1' to 'call:WAITER 10'.