UNPKG

u-he-preset-randomizer

Version:

Create random u-he synth presets through randomization and merging of your existing presets.

159 lines 5.97 kB
/** * @file Preset library analyzer for statistical parameter analysis. * Analyzes preset libraries to extract parameter distributions and statistics for randomization. */ import chalk from 'chalk'; import { getSpecialParameterHandling } from './synthConfigs/index.js'; export function analyzeParamsTypeAndRange(presetLibrary, config) { // Get special parameter handling rules for this synth (global + synth-specific) const specialParameterHandling = getSpecialParameterHandling(presetLibrary.synth); const paramsModel = {}; for (const preset of presetLibrary.presets) { for (const param of preset.params) { const key = param.id; if (!paramsModel[key]) { if (key.includes('[object Object]')) { // Ignore broken presets, the generator did accidentally create in the past continue; } paramsModel[key] = { type: param.type, values: [param.value], distinctValues: [], }; for (const paramHandling of specialParameterHandling) { if (key.includes(paramHandling.id)) { paramsModel[key].keepStable = paramHandling.keepStable; } } } else { paramsModel[key].values.push(param.value); if (paramsModel[key].type !== param.type) { if (paramsModel[key].type === 'integer') { paramsModel[key].type = param.type; } else if (paramsModel[key].type === 'float' && param.type === 'string') { paramsModel[key].type = param.type; } } } } } // Post Analytics for (const paramName in paramsModel) { const param = paramsModel[paramName]; if (!param) continue; param.distinctValues = [...new Set(param.values)]; // Build frequency map for weighted sampling param.frequencies = {}; for (const value of param.values) { const key = String(value); param.frequencies[key] = (param.frequencies[key] ?? 0) + 1; } // Memory optimization: Always compact values to distinctValues // Frequency information is preserved in the frequencies map param.values = param.distinctValues; if (param.type !== 'string') { const values = param.distinctValues; param.maxValue = Math.max(...values); param.minValue = Math.min(...values); param.avgValue = average(values); } } // Debug: Log memory usage after computing analytics if (config?.debug) { const memUsage = process.memoryUsage(); const paramCount = Object.keys(paramsModel).length; let totalDistinctValues = 0; let totalFrequencyEntries = 0; for (const param of Object.values(paramsModel)) { totalDistinctValues += param.distinctValues.length; totalFrequencyEntries += Object.keys(param.frequencies ?? {}).length; } console.log(' '); console.log(chalk.cyan('Memory Usage After Computing Analytics:')); console.log(chalk.gray(` Heap Used: ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`)); console.log(chalk.gray(` Heap Total: ${(memUsage.heapTotal / 1024 / 1024).toFixed(2)} MB`)); console.log(chalk.gray(` RSS: ${(memUsage.rss / 1024 / 1024).toFixed(2)} MB`)); console.log(chalk.gray(` Parameters Analyzed: ${paramCount.toLocaleString()}`)); console.log(chalk.gray(` Total Distinct Values: ${totalDistinctValues.toLocaleString()}`)); console.log(chalk.gray(` Total Frequency Entries: ${totalFrequencyEntries.toLocaleString()}`)); console.log(' '); } return paramsModel; } /** * Returns a list of names, gathered from the preset library */ export function getDictionaryOfNames(presetLibrary) { const names = []; const excludedWords = new Set([ 'bass', 'guitar', 'piano', 'lead', 'unison', 'sub', 'strings', 'keys', 'flute', 'organ', 'brass', 'bells', 'pluck', 'plucked', 'epiano', 'chorus', 'stab', 'chord', 'chords', 'drum', 'synth', 'kick', 'snare', 'clap', 'hihat', 'edit', ]); for (const preset of presetLibrary.presets) { const cleanedUpName = preset.presetName.split('_').join(' '); const splitName = cleanedUpName.split(' '); for (const split of splitName) { if (split.length > 3 && split.toUpperCase() !== split && !split.includes('-') && !split.includes('(') && !split.includes(')') && !excludedWords.has(split.toLowerCase())) { names.push(split); } } } return names; } export function convertParamsModelBySection(paramsModel) { const paramsModelBySection = {}; for (const id in paramsModel) { const split = id.split('/'); const section = split[0]; // Skip if section is undefined (shouldn't happen with valid preset IDs) if (!section) continue; paramsModelBySection[section] ??= {}; const sectionModel = paramsModelBySection[section]; const paramData = paramsModel[id]; if (sectionModel && paramData) { sectionModel[id] = paramData; } } return paramsModelBySection; } export function average(arr) { if (arr.length === 0) return 0; return arr.reduce((p, c) => p + c, 0) / arr.length; } //# sourceMappingURL=analyzer.js.map