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

Stems hot cues + OSC #13745

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,8 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/preferences/dialog/dlgpreflibrarydlg.ui
src/preferences/dialog/dlgprefmixer.cpp
src/preferences/dialog/dlgprefmixerdlg.ui
src/preferences/dialog/dlgprefosc.cpp
src/preferences/dialog/dlgprefoscdlg.ui
src/preferences/dialog/dlgprefrecord.cpp
src/preferences/dialog/dlgprefrecorddlg.ui
src/preferences/dialog/dlgprefreplaygain.cpp
Expand Down Expand Up @@ -2557,6 +2559,43 @@ add_library(rekordbox_metadata STATIC EXCLUDE_FROM_ALL
target_include_directories(rekordbox_metadata SYSTEM PUBLIC lib/rekordbox-metadata)
target_link_libraries(mixxx-lib PRIVATE rekordbox_metadata)

IF(WIN32)
set(IpSystemTypePath src/osc/ip/win32)
set(LIBS ${LIBS} Ws2_32 winmm)
ELSE(WIN32)
set(IpSystemTypePath src/osc/ip/posix)
ENDIF(WIN32)

#eve osc
ADD_LIBRARY(oscpack
src/osc/ip/IpEndpointName.cpp
src/osc/ip/IpEndpointName.h
src/osc/ip/NetworkingUtils.h
${IpSystemTypePath}/NetworkingUtils.cpp
src/osc/ip/PacketListener.h
src/osc/ip/TimerListener.h
src/osc/ip/UdpSocket.h
${IpSystemTypePath}/UdpSocket.cpp
src/osc/osc/MessageMappingOscPacketListener.h
src/osc/osc/OscException.h
src/osc/osc/OscHostEndianness.h
src/osc/osc/OscOutboundPacketStream.cpp
src/osc/osc/OscOutboundPacketStream.h
src/osc/osc/OscPacketListener.h
src/osc/osc/OscPrintReceivedElements.cpp
src/osc/osc/OscPrintReceivedElements.h
src/osc/osc/OscReceivedElements.cpp
src/osc/osc/OscReceivedElements.h
src/osc/osc/OscTypes.cpp
src/osc/osc/OscTypes.h
)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR})
#target_link_libraries(mixxx oscpack ${LIBS})
target_include_directories(mixxx-lib SYSTEM PRIVATE ip)
target_include_directories(mixxx-lib SYSTEM PRIVATE osc)
target_link_libraries(mixxx-lib PRIVATE oscpack)
#eve osc

#silence "enumeration values not handled in switch" in generated code
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(rekordbox_metadata PRIVATE -Wno-switch)
Expand Down
Binary file added src/RCa13796
Binary file not shown.
Binary file added src/RCb13796
Binary file not shown.
149 changes: 148 additions & 1 deletion src/engine/controls/cuecontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,10 @@ void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueSetMode
mixxx::audio::FramePos cueStartPosition;
mixxx::audio::FramePos cueEndPosition;
mixxx::CueType cueType = mixxx::CueType::Invalid;
int passStem1Vol;
int passStem2Vol;
int passStem3Vol;
int passStem4Vol;

bool loopEnabled = m_pLoopEnabled->toBool();
if (mode == HotcueSetMode::Auto) {
Expand Down Expand Up @@ -888,6 +892,49 @@ void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueSetMode
// If no loop is enabled, just store regular jump cue
cueStartPosition = getQuantizedCurrentPosition();
cueType = mixxx::CueType::HotCue;
// EveCue
bool TrackStem = m_pLoadedTrack->hasStem();

if (TrackStem) {
const QString groupBaseName = getGroup().remove("[").remove("]");
const QString stemGroups[] = {
QString("[%1Stem1]").arg(groupBaseName),
QString("[%1Stem2]").arg(groupBaseName),
QString("[%1Stem3]").arg(groupBaseName),
QString("[%1Stem4]").arg(groupBaseName),
};

// Helper lambda to get the mute multiplier
auto getMuteMultiplier = [](const QString& group) -> int {
if (ControlObject::exists(ConfigKey(group, "mute"))) {
auto proxyMute = std::make_unique<PollingControlProxy>(group, "mute");
return proxyMute->get() ? -1 : 1;
}
return 1; // Default multiplier when no mute exists
};

// Helper lambda to get the volume value adjusted by the mute multiplier
auto getVolume = [](const QString& group, int muteMultiplier) -> int {
if (ControlObject::exists(ConfigKey(group, "volume"))) {
auto proxyVolume = std::make_unique<PollingControlProxy>(group, "volume");
return static_cast<int>(proxyVolume->get() * 100 * muteMultiplier);
}
return 100 * muteMultiplier; // Default value when no volume exists
};

// Retrieve and assign stem volume values using helpers
passStem1Vol = getVolume(stemGroups[0], getMuteMultiplier(stemGroups[0]));
passStem2Vol = getVolume(stemGroups[1], getMuteMultiplier(stemGroups[1]));
passStem3Vol = getVolume(stemGroups[2], getMuteMultiplier(stemGroups[2]));
passStem4Vol = getVolume(stemGroups[3], getMuteMultiplier(stemGroups[3]));

} else {
passStem1Vol = 100;
passStem2Vol = 100;
passStem3Vol = 100;
passStem4Vol = 100;
}
// EveCue
break;
}
case HotcueSetMode::Loop: {
Expand All @@ -912,6 +959,49 @@ void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueSetMode
cueEndPosition = pBeats->findNBeatsFromPosition(cueStartPosition, beatloopSize);
}
}
// EveLoop
bool TrackStem = m_pLoadedTrack->hasStem();

if (TrackStem) {
const QString groupBaseName = getGroup().remove("[").remove("]");
const QString stemGroups[] = {
QString("[%1Stem1]").arg(groupBaseName),
QString("[%1Stem2]").arg(groupBaseName),
QString("[%1Stem3]").arg(groupBaseName),
QString("[%1Stem4]").arg(groupBaseName),
};

// Helper lambda to get the mute multiplier
auto getMuteMultiplier = [](const QString& group) -> int {
if (ControlObject::exists(ConfigKey(group, "mute"))) {
auto proxyMute = std::make_unique<PollingControlProxy>(group, "mute");
return proxyMute->get() ? -1 : 1;
}
return 1; // Default multiplier when no mute exists
};

// Helper lambda to get the volume value adjusted by the mute multiplier
auto getVolume = [](const QString& group, int muteMultiplier) -> int {
if (ControlObject::exists(ConfigKey(group, "volume"))) {
auto proxyVolume = std::make_unique<PollingControlProxy>(group, "volume");
return static_cast<int>(proxyVolume->get() * 100 * muteMultiplier);
}
return 100 * muteMultiplier; // Default value when no volume exists
};

// Retrieve and assign stem volume values using helpers
passStem1Vol = getVolume(stemGroups[0], getMuteMultiplier(stemGroups[0]));
passStem2Vol = getVolume(stemGroups[1], getMuteMultiplier(stemGroups[1]));
passStem3Vol = getVolume(stemGroups[2], getMuteMultiplier(stemGroups[2]));
passStem4Vol = getVolume(stemGroups[3], getMuteMultiplier(stemGroups[3]));

} else {
passStem1Vol = 100;
passStem2Vol = 100;
passStem3Vol = 100;
passStem4Vol = 100;
}
// EveLoop
cueType = mixxx::CueType::Loop;
break;
}
Expand Down Expand Up @@ -954,7 +1044,11 @@ void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueSetMode
hotcueIndex,
cueStartPosition,
cueEndPosition,
color);
color,
passStem1Vol,
passStem2Vol,
passStem3Vol,
passStem4Vol);

// TODO(XXX) deal with spurious signals
attachCue(pCue, pControl);
Expand Down Expand Up @@ -1115,13 +1209,43 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double value, HotcueSet
// pressed
if (pCue && pCue->getPosition().isValid() &&
pCue->getType() != mixxx::CueType::Invalid) {
bool TrackStem = m_pLoadedTrack->hasStem();

if (TrackStem) {
const QString groupBaseName = getGroup().remove('[').remove(']');
const std::vector<QString> stemGroups = {
QString("[%1Stem1]").arg(groupBaseName),
QString("[%1Stem2]").arg(groupBaseName),
QString("[%1Stem3]").arg(groupBaseName),
QString("[%1Stem4]").arg(groupBaseName)};

auto setMuteAndVolume = [](const QString& group, int volume) {
if (ControlObject::exists(ConfigKey(group, "mute"))) {
auto proxyMute = std::make_unique<PollingControlProxy>(group, "mute");
proxyMute->set(volume < 1 ? 1 : 0);
}
if (ControlObject::exists(ConfigKey(group, "volume"))) {
auto proxyVol = std::make_unique<PollingControlProxy>(group, "volume");
proxyVol->set(std::abs(volume) / 100.0);
}
};

setMuteAndVolume(stemGroups[0], pCue->getStem1vol());
setMuteAndVolume(stemGroups[1], pCue->getStem2vol());
setMuteAndVolume(stemGroups[2], pCue->getStem3vol());
setMuteAndVolume(stemGroups[3], pCue->getStem4vol());
}

if (m_pPlay->toBool() && m_currentlyPreviewingIndex == Cue::kNoHotCue) {
// playing by Play button

switch (pCue->getType()) {
case mixxx::CueType::HotCue:

hotcueGoto(pControl, value);
break;
case mixxx::CueType::Loop:

if (m_pCurrentSavedLoopControl != pControl) {
setCurrentSavedLoopControlAndActivate(pControl);
} else {
Expand Down Expand Up @@ -2475,6 +2599,15 @@ HotcueControl::HotcueControl(const QString& group, int hotcueIndex)
// Add an alias for the legacy hotcue_X_enabled CO
m_pHotcueStatus->addAlias(keyForControl(QStringLiteral("enabled")));

m_hotcueStem1vol = std::make_unique<ControlObject>(keyForControl(QStringLiteral("stem1vol")));
m_hotcueStem2vol = std::make_unique<ControlObject>(keyForControl(QStringLiteral("stem2vol")));
m_hotcueStem3vol = std::make_unique<ControlObject>(keyForControl(QStringLiteral("stem3vol")));
m_hotcueStem4vol = std::make_unique<ControlObject>(keyForControl(QStringLiteral("stem4vol")));
m_hotcueStem1vol->setReadOnly();
m_hotcueStem2vol->setReadOnly();
m_hotcueStem3vol->setReadOnly();
m_hotcueStem4vol->setReadOnly();

m_hotcueType = std::make_unique<ControlObject>(keyForControl(QStringLiteral("type")));
m_hotcueType->setReadOnly();

Expand Down Expand Up @@ -2685,6 +2818,7 @@ void HotcueControl::setCue(const CuePointer& pCue) {
setEndPosition(pos.endPosition);
// qDebug() << "HotcueControl::setCue";
setColor(pCue->getColor());
// setStemvol(int stemvol);
setStatus((pCue->getType() == mixxx::CueType::Invalid)
? HotcueControl::Status::Empty
: HotcueControl::Status::Set);
Expand Down Expand Up @@ -2726,6 +2860,19 @@ void HotcueControl::setType(mixxx::CueType type) {
m_hotcueType->forceSet(static_cast<double>(type));
}

void HotcueControl::setStem1vol(int stem1vol) {
m_hotcueStem1vol->set(static_cast<int>(stem1vol));
}
void HotcueControl::setStem2vol(int stem2vol) {
m_hotcueStem2vol->set(static_cast<int>(stem2vol));
}
void HotcueControl::setStem3vol(int stem3vol) {
m_hotcueStem3vol->set(static_cast<int>(stem3vol));
}
void HotcueControl::setStem4vol(int stem4vol) {
m_hotcueStem4vol->set(static_cast<int>(stem4vol));
}

void HotcueControl::setStatus(HotcueControl::Status status) {
m_pHotcueStatus->forceSet(static_cast<double>(status));
}
Expand Down
9 changes: 9 additions & 0 deletions src/engine/controls/cuecontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ class HotcueControl : public QObject {
void setColor(mixxx::RgbColor::optional_t newColor);
mixxx::RgbColor::optional_t getColor() const;

void setStem1vol(int stem1vol);
void setStem2vol(int stem2vol);
void setStem3vol(int stem3vol);
void setStem4vol(int stem4vol);

/// Used for caching the preview state of this hotcue control
/// for the case the cue is deleted during preview.
mixxx::CueType getPreviewingType() const {
Expand Down Expand Up @@ -167,6 +172,10 @@ class HotcueControl : public QObject {
std::unique_ptr<ControlObject> m_pHotcueStatus;
std::unique_ptr<ControlObject> m_hotcueType;
std::unique_ptr<ControlObject> m_hotcueColor;
std::unique_ptr<ControlObject> m_hotcueStem1vol;
std::unique_ptr<ControlObject> m_hotcueStem2vol;
std::unique_ptr<ControlObject> m_hotcueStem3vol;
std::unique_ptr<ControlObject> m_hotcueStem4vol;
// Hotcue button controls
std::unique_ptr<ControlPushButton> m_hotcueSet;
std::unique_ptr<ControlPushButton> m_hotcueSetCue;
Expand Down
Loading