nodeskini 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/client/archive/bundle.js +11528 -0
- package/client/archive/golem.html +60 -0
- package/client/archive/golemClient.js +595 -0
- package/client/archive/golembundle.js +11634 -0
- package/client/archive/sequencer.html +43 -0
- package/client/archive/sequenceurClient.js +815 -0
- package/client/archive/stylegolem.css +158 -0
- package/client/archive/stylesequenceur.css +204 -0
- package/client/clientListe/Sortable-master/.circleci/config.yml +33 -0
- package/client/clientListe/Sortable-master/.editorconfig +15 -0
- package/client/clientListe/Sortable-master/.github/ISSUE_TEMPLATE/bug-report.md +73 -0
- package/client/clientListe/Sortable-master/.github/ISSUE_TEMPLATE/custom-template.md +48 -0
- package/client/clientListe/Sortable-master/.github/ISSUE_TEMPLATE/feature-request.md +41 -0
- package/client/clientListe/Sortable-master/.jshintrc +25 -0
- package/client/clientListe/Sortable-master/.testcaferc.json +7 -0
- package/client/clientListe/Sortable-master/CONTRIBUTING.md +26 -0
- package/client/clientListe/Sortable-master/LICENSE +21 -0
- package/client/clientListe/Sortable-master/README.md +813 -0
- package/client/clientListe/Sortable-master/Sortable.js +3709 -0
- package/client/clientListe/Sortable-master/Sortable.min.js +2 -0
- package/client/clientListe/Sortable-master/Sortable.min.old.js +2 -0
- package/client/clientListe/Sortable-master/Sortable.min.old.old.js +2 -0
- package/client/clientListe/Sortable-master/babel.config.js +27 -0
- package/client/clientListe/Sortable-master/bower.json +30 -0
- package/client/clientListe/Sortable-master/entry/entry-complete.js +8 -0
- package/client/clientListe/Sortable-master/entry/entry-core.js +19 -0
- package/client/clientListe/Sortable-master/entry/entry-defaults.js +19 -0
- package/client/clientListe/Sortable-master/index.html +460 -0
- package/client/clientListe/Sortable-master/modular/sortable.complete.esm.js +3701 -0
- package/client/clientListe/Sortable-master/modular/sortable.core.esm.js +3698 -0
- package/client/clientListe/Sortable-master/modular/sortable.esm.js +3699 -0
- package/client/clientListe/Sortable-master/package-lock.json +5704 -0
- package/client/clientListe/Sortable-master/package.json +56 -0
- package/client/clientListe/Sortable-master/plugins/AutoScroll/AutoScroll.js +270 -0
- package/client/clientListe/Sortable-master/plugins/AutoScroll/README.md +80 -0
- package/client/clientListe/Sortable-master/plugins/AutoScroll/index.js +1 -0
- package/client/clientListe/Sortable-master/plugins/MultiDrag/MultiDrag.js +617 -0
- package/client/clientListe/Sortable-master/plugins/MultiDrag/README.md +96 -0
- package/client/clientListe/Sortable-master/plugins/MultiDrag/index.js +1 -0
- package/client/clientListe/Sortable-master/plugins/OnSpill/OnSpill.js +79 -0
- package/client/clientListe/Sortable-master/plugins/OnSpill/README.md +60 -0
- package/client/clientListe/Sortable-master/plugins/OnSpill/index.js +1 -0
- package/client/clientListe/Sortable-master/plugins/README.md +178 -0
- package/client/clientListe/Sortable-master/plugins/Swap/README.md +55 -0
- package/client/clientListe/Sortable-master/plugins/Swap/Swap.js +90 -0
- package/client/clientListe/Sortable-master/plugins/Swap/index.js +1 -0
- package/client/clientListe/Sortable-master/scripts/banner.js +8 -0
- package/client/clientListe/Sortable-master/scripts/build.js +17 -0
- package/client/clientListe/Sortable-master/scripts/esm-build.js +28 -0
- package/client/clientListe/Sortable-master/scripts/minify.js +11 -0
- package/client/clientListe/Sortable-master/scripts/test-compat.js +30 -0
- package/client/clientListe/Sortable-master/scripts/test.js +21 -0
- package/client/clientListe/Sortable-master/scripts/umd-build.js +15 -0
- package/client/clientListe/Sortable-master/src/Animation.js +175 -0
- package/client/clientListe/Sortable-master/src/BrowserInfo.js +12 -0
- package/client/clientListe/Sortable-master/src/EventDispatcher.js +57 -0
- package/client/clientListe/Sortable-master/src/PluginManager.js +87 -0
- package/client/clientListe/Sortable-master/src/Sortable.js +1971 -0
- package/client/clientListe/Sortable-master/src/utils.js +556 -0
- package/client/clientListe/Sortable-master/st/app.js +224 -0
- package/client/clientListe/Sortable-master/st/iframe/frame.html +32 -0
- package/client/clientListe/Sortable-master/st/iframe/index.html +49 -0
- package/client/clientListe/Sortable-master/st/logo.png +0 -0
- package/client/clientListe/Sortable-master/st/og-image.png +0 -0
- package/client/clientListe/Sortable-master/st/prettify/prettify.css +1 -0
- package/client/clientListe/Sortable-master/st/prettify/prettify.js +46 -0
- package/client/clientListe/Sortable-master/st/prettify/run_prettify.js +64 -0
- package/client/clientListe/Sortable-master/st/saucelabs.svg +1 -0
- package/client/clientListe/Sortable-master/st/theme.css +254 -0
- package/client/clientListe/Sortable-master/tests/Sortable.compat.test.js +39 -0
- package/client/clientListe/Sortable-master/tests/Sortable.test.js +386 -0
- package/client/clientListe/Sortable-master/tests/dual-list.html +34 -0
- package/client/clientListe/Sortable-master/tests/empty-list.html +30 -0
- package/client/clientListe/Sortable-master/tests/filter.html +27 -0
- package/client/clientListe/Sortable-master/tests/handles.html +27 -0
- package/client/clientListe/Sortable-master/tests/nested.html +67 -0
- package/client/clientListe/Sortable-master/tests/single-list.html +25 -0
- package/client/clientListe/Sortable-master/tests/style.css +18 -0
- package/client/clientListe/clientListe.html +148 -0
- package/client/clientListe/clientListe.js +1508 -0
- package/client/clientListe/clientListebundle.js +13164 -0
- package/client/clientListe/images/poubelle.png +0 -0
- package/client/clientListe/images/start.png +0 -0
- package/client/clientListe/images/stop.png +0 -0
- package/client/clientListe/images/submit.png +0 -0
- package/client/clientListe/sortable-theme-bootstrap.css +90 -0
- package/client/configurateur/configReact.js +273 -0
- package/client/configurateur/configReactbundle.js +295 -0
- package/client/configurateur/configurateur.css +95 -0
- package/client/configurateur/configurateur.html +48 -0
- package/client/configurateur/lib/jexcel.css +755 -0
- package/client/configurateur/lib/jexcel.js +14970 -0
- package/client/configurateur/lib/jsuites.css +2801 -0
- package/client/configurateur/lib/jsuites.js +11822 -0
- package/client/configurateur/lib/react-dom.production.min.js +239 -0
- package/client/configurateur/lib/react.production.min.js +32 -0
- package/client/configurateur/src/configReact.js +247 -0
- package/client/controleur/clientcontroleur.js +536 -0
- package/client/controleur/clientcontroleur.test.js +282 -0
- package/client/controleur/controleur.html +51 -0
- package/client/controleur/controleurbundle.js +565 -0
- package/client/controleur/stylecontroleur.css +236 -0
- package/client/controleurHH/controleurHH.html +71 -0
- package/client/controleurHH/controleurHH.js +252 -0
- package/client/controleurHH/styles/index.css +320 -0
- package/client/controleurHH/styles/material.css +11552 -0
- package/client/parametrage/paramReact.js +473 -0
- package/client/parametrage/paramReactbundle.js +500 -0
- package/client/parametrage/parametrage.css +111 -0
- package/client/parametrage/parametrage.html +163 -0
- package/client/parametrage/src/paramReact.js +459 -0
- package/client/score/hash.js +83 -0
- package/client/score/p5.min.js +3 -0
- package/client/score/parto1.js +1171 -0
- package/client/score/parto1bundle.js +1181 -0
- package/client/score/processing.min.js +431 -0
- package/client/score/score.html +15 -0
- package/client/score/score.js +34 -0
- package/client/simulateurListe/simulateurFork.js +750 -0
- package/client/simulateurListe/simulateurFork.mjs +681 -0
- package/client/simulateurListe/simulateurForkSansReorg.js +569 -0
- package/client/simulateurListe/simulateurListe.js +628 -0
- package/myReact/archive/Nodeemitvaluedlocal1.hh.js +52 -0
- package/myReact/archive/abort-parNode.js +79 -0
- package/myReact/archive/abroNode.js +169 -0
- package/myReact/archive/abroNode2.js +80 -0
- package/myReact/archive/atom.compile.hh.js +51 -0
- package/myReact/archive/await-countNode.js +67 -0
- package/myReact/archive/await-nowvalNode.js +44 -0
- package/myReact/archive/callHH.js +96 -0
- package/myReact/archive/emit-if2.hh.compiled.js +113 -0
- package/myReact/archive/every1Node.js +35 -0
- package/myReact/archive/if-runNode.js +74 -0
- package/myReact/archive/if1Node.js +43 -0
- package/myReact/archive/makeawait.js +0 -0
- package/myReact/archive/myReact.old.js +684 -0
- package/myReact/archive/orchestration.js +281 -0
- package/myReact/archive/orchestration1.js +132 -0
- package/myReact/archive/orchestration1.xml +465 -0
- package/myReact/archive/orchestration2.js +161 -0
- package/myReact/archive/orchestrationHH.mano.js +280 -0
- package/myReact/archive/orchestrationHHTest.js +428 -0
- package/myReact/archive/orchestrationHHTest.xml +234 -0
- package/myReact/archive/orchestrationHHTestRun.js +104 -0
- package/myReact/archive/orchestrationHHTestRun.xml +34 -0
- package/myReact/archive/orchestrationTest0.js +178 -0
- package/myReact/archive/orchestrationTest1.js +181 -0
- package/myReact/archive/orchestrationTest2.js +281 -0
- package/myReact/archive/run3pointsNode.js +59 -0
- package/myReact/archive/runNode.js +123 -0
- package/myReact/archive/runNode2.js +91 -0
- package/myReact/archive/testAwait1.js +141 -0
- package/myReact/archive/testAwait1.xml +86 -0
- package/myReact/archive/testEvery1.js +122 -0
- package/myReact/archive/testEvery1.xml +79 -0
- package/myReact/archive/testHH1.js +135 -0
- package/myReact/archive/testHH1.xml +86 -0
- package/myReact/archive/testHH1revu.js +104 -0
- package/myReact/archive/testHH2.js +122 -0
- package/myReact/archive/testHH2.xml +79 -0
- package/myReact/archive/testHH3.js +130 -0
- package/myReact/archive/testHH3.xml +86 -0
- package/myReact/archive/testHHabort.js +121 -0
- package/myReact/archive/testHHabort.xml +83 -0
- package/myReact/archive/testMakeawait.js +202 -0
- package/myReact/archive/testRun1.js +168 -0
- package/myReact/archive/testRun1.xml +142 -0
- package/myReact/archive/titi.js +28 -0
- package/myReact/archive/titi.xml +110 -0
- package/myReact/archive/toto.js +73 -0
- package/myReact/archive/toto.xml +198 -0
- package/myReact/archive/trap-await-parallelNode.js +123 -0
- package/myReact/inutiles/hiver2022.xml +804 -0
- package/myReact/inutiles/hopeNode.xml +459 -0
- package/myReact/inutiles/mars2022.xml +871 -0
- package/myReact/inutiles/mystique1.xml +318 -0
- package/myReact/inutiles/mystiqueOSC.xml +277 -0
- package/myReact/inutiles/opus5Node.xml +1271 -0
- package/myReact/inutiles/opus5NodeLinux.xml +1241 -0
- package/myReact/inutiles/orchestrationHH.xml +541 -0
- package/myReact/inutiles/orchestrationHH2.xml +547 -0
- package/myReact/inutiles/testHH.xml +95 -0
- package/myReact/inutiles/trouveLaPercuTenor.xml +349 -0
- package/myReact/myReact.js +744 -0
- package/myReact/myReact.min.js +1 -0
- package/myReact/orchestrationHH.js +311 -0
- package/myReact/orchestrationHH.mjs +436 -0
- package/myReact/orchestrationHH.mjs.map +1 -0
- package/package.json +46 -0
- package/serveur/OSCandMidi.mjs +361 -0
- package/serveur/computeScore.mjs +415 -0
- package/serveur/controleDAW.mjs +1149 -0
- package/serveur/defaultSession.csv +2 -0
- package/serveur/defaultSkiniParametres.js +119 -0
- package/serveur/gameOSC.mjs +96 -0
- package/serveur/groupeClientsSons.mjs +1014 -0
- package/serveur/ipConfig.json +24 -0
- package/serveur/ipConfig127.json +19 -0
- package/serveur/ipConfig75.json +17 -0
- package/serveur/ipConfigBH.json +19 -0
- package/serveur/ipConfigLocal.json +19 -0
- package/serveur/midiConfig.json +26 -0
- package/serveur/midiConfigBH.json +26 -0
- package/serveur/midiConfigVoid.json +3 -0
- package/serveur/midimix.mjs +570 -0
- package/serveur/saveParam.mjs +159 -0
- package/serveur/skiniParametres.good.js +132 -0
- package/serveur/skiniParametres.js +106 -0
- package/serveur/utilsHHSkini.hh.js +64 -0
- package/serveur/utilsSkini.mjs +137 -0
- package/serveur/websocketServer.mjs +2052 -0
- package/serveur/workerInterfaceZ.mjs +327 -0
- package/serveur/workerSynchro.mjs +49 -0
- package/skini.mjs +141 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileOverview
|
|
3
|
+
* <H3> CONTROLE DEPUIS LES COMMANDES MIDI OU OSC </H3>
|
|
4
|
+
* <BR>Ce programme est utilisé:
|
|
5
|
+
* <BR>1) Dans le cas d'Ableton, pour recevoir et traiter les commandes OSC venant de Processing qui sert de pont MIDI.
|
|
6
|
+
* Processing reçoit le MIDI qui envoie ces données MIDI de façon assez brute: NoteOn, NoteOff et ControlChange.
|
|
7
|
+
* <BR>2) Dans le cas de Bitwig, pour traité les message OSC envoyé directement par le controleur Bitwig.
|
|
8
|
+
* <BR>3) Dans le cas de Bitwig ou ABleton, pour traiter les messages MIDI envoyés directement pas la DAW.
|
|
9
|
+
* <BR><BR>On peut émettre des signaux HipHop d'ici.
|
|
10
|
+
* <BR>Le port de réception des commandes OSC est portWebSocket de la config IP
|
|
11
|
+
* <BR>Remarque: la chaine peut être complexe pour MIDIMIX:
|
|
12
|
+
* <BR>MIDIMIX =(midi)=> Processing =(OSC)=> Serveur =(OSC)=> Processing (VISU)
|
|
13
|
+
* @copyright (C) 2018-2024 Bertrand Petit-Hédelin
|
|
14
|
+
*
|
|
15
|
+
* This program is free software: you can redistribute it and/or modify
|
|
16
|
+
* it under the terms of the GNU General Public License as published by
|
|
17
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
18
|
+
* any later version.
|
|
19
|
+
*
|
|
20
|
+
* This program is distributed in the hope that it will be useful,
|
|
21
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
22
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
23
|
+
* GNU General Public License for more details.
|
|
24
|
+
*
|
|
25
|
+
* You should have received a copy of the GNU General Public License
|
|
26
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
27
|
+
*
|
|
28
|
+
* @author Bertrand Petit-Hédelin <bertrand@hedelin.fr>
|
|
29
|
+
* @version 1.3
|
|
30
|
+
*/
|
|
31
|
+
"use strict"
|
|
32
|
+
import { createRequire } from 'module';
|
|
33
|
+
const require = createRequire(import.meta.url);
|
|
34
|
+
import * as dgram from "dgram";
|
|
35
|
+
|
|
36
|
+
var debug = false;
|
|
37
|
+
var debug1 = true;
|
|
38
|
+
|
|
39
|
+
var param;
|
|
40
|
+
var synchroLink = false;
|
|
41
|
+
var linkReadyTostart = false;
|
|
42
|
+
var websocketServer;
|
|
43
|
+
var socketOpen = false;
|
|
44
|
+
|
|
45
|
+
var _setTempoLink, _initMidiIN;
|
|
46
|
+
export {
|
|
47
|
+
_setTempoLink as setTempoLink,
|
|
48
|
+
_initMidiIN as initMidiIN
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Set the parameters
|
|
53
|
+
* @param {array} list of parameters
|
|
54
|
+
*/
|
|
55
|
+
export function setParameters(parameters) {
|
|
56
|
+
param = parameters;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Set the websocket server module
|
|
61
|
+
* @param {object} module
|
|
62
|
+
*/
|
|
63
|
+
export function setWebSocketServer(socketServer) {
|
|
64
|
+
websocketServer = socketServer;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Give the status of Ableton link
|
|
69
|
+
* true if activated
|
|
70
|
+
* @returns {boolean} status
|
|
71
|
+
*/
|
|
72
|
+
export function getAbletonLinkStatus() {
|
|
73
|
+
return synchroLink;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** @namespace midimix */
|
|
77
|
+
/**
|
|
78
|
+
* Process the MIDI and OSC messages received from the DAW to send it to the orchestration.
|
|
79
|
+
* @memberof midimix
|
|
80
|
+
* @param {object} machineServeur
|
|
81
|
+
*/
|
|
82
|
+
export function midimix(machineServeur) {
|
|
83
|
+
var par = require('./ipConfig');
|
|
84
|
+
var osc = require('osc-min');
|
|
85
|
+
var sock = dgram.createSocket('udp4');
|
|
86
|
+
var midiConfig = require("./midiConfig.json");
|
|
87
|
+
|
|
88
|
+
var previousNote = 0;
|
|
89
|
+
var previousNotes = [0, 0, 0];
|
|
90
|
+
var previousChannel = 0;
|
|
91
|
+
var previousTimeStamp = 0;
|
|
92
|
+
|
|
93
|
+
var note;
|
|
94
|
+
var canal;
|
|
95
|
+
var timeStamp;
|
|
96
|
+
var noteSkini;
|
|
97
|
+
let link;
|
|
98
|
+
|
|
99
|
+
// Pour la synchro via Ableton Link.
|
|
100
|
+
if (param.synchroLink !== undefined) {
|
|
101
|
+
if (param.synchroLink) synchroLink = true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (synchroLink && !socketOpen) {
|
|
105
|
+
console.log("INFO: Synchro Ableton Link");
|
|
106
|
+
const abletonlink = require('abletonlink');
|
|
107
|
+
link = new abletonlink();
|
|
108
|
+
let localBeat = 0;
|
|
109
|
+
let instantBeat = 0;
|
|
110
|
+
let instantPhase = 0;
|
|
111
|
+
|
|
112
|
+
link.startUpdate(10, (beat, phase, bpm) => {
|
|
113
|
+
instantBeat = Math.round(beat);
|
|
114
|
+
instantPhase = Math.round(phase*100);
|
|
115
|
+
|
|
116
|
+
// On envoie un tick à chaque changement de beat.
|
|
117
|
+
// Ce serait peut-être mieux d'utiliser la phase ?
|
|
118
|
+
if (localBeat !== instantBeat) {
|
|
119
|
+
if (debug) console.log("midimix.js: Synchro Link ", Math.round(beat), Math.round(phase), Math.round(bpm));
|
|
120
|
+
|
|
121
|
+
// On a besoin de la phase pour synchroniser les départs.
|
|
122
|
+
// On commence à envoyer des Tick après avoir reçu la phase 1.
|
|
123
|
+
// La numérotation de la phase commence à 1 dans node et non à 0 comme sur PureData.
|
|
124
|
+
if(!linkReadyTostart){
|
|
125
|
+
if(instantPhase === 100){
|
|
126
|
+
linkReadyTostart = true;
|
|
127
|
+
if(debug1) console.log("INFO: midimix: link ready");
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
localBeat = instantBeat;
|
|
132
|
+
websocketServer.sendOSCTick();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* To set the tempo when synchro using Ableton Link
|
|
139
|
+
* @function
|
|
140
|
+
* @param {number} tempo
|
|
141
|
+
* @memberof midimix
|
|
142
|
+
* @inner
|
|
143
|
+
*/
|
|
144
|
+
function setTempoLink(tempo) {
|
|
145
|
+
if (link !== undefined) {
|
|
146
|
+
link.bpm = tempo;
|
|
147
|
+
if(debug) console.log("INFO: midimix.js: setTempolink:", tempo);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
_setTempoLink = setTempoLink;
|
|
151
|
+
|
|
152
|
+
// Pour la synchro MIDI
|
|
153
|
+
var synchroMidi = false;
|
|
154
|
+
if (param.synchoOnMidiClock !== undefined) {
|
|
155
|
+
if (param.synchoOnMidiClock) synchroMidi = true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Pour commande direct de Skini en MIDI sans passer par une passerèle ====================
|
|
159
|
+
// Par défaut on communique en OSC avec la DAW ou la passerèle
|
|
160
|
+
var directMidi = false;
|
|
161
|
+
if (param.directMidiON !== undefined) {
|
|
162
|
+
if (param.directMidiON) directMidi = true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (synchroMidi && synchroLink) console.log("WARN: Two synchronisations activated MIDI and Link");
|
|
166
|
+
|
|
167
|
+
if (debug) console.log("========= directMidi dans midimix:", directMidi);
|
|
168
|
+
|
|
169
|
+
if (directMidi && midiConfig[0] !== undefined ) {
|
|
170
|
+
// Le require est fait ici car on doit pouvoir fonctionner en OSC sans MIDI du tout
|
|
171
|
+
// midi-node est dépendant de l'OS. Il faut installer le bon npm.
|
|
172
|
+
var midi = require('midi');
|
|
173
|
+
|
|
174
|
+
var midiInput = new midi.Input();
|
|
175
|
+
var midiSync = new midi.Input();
|
|
176
|
+
|
|
177
|
+
// Les controleurs
|
|
178
|
+
var controlers = [];
|
|
179
|
+
var controlerIndex;
|
|
180
|
+
var midiPortSync;
|
|
181
|
+
var midiPortClipFromDAW;
|
|
182
|
+
var tempoTickDuration = 0;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Update the list of MIDI controlers according the MIDI configuration file.
|
|
186
|
+
* @function
|
|
187
|
+
* @memberof midimix
|
|
188
|
+
* @inner
|
|
189
|
+
*/
|
|
190
|
+
function getMidiPortControlers() {
|
|
191
|
+
for (var i = 0; i < midiConfig.length; i++) {
|
|
192
|
+
if (midiConfig[i].spec === "controler") {
|
|
193
|
+
var input = new midi.Input();
|
|
194
|
+
var controler = {
|
|
195
|
+
"input": input,
|
|
196
|
+
"name": midiConfig[i].name
|
|
197
|
+
}
|
|
198
|
+
controlers.push(controler);
|
|
199
|
+
|
|
200
|
+
if (debug) console.log("getMidiPortControlers: Midi" +
|
|
201
|
+
midiConfig[i].type + ", usage:" + midiConfig[i].spec +
|
|
202
|
+
", bus: " + midiConfig[i].name + ", " + midiConfig[i].comment, controlers);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Get the index of a MIDI controler in te list of MIDI controlers
|
|
209
|
+
* of the MIDI configuration file.
|
|
210
|
+
* @function
|
|
211
|
+
* @memberof midimix
|
|
212
|
+
* @param {string} Midi port name
|
|
213
|
+
* @return {number} index
|
|
214
|
+
* @inner
|
|
215
|
+
*/
|
|
216
|
+
function getControlerIndex(portName) {
|
|
217
|
+
for (var j = 0; j < midiInput.getPortCount(); ++j) {
|
|
218
|
+
if (midiInput.getPortName(j) === portName) {
|
|
219
|
+
if (debug) console.log("getControlerIndex: Midi", j);
|
|
220
|
+
return j;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return -1;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* To process MIDI message comming from the MIDI controlers.
|
|
228
|
+
* @function
|
|
229
|
+
* @memberof midimix
|
|
230
|
+
* @inner
|
|
231
|
+
*/
|
|
232
|
+
function createControlerMessageOn() {
|
|
233
|
+
for (var i = 0; i < controlers.length; i++) {
|
|
234
|
+
controlerIndex = getControlerIndex(controlers[i].name);
|
|
235
|
+
if (controlerIndex === -1) {
|
|
236
|
+
console.log("WARN: controler :", controlers[i].name, " does not exist");
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
controlers[i].input.openPort(controlerIndex);
|
|
240
|
+
controlers[i].input.ignoreTypes(false, false, false);
|
|
241
|
+
if (debug) console.log("create Controler listener : ",
|
|
242
|
+
controlers[i].input.getPortName(controlerIndex));
|
|
243
|
+
|
|
244
|
+
controlers[i].input.on('message', function (deltaTime, message) {
|
|
245
|
+
if (debug1) console.log('midimix.js: Input received : ' + message + ' d:' + deltaTime);
|
|
246
|
+
|
|
247
|
+
// Ici les actions sur commande MIDI
|
|
248
|
+
// On ne distingue pas les controleurs.
|
|
249
|
+
|
|
250
|
+
});
|
|
251
|
+
controlerIndex++;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get the MIDI port used by the DAW for receiving the clips (patterns)
|
|
257
|
+
* command from Skini.
|
|
258
|
+
* @function
|
|
259
|
+
* @memberof midimix
|
|
260
|
+
* @return {number} index of the MIDI port
|
|
261
|
+
* @inner
|
|
262
|
+
*/
|
|
263
|
+
function getMidiPortForClipFromDAW() {
|
|
264
|
+
for (var i = 0; i < midiConfig.length; i++) {
|
|
265
|
+
if (midiConfig[i].spec === "clipFromDAW") {
|
|
266
|
+
for (var j = 0; j < midiInput.getPortCount(); ++j) {
|
|
267
|
+
if (midiInput.getPortName(j) === midiConfig[i].name) {
|
|
268
|
+
if (debug) console.log("getPortForClipFromDAW: Midi" +
|
|
269
|
+
midiConfig[i].type + ", usage:" + midiConfig[i].spec +
|
|
270
|
+
", bus: " + midiConfig[i].name + ", " + midiConfig[i].comment);
|
|
271
|
+
return j;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
console.log("ERR: getPortForClipFromDAW: no Midi port for receiving from DAW");
|
|
277
|
+
return -1;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Get the MIDI port used by the DAW for sending the MIDI synchro.
|
|
282
|
+
* @function
|
|
283
|
+
* @memberof midimix
|
|
284
|
+
* @return {number} index of the MIDI port
|
|
285
|
+
* @inner
|
|
286
|
+
*/
|
|
287
|
+
function getMidiPortForSyncFromDAW() {
|
|
288
|
+
for (var i = 0; i < midiConfig.length; i++) {
|
|
289
|
+
if (midiConfig[i].spec === "syncFromDAW") {
|
|
290
|
+
for (var j = 0; j < midiInput.getPortCount(); ++j) {
|
|
291
|
+
if (midiSync.getPortName(j) === midiConfig[i].name) {
|
|
292
|
+
if (debug) console.log("getMidiPortForSyncFromDAW: Midi" +
|
|
293
|
+
midiConfig[i].type + ", usage:" + midiConfig[i].spec +
|
|
294
|
+
", bus: " + midiConfig[i].name + ", " + midiConfig[i].comment);
|
|
295
|
+
return j;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
console.log("ERR: getMidiPortForSyncFromDAW: no Midi port for receiving sync from DAW");
|
|
301
|
+
return -1;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Initialize the MIDI ports for processing the MIDI messages/commands from DAW and
|
|
306
|
+
* controlers.
|
|
307
|
+
* Put two MIDI listeners one on NoteOn and one on Synchro.
|
|
308
|
+
* @function
|
|
309
|
+
* @memberof midimix
|
|
310
|
+
* @inner
|
|
311
|
+
*/
|
|
312
|
+
function initMidiIN() {
|
|
313
|
+
midiPortSync = getMidiPortForSyncFromDAW();
|
|
314
|
+
midiPortClipFromDAW = getMidiPortForClipFromDAW();
|
|
315
|
+
|
|
316
|
+
getMidiPortControlers();
|
|
317
|
+
createControlerMessageOn();
|
|
318
|
+
|
|
319
|
+
midiInput.openPort(midiPortClipFromDAW);
|
|
320
|
+
midiInput.ignoreTypes(false, true, false);
|
|
321
|
+
//console.log("ClipToDaw: ", midiPortClipFromDAW, midiInput.getPortName(midiPortClipFromDAW));
|
|
322
|
+
|
|
323
|
+
midiSync.openPort(midiPortSync);
|
|
324
|
+
midiSync.ignoreTypes(false, false, false);
|
|
325
|
+
//console.log("midiSync: ", midiPortSync, midiSync.getPortName(midiPortSync));
|
|
326
|
+
|
|
327
|
+
// Traitement des commande Midi reçues d'Ableton Live
|
|
328
|
+
// pour les patterns lancés.
|
|
329
|
+
midiInput.on('message', function (deltaTime, message) {
|
|
330
|
+
// On ne traite que les noteON, de 1001 0000 (144) à 1001 1111 (159)
|
|
331
|
+
if (message[0] >= 144 && message[0] <= 159) {
|
|
332
|
+
if (debug) console.log('midimix.js: initMidiIN: Input recieved :' + message + ' d:' + deltaTime);
|
|
333
|
+
note = message[1];
|
|
334
|
+
canal = message[0] - 144;
|
|
335
|
+
//timeStamp = deltaTime;
|
|
336
|
+
|
|
337
|
+
// Ableton envoie les commandes MIDI en comptant depuis le canal 1 (et pas 0 comme d'autres contrôleurs)
|
|
338
|
+
// Il faut donc faire attention à la gestion des canaux MIDI en fonction du contrôleur.
|
|
339
|
+
noteSkini = note + (canal - 1) * 127;
|
|
340
|
+
|
|
341
|
+
// Ableton répéte 1 fois le message NoteON une première fois (deux envois) avec un léger décalage temporel.
|
|
342
|
+
// Si le pattern tourne, et qu'il est activé, Ableton envoie 4 commandes MIDI noteON avec le même timestamp.
|
|
343
|
+
// Le timestamp est proche de la micro-seconde.
|
|
344
|
+
if (isInPreviousNotes(noteSkini) && Math.round(deltaTime) === 0) {
|
|
345
|
+
//if (isInPreviousNotes(noteSkini) && previousTimeStamp === Math.round(timeStamp)){ // à peu près une seconde
|
|
346
|
+
if (debug) console.log("midimix.js: REPETITION : ", noteSkini, timeStamp, previousTimeStamp);
|
|
347
|
+
} else {
|
|
348
|
+
//previousTimeStamp = Math.round(timeStamp);
|
|
349
|
+
|
|
350
|
+
if (debug) console.log("midimix.js: noteSkini: ", noteSkini, note, canal);
|
|
351
|
+
if (debug) console.log("midimix.js: isInPreviousNotes:", isInPreviousNotes(noteSkini));
|
|
352
|
+
|
|
353
|
+
// Avec PUSH branché, Ableton Live envoie des notes négatives...
|
|
354
|
+
// dont je ne connais pas la signification
|
|
355
|
+
if (noteSkini > 0) {
|
|
356
|
+
insertInPreviousNotes(noteSkini);
|
|
357
|
+
if (debug) console.log("midimix.js: Note de pattern reçue d'Ableton:", noteSkini);
|
|
358
|
+
websocketServer.sendSignalFromDAW(noteSkini);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// Traitement des messages de synchro Midi (24 messages pour une noire)
|
|
365
|
+
let v0 = 0;
|
|
366
|
+
midiSync.on('message', function (deltaTime, message) {
|
|
367
|
+
tempoTickDuration++;
|
|
368
|
+
if (message[0] === 248) {
|
|
369
|
+
if (tempoTickDuration > 23) {
|
|
370
|
+
if (debug) console.log("midimix.js: midiSync.on:", Date.now() - v0, "ms");
|
|
371
|
+
//console.log('Sync recieved :' + message + ' d:' + deltaTime);
|
|
372
|
+
if (debug) console.log("midimix 1 : Tick", message[0]);
|
|
373
|
+
// Test pour éviter une "double synchro en OSC est en MIDI"
|
|
374
|
+
if (synchroMidi) {
|
|
375
|
+
websocketServer.sendOSCTick();
|
|
376
|
+
}
|
|
377
|
+
tempoTickDuration = 0;
|
|
378
|
+
if (debug) { v0 = Date.now(); }
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
_initMidiIN = initMidiIN;
|
|
384
|
+
|
|
385
|
+
initMidiIN();
|
|
386
|
+
} // Fin fonction si MIDI
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Insert a node in the table previousNotes[] which is used
|
|
390
|
+
* to process the MIDI message send by Ableton Live.
|
|
391
|
+
* Ableton repeats the NoteON message once (two times) with a slight time delay.
|
|
392
|
+
* If the pattern is running, and it is activated, Ableton sends 4 MIDI noteON commands with the same timestamp.
|
|
393
|
+
* The timestamp is close to the micro-second.
|
|
394
|
+
* @function
|
|
395
|
+
* @memberof midimix
|
|
396
|
+
* @param {number} Skini Note
|
|
397
|
+
* @inner
|
|
398
|
+
*/
|
|
399
|
+
function insertInPreviousNotes(laNote) {
|
|
400
|
+
for (var i = 1; i < previousNotes.length; i++) {
|
|
401
|
+
previousNotes[i - 1] = previousNotes[i];
|
|
402
|
+
}
|
|
403
|
+
previousNotes[previousNotes.length - 1] = laNote;
|
|
404
|
+
if (debug) console.log("midimix: insInPreviousNote: ", previousNotes);
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Check if the Skini Note is in the previousNotes table.
|
|
409
|
+
* to process the MIDI message send by Ableton Live.
|
|
410
|
+
* @function
|
|
411
|
+
* @memberof midimix
|
|
412
|
+
* @param {number} Skini Note
|
|
413
|
+
* @inner
|
|
414
|
+
*/
|
|
415
|
+
function isInPreviousNotes(laNote) {
|
|
416
|
+
for (var i = 0; i < previousNotes.length; i++) {
|
|
417
|
+
if (previousNotes[i] === laNote) return true;
|
|
418
|
+
}
|
|
419
|
+
return false;
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Management of the UDP socket for OSC and OSC messages.
|
|
424
|
+
* @function
|
|
425
|
+
* @memberof midimix
|
|
426
|
+
* @param {number} Skini Note
|
|
427
|
+
* @inner
|
|
428
|
+
*/
|
|
429
|
+
sock.close();
|
|
430
|
+
|
|
431
|
+
sock = dgram.createSocket("udp4", function (msg, rinfo) {
|
|
432
|
+
var error, message;
|
|
433
|
+
try {
|
|
434
|
+
message = osc.fromBuffer(msg); // Message OSC recu
|
|
435
|
+
//msgloc.type = message.address;
|
|
436
|
+
//msgloc.value1 = message.args[0].value; // C'est compliqué le parsing OSC
|
|
437
|
+
//ws.send(JSON.stringify(msgloc)); // Pas utile pour le moment
|
|
438
|
+
if (debug) {
|
|
439
|
+
console.log("midimix.js: socket reçoit OSC: [", message.address + " : " + message.args[0].value, "]");
|
|
440
|
+
}
|
|
441
|
+
switch (message.address) {
|
|
442
|
+
|
|
443
|
+
case "/AkaiControlerChange": // Emission des signaux en fonction des CC reçus
|
|
444
|
+
switch (message.args[0].value) {
|
|
445
|
+
case 62: // Ce CC de MIDIMIX est suivi de la configuration complète de la table...
|
|
446
|
+
machineServeur.inputAndReact("scene", 4); // Pour démo, pas utilisable en l'état
|
|
447
|
+
break;
|
|
448
|
+
default:
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
break;
|
|
452
|
+
|
|
453
|
+
case "/AkaiNoteOff":
|
|
454
|
+
if (debug) console.log("midimix.js: Commande NoteOFF OSC:", message.args[0].value);
|
|
455
|
+
break;
|
|
456
|
+
|
|
457
|
+
case "/nanoKEY2NoteOff":
|
|
458
|
+
if (debug) console.log("midimix.js: Commande NoteOFF OSC:", message.args[0].value);
|
|
459
|
+
break;
|
|
460
|
+
|
|
461
|
+
case "/AbletonNoteOn":
|
|
462
|
+
case "/BitwigNoteOn":
|
|
463
|
+
case "/AkaiNoteOn": // Emission des signaux en fonction des notes Midi reçues
|
|
464
|
+
case "/nanoKEY2NoteOn":
|
|
465
|
+
if (debug) console.log("midimix.js: Commande NoteON OSC:", message.args[0].value);
|
|
466
|
+
switch (message.args[0].value) {
|
|
467
|
+
|
|
468
|
+
case 25:
|
|
469
|
+
websocketServer.sendSignalStartFromMIDI();
|
|
470
|
+
break;
|
|
471
|
+
|
|
472
|
+
case 26:
|
|
473
|
+
websocketServer.sendSignalStopFromMIDI();
|
|
474
|
+
break;
|
|
475
|
+
|
|
476
|
+
default:
|
|
477
|
+
websocketServer.sendSignalFromMIDI(message.args[0].value);
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
break;
|
|
481
|
+
|
|
482
|
+
case "/MPK25NoteOn":
|
|
483
|
+
case "/Session1NoteOn":
|
|
484
|
+
break;
|
|
485
|
+
|
|
486
|
+
// Traitement des commandes MIDI reçues d'Ableton lorsqu'un clip est lancé.
|
|
487
|
+
// C'est un mécanisme utilisé pour traiter des "patterns pivots", cad qui peuvent être utilisés
|
|
488
|
+
// dans l'orchestration comme événements.
|
|
489
|
+
// Il y a ici un filtrage un peu particulier lié à la façon dont Ableton envoie les commandes MIDI
|
|
490
|
+
// à l'activation d'un clip.
|
|
491
|
+
case "/StartClipNoteOn":
|
|
492
|
+
note = parseInt(message.args[0].value);
|
|
493
|
+
canal = parseInt(message.args[1].value);
|
|
494
|
+
timeStamp = parseFloat(message.args[2].value); // String car pb avec les Floats
|
|
495
|
+
// Ableton envoie les commandes MIDI en comptant depuis le canal 1 (et pas 0 comme d'autres contrôleurs)
|
|
496
|
+
// Il faut donc faire attention à la gestion des canaux MIDI en fonction du contrôleur.
|
|
497
|
+
noteSkini = note + (canal - 1) * 127;
|
|
498
|
+
|
|
499
|
+
// Ableton répéte 1 fois le message NoteON une première fois (deux envois) avec un léger décalage temporel.
|
|
500
|
+
// Si le pattern tourne, et qu'il est activé, Ableton envoie 4 commandes MIDI noteON avec le même timestamp.
|
|
501
|
+
// En divisant le timestamp par 1 000 000, on est proche de la seconde. Le timestamp est proche de la micro-seconde.
|
|
502
|
+
if (isInPreviousNotes(noteSkini) && previousTimeStamp === Math.round(timeStamp / 1000000)) { // à peu près une seconde
|
|
503
|
+
if (debug) console.log("midimix.js: REPETITION : ", noteSkini, timeStamp, previousTimeStamp);
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
previousTimeStamp = Math.round(timeStamp / 1000000);
|
|
508
|
+
|
|
509
|
+
if (debug) {
|
|
510
|
+
console.log("midimix.js: socket reçoit OSC: [", message.address + " : " +
|
|
511
|
+
message.args[0].value,
|
|
512
|
+
+message.args[1].value,
|
|
513
|
+
+message.args[2].value,
|
|
514
|
+
"]");
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (debug) console.log("midimix.js: noteSkini: ", noteSkini, note, canal);
|
|
518
|
+
if (debug) console.log("isInPreviousNotes:", isInPreviousNotes(noteSkini));
|
|
519
|
+
|
|
520
|
+
// Avec PUSH branché, Ableton Live envoie des notes négatives...
|
|
521
|
+
// dont je ne connais pas la signification
|
|
522
|
+
if (noteSkini > 0) {
|
|
523
|
+
insertInPreviousNotes(noteSkini);
|
|
524
|
+
websocketServer.sendSignalFromDAW(noteSkini);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
break;
|
|
528
|
+
|
|
529
|
+
case "/StopClipNoteOff":
|
|
530
|
+
break;
|
|
531
|
+
|
|
532
|
+
case "/ClipControlerChange":
|
|
533
|
+
if (debug) console.log("Valeur du CC=", message.args[1].value);
|
|
534
|
+
break;
|
|
535
|
+
|
|
536
|
+
case "/videoNoteOn":
|
|
537
|
+
websocketServer.sendSignalFromMidiMix(message.args[0].value);
|
|
538
|
+
break;
|
|
539
|
+
|
|
540
|
+
case "/AbletonTick":
|
|
541
|
+
case "/BitwigTick":
|
|
542
|
+
if (debug) console.log("midimix 2: bitwig tick: ", message.args[0].value);
|
|
543
|
+
// Test pour éviter une "double synchro en OSC et en MIDI ou Link, si on oublie
|
|
544
|
+
// de désactiver l'une ou l'autre dans la DAW.
|
|
545
|
+
if (!synchroMidi && !synchroLink) {
|
|
546
|
+
websocketServer.sendOSCTick();
|
|
547
|
+
}
|
|
548
|
+
break;
|
|
549
|
+
|
|
550
|
+
default:
|
|
551
|
+
console.log("midimix.js: socket reçoit OSC: [", message.address + " : " + (message.args[0].value), "]");
|
|
552
|
+
break;
|
|
553
|
+
}
|
|
554
|
+
return; // console.log(osc.fromBuffer(msg));
|
|
555
|
+
} catch (error) {
|
|
556
|
+
console.log("midimix.js: ERR dans réception OSC :", message.args, error);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
sock.on('listening', function () {
|
|
562
|
+
var address = sock.address();
|
|
563
|
+
if (debug1) console.log('INFO: midimix.js: UDP Server listening on ' + address.address + ":" + address.port);
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
if (!socketOpen) {
|
|
567
|
+
sock.bind(par.InPortOSCMIDIfromDAW, par.serverIPAddress);
|
|
568
|
+
socketOpen = true;
|
|
569
|
+
}
|
|
570
|
+
}
|