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,1825 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beat Detection type definitions
|
|
3
|
+
*
|
|
4
|
+
* Based on the Ellis Dynamic Programming beat tracking algorithm
|
|
5
|
+
* Reference: "Beat Tracking by Dynamic Programming" (Ellis, 2007)
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Represents a single detected beat in the audio
|
|
9
|
+
*/
|
|
10
|
+
export interface Beat {
|
|
11
|
+
/** Timestamp in seconds from the start of the audio */
|
|
12
|
+
timestamp: number;
|
|
13
|
+
/** Position within the measure (0 = downbeat, 1, 2, 3, etc. for subsequent beats) */
|
|
14
|
+
beatInMeasure: number;
|
|
15
|
+
/** Whether this beat is a downbeat (first beat of a measure) */
|
|
16
|
+
isDownbeat: boolean;
|
|
17
|
+
/** Measure number (0-indexed from first detected downbeat) */
|
|
18
|
+
measureNumber: number;
|
|
19
|
+
/** Onset strength at this beat (0.0 - 1.0, normalized) */
|
|
20
|
+
intensity: number;
|
|
21
|
+
/** Confidence score for this beat detection (0.0 - 1.0) */
|
|
22
|
+
confidence: number;
|
|
23
|
+
/**
|
|
24
|
+
* Optional required key for rhythm game chart creation.
|
|
25
|
+
* When specified, this key must be pressed for the beat to count as a hit.
|
|
26
|
+
* Frontend maps physical inputs to these strings before calling the engine.
|
|
27
|
+
* @example 'up', 'down', 'left', 'right', 'a', 'b', 'x', 'y'
|
|
28
|
+
*/
|
|
29
|
+
requiredKey?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Time signature configuration for beat grid
|
|
33
|
+
* Defaults to 4/4 time if not specified
|
|
34
|
+
*/
|
|
35
|
+
export interface TimeSignatureConfig {
|
|
36
|
+
/** Number of beats per measure (default: 4 for 4/4 time) */
|
|
37
|
+
beatsPerMeasure: number;
|
|
38
|
+
}
|
|
39
|
+
/** Default time signature (4/4) */
|
|
40
|
+
export declare const DEFAULT_TIME_SIGNATURE: TimeSignatureConfig;
|
|
41
|
+
/**
|
|
42
|
+
* A segment of downbeat configuration
|
|
43
|
+
* Used to support time signature changes within a track
|
|
44
|
+
*
|
|
45
|
+
* Segments are CONTIGUOUS - each segment covers all beats from its startBeat
|
|
46
|
+
* until the next segment's startBeat (or end of track). There are no gaps.
|
|
47
|
+
*
|
|
48
|
+
* Example: If segment 1 has startBeat: 0 and segment 2 has startBeat: 32,
|
|
49
|
+
* then segment 1 covers beats 0-31 and segment 2 covers beats 32+.
|
|
50
|
+
*/
|
|
51
|
+
export interface DownbeatSegment {
|
|
52
|
+
/**
|
|
53
|
+
* Beat index where this segment starts
|
|
54
|
+
* The first segment should typically have startBeat: 0
|
|
55
|
+
*/
|
|
56
|
+
startBeat: number;
|
|
57
|
+
/**
|
|
58
|
+
* Beat index that represents the "one" (downbeat) in this segment
|
|
59
|
+
* This is an absolute beat index, not relative to startBeat
|
|
60
|
+
*
|
|
61
|
+
* Example: If set to 9 with beatsPerMeasure: 4, then beats 1, 5, 9, 13, 17... are downbeats
|
|
62
|
+
* (calculated bidirectionally from beat 9)
|
|
63
|
+
*/
|
|
64
|
+
downbeatBeatIndex: number;
|
|
65
|
+
/** Time signature for this segment */
|
|
66
|
+
timeSignature: TimeSignatureConfig;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Downbeat configuration for manual placement
|
|
70
|
+
* Supports multiple segments for time signature changes within a track
|
|
71
|
+
*/
|
|
72
|
+
export interface DownbeatConfig {
|
|
73
|
+
/**
|
|
74
|
+
* Array of downbeat segments
|
|
75
|
+
* - For simple tracks: single segment with startBeat: 0
|
|
76
|
+
* - For time signature changes: multiple segments ordered by startBeat
|
|
77
|
+
*
|
|
78
|
+
* Each segment defines its own downbeat anchor and time signature.
|
|
79
|
+
* The downbeatBeatIndex is absolute (not relative to segment start).
|
|
80
|
+
*/
|
|
81
|
+
segments: DownbeatSegment[];
|
|
82
|
+
}
|
|
83
|
+
/** Default downbeat config (first beat is the one, 4/4 time) */
|
|
84
|
+
export declare const DEFAULT_DOWNBEAT_CONFIG: DownbeatConfig;
|
|
85
|
+
/** Minimum beats per measure */
|
|
86
|
+
export declare const MIN_BEATS_PER_MEASURE = 2;
|
|
87
|
+
/** Maximum beats per measure */
|
|
88
|
+
export declare const MAX_BEATS_PER_MEASURE = 12;
|
|
89
|
+
/**
|
|
90
|
+
* Validate downbeat configuration (structural validation only)
|
|
91
|
+
*
|
|
92
|
+
* Note: Beat count validation (e.g., downbeatBeatIndex < totalBeats) happens
|
|
93
|
+
* inside generateBeatMap() AFTER beat detection, since we don't know the
|
|
94
|
+
* total beat count until then.
|
|
95
|
+
*
|
|
96
|
+
* @param config - The downbeat configuration to validate
|
|
97
|
+
* @throws Error if configuration is invalid
|
|
98
|
+
*/
|
|
99
|
+
export declare function validateDownbeatConfig(config: DownbeatConfig): void;
|
|
100
|
+
/**
|
|
101
|
+
* Validate downbeat config against actual beat count
|
|
102
|
+
* Called inside generateBeatMap() after beat detection
|
|
103
|
+
*
|
|
104
|
+
* @param config - The downbeat configuration to validate
|
|
105
|
+
* @param totalBeats - The total number of beats in the beat map
|
|
106
|
+
* @throws Error if downbeatBeatIndex exceeds total beats
|
|
107
|
+
*/
|
|
108
|
+
export declare function validateDownbeatConfigAgainstBeats(config: DownbeatConfig, totalBeats: number): void;
|
|
109
|
+
/**
|
|
110
|
+
* Reapply downbeat configuration to recalculate measure labels
|
|
111
|
+
*
|
|
112
|
+
* This is the PRIMARY way to set downbeat configuration. The typical workflow is:
|
|
113
|
+
* 1. Generate beat map with default config
|
|
114
|
+
* 2. Examine the beat map to identify the correct downbeat position
|
|
115
|
+
* 3. Call this function to apply the correct configuration
|
|
116
|
+
*
|
|
117
|
+
* This does NOT re-analyze audio - it only recalculates measure labels.
|
|
118
|
+
*
|
|
119
|
+
* @param beatMap - The original beat map
|
|
120
|
+
* @param newConfig - New downbeat configuration to apply
|
|
121
|
+
* @returns New BeatMap with updated measure labels (original is not modified)
|
|
122
|
+
* @throws Error if configuration is invalid or downbeatBeatIndex exceeds total beats
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* // Generate first, then configure
|
|
127
|
+
* const beatMap = await generator.generateBeatMap('song.mp3', 'track-1');
|
|
128
|
+
*
|
|
129
|
+
* // After examining, you identify beat 9 as the downbeat
|
|
130
|
+
* const correctedMap = reapplyDownbeatConfig(beatMap, {
|
|
131
|
+
* segments: [{
|
|
132
|
+
* startBeat: 0,
|
|
133
|
+
* downbeatBeatIndex: 9, // Beat 9 is the "one"
|
|
134
|
+
* timeSignature: { beatsPerMeasure: 4 },
|
|
135
|
+
* }],
|
|
136
|
+
* });
|
|
137
|
+
* // Beats 1, 5, 9, 13, 17... are now downbeats
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export declare function reapplyDownbeatConfig(beatMap: BeatMap, newConfig: DownbeatConfig): BeatMap;
|
|
141
|
+
/**
|
|
142
|
+
* Metadata about the beat detection algorithm and settings used
|
|
143
|
+
*/
|
|
144
|
+
export interface BeatMapMetadata {
|
|
145
|
+
/** Version of the beat detection algorithm */
|
|
146
|
+
version: string;
|
|
147
|
+
/** Algorithm name (e.g., 'ellis-dp-v1') */
|
|
148
|
+
algorithm: string;
|
|
149
|
+
/** Minimum BPM threshold used during detection */
|
|
150
|
+
minBpm: number;
|
|
151
|
+
/** Maximum BPM threshold used during detection */
|
|
152
|
+
maxBpm: number;
|
|
153
|
+
/** Pre-processing sensitivity used (0.1 - 10.0) */
|
|
154
|
+
sensitivity: number;
|
|
155
|
+
/** Post-processing grid-alignment filter used (0.0 - 1.0) */
|
|
156
|
+
filter: number;
|
|
157
|
+
/** Noise floor threshold for filtering low-energy detections */
|
|
158
|
+
noiseFloorThreshold: number;
|
|
159
|
+
/** Milliseconds between FFT frames */
|
|
160
|
+
hopSizeMs: number;
|
|
161
|
+
/** FFT window size in samples */
|
|
162
|
+
fftSize: number;
|
|
163
|
+
/** Ellis balance factor (alpha) for tempo consistency vs onset strength */
|
|
164
|
+
dpAlpha: number;
|
|
165
|
+
/** Number of Mel frequency bands for onset strength envelope */
|
|
166
|
+
melBands: number;
|
|
167
|
+
/** High-pass filter cutoff in Hz for onset strength envelope */
|
|
168
|
+
highPassCutoff: number;
|
|
169
|
+
/** Gaussian smoothing window in ms for onset strength envelope */
|
|
170
|
+
gaussianSmoothMs: number;
|
|
171
|
+
/** Tempo center in seconds (default 0.5s = 120 BPM) */
|
|
172
|
+
tempoCenter: number;
|
|
173
|
+
/** Tempo width in octaves for perception weighting */
|
|
174
|
+
tempoWidth: number;
|
|
175
|
+
/** Whether TPS2 octave resolution was enabled for duple meter detection */
|
|
176
|
+
useOctaveResolution: boolean;
|
|
177
|
+
/** Whether TPS3 triple meter resolution was enabled for 3/4, 6/8 detection */
|
|
178
|
+
useTripleMeter: boolean;
|
|
179
|
+
/** Timestamp when the beat map was generated */
|
|
180
|
+
generatedAt: string;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Complete beat map for a single audio track
|
|
184
|
+
*
|
|
185
|
+
* Contains all detected beats and metadata. BPM is calculated dynamically
|
|
186
|
+
* during playback from actual beat intervals, not stored as a static value.
|
|
187
|
+
*/
|
|
188
|
+
export interface BeatMap {
|
|
189
|
+
/** Unique identifier for the audio source */
|
|
190
|
+
audioId: string;
|
|
191
|
+
/** Duration of the audio in seconds */
|
|
192
|
+
duration: number;
|
|
193
|
+
/** Array of all detected beats */
|
|
194
|
+
beats: Beat[];
|
|
195
|
+
/** Initial BPM estimate from tempo detection */
|
|
196
|
+
bpm: number;
|
|
197
|
+
/** Algorithm metadata and settings */
|
|
198
|
+
metadata: BeatMapMetadata;
|
|
199
|
+
/**
|
|
200
|
+
* The downbeat configuration used to generate this beat map
|
|
201
|
+
* Only stored if explicitly provided; undefined means default (beat 0 = downbeat, 4/4 time)
|
|
202
|
+
* Stored for reproducibility and reprocessing
|
|
203
|
+
*/
|
|
204
|
+
downbeatConfig?: DownbeatConfig;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Event types emitted by the BeatStream during playback
|
|
208
|
+
*/
|
|
209
|
+
export type BeatEventType = 'upcoming' | 'exact' | 'passed';
|
|
210
|
+
/**
|
|
211
|
+
* Event emitted by the BeatStream during playback
|
|
212
|
+
*/
|
|
213
|
+
export interface BeatEvent {
|
|
214
|
+
/** The beat this event relates to */
|
|
215
|
+
beat: Beat;
|
|
216
|
+
/** Current BPM calculated from recent beat intervals */
|
|
217
|
+
currentBpm: number;
|
|
218
|
+
/** Current audio context time in seconds */
|
|
219
|
+
audioTime: number;
|
|
220
|
+
/** Time until the beat occurs (negative if passed) */
|
|
221
|
+
timeUntilBeat: number;
|
|
222
|
+
/** Type of event: 'upcoming', 'exact', or 'passed' */
|
|
223
|
+
type: BeatEventType;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Callback function type for BeatStream subscriptions
|
|
227
|
+
*/
|
|
228
|
+
export type BeatStreamCallback = (event: BeatEvent) => void;
|
|
229
|
+
/**
|
|
230
|
+
* Audio synchronization state for debugging and monitoring
|
|
231
|
+
*/
|
|
232
|
+
export interface AudioSyncState {
|
|
233
|
+
/** Current audio context time in seconds */
|
|
234
|
+
audioContextTime: number;
|
|
235
|
+
/** Audio element current time in seconds */
|
|
236
|
+
audioElementTime: number;
|
|
237
|
+
/** Calculated drift between audio and beat stream */
|
|
238
|
+
drift: number;
|
|
239
|
+
/** Whether the sync is within acceptable tolerance */
|
|
240
|
+
isSynchronized: boolean;
|
|
241
|
+
/** Output latency from AudioContext (0 if unsupported) */
|
|
242
|
+
outputLatency: number;
|
|
243
|
+
/** Base latency from AudioContext (0 if unsupported) */
|
|
244
|
+
baseLatency: number;
|
|
245
|
+
/** User-calibrated offset in milliseconds */
|
|
246
|
+
userOffsetMs: number;
|
|
247
|
+
/** Total effective latency compensation in seconds */
|
|
248
|
+
totalCompensation: number;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Options for BeatMapGenerator
|
|
252
|
+
*
|
|
253
|
+
* ## OSE Parameter Modes
|
|
254
|
+
*
|
|
255
|
+
* OSE parameters support two configuration styles:
|
|
256
|
+
* - **Mode-based**: Use `hopSizeMode`, `melBandsMode`, `gaussianSmoothMode` for preset values
|
|
257
|
+
* - **Direct numeric**: Use `hopSizeMs`, `melBands`, `gaussianSmoothMs` for exact control
|
|
258
|
+
*
|
|
259
|
+
* **Precedence**: When both mode and direct value are provided, mode takes precedence.
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* ```typescript
|
|
263
|
+
* // Mode-based configuration (recommended)
|
|
264
|
+
* const options: BeatMapGeneratorOptions = {
|
|
265
|
+
* hopSizeMode: { mode: 'standard' }, // 4ms (Ellis 2007 paper spec)
|
|
266
|
+
* melBandsMode: { mode: 'detailed' }, // 64 bands
|
|
267
|
+
* gaussianSmoothMode: { mode: 'smooth' } // 40ms
|
|
268
|
+
* };
|
|
269
|
+
*
|
|
270
|
+
* // Direct numeric configuration (backward compatible)
|
|
271
|
+
* const options: BeatMapGeneratorOptions = {
|
|
272
|
+
* hopSizeMs: 4,
|
|
273
|
+
* melBands: 40,
|
|
274
|
+
* gaussianSmoothMs: 20
|
|
275
|
+
* };
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
export interface BeatMapGeneratorOptions {
|
|
279
|
+
/** Minimum BPM to detect (default: 90) */
|
|
280
|
+
minBpm?: number;
|
|
281
|
+
/** Maximum BPM to detect (default: 180) */
|
|
282
|
+
maxBpm?: number;
|
|
283
|
+
/** Pre-processing sensitivity (0.1-10.0, default: 1.0) */
|
|
284
|
+
sensitivity?: number;
|
|
285
|
+
/** Post-processing grid-alignment filter (0.0-1.0, default: 0.0) */
|
|
286
|
+
filter?: number;
|
|
287
|
+
/** Minimum threshold to prevent noise detection (default: 0) */
|
|
288
|
+
noiseFloorThreshold?: number;
|
|
289
|
+
/**
|
|
290
|
+
* Milliseconds between FFT frames (default: 4).
|
|
291
|
+
* Ignored if hopSizeMode is provided.
|
|
292
|
+
* @see hopSizeMode for mode-based configuration
|
|
293
|
+
*/
|
|
294
|
+
hopSizeMs?: number;
|
|
295
|
+
/** FFT window size in samples (default: 2048) */
|
|
296
|
+
fftSize?: number;
|
|
297
|
+
/** Number of beats for rolling BPM calculation (default: 8) */
|
|
298
|
+
rollingBpmWindowSize?: number;
|
|
299
|
+
/**
|
|
300
|
+
* Ellis balance factor for tempo consistency vs onset strength (default: 680)
|
|
301
|
+
* Higher values = stricter tempo adherence (good for songs with clear beats)
|
|
302
|
+
* Lower values = more flexibility for songs with weak/irregular beats
|
|
303
|
+
*/
|
|
304
|
+
dpAlpha?: number;
|
|
305
|
+
/**
|
|
306
|
+
* Number of Mel frequency bands for OSE (default: 40).
|
|
307
|
+
* Ignored if melBandsMode is provided.
|
|
308
|
+
* @see melBandsMode for mode-based configuration
|
|
309
|
+
*/
|
|
310
|
+
melBands?: number;
|
|
311
|
+
/** High-pass filter cutoff in Hz, removes DC offset from OSE (default: 0.4) */
|
|
312
|
+
highPassCutoff?: number;
|
|
313
|
+
/**
|
|
314
|
+
* Gaussian smoothing window in ms for OSE (default: 20).
|
|
315
|
+
* Ignored if gaussianSmoothMode is provided.
|
|
316
|
+
* @see gaussianSmoothMode for mode-based configuration
|
|
317
|
+
*/
|
|
318
|
+
gaussianSmoothMs?: number;
|
|
319
|
+
/** Tempo center in seconds for perception bias (default: 0.5 = 120 BPM) */
|
|
320
|
+
tempoCenter?: number;
|
|
321
|
+
/** Tempo width in octaves for perception weighting (default: 1.4) */
|
|
322
|
+
tempoWidth?: number;
|
|
323
|
+
/**
|
|
324
|
+
* Whether to use TPS2 octave resolution to prevent half-tempo/double-tempo ambiguity.
|
|
325
|
+
*
|
|
326
|
+
* When enabled, uses the Ellis TPS2 calculation (Equation 7) to prefer tempos
|
|
327
|
+
* with strong half-period evidence, improving accuracy from 77% to 84%.
|
|
328
|
+
*
|
|
329
|
+
* This helps prevent the algorithm from locking onto 73 BPM when the true tempo
|
|
330
|
+
* is 146 BPM (octave error).
|
|
331
|
+
*
|
|
332
|
+
* Default: false (opt-in for now)
|
|
333
|
+
*/
|
|
334
|
+
useOctaveResolution?: boolean;
|
|
335
|
+
/**
|
|
336
|
+
* Whether to use TPS3 triple meter resolution for 3/4, 6/8 time signatures.
|
|
337
|
+
*
|
|
338
|
+
* When enabled, uses the Ellis TPS3 calculation (Equation 7 variant) to prefer tempos
|
|
339
|
+
* with strong third-period evidence, improving detection for waltzes and triple meter music.
|
|
340
|
+
*
|
|
341
|
+
* The TPS3 formula combines the main tempo with its third-harmonic:
|
|
342
|
+
* `TPS3(τ) = TPS(τ) + 0.33×TPS(3τ) + 0.33×TPS(3τ-1) + 0.33×TPS(3τ+1)`
|
|
343
|
+
*
|
|
344
|
+
* Tempos with strong third-period evidence (indicating triple meter) will have
|
|
345
|
+
* higher TPS3 scores, allowing proper beat detection for waltzes and 6/8 shuffles.
|
|
346
|
+
*
|
|
347
|
+
* Default: false (opt-in for triple meter music)
|
|
348
|
+
*/
|
|
349
|
+
useTripleMeter?: boolean;
|
|
350
|
+
/**
|
|
351
|
+
* Hop size mode configuration.
|
|
352
|
+
* Takes precedence over hopSizeMs when both are provided.
|
|
353
|
+
* @default { mode: 'standard' } (4ms)
|
|
354
|
+
*/
|
|
355
|
+
hopSizeMode?: HopSizeConfig;
|
|
356
|
+
/**
|
|
357
|
+
* Mel bands mode configuration.
|
|
358
|
+
* Takes precedence over melBands when both are provided.
|
|
359
|
+
* @default { mode: 'standard' } (40 bands)
|
|
360
|
+
*/
|
|
361
|
+
melBandsMode?: MelBandsConfig;
|
|
362
|
+
/**
|
|
363
|
+
* Gaussian smooth mode configuration.
|
|
364
|
+
* Takes precedence over gaussianSmoothMs when both are provided.
|
|
365
|
+
* @default { mode: 'standard' } (20ms)
|
|
366
|
+
*/
|
|
367
|
+
gaussianSmoothMode?: GaussianSmoothConfig;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Options for BeatStream configuration
|
|
371
|
+
*/
|
|
372
|
+
export interface BeatStreamOptions {
|
|
373
|
+
/** Time before beat to emit 'upcoming' event in seconds (default: 2.0) */
|
|
374
|
+
anticipationTime?: number;
|
|
375
|
+
/** Player-calibrated audio/visual offset in milliseconds (default: 0) */
|
|
376
|
+
userOffsetMs?: number;
|
|
377
|
+
/**
|
|
378
|
+
* Auto-adjust using AudioContext.outputLatency (default: true)
|
|
379
|
+
* Gracefully falls back to 0 if unsupported (e.g., Safari/older browsers)
|
|
380
|
+
*/
|
|
381
|
+
compensateOutputLatency?: boolean;
|
|
382
|
+
/** Timing tolerance for synchronization in seconds (default: 0.01 = 10ms) */
|
|
383
|
+
timingTolerance?: number;
|
|
384
|
+
/**
|
|
385
|
+
* Difficulty preset for accuracy thresholds (default: 'medium')
|
|
386
|
+
* Ignored if customThresholds is provided.
|
|
387
|
+
*/
|
|
388
|
+
difficultyPreset?: DifficultyPreset;
|
|
389
|
+
/**
|
|
390
|
+
* Custom accuracy thresholds (in seconds)
|
|
391
|
+
* If provided, overrides difficultyPreset.
|
|
392
|
+
*/
|
|
393
|
+
customThresholds?: Partial<AccuracyThresholds>;
|
|
394
|
+
/**
|
|
395
|
+
* Use interpolated beats from InterpolatedBeatMap (default: false)
|
|
396
|
+
* If true and an InterpolatedBeatMap is provided to the BeatStream constructor,
|
|
397
|
+
* the stream will use mergedBeats (interpolated + detected) instead of
|
|
398
|
+
* the original detectedBeats.
|
|
399
|
+
*
|
|
400
|
+
* This allows seamless use of beat interpolation without modifying the BeatMap.
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```typescript
|
|
404
|
+
* // With interpolation
|
|
405
|
+
* const interpolatedMap = interpolator.interpolate(beatMap);
|
|
406
|
+
* const beatStream = new BeatStream(interpolatedMap, audioContext, {
|
|
407
|
+
* useInterpolatedBeats: true // Use mergedBeats
|
|
408
|
+
* });
|
|
409
|
+
*
|
|
410
|
+
* // Without interpolation (original behavior)
|
|
411
|
+
* const beatStream = new BeatStream(beatMap, audioContext, {
|
|
412
|
+
* useInterpolatedBeats: false // Use beats array
|
|
413
|
+
* });
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
416
|
+
useInterpolatedBeats?: boolean;
|
|
417
|
+
/**
|
|
418
|
+
* Ignore required key assignments on beats (default: false)
|
|
419
|
+
* When true, beats with requiredKey will use timing-only evaluation,
|
|
420
|
+
* ignoring key matching. Useful for "easy mode" gameplay.
|
|
421
|
+
*
|
|
422
|
+
* When false (default), if a beat has a requiredKey:
|
|
423
|
+
* - Correct key: timing-based accuracy (perfect/great/good/ok/miss)
|
|
424
|
+
* - Wrong key: accuracy becomes 'wrongKey' regardless of timing
|
|
425
|
+
* - No key provided: treated as 'miss'
|
|
426
|
+
*/
|
|
427
|
+
ignoreKeyRequirements?: boolean;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Accuracy levels for button press detection
|
|
431
|
+
*/
|
|
432
|
+
export type BeatAccuracy = 'perfect' | 'great' | 'good' | 'ok' | 'miss' | 'wrongKey';
|
|
433
|
+
/**
|
|
434
|
+
* Accuracy thresholds for button press detection (in seconds)
|
|
435
|
+
* Used to configure difficulty levels for rhythm games.
|
|
436
|
+
*/
|
|
437
|
+
export interface AccuracyThresholds {
|
|
438
|
+
/** Perfect: within this threshold (seconds) */
|
|
439
|
+
perfect: number;
|
|
440
|
+
/** Great: within this threshold (seconds) */
|
|
441
|
+
great: number;
|
|
442
|
+
/** Good: within this threshold (seconds) */
|
|
443
|
+
good: number;
|
|
444
|
+
/** Ok: within this threshold (seconds) */
|
|
445
|
+
ok: number;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Preset difficulty levels for accuracy thresholds
|
|
449
|
+
*
|
|
450
|
+
* - 'easy': Forgiving timing, simplified rhythm
|
|
451
|
+
* - 'medium': Balanced timing and rhythm
|
|
452
|
+
* - 'hard': Tight timing, full rhythm density
|
|
453
|
+
* - 'natural': Unedited composite stream (what was actually detected in the audio)
|
|
454
|
+
* - 'custom': User-defined settings
|
|
455
|
+
*/
|
|
456
|
+
export type DifficultyPreset = 'easy' | 'medium' | 'hard' | 'natural' | 'custom';
|
|
457
|
+
/**
|
|
458
|
+
* Easy difficulty thresholds (forgiving)
|
|
459
|
+
*/
|
|
460
|
+
export declare const EASY_ACCURACY_THRESHOLDS: AccuracyThresholds;
|
|
461
|
+
/**
|
|
462
|
+
* Medium difficulty thresholds (balanced)
|
|
463
|
+
*/
|
|
464
|
+
export declare const MEDIUM_ACCURACY_THRESHOLDS: AccuracyThresholds;
|
|
465
|
+
/**
|
|
466
|
+
* Hard difficulty thresholds (strict - for veterans)
|
|
467
|
+
*/
|
|
468
|
+
export declare const HARD_ACCURACY_THRESHOLDS: AccuracyThresholds;
|
|
469
|
+
/**
|
|
470
|
+
* Natural difficulty thresholds (same as hard - unedited composite)
|
|
471
|
+
*/
|
|
472
|
+
export declare const NATURAL_ACCURACY_THRESHOLDS: AccuracyThresholds;
|
|
473
|
+
/**
|
|
474
|
+
* Result of a button press accuracy check
|
|
475
|
+
*/
|
|
476
|
+
export interface ButtonPressResult {
|
|
477
|
+
/** Accuracy level of the press */
|
|
478
|
+
accuracy: BeatAccuracy;
|
|
479
|
+
/** Time difference from nearest beat in seconds (negative = early, positive = late) */
|
|
480
|
+
offset: number;
|
|
481
|
+
/** The beat that was matched (nearest beat to the press) */
|
|
482
|
+
matchedBeat: Beat;
|
|
483
|
+
/** Absolute time difference in seconds */
|
|
484
|
+
absoluteOffset: number;
|
|
485
|
+
/**
|
|
486
|
+
* Whether the pressed key matched the required key (if any).
|
|
487
|
+
* True if: no key required, or pressedKey matches requiredKey.
|
|
488
|
+
* False if: key required but wrong key pressed (accuracy will be 'wrongKey').
|
|
489
|
+
*/
|
|
490
|
+
keyMatch: boolean;
|
|
491
|
+
/**
|
|
492
|
+
* The key that was pressed (passed to checkButtonPress).
|
|
493
|
+
* Undefined if no key was provided.
|
|
494
|
+
*/
|
|
495
|
+
pressedKey?: string;
|
|
496
|
+
/**
|
|
497
|
+
* The required key from the matched beat (convenience copy).
|
|
498
|
+
* Undefined if the beat has no required key.
|
|
499
|
+
*/
|
|
500
|
+
requiredKey?: string;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* JSON-serializable version of BeatMap
|
|
504
|
+
*
|
|
505
|
+
* Identical to BeatMap but ensures all values are JSON-safe
|
|
506
|
+
* for serialization/deserialization operations
|
|
507
|
+
*/
|
|
508
|
+
export interface BeatMapJSON {
|
|
509
|
+
audioId: string;
|
|
510
|
+
duration: number;
|
|
511
|
+
beats: Array<{
|
|
512
|
+
timestamp: number;
|
|
513
|
+
beatInMeasure: number;
|
|
514
|
+
isDownbeat: boolean;
|
|
515
|
+
measureNumber: number;
|
|
516
|
+
intensity: number;
|
|
517
|
+
confidence: number;
|
|
518
|
+
requiredKey?: string;
|
|
519
|
+
}>;
|
|
520
|
+
bpm: number;
|
|
521
|
+
metadata: BeatMapMetadata;
|
|
522
|
+
/**
|
|
523
|
+
* The downbeat configuration used to generate this beat map
|
|
524
|
+
* Only stored if explicitly provided; undefined means default (beat 0 = downbeat, 4/4 time)
|
|
525
|
+
* Stored for reproducibility and reprocessing
|
|
526
|
+
*/
|
|
527
|
+
downbeatConfig?: DownbeatConfig;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* JSON-serializable version of BeatWithSource
|
|
531
|
+
*/
|
|
532
|
+
export interface BeatWithSourceJSON {
|
|
533
|
+
timestamp: number;
|
|
534
|
+
beatInMeasure: number;
|
|
535
|
+
isDownbeat: boolean;
|
|
536
|
+
measureNumber: number;
|
|
537
|
+
intensity: number;
|
|
538
|
+
confidence: number;
|
|
539
|
+
requiredKey?: string;
|
|
540
|
+
source: BeatSource;
|
|
541
|
+
distanceToAnchor?: number;
|
|
542
|
+
nearestAnchorTimestamp?: number;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* JSON-serializable version of QuarterNoteDetection
|
|
546
|
+
*/
|
|
547
|
+
export interface QuarterNoteDetectionJSON {
|
|
548
|
+
intervalSeconds: number;
|
|
549
|
+
bpm: number;
|
|
550
|
+
confidence: number;
|
|
551
|
+
histogramPeak: number;
|
|
552
|
+
secondaryPeaks: number[];
|
|
553
|
+
method: 'histogram' | 'kde' | 'tempo-detector-fallback';
|
|
554
|
+
denseSectionCount: number;
|
|
555
|
+
denseSectionBeats: number;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* JSON-serializable version of GapAnalysis
|
|
559
|
+
*/
|
|
560
|
+
export interface GapAnalysisJSON {
|
|
561
|
+
totalGaps: number;
|
|
562
|
+
halfNoteGaps: number;
|
|
563
|
+
anomalies: number[];
|
|
564
|
+
avgGapSize: number;
|
|
565
|
+
gridAlignmentScore: number;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* JSON-serializable version of TempoSection
|
|
569
|
+
*/
|
|
570
|
+
export interface TempoSectionJSON {
|
|
571
|
+
start: number;
|
|
572
|
+
end: number;
|
|
573
|
+
bpm: number;
|
|
574
|
+
intervalSeconds: number;
|
|
575
|
+
beatCount: number;
|
|
576
|
+
startBeatIndex: number;
|
|
577
|
+
endBeatIndex: number;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* JSON-serializable version of InterpolationMetadata
|
|
581
|
+
*/
|
|
582
|
+
export interface InterpolationMetadataJSON {
|
|
583
|
+
quarterNoteDetection: QuarterNoteDetectionJSON;
|
|
584
|
+
gapAnalysis: GapAnalysisJSON;
|
|
585
|
+
detectedBeatCount: number;
|
|
586
|
+
interpolatedBeatCount: number;
|
|
587
|
+
totalBeatCount: number;
|
|
588
|
+
interpolationRatio: number;
|
|
589
|
+
avgInterpolatedConfidence: number;
|
|
590
|
+
tempoDriftRatio: number;
|
|
591
|
+
/** Tempos found during normal analysis (e.g., [128, 140]) */
|
|
592
|
+
detectedClusterTempos?: number[];
|
|
593
|
+
/** Quick flag for checking if multi-tempo re-analysis is available */
|
|
594
|
+
hasMultipleTempos: boolean;
|
|
595
|
+
/** Full section data (only after multi-tempo re-analysis) */
|
|
596
|
+
tempoSections?: TempoSectionJSON[];
|
|
597
|
+
/** True only after multi-tempo re-analysis completes */
|
|
598
|
+
hasMultiTempoApplied?: boolean;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* JSON-serializable version of InterpolatedBeatMap
|
|
602
|
+
*
|
|
603
|
+
* Ensures all values are JSON-safe for serialization/deserialization operations.
|
|
604
|
+
* Use with BeatInterpolator.toJSON() and BeatInterpolator.fromJSON() methods.
|
|
605
|
+
*/
|
|
606
|
+
export interface InterpolatedBeatMapJSON {
|
|
607
|
+
audioId: string;
|
|
608
|
+
duration: number;
|
|
609
|
+
detectedBeats: Array<{
|
|
610
|
+
timestamp: number;
|
|
611
|
+
beatInMeasure: number;
|
|
612
|
+
isDownbeat: boolean;
|
|
613
|
+
measureNumber: number;
|
|
614
|
+
intensity: number;
|
|
615
|
+
confidence: number;
|
|
616
|
+
requiredKey?: string;
|
|
617
|
+
}>;
|
|
618
|
+
mergedBeats: BeatWithSourceJSON[];
|
|
619
|
+
quarterNoteInterval: number;
|
|
620
|
+
quarterNoteBpm: number;
|
|
621
|
+
quarterNoteConfidence: number;
|
|
622
|
+
originalMetadata: BeatMapMetadata;
|
|
623
|
+
interpolationMetadata: InterpolationMetadataJSON;
|
|
624
|
+
/** The downbeat configuration inherited from the original BeatMap */
|
|
625
|
+
downbeatConfig?: DownbeatConfig;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* JSON-serializable version of SubdividedBeat
|
|
629
|
+
*
|
|
630
|
+
* Extends Beat with subdivision-specific fields.
|
|
631
|
+
* Use with BeatSubdivider.toJSON() and BeatSubdivider.fromJSON() methods.
|
|
632
|
+
*/
|
|
633
|
+
export interface SubdividedBeatJSON {
|
|
634
|
+
timestamp: number;
|
|
635
|
+
beatInMeasure: number;
|
|
636
|
+
isDownbeat: boolean;
|
|
637
|
+
measureNumber: number;
|
|
638
|
+
intensity: number;
|
|
639
|
+
confidence: number;
|
|
640
|
+
requiredKey?: string;
|
|
641
|
+
isDetected: boolean;
|
|
642
|
+
originalBeatIndex?: number;
|
|
643
|
+
subdivisionType: SubdivisionType;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* JSON-serializable version of SubdivisionMetadata
|
|
647
|
+
*/
|
|
648
|
+
export interface SubdivisionMetadataJSON {
|
|
649
|
+
originalBeatCount: number;
|
|
650
|
+
subdividedBeatCount: number;
|
|
651
|
+
averageDensityMultiplier: number;
|
|
652
|
+
explicitBeatCount: number;
|
|
653
|
+
subdivisionsUsed: SubdivisionType[];
|
|
654
|
+
hasMultipleTempos: boolean;
|
|
655
|
+
maxDensity: number;
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* JSON-serializable version of SubdividedBeatMap
|
|
659
|
+
*
|
|
660
|
+
* Ensures all values are JSON-safe for serialization/deserialization operations.
|
|
661
|
+
* Use with BeatSubdivider.toJSON() and BeatSubdivider.fromJSON() methods.
|
|
662
|
+
*/
|
|
663
|
+
export interface SubdividedBeatMapJSON {
|
|
664
|
+
audioId: string;
|
|
665
|
+
duration: number;
|
|
666
|
+
beats: SubdividedBeatJSON[];
|
|
667
|
+
detectedBeatIndices: number[];
|
|
668
|
+
subdivisionConfig: SubdivisionConfigJSON;
|
|
669
|
+
downbeatConfig: DownbeatConfig;
|
|
670
|
+
tempoSections?: TempoSectionJSON[];
|
|
671
|
+
subdivisionMetadata: SubdivisionMetadataJSON;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Tempo estimation result from the TempoDetector
|
|
675
|
+
*/
|
|
676
|
+
export interface TempoEstimate {
|
|
677
|
+
/** Main tempo estimate in BPM */
|
|
678
|
+
primaryBpm: number;
|
|
679
|
+
/** Adjacent metrical level in BPM (e.g., half-time or double-time) */
|
|
680
|
+
secondaryBpm: number;
|
|
681
|
+
/** Relative strength of the primary tempo (0.0 - 1.0) */
|
|
682
|
+
primaryWeight: number;
|
|
683
|
+
/** Relative strength of the secondary tempo (0.0 - 1.0) */
|
|
684
|
+
secondaryWeight: number;
|
|
685
|
+
/** Target inter-beat interval in seconds for DP tracker */
|
|
686
|
+
targetIntervalSeconds: number;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Tier 1: Hop size mode for controlling beat detection precision
|
|
690
|
+
*
|
|
691
|
+
* Hop size determines the time resolution of onset detection.
|
|
692
|
+
* Smaller values = more precise but slower analysis.
|
|
693
|
+
*/
|
|
694
|
+
export type HopSizeMode = 'efficient' | 'standard' | 'hq' | 'custom';
|
|
695
|
+
/**
|
|
696
|
+
* Preset hop size values in milliseconds
|
|
697
|
+
*
|
|
698
|
+
* - efficient: 10ms - Fast analysis, reduced precision (legacy default)
|
|
699
|
+
* - standard: 4ms - Paper specification (Ellis 2007) - RECOMMENDED
|
|
700
|
+
* - hq: 2ms - High quality, maximum precision
|
|
701
|
+
*/
|
|
702
|
+
export declare const HOP_SIZE_PRESETS: {
|
|
703
|
+
readonly efficient: 10;
|
|
704
|
+
readonly standard: 4;
|
|
705
|
+
readonly hq: 2;
|
|
706
|
+
};
|
|
707
|
+
/**
|
|
708
|
+
* Configuration for hop size mode selection
|
|
709
|
+
*/
|
|
710
|
+
export interface HopSizeConfig {
|
|
711
|
+
/** The hop size mode to use */
|
|
712
|
+
mode: HopSizeMode;
|
|
713
|
+
/** Custom hop size in milliseconds (only used when mode === 'custom') */
|
|
714
|
+
customValue?: number;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Tier 2: Mel bands mode for controlling frequency resolution
|
|
718
|
+
*
|
|
719
|
+
* Mel bands determine the frequency resolution of the onset detection.
|
|
720
|
+
* More bands = better frequency resolution but slightly slower analysis.
|
|
721
|
+
*/
|
|
722
|
+
export type MelBandsMode = 'standard' | 'detailed' | 'maximum';
|
|
723
|
+
/**
|
|
724
|
+
* Preset mel bands values
|
|
725
|
+
*
|
|
726
|
+
* - standard: 40 bands - Paper default, librosa default - RECOMMENDED
|
|
727
|
+
* - detailed: 64 bands - Better frequency resolution
|
|
728
|
+
* - maximum: 80 bands - Maximum detail
|
|
729
|
+
*/
|
|
730
|
+
export declare const MEL_BANDS_PRESETS: {
|
|
731
|
+
readonly standard: 40;
|
|
732
|
+
readonly detailed: 64;
|
|
733
|
+
readonly maximum: 80;
|
|
734
|
+
};
|
|
735
|
+
/**
|
|
736
|
+
* Configuration for mel bands mode selection
|
|
737
|
+
*/
|
|
738
|
+
export interface MelBandsConfig {
|
|
739
|
+
/** The mel bands mode to use */
|
|
740
|
+
mode: MelBandsMode;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Tier 2: Gaussian smooth mode for controlling onset envelope smoothing
|
|
744
|
+
*
|
|
745
|
+
* Gaussian smoothing determines how much the onset envelope is smoothed.
|
|
746
|
+
* More smoothing = cleaner peaks but may miss fast transients.
|
|
747
|
+
*/
|
|
748
|
+
export type GaussianSmoothMode = 'minimal' | 'standard' | 'smooth';
|
|
749
|
+
/**
|
|
750
|
+
* Preset gaussian smoothing values in milliseconds
|
|
751
|
+
*
|
|
752
|
+
* - minimal: 10ms - Preserves fast transients
|
|
753
|
+
* - standard: 20ms - Paper default - RECOMMENDED
|
|
754
|
+
* - smooth: 40ms - Cleaner peaks, less noise
|
|
755
|
+
*/
|
|
756
|
+
export declare const GAUSSIAN_SMOOTH_PRESETS: {
|
|
757
|
+
readonly minimal: 10;
|
|
758
|
+
readonly standard: 20;
|
|
759
|
+
readonly smooth: 40;
|
|
760
|
+
};
|
|
761
|
+
/**
|
|
762
|
+
* Configuration for gaussian smooth mode selection
|
|
763
|
+
*/
|
|
764
|
+
export interface GaussianSmoothConfig {
|
|
765
|
+
/** The gaussian smooth mode to use */
|
|
766
|
+
mode: GaussianSmoothMode;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Convert hop size mode to actual milliseconds value
|
|
770
|
+
*
|
|
771
|
+
* @param config - Hop size configuration (default: { mode: 'standard' })
|
|
772
|
+
* @returns Hop size in milliseconds
|
|
773
|
+
*
|
|
774
|
+
* @example
|
|
775
|
+
* ```typescript
|
|
776
|
+
* // Using preset modes
|
|
777
|
+
* getHopSizeMs({ mode: 'standard' }); // 4ms (Ellis 2007 paper spec)
|
|
778
|
+
* getHopSizeMs({ mode: 'efficient' }); // 10ms (fast analysis)
|
|
779
|
+
* getHopSizeMs({ mode: 'hq' }); // 2ms (maximum precision)
|
|
780
|
+
*
|
|
781
|
+
* // Using custom value (clamped to 1-50ms)
|
|
782
|
+
* getHopSizeMs({ mode: 'custom', customValue: 5 }); // 5ms
|
|
783
|
+
* getHopSizeMs({ mode: 'custom', customValue: 100 }); // 50ms (clamped)
|
|
784
|
+
* ```
|
|
785
|
+
*/
|
|
786
|
+
export declare function getHopSizeMs(config?: HopSizeConfig): number;
|
|
787
|
+
/**
|
|
788
|
+
* Convert mel bands mode to actual count
|
|
789
|
+
*
|
|
790
|
+
* @param config - Mel bands configuration (default: { mode: 'standard' })
|
|
791
|
+
* @returns Number of mel bands
|
|
792
|
+
*
|
|
793
|
+
* @example
|
|
794
|
+
* ```typescript
|
|
795
|
+
* getMelBands({ mode: 'standard' }); // 40 bands (librosa default)
|
|
796
|
+
* getMelBands({ mode: 'detailed' }); // 64 bands (better resolution)
|
|
797
|
+
* getMelBands({ mode: 'maximum' }); // 80 bands (maximum detail)
|
|
798
|
+
* ```
|
|
799
|
+
*/
|
|
800
|
+
export declare function getMelBands(config?: MelBandsConfig): number;
|
|
801
|
+
/**
|
|
802
|
+
* Convert gaussian smooth mode to actual milliseconds value
|
|
803
|
+
*
|
|
804
|
+
* @param config - Gaussian smooth configuration (default: { mode: 'standard' })
|
|
805
|
+
* @returns Smoothing window in milliseconds
|
|
806
|
+
*
|
|
807
|
+
* @example
|
|
808
|
+
* ```typescript
|
|
809
|
+
* getGaussianSmoothMs({ mode: 'minimal' }); // 10ms (preserves transients)
|
|
810
|
+
* getGaussianSmoothMs({ mode: 'standard' }); // 20ms (paper default)
|
|
811
|
+
* getGaussianSmoothMs({ mode: 'smooth' }); // 40ms (cleaner peaks)
|
|
812
|
+
* ```
|
|
813
|
+
*/
|
|
814
|
+
export declare function getGaussianSmoothMs(config?: GaussianSmoothConfig): number;
|
|
815
|
+
/**
|
|
816
|
+
* Configuration for Onset Strength Envelope calculation
|
|
817
|
+
*
|
|
818
|
+
* ## Parameter Modes vs Direct Values
|
|
819
|
+
*
|
|
820
|
+
* OSE parameters support two configuration styles:
|
|
821
|
+
* - **Mode-based**: Use `hopSizeMode`, `melBandsMode`, `gaussianSmoothMode` for preset values
|
|
822
|
+
* - **Direct numeric**: Use `hopSizeMs`, `melBands`, `gaussianSmoothMs` for exact control
|
|
823
|
+
*
|
|
824
|
+
* **Precedence**: When both mode and direct value are provided, mode takes precedence.
|
|
825
|
+
*
|
|
826
|
+
* @example
|
|
827
|
+
* ```typescript
|
|
828
|
+
* // Mode-based configuration (recommended)
|
|
829
|
+
* const config: OSEConfig = {
|
|
830
|
+
* hopSizeMode: { mode: 'standard' }, // 4ms (Ellis 2007 paper spec)
|
|
831
|
+
* melBandsMode: { mode: 'detailed' }, // 64 bands
|
|
832
|
+
* gaussianSmoothMode: { mode: 'smooth' } // 40ms
|
|
833
|
+
* };
|
|
834
|
+
*
|
|
835
|
+
* // Direct numeric configuration (backward compatible)
|
|
836
|
+
* const config: OSEConfig = {
|
|
837
|
+
* hopSizeMs: 4,
|
|
838
|
+
* melBands: 40,
|
|
839
|
+
* gaussianSmoothMs: 20
|
|
840
|
+
* };
|
|
841
|
+
*
|
|
842
|
+
* // Mixed - mode takes precedence (hopSizeMs is ignored)
|
|
843
|
+
* const config: OSEConfig = {
|
|
844
|
+
* hopSizeMode: { mode: 'hq' }, // Uses 2ms
|
|
845
|
+
* hopSizeMs: 10 // Ignored because hopSizeMode is set
|
|
846
|
+
* };
|
|
847
|
+
* ```
|
|
848
|
+
*/
|
|
849
|
+
export interface OSEConfig {
|
|
850
|
+
/** Target sample rate for resampling (default: 8000 Hz) */
|
|
851
|
+
targetSampleRate?: number;
|
|
852
|
+
/** FFT window size in milliseconds (default: 32) */
|
|
853
|
+
fftWindowSize?: number;
|
|
854
|
+
/**
|
|
855
|
+
* Hop size in milliseconds (default: 4).
|
|
856
|
+
* Ignored if hopSizeMode is provided.
|
|
857
|
+
* @see hopSizeMode for mode-based configuration
|
|
858
|
+
*/
|
|
859
|
+
hopSizeMs?: number;
|
|
860
|
+
/**
|
|
861
|
+
* Hop size mode configuration.
|
|
862
|
+
* Takes precedence over hopSizeMs when both are provided.
|
|
863
|
+
* @default { mode: 'standard' }
|
|
864
|
+
*/
|
|
865
|
+
hopSizeMode?: HopSizeConfig;
|
|
866
|
+
/**
|
|
867
|
+
* Number of Mel frequency bands (default: 40).
|
|
868
|
+
* Ignored if melBandsMode is provided.
|
|
869
|
+
* @see melBandsMode for mode-based configuration
|
|
870
|
+
*/
|
|
871
|
+
melBands?: number;
|
|
872
|
+
/**
|
|
873
|
+
* Mel bands mode configuration.
|
|
874
|
+
* Takes precedence over melBands when both are provided.
|
|
875
|
+
* @default { mode: 'standard' }
|
|
876
|
+
*/
|
|
877
|
+
melBandsMode?: MelBandsConfig;
|
|
878
|
+
/** High-pass filter cutoff in Hz (default: 0.4) */
|
|
879
|
+
highPassCutoff?: number;
|
|
880
|
+
/**
|
|
881
|
+
* Gaussian smoothing window in ms (default: 20).
|
|
882
|
+
* Ignored if gaussianSmoothMode is provided.
|
|
883
|
+
* @see gaussianSmoothMode for mode-based configuration
|
|
884
|
+
*/
|
|
885
|
+
gaussianSmoothMs?: number;
|
|
886
|
+
/**
|
|
887
|
+
* Gaussian smooth mode configuration.
|
|
888
|
+
* Takes precedence over gaussianSmoothMs when both are provided.
|
|
889
|
+
* @default { mode: 'standard' }
|
|
890
|
+
*/
|
|
891
|
+
gaussianSmoothMode?: GaussianSmoothConfig;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Configuration for the BeatTracker (DP algorithm)
|
|
895
|
+
*/
|
|
896
|
+
export interface BeatTrackerConfig {
|
|
897
|
+
/** Ellis balance factor (default: 680) */
|
|
898
|
+
dpAlpha?: number;
|
|
899
|
+
/** Sensitivity multiplier (0.1-10, default: 1.0) */
|
|
900
|
+
sensitivity?: number;
|
|
901
|
+
/** Minimum predecessor ratio (default: 0.5 = τp/2) */
|
|
902
|
+
minPredecessorRatio?: number;
|
|
903
|
+
/** Maximum predecessor ratio (default: 2.0 = 2τp) */
|
|
904
|
+
maxPredecessorRatio?: number;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Configuration for the TempoDetector.
|
|
908
|
+
*
|
|
909
|
+
* Controls tempo estimation behavior including BPM range, perceptual weighting,
|
|
910
|
+
* and optional meter resolution algorithms.
|
|
911
|
+
*
|
|
912
|
+
* Key options:
|
|
913
|
+
* - `useOctaveResolution`: Enable TPS2 calculation to resolve duple meter ambiguity
|
|
914
|
+
* (half-tempo/double-tempo errors). Use for most 4/4, 2/4 music.
|
|
915
|
+
* - `useTripleMeter`: Enable TPS3 calculation to resolve triple meter ambiguity
|
|
916
|
+
* (3/4, 6/8 time signatures). Use for waltzes and shuffle feels.
|
|
917
|
+
*
|
|
918
|
+
* Both options can be enabled simultaneously - they run independently and each
|
|
919
|
+
* resolves its respective meter ambiguity.
|
|
920
|
+
*
|
|
921
|
+
* @see {@link https://eeewing.com/pubs/ismir2007.pdf} - Ellis 2007, "Beat Tracking by Dynamic Programming"
|
|
922
|
+
*/
|
|
923
|
+
export interface TempoDetectorConfig {
|
|
924
|
+
/** Tempo center in seconds (default: 0.5 = 120 BPM) */
|
|
925
|
+
tempoCenter?: number;
|
|
926
|
+
/** Tempo width in octaves (default: 1.4, or 0.9 for stricter) */
|
|
927
|
+
tempoWidth?: number;
|
|
928
|
+
/** Minimum BPM (default: 90) */
|
|
929
|
+
minBpm?: number;
|
|
930
|
+
/** Maximum BPM (default: 180) */
|
|
931
|
+
maxBpm?: number;
|
|
932
|
+
/**
|
|
933
|
+
* Whether to use TPS2 octave resolution to prevent half-tempo/double-tempo ambiguity.
|
|
934
|
+
*
|
|
935
|
+
* When enabled, uses the Ellis TPS2 calculation (Equation 7) to prefer tempos
|
|
936
|
+
* with strong half-period evidence, improving accuracy from 77% to 84%.
|
|
937
|
+
*
|
|
938
|
+
* This helps prevent the algorithm from locking onto 73 BPM when the true tempo
|
|
939
|
+
* is 146 BPM (octave error).
|
|
940
|
+
*
|
|
941
|
+
* Default: false (opt-in for now)
|
|
942
|
+
*/
|
|
943
|
+
useOctaveResolution?: boolean;
|
|
944
|
+
/**
|
|
945
|
+
* Whether to use TPS3 triple meter resolution for 3/4, 6/8 time signatures.
|
|
946
|
+
*
|
|
947
|
+
* When enabled, uses the Ellis TPS3 calculation (Equation 7 variant) to prefer tempos
|
|
948
|
+
* with strong third-period evidence, improving detection for waltzes and triple meter music.
|
|
949
|
+
*
|
|
950
|
+
* The TPS3 formula combines the main tempo with its third-harmonic:
|
|
951
|
+
* `TPS3(τ) = TPS(τ) + 0.33×TPS(3τ) + 0.33×TPS(3τ-1) + 0.33×TPS(3τ+1)`
|
|
952
|
+
*
|
|
953
|
+
* Tempos with strong third-period evidence (indicating triple meter) will have
|
|
954
|
+
* higher TPS3 scores, allowing proper beat detection for waltzes and 6/8 shuffles.
|
|
955
|
+
*
|
|
956
|
+
* Default: false (opt-in for triple meter music)
|
|
957
|
+
*/
|
|
958
|
+
useTripleMeter?: boolean;
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Progress information during beat map generation
|
|
962
|
+
*/
|
|
963
|
+
export interface BeatMapGenerationProgress {
|
|
964
|
+
/** Current phase of generation */
|
|
965
|
+
phase: 'loading' | 'preprocessing' | 'ose_calculation' | 'tempo_estimation' | 'beat_tracking' | 'measure_labeling' | 'finalizing' | 'complete' | 'error';
|
|
966
|
+
/** Progress percentage (0-100) */
|
|
967
|
+
progress: number;
|
|
968
|
+
/** Human-readable status message */
|
|
969
|
+
message: string;
|
|
970
|
+
/** Error message if phase is 'error' */
|
|
971
|
+
error?: string;
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Default values for BeatMapGeneratorOptions
|
|
975
|
+
*/
|
|
976
|
+
export declare const DEFAULT_BEATMAP_GENERATOR_OPTIONS: Required<BeatMapGeneratorOptions>;
|
|
977
|
+
/**
|
|
978
|
+
* Default values for BeatStreamOptions
|
|
979
|
+
*/
|
|
980
|
+
export declare const DEFAULT_BEATSTREAM_OPTIONS: Required<BeatStreamOptions>;
|
|
981
|
+
/**
|
|
982
|
+
* Default accuracy thresholds (Hard difficulty preset)
|
|
983
|
+
* Equivalent to HARD_ACCURACY_THRESHOLDS - use either constant
|
|
984
|
+
*/
|
|
985
|
+
export declare const BEAT_ACCURACY_THRESHOLDS: AccuracyThresholds;
|
|
986
|
+
/**
|
|
987
|
+
* Get accuracy thresholds for a difficulty preset
|
|
988
|
+
* @param preset - The difficulty preset ('easy', 'medium', 'hard', or 'custom')
|
|
989
|
+
* @returns The accuracy thresholds for the specified preset
|
|
990
|
+
* @note 'custom' preset returns hard thresholds as a base for customization
|
|
991
|
+
*/
|
|
992
|
+
export declare function getAccuracyThresholdsForPreset(preset: DifficultyPreset): AccuracyThresholds;
|
|
993
|
+
/**
|
|
994
|
+
* Result of validating accuracy thresholds
|
|
995
|
+
*/
|
|
996
|
+
export interface ThresholdValidationResult {
|
|
997
|
+
/** Whether the thresholds are valid */
|
|
998
|
+
valid: boolean;
|
|
999
|
+
/** List of validation error messages (empty if valid) */
|
|
1000
|
+
errors: string[];
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Source of a beat - whether it was detected by the algorithm or interpolated
|
|
1004
|
+
*/
|
|
1005
|
+
export type BeatSource = 'detected' | 'interpolated';
|
|
1006
|
+
/**
|
|
1007
|
+
* A beat with source information for interpolation
|
|
1008
|
+
*
|
|
1009
|
+
* Extends the base Beat interface with fields tracking the beat's origin
|
|
1010
|
+
* and relationship to detected beats.
|
|
1011
|
+
*/
|
|
1012
|
+
export interface BeatWithSource extends Beat {
|
|
1013
|
+
/** Whether this beat was detected or interpolated */
|
|
1014
|
+
source: BeatSource;
|
|
1015
|
+
/** Distance in seconds to the nearest detected beat (for interpolated beats) */
|
|
1016
|
+
distanceToAnchor?: number;
|
|
1017
|
+
/** Timestamp of the nearest detected beat (for interpolated beats) */
|
|
1018
|
+
nearestAnchorTimestamp?: number;
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Result of quarter note detection with dense section priority
|
|
1022
|
+
*
|
|
1023
|
+
* The quarter note interval is determined by analyzing beat intervals,
|
|
1024
|
+
* with higher weight given to intervals from dense sections (consecutive
|
|
1025
|
+
* beats at regular spacing).
|
|
1026
|
+
*/
|
|
1027
|
+
export interface QuarterNoteDetection {
|
|
1028
|
+
/** Detected quarter note duration in seconds */
|
|
1029
|
+
intervalSeconds: number;
|
|
1030
|
+
/** Equivalent BPM (60 / intervalSeconds) */
|
|
1031
|
+
bpm: number;
|
|
1032
|
+
/** Confidence in the detection (0-1) */
|
|
1033
|
+
confidence: number;
|
|
1034
|
+
/** Raw histogram peak value for the detected interval */
|
|
1035
|
+
histogramPeak: number;
|
|
1036
|
+
/** Other significant peaks (e.g., half-note = 2× quarter note) */
|
|
1037
|
+
secondaryPeaks: number[];
|
|
1038
|
+
/** Method used for detection */
|
|
1039
|
+
method: 'histogram' | 'kde' | 'tempo-detector-fallback';
|
|
1040
|
+
/** Number of dense sections that contributed to the detection */
|
|
1041
|
+
denseSectionCount: number;
|
|
1042
|
+
/** Total beats from dense sections used in the detection */
|
|
1043
|
+
denseSectionBeats: number;
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Analysis of gaps between detected beats
|
|
1047
|
+
*
|
|
1048
|
+
* Identifies missing beats and anomalies in the detected beat pattern.
|
|
1049
|
+
*/
|
|
1050
|
+
export interface GapAnalysis {
|
|
1051
|
+
/** Total number of gaps found between detected beats */
|
|
1052
|
+
totalGaps: number;
|
|
1053
|
+
/** Number of gaps that are exactly 2× quarter note (half-note gaps) */
|
|
1054
|
+
halfNoteGaps: number;
|
|
1055
|
+
/** Indices of beats that appear to be anomalies (false positives) */
|
|
1056
|
+
anomalies: number[];
|
|
1057
|
+
/** Average gap size in beats (1.0 = one quarter note) */
|
|
1058
|
+
avgGapSize: number;
|
|
1059
|
+
/** How well the detected beats align to the grid (0-1, higher is better) */
|
|
1060
|
+
gridAlignmentScore: number;
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Represents a distinct tempo section within a track
|
|
1064
|
+
*
|
|
1065
|
+
* When a track has multiple distinct tempo sections (e.g., a slow intro at 90 BPM
|
|
1066
|
+
* followed by a fast section at 140 BPM), each section is represented by this interface.
|
|
1067
|
+
*
|
|
1068
|
+
* Sections have hard boundaries - no morphing/blending between tempos.
|
|
1069
|
+
* This is only populated when multi-tempo analysis is enabled and detects multiple tempos.
|
|
1070
|
+
*/
|
|
1071
|
+
export interface TempoSection {
|
|
1072
|
+
/** Section start time in seconds */
|
|
1073
|
+
start: number;
|
|
1074
|
+
/** Section end time in seconds */
|
|
1075
|
+
end: number;
|
|
1076
|
+
/** Tempo for this section in BPM */
|
|
1077
|
+
bpm: number;
|
|
1078
|
+
/** Quarter note interval in seconds (60 / bpm) */
|
|
1079
|
+
intervalSeconds: number;
|
|
1080
|
+
/** Number of detected beats in this section's cluster */
|
|
1081
|
+
beatCount: number;
|
|
1082
|
+
/** Index of the first beat in this section */
|
|
1083
|
+
startBeatIndex: number;
|
|
1084
|
+
/** Index of the last beat in this section */
|
|
1085
|
+
endBeatIndex: number;
|
|
1086
|
+
}
|
|
1087
|
+
/**
|
|
1088
|
+
* Metadata about the interpolation process
|
|
1089
|
+
*/
|
|
1090
|
+
export interface InterpolationMetadata {
|
|
1091
|
+
/** Quarter note detection details */
|
|
1092
|
+
quarterNoteDetection: QuarterNoteDetection;
|
|
1093
|
+
/** Gap analysis results */
|
|
1094
|
+
gapAnalysis: GapAnalysis;
|
|
1095
|
+
/** Number of originally detected beats */
|
|
1096
|
+
detectedBeatCount: number;
|
|
1097
|
+
/** Number of beats added by interpolation */
|
|
1098
|
+
interpolatedBeatCount: number;
|
|
1099
|
+
/** Total beats in the merged output */
|
|
1100
|
+
totalBeatCount: number;
|
|
1101
|
+
/** Ratio of interpolated beats to total beats */
|
|
1102
|
+
interpolationRatio: number;
|
|
1103
|
+
/** Average confidence of interpolated beats */
|
|
1104
|
+
avgInterpolatedConfidence: number;
|
|
1105
|
+
/** Ratio of maximum local tempo to minimum local tempo (drift indicator) */
|
|
1106
|
+
tempoDriftRatio: number;
|
|
1107
|
+
/**
|
|
1108
|
+
* Tempos found during normal analysis (e.g., [128, 140])
|
|
1109
|
+
* Populated by normal analysis - cheap to compute
|
|
1110
|
+
*/
|
|
1111
|
+
detectedClusterTempos?: number[];
|
|
1112
|
+
/**
|
|
1113
|
+
* Quick flag for checking if multi-tempo re-analysis is available
|
|
1114
|
+
* True if detectedClusterTempos has more than one tempo
|
|
1115
|
+
*/
|
|
1116
|
+
hasMultipleTempos: boolean;
|
|
1117
|
+
/**
|
|
1118
|
+
* Full section data with boundaries
|
|
1119
|
+
* Only populated after multi-tempo re-analysis (enableMultiTempo: true)
|
|
1120
|
+
*/
|
|
1121
|
+
tempoSections?: TempoSection[];
|
|
1122
|
+
/**
|
|
1123
|
+
* True only after multi-tempo re-analysis completes
|
|
1124
|
+
* Used to distinguish between "detected multi-tempo" and "applied multi-tempo"
|
|
1125
|
+
*/
|
|
1126
|
+
hasMultiTempoApplied?: boolean;
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Complete interpolated beat map with two output streams
|
|
1130
|
+
*
|
|
1131
|
+
* Contains both the original detected beats and a merged stream that
|
|
1132
|
+
* includes interpolated beats to fill gaps.
|
|
1133
|
+
*/
|
|
1134
|
+
export interface InterpolatedBeatMap {
|
|
1135
|
+
/** Unique identifier for the audio source */
|
|
1136
|
+
audioId: string;
|
|
1137
|
+
/** Duration of the audio in seconds */
|
|
1138
|
+
duration: number;
|
|
1139
|
+
/** Original detected beats only (unchanged from BeatMap) */
|
|
1140
|
+
detectedBeats: Beat[];
|
|
1141
|
+
/** Interpolated beats with detected beats overriding at same positions */
|
|
1142
|
+
mergedBeats: BeatWithSource[];
|
|
1143
|
+
/** Detected quarter note interval in seconds */
|
|
1144
|
+
quarterNoteInterval: number;
|
|
1145
|
+
/** Equivalent BPM for the quarter note */
|
|
1146
|
+
quarterNoteBpm: number;
|
|
1147
|
+
/** Confidence in the quarter note detection */
|
|
1148
|
+
quarterNoteConfidence: number;
|
|
1149
|
+
/** Metadata from the original BeatMap */
|
|
1150
|
+
originalMetadata: BeatMapMetadata;
|
|
1151
|
+
/** Metadata about the interpolation process */
|
|
1152
|
+
interpolationMetadata: InterpolationMetadata;
|
|
1153
|
+
/**
|
|
1154
|
+
* The downbeat configuration inherited from the original BeatMap
|
|
1155
|
+
* Used for subdivision to determine measure boundaries
|
|
1156
|
+
*/
|
|
1157
|
+
downbeatConfig?: DownbeatConfig;
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Options for beat interpolation
|
|
1161
|
+
*
|
|
1162
|
+
* Controls how the interpolation algorithm generates the beat grid.
|
|
1163
|
+
* Uses the Adaptive Phase-Locked Grid algorithm for beat interpolation.
|
|
1164
|
+
*/
|
|
1165
|
+
export interface BeatInterpolationOptions {
|
|
1166
|
+
/** Minimum confidence for a beat to be used as an anchor (default: 0.3) */
|
|
1167
|
+
minAnchorConfidence?: number;
|
|
1168
|
+
/** Tolerance in seconds for snapping detected beats to grid (default: 0.05) */
|
|
1169
|
+
gridSnapTolerance?: number;
|
|
1170
|
+
/**
|
|
1171
|
+
* Rate of tempo adaptation at anchor points (0-1, default: 0.3)
|
|
1172
|
+
* 0 = fixed tempo, 1 = full adaptation to each anchor
|
|
1173
|
+
*/
|
|
1174
|
+
tempoAdaptationRate?: number;
|
|
1175
|
+
/** Whether to extrapolate grid before first detected beat (default: true) */
|
|
1176
|
+
extrapolateStart?: boolean;
|
|
1177
|
+
/** Whether to extrapolate grid after last detected beat (default: true) */
|
|
1178
|
+
extrapolateEnd?: boolean;
|
|
1179
|
+
/**
|
|
1180
|
+
* Multiplier for anomaly detection (default: 0.4)
|
|
1181
|
+
* Intervals < (1 - threshold) × QN or > (1 + threshold) × QN are flagged
|
|
1182
|
+
*/
|
|
1183
|
+
anomalyThreshold?: number;
|
|
1184
|
+
/** Minimum beats to count as a dense section (default: 3) */
|
|
1185
|
+
denseSectionMinBeats?: number;
|
|
1186
|
+
/** Weight for grid alignment in confidence calculation (default: 0.5) */
|
|
1187
|
+
gridAlignmentWeight?: number;
|
|
1188
|
+
/** Weight for anchor confidence in confidence calculation (default: 0.3) */
|
|
1189
|
+
anchorConfidenceWeight?: number;
|
|
1190
|
+
/** Weight for pace confidence in confidence calculation (default: 0.2) */
|
|
1191
|
+
paceConfidenceWeight?: number;
|
|
1192
|
+
/**
|
|
1193
|
+
* Tempo difference threshold for section detection (default: 0.1 = 10%)
|
|
1194
|
+
* Two tempos must differ by more than this ratio to be considered separate sections
|
|
1195
|
+
*/
|
|
1196
|
+
tempoSectionThreshold?: number;
|
|
1197
|
+
/**
|
|
1198
|
+
* Minimum beats for a valid tempo cluster (default: 4)
|
|
1199
|
+
* Clusters with fewer beats are not considered for multi-tempo detection
|
|
1200
|
+
*/
|
|
1201
|
+
minClusterBeats?: number;
|
|
1202
|
+
/**
|
|
1203
|
+
* Enable multi-tempo analysis and interpolation (default: false)
|
|
1204
|
+
* If true and hasMultipleTempos is detected, runs crossing paths analysis
|
|
1205
|
+
* and applies per-section interpolation
|
|
1206
|
+
*/
|
|
1207
|
+
enableMultiTempo?: boolean;
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* Default values for BeatInterpolationOptions
|
|
1211
|
+
*/
|
|
1212
|
+
export declare const DEFAULT_BEAT_INTERPOLATION_OPTIONS: Required<BeatInterpolationOptions>;
|
|
1213
|
+
/**
|
|
1214
|
+
* Validate accuracy thresholds for correctness
|
|
1215
|
+
*
|
|
1216
|
+
* Checks that:
|
|
1217
|
+
* - All provided threshold values are positive numbers
|
|
1218
|
+
* - Thresholds are in ascending order (perfect < great < good < ok)
|
|
1219
|
+
*
|
|
1220
|
+
* @param thresholds - The thresholds to validate (can be partial)
|
|
1221
|
+
* @returns Validation result with detailed error messages
|
|
1222
|
+
*
|
|
1223
|
+
* @example
|
|
1224
|
+
* ```typescript
|
|
1225
|
+
* // Valid thresholds
|
|
1226
|
+
* const result = validateThresholds({ perfect: 0.05, great: 0.1, good: 0.15, ok: 0.2 });
|
|
1227
|
+
* console.log(result.valid); // true
|
|
1228
|
+
*
|
|
1229
|
+
* // Invalid thresholds (not ascending)
|
|
1230
|
+
* const invalid = validateThresholds({ perfect: 0.1, great: 0.05 });
|
|
1231
|
+
* console.log(invalid.valid); // false
|
|
1232
|
+
* console.log(invalid.errors); // ['great (0.05) must be greater than perfect (0.1)']
|
|
1233
|
+
* ```
|
|
1234
|
+
*/
|
|
1235
|
+
export declare function validateThresholds(thresholds: Partial<AccuracyThresholds>): ThresholdValidationResult;
|
|
1236
|
+
/**
|
|
1237
|
+
* Types of beat subdivision
|
|
1238
|
+
*
|
|
1239
|
+
* - quarter: Default, 1x density (unchanged)
|
|
1240
|
+
* - half: 0.5x density (beats on 1 and 3 only)
|
|
1241
|
+
* - eighth: 2x density (beat between each quarter)
|
|
1242
|
+
* - sixteenth: 4x density (3 beats between each quarter) - MAXIMUM DENSITY
|
|
1243
|
+
* - triplet8: Eighth triplets (3 beats per quarter note)
|
|
1244
|
+
* - triplet4: Quarter triplets (3 beats per half note)
|
|
1245
|
+
* - dotted4: Dotted quarter (keeps every 3rd beat: positions 0, 3, 6...)
|
|
1246
|
+
* - dotted8: Dotted eighth (beat at 3/4 between quarters - 3:1 long-short ratio)
|
|
1247
|
+
* - swing: Swing feel (beat at 2/3 between quarters - 2:1 long-short ratio)
|
|
1248
|
+
* - offbeat8: 8th rest + 8th note (skips original beat, adds beat at 0.5)
|
|
1249
|
+
* - rest: 0x density (no beats generated - used for gaps in rhythm patterns)
|
|
1250
|
+
*
|
|
1251
|
+
* Note: Sixteenth notes (4x) are the maximum supported density.
|
|
1252
|
+
* Higher densities are not supported and will throw an error.
|
|
1253
|
+
*/
|
|
1254
|
+
export type SubdivisionType = 'quarter' | 'half' | 'eighth' | 'sixteenth' | 'triplet8' | 'triplet4' | 'dotted4' | 'dotted8' | 'swing' | 'offbeat8' | 'rest';
|
|
1255
|
+
/**
|
|
1256
|
+
* Subdivision configuration for rhythm pattern generation
|
|
1257
|
+
*
|
|
1258
|
+
* This configuration allows each beat to have its own subdivision type,
|
|
1259
|
+
* enabling fine-grained control for creating complex rhythmic phrases.
|
|
1260
|
+
* Uses a sparse Map for efficient storage - beats not in the map use
|
|
1261
|
+
* the default subdivision.
|
|
1262
|
+
*
|
|
1263
|
+
* @example
|
|
1264
|
+
* ```typescript
|
|
1265
|
+
* // Create a rhythm phrase with varying subdivisions
|
|
1266
|
+
* const config: SubdivisionConfig = {
|
|
1267
|
+
* beatSubdivisions: new Map([
|
|
1268
|
+
* [0, 'quarter'], // Beat 0: quarter note
|
|
1269
|
+
* [1, 'eighth'], // Beat 1: eighth notes
|
|
1270
|
+
* [2, 'eighth'], // Beat 2: eighth notes
|
|
1271
|
+
* [3, 'quarter'], // Beat 3: quarter note
|
|
1272
|
+
* ]),
|
|
1273
|
+
* defaultSubdivision: 'quarter',
|
|
1274
|
+
* };
|
|
1275
|
+
*
|
|
1276
|
+
* // Sparse representation - only specify beats that differ from default
|
|
1277
|
+
* const sparseConfig: SubdivisionConfig = {
|
|
1278
|
+
* beatSubdivisions: new Map([
|
|
1279
|
+
* [4, 'triplet8'], // Only beat 4 uses triplets
|
|
1280
|
+
* [8, 'triplet8'], // Only beat 8 uses triplets
|
|
1281
|
+
* ]),
|
|
1282
|
+
* defaultSubdivision: 'quarter', // All other beats are quarter notes
|
|
1283
|
+
* };
|
|
1284
|
+
*
|
|
1285
|
+
* // Create gaps in rhythm using 'rest'
|
|
1286
|
+
* const configWithRests: SubdivisionConfig = {
|
|
1287
|
+
* beatSubdivisions: new Map([
|
|
1288
|
+
* [0, 'quarter'], // Beat 0: quarter note
|
|
1289
|
+
* [1, 'rest'], // Beat 1: no beat (rest)
|
|
1290
|
+
* [2, 'eighth'], // Beat 2: eighth notes
|
|
1291
|
+
* [3, 'rest'], // Beat 3: no beat (rest)
|
|
1292
|
+
* ]),
|
|
1293
|
+
* defaultSubdivision: 'quarter',
|
|
1294
|
+
* };
|
|
1295
|
+
* ```
|
|
1296
|
+
*/
|
|
1297
|
+
export interface SubdivisionConfig {
|
|
1298
|
+
/**
|
|
1299
|
+
* Subdivision type for each beat index (sparse).
|
|
1300
|
+
* Beats not in this map use the defaultSubdivision.
|
|
1301
|
+
* Key: beat index (0-based), Value: subdivision type
|
|
1302
|
+
*/
|
|
1303
|
+
beatSubdivisions: Map<number, SubdivisionType>;
|
|
1304
|
+
/** Default subdivision for beats not in the beatSubdivisions map */
|
|
1305
|
+
defaultSubdivision: SubdivisionType;
|
|
1306
|
+
}
|
|
1307
|
+
/** JSON-serializable version of SubdivisionConfig */
|
|
1308
|
+
export interface SubdivisionConfigJSON {
|
|
1309
|
+
/** Subdivision assignments as array of [beatIndex, subdivisionType] tuples */
|
|
1310
|
+
beatSubdivisions: [number, SubdivisionType][];
|
|
1311
|
+
/** Default subdivision for beats not in the beatSubdivisions array */
|
|
1312
|
+
defaultSubdivision: SubdivisionType;
|
|
1313
|
+
}
|
|
1314
|
+
/** Default subdivision config (quarter notes throughout) */
|
|
1315
|
+
export declare const DEFAULT_SUBDIVISION_CONFIG: SubdivisionConfig;
|
|
1316
|
+
/**
|
|
1317
|
+
* A unified beat map with detected + interpolated beats merged
|
|
1318
|
+
*
|
|
1319
|
+
* This is the foundation for subdivision. All beats are treated equally
|
|
1320
|
+
* regardless of whether they were originally detected or interpolated.
|
|
1321
|
+
* Detected beats are flagged for accent/rhythm pattern use.
|
|
1322
|
+
*
|
|
1323
|
+
* Created from an InterpolatedBeatMap by the unifyBeatMap() utility.
|
|
1324
|
+
*
|
|
1325
|
+
* @example
|
|
1326
|
+
* ```typescript
|
|
1327
|
+
* import { BeatMapGenerator, BeatInterpolator, unifyBeatMap } from 'playlist-data-engine';
|
|
1328
|
+
*
|
|
1329
|
+
* // Generate and interpolate beat map
|
|
1330
|
+
* const beatMap = await generator.generateBeatMap('song.mp3', 'track-1');
|
|
1331
|
+
* const interpolatedMap = interpolator.interpolate(beatMap);
|
|
1332
|
+
*
|
|
1333
|
+
* // Create unified beat map (foundation for subdivision)
|
|
1334
|
+
* const unifiedMap = unifyBeatMap(interpolatedMap);
|
|
1335
|
+
*
|
|
1336
|
+
* // Access detected beats for accent patterns
|
|
1337
|
+
* const detectedBeats = unifiedMap.beats.filter((_, i) =>
|
|
1338
|
+
* unifiedMap.detectedBeatIndices.includes(i)
|
|
1339
|
+
* );
|
|
1340
|
+
* ```
|
|
1341
|
+
*/
|
|
1342
|
+
export interface UnifiedBeatMap {
|
|
1343
|
+
/** Unique identifier for the audio source */
|
|
1344
|
+
audioId: string;
|
|
1345
|
+
/** Duration of the audio in seconds */
|
|
1346
|
+
duration: number;
|
|
1347
|
+
/** All beats (detected + interpolated) as a single unified list */
|
|
1348
|
+
beats: Beat[];
|
|
1349
|
+
/** Indices of beats that were originally detected (for accent lookup) */
|
|
1350
|
+
detectedBeatIndices: number[];
|
|
1351
|
+
/** Quarter note interval in seconds (primary tempo) */
|
|
1352
|
+
quarterNoteInterval: number;
|
|
1353
|
+
/** Equivalent BPM for the quarter note (primary tempo) */
|
|
1354
|
+
quarterNoteBpm: number;
|
|
1355
|
+
/** The downbeat configuration inherited from interpolation */
|
|
1356
|
+
downbeatConfig: DownbeatConfig;
|
|
1357
|
+
/** Tempo sections for multi-tempo support (from InterpolationMetadata) */
|
|
1358
|
+
tempoSections?: TempoSection[];
|
|
1359
|
+
/** Metadata from the original beat map */
|
|
1360
|
+
originalMetadata: BeatMapMetadata;
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* A beat in a subdivided beat map
|
|
1364
|
+
*
|
|
1365
|
+
* Note: beatInMeasure is a DECIMAL in SubdividedBeat (e.g., 0.5, 1.25, 2.75)
|
|
1366
|
+
* while the base Beat interface uses integers. This allows for positions
|
|
1367
|
+
* like "the 'and' of beat 1" (1.5) or swing patterns.
|
|
1368
|
+
*
|
|
1369
|
+
* @example
|
|
1370
|
+
* ```typescript
|
|
1371
|
+
* // Eighth note positions in 4/4 time
|
|
1372
|
+
* // beatInMeasure values: 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5
|
|
1373
|
+
*
|
|
1374
|
+
* // Triplet positions in 4/4 time
|
|
1375
|
+
* // beatInMeasure values: 0, 0.33, 0.66, 1, 1.33, 1.66...
|
|
1376
|
+
*
|
|
1377
|
+
* // Check if a beat was originally detected
|
|
1378
|
+
* if (beat.isDetected) {
|
|
1379
|
+
* // Use for accent patterns
|
|
1380
|
+
* playAccentSound(beat);
|
|
1381
|
+
* }
|
|
1382
|
+
*
|
|
1383
|
+
* // Get original position before subdivision
|
|
1384
|
+
* const originalIndex = beat.originalBeatIndex; // undefined for generated beats
|
|
1385
|
+
* ```
|
|
1386
|
+
*/
|
|
1387
|
+
export interface SubdividedBeat extends Beat {
|
|
1388
|
+
/** Position within the measure as a decimal (e.g., 0, 0.5, 1, 1.5 for eighth notes) */
|
|
1389
|
+
beatInMeasure: number;
|
|
1390
|
+
/** Whether this beat was originally detected (vs interpolated or subdivision-generated) */
|
|
1391
|
+
isDetected: boolean;
|
|
1392
|
+
/** Index of the original beat in the UnifiedBeatMap (input to subdivider) */
|
|
1393
|
+
originalBeatIndex?: number;
|
|
1394
|
+
/** The subdivision type that created this beat */
|
|
1395
|
+
subdivisionType: SubdivisionType;
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Metadata about the subdivision process
|
|
1399
|
+
*
|
|
1400
|
+
* @example
|
|
1401
|
+
* ```typescript
|
|
1402
|
+
* const metadata = subdividedMap.subdivisionMetadata;
|
|
1403
|
+
*
|
|
1404
|
+
* console.log(`Original beats: ${metadata.originalBeatCount}`);
|
|
1405
|
+
* console.log(`Subdivided beats: ${metadata.subdividedBeatCount}`);
|
|
1406
|
+
* console.log(`Density multiplier: ${metadata.averageDensityMultiplier}x`);
|
|
1407
|
+
* console.log(`Subdivisions used: ${metadata.subdivisionsUsed.join(', ')}`);
|
|
1408
|
+
* console.log(`Has tempo changes: ${metadata.hasMultipleTempos}`);
|
|
1409
|
+
* console.log(`Max density: ${metadata.maxDensity}x`);
|
|
1410
|
+
* ```
|
|
1411
|
+
*/
|
|
1412
|
+
export interface SubdivisionMetadata {
|
|
1413
|
+
/** Number of beats in the original unified map */
|
|
1414
|
+
originalBeatCount: number;
|
|
1415
|
+
/** Number of beats after subdivision */
|
|
1416
|
+
subdividedBeatCount: number;
|
|
1417
|
+
/** Overall density multiplier (2.0 = twice as many beats) */
|
|
1418
|
+
averageDensityMultiplier: number;
|
|
1419
|
+
/** Number of beats with explicit non-default subdivision */
|
|
1420
|
+
explicitBeatCount: number;
|
|
1421
|
+
/** Subdivision types used */
|
|
1422
|
+
subdivisionsUsed: SubdivisionType[];
|
|
1423
|
+
/** Whether the track has multiple tempo sections */
|
|
1424
|
+
hasMultipleTempos: boolean;
|
|
1425
|
+
/** Maximum density encountered (for validation against limit) */
|
|
1426
|
+
maxDensity: number;
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* A beat map with subdivision applied
|
|
1430
|
+
*
|
|
1431
|
+
* The beat grid has been transformed according to the subdivision config,
|
|
1432
|
+
* which may add beats (eighth, sixteenth, triplets), remove beats (half),
|
|
1433
|
+
* or reposition beats (dotted patterns).
|
|
1434
|
+
*
|
|
1435
|
+
* @example
|
|
1436
|
+
* ```typescript
|
|
1437
|
+
* import { BeatSubdivider, unifyBeatMap } from 'playlist-data-engine';
|
|
1438
|
+
*
|
|
1439
|
+
* const subdivider = new BeatSubdivider();
|
|
1440
|
+
* const unifiedMap = unifyBeatMap(interpolatedMap);
|
|
1441
|
+
*
|
|
1442
|
+
* // Apply subdivision
|
|
1443
|
+
* const subdividedMap = subdivider.subdivide(unifiedMap, {
|
|
1444
|
+
* beatSubdivisions: new Map(),
|
|
1445
|
+
* defaultSubdivision: 'eighth',
|
|
1446
|
+
* });
|
|
1447
|
+
*
|
|
1448
|
+
* // Access subdivision results
|
|
1449
|
+
* console.log(`Original beats: ${subdividedMap.subdivisionMetadata.originalBeatCount}`);
|
|
1450
|
+
* console.log(`Subdivided beats: ${subdividedMap.subdivisionMetadata.subdividedBeatCount}`);
|
|
1451
|
+
* console.log(`Density multiplier: ${subdividedMap.subdivisionMetadata.averageDensityMultiplier}`);
|
|
1452
|
+
*
|
|
1453
|
+
* // Filter beats by type
|
|
1454
|
+
* const detectedBeats = subdividedMap.beats.filter(b => b.isDetected);
|
|
1455
|
+
* ```
|
|
1456
|
+
*/
|
|
1457
|
+
export interface SubdividedBeatMap {
|
|
1458
|
+
/** Unique identifier for the audio source */
|
|
1459
|
+
audioId: string;
|
|
1460
|
+
/** Duration of the audio in seconds */
|
|
1461
|
+
duration: number;
|
|
1462
|
+
/** Beats after subdivision applied */
|
|
1463
|
+
beats: SubdividedBeat[];
|
|
1464
|
+
/** Indices of beats that were originally detected (for accent lookup) */
|
|
1465
|
+
detectedBeatIndices: number[];
|
|
1466
|
+
/** The subdivision configuration used */
|
|
1467
|
+
subdivisionConfig: SubdivisionConfig;
|
|
1468
|
+
/** The downbeat configuration inherited from UnifiedBeatMap (preserved unchanged) */
|
|
1469
|
+
downbeatConfig: DownbeatConfig;
|
|
1470
|
+
/** Tempo sections inherited from UnifiedBeatMap (for reference) */
|
|
1471
|
+
tempoSections?: TempoSection[];
|
|
1472
|
+
/** Metadata about the subdivision process */
|
|
1473
|
+
subdivisionMetadata: SubdivisionMetadata;
|
|
1474
|
+
}
|
|
1475
|
+
/** Maximum density multiplier (sixteenth notes = 4x) */
|
|
1476
|
+
export declare const MAX_SUBDIVISION_DENSITY = 4;
|
|
1477
|
+
/** All valid subdivision type values */
|
|
1478
|
+
export declare const VALID_SUBDIVISION_TYPES: SubdivisionType[];
|
|
1479
|
+
/**
|
|
1480
|
+
* Check if a value is a valid SubdivisionType
|
|
1481
|
+
*
|
|
1482
|
+
* @param value - The value to check
|
|
1483
|
+
* @returns true if the value is a valid SubdivisionType
|
|
1484
|
+
*/
|
|
1485
|
+
export declare function isValidSubdivisionType(value: unknown): value is SubdivisionType;
|
|
1486
|
+
/**
|
|
1487
|
+
* Get the density multiplier for a subdivision type
|
|
1488
|
+
*
|
|
1489
|
+
* @param subdivision - The subdivision type
|
|
1490
|
+
* @returns The density multiplier (e.g., 2 for eighth notes, 4 for sixteenth notes)
|
|
1491
|
+
*/
|
|
1492
|
+
export declare function getSubdivisionDensity(subdivision: SubdivisionType): number;
|
|
1493
|
+
/**
|
|
1494
|
+
* Validate subdivision configuration (structural validation only)
|
|
1495
|
+
*
|
|
1496
|
+
* This validates:
|
|
1497
|
+
* - beatSubdivisions is a Map
|
|
1498
|
+
* - All subdivision types in the map are valid
|
|
1499
|
+
* - defaultSubdivision is a valid subdivision type
|
|
1500
|
+
*
|
|
1501
|
+
* @param config - The subdivision configuration to validate
|
|
1502
|
+
* @throws Error if configuration is invalid
|
|
1503
|
+
*/
|
|
1504
|
+
export declare function validateSubdivisionConfig(config: SubdivisionConfig): void;
|
|
1505
|
+
/**
|
|
1506
|
+
* Validate subdivision config against actual beat count
|
|
1507
|
+
*
|
|
1508
|
+
* This validates:
|
|
1509
|
+
* - Beat indices in beatSubdivisions don't exceed total beat count
|
|
1510
|
+
*
|
|
1511
|
+
* Note: Beat indices beyond the beat count are no-ops (they just won't apply).
|
|
1512
|
+
*
|
|
1513
|
+
* @param config - The subdivision configuration to validate
|
|
1514
|
+
* @param totalBeats - The total number of beats in the unified beat map
|
|
1515
|
+
* @throws Error if beat index configuration is invalid
|
|
1516
|
+
*/
|
|
1517
|
+
export declare function validateSubdivisionConfigAgainstBeats(config: SubdivisionConfig, totalBeats: number): void;
|
|
1518
|
+
/**
|
|
1519
|
+
* Validate that subdivision density does not exceed maximum
|
|
1520
|
+
*
|
|
1521
|
+
* This validates that the requested subdivision doesn't exceed the
|
|
1522
|
+
* maximum supported density (sixteenth notes = 4x).
|
|
1523
|
+
*
|
|
1524
|
+
* @param subdivision - The subdivision type to validate
|
|
1525
|
+
* @throws Error if subdivision exceeds maximum density
|
|
1526
|
+
*/
|
|
1527
|
+
export declare function validateSubdivisionDensity(subdivision: SubdivisionType): void;
|
|
1528
|
+
/**
|
|
1529
|
+
* Transition mode for subdivision changes during playback
|
|
1530
|
+
*
|
|
1531
|
+
* - 'immediate': Switch subdivision instantly at the current position
|
|
1532
|
+
* - 'next-downbeat': Wait for the next downbeat before switching
|
|
1533
|
+
* - 'next-measure': Wait for the next measure before switching
|
|
1534
|
+
*/
|
|
1535
|
+
export type SubdivisionTransitionMode = 'immediate' | 'next-downbeat' | 'next-measure';
|
|
1536
|
+
/**
|
|
1537
|
+
* Options for the SubdivisionPlaybackController
|
|
1538
|
+
*
|
|
1539
|
+
* @example
|
|
1540
|
+
* ```typescript
|
|
1541
|
+
* const controller = new SubdivisionPlaybackController(unifiedMap, audioContext, {
|
|
1542
|
+
* initialSubdivision: 'quarter',
|
|
1543
|
+
* transitionMode: 'next-downbeat',
|
|
1544
|
+
* anticipationTime: 2.0,
|
|
1545
|
+
* onSubdivisionChange: (oldType, newType) => {
|
|
1546
|
+
* console.log(`Switched from ${oldType} to ${newType}`);
|
|
1547
|
+
* },
|
|
1548
|
+
* });
|
|
1549
|
+
* ```
|
|
1550
|
+
*/
|
|
1551
|
+
export interface SubdivisionPlaybackOptions {
|
|
1552
|
+
/** Starting subdivision type (default: 'quarter') */
|
|
1553
|
+
initialSubdivision?: SubdivisionType;
|
|
1554
|
+
/** How to handle subdivision changes (default: 'immediate') */
|
|
1555
|
+
transitionMode?: SubdivisionTransitionMode;
|
|
1556
|
+
/** Callback when subdivision changes */
|
|
1557
|
+
onSubdivisionChange?: (oldType: SubdivisionType, newType: SubdivisionType) => void;
|
|
1558
|
+
/** Anticipation time for beat events in seconds (default: 2.0) */
|
|
1559
|
+
anticipationTime?: number;
|
|
1560
|
+
/** Timing tolerance for beat event detection in seconds (default: 0.01) */
|
|
1561
|
+
timingTolerance?: number;
|
|
1562
|
+
/** User-calibrated offset in milliseconds (default: 0) */
|
|
1563
|
+
userOffsetMs?: number;
|
|
1564
|
+
/** Whether to compensate for output latency (default: true) */
|
|
1565
|
+
compensateOutputLatency?: boolean;
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Default options for SubdivisionPlaybackController
|
|
1569
|
+
*/
|
|
1570
|
+
export declare const DEFAULT_SUBDIVISION_PLAYBACK_OPTIONS: Required<SubdivisionPlaybackOptions>;
|
|
1571
|
+
/**
|
|
1572
|
+
* Event emitted by the SubdivisionPlaybackController during playback
|
|
1573
|
+
*
|
|
1574
|
+
* @example
|
|
1575
|
+
* ```typescript
|
|
1576
|
+
* controller.subscribe((event) => {
|
|
1577
|
+
* console.log(`Beat at ${event.beat.timestamp}s, subdivision: ${event.currentSubdivision}`);
|
|
1578
|
+
* console.log(`Time until beat: ${event.timeUntilBeat}s`);
|
|
1579
|
+
* });
|
|
1580
|
+
* ```
|
|
1581
|
+
*/
|
|
1582
|
+
export interface SubdivisionBeatEvent {
|
|
1583
|
+
/** The beat this event relates to */
|
|
1584
|
+
beat: SubdividedBeat;
|
|
1585
|
+
/** Current subdivision type being used */
|
|
1586
|
+
currentSubdivision: SubdivisionType;
|
|
1587
|
+
/** Time until the beat occurs (negative if passed) */
|
|
1588
|
+
timeUntilBeat: number;
|
|
1589
|
+
/** Current audio context time in seconds */
|
|
1590
|
+
audioTime: number;
|
|
1591
|
+
/** Type of event: 'upcoming', 'exact', or 'passed' */
|
|
1592
|
+
type: BeatEventType;
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* Callback function type for SubdivisionPlaybackController subscriptions
|
|
1596
|
+
*/
|
|
1597
|
+
export type SubdivisionCallback = (event: SubdivisionBeatEvent) => void;
|
|
1598
|
+
/**
|
|
1599
|
+
* Current version of the beat detection algorithm
|
|
1600
|
+
*/
|
|
1601
|
+
export declare const BEAT_DETECTION_VERSION = "1.0.0";
|
|
1602
|
+
/**
|
|
1603
|
+
* Algorithm identifier for the Ellis DP beat tracker
|
|
1604
|
+
*/
|
|
1605
|
+
export declare const BEAT_DETECTION_ALGORITHM = "ellis-dp-v1";
|
|
1606
|
+
/**
|
|
1607
|
+
* Groove tier representing the player's current groove intensity level.
|
|
1608
|
+
*
|
|
1609
|
+
* Tiers are determined by hotness value:
|
|
1610
|
+
* - D: 0-33 (starting groove)
|
|
1611
|
+
* - C: 33-66 (building momentum)
|
|
1612
|
+
* - B: 66-100 (solid groove)
|
|
1613
|
+
* - A: 100-150 (locked in)
|
|
1614
|
+
* - S: 150-200 (exceptional)
|
|
1615
|
+
* - SS: 200+ (legendary)
|
|
1616
|
+
*/
|
|
1617
|
+
export type GrooveTier = 'D' | 'C' | 'B' | 'A' | 'S' | 'SS' | 'Platinum';
|
|
1618
|
+
/**
|
|
1619
|
+
* Configuration for a single groove tier.
|
|
1620
|
+
*/
|
|
1621
|
+
export interface GrooveTierConfig {
|
|
1622
|
+
/** Tier name/label */
|
|
1623
|
+
tier: GrooveTier;
|
|
1624
|
+
/** Minimum hotness for this tier (inclusive) */
|
|
1625
|
+
minHotness: number;
|
|
1626
|
+
/** Maximum hotness for this tier (exclusive, except for SS which has no max) */
|
|
1627
|
+
maxHotness: number;
|
|
1628
|
+
/** Pocket window size in milliseconds at this tier */
|
|
1629
|
+
windowMs: number;
|
|
1630
|
+
}
|
|
1631
|
+
/**
|
|
1632
|
+
* Groove tier configurations with thresholds and window sizes.
|
|
1633
|
+
*
|
|
1634
|
+
* Window sizes represent the pocket tolerance at each tier:
|
|
1635
|
+
* - Lower tier = more forgiving (larger window)
|
|
1636
|
+
* - Higher tier = more demanding (smaller window)
|
|
1637
|
+
*
|
|
1638
|
+
* The window continues to shrink as you climb tiers, making it progressively
|
|
1639
|
+
* harder to maintain your groove.
|
|
1640
|
+
*/
|
|
1641
|
+
export declare const GROOVE_TIERS: GrooveTierConfig[];
|
|
1642
|
+
/**
|
|
1643
|
+
* Get the groove tier for a given hotness value.
|
|
1644
|
+
*
|
|
1645
|
+
* @param hotness - Current hotness value (can exceed 100)
|
|
1646
|
+
* @returns The groove tier (D, C, B, A, S, SS, or Platinum)
|
|
1647
|
+
*/
|
|
1648
|
+
export declare function getGrooveTier(hotness: number): GrooveTier;
|
|
1649
|
+
/**
|
|
1650
|
+
* Get the pocket window size in milliseconds for a given hotness value.
|
|
1651
|
+
*
|
|
1652
|
+
* Uses linear interpolation within each tier for smooth transitions.
|
|
1653
|
+
*
|
|
1654
|
+
* @param hotness - Current hotness value
|
|
1655
|
+
* @returns Pocket window size in milliseconds
|
|
1656
|
+
*/
|
|
1657
|
+
export declare function getGrooveWindowMs(hotness: number): number;
|
|
1658
|
+
/**
|
|
1659
|
+
* Get the minimum hotness required for a specific tier.
|
|
1660
|
+
*
|
|
1661
|
+
* @param tier - The groove tier
|
|
1662
|
+
* @returns Minimum hotness required for that tier
|
|
1663
|
+
*/
|
|
1664
|
+
export declare function getMinHotnessForTier(tier: GrooveTier): number;
|
|
1665
|
+
/**
|
|
1666
|
+
* Direction of the established pocket relative to the beat
|
|
1667
|
+
*
|
|
1668
|
+
* - 'push': Playing ahead of the beat (rushing, negative offset)
|
|
1669
|
+
* - 'pull': Playing behind the beat (dragging, positive offset)
|
|
1670
|
+
* - 'neutral': Playing on the beat (within ±10ms dead zone)
|
|
1671
|
+
*/
|
|
1672
|
+
export type GrooveDirection = 'push' | 'pull' | 'neutral';
|
|
1673
|
+
/**
|
|
1674
|
+
* Result returned after each hit recorded by the GrooveAnalyzer
|
|
1675
|
+
*
|
|
1676
|
+
* Provides all information needed for UI display and game feedback.
|
|
1677
|
+
*/
|
|
1678
|
+
export interface GrooveResult {
|
|
1679
|
+
/** Direction of current pocket */
|
|
1680
|
+
pocketDirection: GrooveDirection;
|
|
1681
|
+
/** Running average offset in seconds (established pocket center) */
|
|
1682
|
+
establishedOffset: number;
|
|
1683
|
+
/** How close this hit was to the pocket (0-1, 1 = perfect consistency) */
|
|
1684
|
+
consistency: number;
|
|
1685
|
+
/** Current hotness/meter value (0+, can exceed 100 for higher tiers) */
|
|
1686
|
+
hotness: number;
|
|
1687
|
+
/** Current groove tier based on hotness (D, C, B, A, S, or SS) */
|
|
1688
|
+
tier: GrooveTier;
|
|
1689
|
+
/** Current streak length within pocket */
|
|
1690
|
+
streakLength: number;
|
|
1691
|
+
/** Whether this hit was in the pocket window */
|
|
1692
|
+
inPocket: boolean;
|
|
1693
|
+
/** Current pocket window size in seconds (changes with tier) */
|
|
1694
|
+
pocketWindow: number;
|
|
1695
|
+
/**
|
|
1696
|
+
* Stats from the groove that just ended (if any).
|
|
1697
|
+
* Present when hotness drops to 0 or direction changes (push↔pull).
|
|
1698
|
+
* Use this to calculate groove end bonus XP immediately.
|
|
1699
|
+
*/
|
|
1700
|
+
endedGrooveStats?: {
|
|
1701
|
+
maxStreak: number;
|
|
1702
|
+
maxHotness: number;
|
|
1703
|
+
avgHotness: number;
|
|
1704
|
+
duration: number;
|
|
1705
|
+
totalHits: number;
|
|
1706
|
+
startTime: number;
|
|
1707
|
+
endTime: number;
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
/**
|
|
1711
|
+
* Snapshot of current groove analyzer state
|
|
1712
|
+
*
|
|
1713
|
+
* Used for UI display and state inspection.
|
|
1714
|
+
*/
|
|
1715
|
+
export interface GrooveState {
|
|
1716
|
+
/** Direction of established pocket */
|
|
1717
|
+
pocketDirection: GrooveDirection;
|
|
1718
|
+
/** Running average offset in seconds */
|
|
1719
|
+
establishedOffset: number;
|
|
1720
|
+
/** Current hotness/meter value (0+, can exceed 100 for higher tiers) */
|
|
1721
|
+
hotness: number;
|
|
1722
|
+
/** Current groove tier based on hotness (D, C, B, A, S, or SS) */
|
|
1723
|
+
tier: GrooveTier;
|
|
1724
|
+
/** Current streak length within pocket */
|
|
1725
|
+
streakLength: number;
|
|
1726
|
+
/** Total number of hits recorded */
|
|
1727
|
+
hitCount: number;
|
|
1728
|
+
/** Current pocket window size in seconds */
|
|
1729
|
+
pocketWindow: number;
|
|
1730
|
+
/** When the current groove started (audio time in seconds), null if no active groove */
|
|
1731
|
+
grooveStartTime: number | null;
|
|
1732
|
+
/** Duration of the current groove in seconds (0 if no active groove) */
|
|
1733
|
+
grooveDuration: number;
|
|
1734
|
+
/** Peak hotness reached during the current groove (0+) */
|
|
1735
|
+
maxHotness: number;
|
|
1736
|
+
/** Average hotness over the groove lifetime (0+) */
|
|
1737
|
+
avgHotness: number;
|
|
1738
|
+
/** Total hits in the current groove */
|
|
1739
|
+
grooveHitCount: number;
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Statistics for groove end bonus calculation.
|
|
1743
|
+
* Returned by GrooveAnalyzer.getGrooveStats() when a groove ends.
|
|
1744
|
+
*/
|
|
1745
|
+
export interface GrooveStats {
|
|
1746
|
+
/** Peak streak during the groove */
|
|
1747
|
+
maxStreak: number;
|
|
1748
|
+
/** Peak hotness reached during the groove (0-100) */
|
|
1749
|
+
maxHotness: number;
|
|
1750
|
+
/** Average hotness over the groove lifetime (0-100) */
|
|
1751
|
+
avgHotness: number;
|
|
1752
|
+
/** How long the groove lasted in seconds */
|
|
1753
|
+
duration: number;
|
|
1754
|
+
/** Total hits in the groove */
|
|
1755
|
+
totalHits: number;
|
|
1756
|
+
/** When the groove started (audio time in seconds) */
|
|
1757
|
+
startTime: number;
|
|
1758
|
+
/** When the groove ended (audio time in seconds) */
|
|
1759
|
+
endTime: number;
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Configuration options for the GrooveAnalyzer
|
|
1763
|
+
*/
|
|
1764
|
+
export interface GrooveAnalyzerOptions {
|
|
1765
|
+
/** Minimum hits to establish a pocket (default: 3) */
|
|
1766
|
+
minHitsForPocket: number;
|
|
1767
|
+
/** Base pocket window as fraction of beat (default: 0.03125 = 1/32 note) */
|
|
1768
|
+
basePocketWindowFraction: number;
|
|
1769
|
+
/** Minimum pocket window in seconds (floor for progressive tightening) */
|
|
1770
|
+
minPocketWindowSeconds: number;
|
|
1771
|
+
/** Hotness gain per consistent hit (default: 8) */
|
|
1772
|
+
hotnessGainPerHit: number;
|
|
1773
|
+
/** Hotness loss on pocket break (default: 80) */
|
|
1774
|
+
hotnessLossOnBreak: number;
|
|
1775
|
+
/** Hotness loss on missed beat (default: 80) */
|
|
1776
|
+
hotnessLossOnMiss: number;
|
|
1777
|
+
/** Number of recent hits to average for pocket establishment (default: 4) */
|
|
1778
|
+
averagingWindowSize: number;
|
|
1779
|
+
/** Dead zone around zero for neutral classification in seconds (default: 0.010 = ±10ms) */
|
|
1780
|
+
neutralDeadZone: number;
|
|
1781
|
+
}
|
|
1782
|
+
/**
|
|
1783
|
+
* Default configuration options for the GrooveAnalyzer
|
|
1784
|
+
*/
|
|
1785
|
+
export declare const DEFAULT_GROOVE_OPTIONS: GrooveAnalyzerOptions;
|
|
1786
|
+
/**
|
|
1787
|
+
* Groove penalty configuration for difficulty presets.
|
|
1788
|
+
*
|
|
1789
|
+
* These values control how harshly the groove meter punishes mistakes.
|
|
1790
|
+
* Higher values = more severe penalties for misses and wrong keys.
|
|
1791
|
+
*/
|
|
1792
|
+
export interface GroovePenaltyConfig {
|
|
1793
|
+
/** Hotness loss when missing a beat or pressing wrong key */
|
|
1794
|
+
hotnessLossOnMiss: number;
|
|
1795
|
+
/** Hotness loss when breaking the pocket (hitting outside established timing) */
|
|
1796
|
+
hotnessLossOnBreak: number;
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Easy groove penalties - forgiving for casual players.
|
|
1800
|
+
* Miss penalty: 35 (moderate)
|
|
1801
|
+
*/
|
|
1802
|
+
export declare const EASY_GROOVE_PENALTIES: GroovePenaltyConfig;
|
|
1803
|
+
/**
|
|
1804
|
+
* Medium groove penalties - balanced difficulty.
|
|
1805
|
+
* Miss penalty: 50 (noticeable)
|
|
1806
|
+
*/
|
|
1807
|
+
export declare const MEDIUM_GROOVE_PENALTIES: GroovePenaltyConfig;
|
|
1808
|
+
/**
|
|
1809
|
+
* Hard groove penalties - strict for veterans.
|
|
1810
|
+
* Miss penalty: 65 (severe)
|
|
1811
|
+
*/
|
|
1812
|
+
export declare const HARD_GROOVE_PENALTIES: GroovePenaltyConfig;
|
|
1813
|
+
/**
|
|
1814
|
+
* Map of preset names to their groove penalty configurations.
|
|
1815
|
+
*/
|
|
1816
|
+
export declare const GROOVE_PENALTY_PRESETS: Record<Exclude<DifficultyPreset, 'custom'>, GroovePenaltyConfig>;
|
|
1817
|
+
/**
|
|
1818
|
+
* Get groove penalty configuration for a difficulty preset.
|
|
1819
|
+
*
|
|
1820
|
+
* @param preset - The difficulty preset ('easy', 'medium', 'hard', or 'custom')
|
|
1821
|
+
* @param customPenalties - Custom penalties to use when preset is 'custom'
|
|
1822
|
+
* @returns The groove penalty configuration for the given preset
|
|
1823
|
+
*/
|
|
1824
|
+
export declare function getGroovePenaltiesForPreset(preset: DifficultyPreset, customPenalties?: Partial<GroovePenaltyConfig>): GroovePenaltyConfig;
|
|
1825
|
+
//# sourceMappingURL=BeatMap.d.ts.map
|