@marmooo/midy 0.2.9 → 0.3.0
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 -6
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +72 -55
- package/esm/midy-GM2.d.ts +14 -10
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +189 -87
- package/esm/midy-GMLite.d.ts +11 -8
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +124 -61
- package/esm/midy.d.ts +14 -10
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +190 -87
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +8 -6
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +72 -55
- package/script/midy-GM2.d.ts +14 -10
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +189 -87
- package/script/midy-GMLite.d.ts +11 -8
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +124 -61
- package/script/midy.d.ts +14 -10
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +190 -87
package/script/midy-GM2.js
CHANGED
|
@@ -154,6 +154,39 @@ class Note {
|
|
|
154
154
|
this.voiceParams = voiceParams;
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
+
const drumExclusiveClassesByKit = new Array(57);
|
|
158
|
+
const drumExclusiveClassCount = 10;
|
|
159
|
+
const standardSet = new Uint8Array(128);
|
|
160
|
+
standardSet[42] = 1;
|
|
161
|
+
standardSet[44] = 1;
|
|
162
|
+
standardSet[46] = 1; // HH
|
|
163
|
+
standardSet[71] = 2;
|
|
164
|
+
standardSet[72] = 2; // Whistle
|
|
165
|
+
standardSet[73] = 3;
|
|
166
|
+
standardSet[74] = 3; // Guiro
|
|
167
|
+
standardSet[78] = 4;
|
|
168
|
+
standardSet[79] = 4; // Cuica
|
|
169
|
+
standardSet[80] = 5;
|
|
170
|
+
standardSet[81] = 5; // Triangle
|
|
171
|
+
standardSet[29] = 6;
|
|
172
|
+
standardSet[30] = 6; // Scratch
|
|
173
|
+
standardSet[86] = 7;
|
|
174
|
+
standardSet[87] = 7; // Surdo
|
|
175
|
+
drumExclusiveClassesByKit[0] = standardSet;
|
|
176
|
+
const analogSet = new Uint8Array(128);
|
|
177
|
+
analogSet[42] = 8;
|
|
178
|
+
analogSet[44] = 8;
|
|
179
|
+
analogSet[46] = 8; // CHH
|
|
180
|
+
drumExclusiveClassesByKit[25] = analogSet;
|
|
181
|
+
const orchestraSet = new Uint8Array(128);
|
|
182
|
+
orchestraSet[27] = 9;
|
|
183
|
+
orchestraSet[28] = 9;
|
|
184
|
+
orchestraSet[29] = 9; // HH
|
|
185
|
+
drumExclusiveClassesByKit[48] = orchestraSet;
|
|
186
|
+
const sfxSet = new Uint8Array(128);
|
|
187
|
+
sfxSet[41] = 10;
|
|
188
|
+
sfxSet[42] = 10; // Scratch
|
|
189
|
+
drumExclusiveClassesByKit[56] = sfxSet;
|
|
157
190
|
// normalized to 0-1 for use with the SF2 modulator model
|
|
158
191
|
const defaultControllerState = {
|
|
159
192
|
noteOnVelocity: { type: 2, defaultValue: 0 },
|
|
@@ -248,18 +281,6 @@ class MidyGM2 {
|
|
|
248
281
|
writable: true,
|
|
249
282
|
value: "GM2"
|
|
250
283
|
});
|
|
251
|
-
Object.defineProperty(this, "ticksPerBeat", {
|
|
252
|
-
enumerable: true,
|
|
253
|
-
configurable: true,
|
|
254
|
-
writable: true,
|
|
255
|
-
value: 120
|
|
256
|
-
});
|
|
257
|
-
Object.defineProperty(this, "totalTime", {
|
|
258
|
-
enumerable: true,
|
|
259
|
-
configurable: true,
|
|
260
|
-
writable: true,
|
|
261
|
-
value: 0
|
|
262
|
-
});
|
|
263
284
|
Object.defineProperty(this, "masterFineTuning", {
|
|
264
285
|
enumerable: true,
|
|
265
286
|
configurable: true,
|
|
@@ -293,6 +314,24 @@ class MidyGM2 {
|
|
|
293
314
|
delayTimes: this.generateDistributedArray(0.02, 2, 0.5),
|
|
294
315
|
}
|
|
295
316
|
});
|
|
317
|
+
Object.defineProperty(this, "numChannels", {
|
|
318
|
+
enumerable: true,
|
|
319
|
+
configurable: true,
|
|
320
|
+
writable: true,
|
|
321
|
+
value: 16
|
|
322
|
+
});
|
|
323
|
+
Object.defineProperty(this, "ticksPerBeat", {
|
|
324
|
+
enumerable: true,
|
|
325
|
+
configurable: true,
|
|
326
|
+
writable: true,
|
|
327
|
+
value: 120
|
|
328
|
+
});
|
|
329
|
+
Object.defineProperty(this, "totalTime", {
|
|
330
|
+
enumerable: true,
|
|
331
|
+
configurable: true,
|
|
332
|
+
writable: true,
|
|
333
|
+
value: 0
|
|
334
|
+
});
|
|
296
335
|
Object.defineProperty(this, "noteCheckInterval", {
|
|
297
336
|
enumerable: true,
|
|
298
337
|
configurable: true,
|
|
@@ -395,11 +434,17 @@ class MidyGM2 {
|
|
|
395
434
|
writable: true,
|
|
396
435
|
value: []
|
|
397
436
|
});
|
|
398
|
-
Object.defineProperty(this, "
|
|
437
|
+
Object.defineProperty(this, "exclusiveClassNotes", {
|
|
438
|
+
enumerable: true,
|
|
439
|
+
configurable: true,
|
|
440
|
+
writable: true,
|
|
441
|
+
value: new Array(128)
|
|
442
|
+
});
|
|
443
|
+
Object.defineProperty(this, "drumExclusiveClassNotes", {
|
|
399
444
|
enumerable: true,
|
|
400
445
|
configurable: true,
|
|
401
446
|
writable: true,
|
|
402
|
-
value: new
|
|
447
|
+
value: new Array(this.numChannels * drumExclusiveClassCount)
|
|
403
448
|
});
|
|
404
449
|
Object.defineProperty(this, "defaultOptions", {
|
|
405
450
|
enumerable: true,
|
|
@@ -493,8 +538,10 @@ class MidyGM2 {
|
|
|
493
538
|
};
|
|
494
539
|
}
|
|
495
540
|
createChannels(audioContext) {
|
|
496
|
-
const channels = Array.from({ length:
|
|
541
|
+
const channels = Array.from({ length: this.numChannels }, () => {
|
|
497
542
|
return {
|
|
543
|
+
currentBufferSource: null,
|
|
544
|
+
isDrum: false,
|
|
498
545
|
...this.constructor.channelSettings,
|
|
499
546
|
state: new ControllerState(),
|
|
500
547
|
controlTable: this.initControlTable(),
|
|
@@ -538,24 +585,10 @@ class MidyGM2 {
|
|
|
538
585
|
return audioBuffer;
|
|
539
586
|
}
|
|
540
587
|
}
|
|
541
|
-
|
|
542
|
-
if (channel.isDrum) {
|
|
543
|
-
const noteNumber = note.noteNumber;
|
|
544
|
-
if (noteNumber === 88 || 47 <= noteNumber && noteNumber <= 84) {
|
|
545
|
-
return true;
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
return false;
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
else {
|
|
552
|
-
return voiceParams.sampleModes % 2 !== 0;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
createBufferSource(channel, note, voiceParams, audioBuffer) {
|
|
588
|
+
createBufferSource(voiceParams, audioBuffer) {
|
|
556
589
|
const bufferSource = new AudioBufferSourceNode(this.audioContext);
|
|
557
590
|
bufferSource.buffer = audioBuffer;
|
|
558
|
-
bufferSource.loop =
|
|
591
|
+
bufferSource.loop = voiceParams.sampleModes % 2 !== 0;
|
|
559
592
|
if (bufferSource.loop) {
|
|
560
593
|
bufferSource.loopStart = voiceParams.loopStart / voiceParams.sampleRate;
|
|
561
594
|
bufferSource.loopEnd = voiceParams.loopEnd / voiceParams.sampleRate;
|
|
@@ -643,7 +676,8 @@ class MidyGM2 {
|
|
|
643
676
|
if (queueIndex >= this.timeline.length) {
|
|
644
677
|
await Promise.all(this.notePromises);
|
|
645
678
|
this.notePromises = [];
|
|
646
|
-
this.
|
|
679
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
680
|
+
this.drumExclusiveClassNotes.fill(undefined);
|
|
647
681
|
this.audioBufferCache.clear();
|
|
648
682
|
resolve();
|
|
649
683
|
return;
|
|
@@ -662,7 +696,8 @@ class MidyGM2 {
|
|
|
662
696
|
else if (this.isStopping) {
|
|
663
697
|
await this.stopNotes(0, true, now);
|
|
664
698
|
this.notePromises = [];
|
|
665
|
-
this.
|
|
699
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
700
|
+
this.drumExclusiveClassNotes.fill(undefined);
|
|
666
701
|
this.audioBufferCache.clear();
|
|
667
702
|
resolve();
|
|
668
703
|
this.isStopping = false;
|
|
@@ -671,7 +706,8 @@ class MidyGM2 {
|
|
|
671
706
|
}
|
|
672
707
|
else if (this.isSeeking) {
|
|
673
708
|
this.stopNotes(0, true, now);
|
|
674
|
-
this.
|
|
709
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
710
|
+
this.drumExclusiveClassNotes.fill(undefined);
|
|
675
711
|
this.startTime = this.audioContext.currentTime;
|
|
676
712
|
queueIndex = this.getQueueIndex(this.resumeTime);
|
|
677
713
|
offset = this.resumeTime - this.startTime;
|
|
@@ -699,7 +735,7 @@ class MidyGM2 {
|
|
|
699
735
|
extractMidiData(midi) {
|
|
700
736
|
const instruments = new Set();
|
|
701
737
|
const timeline = [];
|
|
702
|
-
const tmpChannels = new Array(
|
|
738
|
+
const tmpChannels = new Array(this.channels.length);
|
|
703
739
|
for (let i = 0; i < tmpChannels.length; i++) {
|
|
704
740
|
tmpChannels[i] = {
|
|
705
741
|
programNumber: -1,
|
|
@@ -827,6 +863,9 @@ class MidyGM2 {
|
|
|
827
863
|
if (!this.isPlaying)
|
|
828
864
|
return;
|
|
829
865
|
this.isStopping = true;
|
|
866
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
867
|
+
this.resetAllStates(i);
|
|
868
|
+
}
|
|
830
869
|
}
|
|
831
870
|
pause() {
|
|
832
871
|
if (!this.isPlaying || this.isPaused)
|
|
@@ -1197,8 +1236,8 @@ class MidyGM2 {
|
|
|
1197
1236
|
note.vibratoLFO.connect(note.vibratoDepth);
|
|
1198
1237
|
note.vibratoDepth.connect(note.bufferSource.detune);
|
|
1199
1238
|
}
|
|
1200
|
-
async getAudioBuffer(
|
|
1201
|
-
const audioBufferId = this.getAudioBufferId(
|
|
1239
|
+
async getAudioBuffer(programNumber, noteNumber, velocity, voiceParams, isSF3) {
|
|
1240
|
+
const audioBufferId = this.getAudioBufferId(programNumber, noteNumber, velocity);
|
|
1202
1241
|
const cache = this.audioBufferCache.get(audioBufferId);
|
|
1203
1242
|
if (cache) {
|
|
1204
1243
|
cache.counter += 1;
|
|
@@ -1221,8 +1260,8 @@ class MidyGM2 {
|
|
|
1221
1260
|
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
1222
1261
|
const voiceParams = voice.getAllParams(controllerState);
|
|
1223
1262
|
const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
|
|
1224
|
-
const audioBuffer = await this.getAudioBuffer(channel.
|
|
1225
|
-
note.bufferSource = this.createBufferSource(
|
|
1263
|
+
const audioBuffer = await this.getAudioBuffer(channel.programNumber, noteNumber, velocity, voiceParams, isSF3);
|
|
1264
|
+
note.bufferSource = this.createBufferSource(voiceParams, audioBuffer);
|
|
1226
1265
|
note.volumeNode = new GainNode(this.audioContext);
|
|
1227
1266
|
note.gainL = new GainNode(this.audioContext);
|
|
1228
1267
|
note.gainR = new GainNode(this.audioContext);
|
|
@@ -1282,14 +1321,56 @@ class MidyGM2 {
|
|
|
1282
1321
|
return channel.bank;
|
|
1283
1322
|
}
|
|
1284
1323
|
}
|
|
1324
|
+
handleExclusiveClass(note, channelNumber, startTime) {
|
|
1325
|
+
const exclusiveClass = note.voiceParams.exclusiveClass;
|
|
1326
|
+
if (exclusiveClass === 0)
|
|
1327
|
+
return;
|
|
1328
|
+
const prev = this.exclusiveClassNotes[exclusiveClass];
|
|
1329
|
+
if (prev) {
|
|
1330
|
+
const [prevNote, prevChannelNumber] = prev;
|
|
1331
|
+
if (prevNote && !prevNote.ending) {
|
|
1332
|
+
this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
1333
|
+
startTime, true, // force
|
|
1334
|
+
undefined);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
this.exclusiveClassNotes[exclusiveClass] = [note, channelNumber];
|
|
1338
|
+
}
|
|
1339
|
+
handleDrumExclusiveClass(note, channelNumber, startTime) {
|
|
1340
|
+
const channel = this.channels[channelNumber];
|
|
1341
|
+
if (!channel.isDrum)
|
|
1342
|
+
return;
|
|
1343
|
+
const kitTable = drumExclusiveClassesByKit[channel.programNumber];
|
|
1344
|
+
if (!kitTable)
|
|
1345
|
+
return;
|
|
1346
|
+
const drumExclusiveClass = kitTable[note.noteNumber];
|
|
1347
|
+
if (drumExclusiveClass === 0)
|
|
1348
|
+
return;
|
|
1349
|
+
const index = (drumExclusiveClass - 1) * this.channels.length +
|
|
1350
|
+
channelNumber;
|
|
1351
|
+
const prevNote = this.drumExclusiveClassNotes[index];
|
|
1352
|
+
if (prevNote && !prevNote.ending) {
|
|
1353
|
+
this.scheduleNoteOff(channelNumber, prevNote.noteNumber, 0, // velocity,
|
|
1354
|
+
startTime, true, // force
|
|
1355
|
+
undefined);
|
|
1356
|
+
}
|
|
1357
|
+
this.drumExclusiveClassNotes[index] = note;
|
|
1358
|
+
}
|
|
1359
|
+
isDrumNoteOffException(channel, noteNumber) {
|
|
1360
|
+
if (!channel.isDrum)
|
|
1361
|
+
return false;
|
|
1362
|
+
const programNumber = channel.programNumber;
|
|
1363
|
+
return (programNumber === 48 && noteNumber === 88) ||
|
|
1364
|
+
(programNumber === 56 && 47 <= noteNumber && noteNumber <= 84);
|
|
1365
|
+
}
|
|
1285
1366
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, portamento) {
|
|
1286
1367
|
const channel = this.channels[channelNumber];
|
|
1287
1368
|
const bankNumber = this.calcBank(channel, channelNumber);
|
|
1288
|
-
const soundFontIndex = this.soundFontTable[channel.
|
|
1369
|
+
const soundFontIndex = this.soundFontTable[channel.programNumber].get(bankNumber);
|
|
1289
1370
|
if (soundFontIndex === undefined)
|
|
1290
1371
|
return;
|
|
1291
1372
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
1292
|
-
const voice = soundFont.getVoice(bankNumber, channel.
|
|
1373
|
+
const voice = soundFont.getVoice(bankNumber, channel.programNumber, noteNumber, velocity);
|
|
1293
1374
|
if (!voice)
|
|
1294
1375
|
return;
|
|
1295
1376
|
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
@@ -1299,31 +1380,58 @@ class MidyGM2 {
|
|
|
1299
1380
|
if (0.5 <= channel.state.sustainPedal) {
|
|
1300
1381
|
channel.sustainNotes.push(note);
|
|
1301
1382
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
if (this.exclusiveClassMap.has(exclusiveClass)) {
|
|
1305
|
-
const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
|
|
1306
|
-
const [prevNote, prevChannelNumber] = prevEntry;
|
|
1307
|
-
if (prevNote && !prevNote.ending) {
|
|
1308
|
-
this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
1309
|
-
startTime, true, // force
|
|
1310
|
-
undefined);
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
this.exclusiveClassMap.set(exclusiveClass, [note, channelNumber]);
|
|
1314
|
-
}
|
|
1383
|
+
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
1384
|
+
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
1315
1385
|
const scheduledNotes = channel.scheduledNotes;
|
|
1316
|
-
|
|
1317
|
-
|
|
1386
|
+
let notes = scheduledNotes.get(noteNumber);
|
|
1387
|
+
if (notes) {
|
|
1388
|
+
notes.push(note);
|
|
1318
1389
|
}
|
|
1319
1390
|
else {
|
|
1320
|
-
|
|
1391
|
+
notes = [note];
|
|
1392
|
+
scheduledNotes.set(noteNumber, notes);
|
|
1393
|
+
}
|
|
1394
|
+
if (this.isDrumNoteOffException(channel, noteNumber)) {
|
|
1395
|
+
const stopTime = startTime + note.bufferSource.buffer.duration;
|
|
1396
|
+
const index = notes.length - 1;
|
|
1397
|
+
const promise = new Promise((resolve) => {
|
|
1398
|
+
note.bufferSource.onended = () => {
|
|
1399
|
+
this.disconnectNote(note, scheduledNotes, index);
|
|
1400
|
+
resolve();
|
|
1401
|
+
};
|
|
1402
|
+
note.bufferSource.stop(stopTime);
|
|
1403
|
+
});
|
|
1404
|
+
this.notePromises.push(promise);
|
|
1321
1405
|
}
|
|
1322
1406
|
}
|
|
1323
1407
|
noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
1324
1408
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1325
1409
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, false);
|
|
1326
1410
|
}
|
|
1411
|
+
disconnectNote(note, scheduledNotes, index) {
|
|
1412
|
+
scheduledNotes[index] = null;
|
|
1413
|
+
note.bufferSource.disconnect();
|
|
1414
|
+
note.filterNode.disconnect();
|
|
1415
|
+
note.volumeEnvelopeNode.disconnect();
|
|
1416
|
+
note.volumeNode.disconnect();
|
|
1417
|
+
note.gainL.disconnect();
|
|
1418
|
+
note.gainR.disconnect();
|
|
1419
|
+
if (note.modulationDepth) {
|
|
1420
|
+
note.volumeDepth.disconnect();
|
|
1421
|
+
note.modulationDepth.disconnect();
|
|
1422
|
+
note.modulationLFO.stop();
|
|
1423
|
+
}
|
|
1424
|
+
if (note.vibratoDepth) {
|
|
1425
|
+
note.vibratoDepth.disconnect();
|
|
1426
|
+
note.vibratoLFO.stop();
|
|
1427
|
+
}
|
|
1428
|
+
if (note.reverbEffectsSend) {
|
|
1429
|
+
note.reverbEffectsSend.disconnect();
|
|
1430
|
+
}
|
|
1431
|
+
if (note.chorusEffectsSend) {
|
|
1432
|
+
note.chorusEffectsSend.disconnect();
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1327
1435
|
stopNote(endTime, stopTime, scheduledNotes, index) {
|
|
1328
1436
|
const note = scheduledNotes[index];
|
|
1329
1437
|
note.volumeEnvelopeNode.gain
|
|
@@ -1335,28 +1443,7 @@ class MidyGM2 {
|
|
|
1335
1443
|
}, stopTime);
|
|
1336
1444
|
return new Promise((resolve) => {
|
|
1337
1445
|
note.bufferSource.onended = () => {
|
|
1338
|
-
scheduledNotes
|
|
1339
|
-
note.bufferSource.disconnect();
|
|
1340
|
-
note.filterNode.disconnect();
|
|
1341
|
-
note.volumeEnvelopeNode.disconnect();
|
|
1342
|
-
note.volumeNode.disconnect();
|
|
1343
|
-
note.gainL.disconnect();
|
|
1344
|
-
note.gainR.disconnect();
|
|
1345
|
-
if (note.modulationDepth) {
|
|
1346
|
-
note.volumeDepth.disconnect();
|
|
1347
|
-
note.modulationDepth.disconnect();
|
|
1348
|
-
note.modulationLFO.stop();
|
|
1349
|
-
}
|
|
1350
|
-
if (note.vibratoDepth) {
|
|
1351
|
-
note.vibratoDepth.disconnect();
|
|
1352
|
-
note.vibratoLFO.stop();
|
|
1353
|
-
}
|
|
1354
|
-
if (note.reverbEffectsSend) {
|
|
1355
|
-
note.reverbEffectsSend.disconnect();
|
|
1356
|
-
}
|
|
1357
|
-
if (note.chorusEffectsSend) {
|
|
1358
|
-
note.chorusEffectsSend.disconnect();
|
|
1359
|
-
}
|
|
1446
|
+
this.disconnectNote(note, scheduledNotes, index);
|
|
1360
1447
|
resolve();
|
|
1361
1448
|
};
|
|
1362
1449
|
note.bufferSource.stop(stopTime);
|
|
@@ -1364,6 +1451,8 @@ class MidyGM2 {
|
|
|
1364
1451
|
}
|
|
1365
1452
|
scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force, portamentoNoteNumber) {
|
|
1366
1453
|
const channel = this.channels[channelNumber];
|
|
1454
|
+
if (this.isDrumNoteOffException(channel, noteNumber))
|
|
1455
|
+
return;
|
|
1367
1456
|
const state = channel.state;
|
|
1368
1457
|
if (!force) {
|
|
1369
1458
|
if (0.5 <= state.sustainPedal)
|
|
@@ -1449,10 +1538,10 @@ class MidyGM2 {
|
|
|
1449
1538
|
console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
|
|
1450
1539
|
}
|
|
1451
1540
|
}
|
|
1452
|
-
handleProgramChange(channelNumber,
|
|
1541
|
+
handleProgramChange(channelNumber, programNumber, _scheduleTime) {
|
|
1453
1542
|
const channel = this.channels[channelNumber];
|
|
1454
1543
|
channel.bank = channel.bankMSB * 128 + channel.bankLSB;
|
|
1455
|
-
channel.
|
|
1544
|
+
channel.programNumber = programNumber;
|
|
1456
1545
|
if (this.mode === "GM2") {
|
|
1457
1546
|
switch (channel.bankMSB) {
|
|
1458
1547
|
case 120:
|
|
@@ -2083,16 +2172,30 @@ class MidyGM2 {
|
|
|
2083
2172
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2084
2173
|
return this.stopChannelNotes(channelNumber, 0, true, scheduleTime);
|
|
2085
2174
|
}
|
|
2175
|
+
resetAllStates(channelNumber) {
|
|
2176
|
+
const channel = this.channels[channelNumber];
|
|
2177
|
+
const state = channel.state;
|
|
2178
|
+
for (const type of Object.keys(defaultControllerState)) {
|
|
2179
|
+
state[type] = defaultControllerState[type].defaultValue;
|
|
2180
|
+
}
|
|
2181
|
+
for (const type of Object.keys(this.constructor.channelSettings)) {
|
|
2182
|
+
channel[type] = this.constructor.channelSettings[type];
|
|
2183
|
+
}
|
|
2184
|
+
this.mode = "GM2";
|
|
2185
|
+
this.masterFineTuning = 0; // cb
|
|
2186
|
+
this.masterCoarseTuning = 0; // cb
|
|
2187
|
+
}
|
|
2188
|
+
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp15.pdf
|
|
2086
2189
|
resetAllControllers(channelNumber) {
|
|
2087
2190
|
const stateTypes = [
|
|
2191
|
+
"channelPressure",
|
|
2192
|
+
"pitchWheel",
|
|
2088
2193
|
"expression",
|
|
2089
2194
|
"modulationDepth",
|
|
2090
2195
|
"sustainPedal",
|
|
2091
2196
|
"portamento",
|
|
2092
2197
|
"sostenutoPedal",
|
|
2093
2198
|
"softPedal",
|
|
2094
|
-
"channelPressure",
|
|
2095
|
-
"pitchWheelSensitivity",
|
|
2096
2199
|
];
|
|
2097
2200
|
const channel = this.channels[channelNumber];
|
|
2098
2201
|
const state = channel.state;
|
|
@@ -2457,7 +2560,7 @@ class MidyGM2 {
|
|
|
2457
2560
|
return value * 0.00787;
|
|
2458
2561
|
}
|
|
2459
2562
|
getChannelBitmap(data) {
|
|
2460
|
-
const bitmap = new Array(
|
|
2563
|
+
const bitmap = new Array(this.channels.length).fill(false);
|
|
2461
2564
|
const ff = data[4] & 0b11;
|
|
2462
2565
|
const gg = data[5] & 0x7F;
|
|
2463
2566
|
const hh = data[6] & 0x7F;
|
|
@@ -2599,6 +2702,7 @@ class MidyGM2 {
|
|
|
2599
2702
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
2600
2703
|
}
|
|
2601
2704
|
}
|
|
2705
|
+
// https://github.com/marmooo/js-timer-benchmark
|
|
2602
2706
|
scheduleTask(callback, scheduleTime) {
|
|
2603
2707
|
return new Promise((resolve) => {
|
|
2604
2708
|
const bufferSource = new AudioBufferSourceNode(this.audioContext, {
|
|
@@ -2624,10 +2728,8 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
2624
2728
|
configurable: true,
|
|
2625
2729
|
writable: true,
|
|
2626
2730
|
value: {
|
|
2627
|
-
currentBufferSource: null,
|
|
2628
|
-
isDrum: false,
|
|
2629
2731
|
detune: 0,
|
|
2630
|
-
|
|
2732
|
+
programNumber: 0,
|
|
2631
2733
|
bank: 121 * 128,
|
|
2632
2734
|
bankMSB: 121,
|
|
2633
2735
|
bankLSB: 0,
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export class MidyGMLite {
|
|
2
2
|
static channelSettings: {
|
|
3
|
-
currentBufferSource: null;
|
|
4
|
-
isDrum: boolean;
|
|
5
3
|
detune: number;
|
|
6
|
-
|
|
4
|
+
programNumber: number;
|
|
7
5
|
bank: number;
|
|
8
6
|
dataMSB: number;
|
|
9
7
|
dataLSB: number;
|
|
@@ -13,6 +11,7 @@ export class MidyGMLite {
|
|
|
13
11
|
};
|
|
14
12
|
constructor(audioContext: any);
|
|
15
13
|
mode: string;
|
|
14
|
+
numChannels: number;
|
|
16
15
|
ticksPerBeat: number;
|
|
17
16
|
totalTime: number;
|
|
18
17
|
noteCheckInterval: number;
|
|
@@ -32,7 +31,8 @@ export class MidyGMLite {
|
|
|
32
31
|
timeline: any[];
|
|
33
32
|
instruments: any[];
|
|
34
33
|
notePromises: any[];
|
|
35
|
-
|
|
34
|
+
exclusiveClassNotes: any[];
|
|
35
|
+
drumExclusiveClassNotes: any[];
|
|
36
36
|
audioContext: any;
|
|
37
37
|
masterVolume: any;
|
|
38
38
|
scheduler: any;
|
|
@@ -75,8 +75,7 @@ export class MidyGMLite {
|
|
|
75
75
|
};
|
|
76
76
|
createChannels(audioContext: any): any[];
|
|
77
77
|
createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
|
|
78
|
-
|
|
79
|
-
createBufferSource(channel: any, voiceParams: any, audioBuffer: any): any;
|
|
78
|
+
createBufferSource(voiceParams: any, audioBuffer: any): any;
|
|
80
79
|
scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
|
|
81
80
|
getQueueIndex(second: any): number;
|
|
82
81
|
playNotes(): Promise<any>;
|
|
@@ -111,16 +110,19 @@ export class MidyGMLite {
|
|
|
111
110
|
clampCutoffFrequency(frequency: any): number;
|
|
112
111
|
setFilterEnvelope(note: any, scheduleTime: any): void;
|
|
113
112
|
startModulation(channel: any, note: any, scheduleTime: any): void;
|
|
114
|
-
getAudioBuffer(
|
|
113
|
+
getAudioBuffer(programNumber: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
|
|
115
114
|
createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
115
|
+
handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
116
|
+
handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
116
117
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
117
118
|
noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
|
|
119
|
+
disconnectNote(note: any, scheduledNotes: any, index: any): void;
|
|
118
120
|
stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
|
|
119
121
|
scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): Promise<any> | undefined;
|
|
120
122
|
noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<any> | undefined;
|
|
121
123
|
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
122
124
|
handleMIDIMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<any>;
|
|
123
|
-
handleProgramChange(channelNumber: any,
|
|
125
|
+
handleProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
|
|
124
126
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
|
|
125
127
|
setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
|
|
126
128
|
setModLfoToPitch(channel: any, note: any, scheduleTime: any): void;
|
|
@@ -177,6 +179,7 @@ export class MidyGMLite {
|
|
|
177
179
|
handlePitchBendRangeRPN(channelNumber: any, scheduleTime: any): void;
|
|
178
180
|
setPitchBendRange(channelNumber: any, value: any, scheduleTime: any): void;
|
|
179
181
|
allSoundOff(channelNumber: any, _value: any, scheduleTime: any): Promise<any[]>;
|
|
182
|
+
resetAllStates(channelNumber: any): void;
|
|
180
183
|
resetAllControllers(channelNumber: any): void;
|
|
181
184
|
allNotesOff(channelNumber: any, _value: any, scheduleTime: any): Promise<any[]>;
|
|
182
185
|
handleUniversalNonRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA+JA;IA2BE;;;;;;;;;MASE;IAEF,+BAcC;IAnDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,2BAAqC;IACrC,+BAEE;IAcA,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAMnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAaC;IAED,6DA2BC;IAED,4DASC;IAED,2EAsDC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,mGAgBC;IAED,wEAMC;IAED,uBAKC;IAED,aAMC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDAQC;IAED,2DASC;IAED,qDAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,+GA0BC;IAED,gHAwCC;IAED,0EAiBC;IAED,8EAiBC;IAED,kGAmDC;IAED,6FAQC;IAED,iEAUC;IAED,qFAgBC;IAED,yHAwBC;IAED,yGASC;IAED,4GAeC;IAED,mGA2BC;IAED,sFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAQC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MA2BC;IAED,oFAMC;IAED,6EA2CC;IAED;;;;;;;;;;;;;MAeC;IAED,kGAWC;IAED,wDAUC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,uDAYC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,gFAGC;IAED,yCAUC;IAGD,8CAqBC;IAED,gFAGC;IAED,+EAgBC;IAED,qCAWC;IAED,4EAaC;IAED,4DAGC;IAED,sDASC;IAED,gDAYC;IAGD,6DAgBC;CACF;AA79CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IASE,0FAMC;IAdD,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
|