🎵 Projekt: Audio-Player
Erstelle deinen eigenen Web-Audio-Player mit Effekten
Projektübersicht
In diesem Projekt wirst du einen vollständigen Audio-Player mit Hilfe der Web Audio API erstellen. Der Player soll grundlegende Funktionen bieten sowie verschiedene Audio-Effekte implementieren.
💡 Ziel: Ein funktionsfähiger Audio-Player mit Wiedergabesteuerung
und Effektparametern, der im Browser läuft.
💡 W3Schools Ressource: Für Informationen über Audio-Player-Implementierung mit HTML5 siehe
HTML5 Audio Player auf W3Schools
Lernziele
- Implementierung eines Audio-Players mit Web Audio API
- Integration von Wiedergabesteuerungen
- Implementierung von Audio-Effekten
- Erstellung einer benutzerfreundlichen Oberfläche
- Verständnis für Audio-Graphen und deren Verwaltung
Voraussetzungen
- Grundkenntnisse in HTML, CSS und JavaScript
- Verständnis der Web Audio API Grundlagen
- Texteditor und moderner Web-Browser
- Beispiel-Audiodatei zum Testen
Projektstruktur
audio-player/
├── index.html
├── css/
│ └── style.css
├── js/
│ └── player.js
└── audio/
└── beispiel.mp3
HTML-Grundgerüst
Erstelle die grundlegende HTML-Struktur für den Audio-Player:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Audio-Player</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="player-container">
<h1>Mein Audio-Player</h1>
<!-- Audio-Datei-Auswahl -->
<input type="file" id="audioFile" accept="audio/*">
<!-- Wiedergabesteuerung -->
<div class="controls">
<button id="playBtn">▶</button>
<button id="pauseBtn">⏸</button>
<button id="stopBtn">⏹</button>
</div>
<!-- Fortschrittsanzeige -->
<div class="progress-container">
<input type="range" id="progressBar" min="0" max="100" value="0">
<span id="timeDisplay">0:00 / 0:00</span>
</div>
<!-- Lautstärke -->
<div class="volume-control">
<label for="volumeSlider">Lautstärke:</label>
<input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="0.8">
</div>
<!-- Effekt-Steuerung -->
<div class="effects-controls">
<label for="reverbSlider">Hall:</label>
<input type="range" id="reverbSlider" min="0" max="1" step="0.01" value="0">
<label for="delaySlider">Verzögerung:</label>
<input type="range" id="delaySlider" min="0" max="1" step="0.01" value="0">
</div>
</div>
<script src="js/player.js"></script>
</body>
</html>
JavaScript-Implementierung
Implementiere die Hauptfunktionalitäten des Audio-Players:
// player.js
class AudioPlayer {
constructor() {
this.audioContext = null;
this.audioSource = null;
this.audioBuffer = null;
this.isPlaying = false;
this.startTime = 0;
this.pauseTime = 0;
// Effekt-Knoten
this.gainNode = null;
this.reverbNode = null;
this.delayNode = null;
this.initializeElements();
this.setupEventListeners();
this.initAudioContext();
}
initializeElements() {
this.playBtn = document.getElementById('playBtn');
this.pauseBtn = document.getElementById('pauseBtn');
this.stopBtn = document.getElementById('stopBtn');
this.progressBar = document.getElementById('progressBar');
this.timeDisplay = document.getElementById('timeDisplay');
this.volumeSlider = document.getElementById('volumeSlider');
this.reverbSlider = document.getElementById('reverbSlider');
this.delaySlider = document.getElementById('delaySlider');
this.audioFileInput = document.getElementById('audioFile');
}
setupEventListeners() {
this.playBtn.addEventListener('click', () => this.play());
this.pauseBtn.addEventListener('click', () => this.pause());
this.stopBtn.addEventListener('click', () => this.stop());
this.volumeSlider.addEventListener('input', () => this.updateVolume());
this.reverbSlider.addEventListener('input', () => this.updateReverb());
this.delaySlider.addEventListener('input', () => this.updateDelay());
this.audioFileInput.addEventListener('change', (e) => this.loadAudioFile(e));
}
initAudioContext() {
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
// Initialisiere Effekt-Knoten
this.gainNode = this.audioContext.createGain();
this.gainNode.gain.value = this.volumeSlider.value;
// Reverb (vereinfacht mit Convolver)
this.reverbNode = this.audioContext.createConvolver();
// Delay
this.delayNode = this.audioContext.createDelay(1.0);
const feedback = this.audioContext.createGain();
feedback.gain.value = 0.3;
// Verbindungen: Quelle -> Effekte -> Ausgabe
this.gainNode.connect(this.delayNode);
this.delayNode.connect(feedback);
feedback.connect(this.delayNode);
this.delayNode.connect(this.reverbNode);
this.reverbNode.connect(this.audioContext.destination);
}
async loadAudioFile(event) {
const file = event.target.files[0];
if (!file) return;
const arrayBuffer = await file.arrayBuffer();
this.audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);
this.updateTimeDisplay();
}
play() {
if (!this.audioBuffer) return;
if (this.audioContext.state === 'suspended') {
this.audioContext.resume();
}
// Stoppe vorherige Wiedergabe
if (this.audioSource) {
this.audioSource.disconnect();
}
// Erstelle neue Quelle
this.audioSource = this.audioContext.createBufferSource();
this.audioSource.buffer = this.audioBuffer;
this.audioSource.connect(this.gainNode);
// Starte Wiedergabe
const startTime = this.audioContext.currentTime;
this.audioSource.start(0, this.pauseTime);
this.isPlaying = true;
this.startTime = startTime - this.pauseTime;
// Starte Fortschrittsaktualisierung
this.updateProgress();
}
pause() {
if (!this.isPlaying) return;
this.audioSource.stop();
this.pauseTime = this.audioContext.currentTime - this.startTime;
this.isPlaying = false;
}
stop() {
if (this.audioSource) {
this.audioSource.stop();
this.audioSource.disconnect();
this.audioSource = null;
}
this.isPlaying = false;
this.pauseTime = 0;
this.startTime = 0;
this.progressBar.value = 0;
this.updateTimeDisplay();
}
updateVolume() {
if (this.gainNode) {
this.gainNode.gain.value = this.volumeSlider.value;
}
}
updateReverb() {
// Vereinfachte Implementierung - in der Realität müsste ein Impulsantwort geladen werden
// Für dieses Beispiel simulieren wir den Effekt mit einem Gain-Node
if (this.reverbNode) {
this.reverbNode.gain.value = this.reverbSlider.value;
}
}
updateDelay() {
if (this.delayNode) {
this.delayNode.delayTime.value = this.delaySlider.value * 0.5; // Max 500ms
}
}
updateProgress() {
if (!this.isPlaying) return;
const currentTime = this.audioContext.currentTime - this.startTime;
const duration = this.audioBuffer ? this.audioBuffer.duration : 0;
if (duration > 0) {
const progress = (currentTime / duration) * 100;
this.progressBar.value = Math.min(progress, 100);
this.updateTimeDisplay(currentTime, duration);
}
if (currentTime < duration) {
requestAnimationFrame(() => this.updateProgress());
} else {
this.isPlaying = false;
this.pauseTime = 0;
}
}
updateTimeDisplay(currentTime = 0, duration = 0) {
if (!this.audioBuffer) {
duration = this.audioBuffer.duration;
}
const formatTime = (seconds) => {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
};
this.timeDisplay.textContent = `${formatTime(currentTime)} / ${formatTime(duration)}`;
}
}
// Initialisiere den Player sobald die Seite geladen ist
document.addEventListener('DOMContentLoaded', () => {
new AudioPlayer();
});
CSS-Styling
Erstelle ein ansprechendes Styling für den Audio-Player:
/* style.css */
.player-container {
max-width: 600px;
margin: 2rem auto;
padding: 2rem;
background: var(--card-bg);
border-radius: 16px;
box-shadow: 0 6px 20px rgba(0,0,0,0.08);
border: 1px solid var(--border-light);
}
.player-container h1 {
text-align: center;
color: var(--h1-color);
margin-bottom: 1.5rem;
}
.controls {
display: flex;
justify-content: center;
gap: 1rem;
margin-bottom: 1.5rem;
}
.controls button {
padding: 0.8rem 1.5rem;
font-size: 1.2rem;
border-radius: 8px;
cursor: pointer;
background-color: var(--primary);
color: white;
border: none;
}
.controls button:hover {
background-color: var(--primary-light);
}
.progress-container {
margin-bottom: 1.5rem;
}
#progressBar {
width: 100%;
margin-bottom: 0.5rem;
}
#timeDisplay {
display: block;
text-align: center;
color: var(--text-secondary);
font-size: 0.9rem;
}
.volume-control, .effects-controls {
margin-bottom: 1.5rem;
}
.volume-control label, .effects-controls label {
display: block;
margin-bottom: 0.5rem;
color: var(--text);
}
.effects-controls {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.effects-controls label {
margin-bottom: 0.25rem;
}
input[type="range"] {
width: 100%;
margin-bottom: 1rem;
}
Erweiterte Funktionen
Playlist-Funktionalität
Erweitere den Player um Playlist-Unterstützung:
- Hinzufügen mehrerer Dateien
- Wiedergabeliste anzeigen
- Weiter/zurück-Schaltflächen
- Zufallswiedergabe
- Wiederholungsmodus
Visualisierung
Füge eine Audio-Visualisierung hinzu:
// Füge dies zur Klasse hinzu
initVisualizer() {
this.analyser = this.audioContext.createAnalyser();
this.analyser.fftSize = 2048;
// Verbinde nach dem Gain-Node
this.gainNode.connect(this.analyser);
this.analyser.connect(this.audioContext.destination);
// Canvas für Visualisierung
this.canvas = document.createElement('canvas');
this.canvas.width = 600;
this.canvas.height = 200;
document.querySelector('.player-container').appendChild(this.canvas);
this.canvasCtx = this.canvas.getContext('2d');
this.drawVisualizer();
}
drawVisualizer() {
if (!this.analyser) return;
const bufferLength = this.analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const draw = () => {
requestAnimationFrame(draw);
this.analyser.getByteTimeDomainData(dataArray);
this.canvasCtx.fillStyle = 'rgb(0, 0, 0)';
this.canvasCtx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.canvasCtx.lineWidth = 2;
this.canvasCtx.strokeStyle = '#00bcd4';
this.canvasCtx.beginPath();
const sliceWidth = this.canvas.width * 1.0 / bufferLength;
let x = 0;
for (let i = 0; i < bufferLength; i++) {
const v = dataArray[i] / 128.0;
const y = v * this.canvas.height / 2;
if (i === 0) {
this.canvasCtx.moveTo(x, y);
} else {
this.canvasCtx.lineTo(x, y);
}
x += sliceWidth;
}
this.canvasCtx.lineTo(this.canvas.width, this.canvas.height / 2);
this.canvasCtx.stroke();
};
draw();
}
Test und Debugging
Testfälle
- Laden verschiedener Audioformate (MP3, WAV, OGG)
- Wiedergabesteuerung (Play, Pause, Stop)
- Lautstärkeregelung
- Effektänderungen während der Wiedergabe
- Positionierung innerhalb der Datei
- Browser-Kompatibilität
Debugging-Tipps
- Verwende die Browser-Entwicklertools (insbesondere die Audio-Tab)
- Überprüfe die Konsole auf Fehlermeldungen
- Teste auf verschiedenen Geräten und Browsern
- Überprüfe die Audio-Graph-Verbindungen
Deployment
Um den Audio-Player online verfügbar zu machen:
- Stelle sicher, dass alle Dateien korrekt organisiert sind
- Teste die Anwendung lokal mit einem Webserver
- Lade die Dateien auf einen Webserver hoch
- Stelle sicher, dass die Audio-Dateien korrekt bereitgestellt werden
- Teste die Online-Version auf verschiedenen Geräten
⚠️ Hinweis: Einige Browser blockieren Audio-Wiedergabe,
bis der Nutzer eine Interaktion durchgeführt hat (z.B. Klick auf Play-Button).
Erweiterungsideen
- Equalizer mit mehreren Bändern
- Unterstützung für Streaming-URLs
- Speichern von Effektvoreinstellungen
- Unterstützung für MIDI-Eingabe
- Audio-Aufnahmefunktion
- Unterstützung für WebMIDI
- Offline-Funktionalität mit Service Worker