@marmooo/midy 0.3.8 → 0.4.0
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 +6 -24
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +98 -51
- package/esm/midy-GM2.d.ts +6 -29
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +107 -60
- package/esm/midy-GMLite.d.ts +6 -24
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +100 -53
- package/esm/midy.d.ts +6 -30
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +107 -60
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +6 -24
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +98 -51
- package/script/midy-GM2.d.ts +6 -29
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +107 -60
- package/script/midy-GMLite.d.ts +6 -24
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +100 -53
- package/script/midy.d.ts +6 -30
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +107 -60
package/esm/midy-GMLite.js
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { parseMidi } from "midi-file";
|
|
2
2
|
import { parse, SoundFont } from "@marmooo/soundfont-parser";
|
|
3
3
|
class Note {
|
|
4
|
-
constructor(noteNumber, velocity, startTime
|
|
4
|
+
constructor(noteNumber, velocity, startTime) {
|
|
5
|
+
Object.defineProperty(this, "voice", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true,
|
|
9
|
+
value: void 0
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(this, "voiceParams", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
value: void 0
|
|
16
|
+
});
|
|
5
17
|
Object.defineProperty(this, "index", {
|
|
6
18
|
enumerable: true,
|
|
7
19
|
configurable: true,
|
|
@@ -14,6 +26,12 @@ class Note {
|
|
|
14
26
|
writable: true,
|
|
15
27
|
value: false
|
|
16
28
|
});
|
|
29
|
+
Object.defineProperty(this, "pending", {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
configurable: true,
|
|
32
|
+
writable: true,
|
|
33
|
+
value: true
|
|
34
|
+
});
|
|
17
35
|
Object.defineProperty(this, "bufferSource", {
|
|
18
36
|
enumerable: true,
|
|
19
37
|
configurable: true,
|
|
@@ -59,8 +77,6 @@ class Note {
|
|
|
59
77
|
this.noteNumber = noteNumber;
|
|
60
78
|
this.velocity = velocity;
|
|
61
79
|
this.startTime = startTime;
|
|
62
|
-
this.voice = voice;
|
|
63
|
-
this.voiceParams = voiceParams;
|
|
64
80
|
}
|
|
65
81
|
}
|
|
66
82
|
const drumExclusiveClasses = new Uint8Array(128);
|
|
@@ -227,6 +243,12 @@ export class MidyGMLite {
|
|
|
227
243
|
writable: true,
|
|
228
244
|
value: new Map()
|
|
229
245
|
});
|
|
246
|
+
Object.defineProperty(this, "realtimeVoiceCache", {
|
|
247
|
+
enumerable: true,
|
|
248
|
+
configurable: true,
|
|
249
|
+
writable: true,
|
|
250
|
+
value: new Map()
|
|
251
|
+
});
|
|
230
252
|
Object.defineProperty(this, "isPlaying", {
|
|
231
253
|
enumerable: true,
|
|
232
254
|
configurable: true,
|
|
@@ -465,10 +487,10 @@ export class MidyGMLite {
|
|
|
465
487
|
const startTime = event.startTime + schedulingOffset;
|
|
466
488
|
switch (event.type) {
|
|
467
489
|
case "noteOn":
|
|
468
|
-
await this.
|
|
490
|
+
await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
469
491
|
break;
|
|
470
492
|
case "noteOff": {
|
|
471
|
-
const notePromise = this.
|
|
493
|
+
const notePromise = this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
|
|
472
494
|
if (notePromise)
|
|
473
495
|
this.notePromises.push(notePromise);
|
|
474
496
|
break;
|
|
@@ -501,6 +523,7 @@ export class MidyGMLite {
|
|
|
501
523
|
this.exclusiveClassNotes.fill(undefined);
|
|
502
524
|
this.drumExclusiveClassNotes.fill(undefined);
|
|
503
525
|
this.voiceCache.clear();
|
|
526
|
+
this.realtimeVoiceCache.clear();
|
|
504
527
|
for (let i = 0; i < this.channels.length; i++) {
|
|
505
528
|
this.channels[i].scheduledNotes = [];
|
|
506
529
|
this.resetChannelStates(i);
|
|
@@ -538,7 +561,6 @@ export class MidyGMLite {
|
|
|
538
561
|
this.notePromises = [];
|
|
539
562
|
while (queueIndex < this.timeline.length) {
|
|
540
563
|
const now = this.audioContext.currentTime;
|
|
541
|
-
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
542
564
|
if (this.isPausing) {
|
|
543
565
|
await this.stopNotes(0, true, now);
|
|
544
566
|
await this.audioContext.suspend();
|
|
@@ -560,6 +582,7 @@ export class MidyGMLite {
|
|
|
560
582
|
this.isSeeking = false;
|
|
561
583
|
continue;
|
|
562
584
|
}
|
|
585
|
+
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
563
586
|
const waitTime = now + this.noteCheckInterval;
|
|
564
587
|
await this.scheduleTask(() => { }, waitTime);
|
|
565
588
|
}
|
|
@@ -637,7 +660,7 @@ export class MidyGMLite {
|
|
|
637
660
|
const channel = this.channels[channelNumber];
|
|
638
661
|
const promises = [];
|
|
639
662
|
this.processActiveNotes(channel, scheduleTime, (note) => {
|
|
640
|
-
const promise = this.
|
|
663
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
641
664
|
this.notePromises.push(promise);
|
|
642
665
|
promises.push(promise);
|
|
643
666
|
});
|
|
@@ -647,7 +670,7 @@ export class MidyGMLite {
|
|
|
647
670
|
const channel = this.channels[channelNumber];
|
|
648
671
|
const promises = [];
|
|
649
672
|
this.processScheduledNotes(channel, (note) => {
|
|
650
|
-
const promise = this.
|
|
673
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
651
674
|
this.notePromises.push(promise);
|
|
652
675
|
promises.push(promise);
|
|
653
676
|
});
|
|
@@ -680,7 +703,7 @@ export class MidyGMLite {
|
|
|
680
703
|
if (!this.isPlaying || this.isPaused)
|
|
681
704
|
return;
|
|
682
705
|
const now = this.audioContext.currentTime;
|
|
683
|
-
this.resumeTime
|
|
706
|
+
this.resumeTime = now - this.startTime - this.startDelay;
|
|
684
707
|
this.isPausing = true;
|
|
685
708
|
await this.playPromise;
|
|
686
709
|
this.isPausing = false;
|
|
@@ -706,11 +729,13 @@ export class MidyGMLite {
|
|
|
706
729
|
if (totalTime < event.startTime)
|
|
707
730
|
totalTime = event.startTime;
|
|
708
731
|
}
|
|
709
|
-
return totalTime;
|
|
732
|
+
return totalTime + this.startDelay;
|
|
710
733
|
}
|
|
711
734
|
currentTime() {
|
|
735
|
+
if (!this.isPlaying)
|
|
736
|
+
return this.resumeTime;
|
|
712
737
|
const now = this.audioContext.currentTime;
|
|
713
|
-
return
|
|
738
|
+
return now + this.resumeTime - this.startTime;
|
|
714
739
|
}
|
|
715
740
|
processScheduledNotes(channel, callback) {
|
|
716
741
|
const scheduledNotes = channel.scheduledNotes;
|
|
@@ -847,31 +872,42 @@ export class MidyGMLite {
|
|
|
847
872
|
note.modulationLFO.connect(note.volumeDepth);
|
|
848
873
|
note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
|
|
849
874
|
}
|
|
850
|
-
async getAudioBuffer(channel, noteNumber, velocity, voiceParams) {
|
|
875
|
+
async getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime) {
|
|
851
876
|
const audioBufferId = this.getVoiceId(channel, noteNumber, velocity);
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
this.voiceCache.delete(audioBufferId);
|
|
857
|
-
}
|
|
858
|
-
return cache.audioBuffer;
|
|
859
|
-
}
|
|
860
|
-
else {
|
|
861
|
-
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
877
|
+
if (realtime) {
|
|
878
|
+
const cachedAudioBuffer = this.realtimeVoiceCache.get(audioBufferId);
|
|
879
|
+
if (cachedAudioBuffer)
|
|
880
|
+
return cachedAudioBuffer;
|
|
862
881
|
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
863
|
-
|
|
864
|
-
this.voiceCache.set(audioBufferId, cache);
|
|
882
|
+
this.realtimeVoiceCache.set(audioBufferId, audioBuffer);
|
|
865
883
|
return audioBuffer;
|
|
866
884
|
}
|
|
885
|
+
else {
|
|
886
|
+
const cache = this.voiceCache.get(audioBufferId);
|
|
887
|
+
if (cache) {
|
|
888
|
+
cache.counter += 1;
|
|
889
|
+
if (cache.maxCount <= cache.counter) {
|
|
890
|
+
this.voiceCache.delete(audioBufferId);
|
|
891
|
+
}
|
|
892
|
+
return cache.audioBuffer;
|
|
893
|
+
}
|
|
894
|
+
else {
|
|
895
|
+
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
896
|
+
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
897
|
+
const cache = { audioBuffer, maxCount, counter: 1 };
|
|
898
|
+
this.voiceCache.set(audioBufferId, cache);
|
|
899
|
+
return audioBuffer;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
867
902
|
}
|
|
868
|
-
async
|
|
903
|
+
async setNoteAudioNode(channel, note, realtime) {
|
|
869
904
|
const now = this.audioContext.currentTime;
|
|
905
|
+
const { noteNumber, velocity, startTime } = note;
|
|
870
906
|
const state = channel.state;
|
|
871
907
|
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
872
|
-
const voiceParams = voice.getAllParams(controllerState);
|
|
873
|
-
|
|
874
|
-
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams);
|
|
908
|
+
const voiceParams = note.voice.getAllParams(controllerState);
|
|
909
|
+
note.voiceParams = voiceParams;
|
|
910
|
+
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime);
|
|
875
911
|
note.bufferSource = this.createBufferSource(channel, voiceParams, audioBuffer);
|
|
876
912
|
note.volumeEnvelopeNode = new GainNode(this.audioContext);
|
|
877
913
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
@@ -898,7 +934,7 @@ export class MidyGMLite {
|
|
|
898
934
|
if (prev) {
|
|
899
935
|
const [prevNote, prevChannelNumber] = prev;
|
|
900
936
|
if (prevNote && !prevNote.ending) {
|
|
901
|
-
this.
|
|
937
|
+
this.noteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
902
938
|
startTime, true);
|
|
903
939
|
}
|
|
904
940
|
}
|
|
@@ -914,13 +950,31 @@ export class MidyGMLite {
|
|
|
914
950
|
const index = drumExclusiveClass * this.channels.length + channelNumber;
|
|
915
951
|
const prevNote = this.drumExclusiveClassNotes[index];
|
|
916
952
|
if (prevNote && !prevNote.ending) {
|
|
917
|
-
this.
|
|
953
|
+
this.noteOff(channelNumber, prevNote.noteNumber, 0, // velocity,
|
|
918
954
|
startTime, true);
|
|
919
955
|
}
|
|
920
956
|
this.drumExclusiveClassNotes[index] = note;
|
|
921
957
|
}
|
|
922
|
-
|
|
958
|
+
setNoteRouting(channelNumber, note, startTime) {
|
|
959
|
+
const channel = this.channels[channelNumber];
|
|
960
|
+
const volumeEnvelopeNode = note.volumeEnvelopeNode;
|
|
961
|
+
volumeEnvelopeNode.connect(channel.gainL);
|
|
962
|
+
volumeEnvelopeNode.connect(channel.gainR);
|
|
963
|
+
if (0.5 <= channel.state.sustainPedal) {
|
|
964
|
+
channel.sustainNotes.push(note);
|
|
965
|
+
}
|
|
966
|
+
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
967
|
+
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
968
|
+
}
|
|
969
|
+
async noteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
923
970
|
const channel = this.channels[channelNumber];
|
|
971
|
+
const realtime = startTime === undefined;
|
|
972
|
+
if (realtime)
|
|
973
|
+
startTime = this.audioContext.currentTime;
|
|
974
|
+
const note = new Note(noteNumber, velocity, startTime);
|
|
975
|
+
const scheduledNotes = channel.scheduledNotes;
|
|
976
|
+
note.index = scheduledNotes.length;
|
|
977
|
+
scheduledNotes.push(note);
|
|
924
978
|
const programNumber = channel.programNumber;
|
|
925
979
|
const bankTable = this.soundFontTable[programNumber];
|
|
926
980
|
if (!bankTable)
|
|
@@ -930,24 +984,16 @@ export class MidyGMLite {
|
|
|
930
984
|
if (soundFontIndex === undefined)
|
|
931
985
|
return;
|
|
932
986
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
933
|
-
|
|
934
|
-
if (!voice)
|
|
987
|
+
note.voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
|
|
988
|
+
if (!note.voice)
|
|
935
989
|
return;
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
note.
|
|
939
|
-
|
|
940
|
-
|
|
990
|
+
await this.setNoteAudioNode(channel, note, realtime);
|
|
991
|
+
this.setNoteRouting(channelNumber, note, startTime);
|
|
992
|
+
note.pending = false;
|
|
993
|
+
const off = note.offEvent;
|
|
994
|
+
if (off) {
|
|
995
|
+
this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
|
|
941
996
|
}
|
|
942
|
-
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
943
|
-
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
944
|
-
const scheduledNotes = channel.scheduledNotes;
|
|
945
|
-
note.index = scheduledNotes.length;
|
|
946
|
-
scheduledNotes.push(note);
|
|
947
|
-
}
|
|
948
|
-
noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
949
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
950
|
-
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, undefined);
|
|
951
997
|
}
|
|
952
998
|
disconnectNote(note) {
|
|
953
999
|
note.bufferSource.disconnect();
|
|
@@ -960,6 +1006,7 @@ export class MidyGMLite {
|
|
|
960
1006
|
}
|
|
961
1007
|
}
|
|
962
1008
|
releaseNote(channel, note, endTime) {
|
|
1009
|
+
endTime ??= this.audioContext.currentTime;
|
|
963
1010
|
const volRelease = endTime + note.voiceParams.volRelease;
|
|
964
1011
|
const modRelease = endTime + note.voiceParams.modRelease;
|
|
965
1012
|
const stopTime = Math.min(volRelease, modRelease);
|
|
@@ -980,7 +1027,7 @@ export class MidyGMLite {
|
|
|
980
1027
|
}, stopTime);
|
|
981
1028
|
});
|
|
982
1029
|
}
|
|
983
|
-
|
|
1030
|
+
noteOff(channelNumber, noteNumber, velocity, endTime, force) {
|
|
984
1031
|
const channel = this.channels[channelNumber];
|
|
985
1032
|
if (!force) {
|
|
986
1033
|
if (channel.isDrum)
|
|
@@ -992,6 +1039,10 @@ export class MidyGMLite {
|
|
|
992
1039
|
if (index < 0)
|
|
993
1040
|
return;
|
|
994
1041
|
const note = channel.scheduledNotes[index];
|
|
1042
|
+
if (note.pending) {
|
|
1043
|
+
note.offEvent = { velocity, startTime: endTime };
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
995
1046
|
note.ending = true;
|
|
996
1047
|
this.setNoteIndex(channel, index);
|
|
997
1048
|
this.releaseNote(channel, note, endTime);
|
|
@@ -1022,16 +1073,12 @@ export class MidyGMLite {
|
|
|
1022
1073
|
}
|
|
1023
1074
|
return -1;
|
|
1024
1075
|
}
|
|
1025
|
-
noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
1026
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1027
|
-
return this.scheduleNoteOff(channelNumber, noteNumber, velocity, scheduleTime, false);
|
|
1028
|
-
}
|
|
1029
1076
|
releaseSustainPedal(channelNumber, halfVelocity, scheduleTime) {
|
|
1030
1077
|
const velocity = halfVelocity * 2;
|
|
1031
1078
|
const channel = this.channels[channelNumber];
|
|
1032
1079
|
const promises = [];
|
|
1033
1080
|
for (let i = 0; i < channel.sustainNotes.length; i++) {
|
|
1034
|
-
const promise = this.
|
|
1081
|
+
const promise = this.noteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
|
|
1035
1082
|
promises.push(promise);
|
|
1036
1083
|
}
|
|
1037
1084
|
channel.sustainNotes = [];
|
package/esm/midy.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export class Midy {
|
|
|
44
44
|
soundFontTable: never[][];
|
|
45
45
|
voiceCounter: Map<any, any>;
|
|
46
46
|
voiceCache: Map<any, any>;
|
|
47
|
+
realtimeVoiceCache: Map<any, any>;
|
|
47
48
|
isPlaying: boolean;
|
|
48
49
|
isPausing: boolean;
|
|
49
50
|
isPaused: boolean;
|
|
@@ -173,18 +174,17 @@ export class Midy {
|
|
|
173
174
|
setFilterEnvelope(channel: any, note: any, scheduleTime: any): void;
|
|
174
175
|
startModulation(channel: any, note: any, scheduleTime: any): void;
|
|
175
176
|
startVibrato(channel: any, note: any, scheduleTime: any): void;
|
|
176
|
-
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any): Promise<any>;
|
|
177
|
-
|
|
177
|
+
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any, realtime: any): Promise<any>;
|
|
178
|
+
setNoteAudioNode(channel: any, note: any, realtime: any): Promise<any>;
|
|
178
179
|
handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
179
180
|
handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
180
|
-
|
|
181
|
-
noteOn(channelNumber: any, noteNumber: any, velocity: any,
|
|
181
|
+
setNoteRouting(channelNumber: any, note: any, startTime: any): void;
|
|
182
|
+
noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
182
183
|
disconnectNote(note: any): void;
|
|
183
184
|
releaseNote(channel: any, note: any, endTime: any): Promise<any>;
|
|
184
|
-
|
|
185
|
+
noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): void;
|
|
185
186
|
setNoteIndex(channel: any, index: any): void;
|
|
186
187
|
findNoteOffIndex(channel: any, noteNumber: any): any;
|
|
187
|
-
noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): void;
|
|
188
188
|
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
|
|
189
189
|
releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
|
|
190
190
|
createMessageHandlers(): any[];
|
|
@@ -326,28 +326,4 @@ export class Midy {
|
|
|
326
326
|
handleSysEx(data: any, scheduleTime: any): void;
|
|
327
327
|
scheduleTask(callback: any, scheduleTime: any): Promise<any>;
|
|
328
328
|
}
|
|
329
|
-
declare class Note {
|
|
330
|
-
constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
|
|
331
|
-
index: number;
|
|
332
|
-
ending: boolean;
|
|
333
|
-
bufferSource: any;
|
|
334
|
-
filterNode: any;
|
|
335
|
-
filterDepth: any;
|
|
336
|
-
volumeEnvelopeNode: any;
|
|
337
|
-
volumeDepth: any;
|
|
338
|
-
modulationLFO: any;
|
|
339
|
-
modulationDepth: any;
|
|
340
|
-
vibratoLFO: any;
|
|
341
|
-
vibratoDepth: any;
|
|
342
|
-
reverbSend: any;
|
|
343
|
-
chorusSend: any;
|
|
344
|
-
portamentoNoteNumber: number;
|
|
345
|
-
pressure: number;
|
|
346
|
-
noteNumber: any;
|
|
347
|
-
velocity: any;
|
|
348
|
-
startTime: any;
|
|
349
|
-
voice: any;
|
|
350
|
-
voiceParams: any;
|
|
351
|
-
}
|
|
352
|
-
export {};
|
|
353
329
|
//# sourceMappingURL=midy.d.ts.map
|
package/esm/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|