@marmooo/midy 0.0.3 → 0.0.4

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.
@@ -32,6 +32,14 @@ export class MidyGM2 {
32
32
  channelPressure: number;
33
33
  pitchBendRange: number;
34
34
  };
35
+ static controllerDestinationSettings: {
36
+ pitchControl: number;
37
+ filterCutoffControl: number;
38
+ amplitudeControl: number;
39
+ lfoPitchDepth: number;
40
+ lfoFilterDepth: number;
41
+ lfoAmplitudeDepth: number;
42
+ };
35
43
  constructor(audioContext: any);
36
44
  ticksPerBeat: number;
37
45
  totalTime: number;
@@ -57,55 +65,7 @@ export class MidyGM2 {
57
65
  notePromises: any[];
58
66
  audioContext: any;
59
67
  masterGain: any;
60
- channels: {
61
- scheduledNotes: Map<any, any>;
62
- sostenutoNotes: Map<any, any>;
63
- gainNode: any;
64
- pannerNode: any;
65
- modulationEffect: {
66
- lfo: any;
67
- };
68
- reverbEffect: {
69
- convolverNode: any;
70
- dryGain: any;
71
- wetGain: any;
72
- };
73
- chorusEffect: {
74
- lfo: any;
75
- lfoGain: any;
76
- delayNodes: any[];
77
- chorusGains: any[];
78
- };
79
- expression: number;
80
- modulation: number;
81
- sustainPedal: boolean;
82
- portamento: boolean;
83
- sostenutoPedal: boolean;
84
- softPedal: number;
85
- rpnMSB: number;
86
- rpnLSB: number;
87
- channelPressure: number;
88
- pitchBendRange: number;
89
- currentBufferSource: null;
90
- volume: number;
91
- pan: number;
92
- portamentoTime: number;
93
- reverb: number;
94
- chorus: number;
95
- vibratoRate: number;
96
- vibratoDepth: number;
97
- vibratoDelay: number;
98
- bank: number;
99
- bankMSB: number;
100
- bankLSB: number;
101
- dataMSB: number;
102
- dataLSB: number;
103
- program: number;
104
- pitchBend: number;
105
- fineTuning: number;
106
- coarseTuning: number;
107
- modulationDepthRange: number;
108
- }[];
68
+ channels: any[];
109
69
  initSoundFontTable(): any[];
110
70
  addSoundFont(soundFont: any): void;
111
71
  loadSoundFont(soundFontUrl: any): Promise<void>;
@@ -128,55 +88,7 @@ export class MidyGM2 {
128
88
  chorusGains: any[];
129
89
  };
130
90
  };
131
- createChannels(audioContext: any): {
132
- scheduledNotes: Map<any, any>;
133
- sostenutoNotes: Map<any, any>;
134
- gainNode: any;
135
- pannerNode: any;
136
- modulationEffect: {
137
- lfo: any;
138
- };
139
- reverbEffect: {
140
- convolverNode: any;
141
- dryGain: any;
142
- wetGain: any;
143
- };
144
- chorusEffect: {
145
- lfo: any;
146
- lfoGain: any;
147
- delayNodes: any[];
148
- chorusGains: any[];
149
- };
150
- expression: number;
151
- modulation: number;
152
- sustainPedal: boolean;
153
- portamento: boolean;
154
- sostenutoPedal: boolean;
155
- softPedal: number;
156
- rpnMSB: number;
157
- rpnLSB: number;
158
- channelPressure: number;
159
- pitchBendRange: number;
160
- currentBufferSource: null;
161
- volume: number;
162
- pan: number;
163
- portamentoTime: number;
164
- reverb: number;
165
- chorus: number;
166
- vibratoRate: number;
167
- vibratoDepth: number;
168
- vibratoDelay: number;
169
- bank: number;
170
- bankMSB: number;
171
- bankLSB: number;
172
- dataMSB: number;
173
- dataLSB: number;
174
- program: number;
175
- pitchBend: number;
176
- fineTuning: number;
177
- coarseTuning: number;
178
- modulationDepthRange: number;
179
- }[];
91
+ createChannels(audioContext: any): any[];
180
92
  createNoteBuffer(noteInfo: any, isSF3: any): Promise<any>;
181
93
  createNoteBufferNode(noteInfo: any, isSF3: any): Promise<any>;
182
94
  convertToFloat32Array(uint8Array: any): Float32Array;
@@ -216,6 +128,8 @@ export class MidyGM2 {
216
128
  connectNoteEffects(channel: any, gainNode: any): void;
217
129
  cbToRatio(cb: any): number;
218
130
  centToHz(cent: any): number;
131
+ calcSemitoneOffset(channel: any): any;
132
+ calcPlaybackRate(noteInfo: any, noteNumber: any, semitoneOffset: any): number;
219
133
  createNoteAudioChain(channel: any, noteInfo: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<{
220
134
  bufferSource: any;
221
135
  gainNode: any;
@@ -230,10 +144,10 @@ export class MidyGM2 {
230
144
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
231
145
  releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
232
146
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
233
- handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
234
147
  handleProgramChange(channelNumber: any, program: any): void;
235
148
  handleChannelPressure(channelNumber: any, pressure: any): void;
236
- handlePitchBend(channelNumber: any, lsb: any, msb: any): void;
149
+ handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
150
+ handlePitchBend(channelNumber: any, pitchBend: any): void;
237
151
  handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
238
152
  setBankMSB(channelNumber: any, msb: any): void;
239
153
  setModulation(channelNumber: any, modulation: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAhED,qBAAmB;IACnB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,cAAa;IACb,cAAa;IACb,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA4CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA2GC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;;OAsFC;IAED,gDAQC;IAED,kGAgDC;IAED,0EAGC;IAED,sIA6CC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,mFAuDC;IAED,+CAEC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAUC;IAED,uDAGC;IAED,gDAEC;IAED,gDAEC;IAED,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;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,gBAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;MAuBC;IAED,yCAcC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EAkDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA2GC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,8EAEC;IAED;;;;;OAqFC;IAED,gDAQC;IAED,kGAgDC;IAED,0EAGC;IAED,sIA6CC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAmBC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,0DAiBC;IAED,mFAuDC;IAED,+CAEC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAUC;IAED,uDAGC;IAED,gDAEC;IAED,gDAEC;IAED,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAQC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
@@ -204,11 +204,14 @@ class MidyGM2 {
204
204
  createChannels(audioContext) {
205
205
  const channels = Array.from({ length: 16 }, () => {
206
206
  return {
207
- ...MidyGM2.channelSettings,
208
- ...MidyGM2.effectSettings,
207
+ ...Midy.channelSettings,
208
+ ...Midy.effectSettings,
209
209
  ...this.setChannelAudioNodes(audioContext),
210
210
  scheduledNotes: new Map(),
211
211
  sostenutoNotes: new Map(),
212
+ channelPressure: {
213
+ ...Midy.controllerDestinationSettings,
214
+ },
212
215
  };
213
216
  });
214
217
  return channels;
@@ -263,9 +266,6 @@ class MidyGM2 {
263
266
  if (event.startTime > t + this.lookAhead)
264
267
  break;
265
268
  switch (event.type) {
266
- case "controller":
267
- this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
268
- break;
269
269
  case "noteOn":
270
270
  if (event.velocity !== 0) {
271
271
  await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
@@ -279,9 +279,18 @@ class MidyGM2 {
279
279
  }
280
280
  break;
281
281
  }
282
+ case "controller":
283
+ this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
284
+ break;
282
285
  case "programChange":
283
286
  this.handleProgramChange(event.channel, event.programNumber);
284
287
  break;
288
+ case "channelAftertouch":
289
+ this.handleChannelPressure(event.channel, event.amount);
290
+ break;
291
+ case "pitchBend":
292
+ this.handlePitchBend(event.channel, event.value);
293
+ break;
285
294
  case "sysEx":
286
295
  this.handleSysEx(event.data);
287
296
  }
@@ -645,15 +654,19 @@ class MidyGM2 {
645
654
  centToHz(cent) {
646
655
  return 8.176 * Math.pow(2, cent / 1200);
647
656
  }
648
- async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
657
+ calcSemitoneOffset(channel) {
649
658
  const masterTuning = this.masterCoarseTuning + this.masterFineTuning;
650
659
  const channelTuning = channel.coarseTuning + channel.fineTuning;
651
660
  const tuning = masterTuning + channelTuning;
652
- const semitoneOffset = channel.pitchBend * channel.pitchBendRange + tuning;
653
- const playbackRate = noteInfo.playbackRate(noteNumber) *
654
- Math.pow(2, semitoneOffset / 12);
661
+ return channel.pitchBend * channel.pitchBendRange + tuning;
662
+ }
663
+ calcPlaybackRate(noteInfo, noteNumber, semitoneOffset) {
664
+ return noteInfo.playbackRate(noteNumber) * Math.pow(2, semitoneOffset / 12);
665
+ }
666
+ async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
655
667
  const bufferSource = await this.createNoteBufferNode(noteInfo, isSF3);
656
- bufferSource.playbackRate.value = playbackRate;
668
+ const semitoneOffset = this.calcSemitoneOffset(channel);
669
+ bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
657
670
  // volume envelope
658
671
  const gainNode = new GainNode(this.audioContext, {
659
672
  gain: 0,
@@ -858,8 +871,6 @@ class MidyGM2 {
858
871
  return this.releaseNote(channelNumber, data1, data2);
859
872
  case 0x90:
860
873
  return this.noteOn(channelNumber, data1, data2);
861
- case 0xA0:
862
- return this.handlePolyphonicKeyPressure(channelNumber, data1, data2);
863
874
  case 0xB0:
864
875
  return this.handleControlChange(channelNumber, data1, data2);
865
876
  case 0xC0:
@@ -867,38 +878,48 @@ class MidyGM2 {
867
878
  case 0xD0:
868
879
  return this.handleChannelPressure(channelNumber, data1);
869
880
  case 0xE0:
870
- return this.handlePitchBend(channelNumber, data1, data2);
881
+ return this.handlePitchBendMessage(channelNumber, data1, data2);
871
882
  default:
872
883
  console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
873
884
  }
874
885
  }
875
- handlePolyphonicKeyPressure(channelNumber, noteNumber, pressure) {
876
- const now = this.audioContext.currentTime;
877
- const channel = this.channels[channelNumber];
878
- const scheduledNotes = channel.scheduledNotes.get(noteNumber);
879
- pressure /= 127;
880
- if (scheduledNotes) {
881
- scheduledNotes.forEach((scheduledNote) => {
882
- if (scheduledNote) {
883
- const { initialAttenuation } = scheduledNote.noteInfo;
884
- const gain = this.cbToRatio(-initialAttenuation) * pressure;
885
- scheduledNote.gainNode.gain.cancelScheduledValues(now);
886
- scheduledNote.gainNode.gain.setValueAtTime(gain, now);
887
- }
888
- });
889
- }
890
- }
891
886
  handleProgramChange(channelNumber, program) {
892
887
  const channel = this.channels[channelNumber];
893
888
  channel.bank = channel.bankMSB * 128 + channel.bankLSB;
894
889
  channel.program = program;
895
890
  }
896
891
  handleChannelPressure(channelNumber, pressure) {
897
- this.channels[channelNumber].channelPressure = pressure;
892
+ const now = this.audioContext.currentTime;
893
+ const channel = this.channels[channelNumber];
894
+ pressure /= 64;
895
+ channel.channelPressure = pressure;
896
+ const activeNotes = this.getActiveNotes(channel);
897
+ if (channel.channelPressure.amplitudeControl !== 1) {
898
+ activeNotes.forEach((activeNote) => {
899
+ const gain = activeNote.gainNode.gain.value;
900
+ activeNote.gainNode.gain
901
+ .cancelScheduledValues(now)
902
+ .setValueAtTime(gain * pressure, now);
903
+ });
904
+ }
898
905
  }
899
- handlePitchBend(channelNumber, lsb, msb) {
900
- const pitchBend = (msb * 128 + lsb - 8192) / 8192;
901
- this.channels[channelNumber].pitchBend = pitchBend;
906
+ handlePitchBendMessage(channelNumber, lsb, msb) {
907
+ const pitchBend = msb * 128 + lsb;
908
+ this.handlePitchBend(channelNumber, pitchBend);
909
+ }
910
+ handlePitchBend(channelNumber, pitchBend) {
911
+ const now = this.audioContext.currentTime;
912
+ const channel = this.channels[channelNumber];
913
+ channel.pitchBend = (pitchBend - 8192) / 8192;
914
+ const semitoneOffset = this.calcSemitoneOffset(channel);
915
+ const activeNotes = this.getActiveNotes(channel);
916
+ activeNotes.forEach((activeNote) => {
917
+ const { bufferSource, noteInfo, noteNumber } = activeNote;
918
+ const playbackRate = calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
919
+ bufferSource.playbackRate
920
+ .cancelScheduledValues(now)
921
+ .setValueAtTime(playbackRate * pressure, now);
922
+ });
902
923
  }
903
924
  handleControlChange(channelNumber, controller, value) {
904
925
  switch (controller) {
@@ -1171,10 +1192,10 @@ class MidyGM2 {
1171
1192
  switch (data[3]) {
1172
1193
  // case 1:
1173
1194
  // // TODO
1174
- // return this.handleChannelPressure();
1195
+ // return this.setChannelPressure();
1175
1196
  // case 3:
1176
1197
  // // TODO
1177
- // return this.handleControlChange();
1198
+ // return this.setControlChange();
1178
1199
  default:
1179
1200
  console.warn(`Unsupported Exclusive Message ${data}`);
1180
1201
  }
@@ -1193,20 +1214,25 @@ class MidyGM2 {
1193
1214
  }
1194
1215
  }
1195
1216
  handleMasterVolumeSysEx(data) {
1196
- const volume = (data[5] * 128 + data[4] - 8192) / 8192;
1217
+ const volume = (data[5] * 128 + data[4]) / 16383;
1197
1218
  this.handleMasterVolume(volume);
1198
1219
  }
1199
1220
  handleMasterVolume(volume) {
1200
- const now = this.audioContext.currentTime;
1201
- this.masterGain.gain.cancelScheduledValues(now);
1202
- this.masterGain.gain.setValueAtTime(volume * volume, now);
1221
+ if (volume < 0 && 1 < volume) {
1222
+ console.error("Master Volume is out of range");
1223
+ }
1224
+ else {
1225
+ const now = this.audioContext.currentTime;
1226
+ this.masterGain.gain.cancelScheduledValues(now);
1227
+ this.masterGain.gain.setValueAtTime(volume * volume, now);
1228
+ }
1203
1229
  }
1204
1230
  handleMasterFineTuningSysEx(data) {
1205
1231
  const fineTuning = (data[5] * 128 + data[4] - 8192) / 8192;
1206
1232
  this.handleMasterFineTuning(fineTuning);
1207
1233
  }
1208
1234
  handleMasterFineTuning(fineTuning) {
1209
- if (fineTuning < 0 && 1 < fineTuning) {
1235
+ if (fineTuning < -1 && 1 < fineTuning) {
1210
1236
  console.error("Master Fine Tuning value is out of range");
1211
1237
  }
1212
1238
  else {
@@ -1294,3 +1320,16 @@ Object.defineProperty(MidyGM2, "effectSettings", {
1294
1320
  pitchBendRange: 2,
1295
1321
  }
1296
1322
  });
1323
+ Object.defineProperty(MidyGM2, "controllerDestinationSettings", {
1324
+ enumerable: true,
1325
+ configurable: true,
1326
+ writable: true,
1327
+ value: {
1328
+ pitchControl: 0,
1329
+ filterCutoffControl: 0,
1330
+ amplitudeControl: 1,
1331
+ lfoPitchDepth: 0,
1332
+ lfoFilterDepth: 0,
1333
+ lfoAmplitudeDepth: 0,
1334
+ }
1335
+ });
@@ -131,6 +131,8 @@ export class MidyGMLite {
131
131
  connectNoteEffects(channel: any, gainNode: any): void;
132
132
  cbToRatio(cb: any): number;
133
133
  centToHz(cent: any): number;
134
+ calcSemitoneOffset(channel: any): any;
135
+ calcPlaybackRate(noteInfo: any, noteNumber: any, semitoneOffset: any): number;
134
136
  createNoteAudioChain(channel: any, noteInfo: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<{
135
137
  bufferSource: any;
136
138
  gainNode: any;
@@ -143,10 +145,9 @@ export class MidyGMLite {
143
145
  releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
144
146
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
145
147
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
146
- handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
147
148
  handleProgramChange(channelNumber: any, program: any): void;
148
- handleChannelPressure(channelNumber: any, pressure: any): void;
149
- handlePitchBend(channelNumber: any, lsb: any, msb: any): void;
149
+ handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
150
+ handlePitchBend(channelNumber: any, pitchBend: any): void;
150
151
  handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
151
152
  setModulation(channelNumber: any, modulation: any): void;
152
153
  setVolume(channelNumber: any, volume: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAMA;IAmBE;;;;;;;;;;;;MAYE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA/CD,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;IA0BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA4CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAyEC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;;OA4EC;IAED,kGAuCC;IAED,0EAGC;IAED,sIA4CC;IAED,0FAGC;IAED,kEAeC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAIC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAcC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAMA;IAmBE;;;;;;;;;;;;MAYE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA/CD,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;IA0BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAyEC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED,sCAEC;IAED,8EAEC;IAED;;;;;OA8EC;IAED,kGAuCC;IAED,0EAGC;IAED,sIA4CC;IAED,0FAGC;IAED,kEAeC;IAED,wFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,0DAiBC;IAED,mFA+BC;IAED,yDAIC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAcC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
@@ -226,9 +226,6 @@ class MidyGMLite {
226
226
  if (event.startTime > t + this.lookAhead)
227
227
  break;
228
228
  switch (event.type) {
229
- case "controller":
230
- this.handleControlChange(event.channel, event.controllerType, event.value);
231
- break;
232
229
  case "noteOn":
233
230
  if (event.velocity !== 0) {
234
231
  await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
@@ -242,9 +239,15 @@ class MidyGMLite {
242
239
  }
243
240
  break;
244
241
  }
242
+ case "controller":
243
+ this.handleControlChange(event.channel, event.controllerType, event.value);
244
+ break;
245
245
  case "programChange":
246
246
  this.handleProgramChange(event.channel, event.programNumber);
247
247
  break;
248
+ case "pitchBend":
249
+ this.handlePitchBend(event.channel, event.value);
250
+ break;
248
251
  case "sysEx":
249
252
  this.handleSysEx(event.data);
250
253
  }
@@ -481,12 +484,16 @@ class MidyGMLite {
481
484
  centToHz(cent) {
482
485
  return 8.176 * Math.pow(2, cent / 1200);
483
486
  }
487
+ calcSemitoneOffset(channel) {
488
+ return channel.pitchBend * channel.pitchBendRange + tuning;
489
+ }
490
+ calcPlaybackRate(noteInfo, noteNumber, semitoneOffset) {
491
+ return noteInfo.playbackRate(noteNumber) * Math.pow(2, semitoneOffset / 12);
492
+ }
484
493
  async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
485
- const semitoneOffset = channel.pitchBend * channel.pitchBendRange;
486
- const playbackRate = noteInfo.playbackRate(noteNumber) *
487
- Math.pow(2, semitoneOffset / 12);
488
494
  const bufferSource = await this.createNoteBufferNode(noteInfo, isSF3);
489
- bufferSource.playbackRate.value = playbackRate;
495
+ const semitoneOffset = this.calcSemitoneOffset(channel);
496
+ bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
490
497
  // volume envelope
491
498
  const gainNode = new GainNode(this.audioContext, {
492
499
  gain: 0,
@@ -652,46 +659,37 @@ class MidyGMLite {
652
659
  return this.releaseNote(channelNumber, data1, data2);
653
660
  case 0x90:
654
661
  return this.noteOn(channelNumber, data1, data2);
655
- case 0xA0:
656
- return this.handlePolyphonicKeyPressure(channelNumber, data1, data2);
657
662
  case 0xB0:
658
663
  return this.handleControlChange(channelNumber, data1, data2);
659
664
  case 0xC0:
660
665
  return this.handleProgramChange(channelNumber, data1);
661
- case 0xD0:
662
- return this.handleChannelPressure(channelNumber, data1);
663
666
  case 0xE0:
664
- return this.handlePitchBend(channelNumber, data1, data2);
667
+ return this.handlePitchBendMessage(channelNumber, data1, data2);
665
668
  default:
666
669
  console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
667
670
  }
668
671
  }
669
- handlePolyphonicKeyPressure(channelNumber, noteNumber, pressure) {
670
- const now = this.audioContext.currentTime;
671
- const channel = this.channels[channelNumber];
672
- const scheduledNotes = channel.scheduledNotes.get(noteNumber);
673
- pressure /= 127;
674
- if (scheduledNotes) {
675
- scheduledNotes.forEach((scheduledNote) => {
676
- if (scheduledNote) {
677
- const { initialAttenuation } = scheduledNote.noteInfo;
678
- const gain = this.cbToRatio(-initialAttenuation) * pressure;
679
- scheduledNote.gainNode.gain.cancelScheduledValues(now);
680
- scheduledNote.gainNode.gain.setValueAtTime(gain, now);
681
- }
682
- });
683
- }
684
- }
685
672
  handleProgramChange(channelNumber, program) {
686
673
  const channel = this.channels[channelNumber];
687
674
  channel.program = program;
688
675
  }
689
- handleChannelPressure(channelNumber, pressure) {
690
- this.channels[channelNumber].channelPressure = pressure;
676
+ handlePitchBendMessage(channelNumber, lsb, msb) {
677
+ const pitchBend = msb * 128 + lsb;
678
+ this.handlePitchBend(channelNumber, pitchBend);
691
679
  }
692
- handlePitchBend(channelNumber, lsb, msb) {
693
- const pitchBend = (msb * 128 + lsb - 8192) / 8192;
694
- this.channels[channelNumber].pitchBend = pitchBend;
680
+ handlePitchBend(channelNumber, pitchBend) {
681
+ const now = this.audioContext.currentTime;
682
+ const channel = this.channels[channelNumber];
683
+ channel.pitchBend = (pitchBend - 8192) / 8192;
684
+ const semitoneOffset = this.calcSemitoneOffset(channel);
685
+ const activeNotes = this.getActiveNotes(channel);
686
+ activeNotes.forEach((activeNote) => {
687
+ const { bufferSource, noteInfo, noteNumber } = activeNote;
688
+ const playbackRate = calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
689
+ bufferSource.playbackRate
690
+ .cancelScheduledValues(now)
691
+ .setValueAtTime(playbackRate * pressure, now);
692
+ });
695
693
  }
696
694
  handleControlChange(channelNumber, controller, value) {
697
695
  switch (controller) {
@@ -851,13 +849,18 @@ class MidyGMLite {
851
849
  }
852
850
  }
853
851
  handleMasterVolumeSysEx(data) {
854
- const volume = (data[5] * 128 + data[4] - 8192) / 8192;
852
+ const volume = (data[5] * 128 + data[4]) / 16383;
855
853
  this.handleMasterVolume(volume);
856
854
  }
857
855
  handleMasterVolume(volume) {
858
- const now = this.audioContext.currentTime;
859
- this.masterGain.gain.cancelScheduledValues(now);
860
- this.masterGain.gain.setValueAtTime(volume * volume, now);
856
+ if (volume < 0 && 1 < volume) {
857
+ console.error("Master Volume is out of range");
858
+ }
859
+ else {
860
+ const now = this.audioContext.currentTime;
861
+ this.masterGain.gain.cancelScheduledValues(now);
862
+ this.masterGain.gain.setValueAtTime(volume * volume, now);
863
+ }
861
864
  }
862
865
  handleExclusiveMessage(data) {
863
866
  console.warn(`Unsupported Exclusive Message ${data}`);
package/script/midy.d.ts CHANGED
@@ -32,6 +32,14 @@ export class Midy {
32
32
  channelPressure: number;
33
33
  pitchBendRange: number;
34
34
  };
35
+ static controllerDestinationSettings: {
36
+ pitchControl: number;
37
+ filterCutoffControl: number;
38
+ amplitudeControl: number;
39
+ lfoPitchDepth: number;
40
+ lfoFilterDepth: number;
41
+ lfoAmplitudeDepth: number;
42
+ };
35
43
  constructor(audioContext: any);
36
44
  ticksPerBeat: number;
37
45
  totalTime: number;
@@ -60,6 +68,22 @@ export class Midy {
60
68
  channels: {
61
69
  scheduledNotes: Map<any, any>;
62
70
  sostenutoNotes: Map<any, any>;
71
+ polyphonicKeyPressure: {
72
+ pitchControl: number;
73
+ filterCutoffControl: number;
74
+ amplitudeControl: number;
75
+ lfoPitchDepth: number;
76
+ lfoFilterDepth: number;
77
+ lfoAmplitudeDepth: number;
78
+ };
79
+ channelPressure: {
80
+ pitchControl: number;
81
+ filterCutoffControl: number;
82
+ amplitudeControl: number;
83
+ lfoPitchDepth: number;
84
+ lfoFilterDepth: number;
85
+ lfoAmplitudeDepth: number;
86
+ };
63
87
  gainNode: any;
64
88
  pannerNode: any;
65
89
  modulationEffect: {
@@ -84,7 +108,6 @@ export class Midy {
84
108
  softPedal: number;
85
109
  rpnMSB: number;
86
110
  rpnLSB: number;
87
- channelPressure: number;
88
111
  pitchBendRange: number;
89
112
  currentBufferSource: null;
90
113
  volume: number;
@@ -131,6 +154,22 @@ export class Midy {
131
154
  createChannels(audioContext: any): {
132
155
  scheduledNotes: Map<any, any>;
133
156
  sostenutoNotes: Map<any, any>;
157
+ polyphonicKeyPressure: {
158
+ pitchControl: number;
159
+ filterCutoffControl: number;
160
+ amplitudeControl: number;
161
+ lfoPitchDepth: number;
162
+ lfoFilterDepth: number;
163
+ lfoAmplitudeDepth: number;
164
+ };
165
+ channelPressure: {
166
+ pitchControl: number;
167
+ filterCutoffControl: number;
168
+ amplitudeControl: number;
169
+ lfoPitchDepth: number;
170
+ lfoFilterDepth: number;
171
+ lfoAmplitudeDepth: number;
172
+ };
134
173
  gainNode: any;
135
174
  pannerNode: any;
136
175
  modulationEffect: {
@@ -155,7 +194,6 @@ export class Midy {
155
194
  softPedal: number;
156
195
  rpnMSB: number;
157
196
  rpnLSB: number;
158
- channelPressure: number;
159
197
  pitchBendRange: number;
160
198
  currentBufferSource: null;
161
199
  volume: number;
@@ -216,10 +254,13 @@ export class Midy {
216
254
  connectNoteEffects(channel: any, gainNode: any): void;
217
255
  cbToRatio(cb: any): number;
218
256
  centToHz(cent: any): number;
257
+ calcSemitoneOffset(channel: any): any;
258
+ calcPlaybackRate(noteInfo: any, noteNumber: any, semitoneOffset: any): number;
219
259
  createNoteAudioChain(channel: any, noteInfo: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<{
220
260
  bufferSource: any;
221
261
  gainNode: any;
222
262
  filterNode: any;
263
+ lfoGain: any;
223
264
  }>;
224
265
  calcBank(channel: any, channelNumber: any): any;
225
266
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
@@ -232,7 +273,8 @@ export class Midy {
232
273
  handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
233
274
  handleProgramChange(channelNumber: any, program: any): void;
234
275
  handleChannelPressure(channelNumber: any, pressure: any): void;
235
- handlePitchBend(channelNumber: any, lsb: any, msb: any): void;
276
+ handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
277
+ handlePitchBend(channelNumber: any, pitchBend: any): void;
236
278
  handleControlChange(channelNumber: any, controller: any, value: any): any;
237
279
  setBankMSB(channelNumber: any, msb: any): void;
238
280
  setModulation(channelNumber: any, modulation: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAMA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAhED,qBAAmB;IACnB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,cAAa;IACb,cAAa;IACb,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA4CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA2GC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAsFC;IAED,gDAQC;IAED,kGAgDC;IAED,0EAGC;IAED,sIA6CC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,gEAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAUC;IAED,uDAGC;IAED,2DAOC;IAED,6DAOC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAMA;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;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiBC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EAyDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA2GC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,8EAEC;IAED;;;;;OAqFC;IAED,gDAQC;IAED,kGAgDC;IAED,0EAGC;IAED,sIA6CC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,gEAqBC;IAED,sFAcC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,0DAiBC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAUC;IAED,uDAGC;IAED,2DAOC;IAED,6DAOC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAQC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}