@marmooo/midy 0.2.8 → 0.2.9
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/esm/midy-GM1.d.ts +8 -4
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +54 -17
- package/esm/midy-GM2.d.ts +13 -8
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +147 -40
- package/esm/midy-GMLite.d.ts +9 -3
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +57 -16
- package/esm/midy.d.ts +13 -8
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +187 -51
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +8 -4
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +54 -17
- package/script/midy-GM2.d.ts +13 -8
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +147 -40
- package/script/midy-GMLite.d.ts +9 -3
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +57 -16
- package/script/midy.d.ts +13 -8
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +187 -51
package/esm/midy.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export class Midy {
|
|
2
2
|
static channelSettings: {
|
|
3
3
|
currentBufferSource: null;
|
|
4
|
+
isDrum: boolean;
|
|
4
5
|
detune: number;
|
|
5
6
|
program: number;
|
|
6
7
|
bank: number;
|
|
@@ -11,9 +12,9 @@ export class Midy {
|
|
|
11
12
|
rpnMSB: number;
|
|
12
13
|
rpnLSB: number;
|
|
13
14
|
mono: boolean;
|
|
15
|
+
modulationDepthRange: number;
|
|
14
16
|
fineTuning: number;
|
|
15
17
|
coarseTuning: number;
|
|
16
|
-
modulationDepthRange: number;
|
|
17
18
|
};
|
|
18
19
|
constructor(audioContext: any, options?: {
|
|
19
20
|
reverbAlgorithm: (audioContext: any) => {
|
|
@@ -21,6 +22,7 @@ export class Midy {
|
|
|
21
22
|
output: any;
|
|
22
23
|
};
|
|
23
24
|
});
|
|
25
|
+
mode: string;
|
|
24
26
|
ticksPerBeat: number;
|
|
25
27
|
totalTime: number;
|
|
26
28
|
masterFineTuning: number;
|
|
@@ -68,6 +70,8 @@ export class Midy {
|
|
|
68
70
|
};
|
|
69
71
|
};
|
|
70
72
|
masterVolume: any;
|
|
73
|
+
scheduler: any;
|
|
74
|
+
schedulerBuffer: any;
|
|
71
75
|
voiceParamsHandlers: {
|
|
72
76
|
modLfoToPitch: (channel: any, note: any, _prevValue: any, scheduleTime: any) => void;
|
|
73
77
|
vibLfoToPitch: (channel: any, note: any, _prevValue: any, scheduleTime: any) => void;
|
|
@@ -93,7 +97,7 @@ export class Midy {
|
|
|
93
97
|
64: (channelNumber: any, value: any, scheduleTime: any) => void;
|
|
94
98
|
65: (channelNumber: any, value: any) => void;
|
|
95
99
|
66: (channelNumber: any, value: any, scheduleTime: any) => void;
|
|
96
|
-
67: (channelNumber: any, softPedal: any,
|
|
100
|
+
67: (channelNumber: any, softPedal: any, scheduleTime: any) => void;
|
|
97
101
|
71: (channelNumber: any, filterResonance: any, scheduleTime: any) => void;
|
|
98
102
|
72: (channelNumber: any, releaseTime: any, _scheduleTime: any) => void;
|
|
99
103
|
73: (channelNumber: any, attackTime: any, scheduleTime: any) => void;
|
|
@@ -141,7 +145,8 @@ export class Midy {
|
|
|
141
145
|
};
|
|
142
146
|
createChannels(audioContext: any): any[];
|
|
143
147
|
createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
|
|
144
|
-
|
|
148
|
+
calcLoopMode(channel: any, note: any, voiceParams: any): boolean;
|
|
149
|
+
createBufferSource(channel: any, note: any, voiceParams: any, audioBuffer: any): any;
|
|
145
150
|
findPortamentoTarget(queueIndex: any): any;
|
|
146
151
|
scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
|
|
147
152
|
getQueueIndex(second: any): number;
|
|
@@ -206,7 +211,7 @@ export class Midy {
|
|
|
206
211
|
startVibrato(channel: any, note: any, scheduleTime: any): void;
|
|
207
212
|
getAudioBuffer(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
|
|
208
213
|
createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, portamento: any, isSF3: any): Promise<Note>;
|
|
209
|
-
calcBank(channel: any
|
|
214
|
+
calcBank(channel: any): any;
|
|
210
215
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
|
|
211
216
|
noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
|
|
212
217
|
stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
|
|
@@ -256,7 +261,7 @@ export class Midy {
|
|
|
256
261
|
64: (channelNumber: any, value: any, scheduleTime: any) => void;
|
|
257
262
|
65: (channelNumber: any, value: any) => void;
|
|
258
263
|
66: (channelNumber: any, value: any, scheduleTime: any) => void;
|
|
259
|
-
67: (channelNumber: any, softPedal: any,
|
|
264
|
+
67: (channelNumber: any, softPedal: any, scheduleTime: any) => void;
|
|
260
265
|
71: (channelNumber: any, filterResonance: any, scheduleTime: any) => void;
|
|
261
266
|
72: (channelNumber: any, releaseTime: any, _scheduleTime: any) => void;
|
|
262
267
|
73: (channelNumber: any, attackTime: any, scheduleTime: any) => void;
|
|
@@ -299,7 +304,7 @@ export class Midy {
|
|
|
299
304
|
setSustainPedal(channelNumber: any, value: any, scheduleTime: any): void;
|
|
300
305
|
setPortamento(channelNumber: any, value: any): void;
|
|
301
306
|
setSostenutoPedal(channelNumber: any, value: any, scheduleTime: any): void;
|
|
302
|
-
setSoftPedal(channelNumber: any, softPedal: any,
|
|
307
|
+
setSoftPedal(channelNumber: any, softPedal: any, scheduleTime: any): void;
|
|
303
308
|
setFilterResonance(channelNumber: any, filterResonance: any, scheduleTime: any): void;
|
|
304
309
|
setReleaseTime(channelNumber: any, releaseTime: any, _scheduleTime: any): void;
|
|
305
310
|
setAttackTime(channelNumber: any, attackTime: any, scheduleTime: any): void;
|
|
@@ -334,8 +339,8 @@ export class Midy {
|
|
|
334
339
|
monoOn(channelNumber: any, value: any, scheduleTime: any): void;
|
|
335
340
|
polyOn(channelNumber: any, value: any, scheduleTime: any): void;
|
|
336
341
|
handleUniversalNonRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
|
|
337
|
-
GM1SystemOn(): void;
|
|
338
|
-
GM2SystemOn(): void;
|
|
342
|
+
GM1SystemOn(scheduleTime: any): void;
|
|
343
|
+
GM2SystemOn(scheduleTime: any): void;
|
|
339
344
|
handleUniversalRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
|
|
340
345
|
handleMasterVolumeSysEx(data: any, scheduleTime: any): void;
|
|
341
346
|
setMasterVolume(volume: any, scheduleTime: any): void;
|
package/esm/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAgLA;
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|
package/esm/midy.js
CHANGED
|
@@ -246,6 +246,12 @@ const volumeEnvelopeKeys = [
|
|
|
246
246
|
const volumeEnvelopeKeySet = new Set(volumeEnvelopeKeys);
|
|
247
247
|
export class Midy {
|
|
248
248
|
constructor(audioContext, options = this.defaultOptions) {
|
|
249
|
+
Object.defineProperty(this, "mode", {
|
|
250
|
+
enumerable: true,
|
|
251
|
+
configurable: true,
|
|
252
|
+
writable: true,
|
|
253
|
+
value: "GM2"
|
|
254
|
+
});
|
|
249
255
|
Object.defineProperty(this, "ticksPerBeat", {
|
|
250
256
|
enumerable: true,
|
|
251
257
|
configurable: true,
|
|
@@ -424,6 +430,11 @@ export class Midy {
|
|
|
424
430
|
this.audioContext = audioContext;
|
|
425
431
|
this.options = { ...this.defaultOptions, ...options };
|
|
426
432
|
this.masterVolume = new GainNode(audioContext);
|
|
433
|
+
this.scheduler = new GainNode(audioContext, { gain: 0 });
|
|
434
|
+
this.schedulerBuffer = new AudioBuffer({
|
|
435
|
+
length: 1,
|
|
436
|
+
sampleRate: audioContext.sampleRate,
|
|
437
|
+
});
|
|
427
438
|
this.voiceParamsHandlers = this.createVoiceParamsHandlers();
|
|
428
439
|
this.controlChangeHandlers = this.createControlChangeHandlers();
|
|
429
440
|
this.channels = this.createChannels(audioContext);
|
|
@@ -432,6 +443,7 @@ export class Midy {
|
|
|
432
443
|
this.chorusEffect.output.connect(this.masterVolume);
|
|
433
444
|
this.reverbEffect.output.connect(this.masterVolume);
|
|
434
445
|
this.masterVolume.connect(audioContext.destination);
|
|
446
|
+
this.scheduler.connect(audioContext.destination);
|
|
435
447
|
this.GM2SystemOn();
|
|
436
448
|
}
|
|
437
449
|
initSoundFontTable() {
|
|
@@ -531,10 +543,24 @@ export class Midy {
|
|
|
531
543
|
return audioBuffer;
|
|
532
544
|
}
|
|
533
545
|
}
|
|
534
|
-
|
|
546
|
+
calcLoopMode(channel, note, voiceParams) {
|
|
547
|
+
if (channel.isDrum) {
|
|
548
|
+
const noteNumber = note.noteNumber;
|
|
549
|
+
if (noteNumber === 88 || 47 <= noteNumber && noteNumber <= 84) {
|
|
550
|
+
return true;
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
return voiceParams.sampleModes % 2 !== 0;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
createBufferSource(channel, note, voiceParams, audioBuffer) {
|
|
535
561
|
const bufferSource = new AudioBufferSourceNode(this.audioContext);
|
|
536
562
|
bufferSource.buffer = audioBuffer;
|
|
537
|
-
bufferSource.loop =
|
|
563
|
+
bufferSource.loop = this.calcLoopMode(channel, note, voiceParams);
|
|
538
564
|
if (bufferSource.loop) {
|
|
539
565
|
bufferSource.loopStart = voiceParams.loopStart / voiceParams.sampleRate;
|
|
540
566
|
bufferSource.loopEnd = voiceParams.loopEnd / voiceParams.sampleRate;
|
|
@@ -1014,7 +1040,9 @@ export class Midy {
|
|
|
1014
1040
|
return 8.176 * this.centToRate(cent);
|
|
1015
1041
|
}
|
|
1016
1042
|
calcChannelDetune(channel) {
|
|
1017
|
-
const masterTuning =
|
|
1043
|
+
const masterTuning = channel.isDrum
|
|
1044
|
+
? 0
|
|
1045
|
+
: this.masterCoarseTuning + this.masterFineTuning;
|
|
1018
1046
|
const channelTuning = channel.coarseTuning + channel.fineTuning;
|
|
1019
1047
|
const tuning = masterTuning + channelTuning;
|
|
1020
1048
|
const pitchWheel = channel.state.pitchWheel * 2 - 1;
|
|
@@ -1041,9 +1069,8 @@ export class Midy {
|
|
|
1041
1069
|
.setValueAtTime(detune, scheduleTime);
|
|
1042
1070
|
}
|
|
1043
1071
|
getPortamentoTime(channel) {
|
|
1044
|
-
const factor = 5 * Math.log(10)
|
|
1045
|
-
|
|
1046
|
-
return Math.log(time) / factor;
|
|
1072
|
+
const factor = 5 * Math.log(10) * 127;
|
|
1073
|
+
return channel.state.portamentoTime * factor;
|
|
1047
1074
|
}
|
|
1048
1075
|
setPortamentoStartVolumeEnvelope(channel, note, scheduleTime) {
|
|
1049
1076
|
const { voiceParams, startTime } = note;
|
|
@@ -1207,7 +1234,7 @@ export class Midy {
|
|
|
1207
1234
|
const voiceParams = voice.getAllParams(controllerState);
|
|
1208
1235
|
const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
|
|
1209
1236
|
const audioBuffer = await this.getAudioBuffer(channel.program, noteNumber, velocity, voiceParams, isSF3);
|
|
1210
|
-
note.bufferSource = this.
|
|
1237
|
+
note.bufferSource = this.createBufferSource(channel, note, voiceParams, audioBuffer);
|
|
1211
1238
|
note.volumeNode = new GainNode(this.audioContext);
|
|
1212
1239
|
note.gainL = new GainNode(this.audioContext);
|
|
1213
1240
|
note.gainR = new GainNode(this.audioContext);
|
|
@@ -1251,14 +1278,21 @@ export class Midy {
|
|
|
1251
1278
|
note.bufferSource.start(startTime);
|
|
1252
1279
|
return note;
|
|
1253
1280
|
}
|
|
1254
|
-
calcBank(channel
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1281
|
+
calcBank(channel) {
|
|
1282
|
+
switch (this.mode) {
|
|
1283
|
+
case "GM1":
|
|
1284
|
+
if (channel.isDrum)
|
|
1285
|
+
return 128;
|
|
1286
|
+
return 0;
|
|
1287
|
+
case "GM2":
|
|
1288
|
+
if (channel.bankMSB === 121)
|
|
1289
|
+
return 0;
|
|
1290
|
+
if (channel.isDrum)
|
|
1291
|
+
return 128;
|
|
1292
|
+
return channel.bank;
|
|
1293
|
+
default:
|
|
1294
|
+
return channel.bank;
|
|
1260
1295
|
}
|
|
1261
|
-
return channel.bank;
|
|
1262
1296
|
}
|
|
1263
1297
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, portamento) {
|
|
1264
1298
|
const channel = this.channels[channelNumber];
|
|
@@ -1282,7 +1316,7 @@ export class Midy {
|
|
|
1282
1316
|
if (this.exclusiveClassMap.has(exclusiveClass)) {
|
|
1283
1317
|
const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
|
|
1284
1318
|
const [prevNote, prevChannelNumber] = prevEntry;
|
|
1285
|
-
if (!prevNote.ending) {
|
|
1319
|
+
if (prevNote && !prevNote.ending) {
|
|
1286
1320
|
this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
1287
1321
|
startTime, true, // force
|
|
1288
1322
|
undefined);
|
|
@@ -1445,9 +1479,21 @@ export class Midy {
|
|
|
1445
1479
|
const channel = this.channels[channelNumber];
|
|
1446
1480
|
channel.bank = channel.bankMSB * 128 + channel.bankLSB;
|
|
1447
1481
|
channel.program = program;
|
|
1482
|
+
if (this.mode === "GM2") {
|
|
1483
|
+
switch (channel.bankMSB) {
|
|
1484
|
+
case 120:
|
|
1485
|
+
channel.isDrum = true;
|
|
1486
|
+
break;
|
|
1487
|
+
case 121:
|
|
1488
|
+
channel.isDrum = false;
|
|
1489
|
+
break;
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1448
1492
|
}
|
|
1449
1493
|
handleChannelPressure(channelNumber, value, scheduleTime) {
|
|
1450
1494
|
const channel = this.channels[channelNumber];
|
|
1495
|
+
if (channel.isDrum)
|
|
1496
|
+
return;
|
|
1451
1497
|
const prev = channel.state.channelPressure;
|
|
1452
1498
|
const next = value / 127;
|
|
1453
1499
|
channel.state.channelPressure = next;
|
|
@@ -1466,8 +1512,10 @@ export class Midy {
|
|
|
1466
1512
|
this.setPitchBend(channelNumber, pitchBend, scheduleTime);
|
|
1467
1513
|
}
|
|
1468
1514
|
setPitchBend(channelNumber, value, scheduleTime) {
|
|
1469
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1470
1515
|
const channel = this.channels[channelNumber];
|
|
1516
|
+
if (channel.isDrum)
|
|
1517
|
+
return;
|
|
1518
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1471
1519
|
const state = channel.state;
|
|
1472
1520
|
const prev = state.pitchWheel * 2 - 1;
|
|
1473
1521
|
const next = (value - 8192) / 8192;
|
|
@@ -1749,15 +1797,16 @@ export class Midy {
|
|
|
1749
1797
|
});
|
|
1750
1798
|
}
|
|
1751
1799
|
setModulationDepth(channelNumber, modulation, scheduleTime) {
|
|
1752
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1753
1800
|
const channel = this.channels[channelNumber];
|
|
1801
|
+
if (channel.isDrum)
|
|
1802
|
+
return;
|
|
1803
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1754
1804
|
channel.state.modulationDepth = modulation / 127;
|
|
1755
1805
|
this.updateModulation(channel, scheduleTime);
|
|
1756
1806
|
}
|
|
1757
1807
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
1758
1808
|
const channel = this.channels[channelNumber];
|
|
1759
|
-
|
|
1760
|
-
channel.state.portamentoTime = Math.exp(factor * portamentoTime);
|
|
1809
|
+
channel.state.portamentoTime = portamentoTime / 127;
|
|
1761
1810
|
}
|
|
1762
1811
|
setKeyBasedVolume(channel, scheduleTime) {
|
|
1763
1812
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -1829,8 +1878,10 @@ export class Midy {
|
|
|
1829
1878
|
.setValueAtTime(volume * gainRight, scheduleTime);
|
|
1830
1879
|
}
|
|
1831
1880
|
setSustainPedal(channelNumber, value, scheduleTime) {
|
|
1832
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1833
1881
|
const channel = this.channels[channelNumber];
|
|
1882
|
+
if (channel.isDrum)
|
|
1883
|
+
return;
|
|
1884
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1834
1885
|
channel.state.sustainPedal = value / 127;
|
|
1835
1886
|
if (64 <= value) {
|
|
1836
1887
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -1842,11 +1893,16 @@ export class Midy {
|
|
|
1842
1893
|
}
|
|
1843
1894
|
}
|
|
1844
1895
|
setPortamento(channelNumber, value) {
|
|
1845
|
-
this.channels[channelNumber]
|
|
1896
|
+
const channel = this.channels[channelNumber];
|
|
1897
|
+
if (channel.isDrum)
|
|
1898
|
+
return;
|
|
1899
|
+
channel.state.portamento = value / 127;
|
|
1846
1900
|
}
|
|
1847
1901
|
setSostenutoPedal(channelNumber, value, scheduleTime) {
|
|
1848
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1849
1902
|
const channel = this.channels[channelNumber];
|
|
1903
|
+
if (channel.isDrum)
|
|
1904
|
+
return;
|
|
1905
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1850
1906
|
channel.state.sostenutoPedal = value / 127;
|
|
1851
1907
|
if (64 <= value) {
|
|
1852
1908
|
channel.sostenutoNotes = this.getActiveNotes(channel, scheduleTime);
|
|
@@ -1855,13 +1911,28 @@ export class Midy {
|
|
|
1855
1911
|
this.releaseSostenutoPedal(channelNumber, value, scheduleTime);
|
|
1856
1912
|
}
|
|
1857
1913
|
}
|
|
1858
|
-
setSoftPedal(channelNumber, softPedal,
|
|
1914
|
+
setSoftPedal(channelNumber, softPedal, scheduleTime) {
|
|
1859
1915
|
const channel = this.channels[channelNumber];
|
|
1916
|
+
if (channel.isDrum)
|
|
1917
|
+
return;
|
|
1918
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1860
1919
|
channel.state.softPedal = softPedal / 127;
|
|
1920
|
+
this.processScheduledNotes(channel, (note) => {
|
|
1921
|
+
if (note.portamento) {
|
|
1922
|
+
this.setPortamentoStartVolumeEnvelope(channel, note, scheduleTime);
|
|
1923
|
+
this.setPortamentoStartFilterEnvelope(channel, note, scheduleTime);
|
|
1924
|
+
}
|
|
1925
|
+
else {
|
|
1926
|
+
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
1927
|
+
this.setFilterEnvelope(channel, note, scheduleTime);
|
|
1928
|
+
}
|
|
1929
|
+
});
|
|
1861
1930
|
}
|
|
1862
1931
|
setFilterResonance(channelNumber, filterResonance, scheduleTime) {
|
|
1863
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1864
1932
|
const channel = this.channels[channelNumber];
|
|
1933
|
+
if (channel.isDrum)
|
|
1934
|
+
return;
|
|
1935
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1865
1936
|
const state = channel.state;
|
|
1866
1937
|
state.filterResonance = filterResonance / 64;
|
|
1867
1938
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -1870,13 +1941,17 @@ export class Midy {
|
|
|
1870
1941
|
});
|
|
1871
1942
|
}
|
|
1872
1943
|
setReleaseTime(channelNumber, releaseTime, _scheduleTime) {
|
|
1873
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1874
1944
|
const channel = this.channels[channelNumber];
|
|
1945
|
+
if (channel.isDrum)
|
|
1946
|
+
return;
|
|
1947
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1875
1948
|
channel.state.releaseTime = releaseTime / 64;
|
|
1876
1949
|
}
|
|
1877
1950
|
setAttackTime(channelNumber, attackTime, scheduleTime) {
|
|
1878
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1879
1951
|
const channel = this.channels[channelNumber];
|
|
1952
|
+
if (channel.isDrum)
|
|
1953
|
+
return;
|
|
1954
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1880
1955
|
channel.state.attackTime = attackTime / 64;
|
|
1881
1956
|
this.processScheduledNotes(channel, (note) => {
|
|
1882
1957
|
if (note.startTime < scheduleTime)
|
|
@@ -1885,8 +1960,10 @@ export class Midy {
|
|
|
1885
1960
|
});
|
|
1886
1961
|
}
|
|
1887
1962
|
setBrightness(channelNumber, brightness, scheduleTime) {
|
|
1888
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1889
1963
|
const channel = this.channels[channelNumber];
|
|
1964
|
+
if (channel.isDrum)
|
|
1965
|
+
return;
|
|
1966
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1890
1967
|
channel.state.brightness = brightness / 64;
|
|
1891
1968
|
this.processScheduledNotes(channel, (note) => {
|
|
1892
1969
|
if (note.portamento) {
|
|
@@ -1898,16 +1975,20 @@ export class Midy {
|
|
|
1898
1975
|
});
|
|
1899
1976
|
}
|
|
1900
1977
|
setDecayTime(channelNumber, dacayTime, scheduleTime) {
|
|
1901
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1902
1978
|
const channel = this.channels[channelNumber];
|
|
1979
|
+
if (channel.isDrum)
|
|
1980
|
+
return;
|
|
1981
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1903
1982
|
channel.state.decayTime = dacayTime / 64;
|
|
1904
1983
|
this.processScheduledNotes(channel, (note) => {
|
|
1905
1984
|
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
1906
1985
|
});
|
|
1907
1986
|
}
|
|
1908
1987
|
setVibratoRate(channelNumber, vibratoRate, scheduleTime) {
|
|
1909
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1910
1988
|
const channel = this.channels[channelNumber];
|
|
1989
|
+
if (channel.isDrum)
|
|
1990
|
+
return;
|
|
1991
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1911
1992
|
channel.state.vibratoRate = vibratoRate / 64;
|
|
1912
1993
|
if (channel.vibratoDepth <= 0)
|
|
1913
1994
|
return;
|
|
@@ -1916,8 +1997,10 @@ export class Midy {
|
|
|
1916
1997
|
});
|
|
1917
1998
|
}
|
|
1918
1999
|
setVibratoDepth(channelNumber, vibratoDepth, scheduleTime) {
|
|
1919
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1920
2000
|
const channel = this.channels[channelNumber];
|
|
2001
|
+
if (channel.isDrum)
|
|
2002
|
+
return;
|
|
2003
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1921
2004
|
const prev = channel.state.vibratoDepth;
|
|
1922
2005
|
channel.state.vibratoDepth = vibratoDepth / 64;
|
|
1923
2006
|
if (0 < prev) {
|
|
@@ -1932,8 +2015,10 @@ export class Midy {
|
|
|
1932
2015
|
}
|
|
1933
2016
|
}
|
|
1934
2017
|
setVibratoDelay(channelNumber, vibratoDelay) {
|
|
1935
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1936
2018
|
const channel = this.channels[channelNumber];
|
|
2019
|
+
if (channel.isDrum)
|
|
2020
|
+
return;
|
|
2021
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1937
2022
|
channel.state.vibratoDelay = vibratoDelay / 64;
|
|
1938
2023
|
if (0 < channel.state.vibratoDepth) {
|
|
1939
2024
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -2080,8 +2165,10 @@ export class Midy {
|
|
|
2080
2165
|
this.setPitchBendRange(channelNumber, pitchBendRange, scheduleTime);
|
|
2081
2166
|
}
|
|
2082
2167
|
setPitchBendRange(channelNumber, value, scheduleTime) {
|
|
2083
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
2084
2168
|
const channel = this.channels[channelNumber];
|
|
2169
|
+
if (channel.isDrum)
|
|
2170
|
+
return;
|
|
2171
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2085
2172
|
const state = channel.state;
|
|
2086
2173
|
const prev = state.pitchWheelSensitivity;
|
|
2087
2174
|
const next = value / 128;
|
|
@@ -2097,8 +2184,10 @@ export class Midy {
|
|
|
2097
2184
|
this.setFineTuning(channelNumber, fineTuning, scheduleTime);
|
|
2098
2185
|
}
|
|
2099
2186
|
setFineTuning(channelNumber, value, scheduleTime) {
|
|
2100
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
2101
2187
|
const channel = this.channels[channelNumber];
|
|
2188
|
+
if (channel.isDrum)
|
|
2189
|
+
return;
|
|
2190
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2102
2191
|
const prev = channel.fineTuning;
|
|
2103
2192
|
const next = (value - 8192) / 8.192; // cent
|
|
2104
2193
|
channel.fineTuning = next;
|
|
@@ -2112,8 +2201,10 @@ export class Midy {
|
|
|
2112
2201
|
this.setCoarseTuning(channelNumber, coarseTuning, scheduleTime);
|
|
2113
2202
|
}
|
|
2114
2203
|
setCoarseTuning(channelNumber, value, scheduleTime) {
|
|
2115
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
2116
2204
|
const channel = this.channels[channelNumber];
|
|
2205
|
+
if (channel.isDrum)
|
|
2206
|
+
return;
|
|
2207
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2117
2208
|
const prev = channel.coarseTuning;
|
|
2118
2209
|
const next = (value - 64) * 100; // cent
|
|
2119
2210
|
channel.coarseTuning = next;
|
|
@@ -2127,8 +2218,10 @@ export class Midy {
|
|
|
2127
2218
|
this.setModulationDepthRange(channelNumber, modulationDepthRange, scheduleTime);
|
|
2128
2219
|
}
|
|
2129
2220
|
setModulationDepthRange(channelNumber, modulationDepthRange, scheduleTime) {
|
|
2130
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
2131
2221
|
const channel = this.channels[channelNumber];
|
|
2222
|
+
if (channel.isDrum)
|
|
2223
|
+
return;
|
|
2224
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2132
2225
|
channel.modulationDepthRange = modulationDepthRange;
|
|
2133
2226
|
this.updateModulation(channel, scheduleTime);
|
|
2134
2227
|
}
|
|
@@ -2199,12 +2292,12 @@ export class Midy {
|
|
|
2199
2292
|
case 9:
|
|
2200
2293
|
switch (data[3]) {
|
|
2201
2294
|
case 1:
|
|
2202
|
-
this.GM1SystemOn();
|
|
2295
|
+
this.GM1SystemOn(scheduleTime);
|
|
2203
2296
|
break;
|
|
2204
2297
|
case 2: // GM System Off
|
|
2205
2298
|
break;
|
|
2206
2299
|
case 3:
|
|
2207
|
-
this.GM2SystemOn();
|
|
2300
|
+
this.GM2SystemOn(scheduleTime);
|
|
2208
2301
|
break;
|
|
2209
2302
|
default:
|
|
2210
2303
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
@@ -2214,25 +2307,35 @@ export class Midy {
|
|
|
2214
2307
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
2215
2308
|
}
|
|
2216
2309
|
}
|
|
2217
|
-
GM1SystemOn() {
|
|
2310
|
+
GM1SystemOn(scheduleTime) {
|
|
2311
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2312
|
+
this.mode = "GM1";
|
|
2218
2313
|
for (let i = 0; i < this.channels.length; i++) {
|
|
2314
|
+
this.allSoundOff(i, 0, scheduleTime);
|
|
2219
2315
|
const channel = this.channels[i];
|
|
2220
2316
|
channel.bankMSB = 0;
|
|
2221
2317
|
channel.bankLSB = 0;
|
|
2222
2318
|
channel.bank = 0;
|
|
2319
|
+
channel.isDrum = false;
|
|
2223
2320
|
}
|
|
2224
2321
|
this.channels[9].bankMSB = 1;
|
|
2225
2322
|
this.channels[9].bank = 128;
|
|
2323
|
+
this.channels[9].isDrum = true;
|
|
2226
2324
|
}
|
|
2227
|
-
GM2SystemOn() {
|
|
2325
|
+
GM2SystemOn(scheduleTime) {
|
|
2326
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2327
|
+
this.mode = "GM2";
|
|
2228
2328
|
for (let i = 0; i < this.channels.length; i++) {
|
|
2329
|
+
this.allSoundOff(i, 0, scheduleTime);
|
|
2229
2330
|
const channel = this.channels[i];
|
|
2230
2331
|
channel.bankMSB = 121;
|
|
2231
2332
|
channel.bankLSB = 0;
|
|
2232
2333
|
channel.bank = 121 * 128;
|
|
2334
|
+
channel.isDrum = false;
|
|
2233
2335
|
}
|
|
2234
2336
|
this.channels[9].bankMSB = 120;
|
|
2235
2337
|
this.channels[9].bank = 120 * 128;
|
|
2338
|
+
this.channels[9].isDrum = true;
|
|
2236
2339
|
}
|
|
2237
2340
|
handleUniversalRealTimeExclusiveMessage(data, scheduleTime) {
|
|
2238
2341
|
switch (data[2]) {
|
|
@@ -2308,8 +2411,14 @@ export class Midy {
|
|
|
2308
2411
|
const prev = this.masterFineTuning;
|
|
2309
2412
|
const next = (value - 8192) / 8.192; // cent
|
|
2310
2413
|
this.masterFineTuning = next;
|
|
2311
|
-
|
|
2312
|
-
this.
|
|
2414
|
+
const detuneChange = next - prev;
|
|
2415
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
2416
|
+
const channel = this.channels[i];
|
|
2417
|
+
if (channel.isDrum)
|
|
2418
|
+
continue;
|
|
2419
|
+
channel.detune += detuneChange;
|
|
2420
|
+
this.updateChannelDetune(channel, scheduleTime);
|
|
2421
|
+
}
|
|
2313
2422
|
}
|
|
2314
2423
|
handleMasterCoarseTuningSysEx(data, scheduleTime) {
|
|
2315
2424
|
const coarseTuning = data[4];
|
|
@@ -2319,8 +2428,14 @@ export class Midy {
|
|
|
2319
2428
|
const prev = this.masterCoarseTuning;
|
|
2320
2429
|
const next = (value - 64) * 100; // cent
|
|
2321
2430
|
this.masterCoarseTuning = next;
|
|
2322
|
-
|
|
2323
|
-
this.
|
|
2431
|
+
const detuneChange = next - prev;
|
|
2432
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
2433
|
+
const channel = this.channels[i];
|
|
2434
|
+
if (channel.isDrum)
|
|
2435
|
+
continue;
|
|
2436
|
+
channel.detune += detuneChange;
|
|
2437
|
+
this.updateChannelDetune(channel, scheduleTime);
|
|
2438
|
+
}
|
|
2324
2439
|
}
|
|
2325
2440
|
handleGlobalParameterControlSysEx(data, scheduleTime) {
|
|
2326
2441
|
if (data[7] === 1) {
|
|
@@ -2532,6 +2647,8 @@ export class Midy {
|
|
|
2532
2647
|
if (!channelBitmap[i])
|
|
2533
2648
|
continue;
|
|
2534
2649
|
const channel = this.channels[i];
|
|
2650
|
+
if (channel.isDrum)
|
|
2651
|
+
continue;
|
|
2535
2652
|
for (let j = 0; j < 12; j++) {
|
|
2536
2653
|
const centValue = data[j + 7] - 64;
|
|
2537
2654
|
channel.scaleOctaveTuningTable[j] = centValue;
|
|
@@ -2550,6 +2667,8 @@ export class Midy {
|
|
|
2550
2667
|
if (!channelBitmap[i])
|
|
2551
2668
|
continue;
|
|
2552
2669
|
const channel = this.channels[i];
|
|
2670
|
+
if (channel.isDrum)
|
|
2671
|
+
continue;
|
|
2553
2672
|
for (let j = 0; j < 12; j++) {
|
|
2554
2673
|
const index = 7 + j * 2;
|
|
2555
2674
|
const msb = data[index] & 0x7F;
|
|
@@ -2620,7 +2739,10 @@ export class Midy {
|
|
|
2620
2739
|
}
|
|
2621
2740
|
handlePressureSysEx(data, tableName) {
|
|
2622
2741
|
const channelNumber = data[4];
|
|
2623
|
-
const
|
|
2742
|
+
const channel = this.channels[channelNumber];
|
|
2743
|
+
if (channel.isDrum)
|
|
2744
|
+
return;
|
|
2745
|
+
const table = channel[tableName];
|
|
2624
2746
|
for (let i = 5; i < data.length - 1; i += 2) {
|
|
2625
2747
|
const pp = data[i];
|
|
2626
2748
|
const rr = data[i + 1];
|
|
@@ -2648,8 +2770,11 @@ export class Midy {
|
|
|
2648
2770
|
}
|
|
2649
2771
|
handleControlChangeSysEx(data) {
|
|
2650
2772
|
const channelNumber = data[4];
|
|
2773
|
+
const channel = this.channels[channelNumber];
|
|
2774
|
+
if (channel.isDrum)
|
|
2775
|
+
return;
|
|
2651
2776
|
const controllerType = data[5];
|
|
2652
|
-
const table =
|
|
2777
|
+
const table = channel.controlTable[controllerType];
|
|
2653
2778
|
for (let i = 6; i < data.length - 1; i += 2) {
|
|
2654
2779
|
const pp = data[i];
|
|
2655
2780
|
const rr = data[i + 1];
|
|
@@ -2663,8 +2788,11 @@ export class Midy {
|
|
|
2663
2788
|
}
|
|
2664
2789
|
handleKeyBasedInstrumentControlSysEx(data, scheduleTime) {
|
|
2665
2790
|
const channelNumber = data[4];
|
|
2791
|
+
const channel = this.channels[channelNumber];
|
|
2792
|
+
if (channel.isDrum)
|
|
2793
|
+
return;
|
|
2666
2794
|
const keyNumber = data[5];
|
|
2667
|
-
const table =
|
|
2795
|
+
const table = channel.keyBasedInstrumentControlTable;
|
|
2668
2796
|
for (let i = 6; i < data.length - 1; i += 2) {
|
|
2669
2797
|
const controllerType = data[i];
|
|
2670
2798
|
const value = data[i + 1];
|
|
@@ -2685,13 +2813,20 @@ export class Midy {
|
|
|
2685
2813
|
}
|
|
2686
2814
|
scheduleTask(callback, scheduleTime) {
|
|
2687
2815
|
return new Promise((resolve) => {
|
|
2688
|
-
const bufferSource = new AudioBufferSourceNode(this.audioContext
|
|
2816
|
+
const bufferSource = new AudioBufferSourceNode(this.audioContext, {
|
|
2817
|
+
buffer: this.schedulerBuffer,
|
|
2818
|
+
});
|
|
2819
|
+
bufferSource.connect(this.scheduler);
|
|
2689
2820
|
bufferSource.onended = () => {
|
|
2690
|
-
|
|
2691
|
-
|
|
2821
|
+
try {
|
|
2822
|
+
callback();
|
|
2823
|
+
}
|
|
2824
|
+
finally {
|
|
2825
|
+
bufferSource.disconnect();
|
|
2826
|
+
resolve();
|
|
2827
|
+
}
|
|
2692
2828
|
};
|
|
2693
2829
|
bufferSource.start(scheduleTime);
|
|
2694
|
-
bufferSource.stop(scheduleTime);
|
|
2695
2830
|
});
|
|
2696
2831
|
}
|
|
2697
2832
|
}
|
|
@@ -2701,6 +2836,7 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
2701
2836
|
writable: true,
|
|
2702
2837
|
value: {
|
|
2703
2838
|
currentBufferSource: null,
|
|
2839
|
+
isDrum: false,
|
|
2704
2840
|
detune: 0,
|
|
2705
2841
|
program: 0,
|
|
2706
2842
|
bank: 121 * 128,
|
|
@@ -2711,8 +2847,8 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
2711
2847
|
rpnMSB: 127,
|
|
2712
2848
|
rpnLSB: 127,
|
|
2713
2849
|
mono: false, // CC#124, CC#125
|
|
2850
|
+
modulationDepthRange: 50, // cent
|
|
2714
2851
|
fineTuning: 0, // cb
|
|
2715
2852
|
coarseTuning: 0, // cb
|
|
2716
|
-
modulationDepthRange: 50, // cent
|
|
2717
2853
|
}
|
|
2718
2854
|
});
|