101 lines
2.7 KiB
TypeScript
101 lines
2.7 KiB
TypeScript
import type { TileState } from '../types/tiles'
|
|
import { getDefaultEngineValues, getDefaultEffectValues } from '../config/parameters'
|
|
import { getDefaultLFOValues } from '../stores/settings'
|
|
|
|
export interface FMPatchConfig {
|
|
algorithm: number
|
|
feedback: number
|
|
lfoRates: [number, number, number, number]
|
|
pitchLFO: {
|
|
waveform: number
|
|
depth: number
|
|
baseRate: number
|
|
}
|
|
}
|
|
|
|
export function generateRandomFMPatch(complexity: number = 1): FMPatchConfig {
|
|
let algorithmRange: number[]
|
|
|
|
switch (complexity) {
|
|
case 0:
|
|
algorithmRange = [0, 2, 6, 8, 9, 10]
|
|
break
|
|
case 2:
|
|
algorithmRange = [1, 4, 5, 7, 11, 12, 13, 14, 15]
|
|
break
|
|
default:
|
|
algorithmRange = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
}
|
|
|
|
const algorithm = algorithmRange[Math.floor(Math.random() * algorithmRange.length)]
|
|
const feedback = Math.floor(Math.random() * 100)
|
|
|
|
const lfoRates: [number, number, number, number] = [
|
|
0.2 + Math.random() * 0.8,
|
|
0.3 + Math.random() * 1.0,
|
|
0.4 + Math.random() * 1.2,
|
|
0.25 + Math.random() * 0.9
|
|
]
|
|
|
|
const pitchLFO = {
|
|
waveform: Math.floor(Math.random() * 8),
|
|
depth: Math.random() < 0.4 ? 0.03 + Math.random() * 0.22 : 0,
|
|
baseRate: 0.1 + Math.random() * 9.9
|
|
}
|
|
|
|
return { algorithm, feedback, lfoRates, pitchLFO }
|
|
}
|
|
|
|
export function createFMTileState(patch: FMPatchConfig): TileState {
|
|
const formula = JSON.stringify(patch)
|
|
|
|
const pitchValues = [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2.0]
|
|
const randomPitch = pitchValues[Math.floor(Math.random() * pitchValues.length)]
|
|
|
|
return {
|
|
formula,
|
|
engineParams: {
|
|
...getDefaultEngineValues(),
|
|
a: Math.floor(Math.random() * 128) + 64,
|
|
b: Math.floor(Math.random() * 128) + 64,
|
|
c: Math.floor(Math.random() * 128) + 64,
|
|
d: Math.floor(Math.random() * 128) + 64,
|
|
pitch: randomPitch,
|
|
fmAlgorithm: patch.algorithm,
|
|
fmFeedback: patch.feedback
|
|
},
|
|
effectParams: getDefaultEffectValues(),
|
|
lfoConfigs: getDefaultLFOValues()
|
|
}
|
|
}
|
|
|
|
export function generateFMTileGrid(size: number, columns: number, complexity: number = 1): TileState[][] {
|
|
const tiles: TileState[][] = []
|
|
const rows = Math.ceil(size / columns)
|
|
|
|
for (let i = 0; i < rows; i++) {
|
|
const row: TileState[] = []
|
|
for (let j = 0; j < columns; j++) {
|
|
if (i * columns + j < size) {
|
|
const patch = generateRandomFMPatch(complexity)
|
|
row.push(createFMTileState(patch))
|
|
}
|
|
}
|
|
tiles.push(row)
|
|
}
|
|
|
|
return tiles
|
|
}
|
|
|
|
export function parseFMPatch(formula: string): FMPatchConfig | null {
|
|
try {
|
|
const parsed = JSON.parse(formula)
|
|
if (typeof parsed.algorithm === 'number' && typeof parsed.feedback === 'number') {
|
|
return parsed
|
|
}
|
|
} catch {
|
|
// Not a valid FM patch
|
|
}
|
|
return null
|
|
}
|