initial commit
This commit is contained in:
commit
3705d8cca7
14 changed files with 1202 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules/
|
||||||
|
yarn.lock
|
14
.vscode/launch.json
vendored
Normal file
14
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "pwa-node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "api",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}/api.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
7
README.md
Normal file
7
README.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# pbc
|
||||||
|
|
||||||
|
pedal board control
|
||||||
|
|
||||||
|
## description
|
||||||
|
|
||||||
|
control your MODEP pedalboard(s) via http requests
|
19
config.json
Normal file
19
config.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"listen": "0.0.0.0",
|
||||||
|
"port": 3000,
|
||||||
|
"timestamp": "DD.MM.YYYY HH:mm:ss:SS"
|
||||||
|
},
|
||||||
|
"log": {
|
||||||
|
"level": "debug"
|
||||||
|
},
|
||||||
|
"osc": {
|
||||||
|
"host": "192.168.1.24",
|
||||||
|
"port": "12101",
|
||||||
|
"address": "/midi"
|
||||||
|
},
|
||||||
|
"modep": {
|
||||||
|
"host": "192.168.1.24",
|
||||||
|
"port": 80
|
||||||
|
}
|
||||||
|
}
|
354
dev/FUZZ.ttl
Normal file
354
dev/FUZZ.ttl
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
|
||||||
|
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||||
|
@prefix ingen: <http://drobilla.net/ns/ingen#> .
|
||||||
|
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||||
|
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
|
||||||
|
@prefix mod: <http://moddevices.com/ns/mod#> .
|
||||||
|
@prefix pedal: <http://moddevices.com/ns/modpedal#> .
|
||||||
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||||
|
|
||||||
|
_:b1
|
||||||
|
ingen:tail <capture_1> ;
|
||||||
|
ingen:head <StompBox_fuzz/INPUT_L> .
|
||||||
|
|
||||||
|
_:b2
|
||||||
|
ingen:tail <BigMuffPi/Out1> ;
|
||||||
|
ingen:head <Overdrive/right_in> .
|
||||||
|
|
||||||
|
_:b3
|
||||||
|
ingen:tail <capture_2> ;
|
||||||
|
ingen:head <BigMuffPi/In> .
|
||||||
|
|
||||||
|
_:b4
|
||||||
|
ingen:tail <Overdrive/left_out> ;
|
||||||
|
ingen:head <playback_1> .
|
||||||
|
|
||||||
|
_:b5
|
||||||
|
ingen:tail <capture_1> ;
|
||||||
|
ingen:head <BigMuffPi/In> .
|
||||||
|
|
||||||
|
_:b6
|
||||||
|
ingen:tail <StompBox_fuzz/OUTPUT_L> ;
|
||||||
|
ingen:head <playback_1> .
|
||||||
|
|
||||||
|
_:b7
|
||||||
|
ingen:tail <capture_2> ;
|
||||||
|
ingen:head <StompBox_fuzz/INPUT_R> .
|
||||||
|
|
||||||
|
_:b8
|
||||||
|
ingen:tail <StompBox_fuzz/OUTPUT_R> ;
|
||||||
|
ingen:head <playback_2> .
|
||||||
|
|
||||||
|
_:b9
|
||||||
|
ingen:tail <BigMuffPi/Out1> ;
|
||||||
|
ingen:head <Overdrive/left_in> .
|
||||||
|
|
||||||
|
_:b10
|
||||||
|
ingen:tail <Overdrive/right_out> ;
|
||||||
|
ingen:head <playback_2> .
|
||||||
|
|
||||||
|
<BigMuffPi>
|
||||||
|
ingen:canvasX 561.0 ;
|
||||||
|
ingen:canvasY 210.0 ;
|
||||||
|
ingen:enabled false ;
|
||||||
|
ingen:polyphonic false ;
|
||||||
|
lv2:microVersion 0 ;
|
||||||
|
lv2:minorVersion 0 ;
|
||||||
|
mod:builderVersion 0 ;
|
||||||
|
mod:releaseNumber 0 ;
|
||||||
|
lv2:port <BigMuffPi/In> ,
|
||||||
|
<BigMuffPi/Out1> ,
|
||||||
|
<BigMuffPi/Tone> ,
|
||||||
|
<BigMuffPi/Level> ,
|
||||||
|
<BigMuffPi/Sustain> ,
|
||||||
|
<BigMuffPi/:bypass> ;
|
||||||
|
lv2:prototype <http://moddevices.com/plugins/mod-devel/BigMuffPi> ;
|
||||||
|
pedal:preset <> ;
|
||||||
|
a ingen:Block .
|
||||||
|
|
||||||
|
<BigMuffPi/In>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<BigMuffPi/In>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:OutputPort .
|
||||||
|
|
||||||
|
<BigMuffPi/Tone>
|
||||||
|
ingen:value 0.250000 ;
|
||||||
|
midi:binding [
|
||||||
|
midi:channel 0 ;
|
||||||
|
midi:controllerNumber 1 ;
|
||||||
|
lv2:minimum 0.000000 ;
|
||||||
|
lv2:maximum 1.000000 ;
|
||||||
|
a midi:Controller ;
|
||||||
|
] ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<BigMuffPi/Level>
|
||||||
|
ingen:value 0.500000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<BigMuffPi/Sustain>
|
||||||
|
ingen:value 0.500000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<BigMuffPi/:bypass>
|
||||||
|
ingen:value 1 ;
|
||||||
|
midi:binding [
|
||||||
|
midi:channel 0 ;
|
||||||
|
midi:controllerNumber 0 ;
|
||||||
|
a midi:Controller ;
|
||||||
|
] ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<Overdrive>
|
||||||
|
ingen:canvasX 1061.0 ;
|
||||||
|
ingen:canvasY 180.0 ;
|
||||||
|
ingen:enabled true ;
|
||||||
|
ingen:polyphonic false ;
|
||||||
|
lv2:microVersion 4 ;
|
||||||
|
lv2:minorVersion 0 ;
|
||||||
|
mod:builderVersion 0 ;
|
||||||
|
mod:releaseNumber 0 ;
|
||||||
|
lv2:port <Overdrive/left_in> ,
|
||||||
|
<Overdrive/right_in> ,
|
||||||
|
<Overdrive/left_out> ,
|
||||||
|
<Overdrive/right_out> ,
|
||||||
|
<Overdrive/drive> ,
|
||||||
|
<Overdrive/muffle> ,
|
||||||
|
<Overdrive/output> ,
|
||||||
|
<Overdrive/:bypass> ;
|
||||||
|
lv2:prototype <http://moddevices.com/plugins/mda/Overdrive> ;
|
||||||
|
pedal:preset <> ;
|
||||||
|
a ingen:Block .
|
||||||
|
|
||||||
|
<Overdrive/left_in>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<Overdrive/right_in>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<Overdrive/left_in>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:OutputPort .
|
||||||
|
|
||||||
|
<Overdrive/right_in>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:OutputPort .
|
||||||
|
|
||||||
|
<Overdrive/drive>
|
||||||
|
ingen:value 50.000000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<Overdrive/muffle>
|
||||||
|
ingen:value 25.000000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<Overdrive/output>
|
||||||
|
ingen:value 0.000000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<Overdrive/:bypass>
|
||||||
|
ingen:value 0 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz>
|
||||||
|
ingen:canvasX 547.0 ;
|
||||||
|
ingen:canvasY 740.0 ;
|
||||||
|
ingen:enabled true ;
|
||||||
|
ingen:polyphonic false ;
|
||||||
|
lv2:microVersion 0 ;
|
||||||
|
lv2:minorVersion 0 ;
|
||||||
|
mod:builderVersion 0 ;
|
||||||
|
mod:releaseNumber 0 ;
|
||||||
|
lv2:port <StompBox_fuzz/INPUT_L> ,
|
||||||
|
<StompBox_fuzz/INPUT_R> ,
|
||||||
|
<StompBox_fuzz/OUTPUT_L> ,
|
||||||
|
<StompBox_fuzz/OUTPUT_R> ,
|
||||||
|
<StompBox_fuzz/BYPASS> ,
|
||||||
|
<StompBox_fuzz/LEVEL> ,
|
||||||
|
<StompBox_fuzz/HI> ,
|
||||||
|
<StompBox_fuzz/MID> ,
|
||||||
|
<StompBox_fuzz/LO> ,
|
||||||
|
<StompBox_fuzz/GAIN> ,
|
||||||
|
<StompBox_fuzz/:bypass> ;
|
||||||
|
lv2:prototype <http://rakarrack.sourceforge.net/effects.html#StompBox_fuzz> ;
|
||||||
|
pedal:preset <> ;
|
||||||
|
a ingen:Block .
|
||||||
|
|
||||||
|
<StompBox_fuzz/INPUT_L>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/INPUT_R>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/INPUT_L>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:OutputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/INPUT_R>
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:OutputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/BYPASS>
|
||||||
|
ingen:value 0.000000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/LEVEL>
|
||||||
|
ingen:value 64.000000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/HI>
|
||||||
|
ingen:value 20.000000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/MID>
|
||||||
|
ingen:value 29.000000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/LO>
|
||||||
|
ingen:value 20.000000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/GAIN>
|
||||||
|
ingen:value 64.000000 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<StompBox_fuzz/:bypass>
|
||||||
|
ingen:value 0 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<:bpb>
|
||||||
|
ingen:value 4.000000 ;
|
||||||
|
lv2:index 0 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<:bpm>
|
||||||
|
ingen:value 120.000000 ;
|
||||||
|
lv2:index 1 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<:rolling>
|
||||||
|
ingen:value 0 ;
|
||||||
|
lv2:index 2 ;
|
||||||
|
a lv2:ControlPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<control_in>
|
||||||
|
atom:bufferType atom:Sequence ;
|
||||||
|
lv2:index 3 ;
|
||||||
|
lv2:name "Control In" ;
|
||||||
|
lv2:portProperty lv2:connectionOptional ;
|
||||||
|
lv2:symbol "control_in" ;
|
||||||
|
<http://lv2plug.in/ns/ext/resize-port#minimumSize> 4096 ;
|
||||||
|
a atom:AtomPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<control_out>
|
||||||
|
atom:bufferType atom:Sequence ;
|
||||||
|
lv2:index 4 ;
|
||||||
|
lv2:name "Control Out" ;
|
||||||
|
lv2:portProperty lv2:connectionOptional ;
|
||||||
|
lv2:symbol "control_out" ;
|
||||||
|
<http://lv2plug.in/ns/ext/resize-port#minimumSize> 4096 ;
|
||||||
|
a atom:AtomPort ,
|
||||||
|
lv2:OutputPort .
|
||||||
|
|
||||||
|
<capture_1>
|
||||||
|
lv2:index 5 ;
|
||||||
|
lv2:name "Capture 1" ;
|
||||||
|
lv2:portProperty lv2:connectionOptional ;
|
||||||
|
lv2:symbol "capture_1" ;
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<capture_2>
|
||||||
|
lv2:index 6 ;
|
||||||
|
lv2:name "Capture 2" ;
|
||||||
|
lv2:portProperty lv2:connectionOptional ;
|
||||||
|
lv2:symbol "capture_2" ;
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<playback_1>
|
||||||
|
lv2:index 7 ;
|
||||||
|
lv2:name "Playback 1" ;
|
||||||
|
lv2:portProperty lv2:connectionOptional ;
|
||||||
|
lv2:symbol "playback_1" ;
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:OutputPort .
|
||||||
|
|
||||||
|
<playback_2>
|
||||||
|
lv2:index 8 ;
|
||||||
|
lv2:name "Playback 2" ;
|
||||||
|
lv2:portProperty lv2:connectionOptional ;
|
||||||
|
lv2:symbol "playback_2" ;
|
||||||
|
a lv2:AudioPort ,
|
||||||
|
lv2:OutputPort .
|
||||||
|
|
||||||
|
<midi_separated_mode>
|
||||||
|
ingen:value 0 ;
|
||||||
|
lv2:index 9 ;
|
||||||
|
a atom:AtomPort ,
|
||||||
|
lv2:InputPort .
|
||||||
|
|
||||||
|
<>
|
||||||
|
doap:name "FUZZ" ;
|
||||||
|
pedal:unitName "Unknown" ;
|
||||||
|
pedal:unitModel "Unknown" ;
|
||||||
|
pedal:width 3788 ;
|
||||||
|
pedal:height 1546 ;
|
||||||
|
pedal:addressings <addressings.json> ;
|
||||||
|
pedal:screenshot <screenshot.png> ;
|
||||||
|
pedal:thumbnail <thumbnail.png> ;
|
||||||
|
pedal:version 7 ;
|
||||||
|
ingen:polyphony 1 ;
|
||||||
|
ingen:arc _:b1 ,
|
||||||
|
_:b2 ,
|
||||||
|
_:b3 ,
|
||||||
|
_:b4 ,
|
||||||
|
_:b5 ,
|
||||||
|
_:b6 ,
|
||||||
|
_:b7 ,
|
||||||
|
_:b8 ,
|
||||||
|
_:b9 ,
|
||||||
|
_:b10 ;
|
||||||
|
ingen:block <BigMuffPi> ,
|
||||||
|
<Overdrive> ,
|
||||||
|
<StompBox_fuzz> ;
|
||||||
|
lv2:port <:bpb> ,
|
||||||
|
<:bpm> ,
|
||||||
|
<:rolling> ,
|
||||||
|
<midi_separated_mode> ,
|
||||||
|
<control_in> ,
|
||||||
|
<control_out> ,
|
||||||
|
<capture_1> ,
|
||||||
|
<capture_2> ,
|
||||||
|
<playback_1> ,
|
||||||
|
<playback_2> ;
|
||||||
|
lv2:extensionData <http://lv2plug.in/ns/ext/state#interface> ;
|
||||||
|
a lv2:Plugin ,
|
||||||
|
ingen:Graph ,
|
||||||
|
pedal:Pedalboard .
|
64
libs/api.js
Normal file
64
libs/api.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
const logger = require('./logger.js');
|
||||||
|
const util = require('./util.js');
|
||||||
|
const constants = require('./constants.js');
|
||||||
|
const modep = require('./modep.js');
|
||||||
|
|
||||||
|
const endpoints = new Map();
|
||||||
|
|
||||||
|
function setEndpoints(url, data) {
|
||||||
|
var startTime = new Date();
|
||||||
|
var index = 0;
|
||||||
|
var elements = [];
|
||||||
|
for (var index = 0; index < data.length; index++) {
|
||||||
|
var element = data[index];
|
||||||
|
element.id = index;
|
||||||
|
setEndpoint(url + '/' + element.id, [constants.HTTP_GET, constants.HTTP_POST], element);
|
||||||
|
elements.push(element);
|
||||||
|
}
|
||||||
|
elements = elements.sort(function (a, b) {
|
||||||
|
return a.id - b.id;
|
||||||
|
});
|
||||||
|
setEndpoint(url, constants.HTTP_GET, elements);
|
||||||
|
logger.debug('setting up ' + elements.length + ' endpoint(s) for path \'' + url + '\' took ' + util.timeDiff(startTime) + 'ms');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setEndpoint(url, types, data) {
|
||||||
|
logger.debug('setting up \'' + types + '\' endpoint \'' + url + '\'...')
|
||||||
|
endpoints.set(url, { types: types, data: data });
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEndpoints() {
|
||||||
|
return endpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupEndpoints() {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
modep.getBanks()
|
||||||
|
.then(function (data) {
|
||||||
|
setEndpoints(constants.API_BANKS, data);
|
||||||
|
})
|
||||||
|
.then(modep.getPedalboards)
|
||||||
|
.then(function (data) {
|
||||||
|
setEndpoints(constants.API_PEDALBOARDS, data);
|
||||||
|
})
|
||||||
|
.then(modep.getDefaultPedalboard)
|
||||||
|
.then(function (data) {
|
||||||
|
setEndpoint(constants.API_PEDALBOARDS_DEFAULT, constants.HTTP_GET, data);
|
||||||
|
})
|
||||||
|
.then(modep.getCurrentPedalboard)
|
||||||
|
.then(function (data) {
|
||||||
|
setEndpoint(constants.API_PEDALBOARDS_CURRENT, constants.HTTP_GET, data);
|
||||||
|
})
|
||||||
|
.then(modep.getCurrentPedals)
|
||||||
|
.then(function (data) {
|
||||||
|
setEndpoints(constants.API_PEDALS, data);
|
||||||
|
})
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
setupEndpoints,
|
||||||
|
getEndpoints
|
||||||
|
}
|
27
libs/commands.js
Normal file
27
libs/commands.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const logger = require('../libs/logger.js');
|
||||||
|
const { spawn } = require('child_process')
|
||||||
|
|
||||||
|
function execute(endpoint) {
|
||||||
|
if (!endpoint || !endpoint.command) {
|
||||||
|
logger.warn('no command defined');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.debug('executing command \'' + endpoint.command + '\' with args \'' + endpoint.args + '\'...');
|
||||||
|
var cmd = spawn(endpoint.command, endpoint.args);
|
||||||
|
cmd.stdout.on('data', function(data) {
|
||||||
|
logger.debug(data);
|
||||||
|
});
|
||||||
|
cmd.stderr.on('data', function(data) {
|
||||||
|
logger.error(data);
|
||||||
|
});
|
||||||
|
cmd.on('close', function(code) {
|
||||||
|
logger.debug('command \'' + endpoint.command + '\' with args \'' + endpoint.args + '\' finished with exit code ' + code);
|
||||||
|
});
|
||||||
|
cmd.on('error', function(err) {
|
||||||
|
logger.error('command \'' + endpoint.command + '\' with args \'' + endpoint.args + '\' encountered an error >>> ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
execute
|
||||||
|
}
|
10
libs/constants.js
Normal file
10
libs/constants.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
exports.HTTP_GET = 'GET';
|
||||||
|
exports.HTTP_POST = 'POST';
|
||||||
|
|
||||||
|
exports.API_BANKS = '/banks';
|
||||||
|
exports.API_PEDALBOARDS = '/pedalboards';
|
||||||
|
exports.API_PEDALBOARDS_DEFAULT = '/pedalboards/default';
|
||||||
|
exports.API_PEDALBOARDS_CURRENT = '/pedalboards/current';
|
||||||
|
exports.API_PEDALS = '/pedals';
|
||||||
|
|
||||||
|
exports.PEDALBOARD_DEFAULT = '/var/modep/pedalboards/default.pedalboard';
|
110
libs/logger.js
Normal file
110
libs/logger.js
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
const config = require("../config.json");
|
||||||
|
const moment = require("moment");
|
||||||
|
|
||||||
|
// constants
|
||||||
|
const LOG_PREFIX_DEBUG = "debug";
|
||||||
|
const LOG_PREFIX_INFO = "info";
|
||||||
|
const LOG_PREFIX_WARNING = "warning";
|
||||||
|
const LOG_PREFIX_ERROR = "error";
|
||||||
|
const LOGLEVEL_DEBUG = 0;
|
||||||
|
const LOGLEVEL_INFO = 1;
|
||||||
|
const LOGLEVEL_WARNING = 2;
|
||||||
|
const LOGLEVEL_ERROR = 3;
|
||||||
|
|
||||||
|
// set loglevel on "require"
|
||||||
|
const loglevel = function() {
|
||||||
|
switch (config.log.level) {
|
||||||
|
case LOG_PREFIX_DEBUG:
|
||||||
|
case LOGLEVEL_DEBUG:
|
||||||
|
return LOGLEVEL_DEBUG;
|
||||||
|
case LOG_PREFIX_INFO:
|
||||||
|
case LOGLEVEL_INFO:
|
||||||
|
return LOGLEVEL_INFO;
|
||||||
|
case LOG_PREFIX_WARNING:
|
||||||
|
case LOGLEVEL_WARNING:
|
||||||
|
return LOGLEVEL_WARNING;
|
||||||
|
case LOG_PREFIX_ERROR:
|
||||||
|
case LOGLEVEL_ERROR:
|
||||||
|
return LOGLEVEL_ERROR;
|
||||||
|
default:
|
||||||
|
return LOGLEVEL_INFO;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
// log a http request
|
||||||
|
function request(request) {
|
||||||
|
let message = "[" + request.method + "] url: \"" + request.url + "\"";
|
||||||
|
let counter = 1;
|
||||||
|
for (let param in request.body) {
|
||||||
|
message += ", parameter " + counter + ": \"" + param + "=" + request.body[param] + "\"";
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
debug(message.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix log with "info"
|
||||||
|
function info(message) {
|
||||||
|
if (loglevel > LOGLEVEL_INFO) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
trace(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix log with "info"
|
||||||
|
function warn(message) {
|
||||||
|
if (loglevel > LOGLEVEL_WARNING) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
trace(message, "warning");
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix log with "debug"
|
||||||
|
function debug(message) {
|
||||||
|
if (loglevel > LOGLEVEL_DEBUG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
trace(message, "debug");
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix log with "error"
|
||||||
|
function error(message) {
|
||||||
|
if (loglevel > LOGLEVEL_ERROR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
trace(message, "error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// default logging function
|
||||||
|
function trace(message, prefix) {
|
||||||
|
if (message === undefined || message === null || message.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (prefix === undefined || prefix === null || prefix.length === 0) {
|
||||||
|
prefix = "info";
|
||||||
|
}
|
||||||
|
let print;
|
||||||
|
switch (prefix) {
|
||||||
|
case "error":
|
||||||
|
print = console.error;
|
||||||
|
break;
|
||||||
|
case "debug":
|
||||||
|
print = console.debug;
|
||||||
|
break;
|
||||||
|
case "warning":
|
||||||
|
print = console.warn;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print = console.log;
|
||||||
|
}
|
||||||
|
message = moment().format(config.server.timestamp) + " | " + prefix + " > " + message;
|
||||||
|
print(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// exports
|
||||||
|
module.exports = {
|
||||||
|
info,
|
||||||
|
warn,
|
||||||
|
debug,
|
||||||
|
error,
|
||||||
|
request
|
||||||
|
};
|
329
libs/modep.js
Normal file
329
libs/modep.js
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
const config = require('../config.json');
|
||||||
|
const util = require('./util.js');
|
||||||
|
const constants = require('./constants.js');
|
||||||
|
const logger = require('./logger.js');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const { spawn } = require('child_process')
|
||||||
|
const ttl2jsonld = require('@frogcat/ttl2jsonld').parse;
|
||||||
|
|
||||||
|
var banks = undefined;
|
||||||
|
var pedalboards = undefined;
|
||||||
|
var defaultPedalboard = undefined;
|
||||||
|
var currentPedalboard = undefined;
|
||||||
|
var currentPedals = undefined;
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
util.httpGET(config.modep.host, config.modep.port, '/reset')
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBanks() {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (banks) {
|
||||||
|
return resolve(banks);
|
||||||
|
}
|
||||||
|
// FAKE DATA
|
||||||
|
var fake = [{ "title": "The Button", "pedalboards": [{ "valid": true, "broken": false, "uri": "file:///var/modep/pedalboards/default.pedalboard/default.ttl", "bundle": "/var/modep/pedalboards/default.pedalboard", "title": "Default", "version": 0 }, { "valid": true, "broken": false, "uri": "file:///var/modep/pedalboards/FUZZ.pedalboard/FUZZ.ttl", "bundle": "/var/modep/pedalboards/FUZZ.pedalboard", "title": "FUZZ", "version": 1 }] }];
|
||||||
|
for (var index = 0; index < fake.length; index++) {
|
||||||
|
fake.id = index;
|
||||||
|
}
|
||||||
|
banks = util.sortById(fake);
|
||||||
|
return resolve(fake);
|
||||||
|
|
||||||
|
util.httpGET(config.modep.host, config.modep.port, '/banks')
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPedalboards() {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (pedalboards) {
|
||||||
|
return resolve(pedalboards);
|
||||||
|
}
|
||||||
|
// FAKE DATA
|
||||||
|
var fake = [{ "valid": true, "broken": false, "uri": "file:///var/modep/pedalboards/FUZZ.pedalboard/FUZZ.ttl", "bundle": "/var/modep/pedalboards/FUZZ.pedalboard", "title": "FUZZ", "version": 1 }, { "valid": true, "broken": false, "uri": "file:///var/modep/pedalboards/default.pedalboard/default.ttl", "bundle": "/var/modep/pedalboards/default.pedalboard", "title": "Default", "version": 0 }];
|
||||||
|
var id = 1;
|
||||||
|
for (var index = 0; index < fake.length; index++) {
|
||||||
|
var pedalboard = fake[index];
|
||||||
|
if (pedalboard.bundle == constants.PEDALBOARD_DEFAULT) {
|
||||||
|
pedalboard.id = 0;
|
||||||
|
defaultPedalboard = pedalboard;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pedalboard.id = id;
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
pedalboards = util.sortById(fake);
|
||||||
|
return resolve(fake);
|
||||||
|
|
||||||
|
util.httpGET(config.modep.host, config.modep.port, '/pedalboard/list')
|
||||||
|
.then(function (pedalboards) {
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultPedalboard() {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (defaultPedalboard) {
|
||||||
|
return resolve(defaultPedalboard);
|
||||||
|
}
|
||||||
|
getPedalboardByBundle(constants.PEDALBOARD_DEFAULT)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentPedalboard() {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (currentPedalboard && currentPedalboard.id) {
|
||||||
|
return resolve(currentPedalboard);
|
||||||
|
}
|
||||||
|
// FAKE DATA
|
||||||
|
var fake = '/var/modep/pedalboards/FUZZ.pedalboard';
|
||||||
|
getPedalboardByBundle(fake)
|
||||||
|
.then(function (pedalboard) {
|
||||||
|
currentPedalboard = pedalboard;
|
||||||
|
return resolve(pedalboard);
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
|
||||||
|
// PRODUCTION
|
||||||
|
// util.httpGET(config.modep.host, config.modep.port, '/pedalboard/current')
|
||||||
|
// .then(getPedalboardByBundle)
|
||||||
|
// .then(resolve)
|
||||||
|
// .catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPedalboardById(pedalboardId) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
getPedalboards()
|
||||||
|
.then(function (pedalboards) {
|
||||||
|
for (var index = 0; index < pedalboards.length; index++) {
|
||||||
|
if (pedalboards[index].id != pedalboardId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return resolve(pedalboards[index]);
|
||||||
|
}
|
||||||
|
return reject('error: could not find pedalboard by id \'' + controlId + '\'');
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPedalboardByBundle(pedalboardBundle) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
getPedalboards()
|
||||||
|
.then(function (pedalboards) {
|
||||||
|
for (var index = 0; index < pedalboards.length; index++) {
|
||||||
|
if (pedalboards[index].bundle != pedalboardBundle) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return resolve(pedalboards[index]);
|
||||||
|
}
|
||||||
|
return reject('error: could not find pedalboard by bundle \'' + pedalboardBundle + '\'');
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPedalControlById(pedalId, controlId) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
getCurrentPedalById(pedalId)
|
||||||
|
.then(function (pedal) {
|
||||||
|
for (var index = 0; index < pedal.controls.length; index++) {
|
||||||
|
if (pedal.controls[index].id != controlId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return resolve(pedal.controls[index]);
|
||||||
|
}
|
||||||
|
return reject('error: could not find control for pedal \'' + pedalId + '\' by id \'' + controlId + '\'');
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentPedalById(id) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
getCurrentPedals()
|
||||||
|
.then(function () {
|
||||||
|
for (var index = 0; index < currentPedals.length; index++) {
|
||||||
|
if (currentPedals[index].id != id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return resolve(currentPedals[index]);
|
||||||
|
}
|
||||||
|
return reject('error: could not find current pedal by id \'' + id + '\'');
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentPedals() {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (currentPedals) {
|
||||||
|
return resolve(currentPedals);
|
||||||
|
}
|
||||||
|
getCurrentPedalboard()
|
||||||
|
.then(parseCurrentPedalboard)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCurrentPedalboard(pedalboardBundle) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var startTime = new Date();
|
||||||
|
logger.debug('parsing current pedalboard...');
|
||||||
|
if (!currentPedalboard || !currentPedalboard.uri) {
|
||||||
|
for (var index = 0; index < pedalboards.length; index++) {
|
||||||
|
var pedalboard = pedalboards[index];
|
||||||
|
if (!pedalboard.bundle || pedalboardBundle != pedalboard.bundle) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
currentPedalboard = pedalboard;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!currentPedalboard.uri) {
|
||||||
|
reject('error: could not determine current pedalboard config file');
|
||||||
|
}
|
||||||
|
// FAKE DATA
|
||||||
|
var file = path.resolve('./dev/FUZZ.ttl');
|
||||||
|
// var file = path.resolve(currentPedalboard.uri.replace('file://', ''));
|
||||||
|
fs.readFile(file, function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
return reject('error: could not parse current pedalboard file \'' + file + '\' >>> ' + err);
|
||||||
|
}
|
||||||
|
currentPedals = [];
|
||||||
|
var json = ttl2jsonld(data.toString())['@graph'];
|
||||||
|
var id = 0;
|
||||||
|
for (var index = 0; index < json.length; index++) {
|
||||||
|
var tmp = json[index];
|
||||||
|
if (!tmp['lv2:prototype']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var name = tmp['@id'];
|
||||||
|
currentPedals.push({ id: id, name: name, controls: [] });
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
for (var index = 0; index < json.length; index++) {
|
||||||
|
var tmp = json[index];
|
||||||
|
var name = tmp['@id'];
|
||||||
|
var value = tmp['ingen:value'];
|
||||||
|
if (value == undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var pedal = undefined;
|
||||||
|
for (var pedalIndex = 0; pedalIndex < currentPedals.length; pedalIndex++) {
|
||||||
|
if (!name.startsWith(currentPedals[pedalIndex].name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pedal = currentPedals[pedalIndex];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!pedal) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
id = pedal.controls.length;
|
||||||
|
name = name.replace(pedal.name + '/', '');
|
||||||
|
if (name == ':bypass') {
|
||||||
|
value = value;
|
||||||
|
} else {
|
||||||
|
value = value['@value'];
|
||||||
|
}
|
||||||
|
var control = { id: id, name: name, value: value };
|
||||||
|
pedal.controls.push(control);
|
||||||
|
id++;
|
||||||
|
var midi = tmp['midi:binding'];
|
||||||
|
if (!midi) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
control.midi = { channel: midi['midi:channel'], controller: midi['midi:controllerNumber'] }
|
||||||
|
}
|
||||||
|
logger.debug('parsing current pedalboard file \'' + file + '\' took ' + util.timeDiff(startTime) + 'ms')
|
||||||
|
resolve(currentPedals);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendValueToControl(value, control) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (!control || !control.midi) {
|
||||||
|
return reject('error: control \'' + control.name + '\' with id \'' + control.id + '\' has no midi bindings');
|
||||||
|
}
|
||||||
|
if (value > 127) {
|
||||||
|
value = 127;
|
||||||
|
} else if (value < 0) {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
value = '00' + util.toHex(value) + '0' + util.toHex(control.midi.controller) + 'b' + util.toHex(control.midi.channel);
|
||||||
|
var cmd = 'oscsend';
|
||||||
|
var args = [config.osc.host, config.osc.port, config.osc.address, 'm', value];
|
||||||
|
logger.debug('executing command \'' + cmd + '\' with args \'' + args + '\'...');
|
||||||
|
var spawned = spawn(cmd, args);
|
||||||
|
spawned.stdout.on('data', function (data) {
|
||||||
|
logger.debug(data);
|
||||||
|
});
|
||||||
|
spawned.stderr.on('data', function (data) {
|
||||||
|
logger.error(data);
|
||||||
|
});
|
||||||
|
spawned.on('close', function (code) {
|
||||||
|
logger.debug('command \'' + cmd + '\' with args \'' + args + '\' finished with exit code ' + code);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
spawned.on('error', function (err) {
|
||||||
|
logger.error('command \'' + cmd + '\' with args \'' + args + '\' encountered an error >>> ' + err);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPedalboardById(pedalboardId) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (!pedalboardId) {
|
||||||
|
return reject('error: no pedalboard id given');
|
||||||
|
}
|
||||||
|
getPedalboardById(pedalboardId)
|
||||||
|
.then(setPedalboard)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPedalboard(pedalboard) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (!pedalboard || !pedalboard.bundle) {
|
||||||
|
return reject('error: no bundle set for pedalboard');
|
||||||
|
}
|
||||||
|
if (pedalboard.id == currentPedalboard.id) {
|
||||||
|
return resolve('pedalboard \'' + pedalboard.id + '\' is already active');
|
||||||
|
}
|
||||||
|
reset()
|
||||||
|
.then(function () {
|
||||||
|
util.httpPOST(config.modep.host, config.modep.port, '/pedalboard/load_bundle/?bundlepath=' + pedalboard.bundle)
|
||||||
|
})
|
||||||
|
.then(getCurrentPedalboard)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getBanks,
|
||||||
|
getPedalboards,
|
||||||
|
getDefaultPedalboard,
|
||||||
|
getCurrentPedalboard,
|
||||||
|
getCurrentPedals,
|
||||||
|
getCurrentPedalById,
|
||||||
|
getPedalControlById,
|
||||||
|
sendValueToControl,
|
||||||
|
setPedalboard,
|
||||||
|
setPedalboardById,
|
||||||
|
}
|
151
libs/server.js
Normal file
151
libs/server.js
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
const config = require('../config.json');
|
||||||
|
const logger = require('./logger.js');
|
||||||
|
const api = require('./api.js')
|
||||||
|
const constants = require('./constants.js');
|
||||||
|
const modep = require('./modep.js');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
var server;
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (!server) {
|
||||||
|
server = http.createServer();
|
||||||
|
}
|
||||||
|
server.listen(config.server.port, config.server.listen).on('listening', function () {
|
||||||
|
logger.debug('server listening on ' + config.server.listen + ':' + config.server.port + '...');
|
||||||
|
handleRequests();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRequests() {
|
||||||
|
server.on('request', function (request, response) {
|
||||||
|
logger.request(request);
|
||||||
|
var endpoint = api.getEndpoints().get(request.url);
|
||||||
|
if (!endpoint) {
|
||||||
|
var msg = 'endpoint \'' + request.url + '\' not defined';
|
||||||
|
response.writeHead(501);
|
||||||
|
response.end(msg);
|
||||||
|
logger.debug(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!endpoint.types.includes(request.method)) {
|
||||||
|
var msg = 'endpoint \'' + request.url + '\' does not support ' + request.method + ' requests';
|
||||||
|
response.writeHead(405);
|
||||||
|
response.end(msg);
|
||||||
|
logger.debug(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (request.method == constants.HTTP_GET) {
|
||||||
|
handleGET(response, endpoint);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (request.method == constants.HTTP_POST) {
|
||||||
|
handlePOST(request, response, endpoint);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var msg = 'endpoint \'' + request.url + '\' does not have any handlers for ' + request.method + ' requests';
|
||||||
|
response.writeHead(405);
|
||||||
|
response.end(msg);
|
||||||
|
logger.debug(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGET(response, endpoint) {
|
||||||
|
var data = endpoint.data;
|
||||||
|
if (!data) {
|
||||||
|
response.writeHead(500);
|
||||||
|
response.end('error: could not get data for endpoint')
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.writeHead(200);
|
||||||
|
response.end(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePOST(request, response, endpoint) {
|
||||||
|
if (request.url.startsWith(constants.API_PEDALS)) {
|
||||||
|
handlePOSTPedals(request)
|
||||||
|
.then(function (msg) {
|
||||||
|
response.writeHead(200);
|
||||||
|
response.end(msg);
|
||||||
|
})
|
||||||
|
.catch(function (err, code) {
|
||||||
|
if (!code) {
|
||||||
|
code = 500;
|
||||||
|
}
|
||||||
|
response.writeHead(code);
|
||||||
|
response.end(err);
|
||||||
|
logger.error(err);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (request.url.startsWith(constants.API_PEDALBOARDS)) {
|
||||||
|
handlePOSTPedalboards(request)
|
||||||
|
.then(function (msg) {
|
||||||
|
response.writeHead(200);
|
||||||
|
response.end(msg);
|
||||||
|
})
|
||||||
|
.catch(function (err, code) {
|
||||||
|
if (!code) {
|
||||||
|
code = 500;
|
||||||
|
}
|
||||||
|
response.writeHead(code);
|
||||||
|
response.end(err);
|
||||||
|
logger.error(err);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var msg = 'endpoint \'' + request.url + '\' is not yet implemented for ' + request.method + ' requests';
|
||||||
|
response.writeHead(405);
|
||||||
|
response.end(msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPOSTParams(request) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var params = "";
|
||||||
|
request.on("data", function (data) {
|
||||||
|
params += data;
|
||||||
|
});
|
||||||
|
request.on("end", function () {
|
||||||
|
return resolve(new URLSearchParams(params));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePOSTPedals(request) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
getPOSTParams(request)
|
||||||
|
.then(function (params) {
|
||||||
|
var pedalId = request.url.substring(request.url.lastIndexOf('/') + 1);
|
||||||
|
var controlId = params.get('id');
|
||||||
|
if (controlId == undefined) {
|
||||||
|
reject('error: could not handle POST - missing parameter \'id\'', 400)
|
||||||
|
}
|
||||||
|
var value = params.get('value');
|
||||||
|
if (value == undefined) {
|
||||||
|
reject('error: could not handle POST - missing parameter \'value\'', 400)
|
||||||
|
}
|
||||||
|
modep.getPedalControlById(pedalId, controlId)
|
||||||
|
.then(function (control) {
|
||||||
|
modep.sendValueToControl(value, control);
|
||||||
|
})
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePOSTPedalboards(request) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
modep.setPedalboardById(request.url.substring(request.url.lastIndexOf('/') + 1))
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
start
|
||||||
|
}
|
78
libs/util.js
Normal file
78
libs/util.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
const logger = require('./logger.js');
|
||||||
|
const http = require('http');
|
||||||
|
const { HTTP_GET } = require('./constants.js');
|
||||||
|
|
||||||
|
function timeDiff(startTime) {
|
||||||
|
if (startTime instanceof Date) {
|
||||||
|
return (new Date().getTime() - startTime.getTime());
|
||||||
|
}
|
||||||
|
return new Date().getTime - startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clone(object) {
|
||||||
|
var clone = {};
|
||||||
|
for (key in object) {
|
||||||
|
clone[key] = object[key];
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
function httpGET(host, port, path, args) {
|
||||||
|
return httpRequest(host, port, path, HTTP_GET, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
function httpPOST(host, port, path, args) {
|
||||||
|
return httpRequest(host, port, path, HTTP_POST, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
function httpRequest(host, port, path, method, args) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (!path.startsWith("/")) {
|
||||||
|
path = "/" + path;
|
||||||
|
}
|
||||||
|
logger.debug('sending http \'' + method + '\' request to \'' + host + ':' + port + path + '\'...');
|
||||||
|
const request = http.request({
|
||||||
|
hostname: host,
|
||||||
|
port: port,
|
||||||
|
path: path,
|
||||||
|
method: method
|
||||||
|
}, function (response) {
|
||||||
|
if (!response) {
|
||||||
|
return reject('error: no response from host for http \'' + method + '\' request \'' + host + ':' + port + path + '\'');
|
||||||
|
}
|
||||||
|
logger.debug('http \'' + method + '\' request \'' + host + ':' + port + path + '\' returned status code ' + response.statusCode);
|
||||||
|
var responseData = "";
|
||||||
|
response.on('data', function (data) {
|
||||||
|
responseData += data;
|
||||||
|
});
|
||||||
|
response.on('end', function () {
|
||||||
|
logger.debug('http \'' + method + '\' request \'' + host + ':' + port + path + '\' returned data \'' + responseData + '\'');
|
||||||
|
return resolve(responseData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
request.on('error', function (err) {
|
||||||
|
return reject('http \'' + method + '\' request \'' + host + ':' + port + path + '\' returned an error >>> ' + err);
|
||||||
|
});
|
||||||
|
request.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toHex(value) {
|
||||||
|
var hex = Number(value).toString(16);
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortById(array) {
|
||||||
|
return array.sort(function (a, b) {
|
||||||
|
return a.id - b.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
timeDiff,
|
||||||
|
clone,
|
||||||
|
httpGET,
|
||||||
|
httpPOST,
|
||||||
|
toHex,
|
||||||
|
sortById
|
||||||
|
}
|
25
package.json
Normal file
25
package.json
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"name": "pbc",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "pedal board control",
|
||||||
|
"main": "pbc.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node pbc.js"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"scripts",
|
||||||
|
"commands",
|
||||||
|
"remote",
|
||||||
|
"api"
|
||||||
|
],
|
||||||
|
"author": "Daniel Sommer <daniel.sommer@velvettear.de>",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.velvettear.de/velvettear/pbc.git"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@frogcat/ttl2jsonld": "^0.0.6",
|
||||||
|
"moment": "^2.29.1"
|
||||||
|
}
|
||||||
|
}
|
12
pbc.js
Normal file
12
pbc.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
const logger = require('./libs/logger.js');
|
||||||
|
const api = require('./libs/api.js');
|
||||||
|
const server = require('./libs/server.js')
|
||||||
|
const packageJSON = require('./package.json');
|
||||||
|
|
||||||
|
logger.info("launching " + packageJSON.name + " " + packageJSON.version);
|
||||||
|
api.setupEndpoints()
|
||||||
|
.then(server.start)
|
||||||
|
.catch(function (err) {
|
||||||
|
logger.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
Loading…
Reference in a new issue