@marmooo/midy 0.2.0 → 0.2.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/LICENSE +201 -0
- package/README.md +118 -0
- package/esm/midy-GM1.d.ts +10 -8
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +73 -66
- package/esm/midy-GM2.d.ts +17 -11
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +148 -101
- package/esm/midy-GMLite.d.ts +7 -5
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +50 -47
- package/esm/midy.d.ts +19 -13
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +233 -177
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +10 -8
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +73 -66
- package/script/midy-GM2.d.ts +17 -11
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +148 -101
- package/script/midy-GMLite.d.ts +7 -5
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +50 -47
- package/script/midy.d.ts +19 -13
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +233 -177
package/script/midy.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export class Midy {
|
|
2
2
|
static channelSettings: {
|
|
3
3
|
currentBufferSource: null;
|
|
4
|
+
detune: number;
|
|
5
|
+
scaleOctaveTuningTable: any[];
|
|
4
6
|
program: number;
|
|
5
7
|
bank: number;
|
|
6
8
|
bankMSB: number;
|
|
@@ -192,12 +194,15 @@ export class Midy {
|
|
|
192
194
|
feedbackGains: any[];
|
|
193
195
|
};
|
|
194
196
|
cbToRatio(cb: any): number;
|
|
197
|
+
rateToCent(rate: any): number;
|
|
198
|
+
centToRate(cent: any): number;
|
|
195
199
|
centToHz(cent: any): number;
|
|
196
|
-
|
|
200
|
+
calcChannelDetune(channel: any): any;
|
|
201
|
+
calcNoteDetune(channel: any, note: any): any;
|
|
202
|
+
updateDetune(channel: any): void;
|
|
197
203
|
setPortamentoStartVolumeEnvelope(channel: any, note: any): void;
|
|
198
204
|
setVolumeEnvelope(channel: any, note: any): void;
|
|
199
|
-
|
|
200
|
-
setPitch(channel: any, note: any): void;
|
|
205
|
+
setPitchEnvelope(note: any): void;
|
|
201
206
|
clampCutoffFrequency(frequency: any): number;
|
|
202
207
|
setPortamentoStartFilterEnvelope(channel: any, note: any): void;
|
|
203
208
|
setFilterEnvelope(channel: any, note: any): void;
|
|
@@ -219,11 +224,11 @@ export class Midy {
|
|
|
219
224
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
220
225
|
setPitchBend(channelNumber: any, value: any): void;
|
|
221
226
|
setModLfoToPitch(channel: any, note: any): void;
|
|
227
|
+
setVibLfoToPitch(channel: any, note: any): void;
|
|
228
|
+
setModLfoToFilterFc(note: any): void;
|
|
222
229
|
setModLfoToVolume(note: any): void;
|
|
223
230
|
setChorusEffectsSend(note: any, prevValue: any): void;
|
|
224
231
|
setReverbEffectsSend(note: any, prevValue: any): void;
|
|
225
|
-
setVibLfoToPitch(channel: any, note: any): void;
|
|
226
|
-
setModLfoToFilterFc(note: any): void;
|
|
227
232
|
setDelayModLFO(note: any): void;
|
|
228
233
|
setFreqModLFO(note: any): void;
|
|
229
234
|
createVoiceParamsHandlers(): {
|
|
@@ -293,8 +298,6 @@ export class Midy {
|
|
|
293
298
|
updateChannelVolume(channel: any): void;
|
|
294
299
|
setSustainPedal(channelNumber: any, value: any): void;
|
|
295
300
|
setPortamento(channelNumber: any, value: any): void;
|
|
296
|
-
setReverbSendLevel(channelNumber: any, reverbSendLevel: any): void;
|
|
297
|
-
setChorusSendLevel(channelNumber: any, chorusSendLevel: any): void;
|
|
298
301
|
setSostenutoPedal(channelNumber: any, value: any): void;
|
|
299
302
|
setSoftPedal(channelNumber: any, softPedal: any): void;
|
|
300
303
|
setFilterResonance(channelNumber: any, filterResonance: any): void;
|
|
@@ -305,6 +308,8 @@ export class Midy {
|
|
|
305
308
|
setVibratoRate(channelNumber: any, vibratoRate: any): void;
|
|
306
309
|
setVibratoDepth(channelNumber: any, vibratoDepth: any): void;
|
|
307
310
|
setVibratoDelay(channelNumber: any, vibratoDelay: any): void;
|
|
311
|
+
setReverbSendLevel(channelNumber: any, reverbSendLevel: any): void;
|
|
312
|
+
setChorusSendLevel(channelNumber: any, chorusSendLevel: any): void;
|
|
308
313
|
limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
|
|
309
314
|
limitDataMSB(channel: any, minMSB: any, maxMSB: any): void;
|
|
310
315
|
handleRPN(channelNumber: any, value: any): void;
|
|
@@ -313,13 +318,12 @@ export class Midy {
|
|
|
313
318
|
setRPNMSB(channelNumber: any, value: any): void;
|
|
314
319
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
315
320
|
dataEntryMSB(channelNumber: any, value: any): void;
|
|
316
|
-
updateDetune(channel: any, detune: any): void;
|
|
317
321
|
handlePitchBendRangeRPN(channelNumber: any): void;
|
|
318
|
-
setPitchBendRange(channelNumber: any,
|
|
322
|
+
setPitchBendRange(channelNumber: any, value: any): void;
|
|
319
323
|
handleFineTuningRPN(channelNumber: any): void;
|
|
320
|
-
setFineTuning(channelNumber: any,
|
|
324
|
+
setFineTuning(channelNumber: any, value: any): void;
|
|
321
325
|
handleCoarseTuningRPN(channelNumber: any): void;
|
|
322
|
-
setCoarseTuning(channelNumber: any,
|
|
326
|
+
setCoarseTuning(channelNumber: any, value: any): void;
|
|
323
327
|
handleModulationDepthRangeRPN(channelNumber: any): void;
|
|
324
328
|
setModulationDepthRange(channelNumber: any, modulationDepthRange: any): void;
|
|
325
329
|
allSoundOff(channelNumber: any): Promise<void>;
|
|
@@ -336,9 +340,11 @@ export class Midy {
|
|
|
336
340
|
handleMasterVolumeSysEx(data: any): void;
|
|
337
341
|
setMasterVolume(volume: any): void;
|
|
338
342
|
handleMasterFineTuningSysEx(data: any): void;
|
|
339
|
-
setMasterFineTuning(
|
|
343
|
+
setMasterFineTuning(value: any): void;
|
|
340
344
|
handleMasterCoarseTuningSysEx(data: any): void;
|
|
341
|
-
setMasterCoarseTuning(
|
|
345
|
+
setMasterCoarseTuning(value: any): void;
|
|
346
|
+
getChannelBitmap(data: any): any[];
|
|
347
|
+
handleScaleOctaveTuning1ByteFormat(data: any): void;
|
|
342
348
|
handleGlobalParameterControlSysEx(data: any): void;
|
|
343
349
|
handleReverbParameterSysEx(data: any): void;
|
|
344
350
|
setReverbType(type: any): void;
|
package/script/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AA8GA;IAmCE
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|
package/script/midy.js
CHANGED
|
@@ -907,16 +907,41 @@ class Midy {
|
|
|
907
907
|
cbToRatio(cb) {
|
|
908
908
|
return Math.pow(10, cb / 200);
|
|
909
909
|
}
|
|
910
|
+
rateToCent(rate) {
|
|
911
|
+
return 1200 * Math.log2(rate);
|
|
912
|
+
}
|
|
913
|
+
centToRate(cent) {
|
|
914
|
+
return Math.pow(2, cent / 1200);
|
|
915
|
+
}
|
|
910
916
|
centToHz(cent) {
|
|
911
|
-
return 8.176 *
|
|
917
|
+
return 8.176 * this.centToRate(cent);
|
|
912
918
|
}
|
|
913
|
-
|
|
919
|
+
calcChannelDetune(channel) {
|
|
914
920
|
const masterTuning = this.masterCoarseTuning + this.masterFineTuning;
|
|
915
921
|
const channelTuning = channel.coarseTuning + channel.fineTuning;
|
|
922
|
+
const tuning = masterTuning + channelTuning;
|
|
916
923
|
const pitchWheel = channel.state.pitchWheel * 2 - 1;
|
|
917
|
-
const pitchWheelSensitivity = channel.state.pitchWheelSensitivity *
|
|
924
|
+
const pitchWheelSensitivity = channel.state.pitchWheelSensitivity * 12800;
|
|
918
925
|
const pitch = pitchWheel * pitchWheelSensitivity;
|
|
919
|
-
return
|
|
926
|
+
return tuning + pitch;
|
|
927
|
+
}
|
|
928
|
+
calcNoteDetune(channel, note) {
|
|
929
|
+
return channel.scaleOctaveTuningTable[note.noteNumber % 12];
|
|
930
|
+
}
|
|
931
|
+
updateDetune(channel) {
|
|
932
|
+
const now = this.audioContext.currentTime;
|
|
933
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
934
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
935
|
+
const note = noteList[i];
|
|
936
|
+
if (!note)
|
|
937
|
+
continue;
|
|
938
|
+
const noteDetune = this.calcNoteDetune(channel, note);
|
|
939
|
+
const detune = channel.detune + noteDetune;
|
|
940
|
+
note.bufferSource.detune
|
|
941
|
+
.cancelScheduledValues(now)
|
|
942
|
+
.setValueAtTime(detune, now);
|
|
943
|
+
}
|
|
944
|
+
});
|
|
920
945
|
}
|
|
921
946
|
setPortamentoStartVolumeEnvelope(channel, note) {
|
|
922
947
|
const now = this.audioContext.currentTime;
|
|
@@ -948,32 +973,28 @@ class Midy {
|
|
|
948
973
|
.setValueAtTime(attackVolume, volHold)
|
|
949
974
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
950
975
|
}
|
|
951
|
-
|
|
976
|
+
setPitchEnvelope(note) {
|
|
952
977
|
const now = this.audioContext.currentTime;
|
|
978
|
+
const { voiceParams } = note;
|
|
979
|
+
const baseRate = voiceParams.playbackRate;
|
|
953
980
|
note.bufferSource.playbackRate
|
|
954
981
|
.cancelScheduledValues(now)
|
|
955
|
-
.setValueAtTime(
|
|
956
|
-
|
|
957
|
-
setPitch(channel, note) {
|
|
958
|
-
const now = this.audioContext.currentTime;
|
|
959
|
-
const { startTime } = note;
|
|
960
|
-
const basePitch = this.calcSemitoneOffset(channel) * 100;
|
|
961
|
-
note.bufferSource.detune
|
|
962
|
-
.cancelScheduledValues(now)
|
|
963
|
-
.setValueAtTime(basePitch, startTime);
|
|
964
|
-
const modEnvToPitch = note.voiceParams.modEnvToPitch;
|
|
982
|
+
.setValueAtTime(baseRate, now);
|
|
983
|
+
const modEnvToPitch = voiceParams.modEnvToPitch;
|
|
965
984
|
if (modEnvToPitch === 0)
|
|
966
985
|
return;
|
|
986
|
+
const basePitch = this.rateToCent(baseRate);
|
|
967
987
|
const peekPitch = basePitch + modEnvToPitch;
|
|
988
|
+
const peekRate = this.centToRate(peekPitch);
|
|
968
989
|
const modDelay = startTime + voiceParams.modDelay;
|
|
969
990
|
const modAttack = modDelay + voiceParams.modAttack;
|
|
970
991
|
const modHold = modAttack + voiceParams.modHold;
|
|
971
992
|
const modDecay = modHold + voiceParams.modDecay;
|
|
972
|
-
note.bufferSource.
|
|
973
|
-
.setValueAtTime(
|
|
974
|
-
.exponentialRampToValueAtTime(
|
|
975
|
-
.setValueAtTime(
|
|
976
|
-
.linearRampToValueAtTime(
|
|
993
|
+
note.bufferSource.playbackRate
|
|
994
|
+
.setValueAtTime(baseRate, modDelay)
|
|
995
|
+
.exponentialRampToValueAtTime(peekRate, modAttack)
|
|
996
|
+
.setValueAtTime(peekRate, modHold)
|
|
997
|
+
.linearRampToValueAtTime(baseRate, modDecay);
|
|
977
998
|
}
|
|
978
999
|
clampCutoffFrequency(frequency) {
|
|
979
1000
|
const minFrequency = 20; // min Hz of initialFilterFc
|
|
@@ -1084,9 +1105,8 @@ class Midy {
|
|
|
1084
1105
|
if (0 < state.vibratoDepth) {
|
|
1085
1106
|
this.startVibrato(channel, note, startTime);
|
|
1086
1107
|
}
|
|
1087
|
-
this.
|
|
1108
|
+
this.setPitchEnvelope(note);
|
|
1088
1109
|
if (0 < state.modulationDepth) {
|
|
1089
|
-
this.setPitch(channel, note);
|
|
1090
1110
|
this.startModulation(channel, note, startTime);
|
|
1091
1111
|
}
|
|
1092
1112
|
if (this.mono && channel.currentBufferSource) {
|
|
@@ -1220,11 +1240,12 @@ class Midy {
|
|
|
1220
1240
|
}
|
|
1221
1241
|
else {
|
|
1222
1242
|
const portamentoTime = endTime + state.portamentoTime;
|
|
1223
|
-
const
|
|
1224
|
-
const
|
|
1225
|
-
|
|
1243
|
+
const deltaNote = portamentoNoteNumber - noteNumber;
|
|
1244
|
+
const baseRate = note.voiceParams.playbackRate;
|
|
1245
|
+
const targetRate = baseRate * Math.pow(2, deltaNote / 12);
|
|
1246
|
+
note.bufferSource.playbackRate
|
|
1226
1247
|
.cancelScheduledValues(endTime)
|
|
1227
|
-
.linearRampToValueAtTime(
|
|
1248
|
+
.linearRampToValueAtTime(targetRate, portamentoTime);
|
|
1228
1249
|
return this.stopNote(endTime, portamentoTime, scheduledNotes, i);
|
|
1229
1250
|
}
|
|
1230
1251
|
}
|
|
@@ -1329,10 +1350,11 @@ class Midy {
|
|
|
1329
1350
|
setPitchBend(channelNumber, value) {
|
|
1330
1351
|
const channel = this.channels[channelNumber];
|
|
1331
1352
|
const state = channel.state;
|
|
1353
|
+
const prev = state.pitchWheel * 2 - 1;
|
|
1354
|
+
const next = (value - 8192) / 8192;
|
|
1332
1355
|
state.pitchWheel = value / 16383;
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
this.updateDetune(channel, detuneChange);
|
|
1356
|
+
channel.detune += (next - prev) * state.pitchWheelSensitivity * 12800;
|
|
1357
|
+
this.updateDetune(channel);
|
|
1336
1358
|
this.applyVoiceParams(channel, 14);
|
|
1337
1359
|
}
|
|
1338
1360
|
setModLfoToPitch(channel, note) {
|
|
@@ -1345,6 +1367,23 @@ class Midy {
|
|
|
1345
1367
|
.cancelScheduledValues(now)
|
|
1346
1368
|
.setValueAtTime(modulationDepth * modulationDepthSign, now);
|
|
1347
1369
|
}
|
|
1370
|
+
setVibLfoToPitch(channel, note) {
|
|
1371
|
+
const now = this.audioContext.currentTime;
|
|
1372
|
+
const vibLfoToPitch = note.voiceParams.vibLfoToPitch;
|
|
1373
|
+
const vibratoDepth = Math.abs(vibLfoToPitch) * channel.state.vibratoDepth *
|
|
1374
|
+
2;
|
|
1375
|
+
const vibratoDepthSign = 0 < vibLfoToPitch;
|
|
1376
|
+
note.vibratoDepth.gain
|
|
1377
|
+
.cancelScheduledValues(now)
|
|
1378
|
+
.setValueAtTime(vibratoDepth * vibratoDepthSign, now);
|
|
1379
|
+
}
|
|
1380
|
+
setModLfoToFilterFc(note) {
|
|
1381
|
+
const now = this.audioContext.currentTime;
|
|
1382
|
+
const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc;
|
|
1383
|
+
note.filterDepth.gain
|
|
1384
|
+
.cancelScheduledValues(now)
|
|
1385
|
+
.setValueAtTime(modLfoToFilterFc, now);
|
|
1386
|
+
}
|
|
1348
1387
|
setModLfoToVolume(note) {
|
|
1349
1388
|
const now = this.audioContext.currentTime;
|
|
1350
1389
|
const modLfoToVolume = note.voiceParams.modLfoToVolume;
|
|
@@ -1404,23 +1443,6 @@ class Midy {
|
|
|
1404
1443
|
}
|
|
1405
1444
|
}
|
|
1406
1445
|
}
|
|
1407
|
-
setVibLfoToPitch(channel, note) {
|
|
1408
|
-
const now = this.audioContext.currentTime;
|
|
1409
|
-
const vibLfoToPitch = note.voiceParams.vibLfoToPitch;
|
|
1410
|
-
const vibratoDepth = Math.abs(vibLfoToPitch) * channel.state.vibratoDepth *
|
|
1411
|
-
2;
|
|
1412
|
-
const vibratoDepthSign = 0 < vibLfoToPitch;
|
|
1413
|
-
note.vibratoDepth.gain
|
|
1414
|
-
.cancelScheduledValues(now)
|
|
1415
|
-
.setValueAtTime(vibratoDepth * vibratoDepthSign, now);
|
|
1416
|
-
}
|
|
1417
|
-
setModLfoToFilterFc(note) {
|
|
1418
|
-
const now = this.audioContext.currentTime;
|
|
1419
|
-
const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc;
|
|
1420
|
-
note.filterDepth.gain
|
|
1421
|
-
.cancelScheduledValues(now)
|
|
1422
|
-
.setValueAtTime(modLfoToFilterFc, now);
|
|
1423
|
-
}
|
|
1424
1446
|
setDelayModLFO(note) {
|
|
1425
1447
|
const now = this.audioContext.currentTime;
|
|
1426
1448
|
const startTime = note.startTime;
|
|
@@ -1529,7 +1551,7 @@ class Midy {
|
|
|
1529
1551
|
else {
|
|
1530
1552
|
this.setFilterEnvelope(channel, note);
|
|
1531
1553
|
}
|
|
1532
|
-
this.
|
|
1554
|
+
this.setPitchEnvelope(note);
|
|
1533
1555
|
}
|
|
1534
1556
|
else if (volumeEnvelopeKeySet.has(key)) {
|
|
1535
1557
|
if (appliedVolumeEnvelope)
|
|
@@ -1611,7 +1633,7 @@ class Midy {
|
|
|
1611
1633
|
note.modulationDepth.gain.setValueAtTime(channel.state.modulationDepth, now);
|
|
1612
1634
|
}
|
|
1613
1635
|
else {
|
|
1614
|
-
this.
|
|
1636
|
+
this.setPitchEnvelope(note);
|
|
1615
1637
|
this.startModulation(channel, note, now);
|
|
1616
1638
|
}
|
|
1617
1639
|
}
|
|
@@ -1678,88 +1700,6 @@ class Midy {
|
|
|
1678
1700
|
setPortamento(channelNumber, value) {
|
|
1679
1701
|
this.channels[channelNumber].state.portamento = value / 127;
|
|
1680
1702
|
}
|
|
1681
|
-
setReverbSendLevel(channelNumber, reverbSendLevel) {
|
|
1682
|
-
const channel = this.channels[channelNumber];
|
|
1683
|
-
const state = channel.state;
|
|
1684
|
-
const reverbEffect = this.reverbEffect;
|
|
1685
|
-
if (0 < state.reverbSendLevel) {
|
|
1686
|
-
if (0 < reverbSendLevel) {
|
|
1687
|
-
const now = this.audioContext.currentTime;
|
|
1688
|
-
state.reverbSendLevel = reverbSendLevel / 127;
|
|
1689
|
-
reverbEffect.input.gain.cancelScheduledValues(now);
|
|
1690
|
-
reverbEffect.input.gain.setValueAtTime(state.reverbSendLevel, now);
|
|
1691
|
-
}
|
|
1692
|
-
else {
|
|
1693
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1694
|
-
for (let i = 0; i < noteList.length; i++) {
|
|
1695
|
-
const note = noteList[i];
|
|
1696
|
-
if (!note)
|
|
1697
|
-
continue;
|
|
1698
|
-
if (note.voiceParams.reverbEffectsSend <= 0)
|
|
1699
|
-
continue;
|
|
1700
|
-
note.reverbEffectsSend.disconnect();
|
|
1701
|
-
}
|
|
1702
|
-
});
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
else {
|
|
1706
|
-
if (0 < reverbSendLevel) {
|
|
1707
|
-
const now = this.audioContext.currentTime;
|
|
1708
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1709
|
-
for (let i = 0; i < noteList.length; i++) {
|
|
1710
|
-
const note = noteList[i];
|
|
1711
|
-
if (!note)
|
|
1712
|
-
continue;
|
|
1713
|
-
this.setReverbEffectsSend(note, 0);
|
|
1714
|
-
}
|
|
1715
|
-
});
|
|
1716
|
-
state.reverbSendLevel = reverbSendLevel / 127;
|
|
1717
|
-
reverbEffect.input.gain.cancelScheduledValues(now);
|
|
1718
|
-
reverbEffect.input.gain.setValueAtTime(state.reverbSendLevel, now);
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
setChorusSendLevel(channelNumber, chorusSendLevel) {
|
|
1723
|
-
const channel = this.channels[channelNumber];
|
|
1724
|
-
const state = channel.state;
|
|
1725
|
-
const chorusEffect = this.chorusEffect;
|
|
1726
|
-
if (0 < state.chorusSendLevel) {
|
|
1727
|
-
if (0 < chorusSendLevel) {
|
|
1728
|
-
const now = this.audioContext.currentTime;
|
|
1729
|
-
state.chorusSendLevel = chorusSendLevel / 127;
|
|
1730
|
-
chorusEffect.input.gain.cancelScheduledValues(now);
|
|
1731
|
-
chorusEffect.input.gain.setValueAtTime(state.chorusSendLevel, now);
|
|
1732
|
-
}
|
|
1733
|
-
else {
|
|
1734
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1735
|
-
for (let i = 0; i < noteList.length; i++) {
|
|
1736
|
-
const note = noteList[i];
|
|
1737
|
-
if (!note)
|
|
1738
|
-
continue;
|
|
1739
|
-
if (note.voiceParams.chorusEffectsSend <= 0)
|
|
1740
|
-
continue;
|
|
1741
|
-
note.chorusEffectsSend.disconnect();
|
|
1742
|
-
}
|
|
1743
|
-
});
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
else {
|
|
1747
|
-
if (0 < chorusSendLevel) {
|
|
1748
|
-
const now = this.audioContext.currentTime;
|
|
1749
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1750
|
-
for (let i = 0; i < noteList.length; i++) {
|
|
1751
|
-
const note = noteList[i];
|
|
1752
|
-
if (!note)
|
|
1753
|
-
continue;
|
|
1754
|
-
this.setChorusEffectsSend(note, 0);
|
|
1755
|
-
}
|
|
1756
|
-
});
|
|
1757
|
-
state.chorusSendLevel = chorusSendLevel / 127;
|
|
1758
|
-
chorusEffect.input.gain.cancelScheduledValues(now);
|
|
1759
|
-
chorusEffect.input.gain.setValueAtTime(state.chorusSendLevel, now);
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
1703
|
setSostenutoPedal(channelNumber, value) {
|
|
1764
1704
|
const channel = this.channels[channelNumber];
|
|
1765
1705
|
channel.state.sostenutoPedal = value / 127;
|
|
@@ -1855,6 +1795,88 @@ class Midy {
|
|
|
1855
1795
|
const channel = this.channels[channelNumber];
|
|
1856
1796
|
channel.state.vibratoDelay = vibratoDelay / 64;
|
|
1857
1797
|
}
|
|
1798
|
+
setReverbSendLevel(channelNumber, reverbSendLevel) {
|
|
1799
|
+
const channel = this.channels[channelNumber];
|
|
1800
|
+
const state = channel.state;
|
|
1801
|
+
const reverbEffect = this.reverbEffect;
|
|
1802
|
+
if (0 < state.reverbSendLevel) {
|
|
1803
|
+
if (0 < reverbSendLevel) {
|
|
1804
|
+
const now = this.audioContext.currentTime;
|
|
1805
|
+
state.reverbSendLevel = reverbSendLevel / 127;
|
|
1806
|
+
reverbEffect.input.gain.cancelScheduledValues(now);
|
|
1807
|
+
reverbEffect.input.gain.setValueAtTime(state.reverbSendLevel, now);
|
|
1808
|
+
}
|
|
1809
|
+
else {
|
|
1810
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1811
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1812
|
+
const note = noteList[i];
|
|
1813
|
+
if (!note)
|
|
1814
|
+
continue;
|
|
1815
|
+
if (note.voiceParams.reverbEffectsSend <= 0)
|
|
1816
|
+
continue;
|
|
1817
|
+
note.reverbEffectsSend.disconnect();
|
|
1818
|
+
}
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
else {
|
|
1823
|
+
if (0 < reverbSendLevel) {
|
|
1824
|
+
const now = this.audioContext.currentTime;
|
|
1825
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1826
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1827
|
+
const note = noteList[i];
|
|
1828
|
+
if (!note)
|
|
1829
|
+
continue;
|
|
1830
|
+
this.setReverbEffectsSend(note, 0);
|
|
1831
|
+
}
|
|
1832
|
+
});
|
|
1833
|
+
state.reverbSendLevel = reverbSendLevel / 127;
|
|
1834
|
+
reverbEffect.input.gain.cancelScheduledValues(now);
|
|
1835
|
+
reverbEffect.input.gain.setValueAtTime(state.reverbSendLevel, now);
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
setChorusSendLevel(channelNumber, chorusSendLevel) {
|
|
1840
|
+
const channel = this.channels[channelNumber];
|
|
1841
|
+
const state = channel.state;
|
|
1842
|
+
const chorusEffect = this.chorusEffect;
|
|
1843
|
+
if (0 < state.chorusSendLevel) {
|
|
1844
|
+
if (0 < chorusSendLevel) {
|
|
1845
|
+
const now = this.audioContext.currentTime;
|
|
1846
|
+
state.chorusSendLevel = chorusSendLevel / 127;
|
|
1847
|
+
chorusEffect.input.gain.cancelScheduledValues(now);
|
|
1848
|
+
chorusEffect.input.gain.setValueAtTime(state.chorusSendLevel, now);
|
|
1849
|
+
}
|
|
1850
|
+
else {
|
|
1851
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1852
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1853
|
+
const note = noteList[i];
|
|
1854
|
+
if (!note)
|
|
1855
|
+
continue;
|
|
1856
|
+
if (note.voiceParams.chorusEffectsSend <= 0)
|
|
1857
|
+
continue;
|
|
1858
|
+
note.chorusEffectsSend.disconnect();
|
|
1859
|
+
}
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
else {
|
|
1864
|
+
if (0 < chorusSendLevel) {
|
|
1865
|
+
const now = this.audioContext.currentTime;
|
|
1866
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1867
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1868
|
+
const note = noteList[i];
|
|
1869
|
+
if (!note)
|
|
1870
|
+
continue;
|
|
1871
|
+
this.setChorusEffectsSend(note, 0);
|
|
1872
|
+
}
|
|
1873
|
+
});
|
|
1874
|
+
state.chorusSendLevel = chorusSendLevel / 127;
|
|
1875
|
+
chorusEffect.input.gain.cancelScheduledValues(now);
|
|
1876
|
+
chorusEffect.input.gain.setValueAtTime(state.chorusSendLevel, now);
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1858
1880
|
limitData(channel, minMSB, maxMSB, minLSB, maxLSB) {
|
|
1859
1881
|
if (maxLSB < channel.dataLSB) {
|
|
1860
1882
|
channel.dataMSB++;
|
|
@@ -1923,59 +1945,49 @@ class Midy {
|
|
|
1923
1945
|
this.channels[channelNumber].dataMSB = value;
|
|
1924
1946
|
this.handleRPN(channelNumber, 0);
|
|
1925
1947
|
}
|
|
1926
|
-
updateDetune(channel, detune) {
|
|
1927
|
-
const now = this.audioContext.currentTime;
|
|
1928
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1929
|
-
for (let i = 0; i < noteList.length; i++) {
|
|
1930
|
-
const note = noteList[i];
|
|
1931
|
-
if (!note)
|
|
1932
|
-
continue;
|
|
1933
|
-
const { bufferSource } = note;
|
|
1934
|
-
bufferSource.detune
|
|
1935
|
-
.cancelScheduledValues(now)
|
|
1936
|
-
.setValueAtTime(detune, now);
|
|
1937
|
-
}
|
|
1938
|
-
});
|
|
1939
|
-
}
|
|
1940
1948
|
handlePitchBendRangeRPN(channelNumber) {
|
|
1941
1949
|
const channel = this.channels[channelNumber];
|
|
1942
1950
|
this.limitData(channel, 0, 127, 0, 99);
|
|
1943
1951
|
const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
|
|
1944
1952
|
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
1945
1953
|
}
|
|
1946
|
-
setPitchBendRange(channelNumber,
|
|
1954
|
+
setPitchBendRange(channelNumber, value) {
|
|
1947
1955
|
const channel = this.channels[channelNumber];
|
|
1948
1956
|
const state = channel.state;
|
|
1949
|
-
|
|
1950
|
-
const
|
|
1951
|
-
|
|
1957
|
+
const prev = state.pitchWheelSensitivity;
|
|
1958
|
+
const next = value / 128;
|
|
1959
|
+
state.pitchWheelSensitivity = next;
|
|
1960
|
+
channel.detune += (state.pitchWheel * 2 - 1) * (next - prev) * 12800;
|
|
1961
|
+
this.updateDetune(channel);
|
|
1952
1962
|
this.applyVoiceParams(channel, 16);
|
|
1953
1963
|
}
|
|
1954
1964
|
handleFineTuningRPN(channelNumber) {
|
|
1955
1965
|
const channel = this.channels[channelNumber];
|
|
1956
1966
|
this.limitData(channel, 0, 127, 0, 127);
|
|
1957
|
-
const fineTuning =
|
|
1967
|
+
const fineTuning = channel.dataMSB * 128 + channel.dataLSB;
|
|
1958
1968
|
this.setFineTuning(channelNumber, fineTuning);
|
|
1959
1969
|
}
|
|
1960
|
-
setFineTuning(channelNumber,
|
|
1970
|
+
setFineTuning(channelNumber, value) {
|
|
1961
1971
|
const channel = this.channels[channelNumber];
|
|
1962
|
-
const
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1972
|
+
const prev = channel.fineTuning;
|
|
1973
|
+
const next = (value - 8192) / 8.192; // cent
|
|
1974
|
+
channel.fineTuning = next;
|
|
1975
|
+
channel.detune += next - prev;
|
|
1976
|
+
this.updateDetune(channel);
|
|
1966
1977
|
}
|
|
1967
1978
|
handleCoarseTuningRPN(channelNumber) {
|
|
1968
1979
|
const channel = this.channels[channelNumber];
|
|
1969
1980
|
this.limitDataMSB(channel, 0, 127);
|
|
1970
|
-
const coarseTuning = channel.dataMSB
|
|
1971
|
-
this.
|
|
1981
|
+
const coarseTuning = channel.dataMSB;
|
|
1982
|
+
this.setCoarseTuning(channelNumber, coarseTuning);
|
|
1972
1983
|
}
|
|
1973
|
-
setCoarseTuning(channelNumber,
|
|
1984
|
+
setCoarseTuning(channelNumber, value) {
|
|
1974
1985
|
const channel = this.channels[channelNumber];
|
|
1975
|
-
const
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1986
|
+
const prev = channel.coarseTuning;
|
|
1987
|
+
const next = (value - 64) * 100; // cent
|
|
1988
|
+
channel.coarseTuning = next;
|
|
1989
|
+
channel.detune += next - prev;
|
|
1990
|
+
this.updateDetune(channel);
|
|
1979
1991
|
}
|
|
1980
1992
|
handleModulationDepthRangeRPN(channelNumber) {
|
|
1981
1993
|
const channel = this.channels[channelNumber];
|
|
@@ -2035,6 +2047,15 @@ class Midy {
|
|
|
2035
2047
|
}
|
|
2036
2048
|
handleUniversalNonRealTimeExclusiveMessage(data) {
|
|
2037
2049
|
switch (data[2]) {
|
|
2050
|
+
case 8:
|
|
2051
|
+
switch (data[3]) {
|
|
2052
|
+
case 8:
|
|
2053
|
+
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca21.pdf
|
|
2054
|
+
return this.handleScaleOctaveTuning1ByteFormat(data);
|
|
2055
|
+
default:
|
|
2056
|
+
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
2057
|
+
}
|
|
2058
|
+
break;
|
|
2038
2059
|
case 9:
|
|
2039
2060
|
switch (data[3]) {
|
|
2040
2061
|
case 1:
|
|
@@ -2091,9 +2112,10 @@ class Midy {
|
|
|
2091
2112
|
break;
|
|
2092
2113
|
case 8:
|
|
2093
2114
|
switch (data[3]) {
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2115
|
+
case 8:
|
|
2116
|
+
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca21.pdf
|
|
2117
|
+
// TODO: realtime
|
|
2118
|
+
return this.handleScaleOctaveTuning1ByteFormat(data);
|
|
2097
2119
|
default:
|
|
2098
2120
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
2099
2121
|
}
|
|
@@ -2138,27 +2160,59 @@ class Midy {
|
|
|
2138
2160
|
}
|
|
2139
2161
|
}
|
|
2140
2162
|
handleMasterFineTuningSysEx(data) {
|
|
2141
|
-
const fineTuning =
|
|
2163
|
+
const fineTuning = data[5] * 128 + data[4];
|
|
2142
2164
|
this.setMasterFineTuning(fineTuning);
|
|
2143
2165
|
}
|
|
2144
|
-
setMasterFineTuning(
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
}
|
|
2166
|
+
setMasterFineTuning(value) {
|
|
2167
|
+
const prev = this.masterFineTuning;
|
|
2168
|
+
const next = (value - 8192) / 8.192; // cent
|
|
2169
|
+
this.masterFineTuning = next;
|
|
2170
|
+
channel.detune += next - prev;
|
|
2171
|
+
this.updateDetune(channel);
|
|
2151
2172
|
}
|
|
2152
2173
|
handleMasterCoarseTuningSysEx(data) {
|
|
2153
2174
|
const coarseTuning = data[4];
|
|
2154
2175
|
this.setMasterCoarseTuning(coarseTuning);
|
|
2155
2176
|
}
|
|
2156
|
-
setMasterCoarseTuning(
|
|
2157
|
-
|
|
2158
|
-
|
|
2177
|
+
setMasterCoarseTuning(value) {
|
|
2178
|
+
const prev = this.masterCoarseTuning;
|
|
2179
|
+
const next = (value - 64) * 100; // cent
|
|
2180
|
+
this.masterCoarseTuning = next;
|
|
2181
|
+
channel.detune += next - prev;
|
|
2182
|
+
this.updateDetune(channel);
|
|
2183
|
+
}
|
|
2184
|
+
getChannelBitmap(data) {
|
|
2185
|
+
const bitmap = new Array(16).fill(false);
|
|
2186
|
+
const ff = data[4] & 0b11;
|
|
2187
|
+
const gg = data[5] & 0x7F;
|
|
2188
|
+
const hh = data[6] & 0x7F;
|
|
2189
|
+
for (let bit = 0; bit < 7; bit++) {
|
|
2190
|
+
if (hh & (1 << bit))
|
|
2191
|
+
bitmap[bit] = true;
|
|
2192
|
+
}
|
|
2193
|
+
for (let bit = 0; bit < 7; bit++) {
|
|
2194
|
+
if (gg & (1 << bit))
|
|
2195
|
+
bitmap[bit + 7] = true;
|
|
2196
|
+
}
|
|
2197
|
+
for (let bit = 0; bit < 2; bit++) {
|
|
2198
|
+
if (ff & (1 << bit))
|
|
2199
|
+
bitmap[bit + 14] = true;
|
|
2200
|
+
}
|
|
2201
|
+
return bitmap;
|
|
2202
|
+
}
|
|
2203
|
+
handleScaleOctaveTuning1ByteFormat(data) {
|
|
2204
|
+
if (data.length < 18) {
|
|
2205
|
+
console.error("Data length is too short");
|
|
2206
|
+
return;
|
|
2159
2207
|
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2208
|
+
const channelBitmap = this.getChannelBitmap(data);
|
|
2209
|
+
for (let i = 0; i < channelBitmap.length; i++) {
|
|
2210
|
+
if (!channelBitmap[i])
|
|
2211
|
+
continue;
|
|
2212
|
+
for (let j = 0; j < 12; j++) {
|
|
2213
|
+
const value = data[j + 7] - 64; // cent
|
|
2214
|
+
this.channels[i].scaleOctaveTuningTable[j] = value;
|
|
2215
|
+
}
|
|
2162
2216
|
}
|
|
2163
2217
|
}
|
|
2164
2218
|
handleGlobalParameterControlSysEx(data) {
|
|
@@ -2379,6 +2433,8 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
2379
2433
|
writable: true,
|
|
2380
2434
|
value: {
|
|
2381
2435
|
currentBufferSource: null,
|
|
2436
|
+
detune: 0,
|
|
2437
|
+
scaleOctaveTuningTable: new Array(12).fill(0), // cent
|
|
2382
2438
|
program: 0,
|
|
2383
2439
|
bank: 121 * 128,
|
|
2384
2440
|
bankMSB: 121,
|