@marmooo/midy 0.0.1 → 0.0.3
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 +2 -11
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +83 -126
- package/esm/midy-GM2.d.ts +3 -7
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +91 -102
- package/esm/midy-GMLite.d.ts +2 -11
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +84 -127
- package/esm/midy.d.ts +2 -7
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +94 -102
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +2 -11
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +83 -126
- package/script/midy-GM2.d.ts +3 -7
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +91 -102
- package/script/midy-GMLite.d.ts +2 -11
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +84 -127
- package/script/midy.d.ts +2 -7
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +94 -102
package/esm/midy-GM1.d.ts
CHANGED
|
@@ -24,7 +24,6 @@ export class MidyGM1 {
|
|
|
24
24
|
};
|
|
25
25
|
constructor(audioContext: any);
|
|
26
26
|
ticksPerBeat: number;
|
|
27
|
-
secondsPerBeat: number;
|
|
28
27
|
totalTime: number;
|
|
29
28
|
noteCheckInterval: number;
|
|
30
29
|
lookAhead: number;
|
|
@@ -50,7 +49,6 @@ export class MidyGM1 {
|
|
|
50
49
|
pannerNode: any;
|
|
51
50
|
modulationEffect: {
|
|
52
51
|
lfo: any;
|
|
53
|
-
lfoGain: any;
|
|
54
52
|
};
|
|
55
53
|
expression: number;
|
|
56
54
|
modulation: number;
|
|
@@ -81,7 +79,6 @@ export class MidyGM1 {
|
|
|
81
79
|
pannerNode: any;
|
|
82
80
|
modulationEffect: {
|
|
83
81
|
lfo: any;
|
|
84
|
-
lfoGain: any;
|
|
85
82
|
};
|
|
86
83
|
};
|
|
87
84
|
createChannels(audioContext: any): {
|
|
@@ -91,7 +88,6 @@ export class MidyGM1 {
|
|
|
91
88
|
pannerNode: any;
|
|
92
89
|
modulationEffect: {
|
|
93
90
|
lfo: any;
|
|
94
|
-
lfoGain: any;
|
|
95
91
|
};
|
|
96
92
|
expression: number;
|
|
97
93
|
modulation: number;
|
|
@@ -137,12 +133,6 @@ export class MidyGM1 {
|
|
|
137
133
|
getActiveChannelNotes(scheduledNotes: any): any;
|
|
138
134
|
createModulationEffect(audioContext: any): {
|
|
139
135
|
lfo: any;
|
|
140
|
-
lfoGain: any;
|
|
141
|
-
};
|
|
142
|
-
createReverbEffect(audioContext: any, options?: {}): {
|
|
143
|
-
convolverNode: any;
|
|
144
|
-
dryGain: any;
|
|
145
|
-
wetGain: any;
|
|
146
136
|
};
|
|
147
137
|
connectNoteEffects(channel: any, gainNode: any): void;
|
|
148
138
|
cbToRatio(cb: any): number;
|
|
@@ -151,12 +141,13 @@ export class MidyGM1 {
|
|
|
151
141
|
bufferSource: any;
|
|
152
142
|
gainNode: any;
|
|
153
143
|
filterNode: any;
|
|
144
|
+
lfoGain: any;
|
|
154
145
|
}>;
|
|
155
146
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
156
147
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
157
148
|
scheduleNoteRelease(channelNumber: any, noteNumber: any, velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
|
|
158
149
|
releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
|
|
159
|
-
releaseSustainPedal(channelNumber: any):
|
|
150
|
+
releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
|
|
160
151
|
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
|
|
161
152
|
handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
|
|
162
153
|
handleProgramChange(channelNumber: any, program: any): void;
|
package/esm/midy-GM1.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAMA;
|
|
1
|
+
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAMA;IAmBE;;;;;;;;;;;;;;MAcE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAjDD,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;IA4BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA4CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAyEC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;;OA6EC;IAED,kGAuCC;IAED,0EAGC;IAED,sIA4CC;IAED,0FAGC;IAED,kEAeC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAIC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAoBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
|
package/esm/midy-GM1.js
CHANGED
|
@@ -8,12 +8,6 @@ export class MidyGM1 {
|
|
|
8
8
|
writable: true,
|
|
9
9
|
value: 120
|
|
10
10
|
});
|
|
11
|
-
Object.defineProperty(this, "secondsPerBeat", {
|
|
12
|
-
enumerable: true,
|
|
13
|
-
configurable: true,
|
|
14
|
-
writable: true,
|
|
15
|
-
value: 0.5
|
|
16
|
-
});
|
|
17
11
|
Object.defineProperty(this, "totalTime", {
|
|
18
12
|
enumerable: true,
|
|
19
13
|
configurable: true,
|
|
@@ -144,10 +138,10 @@ export class MidyGM1 {
|
|
|
144
138
|
const response = await fetch(midiUrl);
|
|
145
139
|
const arrayBuffer = await response.arrayBuffer();
|
|
146
140
|
const midi = parseMidi(new Uint8Array(arrayBuffer));
|
|
141
|
+
this.ticksPerBeat = midi.header.ticksPerBeat;
|
|
147
142
|
const midiData = this.extractMidiData(midi);
|
|
148
143
|
this.instruments = midiData.instruments;
|
|
149
144
|
this.timeline = midiData.timeline;
|
|
150
|
-
this.ticksPerBeat = midi.header.ticksPerBeat;
|
|
151
145
|
this.totalTime = this.calcTotalTime();
|
|
152
146
|
}
|
|
153
147
|
setChannelAudioNodes(audioContext) {
|
|
@@ -226,18 +220,20 @@ export class MidyGM1 {
|
|
|
226
220
|
async scheduleTimelineEvents(t, offset, queueIndex) {
|
|
227
221
|
while (queueIndex < this.timeline.length) {
|
|
228
222
|
const event = this.timeline[queueIndex];
|
|
229
|
-
|
|
230
|
-
if (time > t + this.lookAhead)
|
|
223
|
+
if (event.startTime > t + this.lookAhead)
|
|
231
224
|
break;
|
|
232
225
|
switch (event.type) {
|
|
233
226
|
case "controller":
|
|
234
227
|
this.handleControlChange(event.channel, event.controllerType, event.value);
|
|
235
228
|
break;
|
|
236
229
|
case "noteOn":
|
|
237
|
-
|
|
238
|
-
|
|
230
|
+
if (event.velocity !== 0) {
|
|
231
|
+
await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
/* falls through */
|
|
239
235
|
case "noteOff": {
|
|
240
|
-
const notePromise = this.scheduleNoteRelease(event.channel, event.noteNumber, event.velocity,
|
|
236
|
+
const notePromise = this.scheduleNoteRelease(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
|
|
241
237
|
if (notePromise) {
|
|
242
238
|
this.notePromises.push(notePromise);
|
|
243
239
|
}
|
|
@@ -246,9 +242,6 @@ export class MidyGM1 {
|
|
|
246
242
|
case "programChange":
|
|
247
243
|
this.handleProgramChange(event.channel, event.programNumber);
|
|
248
244
|
break;
|
|
249
|
-
case "setTempo":
|
|
250
|
-
this.secondsPerBeat = event.microsecondsPerBeat / 1000000;
|
|
251
|
-
break;
|
|
252
245
|
case "sysEx":
|
|
253
246
|
this.handleSysEx(event.data);
|
|
254
247
|
}
|
|
@@ -257,9 +250,8 @@ export class MidyGM1 {
|
|
|
257
250
|
return queueIndex;
|
|
258
251
|
}
|
|
259
252
|
getQueueIndex(second) {
|
|
260
|
-
const ticks = this.secondToTicks(second, this.secondsPerBeat);
|
|
261
253
|
for (let i = 0; i < this.timeline.length; i++) {
|
|
262
|
-
if (
|
|
254
|
+
if (second <= this.timeline[i].startTime) {
|
|
263
255
|
return i;
|
|
264
256
|
}
|
|
265
257
|
}
|
|
@@ -367,18 +359,28 @@ export class MidyGM1 {
|
|
|
367
359
|
timeline.push(event);
|
|
368
360
|
});
|
|
369
361
|
});
|
|
362
|
+
const priority = {
|
|
363
|
+
setTempo: 0,
|
|
364
|
+
controller: 1,
|
|
365
|
+
};
|
|
370
366
|
timeline.sort((a, b) => {
|
|
371
|
-
if (a.ticks !== b.ticks)
|
|
367
|
+
if (a.ticks !== b.ticks)
|
|
372
368
|
return a.ticks - b.ticks;
|
|
373
|
-
|
|
374
|
-
if (a.type !== "controller" && b.type === "controller") {
|
|
375
|
-
return -1;
|
|
376
|
-
}
|
|
377
|
-
if (a.type === "controller" && b.type !== "controller") {
|
|
378
|
-
return 1;
|
|
379
|
-
}
|
|
380
|
-
return 0;
|
|
369
|
+
return (priority[a.type] || 2) - (priority[b.type] || 2);
|
|
381
370
|
});
|
|
371
|
+
let prevTempoTime = 0;
|
|
372
|
+
let prevTempoTicks = 0;
|
|
373
|
+
let secondsPerBeat = 0.5;
|
|
374
|
+
for (let i = 0; i < timeline.length; i++) {
|
|
375
|
+
const event = timeline[i];
|
|
376
|
+
const timeFromPrevTempo = this.ticksToSecond(event.ticks - prevTempoTicks, secondsPerBeat);
|
|
377
|
+
event.startTime = prevTempoTime + timeFromPrevTempo;
|
|
378
|
+
if (event.type === "setTempo") {
|
|
379
|
+
prevTempoTime += this.ticksToSecond(event.ticks - prevTempoTicks, secondsPerBeat);
|
|
380
|
+
secondsPerBeat = event.microsecondsPerBeat / 1000000;
|
|
381
|
+
prevTempoTicks = event.ticks;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
382
384
|
return { instruments, timeline };
|
|
383
385
|
}
|
|
384
386
|
stopNotes() {
|
|
@@ -430,32 +432,12 @@ export class MidyGM1 {
|
|
|
430
432
|
}
|
|
431
433
|
}
|
|
432
434
|
calcTotalTime() {
|
|
433
|
-
const endOfTracks = [];
|
|
434
|
-
let prevTicks = 0;
|
|
435
435
|
let totalTime = 0;
|
|
436
|
-
let secondsPerBeat = 0.5;
|
|
437
436
|
for (let i = 0; i < this.timeline.length; i++) {
|
|
438
437
|
const event = this.timeline[i];
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
const durationTicks = event.ticks - prevTicks;
|
|
442
|
-
totalTime += this.ticksToSecond(durationTicks, secondsPerBeat);
|
|
443
|
-
secondsPerBeat = event.microsecondsPerBeat / 1000000;
|
|
444
|
-
prevTicks = event.ticks;
|
|
445
|
-
break;
|
|
446
|
-
}
|
|
447
|
-
case "endOfTrack":
|
|
448
|
-
endOfTracks.push(event);
|
|
449
|
-
}
|
|
438
|
+
if (totalTime < event.startTime)
|
|
439
|
+
totalTime = event.startTime;
|
|
450
440
|
}
|
|
451
|
-
let maxTicks = 0;
|
|
452
|
-
for (let i = 0; i < endOfTracks.length; i++) {
|
|
453
|
-
const event = endOfTracks[i];
|
|
454
|
-
if (maxTicks < event.ticks)
|
|
455
|
-
maxTicks = event.ticks;
|
|
456
|
-
}
|
|
457
|
-
const durationTicks = maxTicks - prevTicks;
|
|
458
|
-
totalTime += this.ticksToSecond(durationTicks, secondsPerBeat);
|
|
459
441
|
return totalTime;
|
|
460
442
|
}
|
|
461
443
|
currentTime() {
|
|
@@ -464,7 +446,7 @@ export class MidyGM1 {
|
|
|
464
446
|
}
|
|
465
447
|
getActiveNotes(channel) {
|
|
466
448
|
const activeNotes = new Map();
|
|
467
|
-
channel.scheduledNotes.
|
|
449
|
+
channel.scheduledNotes.forEach((scheduledNotes) => {
|
|
468
450
|
const activeNote = this.getActiveChannelNotes(scheduledNotes);
|
|
469
451
|
if (activeNote) {
|
|
470
452
|
activeNotes.set(activeNote.noteNumber, activeNote);
|
|
@@ -483,43 +465,8 @@ export class MidyGM1 {
|
|
|
483
465
|
const lfo = new OscillatorNode(audioContext, {
|
|
484
466
|
frequency: 5,
|
|
485
467
|
});
|
|
486
|
-
const lfoGain = new GainNode(audioContext);
|
|
487
|
-
lfo.connect(lfoGain);
|
|
488
468
|
return {
|
|
489
469
|
lfo,
|
|
490
|
-
lfoGain,
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
createReverbEffect(audioContext, options = {}) {
|
|
494
|
-
const { decay = 0.8, preDecay = 0, } = options;
|
|
495
|
-
const sampleRate = audioContext.sampleRate;
|
|
496
|
-
const length = sampleRate * decay;
|
|
497
|
-
const impulse = new AudioBuffer({
|
|
498
|
-
numberOfChannels: 2,
|
|
499
|
-
length,
|
|
500
|
-
sampleRate,
|
|
501
|
-
});
|
|
502
|
-
const preDecayLength = Math.min(sampleRate * preDecay, length);
|
|
503
|
-
for (let channel = 0; channel < impulse.numberOfChannels; channel++) {
|
|
504
|
-
const channelData = impulse.getChannelData(channel);
|
|
505
|
-
for (let i = 0; i < preDecayLength; i++) {
|
|
506
|
-
channelData[i] = Math.random() * 2 - 1;
|
|
507
|
-
}
|
|
508
|
-
for (let i = preDecayLength; i < length; i++) {
|
|
509
|
-
const attenuation = Math.exp(-(i - preDecayLength) / sampleRate / decay);
|
|
510
|
-
channelData[i] = (Math.random() * 2 - 1) * attenuation;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
const convolverNode = new ConvolverNode(audioContext, {
|
|
514
|
-
buffer: impulse,
|
|
515
|
-
});
|
|
516
|
-
const dryGain = new GainNode(audioContext);
|
|
517
|
-
const wetGain = new GainNode(audioContext);
|
|
518
|
-
convolverNode.connect(wetGain);
|
|
519
|
-
return {
|
|
520
|
-
convolverNode,
|
|
521
|
-
dryGain,
|
|
522
|
-
wetGain,
|
|
523
470
|
};
|
|
524
471
|
}
|
|
525
472
|
connectNoteEffects(channel, gainNode) {
|
|
@@ -556,35 +503,46 @@ export class MidyGM1 {
|
|
|
556
503
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
557
504
|
.setValueAtTime(attackVolume, volHold)
|
|
558
505
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
559
|
-
if (channel.modulation > 0) {
|
|
560
|
-
const lfoGain = channel.modulationEffect.lfoGain;
|
|
561
|
-
lfoGain.connect(bufferSource.detune);
|
|
562
|
-
lfoGain.gain.cancelScheduledValues(startTime + channel.vibratoDelay);
|
|
563
|
-
lfoGain.gain.setValueAtTime(channel.modulation, startTime + channel.vibratoDelay);
|
|
564
|
-
}
|
|
565
506
|
// filter envelope
|
|
507
|
+
const maxFreq = this.audioContext.sampleRate / 2;
|
|
566
508
|
const baseFreq = this.centToHz(noteInfo.initialFilterFc);
|
|
567
509
|
const peekFreq = this.centToHz(noteInfo.initialFilterFc + noteInfo.modEnvToFilterFc);
|
|
568
510
|
const sustainFreq = baseFreq +
|
|
569
511
|
(peekFreq - baseFreq) * (1 - noteInfo.modSustain);
|
|
512
|
+
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
513
|
+
const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
|
|
514
|
+
const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
|
|
570
515
|
const filterNode = new BiquadFilterNode(this.audioContext, {
|
|
571
516
|
type: "lowpass",
|
|
572
|
-
Q:
|
|
573
|
-
frequency:
|
|
517
|
+
Q: noteInfo.initialFilterQ / 10, // dB
|
|
518
|
+
frequency: adjustedBaseFreq,
|
|
574
519
|
});
|
|
575
520
|
const modDelay = startTime + noteInfo.modDelay;
|
|
576
521
|
const modAttack = modDelay + noteInfo.modAttack;
|
|
577
522
|
const modHold = modAttack + noteInfo.modHold;
|
|
578
523
|
const modDecay = modHold + noteInfo.modDecay;
|
|
579
524
|
filterNode.frequency
|
|
580
|
-
.setValueAtTime(
|
|
581
|
-
.exponentialRampToValueAtTime(
|
|
582
|
-
.setValueAtTime(
|
|
583
|
-
.linearRampToValueAtTime(
|
|
525
|
+
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
526
|
+
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
527
|
+
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
528
|
+
.linearRampToValueAtTime(adjustedSustainFreq, modDecay);
|
|
529
|
+
let lfoGain;
|
|
530
|
+
if (channel.modulation > 0) {
|
|
531
|
+
const vibratoDelay = startTime + channel.vibratoDelay;
|
|
532
|
+
const vibratoAttack = vibratoDelay + 0.1;
|
|
533
|
+
lfoGain = new GainNode(this.audioContext, {
|
|
534
|
+
gain: 0,
|
|
535
|
+
});
|
|
536
|
+
lfoGain.gain
|
|
537
|
+
.setValueAtTime(1e-6, vibratoDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
538
|
+
.exponentialRampToValueAtTime(channel.modulation, vibratoAttack);
|
|
539
|
+
channel.modulationEffect.lfo.connect(lfoGain);
|
|
540
|
+
lfoGain.connect(bufferSource.detune);
|
|
541
|
+
}
|
|
584
542
|
bufferSource.connect(filterNode);
|
|
585
543
|
filterNode.connect(gainNode);
|
|
586
544
|
bufferSource.start(startTime, noteInfo.start / noteInfo.sampleRate);
|
|
587
|
-
return { bufferSource, gainNode, filterNode };
|
|
545
|
+
return { bufferSource, gainNode, filterNode, lfoGain };
|
|
588
546
|
}
|
|
589
547
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
590
548
|
const channel = this.channels[channelNumber];
|
|
@@ -597,16 +555,17 @@ export class MidyGM1 {
|
|
|
597
555
|
const noteInfo = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
|
|
598
556
|
if (!noteInfo)
|
|
599
557
|
return;
|
|
600
|
-
const { bufferSource, gainNode, filterNode } = await this
|
|
558
|
+
const { bufferSource, gainNode, filterNode, lfoGain } = await this
|
|
601
559
|
.createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3);
|
|
602
560
|
this.connectNoteEffects(channel, gainNode);
|
|
603
561
|
const scheduledNotes = channel.scheduledNotes;
|
|
604
562
|
const scheduledNote = {
|
|
605
|
-
gainNode,
|
|
606
|
-
filterNode,
|
|
607
563
|
bufferSource,
|
|
608
|
-
|
|
564
|
+
filterNode,
|
|
565
|
+
gainNode,
|
|
566
|
+
lfoGain,
|
|
609
567
|
noteInfo,
|
|
568
|
+
noteNumber,
|
|
610
569
|
startTime,
|
|
611
570
|
};
|
|
612
571
|
if (scheduledNotes.has(noteNumber)) {
|
|
@@ -633,15 +592,18 @@ export class MidyGM1 {
|
|
|
633
592
|
continue;
|
|
634
593
|
if (targetNote.ending)
|
|
635
594
|
continue;
|
|
636
|
-
const { bufferSource, filterNode, gainNode, noteInfo } = targetNote;
|
|
595
|
+
const { bufferSource, filterNode, gainNode, lfoGain, noteInfo } = targetNote;
|
|
637
596
|
const velocityRate = (velocity + 127) / 127;
|
|
638
597
|
const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
|
|
639
598
|
gainNode.gain.cancelScheduledValues(stopTime);
|
|
640
599
|
gainNode.gain.linearRampToValueAtTime(0, volEndTime);
|
|
600
|
+
const maxFreq = this.audioContext.sampleRate / 2;
|
|
641
601
|
const baseFreq = this.centToHz(noteInfo.initialFilterFc);
|
|
602
|
+
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
642
603
|
const modEndTime = stopTime + noteInfo.modRelease * velocityRate;
|
|
643
|
-
filterNode.frequency
|
|
644
|
-
|
|
604
|
+
filterNode.frequency
|
|
605
|
+
.cancelScheduledValues(stopTime)
|
|
606
|
+
.linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
|
|
645
607
|
targetNote.ending = true;
|
|
646
608
|
this.scheduleTask(() => {
|
|
647
609
|
bufferSource.loop = false;
|
|
@@ -652,6 +614,8 @@ export class MidyGM1 {
|
|
|
652
614
|
bufferSource.disconnect(0);
|
|
653
615
|
filterNode.disconnect(0);
|
|
654
616
|
gainNode.disconnect(0);
|
|
617
|
+
if (lfoGain)
|
|
618
|
+
lfoGain.disconnect(0);
|
|
655
619
|
resolve();
|
|
656
620
|
};
|
|
657
621
|
bufferSource.stop(volEndTime);
|
|
@@ -662,25 +626,21 @@ export class MidyGM1 {
|
|
|
662
626
|
const now = this.audioContext.currentTime;
|
|
663
627
|
return this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now);
|
|
664
628
|
}
|
|
665
|
-
releaseSustainPedal(channelNumber) {
|
|
666
|
-
const
|
|
629
|
+
releaseSustainPedal(channelNumber, halfVelocity) {
|
|
630
|
+
const velocity = halfVelocity * 2;
|
|
667
631
|
const channel = this.channels[channelNumber];
|
|
632
|
+
const promises = [];
|
|
668
633
|
channel.sustainPedal = false;
|
|
669
634
|
channel.scheduledNotes.forEach((scheduledNotes) => {
|
|
670
635
|
scheduledNotes.forEach((scheduledNote) => {
|
|
671
636
|
if (scheduledNote) {
|
|
672
|
-
const {
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
gainNode.gain.linearRampToValueAtTime(0, volEndTime);
|
|
676
|
-
const baseFreq = this.centToHz(noteInfo.initialFilterFc);
|
|
677
|
-
const modEndTime = stopTime + noteInfo.modRelease;
|
|
678
|
-
filterNode.frequency.cancelScheduledValues(stopTime);
|
|
679
|
-
filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
|
|
680
|
-
bufferSource.stop(volEndTime);
|
|
637
|
+
const { noteNumber } = scheduledNote;
|
|
638
|
+
const promise = this.releaseNote(channelNumber, noteNumber, velocity);
|
|
639
|
+
promises.push(promise);
|
|
681
640
|
}
|
|
682
641
|
});
|
|
683
642
|
});
|
|
643
|
+
return promises;
|
|
684
644
|
}
|
|
685
645
|
handleMIDIMessage(statusByte, data1, data2) {
|
|
686
646
|
const channelNumber = statusByte & 0x0F;
|
|
@@ -713,7 +673,7 @@ export class MidyGM1 {
|
|
|
713
673
|
scheduledNotes.forEach((scheduledNote) => {
|
|
714
674
|
if (scheduledNote) {
|
|
715
675
|
const { initialAttenuation } = scheduledNote.noteInfo;
|
|
716
|
-
const gain = this.cbToRatio(initialAttenuation) * pressure;
|
|
676
|
+
const gain = this.cbToRatio(-initialAttenuation) * pressure;
|
|
717
677
|
scheduledNote.gainNode.gain.cancelScheduledValues(now);
|
|
718
678
|
scheduledNote.gainNode.gain.setValueAtTime(gain, now);
|
|
719
679
|
}
|
|
@@ -762,13 +722,9 @@ export class MidyGM1 {
|
|
|
762
722
|
}
|
|
763
723
|
}
|
|
764
724
|
setModulation(channelNumber, modulation) {
|
|
765
|
-
const now = this.audioContext.currentTime;
|
|
766
725
|
const channel = this.channels[channelNumber];
|
|
767
|
-
channel.modulation = (modulation
|
|
768
|
-
channel.modulationDepthRange;
|
|
769
|
-
const lfoGain = channel.modulationEffect.lfoGain;
|
|
770
|
-
lfoGain.gain.cancelScheduledValues(now);
|
|
771
|
-
lfoGain.gain.setValueAtTime(channel.modulation, now);
|
|
726
|
+
channel.modulation = (modulation / 127) *
|
|
727
|
+
(channel.modulationDepthRange * 100);
|
|
772
728
|
}
|
|
773
729
|
setVolume(channelNumber, volume) {
|
|
774
730
|
const channel = this.channels[channelNumber];
|
|
@@ -794,9 +750,10 @@ export class MidyGM1 {
|
|
|
794
750
|
channel.gainNode.gain.setValueAtTime(volume, now);
|
|
795
751
|
}
|
|
796
752
|
setSustainPedal(channelNumber, value) {
|
|
797
|
-
|
|
753
|
+
const isOn = value >= 64;
|
|
754
|
+
this.channels[channelNumber].sustainPedal = isOn;
|
|
798
755
|
if (!isOn) {
|
|
799
|
-
this.releaseSustainPedal(channelNumber);
|
|
756
|
+
this.releaseSustainPedal(channelNumber, value);
|
|
800
757
|
}
|
|
801
758
|
}
|
|
802
759
|
setRPNMSB(channelNumber, value) {
|
|
@@ -936,7 +893,7 @@ Object.defineProperty(MidyGM1, "channelSettings", {
|
|
|
936
893
|
configurable: true,
|
|
937
894
|
writable: true,
|
|
938
895
|
value: {
|
|
939
|
-
volume:
|
|
896
|
+
volume: 100 / 127,
|
|
940
897
|
pan: 0,
|
|
941
898
|
vibratoRate: 5,
|
|
942
899
|
vibratoDepth: 0.5,
|
|
@@ -948,7 +905,7 @@ Object.defineProperty(MidyGM1, "channelSettings", {
|
|
|
948
905
|
pitchBend: 0,
|
|
949
906
|
fineTuning: 0,
|
|
950
907
|
coarseTuning: 0,
|
|
951
|
-
modulationDepthRange:
|
|
908
|
+
modulationDepthRange: 0.5,
|
|
952
909
|
}
|
|
953
910
|
});
|
|
954
911
|
Object.defineProperty(MidyGM1, "effectSettings", {
|
package/esm/midy-GM2.d.ts
CHANGED
|
@@ -34,7 +34,6 @@ export class MidyGM2 {
|
|
|
34
34
|
};
|
|
35
35
|
constructor(audioContext: any);
|
|
36
36
|
ticksPerBeat: number;
|
|
37
|
-
secondsPerBeat: number;
|
|
38
37
|
totalTime: number;
|
|
39
38
|
reverbFactor: number;
|
|
40
39
|
masterFineTuning: number;
|
|
@@ -65,7 +64,6 @@ export class MidyGM2 {
|
|
|
65
64
|
pannerNode: any;
|
|
66
65
|
modulationEffect: {
|
|
67
66
|
lfo: any;
|
|
68
|
-
lfoGain: any;
|
|
69
67
|
};
|
|
70
68
|
reverbEffect: {
|
|
71
69
|
convolverNode: any;
|
|
@@ -117,7 +115,6 @@ export class MidyGM2 {
|
|
|
117
115
|
pannerNode: any;
|
|
118
116
|
modulationEffect: {
|
|
119
117
|
lfo: any;
|
|
120
|
-
lfoGain: any;
|
|
121
118
|
};
|
|
122
119
|
reverbEffect: {
|
|
123
120
|
convolverNode: any;
|
|
@@ -138,7 +135,6 @@ export class MidyGM2 {
|
|
|
138
135
|
pannerNode: any;
|
|
139
136
|
modulationEffect: {
|
|
140
137
|
lfo: any;
|
|
141
|
-
lfoGain: any;
|
|
142
138
|
};
|
|
143
139
|
reverbEffect: {
|
|
144
140
|
convolverNode: any;
|
|
@@ -205,7 +201,6 @@ export class MidyGM2 {
|
|
|
205
201
|
getActiveChannelNotes(scheduledNotes: any): any;
|
|
206
202
|
createModulationEffect(audioContext: any): {
|
|
207
203
|
lfo: any;
|
|
208
|
-
lfoGain: any;
|
|
209
204
|
};
|
|
210
205
|
createReverbEffect(audioContext: any, options?: {}): {
|
|
211
206
|
convolverNode: any;
|
|
@@ -225,14 +220,15 @@ export class MidyGM2 {
|
|
|
225
220
|
bufferSource: any;
|
|
226
221
|
gainNode: any;
|
|
227
222
|
filterNode: any;
|
|
223
|
+
lfoGain: any;
|
|
228
224
|
}>;
|
|
229
225
|
calcBank(channel: any, channelNumber: any): any;
|
|
230
226
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
231
227
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
232
228
|
scheduleNoteRelease(channelNumber: any, noteNumber: any, velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
|
|
233
229
|
releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
|
|
234
|
-
releaseSustainPedal(channelNumber: any):
|
|
235
|
-
|
|
230
|
+
releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
|
|
231
|
+
releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
|
|
236
232
|
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
|
|
237
233
|
handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
|
|
238
234
|
handleProgramChange(channelNumber: any, program: any): void;
|
package/esm/midy-GM2.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;
|
|
1
|
+
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAhED,qBAAmB;IACnB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,cAAa;IACb,cAAa;IACb,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;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA4CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA2GC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;;OAsFC;IAED,gDAQC;IAED,kGAgDC;IAED,0EAGC;IAED,sIA6CC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,mFAuDC;IAED,+CAEC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAUC;IAED,uDAGC;IAED,gDAEC;IAED,gDAEC;IAED,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
|