Add WIP sound generation

This commit is contained in:
Andras Schmelczer 2026-05-10 15:26:44 +01:00
commit 34ac200437
10 changed files with 1542 additions and 0 deletions

View file

@ -0,0 +1,52 @@
import { clamp } from '../utils/clamp';
import { VibePreset } from '../vibes';
import {
GardenAudioChord,
GardenAudioConfig,
GardenAudioVibeProfile,
} from './garden-audio-config';
import { GardenAudioColorIndex } from './garden-audio-types';
export const normalizeColorIndex = (index: number): GardenAudioColorIndex =>
Math.max(0, Math.min(2, Math.round(index))) as GardenAudioColorIndex;
export const clampMidi = (midi: number, min: number, max: number): number =>
Math.round(clamp(midi, min, max));
export const getVibeProfile = (
config: GardenAudioConfig,
vibe: VibePreset
): GardenAudioVibeProfile =>
config.vibes[vibe.id] ??
config.vibes[config.fallbackVibeId] ??
Object.values(config.vibes)[0];
export const getChordAtStep = (
config: GardenAudioConfig,
profile: GardenAudioVibeProfile,
stepIndex: number
): GardenAudioChord => {
const barIndex = Math.floor(stepIndex / config.rhythm.stepsPerBar);
return profile.progression[barIndex % profile.progression.length];
};
export const getChordIntervals = (
chord: GardenAudioChord,
openVoicing: boolean
): Array<number> => {
if (openVoicing) {
return chord.quality === 'major' ? [0, 7, 12, 16] : [0, 7, 12, 15];
}
return chord.quality === 'major' ? [0, 4, 7, 12, 16] : [0, 3, 7, 12, 15];
};
export const degreeToSemitone = (
profile: GardenAudioVibeProfile,
degree: number
): number => {
const scaleIndex =
((degree % profile.scale.length) + profile.scale.length) % profile.scale.length;
const octave = Math.floor(degree / profile.scale.length);
return profile.scale[scaleIndex] + octave * 12;
};