diff --git a/.vscode/launch.json b/.vscode/launch.json index 22a21e2..f2c3d92 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -113,7 +113,7 @@ // Resolved by CMake Tools: "program": "${command:cmake.launchTargetPath}", - "args": [ "--rate", "48000", "hw:M2" ], + "args": [ "--rate", "48000", "hw:KATANA", "-i","0,1","-o","2,3" ], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/react/public/var/config.json b/react/public/var/config.json index 6dc7986..20919e1 100644 --- a/react/public/var/config.json +++ b/react/public/var/config.json @@ -1,5 +1,5 @@ { - "socket_server_port": 80, + "socket_server_port": 8080, "socket_server_address": "*", "debug": true, "max_upload_size": 1048576, diff --git a/react/src/GxTunerControl.tsx b/react/src/GxTunerControl.tsx index 3238747..ca81fdf 100644 --- a/react/src/GxTunerControl.tsx +++ b/react/src/GxTunerControl.tsx @@ -94,6 +94,7 @@ type GxTunerControlState = { pitchInfo: PitchInfo tet: number; refFrequency: number; + animationTime: number; }; const GxTunerControl = @@ -119,6 +120,7 @@ const GxTunerControl = fraction: 0, semitoneCents: 100}, tet: 12, + animationTime: 0, refFrequency: 440 }; @@ -204,6 +206,38 @@ const GxTunerControl = this.setState({ pitchInfo: pitchInfo }); + if (value === 0) + { + this.startAnimationTimer(); + } else { + this.cancelAnimationTimer(); + } + } + + animationTimer?: NodeJS.Timeout = undefined; + + cancelAnimationTimer(): void { + if (this.animationTimer) + { + clearTimeout(this.animationTimer); + this.animationTimer = undefined; + } + } + + + startAnimationTimer(): void { + if (!this.animationTimer) + { + this.animationTimer = setInterval( + () => { + this.setState({ + animationTime: new Date().getTime() + }); + }, + 1000/30 + ); + } + } subscribedInstanceId: number = -1; @@ -251,6 +285,7 @@ const GxTunerControl = { this.model.state.removeOnChangedHandler(this.onStateChanged); this.removeSubscription(); + this.cancelAnimationTimer(); } @@ -295,7 +330,7 @@ const GxTunerControl = let cents: number; if (!pitchInfo.valid) { - const NEEDLE_DECAY_RATE_PER_MS = -25/100; + const NEEDLE_DECAY_RATE_PER_MS = -50*7/1000; // animate to zero position. let time = new Date().getTime(); @@ -306,6 +341,7 @@ const GxTunerControl = { cents = -maxCents; this.animationIdle = true; + this.cancelAnimationTimer(); } else { this.animationIdle = false; } diff --git a/react/src/JackServerSettings.tsx b/react/src/JackServerSettings.tsx index 59b5835..a967217 100644 --- a/react/src/JackServerSettings.tsx +++ b/react/src/JackServerSettings.tsx @@ -22,6 +22,7 @@ export default class JackServerSettings { deserialize(input: any) : JackServerSettings{ this.valid = input.valid; + this.isJackAudio = input.isJackAudio; this.rebootRequired = input.rebootRequired; this.alsaDevice = input.alsaDevice?? ""; this.sampleRate = input.sampleRate; @@ -44,6 +45,7 @@ export default class JackServerSettings { } valid: boolean = false; rebootRequired = false; + isJackAudio = false; alsaDevice: string = ""; sampleRate = 48000; bufferSize = 64; diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index a49bf3c..ea7bf58 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.cpp @@ -582,7 +582,7 @@ namespace pipedal { int err; - alsa_device_name = jackServerSettings.GetAlsaDevice(); + alsa_device_name = jackServerSettings.GetAlsaInputDevice(); this->numberOfBuffers = jackServerSettings.GetNumberOfBuffers(); this->bufferSize = jackServerSettings.GetBufferSize(); @@ -1506,7 +1506,7 @@ namespace pipedal snd_pcm_t *captureHandle = nullptr; snd_pcm_hw_params_t *playbackHwParams = nullptr; snd_pcm_hw_params_t *captureHwParams = nullptr; - std::string alsaDeviceName = jackServerSettings.GetAlsaDevice(); + std::string alsaDeviceName = jackServerSettings.GetAlsaInputDevice(); bool result = false; try diff --git a/src/JackServerSettings.cpp b/src/JackServerSettings.cpp index b641741..15115d7 100644 --- a/src/JackServerSettings.cpp +++ b/src/JackServerSettings.cpp @@ -241,6 +241,7 @@ void JackServerSettings::Write() JSON_MAP_BEGIN(JackServerSettings) JSON_MAP_REFERENCE(JackServerSettings, valid) JSON_MAP_REFERENCE(JackServerSettings, rebootRequired) +JSON_MAP_REFERENCE(JackServerSettings, isJackAudio) JSON_MAP_REFERENCE(JackServerSettings, alsaDevice) JSON_MAP_REFERENCE(JackServerSettings, sampleRate) JSON_MAP_REFERENCE(JackServerSettings, bufferSize) diff --git a/src/JackServerSettings.hpp b/src/JackServerSettings.hpp index 0e81c99..61b31aa 100644 --- a/src/JackServerSettings.hpp +++ b/src/JackServerSettings.hpp @@ -20,11 +20,15 @@ #pragma once #include #include "json.hpp" +#include "AudioConfig.hpp" -namespace pipedal { +namespace pipedal +{ // Jack Daemon configuration. - class JackServerSettings { + class JackServerSettings + { bool valid_ = false; + bool isJackAudio_ = JACK_HOST ? true : false; bool rebootRequired_ = false; std::string alsaDevice_; uint64_t sampleRate_ = 0; @@ -33,20 +37,21 @@ namespace pipedal { public: JackServerSettings(); - JackServerSettings(const std::string alsaDevice, uint64_t sampleRate, uint32_t bufferSize, uint32_t numberOfBuffers) - : valid_(true), - alsaDevice_(alsaDevice), - sampleRate_(sampleRate), - bufferSize_(bufferSize), - numberOfBuffers_(numberOfBuffers) + JackServerSettings( + const std::string alsaInputDevice, + uint64_t sampleRate, uint32_t bufferSize, uint32_t numberOfBuffers) + : valid_(true), + alsaDevice_(alsaInputDevice), + sampleRate_(sampleRate), + bufferSize_(bufferSize), + numberOfBuffers_(numberOfBuffers) { - } uint64_t GetSampleRate() const { return sampleRate_; } uint32_t GetBufferSize() const { return bufferSize_; } uint32_t GetNumberOfBuffers() const { return numberOfBuffers_; } - const std::string&GetAlsaDevice() const { return alsaDevice_; } + const std::string &GetAlsaInputDevice() const { return alsaDevice_; } void ReadJackConfiguration(); @@ -56,22 +61,20 @@ namespace pipedal { { this->valid_ = true; this->rebootRequired_ = true; - this->sampleRate_ = sampleRate; this->bufferSize_ = bufferSize; this->numberOfBuffers_ = numberOfBuffers; + this->sampleRate_ = sampleRate; + this->bufferSize_ = bufferSize; + this->numberOfBuffers_ = numberOfBuffers; } void Write(); // requires root perms. void SetRebootRequired(bool value) { rebootRequired_ = value; } - bool Equals(const JackServerSettings&other) + bool Equals(const JackServerSettings &other) { - return this->sampleRate_ == other.sampleRate_ - && this->bufferSize_ == other.bufferSize_ - && this->numberOfBuffers_ == other.numberOfBuffers_; + return this->alsaDevice_ == other.alsaDevice_ && this->sampleRate_ == other.sampleRate_ && this->bufferSize_ == other.bufferSize_ && this->numberOfBuffers_ == other.numberOfBuffers_; } - DECLARE_JSON_MAP(JackServerSettings); - }; } // namespace \ No newline at end of file diff --git a/src/PiLatencyMain.cpp b/src/PiLatencyMain.cpp index 1052052..11c0b36 100644 --- a/src/PiLatencyMain.cpp +++ b/src/PiLatencyMain.cpp @@ -23,6 +23,7 @@ */ #include "CommandLineParser.hpp" +#include "ss.hpp" #include "PrettyPrinter.hpp" #include #include "PiPedalAlsa.hpp" @@ -40,7 +41,8 @@ constexpr int E_XRUN = 3; constexpr uint64_t NO_SIGNAL_VALUE = 0x7000000; -struct TestResult { +struct TestResult +{ int error = 0; uint64_t latency = 0; float cpuOverhead = 0; @@ -62,6 +64,11 @@ void PrintHelp() << "List available devices.\n\n"; pp << HangingIndent() << " -r --rate\t" << "Sample rate (default 48000).\n\n"; + pp << HangingIndent() << " -i --in_channels\t" + << "Input channels. Command-seperated list. e.g.: 0,3. Default: all channels.\n\n"; + pp << HangingIndent() << " -o --out_channels\t" + << "Output channels. Command-seperated list. e.g.: 0,1,4. Default: all channels.\n\n"; + pp << HangingIndent() << " -h --help\t" << "Display this message.\n\n"; @@ -107,6 +114,9 @@ void ListDevices() } } + +using ChannelsT = std::vector; + class AlsaTester : private AudioDriverHost { public: @@ -121,14 +131,22 @@ private: AudioDriver *audioDriver = nullptr; const std::string &deviceId; + ChannelsT inputChannels; + ChannelsT outputChannels; uint32_t sampleRate; int bufferSize; int buffers; public: - AlsaTester(const std::string &deviceId, uint32_t sampleRate, int bufferSize, int buffers) + AlsaTester( + const std::string &deviceId, + const ChannelsT &inputChannels, + const ChannelsT &outputChannels, + uint32_t sampleRate, int bufferSize, int buffers) : deviceId(deviceId), sampleRate(sampleRate), + inputChannels(inputChannels), + outputChannels(outputChannels), bufferSize(bufferSize), buffers(buffers) { @@ -139,6 +157,21 @@ public: delete[] inputBuffers; delete[] outputBuffers; } + std::vector SelectChannels(const std::vector&available, const std::vector& selection) + { + if (selection.size() == 0) return available; + + std::vector result; + for (int sel: selection) + { + if (sel < 0 || sel >= available.size()) + { + throw PiPedalArgumentException(SS("Invalid channel: " + sel)); + } + result.push_back(available[sel]); + } + return result; + } TestResult Test() { @@ -150,9 +183,17 @@ public: JackConfiguration jackConfiguration; jackConfiguration.AlsaInitialize(serverSettings); + auto & availableInputs = jackConfiguration.GetInputAudioPorts(); + auto & availableOutputs = jackConfiguration.GetOutputAudioPorts(); + + + std::vector inputAudioPorts, outputAudioPorts; + + inputAudioPorts = SelectChannels(availableInputs,this->inputChannels); + outputAudioPorts = SelectChannels(availableOutputs,this->outputChannels); + JackChannelSelection channelSelection( - jackConfiguration.GetInputAudioPorts(), - jackConfiguration.GetOutputAudioPorts(), + inputAudioPorts, outputAudioPorts, std::vector()); audioDriver = CreateAlsaDriver(this); @@ -176,11 +217,11 @@ public: if (this->GetXruns() != 0) { - result.error = E_XRUN; + result.error = E_XRUN; return result; } - result.latency = latencyMonitor.GetLatency(); - if (result.latency == NO_SIGNAL_VALUE) + result.latency = latencyMonitor.GetLatency(); + if (result.latency == NO_SIGNAL_VALUE) { result.error = E_NOSIGNAL; } @@ -267,7 +308,7 @@ public: state = State::Waiting; current_latency = 0; } - return 0.01; + return 0.001; } break; case State::Waiting: @@ -349,9 +390,13 @@ public: } }; -TestResult RunLatencyTest(const std::string deviceId, uint32_t sampleRate, int bufferSize, int buffers) +TestResult RunLatencyTest( + const std::string deviceId, + const ChannelsT &inputChannels, + const ChannelsT &outputChannels, + uint32_t sampleRate, int bufferSize, int buffers) { - AlsaTester tester(deviceId, sampleRate, bufferSize, buffers); + AlsaTester tester(deviceId, inputChannels, outputChannels, sampleRate, bufferSize, buffers); return tester.Test(); } @@ -360,7 +405,7 @@ static std::string msDisplay(float value) std::stringstream s; s << fixed; s.precision(1); - s << value << "ms"; + s << value << "ms"; return s.str(); } static std::string overheadDisplay(float value) @@ -370,7 +415,11 @@ static std::string overheadDisplay(float value) return s.str(); } -void RunLatencyTest(const std::string &deviceId, uint32_t sampleRate) +void RunLatencyTest( + const std::string &deviceId, + const ChannelsT &inputChannels, + const ChannelsT &outputChannels, + uint32_t sampleRate) { PrettyPrinter pp; pp << "Device: " << deviceId << " Rate: " << sampleRate << "\n\n"; @@ -400,7 +449,7 @@ void RunLatencyTest(const std::string &deviceId, uint32_t sampleRate) for (auto bufferCount : bufferCounts) { - auto result = RunLatencyTest(deviceId, sampleRate, bufferSize, bufferCount); + auto result = RunLatencyTest(deviceId, inputChannels,outputChannels, sampleRate, bufferSize, bufferCount); pp.Column(column); column += BUFFERS_COLUMN_WIDTH; @@ -419,7 +468,7 @@ void RunLatencyTest(const std::string &deviceId, uint32_t sampleRate) default: { float ms = 1000.0f * result.latency / sampleRate; - pp << result.latency << "/" << msDisplay(ms) ; + pp << result.latency << "/" << msDisplay(ms); break; } } @@ -428,6 +477,39 @@ void RunLatencyTest(const std::string &deviceId, uint32_t sampleRate) } } + +ChannelsT ParseChannels(const std::string&channels) +{ + ChannelsT result; + std::stringstream s(channels); + + while (true) + { + int c = s.peek(); + if (c == -1) break; + + if (c == ',') { + s.get(); + c = s.peek(); + } + if (c < '0' || c > '9') + { + throw PiPedalArgumentException("Invalid channel selection: " + channels); + } + int v = 0; + while (s.peek() >= '0' && s.peek() <= '9') + { + c = s.get(); + v = v*10 + c-'0'; + } + result.push_back(v); + } + + return result; + + +} + int main(int argc, const char **argv) { @@ -439,10 +521,16 @@ int main(int argc, const char **argv) bool listDevices = false; bool help = false; uint32_t sampleRate = 48000; +std: + string strInputChannels, strOutputChannels; + + ChannelsT inputChannels, outputChannels; parser.AddOption("l", "list", &listDevices); parser.AddOption("h", "help", &help); parser.AddOption("r", "rate", &sampleRate); + parser.AddOption("i", "in_channels", &strInputChannels); + parser.AddOption("o", "out_channels", &strOutputChannels); try { @@ -458,7 +546,9 @@ int main(int argc, const char **argv) } else if (parser.Arguments().size() == 1) { - RunLatencyTest(parser.Arguments()[0], sampleRate); + inputChannels = ParseChannels(strInputChannels); + outputChannels = ParseChannels(strInputChannels); + RunLatencyTest(parser.Arguments()[0], inputChannels, outputChannels, sampleRate); } else { diff --git a/src/PiPedalSocket.cpp b/src/PiPedalSocket.cpp index 094b467..91b0095 100644 --- a/src/PiPedalSocket.cpp +++ b/src/PiPedalSocket.cpp @@ -24,6 +24,7 @@ #include "viewstream.hpp" #include "PiPedalVersion.hpp" #include +#include #include "Lv2Log.hpp" #include "JackConfiguration.hpp" #include @@ -41,14 +42,13 @@ using namespace std; using namespace pipedal; - -class NotifyMidiListenerBody { +class NotifyMidiListenerBody +{ public: int64_t clientHandle_; bool isNote_; int32_t noteOrControl_; DECLARE_JSON_MAP(NotifyMidiListenerBody); - }; JSON_MAP_BEGIN(NotifyMidiListenerBody) JSON_MAP_REFERENCE(NotifyMidiListenerBody, clientHandle) @@ -56,7 +56,8 @@ JSON_MAP_REFERENCE(NotifyMidiListenerBody, isNote) JSON_MAP_REFERENCE(NotifyMidiListenerBody, noteOrControl) JSON_MAP_END() -class NotifyAtomOutputBody { +class NotifyAtomOutputBody +{ public: int64_t clientHandle_; uint64_t instanceId_; @@ -71,8 +72,9 @@ JSON_MAP_REFERENCE(NotifyAtomOutputBody, instanceId) JSON_MAP_REFERENCE(NotifyAtomOutputBody, atomJson) JSON_MAP_END() -class ListenForMidiEventBody { -public: +class ListenForMidiEventBody +{ +public: bool listenForControlsOnly_; int64_t handle_; DECLARE_JSON_MAP(ListenForMidiEventBody); @@ -83,8 +85,9 @@ JSON_MAP_REFERENCE(ListenForMidiEventBody, listenForControlsOnly) JSON_MAP_REFERENCE(ListenForMidiEventBody, handle) JSON_MAP_END() -class ListenForAtomOutputBody { -public: +class ListenForAtomOutputBody +{ +public: uint64_t instanceId_; int64_t handle_; DECLARE_JSON_MAP(ListenForAtomOutputBody); @@ -95,9 +98,9 @@ JSON_MAP_REFERENCE(ListenForAtomOutputBody, instanceId) JSON_MAP_REFERENCE(ListenForAtomOutputBody, handle) JSON_MAP_END() - -class OnLoadPluginPresetBody { -public: +class OnLoadPluginPresetBody +{ +public: int64_t instanceId_; std::vector controlValues_; DECLARE_JSON_MAP(OnLoadPluginPresetBody); @@ -108,8 +111,9 @@ JSON_MAP_REFERENCE(OnLoadPluginPresetBody, instanceId) JSON_MAP_REFERENCE(OnLoadPluginPresetBody, controlValues) JSON_MAP_END() -class LoadPluginPresetBody { -public: +class LoadPluginPresetBody +{ +public: uint64_t pluginInstanceId_; uint64_t presetInstanceId_; DECLARE_JSON_MAP(LoadPluginPresetBody); @@ -147,7 +151,6 @@ JSON_MAP_REFERENCE(MonitorResultBody, subscriptionHandle) JSON_MAP_REFERENCE(MonitorResultBody, value) JSON_MAP_END() - class GetLv2ParameterBody { public: @@ -204,15 +207,15 @@ JSON_MAP_REFERENCE(SavePluginPresetAsBody, instanceId) JSON_MAP_REFERENCE(SavePluginPresetAsBody, name) JSON_MAP_END() -class RenameBankBody { +class RenameBankBody +{ public: int64_t bankId_; std::string newName_; DECLARE_JSON_MAP(RenameBankBody); - }; JSON_MAP_BEGIN(RenameBankBody) -JSON_MAP_REFERENCE(RenameBankBody,bankId) +JSON_MAP_REFERENCE(RenameBankBody, bankId) JSON_MAP_REFERENCE(RenameBankBody, newName) JSON_MAP_END() @@ -332,15 +335,11 @@ JSON_MAP_REFERENCE(ControlChangedBody, symbol) JSON_MAP_REFERENCE(ControlChangedBody, value) JSON_MAP_END() - - - - - class PiPedalSocketHandler : public SocketHandler, public IPiPedalModelSubscriber { private: - AdminClient& GetAdminClient() const { + AdminClient &GetAdminClient() const + { return model.GetAdminClient(); } void RequestShutdown(bool restart); @@ -364,8 +363,11 @@ private: { int64_t subscriptionHandle = -1; int64_t instanceId = -1; - bool waitingForAck = false; std::string key; + + float lastSentValue = 0; + bool pendingValue = false; + bool waitingForAck = false; }; std::vector activePortMonitors; @@ -396,9 +398,9 @@ public: : model(model), clientId(++nextClientId) { std::stringstream imageList; - const std::filesystem::path& webRoot = model.GetWebRoot() / "img"; + const std::filesystem::path &webRoot = model.GetWebRoot() / "img"; bool firstTime = true; - for (const auto&entry: std::filesystem::directory_iterator(webRoot)) + for (const auto &entry : std::filesystem::directory_iterator(webRoot)) { if (!firstTime) { @@ -407,7 +409,7 @@ public: firstTime = false; imageList << entry.path().filename().string(); } - this->imageList = imageList.str(); + this->imageList = imageList.str(); } private: @@ -637,40 +639,89 @@ public: Reply(replyTo, "error", what); } - bool waitingForPortMonitorAck(uint64_t subscriptionId) + PortMonitorSubscription *getPortMonitorSubscription(uint64_t subscriptionId) { + for (int i = 0; i < this->activePortMonitors.size(); ++i) { - std::lock_guard guard(subscriptionMutex); - for (int i = 0; i < this->activePortMonitors.size(); ++i) + auto *portMonitor = &activePortMonitors[i]; + if (portMonitor->subscriptionHandle == subscriptionId) { - auto &portMonitor = activePortMonitors[i]; - if (portMonitor.subscriptionHandle == subscriptionId) - { - if (portMonitor.waitingForAck) - return true; - portMonitor.waitingForAck = true; - return false; - } + return portMonitor; } } - return true; // subscription has been closed. don't sent to client. + return nullptr; } - void portMonitorAck(uint64_t subscriptionId) + + void SendMonitorPortMessage(PortMonitorSubscription *subscription, float value) { - { - std::lock_guard guard(subscriptionMutex); - for (int i = 0; i < this->activePortMonitors.size(); ++i) + + auto subscriptionHandle_ = subscription->subscriptionHandle; + MonitorResultBody body; + body.subscriptionHandle_ = subscriptionHandle_; + body.value_ = value; + this->Request( // send the message and wait for a response. + "onMonitorPortOutput", + body, + [this, subscriptionHandle_](const bool &result) { - auto &portMonitor = activePortMonitors[i]; - if (portMonitor.subscriptionHandle == subscriptionId) + PortMonitorSubscription *subscription = getPortMonitorSubscription(subscriptionHandle_); + if (subscription == nullptr) return; + + if (subscription->pendingValue) { - portMonitor.waitingForAck = false; - break; + subscription->pendingValue = false; + SendMonitorPortMessage(subscription, subscription->lastSentValue); + } + else + { + subscription->waitingForAck = false; + } + }, + [](const std::exception &e) + { + Lv2Log::debug("Failed to monitor port output. (%s)", e.what()); + }); + } + void MonitorPort(int replyTo,MonitorPortBody &body) + { + std::lock_guard guard(subscriptionMutex); + int64_t subscriptionHandle = model.MonitorPort( + body.instanceId_, + body.key_, + body.updateRate_, + [this](int64_t subscriptionHandle_, float value) + { + PortMonitorSubscription *subscription = getPortMonitorSubscription(subscriptionHandle_); + + if (subscription) + { + if (subscription->waitingForAck) + { + if (subscription->lastSentValue != value) + { + subscription->lastSentValue = value; + subscription->pendingValue = true; + } + } + else + { + subscription->lastSentValue = value; + + subscription->waitingForAck = true; + SendMonitorPortMessage(subscription, value); + } } } - } + + ); + activePortMonitors.push_back( + PortMonitorSubscription{subscriptionHandle, body.instanceId_, body.key_}); + + this->Reply(replyTo, "monitorPort", subscriptionHandle); } + /***********************/ + void handleMessage(int reply, int replyTo, const std::string &message, json_reader *pReader) { if (reply != -1) @@ -723,66 +774,66 @@ public: { ListenForMidiEventBody body; pReader->read(&body); - this->model.ListenForMidiEvent(this->clientId,body.handle_, body.listenForControlsOnly_); + this->model.ListenForMidiEvent(this->clientId, body.handle_, body.listenForControlsOnly_); } else if (message == "cancelListenForMidiEvent") { uint64_t handle; pReader->read(&handle); - this->model.CancelListenForMidiEvent(this->clientId,handle); + this->model.CancelListenForMidiEvent(this->clientId, handle); } else if (message == "listenForAtomOutput") { ListenForAtomOutputBody body; pReader->read(&body); - this->model.ListenForAtomOutputs(this->clientId,body.handle_, body.instanceId_); + this->model.ListenForAtomOutputs(this->clientId, body.handle_, body.instanceId_); } else if (message == "cancelListenForAtomOutput") { int64_t handle; pReader->read(&handle); - this->model.CancelListenForMidiEvent(this->clientId,handle); + this->model.CancelListenForMidiEvent(this->clientId, handle); } else if (message == "getJackStatus") { JackHostStatus status = model.GetJackStatus(); - this->Reply(replyTo,"getJackStatus",status); - } else if (message == "getAlsaDevices") + this->Reply(replyTo, "getJackStatus", status); + } + else if (message == "getAlsaDevices") { std::vector devices = model.GetAlsaDevices(); - this->Reply(replyTo,"getAlsaDevices",devices); - - - } else if (message == "getWifiChannels") + this->Reply(replyTo, "getAlsaDevices", devices); + } + else if (message == "getWifiChannels") { std::string country; pReader->read(&country); std::vector channels = pipedal::getWifiChannels(country.c_str()); - this->Reply(replyTo,"getWifiChannels",channels); + this->Reply(replyTo, "getWifiChannels", channels); } else if (message == "getPluginPresets") { std::string uri; pReader->read(&uri); - this->Reply(replyTo,"getPluginPresets",this->model.GetPluginUiPresets(uri)); + this->Reply(replyTo, "getPluginPresets", this->model.GetPluginUiPresets(uri)); } else if (message == "loadPluginPreset") { LoadPluginPresetBody body; pReader->read(&body); - this->model.LoadPluginPreset(body.pluginInstanceId_,body.presetInstanceId_); - + this->model.LoadPluginPreset(body.pluginInstanceId_, body.presetInstanceId_); } - else if (message == "setJackServerSettings") { + else if (message == "setJackServerSettings") + { JackServerSettings jackServerSettings; pReader->read(&jackServerSettings); this->model.SetJackServerSettings(jackServerSettings); - this->Reply(replyTo,"setJackserverSettings"); - + this->Reply(replyTo, "setJackserverSettings"); } - else if (message == "setGovernorSettings") { - std::string governor; + else if (message == "setGovernorSettings") + { + std::string governor; pReader->read(&governor); std::string fromAddress = this->getFromAddress(); if (!IsOnLocalSubnet(fromAddress)) @@ -790,9 +841,10 @@ public: throw PiPedalException("Permission denied. Not on local subnet."); } this->model.SetGovernorSettings(governor); - this->Reply(replyTo,"setGovernorSettings"); + this->Reply(replyTo, "setGovernorSettings"); } - else if (message == "setWifiConfigSettings") { + else if (message == "setWifiConfigSettings") + { WifiConfigSettings wifiConfigSettings; pReader->read(&wifiConfigSettings); if (!GetAdminClient().CanUseShutdownClient()) @@ -805,15 +857,15 @@ public: throw PiPedalException("Permission denied. Not on local subnet."); } - this->model.SetWifiConfigSettings(wifiConfigSettings); - this->Reply(replyTo,"setWifiConfigSettings"); + this->Reply(replyTo, "setWifiConfigSettings"); } - else if (message == "getWifiConfigSettings") { + else if (message == "getWifiConfigSettings") + { this->Reply(replyTo, "getWifiConfigSettings", model.GetWifiConfigSettings()); - } - else if (message == "setWifiDirectConfigSettings") { + else if (message == "setWifiDirectConfigSettings") + { WifiDirectConfigSettings wifiDirectConfigSettings; pReader->read(&wifiDirectConfigSettings); if (!GetAdminClient().CanUseShutdownClient()) @@ -826,28 +878,27 @@ public: throw PiPedalException("Permission denied. Not on local subnet."); } - this->model.SetWifiDirectConfigSettings(wifiDirectConfigSettings); - this->Reply(replyTo,"setWifiDirectConfigSettings"); + this->Reply(replyTo, "setWifiDirectConfigSettings"); } - else if (message == "getWifiDirectConfigSettings") { + else if (message == "getWifiDirectConfigSettings") + { this->Reply(replyTo, "getWifiDirectConfigSettings", model.GetWifiDirectConfigSettings()); - } - else if (message == "getGovernorSettings") { + else if (message == "getGovernorSettings") + { this->Reply(replyTo, "getGovernorSettings", model.GetGovernorSettings()); - } - else if (message == "getJackServerSettings") { + else if (message == "getJackServerSettings") + { this->Reply(replyTo, "getJackServerSettings", model.GetJackServerSettings()); - } - else if (message == "getBankIndex") { + else if (message == "getBankIndex") + { BankIndex bankIndex = model.GetBankIndex(); this->Reply(replyTo, "getBankIndex", bankIndex); - } else if (message == "getJackConfiguration") { @@ -932,7 +983,7 @@ public: } else if (message == "getShowStatusMonitor") { - Reply(replyTo,"getShowStatusMonitor",this->model.GetShowStatusMonitor()); + Reply(replyTo, "getShowStatusMonitor", this->model.GetShowStatusMonitor()); } else if (message == "version") { @@ -970,15 +1021,15 @@ public: else if (message == "shutdown") { PresetIndex newIndex; - + RequestShutdown(false); - this->Reply(replyTo,"shutdown"); + this->Reply(replyTo, "shutdown"); } else if (message == "restart") { PresetIndex newIndex; RequestShutdown(true); - this->Reply(replyTo,"restart"); + this->Reply(replyTo, "restart"); } else if (message == "deletePresetItem") { @@ -1007,40 +1058,46 @@ public: json_reader tReader(tIn); std::string tResult; tReader.read(&tResult); - + body.newName_ = tResult; - - try { - model.RenameBank(this->clientId,body.bankId_, body.newName_); - this->Reply(replyTo, "renameBank"); - } catch (const std::exception &e) + try { - this->SendError(replyTo,std::string(e.what())); + model.RenameBank(this->clientId, body.bankId_, body.newName_); + this->Reply(replyTo, "renameBank"); + } + catch (const std::exception &e) + { + this->SendError(replyTo, std::string(e.what())); } } else if (message == "openBank") { int64_t bankId = -1; pReader->read(&bankId); - try { - model.OpenBank(this->clientId,bankId);; - this->Reply(replyTo, "openBank"); - } catch (const std::exception &e) + try { - this->SendError(replyTo,std::string(e.what())); + model.OpenBank(this->clientId, bankId); + ; + this->Reply(replyTo, "openBank"); + } + catch (const std::exception &e) + { + this->SendError(replyTo, std::string(e.what())); } } else if (message == "saveBankAs") { RenameBankBody body; pReader->read(&body); - try { - int64_t newId = model.SaveBankAs(this->clientId,body.bankId_, body.newName_); - this->Reply(replyTo, "saveBankAs",newId); - } catch (const std::exception &e) + try { - this->SendError(replyTo,std::string(e.what())); + int64_t newId = model.SaveBankAs(this->clientId, body.bankId_, body.newName_); + this->Reply(replyTo, "saveBankAs", newId); + } + catch (const std::exception &e) + { + this->SendError(replyTo, std::string(e.what())); } } else if (message == "renamePresetItem") @@ -1057,31 +1114,31 @@ public: pReader->read(&body); int64_t result = model.CopyPreset(body.clientId_, body.fromId_, body.toId_); this->Reply(replyTo, "copyPreset", result); - } + } else if (message == "copyPluginPreset") { CopyPluginPresetBody body; pReader->read(&body); - uint64_t result = model.CopyPluginPreset(body.pluginUri_,body.instanceId_); + uint64_t result = model.CopyPluginPreset(body.pluginUri_, body.instanceId_); this->Reply(replyTo, "copyPluginPreset", result); - } - else if (message =="getLv2Parameter") + } + else if (message == "getLv2Parameter") { GetLv2ParameterBody body; pReader->read(&body); - + model.GetLv2Parameter( this->clientId, body.instanceId_, body.uri_, - [this,replyTo] (const std::string &jsonResult) + [this, replyTo](const std::string &jsonResult) { - this->JsonReply(replyTo,"getLv2Parameter",jsonResult.c_str()); + this->JsonReply(replyTo, "getLv2Parameter", jsonResult.c_str()); }, - [this,replyTo] (const std::string &error) { - this->SendError(replyTo,error.c_str()); + [this, replyTo](const std::string &error) + { + this->SendError(replyTo, error.c_str()); }); - } else if (message == "monitorPort") { @@ -1089,38 +1146,7 @@ public: MonitorPortBody body; pReader->read(&body); - int64_t subscriptionHandle = model.MonitorPort( - body.instanceId_, - body.key_, - body.updateRate_, - [this](int64_t subscriptionHandle_, float value) - { - MonitorResultBody body; - body.subscriptionHandle_ = subscriptionHandle_; - body.value_ = value; - if (!waitingForPortMonitorAck(subscriptionHandle_)) //only one outstanding response. - { - this->Request( // send the message and wait for a response. - "onMonitorPortOutput", - body, - [this, subscriptionHandle_](const bool &result) - { - this->portMonitorAck(subscriptionHandle_); // please can we have some more. - - }, - [](const std::exception &e) - { - Lv2Log::debug("Failed to monitor port output. (%s)", e.what()); - }); - } - }); - { - std::lock_guard guard(subscriptionMutex); - activePortMonitors.push_back( - PortMonitorSubscription{subscriptionHandle, body.instanceId_,false, body.key_}); - } - - this->Reply(replyTo, "monitorPort", subscriptionHandle); + MonitorPort(replyTo,body); } else if (message == "unmonitorPort") { @@ -1175,16 +1201,17 @@ public: } else if (message == "imageList") { - - this->Reply(replyTo, "imageList", imageList); - } else if (message == "getFavorites") - { - std::map favorites = this->model.GetFavorites(); - this->Reply(replyTo,"getFavorites",favorites); - } else if (message == "setFavorites") + this->Reply(replyTo, "imageList", imageList); + } + else if (message == "getFavorites") { - std::map favorites; + std::map favorites = this->model.GetFavorites(); + this->Reply(replyTo, "getFavorites", favorites); + } + else if (message == "setFavorites") + { + std::map favorites; pReader->read(&favorites); this->model.SetFavorites(favorites); } @@ -1254,20 +1281,21 @@ protected: { SendError(replyTo, e.what()); } - catch (const std::exception & e) + catch (const std::exception &e) { SendError(replyTo, e.what()); } } public: - virtual void OnFavoritesChanged(const std::map &favorites) + virtual void OnFavoritesChanged(const std::map &favorites) { - Send("onFavoritesChanged",favorites); + Send("onFavoritesChanged", favorites); } - virtual void OnShowStatusMonitorChanged(bool show) { - Send("onShowStatusMonitorChanged",show); + virtual void OnShowStatusMonitorChanged(bool show) + { + Send("onShowStatusMonitorChanged", show); } virtual void OnChannelSelectionChanged(int64_t clientId, const JackChannelSelection &channelSelection) @@ -1284,7 +1312,7 @@ public: body.presets_ = const_cast(&presets); Send("onPresetsChanged", body); } - virtual void OnPluginPresetsChanged(const std::string&pluginUri) + virtual void OnPluginPresetsChanged(const std::string &pluginUri) { Send("onPluginPresetsChanged", pluginUri); } @@ -1293,14 +1321,14 @@ public: Send("onJackConfigurationChanged", jackConfiguration); } - virtual void OnLoadPluginPreset(int64_t instanceId,const std::vector&controlValues) { + virtual void OnLoadPluginPreset(int64_t instanceId, const std::vector &controlValues) + { OnLoadPluginPresetBody body; body.instanceId_ = instanceId; - body.controlValues_ = const_cast&>(controlValues); - Send("onLoadPluginPreset",body); + body.controlValues_ = const_cast &>(controlValues); + Send("onLoadPluginPreset", body); } - int updateRequestOutstanding = 0; bool vuUpdateDropped = false; @@ -1359,7 +1387,8 @@ public: Send("onControlChanged", body); } - class DeferredValue { + class DeferredValue + { public: int64_t instanceId; std::string symbol; @@ -1369,11 +1398,12 @@ public: std::vector deferredValues; bool midiValueChangedOutstanding = false; - - virtual void OnMidiValueChanged(int64_t instanceId, const std::string&symbol, float value) { + virtual void OnMidiValueChanged(int64_t instanceId, const std::string &symbol, float value) + { if (midiValueChangedOutstanding) { - for (size_t i = 0; i < deferredValues.size(); ++i) { + for (size_t i = 0; i < deferredValues.size(); ++i) + { auto &deferredValue = deferredValues[i]; if (deferredValue.instanceId == instanceId && deferredValue.symbol == symbol) { @@ -1381,37 +1411,39 @@ public: return; } } - DeferredValue newValue {instanceId,symbol,value}; + DeferredValue newValue{instanceId, symbol, value}; deferredValues.push_back(newValue); - } else { + } + else + { midiValueChangedOutstanding = true; ControlChangedBody body; body.clientId_ = -1; body.instanceId_ = instanceId; body.symbol_ = symbol; body.value_ = value; - Request("onMidiValueChanged", body, - [this] (const bool& value) - { - this->midiValueChangedOutstanding = false; - if (this->deferredValues.size() != 0) + Request( + "onMidiValueChanged", body, + [this](const bool &value) { - DeferredValue value = deferredValues[0]; - deferredValues.erase(deferredValues.begin()); - this->OnMidiValueChanged(value.instanceId,value.symbol,value.value); - } + this->midiValueChangedOutstanding = false; + if (this->deferredValues.size() != 0) + { + DeferredValue value = deferredValues[0]; + deferredValues.erase(deferredValues.begin()); + this->OnMidiValueChanged(value.instanceId, value.symbol, value.value); + } + }, + [](const std::exception &e) { - }, - [] (const std::exception &e) { - - } - ); + }); } } int outstandingNotifyAtomOutputs = 0; - class PendingNotifyAtomOutput { + class PendingNotifyAtomOutput + { public: int64_t clientHandle; uint64_t instanceId; @@ -1421,8 +1453,8 @@ public: std::vector pendingNotifyAtomOutputs; - - void OnAckNotifyAtomOutput() { + void OnAckNotifyAtomOutput() + { std::lock_guard guard(subscriptionMutex); if (--outstandingNotifyAtomOutputs <= 0) { @@ -1436,12 +1468,11 @@ public: t.instanceId, t.atomType, t.json); - } } } - virtual void OnNotifyAtomOutput(int64_t clientHandle,uint64_t instanceId,const std::string&atomType, const std::string&atomJson) + virtual void OnNotifyAtomOutput(int64_t clientHandle, uint64_t instanceId, const std::string &atomType, const std::string &atomJson) { NotifyAtomOutputBody body; body.clientHandle_ = clientHandle; @@ -1462,53 +1493,53 @@ public: return; } } - pendingNotifyAtomOutputs.push_back(PendingNotifyAtomOutput{ clientHandle, instanceId,atomType,atomJson }); + pendingNotifyAtomOutputs.push_back(PendingNotifyAtomOutput{clientHandle, instanceId, atomType, atomJson}); return; } ++outstandingNotifyAtomOutputs; } - - Request("onNotifyAtomOut",body, - [this] (const bool& value) + + Request( + "onNotifyAtomOut", body, + [this](const bool &value) { this->OnAckNotifyAtomOutput(); }, - [] (const std::exception &e) { - - } - ); + [](const std::exception &e) { + }); } - virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) + virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) { NotifyMidiListenerBody body; body.clientHandle_ = clientHandle; body.isNote_ = isNote; body.noteOrControl_ = noteOrControl; - Send("onNotifyMidiListener",body); + Send("onNotifyMidiListener", body); } - - - virtual void OnBankIndexChanged(const BankIndex& bankIndex) + virtual void OnBankIndexChanged(const BankIndex &bankIndex) { - Send("onBanksChanged",bankIndex); + Send("onBanksChanged", bankIndex); } - virtual void OnJackServerSettingsChanged(const JackServerSettings& jackServerSettings) + virtual void OnJackServerSettingsChanged(const JackServerSettings &jackServerSettings) { - Send("onJackServerSettingsChanged",jackServerSettings); + Send("onJackServerSettingsChanged", jackServerSettings); } - virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) { - Send("onWifiConfigSettingsChanged",wifiConfigSettings); + virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings &wifiConfigSettings) + { + Send("onWifiConfigSettingsChanged", wifiConfigSettings); } - virtual void OnWifiDirectConfigSettingsChanged(const WifiDirectConfigSettings&wifiConfigSettings) { - Send("onWifiDirectConfigSettingsChanged",wifiConfigSettings); + virtual void OnWifiDirectConfigSettingsChanged(const WifiDirectConfigSettings &wifiConfigSettings) + { + Send("onWifiDirectConfigSettingsChanged", wifiConfigSettings); } - virtual void OnGovernorSettingsChanged(const std::string& governor) { - Send("onGovernorSettingsChanged",governor); + virtual void OnGovernorSettingsChanged(const std::string &governor) + { + Send("onGovernorSettingsChanged", governor); } virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard) @@ -1519,7 +1550,6 @@ public: Send("onPedalBoardChanged", body); } - virtual void OnItemEnabledChanged(int64_t clientId, int64_t pedalItemId, bool enabled) { PedalBoardItemEnabledBody body; @@ -1564,21 +1594,22 @@ std::shared_ptr pipedal::MakePiPedalSocketFactory(PiPedalModel & return std::make_shared(model); } - void PiPedalSocketHandler::RequestShutdown(bool restart) { if (GetAdminClient().CanUseShutdownClient()) { GetAdminClient().RequestShutdown(restart); } - else { + else + { // ONLY works when interactively logged in. std::stringstream s; s << "/usr/sbin/shutdown "; if (restart) { s << "-r"; - } else + } + else { s << "-P"; } @@ -1587,9 +1618,12 @@ void PiPedalSocketHandler::RequestShutdown(bool restart) if (sysExec(s.str().c_str()) != EXIT_SUCCESS) { Lv2Log::error("shutdown failed."); - if (restart) { + if (restart) + { throw new PiPedalStateException("Restart request failed."); - } else { + } + else + { throw new PiPedalStateException("Shutdown request failed."); } } diff --git a/src/main.cpp b/src/main.cpp index 99d2b23..8550920 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -655,15 +655,15 @@ int main(int argc, char *argv[]) auto devices = model.GetAlsaDevices(); bool firstMessage = true; bool found = false; - if (!HasAlsaDevice(devices, serverSettings.GetAlsaDevice())) + if (!HasAlsaDevice(devices, serverSettings.GetAlsaInputDevice())) { - if (firstMessage) Lv2Log::info(SS("Waiting for ALSA device " << serverSettings.GetAlsaDevice() << " to come online...")); + if (firstMessage) Lv2Log::info(SS("Waiting for ALSA device " << serverSettings.GetAlsaInputDevice() << " to come online...")); firstMessage = false; for (int i = 0; i < 5; ++i) { sleep(3); devices = model.GetAlsaDevices(); - if (HasAlsaDevice(devices, serverSettings.GetAlsaDevice())) + if (HasAlsaDevice(devices, serverSettings.GetAlsaInputDevice())) { found = true; break; @@ -673,9 +673,9 @@ int main(int argc, char *argv[]) } if (found) { - Lv2Log::info(SS("Found ALSA device " << serverSettings.GetAlsaDevice() << ".")); + Lv2Log::info(SS("Found ALSA device " << serverSettings.GetAlsaInputDevice() << ".")); } else { - Lv2Log::info(SS("ALSA device " << serverSettings.GetAlsaDevice() << " not found.")); + Lv2Log::info(SS("ALSA device " << serverSettings.GetAlsaInputDevice() << " not found.")); } } }