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

OSC Server/Client Integration #2078

Closed
wants to merge 15 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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ addons:
- scons
- qtkeychain-dev
- liblilv-dev
- liblo-dev
before_install:
# Virtual X, needed for analyzer waveform tests
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export DISPLAY=:99.0 ; fi
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ for:

install:
- sudo apt-get update
- sudo apt-get -y install gdb libavformat-dev libchromaprint-dev libfaad-dev libflac-dev libid3tag0-dev libmad0-dev libmodplug-dev libmp3lame-dev libmp4v2-dev libopus-dev libopusfile-dev libportmidi-dev libprotobuf-dev libqt5opengl5-dev libqt5sql5-sqlite libqt5svg5-dev librubberband-dev libshout3-dev libsndfile1-dev libsqlite3-dev libtag1-dev libupower-glib-dev libusb-1.0-0-dev libwavpack-dev portaudio19-dev protobuf-compiler qt5-default qtscript5-dev libqt5x11extras5-dev scons qtkeychain-dev liblilv-dev libsoundtouch-dev
- sudo apt-get -y install gdb libavformat-dev libchromaprint-dev libfaad-dev libflac-dev libid3tag0-dev libmad0-dev libmodplug-dev libmp3lame-dev libmp4v2-dev libopus-dev libopusfile-dev libportmidi-dev libprotobuf-dev libqt5opengl5-dev libqt5sql5-sqlite libqt5svg5-dev librubberband-dev libshout3-dev libsndfile1-dev libsqlite3-dev libtag1-dev libupower-glib-dev libusb-1.0-0-dev libwavpack-dev portaudio19-dev protobuf-compiler qt5-default qtscript5-dev libqt5x11extras5-dev scons qtkeychain-dev liblilv-dev libsoundtouch-dev liblo-dev

build_script:
- scons -j4 test=1 mad=1 faad=1 ffmpeg=1 opus=1 modplug=1 wv=1 hss1394=0 virtualize=0 debug_assertions_fatal=1 verbose=0 localecompare=1
Expand Down
15 changes: 14 additions & 1 deletion build/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ def configure(self, build, conf):
def sources(self, build):
return ['src/soundio/sounddeviceportaudio.cpp']

class LibLo(Dependence):
def configure(self, build, conf):
libs = ['lo']

if not conf.CheckLib(libs):
raise Exception("Did not find liblo")

class PortMIDI(Dependence):

Expand Down Expand Up @@ -724,6 +730,7 @@ def sources(self, build):
"src/preferences/dialog/dlgpreflibrary.cpp",
"src/preferences/dialog/dlgprefnovinyl.cpp",
"src/preferences/dialog/dlgprefrecord.cpp",
"src/preferences/dialog/dlgprefosc.cpp",
"src/preferences/dialog/dlgprefreplaygain.cpp",
"src/preferences/dialog/dlgprefsound.cpp",
"src/preferences/dialog/dlgprefsounditem.cpp",
Expand Down Expand Up @@ -1011,6 +1018,11 @@ def sources(self, build):
"src/recording/recordingmanager.cpp",
"src/engine/sidechain/enginerecord.cpp",

"src/oscclient/oscclientmanager.cpp",
"src/engine/sidechain/engineoscclient.cpp",

"src/oscserver/oscserver.cpp",

# External Library Features
"src/library/baseexternallibraryfeature.cpp",
"src/library/baseexternaltrackmodel.cpp",
Expand Down Expand Up @@ -1271,6 +1283,7 @@ def sources(self, build):
'src/preferences/dialog/dlgpreflibrarydlg.ui',
'src/preferences/dialog/dlgprefnovinyldlg.ui',
'src/preferences/dialog/dlgprefrecorddlg.ui',
'src/preferences/dialog/dlgprefoscdlg.ui',
'src/preferences/dialog/dlgprefreplaygaindlg.ui',
'src/preferences/dialog/dlgprefsounddlg.ui',
'src/preferences/dialog/dlgprefsounditem.ui',
Expand Down Expand Up @@ -1510,7 +1523,7 @@ def depends(self, build):
FidLib, SndFile, FLAC, OggVorbis, OpenGL, TagLib, ProtoBuf,
Chromaprint, RubberBand, SecurityFramework, CoreServices, IOKit,
QtScriptByteArray, Reverb, FpClassify, PortAudioRingBuffer, LAME,
QueenMaryDsp]
QueenMaryDsp, LibLo]

def post_dependency_check_configure(self, build, conf):
"""Sets up additional things in the Environment that must happen
Expand Down
Binary file added res/images/preferences/ic_preferences_osc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions res/mixxx.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
<file>images/preferences/ic_preferences_midicontrollers.svg</file>
<file>images/preferences/ic_preferences_modplug.svg</file>
<file>images/preferences/ic_preferences_recording.svg</file>
<file>images/preferences/ic_preferences_osc.png</file>
<file>images/preferences/ic_preferences_replaygain.svg</file>
<file>images/preferences/ic_preferences_sampler.svg</file>
<file>images/preferences/ic_preferences_soundhardware.svg</file>
Expand Down
124 changes: 124 additions & 0 deletions src/engine/sidechain/engineoscclient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/***************************************************************************
EngineOscClient.cpp - class to record the mix
-------------------
copyright : (C) 2007 by John Sully
copyright : (C) 2010 by Tobias Rafreider
email :
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "engine/sidechain/engineoscclient.h"

#include "control/controlobject.h"
#include "control/controlproxy.h"
#include "oscclient/defs_oscclient.h"
#include "preferences/usersettings.h"

#include "errordialoghandler.h"
#include "mixer/playerinfo.h"
#include "util/event.h"

#include "mixer/playermanager.h"
#include <QDebug>

EngineOscClient::EngineOscClient(UserSettingsPointer &pConfig)
: m_pConfig(pConfig), m_prefUpdate(ConfigKey("[Preferences]", "updated")) {

connectServer();

ControlProxy *xfader =
new ControlProxy(ConfigKey("[Master]", "crossfader"), this);
xfader->connectValueChanged(this, &EngineOscClient::maybeSendState);
m_connectedControls.append(xfader);

// connect play buttons
for (int deckNr = 0; deckNr < (int)PlayerManager::numDecks(); deckNr++) {
ControlProxy *play = new ControlProxy(
ConfigKey(PlayerManager::groupForDeck(deckNr), "play"), this);
play->connectValueChanged(this, &EngineOscClient::maybeSendState);
m_connectedControls.append(play);

ControlProxy *volume = new ControlProxy(
ConfigKey(PlayerManager::groupForDeck(deckNr), "volume"), this);
volume->connectValueChanged(this, &EngineOscClient::maybeSendState);
m_connectedControls.append(volume);
}

// connect to settings changes
connect(&m_prefUpdate, SIGNAL(valueChanged(double)), this,
SLOT(connectServer()));
}

EngineOscClient::~EngineOscClient() {}

void EngineOscClient::process(const CSAMPLE *pBuffer, const int iBufferSize) {
if (m_time.elapsed() < 10)
return;
sendState();
}

void EngineOscClient::sendState() {
PlayerInfo &playerInfo = PlayerInfo::instance();
int numDecks = (int)PlayerManager::numDecks();
lo_send(m_serverAddress, "/mixxx/numDecks", "i", numDecks);

for (int deckNr = 0; deckNr < numDecks; deckNr++) {
lo_send(m_serverAddress, "/mixxx/deck/playing", "ii", deckNr,
(int)playerInfo.isDeckPlaying(deckNr));
lo_send(m_serverAddress, "/mixxx/deck/volume", "if", deckNr,
playerInfo.getDeckVolume(deckNr));

// speed
ControlProxy rate(ConfigKey(PlayerManager::groupForDeck(deckNr), "rate"));
ControlProxy rateRange(
ConfigKey(PlayerManager::groupForDeck(deckNr), "rateRange"));
ControlProxy rev(ConfigKey(PlayerManager::groupForDeck(deckNr), "reverse"));
float speed = 1 + float(rate.get()) * float(rateRange.get());
if (rev.get())
speed *= -1;
lo_send(m_serverAddress, "/mixxx/deck/speed", "if", deckNr, speed);

ControlProxy posRel(
ConfigKey(PlayerManager::groupForDeck(deckNr), "playposition"));
lo_send(m_serverAddress, "/mixxx/deck/pos", "if", deckNr,
float(posRel.get()));

ControlProxy dur(
ConfigKey(PlayerManager::groupForDeck(deckNr), "duration"));
lo_send(m_serverAddress, "/mixxx/deck/duration", "if", deckNr,
float(dur.get()));

QString title = "";
TrackPointer pTrack =
playerInfo.getTrackInfo(PlayerManager::groupForDeck(deckNr));
if (pTrack) {
title = pTrack->getTitle();
}
lo_send(m_serverAddress, "/mixxx/deck/title", "is", deckNr,
title.toUtf8().data());
}
m_time.restart();
}

void EngineOscClient::maybeSendState() {
if (m_time.elapsed() < 10)
return;
sendState();
}

void EngineOscClient::connectServer() {
QString server =
m_pConfig->getValueString(ConfigKey(OSC_CLIENT_PREF_KEY, "Server"));
QString port =
m_pConfig->getValueString(ConfigKey(OSC_CLIENT_PREF_KEY, "Port"));
m_serverAddress =
lo_address_new(server.toLatin1().data(), port.toLatin1().data());
}
55 changes: 55 additions & 0 deletions src/engine/sidechain/engineoscclient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/***************************************************************************
EngineOscClient.h - description
-------------------
copyright : (C) 2007 by John Sully
email :
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef EngineOscClient_H
#define EngineOscClient_H

#include "control/controlobject.h"
#include "control/controlproxy.h"
#include "engine/sidechain/sidechainworker.h"
#include "lo/lo.h"
#include "preferences/usersettings.h"
#include "track/track.h"
#include <QList>
#include <QTime>

class ConfigKey;
class Encoder;

class EngineOscClient : public QObject, public SideChainWorker {
Q_OBJECT
public:
EngineOscClient(UserSettingsPointer &pConfig);
virtual ~EngineOscClient();

public slots:
void sendState();
void maybeSendState();
void connectServer();

// interface SideChainWorker
void process(const CSAMPLE *pBuffer, const int iBufferSize);
void shutdown() {}

private:
QTime m_time;
lo_address m_serverAddress;
UserSettingsPointer m_pConfig;
QList<ControlProxy *> m_connectedControls;
ControlProxy m_prefUpdate;
};

#endif
72 changes: 42 additions & 30 deletions src/mixer/playerinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,45 +106,57 @@ void PlayerInfo::timerEvent(QTimerEvent* pTimerEvent) {
updateCurrentPlayingDeck();
}

bool PlayerInfo::isDeckPlaying(int deckNr){
DeckControls* pDc = getDeckControls(deckNr);
return pDc->m_play.get() != 0;
}

double PlayerInfo::getDeckVolume(int deckNr)
{
DeckControls* pDc = getDeckControls(deckNr);
if (pDc->m_play.get() == 0.0) {
return 0;
}

if (pDc->m_pregain.get() <= 0.25) {
return 0;
}

double fvol = pDc->m_volume.get();
if (fvol == 0.0) {
return 0;
}

double xfl, xfr;
// TODO: supply correct parameters to the function. If the hamster style
// for the crossfader is enabled, the result is currently wrong.
EngineXfader::getXfadeGains(m_pCOxfader->get(), 1.0, 0.0, false, false,
&xfl, &xfr);

int orient = pDc->m_orientation.get();
double xfvol;
if (orient == EngineChannel::LEFT) {
xfvol = xfl;
} else if (orient == EngineChannel::RIGHT) {
xfvol = xfr;
} else {
xfvol = 1.0;
}

return fvol * xfvol;
}

void PlayerInfo::updateCurrentPlayingDeck() {
QMutexLocker locker(&m_mutex);

double maxVolume = 0;
int maxDeck = -1;

for (int i = 0; i < (int)PlayerManager::numDecks(); ++i) {
DeckControls* pDc = getDeckControls(i);

if (pDc->m_play.get() == 0.0) {
continue;
}

if (pDc->m_pregain.get() <= 0.25) {
double dvol = getDeckVolume(i);
if(dvol == 0.0)
continue;
}

double fvol = pDc->m_volume.get();
if (fvol == 0.0) {
continue;
}

double xfl, xfr;
// TODO: supply correct parameters to the function. If the hamster style
// for the crossfader is enabled, the result is currently wrong.
EngineXfader::getXfadeGains(m_pCOxfader->get(), 1.0, 0.0, MIXXX_XFADER_ADDITIVE, false,
&xfl, &xfr);

int orient = pDc->m_orientation.get();
double xfvol;
if (orient == EngineChannel::LEFT) {
xfvol = xfl;
} else if (orient == EngineChannel::RIGHT) {
xfvol = xfr;
} else {
xfvol = 1.0;
}

double dvol = fvol * xfvol;
if (dvol > maxVolume) {
maxDeck = i;
maxVolume = dvol;
Expand Down
8 changes: 6 additions & 2 deletions src/mixer/playerinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

class PlayerInfo : public QObject {
Q_OBJECT

public:
static PlayerInfo& instance();
static void destroy();
Expand All @@ -38,13 +39,16 @@ class PlayerInfo : public QObject {
bool isTrackLoaded(const TrackPointer& pTrack) const;
bool isFileLoaded(const QString& track_location) const;

signals:
double getDeckVolume(int deckNr);
bool isDeckPlaying(int deckNr);

signals:
void currentPlayingDeckChanged(int deck);
void currentPlayingTrackChanged(TrackPointer pTrack);
void trackLoaded(QString group, TrackPointer pTrack);
void trackUnloaded(QString group, TrackPointer pTrack);

private:
private:
class DeckControls {
public:
DeckControls(QString& group)
Expand Down
Loading