-
Notifications
You must be signed in to change notification settings - Fork 757
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
fix inconsistent state of clock when tempo is set via setTempoAtSec #2078
fix inconsistent state of clock when tempo is set via setTempoAtSec #2078
Conversation
notification of dependants also happens when tempo is set via `etempo_()`.
an inconsistency can happen when the clock’s tempos was set to <= 0 via `etempo_()` (prTempoClock_SetTempoAtTime), and then later one tries to set it again to a new value via `tempo_()` (prTempoClock_SetTempoAtBeat). Then beats become `nan`. This protects `tempo_()` from being called in such a situation.
Explains the method `etempo_()`
Forgive my misunderstanding, but could you explain why we need to be able to set a TempoClock's tempo to <= 0 at all? I think the documentation is still a bit unclear, and the word 'assuming' not specific enough. But then the methods are poorly named IMO. Probably this is what you meant, and understand, but to be clear, TempoClocks use a base time and base beats to calculate current beats. So their 'memory' only goes back to the last tempo change. What setTempoAtBeat and setTempoAtSecs do change the tempo and the base values. This can mean that the current beats may change as a side effect, which is dangerous. Any documentation should make all this clear. But really, I think these are actually private methods. I'm not sure why users would need them. |
The method that is the "easier" interface is I stumbled upon it because I wanted to be able to set the tempo to zero to pause the clock. This works with |
My gut feeling is that this needs thorough testing before being recommended as a way (or the way) to move clock time arbitrarily. It happens way too often in SC-land that we think of a clever way to do something without properly implementing it as a feature, then push ahead with it before examining the implications... and then it breaks sometime down the road and we have to stick little band-aids onto what was a hack to begin with. Let us please not repeat that mistake here. No problem to have a branch for people to play with and find bugs, but IMO this is very much in progress and not ready to merge. |
@jamshark70 yes, agreed. So I'll remove the example from the helpfile? The rest of the patch has nothing to do with it, it just protects the clock state. |
Yes, I was going to say I also have some reservations about the idea of 0 or negative tempi, because it would commit us to a new and probably rarely used functionality, and could thus constrain us in the future. There's a question of separation of concerns, i.e. what is a Clock? Yes, clocks in SC share some characteristics with timelines, in that you can schedule callbacks on them and thus use them as a simple event queue, but I think they are primarily there to monitor the passage of time, and allow other objects (functions, etc.) to register for notifications of particular times passing. That seems sufficient to me (though convince me otherwise) and I think timeline functionality is better suited to other objects, like Routines, Tasks, and more elaborate objects. Negative tempi won't IIUC allow for time to flow backwards in the current implementation anyway, as clocks and their callback queues have no memory. Whether a TempoClock should be 'pause-able' is perhaps more interesting. Of course Tasks and Routines can pause, but they have no memory of what point between events they paused at, and resume immediately with the next scheduled event. True pausing between events is a desirable behaviour. That should possibly be supported via an alternative method in Task, or similar handling in higher level classes. If it was supported in TempoClock, I'm not sure that etempo = 0 is the way to do it. A proper pause method might be cleaner. If setTempoAtBeat/Sec are documented, I think they should be clearly labelled as private/internal. |
Actually, I found it inconsistent that you can set the clock to tempo 0.0000001, but not to 0. |
Well, I guess I'm just asking what's the use case, and what's the best way to do it. |
I wanted to use the clock by hand, moving it by explicitly setting the beats. Btw. here are some tests. But keep in mind that this is not inside a Thread or anything, I haven't tested any of that yet.
|
Yes, so it would need to be changed. But again, why does one need TempoClock to support negative beat values and negative tempi? If we add that, we're limiting the ways the implementation might be changed or optimised in the future. I think the 'moving by hand' idea could be fairly easily accomplished with something like a PriorityQueue. You could move around, or play, but without needing to alter the basic lower level clock functionality, or give it a memory. Does that make any sense? I just feel like this sort of abstracted event list is higher level than a clock, and likely more a has-a than an is-a relationship. |
... making the "do it all in the clock" approach just the sort of antipattern we've historically loved in SC :p Note that SC's queues give you access to the next upcoming item only. An abstracted event list needs to be a separate thing. |
Yes. In SST, I just used an array, but something smarter would be nice. |
I share your reservations. |
I've removed all debatable documentation: eaac100 The rest is just a protection against getting into the wrong state. |
Protecting clocks against setting them to illogical state seems like an improvement to me. So ok to merge? |
Sorry, I've completely lost the plot on this some months later. Could we just have summary of what exactly this is intended to do now with all the changes? (Sorry, a bit braindead, but worried as this is so core.) Could we also use this as an opportunity to document things like etempo? It makes reviewing these things a real pain that there are all these undocumented methods. |
There is a help entry for |
Sorry Julian! That's great. For my addled brain could somebody just sum up what this is doing now? I gather from the discussion that it's less ambitious then before, but I admit I don't quite understand |
it allows you to set the clock's tempo to zero ( unlike now where you have to set it to a very very very small value). When I looked at the code i also saw that there is nothing that should prevent us from setting it to a negative value either. |
There seems to be consensus. |
But if necessary, it can also be postponed. |
I checked it out, compiled and tried the examples in the help file including
Just one thing: I searched (and failed to find) information on "logical time" vs. "elapsed time". Maybe these can be linked in the helpfile? |
Perhaps add some keywords to the Server Timing help file (for searching -- links would be good too). |
merge it, I say. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! This was quite simple when I finally figured out what was going on. This small snippet was very illuminating to me:
(
r {
t = TempoClock.new;
t.sched(3, {
"baaaa".postln;
nil
});
t.etempo = -1;
"going 6 seconds back in time.".postln;
6.wait;
t.etempo = 3;
"in ".post;
for(3, 1) { |i|
"%...".postf(i);
1.wait;
};
}.play;
)
Note: I did a rebase merge here. This PR is very old and has a mix of recent and old commits, so I didn't want to add noise to the project history. At the same time, squashing didn't seem appropriate since a few of the commits have different purposes (SC style vs cpp changes vs help changes) |
This fixes #2077.
Someone with deeper insight into clock scheduling could check if the explanations in the helpfile are ok.