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 (yt@hjfreyer.com)
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# 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.

Usage:

python metronome.py <duration> <bpm_at_start> <bpm_at_end>.

For example, a metronome invoked with the following:

python metronome.py 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)
pygame.init()

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:
return
tick_sound.play()
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
main(sys.argv)