@litlab/audx 0.6.0 → 0.8.5

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/bin.js CHANGED
@@ -1,10 +1,9 @@
1
- #!/usr/bin/env node
2
1
  import * as p from '@clack/prompts';
2
+ import { a as _object_without_properties_loose, _ as _extends } from './cc-zJdVkWBV.js';
3
3
  import { existsSync, mkdirSync } from 'node:fs';
4
4
  import { readdir, readFile, writeFile, unlink } from 'node:fs/promises';
5
5
  import __node_cjsPath, { resolve, join, basename, isAbsolute } from 'node:path';
6
6
  import pc from 'picocolors';
7
- import { _ as _object_without_properties_loose } from './cc-DgCkkqq8.js';
8
7
  import __node_cjsModule from 'node:module';
9
8
  import __node_cjsUrl from 'node:url';
10
9
 
@@ -386,6 +385,10 @@ function parseAddOptions(args) {
386
385
  options.list = true;
387
386
  } else if (arg === "--theme") {
388
387
  options.theme = args[++i];
388
+ } else if (arg === "--data") {
389
+ options.data = args[++i];
390
+ } else if (arg === "--tune") {
391
+ options.tune = args[++i];
389
392
  } else if (arg && !arg.startsWith("-")) {
390
393
  source = arg;
391
394
  }
@@ -399,9 +402,21 @@ async function add(args) {
399
402
  const { source, options } = parseAddOptions(args);
400
403
  p.intro("@litlab/audx add");
401
404
  if (!source) {
405
+ if (options.data || options.tune) {
406
+ p.log.error("--data and --tune require a sound name.");
407
+ process.exit(1);
408
+ }
402
409
  await addFromRegistry(options);
403
410
  return;
404
411
  }
412
+ if (options.data) {
413
+ await addEncodedSound(source, options);
414
+ return;
415
+ }
416
+ if (options.tune) {
417
+ await addTunedSound(source, options);
418
+ return;
419
+ }
405
420
  if (isLocalSource(source)) {
406
421
  await addFromLocal(source, options);
407
422
  return;
@@ -416,6 +431,178 @@ async function add(args) {
416
431
  }
417
432
  await addSoundFromRegistry(source, options);
418
433
  }
434
+ const WAVEFORM_CODES = {
435
+ o: "original",
436
+ s: "sine",
437
+ t: "triangle",
438
+ q: "square",
439
+ w: "sawtooth"
440
+ };
441
+ function decodeSoundCustomization(value) {
442
+ const [version, pitch, duration, gain, pan, waveform, ...extra] = value.split(".");
443
+ if (version !== "1" || extra.length > 0 || !pitch || !duration || !gain || !pan || !waveform) {
444
+ throw new Error("unsupported tuning token");
445
+ }
446
+ const settings = {
447
+ pitch: Number.parseInt(pitch, 36) - 12,
448
+ duration: Number.parseInt(duration, 36) / 20,
449
+ gain: Number.parseInt(gain, 36) / 20,
450
+ pan: (Number.parseInt(pan, 36) - 20) / 20,
451
+ waveform: WAVEFORM_CODES[waveform]
452
+ };
453
+ if (!Number.isInteger(settings.pitch) || settings.pitch < -12 || settings.pitch > 12 || !Number.isFinite(settings.duration) || settings.duration < 0.25 || settings.duration > 3 || !Number.isFinite(settings.gain) || settings.gain < 0 || settings.gain > 2 || !Number.isFinite(settings.pan) || settings.pan < -1 || settings.pan > 1 || !settings.waveform) {
454
+ throw new Error("invalid tuning values");
455
+ }
456
+ return settings;
457
+ }
458
+ async function addTunedSound(soundName, options) {
459
+ if (!options.theme) {
460
+ p.log.error("--tune requires --theme <name>.");
461
+ process.exit(1);
462
+ }
463
+ let settings;
464
+ try {
465
+ var _options_tune;
466
+ settings = decodeSoundCustomization((_options_tune = options.tune) != null ? _options_tune : "");
467
+ } catch (err) {
468
+ p.log.error(`Invalid tuning token: ${err instanceof Error ? err.message : String(err)}`);
469
+ process.exit(1);
470
+ }
471
+ const s = p.spinner();
472
+ s.start(`Fetching "${soundName}" from ${options.theme}...`);
473
+ try {
474
+ const theme = await fetchThemeJson(options.theme);
475
+ if (!validateTheme(theme)) throw new Error("invalid theme");
476
+ const match = Object.entries(theme.sounds).find(([name])=>name.toLowerCase() === soundName.toLowerCase());
477
+ if (!match) throw new Error(`sound not found in theme "${options.theme}"`);
478
+ const definition = customizeDefinition(match[1], settings);
479
+ if (!validateSoundDefinition(definition)) {
480
+ throw new Error("theme returned an invalid sound definition");
481
+ }
482
+ s.stop(`Customized "${soundName}" from ${theme.name}`);
483
+ await writeSound(soundName, definition, options);
484
+ p.note(` - ${soundName}`, "Installed customized sound");
485
+ p.outro("Done!");
486
+ } catch (err) {
487
+ s.stop("Failed to install customized sound.");
488
+ p.log.error(err instanceof Error ? err.message : String(err));
489
+ process.exit(1);
490
+ }
491
+ }
492
+ function customizeDefinition(value, settings) {
493
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
494
+ const definition = value;
495
+ if (Array.isArray(definition.layers)) {
496
+ return _extends({}, definition, {
497
+ layers: definition.layers.map((layer)=>customizeDefinition(layer, settings)),
498
+ effects: scaleEffects(definition.effects, settings.duration)
499
+ });
500
+ }
501
+ const source = customizeSource(definition.source, settings);
502
+ const envelope = definition.envelope && typeof definition.envelope === "object" && !Array.isArray(definition.envelope) ? scaleEnvelope(definition.envelope, settings.duration) : undefined;
503
+ const gain = typeof definition.gain === "number" ? definition.gain : 0.5;
504
+ const delay = typeof definition.delay === "number" ? definition.delay : 0;
505
+ return _extends({}, definition, {
506
+ source,
507
+ envelope,
508
+ gain: clamp(gain * settings.gain, 0, 1)
509
+ }, "panner" in definition ? {} : {
510
+ pan: clamp((typeof definition.pan === "number" ? definition.pan : 0) + settings.pan, -1, 1)
511
+ }, {
512
+ delay: delay * settings.duration,
513
+ effects: scaleEffects(definition.effects, settings.duration)
514
+ });
515
+ }
516
+ function customizeSource(value, settings) {
517
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
518
+ const source = value;
519
+ const frequencyScale = 2 ** (settings.pitch / 12);
520
+ if (source.type === "sine" || source.type === "triangle" || source.type === "square" || source.type === "sawtooth" || source.type === "wavetable") {
521
+ return _extends({}, source, source.type === "wavetable" || settings.waveform === "original" ? {} : {
522
+ type: settings.waveform
523
+ }, {
524
+ frequency: scaleFrequency(source.frequency, frequencyScale)
525
+ });
526
+ }
527
+ if (source.type === "sample") {
528
+ return _extends({}, source, {
529
+ detune: (typeof source.detune === "number" ? source.detune : 0) + settings.pitch * 100
530
+ });
531
+ }
532
+ return source;
533
+ }
534
+ function scaleFrequency(value, scale) {
535
+ if (typeof value === "number") return value * scale;
536
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
537
+ const frequency = value;
538
+ if (typeof frequency.start !== "number" || typeof frequency.end !== "number") {
539
+ return value;
540
+ }
541
+ return {
542
+ start: frequency.start * scale,
543
+ end: frequency.end * scale
544
+ };
545
+ }
546
+ function scaleEnvelope(envelope, duration) {
547
+ return _extends({}, envelope, {
548
+ attack: (typeof envelope.attack === "number" ? envelope.attack : 0) * duration,
549
+ decay: (typeof envelope.decay === "number" ? envelope.decay : 0) * duration,
550
+ release: (typeof envelope.release === "number" ? envelope.release : 0) * duration
551
+ });
552
+ }
553
+ function scaleEffects(value, duration) {
554
+ if (!Array.isArray(value)) return undefined;
555
+ return value.map((effect)=>{
556
+ if (!effect || typeof effect !== "object" || Array.isArray(effect)) {
557
+ return effect;
558
+ }
559
+ const item = effect;
560
+ if (item.type === "delay") {
561
+ return _extends({}, item, {
562
+ time: (typeof item.time === "number" ? item.time : 0.25) * duration
563
+ });
564
+ }
565
+ if (item.type === "reverb") {
566
+ return _extends({}, item, {
567
+ decay: (typeof item.decay === "number" ? item.decay : 0.5) * duration,
568
+ preDelay: (typeof item.preDelay === "number" ? item.preDelay : 0) * duration
569
+ });
570
+ }
571
+ return item;
572
+ });
573
+ }
574
+ function clamp(value, min, max) {
575
+ return Math.min(max, Math.max(min, value));
576
+ }
577
+ async function addEncodedSound(soundName, options) {
578
+ let definition;
579
+ try {
580
+ var _options_data;
581
+ definition = decodeSoundDefinition((_options_data = options.data) != null ? _options_data : "");
582
+ } catch (err) {
583
+ p.log.error(`Invalid customized sound data: ${err instanceof Error ? err.message : String(err)}`);
584
+ process.exit(1);
585
+ }
586
+ if (!validateSoundDefinition(definition)) {
587
+ p.log.error("Invalid customized sound definition.");
588
+ process.exit(1);
589
+ }
590
+ await writeSound(soundName, definition, options);
591
+ p.note(` - ${soundName}`, "Installed customized sound");
592
+ p.outro("Done!");
593
+ }
594
+ function decodeSoundDefinition(value) {
595
+ if (!value) throw new Error("missing value");
596
+ return JSON.parse(Buffer.from(value, "base64url").toString("utf-8"));
597
+ }
598
+ function validateSoundDefinition(value) {
599
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
600
+ const definition = value;
601
+ if (Array.isArray(definition.layers)) {
602
+ return definition.layers.length > 0 && definition.layers.every(validateSoundDefinition);
603
+ }
604
+ return !!definition.source && typeof definition.source === "object" && !Array.isArray(definition.source);
605
+ }
419
606
  async function addFromLocal(source, options) {
420
607
  const s = p.spinner();
421
608
  s.start("Scanning local path for themes...");
@@ -1147,6 +1334,8 @@ function showHelp() {
1147
1334
  " -l, --list Preview available themes without installing",
1148
1335
  " -y, --yes Skip confirmation prompts",
1149
1336
  " --theme <name> Install a specific theme by name",
1337
+ " --data <value> Install an encoded customized sound definition",
1338
+ " --tune <token> Apply compact editor settings (requires --theme)",
1150
1339
  "",
1151
1340
  "Remove Options:",
1152
1341
  " -y, --yes Skip confirmation prompts"
@@ -1,3 +1,14 @@
1
+ function _extends() {
2
+ _extends = Object.assign || function assign(target) {
3
+ for(var i = 1; i < arguments.length; i++){
4
+ var source = arguments[i];
5
+ for(var key in source)if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
6
+ }
7
+ return target;
8
+ };
9
+ return _extends.apply(this, arguments);
10
+ }
11
+
1
12
  function _object_without_properties_loose(source, excluded) {
2
13
  if (source == null) return {};
3
14
  var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
@@ -10,4 +21,4 @@ function _object_without_properties_loose(source, excluded) {
10
21
  return target;
11
22
  }
12
23
 
13
- export { _object_without_properties_loose as _ };
24
+ export { _extends as _, _object_without_properties_loose as a };
package/dist/index.js CHANGED
@@ -1293,7 +1293,9 @@ function createPatchInstance(data) {
1293
1293
  * @throws {Error} If the network request fails
1294
1294
  */ async function loadPatch(source) {
1295
1295
  if (typeof source === "string") {
1296
- const response = await fetch(source);
1296
+ const response = await fetch(source, {
1297
+ cache: "no-store"
1298
+ });
1297
1299
  if (!response.ok) throw new Error(`Failed to load patch from ${source}: ${response.status}`);
1298
1300
  const data = await response.json();
1299
1301
  return createPatchInstance(data);
package/dist/react.js CHANGED
@@ -1149,7 +1149,9 @@ function createPatchInstance(data) {
1149
1149
  * @throws {Error} If the network request fails
1150
1150
  */ async function loadPatch(source) {
1151
1151
  if (typeof source === "string") {
1152
- const response = await fetch(source);
1152
+ const response = await fetch(source, {
1153
+ cache: "no-store"
1154
+ });
1153
1155
  if (!response.ok) throw new Error(`Failed to load patch from ${source}: ${response.status}`);
1154
1156
  const data = await response.json();
1155
1157
  return createPatchInstance(data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litlab/audx",
3
- "version": "0.6.0",
3
+ "version": "0.8.5",
4
4
  "description": "Core Engine For Semantic Web Audio",
5
5
  "author": "Om Mishra",
6
6
  "license": "MIT",