@marmooo/midy 0.4.0 → 0.4.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/README.md +2 -1
- package/esm/midy-GM1.d.ts +3 -3
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +43 -30
- package/esm/midy-GM2.d.ts +3 -3
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +49 -36
- package/esm/midy-GMLite.d.ts +3 -3
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +35 -23
- package/esm/midy.d.ts +10 -8
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +122 -52
- package/package.json +2 -2
- package/script/midy-GM1.d.ts +3 -3
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +43 -30
- package/script/midy-GM2.d.ts +3 -3
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +49 -36
- package/script/midy-GMLite.d.ts +3 -3
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +35 -23
- package/script/midy.d.ts +10 -8
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +122 -52
package/script/midy.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export class Midy {
|
|
|
13
13
|
modulationDepthRange: number;
|
|
14
14
|
fineTuning: number;
|
|
15
15
|
coarseTuning: number;
|
|
16
|
+
portamentoControl: boolean;
|
|
16
17
|
};
|
|
17
18
|
constructor(audioContext: any);
|
|
18
19
|
mode: string;
|
|
@@ -182,11 +183,11 @@ export class Midy {
|
|
|
182
183
|
noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
183
184
|
disconnectNote(note: any): void;
|
|
184
185
|
releaseNote(channel: any, note: any, endTime: any): Promise<any>;
|
|
185
|
-
noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any):
|
|
186
|
+
noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): Promise<any> | undefined;
|
|
186
187
|
setNoteIndex(channel: any, index: any): void;
|
|
187
188
|
findNoteOffIndex(channel: any, noteNumber: any): any;
|
|
188
|
-
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any):
|
|
189
|
-
releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any):
|
|
189
|
+
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
190
|
+
releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
190
191
|
createMessageHandlers(): any[];
|
|
191
192
|
handleMessage(data: any, scheduleTime: any): void;
|
|
192
193
|
activeSensing(): void;
|
|
@@ -223,16 +224,16 @@ export class Midy {
|
|
|
223
224
|
setControlChange(channelNumber: any, controllerType: any, value: any, scheduleTime: any): void;
|
|
224
225
|
setBankMSB(channelNumber: any, msb: any): void;
|
|
225
226
|
updateModulation(channel: any, scheduleTime: any): void;
|
|
226
|
-
setModulationDepth(channelNumber: any,
|
|
227
|
+
setModulationDepth(channelNumber: any, value: any, scheduleTime: any): void;
|
|
227
228
|
updatePortamento(channel: any, scheduleTime: any): void;
|
|
228
|
-
setPortamentoTime(channelNumber: any,
|
|
229
|
-
setVolume(channelNumber: any,
|
|
229
|
+
setPortamentoTime(channelNumber: any, value: any, scheduleTime: any): void;
|
|
230
|
+
setVolume(channelNumber: any, value: any, scheduleTime: any): void;
|
|
230
231
|
panToGain(pan: any): {
|
|
231
232
|
gainLeft: number;
|
|
232
233
|
gainRight: number;
|
|
233
234
|
};
|
|
234
|
-
setPan(channelNumber: any,
|
|
235
|
-
setExpression(channelNumber: any,
|
|
235
|
+
setPan(channelNumber: any, value: any, scheduleTime: any): void;
|
|
236
|
+
setExpression(channelNumber: any, value: any, scheduleTime: any): void;
|
|
236
237
|
setBankLSB(channelNumber: any, lsb: any): void;
|
|
237
238
|
dataEntryLSB(channelNumber: any, value: any, scheduleTime: any): void;
|
|
238
239
|
updateChannelVolume(channel: any, scheduleTime: any): void;
|
|
@@ -252,6 +253,7 @@ export class Midy {
|
|
|
252
253
|
setVibratoRate(channelNumber: any, vibratoRate: any, scheduleTime: any): void;
|
|
253
254
|
setVibratoDepth(channelNumber: any, vibratoDepth: any, scheduleTime: any): void;
|
|
254
255
|
setVibratoDelay(channelNumber: any, vibratoDelay: any, scheduleTime: any): void;
|
|
256
|
+
setPortamentoNoteNumber(channelNumber: any, value: any, scheduleTime: any): void;
|
|
255
257
|
setReverbSendLevel(channelNumber: any, reverbSendLevel: any, scheduleTime: any): void;
|
|
256
258
|
setChorusSendLevel(channelNumber: any, chorusSendLevel: any, scheduleTime: any): void;
|
|
257
259
|
limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
|
package/script/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|
package/script/midy.js
CHANGED
|
@@ -161,14 +161,19 @@ const defaultControllerState = {
|
|
|
161
161
|
pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
|
|
162
162
|
link: { type: 127, defaultValue: 0 },
|
|
163
163
|
// bankMSB: { type: 128 + 0, defaultValue: 121, },
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
modulationDepthMSB: { type: 128 + 1, defaultValue: 0 },
|
|
165
|
+
portamentoTimeMSB: { type: 128 + 5, defaultValue: 0 },
|
|
166
166
|
// dataMSB: { type: 128 + 6, defaultValue: 0, },
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
volumeMSB: { type: 128 + 7, defaultValue: 100 / 127 },
|
|
168
|
+
panMSB: { type: 128 + 10, defaultValue: 64 / 127 },
|
|
169
|
+
expressionMSB: { type: 128 + 11, defaultValue: 1 },
|
|
170
170
|
// bankLSB: { type: 128 + 32, defaultValue: 0, },
|
|
171
|
+
modulationDepthLSB: { type: 128 + 33, defaultValue: 0 },
|
|
172
|
+
portamentoTimeLSB: { type: 128 + 37, defaultValue: 0 },
|
|
171
173
|
// dataLSB: { type: 128 + 38, defaultValue: 0, },
|
|
174
|
+
volumeLSB: { type: 128 + 39, defaultValue: 0 },
|
|
175
|
+
panLSB: { type: 128 + 42, defaultValue: 0 },
|
|
176
|
+
expressionLSB: { type: 128 + 43, defaultValue: 0 },
|
|
172
177
|
sustainPedal: { type: 128 + 64, defaultValue: 0 },
|
|
173
178
|
portamento: { type: 128 + 65, defaultValue: 0 },
|
|
174
179
|
sostenutoPedal: { type: 128 + 66, defaultValue: 0 },
|
|
@@ -181,6 +186,7 @@ const defaultControllerState = {
|
|
|
181
186
|
vibratoRate: { type: 128 + 76, defaultValue: 64 / 127 },
|
|
182
187
|
vibratoDepth: { type: 128 + 77, defaultValue: 64 / 127 },
|
|
183
188
|
vibratoDelay: { type: 128 + 78, defaultValue: 64 / 127 },
|
|
189
|
+
portamentoNoteNumber: { type: 128 + 84, defaultValue: 0 },
|
|
184
190
|
reverbSendLevel: { type: 128 + 91, defaultValue: 0 },
|
|
185
191
|
chorusSendLevel: { type: 128 + 93, defaultValue: 0 },
|
|
186
192
|
// dataIncrement: { type: 128 + 96, defaultValue: 0 },
|
|
@@ -564,7 +570,7 @@ class Midy {
|
|
|
564
570
|
return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
|
|
565
571
|
}
|
|
566
572
|
createChannelAudioNodes(audioContext) {
|
|
567
|
-
const { gainLeft, gainRight } = this.panToGain(defaultControllerState.
|
|
573
|
+
const { gainLeft, gainRight } = this.panToGain(defaultControllerState.panMSB.defaultValue);
|
|
568
574
|
const gainL = new GainNode(audioContext, { gain: gainLeft });
|
|
569
575
|
const gainR = new GainNode(audioContext, { gain: gainRight });
|
|
570
576
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
@@ -607,10 +613,9 @@ class Midy {
|
|
|
607
613
|
return channels;
|
|
608
614
|
}
|
|
609
615
|
async createAudioBuffer(voiceParams) {
|
|
610
|
-
const sample = voiceParams
|
|
611
|
-
const
|
|
612
|
-
const
|
|
613
|
-
const audioBuffer = await sample.toAudioBuffer(this.audioContext, sampleStart, sampleEnd);
|
|
616
|
+
const { sample, start, end } = voiceParams;
|
|
617
|
+
const sampleEnd = sample.data.length + end;
|
|
618
|
+
const audioBuffer = await sample.toAudioBuffer(this.audioContext, start, sampleEnd);
|
|
614
619
|
return audioBuffer;
|
|
615
620
|
}
|
|
616
621
|
isLoopDrum(channel, noteNumber) {
|
|
@@ -645,9 +650,7 @@ class Midy {
|
|
|
645
650
|
await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
646
651
|
break;
|
|
647
652
|
case "noteOff": {
|
|
648
|
-
|
|
649
|
-
if (notePromise)
|
|
650
|
-
this.notePromises.push(notePromise);
|
|
653
|
+
this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
|
|
651
654
|
break;
|
|
652
655
|
}
|
|
653
656
|
case "noteAftertouch":
|
|
@@ -754,6 +757,12 @@ class Midy {
|
|
|
754
757
|
const waitTime = now + this.noteCheckInterval;
|
|
755
758
|
await this.scheduleTask(() => { }, waitTime);
|
|
756
759
|
}
|
|
760
|
+
if (this.timeline.length <= queueIndex) {
|
|
761
|
+
const now = this.audioContext.currentTime;
|
|
762
|
+
await this.stopNotes(0, true, now);
|
|
763
|
+
await this.audioContext.suspend();
|
|
764
|
+
finished = true;
|
|
765
|
+
}
|
|
757
766
|
if (finished) {
|
|
758
767
|
this.notePromises = [];
|
|
759
768
|
this.resetAllStates();
|
|
@@ -1146,6 +1155,13 @@ class Midy {
|
|
|
1146
1155
|
const noteDetune = this.calcNoteDetune(channel, note);
|
|
1147
1156
|
const pitchControl = this.getPitchControl(channel, note);
|
|
1148
1157
|
const detune = channel.detune + noteDetune + pitchControl;
|
|
1158
|
+
if (channel.portamentoControl) {
|
|
1159
|
+
const state = channel.state;
|
|
1160
|
+
const portamentoNoteNumber = Math.ceil(state.portamentoNoteNumber * 127);
|
|
1161
|
+
note.portamentoNoteNumber = portamentoNoteNumber;
|
|
1162
|
+
channel.portamentoControl = false;
|
|
1163
|
+
state.portamentoNoteNumber = 0;
|
|
1164
|
+
}
|
|
1149
1165
|
if (this.isPortamento(channel, note)) {
|
|
1150
1166
|
const startTime = note.startTime;
|
|
1151
1167
|
const deltaCent = (note.noteNumber - note.portamentoNoteNumber) * 100;
|
|
@@ -1162,8 +1178,10 @@ class Midy {
|
|
|
1162
1178
|
}
|
|
1163
1179
|
}
|
|
1164
1180
|
getPortamentoTime(channel, note) {
|
|
1181
|
+
const { portamentoTimeMSB, portamentoTimeLSB } = channel.state;
|
|
1182
|
+
const portamentoTime = portamentoTimeMSB + portamentoTimeLSB / 128;
|
|
1165
1183
|
const deltaSemitone = Math.abs(note.noteNumber - note.portamentoNoteNumber);
|
|
1166
|
-
const value = Math.ceil(
|
|
1184
|
+
const value = Math.ceil(portamentoTime * 128);
|
|
1167
1185
|
return deltaSemitone / this.getPitchIncrementSpeed(value) / 10;
|
|
1168
1186
|
}
|
|
1169
1187
|
getPitchIncrementSpeed(value) {
|
|
@@ -1427,7 +1445,7 @@ class Midy {
|
|
|
1427
1445
|
if (0 < state.vibratoDepth) {
|
|
1428
1446
|
this.startVibrato(channel, note, now);
|
|
1429
1447
|
}
|
|
1430
|
-
if (0 < state.
|
|
1448
|
+
if (0 < state.modulationDepthMSB + state.modulationDepthLSB) {
|
|
1431
1449
|
this.startModulation(channel, note, now);
|
|
1432
1450
|
}
|
|
1433
1451
|
if (channel.mono && channel.currentBufferSource) {
|
|
@@ -1438,7 +1456,13 @@ class Midy {
|
|
|
1438
1456
|
note.filterNode.connect(note.volumeEnvelopeNode);
|
|
1439
1457
|
this.setChorusSend(channel, note, now);
|
|
1440
1458
|
this.setReverbSend(channel, note, now);
|
|
1441
|
-
|
|
1459
|
+
if (voiceParams.sample.type === "compressed") {
|
|
1460
|
+
const offset = voiceParams.start / audioBuffer.sampleRate;
|
|
1461
|
+
note.bufferSource.start(startTime, offset);
|
|
1462
|
+
}
|
|
1463
|
+
else {
|
|
1464
|
+
note.bufferSource.start(startTime);
|
|
1465
|
+
}
|
|
1442
1466
|
return note;
|
|
1443
1467
|
}
|
|
1444
1468
|
handleExclusiveClass(note, channelNumber, startTime) {
|
|
@@ -1597,7 +1621,9 @@ class Midy {
|
|
|
1597
1621
|
}
|
|
1598
1622
|
note.ending = true;
|
|
1599
1623
|
this.setNoteIndex(channel, index);
|
|
1600
|
-
this.releaseNote(channel, note, endTime);
|
|
1624
|
+
const promise = this.releaseNote(channel, note, endTime);
|
|
1625
|
+
this.notePromises.push(promise);
|
|
1626
|
+
return promise;
|
|
1601
1627
|
}
|
|
1602
1628
|
setNoteIndex(channel, index) {
|
|
1603
1629
|
let allEnds = true;
|
|
@@ -1750,9 +1776,11 @@ class Midy {
|
|
|
1750
1776
|
}
|
|
1751
1777
|
setModLfoToPitch(channel, note, scheduleTime) {
|
|
1752
1778
|
if (note.modulationDepth) {
|
|
1779
|
+
const { modulationDepthMSB, modulationDepthLSB } = channel.state;
|
|
1780
|
+
const modulationDepth = modulationDepthMSB + modulationDepthLSB / 128;
|
|
1753
1781
|
const modLfoToPitch = note.voiceParams.modLfoToPitch +
|
|
1754
1782
|
this.getLFOPitchDepth(channel, note);
|
|
1755
|
-
const baseDepth = Math.abs(modLfoToPitch) +
|
|
1783
|
+
const baseDepth = Math.abs(modLfoToPitch) + modulationDepth;
|
|
1756
1784
|
const depth = baseDepth * Math.sign(modLfoToPitch);
|
|
1757
1785
|
note.modulationDepth.gain
|
|
1758
1786
|
.cancelScheduledValues(scheduleTime)
|
|
@@ -1885,7 +1913,8 @@ class Midy {
|
|
|
1885
1913
|
createVoiceParamsHandlers() {
|
|
1886
1914
|
return {
|
|
1887
1915
|
modLfoToPitch: (channel, note, scheduleTime) => {
|
|
1888
|
-
|
|
1916
|
+
const { modulationDepthMSB, modulationDepthLSB } = channel.state;
|
|
1917
|
+
if (0 < modulationDepthMSB + modulationDepthLSB) {
|
|
1889
1918
|
this.setModLfoToPitch(channel, note, scheduleTime);
|
|
1890
1919
|
}
|
|
1891
1920
|
},
|
|
@@ -1895,12 +1924,14 @@ class Midy {
|
|
|
1895
1924
|
}
|
|
1896
1925
|
},
|
|
1897
1926
|
modLfoToFilterFc: (channel, note, scheduleTime) => {
|
|
1898
|
-
|
|
1927
|
+
const { modulationDepthMSB, modulationDepthLSB } = channel.state;
|
|
1928
|
+
if (0 < modulationDepthMSB + modulationDepthLSB) {
|
|
1899
1929
|
this.setModLfoToFilterFc(channel, note, scheduleTime);
|
|
1900
1930
|
}
|
|
1901
1931
|
},
|
|
1902
1932
|
modLfoToVolume: (channel, note, scheduleTime) => {
|
|
1903
|
-
|
|
1933
|
+
const { modulationDepthMSB, modulationDepthLSB } = channel.state;
|
|
1934
|
+
if (0 < modulationDepthMSB + modulationDepthLSB) {
|
|
1904
1935
|
this.setModLfoToVolume(channel, note, scheduleTime);
|
|
1905
1936
|
}
|
|
1906
1937
|
},
|
|
@@ -1911,12 +1942,14 @@ class Midy {
|
|
|
1911
1942
|
this.setReverbSend(channel, note, scheduleTime);
|
|
1912
1943
|
},
|
|
1913
1944
|
delayModLFO: (_channel, note, _scheduleTime) => {
|
|
1914
|
-
|
|
1945
|
+
const { modulationDepthMSB, modulationDepthLSB } = channel.state;
|
|
1946
|
+
if (0 < modulationDepthMSB + modulationDepthLSB) {
|
|
1915
1947
|
this.setDelayModLFO(note);
|
|
1916
1948
|
}
|
|
1917
1949
|
},
|
|
1918
1950
|
freqModLFO: (_channel, note, scheduleTime) => {
|
|
1919
|
-
|
|
1951
|
+
const { modulationDepthMSB, modulationDepthLSB } = channel.state;
|
|
1952
|
+
if (0 < modulationDepthMSB + modulationDepthLSB) {
|
|
1920
1953
|
this.setFreqModLFO(note, scheduleTime);
|
|
1921
1954
|
}
|
|
1922
1955
|
},
|
|
@@ -1985,7 +2018,12 @@ class Midy {
|
|
|
1985
2018
|
handlers[10] = this.setPan;
|
|
1986
2019
|
handlers[11] = this.setExpression;
|
|
1987
2020
|
handlers[32] = this.setBankLSB;
|
|
2021
|
+
handlers[33] = this.setModulationDepth;
|
|
2022
|
+
handlers[37] = this.setPortamentoTime;
|
|
1988
2023
|
handlers[38] = this.dataEntryLSB;
|
|
2024
|
+
handlers[39] = this.setVolume;
|
|
2025
|
+
handlers[42] = this.setPan;
|
|
2026
|
+
handlers[43] = this.setExpression;
|
|
1989
2027
|
handlers[64] = this.setSustainPedal;
|
|
1990
2028
|
handlers[65] = this.setPortamento;
|
|
1991
2029
|
handlers[66] = this.setSostenutoPedal;
|
|
@@ -1998,6 +2036,7 @@ class Midy {
|
|
|
1998
2036
|
handlers[76] = this.setVibratoRate;
|
|
1999
2037
|
handlers[77] = this.setVibratoDepth;
|
|
2000
2038
|
handlers[78] = this.setVibratoDelay;
|
|
2039
|
+
handlers[84] = this.setPortamentoNoteNumber;
|
|
2001
2040
|
handlers[91] = this.setReverbSendLevel;
|
|
2002
2041
|
handlers[93] = this.setChorusSendLevel;
|
|
2003
2042
|
handlers[96] = this.dataIncrement;
|
|
@@ -2029,7 +2068,9 @@ class Midy {
|
|
|
2029
2068
|
this.channels[channelNumber].bankMSB = msb;
|
|
2030
2069
|
}
|
|
2031
2070
|
updateModulation(channel, scheduleTime) {
|
|
2032
|
-
const
|
|
2071
|
+
const { modulationDepthMSB, modulationDepthLSB } = channel.state;
|
|
2072
|
+
const modulationDepth = modulationDepthMSB + modulationDepthLSB / 128;
|
|
2073
|
+
const depth = modulationDepth * channel.modulationDepthRange;
|
|
2033
2074
|
this.processScheduledNotes(channel, (note) => {
|
|
2034
2075
|
if (note.modulationDepth) {
|
|
2035
2076
|
note.modulationDepth.gain.setValueAtTime(depth, scheduleTime);
|
|
@@ -2039,12 +2080,15 @@ class Midy {
|
|
|
2039
2080
|
}
|
|
2040
2081
|
});
|
|
2041
2082
|
}
|
|
2042
|
-
setModulationDepth(channelNumber,
|
|
2083
|
+
setModulationDepth(channelNumber, value, scheduleTime) {
|
|
2043
2084
|
const channel = this.channels[channelNumber];
|
|
2044
2085
|
if (channel.isDrum)
|
|
2045
2086
|
return;
|
|
2046
2087
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2047
|
-
|
|
2088
|
+
const state = channel.state;
|
|
2089
|
+
const intPart = Math.trunc(value);
|
|
2090
|
+
state.modulationDepthMSB = intPart / 127;
|
|
2091
|
+
state.modulationDepthLSB = value - intPart;
|
|
2048
2092
|
this.updateModulation(channel, scheduleTime);
|
|
2049
2093
|
}
|
|
2050
2094
|
updatePortamento(channel, scheduleTime) {
|
|
@@ -2065,18 +2109,24 @@ class Midy {
|
|
|
2065
2109
|
}
|
|
2066
2110
|
});
|
|
2067
2111
|
}
|
|
2068
|
-
setPortamentoTime(channelNumber,
|
|
2069
|
-
const channel = this.channels[channelNumber];
|
|
2112
|
+
setPortamentoTime(channelNumber, value, scheduleTime) {
|
|
2070
2113
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2071
|
-
channel
|
|
2114
|
+
const channel = this.channels[channelNumber];
|
|
2115
|
+
const state = channel.state;
|
|
2116
|
+
const intPart = Math.trunc(value);
|
|
2117
|
+
state.portamentoTimeMSB = intPart / 127;
|
|
2118
|
+
state.portamentoTimeLSB = value - 127;
|
|
2072
2119
|
if (channel.isDrum)
|
|
2073
2120
|
return;
|
|
2074
2121
|
this.updatePortamento(channel, scheduleTime);
|
|
2075
2122
|
}
|
|
2076
|
-
setVolume(channelNumber,
|
|
2123
|
+
setVolume(channelNumber, value, scheduleTime) {
|
|
2077
2124
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2078
2125
|
const channel = this.channels[channelNumber];
|
|
2079
|
-
|
|
2126
|
+
const state = channel.state;
|
|
2127
|
+
const intPart = Math.trunc(value);
|
|
2128
|
+
state.volumeMSB = intPart / 127;
|
|
2129
|
+
state.volumeLSB = value - intPart;
|
|
2080
2130
|
if (channel.isDrum) {
|
|
2081
2131
|
for (let i = 0; i < 128; i++) {
|
|
2082
2132
|
this.updateKeyBasedVolume(channel, i, scheduleTime);
|
|
@@ -2087,16 +2137,19 @@ class Midy {
|
|
|
2087
2137
|
}
|
|
2088
2138
|
}
|
|
2089
2139
|
panToGain(pan) {
|
|
2090
|
-
const theta = Math.PI / 2 * Math.max(
|
|
2140
|
+
const theta = Math.PI / 2 * Math.max(pan * 127 - 1) / 126;
|
|
2091
2141
|
return {
|
|
2092
2142
|
gainLeft: Math.cos(theta),
|
|
2093
2143
|
gainRight: Math.sin(theta),
|
|
2094
2144
|
};
|
|
2095
2145
|
}
|
|
2096
|
-
setPan(channelNumber,
|
|
2146
|
+
setPan(channelNumber, value, scheduleTime) {
|
|
2097
2147
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2098
2148
|
const channel = this.channels[channelNumber];
|
|
2099
|
-
|
|
2149
|
+
const state = channel.state;
|
|
2150
|
+
const intPart = Math.trunc(value);
|
|
2151
|
+
state.panMSB = intPart / 127;
|
|
2152
|
+
state.panLSB = value - intPart;
|
|
2100
2153
|
if (channel.isDrum) {
|
|
2101
2154
|
for (let i = 0; i < 128; i++) {
|
|
2102
2155
|
this.updateKeyBasedVolume(channel, i, scheduleTime);
|
|
@@ -2106,10 +2159,13 @@ class Midy {
|
|
|
2106
2159
|
this.updateChannelVolume(channel, scheduleTime);
|
|
2107
2160
|
}
|
|
2108
2161
|
}
|
|
2109
|
-
setExpression(channelNumber,
|
|
2162
|
+
setExpression(channelNumber, value, scheduleTime) {
|
|
2110
2163
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2111
2164
|
const channel = this.channels[channelNumber];
|
|
2112
|
-
|
|
2165
|
+
const state = channel.state;
|
|
2166
|
+
const intPart = Math.trunc(value);
|
|
2167
|
+
state.expressionMSB = intPart / 127;
|
|
2168
|
+
state.expressionLSB = value - intPart;
|
|
2113
2169
|
this.updateChannelVolume(channel, scheduleTime);
|
|
2114
2170
|
}
|
|
2115
2171
|
setBankLSB(channelNumber, lsb) {
|
|
@@ -2120,37 +2176,42 @@ class Midy {
|
|
|
2120
2176
|
this.handleRPN(channelNumber, 0, scheduleTime);
|
|
2121
2177
|
}
|
|
2122
2178
|
updateChannelVolume(channel, scheduleTime) {
|
|
2123
|
-
const
|
|
2124
|
-
const volume =
|
|
2125
|
-
const
|
|
2179
|
+
const { expressionMSB, expressionLSB, volumeMSB, volumeLSB, panMSB, panLSB, } = channel.state;
|
|
2180
|
+
const volume = volumeMSB + volumeLSB / 128;
|
|
2181
|
+
const expression = expressionMSB + expressionLSB / 128;
|
|
2182
|
+
const pan = panMSB + panLSB / 128;
|
|
2183
|
+
const gain = volume * expression;
|
|
2184
|
+
const { gainLeft, gainRight } = this.panToGain(pan);
|
|
2126
2185
|
channel.gainL.gain
|
|
2127
2186
|
.cancelScheduledValues(scheduleTime)
|
|
2128
|
-
.setValueAtTime(
|
|
2187
|
+
.setValueAtTime(gain * gainLeft, scheduleTime);
|
|
2129
2188
|
channel.gainR.gain
|
|
2130
2189
|
.cancelScheduledValues(scheduleTime)
|
|
2131
|
-
.setValueAtTime(
|
|
2190
|
+
.setValueAtTime(gain * gainRight, scheduleTime);
|
|
2132
2191
|
}
|
|
2133
2192
|
updateKeyBasedVolume(channel, keyNumber, scheduleTime) {
|
|
2134
2193
|
const gainL = channel.keyBasedGainLs[keyNumber];
|
|
2135
2194
|
if (!gainL)
|
|
2136
2195
|
return;
|
|
2137
2196
|
const gainR = channel.keyBasedGainRs[keyNumber];
|
|
2138
|
-
const
|
|
2139
|
-
const
|
|
2140
|
-
const
|
|
2197
|
+
const { expressionMSB, expressionLSB, volumeMSB, volumeLSB, panMSB, panLSB, } = channel.state;
|
|
2198
|
+
const volume = volumeMSB + volumeLSB / 128;
|
|
2199
|
+
const expression = expressionMSB + expressionLSB / 128;
|
|
2200
|
+
const defaultGain = volume * expression;
|
|
2201
|
+
const defaultPan = panMSB + panLSB / 128;
|
|
2141
2202
|
const keyBasedVolume = this.getKeyBasedValue(channel, keyNumber, 7);
|
|
2142
|
-
const
|
|
2143
|
-
?
|
|
2144
|
-
:
|
|
2203
|
+
const gain = (0 <= keyBasedVolume)
|
|
2204
|
+
? defaultGain * keyBasedVolume / 64
|
|
2205
|
+
: defaultGain;
|
|
2145
2206
|
const keyBasedPan = this.getKeyBasedValue(channel, keyNumber, 10);
|
|
2146
2207
|
const pan = (0 <= keyBasedPan) ? keyBasedPan / 127 : defaultPan;
|
|
2147
2208
|
const { gainLeft, gainRight } = this.panToGain(pan);
|
|
2148
2209
|
gainL.gain
|
|
2149
2210
|
.cancelScheduledValues(scheduleTime)
|
|
2150
|
-
.setValueAtTime(
|
|
2211
|
+
.setValueAtTime(gain * gainLeft, scheduleTime);
|
|
2151
2212
|
gainR.gain
|
|
2152
2213
|
.cancelScheduledValues(scheduleTime)
|
|
2153
|
-
.setValueAtTime(
|
|
2214
|
+
.setValueAtTime(gain * gainRight, scheduleTime);
|
|
2154
2215
|
}
|
|
2155
2216
|
setSustainPedal(channelNumber, value, scheduleTime) {
|
|
2156
2217
|
const channel = this.channels[channelNumber];
|
|
@@ -2223,8 +2284,8 @@ class Midy {
|
|
|
2223
2284
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2224
2285
|
const state = channel.state;
|
|
2225
2286
|
state.filterResonance = ccValue / 127;
|
|
2226
|
-
const filterResonance = this.getRelativeKeyBasedValue(channel, note, 71);
|
|
2227
2287
|
this.processScheduledNotes(channel, (note) => {
|
|
2288
|
+
const filterResonance = this.getRelativeKeyBasedValue(channel, note, 71);
|
|
2228
2289
|
const Q = note.voiceParams.initialFilterQ / 5 * filterResonance;
|
|
2229
2290
|
note.filterNode.Q.setValueAtTime(Q, scheduleTime);
|
|
2230
2291
|
});
|
|
@@ -2324,6 +2385,12 @@ class Midy {
|
|
|
2324
2385
|
});
|
|
2325
2386
|
}
|
|
2326
2387
|
}
|
|
2388
|
+
setPortamentoNoteNumber(channelNumber, value, scheduleTime) {
|
|
2389
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2390
|
+
const channel = this.channels[channelNumber];
|
|
2391
|
+
channel.portamentoControl = true;
|
|
2392
|
+
channel.state.portamentoNoteNumber = value / 127;
|
|
2393
|
+
}
|
|
2327
2394
|
setReverbSendLevel(channelNumber, reverbSendLevel, scheduleTime) {
|
|
2328
2395
|
scheduleTime ??= this.audioContext.currentTime;
|
|
2329
2396
|
const channel = this.channels[channelNumber];
|
|
@@ -2511,8 +2578,10 @@ class Midy {
|
|
|
2511
2578
|
"polyphonicKeyPressure",
|
|
2512
2579
|
"channelPressure",
|
|
2513
2580
|
"pitchWheel",
|
|
2514
|
-
"
|
|
2515
|
-
"
|
|
2581
|
+
"expressionMSB",
|
|
2582
|
+
"expressionLSB",
|
|
2583
|
+
"modulationDepthMSB",
|
|
2584
|
+
"modulationDepthLSB",
|
|
2516
2585
|
"sustainPedal",
|
|
2517
2586
|
"portamento",
|
|
2518
2587
|
"sostenutoPedal",
|
|
@@ -3222,5 +3291,6 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
3222
3291
|
modulationDepthRange: 50, // cent
|
|
3223
3292
|
fineTuning: 0, // cent
|
|
3224
3293
|
coarseTuning: 0, // cent
|
|
3294
|
+
portamentoControl: false,
|
|
3225
3295
|
}
|
|
3226
3296
|
});
|