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; | 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(); | |||||
} | } |
@@ -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 |
@@ -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"; | ||||
@@ -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 |