spessasynth_lib 3.25.7 → 3.25.9
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/midi_parser/README.md +29 -1
- package/midi_parser/basic_midi.js +15 -37
- package/midi_parser/midi_data.js +1 -23
- package/midi_parser/midi_loader.js +4 -3
- package/midi_parser/midi_sequence.js +45 -0
- package/package.json +1 -1
- package/soundfont/basic_soundfont/basic_soundfont.js +8 -2
- package/synthetizer/synthetizer.js +25 -5
- package/synthetizer/worklet_processor.min.js +11 -11
- package/synthetizer/worklet_system/main_processor.js +10 -11
- package/synthetizer/worklet_system/message_protocol/message_sending.js +0 -42
- package/synthetizer/worklet_system/message_protocol/worklet_message.js +5 -6
- package/synthetizer/worklet_system/worklet_methods/create_worklet_channel.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/mute_channel.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/note_on.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/program_change.js +11 -2
- package/synthetizer/worklet_system/worklet_methods/stopping_notes/stop_all_notes.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/tuning_control/pitch_wheel.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/tuning_control/transpose_channel.js +1 -1
- package/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +53 -2
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js";
|
|
11
11
|
import { VOLUME_ENVELOPE_SMOOTHING_FACTOR } from "./worklet_utilities/volume_envelope.js";
|
|
12
12
|
import { handleMessage } from "./message_protocol/handle_message.js";
|
|
13
|
-
import { callEvent
|
|
13
|
+
import { callEvent } from "./message_protocol/message_sending.js";
|
|
14
14
|
import { systemExclusive } from "./worklet_methods/system_exclusive.js";
|
|
15
15
|
import { setMasterGain, setMasterPan, setMIDIVolume } from "./worklet_methods/controller_control/master_parameters.js";
|
|
16
16
|
import { resetAllControllers } from "./worklet_methods/controller_control/reset_controllers.js";
|
|
@@ -437,7 +437,7 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
437
437
|
this.sequencer.processTick();
|
|
438
438
|
|
|
439
439
|
// for every channel
|
|
440
|
-
|
|
440
|
+
this.totalVoicesAmount = 0;
|
|
441
441
|
this.workletProcessorChannels.forEach((channel, index) =>
|
|
442
442
|
{
|
|
443
443
|
if (channel.voices.length < 1 || channel.isMuted)
|
|
@@ -445,6 +445,7 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
445
445
|
// skip the channels
|
|
446
446
|
return;
|
|
447
447
|
}
|
|
448
|
+
let voiceCount = channel.voices.length;
|
|
448
449
|
let outputIndex;
|
|
449
450
|
let outputL;
|
|
450
451
|
let outputR;
|
|
@@ -480,15 +481,14 @@ class SpessaSynthProcessor extends AudioWorkletProcessor
|
|
|
480
481
|
chorusL, chorusR
|
|
481
482
|
);
|
|
482
483
|
|
|
483
|
-
|
|
484
|
+
this.totalVoicesAmount += channel.voices.length;
|
|
485
|
+
// if voice count changed, update voice amount
|
|
486
|
+
if (channel.voices.length !== voiceCount)
|
|
487
|
+
{
|
|
488
|
+
channel.sendChannelProperty();
|
|
489
|
+
}
|
|
484
490
|
});
|
|
485
|
-
|
|
486
|
-
// if voice count changed, update voice amount
|
|
487
|
-
if (totalCurrentVoices !== this.totalVoicesAmount)
|
|
488
|
-
{
|
|
489
|
-
this.totalVoicesAmount = totalCurrentVoices;
|
|
490
|
-
this.sendChannelProperties();
|
|
491
|
-
}
|
|
491
|
+
// keep the processor alive
|
|
492
492
|
return true;
|
|
493
493
|
}
|
|
494
494
|
|
|
@@ -591,7 +591,6 @@ SpessaSynthProcessor.prototype.getWorkletVoices = getWorkletVoices;
|
|
|
591
591
|
|
|
592
592
|
// message port related
|
|
593
593
|
SpessaSynthProcessor.prototype.handleMessage = handleMessage;
|
|
594
|
-
SpessaSynthProcessor.prototype.sendChannelProperties = sendChannelProperties;
|
|
595
594
|
SpessaSynthProcessor.prototype.callEvent = callEvent;
|
|
596
595
|
|
|
597
596
|
// system-exclusive related
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { returnMessageType } from "./worklet_message.js";
|
|
2
2
|
|
|
3
|
-
import { modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
|
|
4
|
-
import { customControllers, NON_CC_INDEX_OFFSET } from "../worklet_utilities/controller_tables.js";
|
|
5
|
-
|
|
6
3
|
/**
|
|
7
4
|
* Calls synth event from the worklet side
|
|
8
5
|
* @param eventName {EventTypes} the event name
|
|
@@ -22,43 +19,4 @@ export function callEvent(eventName, eventData)
|
|
|
22
19
|
eventData: eventData
|
|
23
20
|
}
|
|
24
21
|
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @typedef {Object} ChannelProperty
|
|
29
|
-
* @property {number} voicesAmount
|
|
30
|
-
* @property {number} pitchBend - from -8192 do 8192
|
|
31
|
-
* @property {number} pitchBendRangeSemitones - in semitones
|
|
32
|
-
* @property {boolean} isMuted
|
|
33
|
-
* @property {boolean} isDrum
|
|
34
|
-
* @property {number} transposition
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @this {SpessaSynthProcessor}
|
|
39
|
-
*/
|
|
40
|
-
export function sendChannelProperties()
|
|
41
|
-
{
|
|
42
|
-
if (!this.enableEventSystem)
|
|
43
|
-
{
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* @type {ChannelProperty[]}
|
|
48
|
-
*/
|
|
49
|
-
const data = this.workletProcessorChannels.map(c =>
|
|
50
|
-
{
|
|
51
|
-
return {
|
|
52
|
-
voicesAmount: c.voices.length,
|
|
53
|
-
pitchBend: c.midiControllers[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheel],
|
|
54
|
-
pitchBendRangeSemitones: c.midiControllers[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheelRange] / 128,
|
|
55
|
-
isMuted: c.isMuted,
|
|
56
|
-
isDrum: c.drumChannel,
|
|
57
|
-
transposition: c.channelTransposeKeyShift + c.customControllers[customControllers.channelTransposeFine] / 100
|
|
58
|
-
};
|
|
59
|
-
});
|
|
60
|
-
this.post({
|
|
61
|
-
messageType: returnMessageType.channelProperties,
|
|
62
|
-
messageData: data
|
|
63
|
-
});
|
|
64
22
|
}
|
|
@@ -79,16 +79,15 @@ export const ALL_CHANNELS_OR_DIFFERENT_ACTION = -1;
|
|
|
79
79
|
/**
|
|
80
80
|
* @typedef {{
|
|
81
81
|
* channelNumber: number
|
|
82
|
-
* messageType: workletMessageType,
|
|
82
|
+
* messageType: (workletMessageType|number),
|
|
83
83
|
* messageData: (
|
|
84
|
+
* boolean|
|
|
84
85
|
* number[]
|
|
85
86
|
* |undefined
|
|
86
87
|
* |boolean[]
|
|
87
88
|
* |WorkletVoice[]
|
|
88
89
|
* |number
|
|
89
|
-
* |{sampleData: Float32Array, sampleID: number}
|
|
90
90
|
* |{rate: number, depth: number, delay: number}
|
|
91
|
-
* |boolean
|
|
92
91
|
* |ArrayBuffer
|
|
93
92
|
* |{messageType: WorkletSequencerMessageType, messageData: any}
|
|
94
93
|
* |{messageType: workletKeyModifierMessageType, messageData: any}
|
|
@@ -102,14 +101,14 @@ export const ALL_CHANNELS_OR_DIFFERENT_ACTION = -1;
|
|
|
102
101
|
* @property {{
|
|
103
102
|
* eventName: string,
|
|
104
103
|
* eventData: any
|
|
105
|
-
* }|ChannelProperty
|
|
104
|
+
* }|ChannelProperty
|
|
106
105
|
* |PresetListElement[]
|
|
107
106
|
* |string
|
|
108
107
|
* |{messageType: WorkletSequencerReturnMessageType, messageData: any}
|
|
109
108
|
* |SynthesizerSnapshot
|
|
110
109
|
* |[WorkletSoundfontManagerMessageType, any]} messageData - the message's data
|
|
111
110
|
*
|
|
112
|
-
* 0 - channel
|
|
111
|
+
* 0 - channel property change -> [channel<number>, property<ChannelProperty>] see message_sending.js line 29
|
|
113
112
|
* 1 - event call -> {eventName<string>, eventData:<the event's data>}
|
|
114
113
|
* 2 - master parameter change -> [parameter<masterParameterType>, value<string|number>]
|
|
115
114
|
* 3 - sequencer specific -> [messageType<WorkletSequencerReturnMessageType> messageData<any>] note: refer to sequencer_message.js
|
|
@@ -122,7 +121,7 @@ export const ALL_CHANNELS_OR_DIFFERENT_ACTION = -1;
|
|
|
122
121
|
* @enum {number}
|
|
123
122
|
*/
|
|
124
123
|
export const returnMessageType = {
|
|
125
|
-
|
|
124
|
+
channelPropertyChange: 0,
|
|
126
125
|
eventCall: 1,
|
|
127
126
|
masterParameterChange: 2,
|
|
128
127
|
sequencerSpecific: 3,
|
|
@@ -14,7 +14,7 @@ export function createWorkletChannel(sendEvent = false)
|
|
|
14
14
|
const channel = new WorkletProcessorChannel(this, this.defaultPreset, this.workletProcessorChannels.length);
|
|
15
15
|
this.workletProcessorChannels.push(channel);
|
|
16
16
|
channel.resetControllers();
|
|
17
|
-
|
|
17
|
+
channel.sendChannelProperty();
|
|
18
18
|
if (sendEvent)
|
|
19
19
|
{
|
|
20
20
|
this.callEvent("newchannel", undefined);
|
|
@@ -165,7 +165,7 @@ export function noteOn(midiNote, velocity, enableDebugging = false, sendEvent =
|
|
|
165
165
|
channelVoices.push(...voices);
|
|
166
166
|
if (sendEvent)
|
|
167
167
|
{
|
|
168
|
-
this.
|
|
168
|
+
this.sendChannelProperty();
|
|
169
169
|
this.synth.callEvent("noteon", {
|
|
170
170
|
midiNote: midiNote,
|
|
171
171
|
channel: this.channelNumber,
|
|
@@ -13,6 +13,9 @@ export function programChange(programNumber, userChange = false)
|
|
|
13
13
|
// always 128 for percussion
|
|
14
14
|
let bank = this.getBankSelect();
|
|
15
15
|
let sentBank;
|
|
16
|
+
/**
|
|
17
|
+
* @type {BasicPreset}
|
|
18
|
+
*/
|
|
16
19
|
let preset;
|
|
17
20
|
|
|
18
21
|
const isXG = this.isXGChannel;
|
|
@@ -34,21 +37,27 @@ export function programChange(programNumber, userChange = false)
|
|
|
34
37
|
else
|
|
35
38
|
{
|
|
36
39
|
preset = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
|
|
37
|
-
|
|
40
|
+
const offset = this.synth.soundfontManager.soundfontList
|
|
41
|
+
.find(s => s.soundfont === preset.parentSoundBank).bankOffset;
|
|
42
|
+
sentBank = preset.bank - offset;
|
|
38
43
|
this.presetUsesOverride = false;
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
46
|
else
|
|
42
47
|
{
|
|
43
48
|
preset = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
|
|
44
|
-
|
|
49
|
+
const offset = this.synth.soundfontManager.soundfontList
|
|
50
|
+
.find(s => s.soundfont === preset.parentSoundBank).bankOffset;
|
|
51
|
+
sentBank = preset.bank - offset;
|
|
45
52
|
this.presetUsesOverride = false;
|
|
46
53
|
}
|
|
47
54
|
this.setPreset(preset);
|
|
55
|
+
this.sentBank = sentBank;
|
|
48
56
|
this.synth.callEvent("programchange", {
|
|
49
57
|
channel: this.channelNumber,
|
|
50
58
|
program: preset.program,
|
|
51
59
|
bank: sentBank,
|
|
52
60
|
userCalled: userChange
|
|
53
61
|
});
|
|
62
|
+
this.sendChannelProperty();
|
|
54
63
|
}
|
|
@@ -30,5 +30,5 @@ export function transposeChannel(semitones, force = false)
|
|
|
30
30
|
// apply transpose
|
|
31
31
|
this.channelTransposeKeyShift = keyShift;
|
|
32
32
|
this.setCustomController(customControllers.channelTransposeFine, (semitones - keyShift) * 100);
|
|
33
|
-
this.
|
|
33
|
+
this.sendChannelProperty();
|
|
34
34
|
}
|
|
@@ -2,7 +2,8 @@ import {
|
|
|
2
2
|
CONTROLLER_TABLE_SIZE,
|
|
3
3
|
CUSTOM_CONTROLLER_TABLE_SIZE,
|
|
4
4
|
customControllers,
|
|
5
|
-
dataEntryStates
|
|
5
|
+
dataEntryStates,
|
|
6
|
+
NON_CC_INDEX_OFFSET
|
|
6
7
|
} from "./controller_tables.js";
|
|
7
8
|
import {
|
|
8
9
|
resetControllers,
|
|
@@ -29,6 +30,8 @@ import { setOctaveTuning } from "../worklet_methods/tuning_control/set_octave_tu
|
|
|
29
30
|
import { programChange } from "../worklet_methods/program_change.js";
|
|
30
31
|
import { chooseBank, isSystemXG, parseBankSelect } from "../../../utils/xg_hacks.js";
|
|
31
32
|
import { DEFAULT_PERCUSSION } from "../../synth_constants.js";
|
|
33
|
+
import { modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
|
|
34
|
+
import { returnMessageType } from "../message_protocol/worklet_message.js";
|
|
32
35
|
|
|
33
36
|
/**
|
|
34
37
|
* This class represents a single MIDI Channel within the synthesizer.
|
|
@@ -115,6 +118,12 @@ class WorkletProcessorChannel
|
|
|
115
118
|
*/
|
|
116
119
|
bank = 0;
|
|
117
120
|
|
|
121
|
+
/**
|
|
122
|
+
* The bank number sent as channel properties.
|
|
123
|
+
* @type {number}
|
|
124
|
+
*/
|
|
125
|
+
sentBank = 0;
|
|
126
|
+
|
|
118
127
|
/**
|
|
119
128
|
* The bank LSB number of the channel (used for patch changes in XG mode).
|
|
120
129
|
* @type {number}
|
|
@@ -359,7 +368,7 @@ class WorkletProcessorChannel
|
|
|
359
368
|
isDrumChannel: this.drumChannel
|
|
360
369
|
});
|
|
361
370
|
this.programChange(this.preset.program);
|
|
362
|
-
this.
|
|
371
|
+
this.sendChannelProperty();
|
|
363
372
|
}
|
|
364
373
|
|
|
365
374
|
/**
|
|
@@ -386,6 +395,48 @@ class WorkletProcessorChannel
|
|
|
386
395
|
this.channelVibrato.delay = 0;
|
|
387
396
|
this.channelVibrato.depth = 0;
|
|
388
397
|
}
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* @typedef {Object} ChannelProperty
|
|
402
|
+
* @property {number} voicesAmount - the channel's current voice amount
|
|
403
|
+
* @property {number} pitchBend - the channel's current pitch bend from -8192 do 8192
|
|
404
|
+
* @property {number} pitchBendRangeSemitones - the pitch bend's range, in semitones
|
|
405
|
+
* @property {boolean} isMuted - indicates whether the channel is muted
|
|
406
|
+
* @property {boolean} isDrum - indicates whether the channel is a drum channel
|
|
407
|
+
* @property {number} transposition - the channel's transposition, in semitones
|
|
408
|
+
* @property {number} bank - the bank number of the current preset
|
|
409
|
+
* @property {number} program - the MIDI program number of the current preset
|
|
410
|
+
*/
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Sends this channel's property
|
|
415
|
+
*/
|
|
416
|
+
sendChannelProperty()
|
|
417
|
+
{
|
|
418
|
+
if (!this.synth.enableEventSystem)
|
|
419
|
+
{
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* @type {ChannelProperty}
|
|
424
|
+
*/
|
|
425
|
+
const data = {
|
|
426
|
+
voicesAmount: this.voices.length,
|
|
427
|
+
pitchBend: this.midiControllers[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheel],
|
|
428
|
+
pitchBendRangeSemitones: this.midiControllers[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheelRange] / 128,
|
|
429
|
+
isMuted: this.isMuted,
|
|
430
|
+
isDrum: this.drumChannel,
|
|
431
|
+
transposition: this.channelTransposeKeyShift + this.customControllers[customControllers.channelTransposeFine] / 100,
|
|
432
|
+
bank: this.sentBank,
|
|
433
|
+
program: this.preset.program
|
|
434
|
+
};
|
|
435
|
+
this.synth.post({
|
|
436
|
+
messageType: returnMessageType.channelPropertyChange,
|
|
437
|
+
messageData: [this.channelNumber, data]
|
|
438
|
+
});
|
|
439
|
+
}
|
|
389
440
|
}
|
|
390
441
|
|
|
391
442
|
// voice
|