Hello!
is there a way to dynamically create widgets from the custom module?
thanks
Hello!
is there a way to dynamically create widgets from the custom module?
thanks
Actually it could be enough for me just to be able to edit dynamically the HTML property of a widget from custom module, is it possible?
Of course answer was the listener in the property html linked to a variable in the custom module that changes…
There’s also the possibility to perform edit actions directly using remote control commands.
Thanks, I need to look at this solution too
One question,
I was able to create dynamically objects using the HTML property, but this is limited to certain type of objects
If I want instead to initiate your widgets, what should be the right way of doing it?
thanks
When I need to do that I create an empty container widget in the session and feed its widgets
property from the custom module:
receive('/EDIT', 'container_id', {
widgets: [
{
type: 'fader',
colorWidget: 'red',
range: {min:0, max: 100},
// omitted properties will use defaults
},
// etc
]
})
Here a more advanced example where I build generic plugin interfaces from the informations sent by the DAW : https://github.com/jean-emmanuel/ardour-control/blob/master/ardour-plugins-module.js
Awesome thanks
Thanks,
That works perfectly for me
I want to add widgets once when the application is launched, where is the right place to put this code?
I tried in the init() but it seems is invoked even before the panel is created so nothing happens.
The unload is only when the custom module is reloaded
Is there any method I can use?
Is there a list of methods that can be overridden in the custom module?
Thanks
You can use the app
object to catch the relevant events. In this case:
app.on('sessionOpened', (data, client)=>{
receive('/EDIT', id, widget_data, {clientId: client.id})
})
Hello!
In my case, there is a need to draw a control interface for the supercollider project.
In general terms, this is a simple audio mixer with a focus on spatial audio.
I tried to take the simplest route and created a complete widget with all the children in code.
But quickly enough it began to not fit into one OSC message.
Then I divided content of the interface into many short OSC commands, each of which either prepares the required nesting depth of the widget or adds its content.
// noprotect
var selfAddress = '127.0.0.1:8080';
var mixesAmount = get('varMixesAmount');
var mixesOnPage = get('inpSettingsUIMixesOnPage');
var pagesInGroup = get('inpSettingsUIMixesPagesInGroup');
var mixesPagesAmount = Math.ceil(mixesAmount / mixesOnPage);
var mixesGroupsAmount = Math.ceil(mixesPagesAmount / pagesInGroup);
var primaryGroupsCount = mixesGroupsAmount;
var groupsLevels = 1;
if (mixesPagesAmount == 1) {//One page case
//
send(selfAddress, '/EDIT/MERGE', 'pnlMixes', {
tabs: null,
widgets: [{
type: 'panel',
id: 'pnlMixesPage1',
//Geometry
expand: true,
//Panel Style
layout: 'horizontal',
scroll: false,
innerPadding: false
}]
});
} else {//Several pages case
//
var pnlMixesTabs = [];
if(mixesGroupsAmount == 1) {//One group case
//
for (let i = 1; i <= mixesPagesAmount; i++) {
//
pnlMixesTabs.push({
type: 'tab',
id: 'tabMixesPage' + i
});
}
//Create Tabs
send(selfAddress, '/EDIT/MERGE', 'pnlMixes', {
tabsPosition: 'left',
widgets: null,
tabs: pnlMixesTabs
});
//Configure Tabs
for (let i = 1; i <= mixesPagesAmount; i++) {
//
let tabNumFirst = (i - 1)*mixesOnPage + 1;
let tabNumLast = Math.min(i*mixesOnPage, mixesAmount);
send(selfAddress, '/EDIT/MERGE', 'tabMixesPage' + i, {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: tabNumFirst + '-' + tabNumLast,
widgets: [{
type: 'panel',
id:'pnlMixesPage' + i,
//Geometry
expand: true,
//Panel Style
layout: 'horizontal',
scroll: false,
innerPadding: false
}]
});
}
} else {//Several Groups case
//
while (primaryGroupsCount > pagesInGroup) {
//
primaryGroupsCount /= pagesInGroup;
groupsLevels++;
}
primaryGroupsCount = Math.ceil(primaryGroupsCount);
createGroupTabs(groupsLevels, 1, mixesAmount, 'pnlMixes', 'tabMixesGroup');
}
}
function createGroupTabs(groupsLevel, numFirst, numLast, parentTabID, tabNameDef) {
let currentGroupTabs = [];
let tabsAmount = Math.ceil((numLast - numFirst + 1)/mixesOnPage/Math.pow(pagesInGroup, groupsLevel));
for ( let tabNum = 1; tabNum <= tabsAmount; tabNum++ ) {
//
currentGroupTabs.push({
type: 'tab',
id: tabNameDef + tabNum
});
}
//Create Tabs
send(selfAddress, '/EDIT/MERGE', parentTabID, {
tabsPosition: 'left',
widgets: null,
tabs: currentGroupTabs
});
currentGroupTabs = null;
//Configure Tabs
for (let tabNum = 1; tabNum <= tabsAmount; tabNum++) {
//
let tabNumFirst = (tabNum - 1)*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst;
let tabNumLast = Math.min(tabNum*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst - 1, numLast);
//console.log('first=' + tabNumFirst + ' last=' + tabNumLast);
send(selfAddress, '/EDIT/MERGE', tabNameDef + tabNum, {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
tabsPosition: 'left',
label: tabNumFirst + '-' + tabNumLast,
widgets: null,
tabs: null
});
tabNumFirst = null;
tabNumLast = null;
}
//Recursively Create Tabs
if (groupsLevel > 0) {
for (let tabNum = 1; tabNum <= tabsAmount; tabNum++) {
//
let tabNumFirst = (tabNum - 1)*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst;
let tabNumLast = Math.min(tabNum*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst - 1, numLast);
createGroupTabs(groupsLevel - 1, tabNumFirst, tabNumLast, tabNameDef + tabNum, tabNameDef + tabNum + '-');
//setTimeout(function(){createGroupTabs(groupsLevel - 1, tabNumFirst, tabNumLast, tabNameDef + tabNum, tabNameDef + tabNum + '-')}, tabNum*500);
tabNumFirst = null;
tabNumLast = null;
}
} else {
//Create Pages
for (let tabNum = 1; tabNum <= tabsAmount; tabNum++) {
//
let tabNumFirst = (tabNum - 1)*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst;
let tabNumLast = Math.min(tabNum*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst -1, numLast);
let pageNum = (tabNumFirst - 1)/mixesOnPage + 1;
send(selfAddress, '/EDIT/MERGE', tabNameDef + tabNum, {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
//label: tabNumFirst + '-' + tabNumLast,
widgets: [{
type: 'panel',
id:'pnlMixesPage' + pageNum,
//Geometry
expand: true,
//Panel Style
scroll: false,
innerPadding: false
}]
});
tabNumFirst = null;
tabNumLast = null;
pageNum = null;
}
}
}
//Create Mixes
for (let pageNum = 1; pageNum <= mixesPagesAmount; pageNum++) {
//Create Tabs in Mixes Page
let pageTabs = [];
pageTabs.push({
type: 'tab',
id: 'tabMixesPage' + pageNum + 'All'
});
for (let mixNum = (pageNum - 1)*mixesOnPage + 1; mixNum <= Math.min(pageNum*mixesOnPage, mixesAmount); mixNum++) {
//
pageTabs.push({
type: 'tab',
id: 'tabMix' + mixNum
});
}
send(selfAddress, '/EDIT/MERGE', 'pnlMixesPage' + pageNum, {
//
tabs: pageTabs
});
pageTabs = null;
send(selfAddress, '/EDIT/MERGE', 'tabMixesPage' + pageNum + 'All', {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'ALL',
widgets: [{
type: 'panel',
id: 'pnlMixesPage' + pageNum + 'All',
//Geometry
expand: true,
//Style
//padding: 8,
//Panel Style
layout: 'horizontal',
//justify: 'space-around',
scroll: false,
//innerPadding: false
//Panel
traversing: 'smart'
}]
});
//Create 'ALL' Mixes Page View
let allViewWidgets = [];
for (let mixNum = (pageNum - 1)*mixesOnPage + 1; mixNum <= Math.min(pageNum*mixesOnPage, mixesAmount); mixNum++) {
//
allViewWidgets.push({
type: 'panel',
id:'pnlAllMix' + mixNum
});
}
send(selfAddress, '/EDIT/MERGE', 'pnlMixesPage' + pageNum + 'All', {
widgets: allViewWidgets
});
allViewWidgets = null;
//Individual Mix Panels on 'ALL' View
for (let mixNum = (pageNum - 1)*mixesOnPage + 1; mixNum <= Math.min(pageNum*mixesOnPage, mixesAmount); mixNum++) {
//
let mixPanelWidgets = [];
//'Select' Button
mixPanelWidgets.push({
//
type: 'button',
id: 'btnMix' + mixNum + 'Select',
//Geometry
width: 60,
height: 50,
//Style
colorText: '#ffffff',
//css: "font-size:125%;",
//Button Style
label: 'SEL',
//Scripting
onValue: ''
});
//Volume Panel
mixPanelWidgets.push({
//Widget
type: 'panel',
id: 'pnlMix' + mixNum + 'Volume',
//Geometry
height: 340,
//Panel Style
scroll: false,
innerPadding: false,
widgets: [{
//Widget
type: 'text',
id: 'lblMix' + mixNum + 'Volume',
//Geometry
left: 0,
top: 0,
width: 60,
height: 40,
//Style
colorText: '#ffffff',
//Value
default: 'MIX\n' + mixNum
},{
//Widget
type: 'fader',
id: 'fdrMix' + mixNum + 'Volume',
//Geometry
left: 0,
top: 40,
width: 60,
height: 300,
//Style
colorText: '#ffffff',
//Fader Style
knobSize: 20,
pips: true,
dashed: true,
//Fader
doubleTap: true,
range: "{\"max\": { \"+10\": 0.949481 },\"91%\": { \"+5\": 0.828787 },\"82%\": { \"0.0\": 0.716 },\"73%\": { \"-5\": 0.612454 },\"64%\": { \"-10\": 0.518539 },\"55%\": { \"-15\": 0.435375 },\"46%\": { \"-20\": 0.363271 },\"37%\": { \"-30\": 0.25009 },\"28%\": { \"-40\": 0.170984 },\"19%\": { \"-50\": 0.116622 },\"10%\": { \"-60\": 0.079482 },\"min\": { \"-inf\": 0 }}",
sensitivity: "@{varInput1SendsfdrSensitivity}",
//Value
default: 0.25,
//OSC
decimals: 6
},{
//Widget
type: 'fader',
id: 'fdrMix' + mixNum + 'VU',
interaction: false,
//Geometry
left: 25,
top: 52,
width: 15,
height: 278,
//Style
colorText: '#ffffff',
colorFill: '#97ff6a',
//Fader Style
design: 'compact',
//Fader
range: "{\"max\": { \"+10\": 0.949481 },\"91%\": { \"+5\": 0.828787 },\"82%\": { \"0.0\": 0.716 },\"73%\": { \"-5\": 0.612454 },\"64%\": { \"-10\": 0.518539 },\"55%\": { \"-15\": 0.435375 },\"46%\": { \"-20\": 0.363271 },\"37%\": { \"-30\": 0.25009 },\"28%\": { \"-40\": 0.170984 },\"19%\": { \"-50\": 0.116622 },\"10%\": { \"-60\": 0.079482 },\"min\": { \"-inf\": 0 }}",
//OSC
decimals: 14
}]
});
//'Mute' Button
mixPanelWidgets.push({
//
type: 'button',
id: 'btnMix' + mixNum + 'Mute',
//Geometry
width: 60,
height: 50,
//Style
colorText: '#ffffff',
//css: "font-size:125%;",
//Button Style
label: 'MUTE',
//Scripting
onValue: ''
});
//'0 dB' Button
mixPanelWidgets.push({
//
type: 'button',
id: 'btnMix' + mixNum + '0dB',
//Geometry
width: 60,
height: 40,
//Style
colorText: '#ffffff',
//css: "font-size:125%;",
//Button Style
label: 'set\n0 dB',
//Button
mode: 'momentary',
//Scripting
onValue: "set('fdrMix" + mixNum + "Volume', 0.716);"
});
//'-inf' Button
mixPanelWidgets.push({
//
type: 'button',
id: 'btnMix' + mixNum + '-Inf',
//Geometry
width: 60,
height: 40,
//Style
colorText: '#ffffff',
//css: "font-size:125%;",
//Button Style
label: 'set\n-inf',
//Button
mode: 'momentary',
//Scripting
onValue: "set('fdrMix" + mixNum + "Volume', 0);"
});
send(selfAddress, '/EDIT/MERGE', 'pnlAllMix' + mixNum, {
//Geometry
width: 60,
//Style
alphaStroke: 0,
//Panel Style
layout: 'vertical',
justify: 'space-around',
scroll: false,
innerPadding: false,
widgets: mixPanelWidgets
});
}
//Configure Individual Mix Tabs
for (let mixNum = (pageNum - 1)*mixesOnPage + 1; mixNum <= Math.min(pageNum*mixesOnPage, mixesAmount); mixNum++) {
//
send(selfAddress, '/EDIT/MERGE', 'tabMix' + mixNum, {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: mixNum,
widgets: [{
type: 'panel',
id:'pnlMix' + mixNum,
//Geometry
expand: true,
//Panel Style
layout: 'horizontal',
scroll: false,
innerPadding: false
}]
});
//Create Mix Options Tabs
let mixPage = [];
//Mix Main Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Main',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'MAIN'
});
//Mix EQ Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'EQ',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'EQ'
});
//Mix Gate Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Gate',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'GATE'
});
//Mix Compressor Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Comp',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'COMPRESSOR'
});
//Mix Limiter Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Limit',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'LIMITER'
});
//Mix Sends Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Sends',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'SENDS'
});
send(selfAddress, '/EDIT/MERGE', 'pnlMix' + mixNum, {
//
tabs: mixPage
});
mixPage = null;
//
}
}
But another difficulty arose: all code operations in the widget proceed quickly, but working with large amount of channels (200+) to be generated OSC commands can be transmitted depending on the computer and network environment slowly up to +- once per second, despite the fact that the commands are sent through the localhost.
On Linux until the last OSC command is transmitted, the allocated RAM continues to grow (in my case, up to 30GB) until the page crashes into an error.
On Windows some packets seem to be missed and do not reach the target, thereby leaving holes in the interface.
Now I’m looking towards creating a separate widget that will deal with orbiting the sending of OSC messages accumulated on a stack. Perhaps, so that it receives, along with the next sent message, a command to itself to send the next one. Don't know.
Session File:
Widget with the code shown above:
pnlUI -> pnlUIMain -> tabMixes -> scriptGenerateMixesPage
I'm missing something.
Could it just be that I'm using "send" function instead of "receive" one?
I feel as if I need to move the sofa from one room to another and to do this I drag it through the window to the street and back.
Indeed, you should always use receive() instead of send() to transmit commands from the custom module to the clients.
Thanks for your reply!
This path didn't work either.
A short command is sent from the widget to the module.
var selfAddress = '127.0.0.1:8080';
var mixesAmount = get('varMixesAmount');
var mixesOnPage = get('inpSettingsUIMixesOnPage');
var pagesInGroup = get('inpSettingsUIMixesPagesInGroup');
send(selfAddress, '/drawMix', mixesAmount, mixesOnPage, pagesInGroup);
The module calculates everything necessary and builds the interface.
function drawMixes( mixesAmount, mixesOnPage, pagesInGroup ) {
console.log('drawMixes function start');
var mixesPagesAmount = Math.ceil(mixesAmount / mixesOnPage);
var mixesGroupsAmount = Math.ceil(mixesPagesAmount / pagesInGroup);
var primaryGroupsCount = mixesGroupsAmount;
var groupsLevels = 1;
if (mixesPagesAmount == 1) {//One page case
//
receive('/EDIT/MERGE', 'pnlMixes', {
tabs: null,
widgets: [{
type: 'panel',
id: 'pnlMixesPage1',
//Geometry
expand: true,
//Panel Style
layout: 'horizontal',
scroll: false,
innerPadding: false
}]
});
} else {//Several pages case
//
var pnlMixesTabs = [];
if(mixesGroupsAmount == 1) {//One group case
//
for (let i = 1; i <= mixesPagesAmount; i++) {
//
pnlMixesTabs.push({
type: 'tab',
id: 'tabMixesPage' + i
});
}
//Create Tabs
receive('/EDIT/MERGE', 'pnlMixes', {
tabsPosition: 'left',
widgets: null,
tabs: pnlMixesTabs
});
//Configure Tabs
for (let i = 1; i <= mixesPagesAmount; i++) {
//
let tabNumFirst = (i - 1)*mixesOnPage + 1;
let tabNumLast = Math.min(i*mixesOnPage, mixesAmount);
receive('/EDIT/MERGE', 'tabMixesPage' + i, {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: tabNumFirst + '-' + tabNumLast,
widgets: [{
type: 'panel',
id:'pnlMixesPage' + i,
//Geometry
expand: true,
//Panel Style
layout: 'horizontal',
scroll: false,
innerPadding: false
}]
});
}
} else {//Several Groups case
//
while (primaryGroupsCount > pagesInGroup) {
//
primaryGroupsCount /= pagesInGroup;
groupsLevels++;
}
primaryGroupsCount = Math.ceil(primaryGroupsCount);
createGroupTabs(groupsLevels, 1, mixesAmount, 'pnlMixes', 'tabMixesGroup');
}
}
function createGroupTabs(groupsLevel, numFirst, numLast, parentTabID, tabNameDef) {
let currentGroupTabs = [];
let tabsAmount = Math.ceil((numLast - numFirst + 1)/mixesOnPage/Math.pow(pagesInGroup, groupsLevel));
for ( let tabNum = 1; tabNum <= tabsAmount; tabNum++ ) {
//
currentGroupTabs.push({
type: 'tab',
id: tabNameDef + tabNum
});
}
//Create Tabs
receive('/EDIT/MERGE', parentTabID, {
tabsPosition: 'left',
widgets: null,
tabs: currentGroupTabs
});
currentGroupTabs = null;
//Configure Tabs
for (let tabNum = 1; tabNum <= tabsAmount; tabNum++) {
//
let tabNumFirst = (tabNum - 1)*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst;
let tabNumLast = Math.min(tabNum*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst - 1, numLast);
//console.log('first=' + tabNumFirst + ' last=' + tabNumLast);
receive('/EDIT/MERGE', tabNameDef + tabNum, {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
tabsPosition: 'left',
label: tabNumFirst + '-' + tabNumLast,
widgets: null,
tabs: null
});
tabNumFirst = null;
tabNumLast = null;
}
//Recursively Create Tabs
if (groupsLevel > 0) {
for (let tabNum = 1; tabNum <= tabsAmount; tabNum++) {
//
let tabNumFirst = (tabNum - 1)*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst;
let tabNumLast = Math.min(tabNum*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst - 1, numLast);
createGroupTabs(groupsLevel - 1, tabNumFirst, tabNumLast, tabNameDef + tabNum, tabNameDef + tabNum + '-');
//setTimeout(function(){createGroupTabs(groupsLevel - 1, tabNumFirst, tabNumLast, tabNameDef + tabNum, tabNameDef + tabNum + '-')}, tabNum*500);
tabNumFirst = null;
tabNumLast = null;
}
} else {
//Create Pages
for (let tabNum = 1; tabNum <= tabsAmount; tabNum++) {
//
let tabNumFirst = (tabNum - 1)*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst;
let tabNumLast = Math.min(tabNum*Math.pow(pagesInGroup, groupsLevel)*mixesOnPage + numFirst -1, numLast);
let pageNum = (tabNumFirst - 1)/mixesOnPage + 1;
receive('/EDIT/MERGE', tabNameDef + tabNum, {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
//label: tabNumFirst + '-' + tabNumLast,
widgets: [{
type: 'panel',
id:'pnlMixesPage' + pageNum,
//Geometry
expand: true,
//Panel Style
scroll: false,
innerPadding: false
}]
});
tabNumFirst = null;
tabNumLast = null;
pageNum = null;
}
}
}
//Create Mixes
for (let pageNum = 1; pageNum <= mixesPagesAmount; pageNum++) {
//Create Tabs in Mixes Page
let pageTabs = [];
pageTabs.push({
type: 'tab',
id: 'tabMixesPage' + pageNum + 'All'
});
for (let mixNum = (pageNum - 1)*mixesOnPage + 1; mixNum <= Math.min(pageNum*mixesOnPage, mixesAmount); mixNum++) {
//
pageTabs.push({
type: 'tab',
id: 'tabMix' + mixNum
});
}
receive('/EDIT/MERGE', 'pnlMixesPage' + pageNum, {
//
tabs: pageTabs
});
pageTabs = null;
receive('/EDIT/MERGE', 'tabMixesPage' + pageNum + 'All', {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'ALL',
widgets: [{
type: 'panel',
id: 'pnlMixesPage' + pageNum + 'All',
//Geometry
expand: true,
//Style
//padding: 8,
//Panel Style
layout: 'horizontal',
//justify: 'space-around',
scroll: false,
//innerPadding: false
//Panel
traversing: 'smart'
}]
});
//Create 'ALL' Mixes Page View
let allViewWidgets = [];
for (let mixNum = (pageNum - 1)*mixesOnPage + 1; mixNum <= Math.min(pageNum*mixesOnPage, mixesAmount); mixNum++) {
//
allViewWidgets.push({
type: 'panel',
id:'pnlAllMix' + mixNum
});
}
receive('/EDIT/MERGE', 'pnlMixesPage' + pageNum + 'All', {
widgets: allViewWidgets
});
allViewWidgets = null;
//Individual Mix Panels on 'ALL' View
for (let mixNum = (pageNum - 1)*mixesOnPage + 1; mixNum <= Math.min(pageNum*mixesOnPage, mixesAmount); mixNum++) {
//
let mixPanelWidgets = [];
//'Select' Button
mixPanelWidgets.push({
//
type: 'button',
id: 'btnMix' + mixNum + 'Select',
//Geometry
width: 60,
height: 50,
//Style
colorText: '#ffffff',
//css: "font-size:125%;",
//Button Style
label: 'SEL',
//Scripting
onValue: ''
});
//Volume Panel
mixPanelWidgets.push({
//Widget
type: 'panel',
id: 'pnlMix' + mixNum + 'Volume',
//Geometry
height: 340,
//Panel Style
scroll: false,
innerPadding: false,
widgets: [{
//Widget
type: 'text',
id: 'lblMix' + mixNum + 'Volume',
//Geometry
left: 0,
top: 0,
width: 60,
height: 40,
//Style
colorText: '#ffffff',
//Value
default: 'MIX\n' + mixNum
},{
//Widget
type: 'fader',
id: 'fdrMix' + mixNum + 'Volume',
//Geometry
left: 0,
top: 40,
width: 60,
height: 300,
//Style
colorText: '#ffffff',
//Fader Style
knobSize: 20,
pips: true,
dashed: true,
//Fader
doubleTap: true,
range: "{\"max\": { \"+10\": 0.949481 },\"91%\": { \"+5\": 0.828787 },\"82%\": { \"0.0\": 0.716 },\"73%\": { \"-5\": 0.612454 },\"64%\": { \"-10\": 0.518539 },\"55%\": { \"-15\": 0.435375 },\"46%\": { \"-20\": 0.363271 },\"37%\": { \"-30\": 0.25009 },\"28%\": { \"-40\": 0.170984 },\"19%\": { \"-50\": 0.116622 },\"10%\": { \"-60\": 0.079482 },\"min\": { \"-inf\": 0 }}",
sensitivity: "@{varInput1SendsfdrSensitivity}",
//Value
default: 0.25,
//OSC
decimals: 6
},{
//Widget
type: 'fader',
id: 'fdrMix' + mixNum + 'VU',
interaction: false,
//Geometry
left: 25,
top: 52,
width: 15,
height: 278,
//Style
colorText: '#ffffff',
colorFill: '#97ff6a',
//Fader Style
design: 'compact',
//Fader
range: "{\"max\": { \"+10\": 0.949481 },\"91%\": { \"+5\": 0.828787 },\"82%\": { \"0.0\": 0.716 },\"73%\": { \"-5\": 0.612454 },\"64%\": { \"-10\": 0.518539 },\"55%\": { \"-15\": 0.435375 },\"46%\": { \"-20\": 0.363271 },\"37%\": { \"-30\": 0.25009 },\"28%\": { \"-40\": 0.170984 },\"19%\": { \"-50\": 0.116622 },\"10%\": { \"-60\": 0.079482 },\"min\": { \"-inf\": 0 }}",
//OSC
decimals: 14
}]
});
//'Mute' Button
mixPanelWidgets.push({
//
type: 'button',
id: 'btnMix' + mixNum + 'Mute',
//Geometry
width: 60,
height: 50,
//Style
colorText: '#ffffff',
//css: "font-size:125%;",
//Button Style
label: 'MUTE',
//Scripting
onValue: ''
});
//'0 dB' Button
mixPanelWidgets.push({
//
type: 'button',
id: 'btnMix' + mixNum + '0dB',
//Geometry
width: 60,
height: 40,
//Style
colorText: '#ffffff',
//css: "font-size:125%;",
//Button Style
label: 'set\n0 dB',
//Button
mode: 'momentary',
//Scripting
onValue: "set('fdrMix" + mixNum + "Volume', 0.716);"
});
//'-inf' Button
mixPanelWidgets.push({
//
type: 'button',
id: 'btnMix' + mixNum + '-Inf',
//Geometry
width: 60,
height: 40,
//Style
colorText: '#ffffff',
//css: "font-size:125%;",
//Button Style
label: 'set\n-inf',
//Button
mode: 'momentary',
//Scripting
onValue: "set('fdrMix" + mixNum + "Volume', 0);"
});
receive('/EDIT/MERGE', 'pnlAllMix' + mixNum, {
//Geometry
width: 60,
//Style
alphaStroke: 0,
//Panel Style
layout: 'vertical',
justify: 'space-around',
scroll: false,
innerPadding: false,
widgets: mixPanelWidgets
});
}
//Configure Individual Mix Tabs
for (let mixNum = (pageNum - 1)*mixesOnPage + 1; mixNum <= Math.min(pageNum*mixesOnPage, mixesAmount); mixNum++) {
//
receive('/EDIT/MERGE', 'tabMix' + mixNum, {
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: mixNum,
widgets: [{
type: 'panel',
id:'pnlMix' + mixNum,
//Geometry
expand: true,
//Panel Style
layout: 'horizontal',
scroll: false,
innerPadding: false
}]
});
//Create Mix Options Tabs
let mixPage = [];
//Mix Main Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Main',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'MAIN'
});
//Mix EQ Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'EQ',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'EQ'
});
//Mix Gate Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Gate',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'GATE'
});
//Mix Compressor Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Comp',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'COMPRESSOR'
});
//Mix Limiter Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Limit',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'LIMITER'
});
//Mix Sends Tab
mixPage.push({
type: 'tab',
id: 'tabMix' + mixNum + 'Sends',
//Panel Style
layout: 'vertical',
scroll: false,
innerPadding: false,
//Tab Style
label: 'SENDS'
});
receive('/EDIT/MERGE', 'pnlMix' + mixNum, {
//
tabs: mixPage
});
mixPage = null;
//
}
}
}
module.exports = {
init: function(){
},
oscInFilter:function(data){
// Filter incoming osc messages
var {address, args, host, port} = data
if ( address === '/drawMix' ) {
console.log('task to draw Mixes received');
console.log(args);
try {
let mixesAmount = args[0].value;
let mixesOnPage = args[1].value;
let pagesInGroup = args[2].value;
console.log(mixesAmount);
console.log(mixesOnPage);
console.log(pagesInGroup);
console.log('osc args correct');
drawMixes( mixesAmount, mixesOnPage, pagesInGroup );
} catch (e) {
}
}
return {address, args, host, port}
},
oscOutFilter:function(data){
// Filter outgoing osc messages
var {address, args, host, port, clientId} = data
return {address, args, host, port}
},
unload: function(){
},
}
At some point the page stops responding.
After a while, a notification appears:
"the connection to the server has been restored".
After this, the rest of the messages never arrive.
This can be seen from a fragment of the unfinished interface.
https://drive.google.com/drive/folders/1bJoNYVoNhA4C6w8PNfBcd9iXaI6QiUec?usp=sharing
I'm not sure that's the only problem but I'd avoid sending /EDIT/MERGE commands in loops, it's very inefficient, it'd be much better to build the tree offline and send one big /EDIT command (or as few as possible). Each /EDIT/MERGE sent to add a child to a panel/trigger actually triggers a full rebuild of that container. Implementing something like an optimized /EDIT/ADD or /EDIT/INSERT could be a solution in cases like this one but I'm not convinced it's worth it.
Hi jean-emmanuel,
I tried to dynamically create widgets and the example code in the documentation didn't work unless I created a new project (which I didn't do -> I thought it didn't work at all).
Could you maybe change or expand this section of the example code:
app.once('open', () => {
app.once('sessionSetPath', (data) => {
// Session was created
create_widgets()
})
// Create a new empty session
receive('', '', '/SESSION/CREATE')
})
with something like this:
app.once('sessionOpened', () => {
create_widgets()
})
which works when I open osc from the console using the --load
option.