@@ -97,6 +97,18 @@ const unsigned int PARAMETER_USES_SCALEPOINTS = 0x40; //!< Parameter uses scalep | |||
const unsigned int PARAMETER_USES_CUSTOM_TEXT = 0x80; //!< Parameter uses custom text for displaying its value.\see CarlaPlugin::getParameterText() | |||
/**@}*/ | |||
/*! | |||
* @defgroup PatchbayPortHints Patchbay Port Hints | |||
* | |||
* Various patchbay port hints. | |||
* @{ | |||
*/ | |||
const unsigned int PATCHBAY_PORT_IS_INPUT = 0x1; //!< Patchbay port is input. | |||
const unsigned int PATCHBAY_PORT_IS_OUTPUT = 0x2; //!< Patchbay port is output. | |||
const unsigned int PATCHBAY_PORT_IS_AUDIO = 0x4; //!< Patchbay port is of Audio type. | |||
const unsigned int PATCHBAY_PORT_IS_MIDI = 0x8; //!< Patchbay port is of MIDI type. | |||
/**@}*/ | |||
/*! | |||
* @defgroup CustomDataTypes Custom Data types | |||
* | |||
@@ -497,7 +497,10 @@ public: | |||
#ifdef BUILD_BRIDGE | |||
fHasQuit(false) | |||
#else | |||
fRackPorts{nullptr} | |||
fRackPorts{nullptr}, | |||
fLastGroupId(0), | |||
fLastPortId(0), | |||
fLastConnectionId(0) | |||
#endif | |||
{ | |||
carla_debug("CarlaEngineJack::CarlaEngineJack()"); | |||
@@ -513,6 +516,12 @@ public: | |||
{ | |||
carla_debug("CarlaEngineJack::~CarlaEngineJack()"); | |||
CARLA_ASSERT(fClient == nullptr); | |||
#ifndef BUILD_BRIDGE | |||
fUsedGroupNames.clear(); | |||
fUsedPortNames.clear(); | |||
fUsedConnections.clear(); | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -547,6 +556,14 @@ public: | |||
carla_zeroStruct<jack_position_t>(fTransportPos); | |||
#ifndef BUILD_BRIDGE | |||
fLastGroupId = 0; | |||
fLastPortId = 0; | |||
fLastConnectionId = 0; | |||
fUsedGroupNames.clear(); | |||
fUsedPortNames.clear(); | |||
fUsedConnections.clear(); | |||
fClient = jackbridge_client_open(clientName, JackNullOption, nullptr); | |||
if (fClient != nullptr) | |||
@@ -571,6 +588,14 @@ public: | |||
fRackPorts[rackPortEventOut] = jackbridge_port_register(fClient, "events-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); | |||
} | |||
// TODO - update jackbridge | |||
jack_set_client_registration_callback(fClient, carla_jack_client_registration_callback, this); | |||
jack_set_port_registration_callback(fClient, carla_jack_port_registration_callback, this); | |||
jack_set_port_connect_callback(fClient, carla_jack_port_connect_callback, this); | |||
if (jack_set_port_rename_callback) | |||
jack_set_port_rename_callback(fClient, carla_jack_port_rename_callback, this); | |||
if (jackbridge_activate(fClient) == 0) | |||
{ | |||
const char* const jackClientName = jackbridge_get_client_name(fClient); | |||
@@ -639,6 +664,10 @@ public: | |||
setLastError("Failed to deactivate the JACK client"); | |||
fClient = nullptr; | |||
fUsedGroupNames.clear(); | |||
fUsedPortNames.clear(); | |||
fUsedConnections.clear(); | |||
#endif | |||
return false; | |||
} | |||
@@ -691,9 +720,6 @@ public: | |||
} | |||
#endif | |||
static int test = 0; | |||
callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, test++, 0, 0, plugin->name()); | |||
return new CarlaEngineJackClient(kEngineTypeJack, fOptions.processMode, client); | |||
} | |||
@@ -1047,6 +1073,113 @@ protected: | |||
} | |||
} | |||
#ifndef BUILD_BRIDGE | |||
void handleJackClientRegistrationCallback(const char* name, bool reg) | |||
{ | |||
if (reg) | |||
{ | |||
GroupNameToId groupNameToId; | |||
groupNameToId.id = fLastGroupId; | |||
groupNameToId.name = name; | |||
callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, fLastGroupId, 0, 0.0f, name); | |||
fUsedGroupNames.append(groupNameToId); | |||
fLastGroupId++; | |||
} | |||
else | |||
{ | |||
for (int i=0, count=fUsedGroupNames.count(); i < count; i++) | |||
{ | |||
if (fUsedGroupNames[i].name == name) | |||
{ | |||
callback(CALLBACK_PATCHBAY_CLIENT_REMOVED, 0, fUsedGroupNames[i].id, 0, 0.0f, nullptr); | |||
fUsedGroupNames.takeAt(i); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
void handleJackPortRegistrationCallback(jack_port_id_t port, bool reg) | |||
{ | |||
jack_port_t* jackPort = jack_port_by_id(fClient, port); | |||
QString fullName(jack_port_name(jackPort)); | |||
QString groupName = fullName.split(":").at(0); | |||
int groupId = getGroupId(groupName); | |||
const char* portName = jack_port_short_name(jackPort); | |||
if (reg) | |||
{ | |||
bool portIsInput = (jack_port_flags(jackPort) & JackPortIsInput); | |||
bool portIsAudio = (std::strcmp(jack_port_type(jackPort), JACK_DEFAULT_AUDIO_TYPE) == 0); | |||
unsigned int portFlags = 0x0; | |||
portFlags |= portIsInput ? PATCHBAY_PORT_IS_INPUT : PATCHBAY_PORT_IS_OUTPUT; | |||
portFlags |= portIsAudio ? PATCHBAY_PORT_IS_AUDIO : PATCHBAY_PORT_IS_MIDI; | |||
PortNameToId portNameToId; | |||
portNameToId.groupId = groupId; | |||
portNameToId.portId = fLastPortId; | |||
portNameToId.name = portName; | |||
fUsedPortNames.append(portNameToId); | |||
callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, groupId, fLastPortId, portFlags, portName); | |||
fLastPortId++; | |||
} | |||
else | |||
{ | |||
for (int i=0, count=fUsedPortNames.count(); i < count; i++) | |||
{ | |||
if (fUsedPortNames[i].groupId == groupId && fUsedPortNames[i].name == portName) | |||
{ | |||
callback(CALLBACK_PATCHBAY_PORT_REMOVED, 0, fUsedPortNames[i].portId, 0, 0.0f, nullptr); | |||
fUsedPortNames.takeAt(i); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
void handleJackPortConnectCallback(jack_port_id_t a, jack_port_id_t b, bool connect) | |||
{ | |||
jack_port_t* jackPortA = jack_port_by_id(fClient, a); | |||
jack_port_t* jackPortB = jack_port_by_id(fClient, b); | |||
int portIdA = getPortId(QString(jack_port_name(jackPortA))); | |||
int portIdB = getPortId(QString(jack_port_name(jackPortB))); | |||
if (connect) | |||
{ | |||
ConnectionToId connectionToId; | |||
connectionToId.id = fLastConnectionId; | |||
connectionToId.portOut = portIdA; | |||
connectionToId.portIn = portIdB; | |||
fUsedConnections.append(connectionToId); | |||
callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, portIdA, portIdB, nullptr); | |||
fLastConnectionId++; | |||
} | |||
else | |||
{ | |||
for (int i=0, count=fUsedConnections.count(); i < count; i++) | |||
{ | |||
if (fUsedConnections[i].portOut == portIdA && fUsedConnections[i].portIn == portIdB) | |||
{ | |||
callback(CALLBACK_PATCHBAY_CONNECTION_REMOVED, 0, fUsedConnections[i].id, 0, 0.0f, nullptr); | |||
fUsedConnections.takeAt(i); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
int handleJackPortRenameCallback(jack_port_id_t port, const char* oldName, const char* newName) | |||
{ | |||
} | |||
#endif | |||
void handleJackShutdownCallback() | |||
{ | |||
for (unsigned int i=0; i < kData->curPluginCount; i++) | |||
@@ -1085,6 +1218,61 @@ private: | |||
}; | |||
jack_port_t* fRackPorts[rackPortCount]; | |||
struct GroupNameToId { | |||
int id; | |||
QString name; | |||
}; | |||
struct PortNameToId { | |||
int groupId; | |||
int portId; | |||
QString name; | |||
}; | |||
struct ConnectionToId { | |||
int id; | |||
int portOut; | |||
int portIn; | |||
}; | |||
int fLastGroupId; | |||
int fLastPortId; | |||
int fLastConnectionId ; | |||
QList<GroupNameToId> fUsedGroupNames; | |||
QList<PortNameToId> fUsedPortNames; | |||
QList<ConnectionToId> fUsedConnections; | |||
int getGroupId(QString groupName) | |||
{ | |||
for (int i=0, count=fUsedGroupNames.count(); i < count; i++) | |||
{ | |||
if (fUsedGroupNames[i].name == groupName) | |||
{ | |||
return fUsedGroupNames[i].id; | |||
} | |||
} | |||
return -1; | |||
} | |||
int getPortId(QString fullPortName) | |||
{ | |||
QString groupName = fullPortName.split(":").at(0); | |||
QString portName = fullPortName.replace(groupName+":", ""); | |||
int groupId = getGroupId(groupName); | |||
for (int i=0, count=fUsedPortNames.count(); i < count; i++) | |||
{ | |||
if (fUsedPortNames[i].groupId == groupId && fUsedPortNames[i].name == portName) | |||
{ | |||
return fUsedPortNames[i].portId; | |||
} | |||
} | |||
return -1; | |||
} | |||
#endif | |||
// ------------------------------------- | |||
@@ -1217,6 +1405,29 @@ private: | |||
handlePtr->handleJackLatencyCallback(mode); | |||
} | |||
#ifndef BUILD_BRIDGE | |||
static void carla_jack_client_registration_callback(const char* name, int reg, void* arg) | |||
{ | |||
handlePtr->handleJackClientRegistrationCallback(name, (reg != 0)); | |||
} | |||
static void carla_jack_port_registration_callback(jack_port_id_t port, int reg, void* arg) | |||
{ | |||
handlePtr->handleJackPortRegistrationCallback(port, (reg != 0)); | |||
} | |||
static void carla_jack_port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) | |||
{ | |||
handlePtr->handleJackPortConnectCallback(a, b, (connect != 0)); | |||
} | |||
static int carla_jack_port_rename_callback(jack_port_id_t port, const char* oldName, const char* newName, void* arg) | |||
{ | |||
handlePtr->handleJackPortRenameCallback(port, oldName, newName); | |||
return 0; | |||
} | |||
#endif | |||
static void carla_jack_shutdown_callback(void* arg) | |||
{ | |||
handlePtr->handleJackShutdownCallback(); | |||
@@ -660,11 +660,11 @@ class CarlaMainW(QMainWindow): | |||
self.connect(self, SIGNAL("PatchbayClientAddedCallback(int, QString)"), SLOT("slot_handlePatchbayClientAddedCallback(int, QString)")) | |||
self.connect(self, SIGNAL("PatchbayClientRemovedCallback(int)"), SLOT("slot_handlePatchbayClientRemovedCallback(int)")) | |||
self.connect(self, SIGNAL("PatchbayClientRenamedCallback(int, QString)"), SLOT("slot_handlePatchbayClientRenamedCallback(int, QString)")) | |||
self.connect(self, SIGNAL("PatchbayPortAddedCallback(int, int, QString)"), SLOT("slot_handlePatchbayPortAddedCallback(int, int, QString)")) | |||
self.connect(self, SIGNAL("PatchbayPortAddedCallback(int, int, int, QString)"), SLOT("slot_handlePatchbayPortAddedCallback(int, int, int, QString)")) | |||
self.connect(self, SIGNAL("PatchbayPortRemovedCallback(int)"), SLOT("slot_handlePatchbayPortRemovedCallback(int)")) | |||
self.connect(self, SIGNAL("PatchbayPortRenamedCallback(int, QString)"), SLOT("slot_handlePatchbayPortRenamedCallback(int, QString)")) | |||
self.connect(self, SIGNAL("PatchbayConnectionAddedCallback(int, int)"), SLOT("slot_handlePatchbayConnectionAddedCallback(int, int)")) | |||
self.connect(self, SIGNAL("PatchbayConnectionRemovedCallback(int, int)"), SLOT("slot_handlePatchbayConnectionRemovedCallback(int, int)")) | |||
self.connect(self, SIGNAL("PatchbayConnectionAddedCallback(int, int, int)"), SLOT("slot_handlePatchbayConnectionAddedCallback(int, int, int)")) | |||
self.connect(self, SIGNAL("PatchbayConnectionRemovedCallback(int)"), SLOT("slot_handlePatchbayConnectionRemovedCallback(int)")) | |||
#self.connect(self, SIGNAL("NSM_AnnounceCallback()"), SLOT("slot_handleNSM_AnnounceCallback()")) | |||
#self.connect(self, SIGNAL("NSM_Open1Callback()"), SLOT("slot_handleNSM_Open1Callback()")) | |||
#self.connect(self, SIGNAL("NSM_Open2Callback()"), SLOT("slot_handleNSM_Open2Callback()")) | |||
@@ -839,6 +839,8 @@ class CarlaMainW(QMainWindow): | |||
self.ui.ch_transport.clear() | |||
self.ui.ch_transport.blockSignals(False) | |||
patchcanvas.clear() | |||
def loadProject(self, filename): | |||
self.fProjectFilename = filename | |||
self.setWindowTitle("Carla - %s" % os.path.basename(filename)) | |||
@@ -1232,10 +1234,23 @@ class CarlaMainW(QMainWindow): | |||
def slot_handlePatchbayClientRenamedCallback(self, clientId, newClientName): | |||
patchcanvas.renameGroup(clientId, newClientName) | |||
@pyqtSlot(int, int, str) | |||
def slot_handlePatchbayPortAddedCallback(self, clientId, portId, portName): | |||
# FIXME - needs mode and type | |||
patchcanvas.addPort(clientId, portId, portName, 0, 0) | |||
@pyqtSlot(int, int, int, str) | |||
def slot_handlePatchbayPortAddedCallback(self, clientId, portId, portFlags, portName): | |||
if (portFlags & PATCHBAY_PORT_IS_INPUT): | |||
portMode = patchcanvas.PORT_MODE_INPUT | |||
elif (portFlags & PATCHBAY_PORT_IS_OUTPUT): | |||
portMode = patchcanvas.PORT_MODE_OUTPUT | |||
else: | |||
portMode = patchcanvas.PORT_MODE_NULL | |||
if (portFlags & PATCHBAY_PORT_IS_AUDIO): | |||
portType = patchcanvas.PORT_TYPE_AUDIO_JACK | |||
elif (portFlags & PATCHBAY_PORT_IS_MIDI): | |||
portType = patchcanvas.PORT_TYPE_MIDI_JACK | |||
else: | |||
portType = patchcanvas.PORT_TYPE_NULL | |||
patchcanvas.addPort(clientId, portId, portName, portMode, portType) | |||
@pyqtSlot(int) | |||
def slot_handlePatchbayPortRemovedCallback(self, portId): | |||
@@ -1245,14 +1260,13 @@ class CarlaMainW(QMainWindow): | |||
def slot_handlePatchbayPortRenamedCallback(self, portId, newPortName): | |||
patchcanvas.renamePort(portId, newPortName) | |||
@pyqtSlot(int, int) | |||
def slot_handlePatchbayConnectionAddedCallback(self, portOutId, portInId): | |||
patchcanvas.connectPorts(0, portOutId, portInId) | |||
@pyqtSlot(int, int, int) | |||
def slot_handlePatchbayConnectionAddedCallback(self, connectionId, portOutId, portInId): | |||
patchcanvas.connectPorts(connectionId, portOutId, portInId) | |||
@pyqtSlot(int, int) | |||
def slot_handlePatchbayConnectionRemovedCallback(self, portOutId, portInId): | |||
# FIXME | |||
patchcanvas.disconnectPorts(0) | |||
@pyqtSlot(int) | |||
def slot_handlePatchbayConnectionRemovedCallback(self, connectionId): | |||
patchcanvas.disconnectPorts(connectionId) | |||
@pyqtSlot(str) | |||
def slot_handleErrorCallback(self, error): | |||
@@ -1411,7 +1425,6 @@ class CarlaMainW(QMainWindow): | |||
self.stopEngine() | |||
patchcanvas.clear() | |||
QMainWindow.closeEvent(self, event) | |||
# ------------------------------------------------------------------------------------------------ | |||
@@ -1464,15 +1477,15 @@ def engineCallback(ptr, action, pluginId, value1, value2, value3, valueStr): | |||
elif action == CALLBACK_PATCHBAY_CLIENT_RENAMED: | |||
Carla.gui.emit(SIGNAL("PatchbayClientRenamedCallback(int, QString)"), value1, cString(valueStr)) | |||
elif action == CALLBACK_PATCHBAY_PORT_ADDED: | |||
Carla.gui.emit(SIGNAL("PatchbayPortAddedCallback(int, int, QString)"), value1, value2, cString(valueStr)) | |||
Carla.gui.emit(SIGNAL("PatchbayPortAddedCallback(int, int, int, QString)"), value1, value2, value3, cString(valueStr)) | |||
elif action == CALLBACK_PATCHBAY_PORT_REMOVED: | |||
Carla.gui.emit(SIGNAL("PatchbayPortRemovedCallback(int)"), value1) | |||
elif action == CALLBACK_PATCHBAY_PORT_RENAMED: | |||
Carla.gui.emit(SIGNAL("PatchbayPortRenamedCallback(int, QString)"), value1, cString(valueStr)) | |||
elif action == CALLBACK_PATCHBAY_CONNECTION_ADDED: | |||
Carla.gui.emit(SIGNAL("PatchbayConnectionAddedCallback(int, int)"), value1, value2) | |||
Carla.gui.emit(SIGNAL("PatchbayConnectionAddedCallback(int, int, int)"), value1, value2, value3) | |||
elif action == CALLBACK_PATCHBAY_CONNECTION_REMOVED: | |||
Carla.gui.emit(SIGNAL("PatchbayConnectionRemovedCallback(int, int)"), value1, value2) | |||
Carla.gui.emit(SIGNAL("PatchbayConnectionRemovedCallback(int)"), value1) | |||
#elif action == CALLBACK_NSM_ANNOUNCE: | |||
#Carla.gui._nsmAnnounce2str = cString(Carla.host.get_last_error()) | |||
#Carla.gui.emit(SIGNAL("NSM_AnnounceCallback()")) | |||
@@ -189,6 +189,12 @@ PARAMETER_USES_SAMPLERATE = 0x20 | |||
PARAMETER_USES_SCALEPOINTS = 0x40 | |||
PARAMETER_USES_CUSTOM_TEXT = 0x80 | |||
# Patchbay Port Hints | |||
PATCHBAY_PORT_IS_INPUT = 0x1 | |||
PATCHBAY_PORT_IS_OUTPUT = 0x2 | |||
PATCHBAY_PORT_IS_AUDIO = 0x4 | |||
PATCHBAY_PORT_IS_MIDI = 0x8 | |||
# Custom Data types | |||
CUSTOM_DATA_INVALID = None | |||
CUSTOM_DATA_CHUNK = "http://kxstudio.sf.net/ns/carla/chunk" | |||
@@ -295,6 +295,22 @@ const char* CallbackType2Str(const CallbackType& type) | |||
return "CALLBACK_SHOW_GUI"; | |||
case CALLBACK_UPDATE: | |||
return "CALLBACK_UPDATE"; | |||
case CALLBACK_PATCHBAY_CLIENT_ADDED: | |||
return "CALLBACK_PATCHBAY_CLIENT_ADDED"; | |||
case CALLBACK_PATCHBAY_CLIENT_REMOVED: | |||
return "CALLBACK_PATCHBAY_CLIENT_REMOVED"; | |||
case CALLBACK_PATCHBAY_CLIENT_RENAMED: | |||
return "CALLBACK_PATCHBAY_CLIENT_RENAMED"; | |||
case CALLBACK_PATCHBAY_PORT_ADDED: | |||
return "CALLBACK_PATCHBAY_PORT_ADDED"; | |||
case CALLBACK_PATCHBAY_PORT_REMOVED: | |||
return "CALLBACK_PATCHBAY_PORT_REMOVED"; | |||
case CALLBACK_PATCHBAY_PORT_RENAMED: | |||
return "CALLBACK_PATCHBAY_PORT_RENAMED"; | |||
case CALLBACK_PATCHBAY_CONNECTION_ADDED: | |||
return "CALLBACK_PATCHBAY_CONNECTION_ADDED"; | |||
case CALLBACK_PATCHBAY_CONNECTION_REMOVED: | |||
return "CALLBACK_PATCHBAY_CONNECTION_REMOVED"; | |||
case CALLBACK_RELOAD_INFO: | |||
return "CALLBACK_RELOAD_INFO"; | |||
case CALLBACK_RELOAD_PARAMETERS: | |||