import { Pad, Sound } from '../types/types'; import { PAD_DISPLAY_FROM_INDEX } from './constants'; export function findPad(pad: string, pads: Record) { const group = pad[0]; const padNumber = parseInt(pad.slice(1), 10); const padData = pads[group][padNumber]; return padData; } export function findSoundIdByPad(pad: string, pads: Record) { const padData = findPad(pad, pads); if (!padData) { return null; } if (padData.soundId === 0) { return null; } return padData.soundId; } export function findSoundByPad(pad: string, pads: Record, sounds: Sound[]) { const soundId = findSoundIdByPad(pad, pads); return sounds.find((s) => s.id === soundId) || null; } export function audioFormatAsBitDepth(s: string) { switch (s) { case 's16': return 16; case 's24': return 24; case 'float': return 32; default: throw new Error('unknown bit depth'); } } export function calculateSoundLength(sound: Sound) { const sampleRate = sound.meta?.samplerate; const channels = sound.meta?.channels; const fileSize = sound.fileNode?.fileSize; if (!sampleRate || !channels || !fileSize) { return 0; } return fileSize / 2 / sampleRate / channels; } export class AbortError extends Error { constructor() { super('The operation was aborted.'); this.name = 'AbortError'; } } export function getPadDisplayName(group: string, index: number): string { const padChar = PAD_DISPLAY_FROM_INDEX[index] ?? '?'; return `${group.toUpperCase()} ${padChar}`; } export function hasMultipleNoteVariations( group: string, scenes: { patterns: { pad: string; notes: { note: number }[] }[] }[], ) { const trackNotes: Record> = {}; for (const scene of scenes) { for (const pattern of scene.patterns) { if (!pattern.pad.startsWith(group)) { continue; } if (!trackNotes[pattern.pad]) { trackNotes[pattern.pad] = new Set(); } for (const note of pattern.notes) { trackNotes[pattern.pad].add(note.note); } } } for (const padCode in trackNotes) { if (trackNotes[padCode].size > 1) { return true; } } return false; }