spessasynth_lib 3.16.2 → 3.16.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.
- package/@types/index.d.ts +2 -2
- package/@types/midi_parser/used_keys_loaded.d.ts +2 -2
- package/@types/soundfont/basic_soundfont/basic_instrument.d.ts +29 -0
- package/@types/soundfont/basic_soundfont/basic_preset.d.ts +76 -0
- package/@types/soundfont/basic_soundfont/basic_sample.d.ts +82 -0
- package/@types/soundfont/basic_soundfont/basic_soundfont.d.ts +80 -0
- package/@types/soundfont/basic_soundfont/basic_zone.d.ts +42 -0
- package/@types/soundfont/basic_soundfont/basic_zones.d.ts +18 -0
- package/@types/soundfont/{read → basic_soundfont}/riff_chunk.d.ts +2 -1
- package/@types/soundfont/basic_soundfont/write_sf2/ibag.d.ts +6 -0
- package/@types/soundfont/basic_soundfont/write_sf2/igen.d.ts +6 -0
- package/@types/soundfont/basic_soundfont/write_sf2/imod.d.ts +6 -0
- package/@types/soundfont/basic_soundfont/write_sf2/inst.d.ts +6 -0
- package/@types/soundfont/basic_soundfont/write_sf2/pbag.d.ts +6 -0
- package/@types/soundfont/basic_soundfont/write_sf2/pgen.d.ts +6 -0
- package/@types/soundfont/basic_soundfont/write_sf2/phdr.d.ts +6 -0
- package/@types/soundfont/basic_soundfont/write_sf2/pmod.d.ts +6 -0
- package/@types/soundfont/basic_soundfont/write_sf2/sdta.d.ts +11 -0
- package/@types/soundfont/basic_soundfont/write_sf2/shdr.d.ts +8 -0
- package/@types/soundfont/basic_soundfont/write_sf2/soundfont_trimmer.d.ts +6 -0
- package/@types/soundfont/{write → basic_soundfont/write_sf2}/write.d.ts +2 -2
- package/@types/soundfont/{read → read_sf2}/generators.d.ts +2 -1
- package/@types/soundfont/{read → read_sf2}/instruments.d.ts +3 -24
- package/@types/soundfont/read_sf2/presets.d.ts +28 -0
- package/@types/soundfont/read_sf2/samples.d.ts +56 -0
- package/@types/soundfont/{read → read_sf2}/zones.d.ts +11 -53
- package/@types/soundfont/soundfont.d.ts +6 -67
- package/index.js +2 -2
- package/midi_parser/midi_loader.js +1 -1
- package/midi_parser/rmidi_writer.js +11 -11
- package/midi_parser/used_keys_loaded.js +1 -1
- package/package.json +1 -1
- package/soundfont/basic_soundfont/basic_instrument.js +73 -0
- package/soundfont/{read/presets.js → basic_soundfont/basic_preset.js} +54 -87
- package/soundfont/basic_soundfont/basic_sample.js +132 -0
- package/soundfont/basic_soundfont/basic_soundfont.js +193 -0
- package/soundfont/basic_soundfont/basic_zone.js +39 -0
- package/soundfont/basic_soundfont/basic_zones.js +47 -0
- package/soundfont/{read → basic_soundfont}/riff_chunk.js +8 -1
- package/soundfont/{write → basic_soundfont/write_sf2}/ibag.js +4 -4
- package/soundfont/{write → basic_soundfont/write_sf2}/igen.js +5 -5
- package/soundfont/{write → basic_soundfont/write_sf2}/imod.js +4 -4
- package/soundfont/{write → basic_soundfont/write_sf2}/inst.js +5 -5
- package/soundfont/{write → basic_soundfont/write_sf2}/pbag.js +4 -4
- package/soundfont/{write → basic_soundfont/write_sf2}/pgen.js +5 -5
- package/soundfont/{write → basic_soundfont/write_sf2}/phdr.js +5 -5
- package/soundfont/{write → basic_soundfont/write_sf2}/pmod.js +4 -4
- package/soundfont/{write → basic_soundfont/write_sf2}/sdta.js +5 -5
- package/soundfont/{write → basic_soundfont/write_sf2}/shdr.js +5 -5
- package/soundfont/{write → basic_soundfont/write_sf2}/soundfont_trimmer.js +5 -5
- package/soundfont/{write → basic_soundfont/write_sf2}/write.js +8 -9
- package/soundfont/{read → read_sf2}/generators.js +2 -1
- package/soundfont/{read → read_sf2}/instruments.js +4 -63
- package/soundfont/{read → read_sf2}/modulators.js +1 -1
- package/soundfont/read_sf2/presets.js +78 -0
- package/soundfont/{read → read_sf2}/samples.js +4 -138
- package/soundfont/{read → read_sf2}/zones.js +14 -60
- package/soundfont/soundfont.js +21 -188
- package/synthetizer/worklet_processor.min.js +6 -6
- package/synthetizer/worklet_system/message_protocol/message_sending.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/data_entry.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/note_off.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/note_on.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/program_control.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/reset_controllers.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/tuning_control.js +1 -1
- package/synthetizer/worklet_system/worklet_methods/voice_control.js +1 -1
- package/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +1 -1
- package/synthetizer/worklet_system/worklet_utilities/modulation_envelope.js +2 -2
- package/synthetizer/worklet_system/worklet_utilities/modulator_curves.js +1 -1
- package/synthetizer/worklet_system/worklet_utilities/volume_envelope.js +4 -4
- package/synthetizer/worklet_system/worklet_utilities/worklet_modulator.js +2 -2
- package/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +1 -1
- package/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +1 -1
- package/utils/buffer_to_wav.js +6 -6
- package/@types/soundfont/read/presets.d.ts +0 -88
- package/@types/soundfont/read/samples.d.ts +0 -138
- package/@types/soundfont/write/ibag.d.ts +0 -6
- package/@types/soundfont/write/igen.d.ts +0 -6
- package/@types/soundfont/write/imod.d.ts +0 -6
- package/@types/soundfont/write/inst.d.ts +0 -6
- package/@types/soundfont/write/pbag.d.ts +0 -6
- package/@types/soundfont/write/pgen.d.ts +0 -6
- package/@types/soundfont/write/phdr.d.ts +0 -6
- package/@types/soundfont/write/pmod.d.ts +0 -6
- package/@types/soundfont/write/sdta.d.ts +0 -11
- package/@types/soundfont/write/shdr.d.ts +0 -8
- package/@types/soundfont/write/soundfont_trimmer.d.ts +0 -6
- /package/@types/soundfont/{read → read_sf2}/modulators.d.ts +0 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* samples.js
|
|
3
|
+
* purpose: parses soundfont samples, resamples if needed.
|
|
4
|
+
* loads sample data, handles async loading of sf3 compressed samples
|
|
5
|
+
*/
|
|
6
|
+
import { SpessaSynthWarn } from '../../utils/loggin.js'
|
|
7
|
+
|
|
8
|
+
export class BasicSample {
|
|
9
|
+
/**
|
|
10
|
+
* The basic representation of a soundfont sample
|
|
11
|
+
* @param sampleName {string}
|
|
12
|
+
* @param sampleRate {number}
|
|
13
|
+
* @param samplePitch {number}
|
|
14
|
+
* @param samplePitchCorrection {number}
|
|
15
|
+
* @param sampleLink {number}
|
|
16
|
+
* @param sampleType {number}
|
|
17
|
+
* @param loopStart {number} relative to sample start
|
|
18
|
+
* @param loopEnd {number} relative to sample start
|
|
19
|
+
*/
|
|
20
|
+
constructor(
|
|
21
|
+
sampleName,
|
|
22
|
+
sampleRate,
|
|
23
|
+
samplePitch,
|
|
24
|
+
samplePitchCorrection,
|
|
25
|
+
sampleLink,
|
|
26
|
+
sampleType,
|
|
27
|
+
loopStart,
|
|
28
|
+
loopEnd,
|
|
29
|
+
) {
|
|
30
|
+
/**
|
|
31
|
+
* Sample's name
|
|
32
|
+
* @type {string}
|
|
33
|
+
*/
|
|
34
|
+
this.sampleName = sampleName
|
|
35
|
+
/**
|
|
36
|
+
* Sample rate in Hz
|
|
37
|
+
* @type {number}
|
|
38
|
+
*/
|
|
39
|
+
this.sampleRate = sampleRate
|
|
40
|
+
/**
|
|
41
|
+
* Original pitch of the sample as a MIDI note number
|
|
42
|
+
* @type {number}
|
|
43
|
+
*/
|
|
44
|
+
this.samplePitch = samplePitch
|
|
45
|
+
/**
|
|
46
|
+
* Pitch correction, in cents. Can be negative
|
|
47
|
+
* @type {number}
|
|
48
|
+
*/
|
|
49
|
+
this.samplePitchCorrection = samplePitchCorrection
|
|
50
|
+
/**
|
|
51
|
+
* Sample link, currently unused.
|
|
52
|
+
* @type {number}
|
|
53
|
+
*/
|
|
54
|
+
this.sampleLink = sampleLink
|
|
55
|
+
/**
|
|
56
|
+
* Type of the sample, an enum
|
|
57
|
+
* @type {number}
|
|
58
|
+
*/
|
|
59
|
+
this.sampleType = sampleType
|
|
60
|
+
/**
|
|
61
|
+
* Relative to start of the sample, bytes
|
|
62
|
+
* @type {number}
|
|
63
|
+
*/
|
|
64
|
+
this.sampleLoopStartIndex = loopStart
|
|
65
|
+
/**
|
|
66
|
+
* Relative to start of the sample, in bytes
|
|
67
|
+
* @type {number}
|
|
68
|
+
*/
|
|
69
|
+
this.sampleLoopEndIndex = loopEnd
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Indicates if the sample is compressed
|
|
73
|
+
* @type {boolean}
|
|
74
|
+
*/
|
|
75
|
+
this.isCompressed = (sampleType & 0x10) > 0
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The compressed sample data if it was compressed by spessasynth
|
|
79
|
+
* @type {Uint8Array}
|
|
80
|
+
*/
|
|
81
|
+
this.compressedData = undefined;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The sample's use count
|
|
85
|
+
* @type {number}
|
|
86
|
+
*/
|
|
87
|
+
this.useCount = 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @returns {Uint8Array|IndexedByteArray}
|
|
92
|
+
*/
|
|
93
|
+
getRawData()
|
|
94
|
+
{
|
|
95
|
+
const e = new Error('Not implemented')
|
|
96
|
+
e.name = 'NotImplementedError'
|
|
97
|
+
throw e
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param quality {number}
|
|
102
|
+
* @param encodeVorbis {EncodeVorbisFunction}
|
|
103
|
+
*/
|
|
104
|
+
compressSample(quality, encodeVorbis) {
|
|
105
|
+
// no need to compress
|
|
106
|
+
if (this.isCompressed) {
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
// compress, always mono!
|
|
110
|
+
try {
|
|
111
|
+
this.compressedData = encodeVorbis([this.getAudioData()], 1, this.sampleRate, quality)
|
|
112
|
+
// flag as compressed
|
|
113
|
+
this.sampleType |= 0x10
|
|
114
|
+
this.isCompressed = true
|
|
115
|
+
} catch (e) {
|
|
116
|
+
SpessaSynthWarn(`Failed to compress ${this.sampleName}. Leaving as uncompressed!`)
|
|
117
|
+
this.isCompressed = false
|
|
118
|
+
this.compressedData = undefined
|
|
119
|
+
this.sampleType &= -17
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @returns {Float32Array}
|
|
126
|
+
*/
|
|
127
|
+
getAudioData() {
|
|
128
|
+
const e = new Error('Not implemented')
|
|
129
|
+
e.name = 'NotImplementedError'
|
|
130
|
+
throw e
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { SpessaSynthWarn } from '../../utils/loggin.js'
|
|
2
|
+
import { consoleColors } from '../../utils/other.js'
|
|
3
|
+
import { write } from './write_sf2/write.js'
|
|
4
|
+
|
|
5
|
+
class BasicSoundFont
|
|
6
|
+
{
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new basic soundfont template
|
|
9
|
+
* @param data {undefined|{presets: BasicPreset[], info: Object<string, string>}}
|
|
10
|
+
*/
|
|
11
|
+
constructor(data = undefined)
|
|
12
|
+
{
|
|
13
|
+
/**
|
|
14
|
+
* Soundfont's info stored as name: value. ifil and iver are stored as string representation of float (e.g. 2.1)
|
|
15
|
+
* @type {Object<string, string>}
|
|
16
|
+
*/
|
|
17
|
+
this.soundFontInfo = {};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The soundfont's presets
|
|
21
|
+
* @type {BasicPreset[]}
|
|
22
|
+
*/
|
|
23
|
+
this.presets = []
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The soundfont's samples
|
|
27
|
+
* @type {BasicSample[]}
|
|
28
|
+
*/
|
|
29
|
+
this.samples = [];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The soundfont's instruments
|
|
33
|
+
* @type {BasicInstrument[]}
|
|
34
|
+
*/
|
|
35
|
+
this.instruments = [];
|
|
36
|
+
|
|
37
|
+
if(data?.presets)
|
|
38
|
+
{
|
|
39
|
+
this.presets.push(...data.presets);
|
|
40
|
+
this.soundFontInfo = data.info;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
removeUnusedElements()
|
|
45
|
+
{
|
|
46
|
+
this.instruments.forEach(i => {
|
|
47
|
+
if(i.useCount < 1)
|
|
48
|
+
{
|
|
49
|
+
i.instrumentZones.forEach(z => {if(!z.isGlobal) z.sample.useCount--});
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
this.instruments = this.instruments.filter(i => i.useCount > 0);
|
|
53
|
+
this.samples = this.samples.filter(s => s.useCount > 0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param instrument {BasicInstrument}
|
|
58
|
+
*/
|
|
59
|
+
deleteInstrument(instrument)
|
|
60
|
+
{
|
|
61
|
+
if(instrument.useCount > 0)
|
|
62
|
+
{
|
|
63
|
+
throw new Error(`Cannot delete an instrument that has ${instrument.useCount} usages.`);
|
|
64
|
+
}
|
|
65
|
+
this.instruments.splice(this.instruments.indexOf(instrument), 1);
|
|
66
|
+
instrument.deleteInstrument();
|
|
67
|
+
this.removeUnusedElements();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param sample {BasicSample}
|
|
72
|
+
*/
|
|
73
|
+
deleteSample(sample)
|
|
74
|
+
{
|
|
75
|
+
if(sample.useCount > 0)
|
|
76
|
+
{
|
|
77
|
+
throw new Error(`Cannot delete sample that has ${sample.useCount} usages.`);
|
|
78
|
+
}
|
|
79
|
+
this.samples.splice(this.samples.indexOf(sample), 1);
|
|
80
|
+
this.removeUnusedElements();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param preset {BasicPreset}
|
|
85
|
+
*/
|
|
86
|
+
deletePreset(preset)
|
|
87
|
+
{
|
|
88
|
+
preset.deletePreset();
|
|
89
|
+
this.presets.splice(this.presets.indexOf(preset), 1);
|
|
90
|
+
this.removeUnusedElements();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get the appropriate preset, undefined if not foun d
|
|
95
|
+
* @param bankNr {number}
|
|
96
|
+
* @param presetNr {number}
|
|
97
|
+
* @return {BasicPreset}
|
|
98
|
+
*/
|
|
99
|
+
getPresetNoFallback(bankNr, presetNr)
|
|
100
|
+
{
|
|
101
|
+
return this.presets.find(p => p.bank === bankNr && p.program === presetNr);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* To avoid overlapping on multiple desfonts
|
|
106
|
+
* @param offset {number}
|
|
107
|
+
*/
|
|
108
|
+
setSampleIDOffset(offset)
|
|
109
|
+
{
|
|
110
|
+
this.presets.forEach(p => p.sampleIDOffset = offset);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get the appropriate preset
|
|
115
|
+
* @param bankNr {number}
|
|
116
|
+
* @param presetNr {number}
|
|
117
|
+
* @returns {BasicPreset}
|
|
118
|
+
*/
|
|
119
|
+
getPreset(bankNr, presetNr)
|
|
120
|
+
{
|
|
121
|
+
let preset = this.presets.find(p => p.bank === bankNr && p.program === presetNr);
|
|
122
|
+
if (!preset)
|
|
123
|
+
{
|
|
124
|
+
preset = this.presets.find(p => p.program === presetNr && p.bank !== 128);
|
|
125
|
+
if(bankNr === 128)
|
|
126
|
+
{
|
|
127
|
+
preset = this.presets.find(p => p.bank === 128 && p.program === presetNr);
|
|
128
|
+
if(!preset)
|
|
129
|
+
{
|
|
130
|
+
preset = this.presets.find(p => p.bank === 128);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if(preset)
|
|
134
|
+
{
|
|
135
|
+
SpessaSynthWarn(`%cPreset ${bankNr}.${presetNr} not found. Replaced with %c${preset.presetName} (${preset.bank}.${preset.program})`,
|
|
136
|
+
consoleColors.warn,
|
|
137
|
+
consoleColors.recognized);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if(!preset)
|
|
141
|
+
{
|
|
142
|
+
SpessaSynthWarn(`Preset ${presetNr} not found. Defaulting to`, this.presets[0].presetName);
|
|
143
|
+
preset = this.presets[0];
|
|
144
|
+
}
|
|
145
|
+
return preset;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* gets preset by name
|
|
150
|
+
* @param presetName {string}
|
|
151
|
+
* @returns {BasicPreset}
|
|
152
|
+
*/
|
|
153
|
+
getPresetByName(presetName)
|
|
154
|
+
{
|
|
155
|
+
let preset = this.presets.find(p => p.presetName === presetName);
|
|
156
|
+
if(!preset)
|
|
157
|
+
{
|
|
158
|
+
SpessaSynthWarn("Preset not found. Defaulting to:", this.presets[0].presetName);
|
|
159
|
+
preset = this.presets[0];
|
|
160
|
+
}
|
|
161
|
+
return preset;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Merges soundfonts with the given order. Keep in mind that the info read is copied from the first one
|
|
167
|
+
* @param soundfonts {...BasicSoundFont} the soundfonts to merge, the first overwrites the last
|
|
168
|
+
* @returns {BasicSoundFont}
|
|
169
|
+
*/
|
|
170
|
+
static mergeSoundfonts(...soundfonts)
|
|
171
|
+
{
|
|
172
|
+
const mainSf = soundfonts.shift();
|
|
173
|
+
const presets = mainSf.presets;
|
|
174
|
+
while(soundfonts.length)
|
|
175
|
+
{
|
|
176
|
+
const newPresets = soundfonts.shift().presets;
|
|
177
|
+
newPresets.forEach(newPreset => {
|
|
178
|
+
if(
|
|
179
|
+
presets.find(existingPreset => existingPreset.bank === newPreset.bank && existingPreset.program === newPreset.program) === undefined
|
|
180
|
+
)
|
|
181
|
+
{
|
|
182
|
+
presets.push(newPreset);
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return new BasicSoundFont({presets: presets, info: mainSf.soundFontInfo});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
BasicSoundFont.prototype.write = write;
|
|
192
|
+
|
|
193
|
+
export { BasicSoundFont }
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} SoundFontRange
|
|
3
|
+
* @property {number} min - the minimum midi note
|
|
4
|
+
* @property {number} max - the maximum midi note
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export class BasicZone
|
|
8
|
+
{
|
|
9
|
+
constructor()
|
|
10
|
+
{
|
|
11
|
+
/**
|
|
12
|
+
* The zone's generators
|
|
13
|
+
* @type {Generator[]}
|
|
14
|
+
*/
|
|
15
|
+
this.generators = [];
|
|
16
|
+
/**
|
|
17
|
+
* The zone's modulators
|
|
18
|
+
* @type {Modulator[]}
|
|
19
|
+
*/
|
|
20
|
+
this.modulators = [];
|
|
21
|
+
/**
|
|
22
|
+
* Indicates if the zone is global
|
|
23
|
+
* @type {boolean}
|
|
24
|
+
*/
|
|
25
|
+
this.isGlobal = false;
|
|
26
|
+
/**
|
|
27
|
+
* The zone's key range
|
|
28
|
+
* @type {SoundFontRange}
|
|
29
|
+
*/
|
|
30
|
+
this.keyRange = { min: 0, max: 127 };
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The zone's velocity range
|
|
34
|
+
* @type {SoundFontRange}
|
|
35
|
+
*/
|
|
36
|
+
this.velRange = { min: 0, max: 127 };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BasicZone } from './basic_zone.js'
|
|
2
|
+
|
|
3
|
+
export class BasicInstrumentZone extends BasicZone
|
|
4
|
+
{
|
|
5
|
+
constructor()
|
|
6
|
+
{
|
|
7
|
+
super()
|
|
8
|
+
/**
|
|
9
|
+
* Zone's sample. Undefined if global
|
|
10
|
+
* @type {BasicSample|undefined}
|
|
11
|
+
*/
|
|
12
|
+
this.sample = undefined
|
|
13
|
+
this.useCount = 0
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
deleteZone()
|
|
17
|
+
{
|
|
18
|
+
this.useCount--
|
|
19
|
+
if (this.isGlobal)
|
|
20
|
+
{
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
this.sample.useCount--
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class BasicPresetZone extends BasicZone
|
|
28
|
+
{
|
|
29
|
+
constructor()
|
|
30
|
+
{
|
|
31
|
+
super()
|
|
32
|
+
/**
|
|
33
|
+
* Zone's instrument. Undefined if global
|
|
34
|
+
* @type {BasicInstrument|undefined}
|
|
35
|
+
*/
|
|
36
|
+
this.instrument = undefined
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
deleteZone()
|
|
40
|
+
{
|
|
41
|
+
if(this.isGlobal)
|
|
42
|
+
{
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.instrument.removeUseCount();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -91,10 +91,17 @@ export function writeRIFFChunk(chunk, prepend = undefined)
|
|
|
91
91
|
/**
|
|
92
92
|
* @param header {string}
|
|
93
93
|
* @param data {Uint8Array}
|
|
94
|
+
* @param addZeroByte {Boolean}
|
|
94
95
|
* @returns {IndexedByteArray}
|
|
95
96
|
*/
|
|
96
|
-
export function writeRIFFOddSize(header, data)
|
|
97
|
+
export function writeRIFFOddSize(header, data, addZeroByte = false)
|
|
97
98
|
{
|
|
99
|
+
if(addZeroByte)
|
|
100
|
+
{
|
|
101
|
+
const tempData = new Uint8Array(data.length + 1);
|
|
102
|
+
tempData.set(data, 0);
|
|
103
|
+
data = tempData;
|
|
104
|
+
}
|
|
98
105
|
let finalSize = 8 + data.length;
|
|
99
106
|
if(finalSize % 2 !== 0)
|
|
100
107
|
{
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { IndexedByteArray } from '
|
|
2
|
-
import { writeWord } from '
|
|
3
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
1
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
2
|
+
import { writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
3
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @this {
|
|
6
|
+
* @this {BasicSoundFont}
|
|
7
7
|
* @returns {IndexedByteArray}
|
|
8
8
|
*/
|
|
9
9
|
export function getIBAG()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { writeDword, writeWord } from '
|
|
2
|
-
import { IndexedByteArray } from '
|
|
3
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
4
|
-
import { generatorTypes } from '
|
|
1
|
+
import { writeDword, writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
2
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
3
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
4
|
+
import { generatorTypes } from '../../read_sf2/generators.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @this {
|
|
7
|
+
* @this {BasicSoundFont}
|
|
8
8
|
* @returns {IndexedByteArray}
|
|
9
9
|
*/
|
|
10
10
|
export function getIGEN()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { IndexedByteArray } from '
|
|
2
|
-
import { writeLittleEndian, writeWord } from '
|
|
3
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
1
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
2
|
+
import { writeLittleEndian, writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
3
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @this {
|
|
6
|
+
* @this {BasicSoundFont}
|
|
7
7
|
* @returns {IndexedByteArray}
|
|
8
8
|
*/
|
|
9
9
|
export function getIMOD()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { IndexedByteArray } from '
|
|
2
|
-
import { writeStringAsBytes } from '
|
|
3
|
-
import { writeWord } from '
|
|
4
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
1
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
2
|
+
import { writeStringAsBytes } from '../../../utils/byte_functions/string.js'
|
|
3
|
+
import { writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
4
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @this {
|
|
7
|
+
* @this {BasicSoundFont}
|
|
8
8
|
* @returns {IndexedByteArray}
|
|
9
9
|
*/
|
|
10
10
|
export function getINST()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { IndexedByteArray } from '
|
|
2
|
-
import { writeWord } from '
|
|
3
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
1
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
2
|
+
import { writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
3
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @this {
|
|
6
|
+
* @this {BasicSoundFont}
|
|
7
7
|
* @returns {IndexedByteArray}
|
|
8
8
|
*/
|
|
9
9
|
export function getPBAG()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { writeWord } from '
|
|
2
|
-
import { IndexedByteArray } from '
|
|
3
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
4
|
-
import { generatorTypes } from '
|
|
1
|
+
import { writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
2
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
3
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
4
|
+
import { generatorTypes } from '../../read_sf2/generators.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @this {
|
|
7
|
+
* @this {BasicSoundFont}
|
|
8
8
|
* @returns {IndexedByteArray}
|
|
9
9
|
*/
|
|
10
10
|
export function getPGEN()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { IndexedByteArray } from '
|
|
2
|
-
import { writeStringAsBytes } from '
|
|
3
|
-
import { writeDword, writeWord } from '
|
|
4
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
1
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
2
|
+
import { writeStringAsBytes } from '../../../utils/byte_functions/string.js'
|
|
3
|
+
import { writeDword, writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
4
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @this {
|
|
7
|
+
* @this {BasicSoundFont}
|
|
8
8
|
* @returns {IndexedByteArray}
|
|
9
9
|
*/
|
|
10
10
|
export function getPHDR()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { IndexedByteArray } from '
|
|
2
|
-
import { writeLittleEndian, writeWord } from '
|
|
3
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
1
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
2
|
+
import { writeLittleEndian, writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
3
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @this {
|
|
6
|
+
* @this {BasicSoundFont}
|
|
7
7
|
* @returns {IndexedByteArray}
|
|
8
8
|
*/
|
|
9
9
|
export function getPMOD()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
2
|
-
import { IndexedByteArray } from '
|
|
3
|
-
import { SpessaSynthInfo } from '
|
|
4
|
-
import { consoleColors } from '
|
|
1
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
2
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
3
|
+
import { SpessaSynthInfo } from '../../../utils/loggin.js'
|
|
4
|
+
import { consoleColors } from '../../../utils/other.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @this {
|
|
7
|
+
* @this {BasicSoundFont}
|
|
8
8
|
* @param smplStartOffsets {number[]}
|
|
9
9
|
* @param smplEndOffsets {number[]}
|
|
10
10
|
* @param compress {boolean}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { IndexedByteArray } from '
|
|
2
|
-
import { writeStringAsBytes } from '
|
|
3
|
-
import { writeDword, writeWord } from '
|
|
4
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
1
|
+
import { IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
2
|
+
import { writeStringAsBytes } from '../../../utils/byte_functions/string.js'
|
|
3
|
+
import { writeDword, writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
4
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @this {
|
|
7
|
+
* @this {BasicSoundFont}
|
|
8
8
|
* @param smplStartOffsets {number[]}
|
|
9
9
|
* @param smplEndOffsets {number[]}
|
|
10
10
|
* @returns {IndexedByteArray}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { consoleColors } from '
|
|
1
|
+
import { consoleColors } from '../../../utils/other.js'
|
|
2
2
|
import {
|
|
3
3
|
SpessaSynthGroup,
|
|
4
4
|
SpessaSynthGroupCollapsed,
|
|
5
5
|
SpessaSynthGroupEnd,
|
|
6
|
-
SpessaSynthInfo
|
|
7
|
-
} from '
|
|
8
|
-
import { getUsedProgramsAndKeys } from '
|
|
6
|
+
SpessaSynthInfo
|
|
7
|
+
} from '../../../utils/loggin.js'
|
|
8
|
+
import { getUsedProgramsAndKeys } from '../../../midi_parser/used_keys_loaded.js'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @param soundfont {
|
|
11
|
+
* @param soundfont {BasicSoundFont}
|
|
12
12
|
* @param mid {MIDI}
|
|
13
13
|
* @returns {Uint8Array}
|
|
14
14
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { combineArrays, IndexedByteArray } from '
|
|
2
|
-
import { RiffChunk, writeRIFFChunk } from '../
|
|
3
|
-
import { writeStringAsBytes } from '
|
|
4
|
-
import { consoleColors } from '
|
|
1
|
+
import { combineArrays, IndexedByteArray } from '../../../utils/indexed_array.js'
|
|
2
|
+
import { RiffChunk, writeRIFFChunk } from '../riff_chunk.js'
|
|
3
|
+
import { writeStringAsBytes } from '../../../utils/byte_functions/string.js'
|
|
4
|
+
import { consoleColors } from '../../../utils/other.js'
|
|
5
5
|
import { getIGEN } from './igen.js'
|
|
6
6
|
import { getSDTA } from './sdta.js'
|
|
7
7
|
import { getSHDR } from './shdr.js'
|
|
@@ -12,13 +12,12 @@ import { getPGEN } from './pgen.js'
|
|
|
12
12
|
import { getPMOD } from './pmod.js'
|
|
13
13
|
import { getPBAG } from './pbag.js'
|
|
14
14
|
import { getPHDR } from './phdr.js'
|
|
15
|
-
import { writeWord } from '
|
|
15
|
+
import { writeWord } from '../../../utils/byte_functions/little_endian.js'
|
|
16
16
|
import {
|
|
17
17
|
SpessaSynthGroupCollapsed,
|
|
18
18
|
SpessaSynthGroupEnd,
|
|
19
|
-
SpessaSynthInfo
|
|
20
|
-
} from '
|
|
21
|
-
|
|
19
|
+
SpessaSynthInfo
|
|
20
|
+
} from '../../../utils/loggin.js'
|
|
22
21
|
/**
|
|
23
22
|
* @typedef {Object} SoundFont2WriteOptions
|
|
24
23
|
* @property {boolean} compress - if the soundfont should be compressed with the ogg vorbis codec
|
|
@@ -37,7 +36,7 @@ const DEFAULT_WRITE_OPTIONS = {
|
|
|
37
36
|
|
|
38
37
|
/**
|
|
39
38
|
* Write the soundfont as an .sf2 file. This method is DESTRUCTIVE
|
|
40
|
-
* @this {
|
|
39
|
+
* @this {BasicSoundFont}
|
|
41
40
|
* @param {SoundFont2WriteOptions} options
|
|
42
41
|
* @returns {Uint8Array}
|
|
43
42
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IndexedByteArray } from '../../utils/indexed_array.js'
|
|
2
|
-
import { RiffChunk } from '
|
|
2
|
+
import { RiffChunk } from '../basic_soundfont/riff_chunk.js'
|
|
3
3
|
import { signedInt16 } from '../../utils/byte_functions/little_endian.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -11,6 +11,7 @@ import { signedInt16 } from '../../utils/byte_functions/little_endian.js'
|
|
|
11
11
|
* @enum {number}
|
|
12
12
|
*/
|
|
13
13
|
export const generatorTypes = {
|
|
14
|
+
INVALID: -1, // invalid generator
|
|
14
15
|
startAddrsOffset: 0, // sample control - moves sample start point
|
|
15
16
|
endAddrOffset: 1, // sample control - moves sample end point
|
|
16
17
|
startloopAddrsOffset: 2, // loop control - moves loop start point
|