Skip to content

Conversation

@JoergAtGithub
Copy link
Member

@JoergAtGithub JoergAtGithub commented Apr 23, 2024

This is #4528 with fixed CI and solved merge conflicts.

It implements the following COs without GUI: https://github.com/mixxxdj/mixxx/wiki/Macros

This PR is the first step to implement the Macro feature. The Mixxx Macros feature is designed functional compatible to Serato Flip. If we later add a Serato Flip importer in a Follow-Up PR, Mixxx DJs can use all files prepared with Flips provided by the common DJ pools.
A good (maybe a bit flippy ;-) ) introduction into the use cases of Serato Flip can be found here: https://www.youtube.com/watch?v=sHRWfdxkI7E&t=186s

Copy link
Member

@acolombier acolombier left a comment

Choose a reason for hiding this comment

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

I tried the feature but could only get a single hotcue to work. It could be that I'm not using properly tho. Do you know if there is any wiki or doc on how to use this feature beside the GSoC wiki page?

@JoergAtGithub
Copy link
Member Author

I tried the feature but could only get a single hotcue to work. It could be that I'm not using properly tho. Do you know if there is any wiki or doc on how to use this feature beside the GSoC wiki page?

I think there are only the three GSoC pages in our wiki, and the original PRs of cause. One aim of this feature was to achieve compatibility to Serato Flip, to allow data import from Serato. Therefore I guess, that the Serato Flip feature is similar to use: https://support.serato.com/hc/en-us/articles/203157550-Serato-Flip-User-Guide

Copy link
Member

@acolombier acolombier left a comment

Choose a reason for hiding this comment

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

Thanks for bringing this feature back to life. Appreciate you didn't write this code but I think there quite a few things that don't line up with our coding guidelines.
Haven't had a chance to test it yet!

Comment on lines +9 to +11
optional uint32 type = 1;
optional uint64 source_frame = 2;
optional uint64 target_frame = 3;
Copy link
Member

Choose a reason for hiding this comment

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

Looking at MacroAction::serialize, should not this be mandatory fields?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not familar with protobuf and can't answer this. But I couldn't find any review remark in the predecessor PRs about it.

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, maybe these should be required. Not sure. My understanding of protobuf is that this does not affect the serialized output, just the deserialization code. So we should probably make these required and "downgrade" them to optional only if the becomes necessary.

Copy link
Member Author

Choose a reason for hiding this comment

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

@daschuer @Swiftb0y Do you know Protobuf well enough to answer this question with certainty?

Copy link
Member

Choose a reason for hiding this comment

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

Not with certainty, but until now my rule of thump was that everything should be optional just in case. In protobuf 3 the concept of required fields has been removed altogether:
https://stackoverflow.com/questions/31801257/why-required-and-optional-is-removed-in-protocol-buffers-3

@ronso0
Copy link
Member

ronso0 commented Oct 28, 2024

I thought macros are per track? (= per deck, not one macro manager.

@JoergAtGithub
Copy link
Member Author

JoergAtGithub commented Oct 28, 2024

The GUI controls are global, you click the record button and it records the deck were the DJ does the next action.

I also thought, that this might be difficult to understand and had the idea of a colored border around the deck - e.g. when armed, all decks get a orange border, and once a deck is selected, only this one get a red border.

@ronso0
Copy link
Member

ronso0 commented Oct 28, 2024

But (as I understood it back then) macros are per track, so I can start a macro on deck1, load a track in deck2 and start its macro#5 to do prepared mashups and stuff.
Thats only possible if we have a per-deck GUI.

I don't want to move this off-topic, just saying...

@JoergAtGithub
Copy link
Member Author

Yes, lets discuss the GUI on Zulip. The COs in this PRs should be flexible enough to allow per deck controls as well.

@daschuer
Copy link
Member

Great you picked this up.

What is the difference between the Status::Playing and Status::Enabled? I have not tested it ...

Am I right that Macros do not necessarily include transport actions? Will the track start playing if pressing macro play? This depends probably on the macro itself?

-Use QStringLiteral: in getConfigKey instead of QString member
-Avoiding multiple calls to getConfigKey by using a lambda function
@JoergAtGithub
Copy link
Member Author

What is the difference between the Status::Playing and Status::Enabled? I have not tested it ...

See https://github.com/mixxxdj/mixxx/wiki/Macros
This is the unchanged functionality of the GSoC project, which was jointly agreed on. This PR only addresses the open code style and CI issues for which the original GSoC PR was not merged.

@daschuer
Copy link
Member

Unfortunately I have not yet understand the difference and the underlying use case. Can you explain it?

@Holzhaus
Copy link
Member

What is the difference between the Status::Playing and Status::Enabled? I have not tested it ...

There is no Status::Enabled.

enum class Status : int {
NoTrack = -1,
Empty = 0,
Armed = 1,
Recording = 2,
Recorded = 3,
Playing = 4,
};

@daschuer
Copy link
Member

daschuer commented Nov 1, 2024

There is no Status::Enabled.

Oh I see, I got confused with the StateFlag::Enabled

I have still not fully understand how that interacts.

Is the a description of the state transitions somewhere?
Maybe there is a chance to simplify it a bit.

For my understanding a macro is comparable to Auto DJ, but only for a single track. Is that correct?

It is possible to record a jump between two cue points.
After recording the user has to press "play" on the macro button for the deck to enable the macro. When the deck is then played in terms of transport, for example by Auto DJ, the jump is automatically performed.

Is that correct?

@JoergAtGithub
Copy link
Member Author

JoergAtGithub commented Nov 1, 2024

I don't see a similarty to AutoDJ, but yes, it's per track. I added a video that explains the functionality to the PR description.

And please let not put the feature in question at all. It's all defined and lengthy discussed in GSoC. This is just to fix the final code style and and unit test issues, which prevented merging of the original PR.

@acolombier acolombier dismissed their stale review November 4, 2024 19:52

not available for review

Copy link
Member

@Swiftb0y Swiftb0y left a comment

Choose a reason for hiding this comment

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

couple comments to try and help get this along.

Comment on lines +42 to +44
int value() const {
return m_value;
}
Copy link
Member

Choose a reason for hiding this comment

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

this breaks the encapsulation which is the sole purpose of this class. If the value is used in queries, I think its supposed to go through the QVariant (you may need to look at other usages of DbId).

Comment on lines +1393 to +1398
for (const MacroPointer& pMacro : std::as_const(m_macros)) {
if (pMacro->isDirty()) {
return true;
}
}
return false;
Copy link
Member

Choose a reason for hiding this comment

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

std::any_of

/// but that is subject to change.
class MacroAction {
public:
enum class Type : uint32_t {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
enum class Type : uint32_t {
enum class Type {

///
/// Note that currently only jumps to a m_target position are available,
/// but that is subject to change.
class MacroAction {
Copy link
Member

Choose a reason for hiding this comment

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

trivial constexpr opportunity of the class.

#include "audio/frame.h"
#include "engine/engine.h"
#include "proto/macro.pb.h"
namespace proto = mixxx::track::io;
Copy link
Member

Choose a reason for hiding this comment

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

namespace pollution in header

Suggested change
namespace proto = mixxx::track::io;

Copy link
Member Author

Choose a reason for hiding this comment

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

The suggested code change breaks the build

Copy link
Member

Choose a reason for hiding this comment

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

right, you'll obviously have to replace all the occurences of proto with the longer name...

Comment on lines +27 to +34
m_COStatus([this]() { return getConfigKey("status"); }()),
m_CORecord([this]() { return getConfigKey("record"); }()),
m_COPlay([this]() { return getConfigKey("play"); }()),
m_COEnable([this]() { return getConfigKey("enable"); }()),
m_COLoop([this]() { return getConfigKey("loop"); }()),
m_activate([this]() { return getConfigKey("activate"); }()),
m_toggle([this]() { return getConfigKey("toggle"); }()),
m_clear([this]() { return getConfigKey("clear"); }()) {
Copy link
Member

Choose a reason for hiding this comment

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

this is dubious because it relies on the class already being partially initialized. I think the better option would be to just pass in the group along with getConfigKey and make it static...

Comment on lines +37 to +38

m_updateRecordingTimer.moveToThread(qApp->thread());
Copy link
Member

Choose a reason for hiding this comment

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

this needs a comment.

Comment on lines +82 to +83
// FIXME(xeruf) Jumps while paused (e.g. via GotoAndStop) are not properly recorded
// since this function is not called
Copy link
Member

Choose a reason for hiding this comment

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

do you plan to address these FIXMEs? These certainly sound like bugs.

/// The unquantized FramePos of a jump that is yet to be processed
mixxx::audio::FramePos m_queuedJumpTarget;

rigtorp::SPSCQueue<MacroAction> m_recordedActions;
Copy link
Member

Choose a reason for hiding this comment

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

since this is designed for multithreading, this suggests that MacroControl is also used from multiple threads. Its not clear to me how though so I'd appreciate if you could document which member functions are expected to be accessed concurrently (and thus need to be threadsafe and which dont).

Copy link
Member

Choose a reason for hiding this comment

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

MacroControl obviously lives in the GUI thread, but IIRC some methods (e.g., slotJumpQueued) are invoked via direct connection from the engine thread.

@acolombier acolombier mentioned this pull request Feb 18, 2025
@JoergAtGithub JoergAtGithub added this to the 2.7-beta milestone Mar 16, 2025
@github-project-automation github-project-automation bot moved this to In progress in Releases Mar 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

7 participants