70 lines
2 KiB
TypeScript
70 lines
2 KiB
TypeScript
import type { GardenAudioEngineConfig } from '../config';
|
|
import { clamp01 } from '../utils/clamp';
|
|
import { GardenAudioStroke } from './garden-audio-types';
|
|
|
|
export interface GardenAudioStrokeMetrics {
|
|
distancePixels: number;
|
|
pressure: number;
|
|
speedPixelsPerSecond: number;
|
|
speedAmount: number;
|
|
effectiveEnergy: number;
|
|
}
|
|
|
|
export const getStrokeMetrics = (
|
|
stroke: GardenAudioStroke,
|
|
speedForFullEnergyPixelsPerSecond: number,
|
|
inputConfig: GardenAudioEngineConfig['input']
|
|
): GardenAudioStrokeMetrics => {
|
|
const dx = stroke.to[0] - stroke.from[0];
|
|
const dy = stroke.to[1] - stroke.from[1];
|
|
const distancePixels = Math.hypot(dx, dy);
|
|
const speedPixelsPerSecond = getStrokeVelocity(stroke, distancePixels, inputConfig);
|
|
const pressure = getPressureAmount(stroke);
|
|
const speedAmount = clamp01(speedPixelsPerSecond / speedForFullEnergyPixelsPerSecond);
|
|
const strokeEnergy = clamp01(
|
|
inputConfig.strokeEnergyBase +
|
|
speedAmount * inputConfig.strokeEnergySpeedWeight +
|
|
pressure * inputConfig.strokeEnergyPressureWeight
|
|
);
|
|
const effectiveEnergy =
|
|
strokeEnergy *
|
|
(inputConfig.distanceEnergyBase +
|
|
clamp01(distancePixels / inputConfig.distanceForFullEnergyPixels) *
|
|
inputConfig.distanceEnergyScale);
|
|
|
|
return {
|
|
distancePixels,
|
|
pressure,
|
|
speedPixelsPerSecond,
|
|
speedAmount,
|
|
effectiveEnergy,
|
|
};
|
|
};
|
|
|
|
const getStrokeVelocity = (
|
|
stroke: GardenAudioStroke,
|
|
distancePixels: number,
|
|
inputConfig: GardenAudioEngineConfig['input']
|
|
): number => {
|
|
if (
|
|
stroke.velocityPixelsPerSecond !== undefined &&
|
|
Number.isFinite(stroke.velocityPixelsPerSecond) &&
|
|
stroke.velocityPixelsPerSecond >= 0
|
|
) {
|
|
return stroke.velocityPixelsPerSecond;
|
|
}
|
|
|
|
return distancePixels / inputConfig.fallbackFrameSeconds;
|
|
};
|
|
|
|
const getPressureAmount = (stroke: GardenAudioStroke): number => {
|
|
if (
|
|
stroke.pressure !== undefined &&
|
|
Number.isFinite(stroke.pressure) &&
|
|
stroke.pressure > 0
|
|
) {
|
|
return clamp01(stroke.pressure);
|
|
}
|
|
|
|
return 0;
|
|
};
|