@tspro/web-music-score 4.2.0 → 5.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.0.0] - 2025-10-05
4
+ Major update required to enable independent browser iife instrument modules.
5
+
6
+ ### **Breiking Changes**
7
+ - Converted audio instrument modules (currently only audio-cg) independant of main lib.
8
+ - Instead of using registerClassicalGuitar() => use import { ClassicalGuitar } and Audio.addInstrument(ClassicalGuitar).
9
+ - Renamed Audio.registerInstrument() => Audio.addInstrument().
10
+ - Renamed Audio.setInstrument() => Audio.useInstrument().
11
+
12
+ ## [4.2.1] - 2025-10-04
13
+ ## Fixed
14
+ - Error was thrown with dotted rests.
15
+
3
16
  ## [4.2.0] - 2025-10-03
4
17
  ## Added
5
18
  - Add support for lyrics/syllables with alignment and hyphen/extender.
package/README.md CHANGED
@@ -13,6 +13,19 @@ This is a work in progress project. Lately there has been improvements that requ
13
13
  version update. As the project matures there might be less major updates, and more minor
14
14
  updates and patches.
15
15
 
16
+ ## Version 5 Update
17
+
18
+ Version 5.0.0 updated audio interface, instrument bundles are no longer dependant of the main lib and can be loaded in browser environment as independent modules.
19
+
20
+ - How to add and use instrument, see sections [Instruments](#instruments)
21
+ - How to add and use instrument browser version, see sections [Browser Modules](#browser-modules)
22
+
23
+ ## Help Wanted
24
+
25
+ If someone has piano or keyboard and can record samples for me I'd be happy to add a new instrument.
26
+ About ten mp3 samples between C2 to C6 would be fine (named "E2.mp3", etc).
27
+ My email can be found on [GitHub](https://github.com/pahkasoft) (visible for signed in users).
28
+
16
29
  ## Installation
17
30
 
18
31
  ```sh
@@ -45,29 +58,35 @@ import * as Pieces from "@tspro/web-music-score/pieces";
45
58
  const Score = require("@tspro/web-music-score/score");
46
59
  ```
47
60
 
48
- ## Browser Script
61
+ ## Browser Modules
62
+
63
+ This lib can be used in browser via unpkg CDN using iife bundle. It declares
64
+ global name `WebMusicScore` that contains `Core`, `Audio`, `Theory`, `Score`,
65
+ and `Pieces` as corresponding subpath modules.
49
66
 
50
- This module that can be used in html page via unpkg CDN. It declares global variable
51
- `WebMusicScore` that contains `Core`, `Audio`, `Theory`, `Score`, and `Pieces` as
52
- corresponding subpath modules (`react-ui` and `audio-cg` are not included in this
53
- browser module).
67
+ React module `react-ui` is not included available for browser usage.
54
68
 
55
69
  ```html
56
70
  <!--
57
- It is recommended to use exact version number so that if something
58
- breaks between versions then your web site does not stop working.
71
+ It is recommended to use exact version number and direct link to the bundle so
72
+ that if something breaks between versions then your web site does not stop working.
59
73
  -->
60
- <script src="https://unpkg.com/@tspro/web-music-score@4.2.0"></script>
74
+ <script src="https://unpkg.com/@tspro/web-music-score@5.0.0/dist/iife/index.global.js"></script>
61
75
 
62
76
  <!--
63
- Or you can use direct link to the js bundle.
77
+ Classical guitar now also available for browser module.
64
78
  -->
65
- <script src="https://unpkg.com/@tspro/web-music-score@4.2.0/dist/iife/index.global.js"></script>
66
-
79
+ <script src="https://unpkg.com/@tspro/web-music-score@5.0.0/dist/iife/audio-cg.global.js"></script>
67
80
 
68
81
  <script>
82
+ // The lib is available via global name WebMusicScore.
69
83
  const { Core, Audio, Theory, Score, Pieces } = window.WebMusicScore;
70
- // ...
84
+
85
+ // Classical guitar audio is available via global name Audio_ClassicalGuitar.
86
+ const { ClassicalGuitar } = window.Audio_ClassicalGuitar;
87
+
88
+ // Add and use classical guitar instrument.
89
+ Audio.addInstrument(ClassicalGuitar);
71
90
  </script>
72
91
  ```
73
92
 
@@ -400,17 +419,32 @@ These are the beam groupings for each time signature.
400
419
  How to set beam grouping for `5/8` and `7/8` time signatures,
401
420
  see [Set Time Signature](#set-time-signature) section above.
402
421
 
403
- ### Classical Guitar Audio Module
422
+ ### Instruments
404
423
 
405
- Default instrument is `Synthesizer`.
424
+ Default instrument `Synthesizer` is available out of the box.
425
+ Other instruments need to be registered manually.
406
426
 
407
427
  `Classical Guitar` is available via `audio-cg` module.
408
- It is included as separate module because it contains over 1MB of guitar audio samples bundled in it.
409
428
 
410
429
  ```js
411
- import { registerClassicalGuitar } from "@tspro/web-music-score/audio-cg";
430
+ // Import classical guitar instrument.
431
+ import { ClassicalGuitar } from "@tspro/web-music-score/audio-cg";
432
+
433
+ // Add and use classical guitar instrument.
434
+ Audio.addInstrument(ClassicalGuitar);
435
+ ```
436
+
437
+ You can easily create and register your own instrument.
438
+ ```js
439
+ class MyCoolInstrument implements Audio.Instrument {
440
+ constructor() { }
441
+ getName() { return "My Cool Instrument"; }
442
+ playNote(note: string, duration: number, linearVolume: number) { }
443
+ stop() { }
444
+ }
412
445
 
413
- registerClassicalGuitar(); // This registers classical guitar audio, and takes it into use.
446
+ // Add and use my cool instrument.
447
+ Audio.addInstrument(new MyCoolInstrument());
414
448
  ```
415
449
 
416
450
  ### Play Document
@@ -1,24 +1,7 @@
1
1
  import { N as Note } from '../note-eA2xPPiG.mjs';
2
+ import { I as Instrument } from '../instrument-DYboobMW.mjs';
3
+ export { l as linearToDecibels } from '../instrument-DYboobMW.mjs';
2
4
 
3
- /** Instrument interface. */
4
- interface Instrument {
5
- /**
6
- * Get instrument name.
7
- * @return - Instrument name.
8
- */
9
- getName(): string;
10
- /**
11
- * Play a note.
12
- * @param note - Note to play (e.g. "C4").
13
- * @param duration - Play duration in seconds.
14
- * @param volume - Linear volume in range [0, 1].
15
- */
16
- playNote(note: string, duration?: number, volume?: number): void;
17
- /**
18
- * Stop playback.
19
- */
20
- stop(): void;
21
- }
22
5
  /**
23
6
  * Get instrument name list.
24
7
  * @returns - Array of available instrument names.
@@ -30,15 +13,15 @@ declare function getInstrumentList(): ReadonlyArray<string>;
30
13
  */
31
14
  declare function getCurrentInstrument(): string;
32
15
  /**
33
- * Register new instrument.
34
- * @param instr - Instrument object implementing Instrument interface.
16
+ * Add and use instrument.
17
+ * @param instrument - Object that implements Instrument interface. Can be single instrument or array of instruments.
35
18
  */
36
- declare function registerInstrument(instr: Instrument): void;
19
+ declare function addInstrument(instrument: Instrument | Instrument[]): void;
37
20
  /**
38
- * Set current instrument to use in playback.
39
- * @param instrName - Instrument name.
21
+ * Set instrument to use in playback.
22
+ * @param instrumentName - Instrument name.
40
23
  */
41
- declare function setInstrument(instrName: string): void;
24
+ declare function useInstrument(instrumentName: string): void;
42
25
  /**
43
26
  * Play a note using current instrument.
44
27
  * @param note - Note instance of Note object, note name (e.g. "C4"), or midiNumber.
@@ -51,4 +34,4 @@ declare function playNote(note: Note | string | number, duration?: number, linea
51
34
  */
52
35
  declare function stop(): void;
53
36
 
54
- export { type Instrument, getCurrentInstrument, getInstrumentList, playNote, registerInstrument, setInstrument, stop };
37
+ export { Instrument, addInstrument, getCurrentInstrument, getInstrumentList, playNote, stop, useInstrument };
@@ -1,24 +1,7 @@
1
1
  import { N as Note } from '../note-eA2xPPiG.js';
2
+ import { I as Instrument } from '../instrument-DYboobMW.js';
3
+ export { l as linearToDecibels } from '../instrument-DYboobMW.js';
2
4
 
3
- /** Instrument interface. */
4
- interface Instrument {
5
- /**
6
- * Get instrument name.
7
- * @return - Instrument name.
8
- */
9
- getName(): string;
10
- /**
11
- * Play a note.
12
- * @param note - Note to play (e.g. "C4").
13
- * @param duration - Play duration in seconds.
14
- * @param volume - Linear volume in range [0, 1].
15
- */
16
- playNote(note: string, duration?: number, volume?: number): void;
17
- /**
18
- * Stop playback.
19
- */
20
- stop(): void;
21
- }
22
5
  /**
23
6
  * Get instrument name list.
24
7
  * @returns - Array of available instrument names.
@@ -30,15 +13,15 @@ declare function getInstrumentList(): ReadonlyArray<string>;
30
13
  */
31
14
  declare function getCurrentInstrument(): string;
32
15
  /**
33
- * Register new instrument.
34
- * @param instr - Instrument object implementing Instrument interface.
16
+ * Add and use instrument.
17
+ * @param instrument - Object that implements Instrument interface. Can be single instrument or array of instruments.
35
18
  */
36
- declare function registerInstrument(instr: Instrument): void;
19
+ declare function addInstrument(instrument: Instrument | Instrument[]): void;
37
20
  /**
38
- * Set current instrument to use in playback.
39
- * @param instrName - Instrument name.
21
+ * Set instrument to use in playback.
22
+ * @param instrumentName - Instrument name.
40
23
  */
41
- declare function setInstrument(instrName: string): void;
24
+ declare function useInstrument(instrumentName: string): void;
42
25
  /**
43
26
  * Play a note using current instrument.
44
27
  * @param note - Note instance of Note object, note name (e.g. "C4"), or midiNumber.
@@ -51,4 +34,4 @@ declare function playNote(note: Note | string | number, duration?: number, linea
51
34
  */
52
35
  declare function stop(): void;
53
36
 
54
- export { type Instrument, getCurrentInstrument, getInstrumentList, playNote, registerInstrument, setInstrument, stop };
37
+ export { Instrument, addInstrument, getCurrentInstrument, getInstrumentList, playNote, stop, useInstrument };
@@ -1,4 +1,4 @@
1
- /* WebMusicScore v4.2.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
1
+ /* WebMusicScore v5.0.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
2
2
  "use strict";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -33,20 +33,27 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
33
33
  // src/audio/index.ts
34
34
  var audio_exports = {};
35
35
  __export(audio_exports, {
36
+ addInstrument: () => addInstrument,
36
37
  getCurrentInstrument: () => getCurrentInstrument,
37
38
  getInstrumentList: () => getInstrumentList,
39
+ linearToDecibels: () => linearToDecibels,
38
40
  playNote: () => playNote,
39
- registerInstrument: () => registerInstrument,
40
- setInstrument: () => setInstrument,
41
- stop: () => stop
41
+ stop: () => stop,
42
+ useInstrument: () => useInstrument
42
43
  });
43
44
  module.exports = __toCommonJS(audio_exports);
44
45
  var import_theory = require("@tspro/web-music-score/theory");
45
46
 
46
- // src/audio/synth.ts
47
+ // src/audio/audio-synth.ts
47
48
  var Tone = __toESM(require("tone"));
48
- var import_ts_utils_lib = require("@tspro/ts-utils-lib");
49
- var Synth2 = class {
49
+
50
+ // src/audio/instrument.ts
51
+ function linearToDecibels(linearVolume) {
52
+ return !isFinite(linearVolume) || linearVolume <= 0 ? -Infinity : 20 * Math.log10(linearVolume);
53
+ }
54
+
55
+ // src/audio/audio-synth.ts
56
+ var SynthesizerInstr = class {
50
57
  constructor() {
51
58
  __publicField(this, "audioSource");
52
59
  try {
@@ -74,10 +81,8 @@ var Synth2 = class {
74
81
  playNote(note, duration, linearVolume) {
75
82
  try {
76
83
  if (this.audioSource) {
77
- if (linearVolume !== void 0) {
78
- this.audioSource.volume.value = import_ts_utils_lib.Utils.Math.linearToDecibels(linearVolume);
79
- }
80
- this.audioSource.triggerAttackRelease(note, duration != null ? duration : "2n");
84
+ this.audioSource.volume.value = linearToDecibels(linearVolume);
85
+ this.audioSource.triggerAttackRelease(note, duration);
81
86
  }
82
87
  } catch (err) {
83
88
  }
@@ -91,10 +96,11 @@ var Synth2 = class {
91
96
  }
92
97
  }
93
98
  };
94
- var Synthesizer = new Synth2();
99
+ var Synthesizer = new SynthesizerInstr();
95
100
 
96
101
  // src/audio/index.ts
97
102
  var import_core = require("@tspro/web-music-score/core");
103
+ var import_ts_utils_lib = require("@tspro/ts-utils-lib");
98
104
  (0, import_core.init)();
99
105
  function getNoteName(note) {
100
106
  if (typeof note === "string") {
@@ -112,36 +118,49 @@ function getInstrumentList() {
112
118
  function getCurrentInstrument() {
113
119
  return CurrentInstrument.getName();
114
120
  }
115
- function registerInstrument(instr) {
116
- if (InstrumentList.some((instr2) => instr2.getName() === instr.getName())) {
117
- return;
118
- }
119
- InstrumentList.push(instr);
120
- setInstrument(instr.getName());
121
+ function addInstrument(instrument) {
122
+ (import_ts_utils_lib.Utils.Is.isArray(instrument) ? instrument : [instrument]).forEach((instr) => {
123
+ if (!import_ts_utils_lib.Utils.Obj.hasProperties(instr, ["getName", "playNote", "stop"]) || !import_ts_utils_lib.Utils.Is.isFunction(instr.getName) || !import_ts_utils_lib.Utils.Is.isFunction(instr.playNote) || !import_ts_utils_lib.Utils.Is.isFunction(instr.stop)) {
124
+ throw new import_core.MusicError(import_core.MusicErrorType.Audio, "Invalid instrument object: " + instr);
125
+ }
126
+ if (InstrumentList.some((instr2) => instr2.getName() === instr.getName())) {
127
+ console.warn(`Instrument "${instr.getName()}" already registered!`);
128
+ } else {
129
+ InstrumentList.push(instr);
130
+ }
131
+ useInstrument(instr.getName());
132
+ });
121
133
  }
122
- function setInstrument(instrName) {
123
- if (instrName === CurrentInstrument.getName()) {
134
+ function useInstrument(instrumentName) {
135
+ if (instrumentName === CurrentInstrument.getName()) {
124
136
  return;
125
137
  }
126
138
  CurrentInstrument.stop();
127
- let instr = InstrumentList.find((instr2) => instr2.getName() === instrName);
139
+ let instr = InstrumentList.find((instr2) => instr2.getName() === instrumentName);
128
140
  if (instr) {
129
141
  CurrentInstrument = instr;
130
142
  }
131
143
  }
144
+ var DefaultDuration = (function calcDuration(noteSize, beatsPerMinute, timeTisgnature) {
145
+ var _a;
146
+ let beatSize = parseInt((_a = timeTisgnature.split("/")[1]) != null ? _a : "4");
147
+ return 60 * (1 / noteSize) / (beatsPerMinute * (1 / beatSize));
148
+ })(2, 80, "4/4");
149
+ var DefaultVolume = 1;
132
150
  function playNote(note, duration, linearVolume) {
133
- CurrentInstrument.playNote(getNoteName(note), duration, linearVolume);
151
+ CurrentInstrument.playNote(getNoteName(note), duration != null ? duration : DefaultDuration, linearVolume != null ? linearVolume : DefaultVolume);
134
152
  }
135
153
  function stop() {
136
154
  CurrentInstrument.stop();
137
155
  }
138
156
  // Annotate the CommonJS export names for ESM import in node:
139
157
  0 && (module.exports = {
158
+ addInstrument,
140
159
  getCurrentInstrument,
141
160
  getInstrumentList,
161
+ linearToDecibels,
142
162
  playNote,
143
- registerInstrument,
144
- setInstrument,
145
- stop
163
+ stop,
164
+ useInstrument
146
165
  });
147
166
  //# sourceMappingURL=index.js.map
@@ -1,15 +1,17 @@
1
- /* WebMusicScore v4.2.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
1
+ /* WebMusicScore v5.0.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
2
+ import {
3
+ linearToDecibels
4
+ } from "../chunk-AAL3CMRO.mjs";
2
5
  import {
3
6
  __publicField
4
- } from "../chunk-5NWLGWHS.mjs";
7
+ } from "../chunk-J3KU3U4W.mjs";
5
8
 
6
9
  // src/audio/index.ts
7
10
  import { Note, PitchNotation, SymbolSet } from "@tspro/web-music-score/theory";
8
11
 
9
- // src/audio/synth.ts
12
+ // src/audio/audio-synth.ts
10
13
  import * as Tone from "tone";
11
- import { Utils } from "@tspro/ts-utils-lib";
12
- var Synth2 = class {
14
+ var SynthesizerInstr = class {
13
15
  constructor() {
14
16
  __publicField(this, "audioSource");
15
17
  try {
@@ -37,10 +39,8 @@ var Synth2 = class {
37
39
  playNote(note, duration, linearVolume) {
38
40
  try {
39
41
  if (this.audioSource) {
40
- if (linearVolume !== void 0) {
41
- this.audioSource.volume.value = Utils.Math.linearToDecibels(linearVolume);
42
- }
43
- this.audioSource.triggerAttackRelease(note, duration != null ? duration : "2n");
42
+ this.audioSource.volume.value = linearToDecibels(linearVolume);
43
+ this.audioSource.triggerAttackRelease(note, duration);
44
44
  }
45
45
  } catch (err) {
46
46
  }
@@ -54,10 +54,11 @@ var Synth2 = class {
54
54
  }
55
55
  }
56
56
  };
57
- var Synthesizer = new Synth2();
57
+ var Synthesizer = new SynthesizerInstr();
58
58
 
59
59
  // src/audio/index.ts
60
- import { init as initCore } from "@tspro/web-music-score/core";
60
+ import { init as initCore, MusicError, MusicErrorType } from "@tspro/web-music-score/core";
61
+ import { Utils } from "@tspro/ts-utils-lib";
61
62
  initCore();
62
63
  function getNoteName(note) {
63
64
  if (typeof note === "string") {
@@ -75,35 +76,48 @@ function getInstrumentList() {
75
76
  function getCurrentInstrument() {
76
77
  return CurrentInstrument.getName();
77
78
  }
78
- function registerInstrument(instr) {
79
- if (InstrumentList.some((instr2) => instr2.getName() === instr.getName())) {
80
- return;
81
- }
82
- InstrumentList.push(instr);
83
- setInstrument(instr.getName());
79
+ function addInstrument(instrument) {
80
+ (Utils.Is.isArray(instrument) ? instrument : [instrument]).forEach((instr) => {
81
+ if (!Utils.Obj.hasProperties(instr, ["getName", "playNote", "stop"]) || !Utils.Is.isFunction(instr.getName) || !Utils.Is.isFunction(instr.playNote) || !Utils.Is.isFunction(instr.stop)) {
82
+ throw new MusicError(MusicErrorType.Audio, "Invalid instrument object: " + instr);
83
+ }
84
+ if (InstrumentList.some((instr2) => instr2.getName() === instr.getName())) {
85
+ console.warn(`Instrument "${instr.getName()}" already registered!`);
86
+ } else {
87
+ InstrumentList.push(instr);
88
+ }
89
+ useInstrument(instr.getName());
90
+ });
84
91
  }
85
- function setInstrument(instrName) {
86
- if (instrName === CurrentInstrument.getName()) {
92
+ function useInstrument(instrumentName) {
93
+ if (instrumentName === CurrentInstrument.getName()) {
87
94
  return;
88
95
  }
89
96
  CurrentInstrument.stop();
90
- let instr = InstrumentList.find((instr2) => instr2.getName() === instrName);
97
+ let instr = InstrumentList.find((instr2) => instr2.getName() === instrumentName);
91
98
  if (instr) {
92
99
  CurrentInstrument = instr;
93
100
  }
94
101
  }
102
+ var DefaultDuration = (function calcDuration(noteSize, beatsPerMinute, timeTisgnature) {
103
+ var _a;
104
+ let beatSize = parseInt((_a = timeTisgnature.split("/")[1]) != null ? _a : "4");
105
+ return 60 * (1 / noteSize) / (beatsPerMinute * (1 / beatSize));
106
+ })(2, 80, "4/4");
107
+ var DefaultVolume = 1;
95
108
  function playNote(note, duration, linearVolume) {
96
- CurrentInstrument.playNote(getNoteName(note), duration, linearVolume);
109
+ CurrentInstrument.playNote(getNoteName(note), duration != null ? duration : DefaultDuration, linearVolume != null ? linearVolume : DefaultVolume);
97
110
  }
98
111
  function stop() {
99
112
  CurrentInstrument.stop();
100
113
  }
101
114
  export {
115
+ addInstrument,
102
116
  getCurrentInstrument,
103
117
  getInstrumentList,
118
+ linearToDecibels,
104
119
  playNote,
105
- registerInstrument,
106
- setInstrument,
107
- stop
120
+ stop,
121
+ useInstrument
108
122
  };
109
123
  //# sourceMappingURL=index.mjs.map
@@ -1,6 +1,16 @@
1
+ import { I as Instrument } from '../instrument-DYboobMW.mjs';
2
+
1
3
  /**
2
- * Register classical guitar audio instrument, and set is as current instrument.
4
+ * Default export is the classical guitar instrument object.
5
+ *
6
+ * ```ts
7
+ * // Usage
8
+ * import * as Audio from "@tspro/web-music-score/audio";
9
+ * import { ClassicalGuitar } from "@tspro/web-music-score/audio-cg";
10
+ *
11
+ * Audio.addInstrument(ClassicalGuitar);
12
+ * ```
3
13
  */
4
- declare function registerClassicalGuitar(): void;
14
+ declare const ClassicalGuitar: Instrument;
5
15
 
6
- export { registerClassicalGuitar };
16
+ export { ClassicalGuitar };
@@ -1,6 +1,16 @@
1
+ import { I as Instrument } from '../instrument-DYboobMW.js';
2
+
1
3
  /**
2
- * Register classical guitar audio instrument, and set is as current instrument.
4
+ * Default export is the classical guitar instrument object.
5
+ *
6
+ * ```ts
7
+ * // Usage
8
+ * import * as Audio from "@tspro/web-music-score/audio";
9
+ * import { ClassicalGuitar } from "@tspro/web-music-score/audio-cg";
10
+ *
11
+ * Audio.addInstrument(ClassicalGuitar);
12
+ * ```
3
13
  */
4
- declare function registerClassicalGuitar(): void;
14
+ declare const ClassicalGuitar: Instrument;
5
15
 
6
- export { registerClassicalGuitar };
16
+ export { ClassicalGuitar };