allow changing of port count improve the gui to fit ports in smaller space auto update when ports are changed for eg from another appmaster
@@ -25,76 +25,182 @@ | |||
using namespace std; | |||
static const HostInfo* host; | |||
JackClient* JackClient::m_Singleton = NULL; | |||
bool JackClient::m_Attached = false; | |||
long unsigned int JackClient::m_BufferSize = 0; | |||
long unsigned int JackClient::m_SampleRate = 0; | |||
void (*JackClient::RunCallback)(void*, bool m)=NULL; | |||
void *JackClient::RunContext = NULL; | |||
jack_client_t *JackClient::m_Client = NULL; | |||
map<int,JackClient::JackPort*> JackClient::m_InputPortMap; | |||
map<int,JackClient::JackPort*> JackClient::m_OutputPortMap; | |||
int JackPlugin::m_RefCount = 0; | |||
int JackPlugin::m_NoExecuted = 0; | |||
static int JackInstances = 0; | |||
static int JackProcessInstance = -1; | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
inline void JackClient::JackProcess_i(jack_nframes_t nframes) | |||
{ | |||
SetBufferSize(nframes); | |||
for (int n=0; n<GetJackInputCount(); n++) | |||
{ | |||
if (jack_port_connected(m_InputPortMap[n]->Port)) | |||
{ | |||
sample_t *in = (sample_t *) jack_port_get_buffer(m_InputPortMap[n]->Port, nframes); | |||
memcpy (m_InputPortMap[n]->Buf, in, sizeof (sample_t) * GetBufferSize()); | |||
} | |||
} | |||
for (int n=0; n<GetJackOutputCount(); n++) | |||
{ | |||
if (jack_port_connected(m_OutputPortMap[n]->Port)) | |||
{ | |||
if (m_OutputPortMap[n]->Buf) | |||
{ | |||
sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes); | |||
memcpy (out, m_OutputPortMap[n]->Buf, sizeof (sample_t) * GetBufferSize()); | |||
} | |||
else // no output availible, clear | |||
{ | |||
sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes); | |||
memset (out, 0, sizeof (sample_t) * GetBufferSize()); | |||
} | |||
} | |||
} | |||
if (RunCallback&&RunContext) | |||
{ | |||
if (JackProcessInstance==-1) | |||
JackProcessInstance = m_JackInstanceID; | |||
if (JackProcessInstance==m_JackInstanceID) | |||
RunCallback(RunContext,true); | |||
} | |||
} | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
inline void JackClient::SampleRateChange_i(jack_nframes_t nframes) | |||
{ | |||
SetSampleRate(nframes); | |||
} | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
inline void JackClient::JackShutdown_i() | |||
{ | |||
cerr<<"Shutdown"<<endl; | |||
SetAttached(false); | |||
if (JackProcessInstance==m_JackInstanceID) | |||
JackProcessInstance = -1; | |||
// tells ssm to go back to non callback mode | |||
RunCallback(RunContext, false); | |||
} | |||
/////////////////////////////////////////////////////// | |||
JackClient::JackClient() | |||
{ | |||
m_JackInstanceID = 0; | |||
m_Attached = false; | |||
m_SampleRate = 0; | |||
m_BufferSize = 0; | |||
m_JackInputCount = 8; | |||
m_JackOutputCount = 8; | |||
m_Client=NULL; | |||
} | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
JackClient::~JackClient() | |||
{ | |||
Detach(); | |||
if (IsAttached()) Detach(); | |||
} | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
void JackClient::AddInputPort(int NewPortNumber) | |||
{ | |||
char Name[256]; | |||
JackPort *NewPort; | |||
if (!(m_Client)) return; | |||
NewPort = new JackPort; | |||
sprintf(Name,"In%d", NewPortNumber); | |||
NewPort->PortNo = NewPortNumber; | |||
NewPort->Name=Name; | |||
NewPort->Buf=NULL; | |||
NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
m_InputPortMap[NewPortNumber]=NewPort; | |||
} | |||
void JackClient::AddOutputPort(int NewPortNumber) | |||
{ | |||
char Name[256]; | |||
JackPort *NewPort; | |||
if (!(m_Client)) return; | |||
NewPort = new JackPort; | |||
sprintf(Name,"Out%d", NewPortNumber); | |||
NewPort->PortNo = NewPortNumber; | |||
NewPort->Name=Name; | |||
NewPort->Buf=NULL; | |||
NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
m_OutputPortMap[NewPortNumber]=NewPort; | |||
} | |||
void JackClient::RemoveInputPort(int PortNumber) | |||
{ | |||
char Name[256]; | |||
JackPort *OldPort; | |||
if (!(m_Client)) return; | |||
OldPort = m_InputPortMap[PortNumber]; | |||
m_InputPortMap[PortNumber] = NULL; | |||
jack_port_unregister (m_Client, OldPort->Port); | |||
delete OldPort; | |||
} | |||
void JackClient::RemoveOutputPort(int PortNumber) | |||
{ | |||
char Name[256]; | |||
JackPort *OldPort; | |||
if (!(m_Client)) return; | |||
OldPort = m_OutputPortMap[PortNumber]; | |||
m_OutputPortMap[PortNumber] = NULL; | |||
jack_port_unregister (m_Client, OldPort->Port); | |||
delete OldPort; | |||
} | |||
bool JackClient::Attach() | |||
{ | |||
char JackClientName[256]; | |||
if (m_Attached) return true; | |||
if (!(m_Client = jack_client_new("SSM"))) | |||
sprintf(JackClientName,"SSM%d",GetJackInstanceID()); | |||
if (!(m_Client = jack_client_new(JackClientName))) | |||
{ | |||
cerr<<"jack server not running?"<<endl; | |||
return false; | |||
} | |||
jack_set_process_callback(m_Client, JackClient::Process, 0); | |||
jack_set_sample_rate_callback (m_Client, JackClient::OnSRateChange, 0); | |||
jack_on_shutdown (m_Client, JackClient::OnJackShutdown, this); | |||
m_InputPortMap.clear(); | |||
m_OutputPortMap.clear(); | |||
jack_set_process_callback(m_Client, JackProcess, this); | |||
jack_set_sample_rate_callback (m_Client, SampleRateChange, this); | |||
jack_on_shutdown (m_Client, JackShutdown, this); | |||
// create the ports | |||
for (int n=0; n<NUM_INPUTS; n++) | |||
{ | |||
char Name[256]; | |||
sprintf(Name,"In%d",n); | |||
JackPort *NewPort = new JackPort; | |||
NewPort->Name=Name; | |||
NewPort->Buf=NULL; | |||
NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
m_InputPortMap[n]=NewPort; | |||
} | |||
m_InputPortMap.clear(); | |||
for (int n=0; n<GetJackInputCount(); n++) | |||
AddInputPort(n); | |||
for (int n=0; n<NUM_OUTPUTS; n++) | |||
{ | |||
char Name[256]; | |||
sprintf(Name,"Out%d",n); | |||
JackPort *NewPort = new JackPort; | |||
NewPort->Name=Name; | |||
NewPort->Buf=NULL; | |||
NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
m_OutputPortMap[n]=NewPort; | |||
} | |||
m_OutputPortMap.clear(); | |||
for (int n=0; n<GetJackOutputCount(); n++) | |||
AddOutputPort(n); | |||
// tell the JACK server that we are ready to roll | |||
if (jack_activate (m_Client)) | |||
@@ -122,68 +228,11 @@ void JackClient::Detach() | |||
m_Attached=false; | |||
} | |||
// tells ssm to go back to non callback mode | |||
RunCallback(RunContext, false); | |||
} | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
int JackClient::Process(jack_nframes_t nframes, void *o) | |||
{ | |||
m_BufferSize=nframes; | |||
for (int n=0; n<NUM_INPUTS; n++) | |||
{ | |||
if (jack_port_connected(m_InputPortMap[n]->Port)) | |||
{ | |||
sample_t *in = (sample_t *) jack_port_get_buffer(m_InputPortMap[n]->Port, nframes); | |||
memcpy (m_InputPortMap[n]->Buf, in, sizeof (sample_t) * m_BufferSize); | |||
} | |||
} | |||
for (int n=0; n<NUM_OUTPUTS; n++) | |||
{ | |||
//if (m_OutputPortMap[n]->Connected) | |||
{ | |||
if (m_OutputPortMap[n]->Buf) | |||
{ | |||
sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes); | |||
memcpy (out, m_OutputPortMap[n]->Buf, sizeof (sample_t) * m_BufferSize); | |||
} | |||
else // no output availible, clear | |||
{ | |||
sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes); | |||
memset (out, 0, sizeof (sample_t) * m_BufferSize); | |||
} | |||
} | |||
} | |||
if(RunCallback&&RunContext) | |||
{ | |||
// do the work | |||
RunCallback(RunContext, true); | |||
} | |||
return 0; | |||
} | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
int JackClient::OnSRateChange(long unsigned int n, void *o) | |||
{ | |||
m_SampleRate=n; | |||
return 0; | |||
} | |||
if (JackProcessInstance==m_JackInstanceID) | |||
JackProcessInstance = -1; | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
void JackClient::OnJackShutdown(void *o) | |||
{ | |||
cerr<<"Shutdown"<<endl; | |||
m_Attached=false; | |||
// tells ssm to go back to non callback mode | |||
RunCallback(RunContext, false); | |||
return; | |||
} | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -226,7 +275,7 @@ void JackClient::ConnectInput(int n, const string &JackPort) | |||
{ | |||
if (!IsAttached()) return; | |||
cerr<<"JackClient::ConnectInput: connecting source ["<<JackPort<<"] to dest ["<<m_InputPortMap[n]->Name<<"]"<<endl; | |||
// cerr<<"JackClient::ConnectInput: connecting source ["<<JackPort<<"] to dest ["<<m_InputPortMap[n]->Name<<"]"<<endl; | |||
if (m_InputPortMap[n]->ConnectedTo!="") | |||
{ | |||
@@ -249,7 +298,7 @@ void JackClient::ConnectInput(int n, const string &JackPort) | |||
void JackClient::ConnectOutput(int n, const string &JackPort) | |||
{ | |||
if (!IsAttached()) return; | |||
cerr<<"JackClient::ConnectOutput: connecting source ["<<m_OutputPortMap[n]->Name<<"] to dest ["<<JackPort<<"]"<<endl; | |||
// cerr<<"JackClient::ConnectOutput: connecting source ["<<m_OutputPortMap[n]->Name<<"] to dest ["<<JackPort<<"]"<<endl; | |||
if (m_OutputPortMap[n]->ConnectedTo!="") | |||
{ | |||
@@ -270,7 +319,7 @@ void JackClient::ConnectOutput(int n, const string &JackPort) | |||
void JackClient::DisconnectInput(int n) | |||
{ | |||
if (!IsAttached()) return; | |||
cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl; | |||
// cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl; | |||
if (m_InputPortMap[n]->ConnectedTo!="") | |||
{ | |||
@@ -287,7 +336,7 @@ void JackClient::DisconnectInput(int n) | |||
void JackClient::DisconnectOutput(int n) | |||
{ | |||
if (!IsAttached()) return; | |||
cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl; | |||
// cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl; | |||
if (m_OutputPortMap[n]->ConnectedTo!="") | |||
{ | |||
@@ -312,7 +361,6 @@ void JackClient::SetOutputBuf(int ID, float* s) | |||
if(m_OutputPortMap.find(ID)!=m_OutputPortMap.end()) m_OutputPortMap[ID]->Buf=s; | |||
} | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
///////////////////////////////////////////////////////////////////////////////////////////// | |||
extern "C" { | |||
@@ -343,32 +391,44 @@ JackPlugin::JackPlugin() : | |||
m_UpdateNames(false), | |||
m_Connected(false) | |||
{ | |||
m_RefCount++; | |||
m_JackClient=new JackClient; | |||
m_JackInstanceID = JackInstances ; | |||
JackInstances++; | |||
m_JackClient->SetJackInstanceID(m_JackInstanceID); | |||
// we are an output | |||
m_IsTerminal = true; | |||
m_PluginInfo.Name="Jack"; | |||
m_PluginInfo.Width=200; | |||
m_PluginInfo.Height=325; | |||
m_PluginInfo.NumInputs=NUM_OUTPUTS; | |||
m_PluginInfo.NumOutputs=NUM_INPUTS; | |||
m_PluginInfo.Width=225; | |||
m_PluginInfo.Height=230; | |||
m_PluginInfo.NumInputs=0; | |||
m_PluginInfo.NumOutputs=0; | |||
for (int n=0; n<NUM_OUTPUTS; n++) | |||
{ | |||
m_PluginInfo.PortTips.clear(); | |||
m_PluginInfo.NumInputs = m_JackClient->GetJackOutputCount(); | |||
for (int n=0; n<m_JackClient->GetJackInputCount(); n++) | |||
{ | |||
char Temp[256]; | |||
sprintf(Temp,"SSM Output %d",n); | |||
sprintf(Temp,"SSM Input %d",n); | |||
m_PluginInfo.PortTips.push_back(Temp); | |||
} | |||
} | |||
for (int n=0; n<NUM_INPUTS; n++) | |||
m_PluginInfo.NumOutputs = m_JackClient->GetJackOutputCount(); | |||
for (int n=0; n<m_JackClient->GetJackOutputCount(); n++) | |||
{ | |||
char Temp[256]; | |||
sprintf(Temp,"SSM Input %d",n); | |||
sprintf(Temp,"SSM Output %d",n); | |||
m_PluginInfo.PortTips.push_back(Temp); | |||
} | |||
m_AudioCH->Register("Num",&m_GUIArgs.Num); | |||
} | |||
m_AudioCH->Register("NumInputs",&m_GUIArgs.NumInputs); | |||
m_AudioCH->Register("NumOutputs",&m_GUIArgs.NumOutputs); | |||
m_AudioCH->RegisterData("Port",ChannelHandler::INPUT,&m_GUIArgs.Port,sizeof(m_GUIArgs.Port)); | |||
m_AudioCH->Register("NumInputPortNames",&m_NumInputPortNames,ChannelHandler::OUTPUT); | |||
m_AudioCH->Register("NumOutputPortNames",&m_NumOutputPortNames,ChannelHandler::OUTPUT); | |||
@@ -380,12 +440,9 @@ m_Connected(false) | |||
JackPlugin::~JackPlugin() | |||
{ | |||
m_RefCount--; | |||
if (m_RefCount==0) | |||
{ | |||
JackClient::Get()->Detach(); | |||
JackClient::PackUpAndGoHome(); | |||
} | |||
m_JackClient->Detach(); | |||
delete m_JackClient; | |||
m_JackClient=NULL; | |||
} | |||
PluginInfo &JackPlugin::Initialise(const HostInfo *Host) | |||
@@ -393,7 +450,7 @@ PluginInfo &JackPlugin::Initialise(const HostInfo *Host) | |||
PluginInfo& Info= SpiralPlugin::Initialise(Host); | |||
host=Host; | |||
if (m_RefCount==1) JackClient::Get()->SetCallback(cb_Update,m_Parent); | |||
m_JackClient->SetCallback(cb_Update,m_Parent); | |||
return Info; | |||
} | |||
@@ -405,23 +462,70 @@ SpiralGUIType *JackPlugin::CreateGUI() | |||
this,m_AudioCH,m_HostInfo); | |||
} | |||
void JackPlugin::SetNumberPorts (int nInputs, int nOutputs) { | |||
UpdatePluginInfoWithHost(); | |||
RemoveAllInputs (); | |||
RemoveAllOutputs (); | |||
m_PluginInfo.NumInputs = 0; | |||
m_PluginInfo.NumOutputs = 0; | |||
m_PluginInfo.PortTips.clear (); | |||
CreatePorts (nInputs, nOutputs, true); | |||
UpdatePluginInfoWithHost (); | |||
} | |||
void JackPlugin::CreatePorts (int nInputs, int nOutputs, bool AddPorts) { | |||
m_PluginInfo.PortTips.clear(); | |||
m_PluginInfo.NumInputs = nInputs; | |||
m_JackClient->SetJackInputCount(nInputs); | |||
for (int n=0; n<nInputs; n++) | |||
{ | |||
char Temp[256]; | |||
sprintf(Temp,"SSM Input %d",n); | |||
m_PluginInfo.PortTips.push_back(Temp); | |||
} | |||
m_PluginInfo.NumOutputs = nOutputs; | |||
m_JackClient->SetJackOutputCount(nOutputs); | |||
for (int n=0; n<nOutputs; n++) | |||
{ | |||
char Temp[256]; | |||
sprintf(Temp,"SSM Output %d",n); | |||
m_PluginInfo.PortTips.push_back(Temp); | |||
} | |||
if (AddPorts) { | |||
for (int n=0; n<nInputs; n++) AddInput(); | |||
for (int n=0; n<nOutputs; n++) AddOutput(); | |||
} | |||
} | |||
void JackPlugin::Execute() | |||
{ | |||
} | |||
void JackPlugin::ExecuteCommands() | |||
{ | |||
// only do this once per set of plugins | |||
m_NoExecuted++; | |||
if (m_NoExecuted!=m_RefCount) return; | |||
m_NoExecuted=0; | |||
bool commandwaiting = m_AudioCH->IsCommandWaiting(); | |||
int command = (commandwaiting)?(int)m_AudioCH->GetCommand():0; | |||
if (commandwaiting) | |||
{ | |||
switch (command) { | |||
case SET_PORT_COUNT : | |||
SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs); | |||
} | |||
} | |||
// we want to process this whether we are connected to stuff or not | |||
JackClient* pJack=JackClient::Get(); | |||
JackClient* pJack=m_JackClient; | |||
// connect the buffers up if we are plugged into something | |||
for (int n=0; n<NUM_OUTPUTS; n++) | |||
for (int n=0; n<pJack->GetJackOutputCount(); n++) | |||
{ | |||
if (InputExists(n)) | |||
{ | |||
@@ -433,24 +537,27 @@ void JackPlugin::ExecuteCommands() | |||
} | |||
} | |||
for (int n=0; n<NUM_INPUTS; n++) | |||
for (int n=0; n<pJack->GetJackInputCount(); n++) | |||
{ | |||
pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer()); | |||
} | |||
if (m_AudioCH->IsCommandWaiting()) | |||
if (OutputExists(n)) | |||
{ | |||
pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer()); | |||
} | |||
else | |||
{ | |||
pJack->SetInputBuf(n,NULL); | |||
} | |||
} | |||
if (commandwaiting) | |||
{ | |||
switch (m_AudioCH->GetCommand()) | |||
switch (command) | |||
{ | |||
//case ATTACH : Attach(); break; | |||
//case DETACH : Detach(); break; | |||
//case CONNECTINPUT : pJack->ConnectInput(m_GUIArgs.Num,m_GUIArgs.Port); break; | |||
//case CONNECTOUTPUT : pJack->ConnectOutput(m_GUIArgs.Num,m_GUIArgs.Port); break; | |||
case UPDATE_NAMES : | |||
{ | |||
int c=0; | |||
vector<string> InputNames,OutputNames; | |||
std::vector<string> InputNames,OutputNames; | |||
GetPortNames(InputNames,OutputNames); | |||
for (vector<string>::iterator i=InputNames.begin(); | |||
i!=InputNames.end(); ++i) | |||
@@ -461,7 +568,7 @@ void JackPlugin::ExecuteCommands() | |||
c=0; | |||
for (vector<string>::iterator i=OutputNames.begin(); | |||
for (std::vector<string>::iterator i=OutputNames.begin(); | |||
i!=OutputNames.end(); ++i) | |||
{ | |||
strcpy(m_OutputPortNames[c],i->c_str()); | |||
@@ -472,8 +579,25 @@ void JackPlugin::ExecuteCommands() | |||
m_NumOutputPortNames=OutputNames.size(); | |||
} | |||
break; | |||
case CHECK_PORT_CHANGES : | |||
if ((m_JackClient->IsAttached()) && (!m_JackClient->CheckingPortChanges)) { | |||
m_JackClient->CheckingPortChanges = true; | |||
for (int n=0; n<m_PluginInfo.NumInputs; n++) { | |||
if (jack_port_connected(m_JackClient->m_OutputPortMap[n]->Port)!=m_JackClient->m_OutputPortMap[n]->Connected) | |||
m_JackClient->m_OutputPortsChanged.push_back(m_JackClient->m_OutputPortMap[n]); | |||
if (jack_port_connected(m_JackClient->m_InputPortMap[n]->Port)!=m_JackClient->m_InputPortMap[n]->Connected) | |||
m_JackClient->m_InputPortsChanged.push_back(m_JackClient->m_InputPortMap[n]); | |||
} | |||
m_JackClient->CheckingPortChanges = false; | |||
} | |||
break; | |||
default : break; | |||
} | |||
} | |||
m_Connected=JackClient::Get()->IsAttached(); | |||
m_Connected=m_JackClient->IsAttached(); | |||
} |
@@ -19,28 +19,34 @@ | |||
#include "../SpiralPlugin.h" | |||
#include "../../RiffWav.h" | |||
#include <FL/Fl_Pixmap.H> | |||
#include <map> | |||
#include <jack/jack.h> | |||
using namespace std; | |||
typedef jack_default_audio_sample_t sample_t; | |||
#ifndef JackPLUGIN | |||
#define JackPLUGIN | |||
const int NUM_INPUTS = 8; | |||
const int NUM_OUTPUTS = 8; | |||
const int MAX_INPUTPORTS = 256; | |||
const int MAX_OUTPUTPORTS = 256; | |||
const int MAX_PORTS = 64; | |||
const int MIN_PORTS = 2; | |||
class JackClient | |||
{ | |||
public: | |||
static JackClient *Get() { if(!m_Singleton) m_Singleton=new JackClient; return m_Singleton; } | |||
static void PackUpAndGoHome() { if(m_Singleton) { delete m_Singleton; m_Singleton=NULL; } } | |||
JackClient(); | |||
virtual ~JackClient(); | |||
void AddInputPort(int NewPortNumber); | |||
void AddOutputPort(int NewPortNumber); | |||
void RemoveInputPort(int PortNumber); | |||
void RemoveOutputPort(int PortNumber); | |||
bool Attach(); | |||
void Detach(); | |||
bool IsAttached() { return m_Attached; } | |||
void SetAttached(bool Attached) { m_Attached = Attached; } | |||
void SetCallback(void(*Run)(void*, bool m),void *Context) { RunCallback=Run; RunContext=Context; } | |||
void GetPortNames(std::vector<std::string> &InputNames,std::vector<std::string> &OutputNames); | |||
void ConnectInput(int n, const std::string &JackPort); | |||
@@ -51,17 +57,16 @@ public: | |||
std::string GetOutputName(int ID) { return m_OutputPortMap[ID]->Name; } | |||
void SetInputBuf(int ID, float* s); | |||
void SetOutputBuf(int ID, float* s); | |||
protected: | |||
JackClient(); | |||
~JackClient(); | |||
static int Process(jack_nframes_t nframes, void *o); | |||
static int OnBufSizeChange(long unsigned int n, void *o); | |||
static int OnSRateChange(long unsigned int n, void *o); | |||
static void OnJackShutdown(void *o); | |||
private: | |||
int GetJackInstanceID() { return m_JackInstanceID; } | |||
void SetJackInstanceID(int JackInstanceID) { m_JackInstanceID=JackInstanceID; } | |||
int GetBufferSize() { return m_BufferSize; } | |||
void SetBufferSize(jack_nframes_t BufferSize) { m_BufferSize=BufferSize; } | |||
int GetSampleRate() { return m_BufferSize; } | |||
void SetSampleRate(jack_nframes_t SampleRate) { m_SampleRate=SampleRate; } | |||
int GetJackInputCount() { return m_JackInputCount; } | |||
void SetJackInputCount(int JackInputCount) { m_JackInputCount=JackInputCount; } | |||
int GetJackOutputCount() { return m_JackOutputCount; } | |||
void SetJackOutputCount(int JackOutputCount) { m_JackOutputCount=JackOutputCount; } | |||
class JackPort | |||
{ | |||
@@ -69,23 +74,42 @@ private: | |||
JackPort::JackPort() : | |||
Connected(false),Buf(NULL),Port(NULL) {} | |||
std::string Name; | |||
int PortNo; | |||
std::string Name; | |||
bool Connected; | |||
float* Buf; | |||
jack_port_t* Port; | |||
std::string ConnectedTo; | |||
}; | |||
static JackClient* m_Singleton; | |||
static jack_client_t* m_Client; | |||
static std::map<int,JackPort*> m_InputPortMap; | |||
static std::map<int,JackPort*> m_OutputPortMap; | |||
static long unsigned int m_BufferSize; | |||
static long unsigned int m_SampleRate; | |||
static bool m_Attached; | |||
jack_client_t* m_Client; | |||
std::map<int,JackPort*> m_InputPortMap; | |||
std::map<int,JackPort*> m_OutputPortMap; | |||
//// Kludge for GUI //// | |||
bool CheckingPortChanges; | |||
std::vector<JackPort*> m_OutputPortsChanged; | |||
std::vector<JackPort*> m_InputPortsChanged; | |||
static void(*RunCallback)(void*, bool m); | |||
static void *RunContext; | |||
//// inline Callbacks //// | |||
inline void JackProcess_i(jack_nframes_t nframes); | |||
inline void SampleRateChange_i(jack_nframes_t nframes); | |||
inline void JackShutdown_i(); | |||
//// static Callbacks //// | |||
static int JackProcess(jack_nframes_t nframes, void *jack_client) { ((JackClient *)jack_client)->JackProcess_i(nframes); return 0;} | |||
static int SampleRateChange(jack_nframes_t nframes, void *jack_client) { ((JackClient *)jack_client)->SampleRateChange_i(nframes); return 0;} | |||
static void JackShutdown(void *jack_client) { ((JackClient *)jack_client)->JackShutdown_i();} | |||
private: | |||
jack_nframes_t m_BufferSize; | |||
jack_nframes_t m_SampleRate; | |||
bool m_Attached; | |||
int m_JackInputCount; | |||
int m_JackOutputCount; | |||
int m_JackInstanceID; | |||
void(*RunCallback)(void*, bool m); | |||
void *RunContext; | |||
}; | |||
/////////////////////////////////////////////////// | |||
@@ -103,32 +127,42 @@ public: | |||
virtual void StreamOut(std::ostream &s) {} | |||
virtual void StreamIn(std::istream &s) {} | |||
enum GUICommands{NONE,ATTACH,DETACH,CONNECTINPUT,CONNECTOUTPUT,UPDATE_NAMES}; | |||
JackClient *GetJackClient() { return m_JackClient; } | |||
void SetNumberPorts (int nInputs, int nOutputs); | |||
enum GUICommands{NONE,UPDATE_NAMES,SET_PORT_COUNT,CHECK_PORT_CHANGES}; | |||
struct GUIArgs | |||
{ | |||
int NumInputs; | |||
int NumOutputs; | |||
int Num; | |||
char Port[256]; | |||
}; | |||
void Attach() { m_JackClient->Attach(); } | |||
void Detach() { m_JackClient->Detach(); } | |||
private: | |||
const HostInfo* host; | |||
GUIArgs m_GUIArgs; | |||
// slightly clumsy, but we have to share this data with the gui | |||
int m_NumInputPortNames; | |||
char m_InputPortNames[MAX_INPUTPORTS][256]; | |||
char m_InputPortNames[MAX_PORTS][256]; | |||
int m_NumOutputPortNames; | |||
char m_OutputPortNames[MAX_OUTPUTPORTS][256]; | |||
void Attach() { JackClient::Get()->Attach(); } | |||
void Detach() { JackClient::Get()->Detach(); } | |||
void GetPortNames(std::vector<std::string> &InputNames,std::vector<std::string> &OutputNames) { JackClient::Get()->GetPortNames(InputNames,OutputNames); } | |||
void ConnectInput(int n, const std::string &JackPort) { JackClient::Get()->ConnectInput(n,JackPort); } | |||
void ConnectOutput(int n, const std::string &JackPort) { JackClient::Get()->ConnectOutput(n,JackPort); } | |||
static int m_RefCount; | |||
static int m_NoExecuted; | |||
bool m_UpdateNames; | |||
bool m_Connected; | |||
char m_OutputPortNames[MAX_PORTS][256]; | |||
void GetPortNames(std::vector<std::string> &InputNames,std::vector<std::string> &OutputNames) { m_JackClient->GetPortNames(InputNames,OutputNames); } | |||
void ConnectInput(int n, const std::string &JackPort) { m_JackClient->ConnectInput(n,JackPort); } | |||
void ConnectOutput(int n, const std::string &JackPort) { m_JackClient->ConnectOutput(n,JackPort); } | |||
void CreatePorts (int nInputs, int nOutputs, bool ); | |||
bool m_UpdateNames; | |||
bool m_Connected; | |||
JackClient *m_JackClient; | |||
int m_JackInstanceID; | |||
}; | |||
#endif |
@@ -24,11 +24,9 @@ | |||
using namespace std; | |||
static int Numbers[255]; | |||
//////////////////////////////////////////////////////////////////////// | |||
int OptionsList(const vector<string> &List) | |||
int OptionsList(const std::vector<string> &List) | |||
{ | |||
Fl_Double_Window *Win = new Fl_Double_Window(300,300); | |||
Fl_Button *Ok = new Fl_Button(10,275,40,20,"Ok"); | |||
@@ -37,7 +35,7 @@ int OptionsList(const vector<string> &List) | |||
Cancel->labelsize(10); | |||
Fl_Hold_Browser* Browser = new Fl_Hold_Browser(5,5,290,265,""); | |||
for (vector<string>::const_iterator i = List.begin(); | |||
for (std::vector<string>::const_iterator i = List.begin(); | |||
i!=List.end(); i++) | |||
{ | |||
Browser->add(i->c_str()); | |||
@@ -77,102 +75,357 @@ int OptionsList(const vector<string> &List) | |||
JackPluginGUI::JackPluginGUI(int w, int h,JackPlugin *o,ChannelHandler *ch,const HostInfo *Info) : | |||
SpiralPluginGUI(w,h,o,ch) | |||
{ | |||
for (int n=0; n<255; n++) Numbers[n]=n; | |||
m_GUIColour = (Fl_Color)Info->GUI_COLOUR; | |||
m_JackPlugin =o; | |||
m_JackClient = o->GetJackClient(); | |||
m_Indicator = new Fl_LED_Button(85,15,30,30,""); | |||
m_Indicator = new Fl_LED_Button(w/2 - 15,15,30,30,""); | |||
m_Indicator->value(0); | |||
m_Indicator->color(FL_RED); | |||
add(m_Indicator); | |||
m_Remove = new Fl_Button(5,15,25,25,"-"); | |||
m_Remove->box (FL_PLASTIC_UP_BOX); | |||
m_Remove->color (m_GUIColour); | |||
m_Remove->type(0); | |||
m_Remove->labelsize(2); | |||
m_Remove->selection_color (m_GUIColour); | |||
m_Remove->callback((Fl_Callback*)cb_Remove, this); | |||
add(m_Remove); | |||
m_Attach = new Fl_Button(5,40,190,20,"Attach"); | |||
m_Add = new Fl_Button(30,15,25,25,"+"); | |||
m_Add->box (FL_PLASTIC_UP_BOX); | |||
m_Add->color (m_GUIColour); | |||
m_Add->type(0); | |||
m_Add->labelsize(2); | |||
m_Add->selection_color (m_GUIColour); | |||
m_Add->callback((Fl_Callback*)cb_Add, this); | |||
add(m_Add); | |||
m_Attach = new Fl_Button(5,45,w - 10,20,"Attach"); | |||
m_Attach->box (FL_PLASTIC_UP_BOX); | |||
m_Attach->color (m_GUIColour); | |||
m_Attach->type(0); | |||
m_Attach->labelsize(10); | |||
m_Attach->callback((Fl_Callback*)cb_Attach); | |||
m_Attach->selection_color (m_GUIColour); | |||
m_Attach->callback((Fl_Callback*)cb_Attach, this); | |||
add(m_Attach); | |||
m_Detach = new Fl_Button(5,60,190,20,"Detach"); | |||
m_Detach = new Fl_Button(5,65,w - 10,20,"Detach"); | |||
m_Detach->box (FL_PLASTIC_UP_BOX); | |||
m_Detach->color (m_GUIColour); | |||
m_Detach->type(0); | |||
m_Detach->labelsize(10); | |||
m_Detach->callback((Fl_Callback*)cb_Detach); | |||
m_Detach->selection_color (m_GUIColour); | |||
m_Detach->callback((Fl_Callback*)cb_Detach, this); | |||
add(m_Detach); | |||
int yoff=80; | |||
m_Scroll = new Fl_Scroll(5, 90, w - 10, h - 102); | |||
m_Scroll->box(FL_PLASTIC_DOWN_BOX); | |||
m_Scroll->type(Fl_Scroll::VERTICAL_ALWAYS); | |||
m_Scroll->position(0, 0); | |||
add(m_Scroll); | |||
m_OutputPack = new Fl_Pack(15, 90, 85, h - 102); | |||
m_Scroll->add(m_OutputPack); | |||
for (int n=0; n<NUM_OUTPUTS; n++) | |||
{ | |||
sprintf(m_OutputName[n],"Output %d",n); | |||
m_OutputLabel[n] = new Fl_Box(5,n*30+yoff,95,10,m_OutputName[n]); | |||
m_OutputLabel[n]->labelsize(8); | |||
//m_OutputLabel[n]->labeltype(FL_ENGRAVED_LABEL); | |||
m_OutputButton[n] = new Fl_Button(5,n*30+yoff+10,95,20,"None"); | |||
m_OutputButton[n]->type(1); | |||
m_OutputButton[n]->labelsize(8); | |||
m_OutputButton[n]->callback((Fl_Callback*)cb_OutputConnect,&Numbers[n]); | |||
} | |||
m_InputPack = new Fl_Pack(110, 90, 85, h - 102); | |||
m_Scroll->add(m_InputPack); | |||
for (int n=0; n<NUM_INPUTS; n++) | |||
for (int n=0; n<m_JackClient->GetJackInputCount(); n++) | |||
{ | |||
sprintf(m_InputName[n],"Input %d",n); | |||
m_InputLabel[n] = new Fl_Box(100,n*30+yoff,95,10,m_InputName[n]); | |||
m_InputLabel[n]->labelsize(8); | |||
//m_InputLabel[n]->labeltype(FL_ENGRAVED_LABEL); | |||
m_InputButton[n] = new Fl_Button(100,n*30+yoff+10,95,20,"None"); | |||
m_InputButton[n]->type(1); | |||
m_InputButton[n]->labelsize(8); | |||
m_InputButton[n]->callback((Fl_Callback*)cb_InputConnect,&Numbers[n]); | |||
AddOutput(); | |||
AddInput(); | |||
} | |||
end(); | |||
} | |||
void JackPluginGUI::UpdateValues(SpiralPlugin *o) | |||
{ | |||
} | |||
void JackPluginGUI::Update() | |||
{ | |||
if (m_GUICH->GetBool("Connected")) { | |||
m_JackClient->CheckingPortChanges = true; | |||
for (unsigned int n=0; n<m_JackClient->m_OutputPortsChanged.size(); n++) { | |||
m_JackClient->m_OutputPortsChanged[n]->Connected = jack_port_connected(m_JackClient->m_OutputPortsChanged[n]->Port); | |||
if (jack_port_connected(m_JackClient->m_OutputPortsChanged[n]->Port)) { | |||
if (m_JackClient->m_OutputPortsChanged[n]->ConnectedTo!="") { | |||
m_OutputButton[n]->label(m_JackClient->m_OutputPortsChanged[n]->ConnectedTo.c_str()); | |||
} | |||
else | |||
{ | |||
const char** connections = jack_port_get_all_connections(m_JackClient->m_Client,m_JackClient->m_OutputPortsChanged[n]->Port); | |||
if (connections) { | |||
m_OutputButton[m_JackClient->m_OutputPortsChanged[n]->PortNo]->label(connections[0]); | |||
free(connections); | |||
} | |||
} | |||
m_OutputButton[m_JackClient->m_OutputPortsChanged[n]->PortNo]->value(1); | |||
} | |||
else | |||
{ | |||
m_OutputButton[m_JackClient->m_OutputPortsChanged[n]->PortNo]->value(0); | |||
m_OutputButton[m_JackClient->m_OutputPortsChanged[n]->PortNo]->label("None"); | |||
} | |||
} | |||
m_JackClient->m_OutputPortsChanged.clear(); | |||
for (unsigned int n=0; n<m_JackClient->m_InputPortsChanged.size(); n++) { | |||
m_JackClient->m_InputPortsChanged[n]->Connected = jack_port_connected(m_JackClient->m_InputPortsChanged[n]->Port); | |||
if (m_JackClient->m_InputPortsChanged[n]->Connected) { | |||
if (m_JackClient->m_InputPortsChanged[n]->ConnectedTo!="") { | |||
m_InputButton[n]->label(m_JackClient->m_InputPortsChanged[n]->ConnectedTo.c_str()); | |||
} | |||
else | |||
{ | |||
const char** connections = jack_port_get_all_connections(m_JackClient->m_Client,m_JackClient->m_InputPortsChanged[n]->Port); | |||
if (connections) { | |||
m_InputButton[m_JackClient->m_InputPortsChanged[n]->PortNo]->label(connections[0]); | |||
free(connections); | |||
} | |||
} | |||
m_InputButton[m_JackClient->m_InputPortsChanged[n]->PortNo]->value(1); | |||
} | |||
else | |||
{ | |||
m_InputButton[m_JackClient->m_InputPortsChanged[n]->PortNo]->value(0); | |||
m_InputButton[m_JackClient->m_InputPortsChanged[n]->PortNo]->label("None"); | |||
} | |||
} | |||
m_JackClient->m_InputPortsChanged.clear(); | |||
m_JackClient->CheckingPortChanges = false; | |||
} | |||
m_GUICH->SetCommand (JackPlugin::CHECK_PORT_CHANGES); | |||
m_Indicator->value(m_GUICH->GetBool("Connected")); | |||
redraw(); | |||
} | |||
//// Callbacks //// | |||
inline void JackPluginGUI::cb_Attach_i(Fl_Button* o, void* v) | |||
void JackPluginGUI::RemoveOutput() { | |||
int n =(int) m_InputName.size() - 1; | |||
if (m_OutputName[n]) | |||
{ | |||
delete(m_OutputName[n]); | |||
m_OutputName[n] = NULL; | |||
m_OutputName.pop_back(); | |||
} | |||
if (m_OutputLabel[n]) | |||
{ | |||
m_OutputPack->remove(m_OutputLabel[n]); | |||
delete(m_OutputLabel[n]); | |||
m_OutputLabel[n] = NULL; | |||
m_OutputLabel.pop_back(); | |||
m_OutputPack->redraw(); | |||
m_Scroll->redraw(); | |||
} | |||
if (m_OutputButton[n]) | |||
{ | |||
m_OutputPack->remove(m_OutputButton[n]); | |||
delete(m_OutputButton[n]); | |||
m_OutputButton[n] = NULL; | |||
m_OutputButton.pop_back(); | |||
m_OutputPack->redraw(); | |||
m_Scroll->redraw(); | |||
} | |||
} | |||
void JackPluginGUI::RemoveInput() { | |||
int n = (int) m_InputName.size() - 1; | |||
if (m_InputName[n]) | |||
{ | |||
delete(m_InputName[n]); | |||
m_InputName[n] = NULL; | |||
m_InputName.pop_back(); | |||
} | |||
if (m_InputLabel[n]) | |||
{ | |||
m_InputPack->remove(m_InputLabel[n]); | |||
delete(m_InputLabel[n]); | |||
m_InputLabel[n] = NULL; | |||
m_InputLabel.pop_back(); | |||
m_InputPack->redraw(); | |||
m_Scroll->redraw(); | |||
} | |||
if (m_InputButton[n]) | |||
{ | |||
m_InputPack->remove(m_InputButton[n]); | |||
delete(m_InputButton[n]); | |||
m_InputButton[n] = NULL; | |||
m_InputButton.pop_back(); | |||
m_InputPack->redraw(); | |||
m_Scroll->redraw(); | |||
} | |||
} | |||
void JackPluginGUI::AddOutput() { | |||
int n = (int) m_OutputName.size(); | |||
char *NewName = new char [256]; | |||
sprintf(NewName,"Output %d",n); | |||
m_OutputName.push_back(NewName); | |||
m_OutputLabel.push_back(new Fl_Box(0,n*30,90,10,m_OutputName[n])); | |||
m_OutputLabel[n]->labelsize(8); | |||
m_OutputPack->add(m_OutputLabel[n]); | |||
m_OutputButton.push_back(new Fl_Button(0,n*30+10,90,20,"None")); | |||
m_OutputButton[n]->type(1); | |||
m_OutputButton[n]->labelsize(8); | |||
m_OutputButton[n]->callback((Fl_Callback*)cb_OutputConnect,this); | |||
m_OutputPack->add(m_OutputButton[n]); | |||
redraw(); | |||
Fl::check(); | |||
} | |||
void JackPluginGUI::AddInput() { | |||
int n = (int) m_InputName.size(); | |||
char *NewName = new char [256]; | |||
sprintf(NewName,"Input %d",n); | |||
m_InputName.push_back(NewName); | |||
m_InputLabel.push_back(new Fl_Box(95,n*30,90,10, m_InputName[n])); | |||
m_InputLabel[n]->labelsize(8); | |||
m_InputPack->add(m_InputLabel[n]); | |||
m_InputButton.push_back(new Fl_Button(95,n*30+10,90,20,"None")); | |||
m_InputButton[n]->type(1); | |||
m_InputButton[n]->labelsize(8); | |||
m_InputButton[n]->callback((Fl_Callback*)cb_InputConnect,this); | |||
m_InputPack->add(m_InputButton[n]); | |||
redraw(); | |||
Fl::check(); | |||
} | |||
inline void JackPluginGUI::cb_Remove_i(Fl_Button* o) | |||
{ | |||
//m_GUICH->SetCommand(JackPlugin::ATTACH); | |||
JackClient::Get()->Attach(); | |||
int n = (int) m_InputName.size(); | |||
if (n > MIN_PORTS) | |||
{ | |||
RemoveOutput() ; | |||
RemoveInput() ; | |||
m_GUICH->Set ("NumInputs", n-1); | |||
m_GUICH->Set ("NumOutputs", n-1); | |||
m_GUICH->SetCommand (JackPlugin::SET_PORT_COUNT); | |||
m_GUICH->Wait (); | |||
/* removing connections live must be called directly from here in the GUI thread */ | |||
if (m_GUICH->GetBool("Connected")) { | |||
m_JackClient->RemoveInputPort(n-1); | |||
m_JackClient->RemoveOutputPort(n-1); | |||
} | |||
if (n > 19) { | |||
resize (x(), y(), w(), h()-7); | |||
m_Indicator->resize (x()+w()/2 - 15,y()+15,30,30); | |||
m_Remove->resize (x()+5,y()+15,25,25); | |||
m_Add->resize (x()+30,y()+15,25,25); | |||
m_Attach->resize (x()+5,y()+45,w() - 10,20); | |||
m_Detach->resize (x()+5,y()+65,w() - 10,20); | |||
m_Scroll->resize (x()+5, y()+90, w() - 10, h() - 102); | |||
m_OutputPack->resize (x()+15, y()+90, 85, h() - 102); | |||
m_InputPack->resize (x()+110, y()+90, 85, h() - 102); | |||
} | |||
} | |||
} | |||
void JackPluginGUI::cb_Attach(Fl_Button* o, void* v) | |||
{ ((JackPluginGUI*)(o->parent()))->cb_Attach_i(o,v);} | |||
inline void JackPluginGUI::cb_Detach_i(Fl_Button* o, void* v) | |||
inline void JackPluginGUI::cb_Add_i(Fl_Button* o) | |||
{ | |||
//m_GUICH->SetCommand(JackPlugin::DETACH); | |||
for (int n=0; n<NUM_OUTPUTS; n++) | |||
int n = (int) m_OutputName.size(); | |||
if (n <= MAX_PORTS) | |||
{ | |||
/* Adding connections live must be called directly from here in the GUI thread */ | |||
if (m_GUICH->GetBool("Connected")) { | |||
m_JackClient->AddInputPort(n); | |||
m_JackClient->AddOutputPort(n); | |||
} | |||
m_GUICH->Set ("NumInputs", n+1); | |||
m_GUICH->Set ("NumOutputs", n+1); | |||
m_GUICH->SetCommand (JackPlugin::SET_PORT_COUNT); | |||
m_GUICH->Wait (); | |||
AddOutput() ; | |||
AddInput() ; | |||
if (n > 20) { | |||
resize (x(), y(), w(), h()+12); | |||
m_Indicator->resize (x()+w()/2 - 15,y()+15,30,30); | |||
m_Remove->resize (x()+5,y()+15,25,25); | |||
m_Add->resize (x()+30,y()+15,25,25); | |||
m_Attach->resize (x()+5,y()+45,w() - 10,20); | |||
m_Detach->resize (x()+5,y()+65,w() - 10,20); | |||
m_Scroll->resize (x()+5, y()+90, w() - 10, h() - 102); | |||
m_OutputPack->resize (x()+15, y()+90, 85, h() - 102); | |||
m_InputPack->resize (x()+110, y()+90, 85, h() - 102); | |||
} | |||
} | |||
} | |||
inline void JackPluginGUI::cb_Attach_i(Fl_Button* o) | |||
{ | |||
m_JackPlugin->Attach(); | |||
} | |||
inline void JackPluginGUI::cb_Detach_i(Fl_Button* o) | |||
{ | |||
for (int n=0; n<(int)m_OutputName.size(); n++) | |||
{ | |||
m_OutputButton[n]->value(false); | |||
m_OutputButton[n]->label("None"); | |||
} | |||
for (int n=0; n<NUM_INPUTS; n++) | |||
for (int n=0; n<(int)m_InputName.size(); n++) | |||
{ | |||
m_InputButton[n]->value(false); | |||
m_InputButton[n]->label("None"); | |||
} | |||
JackClient::Get()->Detach(); | |||
m_JackPlugin->Detach(); | |||
} | |||
void JackPluginGUI::cb_Detach(Fl_Button* o, void* v) | |||
{ ((JackPluginGUI*)(o->parent()))->cb_Detach_i(o,v);} | |||
inline void JackPluginGUI::cb_OutputConnect_i(Fl_Button* o, void* v) | |||
inline void JackPluginGUI::cb_OutputConnect_i(Fl_Button* o) | |||
{ | |||
if (o->value()) | |||
int index=0; | |||
std::vector<Fl_Button *>::iterator it = std::find( m_OutputButton.begin(), m_OutputButton.end(), o ); | |||
if ( it != m_OutputButton.end() ) | |||
index = std::distance( m_OutputButton.begin(), it ); | |||
if ((o->value()) && m_GUICH->GetBool("Connected")) | |||
{ | |||
m_GUICH->SetCommand(JackPlugin::UPDATE_NAMES); | |||
m_GUICH->Wait(); | |||
// bit of a hack for multithreaded safety | |||
int ninputs=m_GUICH->GetInt("NumOutputPortNames"); | |||
char inputs[MAX_INPUTPORTS][256]; | |||
char inputs[MAX_PORTS][256]; | |||
m_GUICH->GetData("InputPortNames",inputs); | |||
vector<string> Inputs; | |||
@@ -181,37 +434,43 @@ inline void JackPluginGUI::cb_OutputConnect_i(Fl_Button* o, void* v) | |||
// connect this plugin's output to a jack input | |||
if (choice>0) | |||
{ | |||
//m_GUICH->Set("Num",(*(int*)v)); | |||
//m_GUICH->SetData("Port",inputs[choice-1]); | |||
//m_GUICH->SetCommand(JackPlugin::CONNECTOUTPUT); | |||
JackClient::Get()->ConnectOutput((*(int*)v),inputs[choice-1]); | |||
{ | |||
m_JackClient->ConnectOutput(index,inputs[choice-1]); | |||
o->label(inputs[choice-1]); | |||
o->redraw(); | |||
} | |||
else { | |||
o->label("None"); | |||
o->value(0); | |||
o->redraw(); | |||
} | |||
} | |||
else | |||
{ | |||
JackClient::Get()->DisconnectOutput((*(int*)v)); | |||
m_JackClient->DisconnectOutput(index); | |||
o->label("None"); | |||
o->value(0); | |||
o->redraw(); | |||
} | |||
} | |||
void JackPluginGUI::cb_OutputConnect(Fl_Button* o, void* v) | |||
{ ((JackPluginGUI*)(o->parent()))->cb_OutputConnect_i(o,v);} | |||
inline void JackPluginGUI::cb_InputConnect_i(Fl_Button* o, void* v) | |||
inline void JackPluginGUI::cb_InputConnect_i(Fl_Button* o) | |||
{ | |||
if (o->value()) | |||
int index=0; | |||
std::vector<Fl_Button *>::iterator it = std::find( m_InputButton.begin(), m_InputButton.end(), o ); | |||
if ( it != m_InputButton.end() ) | |||
index = std::distance( m_InputButton.begin(), it ); | |||
if ((o->value()) && (m_JackClient) && (m_JackClient->IsAttached())) | |||
{ | |||
m_GUICH->SetCommand(JackPlugin::UPDATE_NAMES); | |||
m_GUICH->Wait(); | |||
// bit of a hack for multithreaded safety | |||
int noutputs=m_GUICH->GetInt("NumOutputPortNames"); | |||
char outputs[MAX_OUTPUTPORTS][256]; | |||
char outputs[MAX_PORTS][256]; | |||
m_GUICH->GetData("OutputPortNames",outputs); | |||
vector<string> Outputs; | |||
@@ -220,40 +479,36 @@ inline void JackPluginGUI::cb_InputConnect_i(Fl_Button* o, void* v) | |||
// connect this plugin's input to a jack output | |||
if (choice>0) | |||
{ | |||
//m_GUICH->Set("Num",(*(int*)v)); | |||
//m_GUICH->SetData("Port",outputs[choice-1]); | |||
//m_GUICH->SetCommand(JackPlugin::CONNECTINPUT); | |||
JackClient::Get()->ConnectInput((*(int*)v),outputs[choice-1]); | |||
{ | |||
m_JackClient->ConnectInput(index,outputs[choice-1]); | |||
o->label(outputs[choice-1]); | |||
o->redraw(); | |||
} | |||
else { | |||
o->label("None"); | |||
o->value(0); | |||
o->redraw(); | |||
} | |||
} | |||
else | |||
{ | |||
JackClient::Get()->DisconnectInput((*(int*)v)); | |||
m_JackClient->DisconnectInput(index); | |||
o->label("None"); | |||
o->value(0); | |||
o->redraw(); | |||
} | |||
} | |||
void JackPluginGUI::cb_InputConnect(Fl_Button* o, void* v) | |||
{ ((JackPluginGUI*)(o->parent()))->cb_InputConnect_i(o,v);} | |||
const string JackPluginGUI::GetHelpText(const string &loc){ | |||
return string("") | |||
+ "JACK is the Jack Audio Connection Kit, and allows multiple Linux audio\n" | |||
+ "apps to be connected together and run simultaneously in a low latency.\n" | |||
+ "environment.\n\n" | |||
+ "This plugin allows you to connect up to 8 inputs and outputs to other\n" | |||
+ "JACK apps (providing a server is running)\n" | |||
+ "You can use the JackPlugin to connect the ports, or a external program\n" | |||
+ "such as the excellent qjackconnect app. Be aware however that if you\n" | |||
+ "connect from an external app, the port GUI does not update itself yet.\n" | |||
+ "Another problem yet to be fixed is that ssm will get confused if more\n" | |||
+ "than one JackPlugin is being used. It's best to use one central\n" | |||
+ "JackPlugin at this time.\n\n" | |||
+ "This plugin allows you to connect up to 64 inputs and outputs to other\n" | |||
+ "JACK apps (providing a server is running and your system can handle it)\n" | |||
+ "You can use the JackPlugin to connect the ports, or an external program\n" | |||
+ "such as the excellent qjackconnect app.\n\n" | |||
+ "When using JACK, make sure the buffer size and samplerate are set to\n" | |||
+ "match the JACK server, otherwise glitchy playback, and/or crashes may\n" | |||
+ "result"; | |||
@@ -22,6 +22,8 @@ | |||
#include <FL/Fl_Button.H> | |||
#include <FL/Fl_Pixmap.H> | |||
#include <FL/Fl_Box.H> | |||
#include <FL/Fl_Scroll.H> | |||
#include <FL/Fl_Pack.H> | |||
#include "../Widgets/Fl_Knob.H" | |||
#include "../Widgets/Fl_LED_Button.H" | |||
#include "JackPlugin.h" | |||
@@ -30,6 +32,8 @@ | |||
#ifndef JACK_GUI_H | |||
#define JACK_GUI_H | |||
using namespace std; | |||
class JackPluginGUI : public SpiralPluginGUI | |||
{ | |||
public: | |||
@@ -42,28 +46,52 @@ protected: | |||
const std::string GetHelpText(const std::string &loc); | |||
private: | |||
JackClient *m_JackClient; | |||
JackPlugin *m_JackPlugin; | |||
Fl_Color m_GUIColour; | |||
Fl_LED_Button *m_Indicator; | |||
Fl_Button *m_Remove; | |||
Fl_Button *m_Add; | |||
Fl_Button *m_Attach; | |||
Fl_Button *m_Detach; | |||
char m_InputName[NUM_INPUTS][256]; | |||
Fl_Box *m_InputLabel[NUM_INPUTS]; | |||
Fl_Button *m_InputButton[NUM_INPUTS]; | |||
Fl_Scroll *m_Scroll; | |||
Fl_Pack *m_InputPack; | |||
Fl_Pack *m_OutputPack; | |||
std::vector<char*> m_InputName; | |||
std::vector<Fl_Box*> m_InputLabel; | |||
std::vector<Fl_Button*> m_InputButton; | |||
char m_OutputName[NUM_INPUTS][256]; | |||
Fl_Box *m_OutputLabel[NUM_OUTPUTS]; | |||
Fl_Button *m_OutputButton[NUM_OUTPUTS]; | |||
//// Callbacks //// | |||
inline void cb_Attach_i(Fl_Button* o, void* v); | |||
static void cb_Attach(Fl_Button* o, void* v); | |||
inline void cb_Detach_i(Fl_Button* o, void* v); | |||
static void cb_Detach(Fl_Button* o, void* v); | |||
inline void cb_OutputConnect_i(Fl_Button* o, void* v); | |||
static void cb_OutputConnect(Fl_Button* o, void* v); | |||
inline void cb_InputConnect_i(Fl_Button* o, void* v); | |||
static void cb_InputConnect(Fl_Button* o, void* v); | |||
std::vector<char*> m_OutputName; | |||
std::vector<Fl_Box*> m_OutputLabel; | |||
std::vector<Fl_Button*> m_OutputButton; | |||
void RemoveInput() ; | |||
void RemoveOutput() ; | |||
void AddInput() ; | |||
void AddOutput() ; | |||
//// inline Callbacks //// | |||
inline void cb_Add_i(Fl_Button* o); | |||
inline void cb_Remove_i(Fl_Button* o); | |||
inline void cb_Attach_i(Fl_Button* o); | |||
inline void cb_Detach_i(Fl_Button* o); | |||
inline void cb_OutputConnect_i(Fl_Button* o); | |||
inline void cb_InputConnect_i(Fl_Button* o); | |||
//// Static Callbacks //// | |||
static void cb_Add(Fl_Button* o, JackPluginGUI* v) {v->cb_Add_i(o);} | |||
static void cb_Remove(Fl_Button* o, JackPluginGUI* v) {v->cb_Remove_i(o);} | |||
static void cb_Attach(Fl_Button* o, JackPluginGUI* v) {v->cb_Attach_i(o);} | |||
static void cb_Detach(Fl_Button* o, JackPluginGUI* v) {v->cb_Detach_i(o);} | |||
static void cb_OutputConnect(Fl_Button* o, JackPluginGUI* v) {v->cb_OutputConnect_i(o);} | |||
static void cb_InputConnect(Fl_Button* o, JackPluginGUI* v) {v->cb_InputConnect_i(o);} | |||
}; | |||
#endif |