JSFiddle - React, Tailwind, and code Playground

by gustav75

HTML

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Virtuelles Drum Kit</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="drum-kit">
        <div class="drum" data-sound="kick" data-key="A">Kick (A)</div>
        <div class="drum" data-sound="snare" data-key="S">Snare (S)</div>
        <div class="drum" data-sound="hihat" data-key="D">Hi-Hat (D)</div>
    </div>
    <div id="controls">
        <label for="tempo">Tempo (BPM):</label>
        <input type="number" id="tempo" value="90" min="30" max="300">
    </div>
    <button id="record-button">Aufnehmen</button>
    <button id="playback-button" disabled>Abspielen</button>
    <button id="stop-button" disabled>Stopp</button>
    <script src="script.js"></script>
</body>
</html>

CSS

body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #333;
}

#drum-kit {
    display: flex;
    gap: 20px;
}

.drum {
    width: 100px;
    height: 100px;
    background-color: #444;
    color: white;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 10px;
    cursor: pointer;
    user-select: none;
    transition: background-color 0.1s;
}

.drum:active {
    background-color: #666;
}

#controls {
    margin-top: 20px;
}

button {
    margin-top: 20px;
    padding: 10px 20px;
    font-size: 16px;
    cursor: pointer;
}

JavaScript

const sounds = {
    kick: 'https://static.wixstatic.com/mp3/efdc4b_ffbd0fa4b6374aad9c4c593531698326.mp3',
    snare: 'https://static.wixstatic.com/mp3/efdc4b_c77562d756d046c686edeaf608ffac4b.mp3',
    hihat: 'https://static.wixstatic.com/mp3/efdc4b_7c93e3de7fd84f15adab1fcf9e1246f3.mp3',
    click: 'https://static.wixstatic.com/mp3/efdc4b_a086a0ea9e8c44d1bb791060977c4849.mp3'
};

const recordButton = document.getElementById('record-button');
const playbackButton = document.getElementById('playback-button');
const stopButton = document.getElementById('stop-button');
const tempoInput = document.getElementById('tempo');

let recording = [];
let isRecording = false;
let isPlaying = false;
let startTime;
let tempo = 90; // Standardtempo in BPM
let clickInterval;
let playbackInterval;
let preCountIn = 4; // 4 Schläge zum Vorzählen
let maxDuration;

tempoInput.addEventListener('input', () => {
    tempo = parseInt(tempoInput.value, 10);
    maxDuration = (480000 / tempo); // 8 Takte = 8 * 60000ms / BPM
});

document.querySelectorAll('.drum').forEach(drum => {
    drum.addEventListener('mousedown', () => playSound(drum));
});

document.addEventListener('keydown', (event) => {
    const drum = document.querySelector(`.drum[data-key="${event.key.toUpperCase()}"]`);
    if (drum) {
        playSound(drum);
    }
});

recordButton.addEventListener('click', () => {
    if (!isRecording) {
        startRecording();
    }
});

playbackButton.addEventListener('click', playRecordingLoop);
stopButton.addEventListener('click', stopPlayback);

function playSound(drum) {
    const sound = new Audio(sounds[drum.dataset.sound]);
    sound.play();

    if (isRecording) {
        const time = Date.now() - startTime;
        if (time <= maxDuration) {
            recording.push({ sound: drum.dataset.sound, time });
        }
    }
}

function startRecording() {
    recording = [];
    isRecording = true;
    recordButton.textContent = "Aufnahme läuft...";
    playbackButton.disabled =...