nodeskini 1.0.2 → 1.0.5
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/blocklySkini/scripts/hiphop_blocks.js +3991 -6104
- package/blocklySkini/scripts/hiphop_blocks.old.js +3010 -0
- package/blocklySkini/scripts/hiphop_blocks11-2025.js +6104 -0
- package/blocklySkini/scripts/main2.js +4 -4
- package/client/configurateur/configReact.js +1 -1
- package/client/configurateur/configReactbundle.js +16 -10
- package/client/configurateur/src/configReact.js +1 -1
- package/client/parametrage/paramReact.js +1 -1
- package/client/parametrage/paramReactbundle.js +6 -5
- package/client/parametrage/src/paramReact.js +2 -2
- package/client/simulateurListe/simulateurFork.mjs +1 -1
- package/client/simulateurListe/simulateurListe.js +3 -3
- package/myReact/archive/Nodeemitvaluedlocal1.hh.js +18 -18
- package/myReact/archive/atom.compile.hh.js +21 -20
- package/myReact/orchestrationHH.hh.js +2009 -0
- package/myReact/orchestrationHH.mjs +262 -420
- package/myReact/orchestrationHH.mjs.map +1 -1
- package/package.json +8 -3
- package/serveur/OSCandMidi.mjs +7 -5
- package/serveur/controleDAW.mjs +3 -2
- package/serveur/defaultSkiniParametres.js +20 -13
- package/serveur/groupeClientsSons.mjs +10 -5
- package/serveur/ipConfig.json +2 -2
- package/serveur/midimix.mjs +13 -13
- package/serveur/saveParam.mjs +4 -15
- package/serveur/skiniParametres.js +8 -19
- package/serveur/utilsHHSkini.hh.js +64 -64
- package/serveur/websocketServer.mjs +2090 -2052
- package/serveur/workerInterfaceZ.mjs +4 -7
|
@@ -1,2052 +1,2090 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileOverview Websocket management. This is the main part of Skini for messages
|
|
3
|
-
* management and control. Something like a main switch.
|
|
4
|
-
* Most of the API and functions here are local.
|
|
5
|
-
* @copyright (C) 2022-2024 Bertrand Petit-Hédelin
|
|
6
|
-
*
|
|
7
|
-
* This program is free software: you can redistribute it and/or modify
|
|
8
|
-
* it under the terms of the GNU General Public License as published by
|
|
9
|
-
* the Free Software Foundation, either version 3 of the License, or
|
|
10
|
-
* any later version.
|
|
11
|
-
*
|
|
12
|
-
* This program is distributed in the hope that it will be useful,
|
|
13
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
-
* GNU General Public License for more details.
|
|
16
|
-
*
|
|
17
|
-
* You should have received a copy of the GNU General Public License
|
|
18
|
-
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
-
*
|
|
20
|
-
* avec capteurIZTest.csv et TestCapteurIZ.als
|
|
21
|
-
*
|
|
22
|
-
* @author Bertrand Petit-Hédelin <bertrand@hedelin.fr>
|
|
23
|
-
* @version 1.4
|
|
24
|
-
*/
|
|
25
|
-
// @ts-check
|
|
26
|
-
'use strict'
|
|
27
|
-
import { createRequire } from 'module';
|
|
28
|
-
const require = createRequire(import.meta.url);
|
|
29
|
-
|
|
30
|
-
import { compile } from "@hop/hiphop/lib/hhc-compiler.mjs";
|
|
31
|
-
import * as fs from "fs";
|
|
32
|
-
import * as compScore from './computeScore.mjs';
|
|
33
|
-
import * as gameOSC from './gameOSC.mjs';
|
|
34
|
-
import * as oscMidiLocal from './OSCandMidi.mjs';
|
|
35
|
-
import * as saveParam from './saveParam.mjs';
|
|
36
|
-
|
|
37
|
-
const ipConfig = require('./ipConfig.json');
|
|
38
|
-
const midiConfig = require("./midiConfig.json");
|
|
39
|
-
|
|
40
|
-
const decache = require('decache');
|
|
41
|
-
const { stringify } = require('querystring');
|
|
42
|
-
import { Worker } from 'worker_threads';
|
|
43
|
-
import { fork } from "child_process";
|
|
44
|
-
|
|
45
|
-
const defaultOrchestrationName = "orchestrationHH.mjs";
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
let
|
|
49
|
-
let
|
|
50
|
-
let
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
let
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
let
|
|
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
|
-
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
par.
|
|
146
|
-
par.
|
|
147
|
-
par.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
par.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
parlocal.
|
|
185
|
-
parlocal.
|
|
186
|
-
parlocal.
|
|
187
|
-
|
|
188
|
-
parlocal.
|
|
189
|
-
|
|
190
|
-
parlocal.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
parlocal.groupesDesSons[i][7] = entry.map(x => parseInt(x, 10));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
*
|
|
220
|
-
* @
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const
|
|
230
|
-
const
|
|
231
|
-
const
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
const
|
|
235
|
-
const
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
let
|
|
243
|
-
let
|
|
244
|
-
let
|
|
245
|
-
let
|
|
246
|
-
|
|
247
|
-
let
|
|
248
|
-
|
|
249
|
-
let
|
|
250
|
-
let
|
|
251
|
-
let
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
let
|
|
262
|
-
let
|
|
263
|
-
let
|
|
264
|
-
let
|
|
265
|
-
let
|
|
266
|
-
let
|
|
267
|
-
let
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
let
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
let
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
function
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
*
|
|
326
|
-
* @
|
|
327
|
-
* @
|
|
328
|
-
* @
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
*
|
|
374
|
-
* @
|
|
375
|
-
* @
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
*
|
|
506
|
-
* @
|
|
507
|
-
* @
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
*
|
|
531
|
-
* @
|
|
532
|
-
* @
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
*
|
|
550
|
-
* @
|
|
551
|
-
* @
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
if (debug) console.log("
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
* @
|
|
571
|
-
* @
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
*
|
|
585
|
-
* @
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
*
|
|
598
|
-
* @
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
* @
|
|
617
|
-
* @
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
var
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
*
|
|
636
|
-
* @
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
* @
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
//
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
if (timerLocal
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
*
|
|
701
|
-
* @
|
|
702
|
-
* @
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
*
|
|
717
|
-
* @
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
if (
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
//
|
|
768
|
-
//
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
if (DAWState
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
*
|
|
817
|
-
* @
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
* @
|
|
844
|
-
* @
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
if (debug1) {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
*
|
|
862
|
-
*
|
|
863
|
-
* @
|
|
864
|
-
* @
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
*
|
|
925
|
-
* @
|
|
926
|
-
* @
|
|
927
|
-
* @
|
|
928
|
-
* @param {
|
|
929
|
-
* @param {string}
|
|
930
|
-
* @param {number}
|
|
931
|
-
* @
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
DAWNote =
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
let
|
|
944
|
-
let
|
|
945
|
-
let
|
|
946
|
-
let
|
|
947
|
-
let
|
|
948
|
-
let
|
|
949
|
-
|
|
950
|
-
let
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
//
|
|
959
|
-
//
|
|
960
|
-
//
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
if (debug) console.log("Web Socket Server.js: pushClipDAW:
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
*
|
|
978
|
-
* @
|
|
979
|
-
* @
|
|
980
|
-
* @
|
|
981
|
-
* @param {
|
|
982
|
-
* @param {number}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
if (
|
|
989
|
-
if (debug) console.log("
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
//
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
messageLog.
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
console.log("
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
//
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
//
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
if (debug) console.log(
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
//
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
break;
|
|
1220
|
-
|
|
1221
|
-
case "
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
}
|
|
1454
|
-
})
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
//
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
//
|
|
1838
|
-
//
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
}
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
if (
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
if (
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
if (
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
function
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @fileOverview Websocket management. This is the main part of Skini for messages
|
|
3
|
+
* management and control. Something like a main switch.
|
|
4
|
+
* Most of the API and functions here are local.
|
|
5
|
+
* @copyright (C) 2022-2024 Bertrand Petit-Hédelin
|
|
6
|
+
*
|
|
7
|
+
* This program is free software: you can redistribute it and/or modify
|
|
8
|
+
* it under the terms of the GNU General Public License as published by
|
|
9
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
* any later version.
|
|
11
|
+
*
|
|
12
|
+
* This program is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
* GNU General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* You should have received a copy of the GNU General Public License
|
|
18
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
*
|
|
20
|
+
* avec capteurIZTest.csv et TestCapteurIZ.als
|
|
21
|
+
*
|
|
22
|
+
* @author Bertrand Petit-Hédelin <bertrand@hedelin.fr>
|
|
23
|
+
* @version 1.4
|
|
24
|
+
*/
|
|
25
|
+
// @ts-check
|
|
26
|
+
'use strict'
|
|
27
|
+
import { createRequire } from 'module';
|
|
28
|
+
const require = createRequire(import.meta.url);
|
|
29
|
+
|
|
30
|
+
import { compile } from "@hop/hiphop/lib/hhc-compiler.mjs";
|
|
31
|
+
import * as fs from "fs";
|
|
32
|
+
import * as compScore from './computeScore.mjs';
|
|
33
|
+
import * as gameOSC from './gameOSC.mjs';
|
|
34
|
+
import * as oscMidiLocal from './OSCandMidi.mjs';
|
|
35
|
+
import * as saveParam from './saveParam.mjs';
|
|
36
|
+
|
|
37
|
+
const ipConfig = require('./ipConfig.json');
|
|
38
|
+
const midiConfig = require("./midiConfig.json");
|
|
39
|
+
|
|
40
|
+
const decache = require('decache');
|
|
41
|
+
const { stringify } = require('querystring');
|
|
42
|
+
import { Worker } from 'worker_threads';
|
|
43
|
+
import { fork } from "child_process";
|
|
44
|
+
|
|
45
|
+
const defaultOrchestrationName = "orchestrationHH.mjs";
|
|
46
|
+
const defaultOrchestrationNameHH = "orchestrationHH.hh.js";
|
|
47
|
+
|
|
48
|
+
let par;
|
|
49
|
+
let DAW;
|
|
50
|
+
let midimix;
|
|
51
|
+
let sessionFile; // Pour le chemin complet de la session en cours (descripteur en ".csv")
|
|
52
|
+
let parametersFile;
|
|
53
|
+
let parametersFileGlobal;
|
|
54
|
+
const origine = "./serveur/defaultSkiniParametres.js";
|
|
55
|
+
const defaultSession = "./serveur/defaultSession.csv";
|
|
56
|
+
let HipHopSrc; // Fichier HipHop éditer en texte et à compiler
|
|
57
|
+
let decacheParameters;
|
|
58
|
+
let childSimulator;
|
|
59
|
+
const targetHH = "./myReact/orchestrationHH.mjs"; // Redondant à revoir
|
|
60
|
+
// Attention en dur car le chemin est utilisé ailleurs, dans groupClientsSons.js
|
|
61
|
+
// pour orchestrationHH.js
|
|
62
|
+
const generatedDir = "./myReact/";
|
|
63
|
+
|
|
64
|
+
// Declarations to move from CJS to ES6
|
|
65
|
+
let _getBroadCastServer, _sendSignalFromDAW, _sendSignalFromMIDI, _sendSignalStopFromMIDI;
|
|
66
|
+
let _sendSignalStartFromMIDI, _sendSignalFromMidiMix, _sendOSCTick, _getAutomatePossible;
|
|
67
|
+
let _setPatternListLength;
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
_getBroadCastServer as getBroadCastServer,
|
|
71
|
+
_sendSignalFromDAW as sendSignalFromDAW,
|
|
72
|
+
_sendSignalFromMIDI as sendSignalFromMIDI,
|
|
73
|
+
_sendSignalStopFromMIDI as sendSignalStopFromMIDI,
|
|
74
|
+
_sendSignalStartFromMIDI as sendSignalStartFromMIDI,
|
|
75
|
+
_sendSignalFromMidiMix as sendSignalFromMidiMix,
|
|
76
|
+
_sendOSCTick as sendOSCTick,
|
|
77
|
+
_getAutomatePossible as getAutomatePossible,
|
|
78
|
+
_setPatternListLength as setPatternListLength
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Répertoires par défaut, ils sont à fixer dans le fichier de configuration.
|
|
82
|
+
// Où se trouvent les fichiers XML d'orchestration
|
|
83
|
+
// On ne peut pas donner de chemin absolu dans un browser.
|
|
84
|
+
// Ce sont les fichiers csv "descripteurs" des patterns
|
|
85
|
+
// et les fichiers de configuration ".js"
|
|
86
|
+
// Bug de principe (21/06/2022): On ne peut pas changer ces paramètres dans le fichier .js
|
|
87
|
+
// puisque ces paramètres sont fixés avant tous choix de pièces ....
|
|
88
|
+
// Il devrait s'agir de paramètres globaux et non liés aux fichiers de config de chaque pièce.
|
|
89
|
+
const sessionPath = ipConfig.sessionPath; //"./pieces/";
|
|
90
|
+
const piecePath = ipConfig.piecePath; //"./pieces/";
|
|
91
|
+
|
|
92
|
+
import * as groupesClientSon from './groupeClientsSons.mjs';
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* To load some modules.
|
|
96
|
+
* Used only at Skini launch.
|
|
97
|
+
* @param {Object} midimixage reference
|
|
98
|
+
*/
|
|
99
|
+
export async function setParameters(midimixage) {
|
|
100
|
+
midimix = midimixage;
|
|
101
|
+
await import('./controleDAW.mjs').then((daw) => {
|
|
102
|
+
DAW = daw;
|
|
103
|
+
groupesClientSon.setMidimix(midimix);
|
|
104
|
+
initMidiPort();
|
|
105
|
+
startWebSocketServer();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The simulator can be updated at serveral places
|
|
111
|
+
*/
|
|
112
|
+
function updateSimulatorParameters(param) {
|
|
113
|
+
|
|
114
|
+
if (childSimulator !== undefined) {
|
|
115
|
+
let message = {
|
|
116
|
+
type: "PARAMETERS",
|
|
117
|
+
data: param
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
childSimulator.send(message);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.log("ERR: websocketserver: updateSimulatorParameters:", err);
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
if (debug1) console.log("INFO: websocketServer: updateSimulatorParameters :No Fork Simulator");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Convert data in the good format
|
|
131
|
+
* and reload new parametrers in the different
|
|
132
|
+
* modules during a Skini session.
|
|
133
|
+
*
|
|
134
|
+
* Cette fonction n'est pas bonne.
|
|
135
|
+
* Il faut regénerer complétement les paramètres et envoyer
|
|
136
|
+
* la nouvelle version.
|
|
137
|
+
*
|
|
138
|
+
* @param {object} param
|
|
139
|
+
*/
|
|
140
|
+
function reloadParametersOld(param) {
|
|
141
|
+
let par = param; // C'est seulement pour la lecture car on a le même objet
|
|
142
|
+
|
|
143
|
+
// Le transfert des parametre passe tout en chaine de caractère qui ne
|
|
144
|
+
// sont pas traduite en int.
|
|
145
|
+
par.nbeDeGroupesClients = parseInt(param.nbeDeGroupesClients, 10);
|
|
146
|
+
par.algoGestionFifo = parseInt(param.algoGestionFifo, 10);
|
|
147
|
+
par.tempoMax = parseInt(param.tempoMax, 10);
|
|
148
|
+
par.tempoMin = parseInt(param.tempoMin, 10);
|
|
149
|
+
par.limiteDureeAttente = parseInt(param.limiteDureeAttente, 10);
|
|
150
|
+
|
|
151
|
+
// Pas vraiment utile pour les booléens ?
|
|
152
|
+
par.shufflePatterns = param.shufflePatterns;
|
|
153
|
+
par.avecMusicien = param.avecMusicien;
|
|
154
|
+
par.reactOnPlay = param.reactOnPlay;
|
|
155
|
+
|
|
156
|
+
// Typage pour les antécédents dans Score. En rechargeant depuis le client
|
|
157
|
+
// de parametrage on a une chaine de caractères et pas un tableau.
|
|
158
|
+
for (let i = 0; i < param.groupesDesSons.length; i++) {
|
|
159
|
+
if (typeof param.groupesDesSons[i][7] === 'string' || param.groupesDesSons[i][7] instanceof String) {
|
|
160
|
+
par.groupesDesSons[i][7] = param.groupesDesSons[i][7].split(',');
|
|
161
|
+
}
|
|
162
|
+
for (let j = 0; j < par.groupesDesSons[i][7].length; j++) {
|
|
163
|
+
par.groupesDesSons[i][7][j] = parseInt(par.groupesDesSons[i][7][j]);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
oscMidiLocal.setParameters(par);
|
|
168
|
+
DAW.setParameters(par);
|
|
169
|
+
groupesClientSon.setParameters(par);
|
|
170
|
+
midimix.setParameters(par);
|
|
171
|
+
updateSimulatorParameters(par);
|
|
172
|
+
|
|
173
|
+
initMidiPort();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function reloadParameters(param) {
|
|
177
|
+
// Création manuelle d'une copie
|
|
178
|
+
let parlocal = {
|
|
179
|
+
...param, // copie superficielle : fonctions et propriétés simples sont conservées
|
|
180
|
+
groupesDesSons: param.groupesDesSons.map(group => [...group]) // copie des sous-tableaux
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// Conversion des types
|
|
184
|
+
parlocal.nbeDeGroupesClients = parseInt(param.nbeDeGroupesClients, 10);
|
|
185
|
+
parlocal.algoGestionFifo = parseInt(param.algoGestionFifo, 10);
|
|
186
|
+
parlocal.tempoMax = parseInt(param.tempoMax, 10);
|
|
187
|
+
parlocal.tempoMin = parseInt(param.tempoMin, 10);
|
|
188
|
+
parlocal.limiteDureeAttente = parseInt(param.limiteDureeAttente, 10);
|
|
189
|
+
|
|
190
|
+
parlocal.shufflePatterns = param.shufflePatterns;
|
|
191
|
+
parlocal.avecMusicien = param.avecMusicien;
|
|
192
|
+
parlocal.reactOnPlay = param.reactOnPlay;
|
|
193
|
+
|
|
194
|
+
// Traitement des antécédents (index 7)
|
|
195
|
+
for (let i = 0; i < parlocal.groupesDesSons.length; i++) {
|
|
196
|
+
const entry = parlocal.groupesDesSons[i][7];
|
|
197
|
+
if (typeof entry === 'string') {
|
|
198
|
+
parlocal.groupesDesSons[i][7] = entry.split(',').map(x => parseInt(x, 10));
|
|
199
|
+
} else if (Array.isArray(entry)) {
|
|
200
|
+
parlocal.groupesDesSons[i][7] = entry.map(x => parseInt(x, 10));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Envoi aux modules
|
|
205
|
+
oscMidiLocal.setParameters(parlocal);
|
|
206
|
+
DAW.setParameters(parlocal);
|
|
207
|
+
groupesClientSon.setParameters(parlocal);
|
|
208
|
+
midimix.setParameters(parlocal);
|
|
209
|
+
updateSimulatorParameters(parlocal);
|
|
210
|
+
|
|
211
|
+
// Il faut remettre à jour les paramètre de
|
|
212
|
+
// la variable global de websocketServer
|
|
213
|
+
par = parlocal;
|
|
214
|
+
if (debug1) console.log("INFO: websocketServer: reloadParameters:tempo Max",par.tempoMax);
|
|
215
|
+
initMidiPort();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Simple conversion from Array to csv
|
|
220
|
+
* @param {Array} arr
|
|
221
|
+
* @param {String} delimiter
|
|
222
|
+
* @returns {String} csv
|
|
223
|
+
*/
|
|
224
|
+
const arrayToCSV = (arr, delimiter = ',') =>
|
|
225
|
+
arr.map(v => v.join(delimiter)
|
|
226
|
+
).join('\n');
|
|
227
|
+
|
|
228
|
+
// INITIALISATION DES DONNEES D'INTERACTION DU SEQUENCEUR
|
|
229
|
+
const tripleCrocheTR = 2;
|
|
230
|
+
const tripleCrocheR = 3;
|
|
231
|
+
const doubleCrocheTR = 4;
|
|
232
|
+
const doubleCrocheR = 6;
|
|
233
|
+
const crocheTR = 8;
|
|
234
|
+
const crocheR = 12;
|
|
235
|
+
const noireTR = 16;
|
|
236
|
+
const noireR = 24;
|
|
237
|
+
const blancheTR = 32;
|
|
238
|
+
const blancheR = 48;
|
|
239
|
+
const rondeTR = 64;
|
|
240
|
+
const rondeR = 96;
|
|
241
|
+
|
|
242
|
+
let tempsMesure = 4; // Partie haute de la mesure, nombre de temps dans la mesure
|
|
243
|
+
let divisionMesure = noireR; // Partie basse de la mesure
|
|
244
|
+
let nbeDeMesures = 1;
|
|
245
|
+
let tempo = 60; // à la minute
|
|
246
|
+
let canalMidi = 1;
|
|
247
|
+
let dureeDuTick = ((60 / tempo) / divisionMesure) * 1000; // Exprimé ici en millisecondes
|
|
248
|
+
|
|
249
|
+
let previousTime = 0;
|
|
250
|
+
let currentTime = 0;
|
|
251
|
+
let timeToPlay = 0;
|
|
252
|
+
let previousTimeToPlay = 0;
|
|
253
|
+
let defautDeLatence;
|
|
254
|
+
|
|
255
|
+
const debug = false;
|
|
256
|
+
const debug1 = true;
|
|
257
|
+
const warnings = false;
|
|
258
|
+
let timerSynchro;
|
|
259
|
+
|
|
260
|
+
// Automate des possibles
|
|
261
|
+
let DAWStatus = 0; // 0 inactif, sinon actif (originellement pour distinguer des orchestrations, distinction pas utile à présent)
|
|
262
|
+
let setTimer;
|
|
263
|
+
let timerDivision = 1; // Default value for the number of pulses for a tick, can evolve during an orchestration
|
|
264
|
+
let offsetDivision = 0;
|
|
265
|
+
let compteurDivisionMesure = 0;
|
|
266
|
+
let nbeDeGroupesSons = 0;
|
|
267
|
+
let socketControleur;
|
|
268
|
+
let groupeName = "";
|
|
269
|
+
let automatePossibleMachine;
|
|
270
|
+
|
|
271
|
+
// Scoring pour les jeux
|
|
272
|
+
let computeScorePolicy = 0;
|
|
273
|
+
let computeScoreClass = 0;
|
|
274
|
+
|
|
275
|
+
// CONTROLEUR
|
|
276
|
+
let DAWTableReady = false; // Pour pouvoir vérifier que la pièce a bien été chargée.
|
|
277
|
+
|
|
278
|
+
let clientsEnCours = [];
|
|
279
|
+
let groupeEncours = 0;
|
|
280
|
+
|
|
281
|
+
let currentTimePrevMidi = 0;
|
|
282
|
+
let currentTimeMidi = 0;
|
|
283
|
+
|
|
284
|
+
/*************************************************
|
|
285
|
+
INITIALISATION DU PORT MIDI OUT (si paramétré)
|
|
286
|
+
**************************************************/
|
|
287
|
+
/**
|
|
288
|
+
* Init MIDI OUT port if defined in the parameters
|
|
289
|
+
*/
|
|
290
|
+
function initMidiPort() {
|
|
291
|
+
|
|
292
|
+
// Check the midi config before doing something
|
|
293
|
+
if (midiConfig[0] === undefined) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (par !== undefined) {
|
|
298
|
+
let directMidi = false;
|
|
299
|
+
if (par.directMidiON !== undefined) {
|
|
300
|
+
directMidi = par.directMidiON;
|
|
301
|
+
}
|
|
302
|
+
if (directMidi) {
|
|
303
|
+
oscMidiLocal.initMidiOUT();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/************************************************
|
|
309
|
+
WEBSOCKET
|
|
310
|
+
**************************************************/
|
|
311
|
+
/**
|
|
312
|
+
* Main function to manage the websocket
|
|
313
|
+
*/
|
|
314
|
+
function startWebSocketServer() {
|
|
315
|
+
/** @namespace Websocketserver */
|
|
316
|
+
const WebSocketServer = require('ws');
|
|
317
|
+
const serv = new WebSocketServer.Server({ port: ipConfig.websocketServeurPort });
|
|
318
|
+
|
|
319
|
+
/*************************************************************************************
|
|
320
|
+
Worker for synchro if no DAW (ne fonctionne pas dans VSC mais dans le terminal)
|
|
321
|
+
**************************************************************************************/
|
|
322
|
+
var workerSync;
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Function to start a worker for the synchro when not using a midi sync coming from a DAW
|
|
326
|
+
* @function
|
|
327
|
+
* @memberof Websocketserver
|
|
328
|
+
* @param {string} filepath path
|
|
329
|
+
* @param {number} timer
|
|
330
|
+
* @inner
|
|
331
|
+
*/
|
|
332
|
+
function workerSynchroInit(filepath, timer) {
|
|
333
|
+
if (workerSync !== undefined) {
|
|
334
|
+
workerSync.postMessage(['startSynchro', timer]);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return new Promise((resolve, reject) => {
|
|
339
|
+
workerSync = new Worker(filepath);
|
|
340
|
+
if (debug) console.log('Launching worker Synchro', filepath);
|
|
341
|
+
|
|
342
|
+
workerSync.on('online', () => {
|
|
343
|
+
workerSync.postMessage(['startSynchro', timer]);
|
|
344
|
+
if (debug) console.log('Launching worker Synchro');
|
|
345
|
+
})
|
|
346
|
+
workerSync.on('message', messageFromWorker => {
|
|
347
|
+
switch (messageFromWorker) {
|
|
348
|
+
case "synchroWorker":
|
|
349
|
+
receivedTickFromSynchro();
|
|
350
|
+
break;
|
|
351
|
+
|
|
352
|
+
default:
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
return resolve;
|
|
356
|
+
});
|
|
357
|
+
workerSync.on('error', reject);
|
|
358
|
+
workerSync.on('exit', code => {
|
|
359
|
+
if (code !== 0) {
|
|
360
|
+
reject(new Error(`Worker stopped with exit code:` + code));
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/*************************************************************************************
|
|
367
|
+
Worker for the Interface Z management
|
|
368
|
+
**************************************************************************************/
|
|
369
|
+
var workerInterfaceZ;
|
|
370
|
+
var workerInterfaceZRunning = false;
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Function to start a worker for the Interface Z management
|
|
374
|
+
* @function
|
|
375
|
+
* @memberof Websocketserver
|
|
376
|
+
* @param {string} filepath worker path
|
|
377
|
+
* @inner
|
|
378
|
+
*/
|
|
379
|
+
function workerInterfaceZInit(filepath,
|
|
380
|
+
serverAddress,
|
|
381
|
+
interfaceZIPaddress,
|
|
382
|
+
portOSCFromInterfaceZData,
|
|
383
|
+
portOSCFromInterfaceZMidi,
|
|
384
|
+
portOSCFromInterfaceZMiniWi,
|
|
385
|
+
portOSCToInterfaceZ,
|
|
386
|
+
tempoSensorsInit,
|
|
387
|
+
sensorsSensibilities) {
|
|
388
|
+
|
|
389
|
+
if (workerInterfaceZRunning) {
|
|
390
|
+
if (debug1) console.log("INFO: workerInterfaceZRunning");
|
|
391
|
+
if (workerInterfaceZ !== undefined) {
|
|
392
|
+
workerInterfaceZ.postMessage(['startInterfaceZ',
|
|
393
|
+
serverAddress,
|
|
394
|
+
interfaceZIPaddress,
|
|
395
|
+
portOSCFromInterfaceZData,
|
|
396
|
+
portOSCFromInterfaceZMidi,
|
|
397
|
+
portOSCFromInterfaceZMiniWi,
|
|
398
|
+
portOSCToInterfaceZ,
|
|
399
|
+
tempoSensorsInit,
|
|
400
|
+
sensorsSensibilities]);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
workerInterfaceZRunning = true;
|
|
405
|
+
|
|
406
|
+
if (
|
|
407
|
+
interfaceZIPaddress === undefined ||
|
|
408
|
+
portOSCFromInterfaceZData === undefined ||
|
|
409
|
+
portOSCFromInterfaceZMiniWi === undefined ||
|
|
410
|
+
tempoSensorsInit === undefined ||
|
|
411
|
+
sensorsSensibilities === undefined) {
|
|
412
|
+
console.log("WARN: You try to use the Interface Z sensors but do not configure ipConfig");
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return new Promise((resolve, reject) => {
|
|
417
|
+
workerInterfaceZ = new Worker(filepath);
|
|
418
|
+
if (debug) console.log('Launching worker InterfaceZ', filepath);
|
|
419
|
+
|
|
420
|
+
workerInterfaceZ.on('online', () => {
|
|
421
|
+
workerInterfaceZ.postMessage(['startInterfaceZ',
|
|
422
|
+
serverAddress,
|
|
423
|
+
interfaceZIPaddress,
|
|
424
|
+
portOSCFromInterfaceZData,
|
|
425
|
+
portOSCFromInterfaceZMidi,
|
|
426
|
+
portOSCFromInterfaceZMiniWi,
|
|
427
|
+
portOSCToInterfaceZ,
|
|
428
|
+
tempoSensorsInit,
|
|
429
|
+
sensorsSensibilities]);
|
|
430
|
+
if (debug) console.log('Launching worker InterfaceZ');
|
|
431
|
+
})
|
|
432
|
+
workerInterfaceZ.on('message', messageFromWorker => {
|
|
433
|
+
if (debug) console.log("Websoclketserver: messageFromWorker: ", messageFromWorker);
|
|
434
|
+
|
|
435
|
+
switch (messageFromWorker.type) {
|
|
436
|
+
case "INTERFACEZ_RC":
|
|
437
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
438
|
+
inputAutomatePossible({ INTERFACEZ_RC: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
439
|
+
break;
|
|
440
|
+
|
|
441
|
+
case "INTERFACEZ_RC0":
|
|
442
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
443
|
+
reactAutomatePossible({ INTERFACEZ_RC0: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
444
|
+
break;
|
|
445
|
+
case "INTERFACEZ_RC1":
|
|
446
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
447
|
+
reactAutomatePossible({ INTERFACEZ_RC1: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
448
|
+
break;
|
|
449
|
+
case "INTERFACEZ_RC2":
|
|
450
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
451
|
+
reactAutomatePossible({ INTERFACEZ_RC2: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
452
|
+
break;
|
|
453
|
+
case "INTERFACEZ_RC3":
|
|
454
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
455
|
+
reactAutomatePossible({ INTERFACEZ_RC3: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
456
|
+
break;
|
|
457
|
+
case "INTERFACEZ_RC4":
|
|
458
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
459
|
+
reactAutomatePossible({ INTERFACEZ_RC4: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
460
|
+
break;
|
|
461
|
+
case "INTERFACEZ_RC5":
|
|
462
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
463
|
+
reactAutomatePossible({ INTERFACEZ_RC5: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
464
|
+
break;
|
|
465
|
+
case "INTERFACEZ_RC6":
|
|
466
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
467
|
+
reactAutomatePossible({ INTERFACEZ_RC6: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
468
|
+
break;
|
|
469
|
+
case "INTERFACEZ_RC7":
|
|
470
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
471
|
+
reactAutomatePossible({ INTERFACEZ_RC7: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
472
|
+
break;
|
|
473
|
+
case "INTERFACEZ_RC8":
|
|
474
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
475
|
+
reactAutomatePossible({ INTERFACEZ_RC8: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
476
|
+
break;
|
|
477
|
+
case "INTERFACEZ_RC9":
|
|
478
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
479
|
+
reactAutomatePossible({ INTERFACEZ_RC9: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
480
|
+
break;
|
|
481
|
+
case "INTERFACEZ_RC10":
|
|
482
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
483
|
+
reactAutomatePossible({ INTERFACEZ_RC10: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
484
|
+
break;
|
|
485
|
+
case "INTERFACEZ_RC11":
|
|
486
|
+
if (debug) console.log("websocketServer:message from worker:", messageFromWorker);
|
|
487
|
+
reactAutomatePossible({ INTERFACEZ_RC11: [messageFromWorker.sensor, messageFromWorker.value] });
|
|
488
|
+
break;
|
|
489
|
+
|
|
490
|
+
default:
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
return resolve;
|
|
494
|
+
});
|
|
495
|
+
workerInterfaceZ.on('error', reject);
|
|
496
|
+
workerInterfaceZ.on('exit', code => {
|
|
497
|
+
if (code !== 0) {
|
|
498
|
+
reject(new Error(`Worker InterfaceZ stopped with exit code:` + code));
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Define the function in order to Broadcast to all clients.
|
|
506
|
+
* @function
|
|
507
|
+
* @memberof Websocketserver
|
|
508
|
+
* @param {string} data message
|
|
509
|
+
* @inner
|
|
510
|
+
*/
|
|
511
|
+
serv.broadcast = function broadcast(data) {
|
|
512
|
+
//if(debug) console.log("Web Socket Server: broadcast: ", data);
|
|
513
|
+
serv.clients.forEach(function each(client) {
|
|
514
|
+
if (client.readyState === WebSocketServer.OPEN) {
|
|
515
|
+
try {
|
|
516
|
+
client.send(data);
|
|
517
|
+
} catch (err) {
|
|
518
|
+
console.log("ERR: websocketserver.js: broadcast", err);
|
|
519
|
+
throw err;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Pour les broadcasts depuis controle DAW, c'est la structure dans HOP que je garde.
|
|
526
|
+
DAW.initBroadCastServer(serv);
|
|
527
|
+
groupesClientSon.initBroadCastServer(serv);
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* In order to get the server used for broadcasting
|
|
531
|
+
* @returns {serv} - return the server for Broadcasting
|
|
532
|
+
* @function
|
|
533
|
+
* @memberof Websocketserver
|
|
534
|
+
* @inner
|
|
535
|
+
*/
|
|
536
|
+
function getBroadCastServer() {
|
|
537
|
+
if (serv === undefined) {
|
|
538
|
+
console.log("ERR: websocketServer: getBroadCastServer: serv undefined");
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
return serv;
|
|
542
|
+
}
|
|
543
|
+
_getBroadCastServer = getBroadCastServer;
|
|
544
|
+
|
|
545
|
+
/************************************************************************************
|
|
546
|
+
Fonction pour emission de signaux depuis Ableton vers l'automatePossibleMachine.
|
|
547
|
+
*************************************************************************************/
|
|
548
|
+
/**
|
|
549
|
+
* Send a signal to the orchestration according to the skini note
|
|
550
|
+
* @function
|
|
551
|
+
* @memberof Websocketserver
|
|
552
|
+
* @param {number} noteSkini
|
|
553
|
+
* @inner
|
|
554
|
+
*/
|
|
555
|
+
function sendSignalFromDAW(noteSkini) {
|
|
556
|
+
if (debug) console.log("websocketserver.js: sendSignalFromDAW:", noteSkini);
|
|
557
|
+
var patternName = DAW.getPatternNameFromNote(noteSkini);
|
|
558
|
+
if (debug) console.log("INFO: websocketserver.js: sendSignalFromDAW:", noteSkini, patternName);
|
|
559
|
+
if (patternName !== undefined) {
|
|
560
|
+
reactAutomatePossible({ patternSignal: [noteSkini, patternName] });
|
|
561
|
+
} else {
|
|
562
|
+
if (warnings) console.log("WARN: webSocketServeur: sendSignalFromDAW:", noteSkini, patternName);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
_sendSignalFromDAW = sendSignalFromDAW;
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Send a signal "midiSignal" to the orchestration
|
|
569
|
+
* tanks to a skini note.
|
|
570
|
+
* @function
|
|
571
|
+
* @memberof Websocketserver
|
|
572
|
+
* @inner
|
|
573
|
+
* @param {number} noteSkini
|
|
574
|
+
*/
|
|
575
|
+
function sendSignalFromMIDI(noteSkini) {
|
|
576
|
+
if (debug1) console.log("webSocketServeur: sendSignalFromMIDI:", noteSkini);
|
|
577
|
+
if (!reactAutomatePossible({ midiSignal: [noteSkini] })) {
|
|
578
|
+
console.log("WARN: webSocketServeur: sendSignalFromMIDI:", noteSkini);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
_sendSignalFromMIDI = sendSignalFromMIDI;
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Send a signal "halt" to the orchestration.
|
|
585
|
+
* @memberof Websocketserver
|
|
586
|
+
* @function
|
|
587
|
+
* @inner
|
|
588
|
+
*/
|
|
589
|
+
function sendSignalStopFromMIDI() {
|
|
590
|
+
if (!reactAutomatePossible({ halt: undefined })) {
|
|
591
|
+
if (warnings) console.log("WARN: webSocketServeur: sendSignalStopFromMIDI");
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
_sendSignalStopFromMIDI = sendSignalStopFromMIDI;
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Send a signal "start" to the orchestration.
|
|
598
|
+
* @memberof Websocketserver
|
|
599
|
+
* @function
|
|
600
|
+
* @inner
|
|
601
|
+
*/
|
|
602
|
+
function sendSignalStartFromMIDI() {
|
|
603
|
+
if (!reactAutomatePossible({ start: undefined })) {
|
|
604
|
+
if (warnings) console.log("WARN: webSocketServeur: sendSignalStartFromMIDI");
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
_sendSignalStartFromMIDI = sendSignalStartFromMIDI;
|
|
608
|
+
|
|
609
|
+
/************************************************************************************
|
|
610
|
+
Fonction pour émission de signaux depuis midimix.js vers l'automatePossibleMachine.
|
|
611
|
+
Utilisable pour synchro vidéo ou jeu via des notes Midi
|
|
612
|
+
*************************************************************************************/
|
|
613
|
+
/**
|
|
614
|
+
* Send a signal "controlFromVideo" to the orchestration
|
|
615
|
+
* tanks to a skini note.
|
|
616
|
+
* @memberof Websocketserver
|
|
617
|
+
* @function
|
|
618
|
+
* @inner
|
|
619
|
+
* @param {number} noteSkini
|
|
620
|
+
*/
|
|
621
|
+
function sendSignalFromMidiMix(noteSkini) {
|
|
622
|
+
reactAutomatePossible({ controlFromVideo: [noteSkini] });
|
|
623
|
+
}
|
|
624
|
+
_sendSignalFromMidiMix = sendSignalFromMidiMix;
|
|
625
|
+
|
|
626
|
+
/*************************************************************************************
|
|
627
|
+
RECEPTION DES TICK MIDI OU BITWIG
|
|
628
|
+
**************************************************************************************/
|
|
629
|
+
var previousTimeClockMidi = 0;
|
|
630
|
+
var currentTimeClockMidi = 0;
|
|
631
|
+
var tempoTime = 0;
|
|
632
|
+
|
|
633
|
+
// Vient de midiMix.js et directement de Bitwig ou de processing
|
|
634
|
+
/**
|
|
635
|
+
* Called by midimix.js, for OSC, MIDI, and Link messages.
|
|
636
|
+
* @memberof Websocketserver
|
|
637
|
+
* @function
|
|
638
|
+
* @inner
|
|
639
|
+
*/
|
|
640
|
+
function sendOSCTick() {
|
|
641
|
+
if (debug1) {
|
|
642
|
+
//console.log("websocketserver: sendOSCTick");
|
|
643
|
+
serv.broadcast(JSON.stringify({
|
|
644
|
+
type: "synchroSkini",
|
|
645
|
+
text: ""
|
|
646
|
+
}));
|
|
647
|
+
}
|
|
648
|
+
receivedTickFromSynchro();
|
|
649
|
+
}
|
|
650
|
+
_sendOSCTick = sendOSCTick;
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Called on synchro messages received each quarter note
|
|
654
|
+
* emitted by the DAW using MIDI or OSC, or the synchro worker.
|
|
655
|
+
* No parameters the variables are global to the whole module.
|
|
656
|
+
* @memberof Websocketserver
|
|
657
|
+
* @function
|
|
658
|
+
* @inner
|
|
659
|
+
*/
|
|
660
|
+
function receivedTickFromSynchro() {
|
|
661
|
+
if (debug) console.log("websocketserver : receivedTickFromSynchro: tick received");
|
|
662
|
+
currentTimeClockMidi = Date.now();
|
|
663
|
+
tempoTime = currentTimeClockMidi - previousTimeClockMidi; // Real duration of a quarter note
|
|
664
|
+
if (debug) console.log("websocketserver:dureeDuTickHorlogeMidi:tempoTime=", tempoTime,
|
|
665
|
+
compteurDivisionMesure,
|
|
666
|
+
groupesClientSon.getTimerDivision());
|
|
667
|
+
previousTimeClockMidi = currentTimeClockMidi;
|
|
668
|
+
|
|
669
|
+
if (par.pulsationON) {
|
|
670
|
+
reactAutomatePossible({ pulsation: undefined });
|
|
671
|
+
}
|
|
672
|
+
// La remise à jour de la durée des ticks est possible depuis les automates.
|
|
673
|
+
// Si les automates ne mettent pas timerDivision à jour, on garde la valeur par défaut
|
|
674
|
+
// donnée dans le fichier de config de la pièce. (compatibilté ascendante)
|
|
675
|
+
var timerLocal = groupesClientSon.getTimerDivision();
|
|
676
|
+
if (debug) console.log("websocketserver: receivedTickFromSynchro: timerLocal:", timerLocal);
|
|
677
|
+
|
|
678
|
+
if (timerLocal !== undefined) {
|
|
679
|
+
timerDivision = timerLocal;
|
|
680
|
+
} else {
|
|
681
|
+
//console.log("WARN: websocketServer: receivedTickFromSynchro: timerDivision undefined");
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
if (debug) console.log("websocketserver: receivedTickFromSynchro: timerDivision:", timerDivision);
|
|
685
|
+
|
|
686
|
+
//offsetDivision = timerDivision/2;
|
|
687
|
+
// actionOnTick() is called based on the tick not the pulse issued from the synchro.
|
|
688
|
+
if (compteurDivisionMesure === 0) { // offsetDivision
|
|
689
|
+
actionOnTick(timerDivision);
|
|
690
|
+
}
|
|
691
|
+
// Ceci est la définition du tick de l'orchestration
|
|
692
|
+
// Il s'agit d'une conversion de la pulsation MIDI ou worker en "tick".
|
|
693
|
+
compteurDivisionMesure = (compteurDivisionMesure + 1) % timerDivision;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/*************************************************************************************
|
|
697
|
+
MATRICE DES POSSIBLES, AUTOMATE
|
|
698
|
+
**************************************************************************************/
|
|
699
|
+
/**
|
|
700
|
+
* Get the HipHop machine.
|
|
701
|
+
* @memberof Websocketserver
|
|
702
|
+
* @function
|
|
703
|
+
* @inner
|
|
704
|
+
* @returns {automatePossibleMachine} - the HipHop machine
|
|
705
|
+
*/
|
|
706
|
+
function getAutomatePossible() {
|
|
707
|
+
if (automatePossibleMachine !== undefined) {
|
|
708
|
+
return automatePossibleMachine;
|
|
709
|
+
} else {
|
|
710
|
+
console.log("ERR: websocketserverSini.js: getAutomatePossible: automatePossibleMachine undefined")
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
_getAutomatePossible = getAutomatePossible;
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* React on the orchestration
|
|
717
|
+
* @memberof Websocketserver
|
|
718
|
+
* @param {*} signal
|
|
719
|
+
* @returns {boolean} true if no problem
|
|
720
|
+
*/
|
|
721
|
+
function reactAutomatePossible(signal) {
|
|
722
|
+
|
|
723
|
+
if (debug) console.log("reactAutomatePossible 1:", signal, automatePossibleMachine);
|
|
724
|
+
if (debug) console.log("reactAutomatePossible 1:", signal);
|
|
725
|
+
|
|
726
|
+
if (automatePossibleMachine !== undefined) {
|
|
727
|
+
try {
|
|
728
|
+
if (debug) console.log("INFO: webSocketServer.js: reactAutomatePossible 2:", signal);
|
|
729
|
+
automatePossibleMachine.react(signal);
|
|
730
|
+
} catch (err) {
|
|
731
|
+
console.log("ERROR: webSocketServer.js: reactAutomatePossible: Error on react for signal:", signal, err.toString());
|
|
732
|
+
var msg = {
|
|
733
|
+
type: "alertBlocklySkini",
|
|
734
|
+
text: err.toString()
|
|
735
|
+
}
|
|
736
|
+
//throw err;
|
|
737
|
+
serv.broadcast(JSON.stringify(msg));
|
|
738
|
+
return false;
|
|
739
|
+
}
|
|
740
|
+
return true;
|
|
741
|
+
} else {
|
|
742
|
+
if (warnings) console.log("WARN: websocketserver: reactAutomatePossible: automate undefined");
|
|
743
|
+
return false;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
function inputAutomatePossible(signal) {
|
|
748
|
+
if (automatePossibleMachine !== undefined) {
|
|
749
|
+
try {
|
|
750
|
+
if (debug) console.log("INFO: webSocketServer.js: inputAutomatePossible:", signal);
|
|
751
|
+
automatePossibleMachine.input(signal);
|
|
752
|
+
} catch (err) {
|
|
753
|
+
console.log("ERROR: webSocketServer.js: inputAutomatePossible: Error on react:", signal, err.toString());
|
|
754
|
+
serv.broadcast(JSON.stringify({
|
|
755
|
+
type: "alertBlocklySkini",
|
|
756
|
+
text: err.toString()
|
|
757
|
+
}));
|
|
758
|
+
return false;
|
|
759
|
+
}
|
|
760
|
+
return true;
|
|
761
|
+
} else {
|
|
762
|
+
if (warnings) console.log("WARN: websocketserver: inputAutomatePossible: automate undefined");
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// Pas au bon endroit, musicien pas en place dans cette version
|
|
768
|
+
//if (par.avecMusicien !== undefined && par.decalageFIFOavecMusicien !== undefined) {p.
|
|
769
|
+
//DAW.setAvecMusicien(par.avecMusicien, par.decalageFIFOavecMusicien);
|
|
770
|
+
//}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Initialisation if the "matrice des possibles" which is a two dimensional array for
|
|
774
|
+
* the groups of pattern according to the groups of users. It represents the status
|
|
775
|
+
* of the orchestration.
|
|
776
|
+
* @memberof Websocketserver
|
|
777
|
+
* @param {number} DAWState Informs if an orchestration has been selected or not
|
|
778
|
+
*/
|
|
779
|
+
function initMatriceDesPossibles(DAWState) {
|
|
780
|
+
|
|
781
|
+
if (warnings) console.log("WARNING: websocketserver:initMatriceDesPossibles:DAWState:", DAWState);
|
|
782
|
+
|
|
783
|
+
if (DAWState == 0) {
|
|
784
|
+
if (warnings) console.log("WARNING: websocketserver:initMatriceDesPossibles:DAWState à 0");
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
nbeDeGroupesSons = DAW.getNbeDeGroupesSons();
|
|
788
|
+
if(debug1) if (!Number.isInteger(nbeDeGroupesSons) || nbeDeGroupesSons <= 0 )
|
|
789
|
+
{
|
|
790
|
+
console.log("websocketServer:initMatriceDesPossibles:pb nbeDeGroupesons", nbeDeGroupesSons );
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
groupesClientSon.setNbeDeGroupesSons(nbeDeGroupesSons);
|
|
795
|
+
if (groupesClientSon.setGroupesSon(DAWState) == -1) {
|
|
796
|
+
if (warnings) console.log("WARNING: websocketserveur:initMatriceDesPossibles: setGroupesSon: vide");
|
|
797
|
+
}
|
|
798
|
+
groupesClientSon.createMatriceDesPossibles();
|
|
799
|
+
|
|
800
|
+
let mesReponse = {
|
|
801
|
+
type: "setControlerPadSize",
|
|
802
|
+
nbeDeGroupesClients: par.nbeDeGroupesClients,
|
|
803
|
+
nbeDeGroupesSons: nbeDeGroupesSons
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (socketControleur !== undefined) {
|
|
807
|
+
if (socketControleur.readyState == 1) {
|
|
808
|
+
socketControleur.send(JSON.stringify(mesReponse));
|
|
809
|
+
} else {
|
|
810
|
+
if (debug) console.log("WARN: websocketserveur:initMatriceDesPossibles: socketControler status:", socketControleur.readyState);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Action called every quarter note of the MIDI synchro or worker synchro if no MIDI sync.
|
|
817
|
+
* @memberof Websocketserver
|
|
818
|
+
* @param {number} timerDivision
|
|
819
|
+
* @returns {boolean} true if the reaction of the orchestration is ok
|
|
820
|
+
*/
|
|
821
|
+
function actionOnTick(timerDivision) {
|
|
822
|
+
if (debug) {
|
|
823
|
+
currentTimePrevMidi = currentTimeMidi;
|
|
824
|
+
currentTimeMidi = Date.now();
|
|
825
|
+
console.log("webSocketServeur:actionOnTick:diff de temps:", currentTimeMidi - currentTimePrevMidi, ":", timerDivision);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if (!reactAutomatePossible({ tick: undefined })) {
|
|
829
|
+
if (warnings) console.log("WARN: websocketserver: actionOnTick: automate not ready");
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
if (timerDivision == undefined) console.log("WARN:websocketServer:actionOnTick:timerDivision undefined")
|
|
834
|
+
|
|
835
|
+
DAW.playAndShiftEventDAW(timerDivision);
|
|
836
|
+
DAW.displayQueues();
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Fix the timer when using the synchro from Node.js
|
|
842
|
+
* not used when the worker runs.
|
|
843
|
+
* @memberof Websocketserver
|
|
844
|
+
* @function
|
|
845
|
+
* @inner
|
|
846
|
+
* @param {number} timer in ms
|
|
847
|
+
*/
|
|
848
|
+
function setMonTimer(timer) {
|
|
849
|
+
if (!par.synchoOnMidiClock) {
|
|
850
|
+
setTimer = setInterval(function () {
|
|
851
|
+
if (debug1) { let v0 = Date.now(); }
|
|
852
|
+
actionOnTick(timerDivision);
|
|
853
|
+
if (debug1) {
|
|
854
|
+
console.log("websocketserver: setMonTimer timer:", timer, "ms,Temps de réaction de l'automate:", Date.now() - v0, "ms");
|
|
855
|
+
}
|
|
856
|
+
}, timer);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* To update the variable on the list lengths of memorySortable
|
|
862
|
+
* Clients need this variable when connecting. It can change during an orchestration.
|
|
863
|
+
* @memberof Websocketserver
|
|
864
|
+
* @function
|
|
865
|
+
* @inner
|
|
866
|
+
* @param {number} value length of the list of the client
|
|
867
|
+
*/
|
|
868
|
+
function setPatternListLength(value) {
|
|
869
|
+
if (debug1) console.log("websocketserver.js : setPatternListLength : value :", value);
|
|
870
|
+
}
|
|
871
|
+
_setPatternListLength = setPatternListLength;
|
|
872
|
+
|
|
873
|
+
/*************************************************************************************
|
|
874
|
+
WEB SOCKET MANAGEMENT
|
|
875
|
+
**************************************************************************************/
|
|
876
|
+
serv.on('connection', function (ws) {
|
|
877
|
+
|
|
878
|
+
let messageLog = {
|
|
879
|
+
date: "",
|
|
880
|
+
source: "websocketServerSkini.js",
|
|
881
|
+
type: "log",
|
|
882
|
+
note: "",
|
|
883
|
+
pseudo: "",
|
|
884
|
+
id: ""
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// Pour informer que l'on est bien connecté
|
|
888
|
+
if (debug) console.log("INFO: Web Socket Server: a connection established");
|
|
889
|
+
ws.send(JSON.stringify({
|
|
890
|
+
type: "message",
|
|
891
|
+
value: "Bienvenue chez Skini !"
|
|
892
|
+
}));
|
|
893
|
+
|
|
894
|
+
/* // Pour dire à l'ouverture au client si on est ou pas dans une scène où DAW est actif.
|
|
895
|
+
if (debug) console.log("Web Socket Server: DAWON:", par.DAWON);
|
|
896
|
+
var msg = {
|
|
897
|
+
msg.type: "DAWON",
|
|
898
|
+
msg.value: DAWON
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
msg.type = "DAWON";
|
|
902
|
+
msg.value = par.DAWON; // variable true, false, ou un chiffre
|
|
903
|
+
ws.send(JSON.stringify(msg));*/
|
|
904
|
+
|
|
905
|
+
// DONNEES DE TEMPO pour les séquenceurs.
|
|
906
|
+
ws.send(JSON.stringify({
|
|
907
|
+
type: "setConfigSequenceur",
|
|
908
|
+
tempsMesure: tempsMesure,
|
|
909
|
+
divisionMesure: divisionMesure,
|
|
910
|
+
nbeDeMesures: nbeDeMesures,
|
|
911
|
+
tempo: tempo,
|
|
912
|
+
canalMidi: canalMidi,
|
|
913
|
+
dureeDuTick: dureeDuTick
|
|
914
|
+
}));
|
|
915
|
+
ws.on('close', function () {
|
|
916
|
+
if (debug) console.log("Web Socket Server: Socket closed by client.");
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
ws.on('error', function (event) {
|
|
920
|
+
console.log("Web Socket Server: Erreur sur socket:", ws.socket, " ", event);
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* This is where the pattern (clip) descriptor becomes an element in a FIFO.
|
|
925
|
+
* @memberof Websocketserver
|
|
926
|
+
* @function
|
|
927
|
+
* @inner
|
|
928
|
+
* @param {array} clip pattern description according to the csv file.
|
|
929
|
+
* @param {string} signal Hiphop signal
|
|
930
|
+
* @param {number} leGroupe user group (web client group)
|
|
931
|
+
* @param {string} pseudo
|
|
932
|
+
* @param {number} monId
|
|
933
|
+
* @returns {number} waiting time
|
|
934
|
+
*/
|
|
935
|
+
function pushClipDAW(clip, signal, leGroupe, pseudo, monId) {
|
|
936
|
+
let DAWNote = clip[0];
|
|
937
|
+
let DAWChannel = Math.floor(DAWNote / 127) + 1;
|
|
938
|
+
DAWNote = DAWNote % 127;
|
|
939
|
+
if (DAWChannel > 15) {
|
|
940
|
+
if (debug) console.log("Web Socket Server.js : pushNoteOnDAW: Nombre de canaux midi dépassé.");
|
|
941
|
+
return 0;
|
|
942
|
+
}
|
|
943
|
+
let nom = clip[3];
|
|
944
|
+
let DAWInstrument = clip[5];
|
|
945
|
+
let typePattern = clip[7];
|
|
946
|
+
let dureeClip = clip[10];
|
|
947
|
+
let adresseIP = clip[11];
|
|
948
|
+
let numeroBuffer = clip[12];
|
|
949
|
+
let patternLevel = clip[13];
|
|
950
|
+
let typeVertPattern = clip[8];
|
|
951
|
+
|
|
952
|
+
let signalComplet = { [signal]: clip[3] }; // on ajouté le nom du pattern au signal
|
|
953
|
+
let dureeAttente = DAW.pushEventDAW(par.busMidiDAW, DAWChannel,
|
|
954
|
+
DAWInstrument, DAWNote, 125, monId, pseudo, dureeClip, nom,
|
|
955
|
+
signalComplet, typePattern, adresseIP,
|
|
956
|
+
numeroBuffer, patternLevel, typeVertPattern);
|
|
957
|
+
|
|
958
|
+
// Envoi du signal vers l'automate au moment de la demande si reactOnPlay n'existe pas ou est false.
|
|
959
|
+
// Il y a un autre scénario dans controleAbleton.js où on envoie le signal au moment ou la commande Midi part
|
|
960
|
+
// Ce sont deux scénarios différents, celui fonctionne mieux en termes de synchro Midi car les demandes sont réparties dans
|
|
961
|
+
// le temps au fur et à mesure qu'elles arrivent. Il n'y a pas de risque de react successifs au même moment du tick midi.
|
|
962
|
+
// Il traite les activations avant que les patterns aient été jouées.
|
|
963
|
+
if (par.reactOnPlay === undefined) {
|
|
964
|
+
reactAutomatePossible(signalComplet);
|
|
965
|
+
} else if (!par.reactOnPlay) {
|
|
966
|
+
if (debug) console.log("websocketServeur: pushClipDAW: reactOnPlay:", par.reactOnPlay, signalComplet);
|
|
967
|
+
reactAutomatePossible(signalComplet);
|
|
968
|
+
}
|
|
969
|
+
if (debug) console.log("Web Socket Server.js : pushClipDAW :nom ", nom, " pseudo: ", pseudo);
|
|
970
|
+
|
|
971
|
+
if (debug) console.log("Web Socket Server.js: pushClipDAW: DAWInstrument", DAWInstrument, " durée: ", dureeAttente);
|
|
972
|
+
|
|
973
|
+
return dureeAttente;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* HipHop reaction on the orchestration and compute delay.
|
|
978
|
+
* @memberof Websocketserver
|
|
979
|
+
* @function
|
|
980
|
+
* @inner
|
|
981
|
+
* @param {string} unPseudo
|
|
982
|
+
* @param {number} groupe
|
|
983
|
+
* @param {array} pattern
|
|
984
|
+
* @param {number} monId
|
|
985
|
+
*/
|
|
986
|
+
function playPattern(unPseudo, groupe, pattern, monId) {
|
|
987
|
+
|
|
988
|
+
if (pattern === undefined) return; // Protection si pas de selection sur le client
|
|
989
|
+
if (debug) console.log("Web Socket Serveur: playPattern: clipChoisi", pattern, " pour ID: ", monId);
|
|
990
|
+
if (debug) console.log('Websocket serveur : playPattern: demandeDeSonParPseudo : ', unPseudo, "groupe:", groupe, "pattern:", pattern[4]);
|
|
991
|
+
if (debug) console.log("-----webSocketServeur: playPattern: Pattern reçu:", pattern[0]);
|
|
992
|
+
|
|
993
|
+
let signal = groupesClientSon.getSignalFromGroup(pattern[9]) + "IN";
|
|
994
|
+
|
|
995
|
+
if (signal === "-1IN") {
|
|
996
|
+
console.log("WARN: websocketserveur: playPattern : no group declared :", groupe);
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
if (debug) console.log("webSocketServeur: playPattern, signal reçu:", pattern, signal);
|
|
1000
|
+
|
|
1001
|
+
let legroupe = groupe; // groupe d'utilisateur
|
|
1002
|
+
|
|
1003
|
+
// Pour la gestion des messages qui ne sont pas des patterns, on utilise des patterns dont les
|
|
1004
|
+
// commandes MIDI sont négatives. Dans ce cas on émet des signaux sans faire appel au player de patterns
|
|
1005
|
+
// On appelle jamais pushClipAbleton avec une note négative issue de la config.
|
|
1006
|
+
if (pattern[0] < 0) {
|
|
1007
|
+
// Pour associer le nom du pattern au signal de groupe IN
|
|
1008
|
+
// C'est plus pour être cohérent que par besoin.
|
|
1009
|
+
reactAutomatePossible({ [signal]: pattern[3] });
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
let dureeAttente = pushClipDAW(pattern, signal, legroupe, unPseudo, monId);
|
|
1014
|
+
|
|
1015
|
+
// DureeAttente est la somme des durées de la FIFO de l'instrument.
|
|
1016
|
+
if (dureeAttente === -1) {
|
|
1017
|
+
return; // On est dans un cas de note sans durée
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// Conversion in real waiting time
|
|
1021
|
+
dureeAttente = Math.floor(dureeAttente * tempoTime / 1000);
|
|
1022
|
+
if (debug) console.log("Web Socket Serveur: abletonStartClip:dureeAttente", dureeAttente);
|
|
1023
|
+
// On communique au client le temps d'attente en sec. avant d'entendre.
|
|
1024
|
+
ws.send(JSON.stringify({
|
|
1025
|
+
type: "dureeAttente",
|
|
1026
|
+
text: dureeAttente,
|
|
1027
|
+
son: pattern[3]
|
|
1028
|
+
}));
|
|
1029
|
+
|
|
1030
|
+
/*
|
|
1031
|
+
// Informe tout le monde
|
|
1032
|
+
var messageBroadcast = {
|
|
1033
|
+
soundName: pattern[3],
|
|
1034
|
+
soundFileName: pattern[4],
|
|
1035
|
+
instrument: pattern[5],
|
|
1036
|
+
group: pattern[9],
|
|
1037
|
+
pseudo: unPseudo,
|
|
1038
|
+
idClient: monId
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
hop.broadcast('demandeDeSonParPseudo', JSON.stringify(messageBroadcast));
|
|
1042
|
+
|
|
1043
|
+
var messageInstrument = {
|
|
1044
|
+
instrument: pattern[5],
|
|
1045
|
+
attente : dureeAttente
|
|
1046
|
+
}
|
|
1047
|
+
hop.broadcast('attenteInstrument', JSON.stringify(messageInstrument));
|
|
1048
|
+
*/
|
|
1049
|
+
// Log la manip
|
|
1050
|
+
messageLog.note = pattern[3];
|
|
1051
|
+
messageLog.id = ws.id;
|
|
1052
|
+
messageLog.pseudo = unPseudo;
|
|
1053
|
+
logInfoSocket(messageLog);
|
|
1054
|
+
|
|
1055
|
+
delete messageLog.note;
|
|
1056
|
+
delete messageLog.text;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Build the HipHop Programm.
|
|
1061
|
+
* compile is not the good terminology.
|
|
1062
|
+
* It should be buildMachine, or makeMachine...
|
|
1063
|
+
*
|
|
1064
|
+
* @memberof Websocketserver
|
|
1065
|
+
* @function
|
|
1066
|
+
* @inner
|
|
1067
|
+
*/
|
|
1068
|
+
async function compileHH() {
|
|
1069
|
+
DAWTableReady = false;
|
|
1070
|
+
try {
|
|
1071
|
+
automatePossibleMachine = await groupesClientSon.makeOneAutomatePossibleMachine();
|
|
1072
|
+
} catch (err) {
|
|
1073
|
+
//console.log("ERR: websocketserver.js: pb makeOneAutomatePossibleMachine", err);
|
|
1074
|
+
console.log("\n-------------------------------------------------------------");
|
|
1075
|
+
console.log(`ATTENTION:
|
|
1076
|
+
Problem when compiling the Orchestration
|
|
1077
|
+
maybe an hiphop compile Error`);
|
|
1078
|
+
console.log("-------------------------------------------------------------");
|
|
1079
|
+
|
|
1080
|
+
serv.broadcast(JSON.stringify({
|
|
1081
|
+
type: "consoleBlocklySkini",
|
|
1082
|
+
text: "See your console, pb on compilation"
|
|
1083
|
+
}));
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
DAW.setAutomatePossible(automatePossibleMachine);
|
|
1088
|
+
console.log("INFO: websocketServer: loadDAWTable: table loaded\n");
|
|
1089
|
+
serv.broadcast(JSON.stringify({
|
|
1090
|
+
type: "consoleBlocklySkini",
|
|
1091
|
+
text: "Orchestration loaded"
|
|
1092
|
+
}));
|
|
1093
|
+
|
|
1094
|
+
// Pour l'emission des commandes OSC entre l'orchestration et un jeu ou des capteurs
|
|
1095
|
+
if (par.gameOSCSignals) {
|
|
1096
|
+
gameOSC.setOrchestration(automatePossibleMachine);
|
|
1097
|
+
gameOSC.init();
|
|
1098
|
+
} else {
|
|
1099
|
+
// Pour fermer la socket si on change pour une pièce sans gameOSC
|
|
1100
|
+
gameOSC.closeSocket();
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
try {
|
|
1104
|
+
//reactAutomatePossible( {DAWON: 1} ); // !!! en cours
|
|
1105
|
+
} catch (e) {
|
|
1106
|
+
console.log("websocketServerSkini:loadDAWTable:catch react:", e);
|
|
1107
|
+
}
|
|
1108
|
+
DAWTableReady = true;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Load the parameters
|
|
1113
|
+
* @memberof Websocketserver
|
|
1114
|
+
* @function
|
|
1115
|
+
* @inner
|
|
1116
|
+
*/
|
|
1117
|
+
function loadParameters(fileName) {
|
|
1118
|
+
// Chargement des paramètres
|
|
1119
|
+
// à partir du fichier de config de la pièce
|
|
1120
|
+
// qui a le même nom que le fichier d'orchestration
|
|
1121
|
+
|
|
1122
|
+
if (debug1) console.log("INFO: loadBlocks: parametersFile: ", fileName);
|
|
1123
|
+
// Attention decache n'utilise pas le même path que parametersFile
|
|
1124
|
+
decacheParameters = "../" + fileName;
|
|
1125
|
+
|
|
1126
|
+
try {
|
|
1127
|
+
if (fs.existsSync(fileName)) {
|
|
1128
|
+
let extension = fileName.slice(-3);
|
|
1129
|
+
if (extension !== ".js") {
|
|
1130
|
+
console.log("ERR: Not an js file:", fileName);
|
|
1131
|
+
ws.send(JSON.stringify({
|
|
1132
|
+
type: "alertBlocklySkini",
|
|
1133
|
+
text: "Parameter not an JavaScript file " + fileName
|
|
1134
|
+
}));
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
} else {
|
|
1138
|
+
console.log("ERR: No parameter file:", fileName);
|
|
1139
|
+
ws.send(JSON.stringify({
|
|
1140
|
+
type: "alertBlocklySkini",
|
|
1141
|
+
text: "The parameter file " + fileName + " is not updated, don't run the program before modifying it."
|
|
1142
|
+
}));
|
|
1143
|
+
// Initialise un fichier de parametres par défaut
|
|
1144
|
+
// C'est à dire en copie un dans un parametersFile temporaire
|
|
1145
|
+
try {
|
|
1146
|
+
fs.copyFileSync(origine, fileName);
|
|
1147
|
+
} catch (err) {
|
|
1148
|
+
console.log("websocketServer: Pb ecriture: ", fileName, err);
|
|
1149
|
+
}
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
} catch (err) {
|
|
1153
|
+
console.log("ERR: Pb Reading parameter file:", fileName, err);
|
|
1154
|
+
ws.send(JSON.stringify({
|
|
1155
|
+
type: "alertBlocklySkini",
|
|
1156
|
+
text: "Pb Reading parameter file " + fileName
|
|
1157
|
+
}));
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
// Solution proposée par Qodo pour recharger proprement
|
|
1162
|
+
try {
|
|
1163
|
+
const absPathParam = require.resolve(decacheParameters);
|
|
1164
|
+
try { delete require.cache[absPathParam]; } catch (_) {}
|
|
1165
|
+
try { decache(absPathParam); } catch (_) {}
|
|
1166
|
+
par = require(absPathParam);
|
|
1167
|
+
} catch (e) {
|
|
1168
|
+
console.log("ERR: websocketserver: loadParameters: failed to (re)load parameters:", decacheParameters, e.toString());
|
|
1169
|
+
ws.send(JSON.stringify({
|
|
1170
|
+
type: "alertBlocklySkini",
|
|
1171
|
+
text: "Error reloading parameters " + decacheParameters
|
|
1172
|
+
}));
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// Le fait de faire un require ici, annule la référence de par dans
|
|
1177
|
+
// les autres modules. Il faut faire un reload dans tous les modules.
|
|
1178
|
+
if (debug) console.log("websocketserveur.js: loadbloaks; après require de dechacheParameters:", par);
|
|
1179
|
+
reloadParameters(par);
|
|
1180
|
+
|
|
1181
|
+
// On initialise les interfaces Midi ou via OSC et Synchro quand les paramètres sont chargés.
|
|
1182
|
+
midimix.midimix(automatePossibleMachine);
|
|
1183
|
+
ws.send(JSON.stringify({
|
|
1184
|
+
type: "consoleBlocklySkini",
|
|
1185
|
+
text: "Orchestration loaded"
|
|
1186
|
+
}));
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
/**
|
|
1190
|
+
* Process the websocket messages. The protocols are here.
|
|
1191
|
+
* @memberof Websocketserver
|
|
1192
|
+
* @function
|
|
1193
|
+
* @inner
|
|
1194
|
+
*/
|
|
1195
|
+
ws.on('message', async function (message) {
|
|
1196
|
+
if (debug) console.log('received: %s', message);
|
|
1197
|
+
var msgRecu = JSON.parse(message);
|
|
1198
|
+
|
|
1199
|
+
// Pour le Log des messages reçus
|
|
1200
|
+
messageLog.date = getDateTime();
|
|
1201
|
+
messageLog.type = msgRecu.type;
|
|
1202
|
+
|
|
1203
|
+
switch (msgRecu.type) {
|
|
1204
|
+
|
|
1205
|
+
case "checkSession":
|
|
1206
|
+
DAW.displaySession();
|
|
1207
|
+
console.log("------------------------------------");
|
|
1208
|
+
console.log(par);
|
|
1209
|
+
break;
|
|
1210
|
+
|
|
1211
|
+
case "cleanQueues":
|
|
1212
|
+
DAW.cleanQueues();
|
|
1213
|
+
break;
|
|
1214
|
+
|
|
1215
|
+
case "clientPseudo":
|
|
1216
|
+
if (debug) console.log("websocketserver: clientPseudo", msgRecu);
|
|
1217
|
+
compScore.putInClientsEnCours(msgRecu.pseudo, ws.id, msgRecu.groupe, clientsEnCours);
|
|
1218
|
+
if (debug) console.log("websocketserver: clientPseudo : clientsEnCours:", clientsEnCours);
|
|
1219
|
+
break;
|
|
1220
|
+
|
|
1221
|
+
case "clientScenes": // Pas trés utile, c'est dans scenes.js
|
|
1222
|
+
ws.id = msgRecu.value;
|
|
1223
|
+
break;
|
|
1224
|
+
|
|
1225
|
+
case "closeSpectateur":
|
|
1226
|
+
if (debug) console.log("Web Socket Server: received message system : [%s]",
|
|
1227
|
+
msgRecu.text, " from Client ID:", ws.id);
|
|
1228
|
+
//DAW.libereDansTableDesCommandes(ws.id);
|
|
1229
|
+
|
|
1230
|
+
messageLog.id = ws.id;
|
|
1231
|
+
messageLog.pseudo = msgRecu.pseudo;
|
|
1232
|
+
delete messageLog.text;
|
|
1233
|
+
delete messageLog.note;
|
|
1234
|
+
logInfoSocket(messageLog);
|
|
1235
|
+
|
|
1236
|
+
ws.close();
|
|
1237
|
+
break;
|
|
1238
|
+
|
|
1239
|
+
case "combienDeSpectateurs":
|
|
1240
|
+
var value = DAW.nbeDeSpectateursConnectes();
|
|
1241
|
+
ws.send(JSON.stringify({ type: "nbeDeSpectateurs", value }));
|
|
1242
|
+
break;
|
|
1243
|
+
|
|
1244
|
+
case "configuration": // Message converti en signal pour l'automate central
|
|
1245
|
+
if (debug) console.log("Web Socket Server: received message configuration : [%s]",
|
|
1246
|
+
msgRecu.text, " from Client ID:", ws.id);
|
|
1247
|
+
//machineServeur.inputAndReact( msgRecu.text, msgRecu.extra ); // ENVOI DU SIGNAL VERS HIPHOP
|
|
1248
|
+
break;
|
|
1249
|
+
|
|
1250
|
+
case "configDAWMidiNote":
|
|
1251
|
+
if (debug1) console.log("websocketServer: configDAWMidiNote:", msgRecu);
|
|
1252
|
+
//Rappel des paramètres: par.busMidiDAW, DAWChannel, DAWNote, velocity
|
|
1253
|
+
oscMidiLocal.sendNoteOn(msgRecu.bus, msgRecu.channel, msgRecu.note, 120);
|
|
1254
|
+
break;
|
|
1255
|
+
|
|
1256
|
+
case "configDAWCC":
|
|
1257
|
+
if (debug1) console.log("websocketServer: configDAWCC:", msgRecu);
|
|
1258
|
+
oscMidiLocal.sendControlChange(msgRecu.bus, msgRecu.channel, msgRecu.CC, msgRecu.CCValue);
|
|
1259
|
+
break;
|
|
1260
|
+
|
|
1261
|
+
case "compileHH":
|
|
1262
|
+
try {
|
|
1263
|
+
compileHH();
|
|
1264
|
+
} catch (err) {
|
|
1265
|
+
console.error(err);
|
|
1266
|
+
}
|
|
1267
|
+
break;
|
|
1268
|
+
|
|
1269
|
+
case "compileHHEditionFile":
|
|
1270
|
+
if (debug1) console.log("websocketServer: compileHHEditionFile:", msgRecu,
|
|
1271
|
+
":", piecePath + HipHopSrc, ":", targetHH);
|
|
1272
|
+
|
|
1273
|
+
try {
|
|
1274
|
+
// Etape de compilation vers targetHH
|
|
1275
|
+
let fragment = compile(piecePath + HipHopSrc, {});
|
|
1276
|
+
await fragment.output(targetHH);
|
|
1277
|
+
await fragment.sourcemap(targetHH);
|
|
1278
|
+
} catch (err) {
|
|
1279
|
+
console.log("ERR: Erreur dans la compilation du programme hiphop")
|
|
1280
|
+
console.log("websocketServerSkini:compileHHEditionFile:fragment:", err);
|
|
1281
|
+
break; // Pas la peine d'aller plus loin dans la compilation
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// Fabrique la machine à partir du programme généré en dur dans targetHH.
|
|
1285
|
+
// On utilise le même procédé que pour les programmes générés par Blockly
|
|
1286
|
+
try {
|
|
1287
|
+
compileHH();
|
|
1288
|
+
} catch (err) {
|
|
1289
|
+
console.log("websocketServerSkini:compileHHEditionFile:compileHH:", err);
|
|
1290
|
+
}
|
|
1291
|
+
break;
|
|
1292
|
+
|
|
1293
|
+
case "createSession":
|
|
1294
|
+
if (msgRecu.fileName === '') {
|
|
1295
|
+
console.log("WARN: No descriptor file name");
|
|
1296
|
+
break;
|
|
1297
|
+
}
|
|
1298
|
+
if (debug1) console.log("createSession:", sessionPath + msgRecu.fileName + ".csv");
|
|
1299
|
+
sessionFile = sessionPath + msgRecu.fileName + ".csv";
|
|
1300
|
+
// Initialise un fichier de parametres par défaut
|
|
1301
|
+
// C'est à dire en copie un dans un parametersFile temporaire
|
|
1302
|
+
try {
|
|
1303
|
+
fs.copyFileSync(defaultSession, sessionFile);
|
|
1304
|
+
} catch (err) {
|
|
1305
|
+
console.log("websocketServer: Pb ecriture: ", sessionFile, err);
|
|
1306
|
+
}
|
|
1307
|
+
try {
|
|
1308
|
+
DAW.loadDAWTable(sessionFile);
|
|
1309
|
+
} catch (err) {
|
|
1310
|
+
console.log("websocketServer: erreur de chargement:createSession: ", sessionFile, err);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
ws.send(JSON.stringify({ type: "consoleBlocklySkini", text: "session loaded: " + sessionFile }));
|
|
1314
|
+
break;
|
|
1315
|
+
|
|
1316
|
+
case "DAWPseudo":
|
|
1317
|
+
break;
|
|
1318
|
+
|
|
1319
|
+
case "DAWSelectListClips":
|
|
1320
|
+
let listAllClips = new Array(); // Devient alors utilisable pour les controles dans DAW
|
|
1321
|
+
listAllClips = DAW.getListClips(msgRecu.niveaux);
|
|
1322
|
+
//if (debug) console.log("Web Socket Serveur: niveaux pour recherche ", msgRecu.niveaux, listClips);
|
|
1323
|
+
ws.send(JSON.stringify({
|
|
1324
|
+
type: "listClips",
|
|
1325
|
+
listAllClips
|
|
1326
|
+
}));
|
|
1327
|
+
break;
|
|
1328
|
+
|
|
1329
|
+
/* case "DAWStartClip":
|
|
1330
|
+
pseudo = msgRecu.pseudo;
|
|
1331
|
+
if (msgRecu.clipChoisi === undefined ) break; // Protection si pas de selection sur le client
|
|
1332
|
+
if (debug) console.log("Web Socket Serveur: DAWStartClip: clipChoisi", msgRecu.clipChoisi, " pour ID: ", msgRecu.id);
|
|
1333
|
+
if (debug) console.log('Websocket serveur : DAWStartClip: demandeDeSonParPseudo : ', msgRecu.pseudo, msgRecu.clipChoisi[4]);
|
|
1334
|
+
|
|
1335
|
+
// !! Attention pas à jour dans les paramètre de pushClipDAW
|
|
1336
|
+
var dureeAttente = pushClipDAW(msgRecu.clipChoisi);
|
|
1337
|
+
if ( dureeAttente === -1) {
|
|
1338
|
+
break; // On est dans un cas de note répétée
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
var msg = {
|
|
1342
|
+
type: "dureeAttente",
|
|
1343
|
+
text: dureeAttente,
|
|
1344
|
+
son: msgRecu.clipChoisi[3]
|
|
1345
|
+
}
|
|
1346
|
+
// On communique au client le temps d'attente avant d'entendre.
|
|
1347
|
+
ws.send(JSON.stringify(msg));
|
|
1348
|
+
|
|
1349
|
+
oscMidiLocal.sendProcessing( "/DAWPseudo", msgRecu.pseudo );
|
|
1350
|
+
|
|
1351
|
+
// Informe tout le monde
|
|
1352
|
+
var messageBroadcast = msgRecu.pseudo + " a choisi " + msgRecu.clipChoisi[3];
|
|
1353
|
+
msg.type = "demandeDeSonParPseudo";
|
|
1354
|
+
msg.text = messageBroadcast;
|
|
1355
|
+
delete msg.listClips;
|
|
1356
|
+
serv.broadcast(JSON.stringify(msg));
|
|
1357
|
+
|
|
1358
|
+
// Log la manip
|
|
1359
|
+
messageLog.note = msgRecu.clipChoisi[3];
|
|
1360
|
+
messageLog.id = ws.id;
|
|
1361
|
+
messageLog.pseudo = msgRecu.pseudo;
|
|
1362
|
+
messageLog.text = msg.text;
|
|
1363
|
+
logInfoSocket(messageLog);
|
|
1364
|
+
break;*/
|
|
1365
|
+
|
|
1366
|
+
case "dureeDuTickHorlogeMidi": // Reçu de Processing chaque 24 pulses de l'horloge Midi (une noire)
|
|
1367
|
+
receivedTickFromSynchro();
|
|
1368
|
+
break;
|
|
1369
|
+
|
|
1370
|
+
case "getDelayInstrument":
|
|
1371
|
+
if (debug) console.log("Web Socket Serveur: getDelayInstrument", msgRecu.clipChoisi, " pour ID: ", ws.id);
|
|
1372
|
+
let msgDelay = {
|
|
1373
|
+
type: "delaiInstrument"
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
if (msgRecu.clipChoisi === undefined) {
|
|
1377
|
+
msgDelay.text = -1;
|
|
1378
|
+
msgDelay.son = "pattern undefined";
|
|
1379
|
+
ws.send(JSON.stringify(msgDelay));
|
|
1380
|
+
break;
|
|
1381
|
+
} else {
|
|
1382
|
+
let dureeAttente = DAW.getDelayEventDAW(msgRecu.clipChoisi[5]);
|
|
1383
|
+
if (dureeAttente === -1) {
|
|
1384
|
+
break; // On est dans un cas de note répétée
|
|
1385
|
+
}
|
|
1386
|
+
msgDelay.text = dureeAttente;
|
|
1387
|
+
}
|
|
1388
|
+
// On communique au client le délai avant d'entendre.
|
|
1389
|
+
msgDelay.son = msgRecu.clipChoisi[3];
|
|
1390
|
+
ws.send(JSON.stringify(msgDelay));
|
|
1391
|
+
break;
|
|
1392
|
+
|
|
1393
|
+
case "getGroupesClientLength":
|
|
1394
|
+
var longueurs = groupesClientSon.getGroupesClientLength();
|
|
1395
|
+
|
|
1396
|
+
if (debug) console.log("websocketserver: getGroupesClientLength: ", longueurs);
|
|
1397
|
+
ws.send(JSON.stringify({ type: "groupesClientLength", longueurs }));
|
|
1398
|
+
|
|
1399
|
+
break;
|
|
1400
|
+
|
|
1401
|
+
case "getNombreDePatternsPossibleEnListe": // Pour l'initialisation de memorySortable
|
|
1402
|
+
let nombreDePatternsPossible = groupesClientSon.getNombreDePatternsPossibleEnListe();
|
|
1403
|
+
ws.send(JSON.stringify({
|
|
1404
|
+
type: "nombreDePatternsPossibleEnListe",
|
|
1405
|
+
nombreDePatternsPossible: nombreDePatternsPossible
|
|
1406
|
+
}));
|
|
1407
|
+
break;
|
|
1408
|
+
|
|
1409
|
+
case "getPatternGroups":
|
|
1410
|
+
// It happends when calling this function before loading a piece
|
|
1411
|
+
if (par === undefined) break;
|
|
1412
|
+
|
|
1413
|
+
if (DAWStatus !== undefined) {
|
|
1414
|
+
ws.send(JSON.stringify({
|
|
1415
|
+
type: "setPatternGroups",
|
|
1416
|
+
value: par.groupesDesSons
|
|
1417
|
+
}));
|
|
1418
|
+
} else {
|
|
1419
|
+
if (warnings) console.log("WARN: websocketserver: getPatternGroups: DAWStatus not yet defined");
|
|
1420
|
+
}
|
|
1421
|
+
break;
|
|
1422
|
+
|
|
1423
|
+
case "loadBlocks":
|
|
1424
|
+
//
|
|
1425
|
+
// Il manque ici un ménage de ce qui peut se trouver déjà chargé !!!
|
|
1426
|
+
//
|
|
1427
|
+
if(debug1) console.log("INFO: loadBlocks: msgRecu.fileName: ", msgRecu.fileName);
|
|
1428
|
+
if (msgRecu.fileName === '') {
|
|
1429
|
+
console.log("WARN: No orchestration");
|
|
1430
|
+
break;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
let orchestrationFile = piecePath + msgRecu.fileName;
|
|
1434
|
+
|
|
1435
|
+
try {
|
|
1436
|
+
if (fs.existsSync(orchestrationFile)) {
|
|
1437
|
+
let extension = orchestrationFile.slice(-4);
|
|
1438
|
+
if (extension !== ".xml") {
|
|
1439
|
+
console.log("ERR: Not an xml file:", orchestrationFile);
|
|
1440
|
+
ws.send(JSON.stringify({
|
|
1441
|
+
type: "consoleBlocklySkini",
|
|
1442
|
+
text: "Not an XML file " + orchestrationFile
|
|
1443
|
+
}));
|
|
1444
|
+
break;
|
|
1445
|
+
}
|
|
1446
|
+
} else {
|
|
1447
|
+
console.log("ERR: No orchestration file:", orchestrationFile);
|
|
1448
|
+
ws.send(JSON.stringify({
|
|
1449
|
+
type: "consoleBlocklySkini",
|
|
1450
|
+
text: "No orchestration file " + orchestrationFile
|
|
1451
|
+
}));
|
|
1452
|
+
break;
|
|
1453
|
+
}
|
|
1454
|
+
} catch (err) {
|
|
1455
|
+
console.log("ERR: No orchestration file:", orchestrationFile, err);
|
|
1456
|
+
ws.send(JSON.stringify({
|
|
1457
|
+
type: "consoleBlocklySkini",
|
|
1458
|
+
text: "Error reading orchestration file " + orchestrationFile
|
|
1459
|
+
}));
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
fs.readFile(orchestrationFile, 'utf8', (err, data) => {
|
|
1464
|
+
if (err) {
|
|
1465
|
+
console.error(err);
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
if (debug1) console.log("INFO: loadBlocks: orchestrationFile:", orchestrationFile);
|
|
1469
|
+
ws.send(JSON.stringify({
|
|
1470
|
+
type: "blocksLoaded",
|
|
1471
|
+
data
|
|
1472
|
+
}));
|
|
1473
|
+
});
|
|
1474
|
+
|
|
1475
|
+
// Chargement des paramètres
|
|
1476
|
+
// à partir du fichier de config de la pièce
|
|
1477
|
+
// qui a le même nom que le fichier d'orchestration avec un extension js
|
|
1478
|
+
// au lieu de xml
|
|
1479
|
+
|
|
1480
|
+
// Entre autre pour la mise à jour des parametres dans le browser
|
|
1481
|
+
parametersFileGlobal = msgRecu.fileName.slice(0, -4) + ".js";
|
|
1482
|
+
parametersFile = sessionPath + msgRecu.fileName;
|
|
1483
|
+
// Construction du nom à partir du fichier xml
|
|
1484
|
+
parametersFile = parametersFile.slice(0, -4) + ".js";
|
|
1485
|
+
if(debug1) console.log("INFO: loadBlocks: parametersFile: ***** avant loadParameters", parametersFile);
|
|
1486
|
+
loadParameters(parametersFile);
|
|
1487
|
+
break;
|
|
1488
|
+
|
|
1489
|
+
case "loadHHFile":
|
|
1490
|
+
if (msgRecu.fileName === '') {
|
|
1491
|
+
console.log("WARN: No Hiphop file selected");
|
|
1492
|
+
break;
|
|
1493
|
+
}
|
|
1494
|
+
if (debug1) console.log("INFO: loadHHFile:", msgRecu.fileName);
|
|
1495
|
+
HipHopSrc = msgRecu.fileName;
|
|
1496
|
+
|
|
1497
|
+
let extension = HipHopSrc.slice(-6);
|
|
1498
|
+
if (extension !== ".hh.js") {
|
|
1499
|
+
console.log("ERR: Not an HipHop js file:", HipHopSrc);
|
|
1500
|
+
ws.send(JSON.stringify({
|
|
1501
|
+
type: "alertBlocklySkini",
|
|
1502
|
+
text: "You try to load a not HipHop JavaScript file : " + HipHopSrc
|
|
1503
|
+
}));
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// try {
|
|
1507
|
+
// compileHH();
|
|
1508
|
+
// } catch (err) {
|
|
1509
|
+
// console.log("websocketServerSkini:loadHHFile:catch:", err);
|
|
1510
|
+
// }
|
|
1511
|
+
|
|
1512
|
+
// Chargement des paramètres
|
|
1513
|
+
// à partir du fichier de config de la pièce
|
|
1514
|
+
// qui a le même nom que le fichier d'orchestration avec un extension js
|
|
1515
|
+
// au lieu de hh.js
|
|
1516
|
+
// Entre autre pour la mise à jour des parametres dans le browser
|
|
1517
|
+
parametersFileGlobal = msgRecu.fileName.slice(0, -6) + ".js";
|
|
1518
|
+
parametersFile = sessionPath + msgRecu.fileName;
|
|
1519
|
+
// Construction du nom à partir du fichier hh.js
|
|
1520
|
+
parametersFile = parametersFile.slice(0, -6) + ".js";
|
|
1521
|
+
loadParameters(parametersFile);
|
|
1522
|
+
break;
|
|
1523
|
+
|
|
1524
|
+
case "loadSession": // Pour les descripteurs de clips
|
|
1525
|
+
if (msgRecu.fileName === '') {
|
|
1526
|
+
console.log("WARN: No descriptor selected");
|
|
1527
|
+
break;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
if (debug1) console.log("INFO: loadSession:", sessionPath + msgRecu.fileName);
|
|
1531
|
+
sessionFile = sessionPath + msgRecu.fileName;
|
|
1532
|
+
|
|
1533
|
+
try {
|
|
1534
|
+
if (fs.existsSync(sessionFile)) {
|
|
1535
|
+
let extension = sessionFile.slice(-4);
|
|
1536
|
+
if (extension !== ".csv") {
|
|
1537
|
+
console.log("ERR: Not an csv file:", sessionFile);
|
|
1538
|
+
ws.send(JSON.stringify({
|
|
1539
|
+
type: "alertBlocklySkini",
|
|
1540
|
+
text: "Descriptor not a CSV file " + sessionFile
|
|
1541
|
+
}));
|
|
1542
|
+
break;
|
|
1543
|
+
}
|
|
1544
|
+
} else {
|
|
1545
|
+
console.log("ERR: No session file:", sessionFile);
|
|
1546
|
+
ws.send(JSON.stringify({
|
|
1547
|
+
type: "alertBlocklySkini",
|
|
1548
|
+
text: "No session file " + sessionFile
|
|
1549
|
+
}));
|
|
1550
|
+
break;
|
|
1551
|
+
}
|
|
1552
|
+
} catch (err) {
|
|
1553
|
+
console.log("ERR: Pb Reading session file:", sessionFile, err);
|
|
1554
|
+
ws.send(JSON.stringify({
|
|
1555
|
+
type: "alertBlocklySkini",
|
|
1556
|
+
text: "Pb Reading session file " + sessionPath
|
|
1557
|
+
}));
|
|
1558
|
+
break;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
try {
|
|
1562
|
+
DAW.loadDAWTable(sessionPath + msgRecu.fileName);
|
|
1563
|
+
} catch (err) {
|
|
1564
|
+
console.log("websocketServer: erreur de chargement:loadSession: ", sessionFile, err);
|
|
1565
|
+
}
|
|
1566
|
+
ws.send(JSON.stringify({
|
|
1567
|
+
type: "consoleBlocklySkini",
|
|
1568
|
+
text: "session loaded: " + msgRecu.fileName
|
|
1569
|
+
}));
|
|
1570
|
+
break;
|
|
1571
|
+
|
|
1572
|
+
case "putInMatriceDesPossibles":
|
|
1573
|
+
if (debug) console.log("websocketserver:putInMatriceDesPossibles:", msgRecu);
|
|
1574
|
+
groupesClientSon.setInMatriceDesPossibles(msgRecu.clients, msgRecu.sons, msgRecu.status); // groupe de clients, n° du groupe de sons, booleen
|
|
1575
|
+
groupeName = groupesClientSon.getNameGroupeSons(msgRecu.sons);
|
|
1576
|
+
|
|
1577
|
+
if (debug) groupesClientSon.displayMatriceDesPossibles();
|
|
1578
|
+
|
|
1579
|
+
serv.broadcast(JSON.stringify({
|
|
1580
|
+
type: "groupeClientStatus",
|
|
1581
|
+
groupeClient: msgRecu.clients, // Pour identifier le groupe de clients
|
|
1582
|
+
groupeName,
|
|
1583
|
+
status: msgRecu.status
|
|
1584
|
+
}));
|
|
1585
|
+
break;
|
|
1586
|
+
|
|
1587
|
+
case "ResetMatriceDesPossibles":
|
|
1588
|
+
if (debug1) console.log("websocketserver: ResetMatriceDesPossibles");
|
|
1589
|
+
groupesClientSon.resetMatriceDesPossibles();
|
|
1590
|
+
groupeName = "";
|
|
1591
|
+
serv.broadcast(JSON.stringify({
|
|
1592
|
+
type: "groupeClientStatus",
|
|
1593
|
+
groupeClient: 255,
|
|
1594
|
+
groupeName,
|
|
1595
|
+
status: false
|
|
1596
|
+
}));
|
|
1597
|
+
break;
|
|
1598
|
+
|
|
1599
|
+
case "saveBlocklyGeneratedFile":
|
|
1600
|
+
if (msgRecu.fileName === '') {
|
|
1601
|
+
console.log("WARN: No Orchestration");
|
|
1602
|
+
break;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
// Si on crée une orchestration à partir de rien le fichier de paramètre n'existe pas
|
|
1606
|
+
// On en crée un par défaut.
|
|
1607
|
+
parametersFileGlobal = msgRecu.fileName + ".js";
|
|
1608
|
+
try {
|
|
1609
|
+
if (!fs.existsSync(sessionPath + parametersFileGlobal)) {
|
|
1610
|
+
console.log("ERR: No parameter file:", parametersFileGlobal);
|
|
1611
|
+
ws.send(JSON.stringify({
|
|
1612
|
+
type: "alertBlocklySkini",
|
|
1613
|
+
text: "The parameter file " + parametersFileGlobal + " is created, don't run the program before modifying it."
|
|
1614
|
+
}));
|
|
1615
|
+
// Initialise un fichier de parametres par défaut
|
|
1616
|
+
try {
|
|
1617
|
+
fs.copyFileSync(origine, sessionPath + parametersFileGlobal);
|
|
1618
|
+
// On recharge les nouveaux paramètres avant la compilation.
|
|
1619
|
+
// Attention decache n'utilise pas le même path que parametersFile
|
|
1620
|
+
decacheParameters = "../" + sessionPath + parametersFileGlobal;
|
|
1621
|
+
decache(decacheParameters);
|
|
1622
|
+
par = require(decacheParameters);
|
|
1623
|
+
reloadParameters(par);
|
|
1624
|
+
} catch (err) {
|
|
1625
|
+
console.log("websocketServer: Pb ecriture: ", parametersFileGlobal, err.toString());
|
|
1626
|
+
break;
|
|
1627
|
+
}
|
|
1628
|
+
} else {
|
|
1629
|
+
if (debug) console.log("websocketserveur.js: saveBlocklyGeneratedFile: si OK:", par.groupesDesSons);
|
|
1630
|
+
}
|
|
1631
|
+
} catch (err) {
|
|
1632
|
+
console.log("ERR: Pb creating parameter file:", parametersFileGlobal, err.toString());
|
|
1633
|
+
ws.send(JSON.stringify({
|
|
1634
|
+
type: "alertBlocklySkini",
|
|
1635
|
+
text: "Pb creating parameter file " + parametersFileGlobal
|
|
1636
|
+
}));
|
|
1637
|
+
break;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
// Ecrit le programme HH pour création de la machine.
|
|
1641
|
+
// Le programme créé par blockly est dans msgRecu.text
|
|
1642
|
+
fs.writeFile(generatedDir + defaultOrchestrationNameHH, msgRecu.text, function (err) {
|
|
1643
|
+
if (err) {
|
|
1644
|
+
ws.send(JSON.stringify({
|
|
1645
|
+
type: "alertBlocklySkini",
|
|
1646
|
+
text: err.toString()
|
|
1647
|
+
}));
|
|
1648
|
+
return console.log(err);
|
|
1649
|
+
}
|
|
1650
|
+
if (debug1) console.log("INFO: websocketServer:", generatedDir + defaultOrchestrationNameHH, " written");
|
|
1651
|
+
});
|
|
1652
|
+
|
|
1653
|
+
// Ecrit le fichier XML Blockly
|
|
1654
|
+
fs.writeFile(piecePath + msgRecu.fileName + ".xml", msgRecu.xmlBlockly, async function (err) {
|
|
1655
|
+
if (err) {
|
|
1656
|
+
return console.log(err.toString());
|
|
1657
|
+
}
|
|
1658
|
+
console.log("INFO: websocketServer:", msgRecu.fileName + ".xml", " written");
|
|
1659
|
+
ws.send(JSON.stringify({
|
|
1660
|
+
type: "consoleBlocklySkini",
|
|
1661
|
+
text: msgRecu.fileName + ".xml written"
|
|
1662
|
+
}));
|
|
1663
|
+
|
|
1664
|
+
// Pour développement
|
|
1665
|
+
if(debug) console.log("websocketServerSkini:saveBlocklyGeneratedFile:", msgRecu.text);
|
|
1666
|
+
|
|
1667
|
+
try {
|
|
1668
|
+
// Etape de compilation vers targetHH, même principe que
|
|
1669
|
+
// pour "compileHHEditionFile"
|
|
1670
|
+
let fragmentBlocky = compile(generatedDir + defaultOrchestrationNameHH, {});
|
|
1671
|
+
await fragmentBlocky.output(targetHH);
|
|
1672
|
+
await fragmentBlocky.sourcemap(targetHH);
|
|
1673
|
+
} catch (err) {
|
|
1674
|
+
console.log("ERR: Erreur dans la compilation du programme hiphop")
|
|
1675
|
+
console.log("websocketServerSkini:saveBlocklyGeneratedFile:fragment:", err);
|
|
1676
|
+
return; // Pas la peine d'aller plus loin dans la compilation
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
// Création de la machine HH de l'orchestration
|
|
1680
|
+
try {
|
|
1681
|
+
compileHH();
|
|
1682
|
+
} catch (err) {
|
|
1683
|
+
console.log("websocketServerSkini:saveBlocklyGeneratedFile:catch:", err.toString());
|
|
1684
|
+
}
|
|
1685
|
+
});
|
|
1686
|
+
break;
|
|
1687
|
+
|
|
1688
|
+
case "saveSessionAs":
|
|
1689
|
+
if (debug1) console.log("save descriptors as: ", msgRecu.fileName);
|
|
1690
|
+
try {
|
|
1691
|
+
fs.copyFileSync(sessionFile, sessionPath + msgRecu.fileName);
|
|
1692
|
+
} catch (err) {
|
|
1693
|
+
console.log("websocketServer: Pb ecriture save descriptors as: ", msgRecu.fileName, err);
|
|
1694
|
+
}
|
|
1695
|
+
break;
|
|
1696
|
+
|
|
1697
|
+
case "selectAllClips":
|
|
1698
|
+
var listClips = DAW.getAllClips(msgRecu.groupe, groupesClientSon.matriceDesPossibles);
|
|
1699
|
+
if (listClips !== -1) {
|
|
1700
|
+
if (debug) console.log("Web Socket Serveur: selectAllClips for id:", ws.id, "groupe:", msgRecu.groupe, " premier pattern:", listClips[0]);
|
|
1701
|
+
ws.send(JSON.stringify({
|
|
1702
|
+
type: "listClips",
|
|
1703
|
+
listClips
|
|
1704
|
+
}));
|
|
1705
|
+
}
|
|
1706
|
+
break;
|
|
1707
|
+
|
|
1708
|
+
case "sendOSC":
|
|
1709
|
+
oscMidiLocal.sendOSCRasp(msgRecu.message, msgRecu.value1,
|
|
1710
|
+
par.raspOSCPort, msgRecu.IpAddress);
|
|
1711
|
+
break;
|
|
1712
|
+
|
|
1713
|
+
case "sendPatternSequence":
|
|
1714
|
+
var patternSequence = msgRecu.patternSequence;
|
|
1715
|
+
if (debug) console.log("websocketserver: reçu : sendPatternSequence", patternSequence, msgRecu.pseudo);
|
|
1716
|
+
|
|
1717
|
+
// Pour définir la façon dont sera calculé le score pour cette séquence de patterns
|
|
1718
|
+
computeScorePolicy = groupesClientSon.getComputeScorePolicy();
|
|
1719
|
+
computeScoreClass = groupesClientSon.getComputeScoreClass();
|
|
1720
|
+
if (debug) console.log("websocketserver: reçu : sendPatternSequence: computeScorePolicy, computeScoreClass:", computeScorePolicy, computeScoreClass);
|
|
1721
|
+
|
|
1722
|
+
let maPreSequence = compScore.getPreSequence(msgRecu.pseudo, clientsEnCours); //Une liste d'index (notes Skini midi)
|
|
1723
|
+
if (debug) console.log("websocketserver: reçu : sendPatternSequence", patternSequence, msgRecu.pseudo, maPreSequence);
|
|
1724
|
+
|
|
1725
|
+
let monScore = compScore.evaluateSequenceOfPatterns(patternSequence, maPreSequence, computeScorePolicy, computeScoreClass);
|
|
1726
|
+
|
|
1727
|
+
// Met à jour la mémorisation des listes des index de pattern associée au pseudo pour
|
|
1728
|
+
// le calcul du score.
|
|
1729
|
+
compScore.setPreSequence(msgRecu.pseudo, patternSequence, clientsEnCours);
|
|
1730
|
+
|
|
1731
|
+
//Mise à jour du score total en fonction du pseudo
|
|
1732
|
+
let scoreTotal = compScore.updateScore(msgRecu.pseudo, monScore, clientsEnCours);
|
|
1733
|
+
|
|
1734
|
+
for (let i = 0; i < patternSequence.length; i++) {
|
|
1735
|
+
let pattern = DAW.getPatternFromNote(patternSequence[i]);
|
|
1736
|
+
if (pattern === undefined) {
|
|
1737
|
+
if (warnings) console.log("WARN: websocketserver: sendPatternSequence: pattern undefined");
|
|
1738
|
+
ws.send(JSON.stringify({
|
|
1739
|
+
type: "patternSequenceAck",
|
|
1740
|
+
value: false
|
|
1741
|
+
}));
|
|
1742
|
+
}
|
|
1743
|
+
if (debug) console.log("websocketserver: sendPatternSequence: pattern: ", patternSequence[i], pattern);
|
|
1744
|
+
playPattern(msgRecu.pseudo, msgRecu.groupe, pattern, msgRecu.idClient);
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
// On a besoin d'un acknowledge car on pourrait perdre des commandes du client (?? en TCP)
|
|
1748
|
+
// On envoie le score pour la séquence choisie
|
|
1749
|
+
ws.send(JSON.stringify({
|
|
1750
|
+
type: "patternSequenceAck",
|
|
1751
|
+
score: scoreTotal,
|
|
1752
|
+
value: true
|
|
1753
|
+
}));
|
|
1754
|
+
// On passe par groupeClientSon pour informer l'orchestration
|
|
1755
|
+
// Il n'y a pas de lien depuis l'orchestration vers websocketServer.js
|
|
1756
|
+
// (Il y en a dans l'autre sens via des react())
|
|
1757
|
+
groupesClientSon.setClientsEncours(clientsEnCours);
|
|
1758
|
+
break;
|
|
1759
|
+
|
|
1760
|
+
case "setAllMatriceDesPossibles":
|
|
1761
|
+
if (debug1) console.log("websocketserver: setAllMatriceDesPossibles");
|
|
1762
|
+
groupesClientSon.setMatriceDesPossibles();
|
|
1763
|
+
groupeName = "";
|
|
1764
|
+
serv.broadcast(JSON.stringify({
|
|
1765
|
+
type: "groupeClientStatus",
|
|
1766
|
+
groupeClient: 255,
|
|
1767
|
+
groupeName,
|
|
1768
|
+
status: true
|
|
1769
|
+
}));
|
|
1770
|
+
break;
|
|
1771
|
+
|
|
1772
|
+
// DAWON est le SIGNAL d'activation ou désactivation de l'orchestration
|
|
1773
|
+
// DAWStatus est une VARIABLE qui permet de savoir quelle est l'orchestration choisie
|
|
1774
|
+
// (Dans cette version on n'utilise qu'une seule orchestration
|
|
1775
|
+
// mais dans une première version DAWStatus pouvait avoir des valeurs de 1 à 3.)
|
|
1776
|
+
// DAWStatus = 0 signifie pas d'orchestration en cours.
|
|
1777
|
+
case "setDAWON":
|
|
1778
|
+
// msgRecu.value > 0 => DAW Active
|
|
1779
|
+
DAWStatus = msgRecu.value;
|
|
1780
|
+
if (DAWTableReady) {
|
|
1781
|
+
if (debug) console.log("websocketServer:setDAWON:", DAWStatus);
|
|
1782
|
+
DAW.cleanQueues();
|
|
1783
|
+
serv.broadcast(JSON.stringify({
|
|
1784
|
+
type: "DAWStatus",
|
|
1785
|
+
value: msgRecu.value
|
|
1786
|
+
}));
|
|
1787
|
+
initMatriceDesPossibles(DAWStatus);
|
|
1788
|
+
// Pour être en phase avec la création du pad controleur
|
|
1789
|
+
groupesClientSon.resetMatriceDesPossibles();
|
|
1790
|
+
} else {
|
|
1791
|
+
if (warnings) console.log("WARNING: Table des commandes DAW pas encore chargée: ", DAWStatus);
|
|
1792
|
+
ws.send(JSON.stringify({
|
|
1793
|
+
type: "DAWTableNotReady",
|
|
1794
|
+
text: "Table des commandes DAW pas encore chargée"
|
|
1795
|
+
}));
|
|
1796
|
+
}
|
|
1797
|
+
break;
|
|
1798
|
+
|
|
1799
|
+
case "startAutomate": // Lance l'automate orchestrateur de la matrice des possibles
|
|
1800
|
+
if (par.timer !== undefined) {
|
|
1801
|
+
timerSynchro = par.timer;
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
if (DAWTableReady) {
|
|
1805
|
+
if (debug1) console.log("INFO: webSocketServeur:startAutomate: DAWstatus:", DAWStatus);
|
|
1806
|
+
reactAutomatePossible({ start: undefined });
|
|
1807
|
+
|
|
1808
|
+
// S'il n'y a pas de synchro Midi ni Link on lance un worker
|
|
1809
|
+
if (!par.synchoOnMidiClock && !par.synchroLink && par.synchroSkini) {
|
|
1810
|
+
//setMonTimer(timerSynchro); // Pour un timer dans le thread principal, pas utile avec les workers
|
|
1811
|
+
if (debug1) console.log("websocketserver: startAutomate:worker synchro");
|
|
1812
|
+
workerSynchroInit('./serveur/workerSynchro.mjs', timerSynchro); // Avec un worker
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
if (par.sensorOSC) {
|
|
1816
|
+
if (debug1) console.log("INFO: webSocketServeur: With Interface Z sensors");
|
|
1817
|
+
workerInterfaceZInit('./serveur/workerInterfaceZ.mjs',
|
|
1818
|
+
ipConfig.serverIPAddress,
|
|
1819
|
+
ipConfig.interfaceZIPaddress,
|
|
1820
|
+
ipConfig.portOSCFromInterfaceZData,
|
|
1821
|
+
ipConfig.portOSCFromInterfaceZMidi,
|
|
1822
|
+
ipConfig.portOSCFromInterfaceZMiniWi,
|
|
1823
|
+
ipConfig.portOSCToInterfaceZ,
|
|
1824
|
+
par.tempoSensorsInit,
|
|
1825
|
+
par.sensorsSensibilities);
|
|
1826
|
+
} else {
|
|
1827
|
+
if (debug) console.log("INFO: webSocketServeur: stopInterfaceZ", workerInterfaceZ);
|
|
1828
|
+
if (workerInterfaceZ !== undefined) {
|
|
1829
|
+
workerInterfaceZ.postMessage(["stopInterfaceZ"]);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
compScore.resetClientEnCours(clientsEnCours);
|
|
1835
|
+
groupesClientSon.setClientsEncours(clientsEnCours);
|
|
1836
|
+
|
|
1837
|
+
// Sinon n'est envoyé qu'au onopen de la Socket
|
|
1838
|
+
// nécessaire pour les couleurs sur les clients
|
|
1839
|
+
serv.broadcast(JSON.stringify({
|
|
1840
|
+
type: "setPatternGroups",
|
|
1841
|
+
value: par.groupesDesSons
|
|
1842
|
+
}));
|
|
1843
|
+
// Au cas où le client serait connecté avant le début de l'orchestration.
|
|
1844
|
+
if (debug) console.log("Web Socket Server: startAutomate DAWON:", DAWStatus);
|
|
1845
|
+
ws.send(JSON.stringify({
|
|
1846
|
+
type: "DAWON",
|
|
1847
|
+
value: DAWStatus
|
|
1848
|
+
}));
|
|
1849
|
+
break;
|
|
1850
|
+
|
|
1851
|
+
case "startByMidiClock":
|
|
1852
|
+
//compteurDivisionMesure = 0; // Remise à zero de la position dans le motif
|
|
1853
|
+
break;
|
|
1854
|
+
|
|
1855
|
+
case "startSpectateur": // On récupère l'ID du client
|
|
1856
|
+
// On autorise la configuration des patterns même sans piece chargée
|
|
1857
|
+
if (msgRecu.text === "configurateur") {
|
|
1858
|
+
if (debug1) console.log("INFO: webSocketServeur: startSpectateur: un configurateur connecté", msgRecu.id);
|
|
1859
|
+
ws.send(JSON.stringify({
|
|
1860
|
+
type: "skiniParametres",
|
|
1861
|
+
descriptors: DAW.getSession(),
|
|
1862
|
+
value: par
|
|
1863
|
+
}));
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
if (par === undefined) {
|
|
1867
|
+
console.log("WARN: A client try to connect but no piece launched");
|
|
1868
|
+
break;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
ws.id = msgRecu.id;
|
|
1872
|
+
if (debug) console.log("INFO: websocketserbeur: startSpectateur: ", msgRecu.id);
|
|
1873
|
+
|
|
1874
|
+
// On ne permet donc qu'un seul controleur.
|
|
1875
|
+
// Attention: La connexion d'un deuxième contrôleur, fait perdre la première et réinitialise la matrice des possible.
|
|
1876
|
+
if (msgRecu.text === "controleur") {
|
|
1877
|
+
if (debug1) console.log("INFO: webSocketServeur: startSpectateur: un controleur connecté");
|
|
1878
|
+
socketControleur = ws;
|
|
1879
|
+
groupesClientSon.setSocketControleur(ws);
|
|
1880
|
+
initMatriceDesPossibles(DAWStatus);
|
|
1881
|
+
ws.send(JSON.stringify({
|
|
1882
|
+
type: "skiniParametres",
|
|
1883
|
+
value: par
|
|
1884
|
+
}));
|
|
1885
|
+
break;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
if (msgRecu.text === "pieceParameters") {
|
|
1889
|
+
if (debug1) console.log("INFO: webSocketServeur: startSpectateur: Parametre connecté", msgRecu.id);
|
|
1890
|
+
ws.send(JSON.stringify({
|
|
1891
|
+
type: "skiniParametres",
|
|
1892
|
+
value: par
|
|
1893
|
+
}));
|
|
1894
|
+
|
|
1895
|
+
if (debug) console.log("INFO: webSocketServeur: startSpectateur: Parametre connecté", par);
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
if (msgRecu.text === "clientListe") {
|
|
1899
|
+
if (debug1) console.log("INFO: webSocketServeur: startSpectateur: un clientListe connecté", msgRecu.id);
|
|
1900
|
+
ws.send(JSON.stringify({
|
|
1901
|
+
type: "skiniParametres",
|
|
1902
|
+
value: par
|
|
1903
|
+
}));
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
if (msgRecu.text === "simulateur") {
|
|
1907
|
+
if (par.simulatorInAseperateGroup) {
|
|
1908
|
+
// Assignation d'un groupe au client
|
|
1909
|
+
ws.send(JSON.stringify({
|
|
1910
|
+
type: "groupe",
|
|
1911
|
+
noDeGroupe: par.nbeDeGroupesClients - 1
|
|
1912
|
+
}));
|
|
1913
|
+
groupesClientSon.putIdInGroupClient(ws.id, par.nbeDeGroupesClients - 1);
|
|
1914
|
+
|
|
1915
|
+
// Pour dire à l'ouverture au simulateur si on est ou pas dans une scène où DAW est actif.
|
|
1916
|
+
if (debug1) console.log("INFO: Web Socket Server: startSpectateur: simulateur: DAWON:", DAWStatus);
|
|
1917
|
+
ws.send(JSON.stringify({
|
|
1918
|
+
type: "DAWON",
|
|
1919
|
+
value: DAWStatus
|
|
1920
|
+
}));
|
|
1921
|
+
break;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
if (debug) console.log("websocket serveur: startSpectateur: ", ws.id, "dans groupe:", groupeEncours, msgRecu, clientsEnCours);
|
|
1926
|
+
|
|
1927
|
+
// Assignation d'un groupe au client
|
|
1928
|
+
ws.send(JSON.stringify({
|
|
1929
|
+
type: "groupe",
|
|
1930
|
+
noDeGroupe: groupeEncours
|
|
1931
|
+
}));
|
|
1932
|
+
groupesClientSon.putIdInGroupClient(ws.id, groupeEncours);
|
|
1933
|
+
|
|
1934
|
+
if (debug) console.log("websocket serveur: startSpectateur: groupesClientSon:", groupesClientSon.getGroupesClient());
|
|
1935
|
+
|
|
1936
|
+
// Pour une distribution équilibrée entre les groupes
|
|
1937
|
+
// Si on souhaite avoir le simulateur sur un groupe non distribué à l'audience,
|
|
1938
|
+
// dans le fichier de configuration on met simulatorInAseperateGroup = true;
|
|
1939
|
+
// Ceci réserve le dernier groupe Client pour le simulateur puisque groupeEnCours n'aura jamais
|
|
1940
|
+
// la valeur maximale nbeDeGroupesClients
|
|
1941
|
+
if (par.nbeDeGroupesClients === 1 && par.simulatorInAseperateGroup) {
|
|
1942
|
+
if (warnings) console.log("WARN: ATENTION PAS DE GROUPE ASSIGNE A L'AUDIENCE !");
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
groupeEncours++;
|
|
1946
|
+
if (par.simulatorInAseperateGroup) {
|
|
1947
|
+
groupeEncours %= par.nbeDeGroupesClients - 1;
|
|
1948
|
+
}
|
|
1949
|
+
else {
|
|
1950
|
+
groupeEncours %= par.nbeDeGroupesClients;
|
|
1951
|
+
}
|
|
1952
|
+
// Pour dire à l'ouverture au client si on est ou pas dans une scène où DAW est actif.
|
|
1953
|
+
if (debug) console.log("Web Socket Server: startSpectateur: emission DAWStatus:", DAWStatus);
|
|
1954
|
+
ws.send(JSON.stringify({
|
|
1955
|
+
type: "DAWStatus",
|
|
1956
|
+
value: DAWStatus
|
|
1957
|
+
}));
|
|
1958
|
+
break;
|
|
1959
|
+
|
|
1960
|
+
case "startSimulator":
|
|
1961
|
+
if (debug) console.log("Web Socket Server: start Simulator");
|
|
1962
|
+
childSimulator = fork("./client/simulateurListe/simulateurFork.mjs");
|
|
1963
|
+
childSimulator.send({ type: "START_SIMULATOR" });
|
|
1964
|
+
updateSimulatorParameters(par);
|
|
1965
|
+
break;
|
|
1966
|
+
|
|
1967
|
+
case "stopAutomate":
|
|
1968
|
+
if (DAWTableReady) {
|
|
1969
|
+
//if (setTimer !== undefined && !par.synchoOnMidiClock) clearInterval(setTimer);
|
|
1970
|
+
reactAutomatePossible({ halt: undefined });
|
|
1971
|
+
DAWStatus = 0;
|
|
1972
|
+
serv.broadcast(JSON.stringify({
|
|
1973
|
+
type: "DAWStatus",
|
|
1974
|
+
value: false
|
|
1975
|
+
}));
|
|
1976
|
+
}
|
|
1977
|
+
break;
|
|
1978
|
+
|
|
1979
|
+
case "stopSimulator":
|
|
1980
|
+
if (debug) console.log("INFO: Web Socket Server: stop Simulator");
|
|
1981
|
+
childSimulator.send({ type: "STOP_SIMULATOR" });
|
|
1982
|
+
break;
|
|
1983
|
+
|
|
1984
|
+
case "system": // Message converti en signal pour l'automate central
|
|
1985
|
+
if (debug) console.log("Web Socket Server: received message : [%s]",
|
|
1986
|
+
msgRecu.text, " from Client ID:", ws.id);
|
|
1987
|
+
machineServeur.inputAndReact(msgRecu.text, ws.id); // ENVOI DU SIGNAL VERS HIPHOP
|
|
1988
|
+
break;
|
|
1989
|
+
|
|
1990
|
+
case "updateSession":
|
|
1991
|
+
if (sessionFile !== undefined) {
|
|
1992
|
+
if (debug) console.log("updateSession pour:", sessionFile, ": ", arrayToCSV(msgRecu.data));
|
|
1993
|
+
// Ecrire le fichier
|
|
1994
|
+
fs.writeFile(sessionFile, arrayToCSV(msgRecu.data), function (err) {
|
|
1995
|
+
if (err) {
|
|
1996
|
+
ws.send(JSON.stringify({
|
|
1997
|
+
type: "alertBlocklySkini",
|
|
1998
|
+
text: err.toString()
|
|
1999
|
+
}));
|
|
2000
|
+
return console.log("ERR: websocketserver.js: updateSession: ", err);
|
|
2001
|
+
} else {
|
|
2002
|
+
// Le recharger dans DAW
|
|
2003
|
+
try {
|
|
2004
|
+
DAW.loadDAWTable(sessionFile);
|
|
2005
|
+
} catch (err) {
|
|
2006
|
+
console.log("websocketServer: erreur de chargement:createSession: ", sessionFile, err);
|
|
2007
|
+
}
|
|
2008
|
+
ws.send(JSON.stringify({
|
|
2009
|
+
type: "consoleBlocklySkini",
|
|
2010
|
+
text: "session loaded: " + sessionFile
|
|
2011
|
+
}));
|
|
2012
|
+
}
|
|
2013
|
+
});
|
|
2014
|
+
} else {
|
|
2015
|
+
console.log("WARN: No descriptor file specified");
|
|
2016
|
+
break;
|
|
2017
|
+
}
|
|
2018
|
+
break;
|
|
2019
|
+
|
|
2020
|
+
case "updateParameters":
|
|
2021
|
+
//Save the previous parameters
|
|
2022
|
+
fs.copyFile(sessionPath + parametersFileGlobal, "./backup/" + parametersFileGlobal + ".back", function (err) {
|
|
2023
|
+
if (err) {
|
|
2024
|
+
return console.log(err);
|
|
2025
|
+
}
|
|
2026
|
+
if (debug1) console.log("INFO: websocketServer: updateParameters", parametersFileGlobal + ".back written");
|
|
2027
|
+
});
|
|
2028
|
+
|
|
2029
|
+
if (debug1) console.log("INFO: websocketserveur: Update of the piece parameters", msgRecu.data, "in", sessionPath + parametersFileGlobal);
|
|
2030
|
+
if (parametersFileGlobal !== undefined) {
|
|
2031
|
+
saveParam.saveParameters(sessionPath + parametersFileGlobal, msgRecu.data);
|
|
2032
|
+
reloadParameters(msgRecu.data);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
// On recrée le fichier pour son utilisation par le simulateurListe.js
|
|
2036
|
+
let destinationUpdate = "./serveur/skiniParametres.js";
|
|
2037
|
+
try {
|
|
2038
|
+
fs.copyFileSync(sessionPath + parametersFileGlobal, destinationUpdate);
|
|
2039
|
+
} catch (err) {
|
|
2040
|
+
console.log("ERR: websocketserver: destinationUpdate : Pb ecriture", destinationUpdate, err);
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
// Recréé la machine d'orchestration pour intégrer les modifications
|
|
2044
|
+
// des paramétres de groupes et tanks.
|
|
2045
|
+
try {
|
|
2046
|
+
compileHH();
|
|
2047
|
+
} catch (err) {
|
|
2048
|
+
console.log("websocketServerSkini:updateParameters:catch:", err);
|
|
2049
|
+
}
|
|
2050
|
+
break;
|
|
2051
|
+
|
|
2052
|
+
default: console.log("INFO: Web Socket Serveur: Type de message inconnu : ", msgRecu);
|
|
2053
|
+
}
|
|
2054
|
+
});
|
|
2055
|
+
});
|
|
2056
|
+
|
|
2057
|
+
/****** FIN WEBSOCKET ************/
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
function logInfoSocket(message) {
|
|
2061
|
+
fs.appendFile('skinilog.json', JSON.stringify(message) + "\n", "UTF-8", function (err) {
|
|
2062
|
+
if (err) {
|
|
2063
|
+
console.error(err);
|
|
2064
|
+
throw err;
|
|
2065
|
+
}
|
|
2066
|
+
});
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
function getDateTime() {
|
|
2070
|
+
var date = new Date();
|
|
2071
|
+
|
|
2072
|
+
var hour = date.getHours();
|
|
2073
|
+
hour = (hour < 10 ? "0" : "") + hour;
|
|
2074
|
+
|
|
2075
|
+
var min = date.getMinutes();
|
|
2076
|
+
min = (min < 10 ? "0" : "") + min;
|
|
2077
|
+
|
|
2078
|
+
var sec = date.getSeconds();
|
|
2079
|
+
sec = (sec < 10 ? "0" : "") + sec;
|
|
2080
|
+
|
|
2081
|
+
var year = date.getFullYear();
|
|
2082
|
+
|
|
2083
|
+
var month = date.getMonth() + 1;
|
|
2084
|
+
month = (month < 10 ? "0" : "") + month;
|
|
2085
|
+
|
|
2086
|
+
var day = date.getDate();
|
|
2087
|
+
day = (day < 10 ? "0" : "") + day;
|
|
2088
|
+
|
|
2089
|
+
return day + ":" + month + ":" + year + ":" + hour + ":" + min + ":" + sec;
|
|
2090
|
+
}
|