anycoder-2991ea8b / index.html
aavi21458's picture
Upload folder using huggingface_hub
baee9e3 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sam Audio Isolate | AI Sound Separation</title>
<meta name="description" content="Advanced AI audio tool to isolate vocals, drums, bass, and other instruments from any track.">
<!-- Import Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700;800&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
<!-- Import FontAwesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary: #6366f1;
--primary-glow: rgba(99, 102, 241, 0.5);
--secondary: #ec4899;
--bg-dark: #0f172a;
--bg-card: #1e293b;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--success: #10b981;
--border: #334155;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', sans-serif;
background-color: var(--bg-dark);
color: var(--text-main);
line-height: 1.6;
overflow-x: hidden;
background-image:
radial-gradient(circle at 10% 20%, rgba(99, 102, 241, 0.15) 0%, transparent 20%),
radial-gradient(circle at 90% 80%, rgba(236, 72, 153, 0.15) 0%, transparent 20%);
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* Header */
header {
padding: 1.5rem 5%;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--border);
background: rgba(15, 23, 42, 0.8);
backdrop-filter: blur(10px);
position: sticky;
top: 0;
z-index: 100;
}
.logo {
font-size: 1.5rem;
font-weight: 800;
letter-spacing: -0.05em;
display: flex;
align-items: center;
gap: 10px;
}
.logo i {
color: var(--primary);
font-size: 1.8rem;
}
.logo span {
background: linear-gradient(to right, var(--primary), var(--secondary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.built-with-link {
font-size: 0.85rem;
color: var(--text-muted);
text-decoration: none;
display: flex;
align-items: center;
gap: 6px;
transition: color 0.3s;
cursor: pointer;
}
.built-with-link:hover {
color: var(--primary);
}
/* Main Layout */
main {
flex: 1;
display: grid;
grid-template-columns: 1fr 1.2fr;
gap: 2rem;
padding: 3rem 5%;
max-width: 1400px;
margin: 0 auto;
width: 100%;
}
@media (max-width: 968px) {
main {
grid-template-columns: 1fr;
padding: 2rem 1rem;
}
}
/* Left Column: Controls */
.control-panel {
display: flex;
flex-direction: column;
gap: 2rem;
}
.hero-text h1 {
font-size: 3rem;
line-height: 1.1;
margin-bottom: 1rem;
font-weight: 800;
}
.hero-text p {
color: var(--text-muted);
font-size: 1.1rem;
max-width: 400px;
}
.input-group {
background: var(--bg-card);
padding: 2rem;
border-radius: 1rem;
border: 1px solid var(--border);
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
.label {
font-size: 0.9rem;
font-weight: 600;
color: var(--text-muted);
margin-bottom: 0.5rem;
display: block;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.text-input-wrapper {
position: relative;
margin-bottom: 2rem;
}
textarea {
width: 100%;
background: #0f172a;
border: 1px solid var(--border);
color: var(--text-main);
padding: 1rem;
border-radius: 0.5rem;
resize: vertical;
min-height: 100px;
font-family: 'Inter', sans-serif;
transition: all 0.3s ease;
font-size: 1rem;
}
textarea:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 2px var(--primary-glow);
}
.options-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.option-card {
background: #0f172a;
padding: 1rem;
border-radius: 0.5rem;
cursor: pointer;
border: 1px solid var(--border);
transition: all 0.3s;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 10px;
}
.option-card:hover {
border-color: var(--primary);
background: rgba(99, 102, 241, 0.05);
}
.option-card.active {
background: var(--primary);
border-color: var(--primary);
color: white;
box-shadow: 0 0 15px var(--primary-glow);
}
.option-card i {
font-size: 1.5rem;
}
.option-card span {
font-size: 0.9rem;
font-weight: 600;
}
.file-upload-area {
border: 2px dashed var(--border);
padding: 2rem;
border-radius: 1rem;
text-align: center;
cursor: pointer;
transition: all 0.3s;
position: relative;
}
.file-upload-area:hover {
border-color: var(--primary);
background: rgba(99, 102, 241, 0.05);
}
.file-upload-area i {
font-size: 3rem;
color: var(--text-muted);
margin-bottom: 1rem;
}
.file-name {
margin-top: 10px;
font-family: 'JetBrains Mono', monospace;
color: var(--primary);
font-size: 0.9rem;
word-break: break-all;
}
.btn-primary {
width: 100%;
padding: 1rem;
background: linear-gradient(135deg, var(--primary), var(--secondary));
border: none;
border-radius: 0.5rem;
color: white;
font-weight: 700;
font-size: 1.1rem;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(236, 72, 153, 0.3);
}
.btn-primary:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
/* Right Column: Visualization */
.visual-panel {
background: var(--bg-card);
border-radius: 1.5rem;
border: 1px solid var(--border);
padding: 2rem;
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.status-badge {
padding: 0.25rem 0.75rem;
border-radius: 2rem;
font-size: 0.8rem;
font-weight: 600;
background: rgba(16, 185, 129, 0.1);
color: var(--success);
border: 1px solid var(--success);
}
.status-badge.processing {
background: rgba(236, 72, 153, 0.1);
color: var(--secondary);
border-color: var(--secondary);
}
.waveform-container {
flex: 1;
background: #0f172a;
border-radius: 1rem;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid var(--border);
min-height: 300px;
}
canvas {
width: 100%;
height: 100%;
}
.track-info {
margin-top: 2rem;
text-align: center;
}
.track-title {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.5rem;
}
.track-subtitle {
color: var(--text-muted);
font-size: 0.9rem;
}
/* Player Controls */
.player-controls {
display: flex;
align-items: center;
gap: 1.5rem;
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid var(--border);
}
.play-btn {
width: 50px;
height: 50px;
border-radius: 50%;
background: white;
color: var(--bg-dark);
border: none;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: transform 0.2s;
font-size: 1.5rem;
}
.play-btn:hover {
transform: scale(1.1);
}
.time-display {
font-family: 'JetBrains Mono', monospace;
color: var(--text-muted);
font-size: 0.9rem;
min-width: 80px;
}
.volume-control {
margin-left: auto;
display: flex;
align-items: center;
gap: 10px;
color: var(--text-muted);
}
/* Loading Animation */
.loader-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(15, 23, 42, 0.95);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 50;
opacity: 0;
pointer-events: none;
transition: opacity 0.5s;
}
.loader-overlay.active {
opacity: 1;
pointer-events: all;
}
.loader-circle {
width: 60px;
height: 60px;
border: 4px solid var(--border);
border-top: 4px solid var(--primary);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 1.5rem;
}
.loader-text {
font-family: 'JetBrains Mono', monospace;
color: var(--primary);
animation: pulse 1.5s infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes pulse {
0% { opacity: 0.5; }
50% { opacity: 1; }
100% { opacity: 0.5; }
}
/* Result Section */
.result-section {
display: none; /* Hidden by default */
flex-direction: column;
gap: 1rem;
margin-top: 2rem;
}
.download-btn {
padding: 0.75rem;
border-radius: 0.5rem;
border: 1px solid var(--border);
background: transparent;
color: var(--text-main);
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
gap: 10px;
justify-content: center;
text-decoration: none;
font-size: 0.9rem;
}
.download-btn:hover {
background: var(--border);
color: white;
}
.isolate-note {
font-size: 0.85rem;
color: var(--text-muted);
text-align: center;
font-style: italic;
}
</style>
</head>
<body>
<header>
<div class="logo">
<i class="fa-solid fa-wave-square"></i>
<span>Sam Audio</span>
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with-link" title="Built with AnyCoder">
<i class="fa-solid fa-code"></i> Built with anycoder
</a>
</header>
<main>
<!-- Left Side: Inputs -->
<section class="control-panel">
<div class="hero-text">
<h1>Isolate any sound.<br>Describe your wish.</h1>
<p>Upload an audio file and describe the element you want to extract using our AI processing engine.</p>
</div>
<div class="input-group">
<label class="label">Describe what you want to isolate</label>
<div class="text-input-wrapper">
<textarea id="aiPrompt" placeholder="e.g., Isolate the acoustic guitar and remove all background noise...">Isolate the vocals and remove the instrumental track</textarea>
</div>
<label class="label">Select Sound Source</label>
<div class="options-grid">
<div class="option-card active" onclick="selectOption(this, 'vocals')">
<i class="fa-solid fa-microphone-lines"></i>
<span>Vocals</span>
</div>
<div class="option-card" onclick="selectOption(this, 'instrumental')">
<i class="fa-solid fa-guitar"></i>
<span>Instrumental</span>
</div>
<div class="option-card" onclick="selectOption(this, 'drums')">
<i class="fa-solid fa-drum"></i>
<span>Drums</span>
</div>
<div class="option-card" onclick="selectOption(this, 'bass')">
<i class="fa-solid fa-sliders"></i>
<span>Bass</span>
</div>
</div>
<label class="label" style="margin-top: 2rem;">Upload Audio</label>
<div class="file-upload-area" onclick="document.getElementById('fileInput').click()">
<i class="fa-solid fa-cloud-arrow-up"></i>
<p>Click to upload or drag and drop</p>
<input type="file" id="fileInput" accept="audio/*" style="display: none;" onchange="handleFileUpload(this)">
<div class="file-name" id="fileName">No file selected</div>
</div>
<button id="processBtn" class="btn-primary" onclick="startProcessing()">
<i class="fa-solid fa-wand-magic-sparkles"></i>
Process & Isolate
</button>
</div>
</section>
<!-- Right Side: Visualization -->
<section class="visual-panel">
<div class="loader-overlay" id="loader">
<div class="loader-circle"></div>
<div class="loader-text" id="loaderText">Initializing AI Model...</div>
</div>
<div class="panel-header">
<h2>Audio Workspace</h2>
<div class="status-badge" id="statusBadge">Ready</div>
</div>
<div class="waveform-container">
<canvas id="waveformCanvas"></canvas>
</div>
<div class="track-info" id="trackInfo">
<div class="track-title" id="currentTrackName">Demo Track: "Sunny Morning"</div>
<div class="track-subtitle">Sample Audio (Standard License)</div>
</div>
<div class="result-section" id="resultSection">
<h3 style="color: var(--success);">Isolation Complete!</h3>
<p class="isolate-note">Based on your prompt "Isolate the vocals...", the AI has successfully separated the vocal track from the instrumental.</p>
<a href="#" class="download-btn" onclick="event.preventDefault()">
<i class="fa-solid fa-download"></i> Download Isolated Vocals (MP3)
</a>
<a href="#" class="download-btn" onclick="event.preventDefault()">
<i class="fa-solid fa-code"></i> Download Stem (WAV)
</a>
</div>
<div class="player-controls">
<button class="play-btn" id="playBtn" onclick="togglePlay()">
<i class="fa-solid fa-play" id="playIcon"></i>
</button>
<div class="time-display" id="timeDisplay">00:00 / 00:00</div>
<audio id="audioPlayer" crossorigin="anonymous">
<!-- Using a reliable public domain sample audio -->
<source src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg">
</audio>
<div class="volume-control">
<i class="fa-solid fa-volume-high"></i>
<input type="range" min="0" max="1" step="0.01" value="1" onchange="updateVolume(this.value)" style="width: 80px;">
</div>
</div>
</section>
</main>
<script>
// --- DOM Elements ---
const canvas = document.getElementById('waveformCanvas');
const ctx = canvas.getContext('2d');
const playBtn = document.getElementById('playBtn');
const playIcon = document.getElementById('playIcon');
const audioPlayer = document.getElementById('audioPlayer');
const loader = document.getElementById('loader');
const loaderText = document.getElementById('loaderText');
const statusBadge = document.getElementById('statusBadge');
const processBtn = document.getElementById('processBtn');
const resultSection = document.getElementById('resultSection');
const fileNameDisplay = document.getElementById('fileName');
const trackInfo = document.getElementById('trackInfo');
// --- Canvas Setup ---
let animationId;
let audioContext;
let analyser;
let source;
let isPlaying = false;
function resizeCanvas() {
canvas.width = canvas.parentElement.clientWidth;
canvas.height = canvas.parentElement.clientHeight;
drawWaveform();
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// --- Audio Context Initialization ---
function initAudioContext() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
if (audioContext.state === 'suspended') {
audioContext.resume();
}
if (!analyser) {
analyser = audioContext.createAnalyser();
source = audioContext.createMediaElementSource(audioPlayer);
source.connect(analyser);
analyser.connect(audioContext.destination);
analyser.fftSize = 256;
}
}
// --- Visualization Logic ---
const bufferLength = analyser ? analyser.frequencyBinCount : 128;
const dataArray = new Uint8Array(bufferLength);
function drawWaveform() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Background Gradient
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, '#0f172a');
gradient.addColorStop(1, '#1e293b');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (!isPlaying && !analyser) {
// Draw static idle waves
drawIdleWaves();
return;
}
analyser.getByteFrequencyData(dataArray);
const barWidth = (canvas.width / bufferLength) * 2.5;
let barHeight;
let x = 0;
// Create vertical gradient for bars
const barGradient = ctx.createLinearGradient(0, canvas.height, 0, 0);
barGradient.addColorStop(0, '#ec4899'); // Pink
barGradient.addColorStop(0.5, '#6366f1'); // Indigo
barGradient.addColorStop(1, '#10b981'); // Green
ctx.fillStyle = barGradient;
for (let i = 0; i < bufferLength; i++) {
barHeight = dataArray[i] / 2; // Scale down
// Smooth curve effect
ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
animationId = requestAnimationFrame(drawWaveform);
}
function drawIdleWaves() {
ctx.fillStyle = 'rgba(99, 102, 241, 0.1)'; // Faint Indigo
const time = Date.now() * 0.002;
ctx.beginPath();
for (let i = 0; i < canvas.width; i+=5) {
const y = (canvas.height / 2) + Math.sin(i * 0.02 + time) * 30 + Math.sin(i * 0.05 - time * 2) * 10;
if (i === 0) ctx.moveTo(i, y);
else ctx.lineTo(i, y);
}
ctx.lineWidth = 2;
ctx.strokeStyle = '#6366f1';
ctx.stroke();
}
// --- Interactions ---
function togglePlay() {
initAudioContext();
if (audioPlayer.paused) {
audioPlayer.play();
isPlaying = true;
playIcon.classList.remove('fa-play');
playIcon.classList.add('fa-pause');
drawWaveform();
statusBadge.textContent = "Analyzing Audio...";
statusBadge.classList.add('processing');
} else {
audioPlayer.pause();
isPlaying = false;
playIcon.classList.remove('fa-pause');
playIcon.classList.add('fa-play');
cancelAnimationFrame(animationId);
drawWaveform(); // Redraw idle
statusBadge.textContent = "Ready";
statusBadge.classList.remove('processing');
}
}
function updateVolume(val) {
audioPlayer.volume = val;
}
audioPlayer.addEventListener('timeupdate', () => {
const current = audioPlayer.currentTime;
const duration = audioPlayer.duration;
if (!isNaN(duration)) {
const currentMin = Math.floor(current / 60);
const currentSec = Math.floor(current % 60);
const durationMin = Math.floor(duration / 60);
const durationSec = Math.floor(duration % 60);
document.getElementById('timeDisplay').textContent =
`${currentMin.toString().padStart(2, '0')}:${currentSec.toString().padStart(2, '0')} / ${durationMin.toString().padStart(2, '0')}:${durationSec.toString().padStart(2, '0')}`;
}
});
// --- File Handling ---
function handleFileUpload(input) {
if (input.files && input.files[0]) {
const file = input.files[0];
fileNameDisplay.textContent = file.name;
// Create object URL for the uploaded file
const fileURL = URL.createObjectURL(file);
audioPlayer.src = fileURL;
// Reset UI
resultSection.style.display = 'none';
trackInfo.innerHTML = `<div class="track-title" style="color: var(--primary)">${file.name}</div><div class="track-subtitle">User Uploaded File</div>`;
// Auto play for preview (optional, usually better to wait for user action)
// audioPlayer.play();
}
}
// --- Option Selection ---
window.selectOption = function(element, type) {
// Remove active class from all
document.querySelectorAll('.option-card').forEach(card => {
card.classList.remove('active');
});
// Add active to clicked
element.classList.add('active');
// Update prompt text based on selection
const promptInput = document.getElementById('aiPrompt');
let promptText = promptInput.value;
// Simple logic to replace key terms in the prompt
if (type === 'vocals') promptInput.value = "Isolate the vocals and remove the instrumental track";
if (type === 'instrumental') promptInput.value = "Remove vocals to leave only the music track";
if (type === 'drums') promptInput.value = "Extract the drum kit and percussive elements";
if (type === 'bass') promptInput.value = "Isolate the bass guitar and low frequency elements";
};
// --- Processing Simulation ---
window.startProcessing = function() {
const prompt = document.getElementById('aiPrompt').value;
if (audioPlayer.src === "") {
alert("Please upload an audio file first.");
return;
}
// 1. UI Updates
processBtn.disabled = true;
processBtn.innerHTML = '<i class="fa-solid fa-circle-notch fa-spin"></i> Processing...';
loader.classList.add('active');
statusBadge.textContent = "AI Processing...";
statusBadge.classList.add('processing');
resultSection.style.display = 'none';
// 2. Simulated Steps
const steps = [
"Uploading audio to secure environment...",
"Analyzing frequency spectrum...",
"Loading 'VocalIsolate-v4' model...",
"Separating audio stems...",
`Processing: "${prompt.substring(0, 30)}..."`,
"Refining audio edges...",
"Finalizing output..."
];
let stepIndex = 0;
const interval = setInterval(() => {
if (stepIndex < steps.length) {
loaderText.textContent = steps[stepIndex];
stepIndex++;
} else {
clearInterval(interval);
finishProcessing();
}
}, 800); // Simulate 800ms per step
};
function finishProcessing() {
setTimeout(() => {
loader.classList.remove('active');
processBtn.disabled = false;
processBtn.innerHTML = '<i class="fa-solid fa-wand-magic-sparkles"></i> Process & Isolate';
statusBadge.textContent = "Processing Complete";
statusBadge.style.backgroundColor = "rgba(16, 185, 129, 0.1)";
statusBadge.style.color = "var(--success)";
statusBadge.style.border = "1px solid var(--success)";
// Show Result
resultSection.style.display = 'flex';
// Play a "success" sound effect (optional, using a subtle oscillator beep)
playSuccessSound();
}, 500);
}
function playSuccessSound() {
const ctx = new (window.AudioContext || window.webkitAudioContext)();
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(523.25, ctx.currentTime); // C5
osc.frequency.exponentialRampToValueAtTime(1046.5, ctx.currentTime + 0.1); // C6
gain.gain.setValueAtTime(0.1, ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.5);
osc.connect(gain);
gain.connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + 0.5);
}
// Initialize idle animation
drawWaveform();
</script>
</body>
</html>