import React, { useState, useEffect, useRef } from 'react';
const Music8Bit = () => {
const [isPlaying, setIsPlaying] = useState(false);
const [currentBeat, setCurrentBeat] = useState(0);
const [tempo, setTempo] = useState(120);
const [selectedInstrument, setSelectedInstrument] = useState('square');
const [volume, setVolume] = useState(0.3);
const audioContextRef = useRef(null);
const intervalRef = useRef(null);
const BEATS = 16;
const TRACKS = 4;
const [grid, setGrid] = useState(
Array(TRACKS).fill(null).map(() => Array(BEATS).fill(false))
);
const [isAnalyzing, setIsAnalyzing] = useState(false);
const [audioFile, setAudioFile] = useState(null);
const fileInputRef = useRef(null);
const instruments = [
{ id: 'square', name: '🔲 Square', icon: '■', color: 'bg-blue-500' },
{ id: 'sawtooth', name: '🔺 Saw', icon: '▲', color: 'bg-green-500' },
{ id: 'triangle', name: '🔻 Triangle', icon: '▼', color: 'bg-yellow-500' },
{ id: 'sine', name: '〰️ Sine', icon: '~', color: 'bg-purple-500' }
];
const notes = [
{ freq: 523.25, name: 'C5' },
{ freq: 392.00, name: 'G4' },
{ freq: 293.66, name: 'D4' },
{ freq: 196.00, name: 'G3' }
];
useEffect(() => {
if (!audioContextRef.current) {
audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
}
return () => {
if (audioContextRef.current && audioContextRef.current.state !== 'closed') {
audioContextRef.current.close();
}
};
}, []);
useEffect(() => {
if (isPlaying) {
const beatDuration = (60 / tempo) * 250;
intervalRef.current = setInterval(() => {
setCurrentBeat(prev => (prev + 1) % BEATS);
}, beatDuration);
} else {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
}
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [isPlaying, tempo]);
useEffect(() => {
if (isPlaying && audioContextRef.current) {
grid.forEach((track, trackIndex) => {
if (track[currentBeat]) {
playNote(notes[trackIndex].freq, selectedInstrument);
}
});
}
}, [currentBeat, isPlaying]);
const playNote = (frequency, waveType) => {
const ctx = audioContextRef.current;
if (!ctx) return;
const oscillator = ctx.createOscillator();
const gainNode = ctx.createGain();
oscillator.type = waveType;
oscillator.frequency.setValueAtTime(frequency, ctx.currentTime);
gainNode.gain.setValueAtTime(volume, ctx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.2);
oscillator.connect(gainNode);
gainNode.connect(ctx.destination);
oscillator.start(ctx.currentTime);
oscillator.stop(ctx.currentTime + 0.2);
};
const toggleCell = (trackIndex, beatIndex) => {
const newGrid = grid.map((track, tIndex) =>
tIndex === trackIndex
? track.map((cell, bIndex) => bIndex === beatIndex ? !cell : cell)
: track
);
setGrid(newGrid);
};
const clearAll = () => {
setGrid(Array(TRACKS).fill(null).map(() => Array(BEATS).fill(false)));
setIsPlaying(false);
setCurrentBeat(0);
};
const randomize = () => {
setGrid(Array(TRACKS).fill(null).map(() =>
Array(BEATS).fill(null).map(() => Math.random() > 0.7)
));
};
const presets = {
arpeggio: [
[true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
[false, false, true, false, false, false, true, false, false, false, true, false, false, false, true, false],
[false, true, false, false, false, true, false, false, false, true, false, false, false, true, false, false],
[true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false]
],
beat: [
[true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
[false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false],
[true, true, false, true, false, true, true, false, true, true, false, true, false, true, true, false],
[true, false, false, false, true, false, true, false, true, false, false, false, true, false, true, false]
],
melody: [
[true, false, false, true, false, false, true, false, false, true, false, false, true, false, false, false],
[false, true, false, false, true, false, false, true, false, false, true, false, false, true, false, false],
[false, false, true, false, false, true, false, false, true, false, false, true, false, false, true, false],
[true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false]
]
};
const loadPreset = (presetName) => {
setGrid(presets[presetName]);
setIsPlaying(false);
setCurrentBeat(0);
};
const analyzeAudio = async (file) => {
if (!file) {
alert('Lütfen bir dosya seçin');
return;
}
setIsAnalyzing(true);
try {
// Ensure AudioContext is created and resumed
if (!audioContextRef.current) {
audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
}
if (audioContextRef.current.state === 'suspended') {
await audioContextRef.current.resume();
}
const ctx = audioContextRef.current;
const arrayBuffer = await file.arrayBuffer();
const audioBuffer = await ctx.decodeAudioData(arrayBuffer);
const channelData = audioBuffer.getChannelData(0);
const sampleRate = audioBuffer.sampleRate;
// Calculate energy for each 16th of the song
const segmentSize = Math.floor(channelData.length / BEATS);
const energies = [];
for (let i = 0; i < BEATS; i++) {
const start = i * segmentSize;
const end = Math.min(start + segmentSize, channelData.length);
// Calculate RMS energy for this segment
let sum = 0;
for (let j = start; j < end; j++) {
sum += channelData[j] * channelData[j];
}
const rms = Math.sqrt(sum / (end - start));
energies.push(rms);
}
// Normalize energies
const maxEnergy = Math.max(...energies);
const normalizedEnergies = energies.map(e => e / maxEnergy);
// Calculate average and use it for thresholding
const avgEnergy = normalizedEnergies.reduce((a, b) => a + b, 0) / BEATS;
const newGrid = Array(TRACKS).fill(null).map(() => Array(BEATS).fill(false));
// Create smart pattern based on energy levels
normalizedEnergies.forEach((energy, beat) => {
// Bass drum on strong beats (high energy)
if (energy > avgEnergy * 1.2) {
newGrid[3][beat] = true; // Lowest note - kick drum
}
// Snare pattern on medium energy
if (energy > avgEnergy * 0.9 && beat % 4 === 2) {
newGrid[2][beat] = true; // Mid-high note - snare
}
// Hi-hat pattern (consistent rhythm)
if (beat % 2 === 0 && energy > avgEnergy * 0.5) {
newGrid[1][beat] = true; // High note - hi-hat
}
// Melody line on peaks
if (energy > avgEnergy * 1.5) {
newGrid[0][beat] = true; // Highest note - melody
}
// Add some variation on quarter notes
if (beat % 4 === 0 && energy > avgEnergy * 0.8) {
newGrid[0][beat] = true;
}
});
// Ensure we have some pattern (if file is too quiet)
const hasNotes = newGrid.some(track => track.some(note => note));
if (!hasNotes) {
// Create a basic pattern
for (let i = 0; i < BEATS; i++) {
if (i % 4 === 0) newGrid[3][i] = true; // Kick
if (i % 4 === 2) newGrid[2][i] = true; // Snare
if (i % 2 === 0) newGrid[1][i] = true; // Hi-hat
if (i % 8 === 0 || i % 8 === 3) newGrid[0][i] = true; // Melody
}
}
setGrid(newGrid);
setIsPlaying(false);
setCurrentBeat(0);
alert('✅ Müzik başarıyla analiz edildi ve pattern oluşturuldu!');
} catch (error) {
console.error('Audio analysis error:', error);
alert('❌ Hata: ' + error.message + '\n\nLütfen geçerli bir MP3 veya WAV dosyası seçin.');
} finally {
setIsAnalyzing(false);
}
};
const handleFileUpload = (event) => {
const file = event.target.files[0];
if (file) {
if (file.type.startsWith('audio/') || file.name.endsWith('.mp3') || file.name.endsWith('.wav') || file.name.endsWith('.ogg')) {
setAudioFile(file);
analyzeAudio(file);
} else {
alert('Lütfen bir ses dosyası seçin (MP3, WAV, OGG)');
}
}
// Reset input to allow same file to be uploaded again
event.target.value = '';
};
return (
{/* Header */}
🎵 8-BIT MUSIC MAKER
RETRO SOUND SYNTHESIZER
{/* Controls */}
{/* File Upload Section */}
🎧 MP3/WAV YÜKLE & OTOMATIK OLUŞTUR
{audioFile && !isAnalyzing && (
✓ {audioFile.name}
)}
💡 MP3, WAV veya OGG dosyası seç - otomatik ritim oluşturulacak!
{/* Play Controls */}
KONTROL
{/* Tempo Control */}
setTempo(parseInt(e.target.value))}
className="w-full h-2 bg-purple-900 rounded-lg appearance-none cursor-pointer accent-cyan-400"
/>
{/* Volume Control */}
setVolume(parseFloat(e.target.value))}
className="w-full h-2 bg-purple-900 rounded-lg appearance-none cursor-pointer accent-cyan-400"
/>
{/* Instrument Selector */}
DALGA TİPİ
{instruments.map(inst => (
))}
{/* Grid */}
{grid.map((track, trackIndex) => (
{notes[trackIndex].name}
{track.map((cell, beatIndex) => (
))}
{/* Presets and Actions */}
{/* Instructions */}
🎵 Karelere tıklayarak notaları aktifleştir
🎮 Hazır melodiler için preset butonlarını kullan
🎧 Kendi müziğini yükle - otomatik 8-bit versiyonu oluşturulacak!
);
};
export default Music8Bit;
Hiç yorum yok:
Yorum Gönder