@marmooo/midy 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/esm/midy-GM1.d.ts +4 -2
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +52 -29
- package/esm/midy-GM2.d.ts +4 -2
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +73 -49
- package/esm/midy-GMLite.d.ts +4 -2
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +55 -32
- package/esm/midy.d.ts +7 -5
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +79 -54
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +4 -2
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +52 -29
- package/script/midy-GM2.d.ts +4 -2
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +73 -49
- package/script/midy-GMLite.d.ts +4 -2
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +55 -32
- package/script/midy.d.ts +7 -5
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +79 -54
package/script/midy-GM1.js
CHANGED
|
@@ -430,7 +430,7 @@ class MidyGM1 {
|
|
|
430
430
|
const startTime = event.startTime + this.startDelay - offset;
|
|
431
431
|
switch (event.type) {
|
|
432
432
|
case "noteOn":
|
|
433
|
-
if (event.velocity
|
|
433
|
+
if (0 < event.velocity) {
|
|
434
434
|
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
435
435
|
break;
|
|
436
436
|
}
|
|
@@ -478,7 +478,7 @@ class MidyGM1 {
|
|
|
478
478
|
if (queueIndex >= this.timeline.length) {
|
|
479
479
|
await Promise.all(this.notePromises);
|
|
480
480
|
this.notePromises = [];
|
|
481
|
-
this.exclusiveClassNotes.
|
|
481
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
482
482
|
this.audioBufferCache.clear();
|
|
483
483
|
resolve();
|
|
484
484
|
return;
|
|
@@ -597,6 +597,17 @@ class MidyGM1 {
|
|
|
597
597
|
}
|
|
598
598
|
return { instruments, timeline };
|
|
599
599
|
}
|
|
600
|
+
stopActiveNotes(channelNumber, velocity, force, scheduleTime) {
|
|
601
|
+
const channel = this.channels[channelNumber];
|
|
602
|
+
const promises = [];
|
|
603
|
+
const activeNotes = this.getActiveNotes(channel, scheduleTime);
|
|
604
|
+
activeNotes.forEach((note) => {
|
|
605
|
+
const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force, undefined);
|
|
606
|
+
this.notePromises.push(promise);
|
|
607
|
+
promises.push(promise);
|
|
608
|
+
});
|
|
609
|
+
return Promise.all(promises);
|
|
610
|
+
}
|
|
600
611
|
stopChannelNotes(channelNumber, velocity, force, scheduleTime) {
|
|
601
612
|
const channel = this.channels[channelNumber];
|
|
602
613
|
const promises = [];
|
|
@@ -668,6 +679,8 @@ class MidyGM1 {
|
|
|
668
679
|
const note = noteList[i];
|
|
669
680
|
if (!note)
|
|
670
681
|
continue;
|
|
682
|
+
if (note.ending)
|
|
683
|
+
continue;
|
|
671
684
|
callback(note);
|
|
672
685
|
}
|
|
673
686
|
});
|
|
@@ -880,21 +893,21 @@ class MidyGM1 {
|
|
|
880
893
|
channel.sustainNotes.push(note);
|
|
881
894
|
}
|
|
882
895
|
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
896
|
+
const scheduledNotes = channel.scheduledNotes;
|
|
897
|
+
let noteList = scheduledNotes.get(noteNumber);
|
|
898
|
+
if (noteList) {
|
|
899
|
+
noteList.push(note);
|
|
886
900
|
}
|
|
887
901
|
else {
|
|
888
|
-
|
|
889
|
-
scheduledNotes.set(noteNumber,
|
|
902
|
+
noteList = [note];
|
|
903
|
+
scheduledNotes.set(noteNumber, noteList);
|
|
890
904
|
}
|
|
891
905
|
}
|
|
892
906
|
noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
893
907
|
scheduleTime ??= this.audioContext.currentTime;
|
|
894
908
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime);
|
|
895
909
|
}
|
|
896
|
-
disconnectNote(note
|
|
897
|
-
scheduledNotes[index] = null;
|
|
910
|
+
disconnectNote(note) {
|
|
898
911
|
note.bufferSource.disconnect();
|
|
899
912
|
note.filterNode.disconnect();
|
|
900
913
|
note.volumeEnvelopeNode.disconnect();
|
|
@@ -904,8 +917,8 @@ class MidyGM1 {
|
|
|
904
917
|
note.modulationLFO.stop();
|
|
905
918
|
}
|
|
906
919
|
}
|
|
907
|
-
stopNote(endTime, stopTime,
|
|
908
|
-
const note =
|
|
920
|
+
stopNote(endTime, stopTime, noteList, index) {
|
|
921
|
+
const note = noteList[index];
|
|
909
922
|
note.volumeEnvelopeNode.gain
|
|
910
923
|
.cancelScheduledValues(endTime)
|
|
911
924
|
.linearRampToValueAtTime(0, stopTime);
|
|
@@ -915,33 +928,43 @@ class MidyGM1 {
|
|
|
915
928
|
}, stopTime);
|
|
916
929
|
return new Promise((resolve) => {
|
|
917
930
|
note.bufferSource.onended = () => {
|
|
918
|
-
|
|
931
|
+
noteList[index] = undefined;
|
|
932
|
+
this.disconnectNote(note);
|
|
919
933
|
resolve();
|
|
920
934
|
};
|
|
921
935
|
note.bufferSource.stop(stopTime);
|
|
922
936
|
});
|
|
923
937
|
}
|
|
938
|
+
findNoteOffTarget(noteList) {
|
|
939
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
940
|
+
const note = noteList[i];
|
|
941
|
+
if (!note)
|
|
942
|
+
continue;
|
|
943
|
+
if (note.ending)
|
|
944
|
+
continue;
|
|
945
|
+
return [note, i];
|
|
946
|
+
}
|
|
947
|
+
}
|
|
924
948
|
scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force) {
|
|
925
949
|
const channel = this.channels[channelNumber];
|
|
926
950
|
if (!force && 0.5 <= channel.state.sustainPedal)
|
|
927
951
|
return;
|
|
928
952
|
if (!channel.scheduledNotes.has(noteNumber))
|
|
929
953
|
return;
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
}
|
|
954
|
+
const noteList = channel.scheduledNotes.get(noteNumber);
|
|
955
|
+
if (!noteList)
|
|
956
|
+
return; // be careful with drum channel
|
|
957
|
+
const noteOffTarget = this.findNoteOffTarget(noteList, endTime);
|
|
958
|
+
if (!noteOffTarget)
|
|
959
|
+
return;
|
|
960
|
+
const [note, i] = noteOffTarget;
|
|
961
|
+
const volRelease = endTime + note.voiceParams.volRelease;
|
|
962
|
+
const modRelease = endTime + note.voiceParams.modRelease;
|
|
963
|
+
note.filterNode.frequency
|
|
964
|
+
.cancelScheduledValues(endTime)
|
|
965
|
+
.linearRampToValueAtTime(0, modRelease);
|
|
966
|
+
const stopTime = Math.min(volRelease, modRelease);
|
|
967
|
+
return this.stopNote(endTime, stopTime, noteList, i);
|
|
945
968
|
}
|
|
946
969
|
noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
947
970
|
scheduleTime ??= this.audioContext.currentTime;
|
|
@@ -1307,7 +1330,7 @@ class MidyGM1 {
|
|
|
1307
1330
|
}
|
|
1308
1331
|
allSoundOff(channelNumber, _value, scheduleTime) {
|
|
1309
1332
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1310
|
-
return this.
|
|
1333
|
+
return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
|
|
1311
1334
|
}
|
|
1312
1335
|
resetAllStates(channelNumber) {
|
|
1313
1336
|
const channel = this.channels[channelNumber];
|
|
@@ -1345,7 +1368,7 @@ class MidyGM1 {
|
|
|
1345
1368
|
}
|
|
1346
1369
|
allNotesOff(channelNumber, _value, scheduleTime) {
|
|
1347
1370
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1348
|
-
return this.
|
|
1371
|
+
return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
|
|
1349
1372
|
}
|
|
1350
1373
|
handleUniversalNonRealTimeExclusiveMessage(data, scheduleTime) {
|
|
1351
1374
|
switch (data[2]) {
|
package/script/midy-GM2.d.ts
CHANGED
|
@@ -147,6 +147,7 @@ export class MidyGM2 {
|
|
|
147
147
|
instruments: Set<any>;
|
|
148
148
|
timeline: any[];
|
|
149
149
|
};
|
|
150
|
+
stopActiveNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
150
151
|
stopChannelNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
151
152
|
stopNotes(velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
152
153
|
start(): Promise<void>;
|
|
@@ -206,8 +207,9 @@ export class MidyGM2 {
|
|
|
206
207
|
isDrumNoteOffException(channel: any, noteNumber: any): boolean;
|
|
207
208
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
|
|
208
209
|
noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
|
|
209
|
-
disconnectNote(note: any
|
|
210
|
-
stopNote(endTime: any, stopTime: any,
|
|
210
|
+
disconnectNote(note: any): void;
|
|
211
|
+
stopNote(endTime: any, stopTime: any, noteList: any, index: any): Promise<any>;
|
|
212
|
+
findNoteOffTarget(noteList: any): any[] | undefined;
|
|
211
213
|
scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any, portamentoNoteNumber: any): Promise<any> | undefined;
|
|
212
214
|
noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<any> | undefined;
|
|
213
215
|
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
package/script/midy-GM2.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAgNA;IAwCE;;;;;;;;;;;;;;MAcE;IAgCF;;;;;OAmBC;IAxGD,aAAa;IACb,yBAAqB;IACrB,2BAAuB;IACvB;;;MAGE;IACF;;;;;;MAME;IACF,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,2BAAqC;IACrC,+BAEE;IAkBF;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IACjD;;;MAA8D;IAC9D;;;;;;;;MAAyD;IAQ3D,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAkBC;IAED,6DA2BC;IAED,4DASC;IAED,2CAcC;IAED,2EA6DC;IAED,mCAOC;IAED,0BAuDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MAgHC;IAED,mGAiBC;IAED,wEAMC;IAED,uBAKC;IAED,aAMC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,
|
|
1
|
+
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
|
package/script/midy-GM2.js
CHANGED
|
@@ -621,7 +621,7 @@ class MidyGM2 {
|
|
|
621
621
|
const startTime = event.startTime + this.startDelay - offset;
|
|
622
622
|
switch (event.type) {
|
|
623
623
|
case "noteOn":
|
|
624
|
-
if (event.velocity
|
|
624
|
+
if (0 < event.velocity) {
|
|
625
625
|
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime, event.portamento);
|
|
626
626
|
break;
|
|
627
627
|
}
|
|
@@ -834,6 +834,17 @@ class MidyGM2 {
|
|
|
834
834
|
}
|
|
835
835
|
return { instruments, timeline };
|
|
836
836
|
}
|
|
837
|
+
stopActiveNotes(channelNumber, velocity, force, scheduleTime) {
|
|
838
|
+
const channel = this.channels[channelNumber];
|
|
839
|
+
const promises = [];
|
|
840
|
+
const activeNotes = this.getActiveNotes(channel, scheduleTime);
|
|
841
|
+
activeNotes.forEach((note) => {
|
|
842
|
+
const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force, undefined);
|
|
843
|
+
this.notePromises.push(promise);
|
|
844
|
+
promises.push(promise);
|
|
845
|
+
});
|
|
846
|
+
return Promise.all(promises);
|
|
847
|
+
}
|
|
837
848
|
stopChannelNotes(channelNumber, velocity, force, scheduleTime) {
|
|
838
849
|
const channel = this.channels[channelNumber];
|
|
839
850
|
const promises = [];
|
|
@@ -905,6 +916,8 @@ class MidyGM2 {
|
|
|
905
916
|
const note = noteList[i];
|
|
906
917
|
if (!note)
|
|
907
918
|
continue;
|
|
919
|
+
if (note.ending)
|
|
920
|
+
continue;
|
|
908
921
|
callback(note);
|
|
909
922
|
}
|
|
910
923
|
});
|
|
@@ -1270,7 +1283,7 @@ class MidyGM2 {
|
|
|
1270
1283
|
type: "lowpass",
|
|
1271
1284
|
Q: voiceParams.initialFilterQ / 10, // dB
|
|
1272
1285
|
});
|
|
1273
|
-
if (portamento) {
|
|
1286
|
+
if (0.5 <= state.portamento && portamento) {
|
|
1274
1287
|
note.portamento = true;
|
|
1275
1288
|
this.setPortamentoStartVolumeEnvelope(channel, note, now);
|
|
1276
1289
|
this.setPortamentoStartFilterEnvelope(channel, note, now);
|
|
@@ -1360,8 +1373,8 @@ class MidyGM2 {
|
|
|
1360
1373
|
if (!channel.isDrum)
|
|
1361
1374
|
return false;
|
|
1362
1375
|
const programNumber = channel.programNumber;
|
|
1363
|
-
return (programNumber === 48 && noteNumber === 88) ||
|
|
1364
|
-
(programNumber === 56 && 47 <= noteNumber && noteNumber <= 84);
|
|
1376
|
+
return !((programNumber === 48 && noteNumber === 88) ||
|
|
1377
|
+
(programNumber === 56 && 47 <= noteNumber && noteNumber <= 84));
|
|
1365
1378
|
}
|
|
1366
1379
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, portamento) {
|
|
1367
1380
|
const channel = this.channels[channelNumber];
|
|
@@ -1383,20 +1396,21 @@ class MidyGM2 {
|
|
|
1383
1396
|
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
1384
1397
|
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
1385
1398
|
const scheduledNotes = channel.scheduledNotes;
|
|
1386
|
-
let
|
|
1387
|
-
if (
|
|
1388
|
-
|
|
1399
|
+
let noteList = scheduledNotes.get(noteNumber);
|
|
1400
|
+
if (noteList) {
|
|
1401
|
+
noteList.push(note);
|
|
1389
1402
|
}
|
|
1390
1403
|
else {
|
|
1391
|
-
|
|
1392
|
-
scheduledNotes.set(noteNumber,
|
|
1404
|
+
noteList = [note];
|
|
1405
|
+
scheduledNotes.set(noteNumber, noteList);
|
|
1393
1406
|
}
|
|
1394
1407
|
if (this.isDrumNoteOffException(channel, noteNumber)) {
|
|
1395
1408
|
const stopTime = startTime + note.bufferSource.buffer.duration;
|
|
1396
|
-
const index =
|
|
1409
|
+
const index = noteList.length - 1;
|
|
1397
1410
|
const promise = new Promise((resolve) => {
|
|
1398
1411
|
note.bufferSource.onended = () => {
|
|
1399
|
-
|
|
1412
|
+
noteList[index] = undefined;
|
|
1413
|
+
this.disconnectNote(note);
|
|
1400
1414
|
resolve();
|
|
1401
1415
|
};
|
|
1402
1416
|
note.bufferSource.stop(stopTime);
|
|
@@ -1408,8 +1422,7 @@ class MidyGM2 {
|
|
|
1408
1422
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1409
1423
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, false);
|
|
1410
1424
|
}
|
|
1411
|
-
disconnectNote(note
|
|
1412
|
-
scheduledNotes[index] = null;
|
|
1425
|
+
disconnectNote(note) {
|
|
1413
1426
|
note.bufferSource.disconnect();
|
|
1414
1427
|
note.filterNode.disconnect();
|
|
1415
1428
|
note.volumeEnvelopeNode.disconnect();
|
|
@@ -1432,8 +1445,8 @@ class MidyGM2 {
|
|
|
1432
1445
|
note.chorusEffectsSend.disconnect();
|
|
1433
1446
|
}
|
|
1434
1447
|
}
|
|
1435
|
-
stopNote(endTime, stopTime,
|
|
1436
|
-
const note =
|
|
1448
|
+
stopNote(endTime, stopTime, noteList, index) {
|
|
1449
|
+
const note = noteList[index];
|
|
1437
1450
|
note.volumeEnvelopeNode.gain
|
|
1438
1451
|
.cancelScheduledValues(endTime)
|
|
1439
1452
|
.linearRampToValueAtTime(0, stopTime);
|
|
@@ -1443,12 +1456,23 @@ class MidyGM2 {
|
|
|
1443
1456
|
}, stopTime);
|
|
1444
1457
|
return new Promise((resolve) => {
|
|
1445
1458
|
note.bufferSource.onended = () => {
|
|
1446
|
-
|
|
1459
|
+
noteList[index] = undefined;
|
|
1460
|
+
this.disconnectNote(note);
|
|
1447
1461
|
resolve();
|
|
1448
1462
|
};
|
|
1449
1463
|
note.bufferSource.stop(stopTime);
|
|
1450
1464
|
});
|
|
1451
1465
|
}
|
|
1466
|
+
findNoteOffTarget(noteList) {
|
|
1467
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1468
|
+
const note = noteList[i];
|
|
1469
|
+
if (!note)
|
|
1470
|
+
continue;
|
|
1471
|
+
if (note.ending)
|
|
1472
|
+
continue;
|
|
1473
|
+
return [note, i];
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1452
1476
|
scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force, portamentoNoteNumber) {
|
|
1453
1477
|
const channel = this.channels[channelNumber];
|
|
1454
1478
|
if (this.isDrumNoteOffException(channel, noteNumber))
|
|
@@ -1460,34 +1484,32 @@ class MidyGM2 {
|
|
|
1460
1484
|
if (channel.sostenutoNotes.has(noteNumber))
|
|
1461
1485
|
return;
|
|
1462
1486
|
}
|
|
1463
|
-
|
|
1487
|
+
const noteList = channel.scheduledNotes.get(noteNumber);
|
|
1488
|
+
if (!noteList)
|
|
1489
|
+
return; // be careful with drum channel
|
|
1490
|
+
const noteOffTarget = this.findNoteOffTarget(noteList, endTime);
|
|
1491
|
+
if (!noteOffTarget)
|
|
1464
1492
|
return;
|
|
1465
|
-
const
|
|
1466
|
-
|
|
1467
|
-
const
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
const targetRate = baseRate * Math.pow(2, deltaNote / 12);
|
|
1486
|
-
note.bufferSource.playbackRate
|
|
1487
|
-
.cancelScheduledValues(endTime)
|
|
1488
|
-
.linearRampToValueAtTime(targetRate, portamentoTime);
|
|
1489
|
-
return this.stopNote(endTime, portamentoTime, scheduledNotes, i);
|
|
1490
|
-
}
|
|
1493
|
+
const [note, i] = noteOffTarget;
|
|
1494
|
+
if (0.5 <= state.portamento && portamentoNoteNumber !== undefined) {
|
|
1495
|
+
const portamentoTime = endTime + this.getPortamentoTime(channel);
|
|
1496
|
+
const deltaNote = portamentoNoteNumber - noteNumber;
|
|
1497
|
+
const baseRate = note.voiceParams.playbackRate;
|
|
1498
|
+
const targetRate = baseRate * Math.pow(2, deltaNote / 12);
|
|
1499
|
+
note.bufferSource.playbackRate
|
|
1500
|
+
.cancelScheduledValues(endTime)
|
|
1501
|
+
.linearRampToValueAtTime(targetRate, portamentoTime);
|
|
1502
|
+
return this.stopNote(endTime, portamentoTime, noteList, i);
|
|
1503
|
+
}
|
|
1504
|
+
else {
|
|
1505
|
+
const volRelease = endTime +
|
|
1506
|
+
note.voiceParams.volRelease * state.releaseTime * 2;
|
|
1507
|
+
const modRelease = endTime + note.voiceParams.modRelease;
|
|
1508
|
+
note.filterNode.frequency
|
|
1509
|
+
.cancelScheduledValues(endTime)
|
|
1510
|
+
.linearRampToValueAtTime(0, modRelease);
|
|
1511
|
+
const stopTime = Math.min(volRelease, modRelease);
|
|
1512
|
+
return this.stopNote(endTime, stopTime, noteList, i);
|
|
1491
1513
|
}
|
|
1492
1514
|
}
|
|
1493
1515
|
noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
@@ -1568,7 +1590,7 @@ class MidyGM2 {
|
|
|
1568
1590
|
this.getActiveNotes(channel, scheduleTime).forEach((note) => {
|
|
1569
1591
|
this.setControllerParameters(channel, note, table);
|
|
1570
1592
|
});
|
|
1571
|
-
|
|
1593
|
+
this.applyVoiceParams(channel, 13);
|
|
1572
1594
|
}
|
|
1573
1595
|
handlePitchBendMessage(channelNumber, lsb, msb, scheduleTime) {
|
|
1574
1596
|
const pitchBend = msb * 128 + lsb;
|
|
@@ -1745,6 +1767,7 @@ class MidyGM2 {
|
|
|
1745
1767
|
state.set(channel.state.array);
|
|
1746
1768
|
state[2] = velocity / 127;
|
|
1747
1769
|
state[3] = noteNumber / 127;
|
|
1770
|
+
state[13] = state.channelPressure / 127;
|
|
1748
1771
|
return state;
|
|
1749
1772
|
}
|
|
1750
1773
|
applyVoiceParams(channel, controllerType, scheduleTime) {
|
|
@@ -1771,7 +1794,7 @@ class MidyGM2 {
|
|
|
1771
1794
|
if (key in voiceParams)
|
|
1772
1795
|
noteVoiceParams[key] = voiceParams[key];
|
|
1773
1796
|
}
|
|
1774
|
-
if (note.portamento) {
|
|
1797
|
+
if (0.5 <= channel.state.portamento && note.portamento) {
|
|
1775
1798
|
this.setPortamentoStartFilterEnvelope(channel, note, scheduleTime);
|
|
1776
1799
|
}
|
|
1777
1800
|
else {
|
|
@@ -1968,10 +1991,11 @@ class MidyGM2 {
|
|
|
1968
1991
|
const channel = this.channels[channelNumber];
|
|
1969
1992
|
if (channel.isDrum)
|
|
1970
1993
|
return;
|
|
1994
|
+
const state = channel.state;
|
|
1971
1995
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1972
|
-
|
|
1996
|
+
state.softPedal = softPedal / 127;
|
|
1973
1997
|
this.processScheduledNotes(channel, (note) => {
|
|
1974
|
-
if (note.portamento) {
|
|
1998
|
+
if (0.5 <= state.portamento && note.portamento) {
|
|
1975
1999
|
this.setPortamentoStartVolumeEnvelope(channel, note, scheduleTime);
|
|
1976
2000
|
this.setPortamentoStartFilterEnvelope(channel, note, scheduleTime);
|
|
1977
2001
|
}
|
|
@@ -2170,7 +2194,7 @@ class MidyGM2 {
|
|
|
2170
2194
|
}
|
|
2171
2195
|
allSoundOff(channelNumber, _value, scheduleTime) {
|
|
2172
2196
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2173
|
-
return this.
|
|
2197
|
+
return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
|
|
2174
2198
|
}
|
|
2175
2199
|
resetAllStates(channelNumber) {
|
|
2176
2200
|
const channel = this.channels[channelNumber];
|
|
@@ -2214,7 +2238,7 @@ class MidyGM2 {
|
|
|
2214
2238
|
}
|
|
2215
2239
|
allNotesOff(channelNumber, _value, scheduleTime) {
|
|
2216
2240
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2217
|
-
return this.
|
|
2241
|
+
return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
|
|
2218
2242
|
}
|
|
2219
2243
|
omniOff(channelNumber, value, scheduleTime) {
|
|
2220
2244
|
this.allNotesOff(channelNumber, value, scheduleTime);
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -86,6 +86,7 @@ export class MidyGMLite {
|
|
|
86
86
|
instruments: Set<any>;
|
|
87
87
|
timeline: any[];
|
|
88
88
|
};
|
|
89
|
+
stopActiveNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
89
90
|
stopChannelNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
90
91
|
stopNotes(velocity: any, force: any, scheduleTime: any): Promise<any[]>;
|
|
91
92
|
start(): Promise<void>;
|
|
@@ -116,8 +117,9 @@ export class MidyGMLite {
|
|
|
116
117
|
handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
117
118
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
118
119
|
noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
|
|
119
|
-
disconnectNote(note: any
|
|
120
|
-
stopNote(endTime: any, stopTime: any,
|
|
120
|
+
disconnectNote(note: any): void;
|
|
121
|
+
stopNote(endTime: any, stopTime: any, noteList: any, index: any): Promise<any>;
|
|
122
|
+
findNoteOffTarget(noteList: any): any[] | undefined;
|
|
121
123
|
scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): Promise<any> | undefined;
|
|
122
124
|
noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<any> | undefined;
|
|
123
125
|
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA+JA;IA2BE;;;;;;;;;MASE;IAEF,+BAcC;IAnDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,2BAAqC;IACrC,+BAEE;IAcA,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAMnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAaC;IAED,6DA2BC;IAED,4DASC;IAED,2EAsDC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,mGAgBC;IAED,wEAMC;IAED,uBAKC;IAED,aAMC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA+JA;IA2BE;;;;;;;;;MASE;IAEF,+BAcC;IAnDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,2BAAqC;IACrC,+BAEE;IAcA,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAMnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAaC;IAED,6DA2BC;IAED,4DASC;IAED,2EAsDC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,kGAiBC;IAED,mGAgBC;IAED,wEAMC;IAED,uBAKC;IAED,aAMC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDASC;IAED,2DASC;IAED,qDAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,+GA0BC;IAED,gHAwCC;IAED,0EAiBC;IAED,8EAiBC;IAED,kGAoDC;IAED,6FAQC;IAED,gCASC;IAED,+EAiBC;IAED,oDAOC;IAED,yHAuBC;IAED,yGASC;IAED,4GAeC;IAED,mGA2BC;IAED,sFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAQC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MA2BC;IAED,oFAMC;IAED,6EA2CC;IAED;;;;;;;;;;;;;MAeC;IAED,kGAWC;IAED,wDAUC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,uDAYC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,gFAGC;IAED,yCAUC;IAGD,8CAqBC;IAED,gFAGC;IAED,+EAgBC;IAED,qCAWC;IAED,4EAaC;IAED,4DAGC;IAED,sDASC;IAED,gDAYC;IAGD,6DAgBC;CACF;AA1/CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IASE,0FAMC;IAdD,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
|
package/script/midy-GMLite.js
CHANGED
|
@@ -449,7 +449,7 @@ class MidyGMLite {
|
|
|
449
449
|
const startTime = event.startTime + this.startDelay - offset;
|
|
450
450
|
switch (event.type) {
|
|
451
451
|
case "noteOn":
|
|
452
|
-
if (event.velocity
|
|
452
|
+
if (0 < event.velocity) {
|
|
453
453
|
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
454
454
|
break;
|
|
455
455
|
}
|
|
@@ -497,7 +497,7 @@ class MidyGMLite {
|
|
|
497
497
|
if (queueIndex >= this.timeline.length) {
|
|
498
498
|
await Promise.all(this.notePromises);
|
|
499
499
|
this.notePromises = [];
|
|
500
|
-
this.exclusiveClassNotes.
|
|
500
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
501
501
|
this.audioBufferCache.clear();
|
|
502
502
|
resolve();
|
|
503
503
|
return;
|
|
@@ -616,6 +616,17 @@ class MidyGMLite {
|
|
|
616
616
|
}
|
|
617
617
|
return { instruments, timeline };
|
|
618
618
|
}
|
|
619
|
+
stopActiveNotes(channelNumber, velocity, force, scheduleTime) {
|
|
620
|
+
const channel = this.channels[channelNumber];
|
|
621
|
+
const promises = [];
|
|
622
|
+
const activeNotes = this.getActiveNotes(channel, scheduleTime);
|
|
623
|
+
activeNotes.forEach((note) => {
|
|
624
|
+
const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force, undefined);
|
|
625
|
+
this.notePromises.push(promise);
|
|
626
|
+
promises.push(promise);
|
|
627
|
+
});
|
|
628
|
+
return Promise.all(promises);
|
|
629
|
+
}
|
|
619
630
|
stopChannelNotes(channelNumber, velocity, force, scheduleTime) {
|
|
620
631
|
const channel = this.channels[channelNumber];
|
|
621
632
|
const promises = [];
|
|
@@ -687,6 +698,8 @@ class MidyGMLite {
|
|
|
687
698
|
const note = noteList[i];
|
|
688
699
|
if (!note)
|
|
689
700
|
continue;
|
|
701
|
+
if (note.ending)
|
|
702
|
+
continue;
|
|
690
703
|
callback(note);
|
|
691
704
|
}
|
|
692
705
|
});
|
|
@@ -914,20 +927,21 @@ class MidyGMLite {
|
|
|
914
927
|
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
915
928
|
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
916
929
|
const scheduledNotes = channel.scheduledNotes;
|
|
917
|
-
let
|
|
918
|
-
if (
|
|
919
|
-
|
|
930
|
+
let noteList = scheduledNotes.get(noteNumber);
|
|
931
|
+
if (noteList) {
|
|
932
|
+
noteList.push(note);
|
|
920
933
|
}
|
|
921
934
|
else {
|
|
922
|
-
|
|
923
|
-
scheduledNotes.set(noteNumber,
|
|
935
|
+
noteList = [note];
|
|
936
|
+
scheduledNotes.set(noteNumber, noteList);
|
|
924
937
|
}
|
|
925
|
-
if (
|
|
938
|
+
if (channel.isDrum) {
|
|
926
939
|
const stopTime = startTime + note.bufferSource.buffer.duration;
|
|
927
|
-
const index =
|
|
940
|
+
const index = noteList.length - 1;
|
|
928
941
|
const promise = new Promise((resolve) => {
|
|
929
942
|
note.bufferSource.onended = () => {
|
|
930
|
-
|
|
943
|
+
noteList[index] = undefined;
|
|
944
|
+
this.disconnectNote(note);
|
|
931
945
|
resolve();
|
|
932
946
|
};
|
|
933
947
|
note.bufferSource.stop(stopTime);
|
|
@@ -939,8 +953,7 @@ class MidyGMLite {
|
|
|
939
953
|
scheduleTime ??= this.audioContext.currentTime;
|
|
940
954
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime);
|
|
941
955
|
}
|
|
942
|
-
disconnectNote(note
|
|
943
|
-
scheduledNotes[index] = null;
|
|
956
|
+
disconnectNote(note) {
|
|
944
957
|
note.bufferSource.disconnect();
|
|
945
958
|
note.filterNode.disconnect();
|
|
946
959
|
note.volumeEnvelopeNode.disconnect();
|
|
@@ -950,8 +963,8 @@ class MidyGMLite {
|
|
|
950
963
|
note.modulationLFO.stop();
|
|
951
964
|
}
|
|
952
965
|
}
|
|
953
|
-
stopNote(endTime, stopTime,
|
|
954
|
-
const note =
|
|
966
|
+
stopNote(endTime, stopTime, noteList, index) {
|
|
967
|
+
const note = noteList[index];
|
|
955
968
|
note.volumeEnvelopeNode.gain
|
|
956
969
|
.cancelScheduledValues(endTime)
|
|
957
970
|
.linearRampToValueAtTime(0, stopTime);
|
|
@@ -961,12 +974,23 @@ class MidyGMLite {
|
|
|
961
974
|
}, stopTime);
|
|
962
975
|
return new Promise((resolve) => {
|
|
963
976
|
note.bufferSource.onended = () => {
|
|
964
|
-
|
|
977
|
+
noteList[index] = undefined;
|
|
978
|
+
this.disconnectNote(note);
|
|
965
979
|
resolve();
|
|
966
980
|
};
|
|
967
981
|
note.bufferSource.stop(stopTime);
|
|
968
982
|
});
|
|
969
983
|
}
|
|
984
|
+
findNoteOffTarget(noteList) {
|
|
985
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
986
|
+
const note = noteList[i];
|
|
987
|
+
if (!note)
|
|
988
|
+
continue;
|
|
989
|
+
if (note.ending)
|
|
990
|
+
continue;
|
|
991
|
+
return [note, i];
|
|
992
|
+
}
|
|
993
|
+
}
|
|
970
994
|
scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force) {
|
|
971
995
|
const channel = this.channels[channelNumber];
|
|
972
996
|
if (channel.isDrum)
|
|
@@ -975,21 +999,20 @@ class MidyGMLite {
|
|
|
975
999
|
return;
|
|
976
1000
|
if (!channel.scheduledNotes.has(noteNumber))
|
|
977
1001
|
return;
|
|
978
|
-
const
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
}
|
|
1002
|
+
const noteList = channel.scheduledNotes.get(noteNumber);
|
|
1003
|
+
if (!noteList)
|
|
1004
|
+
return; // be careful with drum channel
|
|
1005
|
+
const noteOffTarget = this.findNoteOffTarget(noteList, endTime);
|
|
1006
|
+
if (!noteOffTarget)
|
|
1007
|
+
return;
|
|
1008
|
+
const [note, i] = noteOffTarget;
|
|
1009
|
+
const volRelease = endTime + note.voiceParams.volRelease;
|
|
1010
|
+
const modRelease = endTime + note.voiceParams.modRelease;
|
|
1011
|
+
note.filterNode.frequency
|
|
1012
|
+
.cancelScheduledValues(endTime)
|
|
1013
|
+
.linearRampToValueAtTime(0, modRelease);
|
|
1014
|
+
const stopTime = Math.min(volRelease, modRelease);
|
|
1015
|
+
return this.stopNote(endTime, stopTime, noteList, i);
|
|
993
1016
|
}
|
|
994
1017
|
noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
995
1018
|
scheduleTime ??= this.audioContext.currentTime;
|
|
@@ -1311,7 +1334,7 @@ class MidyGMLite {
|
|
|
1311
1334
|
}
|
|
1312
1335
|
allSoundOff(channelNumber, _value, scheduleTime) {
|
|
1313
1336
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1314
|
-
return this.
|
|
1337
|
+
return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
|
|
1315
1338
|
}
|
|
1316
1339
|
resetAllStates(channelNumber) {
|
|
1317
1340
|
const channel = this.channels[channelNumber];
|
|
@@ -1349,7 +1372,7 @@ class MidyGMLite {
|
|
|
1349
1372
|
}
|
|
1350
1373
|
allNotesOff(channelNumber, _value, scheduleTime) {
|
|
1351
1374
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1352
|
-
return this.
|
|
1375
|
+
return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
|
|
1353
1376
|
}
|
|
1354
1377
|
handleUniversalNonRealTimeExclusiveMessage(data, scheduleTime) {
|
|
1355
1378
|
switch (data[2]) {
|