@marmooo/midy 0.2.2 → 0.2.3
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 +3 -3
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +17 -14
- package/esm/midy-GM2.d.ts +7 -3
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +87 -28
- package/esm/midy-GMLite.d.ts +3 -3
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +11 -9
- package/esm/midy.d.ts +7 -4
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +80 -43
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +3 -3
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +17 -14
- package/script/midy-GM2.d.ts +7 -3
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +87 -28
- package/script/midy-GMLite.d.ts +3 -3
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +11 -9
- package/script/midy.d.ts +7 -4
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +80 -43
package/script/midy-GM2.js
CHANGED
|
@@ -362,15 +362,15 @@ class MidyGM2 {
|
|
|
362
362
|
});
|
|
363
363
|
this.audioContext = audioContext;
|
|
364
364
|
this.options = { ...this.defaultOptions, ...options };
|
|
365
|
-
this.
|
|
365
|
+
this.masterVolume = new GainNode(audioContext);
|
|
366
366
|
this.voiceParamsHandlers = this.createVoiceParamsHandlers();
|
|
367
367
|
this.controlChangeHandlers = this.createControlChangeHandlers();
|
|
368
368
|
this.channels = this.createChannels(audioContext);
|
|
369
369
|
this.reverbEffect = this.options.reverbAlgorithm(audioContext);
|
|
370
370
|
this.chorusEffect = this.createChorusEffect(audioContext);
|
|
371
|
-
this.chorusEffect.output.connect(this.
|
|
372
|
-
this.reverbEffect.output.connect(this.
|
|
373
|
-
this.
|
|
371
|
+
this.chorusEffect.output.connect(this.masterVolume);
|
|
372
|
+
this.reverbEffect.output.connect(this.masterVolume);
|
|
373
|
+
this.masterVolume.connect(audioContext.destination);
|
|
374
374
|
this.GM2SystemOn();
|
|
375
375
|
}
|
|
376
376
|
initSoundFontTable() {
|
|
@@ -416,7 +416,7 @@ class MidyGM2 {
|
|
|
416
416
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
417
417
|
gainL.connect(merger, 0, 0);
|
|
418
418
|
gainR.connect(merger, 0, 1);
|
|
419
|
-
merger.connect(this.
|
|
419
|
+
merger.connect(this.masterVolume);
|
|
420
420
|
return {
|
|
421
421
|
gainL,
|
|
422
422
|
gainR,
|
|
@@ -428,6 +428,7 @@ class MidyGM2 {
|
|
|
428
428
|
return {
|
|
429
429
|
...this.constructor.channelSettings,
|
|
430
430
|
state: new ControllerState(),
|
|
431
|
+
controlTable: this.initControlTable(),
|
|
431
432
|
...this.setChannelAudioNodes(audioContext),
|
|
432
433
|
scheduledNotes: new Map(),
|
|
433
434
|
sostenutoNotes: new Map(),
|
|
@@ -1350,12 +1351,13 @@ class MidyGM2 {
|
|
|
1350
1351
|
const pressureDepth = (channel.pressureTable[0] - 64) / 37.5; // 2400 / 64;
|
|
1351
1352
|
channel.detune += pressureDepth * (next - prev);
|
|
1352
1353
|
}
|
|
1354
|
+
const table = channel.pressureTable;
|
|
1353
1355
|
channel.scheduledNotes.forEach((noteList) => {
|
|
1354
1356
|
for (let i = 0; i < noteList.length; i++) {
|
|
1355
1357
|
const note = noteList[i];
|
|
1356
1358
|
if (!note)
|
|
1357
1359
|
continue;
|
|
1358
|
-
this.
|
|
1360
|
+
this.applyDestinationSettings(channel, note, table);
|
|
1359
1361
|
}
|
|
1360
1362
|
});
|
|
1361
1363
|
// this.applyVoiceParams(channel, 13);
|
|
@@ -1364,11 +1366,13 @@ class MidyGM2 {
|
|
|
1364
1366
|
if (channel.pressureTable[0] !== 64) {
|
|
1365
1367
|
this.updateDetune(channel);
|
|
1366
1368
|
}
|
|
1367
|
-
if (
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1369
|
+
if (!note.portamento) {
|
|
1370
|
+
if (channel.pressureTable[1] !== 64) {
|
|
1371
|
+
this.setFilterEnvelope(channel, note);
|
|
1372
|
+
}
|
|
1373
|
+
if (channel.pressureTable[2] !== 64) {
|
|
1374
|
+
this.setVolumeEnvelope(channel, note);
|
|
1375
|
+
}
|
|
1372
1376
|
}
|
|
1373
1377
|
if (channel.pressureTable[3] !== 0) {
|
|
1374
1378
|
this.setModLfoToPitch(channel, note);
|
|
@@ -1521,7 +1525,7 @@ class MidyGM2 {
|
|
|
1521
1525
|
this.setModLfoToFilterFc(channel, note);
|
|
1522
1526
|
}
|
|
1523
1527
|
},
|
|
1524
|
-
modLfoToVolume: (channel, note) => {
|
|
1528
|
+
modLfoToVolume: (channel, note, _prevValue) => {
|
|
1525
1529
|
if (0 < channel.state.modulationDepth) {
|
|
1526
1530
|
this.setModLfoToVolume(channel, note);
|
|
1527
1531
|
}
|
|
@@ -1537,12 +1541,12 @@ class MidyGM2 {
|
|
|
1537
1541
|
delayVibLFO: (channel, note, prevValue) => {
|
|
1538
1542
|
if (0 < channel.state.vibratoDepth) {
|
|
1539
1543
|
const now = this.audioContext.currentTime;
|
|
1540
|
-
const
|
|
1541
|
-
|
|
1544
|
+
const vibratoDelay = channel.state.vibratoDelay * 2;
|
|
1545
|
+
const prevStartTime = note.startTime + prevValue * vibratoDelay;
|
|
1542
1546
|
if (now < prevStartTime)
|
|
1543
1547
|
return;
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1548
|
+
const value = note.voiceParams.delayVibLFO;
|
|
1549
|
+
const startTime = note.startTime + value * vibratoDelay;
|
|
1546
1550
|
note.vibratoLFO.stop(now);
|
|
1547
1551
|
note.vibratoLFO.start(startTime);
|
|
1548
1552
|
}
|
|
@@ -1550,9 +1554,10 @@ class MidyGM2 {
|
|
|
1550
1554
|
freqVibLFO: (channel, note, _prevValue) => {
|
|
1551
1555
|
if (0 < channel.state.vibratoDepth) {
|
|
1552
1556
|
const now = this.audioContext.currentTime;
|
|
1557
|
+
const freqVibLFO = note.voiceParams.freqVibLFO;
|
|
1553
1558
|
note.vibratoLFO.frequency
|
|
1554
1559
|
.cancelScheduledValues(now)
|
|
1555
|
-
.setValueAtTime(
|
|
1560
|
+
.setValueAtTime(freqVibLFO * channel.state.vibratoRate, now);
|
|
1556
1561
|
}
|
|
1557
1562
|
},
|
|
1558
1563
|
};
|
|
@@ -1649,8 +1654,8 @@ class MidyGM2 {
|
|
|
1649
1654
|
if (handler) {
|
|
1650
1655
|
handler.call(this, channelNumber, value);
|
|
1651
1656
|
const channel = this.channels[channelNumber];
|
|
1652
|
-
|
|
1653
|
-
this.
|
|
1657
|
+
this.applyVoiceParams(channel, controller + 128);
|
|
1658
|
+
this.applyControlTable(channel, controllerType);
|
|
1654
1659
|
}
|
|
1655
1660
|
else {
|
|
1656
1661
|
console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
|
|
@@ -1661,13 +1666,14 @@ class MidyGM2 {
|
|
|
1661
1666
|
}
|
|
1662
1667
|
updateModulation(channel) {
|
|
1663
1668
|
const now = this.audioContext.currentTime;
|
|
1669
|
+
const depth = channel.state.modulationDepth * channel.modulationDepthRange;
|
|
1664
1670
|
channel.scheduledNotes.forEach((noteList) => {
|
|
1665
1671
|
for (let i = 0; i < noteList.length; i++) {
|
|
1666
1672
|
const note = noteList[i];
|
|
1667
1673
|
if (!note)
|
|
1668
1674
|
continue;
|
|
1669
1675
|
if (note.modulationDepth) {
|
|
1670
|
-
note.modulationDepth.gain.setValueAtTime(
|
|
1676
|
+
note.modulationDepth.gain.setValueAtTime(depth, now);
|
|
1671
1677
|
}
|
|
1672
1678
|
else {
|
|
1673
1679
|
this.setPitchEnvelope(note);
|
|
@@ -1678,8 +1684,7 @@ class MidyGM2 {
|
|
|
1678
1684
|
}
|
|
1679
1685
|
setModulationDepth(channelNumber, modulation) {
|
|
1680
1686
|
const channel = this.channels[channelNumber];
|
|
1681
|
-
channel.state.modulationDepth =
|
|
1682
|
-
channel.modulationDepthRange;
|
|
1687
|
+
channel.state.modulationDepth = modulation / 127;
|
|
1683
1688
|
this.updateModulation(channel);
|
|
1684
1689
|
}
|
|
1685
1690
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
@@ -1982,7 +1987,6 @@ class MidyGM2 {
|
|
|
1982
1987
|
setModulationDepthRange(channelNumber, modulationDepthRange) {
|
|
1983
1988
|
const channel = this.channels[channelNumber];
|
|
1984
1989
|
channel.modulationDepthRange = modulationDepthRange;
|
|
1985
|
-
channel.modulationDepth = (modulation / 127) * modulationDepthRange;
|
|
1986
1990
|
this.updateModulation(channel);
|
|
1987
1991
|
}
|
|
1988
1992
|
allSoundOff(channelNumber) {
|
|
@@ -2098,9 +2102,8 @@ class MidyGM2 {
|
|
|
2098
2102
|
switch (data[3]) {
|
|
2099
2103
|
case 1: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca22.pdf
|
|
2100
2104
|
return this.handleChannelPressureSysEx(data);
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
// return this.setControlChange();
|
|
2105
|
+
case 3: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca22.pdf
|
|
2106
|
+
return this.handleControlChangeSysEx(data);
|
|
2104
2107
|
default:
|
|
2105
2108
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
2106
2109
|
}
|
|
@@ -2127,8 +2130,8 @@ class MidyGM2 {
|
|
|
2127
2130
|
}
|
|
2128
2131
|
else {
|
|
2129
2132
|
const now = this.audioContext.currentTime;
|
|
2130
|
-
this.
|
|
2131
|
-
this.
|
|
2133
|
+
this.masterVolume.gain.cancelScheduledValues(now);
|
|
2134
|
+
this.masterVolume.gain.setValueAtTime(volume * volume, now);
|
|
2132
2135
|
}
|
|
2133
2136
|
}
|
|
2134
2137
|
handleMasterFineTuningSysEx(data) {
|
|
@@ -2373,6 +2376,28 @@ class MidyGM2 {
|
|
|
2373
2376
|
}
|
|
2374
2377
|
}
|
|
2375
2378
|
}
|
|
2379
|
+
applyDestinationSettings(channel, note, table) {
|
|
2380
|
+
if (table[0] !== 64) {
|
|
2381
|
+
this.updateDetune(channel);
|
|
2382
|
+
}
|
|
2383
|
+
if (!note.portamento) {
|
|
2384
|
+
if (table[1] !== 64) {
|
|
2385
|
+
this.setFilterEnvelope(channel, note);
|
|
2386
|
+
}
|
|
2387
|
+
if (table[2] !== 64) {
|
|
2388
|
+
this.setVolumeEnvelope(channel, note);
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
if (table[3] !== 0) {
|
|
2392
|
+
this.setModLfoToPitch(channel, note);
|
|
2393
|
+
}
|
|
2394
|
+
if (table[4] !== 0) {
|
|
2395
|
+
this.setModLfoToFilterFc(channel, note);
|
|
2396
|
+
}
|
|
2397
|
+
if (table[5] !== 0) {
|
|
2398
|
+
this.setModLfoToVolume(channel, note);
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2376
2401
|
handleChannelPressureSysEx(data) {
|
|
2377
2402
|
const channelNumber = data[4];
|
|
2378
2403
|
const table = this.channels[channelNumber].pressureTable;
|
|
@@ -2382,6 +2407,40 @@ class MidyGM2 {
|
|
|
2382
2407
|
table[pp] = rr;
|
|
2383
2408
|
}
|
|
2384
2409
|
}
|
|
2410
|
+
initControlTable() {
|
|
2411
|
+
const channelCount = 128;
|
|
2412
|
+
const slotSize = 6;
|
|
2413
|
+
const defaultValues = [64, 64, 64, 0, 0, 0];
|
|
2414
|
+
const table = new Uint8Array(channelCount * slotSize);
|
|
2415
|
+
for (let ch = 0; ch < channelCount; ch++) {
|
|
2416
|
+
const offset = ch * slotSize;
|
|
2417
|
+
table.set(defaultValues, offset);
|
|
2418
|
+
}
|
|
2419
|
+
return table;
|
|
2420
|
+
}
|
|
2421
|
+
applyControlTable(channel, controllerType) {
|
|
2422
|
+
const slotSize = 6;
|
|
2423
|
+
const offset = controllerType * slotSize;
|
|
2424
|
+
const table = channel.controlTable.subarray(offset, offset + slotSize);
|
|
2425
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
2426
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
2427
|
+
const note = noteList[i];
|
|
2428
|
+
if (!note)
|
|
2429
|
+
continue;
|
|
2430
|
+
this.applyDestinationSettings(channel, note, table);
|
|
2431
|
+
}
|
|
2432
|
+
});
|
|
2433
|
+
}
|
|
2434
|
+
handleControlChangeSysEx(data) {
|
|
2435
|
+
const channelNumber = data[4];
|
|
2436
|
+
const controllerType = data[5];
|
|
2437
|
+
const table = this.channels[channelNumber].controlTable[controllerType];
|
|
2438
|
+
for (let i = 6; i < data.length - 1; i += 2) {
|
|
2439
|
+
const pp = data[i];
|
|
2440
|
+
const rr = data[i + 1];
|
|
2441
|
+
table[pp] = rr;
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2385
2444
|
getKeyBasedInstrumentControlValue(channel, keyNumber, controllerType) {
|
|
2386
2445
|
const index = keyNumber * 128 + controllerType;
|
|
2387
2446
|
const controlValue = channel.keyBasedInstrumentControlTable[index];
|
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;
|
|
@@ -120,7 +120,7 @@ export class MidyGMLite {
|
|
|
120
120
|
modLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
|
|
121
121
|
vibLfoToPitch: (_channel: any, _note: any, _prevValue: any) => void;
|
|
122
122
|
modLfoToFilterFc: (channel: any, note: any, _prevValue: any) => void;
|
|
123
|
-
modLfoToVolume: (channel: any, note: any) => void;
|
|
123
|
+
modLfoToVolume: (channel: any, note: any, _prevValue: any) => void;
|
|
124
124
|
chorusEffectsSend: (_channel: any, _note: any, _prevValue: any) => void;
|
|
125
125
|
reverbEffectsSend: (_channel: any, _note: any, _prevValue: any) => void;
|
|
126
126
|
delayModLFO: (_channel: any, note: any, _prevValue: any) => 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,iCAWC;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,wEAOC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAptCD;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"}
|
package/script/midy-GMLite.js
CHANGED
|
@@ -224,11 +224,11 @@ class MidyGMLite {
|
|
|
224
224
|
value: new Map()
|
|
225
225
|
});
|
|
226
226
|
this.audioContext = audioContext;
|
|
227
|
-
this.
|
|
227
|
+
this.masterVolume = new GainNode(audioContext);
|
|
228
228
|
this.voiceParamsHandlers = this.createVoiceParamsHandlers();
|
|
229
229
|
this.controlChangeHandlers = this.createControlChangeHandlers();
|
|
230
230
|
this.channels = this.createChannels(audioContext);
|
|
231
|
-
this.
|
|
231
|
+
this.masterVolume.connect(audioContext.destination);
|
|
232
232
|
this.GM1SystemOn();
|
|
233
233
|
}
|
|
234
234
|
initSoundFontTable() {
|
|
@@ -274,7 +274,7 @@ class MidyGMLite {
|
|
|
274
274
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
275
275
|
gainL.connect(merger, 0, 0);
|
|
276
276
|
gainR.connect(merger, 0, 1);
|
|
277
|
-
merger.connect(this.
|
|
277
|
+
merger.connect(this.masterVolume);
|
|
278
278
|
return {
|
|
279
279
|
gainL,
|
|
280
280
|
gainR,
|
|
@@ -916,7 +916,7 @@ class MidyGMLite {
|
|
|
916
916
|
if (0 < channel.state.modulationDepth)
|
|
917
917
|
this.setModLfoToFilterFc(note);
|
|
918
918
|
},
|
|
919
|
-
modLfoToVolume: (channel, note) => {
|
|
919
|
+
modLfoToVolume: (channel, note, _prevValue) => {
|
|
920
920
|
if (0 < channel.state.modulationDepth)
|
|
921
921
|
this.setModLfoToVolume(note);
|
|
922
922
|
},
|
|
@@ -1002,6 +1002,8 @@ class MidyGMLite {
|
|
|
1002
1002
|
const handler = this.controlChangeHandlers[controllerType];
|
|
1003
1003
|
if (handler) {
|
|
1004
1004
|
handler.call(this, channelNumber, value);
|
|
1005
|
+
const channel = this.channels[channelNumber];
|
|
1006
|
+
this.applyVoiceParams(channel, controller + 128);
|
|
1005
1007
|
}
|
|
1006
1008
|
else {
|
|
1007
1009
|
console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
|
|
@@ -1009,13 +1011,14 @@ class MidyGMLite {
|
|
|
1009
1011
|
}
|
|
1010
1012
|
updateModulation(channel) {
|
|
1011
1013
|
const now = this.audioContext.currentTime;
|
|
1014
|
+
const depth = channel.state.modulationDepth * channel.modulationDepthRange;
|
|
1012
1015
|
channel.scheduledNotes.forEach((noteList) => {
|
|
1013
1016
|
for (let i = 0; i < noteList.length; i++) {
|
|
1014
1017
|
const note = noteList[i];
|
|
1015
1018
|
if (!note)
|
|
1016
1019
|
continue;
|
|
1017
1020
|
if (note.modulationDepth) {
|
|
1018
|
-
note.modulationDepth.gain.setValueAtTime(
|
|
1021
|
+
note.modulationDepth.gain.setValueAtTime(depth, now);
|
|
1019
1022
|
}
|
|
1020
1023
|
else {
|
|
1021
1024
|
this.setPitchEnvelope(note);
|
|
@@ -1026,8 +1029,7 @@ class MidyGMLite {
|
|
|
1026
1029
|
}
|
|
1027
1030
|
setModulationDepth(channelNumber, modulation) {
|
|
1028
1031
|
const channel = this.channels[channelNumber];
|
|
1029
|
-
channel.state.modulationDepth =
|
|
1030
|
-
channel.modulationDepthRange;
|
|
1032
|
+
channel.state.modulationDepth = modulation / 127;
|
|
1031
1033
|
this.updateModulation(channel);
|
|
1032
1034
|
}
|
|
1033
1035
|
setVolume(channelNumber, volume) {
|
|
@@ -1203,8 +1205,8 @@ class MidyGMLite {
|
|
|
1203
1205
|
}
|
|
1204
1206
|
else {
|
|
1205
1207
|
const now = this.audioContext.currentTime;
|
|
1206
|
-
this.
|
|
1207
|
-
this.
|
|
1208
|
+
this.masterVolume.gain.cancelScheduledValues(now);
|
|
1209
|
+
this.masterVolume.gain.setValueAtTime(volume * volume, now);
|
|
1208
1210
|
}
|
|
1209
1211
|
}
|
|
1210
1212
|
handleExclusiveMessage(data) {
|
package/script/midy.d.ts
CHANGED
|
@@ -77,12 +77,12 @@ export class Midy {
|
|
|
77
77
|
output: any;
|
|
78
78
|
};
|
|
79
79
|
};
|
|
80
|
-
|
|
80
|
+
masterVolume: any;
|
|
81
81
|
voiceParamsHandlers: {
|
|
82
82
|
modLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
|
|
83
83
|
vibLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
|
|
84
84
|
modLfoToFilterFc: (channel: any, note: any, _prevValue: any) => void;
|
|
85
|
-
modLfoToVolume: (channel: any, note: any) => void;
|
|
85
|
+
modLfoToVolume: (channel: any, note: any, _prevValue: any) => void;
|
|
86
86
|
chorusEffectsSend: (channel: any, note: any, prevValue: any) => void;
|
|
87
87
|
reverbEffectsSend: (channel: any, note: any, prevValue: any) => void;
|
|
88
88
|
delayModLFO: (_channel: any, note: any, _prevValue: any) => void;
|
|
@@ -224,7 +224,6 @@ export class Midy {
|
|
|
224
224
|
handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
|
|
225
225
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
226
226
|
handleChannelPressure(channelNumber: any, value: any): void;
|
|
227
|
-
setChannelPressure(channel: any, note: any): void;
|
|
228
227
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
229
228
|
setPitchBend(channelNumber: any, value: any): void;
|
|
230
229
|
setModLfoToPitch(channel: any, note: any): void;
|
|
@@ -239,7 +238,7 @@ export class Midy {
|
|
|
239
238
|
modLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
|
|
240
239
|
vibLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
|
|
241
240
|
modLfoToFilterFc: (channel: any, note: any, _prevValue: any) => void;
|
|
242
|
-
modLfoToVolume: (channel: any, note: any) => void;
|
|
241
|
+
modLfoToVolume: (channel: any, note: any, _prevValue: any) => void;
|
|
243
242
|
chorusEffectsSend: (channel: any, note: any, prevValue: any) => void;
|
|
244
243
|
reverbEffectsSend: (channel: any, note: any, prevValue: any) => void;
|
|
245
244
|
delayModLFO: (_channel: any, note: any, _prevValue: any) => void;
|
|
@@ -369,7 +368,11 @@ export class Midy {
|
|
|
369
368
|
getChorusSendToReverb(value: any): number;
|
|
370
369
|
getChannelBitmap(data: any): any[];
|
|
371
370
|
handleScaleOctaveTuning1ByteFormatSysEx(data: any): void;
|
|
371
|
+
applyDestinationSettings(channel: any, note: any, table: any): void;
|
|
372
372
|
handleChannelPressureSysEx(data: any): void;
|
|
373
|
+
initControlTable(): Uint8Array<ArrayBuffer>;
|
|
374
|
+
applyControlTable(channel: any, controllerType: any): void;
|
|
375
|
+
handleControlChangeSysEx(data: any): void;
|
|
373
376
|
getKeyBasedInstrumentControlValue(channel: any, keyNumber: any, controllerType: any): number;
|
|
374
377
|
handleKeyBasedInstrumentControlSysEx(data: any): void;
|
|
375
378
|
handleExclusiveMessage(data: 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":"AAiHA;IAmCE;;;;;;;;;;;;;;;;;MAiBE;IAEF;;;;;;;MAOE;IAgCF;;;;;OAaC;IAzGD,qBAAmB;IACnB,kBAAc;IACd,yBAAqB;IACrB,2BAAuB;IACvB;;;MAGE;IACF;;;;;;MAME;IACF,cAAa;IACb,cAAa;IACb,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;IA8B9B;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|
package/script/midy.js
CHANGED
|
@@ -362,15 +362,15 @@ class Midy {
|
|
|
362
362
|
});
|
|
363
363
|
this.audioContext = audioContext;
|
|
364
364
|
this.options = { ...this.defaultOptions, ...options };
|
|
365
|
-
this.
|
|
365
|
+
this.masterVolume = new GainNode(audioContext);
|
|
366
366
|
this.voiceParamsHandlers = this.createVoiceParamsHandlers();
|
|
367
367
|
this.controlChangeHandlers = this.createControlChangeHandlers();
|
|
368
368
|
this.channels = this.createChannels(audioContext);
|
|
369
369
|
this.reverbEffect = this.options.reverbAlgorithm(audioContext);
|
|
370
370
|
this.chorusEffect = this.createChorusEffect(audioContext);
|
|
371
|
-
this.chorusEffect.output.connect(this.
|
|
372
|
-
this.reverbEffect.output.connect(this.
|
|
373
|
-
this.
|
|
371
|
+
this.chorusEffect.output.connect(this.masterVolume);
|
|
372
|
+
this.reverbEffect.output.connect(this.masterVolume);
|
|
373
|
+
this.masterVolume.connect(audioContext.destination);
|
|
374
374
|
this.GM2SystemOn();
|
|
375
375
|
}
|
|
376
376
|
initSoundFontTable() {
|
|
@@ -416,7 +416,7 @@ class Midy {
|
|
|
416
416
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
417
417
|
gainL.connect(merger, 0, 0);
|
|
418
418
|
gainR.connect(merger, 0, 1);
|
|
419
|
-
merger.connect(this.
|
|
419
|
+
merger.connect(this.masterVolume);
|
|
420
420
|
return {
|
|
421
421
|
gainL,
|
|
422
422
|
gainR,
|
|
@@ -428,6 +428,7 @@ class Midy {
|
|
|
428
428
|
return {
|
|
429
429
|
...this.constructor.channelSettings,
|
|
430
430
|
state: new ControllerState(),
|
|
431
|
+
controlTable: this.initControlTable(),
|
|
431
432
|
...this.setChannelAudioNodes(audioContext),
|
|
432
433
|
scheduledNotes: new Map(),
|
|
433
434
|
sostenutoNotes: new Map(),
|
|
@@ -1376,36 +1377,17 @@ class Midy {
|
|
|
1376
1377
|
const pressureDepth = (channel.pressureTable[0] - 64) / 37.5; // 2400 / 64;
|
|
1377
1378
|
channel.detune += pressureDepth * (next - prev);
|
|
1378
1379
|
}
|
|
1380
|
+
const table = channel.pressureTable;
|
|
1379
1381
|
channel.scheduledNotes.forEach((noteList) => {
|
|
1380
1382
|
for (let i = 0; i < noteList.length; i++) {
|
|
1381
1383
|
const note = noteList[i];
|
|
1382
1384
|
if (!note)
|
|
1383
1385
|
continue;
|
|
1384
|
-
this.
|
|
1386
|
+
this.applyDestinationSettings(channel, note, table);
|
|
1385
1387
|
}
|
|
1386
1388
|
});
|
|
1387
1389
|
// this.applyVoiceParams(channel, 13);
|
|
1388
1390
|
}
|
|
1389
|
-
setChannelPressure(channel, note) {
|
|
1390
|
-
if (channel.pressureTable[0] !== 64) {
|
|
1391
|
-
this.updateDetune(channel);
|
|
1392
|
-
}
|
|
1393
|
-
if (channel.pressureTable[1] !== 64 && !note.portamento) {
|
|
1394
|
-
this.setFilterEnvelope(channel, note);
|
|
1395
|
-
}
|
|
1396
|
-
if (channel.pressureTable[2] !== 64 && !note.portamento) {
|
|
1397
|
-
this.setVolumeEnvelope(channel, note);
|
|
1398
|
-
}
|
|
1399
|
-
if (channel.pressureTable[3] !== 0) {
|
|
1400
|
-
this.setModLfoToPitch(channel, note);
|
|
1401
|
-
}
|
|
1402
|
-
if (channel.pressureTable[4] !== 0) {
|
|
1403
|
-
this.setModLfoToFilterFc(channel, note);
|
|
1404
|
-
}
|
|
1405
|
-
if (channel.pressureTable[5] !== 0) {
|
|
1406
|
-
this.setModLfoToVolume(channel, note);
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
1391
|
handlePitchBendMessage(channelNumber, lsb, msb) {
|
|
1410
1392
|
const pitchBend = msb * 128 + lsb;
|
|
1411
1393
|
this.setPitchBend(channelNumber, pitchBend);
|
|
@@ -1547,7 +1529,7 @@ class Midy {
|
|
|
1547
1529
|
this.setModLfoToFilterFc(channel, note);
|
|
1548
1530
|
}
|
|
1549
1531
|
},
|
|
1550
|
-
modLfoToVolume: (channel, note) => {
|
|
1532
|
+
modLfoToVolume: (channel, note, _prevValue) => {
|
|
1551
1533
|
if (0 < channel.state.modulationDepth) {
|
|
1552
1534
|
this.setModLfoToVolume(channel, note);
|
|
1553
1535
|
}
|
|
@@ -1563,12 +1545,12 @@ class Midy {
|
|
|
1563
1545
|
delayVibLFO: (channel, note, prevValue) => {
|
|
1564
1546
|
if (0 < channel.state.vibratoDepth) {
|
|
1565
1547
|
const now = this.audioContext.currentTime;
|
|
1566
|
-
const
|
|
1567
|
-
|
|
1548
|
+
const vibratoDelay = channel.state.vibratoDelay * 2;
|
|
1549
|
+
const prevStartTime = note.startTime + prevValue * vibratoDelay;
|
|
1568
1550
|
if (now < prevStartTime)
|
|
1569
1551
|
return;
|
|
1570
|
-
const
|
|
1571
|
-
|
|
1552
|
+
const value = note.voiceParams.delayVibLFO;
|
|
1553
|
+
const startTime = note.startTime + value * vibratoDelay;
|
|
1572
1554
|
note.vibratoLFO.stop(now);
|
|
1573
1555
|
note.vibratoLFO.start(startTime);
|
|
1574
1556
|
}
|
|
@@ -1576,9 +1558,10 @@ class Midy {
|
|
|
1576
1558
|
freqVibLFO: (channel, note, _prevValue) => {
|
|
1577
1559
|
if (0 < channel.state.vibratoDepth) {
|
|
1578
1560
|
const now = this.audioContext.currentTime;
|
|
1561
|
+
const freqVibLFO = note.voiceParams.freqVibLFO;
|
|
1579
1562
|
note.vibratoLFO.frequency
|
|
1580
1563
|
.cancelScheduledValues(now)
|
|
1581
|
-
.setValueAtTime(
|
|
1564
|
+
.setValueAtTime(freqVibLFO * channel.state.vibratoRate, now);
|
|
1582
1565
|
}
|
|
1583
1566
|
},
|
|
1584
1567
|
};
|
|
@@ -1685,8 +1668,8 @@ class Midy {
|
|
|
1685
1668
|
if (handler) {
|
|
1686
1669
|
handler.call(this, channelNumber, value);
|
|
1687
1670
|
const channel = this.channels[channelNumber];
|
|
1688
|
-
|
|
1689
|
-
this.
|
|
1671
|
+
this.applyVoiceParams(channel, controllerType + 128);
|
|
1672
|
+
this.applyControlTable(channel, controllerType);
|
|
1690
1673
|
}
|
|
1691
1674
|
else {
|
|
1692
1675
|
console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
|
|
@@ -1697,13 +1680,14 @@ class Midy {
|
|
|
1697
1680
|
}
|
|
1698
1681
|
updateModulation(channel) {
|
|
1699
1682
|
const now = this.audioContext.currentTime;
|
|
1683
|
+
const depth = channel.state.modulationDepth * channel.modulationDepthRange;
|
|
1700
1684
|
channel.scheduledNotes.forEach((noteList) => {
|
|
1701
1685
|
for (let i = 0; i < noteList.length; i++) {
|
|
1702
1686
|
const note = noteList[i];
|
|
1703
1687
|
if (!note)
|
|
1704
1688
|
continue;
|
|
1705
1689
|
if (note.modulationDepth) {
|
|
1706
|
-
note.modulationDepth.gain.setValueAtTime(
|
|
1690
|
+
note.modulationDepth.gain.setValueAtTime(depth, now);
|
|
1707
1691
|
}
|
|
1708
1692
|
else {
|
|
1709
1693
|
this.setPitchEnvelope(note);
|
|
@@ -1714,8 +1698,7 @@ class Midy {
|
|
|
1714
1698
|
}
|
|
1715
1699
|
setModulationDepth(channelNumber, modulation) {
|
|
1716
1700
|
const channel = this.channels[channelNumber];
|
|
1717
|
-
channel.state.modulationDepth =
|
|
1718
|
-
channel.modulationDepthRange;
|
|
1701
|
+
channel.state.modulationDepth = modulation / 127;
|
|
1719
1702
|
this.updateModulation(channel);
|
|
1720
1703
|
}
|
|
1721
1704
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
@@ -2109,7 +2092,6 @@ class Midy {
|
|
|
2109
2092
|
setModulationDepthRange(channelNumber, modulationDepthRange) {
|
|
2110
2093
|
const channel = this.channels[channelNumber];
|
|
2111
2094
|
channel.modulationDepthRange = modulationDepthRange;
|
|
2112
|
-
channel.modulationDepth = (modulation / 127) * modulationDepthRange;
|
|
2113
2095
|
this.updateModulation(channel);
|
|
2114
2096
|
}
|
|
2115
2097
|
allSoundOff(channelNumber) {
|
|
@@ -2234,9 +2216,8 @@ class Midy {
|
|
|
2234
2216
|
switch (data[3]) {
|
|
2235
2217
|
case 1: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca22.pdf
|
|
2236
2218
|
return this.handleChannelPressureSysEx(data);
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
// return this.setControlChange();
|
|
2219
|
+
case 3: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca22.pdf
|
|
2220
|
+
return this.handleControlChangeSysEx(data);
|
|
2240
2221
|
default:
|
|
2241
2222
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
2242
2223
|
}
|
|
@@ -2263,8 +2244,8 @@ class Midy {
|
|
|
2263
2244
|
}
|
|
2264
2245
|
else {
|
|
2265
2246
|
const now = this.audioContext.currentTime;
|
|
2266
|
-
this.
|
|
2267
|
-
this.
|
|
2247
|
+
this.masterVolume.gain.cancelScheduledValues(now);
|
|
2248
|
+
this.masterVolume.gain.setValueAtTime(volume * volume, now);
|
|
2268
2249
|
}
|
|
2269
2250
|
}
|
|
2270
2251
|
handleMasterFineTuningSysEx(data) {
|
|
@@ -2509,6 +2490,28 @@ class Midy {
|
|
|
2509
2490
|
}
|
|
2510
2491
|
}
|
|
2511
2492
|
}
|
|
2493
|
+
applyDestinationSettings(channel, note, table) {
|
|
2494
|
+
if (table[0] !== 64) {
|
|
2495
|
+
this.updateDetune(channel);
|
|
2496
|
+
}
|
|
2497
|
+
if (!note.portamento) {
|
|
2498
|
+
if (table[1] !== 64) {
|
|
2499
|
+
this.setFilterEnvelope(channel, note);
|
|
2500
|
+
}
|
|
2501
|
+
if (table[2] !== 64) {
|
|
2502
|
+
this.setVolumeEnvelope(channel, note);
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
if (table[3] !== 0) {
|
|
2506
|
+
this.setModLfoToPitch(channel, note);
|
|
2507
|
+
}
|
|
2508
|
+
if (table[4] !== 0) {
|
|
2509
|
+
this.setModLfoToFilterFc(channel, note);
|
|
2510
|
+
}
|
|
2511
|
+
if (table[5] !== 0) {
|
|
2512
|
+
this.setModLfoToVolume(channel, note);
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2512
2515
|
handleChannelPressureSysEx(data) {
|
|
2513
2516
|
const channelNumber = data[4];
|
|
2514
2517
|
const table = this.channels[channelNumber].pressureTable;
|
|
@@ -2518,6 +2521,40 @@ class Midy {
|
|
|
2518
2521
|
table[pp] = rr;
|
|
2519
2522
|
}
|
|
2520
2523
|
}
|
|
2524
|
+
initControlTable() {
|
|
2525
|
+
const channelCount = 128;
|
|
2526
|
+
const slotSize = 6;
|
|
2527
|
+
const defaultValues = [64, 64, 64, 0, 0, 0];
|
|
2528
|
+
const table = new Uint8Array(channelCount * slotSize);
|
|
2529
|
+
for (let ch = 0; ch < channelCount; ch++) {
|
|
2530
|
+
const offset = ch * slotSize;
|
|
2531
|
+
table.set(defaultValues, offset);
|
|
2532
|
+
}
|
|
2533
|
+
return table;
|
|
2534
|
+
}
|
|
2535
|
+
applyControlTable(channel, controllerType) {
|
|
2536
|
+
const slotSize = 6;
|
|
2537
|
+
const offset = controllerType * slotSize;
|
|
2538
|
+
const table = channel.controlTable.subarray(offset, offset + slotSize);
|
|
2539
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
2540
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
2541
|
+
const note = noteList[i];
|
|
2542
|
+
if (!note)
|
|
2543
|
+
continue;
|
|
2544
|
+
this.applyDestinationSettings(channel, note, table);
|
|
2545
|
+
}
|
|
2546
|
+
});
|
|
2547
|
+
}
|
|
2548
|
+
handleControlChangeSysEx(data) {
|
|
2549
|
+
const channelNumber = data[4];
|
|
2550
|
+
const controllerType = data[5];
|
|
2551
|
+
const table = this.channels[channelNumber].controlTable[controllerType];
|
|
2552
|
+
for (let i = 6; i < data.length - 1; i += 2) {
|
|
2553
|
+
const pp = data[i];
|
|
2554
|
+
const rr = data[i + 1];
|
|
2555
|
+
table[pp] = rr;
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2521
2558
|
getKeyBasedInstrumentControlValue(channel, keyNumber, controllerType) {
|
|
2522
2559
|
const index = keyNumber * 128 + controllerType;
|
|
2523
2560
|
const controlValue = channel.keyBasedInstrumentControlTable[index];
|