MMPCreator
This commit is contained in:
1 parent
0dda2b1b0c
commit
8395783986
22 files changed
+2883
-460
No files matched your search
@@ -0,0 +1,134 @@
|
||||
//TODO ver Tone.js
|
||||
|
||||
// js/audio.js
|
||||
import { appState } from "./state.js";
|
||||
import { highlightStep } from "./ui.js";
|
||||
import { getTotalSteps } from "./utils.js";
|
||||
|
||||
let audioContext;
|
||||
let mainGainNode;
|
||||
|
||||
export function getAudioContext() {
|
||||
return audioContext;
|
||||
}
|
||||
export function getMainGainNode() {
|
||||
return mainGainNode;
|
||||
}
|
||||
|
||||
export function initializeAudioContext() {
|
||||
if (!audioContext) {
|
||||
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
mainGainNode = audioContext.createGain();
|
||||
mainGainNode.connect(audioContext.destination);
|
||||
}
|
||||
if (audioContext.state === "suspended") {
|
||||
audioContext.resume();
|
||||
}
|
||||
}
|
||||
|
||||
export function playMetronomeSound(isDownbeat) {
|
||||
initializeAudioContext();
|
||||
const oscillator = audioContext.createOscillator();
|
||||
const gainNode = audioContext.createGain();
|
||||
const frequency = isDownbeat ? 1000 : 800;
|
||||
oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
|
||||
oscillator.type = "sine";
|
||||
gainNode.gain.setValueAtTime(1, audioContext.currentTime);
|
||||
gainNode.gain.exponentialRampToValueAtTime(
|
||||
0.00001,
|
||||
audioContext.currentTime + 0.05
|
||||
);
|
||||
oscillator.connect(gainNode);
|
||||
gainNode.connect(audioContext.destination);
|
||||
oscillator.start(audioContext.currentTime);
|
||||
oscillator.stop(audioContext.currentTime + 0.05);
|
||||
}
|
||||
|
||||
export function playSample(filePath, trackId) {
|
||||
initializeAudioContext();
|
||||
if (!filePath) return;
|
||||
|
||||
const track = trackId ? appState.tracks.find((t) => t.id == trackId) : null;
|
||||
const audio = new Audio(filePath);
|
||||
const source = audioContext.createMediaElementSource(audio);
|
||||
|
||||
if (track && track.gainNode) {
|
||||
source.connect(track.gainNode);
|
||||
} else {
|
||||
source.connect(mainGainNode);
|
||||
}
|
||||
|
||||
audio.play();
|
||||
}
|
||||
|
||||
function tick() {
|
||||
const totalSteps = getTotalSteps();
|
||||
if (totalSteps === 0) {
|
||||
stopPlayback();
|
||||
return;
|
||||
}
|
||||
const lastStepIndex =
|
||||
appState.currentStep === 0 ? totalSteps - 1 : appState.currentStep - 1;
|
||||
highlightStep(lastStepIndex, false);
|
||||
|
||||
if (appState.metronomeEnabled) {
|
||||
const noteValue =
|
||||
parseInt(document.getElementById("compasso-b-input").value, 10) || 4;
|
||||
const stepsPerBeat = 16 / noteValue;
|
||||
if (appState.currentStep % stepsPerBeat === 0) {
|
||||
playMetronomeSound(appState.currentStep === 0);
|
||||
}
|
||||
}
|
||||
|
||||
appState.tracks.forEach((track) => {
|
||||
if (track.steps[appState.currentStep] && track.samplePath) {
|
||||
playSample(track.samplePath, track.id);
|
||||
}
|
||||
});
|
||||
|
||||
highlightStep(appState.currentStep, true);
|
||||
appState.currentStep = (appState.currentStep + 1) % totalSteps;
|
||||
}
|
||||
|
||||
export function startPlayback() {
|
||||
if (appState.isPlaying || appState.tracks.length === 0) return;
|
||||
initializeAudioContext();
|
||||
const bpm = parseInt(document.getElementById("bpm-input").value, 10) || 120;
|
||||
const stepInterval = (60 * 1000) / (bpm * 4);
|
||||
|
||||
if (appState.playbackIntervalId) clearInterval(appState.playbackIntervalId);
|
||||
|
||||
appState.isPlaying = true;
|
||||
document.getElementById("play-btn").classList.remove("fa-play");
|
||||
document.getElementById("play-btn").classList.add("fa-pause");
|
||||
|
||||
tick();
|
||||
appState.playbackIntervalId = setInterval(tick, stepInterval);
|
||||
}
|
||||
|
||||
export function stopPlayback() {
|
||||
clearInterval(appState.playbackIntervalId);
|
||||
appState.playbackIntervalId = null;
|
||||
appState.isPlaying = false;
|
||||
highlightStep(appState.currentStep - 1, false);
|
||||
appState.currentStep = 0;
|
||||
document.getElementById("play-btn").classList.remove("fa-pause");
|
||||
document.getElementById("play-btn").classList.add("fa-play");
|
||||
}
|
||||
|
||||
export function rewindPlayback() {
|
||||
appState.currentStep = 0;
|
||||
if (!appState.isPlaying) {
|
||||
document
|
||||
.querySelectorAll(".step.playing")
|
||||
.forEach((s) => s.classList.remove("playing"));
|
||||
}
|
||||
}
|
||||
|
||||
export function togglePlayback() {
|
||||
if (appState.isPlaying) {
|
||||
stopPlayback();
|
||||
} else {
|
||||
startPlayback();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user