A Scala “timer” shell script (plays a sound file after x minutes)

This article shows how to write a command-line timer in Scala. There are simple ways to do this as just a regular Unix/Linux shell script, but I wanted to use Scala, in part so I could try to remember how to use the Java sound libraries. (I also initially thought about writing this is a GUI app, but decided to just make it a command-line app.)

I wanted a simple command-line timer, so I wrote one in Scala.

Usage

My Scala shell script plays a sound file after the number of minutes you specify. It also takes an optional decibal level, so a command to play a “gong” sound after 30 minutes is this:

$ timer 30

This command also says to play the gong sound file in 30 minutes, but to reduce the decibal level with the -20 value:

$ timer 30 -20

Note: I copied my timer script to my ~/bin directory, and that directory is in my Unix command line path, so I can run my timer script regardless of what directory I’m currently in.

Scala timer shell script source code

Without any introduction, here’s the source code for my Scala “timer” shell script:

#!/bin/sh
exec scala -savecompiled "$0" "$@"
!#

import javax.sound.sampled._

val oneMinute = 60*1000

// usage
if (args.length < 1) showUsageAndExit

// initialize the values from the user input
val minutesToWait = args(0).toInt
val gainControl = if (args.length==2) args(1).toInt else -20

println(s"Timer started. Wait time is $minutesToWait minutes.\n")

// wait the desired time
for (i <- 1 to minutesToWait) {
    Thread.sleep(oneMinute)
    println(s"time remaining: ${minutesToWait-i} ...")
}

// play the sound twice
for (i <- 1 to 2) {
    playSoundfile("/Users/al/bin/gong.wav")
    Thread.sleep(7*1000)
}

def playSoundfile(f: String) {
    val audioInputStream = AudioSystem.getAudioInputStream(new java.io.File(f))
    val clip = AudioSystem.getClip
    clip.open(audioInputStream)
    val floatGainControl = clip.getControl(FloatControl.Type.MASTER_GAIN).asInstanceOf[FloatControl]
    floatGainControl.setValue(gainControl)  //reduce volume by x decibels (like -10f or -20f)
    clip.start
}

def showUsageAndExit {
    Console.err.println("Usage: timer minutes-before-alarm <gain-control>")
    Console.err.println("       gain-control should be something like -10 or -20")
    System.exit(1)
}

There’s nothing too special about the code, I just kicked it out pretty fast because I was tired of dealing with my kitchen timer. Because I always have a Mac Terminal window open I thought I’d do this from the command line instead of putting a GUI on it.

Note: If you have any problems with this script, it’s probably with the sound file you’re using. I don’t know all of the details, but I do know that the Java Sound API has a problem with some (many?) files, and it also won’t play MP3 files. I had a problem with an old “.au” sound file, and converted it to a WAV format, and that made it work.