spessasynth_lib 3.20.0 → 3.20.2

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 CHANGED
@@ -2,6 +2,7 @@ import { Sequencer } from './sequencer/sequencer.js';
2
2
  import { Synthetizer } from './synthetizer/synthetizer.js';
3
3
  import { DEFAULT_PERCUSSION } from './synthetizer/synthetizer.js';
4
4
  import { VOICE_CAP } from './synthetizer/synthetizer.js';
5
+ import { BasicSoundFont } from "./soundfont/basic_soundfont/basic_soundfont.js";
5
6
  import { loadSoundFont } from "./soundfont/load_soundfont.js";
6
7
  import { trimSoundfont } from "./soundfont/basic_soundfont/write_sf2/soundfont_trimmer.js";
7
8
  import { modulatorSources } from "./soundfont/read_sf2/modulators.js";
@@ -33,4 +34,4 @@ import { readBytesAsUintBigEndian } from './utils/byte_functions/big_endian.js';
33
34
  import { NON_CC_INDEX_OFFSET } from './synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js';
34
35
  import { ALL_CHANNELS_OR_DIFFERENT_ACTION } from './synthetizer/worklet_system/message_protocol/worklet_message.js';
35
36
  import { WORKLET_URL_ABSOLUTE } from './synthetizer/worklet_url.js';
36
- export { Sequencer, Synthetizer, DEFAULT_PERCUSSION, VOICE_CAP, loadSoundFont, trimSoundfont, modulatorSources, encodeVorbis, MIDI, MIDIBuilder, IndexedByteArray, writeMIDIFile, writeRMIDI, applySnapshotToMIDI, modifyMIDI, audioBufferToWav, SpessaSynthLogging, SpessaSynthGroup, SpessaSynthTable, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn, SpessaSynthGroupCollapsed, midiControllers, messageTypes, MIDIDeviceHandler, WebMidiLinkHandler, arrayToHexString, consoleColors, formatTitle, formatTime, readBytesAsUintBigEndian, NON_CC_INDEX_OFFSET, ALL_CHANNELS_OR_DIFFERENT_ACTION, WORKLET_URL_ABSOLUTE };
37
+ export { Sequencer, Synthetizer, DEFAULT_PERCUSSION, VOICE_CAP, BasicSoundFont, loadSoundFont, trimSoundfont, modulatorSources, encodeVorbis, MIDI, MIDIBuilder, IndexedByteArray, writeMIDIFile, writeRMIDI, applySnapshotToMIDI, modifyMIDI, audioBufferToWav, SpessaSynthLogging, SpessaSynthGroup, SpessaSynthTable, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn, SpessaSynthGroupCollapsed, midiControllers, messageTypes, MIDIDeviceHandler, WebMidiLinkHandler, arrayToHexString, consoleColors, formatTitle, formatTime, readBytesAsUintBigEndian, NON_CC_INDEX_OFFSET, ALL_CHANNELS_OR_DIFFERENT_ACTION, WORKLET_URL_ABSOLUTE };
@@ -11,7 +11,7 @@ export class SoundFont2 extends BasicSoundFont {
11
11
  constructor(arrayBuffer: ArrayBuffer, warnDeprecated?: boolean);
12
12
  dataArray: IndexedByteArray;
13
13
  sampleDataStartIndex: number;
14
- instruments: import("./read_sf2/instruments.js").Instrument[];
14
+ instruments: import("./instruments.js").Instrument[];
15
15
  /**
16
16
  * @param chunk {RiffChunk}
17
17
  * @param expected {string}
@@ -23,6 +23,6 @@ export class SoundFont2 extends BasicSoundFont {
23
23
  */
24
24
  verifyText(text: string, expected: string): void;
25
25
  }
26
- import { BasicSoundFont } from './basic_soundfont/basic_soundfont.js';
27
- import { IndexedByteArray } from '../utils/indexed_array.js';
28
- import { RiffChunk } from './basic_soundfont/riff_chunk.js';
26
+ import { BasicSoundFont } from '../basic_soundfont/basic_soundfont.js';
27
+ import { IndexedByteArray } from '../../utils/indexed_array.js';
28
+ import { RiffChunk } from '../basic_soundfont/riff_chunk.js';
package/README.md CHANGED
@@ -76,7 +76,7 @@ document.getElementById("button").onclick = async () => {
76
76
  - **Easy MIDI editing:** Use [helper functions](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#modifymidi) to modify the song to your needs!
77
77
  - **Loop detection:** Automatically detects loops in MIDIs (e.g., from _Touhou Project_)
78
78
  - **First note detection:** Skip unnecessary silence at the start by jumping to the first note!
79
- - **[Write MIDI files from scratch](https://github.com/spessasus/SpessaSynth/wiki/Creating-MIDI-Files.md)**
79
+ - **[Write MIDI files from scratch](https://github.com/spessasus/SpessaSynth/wiki/Creating-MIDI-Files)**
80
80
  - **Easy saving:** Save with just [one function!](https://github.com/spessasus/SpessaSynth/wiki/Writing-MIDI-Files#writemidifile)
81
81
 
82
82
  #### Read and write [RMID files with embedded SF2 soundfonts](https://github.com/spessasus/sf2-rmidi-specification#readme)
@@ -13,7 +13,8 @@ export class WebMidiLinkHandler
13
13
  /**
14
14
  * @param synth {Synthetizer} the synth to play to
15
15
  */
16
- constructor(synth) {
16
+ constructor(synth)
17
+ {
17
18
 
18
19
  window.addEventListener("message", msg => {
19
20
  if(typeof msg.data !== "string")
package/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // Import modules
2
2
  import { loadSoundFont } from "./soundfont/load_soundfont.js";
3
+ import { BasicSoundFont } from "./soundfont/basic_soundfont/basic_soundfont.js";
3
4
  import { MIDI } from './midi_parser/midi_loader.js';
4
5
  import { MIDIBuilder } from "./midi_parser/midi_builder.js";
5
6
  import { Synthetizer, VOICE_CAP, DEFAULT_PERCUSSION } from './synthetizer/synthetizer.js';
@@ -39,6 +40,7 @@ export {
39
40
  VOICE_CAP,
40
41
 
41
42
  // SoundFont
43
+ BasicSoundFont,
42
44
  loadSoundFont,
43
45
  trimSoundfont,
44
46
  modulatorSources,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "spessasynth_lib",
3
- "version": "3.20.0",
4
- "description": "No compromise MIDI and SoundFont2 Synthesizer library",
3
+ "version": "3.20.2",
4
+ "description": "MIDI and SoundFont2 or DLS Synthesizer library with no compromises",
5
5
  "browser": "index.js",
6
6
  "types": "@types/index.d.ts",
7
7
  "type": "module",
@@ -18,7 +18,10 @@
18
18
  "synth",
19
19
  "sf2",
20
20
  "sf3",
21
+ "dls",
22
+ "dls-to-sf2",
21
23
  "midi",
24
+ "rmi",
22
25
  "midi-player",
23
26
  "web-audio-api",
24
27
  "web-midi-api",
@@ -46,6 +46,14 @@ export class DLSSample extends BasicSample
46
46
 
47
47
  getRawData()
48
48
  {
49
+ if(this.isCompressed)
50
+ {
51
+ if (!this.compressedData)
52
+ {
53
+ throw new Error("Compressed but no data??")
54
+ }
55
+ return this.compressedData;
56
+ }
49
57
  const uint8 = new Uint8Array(this.sampleData.length * 2);
50
58
  for (let i = 0; i < this.sampleData.length; i++)
51
59
  {
@@ -46,7 +46,8 @@ export class DLSZone extends BasicInstrumentZone
46
46
  {
47
47
  const fine = diffStart % 32768;
48
48
  this.generators.push(new Generator(generatorTypes.startloopAddrsOffset, fine));
49
- const coarse = Math.round(diffStart / 32768);
49
+ // coarse generator uses 32768 samples per step
50
+ const coarse = (diffStart - fine) / 32768;
50
51
  if(coarse !== 0)
51
52
  {
52
53
  this.generators.push(new Generator(generatorTypes.startloopAddrsCoarseOffset, fine));
@@ -56,7 +57,8 @@ export class DLSZone extends BasicInstrumentZone
56
57
  {
57
58
  const fine = diffEnd % 32768;
58
59
  this.generators.push(new Generator(generatorTypes.endloopAddrsOffset, fine));
59
- const coarse = Math.round(diffEnd / 32768);
60
+ // coarse generator uses 32768 samples per step
61
+ const coarse = (diffEnd - fine) / 32768;
60
62
  if(coarse !== 0)
61
63
  {
62
64
  this.generators.push(new Generator(generatorTypes.endloopAddrsCoarseOffset, fine));
@@ -76,8 +76,14 @@ export function readArticulation(chunk, disableVibrato)
76
76
  const control = readLittleEndian(artData, 2);
77
77
  const destination = readLittleEndian(artData, 2);
78
78
  const transform = readLittleEndian(artData, 2);
79
- const value = readLittleEndian(artData, 4) >> 16; // convert it to 16 bit as soundfont uses that
79
+ const scale = readLittleEndian(artData, 4) | 0;
80
+ const value = scale >> 16; // convert it to 16 bit as soundfont uses that
80
81
 
82
+ // if(destination === DLSDestinations.volEnvDecay)
83
+ // {
84
+ // console.log(scale, value)
85
+ // }
86
+ //modulatorConverterDebug(source, control, destination, value, transform);
81
87
  // interpret this somehow...
82
88
  // if source and control are both zero, it's a generator
83
89
  if(source === 0 && control === 0 && transform === 0)
@@ -224,26 +230,57 @@ export function readArticulation(chunk, disableVibrato)
224
230
  // key to vol env hold
225
231
  if(source === DLSSources.keyNum && destination === DLSDestinations.volEnvHold)
226
232
  {
227
- // according to viena and another strange (with modulators) rendition of gm.dls in sf2, this is how it should be done???
228
- generators.push(new Generator(generatorTypes.keyNumToVolEnvHold, value / -127));
233
+ // according to viena and another strange (with modulators) rendition of gm.dls in sf2,
234
+ // it shall be divided by -128
235
+ // and a strange correction needs to be applied to the real value:
236
+ // real + (60 / 128) * scale
237
+ generators.push(new Generator(generatorTypes.keyNumToVolEnvHold, value / -128));
238
+ const correction = Math.round((60 / 128) * value);
239
+ generators.forEach(g => {
240
+ if(g.generatorType === generatorTypes.holdVolEnv) g.generatorValue += correction;
241
+ });
229
242
  }
230
243
  else
231
244
  // key to vol env decay
232
245
  if(source === DLSSources.keyNum && destination === DLSDestinations.volEnvDecay)
233
246
  {
234
- generators.push(new Generator(generatorTypes.keyNumToVolEnvDecay, value / -127));
247
+ // according to viena and another strange (with modulators) rendition of gm.dls in sf2,
248
+ // it shall be divided by -128
249
+ // and a strange correction needs to be applied to the real value:
250
+ // real + (60 / 128) * scale
251
+ generators.push(new Generator(generatorTypes.keyNumToVolEnvDecay, value / -128));
252
+ const correction = Math.round((60 / 128) * value);
253
+ generators.forEach(g => {
254
+ if(g.generatorType === generatorTypes.decayVolEnv) g.generatorValue += correction;
255
+ });
235
256
  }
236
257
  else
237
258
  // key to mod env hold
238
259
  if(source === DLSSources.keyNum && destination === DLSDestinations.modEnvHold)
239
260
  {
240
- generators.push(new Generator(generatorTypes.keyNumToModEnvHold, value / -127));
261
+ // according to viena and another strange (with modulators) rendition of gm.dls in sf2,
262
+ // it shall be divided by -128
263
+ // and a strange correction needs to be applied to the real value:
264
+ // real + (60 / 128) * scale
265
+ generators.push(new Generator(generatorTypes.keyNumToModEnvHold, value / -128));
266
+ const correction = Math.round((60 / 128) * value);
267
+ generators.forEach(g => {
268
+ if(g.generatorType === generatorTypes.holdModEnv) g.generatorValue += correction;
269
+ });
241
270
  }
242
271
  else
243
272
  // key to mod env decay
244
273
  if(source === DLSSources.keyNum && destination === DLSDestinations.modEnvDecay)
245
274
  {
246
- generators.push(new Generator(generatorTypes.keyNumToModEnvDecay, value / -127));
275
+ // according to viena and another strange (with modulators) rendition of gm.dls in sf2,
276
+ // it shall be divided by -128
277
+ // and a strange correction needs to be applied to the real value:
278
+ // real + (60 / 128) * scale
279
+ generators.push(new Generator(generatorTypes.keyNumToModEnvDecay, value / -128));
280
+ const correction = Math.round((60 / 128) * value);
281
+ generators.forEach(g => {
282
+ if(g.generatorType === generatorTypes.decayModEnv) g.generatorValue += correction;
283
+ });
247
284
  }
248
285
  else
249
286
  {
@@ -1,7 +1,7 @@
1
1
  import { IndexedByteArray } from '../utils/indexed_array.js'
2
2
  import { readBytesAsString } from '../utils/byte_functions/string.js'
3
3
  import { DLSSoundFont } from './dls/dls_soundfont.js'
4
- import { SoundFont2 } from './soundfont.js'
4
+ import { SoundFont2 } from './read_sf2/soundfont.js'
5
5
 
6
6
  /**
7
7
  * Loads a soundfont file
@@ -1,17 +1,17 @@
1
- import { IndexedByteArray } from '../utils/indexed_array.js'
2
- import {readSamples} from "./read_sf2/samples.js";
3
- import { readLittleEndian } from '../utils/byte_functions/little_endian.js'
4
- import { readGenerators, Generator } from './read_sf2/generators.js'
5
- import {readInstrumentZones, InstrumentZone, readPresetZones} from "./read_sf2/zones.js";
6
- import { readPresets } from "./read_sf2/presets.js";
7
- import {readInstruments} from "./read_sf2/instruments.js";
8
- import {readModulators, Modulator} from "./read_sf2/modulators.js";
9
- import { readRIFFChunk, RiffChunk } from './basic_soundfont/riff_chunk.js'
10
- import { consoleColors } from '../utils/other.js'
11
- import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from '../utils/loggin.js'
12
- import { readBytesAsString } from '../utils/byte_functions/string.js'
13
- import { stbvorbis } from "../externals/stbvorbis_sync/stbvorbis_sync.min.js";
14
- import { BasicSoundFont } from './basic_soundfont/basic_soundfont.js'
1
+ import { IndexedByteArray } from '../../utils/indexed_array.js'
2
+ import { readSamples } from "./samples.js";
3
+ import { readLittleEndian } from '../../utils/byte_functions/little_endian.js'
4
+ import { readGenerators, Generator } from './generators.js'
5
+ import { readInstrumentZones, InstrumentZone, readPresetZones } from "./zones.js";
6
+ import { readPresets } from "./presets.js";
7
+ import { readInstruments } from "./instruments.js";
8
+ import { readModulators, Modulator } from "./modulators.js";
9
+ import { readRIFFChunk, RiffChunk } from '../basic_soundfont/riff_chunk.js'
10
+ import { consoleColors } from '../../utils/other.js'
11
+ import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from '../../utils/loggin.js'
12
+ import { readBytesAsString } from '../../utils/byte_functions/string.js'
13
+ import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js";
14
+ import { BasicSoundFont } from '../basic_soundfont/basic_soundfont.js'
15
15
 
16
16
  /**
17
17
  * soundfont.js