@marmooo/midy 0.2.2 → 0.2.4
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 +3 -5
- package/esm/midy-GM1.d.ts +5 -4
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +31 -25
- package/esm/midy-GM2.d.ts +19 -22
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +148 -119
- package/esm/midy-GMLite.d.ts +6 -5
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +28 -21
- package/esm/midy.d.ts +21 -22
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +229 -139
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +5 -4
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +31 -25
- package/script/midy-GM2.d.ts +19 -22
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +148 -119
- package/script/midy-GMLite.d.ts +6 -5
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +28 -21
- package/script/midy.d.ts +21 -22
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +229 -139
package/script/midy-GM2.js
CHANGED
|
@@ -100,7 +100,6 @@ class Note {
|
|
|
100
100
|
const defaultControllerState = {
|
|
101
101
|
noteOnVelocity: { type: 2, defaultValue: 0 },
|
|
102
102
|
noteOnKeyNumber: { type: 3, defaultValue: 0 },
|
|
103
|
-
polyPressure: { type: 10, defaultValue: 0 },
|
|
104
103
|
channelPressure: { type: 13, defaultValue: 0 },
|
|
105
104
|
pitchWheel: { type: 14, defaultValue: 8192 / 16383 },
|
|
106
105
|
pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
|
|
@@ -362,15 +361,15 @@ class MidyGM2 {
|
|
|
362
361
|
});
|
|
363
362
|
this.audioContext = audioContext;
|
|
364
363
|
this.options = { ...this.defaultOptions, ...options };
|
|
365
|
-
this.
|
|
364
|
+
this.masterVolume = new GainNode(audioContext);
|
|
366
365
|
this.voiceParamsHandlers = this.createVoiceParamsHandlers();
|
|
367
366
|
this.controlChangeHandlers = this.createControlChangeHandlers();
|
|
368
367
|
this.channels = this.createChannels(audioContext);
|
|
369
368
|
this.reverbEffect = this.options.reverbAlgorithm(audioContext);
|
|
370
369
|
this.chorusEffect = this.createChorusEffect(audioContext);
|
|
371
|
-
this.chorusEffect.output.connect(this.
|
|
372
|
-
this.reverbEffect.output.connect(this.
|
|
373
|
-
this.
|
|
370
|
+
this.chorusEffect.output.connect(this.masterVolume);
|
|
371
|
+
this.reverbEffect.output.connect(this.masterVolume);
|
|
372
|
+
this.masterVolume.connect(audioContext.destination);
|
|
374
373
|
this.GM2SystemOn();
|
|
375
374
|
}
|
|
376
375
|
initSoundFontTable() {
|
|
@@ -416,7 +415,7 @@ class MidyGM2 {
|
|
|
416
415
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
417
416
|
gainL.connect(merger, 0, 0);
|
|
418
417
|
gainR.connect(merger, 0, 1);
|
|
419
|
-
merger.connect(this.
|
|
418
|
+
merger.connect(this.masterVolume);
|
|
420
419
|
return {
|
|
421
420
|
gainL,
|
|
422
421
|
gainR,
|
|
@@ -428,12 +427,10 @@ class MidyGM2 {
|
|
|
428
427
|
return {
|
|
429
428
|
...this.constructor.channelSettings,
|
|
430
429
|
state: new ControllerState(),
|
|
430
|
+
controlTable: this.initControlTable(),
|
|
431
431
|
...this.setChannelAudioNodes(audioContext),
|
|
432
432
|
scheduledNotes: new Map(),
|
|
433
433
|
sostenutoNotes: new Map(),
|
|
434
|
-
channelPressure: {
|
|
435
|
-
...this.constructor.controllerDestinationSettings,
|
|
436
|
-
},
|
|
437
434
|
};
|
|
438
435
|
});
|
|
439
436
|
return channels;
|
|
@@ -935,28 +932,31 @@ class MidyGM2 {
|
|
|
935
932
|
const pitchWheel = channel.state.pitchWheel * 2 - 1;
|
|
936
933
|
const pitchWheelSensitivity = channel.state.pitchWheelSensitivity * 12800;
|
|
937
934
|
const pitch = pitchWheel * pitchWheelSensitivity;
|
|
938
|
-
const pressureDepth = (channel.
|
|
935
|
+
const pressureDepth = (channel.channelPressureTable[0] - 64) / 37.5; // 2400 / 64;
|
|
939
936
|
const pressure = pressureDepth * channel.state.channelPressure;
|
|
940
937
|
return tuning + pitch + pressure;
|
|
941
938
|
}
|
|
942
939
|
calcNoteDetune(channel, note) {
|
|
943
940
|
return channel.scaleOctaveTuningTable[note.noteNumber % 12];
|
|
944
941
|
}
|
|
945
|
-
|
|
946
|
-
const now = this.audioContext.currentTime;
|
|
942
|
+
updateChannelDetune(channel) {
|
|
947
943
|
channel.scheduledNotes.forEach((noteList) => {
|
|
948
944
|
for (let i = 0; i < noteList.length; i++) {
|
|
949
945
|
const note = noteList[i];
|
|
950
946
|
if (!note)
|
|
951
947
|
continue;
|
|
952
|
-
|
|
953
|
-
const detune = channel.detune + noteDetune;
|
|
954
|
-
note.bufferSource.detune
|
|
955
|
-
.cancelScheduledValues(now)
|
|
956
|
-
.setValueAtTime(detune, now);
|
|
948
|
+
this.updateDetune(channel, note, 0);
|
|
957
949
|
}
|
|
958
950
|
});
|
|
959
951
|
}
|
|
952
|
+
updateDetune(channel, note, pressure) {
|
|
953
|
+
const now = this.audioContext.currentTime;
|
|
954
|
+
const noteDetune = this.calcNoteDetune(channel, note);
|
|
955
|
+
const detune = channel.detune + noteDetune + pressure;
|
|
956
|
+
note.bufferSource.detune
|
|
957
|
+
.cancelScheduledValues(now)
|
|
958
|
+
.setValueAtTime(detune, now);
|
|
959
|
+
}
|
|
960
960
|
getPortamentoTime(channel) {
|
|
961
961
|
const factor = 5 * Math.log(10) / 127;
|
|
962
962
|
const time = channel.state.portamentoTime;
|
|
@@ -974,14 +974,11 @@ class MidyGM2 {
|
|
|
974
974
|
.setValueAtTime(0, volDelay)
|
|
975
975
|
.linearRampToValueAtTime(sustainVolume, portamentoTime);
|
|
976
976
|
}
|
|
977
|
-
setVolumeEnvelope(
|
|
977
|
+
setVolumeEnvelope(note, pressure) {
|
|
978
978
|
const now = this.audioContext.currentTime;
|
|
979
|
-
const state = channel.state;
|
|
980
979
|
const { voiceParams, startTime } = note;
|
|
981
|
-
const pressureDepth = channel.pressureTable[2] / 64;
|
|
982
|
-
const pressure = 1 + pressureDepth * channel.state.channelPressure;
|
|
983
980
|
const attackVolume = this.cbToRatio(-voiceParams.initialAttenuation) *
|
|
984
|
-
pressure;
|
|
981
|
+
(1 + pressure);
|
|
985
982
|
const sustainVolume = attackVolume * (1 - voiceParams.volSustain);
|
|
986
983
|
const volDelay = startTime + voiceParams.volDelay;
|
|
987
984
|
const volAttack = volDelay + voiceParams.volAttack;
|
|
@@ -1029,10 +1026,8 @@ class MidyGM2 {
|
|
|
1029
1026
|
const { voiceParams, noteNumber, startTime } = note;
|
|
1030
1027
|
const softPedalFactor = 1 -
|
|
1031
1028
|
(0.1 + (noteNumber / 127) * 0.2) * state.softPedal;
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
const baseCent = voiceParams.initialFilterFc + pressure;
|
|
1035
|
-
const baseFreq = this.centToHz(baseCent) * softPedalFactor;
|
|
1029
|
+
const baseFreq = this.centToHz(voiceParams.initialFilterFc) *
|
|
1030
|
+
softPedalFactor;
|
|
1036
1031
|
const peekFreq = this.centToHz(voiceParams.initialFilterFc + voiceParams.modEnvToFilterFc) * softPedalFactor;
|
|
1037
1032
|
const sustainFreq = baseFreq +
|
|
1038
1033
|
(peekFreq - baseFreq) * (1 - voiceParams.modSustain);
|
|
@@ -1046,15 +1041,16 @@ class MidyGM2 {
|
|
|
1046
1041
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
1047
1042
|
.linearRampToValueAtTime(adjustedSustainFreq, portamentoTime);
|
|
1048
1043
|
}
|
|
1049
|
-
setFilterEnvelope(channel, note) {
|
|
1044
|
+
setFilterEnvelope(channel, note, pressure) {
|
|
1050
1045
|
const now = this.audioContext.currentTime;
|
|
1051
1046
|
const state = channel.state;
|
|
1052
1047
|
const { voiceParams, noteNumber, startTime } = note;
|
|
1053
1048
|
const softPedalFactor = 1 -
|
|
1054
1049
|
(0.1 + (noteNumber / 127) * 0.2) * state.softPedal;
|
|
1055
|
-
const
|
|
1050
|
+
const baseCent = voiceParams.initialFilterFc + pressure;
|
|
1051
|
+
const baseFreq = this.centToHz(baseCent) * softPedalFactor;
|
|
1052
|
+
const peekFreq = this.centToHz(baseCent + voiceParams.modEnvToFilterFc) *
|
|
1056
1053
|
softPedalFactor;
|
|
1057
|
-
const peekFreq = this.centToHz(voiceParams.initialFilterFc + voiceParams.modEnvToFilterFc) * softPedalFactor;
|
|
1058
1054
|
const sustainFreq = baseFreq +
|
|
1059
1055
|
(peekFreq - baseFreq) * (1 - voiceParams.modSustain);
|
|
1060
1056
|
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
@@ -1081,9 +1077,9 @@ class MidyGM2 {
|
|
|
1081
1077
|
gain: voiceParams.modLfoToFilterFc,
|
|
1082
1078
|
});
|
|
1083
1079
|
note.modulationDepth = new GainNode(this.audioContext);
|
|
1084
|
-
this.setModLfoToPitch(channel, note);
|
|
1080
|
+
this.setModLfoToPitch(channel, note, 0);
|
|
1085
1081
|
note.volumeDepth = new GainNode(this.audioContext);
|
|
1086
|
-
this.setModLfoToVolume(
|
|
1082
|
+
this.setModLfoToVolume(note, 0);
|
|
1087
1083
|
note.modulationLFO.start(startTime + voiceParams.delayModLFO);
|
|
1088
1084
|
note.modulationLFO.connect(note.filterDepth);
|
|
1089
1085
|
note.filterDepth.connect(note.filterNode.frequency);
|
|
@@ -1096,8 +1092,7 @@ class MidyGM2 {
|
|
|
1096
1092
|
const { voiceParams } = note;
|
|
1097
1093
|
const state = channel.state;
|
|
1098
1094
|
note.vibratoLFO = new OscillatorNode(this.audioContext, {
|
|
1099
|
-
frequency: this.centToHz(voiceParams.freqVibLFO) *
|
|
1100
|
-
state.vibratoRate,
|
|
1095
|
+
frequency: this.centToHz(voiceParams.freqVibLFO) * state.vibratoRate * 2,
|
|
1101
1096
|
});
|
|
1102
1097
|
note.vibratoLFO.start(startTime + voiceParams.delayVibLFO * state.vibratoDelay * 2);
|
|
1103
1098
|
note.vibratoDepth = new GainNode(this.audioContext);
|
|
@@ -1126,8 +1121,8 @@ class MidyGM2 {
|
|
|
1126
1121
|
}
|
|
1127
1122
|
else {
|
|
1128
1123
|
note.portamento = false;
|
|
1129
|
-
this.setVolumeEnvelope(
|
|
1130
|
-
this.setFilterEnvelope(channel, note);
|
|
1124
|
+
this.setVolumeEnvelope(note, 0);
|
|
1125
|
+
this.setFilterEnvelope(channel, note, 0);
|
|
1131
1126
|
}
|
|
1132
1127
|
if (0 < state.vibratoDepth) {
|
|
1133
1128
|
this.startVibrato(channel, note, startTime);
|
|
@@ -1346,40 +1341,21 @@ class MidyGM2 {
|
|
|
1346
1341
|
const prev = channel.state.channelPressure;
|
|
1347
1342
|
const next = value / 127;
|
|
1348
1343
|
channel.state.channelPressure = next;
|
|
1349
|
-
if (channel.
|
|
1350
|
-
const pressureDepth = (channel.
|
|
1344
|
+
if (channel.channelPressureTable[0] !== 64) {
|
|
1345
|
+
const pressureDepth = (channel.channelPressureTable[0] - 64) / 37.5; // 2400 / 64;
|
|
1351
1346
|
channel.detune += pressureDepth * (next - prev);
|
|
1352
1347
|
}
|
|
1348
|
+
const table = channel.channelPressureTable;
|
|
1353
1349
|
channel.scheduledNotes.forEach((noteList) => {
|
|
1354
1350
|
for (let i = 0; i < noteList.length; i++) {
|
|
1355
1351
|
const note = noteList[i];
|
|
1356
1352
|
if (!note)
|
|
1357
1353
|
continue;
|
|
1358
|
-
this.
|
|
1354
|
+
this.applyDestinationSettings(channel, note, table);
|
|
1359
1355
|
}
|
|
1360
1356
|
});
|
|
1361
1357
|
// this.applyVoiceParams(channel, 13);
|
|
1362
1358
|
}
|
|
1363
|
-
setChannelPressure(channel, note) {
|
|
1364
|
-
if (channel.pressureTable[0] !== 64) {
|
|
1365
|
-
this.updateDetune(channel);
|
|
1366
|
-
}
|
|
1367
|
-
if (channel.pressureTable[1] !== 64 && !note.portamento) {
|
|
1368
|
-
this.setFilterEnvelope(channel, note);
|
|
1369
|
-
}
|
|
1370
|
-
if (channel.pressureTable[2] !== 64 && !note.portamento) {
|
|
1371
|
-
this.setVolumeEnvelope(channel, note);
|
|
1372
|
-
}
|
|
1373
|
-
if (channel.pressureTable[3] !== 0) {
|
|
1374
|
-
this.setModLfoToPitch(channel, note);
|
|
1375
|
-
}
|
|
1376
|
-
if (channel.pressureTable[4] !== 0) {
|
|
1377
|
-
this.setModLfoToFilterFc(channel, note);
|
|
1378
|
-
}
|
|
1379
|
-
if (channel.pressureTable[5] !== 0) {
|
|
1380
|
-
this.setModLfoToVolume(channel, note);
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
1359
|
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
1384
1360
|
const pitchBend = msb * 128 + lsb;
|
|
1385
1361
|
this.setPitchBend(channelNumber, pitchBend);
|
|
@@ -1391,16 +1367,13 @@ class MidyGM2 {
|
|
|
1391
1367
|
const next = (value - 8192) / 8192;
|
|
1392
1368
|
state.pitchWheel = value / 16383;
|
|
1393
1369
|
channel.detune += (next - prev) * state.pitchWheelSensitivity * 12800;
|
|
1394
|
-
this.
|
|
1370
|
+
this.updateChannelDetune(channel);
|
|
1395
1371
|
this.applyVoiceParams(channel, 14);
|
|
1396
1372
|
}
|
|
1397
|
-
setModLfoToPitch(channel, note) {
|
|
1373
|
+
setModLfoToPitch(channel, note, pressure) {
|
|
1398
1374
|
const now = this.audioContext.currentTime;
|
|
1399
|
-
const pressureDepth = channel.pressureTable[3] / 127 * 600;
|
|
1400
|
-
const pressure = pressureDepth * channel.state.channelPressure;
|
|
1401
1375
|
const modLfoToPitch = note.voiceParams.modLfoToPitch + pressure;
|
|
1402
|
-
const baseDepth = Math.abs(modLfoToPitch) +
|
|
1403
|
-
channel.state.modulationDepth;
|
|
1376
|
+
const baseDepth = Math.abs(modLfoToPitch) + channel.state.modulationDepth;
|
|
1404
1377
|
const modulationDepth = baseDepth * Math.sign(modLfoToPitch);
|
|
1405
1378
|
note.modulationDepth.gain
|
|
1406
1379
|
.cancelScheduledValues(now)
|
|
@@ -1416,22 +1389,18 @@ class MidyGM2 {
|
|
|
1416
1389
|
.cancelScheduledValues(now)
|
|
1417
1390
|
.setValueAtTime(vibratoDepth * vibratoDepthSign, now);
|
|
1418
1391
|
}
|
|
1419
|
-
setModLfoToFilterFc(
|
|
1392
|
+
setModLfoToFilterFc(note, pressure) {
|
|
1420
1393
|
const now = this.audioContext.currentTime;
|
|
1421
|
-
const pressureDepth = channel.pressureTable[4] / 127 * 2400;
|
|
1422
|
-
const pressure = pressureDepth * channel.state.channelPressure;
|
|
1423
1394
|
const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc + pressure;
|
|
1424
1395
|
note.filterDepth.gain
|
|
1425
1396
|
.cancelScheduledValues(now)
|
|
1426
1397
|
.setValueAtTime(modLfoToFilterFc, now);
|
|
1427
1398
|
}
|
|
1428
|
-
setModLfoToVolume(
|
|
1399
|
+
setModLfoToVolume(note, pressure) {
|
|
1429
1400
|
const now = this.audioContext.currentTime;
|
|
1430
1401
|
const modLfoToVolume = note.voiceParams.modLfoToVolume;
|
|
1431
1402
|
const baseDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
|
|
1432
|
-
const
|
|
1433
|
-
const pressure = 1 + pressureDepth * channel.state.channelPressure;
|
|
1434
|
-
const volumeDepth = baseDepth * Math.sign(modLfoToVolume) * pressure;
|
|
1403
|
+
const volumeDepth = baseDepth * Math.sign(modLfoToVolume) * (1 + pressure);
|
|
1435
1404
|
note.volumeDepth.gain
|
|
1436
1405
|
.cancelScheduledValues(now)
|
|
1437
1406
|
.setValueAtTime(volumeDepth, now);
|
|
@@ -1504,11 +1473,18 @@ class MidyGM2 {
|
|
|
1504
1473
|
.cancelScheduledValues(now)
|
|
1505
1474
|
.setValueAtTime(freqModLFO, now);
|
|
1506
1475
|
}
|
|
1476
|
+
setFreqVibLFO(channel, note) {
|
|
1477
|
+
const now = this.audioContext.currentTime;
|
|
1478
|
+
const freqVibLFO = note.voiceParams.freqVibLFO;
|
|
1479
|
+
note.vibratoLFO.frequency
|
|
1480
|
+
.cancelScheduledValues(now)
|
|
1481
|
+
.setValueAtTime(freqVibLFO * channel.state.vibratoRate * 2, now);
|
|
1482
|
+
}
|
|
1507
1483
|
createVoiceParamsHandlers() {
|
|
1508
1484
|
return {
|
|
1509
1485
|
modLfoToPitch: (channel, note, _prevValue) => {
|
|
1510
1486
|
if (0 < channel.state.modulationDepth) {
|
|
1511
|
-
this.setModLfoToPitch(channel, note);
|
|
1487
|
+
this.setModLfoToPitch(channel, note, 0);
|
|
1512
1488
|
}
|
|
1513
1489
|
},
|
|
1514
1490
|
vibLfoToPitch: (channel, note, _prevValue) => {
|
|
@@ -1518,12 +1494,12 @@ class MidyGM2 {
|
|
|
1518
1494
|
},
|
|
1519
1495
|
modLfoToFilterFc: (channel, note, _prevValue) => {
|
|
1520
1496
|
if (0 < channel.state.modulationDepth) {
|
|
1521
|
-
this.setModLfoToFilterFc(
|
|
1497
|
+
this.setModLfoToFilterFc(note, 0);
|
|
1522
1498
|
}
|
|
1523
1499
|
},
|
|
1524
|
-
modLfoToVolume: (channel, note) => {
|
|
1500
|
+
modLfoToVolume: (channel, note, _prevValue) => {
|
|
1525
1501
|
if (0 < channel.state.modulationDepth) {
|
|
1526
|
-
this.setModLfoToVolume(
|
|
1502
|
+
this.setModLfoToVolume(note, 0);
|
|
1527
1503
|
}
|
|
1528
1504
|
},
|
|
1529
1505
|
chorusEffectsSend: (channel, note, prevValue) => {
|
|
@@ -1537,22 +1513,19 @@ class MidyGM2 {
|
|
|
1537
1513
|
delayVibLFO: (channel, note, prevValue) => {
|
|
1538
1514
|
if (0 < channel.state.vibratoDepth) {
|
|
1539
1515
|
const now = this.audioContext.currentTime;
|
|
1540
|
-
const
|
|
1541
|
-
|
|
1516
|
+
const vibratoDelay = channel.state.vibratoDelay * 2;
|
|
1517
|
+
const prevStartTime = note.startTime + prevValue * vibratoDelay;
|
|
1542
1518
|
if (now < prevStartTime)
|
|
1543
1519
|
return;
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1520
|
+
const value = note.voiceParams.delayVibLFO;
|
|
1521
|
+
const startTime = note.startTime + value * vibratoDelay;
|
|
1546
1522
|
note.vibratoLFO.stop(now);
|
|
1547
1523
|
note.vibratoLFO.start(startTime);
|
|
1548
1524
|
}
|
|
1549
1525
|
},
|
|
1550
1526
|
freqVibLFO: (channel, note, _prevValue) => {
|
|
1551
1527
|
if (0 < channel.state.vibratoDepth) {
|
|
1552
|
-
|
|
1553
|
-
note.vibratoLFO.frequency
|
|
1554
|
-
.cancelScheduledValues(now)
|
|
1555
|
-
.setValueAtTime(value * sate.vibratoRate, now);
|
|
1528
|
+
this.setFreqVibLFO(channel, note);
|
|
1556
1529
|
}
|
|
1557
1530
|
},
|
|
1558
1531
|
};
|
|
@@ -1596,7 +1569,7 @@ class MidyGM2 {
|
|
|
1596
1569
|
this.setPortamentoStartFilterEnvelope(channel, note);
|
|
1597
1570
|
}
|
|
1598
1571
|
else {
|
|
1599
|
-
this.setFilterEnvelope(channel, note);
|
|
1572
|
+
this.setFilterEnvelope(channel, note, 0);
|
|
1600
1573
|
}
|
|
1601
1574
|
this.setPitchEnvelope(note);
|
|
1602
1575
|
}
|
|
@@ -1610,7 +1583,7 @@ class MidyGM2 {
|
|
|
1610
1583
|
if (key in voiceParams)
|
|
1611
1584
|
noteVoiceParams[key] = voiceParams[key];
|
|
1612
1585
|
}
|
|
1613
|
-
this.setVolumeEnvelope(
|
|
1586
|
+
this.setVolumeEnvelope(note, 0);
|
|
1614
1587
|
}
|
|
1615
1588
|
}
|
|
1616
1589
|
}
|
|
@@ -1649,8 +1622,8 @@ class MidyGM2 {
|
|
|
1649
1622
|
if (handler) {
|
|
1650
1623
|
handler.call(this, channelNumber, value);
|
|
1651
1624
|
const channel = this.channels[channelNumber];
|
|
1652
|
-
|
|
1653
|
-
this.
|
|
1625
|
+
this.applyVoiceParams(channel, controllerType + 128);
|
|
1626
|
+
this.applyControlTable(channel, controllerType);
|
|
1654
1627
|
}
|
|
1655
1628
|
else {
|
|
1656
1629
|
console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
|
|
@@ -1661,13 +1634,14 @@ class MidyGM2 {
|
|
|
1661
1634
|
}
|
|
1662
1635
|
updateModulation(channel) {
|
|
1663
1636
|
const now = this.audioContext.currentTime;
|
|
1637
|
+
const depth = channel.state.modulationDepth * channel.modulationDepthRange;
|
|
1664
1638
|
channel.scheduledNotes.forEach((noteList) => {
|
|
1665
1639
|
for (let i = 0; i < noteList.length; i++) {
|
|
1666
1640
|
const note = noteList[i];
|
|
1667
1641
|
if (!note)
|
|
1668
1642
|
continue;
|
|
1669
1643
|
if (note.modulationDepth) {
|
|
1670
|
-
note.modulationDepth.gain.setValueAtTime(
|
|
1644
|
+
note.modulationDepth.gain.setValueAtTime(depth, now);
|
|
1671
1645
|
}
|
|
1672
1646
|
else {
|
|
1673
1647
|
this.setPitchEnvelope(note);
|
|
@@ -1678,8 +1652,7 @@ class MidyGM2 {
|
|
|
1678
1652
|
}
|
|
1679
1653
|
setModulationDepth(channelNumber, modulation) {
|
|
1680
1654
|
const channel = this.channels[channelNumber];
|
|
1681
|
-
channel.state.modulationDepth =
|
|
1682
|
-
channel.modulationDepthRange;
|
|
1655
|
+
channel.state.modulationDepth = modulation / 127;
|
|
1683
1656
|
this.updateModulation(channel);
|
|
1684
1657
|
}
|
|
1685
1658
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
@@ -1942,7 +1915,7 @@ class MidyGM2 {
|
|
|
1942
1915
|
const next = value / 128;
|
|
1943
1916
|
state.pitchWheelSensitivity = next;
|
|
1944
1917
|
channel.detune += (state.pitchWheel * 2 - 1) * (next - prev) * 12800;
|
|
1945
|
-
this.
|
|
1918
|
+
this.updateChannelDetune(channel);
|
|
1946
1919
|
this.applyVoiceParams(channel, 16);
|
|
1947
1920
|
}
|
|
1948
1921
|
handleFineTuningRPN(channelNumber) {
|
|
@@ -1957,7 +1930,7 @@ class MidyGM2 {
|
|
|
1957
1930
|
const next = (value - 8192) / 8.192; // cent
|
|
1958
1931
|
channel.fineTuning = next;
|
|
1959
1932
|
channel.detune += next - prev;
|
|
1960
|
-
this.
|
|
1933
|
+
this.updateChannelDetune(channel);
|
|
1961
1934
|
}
|
|
1962
1935
|
handleCoarseTuningRPN(channelNumber) {
|
|
1963
1936
|
const channel = this.channels[channelNumber];
|
|
@@ -1971,7 +1944,7 @@ class MidyGM2 {
|
|
|
1971
1944
|
const next = (value - 64) * 100; // cent
|
|
1972
1945
|
channel.coarseTuning = next;
|
|
1973
1946
|
channel.detune += next - prev;
|
|
1974
|
-
this.
|
|
1947
|
+
this.updateChannelDetune(channel);
|
|
1975
1948
|
}
|
|
1976
1949
|
handleModulationDepthRangeRPN(channelNumber) {
|
|
1977
1950
|
const channel = this.channels[channelNumber];
|
|
@@ -1982,7 +1955,6 @@ class MidyGM2 {
|
|
|
1982
1955
|
setModulationDepthRange(channelNumber, modulationDepthRange) {
|
|
1983
1956
|
const channel = this.channels[channelNumber];
|
|
1984
1957
|
channel.modulationDepthRange = modulationDepthRange;
|
|
1985
|
-
channel.modulationDepth = (modulation / 127) * modulationDepthRange;
|
|
1986
1958
|
this.updateModulation(channel);
|
|
1987
1959
|
}
|
|
1988
1960
|
allSoundOff(channelNumber) {
|
|
@@ -2003,7 +1975,7 @@ class MidyGM2 {
|
|
|
2003
1975
|
const state = channel.state;
|
|
2004
1976
|
for (let i = 0; i < stateTypes.length; i++) {
|
|
2005
1977
|
const type = stateTypes[i];
|
|
2006
|
-
state[type] = defaultControllerState[type];
|
|
1978
|
+
state[type] = defaultControllerState[type].defaultValue;
|
|
2007
1979
|
}
|
|
2008
1980
|
const settingTypes = [
|
|
2009
1981
|
"rpnMSB",
|
|
@@ -2097,10 +2069,9 @@ class MidyGM2 {
|
|
|
2097
2069
|
case 9:
|
|
2098
2070
|
switch (data[3]) {
|
|
2099
2071
|
case 1: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca22.pdf
|
|
2100
|
-
return this.
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
// return this.setControlChange();
|
|
2072
|
+
return this.handlePressureSysEx(data, "channelPressureTable");
|
|
2073
|
+
case 3: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca22.pdf
|
|
2074
|
+
return this.handleControlChangeSysEx(data);
|
|
2104
2075
|
default:
|
|
2105
2076
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
2106
2077
|
}
|
|
@@ -2127,8 +2098,8 @@ class MidyGM2 {
|
|
|
2127
2098
|
}
|
|
2128
2099
|
else {
|
|
2129
2100
|
const now = this.audioContext.currentTime;
|
|
2130
|
-
this.
|
|
2131
|
-
this.
|
|
2101
|
+
this.masterVolume.gain.cancelScheduledValues(now);
|
|
2102
|
+
this.masterVolume.gain.setValueAtTime(volume * volume, now);
|
|
2132
2103
|
}
|
|
2133
2104
|
}
|
|
2134
2105
|
handleMasterFineTuningSysEx(data) {
|
|
@@ -2140,7 +2111,7 @@ class MidyGM2 {
|
|
|
2140
2111
|
const next = (value - 8192) / 8.192; // cent
|
|
2141
2112
|
this.masterFineTuning = next;
|
|
2142
2113
|
channel.detune += next - prev;
|
|
2143
|
-
this.
|
|
2114
|
+
this.updateChannelDetune(channel);
|
|
2144
2115
|
}
|
|
2145
2116
|
handleMasterCoarseTuningSysEx(data) {
|
|
2146
2117
|
const coarseTuning = data[4];
|
|
@@ -2151,7 +2122,7 @@ class MidyGM2 {
|
|
|
2151
2122
|
const next = (value - 64) * 100; // cent
|
|
2152
2123
|
this.masterCoarseTuning = next;
|
|
2153
2124
|
channel.detune += next - prev;
|
|
2154
|
-
this.
|
|
2125
|
+
this.updateChannelDetune(channel);
|
|
2155
2126
|
}
|
|
2156
2127
|
handleGlobalParameterControlSysEx(data) {
|
|
2157
2128
|
if (data[7] === 1) {
|
|
@@ -2373,15 +2344,86 @@ class MidyGM2 {
|
|
|
2373
2344
|
}
|
|
2374
2345
|
}
|
|
2375
2346
|
}
|
|
2376
|
-
|
|
2347
|
+
applyDestinationSettings(channel, note, table) {
|
|
2348
|
+
if (table[0] !== 64) {
|
|
2349
|
+
this.updateDetune(channel, note, 0);
|
|
2350
|
+
}
|
|
2351
|
+
if (!note.portamento) {
|
|
2352
|
+
if (table[1] !== 64) {
|
|
2353
|
+
const channelPressure = channel.channelPressureTable[1] *
|
|
2354
|
+
channel.state.channelPressure;
|
|
2355
|
+
const pressure = (channelPressure - 64) * 15;
|
|
2356
|
+
this.setFilterEnvelope(channel, note, pressure);
|
|
2357
|
+
}
|
|
2358
|
+
if (table[2] !== 64) {
|
|
2359
|
+
const channelPressure = channel.channelPressureTable[2] *
|
|
2360
|
+
channel.state.channelPressure;
|
|
2361
|
+
const pressure = channelPressure / 64;
|
|
2362
|
+
this.setVolumeEnvelope(note, pressure);
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
if (table[3] !== 0) {
|
|
2366
|
+
const channelPressure = channel.channelPressureTable[3] *
|
|
2367
|
+
channel.state.channelPressure;
|
|
2368
|
+
const pressure = channelPressure / 127 * 600;
|
|
2369
|
+
this.setModLfoToPitch(channel, note, pressure);
|
|
2370
|
+
}
|
|
2371
|
+
if (table[4] !== 0) {
|
|
2372
|
+
const channelPressure = channel.channelPressureTable[4] *
|
|
2373
|
+
channel.state.channelPressure;
|
|
2374
|
+
const pressure = channelPressure / 127 * 2400;
|
|
2375
|
+
this.setModLfoToFilterFc(note, pressure);
|
|
2376
|
+
}
|
|
2377
|
+
if (table[5] !== 0) {
|
|
2378
|
+
const channelPressure = channel.channelPressureTable[5] *
|
|
2379
|
+
channel.state.channelPressure;
|
|
2380
|
+
const pressure = channelPressure / 127;
|
|
2381
|
+
this.setModLfoToVolume(note, pressure);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
handleChannelPressureSysEx(data, tableName) {
|
|
2377
2385
|
const channelNumber = data[4];
|
|
2378
|
-
const table = this.channels[channelNumber]
|
|
2386
|
+
const table = this.channels[channelNumber][tableName];
|
|
2379
2387
|
for (let i = 5; i < data.length - 1; i += 2) {
|
|
2380
2388
|
const pp = data[i];
|
|
2381
2389
|
const rr = data[i + 1];
|
|
2382
2390
|
table[pp] = rr;
|
|
2383
2391
|
}
|
|
2384
2392
|
}
|
|
2393
|
+
initControlTable() {
|
|
2394
|
+
const channelCount = 128;
|
|
2395
|
+
const slotSize = 6;
|
|
2396
|
+
const defaultValues = [64, 64, 64, 0, 0, 0];
|
|
2397
|
+
const table = new Uint8Array(channelCount * slotSize);
|
|
2398
|
+
for (let ch = 0; ch < channelCount; ch++) {
|
|
2399
|
+
const offset = ch * slotSize;
|
|
2400
|
+
table.set(defaultValues, offset);
|
|
2401
|
+
}
|
|
2402
|
+
return table;
|
|
2403
|
+
}
|
|
2404
|
+
applyControlTable(channel, controllerType) {
|
|
2405
|
+
const slotSize = 6;
|
|
2406
|
+
const offset = controllerType * slotSize;
|
|
2407
|
+
const table = channel.controlTable.subarray(offset, offset + slotSize);
|
|
2408
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
2409
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
2410
|
+
const note = noteList[i];
|
|
2411
|
+
if (!note)
|
|
2412
|
+
continue;
|
|
2413
|
+
this.applyDestinationSettings(channel, note, table);
|
|
2414
|
+
}
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2417
|
+
handleControlChangeSysEx(data) {
|
|
2418
|
+
const channelNumber = data[4];
|
|
2419
|
+
const controllerType = data[5];
|
|
2420
|
+
const table = this.channels[channelNumber].controlTable[controllerType];
|
|
2421
|
+
for (let i = 6; i < data.length - 1; i += 2) {
|
|
2422
|
+
const pp = data[i];
|
|
2423
|
+
const rr = data[i + 1];
|
|
2424
|
+
table[pp] = rr;
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2385
2427
|
getKeyBasedInstrumentControlValue(channel, keyNumber, controllerType) {
|
|
2386
2428
|
const index = keyNumber * 128 + controllerType;
|
|
2387
2429
|
const controlValue = channel.keyBasedInstrumentControlTable[index];
|
|
@@ -2433,7 +2475,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
2433
2475
|
currentBufferSource: null,
|
|
2434
2476
|
detune: 0,
|
|
2435
2477
|
scaleOctaveTuningTable: new Array(12).fill(0), // cent
|
|
2436
|
-
|
|
2478
|
+
channelPressureTable: new Uint8Array([64, 64, 64, 0, 0, 0]),
|
|
2437
2479
|
keyBasedInstrumentControlTable: new Int8Array(128 * 128), // [-64, 63]
|
|
2438
2480
|
program: 0,
|
|
2439
2481
|
bank: 121 * 128,
|
|
@@ -2448,16 +2490,3 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
2448
2490
|
modulationDepthRange: 50, // cent
|
|
2449
2491
|
}
|
|
2450
2492
|
});
|
|
2451
|
-
Object.defineProperty(MidyGM2, "controllerDestinationSettings", {
|
|
2452
|
-
enumerable: true,
|
|
2453
|
-
configurable: true,
|
|
2454
|
-
writable: true,
|
|
2455
|
-
value: {
|
|
2456
|
-
pitchControl: 0,
|
|
2457
|
-
filterCutoffControl: 0,
|
|
2458
|
-
amplitudeControl: 1,
|
|
2459
|
-
lfoPitchDepth: 0,
|
|
2460
|
-
lfoFilterDepth: 0,
|
|
2461
|
-
lfoAmplitudeDepth: 0,
|
|
2462
|
-
}
|
|
2463
|
-
});
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -29,12 +29,12 @@ export class MidyGMLite {
|
|
|
29
29
|
notePromises: any[];
|
|
30
30
|
exclusiveClassMap: Map<any, any>;
|
|
31
31
|
audioContext: any;
|
|
32
|
-
|
|
32
|
+
masterVolume: any;
|
|
33
33
|
voiceParamsHandlers: {
|
|
34
34
|
modLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
|
|
35
35
|
vibLfoToPitch: (_channel: any, _note: any, _prevValue: any) => void;
|
|
36
36
|
modLfoToFilterFc: (channel: any, note: any, _prevValue: any) => void;
|
|
37
|
-
modLfoToVolume: (channel: any, note: any) => void;
|
|
37
|
+
modLfoToVolume: (channel: any, note: any, _prevValue: any) => void;
|
|
38
38
|
chorusEffectsSend: (_channel: any, _note: any, _prevValue: any) => void;
|
|
39
39
|
reverbEffectsSend: (_channel: any, _note: any, _prevValue: any) => void;
|
|
40
40
|
delayModLFO: (_channel: any, note: any, _prevValue: any) => void;
|
|
@@ -94,7 +94,8 @@ export class MidyGMLite {
|
|
|
94
94
|
centToRate(cent: any): number;
|
|
95
95
|
centToHz(cent: any): number;
|
|
96
96
|
calcChannelDetune(channel: any): number;
|
|
97
|
-
|
|
97
|
+
updateChannelDetune(channel: any): void;
|
|
98
|
+
updateDetune(channel: any, note: any): void;
|
|
98
99
|
setVolumeEnvelope(note: any): void;
|
|
99
100
|
setPitchEnvelope(note: any): void;
|
|
100
101
|
clampCutoffFrequency(frequency: any): number;
|
|
@@ -120,7 +121,7 @@ export class MidyGMLite {
|
|
|
120
121
|
modLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
|
|
121
122
|
vibLfoToPitch: (_channel: any, _note: any, _prevValue: any) => void;
|
|
122
123
|
modLfoToFilterFc: (channel: any, note: any, _prevValue: any) => void;
|
|
123
|
-
modLfoToVolume: (channel: any, note: any) => void;
|
|
124
|
+
modLfoToVolume: (channel: any, note: any, _prevValue: any) => void;
|
|
124
125
|
chorusEffectsSend: (_channel: any, _note: any, _prevValue: any) => void;
|
|
125
126
|
reverbEffectsSend: (_channel: any, _note: any, _prevValue: any) => void;
|
|
126
127
|
delayModLFO: (_channel: any, note: any, _prevValue: any) => void;
|
|
@@ -163,7 +164,7 @@ export class MidyGMLite {
|
|
|
163
164
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
164
165
|
dataEntryMSB(channelNumber: any, value: any): void;
|
|
165
166
|
handlePitchBendRangeRPN(channelNumber: any): void;
|
|
166
|
-
setPitchBendRange(channelNumber: any,
|
|
167
|
+
setPitchBendRange(channelNumber: any, value: any): void;
|
|
167
168
|
allSoundOff(channelNumber: any): Promise<void>;
|
|
168
169
|
resetAllControllers(channelNumber: any): void;
|
|
169
170
|
allNotesOff(channelNumber: any): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAmFA;IAoBE;;;;;;;;;MASE;IAEF,+BAQC;IAtCD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,iCAA8B;IAc5B,kBAAgC;IAChC,
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAmFA;IAoBE;;;;;;;;;MASE;IAEF,+BAQC;IAtCD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,iCAA8B;IAc5B,kBAAgC;IAChC,kBAA8C;IAC9C;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,6DA2BC;IAED,iEAUC;IAED,2EA+CC;IAED,mCAOC;IAED,0BAkDC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgEC;IAED,+EAmBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,wCAQC;IAED,4CAKC;IAED,mCAgBC;IAED,kCAqBC;IAED,6CAIC;IAED,mCAuBC;IAED,+DAoBC;IAED,gHA2BC;IAED,kGAgDC;IAED,0EAGC;IAED,qFAwBC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,mDASC;IAED,gDASC;IAED,qCAMC;IAED,mCAQC;IAED,gCAOC;IAED,+BAMC;IAED;;;;;;;;;;;MAqBC;IAED,oFAMC;IAED,0DA6CC;IAED;;;;;;;;;;;;;MAeC;IAED,+EAWC;IAED,qCAeC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,wCAWC;IAED,sDAKC;IAED,kFAeC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA1tCD;IAQE,0FAMC;IAbD,kBAAa;IACb,gBAAW;IACX,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
|