/* * Carla Bridge UI * Copyright (C) 2011-2021 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ #include "CarlaBridgeFormat.hpp" #include "CarlaBridgeToolkit.hpp" #include "CarlaBase64Utils.hpp" #include "CarlaProcessUtils.hpp" #include "CarlaMIDI.h" // needed for atom-util #ifndef nullptr # undef NULL # define NULL nullptr #endif #include "lv2/atom-util.h" CARLA_BRIDGE_UI_START_NAMESPACE // --------------------------------------------------------------------- CarlaBridgeFormat::CarlaBridgeFormat() noexcept : CarlaPipeClient(), fQuitReceived(false), fGotOptions(false), fLastMsgTimer(-1), fToolkit(nullptr), fLib(nullptr), fLibFilename(), fBase64ReservedChunk() { carla_debug("CarlaBridgeFormat::CarlaBridgeFormat()"); try { fToolkit = CarlaBridgeToolkit::createNew(this); } CARLA_SAFE_EXCEPTION_RETURN("CarlaBridgeToolkit::createNew",); } CarlaBridgeFormat::~CarlaBridgeFormat() /*noexcept*/ { carla_debug("CarlaBridgeFormat::~CarlaBridgeFormat()"); if (isPipeRunning() && ! fQuitReceived) writeExitingMessageAndWait(); if (fLib != nullptr) { lib_close(fLib); fLib = nullptr; } if (fToolkit != nullptr) { fToolkit->quit(); delete fToolkit; fToolkit = nullptr; } closePipeClient(); } // --------------------------------------------------------------------- bool CarlaBridgeFormat::libOpen(const char* const filename) noexcept { CARLA_SAFE_ASSERT_RETURN(fLib == nullptr, false); fLib = lib_open(filename); fLibFilename = filename; return fLib != nullptr; } void* CarlaBridgeFormat::libSymbol(const char* const symbol) const noexcept { CARLA_SAFE_ASSERT_RETURN(fLib != nullptr, nullptr); return lib_symbol(fLib, symbol); } const char* CarlaBridgeFormat::libError() const noexcept { CARLA_SAFE_ASSERT_RETURN(fLibFilename.isNotEmpty(), nullptr); return lib_error(fLibFilename); } // --------------------------------------------------------------------- bool CarlaBridgeFormat::msgReceived(const char* const msg) noexcept { carla_debug("CarlaBridgeFormat::msgReceived(\"%s\")", msg); if (! fGotOptions && std::strcmp(msg, "urid") != 0 && std::strcmp(msg, "uiOptions") != 0) { carla_stderr2("CarlaBridgeFormat::msgReceived(\"%s\") - invalid message while waiting for options", msg); return true; } if (fLastMsgTimer > 0) --fLastMsgTimer; if (std::strcmp(msg, "atom") == 0) { uint32_t index, atomTotalSize, base64Size; const char* base64atom; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(atomTotalSize), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(base64Size), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(base64atom, false, base64Size), true); carla_getChunkFromBase64String_impl(fBase64ReservedChunk, base64atom); CARLA_SAFE_ASSERT_UINT2_RETURN(fBase64ReservedChunk.size() >= sizeof(LV2_Atom), fBase64ReservedChunk.size(), sizeof(LV2_Atom), true); #ifdef CARLA_PROPER_CPP11_SUPPORT const LV2_Atom* const atom((const LV2_Atom*)fBase64ReservedChunk.data()); #else const LV2_Atom* const atom((const LV2_Atom*)&fBase64ReservedChunk.front()); #endif const uint32_t atomTotalSizeCheck(lv2_atom_total_size(atom)); CARLA_SAFE_ASSERT_UINT2_RETURN(atomTotalSizeCheck == atomTotalSize, atomTotalSizeCheck, atomTotalSize, true); CARLA_SAFE_ASSERT_UINT2_RETURN(atomTotalSizeCheck == fBase64ReservedChunk.size(), atomTotalSizeCheck, fBase64ReservedChunk.size(), true); dspAtomReceived(index, atom); return true; } if (std::strcmp(msg, "urid") == 0) { uint32_t urid, size; const char* uri; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(urid), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(size), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri, false, size), true); if (urid != 0) dspURIDReceived(urid, uri); return true; } 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, "parameter") == 0) { const char* uri; float value; CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri, true), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value), true); dspParameterChanged(uri, 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), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(value, false), true); dspStateChanged(key, value); delete[] key; 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, "uiOptions") == 0) { BridgeFormatOptions opts; uint64_t transientWindowId; CARLA_SAFE_ASSERT_RETURN(readNextLineAsDouble(opts.sampleRate), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(opts.bgColor), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(opts.fgColor), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(opts.uiScale), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(opts.useTheme), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(opts.useThemeColors), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(opts.windowTitle, true), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsULong(transientWindowId), true); opts.transientWindowId = transientWindowId; // we can assume we are not standalone if we got options from controller side opts.isStandalone = false; fGotOptions = true; uiOptionsChanged(opts); delete[] opts.windowTitle; return true; } CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, true); if (std::strcmp(msg, "show") == 0) { fToolkit->show(); fToolkit->focus(); 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, false), true); fToolkit->setTitle(title); return true; } carla_stderr("CarlaBridgeFormat::msgReceived : %s", msg); return false; } // --------------------------------------------------------------------- bool CarlaBridgeFormat::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("CarlaBridgeFormat::init() - did not get options on time, quitting..."); writeExitingMessageAndWait(); closePipeClient(); return false; } } if (! fToolkit->init(argc, argv)) { if (argc == 7) closePipeClient(); return false; } return true; } void CarlaBridgeFormat::exec(const bool showUI) { CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr,); carla_terminateProcessOnParentExit(true); fToolkit->exec(showUI); } // --------------------------------------------------------------------- CARLA_BRIDGE_UI_END_NAMESPACE #include "CarlaPipeUtils.cpp" // ---------------------------------------------------------------------