@marmooo/midy 0.2.8 → 0.2.9
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 +8 -4
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +54 -17
- package/esm/midy-GM2.d.ts +13 -8
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +147 -40
- package/esm/midy-GMLite.d.ts +9 -3
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +57 -16
- package/esm/midy.d.ts +13 -8
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +187 -51
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +8 -4
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +54 -17
- package/script/midy-GM2.d.ts +13 -8
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +147 -40
- package/script/midy-GMLite.d.ts +9 -3
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +57 -16
- package/script/midy.d.ts +13 -8
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +187 -51
package/script/midy.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export class Midy {
|
|
2
2
|
static channelSettings: {
|
|
3
3
|
currentBufferSource: null;
|
|
4
|
+
isDrum: boolean;
|
|
4
5
|
detune: number;
|
|
5
6
|
program: number;
|
|
6
7
|
bank: number;
|
|
@@ -11,9 +12,9 @@ export class Midy {
|
|
|
11
12
|
rpnMSB: number;
|
|
12
13
|
rpnLSB: number;
|
|
13
14
|
mono: boolean;
|
|
15
|
+
modulationDepthRange: number;
|
|
14
16
|
fineTuning: number;
|
|
15
17
|
coarseTuning: number;
|
|
16
|
-
modulationDepthRange: number;
|
|
17
18
|
};
|
|
18
19
|
constructor(audioContext: any, options?: {
|
|
19
20
|
reverbAlgorithm: (audioContext: any) => {
|
|
@@ -21,6 +22,7 @@ export class Midy {
|
|
|
21
22
|
output: any;
|
|
22
23
|
};
|
|
23
24
|
});
|
|
25
|
+
mode: string;
|
|
24
26
|
ticksPerBeat: number;
|
|
25
27
|
totalTime: number;
|
|
26
28
|
masterFineTuning: number;
|
|
@@ -68,6 +70,8 @@ export class Midy {
|
|
|
68
70
|
};
|
|
69
71
|
};
|
|
70
72
|
masterVolume: any;
|
|
73
|
+
scheduler: any;
|
|
74
|
+
schedulerBuffer: any;
|
|
71
75
|
voiceParamsHandlers: {
|
|
72
76
|
modLfoToPitch: (channel: any, note: any, _prevValue: any, scheduleTime: any) => void;
|
|
73
77
|
vibLfoToPitch: (channel: any, note: any, _prevValue: any, scheduleTime: any) => void;
|
|
@@ -93,7 +97,7 @@ export class Midy {
|
|
|
93
97
|
64: (channelNumber: any, value: any, scheduleTime: any) => void;
|
|
94
98
|
65: (channelNumber: any, value: any) => void;
|
|
95
99
|
66: (channelNumber: any, value: any, scheduleTime: any) => void;
|
|
96
|
-
67: (channelNumber: any, softPedal: any,
|
|
100
|
+
67: (channelNumber: any, softPedal: any, scheduleTime: any) => void;
|
|
97
101
|
71: (channelNumber: any, filterResonance: any, scheduleTime: any) => void;
|
|
98
102
|
72: (channelNumber: any, releaseTime: any, _scheduleTime: any) => void;
|
|
99
103
|
73: (channelNumber: any, attackTime: any, scheduleTime: any) => void;
|
|
@@ -141,7 +145,8 @@ export class Midy {
|
|
|
141
145
|
};
|
|
142
146
|
createChannels(audioContext: any): any[];
|
|
143
147
|
createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
|
|
144
|
-
|
|
148
|
+
calcLoopMode(channel: any, note: any, voiceParams: any): boolean;
|
|
149
|
+
createBufferSource(channel: any, note: any, voiceParams: any, audioBuffer: any): any;
|
|
145
150
|
findPortamentoTarget(queueIndex: any): any;
|
|
146
151
|
scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
|
|
147
152
|
getQueueIndex(second: any): number;
|
|
@@ -206,7 +211,7 @@ export class Midy {
|
|
|
206
211
|
startVibrato(channel: any, note: any, scheduleTime: any): void;
|
|
207
212
|
getAudioBuffer(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
|
|
208
213
|
createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, portamento: any, isSF3: any): Promise<Note>;
|
|
209
|
-
calcBank(channel: any
|
|
214
|
+
calcBank(channel: any): any;
|
|
210
215
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
|
|
211
216
|
noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
|
|
212
217
|
stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
|
|
@@ -256,7 +261,7 @@ export class Midy {
|
|
|
256
261
|
64: (channelNumber: any, value: any, scheduleTime: any) => void;
|
|
257
262
|
65: (channelNumber: any, value: any) => void;
|
|
258
263
|
66: (channelNumber: any, value: any, scheduleTime: any) => void;
|
|
259
|
-
67: (channelNumber: any, softPedal: any,
|
|
264
|
+
67: (channelNumber: any, softPedal: any, scheduleTime: any) => void;
|
|
260
265
|
71: (channelNumber: any, filterResonance: any, scheduleTime: any) => void;
|
|
261
266
|
72: (channelNumber: any, releaseTime: any, _scheduleTime: any) => void;
|
|
262
267
|
73: (channelNumber: any, attackTime: any, scheduleTime: any) => void;
|
|
@@ -299,7 +304,7 @@ export class Midy {
|
|
|
299
304
|
setSustainPedal(channelNumber: any, value: any, scheduleTime: any): void;
|
|
300
305
|
setPortamento(channelNumber: any, value: any): void;
|
|
301
306
|
setSostenutoPedal(channelNumber: any, value: any, scheduleTime: any): void;
|
|
302
|
-
setSoftPedal(channelNumber: any, softPedal: any,
|
|
307
|
+
setSoftPedal(channelNumber: any, softPedal: any, scheduleTime: any): void;
|
|
303
308
|
setFilterResonance(channelNumber: any, filterResonance: any, scheduleTime: any): void;
|
|
304
309
|
setReleaseTime(channelNumber: any, releaseTime: any, _scheduleTime: any): void;
|
|
305
310
|
setAttackTime(channelNumber: any, attackTime: any, scheduleTime: any): void;
|
|
@@ -334,8 +339,8 @@ export class Midy {
|
|
|
334
339
|
monoOn(channelNumber: any, value: any, scheduleTime: any): void;
|
|
335
340
|
polyOn(channelNumber: any, value: any, scheduleTime: any): void;
|
|
336
341
|
handleUniversalNonRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
|
|
337
|
-
GM1SystemOn(): void;
|
|
338
|
-
GM2SystemOn(): void;
|
|
342
|
+
GM1SystemOn(scheduleTime: any): void;
|
|
343
|
+
GM2SystemOn(scheduleTime: any): void;
|
|
339
344
|
handleUniversalRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
|
|
340
345
|
handleMasterVolumeSysEx(data: any, scheduleTime: any): void;
|
|
341
346
|
setMasterVolume(volume: any, scheduleTime: 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":"AAgLA;
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAgLA;IAoCE;;;;;;;;;;;;;;;;MAgBE;IAgCF;;;;;OAmBC;IAtGD,aAAa;IACb,qBAAmB;IACnB,kBAAc;IACd,yBAAqB;IACrB,2BAAuB;IACvB;;;MAGE;IACF;;;;;;MAME;IACF,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,6BAAuC;IAoBvC;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IACjD;;;MAA8D;IAC9D;;;;;;;;MAAyD;IAQ3D,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAiBC;IAED,6DA2BC;IAED,iEAWC;IAED,qFASC;IAED,2CAcC;IAED,2EAqEC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MAgHC;IAED,mGAiBC;IAED,wEAMC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDAQC;IAED,2DASC;IAED,qDAQC;IAED,kFAuBC;IAED;;;;MAWC;IAED,gFAUC;IAED,mFAYC;IAED,sGAcC;IAID;;;MA8BC;IAED;;;;;;;;MA0CC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAYC;IAED,6CAEC;IAED,2DAIC;IAED,+DAOC;IAED,wCAGC;IAED,mFAUC;IAED,oEAiBC;IAED,qDAoBC;IAED,6CAIC;IAED,mFAsBC;IAED,oEA2BC;IAED,kEAoBC;IAED,+DAaC;IAED,yGAgBC;IAED,iIA0EC;IAED,4BAYC;IAED,mHA0DC;IAED,6FASC;IAED,qFAqCC;IAED,oJAwCC;IAED,yGAUC;IAED,4GAeC;IAED,uFAgBC;IAED,mGAoCC;IAED,yGAeC;IAED,gFAcC;IAED,+EAeC;IAED,wFAGC;IAED,sEAWC;IAED,mEAQC;IAED,mEAQC;IAED,sEAMC;IAED,oEAQC;IAED,uFA0BC;IAED,uFA0BC;IAED,mDAMC;IAED,kDAKC;IAED,gEAKC;IAED;;;;;;;;;;;MAiDC;IAED,oFAMC;IAED,6EAmDC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAqCC;IAED,kGAYC;IAED,+CAEC;IAED,wDAUC;IAED,iFAMC;IAED,iEAGC;IAED,yDAaC;IAED,oEAMC;IAED;;;MAMC;IAED,sDAiBC;IAED,8DAMC;IAED,4EAKC;IAED,+CAEC;IAED,sEAGC;IAED,2DAUC;IAED,yEAYC;IAED,oDAIC;IAED,2EAUC;IAED,0EAcC;IAED,sFAUC;IAED,+EAKC;IAED,4EASC;IAED,4EAYC;IAED,0EAQC;IAED,8EASC;IAED,gFAeC;IAED,6DAUC;IAED,sFA4BC;IAED,sFA4BC;IAED,kFAeC;IAED,2DAMC;IAED,mEAyBC;IAGD,wCAEC;IAGD,wCAEC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAWC;IAED,iEAKC;IAED,uEASC;IAED,mEAKC;IAED,yEASC;IAED,2EASC;IAED,gGAMC;IAED,gFAGC;IAED,8CAyBC;IAED,gFAGC;IAED,iEAEC;IAED,gEAEC;IAED,gEAIC;IAED,gEAIC;IAED,+EAuCC;IAED,qCAcC;IAED,qCAcC;IAED,4EA6DC;IAED,4DAGC;IAED,sDASC;IAED,gEAGC;IAED,yDAWC;IAED,kEAGC;IAED,2DAWC;IAED,sEAeC;IAED,4CAOC;IAED,+BAKC;IAED,qDAiBC;IAED,gCAIC;IAED,kCAEC;IA6BD,4CAEC;IAED,+DAaC;IAED,kDAiBC;IAED,2GAKC;IAED,sDAIC;IAED,qCAEC;IAED,uDAMC;IAED,sCAEC;IAED,uDASC;IAED,sCAEC;IAED,2DAqBC;IAED,0CAEC;IAED,mCAeC;IAED,2FAgBC;IAED,2FAoBC;IAED,iDAIC;IAED,wDAMC;IAED,qDAMC;IAED,kDAMC;IAED,mDAMC;IAED,sDAMC;IAED,mEASC;IAED,qDAUC;IAED,4CAUC;IAED,2DAOC;IAED,0CAWC;IAED,6FAIC;IAED,yEAiBC;IAED,gDAYC;IAED,6DAgBC;CACF;AAv5FD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IAkBE,0FAMC;IAvBD,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,gBAAW;IACX,WAAM;IACN,WAAM;IACN,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IACb,uBAAkB;IAClB,uBAAkB;IAClB,gBAAW;IACX,iBAAa;IAGX,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
|
package/script/midy.js
CHANGED
|
@@ -249,6 +249,12 @@ const volumeEnvelopeKeys = [
|
|
|
249
249
|
const volumeEnvelopeKeySet = new Set(volumeEnvelopeKeys);
|
|
250
250
|
class Midy {
|
|
251
251
|
constructor(audioContext, options = this.defaultOptions) {
|
|
252
|
+
Object.defineProperty(this, "mode", {
|
|
253
|
+
enumerable: true,
|
|
254
|
+
configurable: true,
|
|
255
|
+
writable: true,
|
|
256
|
+
value: "GM2"
|
|
257
|
+
});
|
|
252
258
|
Object.defineProperty(this, "ticksPerBeat", {
|
|
253
259
|
enumerable: true,
|
|
254
260
|
configurable: true,
|
|
@@ -427,6 +433,11 @@ class Midy {
|
|
|
427
433
|
this.audioContext = audioContext;
|
|
428
434
|
this.options = { ...this.defaultOptions, ...options };
|
|
429
435
|
this.masterVolume = new GainNode(audioContext);
|
|
436
|
+
this.scheduler = new GainNode(audioContext, { gain: 0 });
|
|
437
|
+
this.schedulerBuffer = new AudioBuffer({
|
|
438
|
+
length: 1,
|
|
439
|
+
sampleRate: audioContext.sampleRate,
|
|
440
|
+
});
|
|
430
441
|
this.voiceParamsHandlers = this.createVoiceParamsHandlers();
|
|
431
442
|
this.controlChangeHandlers = this.createControlChangeHandlers();
|
|
432
443
|
this.channels = this.createChannels(audioContext);
|
|
@@ -435,6 +446,7 @@ class Midy {
|
|
|
435
446
|
this.chorusEffect.output.connect(this.masterVolume);
|
|
436
447
|
this.reverbEffect.output.connect(this.masterVolume);
|
|
437
448
|
this.masterVolume.connect(audioContext.destination);
|
|
449
|
+
this.scheduler.connect(audioContext.destination);
|
|
438
450
|
this.GM2SystemOn();
|
|
439
451
|
}
|
|
440
452
|
initSoundFontTable() {
|
|
@@ -534,10 +546,24 @@ class Midy {
|
|
|
534
546
|
return audioBuffer;
|
|
535
547
|
}
|
|
536
548
|
}
|
|
537
|
-
|
|
549
|
+
calcLoopMode(channel, note, voiceParams) {
|
|
550
|
+
if (channel.isDrum) {
|
|
551
|
+
const noteNumber = note.noteNumber;
|
|
552
|
+
if (noteNumber === 88 || 47 <= noteNumber && noteNumber <= 84) {
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
return voiceParams.sampleModes % 2 !== 0;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
createBufferSource(channel, note, voiceParams, audioBuffer) {
|
|
538
564
|
const bufferSource = new AudioBufferSourceNode(this.audioContext);
|
|
539
565
|
bufferSource.buffer = audioBuffer;
|
|
540
|
-
bufferSource.loop =
|
|
566
|
+
bufferSource.loop = this.calcLoopMode(channel, note, voiceParams);
|
|
541
567
|
if (bufferSource.loop) {
|
|
542
568
|
bufferSource.loopStart = voiceParams.loopStart / voiceParams.sampleRate;
|
|
543
569
|
bufferSource.loopEnd = voiceParams.loopEnd / voiceParams.sampleRate;
|
|
@@ -1017,7 +1043,9 @@ class Midy {
|
|
|
1017
1043
|
return 8.176 * this.centToRate(cent);
|
|
1018
1044
|
}
|
|
1019
1045
|
calcChannelDetune(channel) {
|
|
1020
|
-
const masterTuning =
|
|
1046
|
+
const masterTuning = channel.isDrum
|
|
1047
|
+
? 0
|
|
1048
|
+
: this.masterCoarseTuning + this.masterFineTuning;
|
|
1021
1049
|
const channelTuning = channel.coarseTuning + channel.fineTuning;
|
|
1022
1050
|
const tuning = masterTuning + channelTuning;
|
|
1023
1051
|
const pitchWheel = channel.state.pitchWheel * 2 - 1;
|
|
@@ -1044,9 +1072,8 @@ class Midy {
|
|
|
1044
1072
|
.setValueAtTime(detune, scheduleTime);
|
|
1045
1073
|
}
|
|
1046
1074
|
getPortamentoTime(channel) {
|
|
1047
|
-
const factor = 5 * Math.log(10)
|
|
1048
|
-
|
|
1049
|
-
return Math.log(time) / factor;
|
|
1075
|
+
const factor = 5 * Math.log(10) * 127;
|
|
1076
|
+
return channel.state.portamentoTime * factor;
|
|
1050
1077
|
}
|
|
1051
1078
|
setPortamentoStartVolumeEnvelope(channel, note, scheduleTime) {
|
|
1052
1079
|
const { voiceParams, startTime } = note;
|
|
@@ -1210,7 +1237,7 @@ class Midy {
|
|
|
1210
1237
|
const voiceParams = voice.getAllParams(controllerState);
|
|
1211
1238
|
const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
|
|
1212
1239
|
const audioBuffer = await this.getAudioBuffer(channel.program, noteNumber, velocity, voiceParams, isSF3);
|
|
1213
|
-
note.bufferSource = this.
|
|
1240
|
+
note.bufferSource = this.createBufferSource(channel, note, voiceParams, audioBuffer);
|
|
1214
1241
|
note.volumeNode = new GainNode(this.audioContext);
|
|
1215
1242
|
note.gainL = new GainNode(this.audioContext);
|
|
1216
1243
|
note.gainR = new GainNode(this.audioContext);
|
|
@@ -1254,14 +1281,21 @@ class Midy {
|
|
|
1254
1281
|
note.bufferSource.start(startTime);
|
|
1255
1282
|
return note;
|
|
1256
1283
|
}
|
|
1257
|
-
calcBank(channel
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1284
|
+
calcBank(channel) {
|
|
1285
|
+
switch (this.mode) {
|
|
1286
|
+
case "GM1":
|
|
1287
|
+
if (channel.isDrum)
|
|
1288
|
+
return 128;
|
|
1289
|
+
return 0;
|
|
1290
|
+
case "GM2":
|
|
1291
|
+
if (channel.bankMSB === 121)
|
|
1292
|
+
return 0;
|
|
1293
|
+
if (channel.isDrum)
|
|
1294
|
+
return 128;
|
|
1295
|
+
return channel.bank;
|
|
1296
|
+
default:
|
|
1297
|
+
return channel.bank;
|
|
1263
1298
|
}
|
|
1264
|
-
return channel.bank;
|
|
1265
1299
|
}
|
|
1266
1300
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, portamento) {
|
|
1267
1301
|
const channel = this.channels[channelNumber];
|
|
@@ -1285,7 +1319,7 @@ class Midy {
|
|
|
1285
1319
|
if (this.exclusiveClassMap.has(exclusiveClass)) {
|
|
1286
1320
|
const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
|
|
1287
1321
|
const [prevNote, prevChannelNumber] = prevEntry;
|
|
1288
|
-
if (!prevNote.ending) {
|
|
1322
|
+
if (prevNote && !prevNote.ending) {
|
|
1289
1323
|
this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
1290
1324
|
startTime, true, // force
|
|
1291
1325
|
undefined);
|
|
@@ -1448,9 +1482,21 @@ class Midy {
|
|
|
1448
1482
|
const channel = this.channels[channelNumber];
|
|
1449
1483
|
channel.bank = channel.bankMSB * 128 + channel.bankLSB;
|
|
1450
1484
|
channel.program = program;
|
|
1485
|
+
if (this.mode === "GM2") {
|
|
1486
|
+
switch (channel.bankMSB) {
|
|
1487
|
+
case 120:
|
|
1488
|
+
channel.isDrum = true;
|
|
1489
|
+
break;
|
|
1490
|
+
case 121:
|
|
1491
|
+
channel.isDrum = false;
|
|
1492
|
+
break;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1451
1495
|
}
|
|
1452
1496
|
handleChannelPressure(channelNumber, value, scheduleTime) {
|
|
1453
1497
|
const channel = this.channels[channelNumber];
|
|
1498
|
+
if (channel.isDrum)
|
|
1499
|
+
return;
|
|
1454
1500
|
const prev = channel.state.channelPressure;
|
|
1455
1501
|
const next = value / 127;
|
|
1456
1502
|
channel.state.channelPressure = next;
|
|
@@ -1469,8 +1515,10 @@ class Midy {
|
|
|
1469
1515
|
this.setPitchBend(channelNumber, pitchBend, scheduleTime);
|
|
1470
1516
|
}
|
|
1471
1517
|
setPitchBend(channelNumber, value, scheduleTime) {
|
|
1472
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1473
1518
|
const channel = this.channels[channelNumber];
|
|
1519
|
+
if (channel.isDrum)
|
|
1520
|
+
return;
|
|
1521
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1474
1522
|
const state = channel.state;
|
|
1475
1523
|
const prev = state.pitchWheel * 2 - 1;
|
|
1476
1524
|
const next = (value - 8192) / 8192;
|
|
@@ -1752,15 +1800,16 @@ class Midy {
|
|
|
1752
1800
|
});
|
|
1753
1801
|
}
|
|
1754
1802
|
setModulationDepth(channelNumber, modulation, scheduleTime) {
|
|
1755
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1756
1803
|
const channel = this.channels[channelNumber];
|
|
1804
|
+
if (channel.isDrum)
|
|
1805
|
+
return;
|
|
1806
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1757
1807
|
channel.state.modulationDepth = modulation / 127;
|
|
1758
1808
|
this.updateModulation(channel, scheduleTime);
|
|
1759
1809
|
}
|
|
1760
1810
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
1761
1811
|
const channel = this.channels[channelNumber];
|
|
1762
|
-
|
|
1763
|
-
channel.state.portamentoTime = Math.exp(factor * portamentoTime);
|
|
1812
|
+
channel.state.portamentoTime = portamentoTime / 127;
|
|
1764
1813
|
}
|
|
1765
1814
|
setKeyBasedVolume(channel, scheduleTime) {
|
|
1766
1815
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -1832,8 +1881,10 @@ class Midy {
|
|
|
1832
1881
|
.setValueAtTime(volume * gainRight, scheduleTime);
|
|
1833
1882
|
}
|
|
1834
1883
|
setSustainPedal(channelNumber, value, scheduleTime) {
|
|
1835
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1836
1884
|
const channel = this.channels[channelNumber];
|
|
1885
|
+
if (channel.isDrum)
|
|
1886
|
+
return;
|
|
1887
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1837
1888
|
channel.state.sustainPedal = value / 127;
|
|
1838
1889
|
if (64 <= value) {
|
|
1839
1890
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -1845,11 +1896,16 @@ class Midy {
|
|
|
1845
1896
|
}
|
|
1846
1897
|
}
|
|
1847
1898
|
setPortamento(channelNumber, value) {
|
|
1848
|
-
this.channels[channelNumber]
|
|
1899
|
+
const channel = this.channels[channelNumber];
|
|
1900
|
+
if (channel.isDrum)
|
|
1901
|
+
return;
|
|
1902
|
+
channel.state.portamento = value / 127;
|
|
1849
1903
|
}
|
|
1850
1904
|
setSostenutoPedal(channelNumber, value, scheduleTime) {
|
|
1851
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1852
1905
|
const channel = this.channels[channelNumber];
|
|
1906
|
+
if (channel.isDrum)
|
|
1907
|
+
return;
|
|
1908
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1853
1909
|
channel.state.sostenutoPedal = value / 127;
|
|
1854
1910
|
if (64 <= value) {
|
|
1855
1911
|
channel.sostenutoNotes = this.getActiveNotes(channel, scheduleTime);
|
|
@@ -1858,13 +1914,28 @@ class Midy {
|
|
|
1858
1914
|
this.releaseSostenutoPedal(channelNumber, value, scheduleTime);
|
|
1859
1915
|
}
|
|
1860
1916
|
}
|
|
1861
|
-
setSoftPedal(channelNumber, softPedal,
|
|
1917
|
+
setSoftPedal(channelNumber, softPedal, scheduleTime) {
|
|
1862
1918
|
const channel = this.channels[channelNumber];
|
|
1919
|
+
if (channel.isDrum)
|
|
1920
|
+
return;
|
|
1921
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1863
1922
|
channel.state.softPedal = softPedal / 127;
|
|
1923
|
+
this.processScheduledNotes(channel, (note) => {
|
|
1924
|
+
if (note.portamento) {
|
|
1925
|
+
this.setPortamentoStartVolumeEnvelope(channel, note, scheduleTime);
|
|
1926
|
+
this.setPortamentoStartFilterEnvelope(channel, note, scheduleTime);
|
|
1927
|
+
}
|
|
1928
|
+
else {
|
|
1929
|
+
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
1930
|
+
this.setFilterEnvelope(channel, note, scheduleTime);
|
|
1931
|
+
}
|
|
1932
|
+
});
|
|
1864
1933
|
}
|
|
1865
1934
|
setFilterResonance(channelNumber, filterResonance, scheduleTime) {
|
|
1866
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1867
1935
|
const channel = this.channels[channelNumber];
|
|
1936
|
+
if (channel.isDrum)
|
|
1937
|
+
return;
|
|
1938
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1868
1939
|
const state = channel.state;
|
|
1869
1940
|
state.filterResonance = filterResonance / 64;
|
|
1870
1941
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -1873,13 +1944,17 @@ class Midy {
|
|
|
1873
1944
|
});
|
|
1874
1945
|
}
|
|
1875
1946
|
setReleaseTime(channelNumber, releaseTime, _scheduleTime) {
|
|
1876
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1877
1947
|
const channel = this.channels[channelNumber];
|
|
1948
|
+
if (channel.isDrum)
|
|
1949
|
+
return;
|
|
1950
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1878
1951
|
channel.state.releaseTime = releaseTime / 64;
|
|
1879
1952
|
}
|
|
1880
1953
|
setAttackTime(channelNumber, attackTime, scheduleTime) {
|
|
1881
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1882
1954
|
const channel = this.channels[channelNumber];
|
|
1955
|
+
if (channel.isDrum)
|
|
1956
|
+
return;
|
|
1957
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1883
1958
|
channel.state.attackTime = attackTime / 64;
|
|
1884
1959
|
this.processScheduledNotes(channel, (note) => {
|
|
1885
1960
|
if (note.startTime < scheduleTime)
|
|
@@ -1888,8 +1963,10 @@ class Midy {
|
|
|
1888
1963
|
});
|
|
1889
1964
|
}
|
|
1890
1965
|
setBrightness(channelNumber, brightness, scheduleTime) {
|
|
1891
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1892
1966
|
const channel = this.channels[channelNumber];
|
|
1967
|
+
if (channel.isDrum)
|
|
1968
|
+
return;
|
|
1969
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1893
1970
|
channel.state.brightness = brightness / 64;
|
|
1894
1971
|
this.processScheduledNotes(channel, (note) => {
|
|
1895
1972
|
if (note.portamento) {
|
|
@@ -1901,16 +1978,20 @@ class Midy {
|
|
|
1901
1978
|
});
|
|
1902
1979
|
}
|
|
1903
1980
|
setDecayTime(channelNumber, dacayTime, scheduleTime) {
|
|
1904
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1905
1981
|
const channel = this.channels[channelNumber];
|
|
1982
|
+
if (channel.isDrum)
|
|
1983
|
+
return;
|
|
1984
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1906
1985
|
channel.state.decayTime = dacayTime / 64;
|
|
1907
1986
|
this.processScheduledNotes(channel, (note) => {
|
|
1908
1987
|
this.setVolumeEnvelope(channel, note, scheduleTime);
|
|
1909
1988
|
});
|
|
1910
1989
|
}
|
|
1911
1990
|
setVibratoRate(channelNumber, vibratoRate, scheduleTime) {
|
|
1912
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1913
1991
|
const channel = this.channels[channelNumber];
|
|
1992
|
+
if (channel.isDrum)
|
|
1993
|
+
return;
|
|
1994
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1914
1995
|
channel.state.vibratoRate = vibratoRate / 64;
|
|
1915
1996
|
if (channel.vibratoDepth <= 0)
|
|
1916
1997
|
return;
|
|
@@ -1919,8 +2000,10 @@ class Midy {
|
|
|
1919
2000
|
});
|
|
1920
2001
|
}
|
|
1921
2002
|
setVibratoDepth(channelNumber, vibratoDepth, scheduleTime) {
|
|
1922
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1923
2003
|
const channel = this.channels[channelNumber];
|
|
2004
|
+
if (channel.isDrum)
|
|
2005
|
+
return;
|
|
2006
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1924
2007
|
const prev = channel.state.vibratoDepth;
|
|
1925
2008
|
channel.state.vibratoDepth = vibratoDepth / 64;
|
|
1926
2009
|
if (0 < prev) {
|
|
@@ -1935,8 +2018,10 @@ class Midy {
|
|
|
1935
2018
|
}
|
|
1936
2019
|
}
|
|
1937
2020
|
setVibratoDelay(channelNumber, vibratoDelay) {
|
|
1938
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1939
2021
|
const channel = this.channels[channelNumber];
|
|
2022
|
+
if (channel.isDrum)
|
|
2023
|
+
return;
|
|
2024
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
1940
2025
|
channel.state.vibratoDelay = vibratoDelay / 64;
|
|
1941
2026
|
if (0 < channel.state.vibratoDepth) {
|
|
1942
2027
|
this.processScheduledNotes(channel, (note) => {
|
|
@@ -2083,8 +2168,10 @@ class Midy {
|
|
|
2083
2168
|
this.setPitchBendRange(channelNumber, pitchBendRange, scheduleTime);
|
|
2084
2169
|
}
|
|
2085
2170
|
setPitchBendRange(channelNumber, value, scheduleTime) {
|
|
2086
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
2087
2171
|
const channel = this.channels[channelNumber];
|
|
2172
|
+
if (channel.isDrum)
|
|
2173
|
+
return;
|
|
2174
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2088
2175
|
const state = channel.state;
|
|
2089
2176
|
const prev = state.pitchWheelSensitivity;
|
|
2090
2177
|
const next = value / 128;
|
|
@@ -2100,8 +2187,10 @@ class Midy {
|
|
|
2100
2187
|
this.setFineTuning(channelNumber, fineTuning, scheduleTime);
|
|
2101
2188
|
}
|
|
2102
2189
|
setFineTuning(channelNumber, value, scheduleTime) {
|
|
2103
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
2104
2190
|
const channel = this.channels[channelNumber];
|
|
2191
|
+
if (channel.isDrum)
|
|
2192
|
+
return;
|
|
2193
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2105
2194
|
const prev = channel.fineTuning;
|
|
2106
2195
|
const next = (value - 8192) / 8.192; // cent
|
|
2107
2196
|
channel.fineTuning = next;
|
|
@@ -2115,8 +2204,10 @@ class Midy {
|
|
|
2115
2204
|
this.setCoarseTuning(channelNumber, coarseTuning, scheduleTime);
|
|
2116
2205
|
}
|
|
2117
2206
|
setCoarseTuning(channelNumber, value, scheduleTime) {
|
|
2118
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
2119
2207
|
const channel = this.channels[channelNumber];
|
|
2208
|
+
if (channel.isDrum)
|
|
2209
|
+
return;
|
|
2210
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2120
2211
|
const prev = channel.coarseTuning;
|
|
2121
2212
|
const next = (value - 64) * 100; // cent
|
|
2122
2213
|
channel.coarseTuning = next;
|
|
@@ -2130,8 +2221,10 @@ class Midy {
|
|
|
2130
2221
|
this.setModulationDepthRange(channelNumber, modulationDepthRange, scheduleTime);
|
|
2131
2222
|
}
|
|
2132
2223
|
setModulationDepthRange(channelNumber, modulationDepthRange, scheduleTime) {
|
|
2133
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
2134
2224
|
const channel = this.channels[channelNumber];
|
|
2225
|
+
if (channel.isDrum)
|
|
2226
|
+
return;
|
|
2227
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2135
2228
|
channel.modulationDepthRange = modulationDepthRange;
|
|
2136
2229
|
this.updateModulation(channel, scheduleTime);
|
|
2137
2230
|
}
|
|
@@ -2202,12 +2295,12 @@ class Midy {
|
|
|
2202
2295
|
case 9:
|
|
2203
2296
|
switch (data[3]) {
|
|
2204
2297
|
case 1:
|
|
2205
|
-
this.GM1SystemOn();
|
|
2298
|
+
this.GM1SystemOn(scheduleTime);
|
|
2206
2299
|
break;
|
|
2207
2300
|
case 2: // GM System Off
|
|
2208
2301
|
break;
|
|
2209
2302
|
case 3:
|
|
2210
|
-
this.GM2SystemOn();
|
|
2303
|
+
this.GM2SystemOn(scheduleTime);
|
|
2211
2304
|
break;
|
|
2212
2305
|
default:
|
|
2213
2306
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
@@ -2217,25 +2310,35 @@ class Midy {
|
|
|
2217
2310
|
console.warn(`Unsupported Exclusive Message: ${data}`);
|
|
2218
2311
|
}
|
|
2219
2312
|
}
|
|
2220
|
-
GM1SystemOn() {
|
|
2313
|
+
GM1SystemOn(scheduleTime) {
|
|
2314
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2315
|
+
this.mode = "GM1";
|
|
2221
2316
|
for (let i = 0; i < this.channels.length; i++) {
|
|
2317
|
+
this.allSoundOff(i, 0, scheduleTime);
|
|
2222
2318
|
const channel = this.channels[i];
|
|
2223
2319
|
channel.bankMSB = 0;
|
|
2224
2320
|
channel.bankLSB = 0;
|
|
2225
2321
|
channel.bank = 0;
|
|
2322
|
+
channel.isDrum = false;
|
|
2226
2323
|
}
|
|
2227
2324
|
this.channels[9].bankMSB = 1;
|
|
2228
2325
|
this.channels[9].bank = 128;
|
|
2326
|
+
this.channels[9].isDrum = true;
|
|
2229
2327
|
}
|
|
2230
|
-
GM2SystemOn() {
|
|
2328
|
+
GM2SystemOn(scheduleTime) {
|
|
2329
|
+
scheduleTime ??= this.audioContext.currentTime;
|
|
2330
|
+
this.mode = "GM2";
|
|
2231
2331
|
for (let i = 0; i < this.channels.length; i++) {
|
|
2332
|
+
this.allSoundOff(i, 0, scheduleTime);
|
|
2232
2333
|
const channel = this.channels[i];
|
|
2233
2334
|
channel.bankMSB = 121;
|
|
2234
2335
|
channel.bankLSB = 0;
|
|
2235
2336
|
channel.bank = 121 * 128;
|
|
2337
|
+
channel.isDrum = false;
|
|
2236
2338
|
}
|
|
2237
2339
|
this.channels[9].bankMSB = 120;
|
|
2238
2340
|
this.channels[9].bank = 120 * 128;
|
|
2341
|
+
this.channels[9].isDrum = true;
|
|
2239
2342
|
}
|
|
2240
2343
|
handleUniversalRealTimeExclusiveMessage(data, scheduleTime) {
|
|
2241
2344
|
switch (data[2]) {
|
|
@@ -2311,8 +2414,14 @@ class Midy {
|
|
|
2311
2414
|
const prev = this.masterFineTuning;
|
|
2312
2415
|
const next = (value - 8192) / 8.192; // cent
|
|
2313
2416
|
this.masterFineTuning = next;
|
|
2314
|
-
|
|
2315
|
-
this.
|
|
2417
|
+
const detuneChange = next - prev;
|
|
2418
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
2419
|
+
const channel = this.channels[i];
|
|
2420
|
+
if (channel.isDrum)
|
|
2421
|
+
continue;
|
|
2422
|
+
channel.detune += detuneChange;
|
|
2423
|
+
this.updateChannelDetune(channel, scheduleTime);
|
|
2424
|
+
}
|
|
2316
2425
|
}
|
|
2317
2426
|
handleMasterCoarseTuningSysEx(data, scheduleTime) {
|
|
2318
2427
|
const coarseTuning = data[4];
|
|
@@ -2322,8 +2431,14 @@ class Midy {
|
|
|
2322
2431
|
const prev = this.masterCoarseTuning;
|
|
2323
2432
|
const next = (value - 64) * 100; // cent
|
|
2324
2433
|
this.masterCoarseTuning = next;
|
|
2325
|
-
|
|
2326
|
-
this.
|
|
2434
|
+
const detuneChange = next - prev;
|
|
2435
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
2436
|
+
const channel = this.channels[i];
|
|
2437
|
+
if (channel.isDrum)
|
|
2438
|
+
continue;
|
|
2439
|
+
channel.detune += detuneChange;
|
|
2440
|
+
this.updateChannelDetune(channel, scheduleTime);
|
|
2441
|
+
}
|
|
2327
2442
|
}
|
|
2328
2443
|
handleGlobalParameterControlSysEx(data, scheduleTime) {
|
|
2329
2444
|
if (data[7] === 1) {
|
|
@@ -2535,6 +2650,8 @@ class Midy {
|
|
|
2535
2650
|
if (!channelBitmap[i])
|
|
2536
2651
|
continue;
|
|
2537
2652
|
const channel = this.channels[i];
|
|
2653
|
+
if (channel.isDrum)
|
|
2654
|
+
continue;
|
|
2538
2655
|
for (let j = 0; j < 12; j++) {
|
|
2539
2656
|
const centValue = data[j + 7] - 64;
|
|
2540
2657
|
channel.scaleOctaveTuningTable[j] = centValue;
|
|
@@ -2553,6 +2670,8 @@ class Midy {
|
|
|
2553
2670
|
if (!channelBitmap[i])
|
|
2554
2671
|
continue;
|
|
2555
2672
|
const channel = this.channels[i];
|
|
2673
|
+
if (channel.isDrum)
|
|
2674
|
+
continue;
|
|
2556
2675
|
for (let j = 0; j < 12; j++) {
|
|
2557
2676
|
const index = 7 + j * 2;
|
|
2558
2677
|
const msb = data[index] & 0x7F;
|
|
@@ -2623,7 +2742,10 @@ class Midy {
|
|
|
2623
2742
|
}
|
|
2624
2743
|
handlePressureSysEx(data, tableName) {
|
|
2625
2744
|
const channelNumber = data[4];
|
|
2626
|
-
const
|
|
2745
|
+
const channel = this.channels[channelNumber];
|
|
2746
|
+
if (channel.isDrum)
|
|
2747
|
+
return;
|
|
2748
|
+
const table = channel[tableName];
|
|
2627
2749
|
for (let i = 5; i < data.length - 1; i += 2) {
|
|
2628
2750
|
const pp = data[i];
|
|
2629
2751
|
const rr = data[i + 1];
|
|
@@ -2651,8 +2773,11 @@ class Midy {
|
|
|
2651
2773
|
}
|
|
2652
2774
|
handleControlChangeSysEx(data) {
|
|
2653
2775
|
const channelNumber = data[4];
|
|
2776
|
+
const channel = this.channels[channelNumber];
|
|
2777
|
+
if (channel.isDrum)
|
|
2778
|
+
return;
|
|
2654
2779
|
const controllerType = data[5];
|
|
2655
|
-
const table =
|
|
2780
|
+
const table = channel.controlTable[controllerType];
|
|
2656
2781
|
for (let i = 6; i < data.length - 1; i += 2) {
|
|
2657
2782
|
const pp = data[i];
|
|
2658
2783
|
const rr = data[i + 1];
|
|
@@ -2666,8 +2791,11 @@ class Midy {
|
|
|
2666
2791
|
}
|
|
2667
2792
|
handleKeyBasedInstrumentControlSysEx(data, scheduleTime) {
|
|
2668
2793
|
const channelNumber = data[4];
|
|
2794
|
+
const channel = this.channels[channelNumber];
|
|
2795
|
+
if (channel.isDrum)
|
|
2796
|
+
return;
|
|
2669
2797
|
const keyNumber = data[5];
|
|
2670
|
-
const table =
|
|
2798
|
+
const table = channel.keyBasedInstrumentControlTable;
|
|
2671
2799
|
for (let i = 6; i < data.length - 1; i += 2) {
|
|
2672
2800
|
const controllerType = data[i];
|
|
2673
2801
|
const value = data[i + 1];
|
|
@@ -2688,13 +2816,20 @@ class Midy {
|
|
|
2688
2816
|
}
|
|
2689
2817
|
scheduleTask(callback, scheduleTime) {
|
|
2690
2818
|
return new Promise((resolve) => {
|
|
2691
|
-
const bufferSource = new AudioBufferSourceNode(this.audioContext
|
|
2819
|
+
const bufferSource = new AudioBufferSourceNode(this.audioContext, {
|
|
2820
|
+
buffer: this.schedulerBuffer,
|
|
2821
|
+
});
|
|
2822
|
+
bufferSource.connect(this.scheduler);
|
|
2692
2823
|
bufferSource.onended = () => {
|
|
2693
|
-
|
|
2694
|
-
|
|
2824
|
+
try {
|
|
2825
|
+
callback();
|
|
2826
|
+
}
|
|
2827
|
+
finally {
|
|
2828
|
+
bufferSource.disconnect();
|
|
2829
|
+
resolve();
|
|
2830
|
+
}
|
|
2695
2831
|
};
|
|
2696
2832
|
bufferSource.start(scheduleTime);
|
|
2697
|
-
bufferSource.stop(scheduleTime);
|
|
2698
2833
|
});
|
|
2699
2834
|
}
|
|
2700
2835
|
}
|
|
@@ -2705,6 +2840,7 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
2705
2840
|
writable: true,
|
|
2706
2841
|
value: {
|
|
2707
2842
|
currentBufferSource: null,
|
|
2843
|
+
isDrum: false,
|
|
2708
2844
|
detune: 0,
|
|
2709
2845
|
program: 0,
|
|
2710
2846
|
bank: 121 * 128,
|
|
@@ -2715,8 +2851,8 @@ Object.defineProperty(Midy, "channelSettings", {
|
|
|
2715
2851
|
rpnMSB: 127,
|
|
2716
2852
|
rpnLSB: 127,
|
|
2717
2853
|
mono: false, // CC#124, CC#125
|
|
2854
|
+
modulationDepthRange: 50, // cent
|
|
2718
2855
|
fineTuning: 0, // cb
|
|
2719
2856
|
coarseTuning: 0, // cb
|
|
2720
|
-
modulationDepthRange: 50, // cent
|
|
2721
2857
|
}
|
|
2722
2858
|
});
|