Slowing metronome

A few nights ago I was wired and restless and couldn't sleep, and I wondered if there was something I could listen to that would help me chill out. I searched around the Android app store for sleep-related apps, but most of them just played noises of crickets or rain or new age music and it wasn't helping. I wanted something simple and rhythmic I could focus on. Perhaps a metronome.

But what tempo? Too fast and it'd keep me wired. Too slow and I'd be impatient and annoyed. So I had an idea: how about a metronome that slows down gradually over a long time period?

I eventually got to sleep, but I kept playing with the idea. Yesterday I decided to write it up. I grabbed my notebook and used the power of calculus to find a formula for the frequency of the metronome over time. The key condition was that I wanted the period between ticks to get longer by a fixed N% with each tick, so the change would be as uniform as possible.

Here's the formula for the frequency at time t, given that the metronome starts with frequency S and ends with frequency E after D seconds:

So I whipped up a little script using pygame and when going to sleep last night I set it to tick for 15 minutes, starting at 90 beats per minute, ending at 12 bpm. I don't remember when it stopped, so that's a good sign! Try it out and let me know if it works!

Download the code.

 #!/usr/bin/env python  
 # Copyright 2011 Hunter Freyer (  
 # Licensed under the Apache License, Version 2.0 (the "License");  
 # you may not use this file except in compliance with the License.  
 # You may obtain a copy of the License at  
 # Unless required by applicable law or agreed to in writing, software  
 # distributed under the License is distributed on an "AS IS" BASIS,  
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
 # See the License for the specific language governing permissions and  
 # limitations under the License.  
 """A metronome with a gradually changing tempo.  
  python <duration> <bpm_at_start> <bpm_at_end>.  
 For example, a metronome invoked with the following:  
  python 900 120 12  
 Would tick for 15 minutes, slowing from a starting beat of 2 beats per  
 second to an ending rate of one beat every 5 seconds.  
 Requires pygame.  
 import pygame  
 import math  
 def tick(duration, start_rate, end_rate):  
   pygame.mixer.pre_init(44100, -16, 2, 512)  
   def rate(t):  
     return (start_rate*end_rate*duration)/(  
       t*(start_rate-end_rate) + end_rate*duration)  
   clock = pygame.time.Clock()  
   time = 0  
   tick_sound = pygame.mixer.Sound('SoMe TeXt To PlAy')  
   print "Control-C to exit."  
   while True:  
     if time > duration:  
     time += clock.tick(rate(time)) / 1000.0  
 def main(argv):  
   if len(argv) != 4:  
     print __doc__  
     return -1   
   duration = float(argv[1])  
   start = float(argv[2]) / 60  
   end = float(argv[3]) / 60  
   tick(duration, start, end)  
 if __name__ == '__main__':  
   import sys