@mulsense/xnew 0.4.8 → 0.5.1

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/README.md CHANGED
@@ -13,7 +13,7 @@ providing a flexible architecture well-suited for applications with dynamic scen
13
13
  ### Via CDN
14
14
  Include the following script in your HTML file:
15
15
  ```html
16
- <script src="https://unpkg.com/@mulsense/xnew@0.4.x/dist/xnew.js"></script>
16
+ <script src="https://unpkg.com/@mulsense/xnew@0.5.x/dist/xnew.js"></script>
17
17
  ```
18
18
 
19
19
  ### Via CDN (ESM)
@@ -22,7 +22,7 @@ Use the ES module version with an import map:
22
22
  <script type="importmap">
23
23
  {
24
24
  "imports": {
25
- "@mulsense/xnew": "https://unpkg.com/@mulsense/xnew@0.4.x/dist/xnew.mjs"
25
+ "@mulsense/xnew": "https://unpkg.com/@mulsense/xnew@0.5.x/dist/xnew.mjs"
26
26
  }
27
27
  }
28
28
  </script>
@@ -37,7 +37,7 @@ import xnew from '@mulsense/xnew';
37
37
  ### Via npm
38
38
  Install `xnew` using npm:
39
39
  ```bash
40
- npm install @mulsense/xnew@0.4.x
40
+ npm install @mulsense/xnew@0.5.x
41
41
  ```
42
42
 
43
43
  Then import it in your JavaScript file:
package/dist/xnew.js CHANGED
@@ -206,8 +206,6 @@
206
206
  }
207
207
  }
208
208
 
209
- const SYSTEM_EVENTS = ['start', 'update', 'render', 'stop', 'finalize'];
210
-
211
209
  class EventManager {
212
210
  constructor() {
213
211
  this.map = new MapMap();
@@ -524,6 +522,10 @@
524
522
  return { position };
525
523
  }
526
524
 
525
+ //----------------------------------------------------------------------------------------------------
526
+ // utils
527
+ //----------------------------------------------------------------------------------------------------
528
+ const SYSTEM_EVENTS = ['start', 'update', 'render', 'stop', 'finalize'];
527
529
  //----------------------------------------------------------------------------------------------------
528
530
  // unit
529
531
  //----------------------------------------------------------------------------------------------------
@@ -632,11 +634,11 @@
632
634
  unit._.state = 'finalized';
633
635
  }
634
636
  }
635
- static nest(unit, tag) {
637
+ static nest(unit, htmlString, textContent) {
636
638
  if (unit._.state !== 'invoked') {
637
639
  throw new Error('This function can not be called after initialized.');
638
640
  }
639
- const match = tag.match(/<((\w+)[^>]*?)\/?>/);
641
+ const match = htmlString.match(/<((\w+)[^>]*?)\/?>/);
640
642
  if (match !== null) {
641
643
  let element;
642
644
  if (unit._.anchor !== null) {
@@ -649,11 +651,14 @@
649
651
  element = unit._.currentElement.children[unit._.currentElement.children.length - 1];
650
652
  }
651
653
  unit._.currentElement = element;
654
+ if (textContent !== undefined) {
655
+ element.textContent = textContent;
656
+ }
652
657
  unit._.elements.push(element);
653
658
  return element;
654
659
  }
655
660
  else {
656
- throw new Error(`Invalid tag: ${tag}`);
661
+ throw new Error(`Invalid html string: ${htmlString}`);
657
662
  }
658
663
  }
659
664
  static extend(unit, component, props) {
@@ -930,12 +935,6 @@
930
935
  else if (typeof args[0] === 'string' && args[0].match(/<((\w+)[^>]*?)\/?>/)) {
931
936
  target = args.shift();
932
937
  }
933
- else if (typeof args[0] === 'string') {
934
- const query = args.shift();
935
- target = document.querySelector(query);
936
- if (target === null)
937
- throw new Error(`'${query}' can not be found.`);
938
- }
939
938
  else {
940
939
  target = null;
941
940
  }
@@ -951,19 +950,19 @@
951
950
  }, {
952
951
  /**
953
952
  * Creates a nested HTML/SVG element within the current component
954
- * @param tag - HTML or SVG tag name (e.g., '<div>', '<span>', '<svg>')
953
+ * @param htmlString - HTML or SVG tag name (e.g., '<div>', '<span>', '<svg>')
955
954
  * @returns The created HTML/SVG element
956
955
  * @throws Error if called after component initialization
957
956
  * @example
958
957
  * const div = xnew.nest('<div>')
959
958
  * div.textContent = 'Hello'
960
959
  */
961
- nest(tag) {
960
+ nest(htmlString, textContent) {
962
961
  try {
963
- return Unit.nest(Unit.currentUnit, tag);
962
+ return Unit.nest(Unit.currentUnit, htmlString, textContent);
964
963
  }
965
964
  catch (error) {
966
- console.error('xnew.nest(tag: string): ', error);
965
+ console.error('xnew.nest(htmlString: string): ', error);
967
966
  throw error;
968
967
  }
969
968
  },
@@ -1376,51 +1375,6 @@
1376
1375
  });
1377
1376
  }
1378
1377
 
1379
- function TextStream(unit, { text = '', speed = 50, fade = 300 } = {}) {
1380
- const chars = [];
1381
- for (let i = 0; i < text.length; i++) {
1382
- const unit = xnew$1('<span>');
1383
- unit.element.textContent = text[i];
1384
- unit.element.style.opacity = '0';
1385
- unit.element.style.transition = `opacity ${fade}ms ease-in-out`;
1386
- chars.push(unit);
1387
- }
1388
- let start = 0;
1389
- unit.on('start', () => {
1390
- start = new Date().getTime();
1391
- });
1392
- let state = 0;
1393
- unit.on('update', () => {
1394
- const index = Math.floor((new Date().getTime() - start) / speed);
1395
- // Display characters up to the current index (fade in)
1396
- for (let i = 0; i < chars.length; i++) {
1397
- if (i <= index) {
1398
- chars[i].element.style.opacity = '1';
1399
- }
1400
- }
1401
- if (state === 0 && index >= text.length) {
1402
- action();
1403
- }
1404
- });
1405
- xnew$1.timeout(() => {
1406
- xnew$1(document.body).on('click wheel', action);
1407
- unit.on('keydown', action);
1408
- }, 100);
1409
- function action() {
1410
- if (state === 0) {
1411
- state = 1;
1412
- for (let i = 0; i < chars.length; i++) {
1413
- chars[i].element.style.opacity = '1';
1414
- }
1415
- xnew$1.emit('-complete');
1416
- }
1417
- else if (state === 1) {
1418
- state = 2;
1419
- xnew$1.emit('-next');
1420
- }
1421
- }
1422
- }
1423
-
1424
1378
  const context = new window.AudioContext();
1425
1379
  const master = context.createGain();
1426
1380
  //----------------------------------------------------------------------------------------------------
@@ -1649,7 +1603,6 @@
1649
1603
  Screen,
1650
1604
  Modal,
1651
1605
  Accordion,
1652
- TextStream,
1653
1606
  AnalogStick,
1654
1607
  DirectionalPad,
1655
1608
  };
@@ -1680,16 +1633,7 @@
1680
1633
  master.gain.value = value;
1681
1634
  }
1682
1635
  };
1683
- const temp = Object.assign(xnew$1, { basics, audio });
1684
- Object.defineProperty(temp, 'global', {
1685
- get: function () {
1686
- return temp.context('xnew.global');
1687
- },
1688
- set: function (value) {
1689
- temp.context('xnew.global', value);
1690
- }
1691
- });
1692
- const xnew = temp;
1636
+ const xnew = Object.assign(xnew$1, { basics, audio });
1693
1637
 
1694
1638
  return xnew;
1695
1639
 
package/dist/xnew.mjs CHANGED
@@ -200,8 +200,6 @@ class Timer {
200
200
  }
201
201
  }
202
202
 
203
- const SYSTEM_EVENTS = ['start', 'update', 'render', 'stop', 'finalize'];
204
-
205
203
  class EventManager {
206
204
  constructor() {
207
205
  this.map = new MapMap();
@@ -518,6 +516,10 @@ function pointer(element, event) {
518
516
  return { position };
519
517
  }
520
518
 
519
+ //----------------------------------------------------------------------------------------------------
520
+ // utils
521
+ //----------------------------------------------------------------------------------------------------
522
+ const SYSTEM_EVENTS = ['start', 'update', 'render', 'stop', 'finalize'];
521
523
  //----------------------------------------------------------------------------------------------------
522
524
  // unit
523
525
  //----------------------------------------------------------------------------------------------------
@@ -626,11 +628,11 @@ class Unit {
626
628
  unit._.state = 'finalized';
627
629
  }
628
630
  }
629
- static nest(unit, tag) {
631
+ static nest(unit, htmlString, textContent) {
630
632
  if (unit._.state !== 'invoked') {
631
633
  throw new Error('This function can not be called after initialized.');
632
634
  }
633
- const match = tag.match(/<((\w+)[^>]*?)\/?>/);
635
+ const match = htmlString.match(/<((\w+)[^>]*?)\/?>/);
634
636
  if (match !== null) {
635
637
  let element;
636
638
  if (unit._.anchor !== null) {
@@ -643,11 +645,14 @@ class Unit {
643
645
  element = unit._.currentElement.children[unit._.currentElement.children.length - 1];
644
646
  }
645
647
  unit._.currentElement = element;
648
+ if (textContent !== undefined) {
649
+ element.textContent = textContent;
650
+ }
646
651
  unit._.elements.push(element);
647
652
  return element;
648
653
  }
649
654
  else {
650
- throw new Error(`Invalid tag: ${tag}`);
655
+ throw new Error(`Invalid html string: ${htmlString}`);
651
656
  }
652
657
  }
653
658
  static extend(unit, component, props) {
@@ -924,12 +929,6 @@ function parseArguments(...args) {
924
929
  else if (typeof args[0] === 'string' && args[0].match(/<((\w+)[^>]*?)\/?>/)) {
925
930
  target = args.shift();
926
931
  }
927
- else if (typeof args[0] === 'string') {
928
- const query = args.shift();
929
- target = document.querySelector(query);
930
- if (target === null)
931
- throw new Error(`'${query}' can not be found.`);
932
- }
933
932
  else {
934
933
  target = null;
935
934
  }
@@ -945,19 +944,19 @@ const xnew$1 = Object.assign(function (...args) {
945
944
  }, {
946
945
  /**
947
946
  * Creates a nested HTML/SVG element within the current component
948
- * @param tag - HTML or SVG tag name (e.g., '<div>', '<span>', '<svg>')
947
+ * @param htmlString - HTML or SVG tag name (e.g., '<div>', '<span>', '<svg>')
949
948
  * @returns The created HTML/SVG element
950
949
  * @throws Error if called after component initialization
951
950
  * @example
952
951
  * const div = xnew.nest('<div>')
953
952
  * div.textContent = 'Hello'
954
953
  */
955
- nest(tag) {
954
+ nest(htmlString, textContent) {
956
955
  try {
957
- return Unit.nest(Unit.currentUnit, tag);
956
+ return Unit.nest(Unit.currentUnit, htmlString, textContent);
958
957
  }
959
958
  catch (error) {
960
- console.error('xnew.nest(tag: string): ', error);
959
+ console.error('xnew.nest(htmlString: string): ', error);
961
960
  throw error;
962
961
  }
963
962
  },
@@ -1370,51 +1369,6 @@ function DirectionalPad(unit, { diagonal = true, stroke = 'currentColor', stroke
1370
1369
  });
1371
1370
  }
1372
1371
 
1373
- function TextStream(unit, { text = '', speed = 50, fade = 300 } = {}) {
1374
- const chars = [];
1375
- for (let i = 0; i < text.length; i++) {
1376
- const unit = xnew$1('<span>');
1377
- unit.element.textContent = text[i];
1378
- unit.element.style.opacity = '0';
1379
- unit.element.style.transition = `opacity ${fade}ms ease-in-out`;
1380
- chars.push(unit);
1381
- }
1382
- let start = 0;
1383
- unit.on('start', () => {
1384
- start = new Date().getTime();
1385
- });
1386
- let state = 0;
1387
- unit.on('update', () => {
1388
- const index = Math.floor((new Date().getTime() - start) / speed);
1389
- // Display characters up to the current index (fade in)
1390
- for (let i = 0; i < chars.length; i++) {
1391
- if (i <= index) {
1392
- chars[i].element.style.opacity = '1';
1393
- }
1394
- }
1395
- if (state === 0 && index >= text.length) {
1396
- action();
1397
- }
1398
- });
1399
- xnew$1.timeout(() => {
1400
- xnew$1(document.body).on('click wheel', action);
1401
- unit.on('keydown', action);
1402
- }, 100);
1403
- function action() {
1404
- if (state === 0) {
1405
- state = 1;
1406
- for (let i = 0; i < chars.length; i++) {
1407
- chars[i].element.style.opacity = '1';
1408
- }
1409
- xnew$1.emit('-complete');
1410
- }
1411
- else if (state === 1) {
1412
- state = 2;
1413
- xnew$1.emit('-next');
1414
- }
1415
- }
1416
- }
1417
-
1418
1372
  const context = new window.AudioContext();
1419
1373
  const master = context.createGain();
1420
1374
  //----------------------------------------------------------------------------------------------------
@@ -1643,7 +1597,6 @@ const basics = {
1643
1597
  Screen,
1644
1598
  Modal,
1645
1599
  Accordion,
1646
- TextStream,
1647
1600
  AnalogStick,
1648
1601
  DirectionalPad,
1649
1602
  };
@@ -1674,15 +1627,6 @@ const audio = {
1674
1627
  master.gain.value = value;
1675
1628
  }
1676
1629
  };
1677
- const temp = Object.assign(xnew$1, { basics, audio });
1678
- Object.defineProperty(temp, 'global', {
1679
- get: function () {
1680
- return temp.context('xnew.global');
1681
- },
1682
- set: function (value) {
1683
- temp.context('xnew.global', value);
1684
- }
1685
- });
1686
- const xnew = temp;
1630
+ const xnew = Object.assign(xnew$1, { basics, audio });
1687
1631
 
1688
1632
  export { xnew as default };
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "keywords": [
5
5
  "Component-Oriented Programming"
6
6
  ],
7
- "version": "0.4.8",
7
+ "version": "0.5.1",
8
8
  "main": "dist/xnew.js",
9
9
  "module": "dist/xnew.mjs",
10
10
  "types": "dist/xnew.d.ts",
@@ -1,53 +0,0 @@
1
- declare const _default: {
2
- load(path: string): {
3
- promise: Promise<any>;
4
- component: Function | null;
5
- then(callback: Function): /*elided*/ any;
6
- catch(callback: Function): /*elided*/ any;
7
- finally(callback: Function): /*elided*/ any;
8
- };
9
- synthesizer(props: SynthesizerOptions): Synthesizer;
10
- volume: number;
11
- };
12
-
13
- type SynthesizerOptions = {
14
- oscillator: OscillatorOptions;
15
- amp: AmpOptions;
16
- filter?: FilterOptions;
17
- reverb?: ReverbOptions;
18
- bpm?: number;
19
- };
20
- type OscillatorOptions = {
21
- type: OscillatorType;
22
- envelope?: Envelope;
23
- LFO?: LFO;
24
- };
25
- type FilterOptions = {
26
- type: BiquadFilterType;
27
- cutoff: number;
28
- };
29
- type AmpOptions = {
30
- envelope: Envelope;
31
- };
32
- type ReverbOptions = {
33
- time: number;
34
- mix: number;
35
- };
36
- type Envelope = {
37
- amount: number;
38
- ADSR: [number, number, number, number];
39
- };
40
- type LFO = {
41
- amount: number;
42
- type: OscillatorType;
43
- rate: number;
44
- };
45
- declare class Synthesizer {
46
- props: SynthesizerOptions;
47
- constructor(props: SynthesizerOptions);
48
- press(frequency: number | string, duration?: number | string, wait?: number): {
49
- release: () => void;
50
- } | undefined;
51
- }
52
-
53
- export { _default as default };
@@ -1,256 +0,0 @@
1
- (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@mulsense/xnew')) :
3
- typeof define === 'function' && define.amd ? define(['@mulsense/xnew'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.xaudio = factory(global.xnew));
5
- })(this, (function (xnew) { 'use strict';
6
-
7
- var xaudio = {
8
- load(path) {
9
- const music = new AudioFile(path);
10
- const object = {
11
- play(options) {
12
- const unit = xnew();
13
- if (music.played === null) {
14
- music.play(options);
15
- unit.on('finalize', () => music.pause({ fade: options.fade }));
16
- }
17
- },
18
- pause(options) {
19
- music.pause(options);
20
- }
21
- };
22
- return xnew.promise(music.promise).then(() => object);
23
- },
24
- synthesizer(props) {
25
- return new Synthesizer(props);
26
- },
27
- get volume() {
28
- return master.gain.value;
29
- },
30
- set volume(value) {
31
- master.gain.value = value;
32
- }
33
- };
34
- const context = window.AudioContext ? new window.AudioContext() : (null);
35
- const master = context ? context.createGain() : (null);
36
- if (context) {
37
- master.gain.value = 0.1;
38
- master.connect(context.destination);
39
- }
40
- class AudioFile {
41
- constructor(path) {
42
- this.promise = fetch(path)
43
- .then((response) => response.arrayBuffer())
44
- .then((response) => context.decodeAudioData(response))
45
- .then((response) => { this.buffer = response; })
46
- .catch(() => {
47
- console.warn(`"${path}" could not be loaded.`);
48
- });
49
- this.amp = context.createGain();
50
- this.amp.gain.value = 1.0;
51
- this.amp.connect(master);
52
- this.fade = context.createGain();
53
- this.fade.gain.value = 1.0;
54
- this.fade.connect(this.amp);
55
- this.source = null;
56
- this.played = null;
57
- }
58
- set volume(value) {
59
- this.amp.gain.value = value;
60
- }
61
- get volume() {
62
- return this.amp.gain.value;
63
- }
64
- play({ offset = 0, fade = 0, loop = false } = {}) {
65
- if (this.buffer !== undefined && this.played === null) {
66
- this.source = context.createBufferSource();
67
- this.source.buffer = this.buffer;
68
- this.source.loop = loop;
69
- this.source.connect(this.fade);
70
- this.played = context.currentTime;
71
- this.source.playbackRate.value = 1;
72
- this.source.start(context.currentTime, offset / 1000);
73
- // Apply fade-in effect if fade duration is specified
74
- if (fade > 0) {
75
- this.fade.gain.setValueAtTime(0, context.currentTime);
76
- this.fade.gain.linearRampToValueAtTime(1.0, context.currentTime + fade / 1000);
77
- }
78
- this.source.onended = () => {
79
- var _a;
80
- this.played = null;
81
- (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
82
- this.source = null;
83
- };
84
- }
85
- }
86
- pause({ fade = 0 } = {}) {
87
- var _a, _b;
88
- if (this.buffer !== undefined && this.played !== null) {
89
- const elapsed = (context.currentTime - this.played) % this.buffer.duration * 1000;
90
- // Apply fade-out effect if fade duration is specified
91
- if (fade > 0) {
92
- this.fade.gain.setValueAtTime(1.0, context.currentTime);
93
- this.fade.gain.linearRampToValueAtTime(0, context.currentTime + fade / 1000);
94
- (_a = this.source) === null || _a === void 0 ? void 0 : _a.stop(context.currentTime + fade / 1000);
95
- }
96
- else {
97
- (_b = this.source) === null || _b === void 0 ? void 0 : _b.stop(context.currentTime);
98
- }
99
- this.played = null;
100
- return elapsed;
101
- }
102
- }
103
- clear() {
104
- var _a;
105
- this.amp.disconnect();
106
- this.fade.disconnect();
107
- (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
108
- }
109
- }
110
- const keymap = {
111
- 'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
112
- 'C1': 32.703, 'C#1': 34.648, 'D1': 36.708, 'D#1': 38.891, 'E1': 41.203, 'F1': 43.654, 'F#1': 46.249, 'G1': 48.999, 'G#1': 51.913, 'A1': 55.000, 'A#1': 58.270, 'B1': 61.735,
113
- 'C2': 65.406, 'C#2': 69.296, 'D2': 73.416, 'D#2': 77.782, 'E2': 82.407, 'F2': 87.307, 'F#2': 92.499, 'G2': 97.999, 'G#2': 103.826, 'A2': 110.000, 'A#2': 116.541, 'B2': 123.471,
114
- 'C3': 130.813, 'C#3': 138.591, 'D3': 146.832, 'D#3': 155.563, 'E3': 164.814, 'F3': 174.614, 'F#3': 184.997, 'G3': 195.998, 'G#3': 207.652, 'A3': 220.000, 'A#3': 233.082, 'B3': 246.942,
115
- 'C4': 261.626, 'C#4': 277.183, 'D4': 293.665, 'D#4': 311.127, 'E4': 329.628, 'F4': 349.228, 'F#4': 369.994, 'G4': 391.995, 'G#4': 415.305, 'A4': 440.000, 'A#4': 466.164, 'B4': 493.883,
116
- 'C5': 523.251, 'C#5': 554.365, 'D5': 587.330, 'D#5': 622.254, 'E5': 659.255, 'F5': 698.456, 'F#5': 739.989, 'G5': 783.991, 'G#5': 830.609, 'A5': 880.000, 'A#5': 932.328, 'B5': 987.767,
117
- 'C6': 1046.502, 'C#6': 1108.731, 'D6': 1174.659, 'D#6': 1244.508, 'E6': 1318.510, 'F6': 1396.913, 'F#6': 1479.978, 'G6': 1567.982, 'G#6': 1661.219, 'A6': 1760.000, 'A#6': 1864.655, 'B6': 1975.533,
118
- 'C7': 2093.005, 'C#7': 2217.461, 'D7': 2349.318, 'D#7': 2489.016, 'E7': 2637.020, 'F7': 2793.826, 'F#7': 2959.955, 'G7': 3135.963, 'G#7': 3322.438, 'A7': 3520.000, 'A#7': 3729.310, 'B7': 3951.066,
119
- 'C8': 4186.009,
120
- };
121
- const notemap = {
122
- '1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
123
- };
124
- class Synthesizer {
125
- constructor(props) { this.props = props; }
126
- press(frequency, duration, wait) {
127
- var _a;
128
- const props = this.props;
129
- const fv = typeof frequency === 'string' ? keymap[frequency] : frequency;
130
- const dv = typeof duration === 'string' ? (notemap[duration] * 60 / ((_a = props.bpm) !== null && _a !== void 0 ? _a : 120)) : (typeof duration === 'number' ? (duration / 1000) : 0);
131
- const start = context.currentTime + (wait !== null && wait !== void 0 ? wait : 0) / 1000;
132
- const nodes = {};
133
- nodes.oscillator = context.createOscillator();
134
- nodes.oscillator.type = props.oscillator.type;
135
- nodes.oscillator.frequency.value = fv;
136
- if (props.oscillator.LFO) {
137
- nodes.oscillatorLFO = context.createOscillator();
138
- nodes.oscillatorLFODepth = context.createGain();
139
- nodes.oscillatorLFODepth.gain.value = fv * (Math.pow(2.0, props.oscillator.LFO.amount / 12.0) - 1.0);
140
- nodes.oscillatorLFO.type = props.oscillator.LFO.type;
141
- nodes.oscillatorLFO.frequency.value = props.oscillator.LFO.rate;
142
- nodes.oscillatorLFO.start(start);
143
- nodes.oscillatorLFO.connect(nodes.oscillatorLFODepth);
144
- nodes.oscillatorLFODepth.connect(nodes.oscillator.frequency);
145
- }
146
- nodes.amp = context.createGain();
147
- nodes.amp.gain.value = 0.0;
148
- nodes.target = context.createGain();
149
- nodes.target.gain.value = 1.0;
150
- nodes.amp.connect(nodes.target);
151
- nodes.target.connect(master);
152
- if (props.filter) {
153
- nodes.filter = context.createBiquadFilter();
154
- nodes.filter.type = props.filter.type;
155
- nodes.filter.frequency.value = props.filter.cutoff;
156
- nodes.oscillator.connect(nodes.filter);
157
- nodes.filter.connect(nodes.amp);
158
- }
159
- else {
160
- nodes.oscillator.connect(nodes.amp);
161
- }
162
- if (props.reverb) {
163
- nodes.convolver = context.createConvolver();
164
- nodes.convolver.buffer = impulseResponse({ time: props.reverb.time });
165
- nodes.convolverDepth = context.createGain();
166
- nodes.convolverDepth.gain.value = 1.0;
167
- nodes.convolverDepth.gain.value *= props.reverb.mix;
168
- nodes.target.gain.value *= (1.0 - props.reverb.mix);
169
- nodes.amp.connect(nodes.convolver);
170
- nodes.convolver.connect(nodes.convolverDepth);
171
- nodes.convolverDepth.connect(master);
172
- }
173
- if (props.oscillator.envelope) {
174
- const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
175
- startEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
176
- }
177
- if (props.amp.envelope) {
178
- startEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
179
- }
180
- nodes.oscillator.start(start);
181
- if (dv > 0) {
182
- release();
183
- }
184
- else {
185
- return { release };
186
- }
187
- function release() {
188
- let stop = null;
189
- const end = dv > 0 ? dv : (context.currentTime - start);
190
- if (props.amp.envelope) {
191
- const ADSR = props.amp.envelope.ADSR;
192
- const adsr = [ADSR[0] / 1000, ADSR[1] / 1000, ADSR[2], ADSR[3] / 1000];
193
- const rate = adsr[0] === 0.0 ? 1.0 : Math.min(end / (adsr[0] + 0.001), 1.0);
194
- stop = start + Math.max((adsr[0] + adsr[1]) * rate, end) + adsr[3];
195
- }
196
- else {
197
- stop = start + end;
198
- }
199
- if (nodes.oscillatorLFO) {
200
- nodes.oscillatorLFO.stop(stop);
201
- }
202
- if (props.oscillator.envelope) {
203
- const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
204
- stopEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
205
- }
206
- if (props.amp.envelope) {
207
- stopEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
208
- }
209
- nodes.oscillator.stop(stop);
210
- setTimeout(() => {
211
- var _a, _b, _c, _d, _e;
212
- nodes.oscillator.disconnect();
213
- nodes.amp.disconnect();
214
- nodes.target.disconnect();
215
- (_a = nodes.oscillatorLFO) === null || _a === void 0 ? void 0 : _a.disconnect();
216
- (_b = nodes.oscillatorLFODepth) === null || _b === void 0 ? void 0 : _b.disconnect();
217
- (_c = nodes.filter) === null || _c === void 0 ? void 0 : _c.disconnect();
218
- (_d = nodes.convolver) === null || _d === void 0 ? void 0 : _d.disconnect();
219
- (_e = nodes.convolverDepth) === null || _e === void 0 ? void 0 : _e.disconnect();
220
- }, 2000);
221
- }
222
- function stopEnvelope(param, base, amount, ADSR) {
223
- const end = dv > 0 ? dv : (context.currentTime - start);
224
- const rate = ADSR[0] === 0.0 ? 1.0 : Math.min(end / (ADSR[0] / 1000), 1.0);
225
- if (rate < 1.0) {
226
- param.cancelScheduledValues(start);
227
- param.setValueAtTime(base, start);
228
- param.linearRampToValueAtTime(base + amount * rate, start + ADSR[0] / 1000 * rate);
229
- param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000 * rate);
230
- }
231
- param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dv));
232
- param.linearRampToValueAtTime(base, start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, end) + ADSR[3] / 1000);
233
- }
234
- function startEnvelope(param, base, amount, ADSR) {
235
- param.value = base;
236
- param.setValueAtTime(base, start);
237
- param.linearRampToValueAtTime(base + amount, start + ADSR[0] / 1000);
238
- param.linearRampToValueAtTime(base + amount * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000);
239
- }
240
- function impulseResponse({ time, decay = 2.0 }) {
241
- const length = context.sampleRate * time / 1000;
242
- const impulse = context.createBuffer(2, length, context.sampleRate);
243
- const ch0 = impulse.getChannelData(0);
244
- const ch1 = impulse.getChannelData(1);
245
- for (let i = 0; i < length; i++) {
246
- ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
247
- ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
248
- }
249
- return impulse;
250
- }
251
- }
252
- }
253
-
254
- return xaudio;
255
-
256
- }));
@@ -1,250 +0,0 @@
1
- import xnew from '@mulsense/xnew';
2
-
3
- var xaudio = {
4
- load(path) {
5
- const music = new AudioFile(path);
6
- const object = {
7
- play(options) {
8
- const unit = xnew();
9
- if (music.played === null) {
10
- music.play(options);
11
- unit.on('finalize', () => music.pause({ fade: options.fade }));
12
- }
13
- },
14
- pause(options) {
15
- music.pause(options);
16
- }
17
- };
18
- return xnew.promise(music.promise).then(() => object);
19
- },
20
- synthesizer(props) {
21
- return new Synthesizer(props);
22
- },
23
- get volume() {
24
- return master.gain.value;
25
- },
26
- set volume(value) {
27
- master.gain.value = value;
28
- }
29
- };
30
- const context = window.AudioContext ? new window.AudioContext() : (null);
31
- const master = context ? context.createGain() : (null);
32
- if (context) {
33
- master.gain.value = 0.1;
34
- master.connect(context.destination);
35
- }
36
- class AudioFile {
37
- constructor(path) {
38
- this.promise = fetch(path)
39
- .then((response) => response.arrayBuffer())
40
- .then((response) => context.decodeAudioData(response))
41
- .then((response) => { this.buffer = response; })
42
- .catch(() => {
43
- console.warn(`"${path}" could not be loaded.`);
44
- });
45
- this.amp = context.createGain();
46
- this.amp.gain.value = 1.0;
47
- this.amp.connect(master);
48
- this.fade = context.createGain();
49
- this.fade.gain.value = 1.0;
50
- this.fade.connect(this.amp);
51
- this.source = null;
52
- this.played = null;
53
- }
54
- set volume(value) {
55
- this.amp.gain.value = value;
56
- }
57
- get volume() {
58
- return this.amp.gain.value;
59
- }
60
- play({ offset = 0, fade = 0, loop = false } = {}) {
61
- if (this.buffer !== undefined && this.played === null) {
62
- this.source = context.createBufferSource();
63
- this.source.buffer = this.buffer;
64
- this.source.loop = loop;
65
- this.source.connect(this.fade);
66
- this.played = context.currentTime;
67
- this.source.playbackRate.value = 1;
68
- this.source.start(context.currentTime, offset / 1000);
69
- // Apply fade-in effect if fade duration is specified
70
- if (fade > 0) {
71
- this.fade.gain.setValueAtTime(0, context.currentTime);
72
- this.fade.gain.linearRampToValueAtTime(1.0, context.currentTime + fade / 1000);
73
- }
74
- this.source.onended = () => {
75
- var _a;
76
- this.played = null;
77
- (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
78
- this.source = null;
79
- };
80
- }
81
- }
82
- pause({ fade = 0 } = {}) {
83
- var _a, _b;
84
- if (this.buffer !== undefined && this.played !== null) {
85
- const elapsed = (context.currentTime - this.played) % this.buffer.duration * 1000;
86
- // Apply fade-out effect if fade duration is specified
87
- if (fade > 0) {
88
- this.fade.gain.setValueAtTime(1.0, context.currentTime);
89
- this.fade.gain.linearRampToValueAtTime(0, context.currentTime + fade / 1000);
90
- (_a = this.source) === null || _a === void 0 ? void 0 : _a.stop(context.currentTime + fade / 1000);
91
- }
92
- else {
93
- (_b = this.source) === null || _b === void 0 ? void 0 : _b.stop(context.currentTime);
94
- }
95
- this.played = null;
96
- return elapsed;
97
- }
98
- }
99
- clear() {
100
- var _a;
101
- this.amp.disconnect();
102
- this.fade.disconnect();
103
- (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
104
- }
105
- }
106
- const keymap = {
107
- 'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
108
- 'C1': 32.703, 'C#1': 34.648, 'D1': 36.708, 'D#1': 38.891, 'E1': 41.203, 'F1': 43.654, 'F#1': 46.249, 'G1': 48.999, 'G#1': 51.913, 'A1': 55.000, 'A#1': 58.270, 'B1': 61.735,
109
- 'C2': 65.406, 'C#2': 69.296, 'D2': 73.416, 'D#2': 77.782, 'E2': 82.407, 'F2': 87.307, 'F#2': 92.499, 'G2': 97.999, 'G#2': 103.826, 'A2': 110.000, 'A#2': 116.541, 'B2': 123.471,
110
- 'C3': 130.813, 'C#3': 138.591, 'D3': 146.832, 'D#3': 155.563, 'E3': 164.814, 'F3': 174.614, 'F#3': 184.997, 'G3': 195.998, 'G#3': 207.652, 'A3': 220.000, 'A#3': 233.082, 'B3': 246.942,
111
- 'C4': 261.626, 'C#4': 277.183, 'D4': 293.665, 'D#4': 311.127, 'E4': 329.628, 'F4': 349.228, 'F#4': 369.994, 'G4': 391.995, 'G#4': 415.305, 'A4': 440.000, 'A#4': 466.164, 'B4': 493.883,
112
- 'C5': 523.251, 'C#5': 554.365, 'D5': 587.330, 'D#5': 622.254, 'E5': 659.255, 'F5': 698.456, 'F#5': 739.989, 'G5': 783.991, 'G#5': 830.609, 'A5': 880.000, 'A#5': 932.328, 'B5': 987.767,
113
- 'C6': 1046.502, 'C#6': 1108.731, 'D6': 1174.659, 'D#6': 1244.508, 'E6': 1318.510, 'F6': 1396.913, 'F#6': 1479.978, 'G6': 1567.982, 'G#6': 1661.219, 'A6': 1760.000, 'A#6': 1864.655, 'B6': 1975.533,
114
- 'C7': 2093.005, 'C#7': 2217.461, 'D7': 2349.318, 'D#7': 2489.016, 'E7': 2637.020, 'F7': 2793.826, 'F#7': 2959.955, 'G7': 3135.963, 'G#7': 3322.438, 'A7': 3520.000, 'A#7': 3729.310, 'B7': 3951.066,
115
- 'C8': 4186.009,
116
- };
117
- const notemap = {
118
- '1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
119
- };
120
- class Synthesizer {
121
- constructor(props) { this.props = props; }
122
- press(frequency, duration, wait) {
123
- var _a;
124
- const props = this.props;
125
- const fv = typeof frequency === 'string' ? keymap[frequency] : frequency;
126
- const dv = typeof duration === 'string' ? (notemap[duration] * 60 / ((_a = props.bpm) !== null && _a !== void 0 ? _a : 120)) : (typeof duration === 'number' ? (duration / 1000) : 0);
127
- const start = context.currentTime + (wait !== null && wait !== void 0 ? wait : 0) / 1000;
128
- const nodes = {};
129
- nodes.oscillator = context.createOscillator();
130
- nodes.oscillator.type = props.oscillator.type;
131
- nodes.oscillator.frequency.value = fv;
132
- if (props.oscillator.LFO) {
133
- nodes.oscillatorLFO = context.createOscillator();
134
- nodes.oscillatorLFODepth = context.createGain();
135
- nodes.oscillatorLFODepth.gain.value = fv * (Math.pow(2.0, props.oscillator.LFO.amount / 12.0) - 1.0);
136
- nodes.oscillatorLFO.type = props.oscillator.LFO.type;
137
- nodes.oscillatorLFO.frequency.value = props.oscillator.LFO.rate;
138
- nodes.oscillatorLFO.start(start);
139
- nodes.oscillatorLFO.connect(nodes.oscillatorLFODepth);
140
- nodes.oscillatorLFODepth.connect(nodes.oscillator.frequency);
141
- }
142
- nodes.amp = context.createGain();
143
- nodes.amp.gain.value = 0.0;
144
- nodes.target = context.createGain();
145
- nodes.target.gain.value = 1.0;
146
- nodes.amp.connect(nodes.target);
147
- nodes.target.connect(master);
148
- if (props.filter) {
149
- nodes.filter = context.createBiquadFilter();
150
- nodes.filter.type = props.filter.type;
151
- nodes.filter.frequency.value = props.filter.cutoff;
152
- nodes.oscillator.connect(nodes.filter);
153
- nodes.filter.connect(nodes.amp);
154
- }
155
- else {
156
- nodes.oscillator.connect(nodes.amp);
157
- }
158
- if (props.reverb) {
159
- nodes.convolver = context.createConvolver();
160
- nodes.convolver.buffer = impulseResponse({ time: props.reverb.time });
161
- nodes.convolverDepth = context.createGain();
162
- nodes.convolverDepth.gain.value = 1.0;
163
- nodes.convolverDepth.gain.value *= props.reverb.mix;
164
- nodes.target.gain.value *= (1.0 - props.reverb.mix);
165
- nodes.amp.connect(nodes.convolver);
166
- nodes.convolver.connect(nodes.convolverDepth);
167
- nodes.convolverDepth.connect(master);
168
- }
169
- if (props.oscillator.envelope) {
170
- const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
171
- startEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
172
- }
173
- if (props.amp.envelope) {
174
- startEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
175
- }
176
- nodes.oscillator.start(start);
177
- if (dv > 0) {
178
- release();
179
- }
180
- else {
181
- return { release };
182
- }
183
- function release() {
184
- let stop = null;
185
- const end = dv > 0 ? dv : (context.currentTime - start);
186
- if (props.amp.envelope) {
187
- const ADSR = props.amp.envelope.ADSR;
188
- const adsr = [ADSR[0] / 1000, ADSR[1] / 1000, ADSR[2], ADSR[3] / 1000];
189
- const rate = adsr[0] === 0.0 ? 1.0 : Math.min(end / (adsr[0] + 0.001), 1.0);
190
- stop = start + Math.max((adsr[0] + adsr[1]) * rate, end) + adsr[3];
191
- }
192
- else {
193
- stop = start + end;
194
- }
195
- if (nodes.oscillatorLFO) {
196
- nodes.oscillatorLFO.stop(stop);
197
- }
198
- if (props.oscillator.envelope) {
199
- const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
200
- stopEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
201
- }
202
- if (props.amp.envelope) {
203
- stopEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
204
- }
205
- nodes.oscillator.stop(stop);
206
- setTimeout(() => {
207
- var _a, _b, _c, _d, _e;
208
- nodes.oscillator.disconnect();
209
- nodes.amp.disconnect();
210
- nodes.target.disconnect();
211
- (_a = nodes.oscillatorLFO) === null || _a === void 0 ? void 0 : _a.disconnect();
212
- (_b = nodes.oscillatorLFODepth) === null || _b === void 0 ? void 0 : _b.disconnect();
213
- (_c = nodes.filter) === null || _c === void 0 ? void 0 : _c.disconnect();
214
- (_d = nodes.convolver) === null || _d === void 0 ? void 0 : _d.disconnect();
215
- (_e = nodes.convolverDepth) === null || _e === void 0 ? void 0 : _e.disconnect();
216
- }, 2000);
217
- }
218
- function stopEnvelope(param, base, amount, ADSR) {
219
- const end = dv > 0 ? dv : (context.currentTime - start);
220
- const rate = ADSR[0] === 0.0 ? 1.0 : Math.min(end / (ADSR[0] / 1000), 1.0);
221
- if (rate < 1.0) {
222
- param.cancelScheduledValues(start);
223
- param.setValueAtTime(base, start);
224
- param.linearRampToValueAtTime(base + amount * rate, start + ADSR[0] / 1000 * rate);
225
- param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000 * rate);
226
- }
227
- param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dv));
228
- param.linearRampToValueAtTime(base, start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, end) + ADSR[3] / 1000);
229
- }
230
- function startEnvelope(param, base, amount, ADSR) {
231
- param.value = base;
232
- param.setValueAtTime(base, start);
233
- param.linearRampToValueAtTime(base + amount, start + ADSR[0] / 1000);
234
- param.linearRampToValueAtTime(base + amount * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000);
235
- }
236
- function impulseResponse({ time, decay = 2.0 }) {
237
- const length = context.sampleRate * time / 1000;
238
- const impulse = context.createBuffer(2, length, context.sampleRate);
239
- const ch0 = impulse.getChannelData(0);
240
- const ch1 = impulse.getChannelData(1);
241
- for (let i = 0; i < length; i++) {
242
- ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
243
- ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
244
- }
245
- return impulse;
246
- }
247
- }
248
- }
249
-
250
- export { xaudio as default };