Skip to content
Draft
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
34 changes: 34 additions & 0 deletions docs/JSON-RPC.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,23 @@ Results:
| result.clients | array | The client list. See jamulusclient/clientListReceived for the format. |


### jamulusclient/getMidiSettings

Returns all MIDI controller settings.

Parameters:

| Name | Type | Description |
| --- | --- | --- |
| params | object | No parameters (empty object). |

Results:

| Name | Type | Description |
| --- | --- | --- |
| result | object | MIDI settings object. |


### jamulusclient/pollServerList

Request list of servers in a directory.
Expand Down Expand Up @@ -240,6 +257,23 @@ Results:
| result | string | Always "ok". |


### jamulusclient/setMidiSettings

Sets one or more MIDI controller settings.

Parameters:

| Name | Type | Description |
| --- | --- | --- |
| params | object | Any subset of MIDI settings fields to set. |

Results:

| Name | Type | Description |
| --- | --- | --- |
| result | string | "ok" on success, or error message if MIDI failed to enable. |
Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks like it's either {"result":"ok"} or {"error":"...msg..."}, rather than "result" in both cases.



### jamulusclient/setName

Sets your name.
Expand Down
3 changes: 3 additions & 0 deletions src/audiomixerboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,9 @@ void CAudioMixerBoard::ApplyNewConClientList ( CVector<CChannelInfo>& vecChanInf
}
Mutex.unlock(); // release mutex

// Ensure MIDI state is applied to faders during the connection process
SetMIDICtrlUsed ( pSettings->bUseMIDIController );

// sort the channels according to the selected sorting type
ChangeFaderOrder ( eChSortType );

Expand Down
36 changes: 32 additions & 4 deletions src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,21 @@
\******************************************************************************/

#include "client.h"
#include "settings.h"
#include "util.h"

/* Implementation *************************************************************/
CClient::CClient ( const quint16 iPortNumber,
const quint16 iQosNumber,
const QString& strConnOnStartupAddress,
const QString& strMIDISetup,
const bool bNoAutoJackConnect,
const QString& strNClientName,
const bool bNEnableIPv6,
const bool bNMuteMeInPersonalMix ) :
ChannelInfo(),
strClientName ( strNClientName ),
pSignalHandler ( CSignalHandler::getSingletonP() ),
pSettings ( nullptr ),
Channel ( false ), /* we need a client channel -> "false" */
CurOpusEncoder ( nullptr ),
CurOpusDecoder ( nullptr ),
Expand All @@ -49,7 +51,7 @@ CClient::CClient ( const quint16 iPortNumber,
bMuteOutStream ( false ),
fMuteOutStreamGain ( 1.0f ),
Socket ( &Channel, iPortNumber, iQosNumber, "", bNEnableIPv6 ),
Sound ( AudioCallback, this, strMIDISetup, bNoAutoJackConnect, strNClientName ),
Sound ( AudioCallback, this, bNoAutoJackConnect, strNClientName ),
iAudioInFader ( AUD_FADER_IN_MIDDLE ),
bReverbOnLeftChan ( false ),
iReverbLevel ( 0 ),
Expand All @@ -68,8 +70,7 @@ CClient::CClient ( const quint16 iPortNumber,
bJitterBufferOK ( true ),
bEnableIPv6 ( bNEnableIPv6 ),
bMuteMeInPersonalMix ( bNMuteMeInPersonalMix ),
iServerSockBufNumFrames ( DEF_NET_BUF_SIZE_NUM_BL ),
pSignalHandler ( CSignalHandler::getSingletonP() )
iServerSockBufNumFrames ( DEF_NET_BUF_SIZE_NUM_BL )
{
int iOpusError;

Expand Down Expand Up @@ -173,6 +174,8 @@ CClient::CClient ( const quint16 iPortNumber,

QObject::connect ( pSignalHandler, &CSignalHandler::HandledSignal, this, &CClient::OnHandledSignal );

QObject::connect ( &Sound, &CSoundBase::MidiCCReceived, this, [this] ( int ccNumber ) { emit MidiCCReceived ( ccNumber ); } );

// start timer so that elapsed time works
PreciseTime.start();

Expand All @@ -193,6 +196,29 @@ CClient::CClient ( const quint16 iPortNumber,
}
}

// MIDI setup will be handled after settings are assigned
void CClient::SetSettings ( CClientSettings* settings )
{
pSettings = settings;

// Apply MIDI settings
Sound.SetCtrlMIDIChannel ( pSettings->iMidiChannel );
Sound.SetMIDIControllerMapping ( pSettings->iMidiFaderOffset,
pSettings->iMidiFaderCount,
pSettings->iMidiPanOffset,
pSettings->iMidiPanCount,
pSettings->iMidiSoloOffset,
pSettings->iMidiSoloCount,
pSettings->iMidiMuteOffset,
pSettings->iMidiMuteCount,
pSettings->iMidiMuteMyself );
Sound.EnableMIDI ( pSettings->bUseMIDIController );
if ( !pSettings->strMidiDevice.isEmpty() )
{
Sound.SetMIDIDevice ( pSettings->strMidiDevice );
}
}

CClient::~CClient()
{
// if we were running, stop sound device
Expand Down Expand Up @@ -1547,6 +1573,8 @@ void CClient::FreeClientChannel ( const int iServerChannelID )
*/
}

void CClient::OnMidiCCReceived ( int ccNumber ) { emit MidiCCReceived ( ccNumber ); }

// find, and optionally create, a client channel for the supplied server channel ID
// returns a client channel ID or INVALID_INDEX
int CClient::FindClientChannel ( const int iServerChannelID, const bool bCreateIfNew )
Expand Down
20 changes: 17 additions & 3 deletions src/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ class CClientChannel
// can store here other information about an active channel
};

class CClientSettings;

class CClient : public QObject
{
Q_OBJECT
Expand All @@ -127,7 +129,6 @@ class CClient : public QObject
CClient ( const quint16 iPortNumber,
const quint16 iQosNumber,
const QString& strConnOnStartupAddress,
const QString& strMIDISetup,
const bool bNoAutoJackConnect,
const QString& strNClientName,
const bool bNEnableIPv6,
Expand Down Expand Up @@ -293,11 +294,22 @@ class CClient : public QObject
CProtocol* getConnLessProtocol() { return &ConnLessProtocol; }
//### TODO: END ###//

// MIDI control
void EnableMIDI ( bool bEnable ) { Sound.EnableMIDI ( bEnable ); }
bool IsMIDIEnabled() const { return Sound.IsMIDIEnabled(); }

// settings
CChannelCoreInfo ChannelInfo;
QString strClientName;

public:
void SetSettings ( CClientSettings* settings );

protected:
// Signal handler must be declared before pSettings for correct init order
CSignalHandler* pSignalHandler;
// Pointer to settings for MIDI and other config
CClientSettings* pSettings;
// callback function must be static, otherwise it does not work
static void AudioCallback ( CVector<short>& psData, void* arg );

Expand Down Expand Up @@ -407,8 +419,6 @@ class CClient : public QObject
int maxGainOrPanId;
int iCurPingTime;

CSignalHandler* pSignalHandler;

protected slots:
void OnHandledSignal ( int sigNum );
void OnSendProtMessage ( CVector<uint8_t> vecMessage );
Expand Down Expand Up @@ -473,4 +483,8 @@ protected slots:
void ControllerInFaderIsSolo ( int iChannelIdx, bool bIsSolo );
void ControllerInFaderIsMute ( int iChannelIdx, bool bIsMute );
void ControllerInMuteMyself ( bool bMute );
void MidiCCReceived ( int ccNumber );

private slots:
void OnMidiCCReceived ( int ccNumber );
};
21 changes: 19 additions & 2 deletions src/clientdlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
CClientDlg::CClientDlg ( CClient* pNCliP,
CClientSettings* pNSetP,
const QString& strConnOnStartupAddress,
const QString& strMIDISetup,
const bool bNewShowComplRegConnList,
const bool bShowAnalyzerConsole,
const bool bMuteStream,
Expand Down Expand Up @@ -220,7 +219,7 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
MainMixerBoard->SetNumMixerPanelRows ( pSettings->iNumMixerPanelRows );

// Pass through flag for MIDICtrlUsed
MainMixerBoard->SetMIDICtrlUsed ( !strMIDISetup.isEmpty() );
MainMixerBoard->SetMIDICtrlUsed ( pSettings->bUseMIDIController );

// reset mixer board
MainMixerBoard->HideAll();
Expand Down Expand Up @@ -401,6 +400,12 @@ CClientDlg::CClientDlg ( CClient* pNCliP,

pSettingsMenu->addAction ( tr ( "A&dvanced Settings..." ), this, SLOT ( OnOpenAdvancedSettings() ), QKeySequence ( Qt::CTRL + Qt::Key_D ) );

pSettingsMenu->addAction (
tr ( "&MIDI Control Settings..." ),
this,
[this] { ShowGeneralSettings ( SETTING_TAB_MIDI ); },
QKeySequence ( Qt::CTRL + Qt::Key_M ) );

// Main menu bar -----------------------------------------------------------
QMenuBar* pMenu = new QMenuBar ( this );

Expand Down Expand Up @@ -536,6 +541,8 @@ CClientDlg::CClientDlg ( CClient* pNCliP,

QObject::connect ( &ClientSettingsDlg, &CClientSettingsDlg::NumMixerPanelRowsChanged, this, &CClientDlg::OnNumMixerPanelRowsChanged );

QObject::connect ( &ClientSettingsDlg, &CClientSettingsDlg::MIDIControllerUsageChanged, this, &CClientDlg::OnMIDIControllerUsageChanged );

QObject::connect ( this, &CClientDlg::SendTabChange, &ClientSettingsDlg, &CClientSettingsDlg::OnMakeTabChange );

QObject::connect ( MainMixerBoard, &CAudioMixerBoard::ChangeChanGain, this, &CClientDlg::OnChangeChanGain );
Expand Down Expand Up @@ -1526,3 +1533,13 @@ void CClientDlg::SetPingTime ( const int iPingTime, const int iOverallDelayMs, c
// set current LED status
ledDelay->SetLight ( eOverallDelayLEDColor );
}

// OnOpenMidiSettings slot removed; lambda is used in menu action
void CClientDlg::OnMIDIControllerUsageChanged ( bool bEnabled )
{
// Update the mixer board's MIDI flag to trigger proper user numbering display
MainMixerBoard->SetMIDICtrlUsed ( bEnabled );

// Enable/disable runtime MIDI via the sound interface through the public CClient interface
pClient->EnableMIDI ( bEnabled );
}
3 changes: 2 additions & 1 deletion src/clientdlg.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class CClientDlg : public CBaseDlg, private Ui_CClientDlgBase
CClientDlg ( CClient* pNCliP,
CClientSettings* pNSetP,
const QString& strConnOnStartupAddress,
const QString& strMIDISetup,
const bool bNewShowComplRegConnList,
const bool bShowAnalyzerConsole,
const bool bMuteStream,
Expand Down Expand Up @@ -246,6 +245,8 @@ public slots:

void accept() { close(); } // introduced by pljones

void OnMIDIControllerUsageChanged ( bool bEnabled );

signals:
void SendTabChange ( int iTabIdx );
};
67 changes: 66 additions & 1 deletion src/clientrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@

#include "clientrpc.h"

CClientRpc::CClientRpc ( CClient* pClient, CRpcServer* pRpcServer, QObject* parent ) : QObject ( parent )
CClientRpc::CClientRpc ( CClient* pClient, CClientSettings* pSettings, CRpcServer* pRpcServer, QObject* parent ) :
QObject ( parent ),
m_pSettings ( pSettings )
{
/// @rpc_notification jamulusclient/chatTextReceived
/// @brief Emitted when a chat text is received.
Expand Down Expand Up @@ -355,6 +357,69 @@ CClientRpc::CClientRpc ( CClient* pClient, CRpcServer* pRpcServer, QObject* pare
pClient->SetControllerInFaderLevel ( jsonChannelIndex.toInt(), jsonLevel.toInt() );
response["result"] = "ok";
} );

/// @rpc_method jamulusclient/getMidiSettings
/// @brief Returns all MIDI controller settings.
/// @param {object} params - No parameters (empty object).
/// @result {object} result - MIDI settings object.
pRpcServer->HandleMethod ( "jamulusclient/getMidiSettings", [=] ( const QJsonObject& params, QJsonObject& response ) {
QJsonObject jsonMidiParams{ { "bUseMIDIController", m_pSettings->bUseMIDIController },
{ "midiChannel", m_pSettings->iMidiChannel },
{ "midiMuteMyself", m_pSettings->iMidiMuteMyself },
{ "midiFaderOffset", m_pSettings->iMidiFaderOffset },
{ "midiFaderCount", m_pSettings->iMidiFaderCount },
{ "midiPanOffset", m_pSettings->iMidiPanOffset },
{ "midiPanCount", m_pSettings->iMidiPanCount },
{ "midiSoloOffset", m_pSettings->iMidiSoloOffset },
{ "midiSoloCount", m_pSettings->iMidiSoloCount },
{ "midiMuteOffset", m_pSettings->iMidiMuteOffset },
{ "midiMuteCount", m_pSettings->iMidiMuteCount } };
response["result"] = jsonMidiParams;
Q_UNUSED ( params );
} );

/// @rpc_method jamulusclient/setMidiSettings
/// @brief Sets one or more MIDI controller settings.
/// @param {object} params - Any subset of MIDI settings fields to set.
/// @result {string} result - "ok" on success, or error message if MIDI failed to enable.
pRpcServer->HandleMethod ( "jamulusclient/setMidiSettings", [=] ( const QJsonObject& params, QJsonObject& response ) {
bool bPreviousMIDIState = m_pSettings->bUseMIDIController;

QHash<QString, std::function<void ( const QJsonValue& )>> setters = {
{ "bUseMIDIController", [this] ( const QJsonValue& v ) { m_pSettings->bUseMIDIController = v.toBool(); } },
{ "midiChannel", [this] ( const QJsonValue& v ) { m_pSettings->iMidiChannel = v.toInt(); } },
{ "midiMuteMyself", [this] ( const QJsonValue& v ) { m_pSettings->iMidiMuteMyself = v.toInt(); } },
{ "midiFaderOffset", [this] ( const QJsonValue& v ) { m_pSettings->iMidiFaderOffset = v.toInt(); } },
{ "midiFaderCount", [this] ( const QJsonValue& v ) { m_pSettings->iMidiFaderCount = v.toInt(); } },
{ "midiPanOffset", [this] ( const QJsonValue& v ) { m_pSettings->iMidiPanOffset = v.toInt(); } },
{ "midiPanCount", [this] ( const QJsonValue& v ) { m_pSettings->iMidiPanCount = v.toInt(); } },
{ "midiSoloOffset", [this] ( const QJsonValue& v ) { m_pSettings->iMidiSoloOffset = v.toInt(); } },
{ "midiSoloCount", [this] ( const QJsonValue& v ) { m_pSettings->iMidiSoloCount = v.toInt(); } },
{ "midiMuteOffset", [this] ( const QJsonValue& v ) { m_pSettings->iMidiMuteOffset = v.toInt(); } },
{ "midiMuteCount", [this] ( const QJsonValue& v ) { m_pSettings->iMidiMuteCount = v.toInt(); } } };

for ( auto it = setters.constBegin(); it != setters.constEnd(); ++it )
{
if ( params.contains ( it.key() ) )
{
it.value() ( params[it.key()] );
}
}

// Apply settings to actually enable/disable MIDI
pClient->SetSettings ( m_pSettings );

// Check if MIDI was requested but failed to enable
if ( m_pSettings->bUseMIDIController && !pClient->IsMIDIEnabled() )
{
// Restore previous state on failure
m_pSettings->bUseMIDIController = bPreviousMIDIState;
response["error"] = CRpcServer::CreateJsonRpcError ( 1, "Failed to open MIDI port" );
return;
}

response["result"] = "ok";
} );
}

QJsonValue CClientRpc::SerializeSkillLevel ( ESkillLevel eSkillLevel )
Expand Down
4 changes: 3 additions & 1 deletion src/clientrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@
#include "client.h"
#include "util.h"
#include "rpcserver.h"
#include "settings.h"

/* Classes ********************************************************************/
class CClientRpc : public QObject
{
Q_OBJECT

public:
CClientRpc ( CClient* pClient, CRpcServer* pRpcServer, QObject* parent = nullptr );
CClientRpc ( CClient* pClient, CClientSettings* pSettings, CRpcServer* pRpcServer, QObject* parent = nullptr );

private:
CClientSettings* m_pSettings;
QJsonArray arrStoredChanInfo;
static QJsonValue SerializeSkillLevel ( ESkillLevel skillLevel );
};
Loading