-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdivider.js
129 lines (106 loc) · 4.51 KB
/
divider.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
module.exports = function (RED) {
'use strict';
function DividerNode (config) {
const nrp = require('node-red-contrib-properties');
RED.nodes.createNode(this, config);
var node = this;
let properties = new nrp.NodeRedProperties(node, config,
{
name: { value: 'bar' },
input: { value: 'beat' },
output: { value: 'bar' },
ratio: { value: 4 }
});
/*
* node.offsetCount is used as an offest to the number of beats when calculating the number of bars and the beat of bar from the beat number
* This is usually 0, but changes when the ratio is changed
*/
properties.handle(setRatio, 'ratio');
reset();
setRatio(config.ratio || 4);
this.on('input', function (msg) {
if (properties.input(msg)) {
return;
}
switch (msg.payload) {
case 'tick':
const start = msg.start || [];
const end = msg.end || [];
let inputVal, inputCount, outputCount;
inputVal = msg[node.input];
inputCount = counts(inputVal).input;
outputCount = counts(inputVal).output;
if (inputCount >= node.ratio && end.includes(node.input)) {
end.push(node.output);
}
if (inputCount === 1 && start.includes(node.input)) {
start.push(node.output);
}
msg.start = start;
msg.end = end;
var counter = node.input + '_of_' + node.output;
var beatsPerName = 'beats_per_' + node.output;
let beatsPerVal;
if (node.input === 'beat') {
beatsPerVal = node.ratio;
} else {
beatsPerVal = node.ratio * msg['beats_per_' + node.input];
}
msg[beatsPerName] = beatsPerVal;
msg[counter] = inputCount;
node.lastInput = inputCount;
msg[node.output] = outputCount;
node.lastOutput = outputCount;
node.status({ 'text':
node.output + ':' + outputCount + ' ' +
node.input + ':' + inputCount + ' ' +
' ratio ' + node.ratio });
node.send(msg);
break;
case 'reset':
reset();
node.send(msg);
break;
default:
node.send(msg);
break;
}
});
// calculate the counts (e.g. beat of bar, bar)
function counts (inputVal) {
let beatExpr = inputVal - 1 + node.offsetCount;
return { input: beatExpr % node.ratio + 1,
output: Math.floor(beatExpr / node.ratio) + 1 };
}
function setRatio (ratio, msg) {
msg = msg || {};
ratio = Number(ratio);
if (ratio > 0 && Number.isInteger(ratio)) {
let oldRatio = node.ratio;
node.ratio = ratio;
// recalculate the offset to retain the same e.g. bar and beat of bar (bob)
// beat = (bar-1)*ratio + bob + offset
if (node.lastOutput) {
node.offsetCount = node.offsetCount + (node.lastOutput - 1) * (ratio - oldRatio);
// when changing down ratio, make sure the new input is at most the last beat of bar
let changeDown = Math.max(node.lastInput - ratio, 0);
node.offsetCount -= changeDown;
} else {
// should only happen when first deploying
node.offsetCount = 0;
}
} else {
node.warn('Not a valid ratio: ' + ratio);
}
}
function reset () {
node.input = config.input || 'beat';
node.output = config.output || 'bar';
node.ratio = config.ratio || 4;
node.name = config.name;
node.offsetCount = 0;
node.status('');
}
}
RED.nodes.registerType('divider', DividerNode);
};