mmpSearch/assets/js/creations/utils.js

114 lines
3.9 KiB
JavaScript

// js/utils.js
import { appState } from './state.js';
import { PIXELS_PER_STEP, ZOOM_LEVELS } from './config.js';
/**
* Helper interna para ler o BPM do input.
* @returns {number} O BPM atual.
*/
function _getBpm() {
const bpmInput = document.getElementById("bpm-input");
return parseFloat(bpmInput.value, 10) || 120;
}
/**
* Calcula e exporta quantos compassos (beats) existem por compasso (bar).
* @returns {number} O número de batidas por compasso (ex: 4 para 4/4).
*/
export function getBeatsPerBar() {
const compassoAInput = document.getElementById("compasso-a-input");
return parseInt(compassoAInput.value, 10) || 4;
}
/**
* Calcula e exporta quantos segundos dura uma "batida" (beat).
* No contexto de BPM, uma "batida" é quase sempre uma semínima (1/4).
* @returns {number} Duração da batida em segundos.
*/
export function getSecondsPerBeat() {
return 60.0 / _getBpm();
}
/**
* Calcula e exporta quantos segundos dura um "step".
* Baseado na config, um "step" é uma semicolcheia (1/16).
* Há 4 steps (1/16) por batida (1/4).
* @returns {number} Duração do step em segundos.
*/
export function getSecondsPerStep() {
return getSecondsPerBeat() / 4.0; // 4 steps (1/16) por beat (1/4)
}
/**
* Quantiza (arredonda) um tempo em segundos para o "step" do grid mais próximo.
* @param {number} timeInSeconds - O tempo arbitrário (ex: 1.234s).
* @returns {number} O tempo alinhado ao grid (ex: 1.250s).
*/
export function quantizeTime(timeInSeconds) {
// TODO: Adicionar um toggle global (appState.global.isSnapEnabled)
const secondsPerStep = getSecondsPerStep();
if (secondsPerStep <= 0) return timeInSeconds; // Evita divisão por zero
const roundedSteps = Math.round(timeInSeconds / secondsPerStep);
return roundedSteps * secondsPerStep;
}
/**
* Calcula a quantidade de pixels que representa um segundo na timeline,
* levando em conta o BPM e o nível de zoom atual.
* @returns {number} A quantidade de pixels por segundo.
*/
export function getPixelsPerSecond() {
const bpm = _getBpm(); // Usa a helper interna
// (bpm / 60) = batidas por segundo
// * 4 = steps por segundo (assumindo 4 steps/beat)
const stepsPerSecond = (bpm / 60) * 4;
const zoomFactor = ZOOM_LEVELS[appState.global.zoomLevelIndex];
return stepsPerSecond * PIXELS_PER_STEP * zoomFactor;
}
/**
* Calcula o número total de steps no sequenciador de patterns.
* @returns {number} O número total de steps.
*/
export function getTotalSteps() {
const barsInput = document.getElementById("bars-input");
const compassoAInput = document.getElementById("compasso-a-input");
const compassoBInput = document.getElementById("compasso-b-input");
const numberOfBars = parseInt(barsInput.value, 10) || 1;
const beatsPerBar = parseInt(compassoAInput.value, 10) || 4;
const noteValue = parseInt(compassoBInput.value, 10) || 4;
const subdivisions = Math.round(16 / noteValue);
return numberOfBars * beatsPerBar * subdivisions;
}
/**
* Garante que apenas números sejam inseridos em um campo de input.
* @param {Event} event - O evento de input.
*/
export function enforceNumericInput(event) {
event.target.value = event.target.value.replace(/[^0-9]/g, "");
}
/**
* Ajusta o valor de um elemento de input com base em um passo (step),
* respeitando os limites de min/max definidos no elemento.
* @param {HTMLInputElement} inputElement - O elemento de input a ser ajustado.
* @param {number} step - O valor a ser adicionado (pode ser negativo).
*/
export function adjustValue(inputElement, step) {
let currentValue = parseInt(inputElement.value, 10) || 0;
let min = parseInt(inputElement.dataset.min, 10);
let max = parseInt(inputElement.dataset.max, 10);
let newValue = currentValue + step;
if (!isNaN(min) && newValue < min) newValue = min;
if (!isNaN(max) && newValue > max) newValue = max;
inputElement.value = newValue;
inputElement.dispatchEvent(new Event("input", { bubbles: true }));
}