Revisiting Time
Because it does indeed fly. A few months ago I was just starting my journey through coding at Flatiron school, and how I’m wrapping things…
Revisiting Time
Because it does indeed fly. A few months ago I was just starting my journey through coding at Flatiron school, and how I’m wrapping things up. A lot has changed, and it’s time to take a look at the first post I made here, where I built a metronome using setInterval/setTimeout and some basic Javascript. When I wrote that post, I was aware that interval and timeout had some issues maintaining constant time(which is very important when making music), and I was aware that there were some fancy workarounds, but I wasn’t prepared to explore them quite yet.
Fast forward to now, I’ve built an entire 16-step sequencer with custom key, mode, tempo, volume, octave, loop length, reset, oscillator, presets, and effects that I have lovingly named the Zequencer.

While I’d love to explore all the minutia of each and every feature of the Zequencer, I’m going to save it for later, because there’s still lots of room for improvements and new features. There were many hurdles and obstacles that I had to overcome while working on it, the one I’d like to focus on for this post is timing.
I knew that timing was integral to the success of the entire application, as the sequencer would loop back to the beginning once it reaches the end. While researching to prepare for this project I was elated that Tone.js, a Javascript framework came built-in with multiple tools for approaching both timing and looping. However, this elation soon devolved into frustration as I found the documentation for Tone.js was sparse at best, and the examples I could find online were either way over my head or dealt with entirely different situations.
Some options that I explored included Tone.Transport.scheduleRepeat, Tone.Clock, Tone.Sequence, Tone.Pattern, Tone.Loop, and Tone.Transport.loop. And realistically, almost any of these solutions could work, and there may be one of these options that is objectively best, but the one I went with was Tone.Transport.loop.
The major issue that I kept running into was that most of these timers were measuring time in seconds/milliseconds, whereas I wanted to time a loop based on the current BPM setting. I was unable to find a solution that automatically converted seconds to a beat increment of the BPM, so I set about calculating it myself, just like I did for my metronome from the first blog post. This problem was compounded by the fact that I wanted to have the option to change the length of the sequence in addition to the tempo.
The math is kind of the opposite of my metronome, where before I wanted to convert a specific amount of time into 16th notes, now I wanted to convert a specific number of 16th notes into time.
So running through the basics, at 120BPM there are 2 1/4 notes per second or 8 1/16th notes per second. So it should take 2 seconds to get through all 16th notes. Spending some time I found that if I wanted to find out how many seconds it would take to get through a specific number of 16th notes at different tempos:
60 BPM = 4 seconds
70 BPM = 3.84 seconds
80 BPM = 3 seconds
90 BPM = 2.66 seconds
100 BPM = 2.4 seconds
110 BPM = 2.18 seconds
120 BPM = 2 seconds
The magic formula was:
*loop length 15 / tempo = loop time in seconds**
If one wanted to find out how long it would take to get through in 8th notes, for example, you could multiply it by 30 instead of 15, or use 60 for 1/4th notes.
This solution was especially useful because you can swap out the loop length to any length and it still works.
In the end, the play button onClick looked like this:

And my stop looked like this:

This allows me to change both the loop length, as well as the tempo and have my transport to maintain looping on time.
It seems simple now, but a lot of trial and error went into getting the looping to work on this project, so hopefully, this will save someone else some time and a headache. I’ll be returning with more details about how I built the Zequencer soon.
메타데이터
- post_id
- a849f16971ee
- slug
- revisiting-time-a849f16971ee
- url
- https://medium.com/@zaak.kerstetter/revisiting-time-a849f16971ee
- canonical_url
- https://medium.com/@zaak.kerstetter/revisiting-time-a849f16971ee
- author_url
- https://medium.com/@zaak.kerstetter
- status
- ok
- fetched_at
- 2026-07-26 18:12:23