Browse Source

reworked JACK plugin to allow multiple instance

allow changing of port count
improve the gui to fit ports in smaller space
auto update when ports are changed for eg from another app
master
aj_genius 21 years ago
parent
commit
27d0761b9c
4 changed files with 728 additions and 287 deletions
  1. +274
    -150
      SpiralSound/Plugins/JackPlugin/JackPlugin.C
  2. +77
    -43
      SpiralSound/Plugins/JackPlugin/JackPlugin.h
  3. +333
    -78
      SpiralSound/Plugins/JackPlugin/JackPluginGUI.C
  4. +44
    -16
      SpiralSound/Plugins/JackPlugin/JackPluginGUI.h

+ 274
- 150
SpiralSound/Plugins/JackPlugin/JackPlugin.C View File

@@ -25,76 +25,182 @@


using namespace std; 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() 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() 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() bool JackClient::Attach()
{ {
char JackClientName[256];

if (m_Attached) return true; 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; cerr<<"jack server not running?"<<endl;
return false; 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 // 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 // tell the JACK server that we are ready to roll
if (jack_activate (m_Client)) if (jack_activate (m_Client))
@@ -122,68 +228,11 @@ void JackClient::Detach()
m_Attached=false; 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 // tells ssm to go back to non callback mode
RunCallback(RunContext, false); RunCallback(RunContext, false);
return;
} }


///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////
@@ -226,7 +275,7 @@ void JackClient::ConnectInput(int n, const string &JackPort)
{ {
if (!IsAttached()) return; 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!="") 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) void JackClient::ConnectOutput(int n, const string &JackPort)
{ {
if (!IsAttached()) return; 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!="") if (m_OutputPortMap[n]->ConnectedTo!="")
{ {
@@ -270,7 +319,7 @@ void JackClient::ConnectOutput(int n, const string &JackPort)
void JackClient::DisconnectInput(int n) void JackClient::DisconnectInput(int n)
{ {
if (!IsAttached()) return; if (!IsAttached()) return;
cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;
// cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;


if (m_InputPortMap[n]->ConnectedTo!="") if (m_InputPortMap[n]->ConnectedTo!="")
{ {
@@ -287,7 +336,7 @@ void JackClient::DisconnectInput(int n)
void JackClient::DisconnectOutput(int n) void JackClient::DisconnectOutput(int n)
{ {
if (!IsAttached()) return; if (!IsAttached()) return;
cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;
// cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;


if (m_OutputPortMap[n]->ConnectedTo!="") 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; if(m_OutputPortMap.find(ID)!=m_OutputPortMap.end()) m_OutputPortMap[ID]->Buf=s;
} }


/////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////


extern "C" { extern "C" {
@@ -343,32 +391,44 @@ JackPlugin::JackPlugin() :
m_UpdateNames(false), m_UpdateNames(false),
m_Connected(false) m_Connected(false)
{ {
m_RefCount++;
m_JackClient=new JackClient;

m_JackInstanceID = JackInstances ;
JackInstances++;

m_JackClient->SetJackInstanceID(m_JackInstanceID);
// we are an output // we are an output
m_IsTerminal = true; m_IsTerminal = true;
m_PluginInfo.Name="Jack"; 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]; char Temp[256];
sprintf(Temp,"SSM Output %d",n);
sprintf(Temp,"SSM Input %d",n);
m_PluginInfo.PortTips.push_back(Temp); 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]; char Temp[256];
sprintf(Temp,"SSM Input %d",n);
sprintf(Temp,"SSM Output %d",n);
m_PluginInfo.PortTips.push_back(Temp); 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->RegisterData("Port",ChannelHandler::INPUT,&m_GUIArgs.Port,sizeof(m_GUIArgs.Port));
m_AudioCH->Register("NumInputPortNames",&m_NumInputPortNames,ChannelHandler::OUTPUT); m_AudioCH->Register("NumInputPortNames",&m_NumInputPortNames,ChannelHandler::OUTPUT);
m_AudioCH->Register("NumOutputPortNames",&m_NumOutputPortNames,ChannelHandler::OUTPUT); m_AudioCH->Register("NumOutputPortNames",&m_NumOutputPortNames,ChannelHandler::OUTPUT);
@@ -380,12 +440,9 @@ m_Connected(false)


JackPlugin::~JackPlugin() 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) PluginInfo &JackPlugin::Initialise(const HostInfo *Host)
@@ -393,7 +450,7 @@ PluginInfo &JackPlugin::Initialise(const HostInfo *Host)
PluginInfo& Info= SpiralPlugin::Initialise(Host); PluginInfo& Info= SpiralPlugin::Initialise(Host);
host=Host; host=Host;
if (m_RefCount==1) JackClient::Get()->SetCallback(cb_Update,m_Parent);
m_JackClient->SetCallback(cb_Update,m_Parent);


return Info; return Info;
} }
@@ -405,23 +462,70 @@ SpiralGUIType *JackPlugin::CreateGUI()
this,m_AudioCH,m_HostInfo); 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::Execute()
{ {

} }


void JackPlugin::ExecuteCommands() 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 // 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 // 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)) 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 : case UPDATE_NAMES :
{ {
int c=0; int c=0;
vector<string> InputNames,OutputNames;
std::vector<string> InputNames,OutputNames;
GetPortNames(InputNames,OutputNames); GetPortNames(InputNames,OutputNames);
for (vector<string>::iterator i=InputNames.begin(); for (vector<string>::iterator i=InputNames.begin();
i!=InputNames.end(); ++i) i!=InputNames.end(); ++i)
@@ -461,7 +568,7 @@ void JackPlugin::ExecuteCommands()
c=0; c=0;
for (vector<string>::iterator i=OutputNames.begin();
for (std::vector<string>::iterator i=OutputNames.begin();
i!=OutputNames.end(); ++i) i!=OutputNames.end(); ++i)
{ {
strcpy(m_OutputPortNames[c],i->c_str()); strcpy(m_OutputPortNames[c],i->c_str());
@@ -472,8 +579,25 @@ void JackPlugin::ExecuteCommands()
m_NumOutputPortNames=OutputNames.size(); m_NumOutputPortNames=OutputNames.size();
} }
break; 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; default : break;
} }
} }
m_Connected=JackClient::Get()->IsAttached();
m_Connected=m_JackClient->IsAttached();
} }

+ 77
- 43
SpiralSound/Plugins/JackPlugin/JackPlugin.h View File

@@ -19,28 +19,34 @@
#include "../SpiralPlugin.h" #include "../SpiralPlugin.h"
#include "../../RiffWav.h" #include "../../RiffWav.h"
#include <FL/Fl_Pixmap.H> #include <FL/Fl_Pixmap.H>
#include <map>
#include <jack/jack.h> #include <jack/jack.h>


using namespace std;

typedef jack_default_audio_sample_t sample_t; typedef jack_default_audio_sample_t sample_t;


#ifndef JackPLUGIN #ifndef JackPLUGIN
#define 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 class JackClient
{ {
public: 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(); bool Attach();
void Detach(); void Detach();
bool IsAttached() { return m_Attached; } 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 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 GetPortNames(std::vector<std::string> &InputNames,std::vector<std::string> &OutputNames);
void ConnectInput(int n, const std::string &JackPort); void ConnectInput(int n, const std::string &JackPort);
@@ -51,17 +57,16 @@ public:
std::string GetOutputName(int ID) { return m_OutputPortMap[ID]->Name; } std::string GetOutputName(int ID) { return m_OutputPortMap[ID]->Name; }
void SetInputBuf(int ID, float* s); void SetInputBuf(int ID, float* s);
void SetOutputBuf(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 class JackPort
{ {
@@ -69,23 +74,42 @@ private:
JackPort::JackPort() : JackPort::JackPort() :
Connected(false),Buf(NULL),Port(NULL) {} Connected(false),Buf(NULL),Port(NULL) {}
std::string Name;
int PortNo;
std::string Name;
bool Connected; bool Connected;
float* Buf; float* Buf;
jack_port_t* Port; jack_port_t* Port;
std::string ConnectedTo; 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 StreamOut(std::ostream &s) {}
virtual void StreamIn(std::istream &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 struct GUIArgs
{ {
int NumInputs;
int NumOutputs;
int Num; int Num;
char Port[256]; char Port[256];
}; };

void Attach() { m_JackClient->Attach(); }
void Detach() { m_JackClient->Detach(); }
private: private:
const HostInfo* host;

GUIArgs m_GUIArgs; GUIArgs m_GUIArgs;
// slightly clumsy, but we have to share this data with the gui // slightly clumsy, but we have to share this data with the gui
int m_NumInputPortNames; int m_NumInputPortNames;
char m_InputPortNames[MAX_INPUTPORTS][256];
char m_InputPortNames[MAX_PORTS][256];
int m_NumOutputPortNames; 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 #endif

+ 333
- 78
SpiralSound/Plugins/JackPlugin/JackPluginGUI.C View File

@@ -24,11 +24,9 @@


using namespace std; 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_Double_Window *Win = new Fl_Double_Window(300,300);
Fl_Button *Ok = new Fl_Button(10,275,40,20,"Ok"); Fl_Button *Ok = new Fl_Button(10,275,40,20,"Ok");
@@ -37,7 +35,7 @@ int OptionsList(const vector<string> &List)
Cancel->labelsize(10); Cancel->labelsize(10);
Fl_Hold_Browser* Browser = new Fl_Hold_Browser(5,5,290,265,""); 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++) i!=List.end(); i++)
{ {
Browser->add(i->c_str()); 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) : JackPluginGUI::JackPluginGUI(int w, int h,JackPlugin *o,ChannelHandler *ch,const HostInfo *Info) :
SpiralPluginGUI(w,h,o,ch) 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->value(0);
m_Indicator->color(FL_RED); 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->type(0);
m_Attach->labelsize(10); 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->type(0);
m_Detach->labelsize(10); 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(); end();
} }


void JackPluginGUI::UpdateValues(SpiralPlugin *o) void JackPluginGUI::UpdateValues(SpiralPlugin *o)
{ {
} }


void JackPluginGUI::Update() 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")); m_Indicator->value(m_GUICH->GetBool("Connected"));
redraw(); redraw();
} }
//// Callbacks //// //// 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]->value(false);
m_OutputButton[n]->label("None"); 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]->value(false);
m_InputButton[n]->label("None"); 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->SetCommand(JackPlugin::UPDATE_NAMES);
m_GUICH->Wait(); m_GUICH->Wait();
// bit of a hack for multithreaded safety // bit of a hack for multithreaded safety
int ninputs=m_GUICH->GetInt("NumOutputPortNames"); int ninputs=m_GUICH->GetInt("NumOutputPortNames");
char inputs[MAX_INPUTPORTS][256];
char inputs[MAX_PORTS][256];
m_GUICH->GetData("InputPortNames",inputs); m_GUICH->GetData("InputPortNames",inputs);
vector<string> 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 // connect this plugin's output to a jack input
if (choice>0) 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->label(inputs[choice-1]);
o->redraw(); o->redraw();
} }
else {
o->label("None");
o->value(0);
o->redraw();
}
} }
else else
{ {
JackClient::Get()->DisconnectOutput((*(int*)v));
m_JackClient->DisconnectOutput(index);
o->label("None"); o->label("None");
o->value(0);
o->redraw(); 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->SetCommand(JackPlugin::UPDATE_NAMES);
m_GUICH->Wait(); m_GUICH->Wait();
// bit of a hack for multithreaded safety // bit of a hack for multithreaded safety
int noutputs=m_GUICH->GetInt("NumOutputPortNames"); int noutputs=m_GUICH->GetInt("NumOutputPortNames");
char outputs[MAX_OUTPUTPORTS][256];
char outputs[MAX_PORTS][256];
m_GUICH->GetData("OutputPortNames",outputs); m_GUICH->GetData("OutputPortNames",outputs);
vector<string> 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 // connect this plugin's input to a jack output
if (choice>0) 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->label(outputs[choice-1]);
o->redraw(); o->redraw();
} }
else {
o->label("None");
o->value(0);
o->redraw();
}
} }
else else
{ {
JackClient::Get()->DisconnectInput((*(int*)v));
m_JackClient->DisconnectInput(index);
o->label("None"); o->label("None");
o->value(0);
o->redraw(); 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){ const string JackPluginGUI::GetHelpText(const string &loc){
return string("") return string("")
+ "JACK is the Jack Audio Connection Kit, and allows multiple Linux audio\n" + "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" + "apps to be connected together and run simultaneously in a low latency.\n"
+ "environment.\n\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" + "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" + "match the JACK server, otherwise glitchy playback, and/or crashes may\n"
+ "result"; + "result";


+ 44
- 16
SpiralSound/Plugins/JackPlugin/JackPluginGUI.h View File

@@ -22,6 +22,8 @@
#include <FL/Fl_Button.H> #include <FL/Fl_Button.H>
#include <FL/Fl_Pixmap.H> #include <FL/Fl_Pixmap.H>
#include <FL/Fl_Box.H> #include <FL/Fl_Box.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Pack.H>
#include "../Widgets/Fl_Knob.H" #include "../Widgets/Fl_Knob.H"
#include "../Widgets/Fl_LED_Button.H" #include "../Widgets/Fl_LED_Button.H"
#include "JackPlugin.h" #include "JackPlugin.h"
@@ -30,6 +32,8 @@
#ifndef JACK_GUI_H #ifndef JACK_GUI_H
#define JACK_GUI_H #define JACK_GUI_H


using namespace std;

class JackPluginGUI : public SpiralPluginGUI class JackPluginGUI : public SpiralPluginGUI
{ {
public: public:
@@ -42,28 +46,52 @@ protected:
const std::string GetHelpText(const std::string &loc); const std::string GetHelpText(const std::string &loc);
private: private:
JackClient *m_JackClient;
JackPlugin *m_JackPlugin;

Fl_Color m_GUIColour;


Fl_LED_Button *m_Indicator; Fl_LED_Button *m_Indicator;

Fl_Button *m_Remove;
Fl_Button *m_Add;
Fl_Button *m_Attach; Fl_Button *m_Attach;
Fl_Button *m_Detach; 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 #endif

Loading…
Cancel
Save