Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instantaneous tempo changes #34

Open
ntrocado opened this issue Jul 3, 2022 · 3 comments
Open

Instantaneous tempo changes #34

ntrocado opened this issue Jul 3, 2022 · 3 comments

Comments

@ntrocado
Copy link
Contributor

ntrocado commented Jul 3, 2022

Is it possible to have a new tempo start immediately (restarting/resyncing the clock), instead of only changing on the next beat?

@defaultxr
Copy link
Owner

In theory an event with :quant 0 should be processed immediately (and not quantized), but it looks like that is not what actually happens. I'll try to fix that soon.

@ntrocado
Copy link
Contributor Author

ntrocado commented Jul 4, 2022

I was thinking more on having e.g. (tempo 60/60) changing tempo immediately instead of scheduling it for the next beat. I'm making a "tap tempo" thing and this would be useful, but also on other situations. I looked on the internals and I don't think this is currently possible. Another way of getting the same result would be to kill the current clock and start a new one, but the new one would have to keep the state (patterns playing) of the old one...

@defaultxr
Copy link
Owner

Well, (tempo 60/60) is basically just shorthand for (play (event :type :tempo :tempo 60/60)) . So if you want a tempo change to be immediate rather than occurring on the next beat, you could just do (play (event :type :tempo :tempo 60/60 :quant 0)) instead. This doesn't work at the moment, though, since :quant 0--at least for tempo events--is broken. I'm intending to refactor the clock code soon though so once that is done I will ensure all :quant 0 events are processed immediately.

You're correct that it's not currently possible, at least through cl-patterns' exported API. The clock keeps track of time by recording the beat and timestamp of the last tempo change (the timestamp-at-tempo and beat-at-tempo slots), so those slots have to be updated as well when changing the tempo. I played around with this a bit and it seems like this function may do what you're asking:

(defun immediate-tempo-change (new-tempo &optional (clock *clock*))
  "Immediately change the tempo of CLOCK to NEW-TEMPO.

Note that this function may stop working in future versions of cl-patterns, after which the following should be used instead:

(play (event :type :tempo :tempo new-tempo :quant 0))"
  (let ((beat (beat clock)))
    (setf (slot-value clock 'cl-patterns:tempo) new-tempo
          (slot-value clock 'cl-patterns::timestamp-at-tempo) (local-time:now)
          (slot-value clock 'cl-patterns::beat-at-tempo) beat
          (slot-value clock 'beat) beat)))

It's possible that this function could result in clock glitches, but just from testing a bit it seems to work.

As its docstring says, this function may stop working in the future, once I finish the clock refactor, but after that point just using :quant 0 in a tempo change event should work as expected instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants