@marmooo/midy 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -446,7 +446,7 @@ export class MidyGMLite {
446
446
  const startTime = event.startTime + this.startDelay - offset;
447
447
  switch (event.type) {
448
448
  case "noteOn":
449
- if (event.velocity !== 0) {
449
+ if (0 < event.velocity) {
450
450
  await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
451
451
  break;
452
452
  }
@@ -494,7 +494,7 @@ export class MidyGMLite {
494
494
  if (queueIndex >= this.timeline.length) {
495
495
  await Promise.all(this.notePromises);
496
496
  this.notePromises = [];
497
- this.exclusiveClassNotes.flll(undefined);
497
+ this.exclusiveClassNotes.fill(undefined);
498
498
  this.audioBufferCache.clear();
499
499
  resolve();
500
500
  return;
@@ -613,6 +613,17 @@ export class MidyGMLite {
613
613
  }
614
614
  return { instruments, timeline };
615
615
  }
616
+ stopActiveNotes(channelNumber, velocity, force, scheduleTime) {
617
+ const channel = this.channels[channelNumber];
618
+ const promises = [];
619
+ const activeNotes = this.getActiveNotes(channel, scheduleTime);
620
+ activeNotes.forEach((note) => {
621
+ const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force, undefined);
622
+ this.notePromises.push(promise);
623
+ promises.push(promise);
624
+ });
625
+ return Promise.all(promises);
626
+ }
616
627
  stopChannelNotes(channelNumber, velocity, force, scheduleTime) {
617
628
  const channel = this.channels[channelNumber];
618
629
  const promises = [];
@@ -684,6 +695,8 @@ export class MidyGMLite {
684
695
  const note = noteList[i];
685
696
  if (!note)
686
697
  continue;
698
+ if (note.ending)
699
+ continue;
687
700
  callback(note);
688
701
  }
689
702
  });
@@ -911,20 +924,21 @@ export class MidyGMLite {
911
924
  this.handleExclusiveClass(note, channelNumber, startTime);
912
925
  this.handleDrumExclusiveClass(note, channelNumber, startTime);
913
926
  const scheduledNotes = channel.scheduledNotes;
914
- let notes = scheduledNotes.get(noteNumber);
915
- if (notes) {
916
- notes.push(note);
927
+ let noteList = scheduledNotes.get(noteNumber);
928
+ if (noteList) {
929
+ noteList.push(note);
917
930
  }
918
931
  else {
919
- notes = [note];
920
- scheduledNotes.set(noteNumber, notes);
932
+ noteList = [note];
933
+ scheduledNotes.set(noteNumber, noteList);
921
934
  }
922
- if (this.isDrumNoteOffException(channel, noteNumber)) {
935
+ if (channel.isDrum) {
923
936
  const stopTime = startTime + note.bufferSource.buffer.duration;
924
- const index = notes.length - 1;
937
+ const index = noteList.length - 1;
925
938
  const promise = new Promise((resolve) => {
926
939
  note.bufferSource.onended = () => {
927
- this.disconnectNote(note, scheduledNotes, index);
940
+ noteList[index] = undefined;
941
+ this.disconnectNote(note);
928
942
  resolve();
929
943
  };
930
944
  note.bufferSource.stop(stopTime);
@@ -936,8 +950,7 @@ export class MidyGMLite {
936
950
  scheduleTime ??= this.audioContext.currentTime;
937
951
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime);
938
952
  }
939
- disconnectNote(note, scheduledNotes, index) {
940
- scheduledNotes[index] = null;
953
+ disconnectNote(note) {
941
954
  note.bufferSource.disconnect();
942
955
  note.filterNode.disconnect();
943
956
  note.volumeEnvelopeNode.disconnect();
@@ -947,8 +960,8 @@ export class MidyGMLite {
947
960
  note.modulationLFO.stop();
948
961
  }
949
962
  }
950
- stopNote(endTime, stopTime, scheduledNotes, index) {
951
- const note = scheduledNotes[index];
963
+ stopNote(endTime, stopTime, noteList, index) {
964
+ const note = noteList[index];
952
965
  note.volumeEnvelopeNode.gain
953
966
  .cancelScheduledValues(endTime)
954
967
  .linearRampToValueAtTime(0, stopTime);
@@ -958,12 +971,23 @@ export class MidyGMLite {
958
971
  }, stopTime);
959
972
  return new Promise((resolve) => {
960
973
  note.bufferSource.onended = () => {
961
- this.disconnectNote(note, scheduledNotes, index);
974
+ noteList[index] = undefined;
975
+ this.disconnectNote(note);
962
976
  resolve();
963
977
  };
964
978
  note.bufferSource.stop(stopTime);
965
979
  });
966
980
  }
981
+ findNoteOffTarget(noteList) {
982
+ for (let i = 0; i < noteList.length; i++) {
983
+ const note = noteList[i];
984
+ if (!note)
985
+ continue;
986
+ if (note.ending)
987
+ continue;
988
+ return [note, i];
989
+ }
990
+ }
967
991
  scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force) {
968
992
  const channel = this.channels[channelNumber];
969
993
  if (channel.isDrum)
@@ -972,21 +996,20 @@ export class MidyGMLite {
972
996
  return;
973
997
  if (!channel.scheduledNotes.has(noteNumber))
974
998
  return;
975
- const scheduledNotes = channel.scheduledNotes.get(noteNumber);
976
- for (let i = 0; i < scheduledNotes.length; i++) {
977
- const note = scheduledNotes[i];
978
- if (!note)
979
- continue;
980
- if (note.ending)
981
- continue;
982
- const volRelease = endTime + note.voiceParams.volRelease;
983
- const modRelease = endTime + note.voiceParams.modRelease;
984
- note.filterNode.frequency
985
- .cancelScheduledValues(endTime)
986
- .linearRampToValueAtTime(0, modRelease);
987
- const stopTime = Math.min(volRelease, modRelease);
988
- return this.stopNote(endTime, stopTime, scheduledNotes, i);
989
- }
999
+ const noteList = channel.scheduledNotes.get(noteNumber);
1000
+ if (!noteList)
1001
+ return; // be careful with drum channel
1002
+ const noteOffTarget = this.findNoteOffTarget(noteList, endTime);
1003
+ if (!noteOffTarget)
1004
+ return;
1005
+ const [note, i] = noteOffTarget;
1006
+ const volRelease = endTime + note.voiceParams.volRelease;
1007
+ const modRelease = endTime + note.voiceParams.modRelease;
1008
+ note.filterNode.frequency
1009
+ .cancelScheduledValues(endTime)
1010
+ .linearRampToValueAtTime(0, modRelease);
1011
+ const stopTime = Math.min(volRelease, modRelease);
1012
+ return this.stopNote(endTime, stopTime, noteList, i);
990
1013
  }
991
1014
  noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
992
1015
  scheduleTime ??= this.audioContext.currentTime;
@@ -1308,7 +1331,7 @@ export class MidyGMLite {
1308
1331
  }
1309
1332
  allSoundOff(channelNumber, _value, scheduleTime) {
1310
1333
  scheduleTime ??= this.audioContext.currentTime;
1311
- return this.stopChannelNotes(channelNumber, 0, true, scheduleTime);
1334
+ return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
1312
1335
  }
1313
1336
  resetAllStates(channelNumber) {
1314
1337
  const channel = this.channels[channelNumber];
@@ -1346,7 +1369,7 @@ export class MidyGMLite {
1346
1369
  }
1347
1370
  allNotesOff(channelNumber, _value, scheduleTime) {
1348
1371
  scheduleTime ??= this.audioContext.currentTime;
1349
- return this.stopChannelNotes(channelNumber, 0, false, scheduleTime);
1372
+ return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
1350
1373
  }
1351
1374
  handleUniversalNonRealTimeExclusiveMessage(data, scheduleTime) {
1352
1375
  switch (data[2]) {
package/esm/midy.d.ts CHANGED
@@ -99,7 +99,7 @@ export class Midy {
99
99
  66: (channelNumber: any, value: any, scheduleTime: any) => void;
100
100
  67: (channelNumber: any, softPedal: any, scheduleTime: any) => void;
101
101
  71: (channelNumber: any, filterResonance: any, scheduleTime: any) => void;
102
- 72: (channelNumber: any, releaseTime: any, _scheduleTime: any) => void;
102
+ 72: (channelNumber: any, releaseTime: any, scheduleTime: any) => void;
103
103
  73: (channelNumber: any, attackTime: any, scheduleTime: any) => void;
104
104
  74: (channelNumber: any, brightness: any, scheduleTime: any) => void;
105
105
  75: (channelNumber: any, dacayTime: any, scheduleTime: any) => void;
@@ -157,6 +157,7 @@ export class Midy {
157
157
  instruments: Set<any>;
158
158
  timeline: any[];
159
159
  };
160
+ stopActiveNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
160
161
  stopChannelNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
161
162
  stopNotes(velocity: any, force: any, scheduleTime: any): Promise<any[]>;
162
163
  start(): Promise<void>;
@@ -216,8 +217,9 @@ export class Midy {
216
217
  isDrumNoteOffException(channel: any, noteNumber: any): boolean;
217
218
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
218
219
  noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
219
- disconnectNote(note: any, scheduledNotes: any, index: any): void;
220
- stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
220
+ disconnectNote(note: any): void;
221
+ stopNote(endTime: any, stopTime: any, noteList: any, index: any): Promise<any>;
222
+ findNoteOffTarget(noteList: any): any[] | undefined;
221
223
  scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any, portamentoNoteNumber: any): Promise<any> | undefined;
222
224
  noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<any> | undefined;
223
225
  releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
@@ -266,7 +268,7 @@ export class Midy {
266
268
  66: (channelNumber: any, value: any, scheduleTime: any) => void;
267
269
  67: (channelNumber: any, softPedal: any, scheduleTime: any) => void;
268
270
  71: (channelNumber: any, filterResonance: any, scheduleTime: any) => void;
269
- 72: (channelNumber: any, releaseTime: any, _scheduleTime: any) => void;
271
+ 72: (channelNumber: any, releaseTime: any, scheduleTime: any) => void;
270
272
  73: (channelNumber: any, attackTime: any, scheduleTime: any) => void;
271
273
  74: (channelNumber: any, brightness: any, scheduleTime: any) => void;
272
274
  75: (channelNumber: any, dacayTime: any, scheduleTime: any) => void;
@@ -309,7 +311,7 @@ export class Midy {
309
311
  setSostenutoPedal(channelNumber: any, value: any, scheduleTime: any): void;
310
312
  setSoftPedal(channelNumber: any, softPedal: any, scheduleTime: any): void;
311
313
  setFilterResonance(channelNumber: any, filterResonance: any, scheduleTime: any): void;
312
- setReleaseTime(channelNumber: any, releaseTime: any, _scheduleTime: any): void;
314
+ setReleaseTime(channelNumber: any, releaseTime: any, scheduleTime: any): void;
313
315
  setAttackTime(channelNumber: any, attackTime: any, scheduleTime: any): void;
314
316
  setBrightness(channelNumber: any, brightness: any, scheduleTime: any): void;
315
317
  setDecayTime(channelNumber: any, dacayTime: any, scheduleTime: any): void;
package/esm/midy.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
package/esm/midy.js CHANGED
@@ -626,7 +626,7 @@ export class Midy {
626
626
  const startTime = event.startTime + this.startDelay - offset;
627
627
  switch (event.type) {
628
628
  case "noteOn":
629
- if (event.velocity !== 0) {
629
+ if (0 < event.velocity) {
630
630
  await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime, event.portamento);
631
631
  break;
632
632
  }
@@ -842,6 +842,17 @@ export class Midy {
842
842
  }
843
843
  return { instruments, timeline };
844
844
  }
845
+ stopActiveNotes(channelNumber, velocity, force, scheduleTime) {
846
+ const channel = this.channels[channelNumber];
847
+ const promises = [];
848
+ const activeNotes = this.getActiveNotes(channel, scheduleTime);
849
+ activeNotes.forEach((note) => {
850
+ const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force, undefined);
851
+ this.notePromises.push(promise);
852
+ promises.push(promise);
853
+ });
854
+ return Promise.all(promises);
855
+ }
845
856
  stopChannelNotes(channelNumber, velocity, force, scheduleTime) {
846
857
  const channel = this.channels[channelNumber];
847
858
  const promises = [];
@@ -913,6 +924,8 @@ export class Midy {
913
924
  const note = noteList[i];
914
925
  if (!note)
915
926
  continue;
927
+ if (note.ending)
928
+ continue;
916
929
  callback(note);
917
930
  }
918
931
  });
@@ -1282,7 +1295,7 @@ export class Midy {
1282
1295
  type: "lowpass",
1283
1296
  Q: voiceParams.initialFilterQ / 5 * state.filterResonance, // dB
1284
1297
  });
1285
- if (portamento) {
1298
+ if (0.5 <= state.portamento && portamento) {
1286
1299
  note.portamento = true;
1287
1300
  this.setPortamentoStartVolumeEnvelope(channel, note, now);
1288
1301
  this.setPortamentoStartFilterEnvelope(channel, note, now);
@@ -1372,8 +1385,8 @@ export class Midy {
1372
1385
  if (!channel.isDrum)
1373
1386
  return false;
1374
1387
  const programNumber = channel.programNumber;
1375
- return (programNumber === 48 && noteNumber === 88) ||
1376
- (programNumber === 56 && 47 <= noteNumber && noteNumber <= 84);
1388
+ return !((programNumber === 48 && noteNumber === 88) ||
1389
+ (programNumber === 56 && 47 <= noteNumber && noteNumber <= 84));
1377
1390
  }
1378
1391
  async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, portamento) {
1379
1392
  const channel = this.channels[channelNumber];
@@ -1395,20 +1408,21 @@ export class Midy {
1395
1408
  this.handleExclusiveClass(note, channelNumber, startTime);
1396
1409
  this.handleDrumExclusiveClass(note, channelNumber, startTime);
1397
1410
  const scheduledNotes = channel.scheduledNotes;
1398
- let notes = scheduledNotes.get(noteNumber);
1399
- if (notes) {
1400
- notes.push(note);
1411
+ let noteList = scheduledNotes.get(noteNumber);
1412
+ if (noteList) {
1413
+ noteList.push(note);
1401
1414
  }
1402
1415
  else {
1403
- notes = [note];
1404
- scheduledNotes.set(noteNumber, notes);
1416
+ noteList = [note];
1417
+ scheduledNotes.set(noteNumber, noteList);
1405
1418
  }
1406
1419
  if (this.isDrumNoteOffException(channel, noteNumber)) {
1407
1420
  const stopTime = startTime + note.bufferSource.buffer.duration;
1408
- const index = notes.length - 1;
1421
+ const index = noteList.length - 1;
1409
1422
  const promise = new Promise((resolve) => {
1410
1423
  note.bufferSource.onended = () => {
1411
- this.disconnectNote(note, scheduledNotes, index);
1424
+ noteList[index] = undefined;
1425
+ this.disconnectNote(note);
1412
1426
  resolve();
1413
1427
  };
1414
1428
  note.bufferSource.stop(stopTime);
@@ -1420,8 +1434,7 @@ export class Midy {
1420
1434
  scheduleTime ??= this.audioContext.currentTime;
1421
1435
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, false);
1422
1436
  }
1423
- disconnectNote(note, scheduledNotes, index) {
1424
- scheduledNotes[index] = null;
1437
+ disconnectNote(note) {
1425
1438
  note.bufferSource.disconnect();
1426
1439
  note.filterNode.disconnect();
1427
1440
  note.volumeEnvelopeNode.disconnect();
@@ -1444,8 +1457,8 @@ export class Midy {
1444
1457
  note.chorusEffectsSend.disconnect();
1445
1458
  }
1446
1459
  }
1447
- stopNote(endTime, stopTime, scheduledNotes, index) {
1448
- const note = scheduledNotes[index];
1460
+ stopNote(endTime, stopTime, noteList, index) {
1461
+ const note = noteList[index];
1449
1462
  note.volumeEnvelopeNode.gain
1450
1463
  .cancelScheduledValues(endTime)
1451
1464
  .linearRampToValueAtTime(0, stopTime);
@@ -1455,12 +1468,23 @@ export class Midy {
1455
1468
  }, stopTime);
1456
1469
  return new Promise((resolve) => {
1457
1470
  note.bufferSource.onended = () => {
1458
- this.disconnectNote(note, scheduledNotes, index);
1471
+ noteList[index] = undefined;
1472
+ this.disconnectNote(note);
1459
1473
  resolve();
1460
1474
  };
1461
1475
  note.bufferSource.stop(stopTime);
1462
1476
  });
1463
1477
  }
1478
+ findNoteOffTarget(noteList) {
1479
+ for (let i = 0; i < noteList.length; i++) {
1480
+ const note = noteList[i];
1481
+ if (!note)
1482
+ continue;
1483
+ if (note.ending)
1484
+ continue;
1485
+ return [note, i];
1486
+ }
1487
+ }
1464
1488
  scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force, portamentoNoteNumber) {
1465
1489
  const channel = this.channels[channelNumber];
1466
1490
  if (this.isDrumNoteOffException(channel, noteNumber))
@@ -1472,35 +1496,32 @@ export class Midy {
1472
1496
  if (channel.sostenutoNotes.has(noteNumber))
1473
1497
  return;
1474
1498
  }
1475
- if (!channel.scheduledNotes.has(noteNumber))
1499
+ const noteList = channel.scheduledNotes.get(noteNumber);
1500
+ if (!noteList)
1501
+ return; // be careful with drum channel
1502
+ const noteOffTarget = this.findNoteOffTarget(noteList, endTime);
1503
+ if (!noteOffTarget)
1476
1504
  return;
1477
- const scheduledNotes = channel.scheduledNotes.get(noteNumber);
1478
- for (let i = 0; i < scheduledNotes.length; i++) {
1479
- const note = scheduledNotes[i];
1480
- if (!note)
1481
- continue;
1482
- if (note.ending)
1483
- continue;
1484
- if (portamentoNoteNumber === undefined) {
1485
- const volRelease = endTime +
1486
- note.voiceParams.volRelease * state.releaseTime * 2;
1487
- const modRelease = endTime + note.voiceParams.modRelease;
1488
- note.filterNode.frequency
1489
- .cancelScheduledValues(endTime)
1490
- .linearRampToValueAtTime(0, modRelease);
1491
- const stopTime = Math.min(volRelease, modRelease);
1492
- return this.stopNote(endTime, stopTime, scheduledNotes, i);
1493
- }
1494
- else {
1495
- const portamentoTime = endTime + this.getPortamentoTime(channel);
1496
- const deltaNote = portamentoNoteNumber - noteNumber;
1497
- const baseRate = note.voiceParams.playbackRate;
1498
- const targetRate = baseRate * Math.pow(2, deltaNote / 12);
1499
- note.bufferSource.playbackRate
1500
- .cancelScheduledValues(endTime)
1501
- .linearRampToValueAtTime(targetRate, portamentoTime);
1502
- return this.stopNote(endTime, portamentoTime, scheduledNotes, i);
1503
- }
1505
+ const [note, i] = noteOffTarget;
1506
+ if (0.5 <= state.portamento && portamentoNoteNumber !== undefined) {
1507
+ const portamentoTime = endTime + this.getPortamentoTime(channel);
1508
+ const deltaNote = portamentoNoteNumber - noteNumber;
1509
+ const baseRate = note.voiceParams.playbackRate;
1510
+ const targetRate = baseRate * Math.pow(2, deltaNote / 12);
1511
+ note.bufferSource.playbackRate
1512
+ .cancelScheduledValues(endTime)
1513
+ .linearRampToValueAtTime(targetRate, portamentoTime);
1514
+ return this.stopNote(endTime, portamentoTime, noteList, i);
1515
+ }
1516
+ else {
1517
+ const volRelease = endTime +
1518
+ note.voiceParams.volRelease * state.releaseTime * 2;
1519
+ const modRelease = endTime + note.voiceParams.modRelease;
1520
+ note.filterNode.frequency
1521
+ .cancelScheduledValues(endTime)
1522
+ .linearRampToValueAtTime(0, modRelease);
1523
+ const stopTime = Math.min(volRelease, modRelease);
1524
+ return this.stopNote(endTime, stopTime, noteList, i);
1504
1525
  }
1505
1526
  }
1506
1527
  noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
@@ -1562,7 +1583,7 @@ export class Midy {
1562
1583
  const note = activeNotes.get(noteNumber);
1563
1584
  this.setControllerParameters(channel, note, table);
1564
1585
  }
1565
- // this.applyVoiceParams(channel, 10);
1586
+ this.applyVoiceParams(channel, 10);
1566
1587
  }
1567
1588
  handleProgramChange(channelNumber, programNumber, _scheduleTime) {
1568
1589
  const channel = this.channels[channelNumber];
@@ -1594,7 +1615,7 @@ export class Midy {
1594
1615
  this.getActiveNotes(channel, scheduleTime).forEach((note) => {
1595
1616
  this.setControllerParameters(channel, note, table);
1596
1617
  });
1597
- // this.applyVoiceParams(channel, 13);
1618
+ this.applyVoiceParams(channel, 13);
1598
1619
  }
1599
1620
  handlePitchBendMessage(channelNumber, lsb, msb, scheduleTime) {
1600
1621
  const pitchBend = msb * 128 + lsb;
@@ -1771,6 +1792,8 @@ export class Midy {
1771
1792
  state.set(channel.state.array);
1772
1793
  state[2] = velocity / 127;
1773
1794
  state[3] = noteNumber / 127;
1795
+ state[10] = state.polyphonicKeyPressure / 127;
1796
+ state[13] = state.channelPressure / 127;
1774
1797
  return state;
1775
1798
  }
1776
1799
  applyVoiceParams(channel, controllerType, scheduleTime) {
@@ -1797,7 +1820,7 @@ export class Midy {
1797
1820
  if (key in voiceParams)
1798
1821
  noteVoiceParams[key] = voiceParams[key];
1799
1822
  }
1800
- if (note.portamento) {
1823
+ if (0.5 <= channel.state.portamento && note.portamento) {
1801
1824
  this.setPortamentoStartFilterEnvelope(channel, note, scheduleTime);
1802
1825
  }
1803
1826
  else {
@@ -2004,10 +2027,11 @@ export class Midy {
2004
2027
  const channel = this.channels[channelNumber];
2005
2028
  if (channel.isDrum)
2006
2029
  return;
2030
+ const state = channel.state;
2007
2031
  scheduleTime ??= this.audioContext.currentTime;
2008
- channel.state.softPedal = softPedal / 127;
2032
+ state.softPedal = softPedal / 127;
2009
2033
  this.processScheduledNotes(channel, (note) => {
2010
- if (note.portamento) {
2034
+ if (0.5 <= state.portamento && note.portamento) {
2011
2035
  this.setPortamentoStartVolumeEnvelope(channel, note, scheduleTime);
2012
2036
  this.setPortamentoStartFilterEnvelope(channel, note, scheduleTime);
2013
2037
  }
@@ -2029,7 +2053,7 @@ export class Midy {
2029
2053
  note.filterNode.Q.setValueAtTime(Q, scheduleTime);
2030
2054
  });
2031
2055
  }
2032
- setReleaseTime(channelNumber, releaseTime, _scheduleTime) {
2056
+ setReleaseTime(channelNumber, releaseTime, scheduleTime) {
2033
2057
  const channel = this.channels[channelNumber];
2034
2058
  if (channel.isDrum)
2035
2059
  return;
@@ -2052,10 +2076,11 @@ export class Midy {
2052
2076
  const channel = this.channels[channelNumber];
2053
2077
  if (channel.isDrum)
2054
2078
  return;
2079
+ const state = channel.state;
2055
2080
  scheduleTime ??= this.audioContext.currentTime;
2056
- channel.state.brightness = brightness / 64;
2081
+ state.brightness = brightness / 64;
2057
2082
  this.processScheduledNotes(channel, (note) => {
2058
- if (note.portamento) {
2083
+ if (0.5 <= state.portamento && note.portamento) {
2059
2084
  this.setPortamentoStartFilterEnvelope(channel, note, scheduleTime);
2060
2085
  }
2061
2086
  else {
@@ -2316,7 +2341,7 @@ export class Midy {
2316
2341
  }
2317
2342
  allSoundOff(channelNumber, _value, scheduleTime) {
2318
2343
  scheduleTime ??= this.audioContext.currentTime;
2319
- return this.stopChannelNotes(channelNumber, 0, true, scheduleTime);
2344
+ return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
2320
2345
  }
2321
2346
  resetAllStates(channelNumber) {
2322
2347
  const channel = this.channels[channelNumber];
@@ -2361,7 +2386,7 @@ export class Midy {
2361
2386
  }
2362
2387
  allNotesOff(channelNumber, _value, scheduleTime) {
2363
2388
  scheduleTime ??= this.audioContext.currentTime;
2364
- return this.stopChannelNotes(channelNumber, 0, false, scheduleTime);
2389
+ return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
2365
2390
  }
2366
2391
  omniOff(channelNumber, value, scheduleTime) {
2367
2392
  this.allNotesOff(channelNumber, value, scheduleTime);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marmooo/midy",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "A MIDI player/synthesizer written in JavaScript that supports GM-Lite/GM1 and SF2/SF3.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -87,6 +87,7 @@ export class MidyGM1 {
87
87
  instruments: Set<any>;
88
88
  timeline: any[];
89
89
  };
90
+ stopActiveNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
90
91
  stopChannelNotes(channelNumber: any, velocity: any, force: any, scheduleTime: any): Promise<any[]>;
91
92
  stopNotes(velocity: any, force: any, scheduleTime: any): Promise<any[]>;
92
93
  start(): Promise<void>;
@@ -116,8 +117,9 @@ export class MidyGM1 {
116
117
  handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
117
118
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
118
119
  noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
119
- disconnectNote(note: any, scheduledNotes: any, index: any): void;
120
- stopNote(endTime: any, stopTime: any, scheduledNotes: any, index: any): Promise<any>;
120
+ disconnectNote(note: any): void;
121
+ stopNote(endTime: any, stopTime: any, noteList: any, index: any): Promise<any>;
122
+ findNoteOffTarget(noteList: any): any[] | undefined;
121
123
  scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): Promise<any> | undefined;
122
124
  noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<any> | undefined;
123
125
  releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAiJA;IAwBE;;;;;;;;;;;MAWE;IAEF,+BAcC;IAlDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,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,2BAAqC;IAgBnC,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAMnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAaC;IAED,6DA2BC;IAED,4DASC;IAED,2EAsDC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,mGAgBC;IAED,wEAMC;IAED,uBAKC;IAED,aAMC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDAQC;IAED,2DASC;IAED,qDAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAMC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,+GA0BC;IAED,gHAwCC;IAED,0EAiBC;IAED,kGAqCC;IAED,6FAQC;IAED,iEAUC;IAED,qFAgBC;IAED,yHAuBC;IAED,yGASC;IAED,4GAeC;IAED,mGA2BC;IAED,sFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAQC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MA2BC;IAED,oFAMC;IAED,6EA2CC;IAED;;;;;;;;;;;;;MAeC;IAED,kGAWC;IAED,wDAUC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,2DAMC;IAED,uDAkBC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,iEAKC;IAED,uEAQC;IAED,mEAKC;IAED,yEAQC;IAED,gFAGC;IAED,yCAUC;IAGD,8CAqBC;IAED,gFAGC;IAED,+EAgBC;IAED,qCAWC;IAED,4EAaC;IAED,4DAGC;IAED,sDASC;IAED,gDAYC;IAGD,6DAgBC;CACF;AA99CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IASE,0FAMC;IAdD,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
1
+ {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAiJA;IAwBE;;;;;;;;;;;MAWE;IAEF,+BAcC;IAlDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,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,2BAAqC;IAgBnC,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAMnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAaC;IAED,6DA2BC;IAED,4DASC;IAED,2EAsDC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,kGAiBC;IAED,mGAgBC;IAED,wEAMC;IAED,uBAKC;IAED,aAMC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDASC;IAED,2DASC;IAED,qDAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAMC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,+GA0BC;IAED,gHAwCC;IAED,0EAiBC;IAED,kGAsCC;IAED,6FAQC;IAED,gCASC;IAED,+EAiBC;IAED,oDAOC;IAED,yHAsBC;IAED,yGASC;IAED,4GAeC;IAED,mGA2BC;IAED,sFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAQC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MA2BC;IAED,oFAMC;IAED,6EA2CC;IAED;;;;;;;;;;;;;MAeC;IAED,kGAWC;IAED,wDAUC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,2DAMC;IAED,uDAkBC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,iEAKC;IAED,uEAQC;IAED,mEAKC;IAED,yEAQC;IAED,gFAGC;IAED,yCAUC;IAGD,8CAqBC;IAED,gFAGC;IAED,+EAgBC;IAED,qCAWC;IAED,4EAaC;IAED,4DAGC;IAED,sDASC;IAED,gDAYC;IAGD,6DAgBC;CACF;AA3/CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IASE,0FAMC;IAdD,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}