@mulsense/xnew 0.4.5 → 0.4.6
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/dist/xnew.d.ts +59 -3
- package/dist/xnew.js +266 -22
- package/dist/xnew.mjs +266 -22
- package/package.json +1 -1
package/dist/xnew.d.ts
CHANGED
|
@@ -56,6 +56,9 @@ interface Internal {
|
|
|
56
56
|
parent: Unit | null;
|
|
57
57
|
target: Object | null;
|
|
58
58
|
props?: Object;
|
|
59
|
+
config: {
|
|
60
|
+
protect: boolean;
|
|
61
|
+
};
|
|
59
62
|
baseElement: UnitElement;
|
|
60
63
|
baseContext: Context;
|
|
61
64
|
baseComponent: Function;
|
|
@@ -65,7 +68,6 @@ interface Internal {
|
|
|
65
68
|
anchor: UnitElement | null;
|
|
66
69
|
state: string;
|
|
67
70
|
tostart: boolean;
|
|
68
|
-
protected: boolean;
|
|
69
71
|
ancestors: Unit[];
|
|
70
72
|
children: Unit[];
|
|
71
73
|
promises: UnitPromise[];
|
|
@@ -274,7 +276,6 @@ declare const xnew$1: CreateUnit & {
|
|
|
274
276
|
* }, 300)
|
|
275
277
|
*/
|
|
276
278
|
transition(transition: Function, duration?: number, easing?: string): any;
|
|
277
|
-
protect(): void;
|
|
278
279
|
};
|
|
279
280
|
|
|
280
281
|
declare function Accordion(unit: Unit, { open, duration, easing }?: {
|
|
@@ -297,6 +298,14 @@ declare function Screen(unit: Unit, { width, height, fit }?: {
|
|
|
297
298
|
resize(width: number, height: number): void;
|
|
298
299
|
};
|
|
299
300
|
|
|
301
|
+
declare function Modal(unit: Unit, { duration, easing }?: {
|
|
302
|
+
duration?: number;
|
|
303
|
+
easing?: string;
|
|
304
|
+
}): {
|
|
305
|
+
state: number;
|
|
306
|
+
close(): void;
|
|
307
|
+
};
|
|
308
|
+
|
|
300
309
|
declare function AnalogStick(unit: Unit, { stroke, strokeOpacity, strokeWidth, strokeLinejoin, fill, fillOpacity }?: {
|
|
301
310
|
stroke?: string;
|
|
302
311
|
strokeOpacity?: number;
|
|
@@ -322,19 +331,66 @@ declare function TextStream(unit: Unit, { text, speed, fade }?: {
|
|
|
322
331
|
fade?: number;
|
|
323
332
|
}): void;
|
|
324
333
|
|
|
334
|
+
type SynthesizerOptions = {
|
|
335
|
+
oscillator: OscillatorOptions;
|
|
336
|
+
amp: AmpOptions;
|
|
337
|
+
filter?: FilterOptions;
|
|
338
|
+
reverb?: ReverbOptions;
|
|
339
|
+
bpm?: number;
|
|
340
|
+
};
|
|
341
|
+
type OscillatorOptions = {
|
|
342
|
+
type: OscillatorType;
|
|
343
|
+
envelope?: Envelope;
|
|
344
|
+
LFO?: LFO;
|
|
345
|
+
};
|
|
346
|
+
type FilterOptions = {
|
|
347
|
+
type: BiquadFilterType;
|
|
348
|
+
cutoff: number;
|
|
349
|
+
};
|
|
350
|
+
type AmpOptions = {
|
|
351
|
+
envelope: Envelope;
|
|
352
|
+
};
|
|
353
|
+
type ReverbOptions = {
|
|
354
|
+
time: number;
|
|
355
|
+
mix: number;
|
|
356
|
+
};
|
|
357
|
+
type Envelope = {
|
|
358
|
+
amount: number;
|
|
359
|
+
ADSR: [number, number, number, number];
|
|
360
|
+
};
|
|
361
|
+
type LFO = {
|
|
362
|
+
amount: number;
|
|
363
|
+
type: OscillatorType;
|
|
364
|
+
rate: number;
|
|
365
|
+
};
|
|
366
|
+
declare class Synthesizer {
|
|
367
|
+
props: SynthesizerOptions;
|
|
368
|
+
constructor(props: SynthesizerOptions);
|
|
369
|
+
press(frequency: number | string, duration?: number | string, wait?: number): {
|
|
370
|
+
release: () => void;
|
|
371
|
+
} | undefined;
|
|
372
|
+
}
|
|
373
|
+
|
|
325
374
|
declare const basics: {
|
|
326
375
|
Screen: typeof Screen;
|
|
327
|
-
Modal:
|
|
376
|
+
Modal: typeof Modal;
|
|
328
377
|
Accordion: typeof Accordion;
|
|
329
378
|
TextStream: typeof TextStream;
|
|
330
379
|
AnalogStick: typeof AnalogStick;
|
|
331
380
|
DirectionalPad: typeof DirectionalPad;
|
|
332
381
|
};
|
|
382
|
+
|
|
383
|
+
declare const audio: {
|
|
384
|
+
load(path: string): UnitPromise;
|
|
385
|
+
synthesizer(props: SynthesizerOptions): Synthesizer;
|
|
386
|
+
volume: number;
|
|
387
|
+
};
|
|
333
388
|
declare namespace xnew {
|
|
334
389
|
type Unit = InstanceType<typeof Unit>;
|
|
335
390
|
}
|
|
336
391
|
declare const xnew: (typeof xnew$1) & {
|
|
337
392
|
basics: typeof basics;
|
|
393
|
+
audio: typeof audio;
|
|
338
394
|
};
|
|
339
395
|
|
|
340
396
|
export { xnew as default };
|
package/dist/xnew.js
CHANGED
|
@@ -529,7 +529,7 @@
|
|
|
529
529
|
//----------------------------------------------------------------------------------------------------
|
|
530
530
|
class Unit {
|
|
531
531
|
constructor(parent, ...args) {
|
|
532
|
-
var _a;
|
|
532
|
+
var _a, _b;
|
|
533
533
|
let target;
|
|
534
534
|
if (args[0] instanceof HTMLElement || args[0] instanceof SVGElement) {
|
|
535
535
|
target = args.shift(); // an existing html element
|
|
@@ -548,6 +548,7 @@
|
|
|
548
548
|
}
|
|
549
549
|
const component = args.shift();
|
|
550
550
|
const props = args.shift();
|
|
551
|
+
const config = args.shift();
|
|
551
552
|
let baseElement;
|
|
552
553
|
if (target instanceof HTMLElement || target instanceof SVGElement) {
|
|
553
554
|
baseElement = target;
|
|
@@ -569,7 +570,8 @@
|
|
|
569
570
|
baseComponent = (unit) => { };
|
|
570
571
|
}
|
|
571
572
|
const baseContext = (_a = parent === null || parent === void 0 ? void 0 : parent._.currentContext) !== null && _a !== void 0 ? _a : { stack: null };
|
|
572
|
-
|
|
573
|
+
const protect = (_b = config === null || config === void 0 ? void 0 : config.protect) !== null && _b !== void 0 ? _b : false;
|
|
574
|
+
this._ = { parent, target, baseElement, baseContext, baseComponent, props, config: { protect } };
|
|
573
575
|
parent === null || parent === void 0 ? void 0 : parent._.children.push(this);
|
|
574
576
|
Unit.initialize(this, null);
|
|
575
577
|
}
|
|
@@ -608,7 +610,6 @@
|
|
|
608
610
|
anchor,
|
|
609
611
|
state: 'invoked',
|
|
610
612
|
tostart: true,
|
|
611
|
-
protected: false,
|
|
612
613
|
ancestors: [...(unit._.parent ? [unit._.parent] : []), ...((_b = (_a = unit._.parent) === null || _a === void 0 ? void 0 : _a._.ancestors) !== null && _b !== void 0 ? _b : [])],
|
|
613
614
|
children: [],
|
|
614
615
|
elements: [],
|
|
@@ -838,7 +839,7 @@
|
|
|
838
839
|
if (type[0] === '+') {
|
|
839
840
|
(_a = Unit.type2units.get(type)) === null || _a === void 0 ? void 0 : _a.forEach((unit) => {
|
|
840
841
|
var _a;
|
|
841
|
-
const find = [unit, ...unit._.ancestors].find(u => u._.
|
|
842
|
+
const find = [unit, ...unit._.ancestors].find(u => u._.config.protect === true);
|
|
842
843
|
if (find === undefined || current._.ancestors.includes(find) === true || current === find) {
|
|
843
844
|
(_a = unit._.listeners.get(type)) === null || _a === void 0 ? void 0 : _a.forEach((item) => item.execute(...args));
|
|
844
845
|
}
|
|
@@ -1157,19 +1158,12 @@
|
|
|
1157
1158
|
transition(transition, duration = 0, easing = 'linear') {
|
|
1158
1159
|
return new UnitTimer({ transition, duration, easing, iterations: 1 });
|
|
1159
1160
|
},
|
|
1160
|
-
protect() {
|
|
1161
|
-
Unit.currentUnit._.protected = true;
|
|
1162
|
-
}
|
|
1163
1161
|
});
|
|
1164
1162
|
|
|
1165
1163
|
function Accordion(unit, { open = false, duration = 200, easing = 'ease' } = {}) {
|
|
1166
1164
|
xnew$1.context('xnew.accordion', unit);
|
|
1167
|
-
unit.on('-transition', ({ state }) =>
|
|
1168
|
-
|
|
1169
|
-
});
|
|
1170
|
-
xnew$1.timeout(() => {
|
|
1171
|
-
xnew$1.emit('-transition', { state: open ? 1.0 : 0.0 });
|
|
1172
|
-
});
|
|
1165
|
+
unit.on('-transition', ({ state }) => unit.state = state);
|
|
1166
|
+
xnew$1.timeout(() => xnew$1.emit('-transition', { state: open ? 1.0 : 0.0 }));
|
|
1173
1167
|
return {
|
|
1174
1168
|
state: open ? 1.0 : 0.0,
|
|
1175
1169
|
toggle() {
|
|
@@ -1244,9 +1238,8 @@
|
|
|
1244
1238
|
xnew$1.context('xnew.modalframe', unit);
|
|
1245
1239
|
xnew$1.nest('<div style="position: fixed; inset: 0; z-index: 1000;">');
|
|
1246
1240
|
unit.on('click', ({ event }) => unit.close());
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
}, duration, easing);
|
|
1241
|
+
unit.on('-transition', ({ state }) => unit.state = state);
|
|
1242
|
+
xnew$1.transition((x) => xnew$1.emit('-transition', { state: x }), duration, easing);
|
|
1250
1243
|
return {
|
|
1251
1244
|
state: 0.0,
|
|
1252
1245
|
close() {
|
|
@@ -1293,7 +1286,7 @@
|
|
|
1293
1286
|
const d = Math.min(1.0, Math.sqrt(x * x + y * y) / (newsize / 4));
|
|
1294
1287
|
const a = (y !== 0 || x !== 0) ? Math.atan2(y, x) : 0;
|
|
1295
1288
|
const vector = { x: Math.cos(a) * d, y: Math.sin(a) * d };
|
|
1296
|
-
target.element.style.filter = 'brightness(
|
|
1289
|
+
target.element.style.filter = 'brightness(80%)';
|
|
1297
1290
|
target.element.style.left = `${vector.x * newsize / 4}px`;
|
|
1298
1291
|
target.element.style.top = `${vector.y * newsize / 4}px`;
|
|
1299
1292
|
const nexttype = { dragstart: '-down', dragmove: '-move' }[type];
|
|
@@ -1357,10 +1350,10 @@
|
|
|
1357
1350
|
vector.x = 0;
|
|
1358
1351
|
vector.y = Math.abs(vector.y) > 0.5 ? Math.sign(vector.y) : 0;
|
|
1359
1352
|
}
|
|
1360
|
-
targets[0].element.style.filter = (vector.y < 0) ? 'brightness(
|
|
1361
|
-
targets[1].element.style.filter = (vector.y > 0) ? 'brightness(
|
|
1362
|
-
targets[2].element.style.filter = (vector.x < 0) ? 'brightness(
|
|
1363
|
-
targets[3].element.style.filter = (vector.x > 0) ? 'brightness(
|
|
1353
|
+
targets[0].element.style.filter = (vector.y < 0) ? 'brightness(80%)' : '';
|
|
1354
|
+
targets[1].element.style.filter = (vector.y > 0) ? 'brightness(80%)' : '';
|
|
1355
|
+
targets[2].element.style.filter = (vector.x < 0) ? 'brightness(80%)' : '';
|
|
1356
|
+
targets[3].element.style.filter = (vector.x > 0) ? 'brightness(80%)' : '';
|
|
1364
1357
|
const nexttype = { dragstart: '-down', dragmove: '-move' }[type];
|
|
1365
1358
|
xnew$1.emit(nexttype, { type: nexttype, vector });
|
|
1366
1359
|
});
|
|
@@ -1419,6 +1412,230 @@
|
|
|
1419
1412
|
}
|
|
1420
1413
|
}
|
|
1421
1414
|
|
|
1415
|
+
const context = new window.AudioContext();
|
|
1416
|
+
const master = context.createGain();
|
|
1417
|
+
//----------------------------------------------------------------------------------------------------
|
|
1418
|
+
// master volume
|
|
1419
|
+
//----------------------------------------------------------------------------------------------------
|
|
1420
|
+
master.gain.value = 0.1;
|
|
1421
|
+
master.connect(context.destination);
|
|
1422
|
+
//----------------------------------------------------------------------------------------------------
|
|
1423
|
+
// audio file
|
|
1424
|
+
//----------------------------------------------------------------------------------------------------
|
|
1425
|
+
class AudioFile {
|
|
1426
|
+
constructor(path) {
|
|
1427
|
+
this.promise = fetch(path)
|
|
1428
|
+
.then((response) => response.arrayBuffer())
|
|
1429
|
+
.then((response) => context.decodeAudioData(response))
|
|
1430
|
+
.then((response) => { this.buffer = response; })
|
|
1431
|
+
.catch(() => {
|
|
1432
|
+
console.warn(`"${path}" could not be loaded.`);
|
|
1433
|
+
});
|
|
1434
|
+
this.amp = context.createGain();
|
|
1435
|
+
this.amp.gain.value = 1.0;
|
|
1436
|
+
this.amp.connect(master);
|
|
1437
|
+
this.fade = context.createGain();
|
|
1438
|
+
this.fade.gain.value = 1.0;
|
|
1439
|
+
this.fade.connect(this.amp);
|
|
1440
|
+
this.source = null;
|
|
1441
|
+
this.start = null;
|
|
1442
|
+
}
|
|
1443
|
+
set volume(value) {
|
|
1444
|
+
this.amp.gain.value = value;
|
|
1445
|
+
}
|
|
1446
|
+
get volume() {
|
|
1447
|
+
return this.amp.gain.value;
|
|
1448
|
+
}
|
|
1449
|
+
play({ offset = 0, fade = 0, loop = false } = {}) {
|
|
1450
|
+
if (this.buffer !== undefined && this.start === null) {
|
|
1451
|
+
this.source = context.createBufferSource();
|
|
1452
|
+
this.source.buffer = this.buffer;
|
|
1453
|
+
this.source.loop = loop;
|
|
1454
|
+
this.source.connect(this.fade);
|
|
1455
|
+
this.start = context.currentTime;
|
|
1456
|
+
this.source.playbackRate.value = 1;
|
|
1457
|
+
this.source.start(context.currentTime, offset / 1000);
|
|
1458
|
+
// Apply fade-in effect if fade duration is specified
|
|
1459
|
+
if (fade > 0) {
|
|
1460
|
+
this.fade.gain.setValueAtTime(0, context.currentTime);
|
|
1461
|
+
this.fade.gain.linearRampToValueAtTime(1.0, context.currentTime + fade / 1000);
|
|
1462
|
+
}
|
|
1463
|
+
this.source.onended = () => {
|
|
1464
|
+
var _a;
|
|
1465
|
+
this.start = null;
|
|
1466
|
+
(_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
1467
|
+
this.source = null;
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
pause({ fade = 0 } = {}) {
|
|
1472
|
+
var _a, _b;
|
|
1473
|
+
if (this.buffer !== undefined && this.start !== null) {
|
|
1474
|
+
const elapsed = (context.currentTime - this.start) % this.buffer.duration * 1000;
|
|
1475
|
+
// Apply fade-out effect if fade duration is specified
|
|
1476
|
+
if (fade > 0) {
|
|
1477
|
+
this.fade.gain.setValueAtTime(1.0, context.currentTime);
|
|
1478
|
+
this.fade.gain.linearRampToValueAtTime(0, context.currentTime + fade / 1000);
|
|
1479
|
+
(_a = this.source) === null || _a === void 0 ? void 0 : _a.stop(context.currentTime + fade / 1000);
|
|
1480
|
+
}
|
|
1481
|
+
else {
|
|
1482
|
+
(_b = this.source) === null || _b === void 0 ? void 0 : _b.stop(context.currentTime);
|
|
1483
|
+
}
|
|
1484
|
+
this.start = null;
|
|
1485
|
+
return elapsed;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
clear() {
|
|
1489
|
+
var _a;
|
|
1490
|
+
this.amp.disconnect();
|
|
1491
|
+
this.fade.disconnect();
|
|
1492
|
+
(_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
const keymap = {
|
|
1496
|
+
'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
|
|
1497
|
+
'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,
|
|
1498
|
+
'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,
|
|
1499
|
+
'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,
|
|
1500
|
+
'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,
|
|
1501
|
+
'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,
|
|
1502
|
+
'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,
|
|
1503
|
+
'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,
|
|
1504
|
+
'C8': 4186.009,
|
|
1505
|
+
};
|
|
1506
|
+
const notemap = {
|
|
1507
|
+
'1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
|
|
1508
|
+
};
|
|
1509
|
+
class Synthesizer {
|
|
1510
|
+
constructor(props) { this.props = props; }
|
|
1511
|
+
press(frequency, duration, wait) {
|
|
1512
|
+
var _a;
|
|
1513
|
+
const props = this.props;
|
|
1514
|
+
const fv = typeof frequency === 'string' ? keymap[frequency] : frequency;
|
|
1515
|
+
const dv = typeof duration === 'string' ? (notemap[duration] * 60 / ((_a = props.bpm) !== null && _a !== void 0 ? _a : 120)) : (typeof duration === 'number' ? (duration / 1000) : 0);
|
|
1516
|
+
const start = context.currentTime + (wait !== null && wait !== void 0 ? wait : 0) / 1000;
|
|
1517
|
+
const nodes = {};
|
|
1518
|
+
nodes.oscillator = context.createOscillator();
|
|
1519
|
+
nodes.oscillator.type = props.oscillator.type;
|
|
1520
|
+
nodes.oscillator.frequency.value = fv;
|
|
1521
|
+
if (props.oscillator.LFO) {
|
|
1522
|
+
nodes.oscillatorLFO = context.createOscillator();
|
|
1523
|
+
nodes.oscillatorLFODepth = context.createGain();
|
|
1524
|
+
nodes.oscillatorLFODepth.gain.value = fv * (Math.pow(2.0, props.oscillator.LFO.amount / 12.0) - 1.0);
|
|
1525
|
+
nodes.oscillatorLFO.type = props.oscillator.LFO.type;
|
|
1526
|
+
nodes.oscillatorLFO.frequency.value = props.oscillator.LFO.rate;
|
|
1527
|
+
nodes.oscillatorLFO.start(start);
|
|
1528
|
+
nodes.oscillatorLFO.connect(nodes.oscillatorLFODepth);
|
|
1529
|
+
nodes.oscillatorLFODepth.connect(nodes.oscillator.frequency);
|
|
1530
|
+
}
|
|
1531
|
+
nodes.amp = context.createGain();
|
|
1532
|
+
nodes.amp.gain.value = 0.0;
|
|
1533
|
+
nodes.target = context.createGain();
|
|
1534
|
+
nodes.target.gain.value = 1.0;
|
|
1535
|
+
nodes.amp.connect(nodes.target);
|
|
1536
|
+
nodes.target.connect(master);
|
|
1537
|
+
if (props.filter) {
|
|
1538
|
+
nodes.filter = context.createBiquadFilter();
|
|
1539
|
+
nodes.filter.type = props.filter.type;
|
|
1540
|
+
nodes.filter.frequency.value = props.filter.cutoff;
|
|
1541
|
+
nodes.oscillator.connect(nodes.filter);
|
|
1542
|
+
nodes.filter.connect(nodes.amp);
|
|
1543
|
+
}
|
|
1544
|
+
else {
|
|
1545
|
+
nodes.oscillator.connect(nodes.amp);
|
|
1546
|
+
}
|
|
1547
|
+
if (props.reverb) {
|
|
1548
|
+
nodes.convolver = context.createConvolver();
|
|
1549
|
+
nodes.convolver.buffer = impulseResponse({ time: props.reverb.time });
|
|
1550
|
+
nodes.convolverDepth = context.createGain();
|
|
1551
|
+
nodes.convolverDepth.gain.value = 1.0;
|
|
1552
|
+
nodes.convolverDepth.gain.value *= props.reverb.mix;
|
|
1553
|
+
nodes.target.gain.value *= (1.0 - props.reverb.mix);
|
|
1554
|
+
nodes.amp.connect(nodes.convolver);
|
|
1555
|
+
nodes.convolver.connect(nodes.convolverDepth);
|
|
1556
|
+
nodes.convolverDepth.connect(master);
|
|
1557
|
+
}
|
|
1558
|
+
if (props.oscillator.envelope) {
|
|
1559
|
+
const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
|
|
1560
|
+
startEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
|
|
1561
|
+
}
|
|
1562
|
+
if (props.amp.envelope) {
|
|
1563
|
+
startEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
|
|
1564
|
+
}
|
|
1565
|
+
nodes.oscillator.start(start);
|
|
1566
|
+
if (dv > 0) {
|
|
1567
|
+
release();
|
|
1568
|
+
}
|
|
1569
|
+
else {
|
|
1570
|
+
return { release };
|
|
1571
|
+
}
|
|
1572
|
+
function release() {
|
|
1573
|
+
let stop = null;
|
|
1574
|
+
const end = dv > 0 ? dv : (context.currentTime - start);
|
|
1575
|
+
if (props.amp.envelope) {
|
|
1576
|
+
const ADSR = props.amp.envelope.ADSR;
|
|
1577
|
+
const adsr = [ADSR[0] / 1000, ADSR[1] / 1000, ADSR[2], ADSR[3] / 1000];
|
|
1578
|
+
const rate = adsr[0] === 0.0 ? 1.0 : Math.min(end / (adsr[0] + 0.001), 1.0);
|
|
1579
|
+
stop = start + Math.max((adsr[0] + adsr[1]) * rate, end) + adsr[3];
|
|
1580
|
+
}
|
|
1581
|
+
else {
|
|
1582
|
+
stop = start + end;
|
|
1583
|
+
}
|
|
1584
|
+
if (nodes.oscillatorLFO) {
|
|
1585
|
+
nodes.oscillatorLFO.stop(stop);
|
|
1586
|
+
}
|
|
1587
|
+
if (props.oscillator.envelope) {
|
|
1588
|
+
const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
|
|
1589
|
+
stopEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
|
|
1590
|
+
}
|
|
1591
|
+
if (props.amp.envelope) {
|
|
1592
|
+
stopEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
|
|
1593
|
+
}
|
|
1594
|
+
nodes.oscillator.stop(stop);
|
|
1595
|
+
setTimeout(() => {
|
|
1596
|
+
var _a, _b, _c, _d, _e;
|
|
1597
|
+
nodes.oscillator.disconnect();
|
|
1598
|
+
nodes.amp.disconnect();
|
|
1599
|
+
nodes.target.disconnect();
|
|
1600
|
+
(_a = nodes.oscillatorLFO) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
1601
|
+
(_b = nodes.oscillatorLFODepth) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
1602
|
+
(_c = nodes.filter) === null || _c === void 0 ? void 0 : _c.disconnect();
|
|
1603
|
+
(_d = nodes.convolver) === null || _d === void 0 ? void 0 : _d.disconnect();
|
|
1604
|
+
(_e = nodes.convolverDepth) === null || _e === void 0 ? void 0 : _e.disconnect();
|
|
1605
|
+
}, 2000);
|
|
1606
|
+
}
|
|
1607
|
+
function stopEnvelope(param, base, amount, ADSR) {
|
|
1608
|
+
const end = dv > 0 ? dv : (context.currentTime - start);
|
|
1609
|
+
const rate = ADSR[0] === 0.0 ? 1.0 : Math.min(end / (ADSR[0] / 1000), 1.0);
|
|
1610
|
+
if (rate < 1.0) {
|
|
1611
|
+
param.cancelScheduledValues(start);
|
|
1612
|
+
param.setValueAtTime(base, start);
|
|
1613
|
+
param.linearRampToValueAtTime(base + amount * rate, start + ADSR[0] / 1000 * rate);
|
|
1614
|
+
param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000 * rate);
|
|
1615
|
+
}
|
|
1616
|
+
param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dv));
|
|
1617
|
+
param.linearRampToValueAtTime(base, start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, end) + ADSR[3] / 1000);
|
|
1618
|
+
}
|
|
1619
|
+
function startEnvelope(param, base, amount, ADSR) {
|
|
1620
|
+
param.value = base;
|
|
1621
|
+
param.setValueAtTime(base, start);
|
|
1622
|
+
param.linearRampToValueAtTime(base + amount, start + ADSR[0] / 1000);
|
|
1623
|
+
param.linearRampToValueAtTime(base + amount * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000);
|
|
1624
|
+
}
|
|
1625
|
+
function impulseResponse({ time, decay = 2.0 }) {
|
|
1626
|
+
const length = context.sampleRate * time / 1000;
|
|
1627
|
+
const impulse = context.createBuffer(2, length, context.sampleRate);
|
|
1628
|
+
const ch0 = impulse.getChannelData(0);
|
|
1629
|
+
const ch1 = impulse.getChannelData(1);
|
|
1630
|
+
for (let i = 0; i < length; i++) {
|
|
1631
|
+
ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
|
|
1632
|
+
ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
|
|
1633
|
+
}
|
|
1634
|
+
return impulse;
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1422
1639
|
const basics = {
|
|
1423
1640
|
Screen,
|
|
1424
1641
|
Modal,
|
|
@@ -1427,7 +1644,34 @@
|
|
|
1427
1644
|
AnalogStick,
|
|
1428
1645
|
DirectionalPad,
|
|
1429
1646
|
};
|
|
1430
|
-
const
|
|
1647
|
+
const audio = {
|
|
1648
|
+
load(path) {
|
|
1649
|
+
const music = new AudioFile(path);
|
|
1650
|
+
const object = {
|
|
1651
|
+
play(options = {}) {
|
|
1652
|
+
const unit = xnew();
|
|
1653
|
+
if (music.start === null) {
|
|
1654
|
+
music.play(options);
|
|
1655
|
+
unit.on('finalize', () => music.pause({ fade: options.fade }));
|
|
1656
|
+
}
|
|
1657
|
+
},
|
|
1658
|
+
pause(options = {}) {
|
|
1659
|
+
music.pause(options);
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
return xnew.promise(music.promise).then(() => object);
|
|
1663
|
+
},
|
|
1664
|
+
synthesizer(props) {
|
|
1665
|
+
return new Synthesizer(props);
|
|
1666
|
+
},
|
|
1667
|
+
get volume() {
|
|
1668
|
+
return master.gain.value;
|
|
1669
|
+
},
|
|
1670
|
+
set volume(value) {
|
|
1671
|
+
master.gain.value = value;
|
|
1672
|
+
}
|
|
1673
|
+
};
|
|
1674
|
+
const xnew = Object.assign(xnew$1, { basics, audio });
|
|
1431
1675
|
|
|
1432
1676
|
return xnew;
|
|
1433
1677
|
|
package/dist/xnew.mjs
CHANGED
|
@@ -523,7 +523,7 @@ function pointer(element, event) {
|
|
|
523
523
|
//----------------------------------------------------------------------------------------------------
|
|
524
524
|
class Unit {
|
|
525
525
|
constructor(parent, ...args) {
|
|
526
|
-
var _a;
|
|
526
|
+
var _a, _b;
|
|
527
527
|
let target;
|
|
528
528
|
if (args[0] instanceof HTMLElement || args[0] instanceof SVGElement) {
|
|
529
529
|
target = args.shift(); // an existing html element
|
|
@@ -542,6 +542,7 @@ class Unit {
|
|
|
542
542
|
}
|
|
543
543
|
const component = args.shift();
|
|
544
544
|
const props = args.shift();
|
|
545
|
+
const config = args.shift();
|
|
545
546
|
let baseElement;
|
|
546
547
|
if (target instanceof HTMLElement || target instanceof SVGElement) {
|
|
547
548
|
baseElement = target;
|
|
@@ -563,7 +564,8 @@ class Unit {
|
|
|
563
564
|
baseComponent = (unit) => { };
|
|
564
565
|
}
|
|
565
566
|
const baseContext = (_a = parent === null || parent === void 0 ? void 0 : parent._.currentContext) !== null && _a !== void 0 ? _a : { stack: null };
|
|
566
|
-
|
|
567
|
+
const protect = (_b = config === null || config === void 0 ? void 0 : config.protect) !== null && _b !== void 0 ? _b : false;
|
|
568
|
+
this._ = { parent, target, baseElement, baseContext, baseComponent, props, config: { protect } };
|
|
567
569
|
parent === null || parent === void 0 ? void 0 : parent._.children.push(this);
|
|
568
570
|
Unit.initialize(this, null);
|
|
569
571
|
}
|
|
@@ -602,7 +604,6 @@ class Unit {
|
|
|
602
604
|
anchor,
|
|
603
605
|
state: 'invoked',
|
|
604
606
|
tostart: true,
|
|
605
|
-
protected: false,
|
|
606
607
|
ancestors: [...(unit._.parent ? [unit._.parent] : []), ...((_b = (_a = unit._.parent) === null || _a === void 0 ? void 0 : _a._.ancestors) !== null && _b !== void 0 ? _b : [])],
|
|
607
608
|
children: [],
|
|
608
609
|
elements: [],
|
|
@@ -832,7 +833,7 @@ class Unit {
|
|
|
832
833
|
if (type[0] === '+') {
|
|
833
834
|
(_a = Unit.type2units.get(type)) === null || _a === void 0 ? void 0 : _a.forEach((unit) => {
|
|
834
835
|
var _a;
|
|
835
|
-
const find = [unit, ...unit._.ancestors].find(u => u._.
|
|
836
|
+
const find = [unit, ...unit._.ancestors].find(u => u._.config.protect === true);
|
|
836
837
|
if (find === undefined || current._.ancestors.includes(find) === true || current === find) {
|
|
837
838
|
(_a = unit._.listeners.get(type)) === null || _a === void 0 ? void 0 : _a.forEach((item) => item.execute(...args));
|
|
838
839
|
}
|
|
@@ -1151,19 +1152,12 @@ const xnew$1 = Object.assign(function (...args) {
|
|
|
1151
1152
|
transition(transition, duration = 0, easing = 'linear') {
|
|
1152
1153
|
return new UnitTimer({ transition, duration, easing, iterations: 1 });
|
|
1153
1154
|
},
|
|
1154
|
-
protect() {
|
|
1155
|
-
Unit.currentUnit._.protected = true;
|
|
1156
|
-
}
|
|
1157
1155
|
});
|
|
1158
1156
|
|
|
1159
1157
|
function Accordion(unit, { open = false, duration = 200, easing = 'ease' } = {}) {
|
|
1160
1158
|
xnew$1.context('xnew.accordion', unit);
|
|
1161
|
-
unit.on('-transition', ({ state }) =>
|
|
1162
|
-
|
|
1163
|
-
});
|
|
1164
|
-
xnew$1.timeout(() => {
|
|
1165
|
-
xnew$1.emit('-transition', { state: open ? 1.0 : 0.0 });
|
|
1166
|
-
});
|
|
1159
|
+
unit.on('-transition', ({ state }) => unit.state = state);
|
|
1160
|
+
xnew$1.timeout(() => xnew$1.emit('-transition', { state: open ? 1.0 : 0.0 }));
|
|
1167
1161
|
return {
|
|
1168
1162
|
state: open ? 1.0 : 0.0,
|
|
1169
1163
|
toggle() {
|
|
@@ -1238,9 +1232,8 @@ function Modal(unit, { duration = 200, easing = 'ease' } = {}) {
|
|
|
1238
1232
|
xnew$1.context('xnew.modalframe', unit);
|
|
1239
1233
|
xnew$1.nest('<div style="position: fixed; inset: 0; z-index: 1000;">');
|
|
1240
1234
|
unit.on('click', ({ event }) => unit.close());
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
}, duration, easing);
|
|
1235
|
+
unit.on('-transition', ({ state }) => unit.state = state);
|
|
1236
|
+
xnew$1.transition((x) => xnew$1.emit('-transition', { state: x }), duration, easing);
|
|
1244
1237
|
return {
|
|
1245
1238
|
state: 0.0,
|
|
1246
1239
|
close() {
|
|
@@ -1287,7 +1280,7 @@ function AnalogStick(unit, { stroke = 'currentColor', strokeOpacity = 0.8, strok
|
|
|
1287
1280
|
const d = Math.min(1.0, Math.sqrt(x * x + y * y) / (newsize / 4));
|
|
1288
1281
|
const a = (y !== 0 || x !== 0) ? Math.atan2(y, x) : 0;
|
|
1289
1282
|
const vector = { x: Math.cos(a) * d, y: Math.sin(a) * d };
|
|
1290
|
-
target.element.style.filter = 'brightness(
|
|
1283
|
+
target.element.style.filter = 'brightness(80%)';
|
|
1291
1284
|
target.element.style.left = `${vector.x * newsize / 4}px`;
|
|
1292
1285
|
target.element.style.top = `${vector.y * newsize / 4}px`;
|
|
1293
1286
|
const nexttype = { dragstart: '-down', dragmove: '-move' }[type];
|
|
@@ -1351,10 +1344,10 @@ function DirectionalPad(unit, { diagonal = true, stroke = 'currentColor', stroke
|
|
|
1351
1344
|
vector.x = 0;
|
|
1352
1345
|
vector.y = Math.abs(vector.y) > 0.5 ? Math.sign(vector.y) : 0;
|
|
1353
1346
|
}
|
|
1354
|
-
targets[0].element.style.filter = (vector.y < 0) ? 'brightness(
|
|
1355
|
-
targets[1].element.style.filter = (vector.y > 0) ? 'brightness(
|
|
1356
|
-
targets[2].element.style.filter = (vector.x < 0) ? 'brightness(
|
|
1357
|
-
targets[3].element.style.filter = (vector.x > 0) ? 'brightness(
|
|
1347
|
+
targets[0].element.style.filter = (vector.y < 0) ? 'brightness(80%)' : '';
|
|
1348
|
+
targets[1].element.style.filter = (vector.y > 0) ? 'brightness(80%)' : '';
|
|
1349
|
+
targets[2].element.style.filter = (vector.x < 0) ? 'brightness(80%)' : '';
|
|
1350
|
+
targets[3].element.style.filter = (vector.x > 0) ? 'brightness(80%)' : '';
|
|
1358
1351
|
const nexttype = { dragstart: '-down', dragmove: '-move' }[type];
|
|
1359
1352
|
xnew$1.emit(nexttype, { type: nexttype, vector });
|
|
1360
1353
|
});
|
|
@@ -1413,6 +1406,230 @@ function TextStream(unit, { text = '', speed = 50, fade = 300 } = {}) {
|
|
|
1413
1406
|
}
|
|
1414
1407
|
}
|
|
1415
1408
|
|
|
1409
|
+
const context = new window.AudioContext();
|
|
1410
|
+
const master = context.createGain();
|
|
1411
|
+
//----------------------------------------------------------------------------------------------------
|
|
1412
|
+
// master volume
|
|
1413
|
+
//----------------------------------------------------------------------------------------------------
|
|
1414
|
+
master.gain.value = 0.1;
|
|
1415
|
+
master.connect(context.destination);
|
|
1416
|
+
//----------------------------------------------------------------------------------------------------
|
|
1417
|
+
// audio file
|
|
1418
|
+
//----------------------------------------------------------------------------------------------------
|
|
1419
|
+
class AudioFile {
|
|
1420
|
+
constructor(path) {
|
|
1421
|
+
this.promise = fetch(path)
|
|
1422
|
+
.then((response) => response.arrayBuffer())
|
|
1423
|
+
.then((response) => context.decodeAudioData(response))
|
|
1424
|
+
.then((response) => { this.buffer = response; })
|
|
1425
|
+
.catch(() => {
|
|
1426
|
+
console.warn(`"${path}" could not be loaded.`);
|
|
1427
|
+
});
|
|
1428
|
+
this.amp = context.createGain();
|
|
1429
|
+
this.amp.gain.value = 1.0;
|
|
1430
|
+
this.amp.connect(master);
|
|
1431
|
+
this.fade = context.createGain();
|
|
1432
|
+
this.fade.gain.value = 1.0;
|
|
1433
|
+
this.fade.connect(this.amp);
|
|
1434
|
+
this.source = null;
|
|
1435
|
+
this.start = null;
|
|
1436
|
+
}
|
|
1437
|
+
set volume(value) {
|
|
1438
|
+
this.amp.gain.value = value;
|
|
1439
|
+
}
|
|
1440
|
+
get volume() {
|
|
1441
|
+
return this.amp.gain.value;
|
|
1442
|
+
}
|
|
1443
|
+
play({ offset = 0, fade = 0, loop = false } = {}) {
|
|
1444
|
+
if (this.buffer !== undefined && this.start === null) {
|
|
1445
|
+
this.source = context.createBufferSource();
|
|
1446
|
+
this.source.buffer = this.buffer;
|
|
1447
|
+
this.source.loop = loop;
|
|
1448
|
+
this.source.connect(this.fade);
|
|
1449
|
+
this.start = context.currentTime;
|
|
1450
|
+
this.source.playbackRate.value = 1;
|
|
1451
|
+
this.source.start(context.currentTime, offset / 1000);
|
|
1452
|
+
// Apply fade-in effect if fade duration is specified
|
|
1453
|
+
if (fade > 0) {
|
|
1454
|
+
this.fade.gain.setValueAtTime(0, context.currentTime);
|
|
1455
|
+
this.fade.gain.linearRampToValueAtTime(1.0, context.currentTime + fade / 1000);
|
|
1456
|
+
}
|
|
1457
|
+
this.source.onended = () => {
|
|
1458
|
+
var _a;
|
|
1459
|
+
this.start = null;
|
|
1460
|
+
(_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
1461
|
+
this.source = null;
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
pause({ fade = 0 } = {}) {
|
|
1466
|
+
var _a, _b;
|
|
1467
|
+
if (this.buffer !== undefined && this.start !== null) {
|
|
1468
|
+
const elapsed = (context.currentTime - this.start) % this.buffer.duration * 1000;
|
|
1469
|
+
// Apply fade-out effect if fade duration is specified
|
|
1470
|
+
if (fade > 0) {
|
|
1471
|
+
this.fade.gain.setValueAtTime(1.0, context.currentTime);
|
|
1472
|
+
this.fade.gain.linearRampToValueAtTime(0, context.currentTime + fade / 1000);
|
|
1473
|
+
(_a = this.source) === null || _a === void 0 ? void 0 : _a.stop(context.currentTime + fade / 1000);
|
|
1474
|
+
}
|
|
1475
|
+
else {
|
|
1476
|
+
(_b = this.source) === null || _b === void 0 ? void 0 : _b.stop(context.currentTime);
|
|
1477
|
+
}
|
|
1478
|
+
this.start = null;
|
|
1479
|
+
return elapsed;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
clear() {
|
|
1483
|
+
var _a;
|
|
1484
|
+
this.amp.disconnect();
|
|
1485
|
+
this.fade.disconnect();
|
|
1486
|
+
(_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
const keymap = {
|
|
1490
|
+
'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
|
|
1491
|
+
'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,
|
|
1492
|
+
'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,
|
|
1493
|
+
'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,
|
|
1494
|
+
'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,
|
|
1495
|
+
'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,
|
|
1496
|
+
'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,
|
|
1497
|
+
'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,
|
|
1498
|
+
'C8': 4186.009,
|
|
1499
|
+
};
|
|
1500
|
+
const notemap = {
|
|
1501
|
+
'1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
|
|
1502
|
+
};
|
|
1503
|
+
class Synthesizer {
|
|
1504
|
+
constructor(props) { this.props = props; }
|
|
1505
|
+
press(frequency, duration, wait) {
|
|
1506
|
+
var _a;
|
|
1507
|
+
const props = this.props;
|
|
1508
|
+
const fv = typeof frequency === 'string' ? keymap[frequency] : frequency;
|
|
1509
|
+
const dv = typeof duration === 'string' ? (notemap[duration] * 60 / ((_a = props.bpm) !== null && _a !== void 0 ? _a : 120)) : (typeof duration === 'number' ? (duration / 1000) : 0);
|
|
1510
|
+
const start = context.currentTime + (wait !== null && wait !== void 0 ? wait : 0) / 1000;
|
|
1511
|
+
const nodes = {};
|
|
1512
|
+
nodes.oscillator = context.createOscillator();
|
|
1513
|
+
nodes.oscillator.type = props.oscillator.type;
|
|
1514
|
+
nodes.oscillator.frequency.value = fv;
|
|
1515
|
+
if (props.oscillator.LFO) {
|
|
1516
|
+
nodes.oscillatorLFO = context.createOscillator();
|
|
1517
|
+
nodes.oscillatorLFODepth = context.createGain();
|
|
1518
|
+
nodes.oscillatorLFODepth.gain.value = fv * (Math.pow(2.0, props.oscillator.LFO.amount / 12.0) - 1.0);
|
|
1519
|
+
nodes.oscillatorLFO.type = props.oscillator.LFO.type;
|
|
1520
|
+
nodes.oscillatorLFO.frequency.value = props.oscillator.LFO.rate;
|
|
1521
|
+
nodes.oscillatorLFO.start(start);
|
|
1522
|
+
nodes.oscillatorLFO.connect(nodes.oscillatorLFODepth);
|
|
1523
|
+
nodes.oscillatorLFODepth.connect(nodes.oscillator.frequency);
|
|
1524
|
+
}
|
|
1525
|
+
nodes.amp = context.createGain();
|
|
1526
|
+
nodes.amp.gain.value = 0.0;
|
|
1527
|
+
nodes.target = context.createGain();
|
|
1528
|
+
nodes.target.gain.value = 1.0;
|
|
1529
|
+
nodes.amp.connect(nodes.target);
|
|
1530
|
+
nodes.target.connect(master);
|
|
1531
|
+
if (props.filter) {
|
|
1532
|
+
nodes.filter = context.createBiquadFilter();
|
|
1533
|
+
nodes.filter.type = props.filter.type;
|
|
1534
|
+
nodes.filter.frequency.value = props.filter.cutoff;
|
|
1535
|
+
nodes.oscillator.connect(nodes.filter);
|
|
1536
|
+
nodes.filter.connect(nodes.amp);
|
|
1537
|
+
}
|
|
1538
|
+
else {
|
|
1539
|
+
nodes.oscillator.connect(nodes.amp);
|
|
1540
|
+
}
|
|
1541
|
+
if (props.reverb) {
|
|
1542
|
+
nodes.convolver = context.createConvolver();
|
|
1543
|
+
nodes.convolver.buffer = impulseResponse({ time: props.reverb.time });
|
|
1544
|
+
nodes.convolverDepth = context.createGain();
|
|
1545
|
+
nodes.convolverDepth.gain.value = 1.0;
|
|
1546
|
+
nodes.convolverDepth.gain.value *= props.reverb.mix;
|
|
1547
|
+
nodes.target.gain.value *= (1.0 - props.reverb.mix);
|
|
1548
|
+
nodes.amp.connect(nodes.convolver);
|
|
1549
|
+
nodes.convolver.connect(nodes.convolverDepth);
|
|
1550
|
+
nodes.convolverDepth.connect(master);
|
|
1551
|
+
}
|
|
1552
|
+
if (props.oscillator.envelope) {
|
|
1553
|
+
const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
|
|
1554
|
+
startEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
|
|
1555
|
+
}
|
|
1556
|
+
if (props.amp.envelope) {
|
|
1557
|
+
startEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
|
|
1558
|
+
}
|
|
1559
|
+
nodes.oscillator.start(start);
|
|
1560
|
+
if (dv > 0) {
|
|
1561
|
+
release();
|
|
1562
|
+
}
|
|
1563
|
+
else {
|
|
1564
|
+
return { release };
|
|
1565
|
+
}
|
|
1566
|
+
function release() {
|
|
1567
|
+
let stop = null;
|
|
1568
|
+
const end = dv > 0 ? dv : (context.currentTime - start);
|
|
1569
|
+
if (props.amp.envelope) {
|
|
1570
|
+
const ADSR = props.amp.envelope.ADSR;
|
|
1571
|
+
const adsr = [ADSR[0] / 1000, ADSR[1] / 1000, ADSR[2], ADSR[3] / 1000];
|
|
1572
|
+
const rate = adsr[0] === 0.0 ? 1.0 : Math.min(end / (adsr[0] + 0.001), 1.0);
|
|
1573
|
+
stop = start + Math.max((adsr[0] + adsr[1]) * rate, end) + adsr[3];
|
|
1574
|
+
}
|
|
1575
|
+
else {
|
|
1576
|
+
stop = start + end;
|
|
1577
|
+
}
|
|
1578
|
+
if (nodes.oscillatorLFO) {
|
|
1579
|
+
nodes.oscillatorLFO.stop(stop);
|
|
1580
|
+
}
|
|
1581
|
+
if (props.oscillator.envelope) {
|
|
1582
|
+
const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
|
|
1583
|
+
stopEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
|
|
1584
|
+
}
|
|
1585
|
+
if (props.amp.envelope) {
|
|
1586
|
+
stopEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
|
|
1587
|
+
}
|
|
1588
|
+
nodes.oscillator.stop(stop);
|
|
1589
|
+
setTimeout(() => {
|
|
1590
|
+
var _a, _b, _c, _d, _e;
|
|
1591
|
+
nodes.oscillator.disconnect();
|
|
1592
|
+
nodes.amp.disconnect();
|
|
1593
|
+
nodes.target.disconnect();
|
|
1594
|
+
(_a = nodes.oscillatorLFO) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
1595
|
+
(_b = nodes.oscillatorLFODepth) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
1596
|
+
(_c = nodes.filter) === null || _c === void 0 ? void 0 : _c.disconnect();
|
|
1597
|
+
(_d = nodes.convolver) === null || _d === void 0 ? void 0 : _d.disconnect();
|
|
1598
|
+
(_e = nodes.convolverDepth) === null || _e === void 0 ? void 0 : _e.disconnect();
|
|
1599
|
+
}, 2000);
|
|
1600
|
+
}
|
|
1601
|
+
function stopEnvelope(param, base, amount, ADSR) {
|
|
1602
|
+
const end = dv > 0 ? dv : (context.currentTime - start);
|
|
1603
|
+
const rate = ADSR[0] === 0.0 ? 1.0 : Math.min(end / (ADSR[0] / 1000), 1.0);
|
|
1604
|
+
if (rate < 1.0) {
|
|
1605
|
+
param.cancelScheduledValues(start);
|
|
1606
|
+
param.setValueAtTime(base, start);
|
|
1607
|
+
param.linearRampToValueAtTime(base + amount * rate, start + ADSR[0] / 1000 * rate);
|
|
1608
|
+
param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000 * rate);
|
|
1609
|
+
}
|
|
1610
|
+
param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dv));
|
|
1611
|
+
param.linearRampToValueAtTime(base, start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, end) + ADSR[3] / 1000);
|
|
1612
|
+
}
|
|
1613
|
+
function startEnvelope(param, base, amount, ADSR) {
|
|
1614
|
+
param.value = base;
|
|
1615
|
+
param.setValueAtTime(base, start);
|
|
1616
|
+
param.linearRampToValueAtTime(base + amount, start + ADSR[0] / 1000);
|
|
1617
|
+
param.linearRampToValueAtTime(base + amount * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000);
|
|
1618
|
+
}
|
|
1619
|
+
function impulseResponse({ time, decay = 2.0 }) {
|
|
1620
|
+
const length = context.sampleRate * time / 1000;
|
|
1621
|
+
const impulse = context.createBuffer(2, length, context.sampleRate);
|
|
1622
|
+
const ch0 = impulse.getChannelData(0);
|
|
1623
|
+
const ch1 = impulse.getChannelData(1);
|
|
1624
|
+
for (let i = 0; i < length; i++) {
|
|
1625
|
+
ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
|
|
1626
|
+
ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
|
|
1627
|
+
}
|
|
1628
|
+
return impulse;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1416
1633
|
const basics = {
|
|
1417
1634
|
Screen,
|
|
1418
1635
|
Modal,
|
|
@@ -1421,6 +1638,33 @@ const basics = {
|
|
|
1421
1638
|
AnalogStick,
|
|
1422
1639
|
DirectionalPad,
|
|
1423
1640
|
};
|
|
1424
|
-
const
|
|
1641
|
+
const audio = {
|
|
1642
|
+
load(path) {
|
|
1643
|
+
const music = new AudioFile(path);
|
|
1644
|
+
const object = {
|
|
1645
|
+
play(options = {}) {
|
|
1646
|
+
const unit = xnew();
|
|
1647
|
+
if (music.start === null) {
|
|
1648
|
+
music.play(options);
|
|
1649
|
+
unit.on('finalize', () => music.pause({ fade: options.fade }));
|
|
1650
|
+
}
|
|
1651
|
+
},
|
|
1652
|
+
pause(options = {}) {
|
|
1653
|
+
music.pause(options);
|
|
1654
|
+
}
|
|
1655
|
+
};
|
|
1656
|
+
return xnew.promise(music.promise).then(() => object);
|
|
1657
|
+
},
|
|
1658
|
+
synthesizer(props) {
|
|
1659
|
+
return new Synthesizer(props);
|
|
1660
|
+
},
|
|
1661
|
+
get volume() {
|
|
1662
|
+
return master.gain.value;
|
|
1663
|
+
},
|
|
1664
|
+
set volume(value) {
|
|
1665
|
+
master.gain.value = value;
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
const xnew = Object.assign(xnew$1, { basics, audio });
|
|
1425
1669
|
|
|
1426
1670
|
export { xnew as default };
|