spessasynth_lib 3.26.5 → 3.26.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.
Files changed (34) hide show
  1. package/.idea/codeStyles/Project.xml +85 -0
  2. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  3. package/.idea/modules.xml +8 -0
  4. package/.idea/spessasynth_lib.iml +12 -0
  5. package/.idea/vcs.xml +7 -0
  6. package/index.js +7 -7
  7. package/package.json +1 -10
  8. package/{sequencer → src/sequencer}/README.md +2 -4
  9. package/{synthetizer → src/synthetizer}/README.md +2 -10
  10. package/{synthetizer → src/synthetizer}/worklet_processor.js +97 -90
  11. package/synthetizer/worklet_processor.min.js +10 -10
  12. package/synthetizer/worklet_processor.min.js.map +0 -7
  13. /package/{external_midi → src/external_midi}/README.md +0 -0
  14. /package/{external_midi → src/external_midi}/midi_handler.js +0 -0
  15. /package/{external_midi → src/external_midi}/web_midi_link.js +0 -0
  16. /package/{sequencer → src/sequencer}/default_sequencer_options.js +0 -0
  17. /package/{sequencer → src/sequencer}/midi_data.js +0 -0
  18. /package/{sequencer → src/sequencer}/sequencer.js +0 -0
  19. /package/{sequencer → src/sequencer}/sequencer_message.js +0 -0
  20. /package/{synthetizer → src/synthetizer}/audio_effects/effects_config.js +0 -0
  21. /package/{synthetizer → src/synthetizer}/audio_effects/fancy_chorus.js +0 -0
  22. /package/{synthetizer → src/synthetizer}/audio_effects/rb_compressed.min.js +0 -0
  23. /package/{synthetizer → src/synthetizer}/audio_effects/reverb.js +0 -0
  24. /package/{synthetizer → src/synthetizer}/audio_effects/reverb_as_binary.js +0 -0
  25. /package/{synthetizer → src/synthetizer}/key_modifier_manager.js +0 -0
  26. /package/{synthetizer → src/synthetizer}/sfman_message.js +0 -0
  27. /package/{synthetizer → src/synthetizer}/synth_event_handler.js +0 -0
  28. /package/{synthetizer → src/synthetizer}/synth_soundfont_manager.js +0 -0
  29. /package/{synthetizer → src/synthetizer}/synthetizer.js +0 -0
  30. /package/{synthetizer → src/synthetizer}/worklet_message.js +0 -0
  31. /package/{synthetizer → src/synthetizer}/worklet_url.js +0 -0
  32. /package/{utils → src/utils}/buffer_to_wav.js +0 -0
  33. /package/{utils → src/utils}/fill_with_defaults.js +0 -0
  34. /package/{utils → src/utils}/other.js +0 -0
@@ -0,0 +1,85 @@
1
+ <component name="ProjectCodeStyleConfiguration">
2
+ <code_scheme name="Project" version="173">
3
+ <option name="LINE_SEPARATOR" value="&#10;" />
4
+ <option name="DO_NOT_FORMAT">
5
+ <list>
6
+ <fileSet type="globPattern" pattern="*.md" />
7
+ </list>
8
+ </option>
9
+ <HTMLCodeStyleSettings>
10
+ <option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
11
+ <option name="HTML_QUOTE_STYLE" value="Single" />
12
+ <option name="HTML_ENFORCE_QUOTES" value="true" />
13
+ </HTMLCodeStyleSettings>
14
+ <JSCodeStyleSettings version="0">
15
+ <option name="FORCE_SEMICOLON_STYLE" value="true" />
16
+ <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
17
+ <option name="FORCE_QUOTE_STYlE" value="true" />
18
+ <option name="ENFORCE_TRAILING_COMMA" value="Remove" />
19
+ <option name="USE_EXPLICIT_JS_EXTENSION" value="ALWAYS_JS" />
20
+ <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
21
+ <option name="SPACES_WITHIN_IMPORTS" value="true" />
22
+ <option name="FUNCTION_EXPRESSION_BRACE_STYLE" value="2" />
23
+ </JSCodeStyleSettings>
24
+ <TypeScriptCodeStyleSettings version="0">
25
+ <option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
26
+ <option name="FORCE_SEMICOLON_STYLE" value="true" />
27
+ <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
28
+ <option name="USE_DOUBLE_QUOTES" value="false" />
29
+ <option name="FORCE_QUOTE_STYlE" value="true" />
30
+ <option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
31
+ <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
32
+ <option name="SPACES_WITHIN_IMPORTS" value="true" />
33
+ </TypeScriptCodeStyleSettings>
34
+ <VueCodeStyleSettings>
35
+ <option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
36
+ <option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
37
+ </VueCodeStyleSettings>
38
+ <codeStyleSettings language="HTML">
39
+ <option name="SOFT_MARGINS" value="120" />
40
+ <indentOptions>
41
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
42
+ </indentOptions>
43
+ </codeStyleSettings>
44
+ <codeStyleSettings language="JavaScript">
45
+ <option name="RIGHT_MARGIN" value="120" />
46
+ <option name="BRACE_STYLE" value="2" />
47
+ <option name="CLASS_BRACE_STYLE" value="2" />
48
+ <option name="METHOD_BRACE_STYLE" value="2" />
49
+ <option name="ELSE_ON_NEW_LINE" value="true" />
50
+ <option name="CATCH_ON_NEW_LINE" value="true" />
51
+ <option name="FINALLY_ON_NEW_LINE" value="true" />
52
+ <option name="CALL_PARAMETERS_WRAP" value="5" />
53
+ <option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
54
+ <option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
55
+ <option name="METHOD_CALL_CHAIN_WRAP" value="5" />
56
+ <option name="IF_BRACE_FORCE" value="3" />
57
+ <option name="DOWHILE_BRACE_FORCE" value="3" />
58
+ <option name="WHILE_BRACE_FORCE" value="3" />
59
+ <option name="FOR_BRACE_FORCE" value="3" />
60
+ <option name="SOFT_MARGINS" value="120" />
61
+ <indentOptions>
62
+ <option name="SMART_TABS" value="true" />
63
+ <option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
64
+ </indentOptions>
65
+ </codeStyleSettings>
66
+ <codeStyleSettings language="Markdown">
67
+ <indentOptions>
68
+ <option name="INDENT_SIZE" value="2" />
69
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
70
+ <option name="TAB_SIZE" value="2" />
71
+ <option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
72
+ </indentOptions>
73
+ </codeStyleSettings>
74
+ <codeStyleSettings language="TypeScript">
75
+ <option name="SOFT_MARGINS" value="120" />
76
+ </codeStyleSettings>
77
+ <codeStyleSettings language="Vue">
78
+ <option name="SOFT_MARGINS" value="120" />
79
+ <indentOptions>
80
+ <option name="INDENT_SIZE" value="4" />
81
+ <option name="TAB_SIZE" value="4" />
82
+ </indentOptions>
83
+ </codeStyleSettings>
84
+ </code_scheme>
85
+ </component>
@@ -0,0 +1,5 @@
1
+ <component name="ProjectCodeStyleConfiguration">
2
+ <state>
3
+ <option name="USE_PER_PROJECT_SETTINGS" value="true" />
4
+ </state>
5
+ </component>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/spessasynth_lib.iml" filepath="$PROJECT_DIR$/.idea/spessasynth_lib.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="WEB_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/.tmp" />
6
+ <excludeFolder url="file://$MODULE_DIR$/temp" />
7
+ <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
+ </content>
9
+ <orderEntry type="inheritedJdk" />
10
+ <orderEntry type="sourceFolder" forTests="false" />
11
+ </component>
12
+ </module>
package/.idea/vcs.xml ADDED
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ <mapping directory="$PROJECT_DIR$/spessasynth_lib.wiki" vcs="Git" />
6
+ </component>
7
+ </project>
package/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  // Import modules
2
2
 
3
- import { Synthetizer } from "./synthetizer/synthetizer.js";
4
- import { Sequencer } from "./sequencer/sequencer.js";
5
- import { audioBufferToWav } from "./utils/buffer_to_wav.js";
6
- import { MIDIDeviceHandler } from "./external_midi/midi_handler.js";
7
- import { WebMIDILinkHandler } from "./external_midi/web_midi_link.js";
8
- import { DEFAULT_SYNTH_CONFIG } from "./synthetizer/audio_effects/effects_config.js";
9
- import { WORKLET_URL_ABSOLUTE } from "./synthetizer/worklet_url.js";
3
+ import { Synthetizer } from "./src/synthetizer/synthetizer.js";
4
+ import { Sequencer } from "./src/sequencer/sequencer.js";
5
+ import { audioBufferToWav } from "./src/utils/buffer_to_wav.js";
6
+ import { MIDIDeviceHandler } from "./src/external_midi/midi_handler.js";
7
+ import { WebMIDILinkHandler } from "./src/external_midi/web_midi_link.js";
8
+ import { DEFAULT_SYNTH_CONFIG } from "./src/synthetizer/audio_effects/effects_config.js";
9
+ import { WORKLET_URL_ABSOLUTE } from "./src/synthetizer/worklet_url.js";
10
10
 
11
11
  // Export modules
12
12
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spessasynth_lib",
3
- "version": "3.26.5",
3
+ "version": "3.26.7",
4
4
  "description": "MIDI and SoundFont2/DLS library for the browsers with no compromises",
5
5
  "browser": "index.js",
6
6
  "type": "module",
@@ -41,15 +41,6 @@
41
41
  "email": "spesekspesek@gmail.com"
42
42
  },
43
43
  "homepage": "https://github.com/spessasus/spessasynth_lib#readme",
44
- "files": [
45
- "index.js",
46
- "LICENSE",
47
- "README.md",
48
- "sequencer",
49
- "synthetizer",
50
- "utils",
51
- "external_midi"
52
- ],
53
44
  "dependencies": {
54
45
  "spessasynth_core": "latest"
55
46
  }
@@ -1,8 +1,6 @@
1
1
  ## This is the sequencer's folder.
2
2
 
3
- The code here is responsible for playing back the parsed MIDI sequence with the synthesizer.
4
-
5
- - `sequencer_engine` - the core sequencer engine, currently runs in audio worklet
3
+ The code here is responsible for wrapping the `SpessaSynthSequencer` from `spessasynth_core`.
6
4
 
7
5
  ### Message protocol:
8
6
 
@@ -29,4 +27,4 @@ The `messageData` is set to the sequencer's return message.
29
27
 
30
28
  ### Process tick
31
29
 
32
- `processTick` is called every time the `process` method is called via `SpessaSynthProcessor.processTickCallback`.
30
+ `processTick` is called every time the `process` method is called via `sequencer.processTick()` every rendering quantum.
@@ -1,19 +1,11 @@
1
1
  ## This is the main synthesizer folder.
2
2
 
3
- The code here is responsible for making the actual sound.
4
- This is the heart of the SpessaSynth library.
5
-
6
- - `audio_engine` - the core synthesis engine, it theoretically can run on non-browser environments.
7
- - `audio_effects` - the WebAudioAPI audio effects.
8
- - `worklet_wrapper` - the wrapper for the core synthesis engine using audio worklets.
9
-
10
- `worklet_processor.min.js` - the minified worklet processor code to import.
11
-
3
+ The code here is responsible for wrapping `SpessaSynthProcessor` from `spessasynth_core`.
12
4
  # About the message protocol
13
5
  Since spessasynth_lib runs in the audioWorklet thread, here is an explanation of how it works:
14
6
 
15
7
  There's one processor per synthesizer, with a `MessagePort` for communication.
16
- Each processor has a single `SpessaSynthequencer` instance that is idle by default.
8
+ Each processor has a single `SpessaSynthSequencer` instance that is idle by default.
17
9
 
18
10
  The `Synthetizer`,
19
11
  `Sequencer` and `SoundFontManager` classes are all interfaces
@@ -2,6 +2,7 @@ import { consoleColors } from "../utils/other.js";
2
2
  import {
3
3
  ALL_CHANNELS_OR_DIFFERENT_ACTION,
4
4
  BasicMIDI,
5
+ loadSoundFont,
5
6
  masterParameterType,
6
7
  MIDI,
7
8
  MIDI_CHANNEL_COUNT,
@@ -88,105 +89,107 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
88
89
  * @type {SpessaSynthProcessor}
89
90
  */
90
91
  this.synthesizer = new SpessaSynthProcessor(
91
- opts.soundfont, // initial sound bank
92
- sampleRate, // AudioWorkletGlobalScope
92
+ sampleRate, // AudioWorkletGlobalScope
93
93
  {
94
- eventCall: (t, d) =>
95
- {
96
- postSyn(returnMessageType.eventCall, {
97
- eventName: t,
98
- eventData: d
99
- });
100
- },
101
- ready: this.postReady.bind(this),
102
- channelPropertyChange: (p, n) => postSyn(returnMessageType.channelPropertyChange, [n, p]),
103
- masterParameterChange: (t, v) => postSyn(returnMessageType.masterParameterChange, [t, v])
104
- },
105
- !this.oneOutputMode, // one output mode disables effects
106
- opts?.enableEventSystem, // enable message port?
107
- currentTime, // AudioWorkletGlobalScope, sync with audioContext time
108
- MIDI_CHANNEL_COUNT, // midi channel count (16)
109
- snapshot
94
+ effectsEnabled: !this.oneOutputMode, // one output mode disables effects
95
+ enableEventSystem: opts?.enableEventSystem, // enable message port?
96
+ midiChannels: MIDI_CHANNEL_COUNT, // midi channel count (16)
97
+ initialTime: currentTime // AudioWorkletGlobalScope, sync with audioContext time
98
+ }
110
99
  );
111
-
112
- // initialize the sequencer engine
113
- this.sequencer = new SpessaSynthSequencer(this.synthesizer);
114
-
115
- const postSeq = (type, data) =>
100
+ this.synthesizer.onEventCall = (t, d) =>
116
101
  {
117
- this.postMessageToMainThread({
118
- messageType: returnMessageType.sequencerSpecific,
119
- messageData: {
120
- messageType: type,
121
- messageData: data
122
- }
102
+ postSyn(returnMessageType.eventCall, {
103
+ eventName: t,
104
+ eventData: d
123
105
  });
124
106
  };
107
+ this.synthesizer.onChannelPropertyChange = (p, n) => postSyn(returnMessageType.channelPropertyChange, [n, p]);
108
+ this.synthesizer.onMasterParameterChange = (t, v) => postSyn(returnMessageType.masterParameterChange, [t, v]);
125
109
 
126
- // receive messages from the main thread
127
- this.port.onmessage = e => this.handleMessage(e.data);
110
+ const bank = loadSoundFont(opts.soundfont);
111
+ this.synthesizer.soundfontManager.reloadManager(bank);
128
112
 
129
- // sequencer events
130
- this.sequencer.onMIDIMessage = m =>
131
- {
132
- postSeq(SpessaSynthSequencerReturnMessageType.midiEvent, m);
133
- };
134
- this.sequencer.onTimeChange = t =>
135
- {
136
- postSeq(SpessaSynthSequencerReturnMessageType.timeChange, t);
137
- };
138
- this.sequencer.onPlaybackStop = p =>
139
- {
140
- postSeq(SpessaSynthSequencerReturnMessageType.pause, p);
141
- };
142
- this.sequencer.onSongChange = (i, a) =>
143
- {
144
- postSeq(SpessaSynthSequencerReturnMessageType.songChange, [i, a]);
145
- };
146
- this.sequencer.onMetaEvent = (e, i) =>
147
- {
148
- postSeq(SpessaSynthSequencerReturnMessageType.metaEvent, [e, i]);
149
- };
150
- this.sequencer.onLoopCountChange = c =>
151
- {
152
- postSeq(SpessaSynthSequencerReturnMessageType.loopCountChange, c);
153
- };
154
- this.sequencer.onSongListChange = l =>
155
- {
156
- const midiDataList = l.map(s => new MIDIData(s));
157
- this.postMessageToMainThread({
158
- messageType: returnMessageType.sequencerSpecific,
159
- messageData: {
160
- messageType: SpessaSynthSequencerReturnMessageType.songListChange,
161
- messageData: midiDataList
162
- }
163
- });
164
- };
165
-
166
- // if sent, start rendering
167
- if (startRenderingData)
113
+ this.synthesizer.processorInitialized.then(() =>
168
114
  {
115
+ // initialize the sequencer engine
116
+ this.sequencer = new SpessaSynthSequencer(this.synthesizer);
117
+
118
+ const postSeq = (type, data) =>
119
+ {
120
+ this.postMessageToMainThread({
121
+ messageType: returnMessageType.sequencerSpecific,
122
+ messageData: {
123
+ messageType: type,
124
+ messageData: data
125
+ }
126
+ });
127
+ };
128
+
129
+ // receive messages from the main thread
130
+ this.port.onmessage = e => this.handleMessage(e.data);
131
+
132
+ // sequencer events
133
+ this.sequencer.onMIDIMessage = m =>
134
+ {
135
+ postSeq(SpessaSynthSequencerReturnMessageType.midiEvent, m);
136
+ };
137
+ this.sequencer.onTimeChange = t =>
138
+ {
139
+ postSeq(SpessaSynthSequencerReturnMessageType.timeChange, t);
140
+ };
141
+ this.sequencer.onPlaybackStop = p =>
142
+ {
143
+ postSeq(SpessaSynthSequencerReturnMessageType.pause, p);
144
+ };
145
+ this.sequencer.onSongChange = (i, a) =>
146
+ {
147
+ postSeq(SpessaSynthSequencerReturnMessageType.songChange, [i, a]);
148
+ };
149
+ this.sequencer.onMetaEvent = (e, i) =>
150
+ {
151
+ postSeq(SpessaSynthSequencerReturnMessageType.metaEvent, [e, i]);
152
+ };
153
+ this.sequencer.onLoopCountChange = c =>
154
+ {
155
+ postSeq(SpessaSynthSequencerReturnMessageType.loopCountChange, c);
156
+ };
157
+ this.sequencer.onSongListChange = l =>
158
+ {
159
+ const midiDataList = l.map(s => new MIDIData(s));
160
+ this.postMessageToMainThread({
161
+ messageType: returnMessageType.sequencerSpecific,
162
+ messageData: {
163
+ messageType: SpessaSynthSequencerReturnMessageType.songListChange,
164
+ messageData: midiDataList
165
+ }
166
+ });
167
+ };
168
+
169
169
  if (snapshot !== undefined)
170
170
  {
171
171
  this.synthesizer.applySynthesizerSnapshot(snapshot);
172
172
  }
173
173
 
174
- util.SpessaSynthInfo("%cRendering enabled! Starting render.", consoleColors.info);
175
- if (startRenderingData.parsedMIDI)
174
+ // if sent, start rendering
175
+ if (startRenderingData)
176
176
  {
177
- if (startRenderingData?.loopCount !== undefined)
178
- {
179
- this.sequencer.loopCount = startRenderingData?.loopCount;
180
- this.sequencer.loop = true;
181
- }
182
- else
183
- {
184
- this.sequencer.loop = false;
185
- }
186
- // set voice cap to unlimited
187
- this.synthesizer.voiceCap = Infinity;
188
- this.synthesizer.processorInitialized.then(() =>
177
+
178
+ util.SpessaSynthInfo("%cRendering enabled! Starting render.", consoleColors.info);
179
+ if (startRenderingData.parsedMIDI)
189
180
  {
181
+ if (startRenderingData?.loopCount !== undefined)
182
+ {
183
+ this.sequencer.loopCount = startRenderingData?.loopCount;
184
+ this.sequencer.loop = true;
185
+ }
186
+ else
187
+ {
188
+ this.sequencer.loop = false;
189
+ }
190
+ // set voice cap to unlimited
191
+ this.synthesizer.voiceCap = Infinity;
192
+
190
193
  /**
191
194
  * set options
192
195
  * @type {SequencerOptions}
@@ -207,9 +210,11 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
207
210
  console.error(e);
208
211
  postSeq(SpessaSynthSequencerReturnMessageType.midiError, e);
209
212
  }
210
- });
213
+ }
211
214
  }
212
- }
215
+
216
+ this.postReady();
217
+ });
213
218
  }
214
219
 
215
220
  postReady()
@@ -316,7 +321,7 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
316
321
  break;
317
322
 
318
323
  case workletMessageType.addNewChannel:
319
- this.synthesizer.createWorkletChannel(true);
324
+ this.synthesizer.createMidiChannel(true);
320
325
  break;
321
326
 
322
327
  case workletMessageType.debugMessage:
@@ -493,10 +498,12 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
493
498
  const sfManager = this.synthesizer.soundfontManager;
494
499
  const type = data[0];
495
500
  const messageData = data[1];
501
+ let font;
496
502
  switch (type)
497
503
  {
498
504
  case WorkletSoundfontManagerMessageType.addNewSoundFont:
499
- sfManager.addNewSoundFont(messageData[0], messageData[1], messageData[2]);
505
+ font = loadSoundFont(messageData[0]);
506
+ sfManager.addNewSoundFont(font, messageData[1], messageData[2]);
500
507
  this.postMessageToMainThread({
501
508
  messageType: returnMessageType.isFullyInitialized,
502
509
  messageData: undefined
@@ -504,7 +511,8 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
504
511
  break;
505
512
 
506
513
  case WorkletSoundfontManagerMessageType.reloadSoundFont:
507
- sfManager.reloadManager(messageData);
514
+ font = loadSoundFont(messageData);
515
+ sfManager.reloadManager(font);
508
516
  this.postMessageToMainThread({
509
517
  messageType: returnMessageType.isFullyInitialized,
510
518
  messageData: undefined
@@ -526,7 +534,6 @@ class WorkletSpessaProcessor extends AudioWorkletProcessor
526
534
  messageData: e
527
535
  });
528
536
  }
529
- this.synthesizer.clearSoundFont(true, false);
530
537
  break;
531
538
 
532
539
  case workletMessageType.keyModifierManager: