@marmooo/midy 0.2.0 → 0.2.1
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/LICENSE +201 -0
- package/README.md +118 -0
- package/esm/midy-GM1.d.ts +10 -8
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +73 -66
- package/esm/midy-GM2.d.ts +17 -11
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +148 -101
- package/esm/midy-GMLite.d.ts +7 -5
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +50 -47
- package/esm/midy.d.ts +19 -13
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +233 -177
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +10 -8
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +73 -66
- package/script/midy-GM2.d.ts +17 -11
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +148 -101
- package/script/midy-GMLite.d.ts +7 -5
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +50 -47
- package/script/midy.d.ts +19 -13
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +233 -177
package/esm/midy-GMLite.js
CHANGED
|
@@ -581,14 +581,33 @@ export class MidyGMLite {
|
|
|
581
581
|
cbToRatio(cb) {
|
|
582
582
|
return Math.pow(10, cb / 200);
|
|
583
583
|
}
|
|
584
|
+
rateToCent(rate) {
|
|
585
|
+
return 1200 * Math.log2(rate);
|
|
586
|
+
}
|
|
587
|
+
centToRate(cent) {
|
|
588
|
+
return Math.pow(2, cent / 1200);
|
|
589
|
+
}
|
|
584
590
|
centToHz(cent) {
|
|
585
|
-
return 8.176 *
|
|
591
|
+
return 8.176 * this.centToRate(cent);
|
|
586
592
|
}
|
|
587
|
-
|
|
593
|
+
calcChannelDetune(channel) {
|
|
588
594
|
const pitchWheel = channel.state.pitchWheel * 2 - 1;
|
|
589
|
-
const pitchWheelSensitivity = channel.state.pitchWheelSensitivity *
|
|
595
|
+
const pitchWheelSensitivity = channel.state.pitchWheelSensitivity * 12800;
|
|
590
596
|
return pitchWheel * pitchWheelSensitivity;
|
|
591
597
|
}
|
|
598
|
+
updateDetune(channel) {
|
|
599
|
+
const now = this.audioContext.currentTime;
|
|
600
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
601
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
602
|
+
const note = noteList[i];
|
|
603
|
+
if (!note)
|
|
604
|
+
continue;
|
|
605
|
+
note.bufferSource.detune
|
|
606
|
+
.cancelScheduledValues(now)
|
|
607
|
+
.setValueAtTime(channel.detune, now);
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
}
|
|
592
611
|
setVolumeEnvelope(note) {
|
|
593
612
|
const now = this.audioContext.currentTime;
|
|
594
613
|
const { voiceParams, startTime } = note;
|
|
@@ -606,32 +625,28 @@ export class MidyGMLite {
|
|
|
606
625
|
.setValueAtTime(attackVolume, volHold)
|
|
607
626
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
608
627
|
}
|
|
609
|
-
|
|
628
|
+
setPitchEnvelope(note) {
|
|
610
629
|
const now = this.audioContext.currentTime;
|
|
630
|
+
const { voiceParams } = note;
|
|
631
|
+
const baseRate = voiceParams.playbackRate;
|
|
611
632
|
note.bufferSource.playbackRate
|
|
612
633
|
.cancelScheduledValues(now)
|
|
613
|
-
.setValueAtTime(
|
|
614
|
-
|
|
615
|
-
setPitch(channel, note) {
|
|
616
|
-
const now = this.audioContext.currentTime;
|
|
617
|
-
const { startTime } = note;
|
|
618
|
-
const basePitch = this.calcSemitoneOffset(channel) * 100;
|
|
619
|
-
note.bufferSource.detune
|
|
620
|
-
.cancelScheduledValues(now)
|
|
621
|
-
.setValueAtTime(basePitch, startTime);
|
|
622
|
-
const modEnvToPitch = note.voiceParams.modEnvToPitch;
|
|
634
|
+
.setValueAtTime(baseRate, now);
|
|
635
|
+
const modEnvToPitch = voiceParams.modEnvToPitch;
|
|
623
636
|
if (modEnvToPitch === 0)
|
|
624
637
|
return;
|
|
638
|
+
const basePitch = this.rateToCent(baseRate);
|
|
625
639
|
const peekPitch = basePitch + modEnvToPitch;
|
|
640
|
+
const peekRate = this.centToRate(peekPitch);
|
|
626
641
|
const modDelay = startTime + voiceParams.modDelay;
|
|
627
642
|
const modAttack = modDelay + voiceParams.modAttack;
|
|
628
643
|
const modHold = modAttack + voiceParams.modHold;
|
|
629
644
|
const modDecay = modHold + voiceParams.modDecay;
|
|
630
|
-
note.bufferSource.
|
|
631
|
-
.setValueAtTime(
|
|
632
|
-
.exponentialRampToValueAtTime(
|
|
633
|
-
.setValueAtTime(
|
|
634
|
-
.linearRampToValueAtTime(
|
|
645
|
+
note.bufferSource.playbackRate
|
|
646
|
+
.setValueAtTime(baseRate, modDelay)
|
|
647
|
+
.exponentialRampToValueAtTime(peekRate, modAttack)
|
|
648
|
+
.setValueAtTime(peekRate, modHold)
|
|
649
|
+
.linearRampToValueAtTime(baseRate, modDecay);
|
|
635
650
|
}
|
|
636
651
|
clampCutoffFrequency(frequency) {
|
|
637
652
|
const minFrequency = 20; // min Hz of initialFilterFc
|
|
@@ -692,9 +707,8 @@ export class MidyGMLite {
|
|
|
692
707
|
});
|
|
693
708
|
this.setVolumeEnvelope(note);
|
|
694
709
|
this.setFilterEnvelope(note);
|
|
695
|
-
this.
|
|
710
|
+
this.setPitchEnvelope(note);
|
|
696
711
|
if (0 < state.modulationDepth) {
|
|
697
|
-
this.setPitch(channel, note);
|
|
698
712
|
this.startModulation(channel, note, startTime);
|
|
699
713
|
}
|
|
700
714
|
note.bufferSource.connect(note.filterNode);
|
|
@@ -838,10 +852,12 @@ export class MidyGMLite {
|
|
|
838
852
|
setPitchBend(channelNumber, value) {
|
|
839
853
|
const channel = this.channels[channelNumber];
|
|
840
854
|
const state = channel.state;
|
|
855
|
+
const prev = state.pitchWheel * 2 - 1;
|
|
856
|
+
const next = (value - 8192) / 8192;
|
|
841
857
|
state.pitchWheel = value / 16383;
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
this.
|
|
858
|
+
channel.detune += (next - prev) * state.pitchWheelSensitivity * 12800;
|
|
859
|
+
this.updateDetune(channel);
|
|
860
|
+
this.applyVoiceParams(channel, 14);
|
|
845
861
|
}
|
|
846
862
|
setModLfoToPitch(channel, note) {
|
|
847
863
|
const now = this.audioContext.currentTime;
|
|
@@ -853,6 +869,13 @@ export class MidyGMLite {
|
|
|
853
869
|
.cancelScheduledValues(now)
|
|
854
870
|
.setValueAtTime(modulationDepth * modulationDepthSign, now);
|
|
855
871
|
}
|
|
872
|
+
setModLfoToFilterFc(note) {
|
|
873
|
+
const now = this.audioContext.currentTime;
|
|
874
|
+
const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc;
|
|
875
|
+
note.filterDepth.gain
|
|
876
|
+
.cancelScheduledValues(now)
|
|
877
|
+
.setValueAtTime(modLfoToFilterFc, now);
|
|
878
|
+
}
|
|
856
879
|
setModLfoToVolume(note) {
|
|
857
880
|
const now = this.audioContext.currentTime;
|
|
858
881
|
const modLfoToVolume = note.voiceParams.modLfoToVolume;
|
|
@@ -862,13 +885,6 @@ export class MidyGMLite {
|
|
|
862
885
|
.cancelScheduledValues(now)
|
|
863
886
|
.setValueAtTime(volumeDepth * volumeDepthSign, now);
|
|
864
887
|
}
|
|
865
|
-
setModLfoToFilterFc(note) {
|
|
866
|
-
const now = this.audioContext.currentTime;
|
|
867
|
-
const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc;
|
|
868
|
-
note.filterDepth.gain
|
|
869
|
-
.cancelScheduledValues(now)
|
|
870
|
-
.setValueAtTime(modLfoToFilterFc, now);
|
|
871
|
-
}
|
|
872
888
|
setDelayModLFO(note) {
|
|
873
889
|
const now = this.audioContext.currentTime;
|
|
874
890
|
const startTime = note.startTime;
|
|
@@ -945,7 +961,7 @@ export class MidyGMLite {
|
|
|
945
961
|
noteVoiceParams[key] = voiceParams[key];
|
|
946
962
|
}
|
|
947
963
|
this.setFilterEnvelope(channel, note);
|
|
948
|
-
this.
|
|
964
|
+
this.setPitchEnvelope(note);
|
|
949
965
|
}
|
|
950
966
|
else if (volumeEnvelopeKeySet.has(key)) {
|
|
951
967
|
if (appliedVolumeEnvelope)
|
|
@@ -999,7 +1015,7 @@ export class MidyGMLite {
|
|
|
999
1015
|
note.modulationDepth.gain.setValueAtTime(channel.state.modulationDepth, now);
|
|
1000
1016
|
}
|
|
1001
1017
|
else {
|
|
1002
|
-
this.
|
|
1018
|
+
this.setPitchEnvelope(note);
|
|
1003
1019
|
this.startModulation(channel, note, now);
|
|
1004
1020
|
}
|
|
1005
1021
|
}
|
|
@@ -1094,20 +1110,6 @@ export class MidyGMLite {
|
|
|
1094
1110
|
this.channels[channelNumber].dataMSB = value;
|
|
1095
1111
|
this.handleRPN(channelNumber);
|
|
1096
1112
|
}
|
|
1097
|
-
updateDetune(channel, detune) {
|
|
1098
|
-
const now = this.audioContext.currentTime;
|
|
1099
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1100
|
-
for (let i = 0; i < noteList.length; i++) {
|
|
1101
|
-
const note = noteList[i];
|
|
1102
|
-
if (!note)
|
|
1103
|
-
continue;
|
|
1104
|
-
const { bufferSource } = note;
|
|
1105
|
-
bufferSource.detune
|
|
1106
|
-
.cancelScheduledValues(now)
|
|
1107
|
-
.setValueAtTime(detune, now);
|
|
1108
|
-
}
|
|
1109
|
-
});
|
|
1110
|
-
}
|
|
1111
1113
|
handlePitchBendRangeRPN(channelNumber) {
|
|
1112
1114
|
const channel = this.channels[channelNumber];
|
|
1113
1115
|
this.limitData(channel, 0, 127, 0, 99);
|
|
@@ -1233,6 +1235,7 @@ Object.defineProperty(MidyGMLite, "channelSettings", {
|
|
|
1233
1235
|
writable: true,
|
|
1234
1236
|
value: {
|
|
1235
1237
|
currentBufferSource: null,
|
|
1238
|
+
detune: 0,
|
|
1236
1239
|
program: 0,
|
|
1237
1240
|
bank: 0,
|
|
1238
1241
|
dataMSB: 0,
|
package/esm/midy.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export class Midy {
|
|
2
2
|
static channelSettings: {
|
|
3
3
|
currentBufferSource: null;
|
|
4
|
+
detune: number;
|
|
5
|
+
scaleOctaveTuningTable: any[];
|
|
4
6
|
program: number;
|
|
5
7
|
bank: number;
|
|
6
8
|
bankMSB: number;
|
|
@@ -192,12 +194,15 @@ export class Midy {
|
|
|
192
194
|
feedbackGains: any[];
|
|
193
195
|
};
|
|
194
196
|
cbToRatio(cb: any): number;
|
|
197
|
+
rateToCent(rate: any): number;
|
|
198
|
+
centToRate(cent: any): number;
|
|
195
199
|
centToHz(cent: any): number;
|
|
196
|
-
|
|
200
|
+
calcChannelDetune(channel: any): any;
|
|
201
|
+
calcNoteDetune(channel: any, note: any): any;
|
|
202
|
+
updateDetune(channel: any): void;
|
|
197
203
|
setPortamentoStartVolumeEnvelope(channel: any, note: any): void;
|
|
198
204
|
setVolumeEnvelope(channel: any, note: any): void;
|
|
199
|
-
|
|
200
|
-
setPitch(channel: any, note: any): void;
|
|
205
|
+
setPitchEnvelope(note: any): void;
|
|
201
206
|
clampCutoffFrequency(frequency: any): number;
|
|
202
207
|
setPortamentoStartFilterEnvelope(channel: any, note: any): void;
|
|
203
208
|
setFilterEnvelope(channel: any, note: any): void;
|
|
@@ -219,11 +224,11 @@ export class Midy {
|
|
|
219
224
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
220
225
|
setPitchBend(channelNumber: any, value: any): void;
|
|
221
226
|
setModLfoToPitch(channel: any, note: any): void;
|
|
227
|
+
setVibLfoToPitch(channel: any, note: any): void;
|
|
228
|
+
setModLfoToFilterFc(note: any): void;
|
|
222
229
|
setModLfoToVolume(note: any): void;
|
|
223
230
|
setChorusEffectsSend(note: any, prevValue: any): void;
|
|
224
231
|
setReverbEffectsSend(note: any, prevValue: any): void;
|
|
225
|
-
setVibLfoToPitch(channel: any, note: any): void;
|
|
226
|
-
setModLfoToFilterFc(note: any): void;
|
|
227
232
|
setDelayModLFO(note: any): void;
|
|
228
233
|
setFreqModLFO(note: any): void;
|
|
229
234
|
createVoiceParamsHandlers(): {
|
|
@@ -293,8 +298,6 @@ export class Midy {
|
|
|
293
298
|
updateChannelVolume(channel: any): void;
|
|
294
299
|
setSustainPedal(channelNumber: any, value: any): void;
|
|
295
300
|
setPortamento(channelNumber: any, value: any): void;
|
|
296
|
-
setReverbSendLevel(channelNumber: any, reverbSendLevel: any): void;
|
|
297
|
-
setChorusSendLevel(channelNumber: any, chorusSendLevel: any): void;
|
|
298
301
|
setSostenutoPedal(channelNumber: any, value: any): void;
|
|
299
302
|
setSoftPedal(channelNumber: any, softPedal: any): void;
|
|
300
303
|
setFilterResonance(channelNumber: any, filterResonance: any): void;
|
|
@@ -305,6 +308,8 @@ export class Midy {
|
|
|
305
308
|
setVibratoRate(channelNumber: any, vibratoRate: any): void;
|
|
306
309
|
setVibratoDepth(channelNumber: any, vibratoDepth: any): void;
|
|
307
310
|
setVibratoDelay(channelNumber: any, vibratoDelay: any): void;
|
|
311
|
+
setReverbSendLevel(channelNumber: any, reverbSendLevel: any): void;
|
|
312
|
+
setChorusSendLevel(channelNumber: any, chorusSendLevel: any): void;
|
|
308
313
|
limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
|
|
309
314
|
limitDataMSB(channel: any, minMSB: any, maxMSB: any): void;
|
|
310
315
|
handleRPN(channelNumber: any, value: any): void;
|
|
@@ -313,13 +318,12 @@ export class Midy {
|
|
|
313
318
|
setRPNMSB(channelNumber: any, value: any): void;
|
|
314
319
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
315
320
|
dataEntryMSB(channelNumber: any, value: any): void;
|
|
316
|
-
updateDetune(channel: any, detune: any): void;
|
|
317
321
|
handlePitchBendRangeRPN(channelNumber: any): void;
|
|
318
|
-
setPitchBendRange(channelNumber: any,
|
|
322
|
+
setPitchBendRange(channelNumber: any, value: any): void;
|
|
319
323
|
handleFineTuningRPN(channelNumber: any): void;
|
|
320
|
-
setFineTuning(channelNumber: any,
|
|
324
|
+
setFineTuning(channelNumber: any, value: any): void;
|
|
321
325
|
handleCoarseTuningRPN(channelNumber: any): void;
|
|
322
|
-
setCoarseTuning(channelNumber: any,
|
|
326
|
+
setCoarseTuning(channelNumber: any, value: any): void;
|
|
323
327
|
handleModulationDepthRangeRPN(channelNumber: any): void;
|
|
324
328
|
setModulationDepthRange(channelNumber: any, modulationDepthRange: any): void;
|
|
325
329
|
allSoundOff(channelNumber: any): Promise<void>;
|
|
@@ -336,9 +340,11 @@ export class Midy {
|
|
|
336
340
|
handleMasterVolumeSysEx(data: any): void;
|
|
337
341
|
setMasterVolume(volume: any): void;
|
|
338
342
|
handleMasterFineTuningSysEx(data: any): void;
|
|
339
|
-
setMasterFineTuning(
|
|
343
|
+
setMasterFineTuning(value: any): void;
|
|
340
344
|
handleMasterCoarseTuningSysEx(data: any): void;
|
|
341
|
-
setMasterCoarseTuning(
|
|
345
|
+
setMasterCoarseTuning(value: any): void;
|
|
346
|
+
getChannelBitmap(data: any): any[];
|
|
347
|
+
handleScaleOctaveTuning1ByteFormat(data: any): void;
|
|
342
348
|
handleGlobalParameterControlSysEx(data: any): void;
|
|
343
349
|
handleReverbParameterSysEx(data: any): void;
|
|
344
350
|
setReverbType(type: any): void;
|
package/esm/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AA8GA;IAmCE
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|