const util = require('./util.js'); const constants = require('./constants.js'); const logger = require('./logger.js'); const cache = require('./cache.js'); const commands = require('./commands.js'); const blinky = require('./blinky.js'); const osc = require('./osc.js'); const path = require('path'); const fs = require('fs'); const ttl2jsonld = require('@frogcat/ttl2jsonld').parse; let pedalboardIdBypassOrigin; function reset() { return new Promise(function (resolve, reject) { util.httpGET(global.config.modep.host, global.config.modep.port, '/reset') .then(resolve) .catch(reject); }); } function getBanks() { return new Promise(function (resolve, reject) { let banks = cache.getBanks(); if (banks != undefined) { return resolve(banks); } // FAKE DATA // let 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 (let index = 0; index < fake.length; index++) { // fake.id = index; // } // banks = util.sortById(fake); // return resolve(fake); util.httpGET(global.config.modep.host, global.config.modep.port, '/banks') .then(function (banks) { for (let index = 0; index < banks.length; index++) { let bank = banks[index]; bank.id = index; } banks = util.sortById(banks); cache.setBanks(banks); return resolve(banks); }) .catch(reject); }); } function getBankById(bankId) { return new Promise(function (resolve, reject) { getBanks() .then(function (banks) { for (let index = 0; index < banks.length; index++) { if (banks[index].id != bankId) { continue; } return resolve(banks[index]); } return reject('could not find bank by id \'' + bankId + '\''); }) .catch(reject); }); } function getPedalboards() { return new Promise(function (resolve, reject) { let pedalboards = cache.getPedalboards(); if (pedalboards != undefined) { return resolve(pedalboards); } // FAKE DATA // let 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 }]; // let id = 1; // for (let index = 0; index < fake.length; index++) { // let 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(global.config.modep.host, global.config.modep.port, '/pedalboard/list') .then(function (pedalboards) { let id = 1; for (let index = 0; index < pedalboards.length; index++) { let pedalboard = pedalboards[index]; if (pedalboard.bundle == constants.PEDALBOARD_DEFAULT) { pedalboard.id = 0; defaultPedalboard = pedalboard; continue; } pedalboard.id = id; id++; } pedalboards = util.sortById(pedalboards); cache.setPedalboards(pedalboards); return resolve(pedalboards); }) .catch(reject); }); } function getDefaultPedalboard() { return new Promise(function (resolve, reject) { let defaultPedalboard = cache.getDefaultPedalboard(); if (defaultPedalboard != undefined) { return resolve(defaultPedalboard); } getPedalboardByBundle(constants.PEDALBOARD_DEFAULT) .then(function (defaultPedalboard) { cache.setDefaultPedalboard(defaultPedalboard); return resolve(defaultPedalboard); }) .catch(reject); }); } function getCurrentPedalboard() { return new Promise(function (resolve, reject) { let currentPedalboard = cache.getCurrentPedalboard(); if (currentPedalboard != undefined && currentPedalboard.id != undefined) { return resolve(currentPedalboard); } // FAKE DATA // let fake = '/var/modep/pedalboards/FUZZ.pedalboard'; // getPedalboardByBundle(fake) // .then(function (pedalboard) { // currentPedalboard = pedalboard; // return resolve(pedalboard); // }) // .catch(reject); // PRODUCTION util.httpGET(global.config.modep.host, global.config.modep.port, '/pedalboard/current') .then(getPedalboardByBundle) .then(function (currentPedalboard) { cache.setCurrentPedalboard(currentPedalboard); return resolve(currentPedalboard) }) .catch(reject); }); } function getPedalboardById(pedalboardId) { return new Promise(function (resolve, reject) { getPedalboards() .then(function (pedalboards) { for (let index = 0; index < pedalboards.length; index++) { if (pedalboards[index].id != pedalboardId) { continue; } return resolve(pedalboards[index]); } return reject('could not find pedalboard by id \'' + pedalboardId + '\''); }) .catch(reject); }); } function getPedalboardByBundle(pedalboardBundle) { return new Promise(function (resolve, reject) { if (pedalboardBundle == undefined) { getDefaultPedalboard() .then(resolve) .catch(reject); return; } getPedalboards() .then(function (pedalboards) { for (let index = 0; index < pedalboards.length; index++) { if (pedalboards[index].bundle != pedalboardBundle) { continue; } return resolve(pedalboards[index]); } return reject('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 (let index = 0; index < pedal.controls.length; index++) { if (pedal.controls[index].id != controlId) { continue; } return resolve(pedal.controls[index]); } return reject('could not find control for pedal \'' + pedalId + '\' by id \'' + controlId + '\''); }) .catch(reject); }); } function getCurrentPedalById(id) { return new Promise(function (resolve, reject) { getCurrentPedals() .then(function (currentPedals) { for (let index = 0; index < currentPedals.length; index++) { if (currentPedals[index].id != id) { continue; } return resolve(currentPedals[index]); } return reject('could not find current pedal by id \'' + id + '\''); }) .catch(reject); }); } function getCurrentPedals() { return new Promise(function (resolve, reject) { let currentPedals = cache.getCurrentPedals(); if (currentPedals) { return resolve(currentPedals); } getCurrentPedalboard() .then(parseCurrentPedalboard) .then(resolve) .catch(reject); }); } async function parseCurrentPedalboard(currentPedalboard) { let pedals = []; const defaultPedalboard = await getDefaultPedalboard(); if (defaultPedalboard.id !== currentPedalboard.id) { let startTime = new Date(); logger.debug('parsing current pedalboard...'); if (currentPedalboard.uri === undefined) { throw new Error('could not determine current pedalboard config file'); } // FAKE DATA // let file = path.resolve(path.dirname(__dirname) + '/dev/' + currentPedalboard.uri.substring(currentPedalboard.uri.lastIndexOf('/') + 1)); let file = path.resolve(currentPedalboard.uri.replace('file://', '')); pedals = await new Promise((resolve, reject) => { fs.readFile(file, function (err, data) { if (err) { return reject('could not parse current pedalboard file \'' + file + '\' >>> ' + err); } let json = ttl2jsonld(data.toString())['@graph']; let id = 0; let currentPedals = []; for (let index = 0; index < json.length; index++) { let tmp = json[index]; if (!tmp['lv2:prototype']) { continue; } let name = tmp['@id']; currentPedals.push({ id: id, name: name, controls: [] }); id++; } for (let index = 0; index < json.length; index++) { let tmp = json[index]; let name = tmp['@id']; let value = tmp['ingen:value']; if (value == undefined) { continue; } let pedal = undefined; for (let 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 == constants.CONTROL_BYPASS) { value = value; } else { value = value['@value']; } let control = { id: id, name: name, value: value }; pedal.controls.push(control); id++; let 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); }); }); } cache.setCurrentPedals(pedals); blinky.setStatus(pedals); return pedals; } function setControlByRequest(pedalId, requestParams) { return new Promise(function (resolve, reject) { let controlId = requestParams.get('id'); if (controlId == undefined) { reject('could not handle POST - missing parameter \'id\'', 400); } let value = parseInt(requestParams.get('value')); if (value == undefined) { reject('could not handle POST - missing parameter \'value\'', 400); } else if (Number.isNaN(value)) { reject('parameter \'value\' is not a number', 400); } getPedalControlById(pedalId, controlId) .then(function (control) { resolve(setControl(control, value)); }) .catch(reject); }); } async function setControl(control, value) { if (control === undefined || control.midi === undefined) { throw new Error('control \'' + control.name + '\' with id \'' + control.id + '\' has no midi bindings'); } control.value = await osc.send(control.midi.controller, control.midi.channel, value); } function setPedalboardById(pedalboardId) { return new Promise(function (resolve, reject) { if (pedalboardId == undefined) { return reject('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('no bundle set for pedalboard'); } getCurrentPedalboard() .then(function (currentPedalboard) { if (pedalboard.id === currentPedalboard.id) { return Promise.reject('pedalboard with id \'' + currentPedalboard.id + '\' is already active'); } }) .then(function () { return reset() }) .then(function () { return util.httpPOST(global.config.modep.host, global.config.modep.port, '/pedalboard/load_bundle/?bundlepath=' + pedalboard.bundle) }) .then(function () { cache.setCurrentPedalboard(pedalboard); return parseCurrentPedalboard(pedalboard); }) .then(resolve) .catch(reject); }); } function hasControlMidiBindings(control) { return control !== undefined && control.midi !== undefined; } function isBypassed(control) { return control.name === constants.CONTROL_BYPASS && control } function isPedalBypassed(pedal) { const control = getBypassControlFromPedal(pedal); return control.value === undefined || control.value === 0; } function getBypassControlFromPedal(pedal) { if (pedal === undefined) { throw new Error('could not get bypass for an undefined pedal'); } if (pedal.controls === undefined || pedal.controls.length === 0) { throw new Error('could not get bypass for pedal \'' + pedal.name + '\' with id \'' + pedal.id + '\', pedal has no controls'); } let bypass; for (let index = 0; index < pedal.controls.length; index++) { const control = pedal.controls[index]; if (control.name === constants.CONTROL_BYPASS) { bypass = pedal.controls[index]; break; } } if (bypass === undefined) { throw new Error('could not find bypass control for pedal \'' + pedal.name + '\' with id \'' + pedal.id + '\''); } return bypass; } async function toggleBypass(pedalId) { let currentPedalboard = await getCurrentPedalboard(); let defaultPedalboard = await getDefaultPedalboard(); if (currentPedalboard.id === defaultPedalboard.id && pedalboardIdBypassOrigin === undefined) { throw new Error('could not activate bypass, default pedalboard is currently already active'); } if (pedalId === undefined) { try { let pedalboardId; if (pedalboardIdBypassOrigin === undefined) { pedalboardId = defaultPedalboard.id; pedalboardIdBypassOrigin = currentPedalboard.id; } else { pedalboardId = pedalboardIdBypassOrigin; pedalboardIdBypassOrigin = undefined; } await setPedalboardById(pedalboardId); blinky.setBypass(pedalboardId === defaultPedalboard.id); } catch (err) { throw new Error(err); } return; } const pedal = await getCurrentPedalById(pedalId); const bypass = getBypassControlFromPedal(pedal); let value = 0; if (bypass.value === undefined || bypass.value === 0) { value = 127; } try { await setControl(bypass, value); blinky.setPedalStatus(pedal); } catch (err) { throw new Error('could not toggle bypass for pedal ' + pedal.name + ' with id \'' + pedal.id + '\' > ' + err); } } module.exports = { getBanks, getBankById, getPedalboards, getPedalboardById, getDefaultPedalboard, getCurrentPedalboard, getCurrentPedals, getCurrentPedalById, getPedalControlById, setPedalboard, setPedalboardById, setControlByRequest, toggleBypass, isPedalBypassed, hasControlMidiBindings, isPedalBypassed, getBypassControlFromPedal }