Looking for "better" tap tempo abstraction

    Dec 04 2011 | 5:48 am
    I'm looking for a tap tempo algorithm in Max that does better time detection than the examples I've found. In particular, I'm looking for something that can both lock in to a tempo quickly but yet be able to adjust as I tap without taking too long to match my new tempo but not be too jumpy. I've played around with the examples, changing the number of taps being averaged, etc, but I can't get it work nearly as well as the tap tempo detection that I have on either my Korg Oasys or on my Boss Digital Space Echo (which seems to work even better than the Oasys). On these, I can let them free-run but if I start tapping, they very quickly adjust to my new tempo with any sudden changes. I suspect they're using some non-linear weighted system for adjusting the tempo based on "recent" taps.
    Anyone know of a more sophisticated tap tempo system for Max?
    Thanks, D

    • Dec 04 2011 | 10:58 am
      Hi "more sophisticated" than what? You don't mention the method you're using; I would suggest [timer] followed by some [zl] objects for averaging, like this:
      The minute fluctuations in timings between physical taps WILL create jumps, unless you use some heavy-handed interpolation - which will introduce a delay. Maybe add a [line] at the output?
      EDIT: added a synced beat generator
    • Dec 04 2011 | 11:53 am
      They both felt like "engineering" / "mechanical" solutions but neither of them "felt" right, at least compared to the way tap tempo works on the instruments and devices I mentioned, both of which I've used in live situations with a band and was able to easily sync my sequenced arpegggiators to the drummer. There were no noticeable jumps nor was there any significant delay.
      I've done a little bit of reading since posting the question and as far as I can tell, it's not sufficient to just take the moving average of some number of taps. The articles I've seen seem to have some non-linear (weighted) bias as well as some beat prediction capabilities.
      To paraphrase the judge, this is one of those things that I know what feels right but I don't know why.
      I'll take a look at your patch when I'm in front of my computer later today.
    • Dec 04 2011 | 12:17 pm
      Ah, ok
      then perhaps my 'solution' is a little simplistic for your needs - no weighted bias or predictive capabilities, just some averaging, but with the [zl] and [line] objects it works for me.
      sorry to disappoint :(
    • Dec 04 2011 | 12:19 pm
      if you keep this thread live over the next week or so, I have no doubt that a maths guru will jump in with some [expr] or other function that does what you need......
      -average the first N timings -accept subsequent timings only within that measurement -set new tempo only after N measurements are completed
    • Dec 04 2011 | 1:07 pm
      First of all, you're not disappointing, I truly appreciate getting responses --- sometimes such dialogs help guide towards solutions. Nor am I suggesting that such things as "weighted bias" and/or "predictive capabilities" ARE the solution, it's just that as I look around, I'm seeing references to such things.
      Now, I just had a chance to play with your patch and as it turns out, your timer triggering that metro actually seems to work quite well EXCEPT that as I manually tap, I think it's generating both the automatic beat as well as my tap, so I get two taps close together.
      (By the way, I'm less interested in actually seeing the BPM value, than just getting a smooth beat that's responsive to manual tapping)
    • Dec 04 2011 | 7:53 pm
      Again, ah yes
      I overlooked that bang duplication;
      maybe a simple [onebang] with a small delayed reset, c. 5-20ms, off the top of my head?
    • Feb 03 2012 | 10:22 pm
      I have found success with the [zl stream] object with the [mean] object underneath it. Using an argument of 3 or 4 is pretty smooth comparatively.
    • Feb 04 2012 | 7:40 am
      How does this compare to the tap tempo in the sync~ object, does anyone know? Can these solutions be used to affect max's global tempo setting?
    • Aug 18 2013 | 2:32 pm
      Hey, it's been a while but I'm going to stick my nose in here. As a DJ, I am looking for a similar solution. Basically, I am looking for a super intuitive timing belt type device that I can use to sync Ableton Live to live performances and cd's with the flexibility to allow for drift.
      Ultimately the goal, I just sit and tap quarter notes into the thing and it does whatever necessary to stay with me. However, if I stop tapping to sip on a martini, it keeps going. If I feel the groove lock, and I want to mess with some other effects, I can stop tapping, but if it starts to fall out of sync, I can just start tapping away and it adjusts to match.
      My first attempt (involving averages and differences...etc) only led to ableton oscillating around the tempo of the song and rapidly going buck wild...one tap it's going 32 bpm, next tap 500 bpm. From there it's just a crap shoot and sonic destruction. I see it only as a great way to end a set...
      But I digress. I"m seeing a few major components to such a system:
      - detection of good vs mistaken taps. If mistakes get filtered out (like 1/2 way between a beat) then junky data won't corrupt your tempo. - some way to detect consistent differences in timing which don't mean a change in tempo (constantly 10 ms behind the beat doesn't mean slower tempo, it just means slow down and speed back up when you've added 10 ms delay. - What to do when you stop tapping...if the user stops tapping when it feels right, there might have to be a final adjustment to keep the system in the groove based on all of the previous data. - some system to keep it from drifting to the wrong downbeat while trying to correct. - of course, how do you recognize an accel. or rit. and work that in? Also, what about a sudden a-tempo which is bound to happen as well.
      DHJDHJDHJ, I think that is closer to the core of what you are asking, and I have been asking that for quite some time now. I wish I had more facility to answer these questions, and unfortunately due to my current work, I haven't been able to devote much time to the problem, but maybe collaboratively, we Max/MSPer's could come up with a solution. Any thoughts?
    • Aug 18 2013 | 4:05 pm
    • Aug 18 2013 | 4:28 pm
      It might be an idea to limit the range of possible right answers to something within 10bpm of the current tempo or manually enter an initial idea for tempo. That way you could stop your patch outputting stupid numbers like 500bpm or 32bpm so limit it to your normal working tempo range which for DJ music tends to be an extremely fine range with many DJ's never going much more than 5BPM either way - a tempo range of 118 to 144 would probably cover almost all techno, house, club DJ's and it would be easy to have HipHop and D'nB modes for those working outside that tempo range.
      Final adjustment could be done with a nudge function - basically a line to the transport object that speeds up/slows down the tempo and the reverts to the original tempo when you let go of the button - so a 1 from the button starts the tempo ramp and a 0 from the button stops the ramp and resets the original tempo.
      Instead of or complimentary to your use of a tap tempo solution you could look into bonk~ and MIDI Clock.
      I haven't built a tap tempo (outside of the one Brendan showed you) but if I was going to this is where I would start - weighting, analysis, MIDI syncing and fine control.
    • Aug 18 2013 | 6:35 pm
      I thought a bit about the problem, and I cooked up this idea. Note the subpatcher. It doesn't measure tempo. Instead, it takes two out of sync metro objects and syncs them up. Of course they have to work at the same tempo, but this can provide final sync once the tempo tapped is established. This could aid in solving bullet 2 of my point mentioned before.
      Audiolemon, that is a good point. It is important to differentiate between half note and quarter note pulses. Is dubstep 140 BPM or 70?
      Another thought, which I'll explore next time I work on this problem, is how does the function of taps affect the clock depending on how many taps have been performed? I expect my first few taps to be out of time, and wouldn't want tap #2 to trigger a skip, but if I've been tapping a while, I would want to have good enough response to lead a ritard, accelerando, or even an a-tempo.
    • Aug 19 2013 | 6:55 am
      My advice would be to avoid rolling your own and instead look at some of the results from the Music information Retrieval world.
      Tempo tracking is hard problem , so it's worth looking at expert solutions. There's always knowledge to be gained from trying to do it yourself, but for sheer efficacy...
      Will try to post some links this week.
    • Aug 19 2013 | 12:58 pm
      Peter, I agree. It is always easier to follow a recipe someone else has hashed out than to work it out yourself. I would take that advice if Ableton's tap tempo function wouldn't spin out of control so easily. At least that's what I've experienced with it.
      I tried combining my shifting abstraction with a kind of ZL filter presented by N00B_MEISTER earlier. It feels good. It averages to your tempo, and then will slowly shift in sync with your taps. However, on extreme jumps it will still oscillate around tempi a bit before it averages in. I think the problem involves how many beats to average in your tempo calculation. I am averaging 16 taps, which leads to a very sluggish tempo change.
      My next thought is to have Max analyze the curve created by the series of taps. More on that later, time for breakfast.
      I'm looking forward to these MIR sites, never knew that existed.
    • Sep 05 2013 | 6:59 pm
      You might also look at a median filter. These are good for this particular type of situation because they ignore outliers.
      (use zl.stream 7 -> zl.median for example)
    • Sep 05 2013 | 8:55 pm
      I didn't think of a median. I never tried that. I'll have to check it out. Thanks man!
    • Sep 07 2013 | 3:07 pm
      Just be sure to account for the difference between odd-numbered and even-numbered medians. (odd-numbered will always output a value in the input set; even numbered will output the average of the two center values)
      Median filters are also really great for threshold detection tasks. Unlike averaging filters, they can jump to a new value faster.
    • Jun 25 2015 | 1:28 pm
      Anybody have an example of using median? Anybody find links to good algorithms?
      Very interesting thread--wondering why it died out.... I'll have a look at the posted code at any rate.
      cheers! -eric
    • Jun 25 2015 | 2:29 pm
      Thanks to notifications...this thread is never dead...
      ZL has a median function. Type "zl median" in an object to get it.
      This patcher I made in a few minutes generates a random list over time. You don't need to sort to get the median. Happy patching!
    • Jun 25 2015 | 2:39 pm
      If you're wondering why I disappeared...well, life happened, but I am still working on it off and on. I am no longer djing...but I am a published composer, so I am transitioning toward electro-acoustic work. So this means I still have an application for the tap tempo algorithm, but I need to make it much more robust...For example, taking a live performance and extracting the tempo & downbeat from subtle fluctuations in velocity and a variety of rhythms. But that is WAAAAY down the road right now, so this particular problem is on hold for me.
    • Jun 25 2015 | 8:56 pm
      Here's a simple tap-tempo abstraction I use often. It's the basic approach outlined at the beginning of the thread. The one change I've made is to sort the list of timings and throw away the highest and lowest values before calculating the average. This helps to deal with spurious values. I'm using mean here; will play with median soon.
    • Jun 26 2015 | 12:45 am
      Holland! Thanks for sharing! Mind if I stitch that together with the beat follower? I'm also playing around with the median and also averaging the median and average together...
      Would there be a better math to do combining the median and the average?
    • Jun 26 2015 | 2:05 pm
      I prefer the simple median myself for most such applications because it will definitely be one of the values I tapped, though YMMV. If you're looking for a more detailed approach, tap-tempo is basically the simplest case of what is called "beat induction". (simplest in the sense that it's totally regular and not looking for a meter) It might be worth checking out the research in this area if you're looking for improvements.
    • Jun 27 2015 | 12:20 am
      Great to see this thread come up! I've tried to do this before but stopped because of seemingly insurmountable problems, e.g. how to recognise the difference between ritard or accel and a sudden tempo change. But as I was reading it occurred to me that the patch could have 2 tap inlets: one for gradual tempo changes and the other for sudden ones. Sudden changes could have the option of waiting (or not) for the next bang output and could kick in from the 2nd tap.
      My patches were intended for playing drum sounds with MIDI bass pedals, and I was trying to make them cover all possible uses - keep going (or not) when input taps stop, use [bucket] to constantly analyse tempo, gradual or sudden changes, output bangs in-between main beats, etc. etc.
      Now you guys have given me a whole swag of ideas to try out, so THANKS! =:-) If I get any good results I'll definitely be back to add to this already terrific pool of ideas and pasted patches.
      Cheers, Bill
    • Jun 27 2015 | 11:03 am
      Peter, that's fascinating! I'll have to read more about beat induction. I found this paper: http://www.mcg.uva.nl/papers/Honing-2012a.pdf :which approaches the process of beat induction from a psychology of expectation. Of course this is drifting away from this thread and going toward something broader in terms of a computer generally following an ensemble.
    • Jun 27 2015 | 11:33 am
      Great paper Chris . Thanks for sharing it !
    • Jun 27 2015 | 1:17 pm
      Definitely great to see this activity....I still haven't found a suitable solution.
      I have vague intuition for a physical model for my purposes but my math is too rusty to implement it these days. I imagine a flywheel with some specified (possibly changeable )weight and diameter that spins at some rate representing a tempo. There would also be a gear that would allow "instantaneous" speed changes (go to half speed, double speed). So the flywheel would tend to keep the tempo rate constant in the absence of taps.
      Incoming taps (including both time between taps, rate of change between taps and perhaps even the velocity of each tap if you're doing it from a keyboard) could be used to influence the behavior. So depending on what you're needing to do, a very slight change in tap rate might be ignored, or cause slight changes. A few missing taps followed by taps at the original rate would have no effect, tapping really hard suddenly might serve to create a rapid change.
      Clearly some of this is can be modeled with some kind of weighted moving average but there's also interpretation needed so the system can differentiate between slight tap change rates, missing taps, the desire to induce sudden change, etc
      Just food for thought. Clearly I should catch up on the literature as well :-)
    • Jun 27 2015 | 6:46 pm
      Good afternoon all! I took some of the latest ideas and threw together a combination of the sync patch I had earlier and added the latest in tempo mean/averaging discussion to create a follower. Some pluses: + It will find a new tempo, and then sync the metronome to play with it. + It seems to be very stable.
      Some areas for improvement: - When doing an accell or decel, it will constantly lag ahead or behind the curve. Maybe some sort of prediction algorithm would be helpful. - When you establish a tempo, you have to tap a full 7-8 clicks or it will pop to a different tempo when you stop tapping. - right now the patcher below averages the mean and average. Is there a way to control that so you could set 100% mean, or 100% average, or 50 50?
      This is quickly growing into a much bigger solution that I'm working on, particularly involving recognizing a tempo within rhythms, and then getting a sense of beat and speed there.
    • Jun 27 2015 | 9:46 pm
      @dhjdhjdhj: there's C++ source code for a beat induction algorithm in Robert Rowe's Machine Musicianship. IIRC (and I may not) it's similar to the attractive oscillator approach which works for subdivisions.
    • Jun 28 2015 | 1:03 pm
      Thanks, Peter --- I'll check it out.
      Take care, D
    • Jul 12 2015 | 11:11 am
      I've been playing around with this and still haven't found a great solution.
      One seemingly insurmountable problem is this: If, for example, you have a click happening at 88 bpm and then want to tap in 100 bpm, if you just start tapping at 100 bpm it's easy enough to make the click speed up to 100, BUT It'll never be in sync with your tapping unless you stop and join in again. Or unless you make it faster than 100 till they're in sync then drop the click to 100 again.
      That can't be how it works on your Korg Oasys or Boss Digital Space Echo, can it, David?! It doesn't seem very intuitive but I can't see how to work around it.
      Working out the mean of the last n tapping times, or removing taps more than a certain percentage away from the current tempo was done pretty quickly, but this problem's got me stumped. Any ideas?
    • Jul 12 2015 | 4:25 pm
      I haven't had time (no pun intended) to look at this again yet but the issues you raise are precisely why I have this vague intuition of modelling tempo using a flywheel with inertia. The wheel would tend to want to keep its current tempo and depending on how you tap (and change your tapping rate), the characteristics of the flywheel (that make it "want" to be at a certain speed) would adjust, sometimes drastically.
      I know this seems vague (that's partially the problem with intuition) but there may be treasure there :-)
      My Kronos (used to be Oasys) just seems to do a very nice job when I tap based on the rest of the band changing speed. I've asked on the Korg forums but never got an answer from anyone. I don't have the Space Echo any more.
    • Jul 12 2015 | 5:04 pm
      The adaptive oscillator algorithm incorporates phase information. You might look at a digital PLL algorithm as well. (Phase locked loop)
    • Jul 13 2015 | 1:52 pm
      @bill I did include a code that picks up a tempo and syncs with your tap. It is my last post from June 27. I would love your feedback on how it works. It's not perfect, but it at least attempts to do everything that you're talking about.
      @DHJDHJDHJ I like the idea of including some sort of fly wheel design. It might also be good to clear out the buffer with the absence of taps, so you could give two definitive taps to get a whole new tempo. All further refinement..Anyway, I'm rambling now. But maybe to clarify final behavior it would be good to define all the kinds of user input that might have to come into the algorithm. Accelerando...Rallentando...A-tempo...Subito allegro...the list goes on. Then we could define ways the user could input that clearly into the system.
      @Peter I'll have to check those out!
    • Jul 13 2015 | 2:15 pm
      @chrisroode Obviously I have no scientific basic for the flywheel idea since I haven't even tried to validate the notion but I'm certainly very appreciate that you are thinking about the whole issue.
      I sort of understand Peter's suggestion about using PLLs. However, it's not obvious to me (because I don't know that stuff deeply) how well the parameters/independent variables, feedback, etc that define a PLL map to a physical model of a flywheel.
      In other words, when I think about simulating a flywheel, I'm thinking more about how the kind of material, thickness, diameter (and therefore the mass) and so forth, impact the speed and resistance to acceleration, etc but changing those kinds of parameters either smoothly or discontinuously seems more intuitive to get the desired behavior.
    • Jul 17 2015 | 11:05 am
      @chrisroode: Sorry - I've been distracted for a few days. Will definitely have a closer look at your patch. The first time I looked I couldn't understand the maths without spending a bit of time on it, but it sounds like it'd be well and truly worth it.
      For now, though, can you tell me whether it makes one of the metros speed up till they're in sync then slow it down again…?
      @dhjdhjdhj: If (at least part of) what you mean with your flywheel metaphor is that the tempo keeps going at its current rate (whether you're tapping or not) until you make it change by tapping at a new tempo, then I've got that happening. If Chris' syncing patch can be added to it we might have a solution - hopefully, one that works well and feels right.
      I'll get onto it in a few days. As Rachel Hunter famously said: It won't heppen overnight, but it will heppen. ;-)
    • Jul 17 2015 | 11:29 am
      @Bill Canty --- it's really more about how the flywheel rate changes when influenced by incoming taps (and perhaps other parameters such as velocity of a tap when available)
    • Jul 21 2015 | 12:56 pm
      @Bill Canty
      Hey, crazy week here. I'll try to answer your question: There are two systems working to adjust the tempo and the phase of the click in my previous patch.
      1) Average and Median the last 8 or so taps to find a tempo. 2) Time the click and the tap, and use the timing difference to predict how far out of phase the click is and adjust it for the next click.
      The problem is that the click is so good at #2 that it can appear to follow you really well. Therefore, if you get to your desired tempo, you need to tap a good 2 measures so that #1 can find the tempo you are at. If you stop tapping prematurely, when #2's phase adjustment returns to 0 in the absence of taps, the metro can end up being as much as 20 clicks off. I have some ideas on how to fix it...but it'll have to wait..thank you band camp...#forTheRecordILoveTeachingDrumline
    • Feb 10 2016 | 3:45 pm
      Someone said this thread never dies.
      @chrisroode, did you fix your remaining problem in the end?
      I just read this on the interwebs (link):
      As each new tap comes in, compare it to the previous average. If it falls outside of a certain range of acceptable variation, throw out all the old ones and start over from scratch. Now we’ve got the best of both worlds: if the taps are nice and steady, just keep on collecting intervals, and the average keeps getting more and more accurate. But, if a rogue tap comes in, you don’t have to wait for the 2 second timeout or the old taps to “fall off” the end of the array, just keep on tapping, and the metronome will adjust to follow your new tempo!
      I thought this approach was pretty interesting.
    • Feb 11 2016 | 4:11 am
      @julian short answer...no
      Band camp led into a one day a week teaching job, which became three, and then some other good news about a composition I submitted to a contest...then it was november...and then december came...Then as a new years resolution I came to prioritize what i'm doing with side project...because my teaching work is crazy and i'm about as organized as a drummer artist can be...So, this project has fallen off on the wayside, but it's not forgotten either way.
      The way I might plop it open is if I start working on my beat induction algorithm for computer music systems...which I might get going at some point...
      You're more than welcome to open up the patch I have above. It's the latest version I had of a tap tempo algorithm...
    • Feb 11 2016 | 12:53 pm
      I had a look at your patch, I like your style! The thing that's missing for my usecase is that you can't just tap three times to get it going, you really have to tap 7 times until the [zl stream 7] is filled. I'll work a bit on it and post the results here as soon as I got something. Maybe I'll get that idea that I talked about earlier to work. Thanks for getting back Chris.