@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/esm/midy.js
CHANGED
|
@@ -157,6 +157,39 @@ class Note {
|
|
|
157
157
|
this.voiceParams = voiceParams;
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
|
+
const drumExclusiveClassesByKit = new Array(57);
|
|
161
|
+
const drumExclusiveClassCount = 10;
|
|
162
|
+
const standardSet = new Uint8Array(128);
|
|
163
|
+
standardSet[42] = 1;
|
|
164
|
+
standardSet[44] = 1;
|
|
165
|
+
standardSet[46] = 1; // HH
|
|
166
|
+
standardSet[71] = 2;
|
|
167
|
+
standardSet[72] = 2; // Whistle
|
|
168
|
+
standardSet[73] = 3;
|
|
169
|
+
standardSet[74] = 3; // Guiro
|
|
170
|
+
standardSet[78] = 4;
|
|
171
|
+
standardSet[79] = 4; // Cuica
|
|
172
|
+
standardSet[80] = 5;
|
|
173
|
+
standardSet[81] = 5; // Triangle
|
|
174
|
+
standardSet[29] = 6;
|
|
175
|
+
standardSet[30] = 6; // Scratch
|
|
176
|
+
standardSet[86] = 7;
|
|
177
|
+
standardSet[87] = 7; // Surdo
|
|
178
|
+
drumExclusiveClassesByKit[0] = standardSet;
|
|
179
|
+
const analogSet = new Uint8Array(128);
|
|
180
|
+
analogSet[42] = 8;
|
|
181
|
+
analogSet[44] = 8;
|
|
182
|
+
analogSet[46] = 8; // CHH
|
|
183
|
+
drumExclusiveClassesByKit[25] = analogSet;
|
|
184
|
+
const orchestraSet = new Uint8Array(128);
|
|
185
|
+
orchestraSet[27] = 9;
|
|
186
|
+
orchestraSet[28] = 9;
|
|
187
|
+
orchestraSet[29] = 9; // HH
|
|
188
|
+
drumExclusiveClassesByKit[48] = orchestraSet;
|
|
189
|
+
const sfxSet = new Uint8Array(128);
|
|
190
|
+
sfxSet[41] = 10;
|
|
191
|
+
sfxSet[42] = 10; // Scratch
|
|
192
|
+
drumExclusiveClassesByKit[56] = sfxSet;
|
|
160
193
|
// normalized to 0-1 for use with the SF2 modulator model
|
|
161
194
|
const defaultControllerState = {
|
|
162
195
|
noteOnVelocity: { type: 2, defaultValue: 0 },
|
|
@@ -252,18 +285,6 @@ export class Midy {
|
|
|
252
285
|
writable: true,
|
|
253
286
|
value: "GM2"
|
|
254
287
|
});
|
|
255
|
-
Object.defineProperty(this, "ticksPerBeat", {
|
|
256
|
-
enumerable: true,
|
|
257
|
-
configurable: true,
|
|
258
|
-
writable: true,
|
|
259
|
-
value: 120
|
|
260
|
-
});
|
|
261
|
-
Object.defineProperty(this, "totalTime", {
|
|
262
|
-
enumerable: true,
|
|
263
|
-
configurable: true,
|
|
264
|
-
writable: true,
|
|
265
|
-
value: 0
|
|
266
|
-
});
|
|
267
288
|
Object.defineProperty(this, "masterFineTuning", {
|
|
268
289
|
enumerable: true,
|
|
269
290
|
configurable: true,
|
|
@@ -297,6 +318,24 @@ export class Midy {
|
|
|
297
318
|
delayTimes: this.generateDistributedArray(0.02, 2, 0.5),
|
|
298
319
|
}
|
|
299
320
|
});
|
|
321
|
+
Object.defineProperty(this, "numChannels", {
|
|
322
|
+
enumerable: true,
|
|
323
|
+
configurable: true,
|
|
324
|
+
writable: true,
|
|
325
|
+
value: 16
|
|
326
|
+
});
|
|
327
|
+
Object.defineProperty(this, "ticksPerBeat", {
|
|
328
|
+
enumerable: true,
|
|
329
|
+
configurable: true,
|
|
330
|
+
writable: true,
|
|
331
|
+
value: 120
|
|
332
|
+
});
|
|
333
|
+
Object.defineProperty(this, "totalTime", {
|
|
334
|
+
enumerable: true,
|
|
335
|
+
configurable: true,
|
|
336
|
+
writable: true,
|
|
337
|
+
value: 0
|
|
338
|
+
});
|
|
300
339
|
Object.defineProperty(this, "noteCheckInterval", {
|
|
301
340
|
enumerable: true,
|
|
302
341
|
configurable: true,
|
|
@@ -399,11 +438,17 @@ export class Midy {
|
|
|
399
438
|
writable: true,
|
|
400
439
|
value: []
|
|
401
440
|
});
|
|
402
|
-
Object.defineProperty(this, "
|
|
441
|
+
Object.defineProperty(this, "exclusiveClassNotes", {
|
|
442
|
+
enumerable: true,
|
|
443
|
+
configurable: true,
|
|
444
|
+
writable: true,
|
|
445
|
+
value: new Array(128)
|
|
446
|
+
});
|
|
447
|
+
Object.defineProperty(this, "drumExclusiveClassNotes", {
|
|
403
448
|
enumerable: true,
|
|
404
449
|
configurable: true,
|
|
405
450
|
writable: true,
|
|
406
|
-
value: new
|
|
451
|
+
value: new Array(this.numChannels * drumExclusiveClassCount)
|
|
407
452
|
});
|
|
408
453
|
Object.defineProperty(this, "defaultOptions", {
|
|
409
454
|
enumerable: true,
|
|
@@ -497,8 +542,10 @@ export class Midy {
|
|
|
497
542
|
};
|
|
498
543
|
}
|
|
499
544
|
createChannels(audioContext) {
|
|
500
|
-
const channels = Array.from({ length:
|
|
545
|
+
const channels = Array.from({ length: this.numChannels }, () => {
|
|
501
546
|
return {
|
|
547
|
+
currentBufferSource: null,
|
|
548
|
+
isDrum: false,
|
|
502
549
|
...this.constructor.channelSettings,
|
|
503
550
|
state: new ControllerState(),
|
|
504
551
|
controlTable: this.initControlTable(),
|
|
@@ -543,24 +590,10 @@ export class Midy {
|
|
|
543
590
|
return audioBuffer;
|
|
544
591
|
}
|
|
545
592
|
}
|
|
546
|
-
|
|
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) {
|
|
593
|
+
createBufferSource(voiceParams, audioBuffer) {
|
|
561
594
|
const bufferSource = new AudioBufferSourceNode(this.audioContext);
|
|
562
595
|
bufferSource.buffer = audioBuffer;
|
|
563
|
-
bufferSource.loop =
|
|
596
|
+
bufferSource.loop = voiceParams.sampleModes % 2 !== 0;
|
|
564
597
|
if (bufferSource.loop) {
|
|
565
598
|
bufferSource.loopStart = voiceParams.loopStart / voiceParams.sampleRate;
|
|
566
599
|
bufferSource.loopEnd = voiceParams.loopEnd / voiceParams.sampleRate;
|
|
@@ -651,7 +684,8 @@ export class Midy {
|
|
|
651
684
|
if (queueIndex >= this.timeline.length) {
|
|
652
685
|
await Promise.all(this.notePromises);
|
|
653
686
|
this.notePromises = [];
|
|
654
|
-
this.
|
|
687
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
688
|
+
this.drumExclusiveClassNotes.fill(undefined);
|
|
655
689
|
this.audioBufferCache.clear();
|
|
656
690
|
resolve();
|
|
657
691
|
return;
|
|
@@ -670,7 +704,8 @@ export class Midy {
|
|
|
670
704
|
else if (this.isStopping) {
|
|
671
705
|
await this.stopNotes(0, true, now);
|
|
672
706
|
this.notePromises = [];
|
|
673
|
-
this.
|
|
707
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
708
|
+
this.drumExclusiveClassNotes.fill(undefined);
|
|
674
709
|
this.audioBufferCache.clear();
|
|
675
710
|
resolve();
|
|
676
711
|
this.isStopping = false;
|
|
@@ -679,7 +714,8 @@ export class Midy {
|
|
|
679
714
|
}
|
|
680
715
|
else if (this.isSeeking) {
|
|
681
716
|
this.stopNotes(0, true, now);
|
|
682
|
-
this.
|
|
717
|
+
this.exclusiveClassNotes.fill(undefined);
|
|
718
|
+
this.drumExclusiveClassNotes.fill(undefined);
|
|
683
719
|
this.startTime = this.audioContext.currentTime;
|
|
684
720
|
queueIndex = this.getQueueIndex(this.resumeTime);
|
|
685
721
|
offset = this.resumeTime - this.startTime;
|
|
@@ -707,7 +743,7 @@ export class Midy {
|
|
|
707
743
|
extractMidiData(midi) {
|
|
708
744
|
const instruments = new Set();
|
|
709
745
|
const timeline = [];
|
|
710
|
-
const tmpChannels = new Array(
|
|
746
|
+
const tmpChannels = new Array(this.channels.length);
|
|
711
747
|
for (let i = 0; i < tmpChannels.length; i++) {
|
|
712
748
|
tmpChannels[i] = {
|
|
713
749
|
programNumber: -1,
|
|
@@ -835,6 +871,9 @@ export class Midy {
|
|
|
835
871
|
if (!this.isPlaying)
|
|
836
872
|
return;
|
|
837
873
|
this.isStopping = true;
|
|
874
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
875
|
+
this.resetAllStates(i);
|
|
876
|
+
}
|
|
838
877
|
}
|
|
839
878
|
pause() {
|
|
840
879
|
if (!this.isPlaying || this.isPaused)
|
|
@@ -1209,8 +1248,8 @@ export class Midy {
|
|
|
1209
1248
|
note.vibratoLFO.connect(note.vibratoDepth);
|
|
1210
1249
|
note.vibratoDepth.connect(note.bufferSource.detune);
|
|
1211
1250
|
}
|
|
1212
|
-
async getAudioBuffer(
|
|
1213
|
-
const audioBufferId = this.getAudioBufferId(
|
|
1251
|
+
async getAudioBuffer(programNumber, noteNumber, velocity, voiceParams, isSF3) {
|
|
1252
|
+
const audioBufferId = this.getAudioBufferId(programNumber, noteNumber, velocity);
|
|
1214
1253
|
const cache = this.audioBufferCache.get(audioBufferId);
|
|
1215
1254
|
if (cache) {
|
|
1216
1255
|
cache.counter += 1;
|
|
@@ -1233,8 +1272,8 @@ export class Midy {
|
|
|
1233
1272
|
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
1234
1273
|
const voiceParams = voice.getAllParams(controllerState);
|
|
1235
1274
|
const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
|
|
1236
|
-
const audioBuffer = await this.getAudioBuffer(channel.
|
|
1237
|
-
note.bufferSource = this.createBufferSource(
|
|
1275
|
+
const audioBuffer = await this.getAudioBuffer(channel.programNumber, noteNumber, velocity, voiceParams, isSF3);
|
|
1276
|
+
note.bufferSource = this.createBufferSource(voiceParams, audioBuffer);
|
|
1238
1277
|
note.volumeNode = new GainNode(this.audioContext);
|
|
1239
1278
|
note.gainL = new GainNode(this.audioContext);
|
|
1240
1279
|
note.gainR = new GainNode(this.audioContext);
|
|
@@ -1294,14 +1333,56 @@ export class Midy {
|
|
|
1294
1333
|
return channel.bank;
|
|
1295
1334
|
}
|
|
1296
1335
|
}
|
|
1336
|
+
handleExclusiveClass(note, channelNumber, startTime) {
|
|
1337
|
+
const exclusiveClass = note.voiceParams.exclusiveClass;
|
|
1338
|
+
if (exclusiveClass === 0)
|
|
1339
|
+
return;
|
|
1340
|
+
const prev = this.exclusiveClassNotes[exclusiveClass];
|
|
1341
|
+
if (prev) {
|
|
1342
|
+
const [prevNote, prevChannelNumber] = prev;
|
|
1343
|
+
if (prevNote && !prevNote.ending) {
|
|
1344
|
+
this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
1345
|
+
startTime, true, // force
|
|
1346
|
+
undefined);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
this.exclusiveClassNotes[exclusiveClass] = [note, channelNumber];
|
|
1350
|
+
}
|
|
1351
|
+
handleDrumExclusiveClass(note, channelNumber, startTime) {
|
|
1352
|
+
const channel = this.channels[channelNumber];
|
|
1353
|
+
if (!channel.isDrum)
|
|
1354
|
+
return;
|
|
1355
|
+
const kitTable = drumExclusiveClassesByKit[channel.programNumber];
|
|
1356
|
+
if (!kitTable)
|
|
1357
|
+
return;
|
|
1358
|
+
const drumExclusiveClass = kitTable[note.noteNumber];
|
|
1359
|
+
if (drumExclusiveClass === 0)
|
|
1360
|
+
return;
|
|
1361
|
+
const index = (drumExclusiveClass - 1) * this.channels.length +
|
|
1362
|
+
channelNumber;
|
|
1363
|
+
const prevNote = this.drumExclusiveClassNotes[index];
|
|
1364
|
+
if (prevNote && !prevNote.ending) {
|
|
1365
|
+
this.scheduleNoteOff(channelNumber, prevNote.noteNumber, 0, // velocity,
|
|
1366
|
+
startTime, true, // force
|
|
1367
|
+
undefined);
|
|
1368
|
+
}
|
|
1369
|
+
this.drumExclusiveClassNotes[index] = note;
|
|
1370
|
+
}
|
|
1371
|
+
isDrumNoteOffException(channel, noteNumber) {
|
|
1372
|
+
if (!channel.isDrum)
|
|
1373
|
+
return false;
|
|
1374
|
+
const programNumber = channel.programNumber;
|
|
1375
|
+
return (programNumber === 48 && noteNumber === 88) ||
|
|
1376
|
+
(programNumber === 56 && 47 <= noteNumber && noteNumber <= 84);
|
|
1377
|
+
}
|
|
1297
1378
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, portamento) {
|
|
1298
1379
|
const channel = this.channels[channelNumber];
|
|
1299
1380
|
const bankNumber = this.calcBank(channel, channelNumber);
|
|
1300
|
-
const soundFontIndex = this.soundFontTable[channel.
|
|
1381
|
+
const soundFontIndex = this.soundFontTable[channel.programNumber].get(bankNumber);
|
|
1301
1382
|
if (soundFontIndex === undefined)
|
|
1302
1383
|
return;
|
|
1303
1384
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
1304
|
-
const voice = soundFont.getVoice(bankNumber, channel.
|
|
1385
|
+
const voice = soundFont.getVoice(bankNumber, channel.programNumber, noteNumber, velocity);
|
|
1305
1386
|
if (!voice)
|
|
1306
1387
|
return;
|
|
1307
1388
|
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
@@ -1311,31 +1392,58 @@ export class Midy {
|
|
|
1311
1392
|
if (0.5 <= channel.state.sustainPedal) {
|
|
1312
1393
|
channel.sustainNotes.push(note);
|
|
1313
1394
|
}
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
if (this.exclusiveClassMap.has(exclusiveClass)) {
|
|
1317
|
-
const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
|
|
1318
|
-
const [prevNote, prevChannelNumber] = prevEntry;
|
|
1319
|
-
if (prevNote && !prevNote.ending) {
|
|
1320
|
-
this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
1321
|
-
startTime, true, // force
|
|
1322
|
-
undefined);
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
this.exclusiveClassMap.set(exclusiveClass, [note, channelNumber]);
|
|
1326
|
-
}
|
|
1395
|
+
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
1396
|
+
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
1327
1397
|
const scheduledNotes = channel.scheduledNotes;
|
|
1328
|
-
|
|
1329
|
-
|
|
1398
|
+
let notes = scheduledNotes.get(noteNumber);
|
|
1399
|
+
if (notes) {
|
|
1400
|
+
notes.push(note);
|
|
1330
1401
|
}
|
|
1331
1402
|
else {
|
|
1332
|
-
|
|
1403
|
+
notes = [note];
|
|
1404
|
+
scheduledNotes.set(noteNumber, notes);
|
|
1405
|
+
}
|
|
1406
|
+
if (this.isDrumNoteOffException(channel, noteNumber)) {
|
|
1407
|
+
const stopTime = startTime + note.bufferSource.buffer.duration;
|
|
1408
|
+
const index = notes.length - 1;
|
|
1409
|
+
const promise = new Promise((resolve) => {
|
|
1410
|
+
note.bufferSource.onended = () => {
|
|
1411
|
+
this.disconnectNote(note, scheduledNotes, index);
|
|
1412
|
+
resolve();
|
|
1413
|
+
};
|
|
1414
|
+
note.bufferSource.stop(stopTime);
|
|
1415
|
+
});
|
|
1416
|
+
this.notePromises.push(promise);
|
|
1333
1417
|
}
|
|
1334
1418
|
}
|
|
1335
1419
|
noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
1336
1420
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1337
1421
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, false);
|
|
1338
1422
|
}
|
|
1423
|
+
disconnectNote(note, scheduledNotes, index) {
|
|
1424
|
+
scheduledNotes[index] = null;
|
|
1425
|
+
note.bufferSource.disconnect();
|
|
1426
|
+
note.filterNode.disconnect();
|
|
1427
|
+
note.volumeEnvelopeNode.disconnect();
|
|
1428
|
+
note.volumeNode.disconnect();
|
|
1429
|
+
note.gainL.disconnect();
|
|
1430
|
+
note.gainR.disconnect();
|
|
1431
|
+
if (note.modulationDepth) {
|
|
1432
|
+
note.volumeDepth.disconnect();
|
|
1433
|
+
note.modulationDepth.disconnect();
|
|
1434
|
+
note.modulationLFO.stop();
|
|
1435
|
+
}
|
|
1436
|
+
if (note.vibratoDepth) {
|
|
1437
|
+
note.vibratoDepth.disconnect();
|
|
1438
|
+
note.vibratoLFO.stop();
|
|
1439
|
+
}
|
|
1440
|
+
if (note.reverbEffectsSend) {
|
|
1441
|
+
note.reverbEffectsSend.disconnect();
|
|
1442
|
+
}
|
|
1443
|
+
if (note.chorusEffectsSend) {
|
|
1444
|
+
note.chorusEffectsSend.disconnect();
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1339
1447
|
stopNote(endTime, stopTime, scheduledNotes, index) {
|
|
1340
1448
|
const note = scheduledNotes[index];
|
|
1341
1449
|
note.volumeEnvelopeNode.gain
|
|
@@ -1347,28 +1455,7 @@ export class Midy {
|
|
|
1347
1455
|
}, stopTime);
|
|
1348
1456
|
return new Promise((resolve) => {
|
|
1349
1457
|
note.bufferSource.onended = () => {
|
|
1350
|
-
scheduledNotes
|
|
1351
|
-
note.bufferSource.disconnect();
|
|
1352
|
-
note.filterNode.disconnect();
|
|
1353
|
-
note.volumeEnvelopeNode.disconnect();
|
|
1354
|
-
note.volumeNode.disconnect();
|
|
1355
|
-
note.gainL.disconnect();
|
|
1356
|
-
note.gainR.disconnect();
|
|
1357
|
-
if (note.modulationDepth) {
|
|
1358
|
-
note.volumeDepth.disconnect();
|
|
1359
|
-
note.modulationDepth.disconnect();
|
|
1360
|
-
note.modulationLFO.stop();
|
|
1361
|
-
}
|
|
1362
|
-
if (note.vibratoDepth) {
|
|
1363
|
-
note.vibratoDepth.disconnect();
|
|
1364
|
-
note.vibratoLFO.stop();
|
|
1365
|
-
}
|
|
1366
|
-
if (note.reverbEffectsSend) {
|
|
1367
|
-
note.reverbEffectsSend.disconnect();
|
|
1368
|
-
}
|
|
1369
|
-
if (note.chorusEffectsSend) {
|
|
1370
|
-
note.chorusEffectsSend.disconnect();
|
|
1371
|
-
}
|
|
1458
|
+
this.disconnectNote(note, scheduledNotes, index);
|
|
1372
1459
|
resolve();
|
|
1373
1460
|
};
|
|
1374
1461
|
note.bufferSource.stop(stopTime);
|
|
@@ -1376,6 +1463,8 @@ export class Midy {
|
|
|
1376
1463
|
}
|
|
1377
1464
|
scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force, portamentoNoteNumber) {
|
|
1378
1465
|
const channel = this.channels[channelNumber];
|
|
1466
|
+
if (this.isDrumNoteOffException(channel, noteNumber))
|
|
1467
|
+
return;
|
|
1379
1468
|
const state = channel.state;
|
|
1380
1469
|
if (!force) {
|
|
1381
1470
|
if (0.5 <= state.sustainPedal)
|
|
@@ -1475,10 +1564,10 @@ export class Midy {
|
|
|
1475
1564
|
}
|
|
1476
1565
|
// this.applyVoiceParams(channel, 10);
|
|
1477
1566
|
}
|
|
1478
|
-
handleProgramChange(channelNumber,
|
|
1567
|
+
handleProgramChange(channelNumber, programNumber, _scheduleTime) {
|
|
1479
1568
|
const channel = this.channels[channelNumber];
|
|
1480
1569
|
channel.bank = channel.bankMSB * 128 + channel.bankLSB;
|
|
1481
|
-
channel.
|
|
1570
|
+
channel.programNumber = programNumber;
|
|
1482
1571
|
if (this.mode === "GM2") {
|
|
1483
1572
|
switch (channel.bankMSB) {
|
|
1484
1573
|
case 120:
|
|
@@ -2229,16 +2318,31 @@ export class Midy {
|
|
|
2229
2318
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2230
2319
|
return this.stopChannelNotes(channelNumber, 0, true, scheduleTime);
|
|
2231
2320
|
}
|
|
2321
|
+
resetAllStates(channelNumber) {
|
|
2322
|
+
const channel = this.channels[channelNumber];
|
|
2323
|
+
const state = channel.state;
|
|
2324
|
+
for (const type of Object.keys(defaultControllerState)) {
|
|
2325
|
+
state[type] = defaultControllerState[type].defaultValue;
|
|
2326
|
+
}
|
|
2327
|
+
for (const type of Object.keys(this.constructor.channelSettings)) {
|
|
2328
|
+
channel[type] = this.constructor.channelSettings[type];
|
|
2329
|
+
}
|
|
2330
|
+
this.mode = "GM2";
|
|
2331
|
+
this.masterFineTuning = 0; // cb
|
|
2332
|
+
this.masterCoarseTuning = 0; // cb
|
|
2333
|
+
}
|
|
2334
|
+
// https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp15.pdf
|
|
2232
2335
|
resetAllControllers(channelNumber) {
|
|
2233
2336
|
const stateTypes = [
|
|
2337
|
+
"polyphonicKeyPressure",
|
|
2338
|
+
"channelPressure",
|
|
2339
|
+
"pitchWheel",
|
|
2234
2340
|
"expression",
|
|
2235
2341
|
"modulationDepth",
|
|
2236
2342
|
"sustainPedal",
|
|
2237
2343
|
"portamento",
|
|
2238
2344
|
"sostenutoPedal",
|
|
2239
2345
|
"softPedal",
|
|
2240
|
-
"channelPressure",
|
|
2241
|
-
"pitchWheelSensitivity",
|
|
2242
2346
|
];
|
|
2243
2347
|
const channel = this.channels[channelNumber];
|
|
2244
2348
|
const state = channel.state;
|
|
@@ -2619,7 +2723,7 @@ export class Midy {
|
|
|
2619
2723
|
return value * 0.00787;
|
|
2620
2724
|
}
|
|
2621
2725
|
getChannelBitmap(data) {
|
|
2622
|
-
const bitmap = new Array(
|
|
2726
|
+
const bitmap = new Array(this.channels.length).fill(false);
|
|
2623
2727
|
const ff = data[4] & 0b11;
|
|
2624
2728
|
const gg = data[5] & 0x7F;
|
|
2625
2729
|
const hh = data[6] & 0x7F;
|
|
@@ -2811,6 +2915,7 @@ export class Midy {
|
|
|
2811
2915
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
2812
2916
|
}
|
|
2813
2917
|
}
|
|
2918
|
+
// https://github.com/marmooo/js-timer-benchmark
|
|
2814
2919
|
scheduleTask(callback, scheduleTime) {
|
|
2815
2920
|
return new Promise((resolve) => {
|
|
2816
2921
|
const bufferSource = new AudioBufferSourceNode(this.audioContext, {
|
|
@@ -2835,10 +2940,8 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
2835
2940
|
configurable: true,
|
|
2836
2941
|
writable: true,
|
|
2837
2942
|
value: {
|
|
2838
|
-
currentBufferSource: null,
|
|
2839
|
-
isDrum: false,
|
|
2840
2943
|
detune: 0,
|
|
2841
|
-
|
|
2944
|
+
programNumber: 0,
|
|
2842
2945
|
bank: 121 * 128,
|
|
2843
2946
|
bankMSB: 121,
|
|
2844
2947
|
bankLSB: 0,
|
package/package.json
CHANGED
package/script/midy-GM1.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export class MidyGM1 {
|
|
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;
|
|
@@ -15,6 +13,7 @@ export class MidyGM1 {
|
|
|
15
13
|
};
|
|
16
14
|
constructor(audioContext: any);
|
|
17
15
|
mode: string;
|
|
16
|
+
numChannels: number;
|
|
18
17
|
ticksPerBeat: number;
|
|
19
18
|
totalTime: number;
|
|
20
19
|
noteCheckInterval: number;
|
|
@@ -34,7 +33,7 @@ export class MidyGM1 {
|
|
|
34
33
|
timeline: any[];
|
|
35
34
|
instruments: any[];
|
|
36
35
|
notePromises: any[];
|
|
37
|
-
|
|
36
|
+
exclusiveClassNotes: any[];
|
|
38
37
|
audioContext: any;
|
|
39
38
|
masterVolume: any;
|
|
40
39
|
scheduler: any;
|
|
@@ -112,16 +111,18 @@ export class MidyGM1 {
|
|
|
112
111
|
clampCutoffFrequency(frequency: any): number;
|
|
113
112
|
setFilterEnvelope(note: any, scheduleTime: any): void;
|
|
114
113
|
startModulation(channel: any, note: any, scheduleTime: any): void;
|
|
115
|
-
getAudioBuffer(
|
|
114
|
+
getAudioBuffer(programNumber: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
|
|
116
115
|
createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
116
|
+
handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
117
117
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
118
118
|
noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
|
|
119
|
+
disconnectNote(note: any, scheduledNotes: any, index: any): void;
|
|
119
120
|
stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
|
|
120
121
|
scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): Promise<any> | undefined;
|
|
121
122
|
noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<any> | undefined;
|
|
122
123
|
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
123
124
|
handleMIDIMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<any>;
|
|
124
|
-
handleProgramChange(channelNumber: any,
|
|
125
|
+
handleProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
|
|
125
126
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
|
|
126
127
|
setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
|
|
127
128
|
setModLfoToPitch(channel: any, note: any, scheduleTime: any): void;
|
|
@@ -183,6 +184,7 @@ export class MidyGM1 {
|
|
|
183
184
|
handleCoarseTuningRPN(channelNumber: any, scheduleTime: any): void;
|
|
184
185
|
setCoarseTuning(channelNumber: any, value: any, scheduleTime: any): void;
|
|
185
186
|
allSoundOff(channelNumber: any, _value: any, scheduleTime: any): Promise<any[]>;
|
|
187
|
+
resetAllStates(channelNumber: any): void;
|
|
186
188
|
resetAllControllers(channelNumber: any): void;
|
|
187
189
|
allNotesOff(channelNumber: any, _value: any, scheduleTime: any): Promise<any[]>;
|
|
188
190
|
handleUniversalNonRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
|
package/script/midy-GM1.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAiJA;
|
|
1
|
+
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAiJA;IAwBE;;;;;;;;;;;MAWE;IAEF,+BAcC;IAlDD,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;IAgBnC,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,qCAMC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,+GA0BC;IAED,gHAwCC;IAED,0EAiBC;IAED,kGAqCC;IAED,6FAQC;IAED,iEAUC;IAED,qFAgBC;IAED,yHAuBC;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,2DAMC;IAED,uDAkBC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,iEAKC;IAED,uEAQC;IAED,mEAKC;IAED,yEAQC;IAED,gFAGC;IAED,yCAUC;IAGD,8CAqBC;IAED,gFAGC;IAED,+EAgBC;IAED,qCAWC;IAED,4EAaC;IAED,4DAGC;IAED,sDASC;IAED,gDAYC;IAGD,6DAgBC;CACF;AA99CD;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"}
|