Tuner display

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