Welcome! Share code as fast as possible.
- Use the language picker to change the language manually.
- The previous link will get modified. You can then share this new link with others.
- Visit
https://code-dump.vercel.app/<extension>
- For example, to create a link which for a JavaScript code you will visit
https://code-dump.vercel.app/js
Any link generated does not have an expiry.
GitHub
import React, { useState, useEffect, useCallback } from 'react';
const EightBitSequencer = () => {
// Audio context setup
const [audioContext, setAudioContext] = useState(null);
const [isPlaying, setIsPlaying] = useState(false);
const [bpm, setBpm] = useState(120);
const [currentStep, setCurrentStep] = useState(0);
const [masterVolume, setMasterVolume] = useState(0.2);
// Sequence state
const [sequence, setSequence] = useState({
kick: Array(16).fill(false),
snare: Array(16).fill(false),
hihat: Array(16).fill(false),
bass: Array(16).fill(false),
lead1: Array(16).fill(false),
lead2: Array(16).fill(false),
lead3: Array(16).fill(false) // Added third lead
});
// Note frequencies (C major pentatonic scale)
const noteFrequencies = {
'C3': 130.81, 'D3': 146.83, 'E3': 164.81, 'G3': 196.00, 'A3': 220.00,
'C4': 261.63, 'D4': 293.66, 'E4': 329.63, 'G4': 392.00, 'A4': 440.00,
'C5': 523.25, 'D5': 587.33, 'E5': 659.26, 'G5': 783.99, 'A5': 880.00,
};
// Instrument note assignments
const [instrumentNotes, setInstrumentNotes] = useState({
bass: ['C3', 'D3', 'E3', 'G3', 'A3'],
lead1: ['C4', 'D4', 'E4', 'G4', 'A4'],
lead2: ['E4', 'G4', 'A4', 'C5', 'D5'],
lead3: ['G4', 'A4', 'C5', 'D5', 'E5'],
});
// Note selection for melodic instruments
const [selectedNotes, setSelectedNotes] = useState({
bass: Array(16).fill('C3'),
lead1: Array(16).fill('C4'),
lead2: Array(16).fill('E4'),
lead3: Array(16).fill('G4'),
});
// Initialize audio context
useEffect(() => {
const initAudio = () => {
const context = new (window.AudioContext || window.webkitAudioContext)();
setAudioContext(context);
};
if (!audioContext) {
initAudio();
}
return () => {
if (audioContext) {
audioContext.close();
}
};
}, [audioContext]);
// Create a master gain node
const [masterGainNode, setMasterGainNode] = useState(null);
useEffect(() => {
if (audioContext && !masterGainNode) {
const gainNode = audioContext.createGain();
gainNode.gain.value = masterVolume;
gainNode.connect(audioContext.destination);
setMasterGainNode(gainNode);
}
}, [audioContext, masterGainNode]);
// Update master volume
useEffect(() => {
if (masterGainNode) {
masterGainNode.gain.value = masterVolume;
}
}, [masterVolume, masterGainNode]);
// Create an oscillator for melodic sounds with limited volume
const createOscillator = useCallback((frequency, type, duration, time, detune = 0, volumeMultiplier = 1) => {
if (!audioContext || !masterGainNode) return;
const osc = audioContext.createOscillator();
const gainNode = audioContext.createGain();
osc.type = type;
osc.frequency.value = frequency;
osc.detune.value = detune;
// Adjust volume based on instrument type
const baseVolume = 0.1 * masterVolume * volumeMultiplier;
// Attack
gainNode.gain.setValueAtTime(0, time);
gainNode.gain.linearRampToValueAtTime(baseVolume, time + 0.01);
// Release
gainNode.gain.setValueAtTime(baseVolume, time + duration - 0.05);
gainNode.gain.linearRampToValueAtTime(0, time + duration);
osc.connect(gainNode).connect(masterGainNode);
osc.start(time);
osc.stop(time + duration);
}, [audioContext, masterGainNode, masterVolume]);
// Create noise for percussion with limited volume
const createNoise = useCallback((duration, time, frequency = 100, volumeMultiplier = 1) => {
if (!audioContext || !masterGainNode) return;
const bufferSize = audioContext.sampleRate * duration;
const buffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = (Math.random() * 2 - 1) * 0.3;
}
const noise = audioContext.createBufferSource();
noise.buffer = buffer;
const gainNode = audioContext.createGain();
const filter = audioContext.createBiquadFilter();
filter.type = 'highpass';
filter.frequency.value = frequency;
// Adjust volume for percussion
const baseVolume = 0.08 * masterVolume * volumeMultiplier;
gainNode.gain.setValueAtTime(baseVolume, time);
gainNode.gain.exponentialRampToValueAtTime(0.001, time + duration);
noise.connect(filter).connect(gainNode).connect(masterGainNode);
noise.start(time);
}, [audioContext, masterGainNode, masterVolume]);
// Play sounds for the current step
const playSounds = useCallback((step) => {
if (!audioContext) return;
const now = audioContext.currentTime;
// Kick drum - increased volume
if (sequence.kick[step]) {
createOscillator(50, 'sine', 0.1, now, 0, 1.5);
createOscillator(40, 'sine', 0.2, now, 0, 1.5);
}
// Snare - increased volume
if (sequence.snare[step]) {
createNoise(0.1, now, 800, 1.5);
createOscillator(150, 'triangle', 0.05, now, 0, 1.5);
}
// Hi-hat - increased volume
if (sequence.hihat[step]) {
createNoise(0.05, now, 8000, 1.5);
}
// Bass - reduced volume
if (sequence.bass[step]) {
const note = selectedNotes.bass[step];
createOscillator(noteFrequencies[note], 'square', 0.15, now, 0, 0.6);
createOscillator(noteFrequencies[note] / 2, 'sine', 0.15, now, 0, 0.6);
}
// Lead 1 - square wave
if (sequence.lead1[step]) {
const note = selectedNotes.lead1[step];
createOscillator(noteFrequencies[note], 'square', 0.1, now);
createOscillator(noteFrequencies[note], 'square', 0.1, now, 5);
}
// Lead 2 - triangle/sine wave mix
if (sequence.lead2[step]) {
const note = selectedNotes.lead2[step];
createOscillator(noteFrequencies[note], 'triangle', 0.1, now);
createOscillator(noteFrequencies[note] * 2, 'sine', 0.05, now, -5);
}
// Lead 3 - sawtooth wave for brighter sound
if (sequence.lead3[step]) {
const note = selectedNotes.lead3[step];
createOscillator(noteFrequencies[note], 'sawtooth', 0.1, now);
createOscillator(noteFrequencies[note] * 1.5, 'sawtooth', 0.08, now, 7, 0.4);
}
}, [sequence, selectedNotes, createOscillator, createNoise, audioContext]);
// Simple interval-based sequencer with correct timing
useEffect(() => {
let intervalId;
if (isPlaying) {
// Correctly calculate interval time in milliseconds
const intervalTime = (60000 / bpm) / 4; // ms per 16th note
intervalId = setInterval(() => {
playSounds(currentStep);
setCurrentStep((prev) => (prev + 1) % 16);
}, intervalTime);
}
return () => {
if (intervalId) {
clearInterval(intervalId);
}
};
}, [isPlaying, bpm, currentStep, playSounds]);
// Toggle sequencer cell
const toggleCell = (instrument, step) => {
setSequence(prev => ({
...prev,
[instrument]: prev[instrument].map((value, i) =>
i === step ? !value : value
)
}));
};
// Change note for melodic instruments
const changeNote = (instrument, step, note) => {
setSelectedNotes(prev => ({
...prev,
[instrument]: prev[instrument].map((value, i) =>
i === step ? note : value
)
}));
};
// Toggle playback
const togglePlayback = () => {
if (!isPlaying && audioContext && audioContext.state === "suspended") {
audioContext.resume();
}
setIsPlaying(!isPlaying);
setCurrentStep(0);
};
// Clear all sequences
const clearAll = () => {
setSequence({
kick: Array(16).fill(false),
snare: Array(16).fill(false),
hihat: Array(16).fill(false),
bass: Array(16).fill(false),
lead1: Array(16).fill(false),
lead2: Array(16).fill(false),
lead3: Array(16).fill(false)
});
};
// Load demo pattern
const loadDemo = () => {
setSequence({
kick: [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
snare: [false, false, true, false, false, false, true, false, false, false, true, false, false, false, true, false],
hihat: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
bass: [true, false, false, false, false, false, true, false, false, false, false, true, false, false, true, false],
lead1: [false, false, true, false, true, false, false, false, false, false, true, false, true, false, false, false],
lead2: [false, false, false, false, false, false, false, true, true, false, false, false, false, true, false, false],
lead3: [false, true, false, false, false, false, true, false, false, false, false, false, true, false, false, true]
});
setSelectedNotes({
bass: ['C3', 'C3', 'C3', 'C3', 'C3', 'C3', 'E3', 'E3', 'G3', 'G3', 'G3', 'A3', 'A3', 'A3', 'C3', 'C3'],
lead1: ['C4', 'C4', 'E4', 'E4', 'G4', 'G4', 'G4', 'G4', 'C4', 'C4', 'E4', 'E4', 'G4', 'G4', 'G4', 'G4'],
lead2: ['E4', 'E4', 'E4', 'E4', 'E4', 'E4', 'E4', 'A4', 'G4', 'G4', 'G4', 'G4', 'G4', 'A4', 'G4', 'G4'],
lead3: ['G4', 'A4', 'C5', 'C5', 'C5', 'C5', 'A4', 'G4', 'G4', 'G4', 'G4', 'G4', 'E5', 'D5', 'C5', 'G4']
});
};
// Get cell color based on state
const getCellColor = (instrument, step) => {
if (currentStep === step && isPlaying) {
return sequence[instrument][step] ? 'bg-yellow-300' : 'bg-yellow-100';
}
return sequence[instrument][step] ? getInstrumentColor(instrument) : 'bg-gray-200';
};
// Instrument-specific colors
const getInstrumentColor = (instrument) => {
switch(instrument) {
case 'kick': return 'bg-red-500';
case 'snare': return 'bg-orange-500';
case 'hihat': return 'bg-amber-500';
case 'bass': return 'bg-blue-500';
case 'lead1': return 'bg-purple-500';
case 'lead2': return 'bg-green-500';
case 'lead3': return 'bg-pink-500';
default: return 'bg-gray-500';
}
};
// Render note selector for melodic instruments
const renderNoteSelector = (instrument, step) => {
return (
<select
className="text-xs p-1 w-full bg-gray-700 text-white border border-gray-600"
value={selectedNotes[instrument][step]}
onChange={(e) => changeNote(instrument, step, e.target.value)}
disabled={!sequence[instrument][step]}
>
{instrumentNotes[instrument].map(note => (
<option key={note} value={note}>{note}</option>
))}
</select>
);
};
return (
<div className="w-full max-w-4xl mx-auto p-4 bg-gray-800 text-white rounded-lg shadow-lg">
<h1 className="text-2xl font-bold text-center mb-4">8-Bit Sequencer</h1>
<div className="flex items-center justify-between gap-4 mb-4">
<div className="flex gap-2">
<button
className={`px-4 py-2 rounded font-bold ${isPlaying ? 'bg-red-500' : 'bg-green-500'}`}
onClick={togglePlayback}
>
{isPlaying ? 'Stop' : 'Play'}
</button>
<button className="px-4 py-2 bg-gray-600 rounded" onClick={clearAll}>
Clear
</button>
<button className="px-4 py-2 bg-blue-600 rounded" onClick={loadDemo}>
Demo
</button>
</div>
<div className="flex items-center gap-2">
<label>BPM:</label>
<input
type="range"
min="60"
max="200"
value={bpm}
onChange={(e) => setBpm(parseInt(e.target.value))}
className="w-24"
/>
<span>{bpm}</span>
</div>
<div className="flex items-center gap-2">
<label>Volume:</label>
<input
type="range"
min="0.01"
max="0.5"
step="0.01"
value={masterVolume}
onChange={(e) => setMasterVolume(parseFloat(e.target.value))}
className="w-24"
/>
</div>
</div>
<div className="overflow-x-auto">
<div className="grid grid-cols-17 gap-1 mb-6 min-w-max">
{/* Column headers */}
<div className="font-bold">Instrument</div>
{Array(16).fill().map((_, i) => (
<div key={i} className="text-center">{i + 1}</div>
))}
{/* Percussion sequencer rows */}
{['kick', 'snare', 'hihat'].map(instrument => (
<React.Fragment key={instrument}>
<div className="flex items-center">
<div className={`w-4 h-4 rounded-full mr-1 ${getInstrumentColor(instrument)}`}></div>
<span className="capitalize">{instrument}</span>
</div>
{Array(16).fill().map((_, step) => (
<div
key={step}
className={`w-8 h-8 rounded cursor-pointer ${getCellColor(instrument, step)}`}
onClick={() => toggleCell(instrument, step)}
></div>
))}
</React.Fragment>
))}
{/* Melodic sequencer rows */}
{['bass', 'lead1', 'lead2', 'lead3'].map(instrument => (
<React.Fragment key={instrument}>
<div className="flex items-center">
<div className={`w-4 h-4 rounded-full mr-1 ${getInstrumentColor(instrument)}`}></div>
<span className="capitalize">
{instrument === 'lead1' ? 'Lead 1' :
instrument === 'lead2' ? 'Lead 2' :
instrument === 'lead3' ? 'Lead 3' : instrument}
</span>
</div>
{Array(16).fill().map((_, step) => (
<div key={step} className="flex flex-col">
<div
className={`w-8 h-8 rounded cursor-pointer ${getCellColor(instrument, step)}`}
onClick={() => toggleCell(instrument, step)}
></div>
{sequence[instrument][step] && renderNoteSelector(instrument, step)}
</div>
))}
</React.Fragment>
))}
</div>
</div>
<div className="mt-4 text-center text-sm text-gray-300">
Click on grid cells to activate/deactivate notes. For melody instruments, select notes from the dropdown when activated.
</div>
</div>
);
};
// Add this CSS to fix grid layout
const styles = document.createElement('style');
styles.innerHTML = `
.grid-cols-17 {
grid-template-columns: 100px repeat(16, minmax(40px, 1fr));
}
`;
document.head.appendChild(styles);
export default EightBitSequencer;