refactor service.conf
This commit is contained in:
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
<http://two-play.com/plugins/toob-cab-sim>
|
<http://two-play.com/plugins/toob-cab-sim>
|
||||||
a lv2:Plugin ,
|
a lv2:Plugin ,
|
||||||
lv2:AmplifierPlugin ;
|
lv2:SimulatorPlugin ;
|
||||||
doap:name "TooB Cab Simulator" ,
|
doap:name "TooB Cab Simulator" ,
|
||||||
"TooB Cab Simulator"@en-gb-gb
|
"TooB Cab Simulator"@en-gb-gb
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ inputStage:filterGroup
|
|||||||
|
|
||||||
<http://two-play.com/plugins/toob-input_stage>
|
<http://two-play.com/plugins/toob-input_stage>
|
||||||
a lv2:Plugin ,
|
a lv2:Plugin ,
|
||||||
lv2:MixerPlugin ;
|
lv2:SimulatorPlugin ;
|
||||||
doap:name "TooB Input Stage" ,
|
doap:name "TooB Input Stage" ,
|
||||||
"TooB Input Stage"@en-gb-gb
|
"TooB Input Stage"@en-gb-gb
|
||||||
;
|
;
|
||||||
@@ -118,7 +118,8 @@ use the following plugins in the following order.
|
|||||||
] , [
|
] , [
|
||||||
rdfs:label "-INF" ;
|
rdfs:label "-INF" ;
|
||||||
rdf:value -60.0
|
rdf:value -60.0
|
||||||
]
|
];
|
||||||
|
rdfs:comment "Input level trim"
|
||||||
], [
|
], [
|
||||||
a lv2:InputPort ,
|
a lv2:InputPort ,
|
||||||
lv2:ControlPort ;
|
lv2:ControlPort ;
|
||||||
@@ -154,7 +155,7 @@ use the following plugins in the following order.
|
|||||||
rdfs:label "OFF" ;
|
rdfs:label "OFF" ;
|
||||||
rdf:value 0.0
|
rdf:value 0.0
|
||||||
];
|
];
|
||||||
rdfs:comment "Boost high frequencies." ;
|
rdfs:comment "High frequency boost. Zero to disable." ;
|
||||||
|
|
||||||
], [
|
], [
|
||||||
a lv2:InputPort ,
|
a lv2:InputPort ,
|
||||||
@@ -173,7 +174,7 @@ use the following plugins in the following order.
|
|||||||
rdfs:label "OFF" ;
|
rdfs:label "OFF" ;
|
||||||
rdf:value 0.0
|
rdf:value 0.0
|
||||||
];
|
];
|
||||||
rdfs:comment "Bright frequency." ;
|
rdfs:comment "Bright cutoff frequency." ;
|
||||||
|
|
||||||
], [
|
], [
|
||||||
a lv2:InputPort ,
|
a lv2:InputPort ,
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ pstage:stage3
|
|||||||
|
|
||||||
<http://two-play.com/plugins/toob-power-stage-2>
|
<http://two-play.com/plugins/toob-power-stage-2>
|
||||||
a lv2:Plugin ,
|
a lv2:Plugin ,
|
||||||
lv2:AmplifierPlugin ;
|
lv2:SimulatorPlugin ;
|
||||||
|
|
||||||
doap:name "TooB Power Stage";
|
doap:name "TooB Power Stage";
|
||||||
|
|
||||||
@@ -79,8 +79,8 @@ pstage:stage3
|
|||||||
|
|
||||||
rdfs:comment """
|
rdfs:comment """
|
||||||
The TooB Power Stage provides flexible and nuanced emulations of guitar amp power stages.
|
The TooB Power Stage provides flexible and nuanced emulations of guitar amp power stages.
|
||||||
The goal of TooB Power Stage is not to inflexibly emulate existing tube power stages, but instead,
|
The goal of TooB Power Stage is emulate the best features of real tube amps without slavishly
|
||||||
to be better.
|
reproducing the undesirable features as well.
|
||||||
|
|
||||||
TooB Power Stage provides 3 consecutive gain stages, each of which can be overdriven to varying
|
TooB Power Stage provides 3 consecutive gain stages, each of which can be overdriven to varying
|
||||||
degrees. Power transformer sag is emulated using the SAG and SAGD controls, which emulate the
|
degrees. Power transformer sag is emulated using the SAG and SAGD controls, which emulate the
|
||||||
@@ -105,19 +105,22 @@ General experience seems to suggest that gradually increasing the gain in each s
|
|||||||
the signal harder without introducing undesirable effects in the output. However, there definitely interesting
|
the signal harder without introducing undesirable effects in the output. However, there definitely interesting
|
||||||
and subtle differences in tone that can be acheived by not adhering to that rule of thumb.
|
and subtle differences in tone that can be acheived by not adhering to that rule of thumb.
|
||||||
|
|
||||||
The SAG and SAGD controls are important controls. You need to undertand how they work. SAG controls how much
|
The SAG and SAGD controls the emulation of "forgiveness", and "compression" that are provided in a real tube
|
||||||
|
amp by sagging of power supply voltage. SAG controls how much
|
||||||
the overall volume of the output decreases as the transform sags. It provides the subtle "compression" that
|
the overall volume of the output decreases as the transform sags. It provides the subtle "compression" that
|
||||||
tube amps provide, which is quite different from the compression provided by compressors. SAGD controls
|
tube amps provide, which is quite different from the compression provided by compressors. SAGD controls
|
||||||
the amount of additional distortion that occurs as the gain stages receive reduced voltage. It provides
|
the amount of additional distortion that occurs as the gain stages receive reduced voltage. It provides
|
||||||
the "forgiveness" of a good tube amp. Specifically, because SAGD operates in a feedback loop that runs through
|
the "forgiveness" of a good tube amp. Because SAGD operates in a feedback loop that runs through
|
||||||
all three gain stages. Increasing the distortion in the gain stages increases the power use of the gain stages;
|
all three gain stages. Increasing the distortion in the gain stages increases the power use of the gain stages;
|
||||||
increasing the power use of the gain stages increases the effect of SAG and SAGD which has an opposing effect
|
increasing the power use of the gain stages increases the effect of SAG and SAGD which has an opposing effect
|
||||||
on power use. The net result is that using SAG and SAGD causes signals to break up more gradually
|
on power use. The net result is that SAGD causes signals to break up more gradually
|
||||||
(hence the perceived "forgiveness"). The effects are non-linear, so not easy to describe completely. You
|
(hence the perceived "forgiveness"). The effects are non-linear, so not easy to describe completely. You
|
||||||
are strongly urged to experiment with SAG and SAGD settings in order to get best tone results.
|
are strongly urged to experiment with SAG and SAGD settings in order to get best tone results. Use very
|
||||||
|
moderate settings to emulate tube amp output; higher settings of SAG and SAGD will cause audible compression
|
||||||
|
and pumping of the outputs which may or may not be desireable.
|
||||||
|
|
||||||
The TooB Power Stage design is based on an experimental design, that unexpectedly produced extraordinarily
|
The TooB Power Stage design is based on an experimental design, that unexpectedly produced extraordinarily
|
||||||
good amp tones. To be perfectly honest, we have not completely explored the sonic possibilities of the
|
good amp tones. We have not completely explored the sonic possibilities of the
|
||||||
TooB Power Stage. What's known so far: it produces exceptionally pretty clean tones; it can be driven really
|
TooB Power Stage. What's known so far: it produces exceptionally pretty clean tones; it can be driven really
|
||||||
hard, and seems to preserve an unusual amount of detail in the signal even when being driven hard; and it
|
hard, and seems to preserve an unusual amount of detail in the signal even when being driven hard; and it
|
||||||
can definitely produce signals that have many of the most prized features of tube amplifiers: warmth, detail,
|
can definitely produce signals that have many of the most prized features of tube amplifiers: warmth, detail,
|
||||||
@@ -235,10 +238,11 @@ use the following plugins in the following order.
|
|||||||
|
|
||||||
lv2:index 5 ;
|
lv2:index 5 ;
|
||||||
lv2:symbol "bias1" ;
|
lv2:symbol "bias1" ;
|
||||||
lv2:name "Bias1";
|
lv2:name "Bias";
|
||||||
lv2:default 0.0 ;
|
lv2:default 0.0 ;
|
||||||
lv2:minimum -2.0 ;
|
lv2:minimum -2.0 ;
|
||||||
lv2:maximum 2.0;
|
lv2:maximum 2.0;
|
||||||
|
rdfs:comment "Waveshape bias (stage 1)"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
@@ -345,10 +349,12 @@ use the following plugins in the following order.
|
|||||||
|
|
||||||
lv2:index 11 ;
|
lv2:index 11 ;
|
||||||
lv2:symbol "bias2" ;
|
lv2:symbol "bias2" ;
|
||||||
lv2:name "Bias2";
|
lv2:name "Bias";
|
||||||
lv2:default 0.0 ;
|
lv2:default 0.0 ;
|
||||||
lv2:minimum -2.0 ;
|
lv2:minimum -2.0 ;
|
||||||
lv2:maximum 2.0;
|
lv2:maximum 2.0;
|
||||||
|
rdfs:comment "Waveshape bias (stage 2)"
|
||||||
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
a lv2:InputPort ,
|
a lv2:InputPort ,
|
||||||
@@ -466,10 +472,12 @@ use the following plugins in the following order.
|
|||||||
|
|
||||||
lv2:index 18 ;
|
lv2:index 18 ;
|
||||||
lv2:symbol "bias3" ;
|
lv2:symbol "bias3" ;
|
||||||
lv2:name "Bias3";
|
lv2:name "Bias";
|
||||||
lv2:default 0.0 ;
|
lv2:default 0.0 ;
|
||||||
lv2:minimum -2.0 ;
|
lv2:minimum -2.0 ;
|
||||||
lv2:maximum 2.0;
|
lv2:maximum 2.0;
|
||||||
|
rdfs:comment "Waveshape bias (stage 3)"
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
<http://two-play.com/plugins/toob-tone-stack>
|
<http://two-play.com/plugins/toob-tone-stack>
|
||||||
a lv2:Plugin ,
|
a lv2:Plugin ,
|
||||||
lv2:AmplifierPlugin ;
|
lv2:SimulatorPlugin ;
|
||||||
doap:name "TooB Tone Stack" ,
|
doap:name "TooB Tone Stack" ,
|
||||||
"TooB Tone Stack"@en-gb-gb
|
"TooB Tone Stack"@en-gb-gb
|
||||||
;
|
;
|
||||||
|
|||||||
Binary file not shown.
@@ -41,7 +41,7 @@
|
|||||||
lv2:minorVersion 0 ;
|
lv2:minorVersion 0 ;
|
||||||
lv2:microVersion 13 ;
|
lv2:microVersion 13 ;
|
||||||
rdfs:comment """
|
rdfs:comment """
|
||||||
Digital delay.
|
A straighforward no-frills digital delay.
|
||||||
|
|
||||||
""" ;
|
""" ;
|
||||||
|
|
||||||
@@ -62,6 +62,7 @@ Digital delay.
|
|||||||
lv2:maximum 1200;
|
lv2:maximum 1200;
|
||||||
units:unit units:ms;
|
units:unit units:ms;
|
||||||
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
|
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
|
||||||
|
rdfs:comment "Delay in ms";
|
||||||
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@@ -76,6 +77,8 @@ Digital delay.
|
|||||||
lv2:minimum 0.0 ;
|
lv2:minimum 0.0 ;
|
||||||
lv2:maximum 100.0 ;
|
lv2:maximum 100.0 ;
|
||||||
units:unit units:pc;
|
units:unit units:pc;
|
||||||
|
rdfs:comment "Attenuation of the first delay";
|
||||||
|
|
||||||
], [
|
], [
|
||||||
a lv2:InputPort ,
|
a lv2:InputPort ,
|
||||||
lv2:ControlPort ;
|
lv2:ControlPort ;
|
||||||
@@ -89,6 +92,7 @@ Digital delay.
|
|||||||
lv2:minimum 0.0 ;
|
lv2:minimum 0.0 ;
|
||||||
lv2:maximum 100.0 ;
|
lv2:maximum 100.0 ;
|
||||||
units:unit units:pc;
|
units:unit units:pc;
|
||||||
|
rdfs:comment "Attenuation of subequent delays";
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
a lv2:AudioPort ,
|
a lv2:AudioPort ,
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ toobml:filterGroup
|
|||||||
|
|
||||||
<http://two-play.com/plugins/toob-ml>
|
<http://two-play.com/plugins/toob-ml>
|
||||||
a lv2:Plugin ,
|
a lv2:Plugin ,
|
||||||
lv2:AmplifierPlugin ;
|
lv2:SimulatorPlugin ;
|
||||||
doap:name "TooB ML Amplifier" ,
|
doap:name "TooB ML Amplifier" ,
|
||||||
"TooB ML Amplifier"@en-gb-gb
|
"TooB ML Amplifier"@en-gb-gb
|
||||||
;
|
;
|
||||||
@@ -84,7 +84,7 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
lv2:minimum -30.0 ;
|
lv2:minimum -30.0 ;
|
||||||
lv2:maximum 30.0 ;
|
lv2:maximum 30.0 ;
|
||||||
units:unit units:db ;
|
units:unit units:db ;
|
||||||
rdf:comment "Input volume trim (pre-model)";
|
rdfs:comment "Input volume trim (pre-model)";
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
a lv2:InputPort, lv2:ControlPort ;
|
a lv2:InputPort, lv2:ControlPort ;
|
||||||
@@ -228,6 +228,7 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
rdfs:label "XoticCompSP";
|
rdfs:label "XoticCompSP";
|
||||||
rdf:value 32.0
|
rdf:value 32.0
|
||||||
];
|
];
|
||||||
|
rdfs:comment "Select neural network model."
|
||||||
] ,
|
] ,
|
||||||
[
|
[
|
||||||
a lv2:InputPort ,
|
a lv2:InputPort ,
|
||||||
@@ -239,7 +240,7 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
lv2:default 3.0 ;
|
lv2:default 3.0 ;
|
||||||
lv2:minimum 0.0 ;
|
lv2:minimum 0.0 ;
|
||||||
lv2:maximum 10.0 ;
|
lv2:maximum 10.0 ;
|
||||||
rdf:comment "Model gain (used by some but not all models)"
|
rdfs:comment "Model gain parameter (used by some but not all models)"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
a lv2:InputPort ,
|
a lv2:InputPort ,
|
||||||
@@ -252,7 +253,7 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
lv2:minimum -30.0 ;
|
lv2:minimum -30.0 ;
|
||||||
lv2:maximum 30.0 ;
|
lv2:maximum 30.0 ;
|
||||||
units:unit units:db ;
|
units:unit units:db ;
|
||||||
rdf:comment "Output volume trim (pot-model)";
|
rdfs:comment "Output volume trim (pre-model)";
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
@@ -269,7 +270,7 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
lv2:minimum 0.0 ;
|
lv2:minimum 0.0 ;
|
||||||
lv2:maximum 1.0 ;
|
lv2:maximum 1.0 ;
|
||||||
|
|
||||||
rdf:comment "Bass eq (pre-model)";
|
rdfs:comment "Bass eq (pre-model)";
|
||||||
], [
|
], [
|
||||||
a lv2:InputPort ,
|
a lv2:InputPort ,
|
||||||
lv2:ControlPort ;
|
lv2:ControlPort ;
|
||||||
@@ -285,9 +286,11 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
lv2:maximum 1.0 ;
|
lv2:maximum 1.0 ;
|
||||||
|
|
||||||
|
|
||||||
rdf:comment "Mid eq (pre-model)";
|
rdfs:comment "Mid eq (pre-model)";
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
[
|
[
|
||||||
a lv2:InputPort ,
|
a lv2:InputPort ,
|
||||||
lv2:ControlPort ;
|
lv2:ControlPort ;
|
||||||
@@ -303,7 +306,7 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
lv2:maximum 1.0 ;
|
lv2:maximum 1.0 ;
|
||||||
|
|
||||||
|
|
||||||
rdf:comment "Treble eq (pre-model)";
|
rdfs:comment "Treble eq (pre-model)";
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
a lv2:OutputPort ,
|
a lv2:OutputPort ,
|
||||||
@@ -320,16 +323,42 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
a lv2:InputPort ,
|
||||||
|
lv2:ControlPort ;
|
||||||
|
|
||||||
|
lv2:index 8 ;
|
||||||
|
lv2:symbol "sag" ;
|
||||||
|
lv2:name "Sag Vol";
|
||||||
|
lv2:default 0.0 ;
|
||||||
|
lv2:minimum 0.0 ;
|
||||||
|
lv2:maximum 1.0;
|
||||||
|
rdfs:comment "Transformer sag (volume)." ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
a lv2:InputPort ,
|
||||||
|
lv2:ControlPort ;
|
||||||
|
|
||||||
|
lv2:index 9 ;
|
||||||
|
lv2:symbol "sagd" ;
|
||||||
|
lv2:name "Sag Dist";
|
||||||
|
lv2:default 0.0 ;
|
||||||
|
lv2:minimum 0.0 ;
|
||||||
|
lv2:maximum 1.0;
|
||||||
|
rdfs:comment "Transformer sag (distortion)." ;
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
[
|
[
|
||||||
a lv2:AudioPort ,
|
a lv2:AudioPort ,
|
||||||
lv2:InputPort ;
|
lv2:InputPort ;
|
||||||
lv2:index 8 ;
|
lv2:index 10 ;
|
||||||
lv2:symbol "in" ;
|
lv2:symbol "in" ;
|
||||||
lv2:name "In"
|
lv2:name "In"
|
||||||
], [
|
], [
|
||||||
a lv2:AudioPort ,
|
a lv2:AudioPort ,
|
||||||
lv2:OutputPort ;
|
lv2:OutputPort ;
|
||||||
lv2:index 9 ;
|
lv2:index 11 ;
|
||||||
lv2:symbol "out" ;
|
lv2:symbol "out" ;
|
||||||
lv2:name "Out"
|
lv2:name "Out"
|
||||||
]
|
]
|
||||||
@@ -340,7 +369,7 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
atom:bufferType atom:Sequence ;
|
atom:bufferType atom:Sequence ;
|
||||||
atom:supports patch:Message;
|
atom:supports patch:Message;
|
||||||
lv2:designation lv2:control ;
|
lv2:designation lv2:control ;
|
||||||
lv2:index 10 ;
|
lv2:index 12 ;
|
||||||
lv2:symbol "control" ;
|
lv2:symbol "control" ;
|
||||||
lv2:name "Control" ;
|
lv2:name "Control" ;
|
||||||
rdfs:comment "Plugin to GUI communication" ;
|
rdfs:comment "Plugin to GUI communication" ;
|
||||||
@@ -351,11 +380,35 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
|
|||||||
atom:bufferType atom:Sequence ;
|
atom:bufferType atom:Sequence ;
|
||||||
atom:supports patch:Message;
|
atom:supports patch:Message;
|
||||||
lv2:designation lv2:control ;
|
lv2:designation lv2:control ;
|
||||||
lv2:index 11 ;
|
lv2:index 13 ;
|
||||||
lv2:symbol "notify" ;
|
lv2:symbol "notify" ;
|
||||||
lv2:name "Notify" ;
|
lv2:name "Notify" ;
|
||||||
rdfs:comment "Plugin to GUI communication" ;
|
rdfs:comment "Plugin to GUI communication" ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
a atom:AtomPort ,
|
||||||
|
lv2:OutputPort ;
|
||||||
|
atom:bufferType atom:Sequence ;
|
||||||
|
atom:supports patch:Message;
|
||||||
|
lv2:designation lv2:control ;
|
||||||
|
lv2:index 13 ;
|
||||||
|
lv2:symbol "notify" ;
|
||||||
|
lv2:name "Notify" ;
|
||||||
|
rdfs:comment "Plugin to GUI communication" ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
a lv2:InputPort ,
|
||||||
|
lv2:ControlPort ;
|
||||||
|
|
||||||
|
lv2:index 14 ;
|
||||||
|
lv2:symbol "sagf" ;
|
||||||
|
lv2:name "SagF";
|
||||||
|
lv2:default 13.0 ;
|
||||||
|
lv2:minimum 5.0 ;
|
||||||
|
lv2:maximum 25.0;
|
||||||
|
rdfs:comment "Sag filter Fc." ;
|
||||||
]
|
]
|
||||||
|
|
||||||
.
|
.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"socket_server_port": 8080,
|
"socket_server_port": 80,
|
||||||
"socket_server_address": "*",
|
"socket_server_address": "*",
|
||||||
"debug": true,
|
"debug": true,
|
||||||
"max_upload_size": 1048576,
|
"max_upload_size": 1048576,
|
||||||
"fakeAndroid": true,
|
"fakeAndroid": false,
|
||||||
"ui_plugins": []
|
"ui_plugins": []
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,7 @@ export class Port implements Deserializable<Port> {
|
|||||||
this.supports_midi = input.supports_midi;
|
this.supports_midi = input.supports_midi;
|
||||||
this.supports_time_position = input.supports_time_position;
|
this.supports_time_position = input.supports_time_position;
|
||||||
this.port_group = input.port_group;
|
this.port_group = input.port_group;
|
||||||
|
this.comment = input.comment;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ export class Port implements Deserializable<Port> {
|
|||||||
supports_midi: boolean = false;
|
supports_midi: boolean = false;
|
||||||
supports_time_position: boolean = false;
|
supports_time_position: boolean = false;
|
||||||
port_group: string = "";
|
port_group: string = "";
|
||||||
|
comment: string = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PortGroup {
|
export class PortGroup {
|
||||||
@@ -221,8 +223,11 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
this.scale_points = ScalePoint.deserialize_array(input.scale_points);
|
this.scale_points = ScalePoint.deserialize_array(input.scale_points);
|
||||||
this.port_group = input.port_group;
|
this.port_group = input.port_group;
|
||||||
this.units = input.units as Units;
|
this.units = input.units as Units;
|
||||||
|
this.comment = input.comment;
|
||||||
|
|
||||||
this.controlType = ControlType.Dial;
|
this.controlType = ControlType.Dial;
|
||||||
|
|
||||||
|
|
||||||
if (this.enumeration_property && this.scale_points.length === 2)
|
if (this.enumeration_property && this.scale_points.length === 2)
|
||||||
{
|
{
|
||||||
this.controlType = ControlType.Toggle;
|
this.controlType = ControlType.Toggle;
|
||||||
@@ -239,7 +244,6 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
{
|
{
|
||||||
this.controlType = ControlType.Select;
|
this.controlType = ControlType.Select;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -271,6 +275,7 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
scale_points: ScalePoint[] = [];
|
scale_points: ScalePoint[] = [];
|
||||||
port_group: string = "";
|
port_group: string = "";
|
||||||
units: Units = Units.none;
|
units: Units = Units.none;
|
||||||
|
comment: string = "";
|
||||||
|
|
||||||
// Return the value of the closest scale_point.
|
// Return the value of the closest scale_point.
|
||||||
clampSelectValue(value: number): number{
|
clampSelectValue(value: number): number{
|
||||||
|
|||||||
@@ -503,7 +503,6 @@ export const MainPage =
|
|||||||
GetControlView(pedalBoardItem)
|
GetControlView(pedalBoardItem)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<MidiBindingsDialog open={this.state.showMidiBindingsDialog}
|
<MidiBindingsDialog open={this.state.showMidiBindingsDialog}
|
||||||
onClose={()=> this.setState({showMidiBindingsDialog: false} ) }
|
onClose={()=> this.setState({showMidiBindingsDialog: false} ) }
|
||||||
|
|||||||
@@ -2020,14 +2020,18 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
let oldSettings = this.wifiDirectConfigSettings.get();
|
let oldSettings = this.wifiDirectConfigSettings.get();
|
||||||
wifiDirectConfigSettings = wifiDirectConfigSettings.clone();
|
wifiDirectConfigSettings = wifiDirectConfigSettings.clone();
|
||||||
|
|
||||||
if ((!oldSettings.enable) && (!wifiDirectConfigSettings.enable)) {
|
if ((!oldSettings.enable) && (!wifiDirectConfigSettings.enable)
|
||||||
|
&& (oldSettings.hotspotName == wifiDirectConfigSettings.hotspotName)
|
||||||
|
) {
|
||||||
// no effective change.
|
// no effective change.
|
||||||
resolve();
|
resolve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!wifiDirectConfigSettings.enable) {
|
if (!wifiDirectConfigSettings.enable) {
|
||||||
|
let t = wifiDirectConfigSettings.hotspotName; // hotspot name can be changed when disabled because it's also the mDNS service name.
|
||||||
wifiDirectConfigSettings = oldSettings.clone();
|
wifiDirectConfigSettings = oldSettings.clone();
|
||||||
wifiDirectConfigSettings.enable = false;
|
wifiDirectConfigSettings.enable = false;
|
||||||
|
wifiDirectConfigSettings.hotspotName = t;
|
||||||
} else {
|
} else {
|
||||||
if (wifiDirectConfigSettings.countryCode === oldSettings.countryCode
|
if (wifiDirectConfigSettings.countryCode === oldSettings.countryCode
|
||||||
&& wifiDirectConfigSettings.channel === oldSettings.channel
|
&& wifiDirectConfigSettings.channel === oldSettings.channel
|
||||||
|
|||||||
@@ -455,7 +455,12 @@ const PluginControlView =
|
|||||||
{
|
{
|
||||||
nodes
|
nodes
|
||||||
}
|
}
|
||||||
<div style={{ flex: "0 0 40px", width: 40, height: 1 }} />
|
<div style={{ flex: "0 0 40px", width: 40, height: 40 }} />
|
||||||
|
{
|
||||||
|
(!this.state.landscapeGrid) && (
|
||||||
|
<div style={{ flex: "0 1 100%", width: "0px", height: 40 }} />
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<FullScreenIME uiControl={this.state.imeUiControl} value={this.state.imeValue}
|
<FullScreenIME uiControl={this.state.imeUiControl} value={this.state.imeValue}
|
||||||
|
|
||||||
|
|||||||
@@ -134,22 +134,63 @@ function makeParagraphs(description: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
function makeControls(controls: UiControl[]) {
|
function makeControls(controls: UiControl[]) {
|
||||||
return (
|
let hasComments = false;
|
||||||
<Grid container direction="row" justifyContent="flex-start" alignItems="flex-start" spacing={1} style={{ paddingLeft: "24px" }}>
|
|
||||||
{
|
for (let i = 0; i < controls.length; ++i) {
|
||||||
controls.map((control) => (
|
if (controls[i].comment !== "") {
|
||||||
<Grid xs={6} sm={4} key={control.symbol} >
|
hasComments = true;
|
||||||
<Typography variant="body2">
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasComments) {
|
||||||
|
let trs: React.ReactElement[] = [];
|
||||||
|
for (let i = 0; i < controls.length; ++i) {
|
||||||
|
let control = controls[i];
|
||||||
|
|
||||||
|
trs.push((
|
||||||
|
<tr>
|
||||||
|
<td style={{ verticalAlign: "top" }}>
|
||||||
|
<Typography variant="body2" style={{ whiteSpace: "nowrap" }}>
|
||||||
{control.name}
|
{control.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</td>
|
||||||
))
|
<td style={{ paddingLeft: "16px", verticalAlign: "top" }}>
|
||||||
}
|
<Typography variant="body2">
|
||||||
</Grid>
|
{control.comment}
|
||||||
);
|
</Typography>
|
||||||
|
</td>
|
||||||
|
</tr >
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<table style={{ paddingLeft: "24px", verticalAlign: "top" }}>
|
||||||
|
{
|
||||||
|
trs
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Grid container direction="row" justifyContent="flex-start" alignItems="flex-start" spacing={1} style={{ paddingLeft: "24px" }}>
|
||||||
|
{
|
||||||
|
controls.map((control) => (
|
||||||
|
<Grid xs={6} sm={4} key={control.symbol + "x"} >
|
||||||
|
<Typography variant="body2">
|
||||||
|
{control.name}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
|
const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
|
||||||
|
|
||||||
let model = PiPedalModelFactory.getInstance();
|
let model = PiPedalModelFactory.getInstance();
|
||||||
@@ -205,19 +246,25 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</MuiDialogTitle>
|
</MuiDialogTitle>
|
||||||
<PluginInfoDialogContent dividers style={{ width: "100%", maxHeight: "80%", overflowX: "hidden" }}>
|
<PluginInfoDialogContent dividers style={{ width: "100%", maxHeight: "80%", overflowX: "hidden" }}>
|
||||||
<Typography gutterBottom>
|
<div style={{ width: "100%",display: "flex", flexFlow: "row", justifyItems: "stretch", flexWrap: "nowrap" }} >
|
||||||
Author:
|
<div style={{ flex: "1 1 100%" }}>
|
||||||
{(plugin.author_homepage !== "")
|
<Typography gutterBottom >
|
||||||
? <a href={plugin.author_homepage} target="_blank" rel="noreferrer">{plugin.author_name}</a>
|
Author:
|
||||||
: (
|
{(plugin.author_homepage !== "")
|
||||||
plugin.author_name
|
? <a href={plugin.author_homepage} target="_blank" rel="noreferrer">{plugin.author_name}</a>
|
||||||
)
|
: (
|
||||||
}
|
plugin.author_name
|
||||||
</Typography>
|
)
|
||||||
<Typography gutterBottom>
|
}
|
||||||
{ioDescription(plugin)}
|
</Typography>
|
||||||
</Typography>
|
</div>
|
||||||
|
<div style={{ flex: "0 0 auto" }}>
|
||||||
|
<Typography gutterBottom >
|
||||||
|
{ioDescription(plugin)}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
<Typography variant="body1" gutterBottom style={{ paddingTop: "1em" }}>
|
<Typography variant="body1" gutterBottom style={{ paddingTop: "1em" }}>
|
||||||
Controls:
|
Controls:
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -38,7 +38,14 @@ export interface ControlEntry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Utility = class {
|
const Utility = class {
|
||||||
|
static isLandscape(): boolean {
|
||||||
|
return window.innerWidth > window.innerHeight;
|
||||||
|
}
|
||||||
static isTouchDevice(): boolean {
|
static isTouchDevice(): boolean {
|
||||||
|
if (!this.isLandscape()) return false;
|
||||||
|
|
||||||
|
if (window.innerHeight > 500) return false;
|
||||||
|
|
||||||
return (('ontouchstart' in window) &&
|
return (('ontouchstart' in window) &&
|
||||||
((navigator.maxTouchPoints??0) > 0) );
|
((navigator.maxTouchPoints??0) > 0) );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
id="name"
|
id="name"
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
label="SSID"
|
label="Service Name"
|
||||||
type="text"
|
type="text"
|
||||||
size={this.state.controlSize}
|
size={this.state.controlSize}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -348,11 +348,11 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
|
|||||||
value={this.state.name}
|
value={this.state.name}
|
||||||
onChange={(e) => this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })}
|
onChange={(e) => this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })}
|
||||||
inputRef={this.refName}
|
inputRef={this.refName}
|
||||||
disabled={!this.state.enabled}
|
|
||||||
variant="filled"
|
variant="filled"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
|
required
|
||||||
inputRef={this.refPassword}
|
inputRef={this.refPassword}
|
||||||
sx={{ maxWidth: this.state.controlWidth }}
|
sx={{ maxWidth: this.state.controlWidth }}
|
||||||
|
|
||||||
@@ -377,7 +377,7 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginTop: 0, display: 'flex', alignItems: 'stretch', gap: 16 }}>
|
<div style={{ marginTop: 0, display: 'flex', alignItems: 'stretch', gap: 16 }}>
|
||||||
<TextField select label="Country" size={this.state.controlSize} value={this.state.countryCode} variant="filled"
|
<TextField required select label="Country" size={this.state.controlSize} value={this.state.countryCode} variant="filled"
|
||||||
sx={{ width: this.state.controlWidth }}
|
sx={{ width: this.state.controlWidth }}
|
||||||
disabled={!this.state.enabled}
|
disabled={!this.state.enabled}
|
||||||
onChange={(event) => { this.handleCountryChanged(event); }}
|
onChange={(event) => { this.handleCountryChanged(event); }}
|
||||||
@@ -413,17 +413,18 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
|
|||||||
)}
|
)}
|
||||||
{(!this.state.landscapeLayout) && (
|
{(!this.state.landscapeLayout) && (
|
||||||
<DialogContent sx={{minHeight: 96}} >
|
<DialogContent sx={{minHeight: 96}} >
|
||||||
<FormControlLabel
|
<div>
|
||||||
control={(
|
<FormControlLabel
|
||||||
<Switch
|
control={(
|
||||||
checked={this.state.enabled}
|
<Switch
|
||||||
onChange={(e: any) => this.handleEnableChanged(e)}
|
checked={this.state.enabled}
|
||||||
color="secondary"
|
onChange={(e: any) => this.handleEnableChanged(e)}
|
||||||
/>
|
color="secondary"
|
||||||
)}
|
/>
|
||||||
label="Wi-Fi Direct Hotspot"
|
)}
|
||||||
/>
|
label="Wi-Fi Direct Hotspot"
|
||||||
<div style={{ marginTop: 16 }}>
|
/>
|
||||||
|
</div><div style={{ marginTop: 16 }}>
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
|
|
||||||
@@ -431,7 +432,7 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
id="name"
|
id="name"
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
label="SSID"
|
label="Service Name"
|
||||||
type="text"
|
type="text"
|
||||||
size={this.state.controlSize}
|
size={this.state.controlSize}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -440,10 +441,10 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
|
|||||||
value={this.state.name}
|
value={this.state.name}
|
||||||
onChange={(e) => this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })}
|
onChange={(e) => this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })}
|
||||||
inputRef={this.refName}
|
inputRef={this.refName}
|
||||||
disabled={!this.state.enabled}
|
|
||||||
variant="filled"
|
variant="filled"
|
||||||
/>
|
/>
|
||||||
</div><div>
|
</div>
|
||||||
|
<div>
|
||||||
<TextField
|
<TextField
|
||||||
inputRef={this.refPassword}
|
inputRef={this.refPassword}
|
||||||
sx={{ maxWidth: this.state.controlWidth }}
|
sx={{ maxWidth: this.state.controlWidth }}
|
||||||
|
|||||||
+5
-5
@@ -210,13 +210,13 @@ bool setJackConfiguration(JackServerSettings serverSettings)
|
|||||||
|
|
||||||
silentSysExec("/usr/bin/systemctl unmask jack");
|
silentSysExec("/usr/bin/systemctl unmask jack");
|
||||||
silentSysExec("/usr/bin/systemctl enable jack");
|
silentSysExec("/usr/bin/systemctl enable jack");
|
||||||
#else
|
|
||||||
// otherwise,
|
|
||||||
// the config was written before invoking admin main. but we still need to restart the service.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::thread delayedRestartThread(delayedRestartProc);
|
std::thread delayedRestartThread(delayedRestartProc);
|
||||||
delayedRestartThread.detach();
|
delayedRestartThread.detach();
|
||||||
|
#else
|
||||||
|
// otherwise,
|
||||||
|
// the config was written before invoking admin main and we don't need to to restart the service.
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
-7
@@ -268,6 +268,15 @@ namespace pipedal
|
|||||||
snd_pcm_sw_params_free(playbackSwParams);
|
snd_pcm_sw_params_free(playbackSwParams);
|
||||||
playbackSwParams = nullptr;
|
playbackSwParams = nullptr;
|
||||||
}
|
}
|
||||||
|
for (auto *midiState: this->midiStates)
|
||||||
|
{
|
||||||
|
if (midiState != nullptr)
|
||||||
|
{
|
||||||
|
midiState->Close();
|
||||||
|
delete midiState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
midiStates.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string discover_alsa_using_apps()
|
std::string discover_alsa_using_apps()
|
||||||
@@ -573,9 +582,14 @@ namespace pipedal
|
|||||||
this->channelSelection = channelSelection;
|
this->channelSelection = channelSelection;
|
||||||
|
|
||||||
open = true;
|
open = true;
|
||||||
|
try {
|
||||||
OpenMidi(jackServerSettings, channelSelection);
|
OpenMidi(jackServerSettings, channelSelection);
|
||||||
OpenAudio(jackServerSettings, channelSelection);
|
OpenAudio(jackServerSettings, channelSelection);
|
||||||
|
} catch (const std::exception&e)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenAudio(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection)
|
void OpenAudio(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection)
|
||||||
@@ -1512,7 +1526,7 @@ namespace pipedal
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
for (int retry = 0; retry < 5; ++retry)
|
for (int retry = 0; retry < 15; ++retry)
|
||||||
{
|
{
|
||||||
err = snd_pcm_open(&playbackHandle, alsaDeviceName.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
err = snd_pcm_open(&playbackHandle, alsaDeviceName.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||||
if (err == -EBUSY)
|
if (err == -EBUSY)
|
||||||
@@ -1524,13 +1538,22 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
{
|
{
|
||||||
throw PiPedalStateException(SS(alsaDeviceName << " not found. "
|
throw PiPedalStateException(SS(alsaDeviceName << " playback device not found. "
|
||||||
<< "(" << snd_strerror(err) << ")"));
|
<< "(" << snd_strerror(err) << ")"));
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_open(&captureHandle, alsaDeviceName.c_str(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
for (int retry = 0; retry < 15; ++retry)
|
||||||
|
{
|
||||||
|
err = snd_pcm_open(&captureHandle, alsaDeviceName.c_str(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
||||||
|
if (err == -EBUSY)
|
||||||
|
{
|
||||||
|
sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
throw PiPedalStateException(SS(alsaDeviceName << " not found."));
|
throw PiPedalStateException(SS(alsaDeviceName << " capture device not found."));
|
||||||
|
|
||||||
if (snd_pcm_hw_params_malloc(&playbackHwParams) < 0)
|
if (snd_pcm_hw_params_malloc(&playbackHwParams) < 0)
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,217 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
// avoid breaking changes from 1.64 to.71
|
|
||||||
// Note that raspbian only prvides 1.64; ubuntu studio only provides 1.71
|
|
||||||
#define BOOST_BEAST_ALLOW_DEPRECATED
|
|
||||||
|
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
|
||||||
#include <boost/beast/http.hpp>
|
|
||||||
#include <boost/asio/ip/network_v4.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
#include "Uri.hpp"
|
|
||||||
#include <string_view>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
|
|
||||||
// forward declaration.
|
|
||||||
|
|
||||||
class websocket_session;
|
|
||||||
|
|
||||||
namespace pipedal {
|
|
||||||
using HttpRequest =boost::beast::http::request<boost::beast::http::string_body>;
|
|
||||||
|
|
||||||
|
|
||||||
std::string last_modified(const std::filesystem::path& path);
|
|
||||||
|
|
||||||
class SocketHandler {
|
|
||||||
public:
|
|
||||||
|
|
||||||
class IWriteCallback {
|
|
||||||
public:
|
|
||||||
virtual void close() = 0;
|
|
||||||
|
|
||||||
virtual void writeCallback(const std::string& text) = 0;
|
|
||||||
virtual std::string getFromAddress() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class ::websocket_session;
|
|
||||||
|
|
||||||
|
|
||||||
IWriteCallback *writeCallback_;
|
|
||||||
|
|
||||||
void setWriteCallback(IWriteCallback *writeCallback) {
|
|
||||||
writeCallback_ = writeCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void onReceive(const std::string_view&text) = 0;
|
|
||||||
public:
|
|
||||||
std::string getFromAddress() const { return writeCallback_->getFromAddress(); }
|
|
||||||
void receive(const std::string_view&text) {
|
|
||||||
onReceive(text);
|
|
||||||
}
|
|
||||||
void send(const std::string &text) {
|
|
||||||
if (writeCallback_ != nullptr)
|
|
||||||
{
|
|
||||||
writeCallback_->writeCallback(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual void Close()
|
|
||||||
{
|
|
||||||
writeCallback_->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~SocketHandler() = default;
|
|
||||||
|
|
||||||
virtual void onAttach() { }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class ISocketFactory {
|
|
||||||
public:
|
|
||||||
virtual bool wants(const uri &request) = 0;
|
|
||||||
virtual std::shared_ptr<SocketHandler> CreateHandler(const uri& request) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RequestHandler {
|
|
||||||
private:
|
|
||||||
uri target_url_;
|
|
||||||
public:
|
|
||||||
RequestHandler(const char*target_url)
|
|
||||||
: target_url_(target_url)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
~RequestHandler() = default;
|
|
||||||
|
|
||||||
virtual bool wantsRedirect(const uri& requestUri)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uri GetRedirect(const uri& requestUri)
|
|
||||||
{
|
|
||||||
return requestUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool wants(boost::beast::http::verb verb,const uri &request_uri) const {
|
|
||||||
if (request_uri.segment_count() < target_url_.segment_count())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < target_url_.segment_count(); ++i)
|
|
||||||
{
|
|
||||||
if (request_uri.segment(i) != target_url_.segment(i))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void head_response(
|
|
||||||
const uri&request_uri,
|
|
||||||
const boost::beast::http::request<boost::beast::http::string_body> &req,
|
|
||||||
boost::beast::http::response<boost::beast::http::empty_body> &res,
|
|
||||||
boost::beast::error_code &ec) = 0;
|
|
||||||
|
|
||||||
virtual void get_response(
|
|
||||||
const uri&request_uri,
|
|
||||||
const boost::beast::http::request<boost::beast::http::string_body> &req,
|
|
||||||
boost::beast::http::response<boost::beast::http::string_body> &res,
|
|
||||||
boost::beast::error_code &ec) = 0;
|
|
||||||
|
|
||||||
virtual void post_response(
|
|
||||||
const uri&request_uri,
|
|
||||||
const boost::beast::http::request<boost::beast::http::string_body> &req,
|
|
||||||
boost::beast::http::response<boost::beast::http::string_body> &res,
|
|
||||||
boost::beast::error_code &ec)
|
|
||||||
{
|
|
||||||
get_response(request_uri,req,res,ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
class BeastServer {
|
|
||||||
private:
|
|
||||||
boost::asio::ip::address address;
|
|
||||||
unsigned short port;
|
|
||||||
std::string doc_root;
|
|
||||||
int threads;
|
|
||||||
std::mutex log_mutex;
|
|
||||||
std::vector<std::shared_ptr<RequestHandler> > request_handlers;
|
|
||||||
std::vector<std::shared_ptr<ISocketFactory> > socket_factories;
|
|
||||||
std::mutex io_mutex;
|
|
||||||
boost::asio::io_context *pIoContext = nullptr;
|
|
||||||
void*pListener = nullptr;
|
|
||||||
std::thread*pBgThread = nullptr;
|
|
||||||
|
|
||||||
bool logHttpRequests = false;
|
|
||||||
|
|
||||||
bool hasAccessPointGateway = false;
|
|
||||||
boost::asio::ip::network_v4 accessPointGateway;
|
|
||||||
std::string accessPointServerAddress;
|
|
||||||
bool stopping = false;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
BeastServer(
|
|
||||||
const boost::asio::ip::address& address,
|
|
||||||
int port,
|
|
||||||
const char*rootPath,
|
|
||||||
int threads = 10);
|
|
||||||
|
|
||||||
void Run();
|
|
||||||
void RunInBackground();
|
|
||||||
bool Stopping() const { return this->stopping; }
|
|
||||||
void Stop();
|
|
||||||
void Join();
|
|
||||||
|
|
||||||
void SetLogHttpRequests(bool logRequests) { this->logHttpRequests = logRequests; }
|
|
||||||
bool LogHttpRequests() const { return this->logHttpRequests; }
|
|
||||||
boost::asio::io_context& IoContext() {
|
|
||||||
return *pIoContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddRequestHandler(std::shared_ptr<RequestHandler> requestHandler)
|
|
||||||
{
|
|
||||||
request_handlers.push_back(requestHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddSocketFactory(const std::shared_ptr<ISocketFactory> &socketHandler)
|
|
||||||
{
|
|
||||||
socket_factories.push_back(socketHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<RequestHandler> > &RequestHandlers() { return request_handlers; }
|
|
||||||
|
|
||||||
const std::string&GetDocRoot() { return doc_root; }
|
|
||||||
|
|
||||||
virtual ~BeastServer();
|
|
||||||
|
|
||||||
std::shared_ptr<ISocketFactory> GetSocketFactory(const uri &request_uri);
|
|
||||||
|
|
||||||
void SetAccessPointGateway(const boost::asio::ip::network_v4 &gateway, const std::string&accessPointServerAddress)
|
|
||||||
{
|
|
||||||
this->accessPointGateway = gateway;
|
|
||||||
this->hasAccessPointGateway = true;
|
|
||||||
this->accessPointServerAddress = accessPointServerAddress;
|
|
||||||
}
|
|
||||||
bool HasAccessPointGateway() const { return hasAccessPointGateway; }
|
|
||||||
boost::asio::ip::network_v4 &GetAccessPointGateway() { return this->accessPointGateway; }
|
|
||||||
const std::string & GetAccessPointServerAddress() const { return this->accessPointServerAddress; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual void onError(boost::system::error_code ec, char const* what);
|
|
||||||
virtual void onWarning(boost::system::error_code ec, char const* what);
|
|
||||||
virtual void onInfo(char const* what);
|
|
||||||
|
|
||||||
virtual void onListenerClosed();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace pipedal;
|
|
||||||
+8
-4
@@ -89,9 +89,10 @@ set (PIPEDAL_SOURCES
|
|||||||
CpuUse.hpp CpuUse.cpp
|
CpuUse.hpp CpuUse.cpp
|
||||||
P2pConfigFiles.hpp
|
P2pConfigFiles.hpp
|
||||||
AvahiService.cpp AvahiService.hpp
|
AvahiService.cpp AvahiService.hpp
|
||||||
DeviceIdFile.cpp DeviceIdFile.hpp
|
ServiceConfiguration.cpp ServiceConfiguration.hpp
|
||||||
WriteTemplateFile.cpp WriteTemplateFile.hpp
|
WriteTemplateFile.cpp WriteTemplateFile.hpp
|
||||||
|
ConfigUtil.hpp ConfigUtil.cpp
|
||||||
|
ConfigSerializer.h ConfigSerializer.cpp
|
||||||
StdErrorCapture.hpp StdErrorCapture.cpp
|
StdErrorCapture.hpp StdErrorCapture.cpp
|
||||||
Ipv6Helpers.cpp Ipv6Helpers.hpp
|
Ipv6Helpers.cpp Ipv6Helpers.hpp
|
||||||
PluginPreset.cpp PluginPreset.hpp
|
PluginPreset.cpp PluginPreset.hpp
|
||||||
@@ -236,12 +237,13 @@ add_test(NAME DevTest COMMAND pipedaltest "[Dev]")
|
|||||||
|
|
||||||
add_executable(pipedalconfig
|
add_executable(pipedalconfig
|
||||||
PrettyPrinter.hpp
|
PrettyPrinter.hpp
|
||||||
DeviceIdFile.cpp DeviceIdFile.hpp
|
ServiceConfiguration.cpp ServiceConfiguration.hpp
|
||||||
json.cpp json.hpp
|
json.cpp json.hpp
|
||||||
HtmlHelper.cpp HtmlHelper.hpp
|
HtmlHelper.cpp HtmlHelper.hpp
|
||||||
CommandLineParser.hpp
|
CommandLineParser.hpp
|
||||||
WriteTemplateFile.hpp WriteTemplateFile.cpp
|
WriteTemplateFile.hpp WriteTemplateFile.cpp
|
||||||
PiPedalException.hpp
|
PiPedalException.hpp
|
||||||
|
ConfigSerializer.h ConfigSerializer.cpp
|
||||||
ConfigMain.cpp
|
ConfigMain.cpp
|
||||||
WifiConfigSettings.cpp WifiConfigSettings.hpp
|
WifiConfigSettings.cpp WifiConfigSettings.hpp
|
||||||
WifiDirectConfigSettings.cpp WifiDirectConfigSettings.hpp
|
WifiDirectConfigSettings.cpp WifiDirectConfigSettings.hpp
|
||||||
@@ -283,7 +285,9 @@ target_link_libraries(pipedal_latency_test PRIVATE pthread asound
|
|||||||
|
|
||||||
add_executable(pipedaladmind AdminMain.cpp CommandLineParser.hpp
|
add_executable(pipedaladmind AdminMain.cpp CommandLineParser.hpp
|
||||||
UnixSocket.cpp UnixSocket.hpp
|
UnixSocket.cpp UnixSocket.hpp
|
||||||
DeviceIdFile.cpp DeviceIdFile.hpp
|
ServiceConfiguration.cpp ServiceConfiguration.hpp
|
||||||
|
ConfigSerializer.h ConfigSerializer.cpp
|
||||||
|
autoptr_vector.h
|
||||||
|
|
||||||
JackServerSettings.hpp JackServerSettings.cpp
|
JackServerSettings.hpp JackServerSettings.cpp
|
||||||
json.hpp json.cpp HtmlHelper.hpp HtmlHelper.cpp Lv2Log.hpp Lv2Log.cpp
|
json.hpp json.cpp HtmlHelper.hpp HtmlHelper.cpp Lv2Log.hpp Lv2Log.cpp
|
||||||
|
|||||||
+59
-26
@@ -33,7 +33,7 @@
|
|||||||
#include "JackServerSettings.hpp"
|
#include "JackServerSettings.hpp"
|
||||||
#include "P2pConfigFiles.hpp"
|
#include "P2pConfigFiles.hpp"
|
||||||
#include "PrettyPrinter.hpp"
|
#include "PrettyPrinter.hpp"
|
||||||
#include "DeviceIdFile.hpp"
|
#include "ServiceConfiguration.hpp"
|
||||||
#include <uuid/uuid.h>
|
#include <uuid/uuid.h>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include "AudioConfig.hpp"
|
#include "AudioConfig.hpp"
|
||||||
@@ -366,6 +366,7 @@ void InstallLimits()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if JACK_HOST
|
||||||
void MaybeStartJackService()
|
void MaybeStartJackService()
|
||||||
{
|
{
|
||||||
std::filesystem::path drcFile = "/etc/jackdrc";
|
std::filesystem::path drcFile = "/etc/jackdrc";
|
||||||
@@ -379,7 +380,9 @@ void MaybeStartJackService()
|
|||||||
silentSysExec(SYSTEMCTL_BIN " mask jack");
|
silentSysExec(SYSTEMCTL_BIN " mask jack");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void InstallJackService()
|
#endif
|
||||||
|
|
||||||
|
void InstallAudioService()
|
||||||
{
|
{
|
||||||
InstallLimits();
|
InstallLimits();
|
||||||
InstallPamEnv();
|
InstallPamEnv();
|
||||||
@@ -435,6 +438,28 @@ int SudoExec(char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsP2pServiceEnabled()
|
||||||
|
{
|
||||||
|
WifiDirectConfigSettings settings;
|
||||||
|
settings.Load();
|
||||||
|
return settings.enable_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RestartP2pdService()
|
||||||
|
{
|
||||||
|
if (IsP2pServiceEnabled())
|
||||||
|
{
|
||||||
|
silentSysExec(SYSTEMCTL_BIN " restart " PIPEDAL_P2PD_SERVICE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UninstallP2pdService()
|
||||||
|
{
|
||||||
|
silentSysExec("systemctl stop " PIPEDAL_P2PD_SERVICE);
|
||||||
|
silentSysExec("systemctl disable " PIPEDAL_P2PD_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Uninstall()
|
void Uninstall()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -444,9 +469,13 @@ void Uninstall()
|
|||||||
|
|
||||||
StopService();
|
StopService();
|
||||||
DisableService();
|
DisableService();
|
||||||
|
UninstallP2pdService();
|
||||||
|
|
||||||
|
#if UNINSTALL_JACK_SERVICE
|
||||||
silentSysExec(SYSTEMCTL_BIN " stop jack");
|
silentSysExec(SYSTEMCTL_BIN " stop jack");
|
||||||
silentSysExec(SYSTEMCTL_BIN " disable jack");
|
silentSysExec(SYSTEMCTL_BIN " disable jack");
|
||||||
OnWifiUninstall();
|
#endif
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -545,33 +574,33 @@ static std::string RandomChars(int nchars)
|
|||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrepareDeviceidFile()
|
static void PrepareServiceConfigurationFile(uint16_t portNumber)
|
||||||
{
|
{
|
||||||
if (!std::filesystem::exists(DeviceIdFile::DEVICEID_FILE_NAME))
|
ServiceConfiguration serviceConfiguration;
|
||||||
|
try {
|
||||||
|
serviceConfiguration.Load();
|
||||||
|
} catch (const std::exception &)
|
||||||
{
|
{
|
||||||
DeviceIdFile deviceIdFile;
|
|
||||||
|
|
||||||
deviceIdFile.deviceName = "PiPedal";
|
|
||||||
deviceIdFile.uuid = MakeUuid();
|
|
||||||
deviceIdFile.Save();
|
|
||||||
} else {
|
|
||||||
DeviceIdFile deviceIdFile;
|
|
||||||
if (deviceIdFile.deviceName == "" || deviceIdFile.uuid == "")
|
|
||||||
{
|
|
||||||
if (deviceIdFile.deviceName == "")
|
|
||||||
{
|
|
||||||
deviceIdFile.deviceName = "PiPedal";
|
|
||||||
}
|
|
||||||
if (deviceIdFile.uuid == "")
|
|
||||||
{
|
|
||||||
deviceIdFile.uuid = MakeUuid();
|
|
||||||
}
|
|
||||||
deviceIdFile.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (serviceConfiguration.deviceName == "" || serviceConfiguration.uuid == ""
|
||||||
|
|| portNumber != serviceConfiguration.server_port
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (serviceConfiguration.deviceName == "")
|
||||||
|
{
|
||||||
|
serviceConfiguration.deviceName = "PiPedal";
|
||||||
|
}
|
||||||
|
if (serviceConfiguration.uuid == "")
|
||||||
|
{
|
||||||
|
serviceConfiguration.uuid = MakeUuid();
|
||||||
|
}
|
||||||
|
serviceConfiguration.server_port = portNumber;
|
||||||
|
serviceConfiguration.Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Install(const std::filesystem::path &programPrefix, const std::string endpointAddress)
|
void Install(const std::filesystem::path &programPrefix, const std::string endpointAddress)
|
||||||
{
|
{
|
||||||
if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
|
if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
|
||||||
@@ -583,8 +612,7 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
|||||||
throw PiPedalException("Failed to create pipedald service group.");
|
throw PiPedalException("Failed to create pipedald service group.");
|
||||||
}
|
}
|
||||||
|
|
||||||
PrepareDeviceidFile();
|
InstallAudioService();
|
||||||
InstallJackService();
|
|
||||||
auto endpos = endpointAddress.find_last_of(':');
|
auto endpos = endpointAddress.find_last_of(':');
|
||||||
if (endpos == string::npos)
|
if (endpos == string::npos)
|
||||||
{
|
{
|
||||||
@@ -610,6 +638,9 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
|||||||
s << "Invalid port number: " << strPort;
|
s << "Invalid port number: " << strPort;
|
||||||
throw PiPedalException(s.str());
|
throw PiPedalException(s.str());
|
||||||
}
|
}
|
||||||
|
PrepareServiceConfigurationFile(port);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool authBindRequired = port < 512;
|
bool authBindRequired = port < 512;
|
||||||
|
|
||||||
@@ -744,6 +775,8 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
|||||||
RestartService(false);
|
RestartService(false);
|
||||||
EnableService();
|
EnableService();
|
||||||
|
|
||||||
|
RestartP2pdService();
|
||||||
|
|
||||||
cout << "Complete"
|
cout << "Complete"
|
||||||
<< "\n";
|
<< "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Robin E. R. Davies
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ConfigSerializer.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace config_serializer;
|
||||||
|
using namespace config_serializer::detail;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
std::string config_serializer::detail::trim(const std::string &v)
|
||||||
|
{
|
||||||
|
size_t start = v.find_first_not_of(' ');
|
||||||
|
size_t end = v.find_last_not_of(' ');
|
||||||
|
if (start >= end+1)
|
||||||
|
return "";
|
||||||
|
return v.substr(start, end+1 - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> config_serializer::detail::split(const std::string &value, char delimiter)
|
||||||
|
{
|
||||||
|
size_t start = 0;
|
||||||
|
std::vector<std::string> result;
|
||||||
|
while (start < value.length())
|
||||||
|
{
|
||||||
|
size_t pos = value.find_first_of(delimiter, start);
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
{
|
||||||
|
result.push_back(value.substr(start));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result.push_back(value.substr(start, pos - start));
|
||||||
|
start = pos + 1;
|
||||||
|
if (start == value.length())
|
||||||
|
{
|
||||||
|
// ends with delimieter? Then there's an empty-length value at the end.
|
||||||
|
result.push_back("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::string config_serializer::detail::EncodeString(const std::string &s)
|
||||||
|
{
|
||||||
|
bool requiresEncoding = false;
|
||||||
|
|
||||||
|
for (char c : s)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\0':
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
case '\t':
|
||||||
|
case '\\':
|
||||||
|
case ' ':
|
||||||
|
case '\"':
|
||||||
|
requiresEncoding = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!requiresEncoding)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
ss << '"';
|
||||||
|
for (char c : s)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\0':
|
||||||
|
// discard.
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
ss << "\\r";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
ss << "\\t";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
ss << "\\\\";
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
ss << "\\\"";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ss << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ss << '"';
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string config_serializer::detail::DecodeString(const std::string &value)
|
||||||
|
{
|
||||||
|
std::stringstream s;
|
||||||
|
const char *p = value.c_str();
|
||||||
|
char quoteChar;
|
||||||
|
if (*p == '\'' || *p == '\"')
|
||||||
|
{
|
||||||
|
quoteChar = *p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (*p != quoteChar)
|
||||||
|
return value;
|
||||||
|
if (value.at(value.length()-1) != quoteChar)
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Invalid quoted string.");
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
while (*p != 0 && *p != quoteChar)
|
||||||
|
{
|
||||||
|
char c = *p++;
|
||||||
|
if (c == '\\')
|
||||||
|
{
|
||||||
|
c = *p++;
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'r':
|
||||||
|
s << '\r';
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
s << '\t';
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
s << '\n';
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
throw std::invalid_argument("Invalid quoted string.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s << c;
|
||||||
|
}
|
||||||
|
if (c != 0)
|
||||||
|
{
|
||||||
|
s << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,369 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Robin E. R. Davies
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <exception>
|
||||||
|
#include "autoptr_vector.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace config_serializer
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
std::string trim(const std::string &v);
|
||||||
|
|
||||||
|
std::vector<std::string> split(const std::string &v, char seperator);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert string to config file format.
|
||||||
|
*
|
||||||
|
* Adds quotes and escapes, but only if neccessary.
|
||||||
|
*
|
||||||
|
* Source text is assumed to be UTF-8. Escapes for the
|
||||||
|
* following values only: \r \n \t \" \\.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* @return std::string Encoded string.
|
||||||
|
*/
|
||||||
|
std::string EncodeString(const std::string &s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Config file format to string.
|
||||||
|
*
|
||||||
|
* Decodes quotes and escapes, but only if neccessary.
|
||||||
|
*
|
||||||
|
* Source text is assumed to be UTF-8. Escapes for the
|
||||||
|
* following values only: \r \n \t \" \\.
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* @return std::string
|
||||||
|
*/
|
||||||
|
std::string DecodeString(const std::string &s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert a string to an integer.
|
||||||
|
*
|
||||||
|
* @tparam T A signed or unsigned integral type.
|
||||||
|
* @param value The string to parse.
|
||||||
|
* @return T The parsed result.
|
||||||
|
* @throws std::invalid_argument if the supplied string is not a valid integer.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
T ToInt(const std::string &value)
|
||||||
|
{
|
||||||
|
std::stringstream s(value);
|
||||||
|
T result;
|
||||||
|
s >> result;
|
||||||
|
if (s.fail())
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Invalid integer value.");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace detail;
|
||||||
|
|
||||||
|
template <class OBJ>
|
||||||
|
class ConfigSerializerBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ConfigSerializerBase(const std::string &name, const std::string &comment)
|
||||||
|
: name(name),
|
||||||
|
comment(comment)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Obj = OBJ;
|
||||||
|
virtual ~ConfigSerializerBase() {}
|
||||||
|
|
||||||
|
const std::string &GetName() const { return name; }
|
||||||
|
const std::string &GetComment() const { return comment; }
|
||||||
|
virtual void SetValue(Obj &configurable, const std::string &value) const = 0;
|
||||||
|
virtual const std::string GetValue(Obj &configurable) const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name;
|
||||||
|
std::string comment;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class ConfigConverter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static T FromString(const std::string &value)
|
||||||
|
{
|
||||||
|
T result;
|
||||||
|
std::stringstream s(value);
|
||||||
|
s >> result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string ToString(const T &value)
|
||||||
|
{
|
||||||
|
std::stringstream s;
|
||||||
|
s << value;
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// string specializations.
|
||||||
|
template <>
|
||||||
|
inline std::string ConfigConverter<std::string>::FromString(const std::string &value)
|
||||||
|
{
|
||||||
|
return DecodeString(value);
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
inline std::string ConfigConverter<std::string>::ToString(const std::string &config)
|
||||||
|
{
|
||||||
|
return EncodeString(config);
|
||||||
|
}
|
||||||
|
// bool specializations.
|
||||||
|
template <>
|
||||||
|
inline bool ConfigConverter<bool>::FromString(const std::string &value)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
if (value == "")
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
else if (value == "true")
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
else if (value == "false")
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int t = ToInt<int>(value);
|
||||||
|
result = (t != 0);
|
||||||
|
}
|
||||||
|
catch (const std::exception &)
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Expecting true or false.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
inline std::string ConfigConverter<bool>::ToString(const bool &value)
|
||||||
|
{
|
||||||
|
return value ? "true" : "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class OBJ, class T>
|
||||||
|
class ConfigSerializer : public ConfigSerializerBase<OBJ>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Obj = OBJ;
|
||||||
|
using pointer_type = T Obj::*;
|
||||||
|
using base = ConfigSerializerBase<Obj>;
|
||||||
|
using converter = ConfigConverter<T>;
|
||||||
|
|
||||||
|
ConfigSerializer(const std::string &name,
|
||||||
|
pointer_type pMember,
|
||||||
|
const std::string &comment)
|
||||||
|
: base(name, comment),
|
||||||
|
pMember(pMember)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual void SetValue(Obj &configurable, const std::string &value) const
|
||||||
|
{
|
||||||
|
configurable.*pMember = ConfigConverter<T>::FromString(value);
|
||||||
|
}
|
||||||
|
virtual const std::string GetValue(Obj &configurable) const
|
||||||
|
{
|
||||||
|
return ConfigConverter<T>::ToString(configurable.*pMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
pointer_type pMember;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class OBJ>
|
||||||
|
class ConfigSerializable
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using Obj = OBJ;
|
||||||
|
|
||||||
|
using serializer_t = ConfigSerializerBase<OBJ>;
|
||||||
|
using serializers_t = p2p::autoptr_vector<serializer_t>;
|
||||||
|
|
||||||
|
const serializers_t &serializers;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ConfigSerializable(const serializers_t &serializers)
|
||||||
|
: serializers(serializers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void Save(std::ostream &f)
|
||||||
|
{
|
||||||
|
bool firstLine = true;
|
||||||
|
for (const serializer_t *serializer : serializers)
|
||||||
|
{
|
||||||
|
if (serializer->GetComment().length() != 0)
|
||||||
|
{
|
||||||
|
if (!firstLine)
|
||||||
|
{
|
||||||
|
f << std::endl;
|
||||||
|
}
|
||||||
|
firstLine = false;
|
||||||
|
std::vector<std::string> comments = split(serializer->GetComment(), '\n');
|
||||||
|
|
||||||
|
if (comments.size() != 0)
|
||||||
|
for (const std::string &comment : comments)
|
||||||
|
{
|
||||||
|
f << "# " << comment << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f << serializer->GetName() << '=' << serializer->GetValue((Obj &)*this) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Save(const std::string &path)
|
||||||
|
{
|
||||||
|
std::ofstream f;
|
||||||
|
f.open(path);
|
||||||
|
if (!f.is_open())
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Can't write to file " + path);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Save(f);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Error writing to '" + path + "'. " + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Load(std::istream &f)
|
||||||
|
{
|
||||||
|
std::unordered_map<std::string, serializer_t *> index;
|
||||||
|
|
||||||
|
for (serializer_t *serializer : serializers)
|
||||||
|
{
|
||||||
|
index[serializer->GetName()] = serializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
int nLine = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (f.eof())
|
||||||
|
break;
|
||||||
|
getline(f, line);
|
||||||
|
++nLine;
|
||||||
|
|
||||||
|
// remove comments.
|
||||||
|
auto npos = line.find_first_of('#');
|
||||||
|
if (npos != std::string::npos)
|
||||||
|
{
|
||||||
|
line = line.substr(0, npos);
|
||||||
|
}
|
||||||
|
size_t start = 0;
|
||||||
|
while (start < line.size() && line[start] == ' ')
|
||||||
|
{
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
if (start == line.size())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pos = line.find_first_of('=', start);
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
{
|
||||||
|
std::stringstream msg;
|
||||||
|
|
||||||
|
msg << "(" << nLine << "," << (start + 1) << "): Syntax error. Expecting '='.";
|
||||||
|
throw std::logic_error(msg.str());
|
||||||
|
}
|
||||||
|
std::string label = trim(line.substr(start, pos - start));
|
||||||
|
std::string value = trim(line.substr(pos + 1));
|
||||||
|
|
||||||
|
if (index.contains(label))
|
||||||
|
{
|
||||||
|
serializer_t *serializer = index[label];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
serializer->SetValue((Obj &)*this, value);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "(" << nLine << ',' << (pos + 1) << "): " << e.what();
|
||||||
|
throw std::logic_error(msg.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "(" << nLine << ',' << (start) << "): "
|
||||||
|
<< "Invalid property: " + label;
|
||||||
|
throw std::logic_error(
|
||||||
|
msg.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Load(const std::string &path, bool throwIfNotFound = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::ifstream f;
|
||||||
|
f.open(path);
|
||||||
|
if (!f.is_open())
|
||||||
|
{
|
||||||
|
if (throwIfNotFound)
|
||||||
|
{
|
||||||
|
throw std::logic_error("Can't open file.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Load(f);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "Error: " << path << " " << e.what();
|
||||||
|
throw std::logic_error(msg.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
+8
-1
@@ -161,6 +161,12 @@ private:
|
|||||||
|
|
||||||
isOpen = false;
|
isOpen = false;
|
||||||
StopReaderThread();
|
StopReaderThread();
|
||||||
|
|
||||||
|
if (realtimeMonitorPortSubscriptions != nullptr)
|
||||||
|
{
|
||||||
|
delete realtimeMonitorPortSubscriptions;
|
||||||
|
realtimeMonitorPortSubscriptions = nullptr;
|
||||||
|
}
|
||||||
if (active)
|
if (active)
|
||||||
{
|
{
|
||||||
audioDriver->Deactivate();
|
audioDriver->Deactivate();
|
||||||
@@ -933,8 +939,9 @@ public:
|
|||||||
Lv2Log::info("Audio started.");
|
Lv2Log::info("Audio started.");
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (PiPedalException &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
|
Lv2Log::error(SS("Failed to start audio. " << e.what()));
|
||||||
Close();
|
Close();
|
||||||
active = false;
|
active = false;
|
||||||
throw;
|
throw;
|
||||||
|
|||||||
@@ -785,6 +785,9 @@ Lv2PortInfo::Lv2PortInfo(Lv2Host *host, const LilvPlugin *plugin, const LilvPort
|
|||||||
NodeAutoFree unitsValueUri = lilv_port_get(plugin, pPort, host->lilvUris.unitsUri);
|
NodeAutoFree unitsValueUri = lilv_port_get(plugin, pPort, host->lilvUris.unitsUri);
|
||||||
this->units_ = UriToUnits(nodeAsString(unitsValueUri));
|
this->units_ = UriToUnits(nodeAsString(unitsValueUri));
|
||||||
|
|
||||||
|
NodeAutoFree commentNode = lilv_port_get(plugin,pPort,host->lilvUris.rdfsComment);
|
||||||
|
this->comment_ = nodeAsString(commentNode);
|
||||||
|
|
||||||
NodeAutoFree bufferType = lilv_port_get(plugin, pPort, host->lilvUris.bufferType_uri);
|
NodeAutoFree bufferType = lilv_port_get(plugin, pPort, host->lilvUris.bufferType_uri);
|
||||||
|
|
||||||
this->buffer_type_ = "";
|
this->buffer_type_ = "";
|
||||||
@@ -1167,6 +1170,7 @@ json_map::storage_type<Lv2PortInfo> Lv2PortInfo::jmap{{
|
|||||||
MAP_REF(Lv2PortInfo, buffer_type),
|
MAP_REF(Lv2PortInfo, buffer_type),
|
||||||
MAP_REF(Lv2PortInfo, port_group),
|
MAP_REF(Lv2PortInfo, port_group),
|
||||||
json_map::enum_reference("units", &Lv2PortInfo::units_, get_units_enum_converter()),
|
json_map::enum_reference("units", &Lv2PortInfo::units_, get_units_enum_converter()),
|
||||||
|
MAP_REF(Lv2PortInfo, comment)
|
||||||
}};
|
}};
|
||||||
|
|
||||||
json_map::storage_type<Lv2PortGroup> Lv2PortGroup::jmap{{
|
json_map::storage_type<Lv2PortGroup> Lv2PortGroup::jmap{{
|
||||||
@@ -1229,6 +1233,7 @@ json_map::storage_type<Lv2PluginUiControlPort> Lv2PluginUiControlPort::jmap{{
|
|||||||
MAP_REF(Lv2PluginUiControlPort, port_group),
|
MAP_REF(Lv2PluginUiControlPort, port_group),
|
||||||
|
|
||||||
json_map::enum_reference("units", &Lv2PluginUiControlPort::units_, get_units_enum_converter()),
|
json_map::enum_reference("units", &Lv2PluginUiControlPort::units_, get_units_enum_converter()),
|
||||||
|
MAP_REF(Lv2PluginUiControlPort, comment),
|
||||||
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ private:
|
|||||||
|
|
||||||
std::string designation_;
|
std::string designation_;
|
||||||
Units units_ = Units::none;
|
Units units_ = Units::none;
|
||||||
|
std::string comment_;
|
||||||
public:
|
public:
|
||||||
bool IsSwitch() const {
|
bool IsSwitch() const {
|
||||||
return min_value_ == 0 && max_value_ == 1
|
return min_value_ == 0 && max_value_ == 1
|
||||||
@@ -261,6 +262,7 @@ public:
|
|||||||
LV2_PROPERTY_GETSET_SCALAR(toggled_property);
|
LV2_PROPERTY_GETSET_SCALAR(toggled_property);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(not_on_gui);
|
LV2_PROPERTY_GETSET_SCALAR(not_on_gui);
|
||||||
LV2_PROPERTY_GETSET(port_group);
|
LV2_PROPERTY_GETSET(port_group);
|
||||||
|
LV2_PROPERTY_GETSET(comment);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(units);
|
LV2_PROPERTY_GETSET_SCALAR(units);
|
||||||
|
|
||||||
LV2_PROPERTY_GETSET(buffer_type);
|
LV2_PROPERTY_GETSET(buffer_type);
|
||||||
@@ -417,6 +419,7 @@ public:
|
|||||||
, toggled_property_(pPort->toggled_property())
|
, toggled_property_(pPort->toggled_property())
|
||||||
, not_on_gui_(pPort->not_on_gui())
|
, not_on_gui_(pPort->not_on_gui())
|
||||||
, scale_points_(pPort->scale_points())
|
, scale_points_(pPort->scale_points())
|
||||||
|
, comment_(pPort->comment())
|
||||||
, units_(pPort->units())
|
, units_(pPort->units())
|
||||||
{
|
{
|
||||||
// Use symbols to index port groups, instead of uris.
|
// Use symbols to index port groups, instead of uris.
|
||||||
@@ -450,6 +453,7 @@ private:
|
|||||||
std::vector<Lv2ScalePoint> scale_points_;
|
std::vector<Lv2ScalePoint> scale_points_;
|
||||||
std::string port_group_;
|
std::string port_group_;
|
||||||
Units units_ = Units::none;
|
Units units_ = Units::none;
|
||||||
|
std::string comment_;
|
||||||
public:
|
public:
|
||||||
LV2_PROPERTY_GETSET(symbol);
|
LV2_PROPERTY_GETSET(symbol);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(index);
|
LV2_PROPERTY_GETSET_SCALAR(index);
|
||||||
@@ -466,6 +470,7 @@ public:
|
|||||||
LV2_PROPERTY_GETSET_SCALAR(not_on_gui);
|
LV2_PROPERTY_GETSET_SCALAR(not_on_gui);
|
||||||
LV2_PROPERTY_GETSET(scale_points);
|
LV2_PROPERTY_GETSET(scale_points);
|
||||||
LV2_PROPERTY_GETSET(units);
|
LV2_PROPERTY_GETSET(units);
|
||||||
|
LV2_PROPERTY_GETSET(comment);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static json_map::storage_type<Lv2PluginUiControlPort> jmap;
|
static json_map::storage_type<Lv2PluginUiControlPort> jmap;
|
||||||
|
|||||||
+155
-84
@@ -18,8 +18,9 @@
|
|||||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "DeviceIdFile.hpp"
|
#include "ServiceConfiguration.hpp"
|
||||||
#include "AudioConfig.hpp"
|
#include "AudioConfig.hpp"
|
||||||
|
#include "ConfigUtil.hpp"
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include "PiPedalModel.hpp"
|
#include "PiPedalModel.hpp"
|
||||||
#include "JackHost.hpp"
|
#include "JackHost.hpp"
|
||||||
@@ -55,8 +56,6 @@ PiPedalModel::PiPedalModel()
|
|||||||
#else
|
#else
|
||||||
this->jackServerSettings = this->storage.GetJackServerSettings();
|
this->jackServerSettings = this->storage.GetJackServerSettings();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::Close()
|
void PiPedalModel::Close()
|
||||||
@@ -84,37 +83,40 @@ void PiPedalModel::Close()
|
|||||||
|
|
||||||
PiPedalModel::~PiPedalModel()
|
PiPedalModel::~PiPedalModel()
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
adminClient.UnmonitorGovernor();
|
{
|
||||||
} catch (...) // noexcept here!
|
adminClient.UnmonitorGovernor();
|
||||||
|
}
|
||||||
|
catch (...) // noexcept here!
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
CurrentPreset currentPreset;
|
CurrentPreset currentPreset;
|
||||||
currentPreset.modified_ = this->hasPresetChanged;
|
currentPreset.modified_ = this->hasPresetChanged;
|
||||||
currentPreset.preset_ = this->pedalBoard;
|
currentPreset.preset_ = this->pedalBoard;
|
||||||
storage.SaveCurrentPreset(currentPreset);
|
storage.SaveCurrentPreset(currentPreset);
|
||||||
} catch (...)
|
}
|
||||||
|
catch (...)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
if (jackHost)
|
if (jackHost)
|
||||||
{
|
{
|
||||||
jackHost->Close();
|
jackHost->Close();
|
||||||
}
|
}
|
||||||
} catch (...)
|
}
|
||||||
|
catch (...)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
void PiPedalModel::Init(const PiPedalConfiguration&configuration)
|
void PiPedalModel::Init(const PiPedalConfiguration &configuration)
|
||||||
{
|
{
|
||||||
this->configuration = configuration;
|
this->configuration = configuration;
|
||||||
storage.SetConfigRoot(configuration.GetDocRoot());
|
storage.SetConfigRoot(configuration.GetDocRoot());
|
||||||
@@ -122,7 +124,6 @@ void PiPedalModel::Init(const PiPedalConfiguration&configuration)
|
|||||||
storage.Initialize();
|
storage.Initialize();
|
||||||
|
|
||||||
this->jackServerSettings.ReadJackConfiguration();
|
this->jackServerSettings.ReadJackConfiguration();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::LoadLv2PluginInfo()
|
void PiPedalModel::LoadLv2PluginInfo()
|
||||||
@@ -147,14 +148,14 @@ void PiPedalModel::LoadLv2PluginInfo()
|
|||||||
// Copy all presets out of Lilv data to json files
|
// Copy all presets out of Lilv data to json files
|
||||||
// so that we can close lilv while we're actually
|
// so that we can close lilv while we're actually
|
||||||
// running.
|
// running.
|
||||||
for (const auto&plugin: lv2Host.GetPlugins())
|
for (const auto &plugin : lv2Host.GetPlugins())
|
||||||
{
|
{
|
||||||
if (plugin->has_factory_presets())
|
if (plugin->has_factory_presets())
|
||||||
{
|
{
|
||||||
if (!storage.HasPluginPresets(plugin->uri()))
|
if (!storage.HasPluginPresets(plugin->uri()))
|
||||||
{
|
{
|
||||||
PluginPresets pluginPresets = lv2Host.GetFactoryPluginPresets(plugin->uri());
|
PluginPresets pluginPresets = lv2Host.GetFactoryPluginPresets(plugin->uri());
|
||||||
storage.SavePluginPresets(plugin->uri(),pluginPresets);
|
storage.SavePluginPresets(plugin->uri(), pluginPresets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,7 +166,6 @@ void PiPedalModel::Load()
|
|||||||
this->webRoot = configuration.GetWebRoot();
|
this->webRoot = configuration.GetWebRoot();
|
||||||
this->webPort = (uint16_t)configuration.GetSocketServerPort();
|
this->webPort = (uint16_t)configuration.GetSocketServerPort();
|
||||||
|
|
||||||
|
|
||||||
adminClient.MonitorGovernor(storage.GetGovernorSettings());
|
adminClient.MonitorGovernor(storage.GetGovernorSettings());
|
||||||
|
|
||||||
// lv2Host.Load(configuration.GetLv2Path().c_str());
|
// lv2Host.Load(configuration.GetLv2Path().c_str());
|
||||||
@@ -200,8 +200,8 @@ void PiPedalModel::Load()
|
|||||||
|
|
||||||
struct sched_param scheduler_params;
|
struct sched_param scheduler_params;
|
||||||
scheduler_params.sched_priority = 10;
|
scheduler_params.sched_priority = 10;
|
||||||
memset(&scheduler_params,0,sizeof(sched_param));
|
memset(&scheduler_params, 0, sizeof(sched_param));
|
||||||
sched_setscheduler(0,SCHED_RR,&scheduler_params);
|
sched_setscheduler(0, SCHED_RR, &scheduler_params);
|
||||||
#if JACK_HOST
|
#if JACK_HOST
|
||||||
this->jackConfiguration = this->jackConfiguration.JackInitialize();
|
this->jackConfiguration = this->jackConfiguration.JackInitialize();
|
||||||
#else
|
#else
|
||||||
@@ -216,7 +216,7 @@ void PiPedalModel::Load()
|
|||||||
this->lv2Host.OnConfigurationChanged(jackConfiguration, selection);
|
this->lv2Host.OnConfigurationChanged(jackConfiguration, selection);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
jackHost->Open(this->jackServerSettings,selection);
|
jackHost->Open(this->jackServerSettings, selection);
|
||||||
|
|
||||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
||||||
this->lv2PedalBoard = lv2PedalBoard;
|
this->lv2PedalBoard = lv2PedalBoard;
|
||||||
@@ -226,7 +226,9 @@ void PiPedalModel::Load()
|
|||||||
{
|
{
|
||||||
Lv2Log::error("Failed to load initial plugin. (%s)", e.what());
|
Lv2Log::error("Failed to load initial plugin. (%s)", e.what());
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Lv2Log::error("Audio device not configured.");
|
Lv2Log::error("Audio device not configured.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -453,7 +455,7 @@ void PiPedalModel::FirePresetsChanged(int64_t clientId)
|
|||||||
delete[] t;
|
delete[] t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void PiPedalModel::FirePluginPresetsChanged(const std::string & pluginUri)
|
void PiPedalModel::FirePluginPresetsChanged(const std::string &pluginUri)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
{
|
{
|
||||||
@@ -473,7 +475,6 @@ void PiPedalModel::FirePluginPresetsChanged(const std::string & pluginUri)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::SaveCurrentPreset(int64_t clientId)
|
void PiPedalModel::SaveCurrentPreset(int64_t clientId)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
@@ -482,31 +483,31 @@ void PiPedalModel::SaveCurrentPreset(int64_t clientId)
|
|||||||
this->SetPresetChanged(clientId, false);
|
this->SetPresetChanged(clientId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t PiPedalModel::CopyPluginPreset(const std::string&pluginUri,uint64_t presetId)
|
uint64_t PiPedalModel::CopyPluginPreset(const std::string &pluginUri, uint64_t presetId)
|
||||||
{
|
{
|
||||||
uint64_t result = storage.CopyPluginPreset(pluginUri,presetId);
|
uint64_t result = storage.CopyPluginPreset(pluginUri, presetId);
|
||||||
FirePluginPresetsChanged(pluginUri);
|
FirePluginPresetsChanged(pluginUri);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::UpdatePluginPresets(const PluginUiPresets&pluginPresets)
|
void PiPedalModel::UpdatePluginPresets(const PluginUiPresets &pluginPresets)
|
||||||
{
|
{
|
||||||
storage.UpdatePluginPresets(pluginPresets);
|
storage.UpdatePluginPresets(pluginPresets);
|
||||||
FirePluginPresetsChanged(pluginPresets.pluginUri_);
|
FirePluginPresetsChanged(pluginPresets.pluginUri_);
|
||||||
}
|
}
|
||||||
int64_t PiPedalModel::SavePluginPresetAs(int64_t instanceId, const std::string&name)
|
int64_t PiPedalModel::SavePluginPresetAs(int64_t instanceId, const std::string &name)
|
||||||
{
|
{
|
||||||
auto *item = this->pedalBoard.GetItem(instanceId);
|
auto *item = this->pedalBoard.GetItem(instanceId);
|
||||||
if (!item)
|
if (!item)
|
||||||
{
|
{
|
||||||
throw PiPedalException("Plugin not found.");
|
throw PiPedalException("Plugin not found.");
|
||||||
}
|
}
|
||||||
std::map<std::string,float> values;
|
std::map<std::string, float> values;
|
||||||
for (const auto & controlValue: item->controlValues())
|
for (const auto &controlValue : item->controlValues())
|
||||||
{
|
{
|
||||||
values[controlValue.key()] = controlValue.value();
|
values[controlValue.key()] = controlValue.value();
|
||||||
}
|
}
|
||||||
uint64_t presetId = storage.SavePluginPreset(item->uri(),name,values);
|
uint64_t presetId = storage.SavePluginPreset(item->uri(), name, values);
|
||||||
FirePluginPresetsChanged(item->uri());
|
FirePluginPresetsChanged(item->uri());
|
||||||
return presetId;
|
return presetId;
|
||||||
}
|
}
|
||||||
@@ -522,16 +523,15 @@ int64_t PiPedalModel::SaveCurrentPresetAs(int64_t clientId, const std::string &n
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::UploadPluginPresets(const PluginPresets&pluginPresets)
|
void PiPedalModel::UploadPluginPresets(const PluginPresets &pluginPresets)
|
||||||
{
|
{
|
||||||
if (pluginPresets.pluginUri_.length() == 0)
|
if (pluginPresets.pluginUri_.length() == 0)
|
||||||
{
|
{
|
||||||
throw PiPedalException("Invalid plugin presets.");
|
throw PiPedalException("Invalid plugin presets.");
|
||||||
}
|
}
|
||||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
storage.SavePluginPresets(pluginPresets.pluginUri_,pluginPresets);
|
storage.SavePluginPresets(pluginPresets.pluginUri_, pluginPresets);
|
||||||
FirePluginPresetsChanged(pluginPresets.pluginUri_);
|
FirePluginPresetsChanged(pluginPresets.pluginUri_);
|
||||||
|
|
||||||
}
|
}
|
||||||
int64_t PiPedalModel::UploadPreset(const BankFile &bankFile, int64_t uploadAfter)
|
int64_t PiPedalModel::UploadPreset(const BankFile &bankFile, int64_t uploadAfter)
|
||||||
{
|
{
|
||||||
@@ -649,7 +649,7 @@ GovernorSettings PiPedalModel::GetGovernorSettings()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void PiPedalModel::SetGovernorSettings(const std::string& governor)
|
void PiPedalModel::SetGovernorSettings(const std::string &governor)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
adminClient.SetGovernorSettings(governor);
|
adminClient.SetGovernorSettings(governor);
|
||||||
@@ -669,7 +669,6 @@ void PiPedalModel::SetGovernorSettings(const std::string& governor)
|
|||||||
}
|
}
|
||||||
delete[] t;
|
delete[] t;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
|
void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
|
||||||
@@ -698,22 +697,46 @@ void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static std::string GetP2pdName()
|
||||||
|
{
|
||||||
|
std::string name = "/etc/pipedal/config/pipedal_p2pd.conf";
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
if (ConfigUtil::GetConfigLine(name,"p2p_device_name",&result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void PiPedalModel::UpdateDnsSd()
|
void PiPedalModel::UpdateDnsSd()
|
||||||
{
|
{
|
||||||
avahiService.Unannounce();
|
avahiService.Unannounce();
|
||||||
|
|
||||||
DeviceIdFile deviceIdFile;
|
ServiceConfiguration deviceIdFile;
|
||||||
deviceIdFile.Load();
|
deviceIdFile.Load();
|
||||||
|
|
||||||
|
|
||||||
|
std::string p2pdName = GetP2pdName();
|
||||||
|
if (p2pdName != "") {
|
||||||
|
deviceIdFile.deviceName = p2pdName;
|
||||||
|
}
|
||||||
|
|
||||||
if (deviceIdFile.deviceName != "" && deviceIdFile.uuid != "")
|
if (deviceIdFile.deviceName != "" && deviceIdFile.uuid != "")
|
||||||
{
|
{
|
||||||
avahiService.Announce(webPort,deviceIdFile.deviceName,deviceIdFile.uuid,"pipedal");
|
avahiService.Announce(webPort, deviceIdFile.deviceName, deviceIdFile.uuid, "pipedal");
|
||||||
} else {
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// device_uuid file is written at install time. This warning is harmless if you're debugging.
|
// device_uuid file is written at install time. This warning is harmless if you're debugging.
|
||||||
// Without it, we can't pulblish the website via dnsDS.
|
// Without it, we can't pulblish the website via dnsDS.
|
||||||
// Run "pipedalconfig --install" to create the file.
|
// Run "pipedalconfig --install" to create the file.
|
||||||
Lv2Log::warning("Cant read device_uuid file. dnsSD announcement skipped.");
|
Lv2Log::warning("Cant read device_uuid file from service.conf file. dnsSD announcement skipped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
void PiPedalModel::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiDirectConfigSettings)
|
void PiPedalModel::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiDirectConfigSettings)
|
||||||
{
|
{
|
||||||
@@ -741,11 +764,7 @@ void PiPedalModel::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &w
|
|||||||
|
|
||||||
// update NSD-SD announement.
|
// update NSD-SD announement.
|
||||||
UpdateDnsSd();
|
UpdateDnsSd();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WifiConfigSettings PiPedalModel::GetWifiConfigSettings()
|
WifiConfigSettings PiPedalModel::GetWifiConfigSettings()
|
||||||
@@ -786,7 +805,6 @@ bool PiPedalModel::GetShowStatusMonitor()
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex); // copy atomically.
|
std::lock_guard<std::recursive_mutex> guard(mutex); // copy atomically.
|
||||||
return storage.GetShowStatusMonitor();
|
return storage.GetShowStatusMonitor();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JackConfiguration PiPedalModel::GetJackConfiguration()
|
JackConfiguration PiPedalModel::GetJackConfiguration()
|
||||||
@@ -795,18 +813,13 @@ JackConfiguration PiPedalModel::GetJackConfiguration()
|
|||||||
return this->jackConfiguration;
|
return this->jackConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::SetJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection)
|
void PiPedalModel::RestartAudio()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex); // copy atomically.
|
|
||||||
this->storage.SetJackChannelSelection(channelSelection);
|
|
||||||
this->FireChannelSelectionChanged(clientId);
|
|
||||||
|
|
||||||
this->lv2Host.OnConfigurationChanged(jackConfiguration, channelSelection);
|
|
||||||
if (this->jackHost->IsOpen())
|
if (this->jackHost->IsOpen())
|
||||||
{
|
{
|
||||||
|
|
||||||
this->jackHost->Close();
|
this->jackHost->Close();
|
||||||
#ifdef JUNK
|
}
|
||||||
// restarting is a bit dodgy. It was impossible with Jack, but
|
// restarting is a bit dodgy. It was impossible with Jack, but
|
||||||
// now very plausible with the ALSA audio stack.
|
// now very plausible with the ALSA audio stack.
|
||||||
|
|
||||||
@@ -818,14 +831,64 @@ void PiPedalModel::SetJackChannelSelection(int64_t clientId, const JackChannelSe
|
|||||||
|
|
||||||
// do a complete reload.
|
// do a complete reload.
|
||||||
|
|
||||||
this->jackHost->SetPedalBoard(nullptr);
|
this->jackHost->SetPedalBoard(nullptr);
|
||||||
this->jackHost->Open(this->jackServerSettings,channelSelection);
|
|
||||||
|
this->jackConfiguration.AlsaInitialize(this->jackServerSettings);
|
||||||
|
|
||||||
|
if (this->jackConfiguration.isValid())
|
||||||
|
{
|
||||||
|
JackChannelSelection selection = storage.GetJackChannelSelection(jackConfiguration);
|
||||||
|
selection = selection.RemoveInvalidChannels(jackConfiguration);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
jackConfiguration.SetErrorStatus("Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
FireJackConfigurationChanged(jackConfiguration);
|
||||||
|
|
||||||
|
|
||||||
|
if (!jackServerSettings.IsValid() || !jackConfiguration.isValid())
|
||||||
|
{
|
||||||
|
Lv2Log::error("Audio configuration not valid.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JackChannelSelection channelSelection = GetJackChannelSelection();
|
||||||
|
if (!channelSelection.isValid())
|
||||||
|
{
|
||||||
|
Lv2Log::error("Audio configuration not valid.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->jackHost->Open(this->jackServerSettings, channelSelection);
|
||||||
|
|
||||||
|
this->lv2Host.OnConfigurationChanged(jackConfiguration, channelSelection);
|
||||||
|
|
||||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
||||||
this->lv2PedalBoard = lv2PedalBoard;
|
this->lv2PedalBoard = lv2PedalBoard;
|
||||||
jackHost->SetPedalBoard(lv2PedalBoard);
|
jackHost->SetPedalBoard(lv2PedalBoard);
|
||||||
this->UpdateRealtimeVuSubscriptions();
|
this->UpdateRealtimeVuSubscriptions();
|
||||||
#endif
|
UpdateRealtimeMonitorPortSubscriptions();
|
||||||
}
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
Lv2Log::error(SS("Failed to start audio. " << e.what()));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PiPedalModel::SetJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mutex); // copy atomically.
|
||||||
|
this->storage.SetJackChannelSelection(channelSelection);
|
||||||
|
|
||||||
|
this->lv2Host.OnConfigurationChanged(jackConfiguration, channelSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
RestartAudio(); // no lock to avoid mutex deadlock when reader thread is sending notifications..
|
||||||
|
|
||||||
|
this->FireChannelSelectionChanged(clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::FireChannelSelectionChanged(int64_t clientId)
|
void PiPedalModel::FireChannelSelectionChanged(int64_t clientId)
|
||||||
@@ -1024,7 +1087,6 @@ void PiPedalModel::UnmonitorPort(int64_t subscriptionHandle)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::OnNotifyMonitorPort(const MonitorPortUpdate &update)
|
void PiPedalModel::OnNotifyMonitorPort(const MonitorPortUpdate &update)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
@@ -1095,7 +1157,7 @@ void PiPedalModel::GetLv2Parameter(
|
|||||||
|
|
||||||
BankIndex PiPedalModel::GetBankIndex() const
|
BankIndex PiPedalModel::GetBankIndex() const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(const_cast<std::recursive_mutex&>(mutex));
|
std::lock_guard<std::recursive_mutex> guard(const_cast<std::recursive_mutex &>(mutex));
|
||||||
return storage.GetBanks();
|
return storage.GetBanks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1137,16 +1199,17 @@ JackServerSettings PiPedalModel::GetJackServerSettings()
|
|||||||
|
|
||||||
void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSettings)
|
void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSettings)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::unique_lock<std::recursive_mutex> guard(mutex);
|
||||||
|
|
||||||
|
#if JACK_HOST
|
||||||
if (!adminClient.CanUseShutdownClient())
|
if (!adminClient.CanUseShutdownClient())
|
||||||
{
|
{
|
||||||
throw PiPedalException("Can't change server settings when running a debug server.");
|
throw PiPedalException("Can't change server settings when running a debug server.");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
this->jackServerSettings = jackServerSettings;
|
this->jackServerSettings = jackServerSettings;
|
||||||
|
|
||||||
|
|
||||||
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
||||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||||
for (size_t i = 0; i < subscribers.size(); ++i)
|
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||||
@@ -1160,13 +1223,19 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
|||||||
}
|
}
|
||||||
delete[] t;
|
delete[] t;
|
||||||
|
|
||||||
|
|
||||||
|
#if ALSA_HOST
|
||||||
|
storage.SetJackServerSettings(jackServerSettings);
|
||||||
|
|
||||||
|
FireJackConfigurationChanged(this->jackConfiguration);
|
||||||
|
|
||||||
|
guard.unlock();
|
||||||
|
RestartAudio();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#if JACK_HOST
|
||||||
if (adminClient.CanUseShutdownClient())
|
if (adminClient.CanUseShutdownClient())
|
||||||
{
|
{
|
||||||
|
|
||||||
#if ALSA_HOST
|
|
||||||
storage.SetJackServerSettings(jackServerSettings);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// save the current (edited) preset now in case the service shutdown isn't clean.
|
// save the current (edited) preset now in case the service shutdown isn't clean.
|
||||||
CurrentPreset currentPreset;
|
CurrentPreset currentPreset;
|
||||||
currentPreset.modified_ = this->hasPresetChanged;
|
currentPreset.modified_ = this->hasPresetChanged;
|
||||||
@@ -1195,8 +1264,8 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we now do a complete restart of the services,
|
// we now do a complete restart of the services,
|
||||||
// so just sit tight and wait for the restart.
|
// so just sit tight and wait for the restart.
|
||||||
#ifdef JUNK
|
#ifdef JUNK
|
||||||
this->jackConfiguration.SetErrorStatus("");
|
this->jackConfiguration.SetErrorStatus("");
|
||||||
FireJackConfigurationChanged(this->jackConfiguration);
|
FireJackConfigurationChanged(this->jackConfiguration);
|
||||||
@@ -1211,7 +1280,9 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::UpdateDefaults(PedalBoardItem *pedalBoardItem)
|
void PiPedalModel::UpdateDefaults(PedalBoardItem *pedalBoardItem)
|
||||||
@@ -1259,15 +1330,14 @@ void PiPedalModel::UpdateDefaults(PedalBoard *pedalBoard)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginPresets PiPedalModel::GetPluginPresets(const std::string& pluginUri)
|
PluginPresets PiPedalModel::GetPluginPresets(const std::string &pluginUri)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
|
|
||||||
return storage.GetPluginPresets(pluginUri);
|
return storage.GetPluginPresets(pluginUri);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginUiPresets PiPedalModel::GetPluginUiPresets(const std::string& pluginUri)
|
PluginUiPresets PiPedalModel::GetPluginUiPresets(const std::string &pluginUri)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
|
|
||||||
@@ -1332,7 +1402,7 @@ void PiPedalModel::DeleteMidiListeners(int64_t clientId)
|
|||||||
jackHost->SetListenForMidiEvent(midiEventListeners.size() != 0);
|
jackHost->SetListenForMidiEvent(midiEventListeners.size() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::OnNotifyAtomOutput(uint64_t instanceId, const std::string&atomType,const std::string&atomJson)
|
void PiPedalModel::OnNotifyAtomOutput(uint64_t instanceId, const std::string &atomType, const std::string &atomJson)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
|
|
||||||
@@ -1344,19 +1414,18 @@ void PiPedalModel::OnNotifyAtomOutput(uint64_t instanceId, const std::string&ato
|
|||||||
auto subscriber = this->GetNotificationSubscriber(listener.clientId);
|
auto subscriber = this->GetNotificationSubscriber(listener.clientId);
|
||||||
if (subscriber)
|
if (subscriber)
|
||||||
{
|
{
|
||||||
subscriber->OnNotifyAtomOutput(listener.clientHandle,instanceId,atomType,atomJson);
|
subscriber->OnNotifyAtomOutput(listener.clientHandle, instanceId, atomType, atomJson);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
atomOutputListeners.erase(atomOutputListeners.begin() + i);
|
atomOutputListeners.erase(atomOutputListeners.begin() + i);
|
||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jackHost->SetListenForAtomOutput(atomOutputListeners.size() != 0);
|
jackHost->SetListenForAtomOutput(atomOutputListeners.size() != 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::OnNotifyMidiListen(bool isNote, uint8_t noteOrControl)
|
void PiPedalModel::OnNotifyMidiListen(bool isNote, uint8_t noteOrControl)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
@@ -1370,7 +1439,9 @@ void PiPedalModel::OnNotifyMidiListen(bool isNote, uint8_t noteOrControl)
|
|||||||
if (subscriber)
|
if (subscriber)
|
||||||
{
|
{
|
||||||
subscriber->OnNotifyMidiListener(listener.clientHandle, isNote, noteOrControl);
|
subscriber->OnNotifyMidiListener(listener.clientHandle, isNote, noteOrControl);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
midiEventListeners.erase(midiEventListeners.begin() + i);
|
midiEventListeners.erase(midiEventListeners.begin() + i);
|
||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
@@ -1400,7 +1471,7 @@ void PiPedalModel::CancelListenForMidiEvent(int64_t clientId, int64_t clientHand
|
|||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
for (size_t i = 0; i < midiEventListeners.size(); ++i)
|
for (size_t i = 0; i < midiEventListeners.size(); ++i)
|
||||||
{
|
{
|
||||||
const auto& listener = midiEventListeners[i];
|
const auto &listener = midiEventListeners[i];
|
||||||
if (listener.clientId == clientId && listener.clientHandle == clientHandle)
|
if (listener.clientId == clientId && listener.clientHandle == clientHandle)
|
||||||
{
|
{
|
||||||
midiEventListeners.erase(midiEventListeners.begin() + i);
|
midiEventListeners.erase(midiEventListeners.begin() + i);
|
||||||
@@ -1417,7 +1488,7 @@ void PiPedalModel::CancelListenForAtomOutputs(int64_t clientId, int64_t clientHa
|
|||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
for (size_t i = 0; i < atomOutputListeners.size(); ++i)
|
for (size_t i = 0; i < atomOutputListeners.size(); ++i)
|
||||||
{
|
{
|
||||||
const auto&listener = atomOutputListeners[i];
|
const auto &listener = atomOutputListeners[i];
|
||||||
if (listener.clientId == clientId && listener.clientHandle == clientHandle)
|
if (listener.clientId == clientId && listener.clientHandle == clientHandle)
|
||||||
{
|
{
|
||||||
atomOutputListeners.erase(atomOutputListeners.begin() + i);
|
atomOutputListeners.erase(atomOutputListeners.begin() + i);
|
||||||
@@ -1434,24 +1505,24 @@ std::vector<AlsaDeviceInfo> PiPedalModel::GetAlsaDevices()
|
|||||||
return this->alsaDevices.GetAlsaDevices();
|
return this->alsaDevices.GetAlsaDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::filesystem::path& PiPedalModel::GetWebRoot() const
|
const std::filesystem::path &PiPedalModel::GetWebRoot() const
|
||||||
{
|
{
|
||||||
return webRoot;
|
return webRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string,bool> PiPedalModel::GetFavorites() const
|
std::map<std::string, bool> PiPedalModel::GetFavorites() const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(const_cast<std::recursive_mutex&>(mutex));
|
std::lock_guard<std::recursive_mutex> guard(const_cast<std::recursive_mutex &>(mutex));
|
||||||
|
|
||||||
return storage.GetFavorites();
|
return storage.GetFavorites();
|
||||||
}
|
}
|
||||||
void PiPedalModel::SetFavorites(const std::map<std::string,bool> &favorites)
|
void PiPedalModel::SetFavorites(const std::map<std::string, bool> &favorites)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
storage.SetFavorites(favorites);
|
storage.SetFavorites(favorites);
|
||||||
|
|
||||||
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
||||||
std::vector<IPiPedalModelSubscriber*> t;
|
std::vector<IPiPedalModelSubscriber *> t;
|
||||||
t.reserve(this->subscribers.size());
|
t.reserve(this->subscribers.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < subscribers.size(); ++i)
|
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||||
|
|||||||
@@ -142,6 +142,8 @@ private:
|
|||||||
void UpdateRealtimeMonitorPortSubscriptions();
|
void UpdateRealtimeMonitorPortSubscriptions();
|
||||||
void OnVuUpdate(const std::vector<VuUpdate>& updates);
|
void OnVuUpdate(const std::vector<VuUpdate>& updates);
|
||||||
|
|
||||||
|
void RestartAudio();
|
||||||
|
|
||||||
std::vector<RealtimeParameterRequest*> outstandingParameterRequests;
|
std::vector<RealtimeParameterRequest*> outstandingParameterRequests;
|
||||||
|
|
||||||
IPiPedalModelSubscriber*GetNotificationSubscriber(int64_t clientId);
|
IPiPedalModelSubscriber*GetNotificationSubscriber(int64_t clientId);
|
||||||
|
|||||||
+12
-12
@@ -836,10 +836,10 @@ public:
|
|||||||
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))
|
||||||
{
|
// {
|
||||||
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");
|
||||||
}
|
}
|
||||||
@@ -852,10 +852,10 @@ public:
|
|||||||
throw PiPedalException("Can't change server settings when running interactively.");
|
throw PiPedalException("Can't change server settings when running interactively.");
|
||||||
}
|
}
|
||||||
std::string fromAddress = this->getFromAddress();
|
std::string fromAddress = this->getFromAddress();
|
||||||
if (!IsOnLocalSubnet(fromAddress))
|
// if (!IsOnLocalSubnet(fromAddress))
|
||||||
{
|
// {
|
||||||
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");
|
||||||
@@ -873,10 +873,10 @@ public:
|
|||||||
throw PiPedalException("Can't change server settings when running interactively.");
|
throw PiPedalException("Can't change server settings when running interactively.");
|
||||||
}
|
}
|
||||||
std::string fromAddress = this->getFromAddress();
|
std::string fromAddress = this->getFromAddress();
|
||||||
if (!IsOnLocalSubnet(fromAddress))
|
// if (!IsOnLocalSubnet(fromAddress))
|
||||||
{
|
// {
|
||||||
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");
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "DeviceIdFile.hpp"
|
#include "ServiceConfiguration.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
@@ -33,44 +33,45 @@
|
|||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace config_serializer;
|
||||||
|
|
||||||
|
|
||||||
const char DeviceIdFile::DEVICEID_FILE_NAME[] = "/etc/pipedal/config/device_uuid";
|
const char ServiceConfiguration::DEVICEID_FILE_NAME[] = "/etc/pipedal/config/service.conf";
|
||||||
|
|
||||||
void DeviceIdFile::Load()
|
#define SERIALIZER_ENTRY(MEMBER_NAME) \
|
||||||
|
new ConfigSerializer<ServiceConfiguration,decltype(ServiceConfiguration::MEMBER_NAME)>(#MEMBER_NAME, &ServiceConfiguration::MEMBER_NAME, "")
|
||||||
|
|
||||||
|
|
||||||
|
static p2p::autoptr_vector<ConfigSerializerBase<ServiceConfiguration>>
|
||||||
|
deviceIdSerializers
|
||||||
|
{
|
||||||
|
SERIALIZER_ENTRY(uuid),
|
||||||
|
SERIALIZER_ENTRY(deviceName),
|
||||||
|
SERIALIZER_ENTRY(server_port)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ServiceConfiguration::ServiceConfiguration()
|
||||||
|
: base(deviceIdSerializers)
|
||||||
{
|
{
|
||||||
{
|
|
||||||
ifstream f;
|
|
||||||
|
|
||||||
f.open(DEVICEID_FILE_NAME);
|
|
||||||
if (f.is_open())
|
|
||||||
{
|
|
||||||
std::getline(f, uuid);
|
|
||||||
std::getline(f, deviceName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void DeviceIdFile::Save()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
std::string path = DEVICEID_FILE_NAME;
|
|
||||||
ofstream f;
|
|
||||||
f.open(path, ios_base::trunc);
|
|
||||||
if (!f.is_open())
|
|
||||||
{
|
|
||||||
throw invalid_argument("Can't write to file " + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void ServiceConfiguration::Load()
|
||||||
|
{
|
||||||
|
base::Load(DEVICEID_FILE_NAME,false);
|
||||||
|
}
|
||||||
|
void ServiceConfiguration::Save()
|
||||||
|
{
|
||||||
|
base::Save(DEVICEID_FILE_NAME);
|
||||||
|
{
|
||||||
struct group *group_;
|
struct group *group_;
|
||||||
group_ = getgrnam("pipedal_d");
|
group_ = getgrnam("pipedal_d");
|
||||||
if (group_ == nullptr)
|
if (group_ == nullptr)
|
||||||
{
|
{
|
||||||
throw logic_error("Group not found: pipedal_d");
|
throw logic_error("Group not found: pipedal_d");
|
||||||
}
|
}
|
||||||
std::ignore = chown(path.c_str(), -1, group_->gr_gid);
|
std::ignore = chown(DEVICEID_FILE_NAME,-1,group_->gr_gid);
|
||||||
std::ignore = chmod(path.c_str(), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
|
std::ignore = chmod(DEVICEID_FILE_NAME, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
|
||||||
f << uuid << endl;
|
|
||||||
f << deviceName << endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,10 +25,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "ConfigSerializer.h"
|
||||||
|
|
||||||
namespace pipedal {
|
namespace pipedal {
|
||||||
class DeviceIdFile {
|
using namespace config_serializer;
|
||||||
|
|
||||||
|
class ServiceConfiguration: protected ConfigSerializable<ServiceConfiguration> {
|
||||||
public:
|
public:
|
||||||
|
using base = ConfigSerializable<ServiceConfiguration>;
|
||||||
|
|
||||||
|
ServiceConfiguration();
|
||||||
|
|
||||||
static const char DEVICEID_FILE_NAME[];
|
static const char DEVICEID_FILE_NAME[];
|
||||||
|
|
||||||
void Load();
|
void Load();
|
||||||
@@ -36,6 +43,7 @@ namespace pipedal {
|
|||||||
|
|
||||||
|
|
||||||
std::string uuid;
|
std::string uuid;
|
||||||
std::string deviceName;
|
std::string deviceName = "PiPedal";
|
||||||
|
uint32_t server_port = 80;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
+13
-6
@@ -21,7 +21,7 @@
|
|||||||
#include "ss.hpp"
|
#include "ss.hpp"
|
||||||
|
|
||||||
#include "P2pConfigFiles.hpp"
|
#include "P2pConfigFiles.hpp"
|
||||||
#include "DeviceIdFile.hpp"
|
#include "ServiceConfiguration.hpp"
|
||||||
#include "SetWifiConfig.hpp"
|
#include "SetWifiConfig.hpp"
|
||||||
#include "PiPedalException.hpp"
|
#include "PiPedalException.hpp"
|
||||||
#include "SystemConfigFile.hpp"
|
#include "SystemConfigFile.hpp"
|
||||||
@@ -410,6 +410,16 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
|
|||||||
{
|
{
|
||||||
cout << "Disabling P2P" << endl;
|
cout << "Disabling P2P" << endl;
|
||||||
UninstallP2p();
|
UninstallP2p();
|
||||||
|
|
||||||
|
ServiceConfiguration deviceIdFile;
|
||||||
|
deviceIdFile.Load();
|
||||||
|
deviceIdFile.deviceName = settings.hotspotName_;
|
||||||
|
deviceIdFile.Save();
|
||||||
|
|
||||||
|
|
||||||
|
// Announce new mDNS service with potentially new deviceName.
|
||||||
|
sysExec(SYSTEMCTL_BIN " restart pipedald");
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -417,7 +427,7 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
|
|||||||
settings.Save();
|
settings.Save();
|
||||||
// ******************* device_uuid
|
// ******************* device_uuid
|
||||||
|
|
||||||
DeviceIdFile deviceIdFile;
|
ServiceConfiguration deviceIdFile;
|
||||||
deviceIdFile.Load();
|
deviceIdFile.Load();
|
||||||
deviceIdFile.deviceName = settings.hotspotName_;
|
deviceIdFile.deviceName = settings.hotspotName_;
|
||||||
deviceIdFile.Save();
|
deviceIdFile.Save();
|
||||||
@@ -502,12 +512,9 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
|
|||||||
sysExec(SYSTEMCTL_BIN " daemon-reload");
|
sysExec(SYSTEMCTL_BIN " daemon-reload");
|
||||||
|
|
||||||
sysExec(SYSTEMCTL_BIN " stop pipedal_p2pd");
|
sysExec(SYSTEMCTL_BIN " stop pipedal_p2pd");
|
||||||
sysExec(SYSTEMCTL_BIN " stop dnsmasq");
|
|
||||||
sysExec(SYSTEMCTL_BIN " stop wpa_supplicant");
|
|
||||||
sysExec(SYSTEMCTL_BIN " restart dhcpcd");
|
sysExec(SYSTEMCTL_BIN " restart dhcpcd");
|
||||||
sysExec(SYSTEMCTL_BIN " unmask wpa_supplicant");
|
|
||||||
sysExec(SYSTEMCTL_BIN " start wpa_supplicant");
|
sysExec(SYSTEMCTL_BIN " start wpa_supplicant");
|
||||||
sysExec(SYSTEMCTL_BIN " enable wpa_supplicant");
|
sysExec(SYSTEMCTL_BIN " enable wpa_supplicant"); // ?? Not sure that's still right. :-/
|
||||||
sysExec(SYSTEMCTL_BIN " start dnsmasq");
|
sysExec(SYSTEMCTL_BIN " start dnsmasq");
|
||||||
sysExec(SYSTEMCTL_BIN " enable dnsmasq");
|
sysExec(SYSTEMCTL_BIN " enable dnsmasq");
|
||||||
sysExec(SYSTEMCTL_BIN " start pipedal_p2pd");
|
sysExec(SYSTEMCTL_BIN " start pipedal_p2pd");
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include "ConfigUtil.hpp"
|
#include "ConfigUtil.hpp"
|
||||||
#include "DeviceIdFile.hpp"
|
#include "ServiceConfiguration.hpp"
|
||||||
#include "WriteTemplateFile.hpp"
|
#include "WriteTemplateFile.hpp"
|
||||||
#include "ss.hpp"
|
#include "ss.hpp"
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ void WifiDirectConfigSettings::Load()
|
|||||||
this->channel_ = "6";
|
this->channel_ = "6";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
DeviceIdFile deviceIdFile;
|
ServiceConfiguration deviceIdFile;
|
||||||
deviceIdFile.Load();
|
deviceIdFile.Load();
|
||||||
if (deviceIdFile.deviceName == "")
|
if (deviceIdFile.deviceName == "")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Robin E. R. Davies
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace p2p {
|
||||||
|
|
||||||
|
template <typename T> class autoptr_vector
|
||||||
|
{
|
||||||
|
std::vector<T*> v;
|
||||||
|
private:
|
||||||
|
// no copy no move.
|
||||||
|
autoptr_vector(const autoptr_vector<T> &) = delete;
|
||||||
|
autoptr_vector(autoptr_vector<T> && ) = delete;
|
||||||
|
public:
|
||||||
|
using iterator = std::vector<T*>::const_iterator;
|
||||||
|
|
||||||
|
autoptr_vector() { }
|
||||||
|
autoptr_vector(std::initializer_list<T*> l)
|
||||||
|
:v(l)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
~autoptr_vector() {
|
||||||
|
for (T *i: v)
|
||||||
|
{
|
||||||
|
delete i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void push_back(T*value) { v.push_back(value);}
|
||||||
|
|
||||||
|
iterator begin() const { return v.begin(); }
|
||||||
|
iterator end() const { return v.end(); }
|
||||||
|
|
||||||
|
T*operator[](size_t index) const { return v[index]; }
|
||||||
|
|
||||||
|
size_t size() const { return v.size(); }
|
||||||
|
};
|
||||||
|
}
|
||||||
+2
-2
@@ -23,7 +23,7 @@
|
|||||||
#include "BeastServer.hpp"
|
#include "BeastServer.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Lv2Log.hpp"
|
#include "Lv2Log.hpp"
|
||||||
#include "DeviceIdFile.hpp"
|
#include "ServiceConfiguration.hpp"
|
||||||
#include "AvahiService.hpp"
|
#include "AvahiService.hpp"
|
||||||
|
|
||||||
#include "PiPedalSocket.hpp"
|
#include "PiPedalSocket.hpp"
|
||||||
@@ -428,7 +428,7 @@ public:
|
|||||||
#define LINK_LOCAL_WEB_SOCKET 1
|
#define LINK_LOCAL_WEB_SOCKET 1
|
||||||
#if LINK_LOCAL_WEB_SOCKET
|
#if LINK_LOCAL_WEB_SOCKET
|
||||||
std::string webSocketAddress = GetLinkLocalAddress(fromAddress);
|
std::string webSocketAddress = GetLinkLocalAddress(fromAddress);
|
||||||
Lv2Log::info(SS("Web Socket Adddress: " << webSocketAddress << ":" << portNumber));
|
Lv2Log::info(SS("Web Socket Address: " << webSocketAddress << ":" << portNumber));
|
||||||
#else
|
#else
|
||||||
std::string webSocketAddress = "*";
|
std::string webSocketAddress = "*";
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=PiPedal P2P Session Manager
|
Description=PiPedal P2P Session Manager
|
||||||
After=network.target
|
After=network.target
|
||||||
|
After=nss-lookup.target
|
||||||
After=wpa_supplicant.service
|
After=wpa_supplicant.service
|
||||||
After=dhcpcd.service
|
After=dhcpcd.service
|
||||||
|
StartLimitIntervalSec=300
|
||||||
|
StartLimitBurst=8
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=${COMMAND} --systemd --log-level debug
|
ExecStart=${COMMAND} --systemd --log-level debug
|
||||||
Type=notify
|
Type=notify
|
||||||
WorkingDirectory=/var/pipedal
|
WorkingDirectory=/var/pipedal
|
||||||
TimeoutStopSec=5
|
TimeoutStopSec=5
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10s
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ After=local-fs.target
|
|||||||
|
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
Restart=on-failure
|
||||||
Type=notify
|
Type=notify
|
||||||
LimitMEMLOCK=infinity
|
LimitMEMLOCK=infinity
|
||||||
LimitRTPRIO=95
|
LimitRTPRIO=95
|
||||||
|
|||||||
+1
-1
Submodule submodules/pipedal_p2pd updated: 85b68b8400...81111f111f
Reference in New Issue
Block a user