CARLA_EXPORT int jack_midi_event_get(jack_midi_event_t* ev, void* buf, uint32_t index) { JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, EFAULT); CARLA_SAFE_ASSERT_RETURN(jmidibuf->isInput, EFAULT); if (index >= jmidibuf->count) return ENODATA; std::memcpy(ev, &jmidibuf->events[index], sizeof(jack_midi_event_t)); return 0; }
CARLA_BACKEND_USE_NAMESPACE // -------------------------------------------------------------------------------------------------------------------- CARLA_EXPORT jack_nframes_t jack_midi_get_event_count(void* buf) { JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, 0); CARLA_SAFE_ASSERT_RETURN(jmidibuf->isInput, 0); return jmidibuf->count; }
CARLA_BACKEND_USE_NAMESPACE // -------------------------------------------------------------------------------------------------------------------- CarlaEngine* carla_get_native_plugin_engine(const NativePluginDescriptor* desc, NativePluginHandle handle) { CARLA_SAFE_ASSERT_RETURN(desc != nullptr, nullptr); CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); return (CarlaEngine*)static_cast<uintptr_t>(desc->dispatcher(handle, NATIVE_PLUGIN_OPCODE_GET_INTERNAL_HANDLE, 0, 0, nullptr, 0.0f)); }
const NativePluginDescriptor* carla_get_native_plugins_data(uint32_t* count) { CARLA_SAFE_ASSERT_RETURN(count != nullptr, nullptr); *count = static_cast<uint32_t>(sizeof(sNativePluginDescriptors)/sizeof(NativePluginDescriptor)); return sNativePluginDescriptors; }
/* * Create and open a new shared memory object. * Returns an invalid object if the operation failed or the filename already exists. */ static inline carla_shm_t carla_shm_create(const char* const filename) noexcept { CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', gNullCarlaShm); carla_shm_t ret; #ifdef CARLA_OS_WIN ret.map = INVALID_HANDLE_VALUE; ret.isServer = true; ret.filename = carla_strdup_safe(filename); #else try { ret.fd = ::shm_open(filename, O_CREAT|O_EXCL|O_RDWR, 0600); ret.filename = (ret.fd >= 0) ? carla_strdup_safe(filename) : nullptr; ret.size = 0; if (ret.fd >= 0 && ret.filename == nullptr) { ::close(ret.fd); ::shm_unlink(filename); ret.fd = -1; } } CARLA_SAFE_EXCEPTION_RETURN("carla_shm_create", gNullCarlaShm); #endif return ret; }
static int real_XMapRaised(Display* display, Window window) { static const XWindowFunc func = (XWindowFunc)::dlsym(RTLD_NEXT, "XMapRaised"); CARLA_SAFE_ASSERT_RETURN(func != nullptr, 0); return func(display, window); }
CARLA_EXPORT int XNextEvent(Display* display, XEvent* event) { const int ret = real_XNextEvent(display, event); if (ret != 0) return ret; if (gCurrentlyMappedWindow == 0) return ret; if (event->type != ClientMessage) return ret; if (event->xclient.window != gCurrentlyMappedWindow) return ret; char* const type = XGetAtomName(display, event->xclient.message_type); CARLA_SAFE_ASSERT_RETURN(type != nullptr, 0); if (std::strcmp(type, "WM_PROTOCOLS") != 0) return ret; if ((Atom)event->xclient.data.l[0] != XInternAtom(display, "WM_DELETE_WINDOW", False)) return ret; gCurrentWindowVisible = false; gCurrentWindowMapped = false; if (gInterposedCallback != nullptr) gInterposedCallback(1, nullptr); event->type = 0; carla_stdout("XNextEvent close event caught, hiding UI instead"); return real_XUnmapWindow(display, gCurrentlyMappedWindow); }
static int real_XNextEvent(Display* display, XEvent* event) { static const XNextEventFunc func = (XNextEventFunc)::dlsym(RTLD_NEXT, "XNextEvent"); CARLA_SAFE_ASSERT_RETURN(func != nullptr, 0); return func(display, event); }
bool msgReceived(const char* const msg) noexcept override { if (CarlaExternalUI::msgReceived(msg)) return true; if (std::strcmp(msg, "control") == 0) { uint32_t param; float value; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(param), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value), true); try { uiParameterChanged(param, value); } catch(...) {} return true; } if (std::strcmp(msg, "program") == 0) { uint32_t channel, bank, program; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(channel), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(bank), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(program), true); CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, true); try { uiMidiProgramChanged(channel, bank, program); } catch(...) {} return true; } if (std::strcmp(msg, "configure") == 0) { const char* key; const char* value; CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(key), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(value), true); try { uiCustomDataChanged(key, value); } catch(...) {} delete[] key; delete[] value; return true; } carla_stderr("msgReceived : %s", msg); return false; }
bool announce(const int pid, const char* const executableName) { CARLA_SAFE_ASSERT_RETURN(pid != 0, false); CARLA_SAFE_ASSERT_RETURN(executableName != nullptr && executableName[0] != '\0', false); const char* const NSM_URL(std::getenv("NSM_URL")); if (NSM_URL == nullptr) return false; const lo_address nsmAddress(lo_address_new_from_url(NSM_URL)); CARLA_SAFE_ASSERT_RETURN(nsmAddress != nullptr, false); const int proto = lo_address_get_protocol(nsmAddress); if (fServerThread == nullptr) { // create new OSC server fServerThread = lo_server_thread_new_with_proto(nullptr, proto, _osc_error_handler); CARLA_SAFE_ASSERT_RETURN(fServerThread != nullptr, false); // register message handlers lo_server_thread_add_method(fServerThread, "/error", "sis", _error_handler, this); lo_server_thread_add_method(fServerThread, "/reply", "ssss", _reply_handler, this); lo_server_thread_add_method(fServerThread, "/nsm/client/open", "sss", _open_handler, this); lo_server_thread_add_method(fServerThread, "/nsm/client/save", "", _save_handler, this); lo_server_thread_add_method(fServerThread, "/nsm/client/session_is_loaded", "", _loaded_handler, this); lo_server_thread_add_method(fServerThread, "/nsm/client/show_optional_gui", "", _show_gui_handler, this); lo_server_thread_add_method(fServerThread, "/nsm/client/hide_optional_gui", "", _hide_gui_handler, this); lo_server_thread_add_method(fServerThread, nullptr, nullptr, _broadcast_handler, this); fServer = lo_server_thread_get_server(fServerThread); fServerURL = lo_server_thread_get_url(fServerThread); } const char* appName = std::getenv("CARLA_NSM_NAME"); if (appName == nullptr) appName = "Carla"; lo_send_from(nsmAddress, fServer, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii", appName, NSM_CLIENT_FEATURES, executableName, NSM_API_VERSION_MAJOR, NSM_API_VERSION_MINOR, pid); lo_address_free(nsmAddress); return true; }
bool msgReceived(const char* const msg) noexcept override { if (CarlaExternalUI::msgReceived(msg)) return true; if (std::strcmp(msg, "control") == 0) { uint32_t param; float value; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(param), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value), true); try { uiParameterChanged(param, value); } CARLA_SAFE_EXCEPTION("uiParameterChanged"); return true; }
static inline const T& carla_fixedValue(const T& min, const T& max, const T& value) noexcept { CARLA_SAFE_ASSERT_RETURN(max > min, max); if (value <= min) return min; if (value >= max) return max; return value; }
bool CarlaBridgeUI::libOpen(const char* const filename) noexcept { CARLA_SAFE_ASSERT_RETURN(fLib == nullptr, false); fLib = lib_open(filename); if (fLib != nullptr) { fLibFilename = filename; return true; } return false; }
/* * Get next power of 2. */ static inline uint32_t carla_nextPowerOf2(uint32_t size) noexcept { CARLA_SAFE_ASSERT_RETURN(size > 0, 0); // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 --size; size |= size >> 1; size |= size >> 2; size |= size >> 4; size |= size >> 8; size |= size >> 16; return ++size; }
CARLA_EXPORT jack_midi_data_t* jack_midi_event_reserve(void* buf, jack_nframes_t frame, size_t size) { JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, nullptr); CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput, nullptr); CARLA_SAFE_ASSERT_RETURN(size < JackMidiPortBuffer::kMaxEventSize, nullptr); // broken jack applicatons, wow... if (size == 0) return nullptr; if (jmidibuf->count >= JackMidiPortBuffer::kMaxEventCount) return nullptr; if (jmidibuf->bufferPoolPos + size >= JackMidiPortBuffer::kBufferPoolSize) return nullptr; jack_midi_data_t* const jmdata = jmidibuf->bufferPool + jmidibuf->bufferPoolPos; jmidibuf->bufferPoolPos += size; jmidibuf->events[jmidibuf->count++] = { frame, size, jmdata }; std::memset(jmdata, 0, size); return jmdata; }
CARLA_EXPORT int jack_midi_event_write(void* buf, jack_nframes_t frame, const jack_midi_data_t* data, size_t size) { JackMidiPortBuffer* const jmidibuf((JackMidiPortBuffer*)buf); CARLA_SAFE_ASSERT_RETURN(jmidibuf != nullptr, EFAULT); CARLA_SAFE_ASSERT_RETURN(! jmidibuf->isInput, EINVAL); CARLA_SAFE_ASSERT_RETURN(size < JackMidiPortBuffer::kMaxEventSize, ENOBUFS); // broken jack applicatons, wow... if (size == 0) return EINVAL; if (jmidibuf->count >= JackMidiPortBuffer::kMaxEventCount) return ENOBUFS; if (jmidibuf->bufferPoolPos + size >= JackMidiPortBuffer::kBufferPoolSize) return ENOBUFS; jack_midi_data_t* const jmdata = jmidibuf->bufferPool + jmidibuf->bufferPoolPos; jmidibuf->bufferPoolPos += size; jmidibuf->events[jmidibuf->count++] = { frame, size, jmdata }; std::memcpy(jmdata, data, size); return 0; }
int main() { const char* const filename = carla_get_library_filename(); CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', 1); const char* const folder = carla_get_library_folder(); CARLA_SAFE_ASSERT_RETURN(folder != nullptr && folder[0] != '\0', 1); const NativePluginDescriptor* const rack = carla_get_native_rack_plugin(); CARLA_SAFE_ASSERT_RETURN(rack != nullptr, 1); const NativePluginDescriptor* const patchbay = carla_get_native_patchbay_plugin(); CARLA_SAFE_ASSERT_RETURN(patchbay != nullptr, 1); const NativeHostDescriptor host = { nullptr, "", // resourceDir "Carla Plugin UI", 0, get_buffer_size, get_sample_rate, is_offline, nullptr, // get_time_info nullptr, // write_midi_event nullptr, // ui_parameter_changed nullptr, // ui_midi_program_changed nullptr, // ui_custom_data_changed nullptr, // ui_closed nullptr, // ui_open_file nullptr, // ui_save_file nullptr, // dispatcher }; const NativePluginHandle handle = rack->instantiate(&host); CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 1); CarlaEngine* const engine = carla_get_native_plugin_engine(rack, handle); CARLA_SAFE_ASSERT_RETURN(engine != nullptr, 1); carla_stdout("Got Engine %p, %s, %i, %f", engine, engine->getName(), engine->getBufferSize(), engine->getSampleRate()); rack->cleanup(handle); return 0; }
/* * Attach to an existing shared memory object. */ static inline carla_shm_t carla_shm_attach(const char* const filename) noexcept { CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', gNullCarlaShm); carla_shm_t ret; #ifdef CARLA_OS_WIN ret.map = INVALID_HANDLE_VALUE; ret.isServer = false; ret.filename = carla_strdup_safe(filename); #else try { ret.fd = ::shm_open(filename, O_RDWR, 0); ret.filename = nullptr; ret.size = 0; } CARLA_SAFE_EXCEPTION_RETURN("carla_shm_attach", gNullCarlaShm); #endif return ret; }
bool CarlaBridgeUI::init(const int argc, const char* argv[]) { CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, false); if (argc == 7) { if (! initPipeClient(argv)) return false; fLastMsgTimer = 0; // wait for ui options for (; ++fLastMsgTimer < 50 && ! fGotOptions;) { idlePipe(true); carla_msleep(20); } if (! fGotOptions) { carla_stderr2("CarlaBridgeUI::init() - did not get options on time, quitting..."); { const CarlaMutexLocker cml(getPipeLock()); writeMessage("exiting\n", 8); flushMessages(); } closePipeClient(); return false; } } if (! fToolkit->init(argc, argv)) { if (argc == 7) closePipeClient(); return false; } return true; }
static inline PluginType getPluginTypeFromString(const char* const ctype) noexcept { CARLA_SAFE_ASSERT_RETURN(ctype != nullptr && ctype[0] != '\0', PLUGIN_NONE); carla_debug("CarlaBackend::getPluginTypeFromString(\"%s\")", ctype); CarlaString stype(ctype); if (stype.isEmpty()) return PLUGIN_NONE; stype.toLower(); if (stype == "none") return PLUGIN_NONE; if (stype == "internal") return PLUGIN_INTERNAL; if (stype == "ladspa") return PLUGIN_LADSPA; if (stype == "dssi") return PLUGIN_DSSI; if (stype == "lv2") return PLUGIN_LV2; if (stype == "vst") return PLUGIN_VST; if (stype == "vst3") return PLUGIN_VST3; if (stype == "au") return PLUGIN_AU; if (stype == "gig") return PLUGIN_GIG; if (stype == "sf2") return PLUGIN_SF2; if (stype == "sfz") return PLUGIN_SFZ; carla_stderr("CarlaBackend::getPluginTypeFromString(\"%s\") - invalid string type", ctype); return PLUGIN_NONE; }
const char* CarlaBridgeUI::libError() const noexcept { CARLA_SAFE_ASSERT_RETURN(fLibFilename.isNotEmpty(), nullptr); return lib_error(fLibFilename); }
bool CarlaBridgeUI::msgReceived(const char* const msg) noexcept { carla_debug("CarlaBridgeUI::msgReceived(\"%s\")", msg); if (! fGotOptions && std::strcmp(msg, "urid") != 0 && std::strcmp(msg, "uiOptions") != 0) { carla_stderr2("CarlaBridgeUI::msgReceived(\"%s\") - invalid message while waiting for options", msg); return true; } if (fLastMsgTimer > 0) --fLastMsgTimer; if (std::strcmp(msg, "control") == 0) { uint32_t index; float value; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value), true); dspParameterChanged(index, value); return true; } if (std::strcmp(msg, "program") == 0) { uint32_t index; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true); dspProgramChanged(index); return true; } if (std::strcmp(msg, "midiprogram") == 0) { uint32_t bank, program; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(bank), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(program), true); dspMidiProgramChanged(bank, program); return true; } if (std::strcmp(msg, "configure") == 0) { const char* key; const char* value; CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(key), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(value), true); dspStateChanged(key, value); delete[] key; delete[] value; return true; } if (std::strcmp(msg, "note") == 0) { bool onOff; uint8_t channel, note, velocity; CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(onOff), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(channel), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(note), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(velocity), true); dspNoteReceived(onOff, channel, note, velocity); return true; } if (std::strcmp(msg, "atom") == 0) { uint32_t index, atomTotalSize; const char* base64atom; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(atomTotalSize), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(base64atom), true); std::vector<uint8_t> chunk(carla_getChunkFromBase64String(base64atom)); delete[] base64atom; CARLA_SAFE_ASSERT_RETURN(chunk.size() >= sizeof(LV2_Atom), true); const LV2_Atom* const atom((const LV2_Atom*)chunk.data()); const uint32_t atomTotalSizeCheck(lv2_atom_total_size(atom)); CARLA_SAFE_ASSERT_RETURN(atomTotalSizeCheck == atomTotalSize, true); CARLA_SAFE_ASSERT_RETURN(atomTotalSizeCheck == chunk.size(), true); dspAtomReceived(index, atom); return true; } if (std::strcmp(msg, "urid") == 0) { uint32_t urid; const char* uri; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(urid), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri), true); if (urid != 0) dspURIDReceived(urid, uri); delete[] uri; return true; } if (std::strcmp(msg, "uiOptions") == 0) { double sampleRate; bool useTheme, useThemeColors; const char* windowTitle; uint64_t transientWindowId; CARLA_SAFE_ASSERT_RETURN(readNextLineAsDouble(sampleRate), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(useTheme), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(useThemeColors), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(windowTitle), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsULong(transientWindowId), true); fGotOptions = true; uiOptionsChanged(sampleRate, useTheme, useThemeColors, windowTitle, static_cast<uintptr_t>(transientWindowId)); delete[] windowTitle; return true; } CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, true); if (std::strcmp(msg, "show") == 0) { fToolkit->show(); return true; } if (std::strcmp(msg, "focus") == 0) { fToolkit->focus(); return true; } if (std::strcmp(msg, "hide") == 0) { fToolkit->hide(); return true; } if (std::strcmp(msg, "quit") == 0) { fQuitReceived = true; fToolkit->quit(); delete fToolkit; fToolkit = nullptr; return true; } if (std::strcmp(msg, "uiTitle") == 0) { const char* title; CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(title), true); fToolkit->setTitle(title); delete[] title; return true; } carla_stderr("CarlaBridgeUI::msgReceived : %s", msg); return false; }
static inline PluginCategory getPluginCategoryFromName(const char* const name) noexcept { CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', PLUGIN_CATEGORY_NONE); carla_debug("CarlaBackend::getPluginCategoryFromName(\"%s\")", name); CarlaString sname(name); if (sname.isEmpty()) return PLUGIN_CATEGORY_NONE; sname.toLower(); // generic tags first if (sname.contains("delay")) return PLUGIN_CATEGORY_DELAY; if (sname.contains("reverb")) return PLUGIN_CATEGORY_DELAY; // filter if (sname.contains("filter")) return PLUGIN_CATEGORY_FILTER; // distortion if (sname.contains("distortion")) return PLUGIN_CATEGORY_DISTORTION; // dynamics if (sname.contains("dynamics")) return PLUGIN_CATEGORY_DYNAMICS; if (sname.contains("amplifier")) return PLUGIN_CATEGORY_DYNAMICS; if (sname.contains("compressor")) return PLUGIN_CATEGORY_DYNAMICS; if (sname.contains("enhancer")) return PLUGIN_CATEGORY_DYNAMICS; if (sname.contains("exciter")) return PLUGIN_CATEGORY_DYNAMICS; if (sname.contains("gate")) return PLUGIN_CATEGORY_DYNAMICS; if (sname.contains("limiter")) return PLUGIN_CATEGORY_DYNAMICS; // modulator if (sname.contains("modulator")) return PLUGIN_CATEGORY_MODULATOR; if (sname.contains("chorus")) return PLUGIN_CATEGORY_MODULATOR; if (sname.contains("flanger")) return PLUGIN_CATEGORY_MODULATOR; if (sname.contains("phaser")) return PLUGIN_CATEGORY_MODULATOR; if (sname.contains("saturator")) return PLUGIN_CATEGORY_MODULATOR; // utility if (sname.contains("utility")) return PLUGIN_CATEGORY_UTILITY; if (sname.contains("analyzer")) return PLUGIN_CATEGORY_UTILITY; if (sname.contains("converter")) return PLUGIN_CATEGORY_UTILITY; if (sname.contains("deesser")) return PLUGIN_CATEGORY_UTILITY; if (sname.contains("mixer")) return PLUGIN_CATEGORY_UTILITY; // common tags if (sname.contains("verb")) return PLUGIN_CATEGORY_DELAY; if (sname.contains("eq")) return PLUGIN_CATEGORY_EQ; if (sname.contains("tool")) return PLUGIN_CATEGORY_UTILITY; return PLUGIN_CATEGORY_NONE; }
void* CarlaBridgeUI::libSymbol(const char* const symbol) const noexcept { CARLA_SAFE_ASSERT_RETURN(fLib != nullptr, nullptr); return lib_symbol<void*>(fLib, symbol); }