playlist-data-engine 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +352 -0
- package/dist/__vite-browser-external-DYxpcVy9.js +4 -0
- package/dist/constants/DefaultClasses.d.ts +46 -0
- package/dist/constants/DefaultClasses.d.ts.map +1 -0
- package/dist/constants/DefaultEnchantments.d.ts +337 -0
- package/dist/constants/DefaultEnchantments.d.ts.map +1 -0
- package/dist/constants/DefaultEnemies.d.ts +83 -0
- package/dist/constants/DefaultEnemies.d.ts.map +1 -0
- package/dist/constants/DefaultEquipment.d.ts +23 -0
- package/dist/constants/DefaultEquipment.d.ts.map +1 -0
- package/dist/constants/DefaultFeatures.d.ts +22 -0
- package/dist/constants/DefaultFeatures.d.ts.map +1 -0
- package/dist/constants/DefaultRaces.d.ts +102 -0
- package/dist/constants/DefaultRaces.d.ts.map +1 -0
- package/dist/constants/DefaultSkills.d.ts +26 -0
- package/dist/constants/DefaultSkills.d.ts.map +1 -0
- package/dist/constants/DefaultSpells.d.ts +41 -0
- package/dist/constants/DefaultSpells.d.ts.map +1 -0
- package/dist/constants/EncounterBalance.d.ts +208 -0
- package/dist/constants/EncounterBalance.d.ts.map +1 -0
- package/dist/constants/EnemyEquipment.d.ts +71 -0
- package/dist/constants/EnemyEquipment.d.ts.map +1 -0
- package/dist/constants/EnemyRarity.d.ts +79 -0
- package/dist/constants/EnemyRarity.d.ts.map +1 -0
- package/dist/constants/EnemyTemplates/Construct.d.ts +63 -0
- package/dist/constants/EnemyTemplates/Construct.d.ts.map +1 -0
- package/dist/constants/EnemyTemplates/Dragon.d.ts +68 -0
- package/dist/constants/EnemyTemplates/Dragon.d.ts.map +1 -0
- package/dist/constants/EnemyTemplates/Elemental.d.ts +64 -0
- package/dist/constants/EnemyTemplates/Elemental.d.ts.map +1 -0
- package/dist/constants/EnemyTemplates/Fiend.d.ts +62 -0
- package/dist/constants/EnemyTemplates/Fiend.d.ts.map +1 -0
- package/dist/constants/EnemyTemplates/Monstrosity.d.ts +63 -0
- package/dist/constants/EnemyTemplates/Monstrosity.d.ts.map +1 -0
- package/dist/constants/EnemyTemplates/Undead.d.ts +61 -0
- package/dist/constants/EnemyTemplates/Undead.d.ts.map +1 -0
- package/dist/constants/ItemTemplates.d.ts +40 -0
- package/dist/constants/ItemTemplates.d.ts.map +1 -0
- package/dist/constants/MagicItems.d.ts +30 -0
- package/dist/constants/MagicItems.d.ts.map +1 -0
- package/dist/constants/SpellSlots.d.ts +30 -0
- package/dist/constants/SpellSlots.d.ts.map +1 -0
- package/dist/constants/StatScaling.d.ts +113 -0
- package/dist/constants/StatScaling.d.ts.map +1 -0
- package/dist/core/analysis/AudioAnalyzer.d.ts +599 -0
- package/dist/core/analysis/AudioAnalyzer.d.ts.map +1 -0
- package/dist/core/analysis/ColorExtractor.d.ts +64 -0
- package/dist/core/analysis/ColorExtractor.d.ts.map +1 -0
- package/dist/core/analysis/EssentiaPitchDetector.d.ts +282 -0
- package/dist/core/analysis/EssentiaPitchDetector.d.ts.map +1 -0
- package/dist/core/analysis/LevelSerializer.d.ts +265 -0
- package/dist/core/analysis/LevelSerializer.d.ts.map +1 -0
- package/dist/core/analysis/MelodyContourAnalyzer.d.ts +283 -0
- package/dist/core/analysis/MelodyContourAnalyzer.d.ts.map +1 -0
- package/dist/core/analysis/MultiBandAnalyzer.d.ts +214 -0
- package/dist/core/analysis/MultiBandAnalyzer.d.ts.map +1 -0
- package/dist/core/analysis/MusicClassifier.d.ts +524 -0
- package/dist/core/analysis/MusicClassifier.d.ts.map +1 -0
- package/dist/core/analysis/PitchAnalyzer.d.ts +266 -0
- package/dist/core/analysis/PitchAnalyzer.d.ts.map +1 -0
- package/dist/core/analysis/PitchDetector.d.ts +251 -0
- package/dist/core/analysis/PitchDetector.d.ts.map +1 -0
- package/dist/core/analysis/SpectrumScanner.d.ts +52 -0
- package/dist/core/analysis/SpectrumScanner.d.ts.map +1 -0
- package/dist/core/analysis/beat/BeatInterpolator.d.ts +477 -0
- package/dist/core/analysis/beat/BeatInterpolator.d.ts.map +1 -0
- package/dist/core/analysis/beat/BeatMapGenerator.d.ts +170 -0
- package/dist/core/analysis/beat/BeatMapGenerator.d.ts.map +1 -0
- package/dist/core/analysis/beat/BeatStream.d.ts +316 -0
- package/dist/core/analysis/beat/BeatStream.d.ts.map +1 -0
- package/dist/core/analysis/beat/BeatSubdivider.d.ts +205 -0
- package/dist/core/analysis/beat/BeatSubdivider.d.ts.map +1 -0
- package/dist/core/analysis/beat/BeatTracker.d.ts +137 -0
- package/dist/core/analysis/beat/BeatTracker.d.ts.map +1 -0
- package/dist/core/analysis/beat/CompositeStreamGenerator.d.ts +180 -0
- package/dist/core/analysis/beat/CompositeStreamGenerator.d.ts.map +1 -0
- package/dist/core/analysis/beat/DensityAnalyzer.d.ts +246 -0
- package/dist/core/analysis/beat/DensityAnalyzer.d.ts.map +1 -0
- package/dist/core/analysis/beat/DifficultyVariantGenerator.d.ts +1082 -0
- package/dist/core/analysis/beat/DifficultyVariantGenerator.d.ts.map +1 -0
- package/dist/core/analysis/beat/GrooveAnalyzer.d.ts +192 -0
- package/dist/core/analysis/beat/GrooveAnalyzer.d.ts.map +1 -0
- package/dist/core/analysis/beat/OnsetStrengthEnvelope.d.ts +133 -0
- package/dist/core/analysis/beat/OnsetStrengthEnvelope.d.ts.map +1 -0
- package/dist/core/analysis/beat/PhraseAnalyzer.d.ts +230 -0
- package/dist/core/analysis/beat/PhraseAnalyzer.d.ts.map +1 -0
- package/dist/core/analysis/beat/RhythmQuantizer.d.ts +399 -0
- package/dist/core/analysis/beat/RhythmQuantizer.d.ts.map +1 -0
- package/dist/core/analysis/beat/RhythmicBalancer.d.ts +262 -0
- package/dist/core/analysis/beat/RhythmicBalancer.d.ts.map +1 -0
- package/dist/core/analysis/beat/StreamScorer.d.ts +275 -0
- package/dist/core/analysis/beat/StreamScorer.d.ts.map +1 -0
- package/dist/core/analysis/beat/TempoAwareQuantizer.d.ts +256 -0
- package/dist/core/analysis/beat/TempoAwareQuantizer.d.ts.map +1 -0
- package/dist/core/analysis/beat/TempoDetector.d.ts +220 -0
- package/dist/core/analysis/beat/TempoDetector.d.ts.map +1 -0
- package/dist/core/analysis/beat/TransientDetector.d.ts +303 -0
- package/dist/core/analysis/beat/TransientDetector.d.ts.map +1 -0
- package/dist/core/analysis/beat/beatKeyHelpers.d.ts +180 -0
- package/dist/core/analysis/beat/beatKeyHelpers.d.ts.map +1 -0
- package/dist/core/analysis/beat/index.d.ts +41 -0
- package/dist/core/analysis/beat/index.d.ts.map +1 -0
- package/dist/core/analysis/beat/utils/audioUtils.d.ts +204 -0
- package/dist/core/analysis/beat/utils/audioUtils.d.ts.map +1 -0
- package/dist/core/analysis/beat/utils/beatInterpolationDebug.d.ts +404 -0
- package/dist/core/analysis/beat/utils/beatInterpolationDebug.d.ts.map +1 -0
- package/dist/core/analysis/beat/utils/subdivideBeatMap.d.ts +61 -0
- package/dist/core/analysis/beat/utils/subdivideBeatMap.d.ts.map +1 -0
- package/dist/core/analysis/beat/utils/unifyBeatMap.d.ts +33 -0
- package/dist/core/analysis/beat/utils/unifyBeatMap.d.ts.map +1 -0
- package/dist/core/analysis/index.d.ts +18 -0
- package/dist/core/analysis/index.d.ts.map +1 -0
- package/dist/core/combat/AI/AICombatRunner.d.ts +108 -0
- package/dist/core/combat/AI/AICombatRunner.d.ts.map +1 -0
- package/dist/core/combat/AI/CombatAI.d.ts +179 -0
- package/dist/core/combat/AI/CombatAI.d.ts.map +1 -0
- package/dist/core/combat/AI/CombatMetricsTracker.d.ts +30 -0
- package/dist/core/combat/AI/CombatMetricsTracker.d.ts.map +1 -0
- package/dist/core/combat/Analysis/BalanceValidator.d.ts +170 -0
- package/dist/core/combat/Analysis/BalanceValidator.d.ts.map +1 -0
- package/dist/core/combat/Analysis/ComparativeAnalyzer.d.ts +231 -0
- package/dist/core/combat/Analysis/ComparativeAnalyzer.d.ts.map +1 -0
- package/dist/core/combat/Analysis/DifficultyCalculator.d.ts +203 -0
- package/dist/core/combat/Analysis/DifficultyCalculator.d.ts.map +1 -0
- package/dist/core/combat/Analysis/ParameterSweep.d.ts +201 -0
- package/dist/core/combat/Analysis/ParameterSweep.d.ts.map +1 -0
- package/dist/core/combat/AttackResolver.d.ts +220 -0
- package/dist/core/combat/AttackResolver.d.ts.map +1 -0
- package/dist/core/combat/CombatEngine.d.ts +388 -0
- package/dist/core/combat/CombatEngine.d.ts.map +1 -0
- package/dist/core/combat/DiceRoller.d.ts +115 -0
- package/dist/core/combat/DiceRoller.d.ts.map +1 -0
- package/dist/core/combat/InitiativeRoller.d.ts +62 -0
- package/dist/core/combat/InitiativeRoller.d.ts.map +1 -0
- package/dist/core/combat/PartyAnalyzer.d.ts +215 -0
- package/dist/core/combat/PartyAnalyzer.d.ts.map +1 -0
- package/dist/core/combat/SeededDiceRoller.d.ts +120 -0
- package/dist/core/combat/SeededDiceRoller.d.ts.map +1 -0
- package/dist/core/combat/Simulation/CombatSimulator.d.ts +366 -0
- package/dist/core/combat/Simulation/CombatSimulator.d.ts.map +1 -0
- package/dist/core/combat/SpellCaster.d.ts +113 -0
- package/dist/core/combat/SpellCaster.d.ts.map +1 -0
- package/dist/core/config/index.d.ts +24 -0
- package/dist/core/config/index.d.ts.map +1 -0
- package/dist/core/config/progressionConfig.d.ts +73 -0
- package/dist/core/config/progressionConfig.d.ts.map +1 -0
- package/dist/core/config/sensorConfig.d.ts +134 -0
- package/dist/core/config/sensorConfig.d.ts.map +1 -0
- package/dist/core/equipment/BoxOpener.d.ts +175 -0
- package/dist/core/equipment/BoxOpener.d.ts.map +1 -0
- package/dist/core/equipment/EquipmentEffectApplier.d.ts +189 -0
- package/dist/core/equipment/EquipmentEffectApplier.d.ts.map +1 -0
- package/dist/core/equipment/EquipmentModifier.d.ts +327 -0
- package/dist/core/equipment/EquipmentModifier.d.ts.map +1 -0
- package/dist/core/equipment/EquipmentSpawnHelper.d.ts +246 -0
- package/dist/core/equipment/EquipmentSpawnHelper.d.ts.map +1 -0
- package/dist/core/equipment/EquipmentValidator.d.ts +173 -0
- package/dist/core/equipment/EquipmentValidator.d.ts.map +1 -0
- package/dist/core/extensions/ExtensionManager.d.ts +517 -0
- package/dist/core/extensions/ExtensionManager.d.ts.map +1 -0
- package/dist/core/extensions/WeightedSelector.d.ts +156 -0
- package/dist/core/extensions/WeightedSelector.d.ts.map +1 -0
- package/dist/core/extensions/index.d.ts +11 -0
- package/dist/core/extensions/index.d.ts.map +1 -0
- package/dist/core/extensions/initializeDefaults.d.ts +170 -0
- package/dist/core/extensions/initializeDefaults.d.ts.map +1 -0
- package/dist/core/features/FeatureEffectApplier.d.ts +102 -0
- package/dist/core/features/FeatureEffectApplier.d.ts.map +1 -0
- package/dist/core/features/FeatureQuery.d.ts +368 -0
- package/dist/core/features/FeatureQuery.d.ts.map +1 -0
- package/dist/core/features/FeatureTypes.d.ts +199 -0
- package/dist/core/features/FeatureTypes.d.ts.map +1 -0
- package/dist/core/features/FeatureValidator.d.ts +149 -0
- package/dist/core/features/FeatureValidator.d.ts.map +1 -0
- package/dist/core/features/index.d.ts +12 -0
- package/dist/core/features/index.d.ts.map +1 -0
- package/dist/core/generation/AbilityScoreCalculator.d.ts +83 -0
- package/dist/core/generation/AbilityScoreCalculator.d.ts.map +1 -0
- package/dist/core/generation/AppearanceGenerator.d.ts +32 -0
- package/dist/core/generation/AppearanceGenerator.d.ts.map +1 -0
- package/dist/core/generation/BeatConverter.d.ts +127 -0
- package/dist/core/generation/BeatConverter.d.ts.map +1 -0
- package/dist/core/generation/ButtonMapper.d.ts +346 -0
- package/dist/core/generation/ButtonMapper.d.ts.map +1 -0
- package/dist/core/generation/ButtonPatternLibrary.d.ts +92 -0
- package/dist/core/generation/ButtonPatternLibrary.d.ts.map +1 -0
- package/dist/core/generation/CRLevelConverter.d.ts +242 -0
- package/dist/core/generation/CRLevelConverter.d.ts.map +1 -0
- package/dist/core/generation/CharacterGenerator.d.ts +194 -0
- package/dist/core/generation/CharacterGenerator.d.ts.map +1 -0
- package/dist/core/generation/ClassSuggester.d.ts +184 -0
- package/dist/core/generation/ClassSuggester.d.ts.map +1 -0
- package/dist/core/generation/EnemyEquipmentGenerator.d.ts +151 -0
- package/dist/core/generation/EnemyEquipmentGenerator.d.ts.map +1 -0
- package/dist/core/generation/EnemyGenerator.d.ts +595 -0
- package/dist/core/generation/EnemyGenerator.d.ts.map +1 -0
- package/dist/core/generation/EquipmentGenerator.d.ts +204 -0
- package/dist/core/generation/EquipmentGenerator.d.ts.map +1 -0
- package/dist/core/generation/LegendaryGenerator.d.ts +213 -0
- package/dist/core/generation/LegendaryGenerator.d.ts.map +1 -0
- package/dist/core/generation/LevelGenerator.d.ts +390 -0
- package/dist/core/generation/LevelGenerator.d.ts.map +1 -0
- package/dist/core/generation/NamingEngine.d.ts +136 -0
- package/dist/core/generation/NamingEngine.d.ts.map +1 -0
- package/dist/core/generation/PitchBeatLinker.d.ts +150 -0
- package/dist/core/generation/PitchBeatLinker.d.ts.map +1 -0
- package/dist/core/generation/RaceSelector.d.ts +58 -0
- package/dist/core/generation/RaceSelector.d.ts.map +1 -0
- package/dist/core/generation/RhythmGenerator.d.ts +597 -0
- package/dist/core/generation/RhythmGenerator.d.ts.map +1 -0
- package/dist/core/generation/SkillAssigner.d.ts +78 -0
- package/dist/core/generation/SkillAssigner.d.ts.map +1 -0
- package/dist/core/generation/SpellManager.d.ts +132 -0
- package/dist/core/generation/SpellManager.d.ts.map +1 -0
- package/dist/core/generation/SpellcastingGenerator.d.ts +255 -0
- package/dist/core/generation/SpellcastingGenerator.d.ts.map +1 -0
- package/dist/core/generation/index.d.ts +41 -0
- package/dist/core/generation/index.d.ts.map +1 -0
- package/dist/core/parser/MetadataExtractor.d.ts +66 -0
- package/dist/core/parser/MetadataExtractor.d.ts.map +1 -0
- package/dist/core/parser/PlaylistParser.d.ts +45 -0
- package/dist/core/parser/PlaylistParser.d.ts.map +1 -0
- package/dist/core/playback/SubdivisionPlaybackController.d.ts +333 -0
- package/dist/core/playback/SubdivisionPlaybackController.d.ts.map +1 -0
- package/dist/core/playback/index.d.ts +5 -0
- package/dist/core/playback/index.d.ts.map +1 -0
- package/dist/core/progression/CharacterUpdater.d.ts +203 -0
- package/dist/core/progression/CharacterUpdater.d.ts.map +1 -0
- package/dist/core/progression/LevelUpProcessor.d.ts +234 -0
- package/dist/core/progression/LevelUpProcessor.d.ts.map +1 -0
- package/dist/core/progression/PrestigeSystem.d.ts +217 -0
- package/dist/core/progression/PrestigeSystem.d.ts.map +1 -0
- package/dist/core/progression/RhythmXPCalculator.d.ts +182 -0
- package/dist/core/progression/RhythmXPCalculator.d.ts.map +1 -0
- package/dist/core/progression/SessionTracker.d.ts +169 -0
- package/dist/core/progression/SessionTracker.d.ts.map +1 -0
- package/dist/core/progression/XPCalculator.d.ts +128 -0
- package/dist/core/progression/XPCalculator.d.ts.map +1 -0
- package/dist/core/progression/stat/StatIncreaseStrategy.d.ts +97 -0
- package/dist/core/progression/stat/StatIncreaseStrategy.d.ts.map +1 -0
- package/dist/core/progression/stat/StatManager.d.ts +179 -0
- package/dist/core/progression/stat/StatManager.d.ts.map +1 -0
- package/dist/core/sensors/EnvironmentalSensors.d.ts +301 -0
- package/dist/core/sensors/EnvironmentalSensors.d.ts.map +1 -0
- package/dist/core/sensors/GamingPlatformSensors.d.ts +162 -0
- package/dist/core/sensors/GamingPlatformSensors.d.ts.map +1 -0
- package/dist/core/sensors/GeolocationProvider.d.ts +156 -0
- package/dist/core/sensors/GeolocationProvider.d.ts.map +1 -0
- package/dist/core/sensors/MotionDetector.d.ts +58 -0
- package/dist/core/sensors/MotionDetector.d.ts.map +1 -0
- package/dist/core/sensors/SteamAPIClient.d.ts +108 -0
- package/dist/core/sensors/SteamAPIClient.d.ts.map +1 -0
- package/dist/core/sensors/WeatherAPIClient.d.ts +360 -0
- package/dist/core/sensors/WeatherAPIClient.d.ts.map +1 -0
- package/dist/core/sensors/schemas/weather.schema.d.ts +144 -0
- package/dist/core/sensors/schemas/weather.schema.d.ts.map +1 -0
- package/dist/core/skills/SkillQuery.d.ts +159 -0
- package/dist/core/skills/SkillQuery.d.ts.map +1 -0
- package/dist/core/skills/SkillTypes.d.ts +233 -0
- package/dist/core/skills/SkillTypes.d.ts.map +1 -0
- package/dist/core/skills/SkillValidator.d.ts +146 -0
- package/dist/core/skills/SkillValidator.d.ts.map +1 -0
- package/dist/core/skills/index.d.ts +11 -0
- package/dist/core/skills/index.d.ts.map +1 -0
- package/dist/core/spells/SpellQuery.d.ts +194 -0
- package/dist/core/spells/SpellQuery.d.ts.map +1 -0
- package/dist/core/spells/SpellTypes.d.ts +71 -0
- package/dist/core/spells/SpellTypes.d.ts.map +1 -0
- package/dist/core/spells/SpellValidator.d.ts +129 -0
- package/dist/core/spells/SpellValidator.d.ts.map +1 -0
- package/dist/core/spells/index.d.ts +11 -0
- package/dist/core/spells/index.d.ts.map +1 -0
- package/dist/core/types/AudioProfile.d.ts +143 -0
- package/dist/core/types/AudioProfile.d.ts.map +1 -0
- package/dist/core/types/BeatMap.d.ts +1825 -0
- package/dist/core/types/BeatMap.d.ts.map +1 -0
- package/dist/core/types/ButtonMapping.d.ts +345 -0
- package/dist/core/types/ButtonMapping.d.ts.map +1 -0
- package/dist/core/types/Character.d.ts +397 -0
- package/dist/core/types/Character.d.ts.map +1 -0
- package/dist/core/types/ChartedBeatMap.d.ts +169 -0
- package/dist/core/types/ChartedBeatMap.d.ts.map +1 -0
- package/dist/core/types/Combat.d.ts +268 -0
- package/dist/core/types/Combat.d.ts.map +1 -0
- package/dist/core/types/CombatAI.d.ts +143 -0
- package/dist/core/types/CombatAI.d.ts.map +1 -0
- package/dist/core/types/Enemy.d.ts +447 -0
- package/dist/core/types/Enemy.d.ts.map +1 -0
- package/dist/core/types/Environmental.d.ts +213 -0
- package/dist/core/types/Environmental.d.ts.map +1 -0
- package/dist/core/types/Equipment.d.ts +309 -0
- package/dist/core/types/Equipment.d.ts.map +1 -0
- package/dist/core/types/ISessionTracker.d.ts +48 -0
- package/dist/core/types/ISessionTracker.d.ts.map +1 -0
- package/dist/core/types/LevelExport.d.ts +366 -0
- package/dist/core/types/LevelExport.d.ts.map +1 -0
- package/dist/core/types/Playlist.d.ts +70 -0
- package/dist/core/types/Playlist.d.ts.map +1 -0
- package/dist/core/types/Prestige.d.ts +94 -0
- package/dist/core/types/Prestige.d.ts.map +1 -0
- package/dist/core/types/Progression.d.ts +214 -0
- package/dist/core/types/Progression.d.ts.map +1 -0
- package/dist/core/types/RhythmXP.d.ts +398 -0
- package/dist/core/types/RhythmXP.d.ts.map +1 -0
- package/dist/core/utils/AbilityConstants.d.ts +31 -0
- package/dist/core/utils/AbilityConstants.d.ts.map +1 -0
- package/dist/core/utils/EffectApplierUtils.d.ts +56 -0
- package/dist/core/utils/EffectApplierUtils.d.ts.map +1 -0
- package/dist/core/utils/ImageValidator.d.ts +66 -0
- package/dist/core/utils/ImageValidator.d.ts.map +1 -0
- package/dist/core/utils/PrerequisiteValidator.d.ts +88 -0
- package/dist/core/utils/PrerequisiteValidator.d.ts.map +1 -0
- package/dist/essentia-wasm.es-BUEnKUts.js +2990 -0
- package/dist/essentia.js-model.es-CGA0xotH.js +306 -0
- package/dist/index.d.ts +176 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/playlist-data-engine.js +124 -0
- package/dist/playlist-data-engine.mjs +49251 -0
- package/dist/utils/EnchantmentLibrary.d.ts +378 -0
- package/dist/utils/EnchantmentLibrary.d.ts.map +1 -0
- package/dist/utils/arweaveGatewayManager.d.ts +485 -0
- package/dist/utils/arweaveGatewayManager.d.ts.map +1 -0
- package/dist/utils/arweaveUtils.d.ts +118 -0
- package/dist/utils/arweaveUtils.d.ts.map +1 -0
- package/dist/utils/constants.d.ts +439 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/equipmentConstants.d.ts +60 -0
- package/dist/utils/equipmentConstants.d.ts.map +1 -0
- package/dist/utils/hash.d.ts +33 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +192 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/magicItemExamples.d.ts +46 -0
- package/dist/utils/magicItemExamples.d.ts.map +1 -0
- package/dist/utils/playlistUtils.d.ts +149 -0
- package/dist/utils/playlistUtils.d.ts.map +1 -0
- package/dist/utils/random.d.ts +34 -0
- package/dist/utils/random.d.ts.map +1 -0
- package/dist/utils/sensorDashboard.d.ts +60 -0
- package/dist/utils/sensorDashboard.d.ts.map +1 -0
- package/dist/utils/validators.d.ts +189 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/vite.svg +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,1082 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Difficulty Variant Generator for Procedural Rhythm Generation
|
|
3
|
+
*
|
|
4
|
+
* Generates difficulty variants (easy/medium/hard) from the composite stream
|
|
5
|
+
* by simplifying or enhancing density based on natural difficulty.
|
|
6
|
+
*
|
|
7
|
+
* Part of the Procedural Rhythm Generation pipeline - Phase 3.3
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* // Basic usage - generate all 3 difficulty variants
|
|
12
|
+
* const generator = new DifficultyVariantGenerator();
|
|
13
|
+
* const variants = generator.generateAll(compositeStream, phraseAnalysis, gridDecisions);
|
|
14
|
+
*
|
|
15
|
+
* // Access each difficulty variant
|
|
16
|
+
* const easyVariant = variants.easy;
|
|
17
|
+
* const mediumVariant = variants.medium;
|
|
18
|
+
* const hardVariant = variants.hard;
|
|
19
|
+
*
|
|
20
|
+
* // Check which variant is unedited (natural difficulty)
|
|
21
|
+
* console.log(`Easy is unedited: ${easyVariant.isUnedited}`);
|
|
22
|
+
* console.log(`Medium is unedited: ${mediumVariant.isUnedited}`);
|
|
23
|
+
* console.log(`Hard is unedited: ${hardVariant.isUnedited}`);
|
|
24
|
+
*
|
|
25
|
+
* // Check edit details
|
|
26
|
+
* console.log(`Medium edit type: ${mediumVariant.editType}`);
|
|
27
|
+
* console.log(`Medium edit amount: ${mediumVariant.editAmount.toFixed(2)}`);
|
|
28
|
+
*
|
|
29
|
+
* // Custom configuration for phrase boundary preservation
|
|
30
|
+
* const customGenerator = new DifficultyVariantGenerator({
|
|
31
|
+
* preservePhraseBoundaries: true,
|
|
32
|
+
* logConversions: true,
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
import type { CompositeBeat, CompositeStream } from './CompositeStreamGenerator.js';
|
|
37
|
+
import type { NaturalDifficulty } from './DensityAnalyzer.js';
|
|
38
|
+
import type { GridType, GridDecision } from './RhythmQuantizer.js';
|
|
39
|
+
import type { PhraseAnalysisResult } from './PhraseAnalyzer.js';
|
|
40
|
+
import type { UnifiedBeatMap } from '../../types/BeatMap.js';
|
|
41
|
+
import type { RhythmicBalanceConfig } from './RhythmicBalancer.js';
|
|
42
|
+
/**
|
|
43
|
+
* Extended grid type including simplified subdivisions for Easy difficulty
|
|
44
|
+
*
|
|
45
|
+
* - `straight_16th`: Standard 16th note grid (4 positions per beat: 0, 1, 2, 3)
|
|
46
|
+
* - `triplet_8th`: 8th note triplet grid (3 positions per beat: 0, 1, 2)
|
|
47
|
+
* - `straight_8th`: Standard 8th note grid (2 positions per beat: 0, 2)
|
|
48
|
+
* - `quarter_triplet`: Quarter note triplet (1 position per beat, triplet feel)
|
|
49
|
+
* - `straight_4th`: Quarter note grid (1 position per beat: 0) — Easy at BPM > 120
|
|
50
|
+
*/
|
|
51
|
+
export type ExtendedGridType = GridType | 'straight_8th' | 'quarter_triplet' | 'straight_4th';
|
|
52
|
+
/**
|
|
53
|
+
* All possible grid types for reference
|
|
54
|
+
*/
|
|
55
|
+
export declare const ALL_GRID_TYPES: ExtendedGridType[];
|
|
56
|
+
/**
|
|
57
|
+
* Subdivision limits for each difficulty level
|
|
58
|
+
*
|
|
59
|
+
* This constant defines which grid types are allowed for each difficulty
|
|
60
|
+
* at slow tempos (BPM < 70). For tempo-aware limits, use
|
|
61
|
+
* `getTempoAwareAllowedGridTypes()`.
|
|
62
|
+
*
|
|
63
|
+
* Easy and Medium have no tempo-dependent variation — their grid restrictions
|
|
64
|
+
* apply at all BPMs. Hard allows all types only at BPM < 70.
|
|
65
|
+
*
|
|
66
|
+
* | Difficulty | BPM < 70 | 70 ≤ BPM ≤ 120 | BPM > 120 |
|
|
67
|
+
* |------------|----------|----------------|-----------|
|
|
68
|
+
* | Easy | `straight_4th`, `quarter_triplet` | same | same |
|
|
69
|
+
* | Medium | `straight_8th`, `quarter_triplet` | same | same |
|
|
70
|
+
* | Hard | All types | `straight_8th`, `quarter_triplet` | same |
|
|
71
|
+
* | Natural | All types | All types | All types |
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* // Check if a grid type is allowed for a difficulty at a given BPM
|
|
76
|
+
* const allowed = getTempoAwareAllowedGridTypes('medium', 120);
|
|
77
|
+
* // ['straight_8th', 'quarter_triplet'] — 16th notes restricted at ≥70 BPM
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare const SUBDIVISION_LIMITS: Record<DifficultyLevel, SubdivisionLimitConfig>;
|
|
81
|
+
/** BPM threshold: medium restricts 16th/triplet_8th at or above this value */
|
|
82
|
+
export declare const MEDIUM_RESTRICT_BPM = 70;
|
|
83
|
+
/** BPM threshold: hard restricts 16th/triplet_8th at or above this value */
|
|
84
|
+
export declare const HARD_RESTRICT_BPM = 70;
|
|
85
|
+
/** BPM threshold: easy restricts to quarter notes above this value */
|
|
86
|
+
export declare const EASY_QUARTER_NOTE_BPM = 120;
|
|
87
|
+
/**
|
|
88
|
+
* Get the allowed grid types for a difficulty at a given BPM.
|
|
89
|
+
*
|
|
90
|
+
* This function returns the effective subdivision limits after applying
|
|
91
|
+
* tempo-based restrictions:
|
|
92
|
+
*
|
|
93
|
+
* - **Easy**: Always `straight_4th` (quarter notes) and `quarter_triplet`.
|
|
94
|
+
* 8th notes are too rapid for beginners at any tempo.
|
|
95
|
+
* - **Medium**: Always `straight_8th` and `quarter_triplet`.
|
|
96
|
+
* 16th notes and 8th note triplets are reserved for hard/natural.
|
|
97
|
+
* - **Hard at BPM ≥ 70**: Only `straight_8th` and `quarter_triplet`.
|
|
98
|
+
* 16th notes and 8th note triplets are reserved for natural/custom at higher tempos.
|
|
99
|
+
* - **Natural**: Always all types (no restrictions).
|
|
100
|
+
*
|
|
101
|
+
* @param difficulty - The difficulty level
|
|
102
|
+
* @param bpm - The tempo in beats per minute
|
|
103
|
+
* @returns Array of allowed grid types
|
|
104
|
+
*/
|
|
105
|
+
export declare function getTempoAwareAllowedGridTypes(difficulty: DifficultyLevel, bpm: number): ExtendedGridType[];
|
|
106
|
+
/**
|
|
107
|
+
* Derive allowed grid types from a DensityGenerationConfig and BPM.
|
|
108
|
+
*
|
|
109
|
+
* This is the core helper for density-based generation. It:
|
|
110
|
+
* 1. Looks up the base set of allowed grid types from the hierarchy based on `maxGridType`
|
|
111
|
+
* 2. Optionally applies BPM-based restrictions if `bpmBasedQuantization` is true
|
|
112
|
+
*
|
|
113
|
+
* @param config - The density generation configuration
|
|
114
|
+
* @param bpm - Current BPM for tempo-aware restrictions
|
|
115
|
+
* @returns Array of allowed ExtendedGridType values
|
|
116
|
+
*/
|
|
117
|
+
export declare function deriveAllowedGridTypes(config: DensityGenerationConfig, bpm: number): ExtendedGridType[];
|
|
118
|
+
/**
|
|
119
|
+
* Calculate the maximum achievable density (notes/second) for a given set of
|
|
120
|
+
* allowed grid types at a specific BPM.
|
|
121
|
+
*
|
|
122
|
+
* This is used to detect impossible configurations (e.g., requesting 4.0 nps
|
|
123
|
+
* with only 8th notes at 60 BPM, where max achievable is ~2.0 nps).
|
|
124
|
+
*
|
|
125
|
+
* @param allowedGridTypes - The grid types that are allowed
|
|
126
|
+
* @param bpm - Current BPM
|
|
127
|
+
* @returns Maximum achievable density in notes/second
|
|
128
|
+
*/
|
|
129
|
+
export declare function calculateMaxAchievableDensity(allowedGridTypes: ExtendedGridType[], bpm: number): number;
|
|
130
|
+
/**
|
|
131
|
+
* Difficulty level for rhythm variants
|
|
132
|
+
*
|
|
133
|
+
* - 'easy': Simplified rhythm with 8th notes max
|
|
134
|
+
* - 'medium': Moderate difficulty with density reduction
|
|
135
|
+
* - 'hard': Full density with all subdivisions
|
|
136
|
+
* - 'natural': Unedited composite stream (what was actually detected)
|
|
137
|
+
* - 'custom': Custom density-based variant — parameters provided at generation time
|
|
138
|
+
*/
|
|
139
|
+
export type DifficultyLevel = 'easy' | 'medium' | 'hard' | 'natural' | 'custom';
|
|
140
|
+
/**
|
|
141
|
+
* Preset difficulty levels (excludes 'custom')
|
|
142
|
+
*
|
|
143
|
+
* Used for GeneratedRhythm.difficultyVariants which only contains preset variants.
|
|
144
|
+
* Custom variants are generated standalone via generateAtDensity().
|
|
145
|
+
*/
|
|
146
|
+
export type PresetDifficultyLevel = 'easy' | 'medium' | 'hard' | 'natural';
|
|
147
|
+
/**
|
|
148
|
+
* Configuration for density-based level generation
|
|
149
|
+
*
|
|
150
|
+
* Provides independent control over target density (notes/second) and maximum
|
|
151
|
+
* quantization grid, enabling a continuous spectrum of difficulty alongside
|
|
152
|
+
* the existing easy/medium/hard/natural presets.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* // Dense chart with only 8th note quantization
|
|
157
|
+
* const config: DensityGenerationConfig = {
|
|
158
|
+
* targetDensity: 3.0,
|
|
159
|
+
* maxGridType: 'straight_8th'
|
|
160
|
+
* };
|
|
161
|
+
*
|
|
162
|
+
* // Sparse chart with 16th note quantization allowed
|
|
163
|
+
* const config: DensityGenerationConfig = {
|
|
164
|
+
* targetDensity: 0.5,
|
|
165
|
+
* maxGridType: 'straight_16th'
|
|
166
|
+
* };
|
|
167
|
+
*
|
|
168
|
+
* // With BPM-based quantization restrictions
|
|
169
|
+
* const config: DensityGenerationConfig = {
|
|
170
|
+
* targetDensity: 2.0,
|
|
171
|
+
* maxGridType: 'straight_16th',
|
|
172
|
+
* bpmBasedQuantization: true, // At 80 BPM, this restricts to 8ths
|
|
173
|
+
* restrictBpm: 70 // Custom threshold (default: 70)
|
|
174
|
+
* };
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
export interface DensityGenerationConfig {
|
|
178
|
+
/** Target density in notes per second */
|
|
179
|
+
targetDensity: number;
|
|
180
|
+
/** Maximum quantization grid allowed (independent of density) */
|
|
181
|
+
maxGridType: ExtendedGridType;
|
|
182
|
+
/**
|
|
183
|
+
* When true, apply BPM-based restrictions on top of maxGridType.
|
|
184
|
+
* Uses medium's thresholds (default: 70 BPM):
|
|
185
|
+
* - At BPM >= restrictBpm: straight_16th and triplet_8th restricted to straight_8th
|
|
186
|
+
* When false, only maxGridType is enforced regardless of BPM.
|
|
187
|
+
* Default: false
|
|
188
|
+
*/
|
|
189
|
+
bpmBasedQuantization?: boolean;
|
|
190
|
+
/** BPM threshold for restricting 16th/triplet_8th to 8ths. Default: 70 (MEDIUM_RESTRICT_BPM) */
|
|
191
|
+
restrictBpm?: number;
|
|
192
|
+
/** BPM threshold for restricting 8ths to quarter notes. Default: 120 (EASY_QUARTER_NOTE_BPM) */
|
|
193
|
+
quarterNoteBpm?: number;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Maximum subdivision type
|
|
197
|
+
*/
|
|
198
|
+
export type MaxSubdivision = 'eighth' | 'sixteenth';
|
|
199
|
+
/**
|
|
200
|
+
* Configuration for subdivision limits at a difficulty level
|
|
201
|
+
*/
|
|
202
|
+
export interface SubdivisionLimitConfig {
|
|
203
|
+
/** Maximum subdivision allowed at this difficulty */
|
|
204
|
+
maxSubdivision: MaxSubdivision;
|
|
205
|
+
/** Grid types allowed at this difficulty */
|
|
206
|
+
allowedGridTypes: ExtendedGridType[];
|
|
207
|
+
/** Human-readable description of the limits */
|
|
208
|
+
description: string;
|
|
209
|
+
/** Target density range for this difficulty (notes per second, BPM-adjusted) */
|
|
210
|
+
targetDensityRange: {
|
|
211
|
+
min: number;
|
|
212
|
+
max: number;
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Type of edit applied to create a difficulty variant
|
|
217
|
+
*/
|
|
218
|
+
export type EditType = 'none' | 'simplified' | 'interpolated' | 'pattern_inserted';
|
|
219
|
+
/**
|
|
220
|
+
* A beat in a difficulty variant that may have been converted to an extended grid type
|
|
221
|
+
*
|
|
222
|
+
* This extends CompositeBeat to support Easy difficulty grid types (straight_8th, quarter_triplet)
|
|
223
|
+
* that aren't in the original GridType.
|
|
224
|
+
*/
|
|
225
|
+
export interface VariantBeat extends Omit<CompositeBeat, 'gridType'> {
|
|
226
|
+
/** Grid type - extended to support simplified subdivisions */
|
|
227
|
+
gridType: ExtendedGridType;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* A difficulty variant of the composite stream
|
|
231
|
+
*/
|
|
232
|
+
export interface DifficultyVariant {
|
|
233
|
+
/** The difficulty level of this variant */
|
|
234
|
+
difficulty: DifficultyLevel;
|
|
235
|
+
/** The beats in this variant (may include converted grid types) */
|
|
236
|
+
beats: VariantBeat[];
|
|
237
|
+
/** Whether this variant is unedited from the composite */
|
|
238
|
+
isUnedited: boolean;
|
|
239
|
+
/** Type of edit applied (if any) */
|
|
240
|
+
editType: EditType;
|
|
241
|
+
/** How much was changed (0 = no changes, 1 = heavily modified) */
|
|
242
|
+
editAmount: number;
|
|
243
|
+
/** IDs of patterns inserted (if editType is 'pattern_inserted') */
|
|
244
|
+
patternsInserted?: string[];
|
|
245
|
+
/** Metadata about subdivision conversions */
|
|
246
|
+
conversionMetadata?: SubdivisionConversionMetadata;
|
|
247
|
+
/** Metadata about density enhancement */
|
|
248
|
+
enhancementMetadata?: EnhancementMetadata;
|
|
249
|
+
/** Task 4.2.3: Density validation result for downstream consumers */
|
|
250
|
+
densityValidation?: VariantDensityValidationResult;
|
|
251
|
+
/** Whether density was clamped due to grid constraints (density-based generation only) */
|
|
252
|
+
densityClamped?: boolean;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Metadata about subdivision conversions during simplification
|
|
256
|
+
*/
|
|
257
|
+
export interface SubdivisionConversionMetadata {
|
|
258
|
+
/** Number of beats converted from 16th to 8th */
|
|
259
|
+
sixteenthToEighth: number;
|
|
260
|
+
/** Number of beats converted from 8th triplet to quarter triplet */
|
|
261
|
+
tripletToQuarterTriplet: number;
|
|
262
|
+
/** Number of beats converted from 8th to quarter note (straight_8th → straight_4th) */
|
|
263
|
+
eighthToQuarter: number;
|
|
264
|
+
/** Number of beats that were removed entirely */
|
|
265
|
+
beatsRemoved: number;
|
|
266
|
+
/** Total beats before conversion */
|
|
267
|
+
totalBeatsBefore: number;
|
|
268
|
+
/** Total beats after conversion */
|
|
269
|
+
totalBeatsAfter: number;
|
|
270
|
+
/** Number of reduction passes used to reach target density */
|
|
271
|
+
reductionPasses?: number;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Metadata about density enhancement during variant generation
|
|
275
|
+
*/
|
|
276
|
+
export interface EnhancementMetadata {
|
|
277
|
+
/** Total beats before enhancement */
|
|
278
|
+
totalBeatsBefore: number;
|
|
279
|
+
/** Total beats after enhancement */
|
|
280
|
+
totalBeatsAfter: number;
|
|
281
|
+
/** Number of beats added via pattern insertion */
|
|
282
|
+
patternsInserted: number;
|
|
283
|
+
/** Number of beats added via grid interpolation */
|
|
284
|
+
interpolatedBeats: number;
|
|
285
|
+
/** IDs of patterns that were inserted */
|
|
286
|
+
insertedPatternIds: string[];
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Result of validating a variant against subdivision limits
|
|
290
|
+
*/
|
|
291
|
+
export interface SubdivisionValidationResult {
|
|
292
|
+
/** Whether the variant passes validation */
|
|
293
|
+
isValid: boolean;
|
|
294
|
+
/** Beats that violate the subdivision limits */
|
|
295
|
+
violations: SubdivisionViolation[];
|
|
296
|
+
/** Total number of beats checked */
|
|
297
|
+
totalBeats: number;
|
|
298
|
+
/** Number of violating beats */
|
|
299
|
+
violationCount: number;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* A single subdivision violation
|
|
303
|
+
*/
|
|
304
|
+
export interface SubdivisionViolation {
|
|
305
|
+
/** The beat that violates the limits */
|
|
306
|
+
beat: VariantBeat;
|
|
307
|
+
/** The grid type that is not allowed */
|
|
308
|
+
gridType: ExtendedGridType;
|
|
309
|
+
/** Suggested conversion target */
|
|
310
|
+
suggestedConversion: ExtendedGridType;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Result of locking grid types per beat index
|
|
314
|
+
*
|
|
315
|
+
* This is the foundational structure for the density balancing refactor.
|
|
316
|
+
* Before any density work, the grid type for each beat index is locked
|
|
317
|
+
* so all subsequent operations know which grid to use.
|
|
318
|
+
*/
|
|
319
|
+
export interface GridLockResult {
|
|
320
|
+
/** Beats after resolving mixed grids (single grid per beat index) */
|
|
321
|
+
beats: CompositeBeat[];
|
|
322
|
+
/** Map from beat index to locked grid type */
|
|
323
|
+
gridLock: Map<number, ExtendedGridType>;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Strategy for where to target within the density range
|
|
327
|
+
*
|
|
328
|
+
* - 'midpoint': Aim for the middle of the range (default)
|
|
329
|
+
* - 'lower': Aim closer to the minimum (more conservative)
|
|
330
|
+
* - 'upper': Aim closer to the maximum (more aggressive)
|
|
331
|
+
*/
|
|
332
|
+
export type DensityTargetStrategy = 'midpoint' | 'lower' | 'upper';
|
|
333
|
+
/**
|
|
334
|
+
* Result of calculating beat count targets for a difficulty
|
|
335
|
+
*/
|
|
336
|
+
export interface BeatCountTarget {
|
|
337
|
+
/** Target beat count to aim for (based on strategy) */
|
|
338
|
+
targetCount: number;
|
|
339
|
+
/** Maximum beat count allowed (upper bound of density range) */
|
|
340
|
+
maxCount: number;
|
|
341
|
+
/** Minimum beat count allowed (lower bound of density range) */
|
|
342
|
+
minCount: number;
|
|
343
|
+
/** The target density value (notes per second) used for calculation */
|
|
344
|
+
targetDensity: number;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Result of calculating how many beats to add for enhancement
|
|
348
|
+
*/
|
|
349
|
+
export interface BeatsToAddResult {
|
|
350
|
+
/** Number of beats to add to reach target */
|
|
351
|
+
beatsToAdd: number;
|
|
352
|
+
/** Target beat count to aim for */
|
|
353
|
+
targetCount: number;
|
|
354
|
+
/** Maximum beats per index based on allowed grid types */
|
|
355
|
+
maxBeatsPerIndex: number;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Result of validating variant density against target range
|
|
359
|
+
*
|
|
360
|
+
* Task 4.1: Created for convergence validation
|
|
361
|
+
*/
|
|
362
|
+
export interface VariantDensityValidationResult {
|
|
363
|
+
/** Whether the variant's density is within the target range */
|
|
364
|
+
inRange: boolean;
|
|
365
|
+
/** The calculated density (notes per second) */
|
|
366
|
+
density: number;
|
|
367
|
+
/** The target density range for this difficulty */
|
|
368
|
+
targetRange: {
|
|
369
|
+
min: number;
|
|
370
|
+
max: number;
|
|
371
|
+
};
|
|
372
|
+
/** The difficulty level that was validated */
|
|
373
|
+
difficulty: DifficultyLevel;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Configuration for difficulty variant generation
|
|
377
|
+
*/
|
|
378
|
+
export interface DifficultyVariantConfig {
|
|
379
|
+
/** Whether to log subdivision conversions for debugging. Default: false */
|
|
380
|
+
logConversions: boolean;
|
|
381
|
+
/** Whether to preserve phrase boundaries when simplifying. Default: true */
|
|
382
|
+
preservePhraseBoundaries: boolean;
|
|
383
|
+
/** Minimum intensity threshold for keeping beats during simplification. Default: 0.3 */
|
|
384
|
+
simplificationIntensityThreshold: number;
|
|
385
|
+
/** Intensity threshold for keeping beats during HEAVY simplification. Default: 0.5 */
|
|
386
|
+
heavySimplificationIntensityThreshold: number;
|
|
387
|
+
/** Intensity threshold for removing offbeat 16ths during moderate simplification (hard→medium). Default: 0.4 */
|
|
388
|
+
moderateSimplificationIntensityThreshold: number;
|
|
389
|
+
/** Minimum intensity threshold for removing beats during density reduction. Default: 0.25 */
|
|
390
|
+
densityReductionMinIntensity: number;
|
|
391
|
+
/** Intensity for interpolated beats (0.0 - 1.0). Default: 0.5 */
|
|
392
|
+
interpolatedBeatIntensity: number;
|
|
393
|
+
/** Whether to prefer pattern insertion over simple interpolation. Default: true */
|
|
394
|
+
preferPatternInsertion: boolean;
|
|
395
|
+
/** Maximum phrase size to consider for pattern insertion (in beats). Default: 4 */
|
|
396
|
+
maxPatternInsertionSize: number;
|
|
397
|
+
/** Strategy for where to target within the density range. Default: 'midpoint' */
|
|
398
|
+
densityTargetStrategy: DensityTargetStrategy;
|
|
399
|
+
/** Maximum number of passes for density reduction with progressively relaxed protections. Default: 3 */
|
|
400
|
+
maxReductionPasses: number;
|
|
401
|
+
/** Seed for deterministic probability rolls in beat enhancement. If not provided, falls back to a hash of beat data. */
|
|
402
|
+
seed?: string;
|
|
403
|
+
/**
|
|
404
|
+
* Rhythmic balance configuration for density reduction awareness.
|
|
405
|
+
* When provided, the density reduction will use the strongBeatEmphasis setting
|
|
406
|
+
* to determine which beats are structurally important.
|
|
407
|
+
*
|
|
408
|
+
* This config is passed from RhythmGenerator to ensure density reduction
|
|
409
|
+
* respects the same rhythmic taste rules as the RhythmicBalancer.
|
|
410
|
+
*/
|
|
411
|
+
rhythmicBalanceConfig?: RhythmicBalanceConfig;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Check if a grid type is allowed for a given difficulty at a given BPM.
|
|
415
|
+
*
|
|
416
|
+
* @param gridType - The grid type to check
|
|
417
|
+
* @param difficulty - The difficulty level
|
|
418
|
+
* @param bpm - Optional BPM. When omitted, uses static SUBDIVISION_LIMITS (no tempo restrictions).
|
|
419
|
+
* @returns True if the grid type is allowed
|
|
420
|
+
*/
|
|
421
|
+
export declare function isGridTypeAllowed(gridType: GridType, difficulty: DifficultyLevel, bpm?: number): boolean;
|
|
422
|
+
/**
|
|
423
|
+
* Get the allowed grid types for a difficulty level at a given BPM.
|
|
424
|
+
*
|
|
425
|
+
* @param difficulty - The difficulty level
|
|
426
|
+
* @param bpm - Optional BPM. When omitted, uses static SUBDIVISION_LIMITS (no tempo restrictions).
|
|
427
|
+
* @returns Array of allowed grid types
|
|
428
|
+
*/
|
|
429
|
+
export declare function getAllowedGridTypes(difficulty: DifficultyLevel, bpm?: number): ExtendedGridType[];
|
|
430
|
+
/**
|
|
431
|
+
* Convert a grid type to the closest allowed type for a difficulty at a given BPM.
|
|
432
|
+
*
|
|
433
|
+
* Conversion rules (when grid type is not already allowed):
|
|
434
|
+
*
|
|
435
|
+
* - `straight_16th` → `straight_8th` (or `straight_4th` for Easy at BPM > 120)
|
|
436
|
+
* - `triplet_8th` → `quarter_triplet`
|
|
437
|
+
* - `straight_8th` → `straight_4th` (Easy at BPM > 120 only)
|
|
438
|
+
*
|
|
439
|
+
* @param gridType - The original grid type (can be extended type)
|
|
440
|
+
* @param difficulty - The target difficulty
|
|
441
|
+
* @param bpm - Optional BPM. When omitted, uses static SUBDIVISION_LIMITS.
|
|
442
|
+
* @param allowedGridTypesOverride - Optional override for allowed grid types (for density-based generation)
|
|
443
|
+
* @returns The converted grid type (or original if already allowed)
|
|
444
|
+
*/
|
|
445
|
+
export declare function convertToAllowedGridType(gridType: ExtendedGridType, difficulty: DifficultyLevel, bpm?: number, allowedGridTypesOverride?: ExtendedGridType[]): ExtendedGridType;
|
|
446
|
+
/**
|
|
447
|
+
* Map natural difficulty to difficulty level
|
|
448
|
+
*
|
|
449
|
+
* @param naturalDifficulty - The natural difficulty from density analysis
|
|
450
|
+
* @returns The corresponding difficulty level
|
|
451
|
+
*/
|
|
452
|
+
export declare function naturalDifficultyToLevel(naturalDifficulty: NaturalDifficulty): DifficultyLevel;
|
|
453
|
+
/**
|
|
454
|
+
* Validate a list of beats against subdivision limits for a difficulty at a given BPM.
|
|
455
|
+
*
|
|
456
|
+
* @param beats - The beats to validate (may include extended grid types)
|
|
457
|
+
* @param difficulty - The difficulty level to validate against
|
|
458
|
+
* @param bpm - Optional BPM. When omitted, uses static SUBDIVISION_LIMITS.
|
|
459
|
+
* @returns Validation result with any violations
|
|
460
|
+
*/
|
|
461
|
+
export declare function validateSubdivisionLimits(beats: VariantBeat[], difficulty: DifficultyLevel, bpm?: number): SubdivisionValidationResult;
|
|
462
|
+
/**
|
|
463
|
+
* Generates difficulty variants from a composite stream
|
|
464
|
+
*
|
|
465
|
+
* ## Algorithm Overview
|
|
466
|
+
*
|
|
467
|
+
* 1. **Determine Variants to Generate**: Based on the composite's natural difficulty,
|
|
468
|
+
* determine which variants need editing vs. remain unedited.
|
|
469
|
+
*
|
|
470
|
+
* 2. **Simplification** (for dense composites needing easier difficulties):
|
|
471
|
+
* - Enforce subdivision limits (primary constraint for Easy)
|
|
472
|
+
* - Prioritize keeping transients on strong beats (1, 3)
|
|
473
|
+
* - Remove offbeat subdivisions first
|
|
474
|
+
* - Snap removed subdivisions to nearest allowed grid
|
|
475
|
+
*
|
|
476
|
+
* 3. **Density Enhancement** (for sparse composites needing harder difficulties):
|
|
477
|
+
* - First priority: Insert detected patterns from phrase library
|
|
478
|
+
* - Fallback: Simple grid interpolation
|
|
479
|
+
*
|
|
480
|
+
* ## Usage
|
|
481
|
+
*
|
|
482
|
+
* ```typescript
|
|
483
|
+
* const generator = new DifficultyVariantGenerator();
|
|
484
|
+
* const variants = generator.generate(composite, phraseAnalysis);
|
|
485
|
+
*
|
|
486
|
+
* // Access each variant
|
|
487
|
+
* const easyVariant = variants.easy;
|
|
488
|
+
* const mediumVariant = variants.medium;
|
|
489
|
+
* const hardVariant = variants.hard;
|
|
490
|
+
*
|
|
491
|
+
* // Check if a variant was edited
|
|
492
|
+
* console.log('Easy was simplified:', easyVariant.editType === 'simplified');
|
|
493
|
+
* console.log('Medium is unedited:', mediumVariant.isUnedited);
|
|
494
|
+
* ```
|
|
495
|
+
*/
|
|
496
|
+
export declare class DifficultyVariantGenerator {
|
|
497
|
+
private config;
|
|
498
|
+
/**
|
|
499
|
+
* Current unifiedBeatMap for time-signature-aware strong beat detection.
|
|
500
|
+
* Set during generate() and used by isStrongBeat().
|
|
501
|
+
*/
|
|
502
|
+
private currentUnifiedBeatMap;
|
|
503
|
+
constructor(config?: Partial<DifficultyVariantConfig>);
|
|
504
|
+
/**
|
|
505
|
+
* Lock grid type per beat index before density work
|
|
506
|
+
*
|
|
507
|
+
* This is the foundational method for the density balancing refactor.
|
|
508
|
+
* Before any density work (simplification or enhancement), lock the grid
|
|
509
|
+
* type for each beat index so all subsequent operations know which grid to use.
|
|
510
|
+
*
|
|
511
|
+
* The method:
|
|
512
|
+
* 1. Runs `enforceSingleGridPerBeat()` to resolve any mixed grids
|
|
513
|
+
* 2. Builds a map of beatIndex → dominantGridType from resolved beats
|
|
514
|
+
* 3. For empty beat indices, resolves grid type from:
|
|
515
|
+
* - gridDecisions map (if available)
|
|
516
|
+
* - Nearest-neighbor fallback (offsets 1, -1, 2, -2, 3, -3)
|
|
517
|
+
* - Default to allowed grid type for target difficulty
|
|
518
|
+
*
|
|
519
|
+
* @param beats - Input beats (may have mixed grids)
|
|
520
|
+
* @param targetDifficulty - Target difficulty level for default grid type
|
|
521
|
+
* @param bpm - BPM for tempo-aware grid type defaults
|
|
522
|
+
* @param gridDecisions - Optional grid decisions from quantized streams
|
|
523
|
+
* @param allowedGridTypes - Optional override for allowed grid types (bypasses getTempoAwareAllowedGridTypes)
|
|
524
|
+
* @returns Grid lock result with cleaned beats and locked grid map
|
|
525
|
+
*/
|
|
526
|
+
lockGridPerBeatIndex(beats: CompositeBeat[], targetDifficulty: DifficultyLevel, bpm: number, gridDecisions?: Map<number, GridDecision>, allowedGridTypes?: ExtendedGridType[]): GridLockResult;
|
|
527
|
+
/**
|
|
528
|
+
* Generate all three difficulty variants from a composite stream
|
|
529
|
+
*
|
|
530
|
+
* After generation, each variant is validated against its subdivision limits
|
|
531
|
+
* to ensure compliance.
|
|
532
|
+
*
|
|
533
|
+
* @param composite - The composite stream from CompositeStreamGenerator
|
|
534
|
+
* @param phraseAnalysis - Optional phrase analysis for pattern library access
|
|
535
|
+
* @param gridDecisions - Optional grid decisions from quantized streams
|
|
536
|
+
* @returns Object containing easy, medium, and hard variants
|
|
537
|
+
*/
|
|
538
|
+
generate(composite: CompositeStream, unifiedBeatMap: UnifiedBeatMap, phraseAnalysis?: PhraseAnalysisResult, gridDecisions?: Map<number, GridDecision>): {
|
|
539
|
+
easy: DifficultyVariant;
|
|
540
|
+
medium: DifficultyVariant;
|
|
541
|
+
hard: DifficultyVariant;
|
|
542
|
+
natural: DifficultyVariant;
|
|
543
|
+
};
|
|
544
|
+
/**
|
|
545
|
+
* Generate a custom difficulty variant at a specific target density.
|
|
546
|
+
*
|
|
547
|
+
* This method provides granular control over difficulty generation by decoupling
|
|
548
|
+
* target density (notes/second) from maximum quantization grid. Unlike the preset
|
|
549
|
+
* difficulties (easy/medium/hard/natural), this allows any combination such as:
|
|
550
|
+
* - Dense chart (3.0 nps) with only 8th note quantization
|
|
551
|
+
* - Sparse chart (0.5 nps) with 16th note quantization allowed
|
|
552
|
+
*
|
|
553
|
+
* The method handles three scenarios:
|
|
554
|
+
* 1. **Current density > target**: Simplify beats (remove/convert notes)
|
|
555
|
+
* 2. **Current density < target**: Enhance beats (add notes via interpolation/patterns)
|
|
556
|
+
* 3. **Current density ≈ target**: Apply grid restrictions only if needed
|
|
557
|
+
*
|
|
558
|
+
* Best-effort: If the target density is impossible given the grid constraints
|
|
559
|
+
* (e.g., 4.0 nps with only 8th notes at 60 BPM), the density is clamped to the
|
|
560
|
+
* maximum achievable and a warning is logged.
|
|
561
|
+
*
|
|
562
|
+
* @param composite - The composite stream from CompositeStreamGenerator
|
|
563
|
+
* @param config - Density generation configuration (target density + max grid type)
|
|
564
|
+
* @param unifiedBeatMap - The unified beat map for timing information
|
|
565
|
+
* @param phraseAnalysis - Optional phrase analysis for pattern library access during enhancement
|
|
566
|
+
* @param gridDecisions - Optional grid decisions from quantized streams
|
|
567
|
+
* @returns A DifficultyVariant with `difficulty: 'custom'`
|
|
568
|
+
*
|
|
569
|
+
* @example
|
|
570
|
+
* ```typescript
|
|
571
|
+
* const generator = new DifficultyVariantGenerator();
|
|
572
|
+
*
|
|
573
|
+
* // Dense chart with 8th note max grid
|
|
574
|
+
* const denseVariant = generator.generateAtDensity(
|
|
575
|
+
* composite,
|
|
576
|
+
* { targetDensity: 3.0, maxGridType: 'straight_8th' },
|
|
577
|
+
* unifiedBeatMap
|
|
578
|
+
* );
|
|
579
|
+
*
|
|
580
|
+
* // Sparse chart with 16th note grid allowed, BPM-based restrictions
|
|
581
|
+
* const sparseVariant = generator.generateAtDensity(
|
|
582
|
+
* composite,
|
|
583
|
+
* { targetDensity: 0.5, maxGridType: 'straight_16th', bpmBasedQuantization: true },
|
|
584
|
+
* unifiedBeatMap
|
|
585
|
+
* );
|
|
586
|
+
* ```
|
|
587
|
+
*/
|
|
588
|
+
generateAtDensity(composite: CompositeStream, config: DensityGenerationConfig, unifiedBeatMap: UnifiedBeatMap, phraseAnalysis?: PhraseAnalysisResult, gridDecisions?: Map<number, GridDecision>): DifficultyVariant;
|
|
589
|
+
/**
|
|
590
|
+
* Generate multiple custom difficulty variants at specific densities in one call
|
|
591
|
+
*
|
|
592
|
+
* This is a convenience method for generating multiple density-based variants
|
|
593
|
+
* efficiently. Each variant is generated independently with its own deep copy
|
|
594
|
+
* of the composite beats, ensuring no shared state or mutations between variants.
|
|
595
|
+
*
|
|
596
|
+
* @param composite - The composite stream from CompositeStreamGenerator
|
|
597
|
+
* @param configs - Array of labeled density configurations
|
|
598
|
+
* @param unifiedBeatMap - The unified beat map for timing information
|
|
599
|
+
* @param phraseAnalysis - Optional phrase analysis for pattern library access during enhancement
|
|
600
|
+
* @param gridDecisions - Optional grid decisions from quantized streams
|
|
601
|
+
* @returns A Map of labels to DifficultyVariants
|
|
602
|
+
*
|
|
603
|
+
* @example
|
|
604
|
+
* ```typescript
|
|
605
|
+
* const generator = new DifficultyVariantGenerator();
|
|
606
|
+
*
|
|
607
|
+
* const variants = generator.generateAtDensities(
|
|
608
|
+
* composite,
|
|
609
|
+
* [
|
|
610
|
+
* { label: 'beginner', config: { targetDensity: 0.5, maxGridType: 'straight_4th' } },
|
|
611
|
+
* { label: 'intermediate', config: { targetDensity: 1.5, maxGridType: 'straight_8th' } },
|
|
612
|
+
* { label: 'expert', config: { targetDensity: 3.0, maxGridType: 'straight_16th' } },
|
|
613
|
+
* ],
|
|
614
|
+
* unifiedBeatMap
|
|
615
|
+
* );
|
|
616
|
+
*
|
|
617
|
+
* const beginnerVariant = variants.get('beginner');
|
|
618
|
+
* const expertVariant = variants.get('expert');
|
|
619
|
+
* ```
|
|
620
|
+
*/
|
|
621
|
+
generateAtDensities(composite: CompositeStream, configs: {
|
|
622
|
+
label: string;
|
|
623
|
+
config: DensityGenerationConfig;
|
|
624
|
+
}[], unifiedBeatMap: UnifiedBeatMap, phraseAnalysis?: PhraseAnalysisResult, gridDecisions?: Map<number, GridDecision>): Map<string, DifficultyVariant>;
|
|
625
|
+
/**
|
|
626
|
+
* Validate a generated variant against its subdivision limits
|
|
627
|
+
*
|
|
628
|
+
* This ensures that all generated variants comply with their respective
|
|
629
|
+
* difficulty's subdivision constraints. Logs warnings if violations are found.
|
|
630
|
+
*
|
|
631
|
+
* @param variant - The variant to validate
|
|
632
|
+
* @param difficulty - The difficulty level
|
|
633
|
+
*/
|
|
634
|
+
private validateVariant;
|
|
635
|
+
/**
|
|
636
|
+
* Validate that a variant's beats have no mixed grid types per beat index
|
|
637
|
+
*
|
|
638
|
+
* Task 1.4.3: Validation-only check for grid lock compliance.
|
|
639
|
+
* When grid lock is used in generateVariant(), this method confirms
|
|
640
|
+
* that no grid violations exist (assert, don't fix).
|
|
641
|
+
*
|
|
642
|
+
* @param beats - The beats to validate
|
|
643
|
+
* @param difficulty - The difficulty level for logging
|
|
644
|
+
*/
|
|
645
|
+
private validateGridLockResult;
|
|
646
|
+
/**
|
|
647
|
+
* Validate that a variant's density falls within the target range for its difficulty
|
|
648
|
+
*
|
|
649
|
+
* Task 4.1: Convergence validation - check final density against target range
|
|
650
|
+
*
|
|
651
|
+
* This method calculates the final density of a variant and compares it against
|
|
652
|
+
* the target density range defined in SUBDIVISION_LIMITS. It logs warnings for
|
|
653
|
+
* out-of-range variants but does NOT throw, since edge cases (very short songs,
|
|
654
|
+
* extreme tempos) may not be able to hit exact targets.
|
|
655
|
+
*
|
|
656
|
+
* @param variant - The variant to validate
|
|
657
|
+
* @param bpm - The tempo in beats per minute
|
|
658
|
+
* @returns DensityValidationResult with inRange status, density, and target range
|
|
659
|
+
*/
|
|
660
|
+
private validateDensityInRange;
|
|
661
|
+
/**
|
|
662
|
+
* Generate a single difficulty variant
|
|
663
|
+
*
|
|
664
|
+
* @param targetDifficulty - The target difficulty level
|
|
665
|
+
* @param composite - The composite stream
|
|
666
|
+
* @param naturalDifficulty - The natural difficulty of the composite
|
|
667
|
+
* @param phraseAnalysis - Optional phrase analysis for pattern library access
|
|
668
|
+
* @param gridDecisions - Optional grid decisions from quantized streams
|
|
669
|
+
* @returns The difficulty variant
|
|
670
|
+
*/
|
|
671
|
+
private generateVariant;
|
|
672
|
+
/**
|
|
673
|
+
* Simplify beats to meet subdivision limits for a target difficulty
|
|
674
|
+
*
|
|
675
|
+
* This method converts beats that violate subdivision limits to allowed grid types:
|
|
676
|
+
* - `straight_16th` → `straight_8th` (snap 16th notes to nearest 8th note)
|
|
677
|
+
* - `triplet_8th` → `quarter_triplet` (snap 8th triplets to quarter note triplet)
|
|
678
|
+
*
|
|
679
|
+
* For heavy simplification (hard -> easy), additional beat prioritization is applied:
|
|
680
|
+
* - Prioritize keeping transients on strong beats (beats 1 and 3 of each measure)
|
|
681
|
+
* - Remove offbeat subdivisions first (gridPosition 1 and 3)
|
|
682
|
+
* - Keep only core beats (high intensity or on strong beats)
|
|
683
|
+
*
|
|
684
|
+
* After conversion, duplicate beats at the same grid position are deduplicated
|
|
685
|
+
* (keeping the highest intensity).
|
|
686
|
+
*
|
|
687
|
+
* @param beats - The beats to simplify
|
|
688
|
+
* @param targetDifficulty - The target difficulty level
|
|
689
|
+
* @param quarterNoteInterval - Duration of a quarter note in seconds for timestamp calculation
|
|
690
|
+
* @param isHeavySimplification - Whether this is heavy simplification (hard -> easy)
|
|
691
|
+
* @param phraseAnalysis - Optional phrase analysis for preserving phrase boundaries
|
|
692
|
+
* @returns Simplified beats with conversion metadata
|
|
693
|
+
*/
|
|
694
|
+
private simplifyBeats;
|
|
695
|
+
/**
|
|
696
|
+
* Filter beats for heavy simplification (hard -> easy)
|
|
697
|
+
*
|
|
698
|
+
* Implements beat prioritization:
|
|
699
|
+
* 1. Strong beats (beats 1 and 3 of each measure) are always kept
|
|
700
|
+
* 2. Downbeats (gridPosition 0) on weak beats are kept if high intensity
|
|
701
|
+
* 3. Offbeats (gridPosition 1, 2, 3) are only kept if very high intensity
|
|
702
|
+
* 4. Beats part of significant phrases get additional consideration
|
|
703
|
+
*
|
|
704
|
+
* In 4/4 time with 0-indexed beats:
|
|
705
|
+
* - Beat 0, 4, 8... = Beat 1 of measure (strong)
|
|
706
|
+
* - Beat 2, 6, 10... = Beat 3 of measure (strong)
|
|
707
|
+
* - Beat 1, 5, 9... = Beat 2 of measure (weak)
|
|
708
|
+
* - Beat 3, 7, 11... = Beat 4 of measure (weak)
|
|
709
|
+
*
|
|
710
|
+
* @param beats - The beats to filter
|
|
711
|
+
* @param metadata - Metadata object to track removals
|
|
712
|
+
* @param phraseMembership - Map of beat indices to phrase membership
|
|
713
|
+
* @returns Filtered beats
|
|
714
|
+
*/
|
|
715
|
+
private filterBeatsForHeavySimplification;
|
|
716
|
+
/**
|
|
717
|
+
* Determine if a beat index is on a strong beat, based on time signature and emphasis mode
|
|
718
|
+
*
|
|
719
|
+
* This method uses the rhythmicBalanceConfig.strongBeatEmphasis to determine
|
|
720
|
+
* which beats are "strong" for density reduction priority. It is
|
|
721
|
+
* time-signature-aware: derives beatsPerMeasure from the active downbeat segment.
|
|
722
|
+
*
|
|
723
|
+
* @param beatIndex - The beat index (0-indexed)
|
|
724
|
+
* @returns True if this is a strong beat
|
|
725
|
+
*/
|
|
726
|
+
private isStrongBeat;
|
|
727
|
+
/**
|
|
728
|
+
* Calculate the density (notes per second) of a beat collection
|
|
729
|
+
*
|
|
730
|
+
* Uses `maxBeatIndex + 1` as the denominator to match DensityAnalyzer's method,
|
|
731
|
+
* Uses the actual track duration in seconds to compute true notes-per-second.
|
|
732
|
+
*
|
|
733
|
+
* @param beats - The beats to analyze
|
|
734
|
+
* @param durationSeconds - Actual track duration in seconds (from unifiedBeatMap.duration)
|
|
735
|
+
* @returns Notes per second (0 if no beats or no duration)
|
|
736
|
+
*/
|
|
737
|
+
private calculateDensity;
|
|
738
|
+
/**
|
|
739
|
+
* Calculate target beat count for a difficulty level based on density ranges
|
|
740
|
+
*
|
|
741
|
+
* This is the foundational helper for global target-based density control.
|
|
742
|
+
* It calculates exactly how many beats should be in the output based on:
|
|
743
|
+
* - The target density range for the difficulty
|
|
744
|
+
* - The total quarter-note span of the song
|
|
745
|
+
* - The BPM
|
|
746
|
+
* - The configured strategy (midpoint/lower/upper)
|
|
747
|
+
*
|
|
748
|
+
* Target densities by difficulty:
|
|
749
|
+
* - Easy: 0.9 nps (biased high within [0, 1.0] to preserve musical interest)
|
|
750
|
+
* - Medium: 1.25 nps (true center of [1.0, 1.5])
|
|
751
|
+
* - Hard: 1.75 nps (target above the 1.5 floor)
|
|
752
|
+
* - Natural: Uses the current density (no target)
|
|
753
|
+
*
|
|
754
|
+
* The formula derives from: density = (beatCount / totalQuarterNotes) * (bpm / 60)
|
|
755
|
+
* Solving for beatCount: beatCount = density * totalQuarterNotes * 60 / bpm
|
|
756
|
+
*
|
|
757
|
+
* @param currentBeatCount - The current number of beats
|
|
758
|
+
* @param totalQuarterNotes - The total quarter-note span (maxBeatIndex + 1)
|
|
759
|
+
* @param bpm - Tempo in beats per minute
|
|
760
|
+
* @param targetDifficulty - The target difficulty level
|
|
761
|
+
* @returns Beat count target with min/max bounds
|
|
762
|
+
*/
|
|
763
|
+
private calculateBeatCountTarget;
|
|
764
|
+
/**
|
|
765
|
+
* Calculate how many beats to add for density enhancement
|
|
766
|
+
*
|
|
767
|
+
* This method calculates the exact number of beats to add to reach the target
|
|
768
|
+
* density for a given difficulty level. It uses the same target density midpoints
|
|
769
|
+
* as calculateBeatCountTarget() for consistency.
|
|
770
|
+
*
|
|
771
|
+
* Task 3.1: Global target-based density enhancement helper
|
|
772
|
+
*
|
|
773
|
+
* @param currentBeatCount - Current number of beats
|
|
774
|
+
* @param durationSeconds - Actual track duration in seconds
|
|
775
|
+
* @param bpm - Beats per minute
|
|
776
|
+
* @param targetDifficulty - Target difficulty level
|
|
777
|
+
* @returns BeatsToAddResult with beatsToAdd, targetCount, and maxBeatsPerIndex
|
|
778
|
+
*/
|
|
779
|
+
private calculateBeatsToAdd;
|
|
780
|
+
/**
|
|
781
|
+
* Get max beats per index from a set of allowed grid types
|
|
782
|
+
*
|
|
783
|
+
* Returns the maximum number of beats that can fit at a single beat index
|
|
784
|
+
* based on the most complex grid type in the allowed set.
|
|
785
|
+
*
|
|
786
|
+
* @param allowedTypes - Array of allowed grid types
|
|
787
|
+
* @returns Maximum beats per index
|
|
788
|
+
*/
|
|
789
|
+
private getMaxBeatsPerIndexFromGridTypes;
|
|
790
|
+
/**
|
|
791
|
+
* Get max beats for a single grid type
|
|
792
|
+
*
|
|
793
|
+
* @param gridType - The grid type
|
|
794
|
+
* @returns Maximum beats per index for this grid type
|
|
795
|
+
*/
|
|
796
|
+
private getMaxBeatsForGridType;
|
|
797
|
+
/**
|
|
798
|
+
* Distribute beats across indices to reach a global target count
|
|
799
|
+
*
|
|
800
|
+
* Uses deterministic global target-based distribution.
|
|
801
|
+
*
|
|
802
|
+
* Strategy:
|
|
803
|
+
* - Phase A: Fill empty indices first (prioritize gaps in rhythm)
|
|
804
|
+
* - Phase B: Fill partially occupied indices (add to existing beats)
|
|
805
|
+
*
|
|
806
|
+
* The distribution is deterministic and greedy. Empty indices are always prioritized.
|
|
807
|
+
* Seed is only used for tiebreaking when multiple indices are equally good candidates.
|
|
808
|
+
*
|
|
809
|
+
* @param beatsToAdd - Global count of beats to add
|
|
810
|
+
* @param beatsByIndex - Current beat occupancy per index
|
|
811
|
+
* @param gridLock - Per-index grid types (from lockGridPerBeatIndex)
|
|
812
|
+
* @param maxBeatIndex - The highest beat index in the song
|
|
813
|
+
* @param seed - Seed for deterministic tiebreaking
|
|
814
|
+
* @returns Map of beatIndex → targetCount (how many beats should be at each index after distribution)
|
|
815
|
+
*/
|
|
816
|
+
private distributeBeatsAcrossIndices;
|
|
817
|
+
/**
|
|
818
|
+
* Group consecutive empty indices into gaps
|
|
819
|
+
*
|
|
820
|
+
* @param emptyIndices - Array of empty beat indices (sorted)
|
|
821
|
+
* @returns Array of gap arrays, each containing consecutive empty indices
|
|
822
|
+
*/
|
|
823
|
+
private groupConsecutiveEmptyIndices;
|
|
824
|
+
/**
|
|
825
|
+
* Reduce density by removing low-priority beats until target is reached
|
|
826
|
+
*
|
|
827
|
+
* This method implements a priority-based beat removal strategy:
|
|
828
|
+
* 1. Calculate current density
|
|
829
|
+
* 2. If above target, sort beats by removal priority (lowest priority first)
|
|
830
|
+
* 3. Remove beats one at a time until density is within target range
|
|
831
|
+
*
|
|
832
|
+
* Removal priority (lowest to highest - low priority = removed first):
|
|
833
|
+
* - Offbeats (gridPosition 1, 3) with low intensity - removed first
|
|
834
|
+
* - Mid-beat positions (gridPosition 2) with low intensity
|
|
835
|
+
* - Downbeats (gridPosition 0) on weak beats (2, 4 of measure)
|
|
836
|
+
* - Strong beats (beats 1, 3 of measure) - kept as long as possible
|
|
837
|
+
*
|
|
838
|
+
* Protected beats (not removed):
|
|
839
|
+
* - Pass 1: Beats with priority >= (1 - densityReductionMinIntensity) or intensity >= moderateSimplificationIntensityThreshold
|
|
840
|
+
* - Pass 2: Relaxed thresholds (priority threshold lowered by 0.15, intensity threshold lowered by 0.1)
|
|
841
|
+
* - Pass 3+: Only strong beats (beatIndex % 4 === 0 or 2) are protected
|
|
842
|
+
*
|
|
843
|
+
* @param beats - The beats to potentially reduce
|
|
844
|
+
* @param targetDifficulty - The target difficulty level
|
|
845
|
+
* @param metadata - Metadata to track removals
|
|
846
|
+
* @param phraseMembership - Map of beat indices to phrase membership
|
|
847
|
+
* @returns Beats with density reduced to target range
|
|
848
|
+
*/
|
|
849
|
+
private reduceDensityToTarget;
|
|
850
|
+
/**
|
|
851
|
+
* Build a map of measureNumber → count of downbeats (gridPosition === 0) in that measure.
|
|
852
|
+
*
|
|
853
|
+
* Uses unifiedBeatMap to resolve measureNumber from beatIndex, supporting any time signature.
|
|
854
|
+
*
|
|
855
|
+
* @param beats - The beats to scan
|
|
856
|
+
* @returns Map from measureNumber to downbeat count
|
|
857
|
+
*/
|
|
858
|
+
private buildDownbeatCountMap;
|
|
859
|
+
/**
|
|
860
|
+
* Calculate removal priority for a beat (higher = more important to keep)
|
|
861
|
+
*
|
|
862
|
+
* Priority factors:
|
|
863
|
+
* - Strong beat bonus: +0.3 (zeroed in 'neutral' mode)
|
|
864
|
+
* - Downbeat bonus: +0.2 (gridPosition 0)
|
|
865
|
+
* - Only-downbeat-in-measure bonus: +0.2 (stacks on downbeat bonus)
|
|
866
|
+
* - Intensity contribution: +intensity * 0.3
|
|
867
|
+
* - Phrase membership bonus: +0.15 (max)
|
|
868
|
+
* - Offbeat penalty: -0.1 (gridPosition 1 or 3)
|
|
869
|
+
*
|
|
870
|
+
* @param beat - The beat to evaluate
|
|
871
|
+
* @param phraseMembership - Map of beat indices to phrase membership
|
|
872
|
+
* @param downbeatCountByMeasure - Map of measureNumber → downbeat count for structural importance
|
|
873
|
+
* @returns Priority score (0-1 range, higher = keep)
|
|
874
|
+
*/
|
|
875
|
+
private calculateRemovalPriority;
|
|
876
|
+
/**
|
|
877
|
+
* Convert a single beat to an allowed grid type
|
|
878
|
+
*
|
|
879
|
+
* Conversion rules for Easy difficulty:
|
|
880
|
+
* - `straight_16th` (4 positions: 0, 1, 2, 3) → `straight_8th` (2 positions: 0, 2)
|
|
881
|
+
* - Position 0 → 0 (quarter note)
|
|
882
|
+
* - Position 1 → 0 (snaps back to quarter)
|
|
883
|
+
* - Position 2 → 2 (8th note)
|
|
884
|
+
* - Position 3 → 2 (snaps to 8th)
|
|
885
|
+
*
|
|
886
|
+
* - `triplet_8th` (3 positions: 0, 1, 2) → `quarter_triplet` (1 position: 0)
|
|
887
|
+
* - All positions snap to 0 (quarter triplet)
|
|
888
|
+
*
|
|
889
|
+
* - `straight_8th` (2 positions: 0, 1) → `straight_4th` (1 position: 0)
|
|
890
|
+
* - All positions snap to 0 (quarter note) — Easy at BPM > 120
|
|
891
|
+
*
|
|
892
|
+
* - `straight_16th` → `straight_4th` (Easy at BPM > 120)
|
|
893
|
+
* - All positions snap to 0 (quarter note)
|
|
894
|
+
*
|
|
895
|
+
* @param beat - The beat to convert
|
|
896
|
+
* @param targetDifficulty - The target difficulty
|
|
897
|
+
* @param quarterNoteInterval - Duration of a quarter note in seconds
|
|
898
|
+
* @param bpm - The tempo in BPM (for tempo-aware grid type selection)
|
|
899
|
+
* @returns The converted beat as VariantBeat, or null if the beat should be removed
|
|
900
|
+
*/
|
|
901
|
+
private convertBeatGridType;
|
|
902
|
+
/**
|
|
903
|
+
* Deduplicate converted beats that may have snapped to the same grid position
|
|
904
|
+
*
|
|
905
|
+
* After conversion, multiple beats may end up at the same (beatIndex, gridPosition, gridType).
|
|
906
|
+
* This method keeps only the highest-intensity beat at each position.
|
|
907
|
+
*
|
|
908
|
+
* @param beats - Converted beats (may have duplicates)
|
|
909
|
+
* @returns Deduplicated beats
|
|
910
|
+
*/
|
|
911
|
+
private deduplicateConvertedBeats;
|
|
912
|
+
/**
|
|
913
|
+
* Determine if simplification is needed
|
|
914
|
+
*
|
|
915
|
+
* @param targetDifficulty - The target difficulty
|
|
916
|
+
* @param naturalDifficulty - The natural difficulty of the composite
|
|
917
|
+
* @returns True if simplification is needed
|
|
918
|
+
*/
|
|
919
|
+
private needsSimplification;
|
|
920
|
+
/**
|
|
921
|
+
* Determine if enhancement is needed
|
|
922
|
+
*
|
|
923
|
+
* @param targetDifficulty - The target difficulty
|
|
924
|
+
* @param naturalDifficulty - The natural difficulty of the composite
|
|
925
|
+
* @returns True if enhancement is needed
|
|
926
|
+
*/
|
|
927
|
+
private needsEnhancement;
|
|
928
|
+
/**
|
|
929
|
+
* Determine if this is heavy simplification (2 levels down)
|
|
930
|
+
*
|
|
931
|
+
* Heavy simplification occurs when going from hard -> easy (skipping medium).
|
|
932
|
+
* This requires more aggressive beat removal - keeping only core beats.
|
|
933
|
+
*
|
|
934
|
+
* @param targetDifficulty - The target difficulty
|
|
935
|
+
* @param naturalDifficulty - The natural difficulty of the composite
|
|
936
|
+
* @returns True if this is heavy simplification
|
|
937
|
+
*/
|
|
938
|
+
private isHeavySimplification;
|
|
939
|
+
/**
|
|
940
|
+
* Enhance beats by adding density through pattern insertion and interpolation
|
|
941
|
+
*
|
|
942
|
+
* ## Algorithm Overview
|
|
943
|
+
*
|
|
944
|
+
* 1. **Pattern Insertion** (first priority):
|
|
945
|
+
* - Look for suitable patterns from the phrase library
|
|
946
|
+
* - Insert patterns at beats that have low density
|
|
947
|
+
* - Patterns are song-specific and more interesting than simple interpolation
|
|
948
|
+
*
|
|
949
|
+
* 2. **Grid Interpolation** (fallback):
|
|
950
|
+
* - For beats where no pattern matches, interpolate additional subdivisions
|
|
951
|
+
* - Respect per-beat grid decisions (16th vs triplet) from Phase 1
|
|
952
|
+
* - Add beats at intermediate grid positions
|
|
953
|
+
*
|
|
954
|
+
* @param beats - The beats to enhance
|
|
955
|
+
* @param targetDifficulty - The target difficulty level
|
|
956
|
+
* @param bpm - BPM for calculating global target beat count
|
|
957
|
+
* @param unifiedBeatMap - The unified beat map for timestamp derivation
|
|
958
|
+
* @param phraseAnalysis - Optional phrase analysis for pattern library
|
|
959
|
+
* @param gridDecisions - Optional grid decisions from quantized streams
|
|
960
|
+
* @param quarterNoteInterval - Duration of a quarter note in seconds for timestamp calculation
|
|
961
|
+
* @param gridLock - Optional grid lock map (from lockGridPerBeatIndex) - if provided, skips initial enforceSingleGridPerBeat
|
|
962
|
+
* @returns Enhanced beats with metadata
|
|
963
|
+
*/
|
|
964
|
+
private enhanceBeats;
|
|
965
|
+
/**
|
|
966
|
+
* Group beats by their beat index
|
|
967
|
+
*/
|
|
968
|
+
private groupBeatsByIndex;
|
|
969
|
+
/**
|
|
970
|
+
* Calculate target beats per beat index based on density multiplier
|
|
971
|
+
*
|
|
972
|
+
* Includes empty beat indices (those with no existing beats) so that
|
|
973
|
+
* enhancement can fill gaps in the rhythm. Empty beats get a target
|
|
974
|
+
* proportional to the multiplier, treating them as having 1 virtual beat.
|
|
975
|
+
*/
|
|
976
|
+
private calculateTargetBeatsPerBeat;
|
|
977
|
+
/**
|
|
978
|
+
* Try to insert a pattern from the phrase library
|
|
979
|
+
*
|
|
980
|
+
* Looks for patterns that:
|
|
981
|
+
* - Have available slots in the current beat
|
|
982
|
+
* - Match the grid type of existing beats
|
|
983
|
+
* - Are within the max pattern size limit
|
|
984
|
+
*/
|
|
985
|
+
private tryInsertPattern;
|
|
986
|
+
/**
|
|
987
|
+
* Create beats for an empty beat index (one with no existing beats)
|
|
988
|
+
*
|
|
989
|
+
* When enhancement needs to fill gaps in the rhythm, this method creates
|
|
990
|
+
* beats from scratch using grid decisions or neighbor context to determine
|
|
991
|
+
* the appropriate grid type and timing.
|
|
992
|
+
*
|
|
993
|
+
* @param beatIndex - The beat index to create beats for
|
|
994
|
+
* @param beatsToAdd - Number of beats to create
|
|
995
|
+
* @param unifiedBeatMap - Optional unified beat map for timestamp derivation
|
|
996
|
+
* @param gridDecisions - Optional grid decisions from quantized streams
|
|
997
|
+
* @param quarterNoteInterval - Duration of a quarter note in seconds
|
|
998
|
+
* @param beatsByIndex - All beats grouped by index (for neighbor lookup)
|
|
999
|
+
* @param occupiedSlots - Global occupied slot tracker
|
|
1000
|
+
* @param lockedGridType - Optional locked grid type from gridLock (takes priority over other sources)
|
|
1001
|
+
* @returns Array of newly created beats
|
|
1002
|
+
*/
|
|
1003
|
+
private createBeatsForEmptyIndex;
|
|
1004
|
+
/**
|
|
1005
|
+
* Interpolate beats to add density
|
|
1006
|
+
*
|
|
1007
|
+
* Adds beats at intermediate grid positions that don't already have beats.
|
|
1008
|
+
* Always uses the existing beats' grid type to avoid mixed grids.
|
|
1009
|
+
*
|
|
1010
|
+
* @param existingBeats - Existing beats at this beat index
|
|
1011
|
+
* @param beatIndex - The beat index to interpolate for
|
|
1012
|
+
* @param beatsToAdd - Number of beats to add
|
|
1013
|
+
* @param quarterNoteInterval - Duration of a quarter note in seconds for timestamp calculation
|
|
1014
|
+
* @param occupiedSlots - Global occupied slot tracker
|
|
1015
|
+
* @param lockedGridType - Grid type locked for this beat index (ExtendedGridType for full support)
|
|
1016
|
+
* @param unifiedBeatMap - The unified beat map for authoritative timestamp derivation
|
|
1017
|
+
* @returns Array of interpolated beats
|
|
1018
|
+
*/
|
|
1019
|
+
private interpolateBeats;
|
|
1020
|
+
/**
|
|
1021
|
+
* Determine the grid type for a beat index.
|
|
1022
|
+
* Used when creating beats for an empty index that has no existing beats.
|
|
1023
|
+
*/
|
|
1024
|
+
private getGridForBeatIndex;
|
|
1025
|
+
/**
|
|
1026
|
+
* Deduplicate enhanced beats — each beat index has exactly one grid type.
|
|
1027
|
+
* Beats at the same beatIndex:gridPosition are the same musical event regardless
|
|
1028
|
+
* of grid type. If two grid types somehow landed at the same position, keep the
|
|
1029
|
+
* one matching the dominant grid type for that beat index.
|
|
1030
|
+
*/
|
|
1031
|
+
private deduplicateEnhancedBeats;
|
|
1032
|
+
/**
|
|
1033
|
+
* Enforce single grid type per beat index.
|
|
1034
|
+
*
|
|
1035
|
+
* When a beat index has notes from both triplet and straight grids,
|
|
1036
|
+
* keep only the grid type with higher total intensity. This prevents
|
|
1037
|
+
* unmusical combinations like a 16th note and a triplet in the same beat.
|
|
1038
|
+
*
|
|
1039
|
+
* @param beats - The beats to enforce single-grid on
|
|
1040
|
+
* @returns Beats with at most one grid type per beat index
|
|
1041
|
+
*/
|
|
1042
|
+
private enforceSingleGridPerBeat;
|
|
1043
|
+
/**
|
|
1044
|
+
* Validate that beats have no mixed grid types per beat index
|
|
1045
|
+
*
|
|
1046
|
+
* Task 1.3.4: Validation-only check for grid lock compliance.
|
|
1047
|
+
* When grid lock is provided to enhanceBeats(), this method confirms
|
|
1048
|
+
* that no grid violations exist (assert, don't fix).
|
|
1049
|
+
*
|
|
1050
|
+
* @param beats - The beats to validate
|
|
1051
|
+
* @returns Validation result with any violations found
|
|
1052
|
+
*/
|
|
1053
|
+
private validateSingleGridPerBeat;
|
|
1054
|
+
/**
|
|
1055
|
+
* Get the current configuration
|
|
1056
|
+
*/
|
|
1057
|
+
getConfig(): DifficultyVariantConfig;
|
|
1058
|
+
/**
|
|
1059
|
+
* Build a map of beat indices to their phrase membership
|
|
1060
|
+
*
|
|
1061
|
+
* This creates a lookup structure to quickly check if a beat is part of
|
|
1062
|
+
* a detected rhythmic phrase, and how significant that phrase is.
|
|
1063
|
+
*
|
|
1064
|
+
* @param phraseAnalysis - The phrase analysis result
|
|
1065
|
+
* @returns Map from beat index to array of phrases that include that beat
|
|
1066
|
+
*/
|
|
1067
|
+
private buildPhraseMembershipMap;
|
|
1068
|
+
/**
|
|
1069
|
+
* Check if a beat should be preserved due to phrase membership
|
|
1070
|
+
*
|
|
1071
|
+
* When preservePhraseBoundaries is enabled, this method determines if
|
|
1072
|
+
* a beat that would normally be removed should be kept because it's
|
|
1073
|
+
* part of a significant detected phrase.
|
|
1074
|
+
*
|
|
1075
|
+
* @param beat - The beat to check
|
|
1076
|
+
* @param phraseMembership - Map of beat indices to phrase membership
|
|
1077
|
+
* @param intensityThreshold - The intensity threshold being used
|
|
1078
|
+
* @returns True if the beat should be preserved due to phrase membership
|
|
1079
|
+
*/
|
|
1080
|
+
private shouldPreserveForPhrase;
|
|
1081
|
+
}
|
|
1082
|
+
//# sourceMappingURL=DifficultyVariantGenerator.d.ts.map
|