ai-bass-simulator / index.html
0Scottzilla0's picture
Add 2 files
9aaec05 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Bass Simulator - Interactive Virtual Bass Guitar</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&display=swap');
body {
font-family: 'Montserrat', sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
color: #e6e6e6;
min-height: 100vh;
overflow-x: hidden;
}
.string {
position: relative;
height: 4px;
background: linear-gradient(to right, #ddd, #fff, #ddd);
border-radius: 2px;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
transition: transform 0.1s;
z-index: 1;
}
.string::after {
content: '';
position: absolute;
top: -2px;
left: 0;
right: 0;
height: 8px;
background: transparent;
z-index: -1;
}
.string.plucked {
animation: pluck 1.5s ease-out;
}
@keyframes pluck {
0% { transform: translateY(0) scaleY(1); }
10% { transform: translateY(-10px) scaleY(1.5); }
20% { transform: translateY(5px) scaleY(0.8); }
30% { transform: translateY(-5px) scaleY(1.2); }
40% { transform: translateY(3px) scaleY(0.9); }
50% { transform: translateY(-2px) scaleY(1.1); }
60% { transform: translateY(1px) scaleY(0.95); }
70% { transform: translateY(-1px) scaleY(1.05); }
100% { transform: translateY(0) scaleY(1); }
}
.fret {
position: absolute;
width: 2px;
background: linear-gradient(to bottom, #555 0%, #888 50%, #555 100%);
z-index: 2;
}
.fret-marker {
position: absolute;
width: 12px;
height: 12px;
background: #4fd1c5;
border-radius: 50%;
z-index: 3;
}
.fingerboard {
position: relative;
background: linear-gradient(to bottom, #2d3748, #1a202c);
border-radius: 8px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
}
.fret-position {
position: absolute;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
z-index: 4;
}
.note-indicator {
position: absolute;
width: 30px;
height: 30px;
background: #4fd1c5;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #1a202c;
font-weight: bold;
transform: translate(-50%, -50%);
opacity: 0;
transition: opacity 0.2s;
z-index: 5;
}
.note-indicator.show {
opacity: 1;
}
.sound-wave {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 100px;
background: linear-gradient(to top, rgba(79, 209, 197, 0.1), transparent);
z-index: 0;
}
.ai-jammer {
transition: all 0.3s ease;
}
.ai-jammer.active {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(79, 209, 197, 0.5);
}
.genre-btn {
transition: all 0.2s ease;
}
.genre-btn.active {
transform: scale(1.05);
box-shadow: 0 0 0 2px #4fd1c5;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #1a202c;
}
::-webkit-scrollbar-thumb {
background: #4fd1c5;
border-radius: 4px;
}
</style>
</head>
<body class="relative">
<!-- Sound wave visualization (hidden by default) -->
<div class="sound-wave" id="soundWave"></div>
<!-- Main container -->
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="flex flex-col md:flex-row justify-between items-center mb-8">
<div class="flex items-center mb-4 md:mb-0">
<i class="fas fa-guitar text-4xl text-teal-400 mr-3"></i>
<h1 class="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-teal-400 to-blue-500">
AI Bass Simulator
</h1>
</div>
<div class="flex space-x-4">
<button id="settingsBtn" class="px-4 py-2 bg-gray-800 rounded-lg hover:bg-gray-700 transition flex items-center">
<i class="fas fa-cog mr-2"></i> Settings
</button>
<button id="helpBtn" class="px-4 py-2 bg-gray-800 rounded-lg hover:bg-gray-700 transition flex items-center">
<i class="fas fa-question-circle mr-2"></i> Help
</button>
</div>
</header>
<!-- Main content -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Left sidebar - Controls -->
<div class="lg:col-span-1 bg-gray-800 bg-opacity-50 rounded-xl p-6 backdrop-blur-sm">
<h2 class="text-xl font-semibold mb-4 text-teal-400 flex items-center">
<i class="fas fa-sliders-h mr-2"></i> Controls
</h2>
<!-- Volume control -->
<div class="mb-6">
<label class="block text-sm font-medium mb-2">Volume</label>
<input type="range" min="0" max="100" value="70"
class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-teal-400">
</div>
<!-- Tone control -->
<div class="mb-6">
<label class="block text-sm font-medium mb-2">Tone</label>
<input type="range" min="0" max="100" value="50"
class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-teal-400">
</div>
<!-- Playing style -->
<div class="mb-6">
<label class="block text-sm font-medium mb-2">Playing Style</label>
<div class="grid grid-cols-3 gap-2">
<button class="py-2 bg-gray-700 rounded hover:bg-gray-600 transition genre-btn active" data-style="finger">
<i class="fas fa-hand-paper"></i> Finger
</button>
<button class="py-2 bg-gray-700 rounded hover:bg-gray-600 transition genre-btn" data-style="slap">
<i class="fas fa-hand-rock"></i> Slap
</button>
<button class="py-2 bg-gray-700 rounded hover:bg-gray-600 transition genre-btn" data-style="pick">
<i class="fas fa-guitar-pick"></i> Pick
</button>
</div>
</div>
<!-- Genre selection -->
<div class="mb-6">
<label class="block text-sm font-medium mb-2">Genre</label>
<div class="grid grid-cols-2 gap-2">
<button class="py-2 px-1 text-xs bg-gray-700 rounded hover:bg-gray-600 transition genre-btn active" data-genre="funk">
Funk
</button>
<button class="py-2 px-1 text-xs bg-gray-700 rounded hover:bg-gray-600 transition genre-btn" data-genre="jazz">
Jazz
</button>
<button class="py-2 px-1 text-xs bg-gray-700 rounded hover:bg-gray-600 transition genre-btn" data-genre="rock">
Rock
</button>
<button class="py-2 px-1 text-xs bg-gray-700 rounded hover:bg-gray-600 transition genre-btn" data-genre="pop">
Pop
</button>
<button class="py-2 px-1 text-xs bg-gray-700 rounded hover:bg-gray-600 transition genre-btn" data-genre="metal">
Metal
</button>
<button class="py-2 px-1 text-xs bg-gray-700 rounded hover:bg-gray-600 transition genre-btn" data-genre="electronic">
EDM
</button>
</div>
</div>
<!-- AI Bandmates -->
<div class="mb-6">
<label class="block text-sm font-medium mb-2 flex items-center">
<i class="fas fa-robot mr-2"></i> AI Bandmates
</label>
<div class="space-y-3">
<div class="flex items-center justify-between p-3 bg-gray-700 rounded-lg ai-jammer" data-instrument="drums">
<div class="flex items-center">
<i class="fas fa-drum text-lg mr-3"></i>
<span>Drummer</span>
</div>
<div class="flex items-center">
<div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div>
<span class="text-xs">Active</span>
</div>
</div>
<div class="flex items-center justify-between p-3 bg-gray-700 rounded-lg ai-jammer" data-instrument="guitar">
<div class="flex items-center">
<i class="fas fa-guitar text-lg mr-3"></i>
<span>Guitarist</span>
</div>
<div class="flex items-center">
<div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div>
<span class="text-xs">Active</span>
</div>
</div>
<div class="flex items-center justify-between p-3 bg-gray-700 rounded-lg ai-jammer" data-instrument="keys">
<div class="flex items-center">
<i class="fas fa-music text-lg mr-3"></i>
<span>Keyboardist</span>
</div>
<div class="flex items-center">
<div class="w-3 h-3 rounded-full bg-gray-500 mr-2"></div>
<span class="text-xs">Off</span>
</div>
</div>
</div>
</div>
<!-- Record/Export -->
<div class="space-y-2">
<button class="w-full py-2 bg-red-600 hover:bg-red-700 rounded-lg transition flex items-center justify-center">
<i class="fas fa-circle mr-2"></i> Record
</button>
<button class="w-full py-2 bg-teal-600 hover:bg-teal-700 rounded-lg transition flex items-center justify-center">
<i class="fas fa-file-export mr-2"></i> Export MIDI
</button>
<button class="w-full py-2 bg-blue-600 hover:bg-blue-700 rounded-lg transition flex items-center justify-center">
<i class="fas fa-cloud-upload-alt mr-2"></i> Share Online
</button>
</div>
</div>
<!-- Center content - Bass guitar -->
<div class="lg:col-span-2">
<div class="bg-gray-800 bg-opacity-50 rounded-xl p-6 backdrop-blur-sm">
<h2 class="text-xl font-semibold mb-4 text-teal-400 flex items-center">
<i class="fas fa-guitar mr-2"></i> Virtual Bass
</h2>
<!-- Bass neck -->
<div class="fingerboard relative w-full h-64 mb-6" id="bassNeck">
<!-- Strings will be added here by JavaScript -->
<!-- Frets will be added here by JavaScript -->
<!-- Note indicators will be added here by JavaScript -->
</div>
<!-- Playback controls -->
<div class="flex justify-between items-center mb-6">
<div class="flex space-x-2">
<button class="p-3 bg-gray-700 rounded-lg hover:bg-gray-600 transition">
<i class="fas fa-backward"></i>
</button>
<button class="p-3 bg-teal-600 rounded-lg hover:bg-teal-700 transition">
<i class="fas fa-play"></i>
</button>
<button class="p-3 bg-gray-700 rounded-lg hover:bg-gray-600 transition">
<i class="fas fa-forward"></i>
</button>
</div>
<div class="text-sm">
<span class="text-teal-400">BPM:</span>
<input type="number" value="120" min="40" max="240"
class="w-16 bg-gray-700 rounded px-2 py-1 ml-2">
</div>
<div class="flex space-x-2">
<button class="p-3 bg-gray-700 rounded-lg hover:bg-gray-600 transition">
<i class="fas fa-random"></i>
</button>
<button class="p-3 bg-gray-700 rounded-lg hover:bg-gray-600 transition">
<i class="fas fa-redo"></i>
</button>
</div>
</div>
<!-- Chord progression -->
<div class="mb-6">
<label class="block text-sm font-medium mb-2">Chord Progression</label>
<div class="grid grid-cols-4 gap-2">
<select class="bg-gray-700 rounded p-2">
<option>Cmaj7</option>
<option>Dm7</option>
<option>Em7</option>
<option>Fmaj7</option>
<option>G7</option>
<option>Am7</option>
<option>Bm7b5</option>
</select>
<select class="bg-gray-700 rounded p-2">
<option>Am7</option>
<option>Dm7</option>
<option>Em7</option>
<option>Fmaj7</option>
<option>G7</option>
<option>Cmaj7</option>
<option>Bm7b5</option>
</select>
<select class="bg-gray-700 rounded p-2">
<option>Fmaj7</option>
<option>Dm7</option>
<option>Em7</option>
<option>Cmaj7</option>
<option>G7</option>
<option>Am7</option>
<option>Bm7b5</option>
</select>
<select class="bg-gray-700 rounded p-2">
<option>G7</option>
<option>Dm7</option>
<option>Em7</option>
<option>Fmaj7</option>
<option>Cmaj7</option>
<option>Am7</option>
<option>Bm7b5</option>
</select>
</div>
</div>
<!-- AI Suggestions -->
<div class="bg-gray-800 rounded-lg p-4">
<div class="flex items-center justify-between mb-2">
<h3 class="text-sm font-medium text-teal-400 flex items-center">
<i class="fas fa-lightbulb mr-2"></i> AI Suggestions
</h3>
<button class="text-xs bg-gray-700 px-2 py-1 rounded hover:bg-gray-600">
<i class="fas fa-sync-alt mr-1"></i> Refresh
</button>
</div>
<div class="grid grid-cols-3 gap-2">
<button class="text-xs bg-gray-700 p-2 rounded hover:bg-gray-600 truncate">
Walking Bass Line
</button>
<button class="text-xs bg-gray-700 p-2 rounded hover:bg-gray-600 truncate">
Funk Groove
</button>
<button class="text-xs bg-gray-700 p-2 rounded hover:bg-gray-600 truncate">
Rock Riff
</button>
<button class="text-xs bg-gray-700 p-2 rounded hover:bg-gray-600 truncate">
Syncopated
</button>
<button class="text-xs bg-gray-700 p-2 rounded hover:bg-gray-600 truncate">
Octaves
</button>
<button class="text-xs bg-gray-700 p-2 rounded hover:bg-gray-600 truncate">
Slap Pattern
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Multiplayer section -->
<div class="mt-8 bg-gray-800 bg-opacity-50 rounded-xl p-6 backdrop-blur-sm">
<h2 class="text-xl font-semibold mb-4 text-teal-400 flex items-center">
<i class="fas fa-users mr-2"></i> Multiplayer Jam Session
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<!-- Current users -->
<div class="bg-gray-800 rounded-lg p-4">
<h3 class="text-sm font-medium mb-3">Online Players (3)</h3>
<div class="space-y-3">
<div class="flex items-center">
<div class="w-8 h-8 rounded-full bg-teal-500 flex items-center justify-center mr-3">
<i class="fas fa-user"></i>
</div>
<div>
<p class="text-sm">BassMaster42</p>
<p class="text-xs text-gray-400">Funk</p>
</div>
</div>
<div class="flex items-center">
<div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center mr-3">
<i class="fas fa-user"></i>
</div>
<div>
<p class="text-sm">SlapQueen</p>
<p class="text-xs text-gray-400">Slap</p>
</div>
</div>
<div class="flex items-center">
<div class="w-8 h-8 rounded-full bg-purple-500 flex items-center justify-center mr-3">
<i class="fas fa-user"></i>
</div>
<div>
<p class="text-sm">JazzCat</p>
<p class="text-xs text-gray-400">Jazz</p>
</div>
</div>
</div>
</div>
<!-- Chat -->
<div class="bg-gray-800 rounded-lg p-4 md:col-span-2">
<h3 class="text-sm font-medium mb-3">Chat</h3>
<div class="h-32 overflow-y-auto mb-3 space-y-2">
<div class="text-sm">
<span class="text-teal-400">BassMaster42:</span> Anyone up for a funk jam?
</div>
<div class="text-sm">
<span class="text-blue-400">SlapQueen:</span> I'm in! 120 BPM?
</div>
<div class="text-sm">
<span class="text-purple-400">JazzCat:</span> Let's do it
</div>
</div>
<div class="flex">
<input type="text" placeholder="Type a message..."
class="flex-grow bg-gray-700 rounded-l px-3 py-2 focus:outline-none">
<button class="bg-teal-600 hover:bg-teal-700 px-4 rounded-r">
<i class="fas fa-paper-plane"></i>
</button>
</div>
</div>
</div>
<div class="mt-4 flex justify-center">
<button class="px-6 py-2 bg-teal-600 hover:bg-teal-700 rounded-lg transition">
<i class="fas fa-plug mr-2"></i> Join Jam Session
</button>
</div>
</div>
</div>
<!-- Note indicator template -->
<div class="note-indicator" id="noteIndicatorTemplate">
<span class="text-sm">E</span>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize bass guitar
const bassNeck = document.getElementById('bassNeck');
const noteIndicatorTemplate = document.getElementById('noteIndicatorTemplate');
// Create strings (4 strings for bass)
const strings = [
{ note: 'E', thickness: 4, color: '#ddd' },
{ note: 'A', thickness: 3, color: '#ccc' },
{ note: 'D', thickness: 2, color: '#bbb' },
{ note: 'G', thickness: 1.5, color: '#aaa' }
];
// Create frets (20 frets)
const fretCount = 20;
// Calculate positions
const neckWidth = bassNeck.offsetWidth;
const neckHeight = bassNeck.offsetHeight;
const stringSpacing = neckHeight / (strings.length + 1);
// Add strings to the neck
strings.forEach((string, stringIndex) => {
const stringElement = document.createElement('div');
stringElement.className = 'string';
stringElement.style.width = `${neckWidth}px`;
stringElement.style.height = `${string.thickness}px`;
stringElement.style.top = `${(stringIndex + 1) * stringSpacing}px`;
stringElement.style.background = `linear-gradient(to right, ${string.color}, #fff, ${string.color})`;
stringElement.dataset.note = string.note;
stringElement.dataset.string = stringIndex;
// Add pluck interaction
stringElement.addEventListener('mousedown', function(e) {
this.classList.add('plucked');
// Calculate fret position
const rect = this.getBoundingClientRect();
const x = e.clientX - rect.left;
const fretPosition = Math.floor((x / neckWidth) * (fretCount + 1));
// Show note indicator
const noteIndicator = noteIndicatorTemplate.cloneNode(true);
noteIndicator.id = '';
noteIndicator.style.left = `${x}px`;
noteIndicator.style.top = `${(stringIndex + 1) * stringSpacing}px`;
noteIndicator.querySelector('span').textContent = getNoteForFret(string.note, fretPosition);
noteIndicator.classList.add('show');
bassNeck.appendChild(noteIndicator);
// Play sound (simulated)
playBassSound(stringIndex, fretPosition);
// Remove indicator after animation
setTimeout(() => {
noteIndicator.classList.remove('show');
setTimeout(() => noteIndicator.remove(), 200);
}, 1000);
});
stringElement.addEventListener('mouseup', function() {
this.classList.remove('plucked');
});
bassNeck.appendChild(stringElement);
});
// Add frets to the neck
for (let i = 0; i <= fretCount; i++) {
const fretElement = document.createElement('div');
fretElement.className = 'fret';
fretElement.style.left = `${(i / fretCount) * neckWidth}px`;
fretElement.style.height = `${neckHeight}px`;
// Add fret markers at specific positions
if ([3, 5, 7, 9, 12, 15, 17, 19].includes(i)) {
const markerElement = document.createElement('div');
markerElement.className = 'fret-marker';
markerElement.style.left = `${(i / fretCount) * neckWidth}px`;
markerElement.style.top = `${neckHeight / 2 - 6}px`;
// Double markers at 12th fret
if (i === 12) {
const markerElement2 = markerElement.cloneNode();
markerElement2.style.top = `${neckHeight / 2 + 6}px`;
bassNeck.appendChild(markerElement2);
}
bassNeck.appendChild(markerElement);
}
bassNeck.appendChild(fretElement);
}
// Function to calculate note based on string and fret
function getNoteForFret(stringNote, fretPosition) {
const notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
const stringIndex = notes.indexOf(stringNote);
const noteIndex = (stringIndex + fretPosition) % 12;
return notes[noteIndex];
}
// Simulate bass sound (in a real app, this would use Web Audio API)
function playBassSound(stringIndex, fretPosition) {
// Visual feedback
const soundWave = document.getElementById('soundWave');
soundWave.style.opacity = '1';
soundWave.style.background = `linear-gradient(to top, rgba(79, 209, 197, ${0.2 + Math.random() * 0.3}), transparent)`;
setTimeout(() => {
soundWave.style.opacity = '0';
}, 300);
// In a real implementation, we would:
// 1. Use Web Audio API to play a sampled bass sound
// 2. Adjust pitch based on fret position
// 3. Apply different filters based on playing style
// 4. Add physical modeling effects (string vibration, fret noise)
}
// Style buttons interaction
const styleButtons = document.querySelectorAll('[data-style]');
styleButtons.forEach(button => {
button.addEventListener('click', function() {
styleButtons.forEach(btn => btn.classList.remove('active'));
this.classList.add('active');
// Change visual feedback based on style
const strings = document.querySelectorAll('.string');
strings.forEach(string => {
if (this.dataset.style === 'slap') {
string.style.boxShadow = '0 0 10px rgba(255, 100, 100, 0.5)';
} else if (this.dataset.style === 'pick') {
string.style.boxShadow = '0 0 10px rgba(100, 255, 100, 0.5)';
} else {
string.style.boxShadow = '0 0 10px rgba(255, 255, 255, 0.3)';
}
});
});
});
// Genre buttons interaction
const genreButtons = document.querySelectorAll('[data-genre]');
genreButtons.forEach(button => {
button.addEventListener('click', function() {
genreButtons.forEach(btn => btn.classList.remove('active'));
this.classList.add('active');
// Change AI suggestions based on genre
// In a real app, this would adjust the AI's playing style
});
});
// AI bandmates interaction
const aiJammers = document.querySelectorAll('.ai-jammer');
aiJammers.forEach(jammer => {
jammer.addEventListener('click', function() {
const isActive = this.querySelector('.bg-green-500');
if (isActive) {
this.querySelector('.bg-green-500').classList.replace('bg-green-500', 'bg-gray-500');
this.querySelector('span').textContent = 'Off';
this.classList.remove('active');
} else {
this.querySelector('.bg-gray-500').classList.replace('bg-gray-500', 'bg-green-500');
this.querySelector('span').textContent = 'Active';
this.classList.add('active');
}
});
});
// Settings button
document.getElementById('settingsBtn').addEventListener('click', function() {
alert('Settings panel would open here');
});
// Help button
document.getElementById('helpBtn').addEventListener('click', function() {
alert('Help documentation would open here');
});
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=0Scottzilla0/ai-bass-simulator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>