@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/esm/midy-GM2.js
CHANGED
|
@@ -249,12 +249,14 @@ export class MidyGM2 {
|
|
|
249
249
|
addSoundFont(soundFont) {
|
|
250
250
|
const index = this.soundFonts.length;
|
|
251
251
|
this.soundFonts.push(soundFont);
|
|
252
|
-
soundFont.parsed.presetHeaders
|
|
252
|
+
const presetHeaders = soundFont.parsed.presetHeaders;
|
|
253
|
+
for (let i = 0; i < presetHeaders.length; i++) {
|
|
254
|
+
const presetHeader = presetHeaders[i];
|
|
253
255
|
if (!presetHeader.presetName.startsWith("\u0000")) { // TODO: Only SF3 generated by PolyPone?
|
|
254
256
|
const banks = this.soundFontTable[presetHeader.preset];
|
|
255
257
|
banks.set(presetHeader.bank, index);
|
|
256
258
|
}
|
|
257
|
-
}
|
|
259
|
+
}
|
|
258
260
|
}
|
|
259
261
|
async loadSoundFont(soundFontUrl) {
|
|
260
262
|
const response = await fetch(soundFontUrl);
|
|
@@ -303,27 +305,25 @@ export class MidyGM2 {
|
|
|
303
305
|
return channels;
|
|
304
306
|
}
|
|
305
307
|
async createNoteBuffer(instrumentKey, isSF3) {
|
|
308
|
+
const sampleStart = instrumentKey.start;
|
|
306
309
|
const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
|
|
307
310
|
if (isSF3) {
|
|
308
|
-
const sample =
|
|
309
|
-
sample.set(instrumentKey.sample);
|
|
311
|
+
const sample = instrumentKey.sample.slice(sampleStart, sampleEnd);
|
|
310
312
|
const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
|
|
311
|
-
for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
|
|
312
|
-
const channelData = audioBuffer.getChannelData(channel);
|
|
313
|
-
channelData.set(channelData.subarray(0, sampleEnd));
|
|
314
|
-
}
|
|
315
313
|
return audioBuffer;
|
|
316
314
|
}
|
|
317
315
|
else {
|
|
318
|
-
const sample = instrumentKey.sample.subarray(
|
|
319
|
-
const floatSample = this.convertToFloat32Array(sample);
|
|
316
|
+
const sample = instrumentKey.sample.subarray(sampleStart, sampleEnd);
|
|
320
317
|
const audioBuffer = new AudioBuffer({
|
|
321
318
|
numberOfChannels: 1,
|
|
322
319
|
length: sample.length,
|
|
323
320
|
sampleRate: instrumentKey.sampleRate,
|
|
324
321
|
});
|
|
325
322
|
const channelData = audioBuffer.getChannelData(0);
|
|
326
|
-
|
|
323
|
+
const int16Array = new Int16Array(sample.buffer);
|
|
324
|
+
for (let i = 0; i < int16Array.length; i++) {
|
|
325
|
+
channelData[i] = int16Array[i] / 32768;
|
|
326
|
+
}
|
|
327
327
|
return audioBuffer;
|
|
328
328
|
}
|
|
329
329
|
}
|
|
@@ -339,13 +339,23 @@ export class MidyGM2 {
|
|
|
339
339
|
}
|
|
340
340
|
return bufferSource;
|
|
341
341
|
}
|
|
342
|
-
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
342
|
+
findPortamentoTarget(queueIndex) {
|
|
343
|
+
const endEvent = this.timeline[queueIndex];
|
|
344
|
+
if (!this.channels[endEvent.channel].portamento)
|
|
345
|
+
return;
|
|
346
|
+
const endTime = endEvent.startTime;
|
|
347
|
+
let target;
|
|
348
|
+
while (++queueIndex < this.timeline.length) {
|
|
349
|
+
const event = this.timeline[queueIndex];
|
|
350
|
+
if (endTime !== event.startTime)
|
|
351
|
+
break;
|
|
352
|
+
if (event.type !== "noteOn")
|
|
353
|
+
continue;
|
|
354
|
+
if (!target || event.noteNumber < target.noteNumber) {
|
|
355
|
+
target = event;
|
|
356
|
+
}
|
|
347
357
|
}
|
|
348
|
-
return
|
|
358
|
+
return target;
|
|
349
359
|
}
|
|
350
360
|
async scheduleTimelineEvents(t, offset, queueIndex) {
|
|
351
361
|
while (queueIndex < this.timeline.length) {
|
|
@@ -355,12 +365,15 @@ export class MidyGM2 {
|
|
|
355
365
|
switch (event.type) {
|
|
356
366
|
case "noteOn":
|
|
357
367
|
if (event.velocity !== 0) {
|
|
358
|
-
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
|
|
368
|
+
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset, event.portamento);
|
|
359
369
|
break;
|
|
360
370
|
}
|
|
361
371
|
/* falls through */
|
|
362
372
|
case "noteOff": {
|
|
363
|
-
const
|
|
373
|
+
const portamentoTarget = this.findPortamentoTarget(queueIndex);
|
|
374
|
+
if (portamentoTarget)
|
|
375
|
+
portamentoTarget.portamento = true;
|
|
376
|
+
const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset, portamentoTarget?.noteNumber, false);
|
|
364
377
|
if (notePromise) {
|
|
365
378
|
this.notePromises.push(notePromise);
|
|
366
379
|
}
|
|
@@ -461,9 +474,11 @@ export class MidyGM2 {
|
|
|
461
474
|
bankLSB: this.channels[i].bankLSB,
|
|
462
475
|
};
|
|
463
476
|
}
|
|
464
|
-
midi.tracks.
|
|
477
|
+
for (let i = 0; i < midi.tracks.length; i++) {
|
|
478
|
+
const track = midi.tracks[i];
|
|
465
479
|
let currentTicks = 0;
|
|
466
|
-
track.
|
|
480
|
+
for (let j = 0; j < track.length; j++) {
|
|
481
|
+
const event = track[j];
|
|
467
482
|
currentTicks += event.deltaTime;
|
|
468
483
|
event.ticks = currentTicks;
|
|
469
484
|
switch (event.type) {
|
|
@@ -516,16 +531,18 @@ export class MidyGM2 {
|
|
|
516
531
|
}
|
|
517
532
|
delete event.deltaTime;
|
|
518
533
|
timeline.push(event);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
521
536
|
const priority = {
|
|
522
537
|
controller: 0,
|
|
523
538
|
sysEx: 1,
|
|
539
|
+
noteOff: 2, // for portamento
|
|
540
|
+
noteOn: 3,
|
|
524
541
|
};
|
|
525
542
|
timeline.sort((a, b) => {
|
|
526
543
|
if (a.ticks !== b.ticks)
|
|
527
544
|
return a.ticks - b.ticks;
|
|
528
|
-
return (priority[a.type] ||
|
|
545
|
+
return (priority[a.type] || 4) - (priority[b.type] || 4);
|
|
529
546
|
});
|
|
530
547
|
let prevTempoTime = 0;
|
|
531
548
|
let prevTempoTicks = 0;
|
|
@@ -542,7 +559,7 @@ export class MidyGM2 {
|
|
|
542
559
|
}
|
|
543
560
|
return { instruments, timeline };
|
|
544
561
|
}
|
|
545
|
-
async stopChannelNotes(channelNumber, velocity,
|
|
562
|
+
async stopChannelNotes(channelNumber, velocity, force) {
|
|
546
563
|
const now = this.audioContext.currentTime;
|
|
547
564
|
const channel = this.channels[channelNumber];
|
|
548
565
|
channel.scheduledNotes.forEach((noteList) => {
|
|
@@ -550,16 +567,17 @@ export class MidyGM2 {
|
|
|
550
567
|
const note = noteList[i];
|
|
551
568
|
if (!note)
|
|
552
569
|
continue;
|
|
553
|
-
const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now,
|
|
570
|
+
const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, undefined, // portamentoNoteNumber
|
|
571
|
+
force);
|
|
554
572
|
this.notePromises.push(promise);
|
|
555
573
|
}
|
|
556
574
|
});
|
|
557
575
|
channel.scheduledNotes.clear();
|
|
558
576
|
await Promise.all(this.notePromises);
|
|
559
577
|
}
|
|
560
|
-
stopNotes(velocity,
|
|
578
|
+
stopNotes(velocity, force) {
|
|
561
579
|
for (let i = 0; i < this.channels.length; i++) {
|
|
562
|
-
this.stopChannelNotes(i, velocity,
|
|
580
|
+
this.stopChannelNotes(i, velocity, force);
|
|
563
581
|
}
|
|
564
582
|
return Promise.all(this.notePromises);
|
|
565
583
|
}
|
|
@@ -773,6 +791,17 @@ export class MidyGM2 {
|
|
|
773
791
|
return instrumentKey.playbackRate(noteNumber) *
|
|
774
792
|
Math.pow(2, semitoneOffset / 12);
|
|
775
793
|
}
|
|
794
|
+
setPortamentoStartVolumeEnvelope(channel, note) {
|
|
795
|
+
const { instrumentKey, startTime } = note;
|
|
796
|
+
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
797
|
+
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
798
|
+
const volDelay = startTime + instrumentKey.volDelay;
|
|
799
|
+
const portamentoTime = volDelay + channel.portamentoTime;
|
|
800
|
+
note.volumeNode.gain
|
|
801
|
+
.cancelScheduledValues(startTime)
|
|
802
|
+
.setValueAtTime(0, volDelay)
|
|
803
|
+
.linearRampToValueAtTime(sustainVolume, portamentoTime);
|
|
804
|
+
}
|
|
776
805
|
setVolumeEnvelope(note) {
|
|
777
806
|
const { instrumentKey, startTime } = note;
|
|
778
807
|
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
@@ -812,6 +841,25 @@ export class MidyGM2 {
|
|
|
812
841
|
const maxFrequency = 20000; // max Hz of initialFilterFc
|
|
813
842
|
return Math.max(minFrequency, Math.min(frequency, maxFrequency));
|
|
814
843
|
}
|
|
844
|
+
setPortamentoStartFilterEnvelope(channel, note) {
|
|
845
|
+
const { instrumentKey, noteNumber, startTime } = note;
|
|
846
|
+
const softPedalFactor = 1 -
|
|
847
|
+
(0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
|
|
848
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
|
|
849
|
+
softPedalFactor;
|
|
850
|
+
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
|
|
851
|
+
const sustainFreq = baseFreq +
|
|
852
|
+
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
|
|
853
|
+
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
854
|
+
const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
|
|
855
|
+
const portamentoTime = startTime + channel.portamentoTime;
|
|
856
|
+
const modDelay = startTime + instrumentKey.modDelay;
|
|
857
|
+
note.filterNode.frequency
|
|
858
|
+
.cancelScheduledValues(startTime)
|
|
859
|
+
.setValueAtTime(adjustedBaseFreq, startTime)
|
|
860
|
+
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
861
|
+
.linearRampToValueAtTime(adjustedSustainFreq, portamentoTime);
|
|
862
|
+
}
|
|
815
863
|
setFilterEnvelope(channel, note) {
|
|
816
864
|
const { instrumentKey, noteNumber, startTime } = note;
|
|
817
865
|
const softPedalFactor = 1 -
|
|
@@ -879,17 +927,23 @@ export class MidyGM2 {
|
|
|
879
927
|
note.vibratoLFO.connect(note.vibratoDepth);
|
|
880
928
|
note.vibratoDepth.connect(note.bufferSource.detune);
|
|
881
929
|
}
|
|
882
|
-
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
|
|
930
|
+
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, portamento, isSF3) {
|
|
883
931
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
884
932
|
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
885
933
|
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
886
934
|
note.volumeNode = new GainNode(this.audioContext);
|
|
887
935
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
888
936
|
type: "lowpass",
|
|
889
|
-
Q: instrumentKey.initialFilterQ / 10
|
|
937
|
+
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
890
938
|
});
|
|
891
|
-
|
|
892
|
-
|
|
939
|
+
if (portamento) {
|
|
940
|
+
this.setPortamentoStartVolumeEnvelope(channel, note);
|
|
941
|
+
this.setPortamentoStartFilterEnvelope(channel, note);
|
|
942
|
+
}
|
|
943
|
+
else {
|
|
944
|
+
this.setVolumeEnvelope(note);
|
|
945
|
+
this.setFilterEnvelope(channel, note);
|
|
946
|
+
}
|
|
893
947
|
if (0 < channel.vibratoDepth) {
|
|
894
948
|
this.startVibrato(channel, note, startTime);
|
|
895
949
|
}
|
|
@@ -906,7 +960,7 @@ export class MidyGM2 {
|
|
|
906
960
|
}
|
|
907
961
|
note.bufferSource.connect(note.filterNode);
|
|
908
962
|
note.filterNode.connect(note.volumeNode);
|
|
909
|
-
note.bufferSource.start(startTime
|
|
963
|
+
note.bufferSource.start(startTime);
|
|
910
964
|
return note;
|
|
911
965
|
}
|
|
912
966
|
calcBank(channel, channelNumber) {
|
|
@@ -918,7 +972,7 @@ export class MidyGM2 {
|
|
|
918
972
|
}
|
|
919
973
|
return channel.bank;
|
|
920
974
|
}
|
|
921
|
-
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
975
|
+
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, portamento) {
|
|
922
976
|
const channel = this.channels[channelNumber];
|
|
923
977
|
const bankNumber = this.calcBank(channel, channelNumber);
|
|
924
978
|
const soundFontIndex = this.soundFontTable[channel.program].get(bankNumber);
|
|
@@ -929,7 +983,7 @@ export class MidyGM2 {
|
|
|
929
983
|
const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber, velocity);
|
|
930
984
|
if (!instrumentKey)
|
|
931
985
|
return;
|
|
932
|
-
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
986
|
+
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, portamento, isSF3);
|
|
933
987
|
note.volumeNode.connect(channel.gainL);
|
|
934
988
|
note.volumeNode.connect(channel.gainR);
|
|
935
989
|
if (channel.sostenutoPedal) {
|
|
@@ -943,13 +997,42 @@ export class MidyGM2 {
|
|
|
943
997
|
scheduledNotes.set(noteNumber, [note]);
|
|
944
998
|
}
|
|
945
999
|
}
|
|
946
|
-
noteOn(channelNumber, noteNumber, velocity) {
|
|
1000
|
+
noteOn(channelNumber, noteNumber, velocity, portamento) {
|
|
947
1001
|
const now = this.audioContext.currentTime;
|
|
948
|
-
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
|
|
1002
|
+
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now, portamento);
|
|
1003
|
+
}
|
|
1004
|
+
stopNote(stopTime, endTime, scheduledNotes, index) {
|
|
1005
|
+
const note = scheduledNotes[index];
|
|
1006
|
+
note.volumeNode.gain
|
|
1007
|
+
.cancelScheduledValues(stopTime)
|
|
1008
|
+
.linearRampToValueAtTime(0, endTime);
|
|
1009
|
+
note.ending = true;
|
|
1010
|
+
this.scheduleTask(() => {
|
|
1011
|
+
note.bufferSource.loop = false;
|
|
1012
|
+
}, endTime);
|
|
1013
|
+
return new Promise((resolve) => {
|
|
1014
|
+
note.bufferSource.onended = () => {
|
|
1015
|
+
scheduledNotes[index] = null;
|
|
1016
|
+
note.bufferSource.disconnect();
|
|
1017
|
+
note.volumeNode.disconnect();
|
|
1018
|
+
note.filterNode.disconnect();
|
|
1019
|
+
if (note.modulationDepth) {
|
|
1020
|
+
note.volumeDepth.disconnect();
|
|
1021
|
+
note.modulationDepth.disconnect();
|
|
1022
|
+
note.modulationLFO.stop();
|
|
1023
|
+
}
|
|
1024
|
+
if (note.vibratoDepth) {
|
|
1025
|
+
note.vibratoDepth.disconnect();
|
|
1026
|
+
note.vibratoLFO.stop();
|
|
1027
|
+
}
|
|
1028
|
+
resolve();
|
|
1029
|
+
};
|
|
1030
|
+
note.bufferSource.stop(endTime);
|
|
1031
|
+
});
|
|
949
1032
|
}
|
|
950
|
-
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime,
|
|
1033
|
+
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, portamentoNoteNumber, force) {
|
|
951
1034
|
const channel = this.channels[channelNumber];
|
|
952
|
-
if (
|
|
1035
|
+
if (!force) {
|
|
953
1036
|
if (channel.sustainPedal)
|
|
954
1037
|
return;
|
|
955
1038
|
if (channel.sostenutoNotes.has(noteNumber))
|
|
@@ -964,38 +1047,28 @@ export class MidyGM2 {
|
|
|
964
1047
|
continue;
|
|
965
1048
|
if (note.ending)
|
|
966
1049
|
continue;
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
.
|
|
970
|
-
.
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
.
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
note.filterNode.disconnect();
|
|
985
|
-
if (note.modulationDepth) {
|
|
986
|
-
note.volumeDepth.disconnect();
|
|
987
|
-
note.modulationDepth.disconnect();
|
|
988
|
-
note.modulationLFO.stop();
|
|
989
|
-
}
|
|
990
|
-
resolve();
|
|
991
|
-
};
|
|
992
|
-
note.bufferSource.stop(volEndTime);
|
|
993
|
-
});
|
|
1050
|
+
if (portamentoNoteNumber === undefined) {
|
|
1051
|
+
const volEndTime = stopTime + note.instrumentKey.volRelease;
|
|
1052
|
+
const modRelease = stopTime + note.instrumentKey.modRelease;
|
|
1053
|
+
note.filterNode.frequency
|
|
1054
|
+
.cancelScheduledValues(stopTime)
|
|
1055
|
+
.linearRampToValueAtTime(0, modRelease);
|
|
1056
|
+
return this.stopNote(stopTime, volEndTime, scheduledNotes, i);
|
|
1057
|
+
}
|
|
1058
|
+
else {
|
|
1059
|
+
const portamentoTime = stopTime + channel.portamentoTime;
|
|
1060
|
+
const detuneChange = (portamentoNoteNumber - noteNumber) * 100;
|
|
1061
|
+
const detune = note.bufferSource.detune.value + detuneChange;
|
|
1062
|
+
note.bufferSource.detune
|
|
1063
|
+
.cancelScheduledValues(stopTime)
|
|
1064
|
+
.linearRampToValueAtTime(detune, portamentoTime);
|
|
1065
|
+
return this.stopNote(stopTime, portamentoTime, scheduledNotes, i);
|
|
1066
|
+
}
|
|
994
1067
|
}
|
|
995
1068
|
}
|
|
996
|
-
releaseNote(channelNumber, noteNumber, velocity) {
|
|
1069
|
+
releaseNote(channelNumber, noteNumber, velocity, portamentoNoteNumber) {
|
|
997
1070
|
const now = this.audioContext.currentTime;
|
|
998
|
-
return this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now);
|
|
1071
|
+
return this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, portamentoNoteNumber, false);
|
|
999
1072
|
}
|
|
1000
1073
|
releaseSustainPedal(channelNumber, halfVelocity) {
|
|
1001
1074
|
const velocity = halfVelocity * 2;
|
|
@@ -1143,12 +1216,14 @@ export class MidyGM2 {
|
|
|
1143
1216
|
this.updateModulation(channel);
|
|
1144
1217
|
}
|
|
1145
1218
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
1146
|
-
this.channels[channelNumber]
|
|
1219
|
+
const channel = this.channels[channelNumber];
|
|
1220
|
+
const factor = 5 * Math.log(10) / 127;
|
|
1221
|
+
channel.portamentoTime = Math.exp(factor * portamentoTime);
|
|
1147
1222
|
}
|
|
1148
1223
|
setVolume(channelNumber, volume) {
|
|
1149
1224
|
const channel = this.channels[channelNumber];
|
|
1150
1225
|
channel.volume = volume / 127;
|
|
1151
|
-
this.
|
|
1226
|
+
this.updateChannelVolume(channel);
|
|
1152
1227
|
}
|
|
1153
1228
|
panToGain(pan) {
|
|
1154
1229
|
const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
|
|
@@ -1160,12 +1235,12 @@ export class MidyGM2 {
|
|
|
1160
1235
|
setPan(channelNumber, pan) {
|
|
1161
1236
|
const channel = this.channels[channelNumber];
|
|
1162
1237
|
channel.pan = pan;
|
|
1163
|
-
this.
|
|
1238
|
+
this.updateChannelVolume(channel);
|
|
1164
1239
|
}
|
|
1165
1240
|
setExpression(channelNumber, expression) {
|
|
1166
1241
|
const channel = this.channels[channelNumber];
|
|
1167
1242
|
channel.expression = expression / 127;
|
|
1168
|
-
this.
|
|
1243
|
+
this.updateChannelVolume(channel);
|
|
1169
1244
|
}
|
|
1170
1245
|
setBankLSB(channelNumber, lsb) {
|
|
1171
1246
|
this.channels[channelNumber].bankLSB = lsb;
|
|
@@ -1174,7 +1249,7 @@ export class MidyGM2 {
|
|
|
1174
1249
|
this.channels[channelNumber].dataLSB = value;
|
|
1175
1250
|
this.handleRPN(channelNumber);
|
|
1176
1251
|
}
|
|
1177
|
-
|
|
1252
|
+
updateChannelVolume(channel) {
|
|
1178
1253
|
const now = this.audioContext.currentTime;
|
|
1179
1254
|
const volume = channel.volume * channel.expression;
|
|
1180
1255
|
const { gainLeft, gainRight } = this.panToGain(channel.pan);
|
|
@@ -1192,12 +1267,12 @@ export class MidyGM2 {
|
|
|
1192
1267
|
this.releaseSustainPedal(channelNumber, value);
|
|
1193
1268
|
}
|
|
1194
1269
|
}
|
|
1195
|
-
// TODO
|
|
1196
1270
|
setPortamento(channelNumber, value) {
|
|
1197
1271
|
this.channels[channelNumber].portamento = value >= 64;
|
|
1198
1272
|
}
|
|
1199
1273
|
setReverbSendLevel(channelNumber, reverbSendLevel) {
|
|
1200
1274
|
const channel = this.channels[channelNumber];
|
|
1275
|
+
const reverbEffect = this.reverbEffect;
|
|
1201
1276
|
if (0 < channel.reverbSendLevel) {
|
|
1202
1277
|
if (0 < reverbSendLevel) {
|
|
1203
1278
|
const now = this.audioContext.currentTime;
|
|
@@ -1425,20 +1500,22 @@ export class MidyGM2 {
|
|
|
1425
1500
|
}
|
|
1426
1501
|
}
|
|
1427
1502
|
GM1SystemOn() {
|
|
1428
|
-
this.channels.
|
|
1503
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1504
|
+
const channel = this.channels[i];
|
|
1429
1505
|
channel.bankMSB = 0;
|
|
1430
1506
|
channel.bankLSB = 0;
|
|
1431
1507
|
channel.bank = 0;
|
|
1432
|
-
}
|
|
1508
|
+
}
|
|
1433
1509
|
this.channels[9].bankMSB = 1;
|
|
1434
1510
|
this.channels[9].bank = 128;
|
|
1435
1511
|
}
|
|
1436
1512
|
GM2SystemOn() {
|
|
1437
|
-
this.channels.
|
|
1513
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
1514
|
+
const channel = this.channels[i];
|
|
1438
1515
|
channel.bankMSB = 121;
|
|
1439
1516
|
channel.bankLSB = 0;
|
|
1440
1517
|
channel.bank = 121 * 128;
|
|
1441
|
-
}
|
|
1518
|
+
}
|
|
1442
1519
|
this.channels[9].bankMSB = 120;
|
|
1443
1520
|
this.channels[9].bank = 120 * 128;
|
|
1444
1521
|
}
|
|
@@ -1747,7 +1824,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
1747
1824
|
currentBufferSource: null,
|
|
1748
1825
|
volume: 100 / 127,
|
|
1749
1826
|
pan: 64,
|
|
1750
|
-
portamentoTime:
|
|
1827
|
+
portamentoTime: 1, // sec
|
|
1751
1828
|
reverbSendLevel: 0,
|
|
1752
1829
|
chorusSendLevel: 0,
|
|
1753
1830
|
vibratoRate: 1,
|
package/esm/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;
|
package/esm/midy-GMLite.d.ts.map
CHANGED
|
@@ -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"}
|