Source code for noisemaker.presets

from __future__ import annotations

from copy import deepcopy
from functools import lru_cache
from pathlib import Path
from typing import Any

import noisemaker.rng as random
from noisemaker.composer import Preset as ComposerPreset
from noisemaker.dsl import parse_preset_dsl

# Global override for custom presets file path
_custom_presets_path: Path | None = None


[docs] def set_presets_path(path: str | Path | None) -> None: """Set a custom path for the presets DSL file. When set, presets will be loaded from this path instead of the default share/dsl/presets.dsl location. Set to None to revert to the default. Args: path: Path to a .dsl file containing preset definitions, or None to use default. """ global _custom_presets_path if path is not None: _custom_presets_path = Path(path).resolve() else: _custom_presets_path = None # Clear the cache so presets are reloaded from the new path _cached_dsl_presets.cache_clear()
[docs] def get_presets_path() -> Path: """Get the current presets DSL file path. Returns: Path to the presets DSL file (either custom or default). """ if _custom_presets_path is not None: return _custom_presets_path return Path(__file__).resolve().parent.parent / "share" / "dsl" / "presets.dsl"
@lru_cache(maxsize=1) def _cached_dsl_presets() -> dict[str, Any]: """Load and cache presets from the DSL file with a deterministic seed. Uses a fixed seed (0) to ensure preset evaluation is consistent across runs. Restores the original RNG seed after loading. Returns: Dictionary of parsed preset definitions from the presets DSL file. """ dsl_path = get_presets_path() seed_before = random.get_seed() random.set_seed(0) try: with open(dsl_path, encoding="utf-8") as fh: return parse_preset_dsl(fh.read()) finally: random.set_seed(seed_before)
[docs] def PRESETS() -> dict[str, Any]: """Get a fresh copy of all presets with synchronized RNG state. Returns a deep copy to prevent mutations from affecting the cached version. Includes mandatory RNG calls to maintain Python/JS parity. Returns: Dictionary of all available preset definitions. """ presets = deepcopy(_cached_dsl_presets()) # This is somehow keeping the Python and JS ports in sync, removing it from both # places breaks parity. WTF random.random() random.random() random.random() return presets
[docs] def Preset(preset_name: str, *, settings: dict[str, Any] | None = None) -> ComposerPreset: """Create a Preset instance from the DSL preset collection. Convenience factory function for creating preset objects with optional settings overrides. Args: preset_name: Name of the preset to load from presets.dsl. settings: Optional dictionary of setting overrides. Returns: Configured Preset object ready for rendering. Raises: ValueError: If preset_name is not found or preset definition is invalid. """ return ComposerPreset(preset_name, presets=PRESETS(), settings=settings)