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

Saved beat jumps #13216

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft

Saved beat jumps #13216

wants to merge 5 commits into from

Conversation

acolombier
Copy link
Contributor

This addresses the feature request #13161

Currently, the activating the saved jump result in enabling or disabling the auto jump (different icon used to provided feedback on jump status)

Kooha-2024-05-06-18-58-03.mp4

TODO:

  • Normal hotcue behaviour if playback ahead
  • Other theme?
  • Manual update

Depends on #13215

}
if (pCue->getPosition() > m_lastProcessedPosition &&
pCue->getPosition() <= currentPosition) {
auto delta = pCue->getPosition() - currentPosition;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does not work well, because the jump is quantized by the engine buffer size. Normally you want to jump beat exact and which can be somewhere within the buffer.

So we need something like the looping engine.

How about actually using the looping engine. Isn't a jump just the same as a loop which disables itself after one iteration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it not work? This is already a simplified version of LoopingControl::process, except that we do not need adjustedPositionInsideAdjustedLoop, but can seek to the "target" directly, (corrected with the engine delay to prevent desync, as done with that delta var)

There is a few drawback I can think about using the looping engine:

  • Loop engine expects start < end, but jump may have from > to. Allowing start > end in LoopingControl sounds wrong
  • They maybe be a loop defined (but not active) and using the LoopingControl will override it for a "one frame" loop (or will have to deal with state restoration, which sounds overkill)

Isn't a jump just the same as a loop which disables itself after one iteration.

To some degree, except it is more simple that a loop, and doesn't need to complexity around the loop (no concept of seekMode for example, or direction). Disabling it at the next iteration implies that is had to be enable at some point, which is why making the most of EngineControl seems a better approach. The engine is already able to perform jumps, so I'm not sure what is the value of using the LoopingControl for a simple unique unidirectional jump

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The seeking code in LoopingControl::process handled only the exceptional cases when adjusting the loop size. The looping itself is done here:

const mixxx::audio::FramePos loopTriggerPosition =

Your current implementation does not work for reverse playing and jumps before the track, and small jumps, < delta.

It took quite some iterations to have the looping code rock solid and I have not a big interest to repeat these iterations with beat jumps again. So let's consider what is the best way for trying that code.

Loop engine expects start < end, but jump may have from > to. Allowing start > end in LoopingControl sounds wrong

I think we have discussed earlier to allow forward loops. The engine don't mind if it is a repeated jump backward or a single jump forward.
However we need to take care not to create surprises when we allow to edit jumps with looping controls. So I agree to not reuse them in the first attempt.

They maybe be a loop defined (but not active) and using the LoopingControl will override it for a "one frame" loop (or will have to deal with state restoration, which sounds overkill)

We have this issue already with saved loops.
For example I would love to have a saved loop at the end of the track to extend a short outro that is always active. Maybe we can solve both in one run.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your current implementation does not work for reverse playing and jumps before the track, and small jumps, < delta.

It does need to, because of the unidirectional aspect of a jump. IMO, you wouldn't expect to jump back to the from position if you play reverse above to

For example I would love to have a saved loop at the end of the track to extend a short outro that is always active

Definitely would like to see this behaviour too as I could use it as well. But perhaps that is out of scope for this feature?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the reverse case, my expectation was that it jumps form the "to" position to "from" just as if you would play backwards a forward recording of the jump. But It is also OK for the first version to not jump at all in reverse, which is is probably not yet the case . (not tested)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of this feature is to "automate" a beatjump_forward so not sure it would make sense to "undo" this jump if playing reverse.
I guess we could make it work with a minimal amount of change, without using the LoopingControl if that the behaviour with would expect.

@ronso0
Copy link
Member

ronso0 commented May 7, 2024

Currently this behaves like a loop, i.e. the jump cue is not deactivated after the jump if the the target is behind to cue.

@ronso0
Copy link
Member

ronso0 commented May 7, 2024

Having to deactivate a special mode in order to get the hotcue mode feels.
I'd vote for three buttons in the popup:

  • hotcue (flag icon?)
  • loop
  • jump

IMO they can be very close (like the hotcue grid), to somehow mimic radio buttons?

@acolombier
Copy link
Contributor Author

acolombier commented May 7, 2024

the jump cue is not deactivated after the jump if the the target is behind to cue.

That's right, and it was on purpose. Do you think it would be best to have it deactivated on run? My thought for the usecase was, when a DJ prepare their track cues, and decide to say that a section should be jumped over, this is likely that they want not to play the section of the track, so we should keep it on at all time. If they decide live to actually play this section, they can trigger the hotcue (hotcue_X_activate/hotcue_X_status=1) which will disable the jump (different icon on LateNight/Palemoon, to be brought on other theme once we've iron the details)

Having to deactivate a special mode in order to get the hotcue mode feels [wrong].

You don't have to. Like for the saved loop, you can use the activate or status CO to change its status to set instead of active. This can be done on the UI (again LateNight/Palemoon only for now) by clicking on the cue, no need to change the type (and lost the jumping destination)

somehow mimic radio buttons?

I like the idea, happy to make it work like this once we are happy with the state of feature

@acolombier acolombier force-pushed the feat/saved-jump branch 2 times, most recently from 4d7c46e to bf74e6e Compare May 9, 2024 15:40
@acolombier
Copy link
Contributor Author

acolombier commented May 9, 2024

I have upgraded the button to behave like a radio group. Also, I adjusted slightly the delete button to put the emphases that they are not part of the radio group.

Kooha-2024-05-09-16-45-06.mp4

@acolombier acolombier marked this pull request as ready for review May 9, 2024 15:50
@acolombier acolombier marked this pull request as draft May 9, 2024 15:51
const mixxx::BeatsPointer pBeats = m_pTrack->getBeats();
const auto position = mixxx::audio::FramePos::fromEngineSamplePos(
m_pPlayPos.get() * m_pTrackSample.get());
if (position == m_pCue->getPosition()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason this doesn't work for me:
when clicking Jump while at the cue position a zero-sized jump is created. When activating thus jump cue I run into an inifinite tiny loop.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the display start and end seem to be idetical.

Maybe a rounding issue with fromEngineSamplePos()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed now

@ronso0
Copy link
Member

ronso0 commented May 11, 2024

I think at least in LateNight we need better styling for the 'active state' of loop/jump cues.
The current inactive jump icon should be the dark/bright active icon, and we could use a highlight border.

I'll tr ysomething.

@acolombier
Copy link
Contributor Author

I've made some minor UI tweak - does that look better @ronso0 ?

Also, I have made the saved beat jump to disable itself if jumping backward, to prevent them making unwanted loops. My use case for this feature was the ability to jump above certain part of track with the low interest, so I would appreciate we don't disable jump forward when possible so a track can be prepared with auto forwarded sections.

If you think it should be different, I can add a setting in preference.

@ronso0
Copy link
Member

ronso0 commented May 25, 2024

For some reason I can't assign a "free" jump target anymore, it'll always use the current jump size, both for righ- and left-click.

@ronso0
Copy link
Member

ronso0 commented May 25, 2024

For some reason I can't assign a "free" jump target anymore, it'll always use the current jump size, both for righ- and left-click.

Strange, I can't reproduce that anymore.

@acolombier
Copy link
Contributor Author

That weird indeed. It sounds like a bug I fixed when I rebased main yesterday tho, couldn't it be some cached sources?

@ronso0
Copy link
Member

ronso0 commented May 25, 2024

What I find a bit disturbing is that the jump range in the overview always appears as 'active', unlike saved loops which are less opaque if disabled.
(ranges covering the signal is another story on its own...)

@acolombier
Copy link
Contributor Author

(ranges covering the signal is another story on its own...)

Yep, agreed. This is why this is still a draft ;)
I want to get rid of the MarkerRange and use custom Marker which allow to display some kind of "cue with a jump flag" on the from and to positions.

I've paused that work because implementing the above requires to touch on lot of waveform renderers atm, which we are hopefully being retired as part of #13226.
I will look at that after. In the meantime, if you have some asset suggestion for the cue design, feel free to help! You probably know by now, but my UI taste are pretty 💩

@ronso0
Copy link
Member

ronso0 commented May 26, 2024

Just an idea I had while reading https://mixxx.discourse.group/t/timing-a-fireworks-show/29693/3
Let's add a 4th cue type 😆
Stop Cue
activate it, and as soon as the play pos hits it... stop

@ronso0
Copy link
Member

ronso0 commented May 26, 2024

For some reason I can't assign a "free" jump target anymore, it'll always use the current jump size, both for righ- and left-click.

Might stem from a previous version where the end was not cleared after changing back to hot/jump cue.

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

Successfully merging this pull request may close these issues.

None yet

3 participants