Files
KGStudio/src/util/timeUtil.ts
T
2025-08-21 21:56:22 -07:00

108 lines
3.6 KiB
TypeScript

/**
* Time utility functions for KGSP
*/
import { TIME_CONSTANTS } from '../constants/coreConstants';
import type { TimeSignature } from '../types/projectTypes';
/**
* Parse and validate time signature string in format "numerator/denominator"
* @param timeSignatureStr - String in format "numerator/denominator" (e.g., "4/4", "3/4", "6/8")
* @returns TimeSignature object if valid, null if invalid
*/
export function parseTimeSignature(timeSignatureStr: string): TimeSignature | null {
// Remove any whitespace and check format
const trimmed = timeSignatureStr.trim();
// Check if it contains exactly one slash
const parts = trimmed.split('/');
if (parts.length !== 2) {
return null;
}
// Parse numerator and denominator
const numerator = parseInt(parts[0]);
const denominator = parseInt(parts[1]);
// Check if both are valid numbers
if (isNaN(numerator) || isNaN(denominator)) {
return null;
}
// Validate against available values
if (!TIME_CONSTANTS.AVAILABLE_TIME_SIGNATURE_NUMERATORS.includes(numerator)) {
return null;
}
if (!TIME_CONSTANTS.AVAILABLE_TIME_SIGNATURE_DENOMINATORS.includes(denominator)) {
return null;
}
return { numerator, denominator };
}
/**
* Get formatted error message for invalid time signature
* @returns User-friendly error message with available options
*/
export function getTimeSignatureErrorMessage(): string {
const numerators = TIME_CONSTANTS.AVAILABLE_TIME_SIGNATURE_NUMERATORS.join(', ');
const denominators = TIME_CONSTANTS.AVAILABLE_TIME_SIGNATURE_DENOMINATORS.join(', ');
return `Invalid time signature format. Please use "numerator/denominator" format.\n\nAvailable numerators: ${numerators}\nAvailable denominators: ${denominators}\n\nExamples: 4/4, 3/4, 6/8, 12/8`;
}
/**
* Convert beats to combined bar/beat and time format (BBB:B | mm:ss:mmm)
* @param beats - Current position in beats
* @param bpm - Beats per minute
* @param timeSignature - Time signature object with numerator and denominator
* @returns Formatted time string in BBB:B | mm:ss:mmm format
*/
export function beatsToTimeString(
beats: number,
bpm: number,
timeSignature: { numerator: number; denominator: number }
): string {
// Calculate bar and beat information
const beatsPerBar = timeSignature.numerator;
const currentBar = Math.floor(beats / beatsPerBar) + 1; // 1-indexed bars
const beatInBar = Math.floor(beats % beatsPerBar) + 1; // 1-indexed beats within bar
// Calculate total seconds from beats for time display
const totalSeconds = (beats / bpm) * 60;
// Extract minutes, seconds, and milliseconds
const minutes = Math.floor(totalSeconds / 60);
const seconds = Math.floor(totalSeconds % 60);
const milliseconds = Math.floor((totalSeconds % 1) * 1000);
// Format bar/beat part
const BBB = currentBar.toString().padStart(3, '0');
const B = beatInBar.toString();
// Format time part with leading zeros
const mm = minutes.toString().padStart(2, '0');
const ss = seconds.toString().padStart(2, '0');
const mmm = milliseconds.toString().padStart(3, '0');
return `${BBB}:${B} | ${mm}:${ss}:${mmm}`;
}
/**
* Format a Date object into a human-readable local datetime string with timezone.
* Example: 2025/08/21, 19:57:11 GMT-7
*/
export function formatLocalDateTime(date: Date): string {
const options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
timeZoneName: 'short'
};
return date.toLocaleString(undefined, options);
}