@marmooo/midy 0.1.5 → 0.1.6
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 +7 -7
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +62 -59
- package/esm/midy-GM2.d.ts +12 -9
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +156 -79
- package/esm/midy-GMLite.d.ts +7 -7
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +62 -59
- package/esm/midy.d.ts +12 -9
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +156 -83
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +7 -7
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +62 -59
- package/script/midy-GM2.d.ts +12 -9
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +156 -79
- package/script/midy-GMLite.d.ts +7 -7
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +62 -59
- package/script/midy.d.ts +12 -9
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +156 -83
package/script/midy-GM2.js
CHANGED
|
@@ -252,12 +252,14 @@ class MidyGM2 {
|
|
|
252
252
|
addSoundFont(soundFont) {
|
|
253
253
|
const index = this.soundFonts.length;
|
|
254
254
|
this.soundFonts.push(soundFont);
|
|
255
|
-
soundFont.parsed.presetHeaders
|
|
255
|
+
const presetHeaders = soundFont.parsed.presetHeaders;
|
|
256
|
+
for (let i = 0; i < presetHeaders.length; i++) {
|
|
257
|
+
const presetHeader = presetHeaders[i];
|
|
256
258
|
if (!presetHeader.presetName.startsWith("\u0000")) { // TODO: Only SF3 generated by PolyPone?
|
|
257
259
|
const banks = this.soundFontTable[presetHeader.preset];
|
|
258
260
|
banks.set(presetHeader.bank, index);
|
|
259
261
|
}
|
|
260
|
-
}
|
|
262
|
+
}
|
|
261
263
|
}
|
|
262
264
|
async loadSoundFont(soundFontUrl) {
|
|
263
265
|
const response = await fetch(soundFontUrl);
|
|
@@ -306,27 +308,25 @@ class MidyGM2 {
|
|
|
306
308
|
return channels;
|
|
307
309
|
}
|
|
308
310
|
async createNoteBuffer(instrumentKey, isSF3) {
|
|
311
|
+
const sampleStart = instrumentKey.start;
|
|
309
312
|
const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
|
|
310
313
|
if (isSF3) {
|
|
311
|
-
const sample =
|
|
312
|
-
sample.set(instrumentKey.sample);
|
|
314
|
+
const sample = instrumentKey.sample.slice(sampleStart, sampleEnd);
|
|
313
315
|
const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
|
|
314
|
-
for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
|
|
315
|
-
const channelData = audioBuffer.getChannelData(channel);
|
|
316
|
-
channelData.set(channelData.subarray(0, sampleEnd));
|
|
317
|
-
}
|
|
318
316
|
return audioBuffer;
|
|
319
317
|
}
|
|
320
318
|
else {
|
|
321
|
-
const sample = instrumentKey.sample.subarray(
|
|
322
|
-
const floatSample = this.convertToFloat32Array(sample);
|
|
319
|
+
const sample = instrumentKey.sample.subarray(sampleStart, sampleEnd);
|
|
323
320
|
const audioBuffer = new AudioBuffer({
|
|
324
321
|
numberOfChannels: 1,
|
|
325
322
|
length: sample.length,
|
|
326
323
|
sampleRate: instrumentKey.sampleRate,
|
|
327
324
|
});
|
|
328
325
|
const channelData = audioBuffer.getChannelData(0);
|
|
329
|
-
|
|
326
|
+
const int16Array = new Int16Array(sample.buffer);
|
|
327
|
+
for (let i = 0; i < int16Array.length; i++) {
|
|
328
|
+
channelData[i] = int16Array[i] / 32768;
|
|
329
|
+
}
|
|
330
330
|
return audioBuffer;
|
|
331
331
|
}
|
|
332
332
|
}
|
|
@@ -342,13 +342,23 @@ class MidyGM2 {
|
|
|
342
342
|
}
|
|
343
343
|
return bufferSource;
|
|
344
344
|
}
|
|
345
|
-
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
345
|
+
findPortamentoTarget(queueIndex) {
|
|
346
|
+
const endEvent = this.timeline[queueIndex];
|
|
347
|
+
if (!this.channels[endEvent.channel].portamento)
|
|
348
|
+
return;
|
|
349
|
+
const endTime = endEvent.startTime;
|
|
350
|
+
let target;
|
|
351
|
+
while (++queueIndex < this.timeline.length) {
|
|
352
|
+
const event = this.timeline[queueIndex];
|
|
353
|
+
if (endTime !== event.startTime)
|
|
354
|
+
break;
|
|
355
|
+
if (event.type !== "noteOn")
|
|
356
|
+
continue;
|
|
357
|
+
if (!target || event.noteNumber < target.noteNumber) {
|
|
358
|
+
target = event;
|
|
359
|
+
}
|
|
350
360
|
}
|
|
351
|
-
return
|
|
361
|
+
return target;
|
|
352
362
|
}
|
|
353
363
|
async scheduleTimelineEvents(t, offset, queueIndex) {
|
|
354
364
|
while (queueIndex < this.timeline.length) {
|
|
@@ -358,12 +368,15 @@ class MidyGM2 {
|
|
|
358
368
|
switch (event.type) {
|
|
359
369
|
case "noteOn":
|
|
360
370
|
if (event.velocity !== 0) {
|
|
361
|
-
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
|
|
371
|
+
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset, event.portamento);
|
|
362
372
|
break;
|
|
363
373
|
}
|
|
364
374
|
/* falls through */
|
|
365
375
|
case "noteOff": {
|
|
366
|
-
const
|
|
376
|
+
const portamentoTarget = this.findPortamentoTarget(queueIndex);
|
|
377
|
+
if (portamentoTarget)
|
|
378
|
+
portamentoTarget.portamento = true;
|
|
379
|
+
const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset, portamentoTarget?.noteNumber, false);
|
|
367
380
|
if (notePromise) {
|
|
368
381
|
this.notePromises.push(notePromise);
|
|
369
382
|
}
|
|
@@ -464,9 +477,11 @@ class MidyGM2 {
|
|
|
464
477
|
bankLSB: this.channels[i].bankLSB,
|
|
465
478
|
};
|
|
466
479
|
}
|
|
467
|
-
midi.tracks.
|
|
480
|
+
for (let i = 0; i < midi.tracks.length; i++) {
|
|
481
|
+
const track = midi.tracks[i];
|
|
468
482
|
let currentTicks = 0;
|
|
469
|
-
track.
|
|
483
|
+
for (let j = 0; j < track.length; j++) {
|
|
484
|
+
const event = track[j];
|
|
470
485
|
currentTicks += event.deltaTime;
|
|
471
486
|
event.ticks = currentTicks;
|
|
472
487
|
switch (event.type) {
|
|
@@ -519,16 +534,18 @@ class MidyGM2 {
|
|
|
519
534
|
}
|
|
520
535
|
delete event.deltaTime;
|
|
521
536
|
timeline.push(event);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
524
539
|
const priority = {
|
|
525
540
|
controller: 0,
|
|
526
541
|
sysEx: 1,
|
|
542
|
+
noteOff: 2, // for portamento
|
|
543
|
+
noteOn: 3,
|
|
527
544
|
};
|
|
528
545
|
timeline.sort((a, b) => {
|
|
529
546
|
if (a.ticks !== b.ticks)
|
|
530
547
|
return a.ticks - b.ticks;
|
|
531
|
-
return (priority[a.type] ||
|
|
548
|
+
return (priority[a.type] || 4) - (priority[b.type] || 4);
|
|
532
549
|
});
|
|
533
550
|
let prevTempoTime = 0;
|
|
534
551
|
let prevTempoTicks = 0;
|
|
@@ -545,7 +562,7 @@ class MidyGM2 {
|
|
|
545
562
|
}
|
|
546
563
|
return { instruments, timeline };
|
|
547
564
|
}
|
|
548
|
-
async stopChannelNotes(channelNumber, velocity,
|
|
565
|
+
async stopChannelNotes(channelNumber, velocity, force) {
|
|
549
566
|
const now = this.audioContext.currentTime;
|
|
550
567
|
const channel = this.channels[channelNumber];
|
|
551
568
|
channel.scheduledNotes.forEach((noteList) => {
|
|
@@ -553,16 +570,17 @@ class MidyGM2 {
|
|
|
553
570
|
const note = noteList[i];
|
|
554
571
|
if (!note)
|
|
555
572
|
continue;
|
|
556
|
-
const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now,
|
|
573
|
+
const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, undefined, // portamentoNoteNumber
|
|
574
|
+
force);
|
|
557
575
|
this.notePromises.push(promise);
|
|
558
576
|
}
|
|
559
577
|
});
|
|
560
578
|
channel.scheduledNotes.clear();
|
|
561
579
|
await Promise.all(this.notePromises);
|
|
562
580
|
}
|
|
563
|
-
stopNotes(velocity,
|
|
581
|
+
stopNotes(velocity, force) {
|
|
564
582
|
for (let i = 0; i < this.channels.length; i++) {
|
|
565
|
-
this.stopChannelNotes(i, velocity,
|
|
583
|
+
this.stopChannelNotes(i, velocity, force);
|
|
566
584
|
}
|
|
567
585
|
return Promise.all(this.notePromises);
|
|
568
586
|
}
|
|
@@ -776,6 +794,17 @@ class MidyGM2 {
|
|
|
776
794
|
return instrumentKey.playbackRate(noteNumber) *
|
|
777
795
|
Math.pow(2, semitoneOffset / 12);
|
|
778
796
|
}
|
|
797
|
+
setPortamentoStartVolumeEnvelope(channel, note) {
|
|
798
|
+
const { instrumentKey, startTime } = note;
|
|
799
|
+
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
800
|
+
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
801
|
+
const volDelay = startTime + instrumentKey.volDelay;
|
|
802
|
+
const portamentoTime = volDelay + channel.portamentoTime;
|
|
803
|
+
note.volumeNode.gain
|
|
804
|
+
.cancelScheduledValues(startTime)
|
|
805
|
+
.setValueAtTime(0, volDelay)
|
|
806
|
+
.linearRampToValueAtTime(sustainVolume, portamentoTime);
|
|
807
|
+
}
|
|
779
808
|
setVolumeEnvelope(note) {
|
|
780
809
|
const { instrumentKey, startTime } = note;
|
|
781
810
|
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
@@ -815,6 +844,25 @@ class MidyGM2 {
|
|
|
815
844
|
const maxFrequency = 20000; // max Hz of initialFilterFc
|
|
816
845
|
return Math.max(minFrequency, Math.min(frequency, maxFrequency));
|
|
817
846
|
}
|
|
847
|
+
setPortamentoStartFilterEnvelope(channel, note) {
|
|
848
|
+
const { instrumentKey, noteNumber, startTime } = note;
|
|
849
|
+
const softPedalFactor = 1 -
|
|
850
|
+
(0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
|
|
851
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
|
|
852
|
+
softPedalFactor;
|
|
853
|
+
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
|
|
854
|
+
const sustainFreq = baseFreq +
|
|
855
|
+
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
|
|
856
|
+
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
857
|
+
const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
|
|
858
|
+
const portamentoTime = startTime + channel.portamentoTime;
|
|
859
|
+
const modDelay = startTime + instrumentKey.modDelay;
|
|
860
|
+
note.filterNode.frequency
|
|
861
|
+
.cancelScheduledValues(startTime)
|
|
862
|
+
.setValueAtTime(adjustedBaseFreq, startTime)
|
|
863
|
+
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
864
|
+
.linearRampToValueAtTime(adjustedSustainFreq, portamentoTime);
|
|
865
|
+
}
|
|
818
866
|
setFilterEnvelope(channel, note) {
|
|
819
867
|
const { instrumentKey, noteNumber, startTime } = note;
|
|
820
868
|
const softPedalFactor = 1 -
|
|
@@ -882,17 +930,23 @@ class MidyGM2 {
|
|
|
882
930
|
note.vibratoLFO.connect(note.vibratoDepth);
|
|
883
931
|
note.vibratoDepth.connect(note.bufferSource.detune);
|
|
884
932
|
}
|
|
885
|
-
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
|
|
933
|
+
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, portamento, isSF3) {
|
|
886
934
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
887
935
|
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
888
936
|
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
889
937
|
note.volumeNode = new GainNode(this.audioContext);
|
|
890
938
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
891
939
|
type: "lowpass",
|
|
892
|
-
Q: instrumentKey.initialFilterQ / 10
|
|
940
|
+
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
893
941
|
});
|
|
894
|
-
|
|
895
|
-
|
|
942
|
+
if (portamento) {
|
|
943
|
+
this.setPortamentoStartVolumeEnvelope(channel, note);
|
|
944
|
+
this.setPortamentoStartFilterEnvelope(channel, note);
|
|
945
|
+
}
|
|
946
|
+
else {
|
|
947
|
+
this.setVolumeEnvelope(note);
|
|
948
|
+
this.setFilterEnvelope(channel, note);
|
|
949
|
+
}
|
|
896
950
|
if (0 < channel.vibratoDepth) {
|
|
897
951
|
this.startVibrato(channel, note, startTime);
|
|
898
952
|
}
|
|
@@ -909,7 +963,7 @@ class MidyGM2 {
|
|
|
909
963
|
}
|
|
910
964
|
note.bufferSource.connect(note.filterNode);
|
|
911
965
|
note.filterNode.connect(note.volumeNode);
|
|
912
|
-
note.bufferSource.start(startTime
|
|
966
|
+
note.bufferSource.start(startTime);
|
|
913
967
|
return note;
|
|
914
968
|
}
|
|
915
969
|
calcBank(channel, channelNumber) {
|
|
@@ -921,7 +975,7 @@ class MidyGM2 {
|
|
|
921
975
|
}
|
|
922
976
|
return channel.bank;
|
|
923
977
|
}
|
|
924
|
-
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
978
|
+
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, portamento) {
|
|
925
979
|
const channel = this.channels[channelNumber];
|
|
926
980
|
const bankNumber = this.calcBank(channel, channelNumber);
|
|
927
981
|
const soundFontIndex = this.soundFontTable[channel.program].get(bankNumber);
|
|
@@ -932,7 +986,7 @@ class MidyGM2 {
|
|
|
932
986
|
const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber, velocity);
|
|
933
987
|
if (!instrumentKey)
|
|
934
988
|
return;
|
|
935
|
-
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
989
|
+
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, portamento, isSF3);
|
|
936
990
|
note.volumeNode.connect(channel.gainL);
|
|
937
991
|
note.volumeNode.connect(channel.gainR);
|
|
938
992
|
if (channel.sostenutoPedal) {
|
|
@@ -946,13 +1000,42 @@ class MidyGM2 {
|
|
|
946
1000
|
scheduledNotes.set(noteNumber, [note]);
|
|
947
1001
|
}
|
|
948
1002
|
}
|
|
949
|
-
noteOn(channelNumber, noteNumber, velocity) {
|
|
1003
|
+
noteOn(channelNumber, noteNumber, velocity, portamento) {
|
|
950
1004
|
const now = this.audioContext.currentTime;
|
|
951
|
-
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
|
|
1005
|
+
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now, portamento);
|
|
1006
|
+
}
|
|
1007
|
+
stopNote(stopTime, endTime, scheduledNotes, index) {
|
|
1008
|
+
const note = scheduledNotes[index];
|
|
1009
|
+
note.volumeNode.gain
|
|
1010
|
+
.cancelScheduledValues(stopTime)
|
|
1011
|
+
.linearRampToValueAtTime(0, endTime);
|
|
1012
|
+
note.ending = true;
|
|
1013
|
+
this.scheduleTask(() => {
|
|
1014
|
+
note.bufferSource.loop = false;
|
|
1015
|
+
}, endTime);
|
|
1016
|
+
return new Promise((resolve) => {
|
|
1017
|
+
note.bufferSource.onended = () => {
|
|
1018
|
+
scheduledNotes[index] = null;
|
|
1019
|
+
note.bufferSource.disconnect();
|
|
1020
|
+
note.volumeNode.disconnect();
|
|
1021
|
+
note.filterNode.disconnect();
|
|
1022
|
+
if (note.modulationDepth) {
|
|
1023
|
+
note.volumeDepth.disconnect();
|
|
1024
|
+
note.modulationDepth.disconnect();
|
|
1025
|
+
note.modulationLFO.stop();
|
|
1026
|
+
}
|
|
1027
|
+
if (note.vibratoDepth) {
|
|
1028
|
+
note.vibratoDepth.disconnect();
|
|
1029
|
+
note.vibratoLFO.stop();
|
|
1030
|
+
}
|
|
1031
|
+
resolve();
|
|
1032
|
+
};
|
|
1033
|
+
note.bufferSource.stop(endTime);
|
|
1034
|
+
});
|
|
952
1035
|
}
|
|
953
|
-
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime,
|
|
1036
|
+
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, portamentoNoteNumber, force) {
|
|
954
1037
|
const channel = this.channels[channelNumber];
|
|
955
|
-
if (
|
|
1038
|
+
if (!force) {
|
|
956
1039
|
if (channel.sustainPedal)
|
|
957
1040
|
return;
|
|
958
1041
|
if (channel.sostenutoNotes.has(noteNumber))
|
|
@@ -967,38 +1050,28 @@ class MidyGM2 {
|
|
|
967
1050
|
continue;
|
|
968
1051
|
if (note.ending)
|
|
969
1052
|
continue;
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
.
|
|
973
|
-
.
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
.
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
note.filterNode.disconnect();
|
|
988
|
-
if (note.modulationDepth) {
|
|
989
|
-
note.volumeDepth.disconnect();
|
|
990
|
-
note.modulationDepth.disconnect();
|
|
991
|
-
note.modulationLFO.stop();
|
|
992
|
-
}
|
|
993
|
-
resolve();
|
|
994
|
-
};
|
|
995
|
-
note.bufferSource.stop(volEndTime);
|
|
996
|
-
});
|
|
1053
|
+
if (portamentoNoteNumber === undefined) {
|
|
1054
|
+
const volEndTime = stopTime + note.instrumentKey.volRelease;
|
|
1055
|
+
const modRelease = stopTime + note.instrumentKey.modRelease;
|
|
1056
|
+
note.filterNode.frequency
|
|
1057
|
+
.cancelScheduledValues(stopTime)
|
|
1058
|
+
.linearRampToValueAtTime(0, modRelease);
|
|
1059
|
+
return this.stopNote(stopTime, volEndTime, scheduledNotes, i);
|
|
1060
|
+
}
|
|
1061
|
+
else {
|
|
1062
|
+
const portamentoTime = stopTime + channel.portamentoTime;
|
|
1063
|
+
const detuneChange = (portamentoNoteNumber - noteNumber) * 100;
|
|
1064
|
+
const detune = note.bufferSource.detune.value + detuneChange;
|
|
1065
|
+
note.bufferSource.detune
|
|
1066
|
+
.cancelScheduledValues(stopTime)
|
|
1067
|
+
.linearRampToValueAtTime(detune, portamentoTime);
|
|
1068
|
+
return this.stopNote(stopTime, portamentoTime, scheduledNotes, i);
|
|
1069
|
+
}
|
|
997
1070
|
}
|
|
998
1071
|
}
|
|
999
|
-
releaseNote(channelNumber, noteNumber, velocity) {
|
|
1072
|
+
releaseNote(channelNumber, noteNumber, velocity, portamentoNoteNumber) {
|
|
1000
1073
|
const now = this.audioContext.currentTime;
|
|
1001
|
-
return this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now);
|
|
1074
|
+
return this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, portamentoNoteNumber, false);
|
|
1002
1075
|
}
|
|
1003
1076
|
releaseSustainPedal(channelNumber, halfVelocity) {
|
|
1004
1077
|
const velocity = halfVelocity * 2;
|
|
@@ -1146,12 +1219,14 @@ class MidyGM2 {
|
|
|
1146
1219
|
this.updateModulation(channel);
|
|
1147
1220
|
}
|
|
1148
1221
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
1149
|
-
this.channels[channelNumber]
|
|
1222
|
+
const channel = this.channels[channelNumber];
|
|
1223
|
+
const factor = 5 * Math.log(10) / 127;
|
|
1224
|
+
channel.portamentoTime = Math.exp(factor * portamentoTime);
|
|
1150
1225
|
}
|
|
1151
1226
|
setVolume(channelNumber, volume) {
|
|
1152
1227
|
const channel = this.channels[channelNumber];
|
|
1153
1228
|
channel.volume = volume / 127;
|
|
1154
|
-
this.
|
|
1229
|
+
this.updateChannelVolume(channel);
|
|
1155
1230
|
}
|
|
1156
1231
|
panToGain(pan) {
|
|
1157
1232
|
const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
|
|
@@ -1163,12 +1238,12 @@ class MidyGM2 {
|
|
|
1163
1238
|
setPan(channelNumber, pan) {
|
|
1164
1239
|
const channel = this.channels[channelNumber];
|
|
1165
1240
|
channel.pan = pan;
|
|
1166
|
-
this.
|
|
1241
|
+
this.updateChannelVolume(channel);
|
|
1167
1242
|
}
|
|
1168
1243
|
setExpression(channelNumber, expression) {
|
|
1169
1244
|
const channel = this.channels[channelNumber];
|
|
1170
1245
|
channel.expression = expression / 127;
|
|
1171
|
-
this.
|
|
1246
|
+
this.updateChannelVolume(channel);
|
|
1172
1247
|
}
|
|
1173
1248
|
setBankLSB(channelNumber, lsb) {
|
|
1174
1249
|
this.channels[channelNumber].bankLSB = lsb;
|
|
@@ -1177,7 +1252,7 @@ class MidyGM2 {
|
|
|
1177
1252
|
this.channels[channelNumber].dataLSB = value;
|
|
1178
1253
|
this.handleRPN(channelNumber);
|
|
1179
1254
|
}
|
|
1180
|
-
|
|
1255
|
+
updateChannelVolume(channel) {
|
|
1181
1256
|
const now = this.audioContext.currentTime;
|
|
1182
1257
|
const volume = channel.volume * channel.expression;
|
|
1183
1258
|
const { gainLeft, gainRight } = this.panToGain(channel.pan);
|
|
@@ -1195,12 +1270,12 @@ class MidyGM2 {
|
|
|
1195
1270
|
this.releaseSustainPedal(channelNumber, value);
|
|
1196
1271
|
}
|
|
1197
1272
|
}
|
|
1198
|
-
// TODO
|
|
1199
1273
|
setPortamento(channelNumber, value) {
|
|
1200
1274
|
this.channels[channelNumber].portamento = value >= 64;
|
|
1201
1275
|
}
|
|
1202
1276
|
setReverbSendLevel(channelNumber, reverbSendLevel) {
|
|
1203
1277
|
const channel = this.channels[channelNumber];
|
|
1278
|
+
const reverbEffect = this.reverbEffect;
|
|
1204
1279
|
if (0 < channel.reverbSendLevel) {
|
|
1205
1280
|
if (0 < reverbSendLevel) {
|
|
1206
1281
|
const now = this.audioContext.currentTime;
|
|
@@ -1428,20 +1503,22 @@ class MidyGM2 {
|
|
|
1428
1503
|
}
|
|
1429
1504
|
}
|
|
1430
1505
|
GM1SystemOn() {
|
|
1431
|
-
this.channels.
|
|
1506
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1507
|
+
const channel = this.channels[i];
|
|
1432
1508
|
channel.bankMSB = 0;
|
|
1433
1509
|
channel.bankLSB = 0;
|
|
1434
1510
|
channel.bank = 0;
|
|
1435
|
-
}
|
|
1511
|
+
}
|
|
1436
1512
|
this.channels[9].bankMSB = 1;
|
|
1437
1513
|
this.channels[9].bank = 128;
|
|
1438
1514
|
}
|
|
1439
1515
|
GM2SystemOn() {
|
|
1440
|
-
this.channels.
|
|
1516
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1517
|
+
const channel = this.channels[i];
|
|
1441
1518
|
channel.bankMSB = 121;
|
|
1442
1519
|
channel.bankLSB = 0;
|
|
1443
1520
|
channel.bank = 121 * 128;
|
|
1444
|
-
}
|
|
1521
|
+
}
|
|
1445
1522
|
this.channels[9].bankMSB = 120;
|
|
1446
1523
|
this.channels[9].bank = 120 * 128;
|
|
1447
1524
|
}
|
|
@@ -1751,7 +1828,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
1751
1828
|
currentBufferSource: null,
|
|
1752
1829
|
volume: 100 / 127,
|
|
1753
1830
|
pan: 64,
|
|
1754
|
-
portamentoTime:
|
|
1831
|
+
portamentoTime: 1, // sec
|
|
1755
1832
|
reverbSendLevel: 0,
|
|
1756
1833
|
chorusSendLevel: 0,
|
|
1757
1834
|
vibratoRate: 1,
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -64,7 +64,6 @@ export class MidyGMLite {
|
|
|
64
64
|
createChannels(audioContext: any): any[];
|
|
65
65
|
createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
|
|
66
66
|
createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
|
|
67
|
-
convertToFloat32Array(uint8Array: any): Float32Array;
|
|
68
67
|
scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
|
|
69
68
|
getQueueIndex(second: any): number;
|
|
70
69
|
playNotes(): Promise<any>;
|
|
@@ -74,8 +73,8 @@ export class MidyGMLite {
|
|
|
74
73
|
instruments: Set<any>;
|
|
75
74
|
timeline: any[];
|
|
76
75
|
};
|
|
77
|
-
stopChannelNotes(channelNumber: any, velocity: any,
|
|
78
|
-
stopNotes(velocity: any,
|
|
76
|
+
stopChannelNotes(channelNumber: any, velocity: any, force: any): Promise<void>;
|
|
77
|
+
stopNotes(velocity: any, force: any): Promise<any[]>;
|
|
79
78
|
start(): Promise<void>;
|
|
80
79
|
stop(): void;
|
|
81
80
|
pause(): void;
|
|
@@ -97,10 +96,11 @@ export class MidyGMLite {
|
|
|
97
96
|
createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
98
97
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
99
98
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
stopNote(stopTime: any, endTime: any, scheduledNotes: any, index: any): Promise<any>;
|
|
100
|
+
scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, force: any): void;
|
|
101
|
+
releaseNote(channelNumber: any, noteNumber: any, velocity: any): void;
|
|
102
102
|
releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
|
|
103
|
-
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<
|
|
103
|
+
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<void>;
|
|
104
104
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
105
105
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
106
106
|
setPitchBend(channelNumber: any, pitchBend: any): void;
|
|
@@ -129,7 +129,7 @@ export class MidyGMLite {
|
|
|
129
129
|
setPan(channelNumber: any, pan: any): void;
|
|
130
130
|
setExpression(channelNumber: any, expression: any): void;
|
|
131
131
|
dataEntryLSB(channelNumber: any, value: any): void;
|
|
132
|
-
|
|
132
|
+
updateChannelVolume(channel: any): void;
|
|
133
133
|
setSustainPedal(channelNumber: any, value: any): void;
|
|
134
134
|
handleRPN(channelNumber: any): void;
|
|
135
135
|
setRPNMSB(channelNumber: any, value: any): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAsBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAOC;IA7CD,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;IAuBhB,kBAAgC;IAChC,gBAA4C;IAC5C;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAsBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAOC;IA7CD,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;IAuBhB,kBAAgC;IAChC,gBAA4C;IAC5C;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,+DAuBC;IAED,mEAWC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;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,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,mCAeC;IAED,+CAwBC;IAED,6CAIC;IAED,mCAsBC;IAED,+DA0BC;IAED,wHAgCC;IAED,kGA8BC;IAED,0EAGC;IAED,qFA4BC;IAED,0GAsBC;IAED,sEAGC;IAED,kEAeC;IAED,iFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED;;;;;;;;;;;;;MAeC;IAED,2EASC;IAED,qCAkBC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,wCAUC;IAED,sDAMC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBASC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAj/BD;IAQE,gFAKC;IAZD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|