@marmooo/midy 0.0.6 → 0.0.7
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 +9 -1
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +79 -31
- package/esm/midy-GM2.d.ts +15 -7
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +97 -47
- package/esm/midy-GMLite.d.ts +3 -1
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +32 -30
- package/esm/midy.d.ts +9 -1
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +85 -64
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +9 -1
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +79 -31
- package/script/midy-GM2.d.ts +15 -7
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +97 -47
- package/script/midy-GMLite.d.ts +3 -1
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +32 -30
- package/script/midy.d.ts +9 -1
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +85 -64
package/script/midy-GM2.js
CHANGED
|
@@ -228,22 +228,23 @@ class MidyGM2 {
|
|
|
228
228
|
this.totalTime = this.calcTotalTime();
|
|
229
229
|
}
|
|
230
230
|
setChannelAudioNodes(audioContext) {
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
});
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
231
|
+
const { gainLeft, gainRight } = this.panToGain(MidyGM2.channelSettings.pan);
|
|
232
|
+
const gainL = new GainNode(audioContext, { gain: gainLeft });
|
|
233
|
+
const gainR = new GainNode(audioContext, { gain: gainRight });
|
|
234
|
+
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
235
|
+
gainL.connect(merger, 0, 0);
|
|
236
|
+
gainR.connect(merger, 0, 1);
|
|
237
|
+
merger.connect(this.masterGain);
|
|
237
238
|
const reverbEffect = this.createReverbEffect(audioContext);
|
|
238
239
|
const chorusEffect = this.createChorusEffect(audioContext);
|
|
239
240
|
chorusEffect.lfo.start();
|
|
240
|
-
reverbEffect.dryGain.connect(
|
|
241
|
-
reverbEffect.
|
|
242
|
-
|
|
243
|
-
|
|
241
|
+
reverbEffect.dryGain.connect(gainL);
|
|
242
|
+
reverbEffect.dryGain.connect(gainR);
|
|
243
|
+
reverbEffect.wetGain.connect(gainL);
|
|
244
|
+
reverbEffect.wetGain.connect(gainR);
|
|
244
245
|
return {
|
|
245
|
-
|
|
246
|
-
|
|
246
|
+
gainL,
|
|
247
|
+
gainR,
|
|
247
248
|
reverbEffect,
|
|
248
249
|
chorusEffect,
|
|
249
250
|
};
|
|
@@ -647,14 +648,16 @@ class MidyGM2 {
|
|
|
647
648
|
connectNoteEffects(channel, gainNode) {
|
|
648
649
|
if (channel.reverb === 0) {
|
|
649
650
|
if (channel.chorus === 0) { // no effect
|
|
650
|
-
gainNode.connect(channel.
|
|
651
|
+
gainNode.connect(channel.gainL);
|
|
652
|
+
gainNode.connect(channel.gainR);
|
|
651
653
|
}
|
|
652
654
|
else { // chorus
|
|
653
655
|
channel.chorusEffect.delayNodes.forEach((delayNode) => {
|
|
654
656
|
gainNode.connect(delayNode);
|
|
655
657
|
});
|
|
656
658
|
channel.chorusEffect.chorusGains.forEach((chorusGain) => {
|
|
657
|
-
chorusGain.connect(channel.
|
|
659
|
+
chorusGain.connect(channel.gainL);
|
|
660
|
+
chorusGain.connect(channel.gainR);
|
|
658
661
|
});
|
|
659
662
|
}
|
|
660
663
|
}
|
|
@@ -935,20 +938,12 @@ class MidyGM2 {
|
|
|
935
938
|
this.setPitchBend(channelNumber, pitchBend);
|
|
936
939
|
}
|
|
937
940
|
setPitchBend(channelNumber, pitchBend) {
|
|
938
|
-
const now = this.audioContext.currentTime;
|
|
939
941
|
const channel = this.channels[channelNumber];
|
|
940
942
|
const prevPitchBend = channel.pitchBend;
|
|
941
943
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
942
944
|
const detuneChange = (channel.pitchBend - prevPitchBend) *
|
|
943
945
|
channel.pitchBendRange * 100;
|
|
944
|
-
|
|
945
|
-
activeNotes.forEach((activeNote) => {
|
|
946
|
-
const { bufferSource } = activeNote;
|
|
947
|
-
const detune = bufferSource.detune.value + detuneChange;
|
|
948
|
-
bufferSource.detune
|
|
949
|
-
.cancelScheduledValues(now)
|
|
950
|
-
.setValueAtTime(detune, now);
|
|
951
|
-
});
|
|
946
|
+
this.updateDetune(channel, detuneChange);
|
|
952
947
|
}
|
|
953
948
|
handleControlChange(channelNumber, controller, value) {
|
|
954
949
|
switch (controller) {
|
|
@@ -983,9 +978,9 @@ class MidyGM2 {
|
|
|
983
978
|
case 93:
|
|
984
979
|
return this.setChorus(channelNumber, value);
|
|
985
980
|
case 100:
|
|
986
|
-
return this.setRPNMSB(channelNumber, value);
|
|
987
|
-
case 101:
|
|
988
981
|
return this.setRPNLSB(channelNumber, value);
|
|
982
|
+
case 101:
|
|
983
|
+
return this.setRPNMSB(channelNumber, value);
|
|
989
984
|
case 120:
|
|
990
985
|
return this.allSoundOff(channelNumber);
|
|
991
986
|
case 121:
|
|
@@ -1104,44 +1099,65 @@ class MidyGM2 {
|
|
|
1104
1099
|
const channel = this.channels[channelNumber];
|
|
1105
1100
|
channel.softPedal = softPedal / 127;
|
|
1106
1101
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1102
|
+
limitData(channel, minMSB, maxMSB, minLSB, maxLSB) {
|
|
1103
|
+
if (maxLSB < channel.dataLSB) {
|
|
1104
|
+
channel.dataMSB++;
|
|
1105
|
+
channel.dataLSB = minLSB;
|
|
1106
|
+
}
|
|
1107
|
+
else if (channel.dataLSB < 0) {
|
|
1108
|
+
channel.dataMSB--;
|
|
1109
|
+
channel.dataLSB = maxLSB;
|
|
1110
|
+
}
|
|
1111
|
+
if (maxMSB < channel.dataMSB) {
|
|
1112
|
+
channel.dataMSB = maxMSB;
|
|
1113
|
+
channel.dataLSB = maxLSB;
|
|
1114
|
+
}
|
|
1115
|
+
else if (channel.dataMSB < 0) {
|
|
1116
|
+
channel.dataMSB = minMSB;
|
|
1117
|
+
channel.dataLSB = minLSB;
|
|
1118
|
+
}
|
|
1109
1119
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1120
|
+
limitDataMSB(channel, minMSB, maxMSB) {
|
|
1121
|
+
if (maxMSB < channel.dataMSB) {
|
|
1122
|
+
channel.dataMSB = maxMSB;
|
|
1123
|
+
}
|
|
1124
|
+
else if (channel.dataMSB < 0) {
|
|
1125
|
+
channel.dataMSB = minMSB;
|
|
1126
|
+
}
|
|
1112
1127
|
}
|
|
1113
|
-
|
|
1128
|
+
handleRPN(channelNumber, value) {
|
|
1114
1129
|
const channel = this.channels[channelNumber];
|
|
1115
1130
|
const rpn = channel.rpnMSB * 128 + channel.rpnLSB;
|
|
1116
|
-
isMSB ? channel.dataMSB = value : channel.dataLSB = value;
|
|
1117
|
-
const { dataMSB, dataLSB } = channel;
|
|
1118
1131
|
switch (rpn) {
|
|
1119
1132
|
case 0:
|
|
1120
|
-
|
|
1133
|
+
channel.dataLSB += value;
|
|
1134
|
+
this.handlePitchBendRangeMessage(channelNumber);
|
|
1135
|
+
break;
|
|
1121
1136
|
case 1:
|
|
1122
|
-
channel.
|
|
1137
|
+
channel.dataLSB += value;
|
|
1138
|
+
this.handleFineTuningMessage(channelNumber);
|
|
1123
1139
|
break;
|
|
1124
1140
|
case 2:
|
|
1125
|
-
channel.
|
|
1126
|
-
|
|
1127
|
-
case 5:
|
|
1128
|
-
channel.modulationDepthRange = dataMSB + dataLSB / 128;
|
|
1141
|
+
channel.dataMSB += value;
|
|
1142
|
+
this.handleCoarseTuningMessage(channelNumber);
|
|
1129
1143
|
break;
|
|
1130
1144
|
default:
|
|
1131
1145
|
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
|
|
1132
1146
|
}
|
|
1133
1147
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
1148
|
+
setRPNMSB(channelNumber, value) {
|
|
1149
|
+
this.channels[channelNumber].rpnMSB = value;
|
|
1137
1150
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1151
|
+
setRPNLSB(channelNumber, value) {
|
|
1152
|
+
this.channels[channelNumber].rpnLSB = value;
|
|
1153
|
+
}
|
|
1154
|
+
setDataEntry(channelNumber, value, isMSB) {
|
|
1140
1155
|
const channel = this.channels[channelNumber];
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1156
|
+
isMSB ? channel.dataMSB = value : channel.dataLSB = value;
|
|
1157
|
+
this.handleRPN(channelNumber);
|
|
1158
|
+
}
|
|
1159
|
+
updateDetune(channel, detuneChange) {
|
|
1160
|
+
const now = this.audioContext.currentTime;
|
|
1145
1161
|
const activeNotes = this.getActiveNotes(channel, now);
|
|
1146
1162
|
activeNotes.forEach((activeNote) => {
|
|
1147
1163
|
const { bufferSource } = activeNote;
|
|
@@ -1151,6 +1167,40 @@ class MidyGM2 {
|
|
|
1151
1167
|
.setValueAtTime(detune, now);
|
|
1152
1168
|
});
|
|
1153
1169
|
}
|
|
1170
|
+
handlePitchBendRangeMessage(channelNumber) {
|
|
1171
|
+
const channel = this.channels[channelNumber];
|
|
1172
|
+
this.limitData(channel, 0, 127, 0, 99);
|
|
1173
|
+
const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
|
|
1174
|
+
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
1175
|
+
}
|
|
1176
|
+
setPitchBendRange(channelNumber, pitchBendRange) {
|
|
1177
|
+
const channel = this.channels[channelNumber];
|
|
1178
|
+
const prevPitchBendRange = channel.pitchBendRange;
|
|
1179
|
+
channel.pitchBendRange = pitchBendRange;
|
|
1180
|
+
const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
|
|
1181
|
+
channel.pitchBend * 100;
|
|
1182
|
+
this.updateDetune(channel, detuneChange);
|
|
1183
|
+
}
|
|
1184
|
+
handleFineTuningMessage(channelNumber) {
|
|
1185
|
+
const channel = this.channels[channelNumber];
|
|
1186
|
+
this.limitData(channel, 0, 127, 0, 127);
|
|
1187
|
+
const fineTuning = (channel.dataMSB * 128 + channel.dataLSB - 8192) / 8192;
|
|
1188
|
+
this.setFineTuning(channelNumber, fineTuning);
|
|
1189
|
+
}
|
|
1190
|
+
setFineTuning(channelNumber, fineTuning) {
|
|
1191
|
+
const channel = this.channels[channelNumber];
|
|
1192
|
+
channel.fineTuning = fineTuning;
|
|
1193
|
+
}
|
|
1194
|
+
handleCoarseTuningMessage(channelNumber) {
|
|
1195
|
+
const channel = this.channels[channelNumber];
|
|
1196
|
+
this.limitDataMSB(channel, 0, 127);
|
|
1197
|
+
const coarseTuning = channel.dataMSB - 64;
|
|
1198
|
+
this.setFineTuning(channelNumber, coarseTuning);
|
|
1199
|
+
}
|
|
1200
|
+
setCoarseTuning(channelNumber, coarseTuning) {
|
|
1201
|
+
const channel = this.channels[channelNumber];
|
|
1202
|
+
channel.fineTuning = coarseTuning;
|
|
1203
|
+
}
|
|
1154
1204
|
allSoundOff(channelNumber) {
|
|
1155
1205
|
const now = this.audioContext.currentTime;
|
|
1156
1206
|
const channel = this.channels[channelNumber];
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -134,10 +134,12 @@ export class MidyGMLite {
|
|
|
134
134
|
setExpression(channelNumber: any, expression: any): void;
|
|
135
135
|
updateChannelGain(channel: any): void;
|
|
136
136
|
setSustainPedal(channelNumber: any, value: any): void;
|
|
137
|
+
handleRPN(channelNumber: any): void;
|
|
137
138
|
setRPNMSB(channelNumber: any, value: any): void;
|
|
138
139
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
139
140
|
setDataEntry(channelNumber: any, value: any, isMSB: any): void;
|
|
140
|
-
|
|
141
|
+
updateDetune(channel: any, detuneChange: any): void;
|
|
142
|
+
handlePitchBendRangeMessage(channelNumber: any): void;
|
|
141
143
|
setPitchBendRange(channelNumber: any, pitchBendRange: any): void;
|
|
142
144
|
allSoundOff(channelNumber: any): any[];
|
|
143
145
|
resetAllControllers(channelNumber: any): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAqBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA5CD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAuBhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;MAcC;IAED;;;;;;;;;;;;;;;;;;QAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA8DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAqBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA5CD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAuBhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;MAcC;IAED;;;;;;;;;;;;;;;;;;QAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA8DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,sDAGC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,wHA6BC;IAED,kGA6BC;IAED,0EAGC;IAED,sIAmDC;IAED,0FAGC;IAED,kEAeC;IAED,wFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED,mFA+BC;IAED,yDAiBC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,sCAUC;IAED,sDAMC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,+DAIC;IAED,oDAUC;IAED,sDAKC;IAED,iEAOC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAl/BD;IAOE,gFAKC;IAXD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|
package/script/midy-GMLite.js
CHANGED
|
@@ -495,7 +495,8 @@ class MidyGMLite {
|
|
|
495
495
|
return noteList[0];
|
|
496
496
|
}
|
|
497
497
|
connectNoteEffects(channel, gainNode) {
|
|
498
|
-
gainNode.connect(channel.
|
|
498
|
+
gainNode.connect(channel.gainL);
|
|
499
|
+
gainNode.connect(channel.gainR);
|
|
499
500
|
}
|
|
500
501
|
cbToRatio(cb) {
|
|
501
502
|
return Math.pow(10, cb / 200);
|
|
@@ -705,20 +706,12 @@ class MidyGMLite {
|
|
|
705
706
|
this.setPitchBend(channelNumber, pitchBend);
|
|
706
707
|
}
|
|
707
708
|
setPitchBend(channelNumber, pitchBend) {
|
|
708
|
-
const now = this.audioContext.currentTime;
|
|
709
709
|
const channel = this.channels[channelNumber];
|
|
710
710
|
const prevPitchBend = channel.pitchBend;
|
|
711
711
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
712
712
|
const detuneChange = (channel.pitchBend - prevPitchBend) *
|
|
713
713
|
channel.pitchBendRange * 100;
|
|
714
|
-
|
|
715
|
-
activeNotes.forEach((activeNote) => {
|
|
716
|
-
const { bufferSource } = activeNote;
|
|
717
|
-
const detune = bufferSource.detune.value + detuneChange;
|
|
718
|
-
bufferSource.detune
|
|
719
|
-
.cancelScheduledValues(now)
|
|
720
|
-
.setValueAtTime(detune, now);
|
|
721
|
-
});
|
|
714
|
+
this.updateDetune(channel, detuneChange);
|
|
722
715
|
}
|
|
723
716
|
handleControlChange(channelNumber, controller, value) {
|
|
724
717
|
switch (controller) {
|
|
@@ -737,9 +730,9 @@ class MidyGMLite {
|
|
|
737
730
|
case 64:
|
|
738
731
|
return this.setSustainPedal(channelNumber, value);
|
|
739
732
|
case 100:
|
|
740
|
-
return this.setRPNMSB(channelNumber, value);
|
|
741
|
-
case 101:
|
|
742
733
|
return this.setRPNLSB(channelNumber, value);
|
|
734
|
+
case 101:
|
|
735
|
+
return this.setRPNMSB(channelNumber, value);
|
|
743
736
|
case 120:
|
|
744
737
|
return this.allSoundOff(channelNumber);
|
|
745
738
|
case 121:
|
|
@@ -806,6 +799,17 @@ class MidyGMLite {
|
|
|
806
799
|
this.releaseSustainPedal(channelNumber, value);
|
|
807
800
|
}
|
|
808
801
|
}
|
|
802
|
+
handleRPN(channelNumber) {
|
|
803
|
+
const channel = this.channels[channelNumber];
|
|
804
|
+
const rpn = channel.rpnMSB * 128 + channel.rpnLSB;
|
|
805
|
+
switch (rpn) {
|
|
806
|
+
case 0:
|
|
807
|
+
this.handlePitchBendRangeMessage(channelNumber);
|
|
808
|
+
break;
|
|
809
|
+
default:
|
|
810
|
+
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
809
813
|
setRPNMSB(channelNumber, value) {
|
|
810
814
|
this.channels[channelNumber].rpnMSB = value;
|
|
811
815
|
}
|
|
@@ -814,27 +818,11 @@ class MidyGMLite {
|
|
|
814
818
|
}
|
|
815
819
|
setDataEntry(channelNumber, value, isMSB) {
|
|
816
820
|
const channel = this.channels[channelNumber];
|
|
817
|
-
const rpn = channel.rpnMSB * 128 + channel.rpnLSB;
|
|
818
821
|
isMSB ? channel.dataMSB = value : channel.dataLSB = value;
|
|
819
|
-
|
|
820
|
-
switch (rpn) {
|
|
821
|
-
case 0:
|
|
822
|
-
return this.handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB);
|
|
823
|
-
default:
|
|
824
|
-
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB) {
|
|
828
|
-
const pitchBendRange = dataMSB + dataLSB / 100;
|
|
829
|
-
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
822
|
+
this.handleRPN(channelNumber);
|
|
830
823
|
}
|
|
831
|
-
|
|
824
|
+
updateDetune(channel, detuneChange) {
|
|
832
825
|
const now = this.audioContext.currentTime;
|
|
833
|
-
const channel = this.channels[channelNumber];
|
|
834
|
-
const prevPitchBendRange = channel.pitchBendRange;
|
|
835
|
-
channel.pitchBendRange = pitchBendRange;
|
|
836
|
-
const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
|
|
837
|
-
channel.pitchBend * 100;
|
|
838
826
|
const activeNotes = this.getActiveNotes(channel, now);
|
|
839
827
|
activeNotes.forEach((activeNote) => {
|
|
840
828
|
const { bufferSource } = activeNote;
|
|
@@ -844,6 +832,20 @@ class MidyGMLite {
|
|
|
844
832
|
.setValueAtTime(detune, now);
|
|
845
833
|
});
|
|
846
834
|
}
|
|
835
|
+
handlePitchBendRangeMessage(channelNumber) {
|
|
836
|
+
const channel = this.channels[channelNumber];
|
|
837
|
+
this.limitData(channel, 0, 127, 0, 99);
|
|
838
|
+
const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
|
|
839
|
+
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
840
|
+
}
|
|
841
|
+
setPitchBendRange(channelNumber, pitchBendRange) {
|
|
842
|
+
const channel = this.channels[channelNumber];
|
|
843
|
+
const prevPitchBendRange = channel.pitchBendRange;
|
|
844
|
+
channel.pitchBendRange = pitchBendRange;
|
|
845
|
+
const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
|
|
846
|
+
channel.pitchBend * 100;
|
|
847
|
+
this.updateDetune(channel, detuneChange);
|
|
848
|
+
}
|
|
847
849
|
allSoundOff(channelNumber) {
|
|
848
850
|
const now = this.audioContext.currentTime;
|
|
849
851
|
const channel = this.channels[channelNumber];
|
package/script/midy.d.ts
CHANGED
|
@@ -284,13 +284,21 @@ export class Midy {
|
|
|
284
284
|
setVibratoRate(channelNumber: any, vibratoRate: any): void;
|
|
285
285
|
setVibratoDepth(channelNumber: any, vibratoDepth: any): void;
|
|
286
286
|
setVibratoDelay(channelNumber: any, vibratoDelay: any): void;
|
|
287
|
+
limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
|
|
288
|
+
limitDataMSB(channel: any, minMSB: any, maxMSB: any): void;
|
|
289
|
+
handleRPN(channelNumber: any, value: any): void;
|
|
287
290
|
incrementRPNValue(channelNumber: any): void;
|
|
288
291
|
decrementRPNValue(channelNumber: any): void;
|
|
289
292
|
setRPNMSB(channelNumber: any, value: any): void;
|
|
290
293
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
291
294
|
setDataEntry(channelNumber: any, value: any, isMSB: any): void;
|
|
292
|
-
|
|
295
|
+
updateDetune(channel: any, detuneChange: any): void;
|
|
296
|
+
handlePitchBendRangeMessage(channelNumber: any): void;
|
|
293
297
|
setPitchBendRange(channelNumber: any, pitchBendRange: any): void;
|
|
298
|
+
handleFineTuningMessage(channelNumber: any): void;
|
|
299
|
+
setFineTuning(channelNumber: any, fineTuning: any): void;
|
|
300
|
+
handleCoarseTuningMessage(channelNumber: any): void;
|
|
301
|
+
setCoarseTuning(channelNumber: any, coarseTuning: any): void;
|
|
294
302
|
allSoundOff(channelNumber: any): any[];
|
|
295
303
|
resetAllControllers(channelNumber: any): void;
|
|
296
304
|
allNotesOff(channelNumber: any): any[];
|
package/script/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAzED,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;IA+ChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;MAqBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiBC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAyDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgGC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED;;;;MAoCC;IAED;;;;;MAqCC;IAED,
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAzED,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;IA+ChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;MAqBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiBC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAyDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgGC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED;;;;MAoCC;IAED;;;;;MAqCC;IAED,sDA6BC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,uDAcC;IAED,wHAqCC;IAED,gDAQC;IAED,kGAgCC;IAED,0EAGC;IAED,sIAwDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,gEAqBC;IAED,sFAcC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAOC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAiBC;IAED,iEAEC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,+CAEC;IAED,sCAUC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAWC;IAED,uDAGC;IAED,2DAGC;IAED,6DAGC;IAED,6DASC;IAED,kFAeC;IAED,2DAMC;IAGD,gDAqBC;IAED,4CAEC;IAED,4CAEC;IAED,gDAEC;IAED,gDAEC;IAED,+DAIC;IAED,oDAUC;IAED,sDAKC;IAED,iEAOC;IAED,kDAKC;IAED,yDAGC;IAED,oDAKC;IAED,6DAGC;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,mCAQC;IAED,6CAGC;IAED,2CAMC;IAED,+CAGC;IAED,+CAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA1hDD;IASE,gFAKC;IAbD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|
package/script/midy.js
CHANGED
|
@@ -654,14 +654,16 @@ class Midy {
|
|
|
654
654
|
connectNoteEffects(channel, gainNode) {
|
|
655
655
|
if (channel.reverb === 0) {
|
|
656
656
|
if (channel.chorus === 0) { // no effect
|
|
657
|
-
gainNode.connect(channel.
|
|
657
|
+
gainNode.connect(channel.gainL);
|
|
658
|
+
gainNode.connect(channel.gainR);
|
|
658
659
|
}
|
|
659
660
|
else { // chorus
|
|
660
661
|
channel.chorusEffect.delayNodes.forEach((delayNode) => {
|
|
661
662
|
gainNode.connect(delayNode);
|
|
662
663
|
});
|
|
663
664
|
channel.chorusEffect.chorusGains.forEach((chorusGain) => {
|
|
664
|
-
chorusGain.connect(channel.
|
|
665
|
+
chorusGain.connect(channel.gainL);
|
|
666
|
+
chorusGain.connect(channel.gainR);
|
|
665
667
|
});
|
|
666
668
|
}
|
|
667
669
|
}
|
|
@@ -980,20 +982,12 @@ class Midy {
|
|
|
980
982
|
this.setPitchBend(channelNumber, pitchBend);
|
|
981
983
|
}
|
|
982
984
|
setPitchBend(channelNumber, pitchBend) {
|
|
983
|
-
const now = this.audioContext.currentTime;
|
|
984
985
|
const channel = this.channels[channelNumber];
|
|
985
986
|
const prevPitchBend = channel.pitchBend;
|
|
986
987
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
987
988
|
const detuneChange = (channel.pitchBend - prevPitchBend) *
|
|
988
989
|
channel.pitchBendRange * 100;
|
|
989
|
-
|
|
990
|
-
activeNotes.forEach((activeNote) => {
|
|
991
|
-
const { bufferSource } = activeNote;
|
|
992
|
-
const detune = bufferSource.detune.value + detuneChange;
|
|
993
|
-
bufferSource.detune
|
|
994
|
-
.cancelScheduledValues(now)
|
|
995
|
-
.setValueAtTime(detune, now);
|
|
996
|
-
});
|
|
990
|
+
this.updateDetune(channel, detuneChange);
|
|
997
991
|
}
|
|
998
992
|
handleControlChange(channelNumber, controller, value) {
|
|
999
993
|
switch (controller) {
|
|
@@ -1034,14 +1028,14 @@ class Midy {
|
|
|
1034
1028
|
return this.setReverb(channelNumber, value);
|
|
1035
1029
|
case 93:
|
|
1036
1030
|
return this.setChorus(channelNumber, value);
|
|
1037
|
-
case 96:
|
|
1031
|
+
case 96: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp18.pdf
|
|
1038
1032
|
return incrementRPNValue(channelNumber);
|
|
1039
|
-
case 97:
|
|
1033
|
+
case 97: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp18.pdf
|
|
1040
1034
|
return decrementRPNValue(channelNumber);
|
|
1041
1035
|
case 100:
|
|
1042
|
-
return this.setRPNMSB(channelNumber, value);
|
|
1043
|
-
case 101:
|
|
1044
1036
|
return this.setRPNLSB(channelNumber, value);
|
|
1037
|
+
case 101:
|
|
1038
|
+
return this.setRPNMSB(channelNumber, value);
|
|
1045
1039
|
case 120:
|
|
1046
1040
|
return this.allSoundOff(channelNumber);
|
|
1047
1041
|
case 121:
|
|
@@ -1178,39 +1172,58 @@ class Midy {
|
|
|
1178
1172
|
const channel = this.channels[channelNumber];
|
|
1179
1173
|
channel.vibratoDelay = vibratoDelay / 127 * 5; // 0-5sec
|
|
1180
1174
|
}
|
|
1181
|
-
|
|
1175
|
+
limitData(channel, minMSB, maxMSB, minLSB, maxLSB) {
|
|
1176
|
+
if (maxLSB < channel.dataLSB) {
|
|
1177
|
+
channel.dataMSB++;
|
|
1178
|
+
channel.dataLSB = minLSB;
|
|
1179
|
+
}
|
|
1180
|
+
else if (channel.dataLSB < 0) {
|
|
1181
|
+
channel.dataMSB--;
|
|
1182
|
+
channel.dataLSB = maxLSB;
|
|
1183
|
+
}
|
|
1184
|
+
if (maxMSB < channel.dataMSB) {
|
|
1185
|
+
channel.dataMSB = maxMSB;
|
|
1186
|
+
channel.dataLSB = maxLSB;
|
|
1187
|
+
}
|
|
1188
|
+
else if (channel.dataMSB < 0) {
|
|
1189
|
+
channel.dataMSB = minMSB;
|
|
1190
|
+
channel.dataLSB = minLSB;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
limitDataMSB(channel, minMSB, maxMSB) {
|
|
1194
|
+
if (maxMSB < channel.dataMSB) {
|
|
1195
|
+
channel.dataMSB = maxMSB;
|
|
1196
|
+
}
|
|
1197
|
+
else if (channel.dataMSB < 0) {
|
|
1198
|
+
channel.dataMSB = minMSB;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
// TODO: support 3-4?
|
|
1202
|
+
handleRPN(channelNumber, value) {
|
|
1182
1203
|
const channel = this.channels[channelNumber];
|
|
1183
1204
|
const rpn = channel.rpnMSB * 128 + channel.rpnLSB;
|
|
1184
1205
|
switch (rpn) {
|
|
1185
1206
|
case 0:
|
|
1186
|
-
channel.
|
|
1207
|
+
channel.dataLSB += value;
|
|
1208
|
+
this.handlePitchBendRangeMessage(channelNumber);
|
|
1187
1209
|
break;
|
|
1188
1210
|
case 1:
|
|
1189
|
-
channel.
|
|
1211
|
+
channel.dataLSB += value;
|
|
1212
|
+
this.handleFineTuningMessage(channelNumber);
|
|
1190
1213
|
break;
|
|
1191
1214
|
case 2:
|
|
1192
|
-
channel.
|
|
1215
|
+
channel.dataMSB += value;
|
|
1216
|
+
this.handleCoarseTuningMessage(channelNumber);
|
|
1193
1217
|
break;
|
|
1194
1218
|
default:
|
|
1195
1219
|
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
|
|
1196
1220
|
}
|
|
1197
1221
|
}
|
|
1222
|
+
incrementRPNValue(channelNumber) {
|
|
1223
|
+
this.handleRPN(channelNumber, 1);
|
|
1224
|
+
}
|
|
1198
1225
|
decrementRPNValue(channelNumber) {
|
|
1199
|
-
|
|
1200
|
-
const rpn = channel.rpnMSB * 128 + channel.rpnLSB;
|
|
1201
|
-
switch (rpn) {
|
|
1202
|
-
case 0:
|
|
1203
|
-
channel.pitchBendRange = Math.max(-1, channel.pitchBendRange - 1);
|
|
1204
|
-
break;
|
|
1205
|
-
case 1:
|
|
1206
|
-
channel.fineTuning = Math.max(-1, channel.fineTuning - 1);
|
|
1207
|
-
break;
|
|
1208
|
-
case 2:
|
|
1209
|
-
channel.coarseTuning = Math.max(40, channel.coarseTuning - 1);
|
|
1210
|
-
break;
|
|
1211
|
-
default:
|
|
1212
|
-
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB}, LSB=${channel.rpnLSB}.`);
|
|
1213
|
-
}
|
|
1226
|
+
this.handleRPN(channelNumber, -1);
|
|
1214
1227
|
}
|
|
1215
1228
|
setRPNMSB(channelNumber, value) {
|
|
1216
1229
|
this.channels[channelNumber].rpnMSB = value;
|
|
@@ -1218,39 +1231,13 @@ class Midy {
|
|
|
1218
1231
|
setRPNLSB(channelNumber, value) {
|
|
1219
1232
|
this.channels[channelNumber].rpnLSB = value;
|
|
1220
1233
|
}
|
|
1221
|
-
// TODO: support 3-4?
|
|
1222
1234
|
setDataEntry(channelNumber, value, isMSB) {
|
|
1223
1235
|
const channel = this.channels[channelNumber];
|
|
1224
|
-
const rpn = channel.rpnMSB * 128 + channel.rpnLSB;
|
|
1225
1236
|
isMSB ? channel.dataMSB = value : channel.dataLSB = value;
|
|
1226
|
-
|
|
1227
|
-
switch (rpn) {
|
|
1228
|
-
case 0:
|
|
1229
|
-
return this.handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB);
|
|
1230
|
-
case 1:
|
|
1231
|
-
channel.fineTuning = (dataMSB * 128 + dataLSB - 8192) / 8192;
|
|
1232
|
-
break;
|
|
1233
|
-
case 2:
|
|
1234
|
-
channel.coarseTuning = dataMSB - 64;
|
|
1235
|
-
break;
|
|
1236
|
-
case 5:
|
|
1237
|
-
channel.modulationDepthRange = dataMSB + dataLSB / 128;
|
|
1238
|
-
break;
|
|
1239
|
-
default:
|
|
1240
|
-
console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
|
|
1241
|
-
}
|
|
1237
|
+
this.handleRPN(channelNumber, 0);
|
|
1242
1238
|
}
|
|
1243
|
-
|
|
1244
|
-
const pitchBendRange = dataMSB + dataLSB / 100;
|
|
1245
|
-
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
1246
|
-
}
|
|
1247
|
-
setPitchBendRange(channelNumber, pitchBendRange) {
|
|
1239
|
+
updateDetune(channel, detuneChange) {
|
|
1248
1240
|
const now = this.audioContext.currentTime;
|
|
1249
|
-
const channel = this.channels[channelNumber];
|
|
1250
|
-
const prevPitchBendRange = channel.pitchBendRange;
|
|
1251
|
-
channel.pitchBendRange = pitchBendRange;
|
|
1252
|
-
const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
|
|
1253
|
-
channel.pitchBend * 100;
|
|
1254
1241
|
const activeNotes = this.getActiveNotes(channel, now);
|
|
1255
1242
|
activeNotes.forEach((activeNote) => {
|
|
1256
1243
|
const { bufferSource } = activeNote;
|
|
@@ -1260,6 +1247,40 @@ class Midy {
|
|
|
1260
1247
|
.setValueAtTime(detune, now);
|
|
1261
1248
|
});
|
|
1262
1249
|
}
|
|
1250
|
+
handlePitchBendRangeMessage(channelNumber) {
|
|
1251
|
+
const channel = this.channels[channelNumber];
|
|
1252
|
+
this.limitData(channel, 0, 127, 0, 99);
|
|
1253
|
+
const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
|
|
1254
|
+
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
1255
|
+
}
|
|
1256
|
+
setPitchBendRange(channelNumber, pitchBendRange) {
|
|
1257
|
+
const channel = this.channels[channelNumber];
|
|
1258
|
+
const prevPitchBendRange = channel.pitchBendRange;
|
|
1259
|
+
channel.pitchBendRange = pitchBendRange;
|
|
1260
|
+
const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
|
|
1261
|
+
channel.pitchBend * 100;
|
|
1262
|
+
this.updateDetune(channel, detuneChange);
|
|
1263
|
+
}
|
|
1264
|
+
handleFineTuningMessage(channelNumber) {
|
|
1265
|
+
const channel = this.channels[channelNumber];
|
|
1266
|
+
this.limitData(channel, 0, 127, 0, 127);
|
|
1267
|
+
const fineTuning = (channel.dataMSB * 128 + channel.dataLSB - 8192) / 8192;
|
|
1268
|
+
this.setFineTuning(channelNumber, fineTuning);
|
|
1269
|
+
}
|
|
1270
|
+
setFineTuning(channelNumber, fineTuning) {
|
|
1271
|
+
const channel = this.channels[channelNumber];
|
|
1272
|
+
channel.fineTuning = fineTuning;
|
|
1273
|
+
}
|
|
1274
|
+
handleCoarseTuningMessage(channelNumber) {
|
|
1275
|
+
const channel = this.channels[channelNumber];
|
|
1276
|
+
this.limitDataMSB(channel, 0, 127);
|
|
1277
|
+
const coarseTuning = channel.dataMSB - 64;
|
|
1278
|
+
this.setFineTuning(channelNumber, coarseTuning);
|
|
1279
|
+
}
|
|
1280
|
+
setCoarseTuning(channelNumber, coarseTuning) {
|
|
1281
|
+
const channel = this.channels[channelNumber];
|
|
1282
|
+
channel.fineTuning = coarseTuning;
|
|
1283
|
+
}
|
|
1263
1284
|
allSoundOff(channelNumber) {
|
|
1264
1285
|
const now = this.audioContext.currentTime;
|
|
1265
1286
|
const channel = this.channels[channelNumber];
|
|
@@ -1331,8 +1352,8 @@ class Midy {
|
|
|
1331
1352
|
channel.bankLSB = 0;
|
|
1332
1353
|
channel.bank = 0;
|
|
1333
1354
|
});
|
|
1334
|
-
this.channels[9].bankMSB =
|
|
1335
|
-
this.channels[9].bank =
|
|
1355
|
+
this.channels[9].bankMSB = 1;
|
|
1356
|
+
this.channels[9].bank = 128;
|
|
1336
1357
|
}
|
|
1337
1358
|
GM2SystemOn() {
|
|
1338
1359
|
this.channels.forEach((channel) => {
|