![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/soundstudiopro.com/public_html/ |
<?php
session_start();
// Include security tracking
require_once 'includes/security_tracking.php';
// Include security functions for admin validation
require_once 'includes/security.php';
// Include audio token system for signed URLs
require_once 'utils/audio_token.php';
// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
header('Location: auth/login.php');
exit;
}
// Validate admin access
validateAdminAccess();
// Set page variables for header
$page_title = 'SoundStudioPro Studio - Professional AI Music Production Platform';
$page_description = 'Advanced AI music generation, lyrics creation, audio processing, and video production in one professional studio environment.';
$current_page = 'studio';
// Include header
include 'includes/header.php';
// Get user data
require_once 'config/database.php';
$pdo = getDBConnection();
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch();
// Get user's recent tracks
$stmt = $pdo->prepare("SELECT * FROM music_tracks WHERE user_id = ? ORDER BY created_at DESC LIMIT 10");
$stmt->execute([$_SESSION['user_id']]);
$recentTracks = $stmt->fetchAll();
?>
<div class="studio-container">
<!-- Studio Header -->
<div class="studio-header">
<div class="studio-header-content">
<div class="studio-title">
<h1>ποΈ SoundStudioPro Studio</h1>
<p>Professional AI Music Production Platform</p>
</div>
<div class="studio-user-info">
<div class="user-credits">
<i class="fas fa-coins"></i>
<span><?php echo $user['credits']; ?> Credits</span>
</div>
<div class="user-plan">
<i class="fas fa-crown"></i>
<span><?php echo ucfirst($user['plan']); ?> Plan</span>
</div>
</div>
</div>
</div>
<!-- Studio Navigation - Simplified -->
<div class="studio-nav">
<div class="studio-nav-item active" data-section="dashboard">
<i class="fas fa-home"></i>
<span>Home</span>
</div>
<div class="studio-nav-item" data-section="create">
<i class="fas fa-plus-circle"></i>
<span>Create</span>
</div>
<div class="studio-nav-item" data-section="process">
<i class="fas fa-tools"></i>
<span>Process</span>
</div>
<div class="studio-nav-item" data-section="library">
<i class="fas fa-folder"></i>
<span>My Library</span>
</div>
</div>
<!-- Studio Content -->
<div class="studio-content">
<!-- Dashboard Section -->
<div id="dashboard" class="studio-section active">
<div class="section-header">
<h2>ποΈ Studio Dashboard</h2>
<p>Welcome to your professional music production workspace</p>
</div>
<div class="dashboard-grid">
<!-- Quick Stats -->
<div class="dashboard-card stats-card">
<h3>π Quick Stats</h3>
<div class="stats-grid">
<div class="stat-item">
<div class="stat-number"><?php echo count($recentTracks); ?></div>
<div class="stat-label">Total Tracks</div>
</div>
<div class="stat-item">
<div class="stat-number"><?php echo $user['credits']; ?></div>
<div class="stat-label">Available Credits</div>
</div>
<div class="stat-item">
<div class="stat-number"><?php echo ucfirst($user['plan']); ?></div>
<div class="stat-label">Current Plan</div>
</div>
<div class="stat-item">
<div class="stat-number">8</div>
<div class="stat-label">Active Tools</div>
</div>
</div>
</div>
<!-- Recent Projects -->
<div class="dashboard-card projects-card">
<h3>π΅ Recent Projects</h3>
<div class="projects-list">
<?php if (empty($recentTracks)): ?>
<div class="empty-state">
<i class="fas fa-music"></i>
<p>No tracks created yet</p>
<button onclick="openCreateMusicModal()" class="btn btn-primary">Create Your First Track</button>
</div>
<?php else: ?>
<?php foreach (array_slice($recentTracks, 0, 5) as $track): ?>
<div class="project-item" data-track-id="<?php echo $track['id']; ?>">
<div class="project-info">
<div class="project-title"><?php echo htmlspecialchars($track['title']); ?></div>
<div class="project-type"><?php echo ucfirst($track['music_type']); ?></div>
</div>
<div class="project-status <?php echo $track['status']; ?>">
<?php echo ucfirst($track['status']); ?>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- Quick Actions -->
<div class="dashboard-card actions-card">
<h3>β‘ Quick Actions</h3>
<div class="actions-grid">
<button onclick="openCreateMusicModal()" class="action-btn">
<i class="fas fa-music"></i>
<span>Create Music</span>
</button>
<button onclick="openAdvancedFunctionsModal()" class="action-btn">
<i class="fas fa-tools"></i>
<span>Advanced Tools</span>
</button>
<button onclick="if(window.ajaxNavigation){window.ajaxNavigation.navigateToPage('/library.php')}else{window.location.href='/library.php'}" class="action-btn">
<i class="fas fa-folder"></i>
<span>View Library</span>
</button>
<button onclick="if(window.ajaxNavigation){window.ajaxNavigation.navigateToPage('/community_fixed.php')}else{window.location.href='/community_fixed.php'}" class="action-btn">
<i class="fas fa-users"></i>
<span>Community</span>
</button>
</div>
</div>
<!-- Available Tools -->
<div class="dashboard-card features-card">
<h3>β¨ Available Tools</h3>
<div class="features-list">
<div class="feature-item available">
<i class="fas fa-music"></i>
<span>AI Music Generation</span>
</div>
<div class="feature-item available">
<i class="fas fa-layer-group"></i>
<span>Full Stem Separation</span>
<span class="badge-new">NEW</span>
</div>
<div class="feature-item available">
<i class="fas fa-microphone-slash"></i>
<span>Vocal Separation</span>
</div>
<div class="feature-item available">
<i class="fas fa-file-audio"></i>
<span>WAV Conversion</span>
</div>
<div class="feature-item available">
<i class="fas fa-video"></i>
<span>Music Videos</span>
</div>
<div class="feature-item available">
<i class="fas fa-chart-line"></i>
<span>Track Extension</span>
</div>
<div class="feature-item available">
<i class="fas fa-pen"></i>
<span>Lyrics Generation</span>
</div>
<div class="feature-item available">
<i class="fas fa-rocket"></i>
<span>Boost Style</span>
</div>
</div>
</div>
</div>
</div>
<!-- Create Section - All Creation Tools -->
<div id="create" class="studio-section">
<div class="section-header">
<h2>β¨ Create</h2>
<p>Generate music, lyrics, and extend your tracks</p>
</div>
<div class="tools-grid">
<div class="tool-card featured">
<div class="tool-icon">
<i class="fas fa-music"></i>
</div>
<h3>AI Music Generation</h3>
<p>Create original music with AI using text prompts</p>
<div class="tool-features">
<span>Multiple AI Models</span>
<span>Custom Prompts</span>
<span>Professional Quality</span>
</div>
<button onclick="openCreateMusicModal()" class="tool-btn">
<i class="fas fa-play"></i>
Create Music
</button>
</div>
<div class="tool-card">
<div class="tool-icon">
<i class="fas fa-pen"></i>
</div>
<h3>Lyrics Generation</h3>
<p>Generate professional lyrics with AI</p>
<div class="tool-features">
<span>Multiple Themes</span>
<span>Style Options</span>
<span>Language Support</span>
</div>
<button onclick="openAdvancedFunctionsModal()" class="tool-btn">
<i class="fas fa-play"></i>
Generate Lyrics
</button>
</div>
<div class="tool-card">
<div class="tool-icon">
<i class="fas fa-chart-line"></i>
</div>
<h3>Track Extension</h3>
<p>Extend existing tracks with AI-powered continuation</p>
<div class="tool-features">
<span>Seamless Extension</span>
<span>Style Preservation</span>
<span>Quality Enhancement</span>
</div>
<button onclick="openAdvancedFunctionsModal()" class="tool-btn">
<i class="fas fa-play"></i>
Extend Track
</button>
</div>
</div>
</div>
<!-- Process Section - All Processing Tools -->
<div id="process" class="studio-section">
<div class="section-header">
<h2>π§ Process</h2>
<p>Enhance, separate, and convert your audio</p>
</div>
<div class="tools-grid">
<div class="tool-card featured new-feature">
<div class="tool-badge">NEW</div>
<div class="tool-icon">
<i class="fas fa-layer-group"></i>
</div>
<h3>Full Stem Separation</h3>
<p>Separate audio into individual stems: vocals, drums, bass, guitar, and more</p>
<div class="tool-features">
<span>12+ Stems</span>
<span>High Quality</span>
<span>Professional Results</span>
</div>
<button onclick="openAdvancedFunctionsModal('vocalRemoval')" class="tool-btn">
<i class="fas fa-play"></i>
Separate All Stems
</button>
</div>
<div class="tool-card">
<div class="tool-icon">
<i class="fas fa-microphone-slash"></i>
</div>
<h3>Vocal Separation</h3>
<p>Extract vocals and instrumental tracks separately</p>
<div class="tool-features">
<span>2-Stem Mode</span>
<span>High Quality</span>
<span>Multiple Formats</span>
</div>
<button onclick="openAdvancedFunctionsModal('vocalRemoval')" class="tool-btn">
<i class="fas fa-play"></i>
Separate Vocals
</button>
</div>
<div class="tool-card">
<div class="tool-icon">
<i class="fas fa-file-audio"></i>
</div>
<h3>WAV Conversion</h3>
<p>Convert to high-quality WAV format for professional use</p>
<div class="tool-features">
<span>Lossless Quality</span>
<span>Multiple Settings</span>
<span>Studio Ready</span>
</div>
<button onclick="openAdvancedFunctionsModal()" class="tool-btn">
<i class="fas fa-play"></i>
Convert to WAV
</button>
</div>
<div class="tool-card">
<div class="tool-icon">
<i class="fas fa-rocket"></i>
</div>
<h3>Boost Style</h3>
<p>Enhance and refine music styles with AI processing</p>
<div class="tool-features">
<span>Style Enhancement</span>
<span>Quality Boost</span>
<span>Professional Polish</span>
</div>
<button onclick="openBoostStyleModal()" class="tool-btn">
<i class="fas fa-play"></i>
Boost Style
</button>
</div>
<div class="tool-card">
<div class="tool-icon">
<i class="fas fa-video"></i>
</div>
<h3>Music Video</h3>
<p>Create visual music videos from audio tracks</p>
<div class="tool-features">
<span>Multiple Styles</span>
<span>High Quality</span>
<span>Visual Effects</span>
</div>
<button onclick="openAdvancedFunctionsModal()" class="tool-btn">
<i class="fas fa-play"></i>
Create Video
</button>
</div>
</div>
</div>
<!-- Timeline Mixer Section -->
<div id="timeline" class="studio-section">
<div class="section-header">
<h2>ποΈ Professional DAW Studio</h2>
<p>Advanced Digital Audio Workstation with Real-Time Processing</p>
</div>
<!-- Professional DAW Interface -->
<div class="daw-container">
<!-- DAW Toolbar -->
<div class="daw-toolbar">
<div class="toolbar-left">
<button class="toolbar-btn" id="saveProject">
<i class="fas fa-save"></i>
<span>Save Project</span>
</button>
<button class="toolbar-btn" id="loadProject">
<i class="fas fa-folder-open"></i>
<span>Load Project</span>
</button>
<button class="toolbar-btn" id="exportProject">
<i class="fas fa-download"></i>
<span>Export</span>
</button>
</div>
<div class="toolbar-center">
<div class="project-info">
<span class="project-name">SoundStudioPro Session</span>
<span class="project-bpm">BPM: <span id="sessionBPM">120</span></span>
<span class="project-key">Key: <span id="sessionKey">C</span></span>
</div>
</div>
<div class="toolbar-right">
<button class="toolbar-btn" id="undoBtn">
<i class="fas fa-undo"></i>
<span>Undo</span>
</button>
<button class="toolbar-btn" id="redoBtn">
<i class="fas fa-redo"></i>
<span>Redo</span>
</button>
<button class="toolbar-btn" id="settingsBtn">
<i class="fas fa-cog"></i>
<span>Settings</span>
</button>
</div>
</div>
<!-- Transport Section -->
<div class="transport-section">
<div class="transport-left">
<button class="transport-btn large" id="playBtn">
<i class="fas fa-play"></i>
</button>
<button class="transport-btn" id="pauseBtn">
<i class="fas fa-pause"></i>
</button>
<button class="transport-btn" id="stopBtn">
<i class="fas fa-stop"></i>
</button>
<button class="transport-btn record" id="recordBtn">
<i class="fas fa-circle"></i>
</button>
</div>
<div class="transport-center">
<div class="time-display">
<span id="currentTime">00:00.000</span>
<span class="time-separator">/</span>
<span id="totalTime">00:00.000</span>
</div>
<div class="tempo-controls">
<button class="tempo-btn" id="tempoDown">-</button>
<span class="tempo-display">BPM: <span id="tempoValue">120</span></span>
<button class="tempo-btn" id="tempoUp">+</button>
</div>
</div>
<div class="transport-right">
<button class="transport-btn" id="metronomeBtn">
<i class="fas fa-bell"></i>
</button>
<button class="transport-btn" id="loopBtn">
<i class="fas fa-redo"></i>
</button>
<button class="transport-btn" id="snapBtn">
<i class="fas fa-magnet"></i>
</button>
<button class="transport-btn" id="quantizeBtn">
<i class="fas fa-align-left"></i>
</button>
</div>
</div>
<!-- Timeline Ruler -->
<div class="timeline-ruler">
<div class="ruler-markers">
<div class="ruler-marker" data-time="0">0</div>
<div class="ruler-marker" data-time="30">30s</div>
<div class="ruler-marker" data-time="60">1m</div>
<div class="ruler-marker" data-time="90">1m30s</div>
<div class="ruler-marker" data-time="120">2m</div>
<div class="ruler-marker" data-time="150">2m30s</div>
<div class="ruler-marker" data-time="180">3m</div>
</div>
<div class="playhead" id="playhead"></div>
</div>
<!-- Track List -->
<div class="track-list-container">
<div class="track-list">
<?php if (empty($recentTracks)): ?>
<div class="empty-timeline">
<i class="fas fa-music"></i>
<p>No tracks available for timeline</p>
<button onclick="openCreateMusicModal()" class="btn btn-primary">Create Your First Track</button>
</div>
<?php else: ?>
<?php foreach ($recentTracks as $index => $track): ?>
<div class="track-row" data-track-id="<?php echo $track['id']; ?>">
<!-- Track Header -->
<div class="track-header">
<div class="track-info">
<div class="track-name"><?php echo htmlspecialchars($track['title']); ?></div>
<div class="track-type"><?php echo ucfirst($track['music_type']); ?></div>
</div>
<div class="track-controls">
<button class="track-btn mute-btn" data-track="<?php echo $track['id']; ?>" title="Mute">
<i class="fas fa-volume-mute"></i>
</button>
<button class="track-btn solo-btn" data-track="<?php echo $track['id']; ?>" title="Solo">
<i class="fas fa-headphones"></i>
</button>
<button class="track-btn record-btn" data-track="<?php echo $track['id']; ?>" title="Record">
<i class="fas fa-circle"></i>
</button>
<button class="track-btn arm-btn" data-track="<?php echo $track['id']; ?>" title="Arm">
<i class="fas fa-microphone"></i>
</button>
</div>
</div>
<!-- Track Timeline -->
<div class="track-timeline">
<div class="track-clip"
data-track-id="<?php echo $track['id']; ?>"
data-audio-url="<?php echo htmlspecialchars(getSignedAudioUrl($track['id'])); ?>"
data-duration="<?php echo $track['duration'] ?? 30; ?>"
data-start-time="0"
style="width: <?php echo min(($track['duration'] ?? 30) * 2, 100); ?>%;">
<div class="clip-content">
<i class="fas fa-music"></i>
<span class="clip-name"><?php echo htmlspecialchars($track['title']); ?></span>
</div>
<div class="clip-handle left-handle"></div>
<div class="clip-handle right-handle"></div>
<div class="clip-waveform">
<canvas class="waveform-canvas" width="200" height="40"></canvas>
</div>
</div>
</div>
<!-- Track Mixer - Redesigned -->
<div class="track-mixer-new">
<!-- EQ Section -->
<div class="mixer-eq">
<div class="eq-label">EQ</div>
<div class="eq-controls">
<div class="eq-band">
<label>Low</label>
<div class="eq-knob-container">
<div class="eq-knob" data-track="<?php echo $track['id']; ?>" data-band="low">
<div class="eq-knob-value">0</div>
</div>
</div>
</div>
<div class="eq-band">
<label>Mid</label>
<div class="eq-knob-container">
<div class="eq-knob" data-track="<?php echo $track['id']; ?>" data-band="mid">
<div class="eq-knob-value">0</div>
</div>
</div>
</div>
<div class="eq-band">
<label>High</label>
<div class="eq-knob-container">
<div class="eq-knob" data-track="<?php echo $track['id']; ?>" data-band="high">
<div class="eq-knob-value">0</div>
</div>
</div>
</div>
</div>
</div>
<!-- Volume Fader -->
<div class="mixer-fader-new">
<div class="fader-label">Volume</div>
<div class="fader-container">
<div class="fader-track-new">
<div class="fader-scale">
<div class="scale-mark">+6</div>
<div class="scale-mark">0</div>
<div class="scale-mark">-6</div>
<div class="scale-mark">-12</div>
<div class="scale-mark">-β</div>
</div>
<div class="fader-knob-new" data-track="<?php echo $track['id']; ?>" style="bottom: 50%;">
<div class="fader-grip"></div>
</div>
</div>
</div>
<div class="fader-value-new">0.0 dB</div>
</div>
<!-- Pan Control -->
<div class="mixer-pan-new">
<div class="pan-label">Pan</div>
<div class="pan-container">
<div class="pan-track">
<div class="pan-mark pan-center">C</div>
<div class="pan-mark pan-left">L</div>
<div class="pan-mark pan-right">R</div>
<div class="pan-knob-new" data-track="<?php echo $track['id']; ?>" style="left: 50%;">
<div class="pan-indicator-new"></div>
</div>
</div>
</div>
<div class="pan-value-new">Center</div>
</div>
<!-- Meter -->
<div class="track-meter-new">
<div class="meter-label">Level</div>
<div class="meter-container">
<div class="meter-bar-new">
<div class="meter-green"></div>
<div class="meter-yellow"></div>
<div class="meter-red"></div>
<div class="meter-level-new" data-track="<?php echo $track['id']; ?>"></div>
<div class="meter-peak" data-track="<?php echo $track['id']; ?>"></div>
</div>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- Master Section -->
<div class="master-section">
<div class="master-label">Master</div>
<div class="master-fader">
<div class="fader-track">
<div class="fader-knob master-knob"></div>
</div>
<div class="fader-value">0dB</div>
</div>
<div class="master-meter">
<div class="meter-bar">
<div class="meter-level" id="masterLevel"></div>
</div>
</div>
<div class="master-controls">
<button class="master-btn" id="masterMute">
<i class="fas fa-volume-mute"></i>
</button>
<button class="master-btn" id="masterSolo">
<i class="fas fa-headphones"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Library Section -->
<div id="library" class="studio-section">
<div class="section-header">
<h2>π My Library</h2>
<p>Your music tracks and projects</p>
</div>
<div style="text-align: center; margin-bottom: 2rem;">
<button onclick="if(window.ajaxNavigation){window.ajaxNavigation.navigateToPage('/library.php')}else{window.location.href='/library.php'}" class="btn btn-primary" style="padding: 1rem 2rem; font-size: 1.6rem;">
<i class="fas fa-folder-open"></i>
View Full Library
</button>
</div>
<div class="library-actions">
<button onclick="if(window.ajaxNavigation){window.ajaxNavigation.navigateToPage('/library.php')}else{window.location.href='/library.php'}" class="library-btn">
<i class="fas fa-folder"></i>
<span>View All Tracks</span>
</button>
<button onclick="if(window.ajaxNavigation){window.ajaxNavigation.navigateToPage('/artists.php')}else{window.location.href='/artists.php'}" class="library-btn">
<i class="fas fa-users"></i>
<span>Discover Artists</span>
</button>
<button onclick="if(window.ajaxNavigation){window.ajaxNavigation.navigateToPage('/community_fixed.php')}else{window.location.href='/community_fixed.php'}" class="library-btn">
<i class="fas fa-comments"></i>
<span>Community</span>
</button>
</div>
</div>
<!-- Analytics Section -->
<div id="analytics" class="studio-section">
<div class="section-header">
<h2>π Analytics</h2>
<p>Track your music performance and insights</p>
</div>
<div class="analytics-grid">
<div class="analytics-card">
<h3>Track Performance</h3>
<div class="analytics-content">
<div class="metric">
<span class="metric-value"><?php echo count($recentTracks); ?></span>
<span class="metric-label">Total Tracks</span>
</div>
<div class="metric">
<span class="metric-value"><?php echo $user['credits']; ?></span>
<span class="metric-label">Available Credits</span>
</div>
</div>
</div>
<div class="analytics-card">
<h3>Usage Statistics</h3>
<div class="analytics-content">
<div class="metric">
<span class="metric-value">5</span>
<span class="metric-label">Active Tools</span>
</div>
<div class="metric">
<span class="metric-value"><?php echo ucfirst($user['plan']); ?></span>
<span class="metric-label">Current Plan</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
/* Studio Styles */
.studio-container {
min-height: 100vh;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 50%, #16213e 100%);
color: #e2e8f0;
position: relative;
}
/* Studio Notifications */
.studio-notification {
position: fixed;
top: 120px;
right: 20px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 10px;
padding: 1.5rem 2rem;
color: #e2e8f0;
font-size: 1.4rem;
font-weight: 600;
z-index: 1000;
transform: translateX(400px);
transition: all 0.3s ease;
max-width: 350px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}
.studio-notification.show {
transform: translateX(0);
}
.studio-notification.success {
border-color: rgba(72, 187, 120, 0.5);
background: rgba(72, 187, 120, 0.1);
}
.studio-notification.error {
border-color: rgba(245, 101, 101, 0.5);
background: rgba(245, 101, 101, 0.1);
}
.studio-notification.warning {
border-color: rgba(237, 137, 54, 0.5);
background: rgba(237, 137, 54, 0.1);
}
.notification-content {
display: flex;
align-items: center;
gap: 1rem;
}
.notification-content i {
font-size: 1.8rem;
}
.studio-notification.success i {
color: #48bb78;
}
.studio-notification.error i {
color: #f56565;
}
.studio-notification.warning i {
color: #ed8936;
}
/* Playable Project Items */
.project-item.playable {
cursor: pointer;
transition: all 0.3s ease;
}
.project-item.playable:hover {
background: rgba(102, 126, 234, 0.1);
border-color: rgba(102, 126, 234, 0.3);
transform: translateY(-2px);
}
.project-item.playable::after {
content: 'βΆ';
position: absolute;
right: 1rem;
color: #667eea;
font-size: 1.2rem;
opacity: 0;
transition: opacity 0.3s ease;
}
.project-item.playable:hover::after {
opacity: 1;
}
/* Real-time Status Indicators */
.project-status.processing {
animation: pulse 2s infinite;
}
.project-status.complete {
background: rgba(72, 187, 120, 0.2);
color: #48bb78;
animation: success-glow 0.5s ease;
}
.project-status.failed {
background: rgba(245, 101, 101, 0.2);
color: #f56565;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
@keyframes success-glow {
0% { box-shadow: 0 0 5px rgba(72, 187, 120, 0.5); }
100% { box-shadow: none; }
}
/* Studio Header */
.studio-header {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
padding: 2rem 0;
}
.studio-header-content {
max-width: 1400px;
margin: 0 auto;
padding: 0 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.studio-title h1 {
font-size: 3.2rem;
font-weight: 800;
margin: 0;
background: linear-gradient(45deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.studio-title p {
font-size: 1.6rem;
color: #a0aec0;
margin: 0.5rem 0 0 0;
}
.studio-user-info {
display: flex;
gap: 2rem;
align-items: center;
}
.user-credits, .user-plan {
display: flex;
align-items: center;
gap: 0.8rem;
padding: 1rem 1.5rem;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
font-size: 1.4rem;
font-weight: 600;
}
.user-credits i, .user-plan i {
color: #667eea;
font-size: 1.6rem;
}
/* Studio Navigation */
.studio-nav {
display: flex;
gap: 1rem;
padding: 2rem;
max-width: 1400px;
margin: 0 auto;
overflow-x: auto;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.studio-nav-item {
display: flex;
align-items: center;
gap: 0.8rem;
padding: 1rem 1.5rem;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
cursor: pointer;
transition: all 0.3s ease;
color: #a0aec0;
font-size: 1.4rem;
font-weight: 600;
white-space: nowrap;
}
.studio-nav-item:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(102, 126, 234, 0.3);
color: #e2e8f0;
}
.studio-nav-item.active {
background: linear-gradient(45deg, #667eea, #764ba2);
border-color: rgba(102, 126, 234, 0.5);
color: white;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}
.studio-nav-item i {
font-size: 1.6rem;
}
/* Studio Content */
.studio-content {
max-width: 1400px;
margin: 0 auto;
padding: 2rem;
}
.studio-section {
display: none;
}
.studio-section.active {
display: block;
}
.section-header {
text-align: center;
margin-bottom: 4rem;
}
.section-header h2 {
font-size: 3.6rem;
font-weight: 700;
margin-bottom: 1rem;
background: linear-gradient(45deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.section-header p {
font-size: 1.8rem;
color: #a0aec0;
}
/* Dashboard Grid */
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.dashboard-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
padding: 2rem;
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.dashboard-card:hover {
transform: translateY(-5px);
border-color: rgba(102, 126, 234, 0.3);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}
.dashboard-card h3 {
font-size: 2rem;
font-weight: 700;
margin-bottom: 2rem;
color: #e2e8f0;
}
/* Stats Grid */
.stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
}
.stat-item {
text-align: center;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
}
.stat-number {
font-size: 2.4rem;
font-weight: 700;
color: #667eea;
display: block;
}
.stat-label {
font-size: 1.2rem;
color: #a0aec0;
margin-top: 0.5rem;
}
/* Projects List */
.projects-list {
max-height: 300px;
overflow-y: auto;
}
.project-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
margin-bottom: 1rem;
position: relative;
transition: all 0.3s ease;
}
.project-title {
font-weight: 600;
color: #e2e8f0;
}
.project-type {
font-size: 1.2rem;
color: #a0aec0;
}
.project-status {
padding: 0.5rem 1rem;
border-radius: 20px;
font-size: 1.2rem;
font-weight: 600;
}
.project-status.complete {
background: rgba(72, 187, 120, 0.2);
color: #48bb78;
}
.project-status.processing {
background: rgba(237, 137, 54, 0.2);
color: #ed8936;
}
.project-status.failed {
background: rgba(245, 101, 101, 0.2);
color: #f56565;
}
/* Actions Grid */
.actions-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.action-btn {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.8rem;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
color: #e2e8f0;
cursor: pointer;
transition: all 0.3s ease;
font-size: 1.4rem;
font-weight: 600;
}
.action-btn:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(102, 126, 234, 0.3);
transform: translateY(-2px);
}
.action-btn i {
font-size: 2rem;
color: #667eea;
}
/* Features List */
.features-list {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.feature-item {
display: flex;
align-items: center;
gap: 0.8rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
font-size: 1.4rem;
font-weight: 600;
}
.feature-item i {
color: #667eea;
font-size: 1.6rem;
}
/* Tools Grid */
.tools-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 2rem;
}
.tool-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
padding: 2.5rem;
text-align: center;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.tool-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(45deg, #667eea, #764ba2);
}
.tool-card:hover {
transform: translateY(-5px);
border-color: rgba(102, 126, 234, 0.3);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3);
}
.tool-icon {
width: 80px;
height: 80px;
background: linear-gradient(45deg, #667eea, #764ba2);
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 2rem;
font-size: 3.2rem;
color: white;
}
.tool-card h3 {
font-size: 2.4rem;
font-weight: 700;
margin-bottom: 1rem;
color: #e2e8f0;
}
.tool-card p {
font-size: 1.6rem;
color: #a0aec0;
margin-bottom: 2rem;
line-height: 1.6;
}
.tool-features {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 2rem;
justify-content: center;
}
.tool-features span {
padding: 0.5rem 1rem;
background: rgba(102, 126, 234, 0.2);
color: #667eea;
border-radius: 20px;
font-size: 1.2rem;
font-weight: 600;
}
/* Featured Tool Cards */
.tool-card.featured {
border: 2px solid rgba(102, 126, 234, 0.5);
background: linear-gradient(135deg, rgba(102, 126, 234, 0.15), rgba(118, 75, 162, 0.15));
box-shadow: 0 8px 30px rgba(102, 126, 234, 0.2);
}
.tool-card.new-feature {
position: relative;
overflow: visible;
}
.tool-badge {
position: absolute;
top: -12px;
right: -12px;
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
font-size: 1rem;
padding: 0.5rem 1rem;
border-radius: 20px;
font-weight: 700;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
z-index: 10;
animation: pulse 2s infinite;
text-transform: uppercase;
letter-spacing: 0.5px;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}
50% {
transform: scale(1.05);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
}
}
/* Feature List Badges */
.feature-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
margin-bottom: 0.5rem;
position: relative;
}
.feature-item.available {
border-left: 3px solid #48bb78;
}
.badge-new {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
font-size: 0.9rem;
padding: 0.2rem 0.6rem;
border-radius: 12px;
font-weight: 600;
margin-left: auto;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.tool-btn {
width: 100%;
padding: 1.2rem 2rem;
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 10px;
font-size: 1.6rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 0.8rem;
}
.tool-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
/* Library Actions */
.library-actions {
display: flex;
gap: 2rem;
justify-content: center;
flex-wrap: wrap;
}
.library-btn {
display: flex;
align-items: center;
gap: 1rem;
padding: 1.5rem 2.5rem;
background: rgba(255, 255, 255, 0.1);
border: 2px solid rgba(255, 255, 255, 0.2);
border-radius: 10px;
color: #e2e8f0;
font-size: 1.6rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
}
.library-btn:hover {
background: rgba(255, 255, 255, 0.2);
border-color: rgba(102, 126, 234, 0.5);
transform: translateY(-2px);
}
.library-btn i {
font-size: 2rem;
color: #667eea;
}
/* Analytics Grid */
.analytics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.analytics-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
padding: 2rem;
}
.analytics-card h3 {
font-size: 2rem;
font-weight: 700;
margin-bottom: 2rem;
color: #e2e8f0;
}
.analytics-content {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
}
.metric {
text-align: center;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
}
.metric-value {
font-size: 2.4rem;
font-weight: 700;
color: #667eea;
display: block;
}
.metric-label {
font-size: 1.2rem;
color: #a0aec0;
margin-top: 0.5rem;
}
/* Empty State */
.empty-state {
text-align: center;
padding: 3rem;
color: #a0aec0;
}
.empty-state i {
font-size: 4rem;
margin-bottom: 1rem;
color: #667eea;
}
.empty-state p {
font-size: 1.6rem;
margin-bottom: 2rem;
}
/* Timeline Mixer Styles */
.timeline-mixer-container {
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 50%, #16213e 100%);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 15px;
margin: 2rem 0;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
/* DAW Toolbar */
.daw-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background: rgba(255, 255, 255, 0.05);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.toolbar-left, .toolbar-right {
display: flex;
gap: 1rem;
}
.toolbar-center {
display: flex;
align-items: center;
gap: 2rem;
}
.toolbar-btn {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
background: rgba(255, 255, 255, 0.08);
color: #a0aec0;
font-size: 1.4rem;
cursor: pointer;
transition: all 0.3s ease;
}
.toolbar-btn:hover {
background: rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.5);
color: #e2e8f0;
}
.toolbar-btn.large {
width: 120px;
justify-content: flex-start;
padding-left: 1rem;
}
.toolbar-btn i {
font-size: 1.6rem;
}
.project-info {
display: flex;
align-items: center;
gap: 1rem;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
padding: 0.5rem 1rem;
font-size: 1.4rem;
color: #a0aec0;
}
.project-name {
font-weight: 600;
color: #e2e8f0;
}
.project-bpm, .project-key {
display: flex;
align-items: center;
gap: 0.5rem;
font-weight: 600;
color: #667eea;
}
.project-bpm span, .project-key span {
font-size: 1.6rem;
color: #e2e8f0;
}
/* Transport Section */
.transport-section {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background: rgba(255, 255, 255, 0.05);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.transport-left, .transport-right {
display: flex;
gap: 1rem;
}
.transport-center {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.transport-btn {
width: 50px;
height: 50px;
border: 2px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
background: rgba(255, 255, 255, 0.05);
color: #e2e8f0;
font-size: 1.8rem;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.transport-btn:hover {
background: rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.5);
transform: scale(1.1);
}
.transport-btn.active {
background: linear-gradient(45deg, #667eea, #764ba2);
border-color: rgba(102, 126, 234, 0.8);
box-shadow: 0 0 20px rgba(102, 126, 234, 0.4);
}
.transport-btn.record {
background: rgba(245, 101, 101, 0.2);
border-color: rgba(245, 101, 101, 0.5);
color: #f56565;
}
.transport-btn.record.active {
background: rgba(245, 101, 101, 0.5);
border-color: rgba(245, 101, 101, 0.8);
box-shadow: 0 0 20px rgba(245, 101, 101, 0.4);
}
.time-display {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.8rem;
font-weight: 700;
color: #e2e8f0;
}
.time-separator {
color: #667eea;
}
.tempo-controls {
display: flex;
align-items: center;
gap: 1rem;
font-size: 1.4rem;
color: #a0aec0;
}
.tempo-btn {
width: 30px;
height: 30px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
background: rgba(255, 255, 255, 0.08);
color: #a0aec0;
font-size: 1.2rem;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.tempo-btn:hover {
background: rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.5);
color: #e2e8f0;
}
.tempo-display {
font-weight: 600;
color: #e2e8f0;
}
.tempo-value {
font-size: 1.6rem;
color: #667eea;
}
/* Timeline Ruler */
.timeline-ruler {
position: relative;
height: 40px;
background: rgba(255, 255, 255, 0.02);
border-radius: 5px;
display: flex;
align-items: center;
padding: 0 1rem;
}
.ruler-markers {
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
padding: 0 1rem;
}
.ruler-marker {
color: #a0aec0;
font-size: 1.2rem;
font-weight: 600;
cursor: pointer;
transition: color 0.3s ease;
}
.ruler-marker:hover {
color: #667eea;
}
.playhead {
position: absolute;
top: 0;
bottom: 0;
width: 2px;
background: #667eea;
border-radius: 1px;
left: 0;
z-index: 10;
}
/* Track List */
.track-list-container {
max-height: 400px;
overflow-y: auto;
background: rgba(255, 255, 255, 0.03);
border-radius: 10px;
margin-top: 1rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.track-list {
display: flex;
flex-direction: column;
}
.track-row {
display: grid;
grid-template-columns: 200px 1fr 150px;
gap: 1rem;
padding: 1rem 2rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
transition: background 0.3s ease;
}
.track-row:last-child {
border-bottom: none;
}
.track-row:hover {
background: rgba(255, 255, 255, 0.02);
}
/* Track Header */
.track-header {
display: flex;
flex-direction: column;
gap: 1rem;
}
.track-info {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.track-name {
font-size: 1.4rem;
font-weight: 600;
color: #e2e8f0;
}
.track-type {
font-size: 1.2rem;
color: #a0aec0;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.track-controls {
display: flex;
gap: 0.5rem;
}
.track-btn {
width: 35px;
height: 35px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 5px;
background: rgba(255, 255, 255, 0.05);
color: #a0aec0;
font-size: 1.2rem;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.track-btn:hover {
background: rgba(102, 126, 234, 0.2);
color: #667eea;
}
.track-btn.active {
background: rgba(102, 126, 234, 0.3);
color: #667eea;
border-color: rgba(102, 126, 234, 0.5);
}
.track-btn.record-btn {
background: rgba(245, 101, 101, 0.2);
border-color: rgba(245, 101, 101, 0.5);
color: #f56565;
}
.track-btn.record-btn.active {
background: rgba(245, 101, 101, 0.5);
border-color: rgba(245, 101, 101, 0.8);
box-shadow: 0 0 20px rgba(245, 101, 101, 0.4);
}
.track-btn.arm-btn {
background: rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.5);
color: #667eea;
}
.track-btn.arm-btn.active {
background: rgba(102, 126, 234, 0.5);
border-color: rgba(102, 126, 234, 0.8);
box-shadow: 0 0 20px rgba(102, 126, 234, 0.4);
}
/* Track Timeline */
.track-timeline {
position: relative;
height: 60px;
background: rgba(255, 255, 255, 0.02);
border-radius: 5px;
overflow: hidden;
}
.track-clip {
position: absolute;
top: 10px;
left: 10px;
height: 40px;
background: linear-gradient(45deg, #667eea, #764ba2);
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
padding: 0 1rem;
min-width: 100px;
}
.track-clip:hover {
transform: scale(1.02);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
}
.clip-content {
display: flex;
align-items: center;
gap: 0.8rem;
color: white;
font-size: 1.2rem;
font-weight: 600;
width: 100%;
}
.clip-handle {
position: absolute;
top: 0;
bottom: 0;
width: 8px;
background: rgba(255, 255, 255, 0.3);
cursor: ew-resize;
transition: background 0.3s ease;
}
.clip-handle:hover {
background: rgba(255, 255, 255, 0.5);
}
.left-handle {
left: 0;
border-radius: 5px 0 0 5px;
}
.right-handle {
right: 0;
border-radius: 0 5px 5px 0;
}
/* Track Mixer - Redesigned */
.track-mixer-new {
display: grid;
grid-template-columns: auto 1fr auto auto;
gap: 1.5rem;
align-items: start;
padding: 1rem;
background: rgba(0, 0, 0, 0.3);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* EQ Section */
.mixer-eq {
display: flex;
flex-direction: column;
gap: 0.5rem;
min-width: 120px;
}
.eq-label {
font-size: 0.85rem;
color: #a0aec0;
text-align: center;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.eq-controls {
display: flex;
gap: 0.8rem;
justify-content: center;
}
.eq-band {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.4rem;
}
.eq-band label {
font-size: 0.75rem;
color: #94a3b8;
font-weight: 600;
}
.eq-knob-container {
position: relative;
width: 50px;
height: 50px;
}
.eq-knob {
width: 50px;
height: 50px;
border-radius: 50%;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2), rgba(118, 75, 162, 0.2));
border: 2px solid rgba(102, 126, 234, 0.4);
position: relative;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
}
.eq-knob:hover {
border-color: rgba(102, 126, 234, 0.7);
background: linear-gradient(135deg, rgba(102, 126, 234, 0.3), rgba(118, 75, 162, 0.3));
transform: scale(1.05);
}
.eq-knob:active {
transform: scale(0.95);
}
.eq-knob-value {
font-size: 0.7rem;
color: #e2e8f0;
font-weight: 700;
pointer-events: none;
}
/* Volume Fader */
.mixer-fader-new {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
min-width: 60px;
}
.fader-label {
font-size: 0.85rem;
color: #a0aec0;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.fader-container {
position: relative;
width: 100%;
}
.fader-track-new {
width: 30px;
height: 200px;
background: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.1));
border: 2px solid rgba(255, 255, 255, 0.15);
border-radius: 15px;
position: relative;
margin: 0 auto;
box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.5);
}
.fader-scale {
position: absolute;
left: -25px;
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 5px 0;
font-size: 0.65rem;
color: #94a3b8;
font-weight: 600;
}
.scale-mark {
height: 1px;
width: 8px;
background: rgba(255, 255, 255, 0.3);
margin-left: auto;
}
.fader-knob-new {
position: absolute;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 16px;
background: linear-gradient(135deg, #667eea, #764ba2);
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 8px;
cursor: grab;
transition: box-shadow 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
z-index: 10;
}
.fader-knob-new:active {
cursor: grabbing;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.6);
}
.fader-grip {
width: 100%;
height: 100%;
background: repeating-linear-gradient(
90deg,
rgba(255, 255, 255, 0.2) 0px,
rgba(255, 255, 255, 0.2) 2px,
transparent 2px,
transparent 4px
);
border-radius: 6px;
}
.fader-value-new {
font-size: 0.9rem;
color: #e2e8f0;
font-weight: 700;
min-height: 1.2rem;
text-align: center;
}
/* Pan Control */
.mixer-pan-new {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
min-width: 100px;
}
.pan-label {
font-size: 0.85rem;
color: #a0aec0;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.pan-container {
width: 100%;
position: relative;
}
.pan-track {
width: 100%;
height: 30px;
background: rgba(0, 0, 0, 0.4);
border: 2px solid rgba(255, 255, 255, 0.15);
border-radius: 15px;
position: relative;
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.5);
}
.pan-mark {
position: absolute;
top: 50%;
transform: translateY(-50%);
font-size: 0.7rem;
color: #94a3b8;
font-weight: 700;
pointer-events: none;
}
.pan-center {
left: 50%;
transform: translate(-50%, -50%);
}
.pan-left {
left: 5px;
}
.pan-right {
right: 5px;
}
.pan-knob-new {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 24px;
height: 24px;
background: linear-gradient(135deg, #667eea, #764ba2);
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
z-index: 10;
}
.pan-knob-new:hover {
transform: translate(-50%, -50%) scale(1.1);
box-shadow: 0 3px 10px rgba(102, 126, 234, 0.5);
}
.pan-knob-new:active {
transform: translate(-50%, -50%) scale(0.95);
}
.pan-indicator-new {
position: absolute;
top: 50%;
left: 50%;
width: 3px;
height: 12px;
background: #fff;
transform: translate(-50%, -50%);
border-radius: 2px;
pointer-events: none;
}
.pan-value-new {
font-size: 0.85rem;
color: #e2e8f0;
font-weight: 600;
min-height: 1.2rem;
text-align: center;
}
/* Meter */
.track-meter-new {
display: flex;
flex-direction: column;
gap: 0.5rem;
min-width: 40px;
}
.meter-label {
font-size: 0.85rem;
color: #a0aec0;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
text-align: center;
}
.meter-container {
width: 100%;
height: 200px;
position: relative;
}
.meter-bar-new {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
border: 2px solid rgba(255, 255, 255, 0.15);
border-radius: 8px;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.5);
}
.meter-green {
flex: 1;
background: linear-gradient(to top, #48bb78, #38a169);
opacity: 0.3;
}
.meter-yellow {
flex: 1;
background: linear-gradient(to top, #ed8936, #dd6b20);
opacity: 0.3;
}
.meter-red {
flex: 1;
background: linear-gradient(to top, #f56565, #e53e3e);
opacity: 0.3;
}
.meter-level-new {
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 100%;
background: linear-gradient(to top, #48bb78 0%, #48bb78 40%, #ed8936 40%, #ed8936 70%, #f56565 70%, #f56565 100%);
transition: height 0.05s linear;
height: 0%;
border-radius: 0 0 6px 6px;
}
.meter-peak {
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 2px;
background: #fff;
height: 0%;
margin: 0 auto;
opacity: 0;
transition: opacity 0.3s ease;
z-index: 5;
}
.meter-peak.active {
opacity: 1;
}
/* Master Section */
.master-section {
display: flex;
align-items: center;
gap: 2rem;
padding: 1.5rem 2rem;
background: rgba(255, 255, 255, 0.05);
border-top: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
.master-label {
font-size: 1.6rem;
font-weight: 700;
color: #e2e8f0;
min-width: 80px;
}
.master-fader {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.master-knob {
background: linear-gradient(45deg, #f56565, #ed8936);
}
.master-meter {
flex: 1;
max-width: 200px;
}
.master-controls {
display: flex;
gap: 1rem;
}
.master-btn {
width: 40px;
height: 40px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
background: rgba(255, 255, 255, 0.08);
color: #a0aec0;
font-size: 1.4rem;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.master-btn:hover {
background: rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.5);
color: #e2e8f0;
}
.master-btn.active {
background: linear-gradient(45deg, #667eea, #764ba2);
border-color: rgba(102, 126, 234, 0.8);
box-shadow: 0 0 20px rgba(102, 126, 234, 0.4);
}
/* Responsive Design */
@media (max-width: 768px) {
.studio-header-content {
flex-direction: column;
gap: 2rem;
text-align: center;
}
.studio-title h1 {
font-size: 2.4rem;
}
.studio-nav {
padding: 1rem;
}
.studio-nav-item {
padding: 0.8rem 1.2rem;
font-size: 1.2rem;
}
.tools-grid {
grid-template-columns: 1fr;
}
.dashboard-grid {
grid-template-columns: 1fr;
}
.stats-grid {
grid-template-columns: 1fr;
}
.actions-grid {
grid-template-columns: 1fr;
}
.features-list {
grid-template-columns: 1fr;
}
.library-actions {
flex-direction: column;
}
.analytics-content {
grid-template-columns: 1fr;
}
.studio-notification {
right: 10px;
left: 10px;
max-width: none;
}
.track-row {
grid-template-columns: 1fr;
gap: 1rem;
}
.track-mixer-new {
grid-template-columns: 1fr;
gap: 1rem;
}
.mixer-eq {
min-width: 100%;
}
.eq-controls {
justify-content: space-around;
}
.fader-track-new {
height: 150px;
}
.meter-container {
height: 150px;
}
.transport-controls {
flex-direction: column;
gap: 1rem;
}
.transport-center {
order: -1;
}
}
</style>
<script>
// Studio Navigation
document.addEventListener('DOMContentLoaded', function() {
const navItems = document.querySelectorAll('.studio-nav-item');
const sections = document.querySelectorAll('.studio-section');
navItems.forEach(item => {
item.addEventListener('click', function() {
const targetSection = this.getAttribute('data-section');
// Remove active class from all nav items and sections
navItems.forEach(nav => nav.classList.remove('active'));
sections.forEach(section => section.classList.remove('active'));
// Add active class to clicked nav item and corresponding section
this.classList.add('active');
document.getElementById(targetSection).classList.add('active');
});
});
// Initialize real-time updates
initializeStudioUpdates();
});
// Real-time Studio Updates
let studioUpdateInterval;
let processingTracks = new Set();
function initializeStudioUpdates() {
console.log('ποΈ Initializing studio real-time updates...');
// Start periodic status checks (optimized for performance)
// Only check when page is visible
studioUpdateInterval = setInterval(function() {
if (!document.hidden) {
checkProcessingTracks();
}
}, 10000); // Increased from 5 to 10 seconds for better performance
// Initial check
checkProcessingTracks();
// Update user stats periodically (optimized)
setInterval(function() {
if (!document.hidden) {
updateUserStats();
}
}, 20000); // Increased from 10 to 20 seconds for better performance
}
function checkProcessingTracks() {
// Get all processing tracks from the page
const processingElements = document.querySelectorAll('.project-status.processing');
if (processingElements.length === 0) {
return; // No processing tracks to check
}
processingElements.forEach(element => {
const projectItem = element.closest('.project-item');
if (!projectItem) return;
// Extract track ID from data attribute or find a way to identify the track
const trackId = projectItem.getAttribute('data-track-id');
if (!trackId) return;
// Check status via API
checkTrackStatus(trackId, projectItem);
});
}
function checkTrackStatus(trackId, projectElement) {
fetch(`/api/check_track_status.php?track_id=${trackId}`)
.then(response => response.json())
.then(data => {
if (data.success && data.data) {
const track = data.data;
updateProjectStatus(projectElement, track);
}
})
.catch(error => {
console.error('Error checking track status:', error);
});
}
function updateProjectStatus(projectElement, track) {
const statusElement = projectElement.querySelector('.project-status');
const titleElement = projectElement.querySelector('.project-title');
if (!statusElement || !titleElement) return;
// Update status
statusElement.className = `project-status ${track.status}`;
statusElement.textContent = track.status.charAt(0).toUpperCase() + track.status.slice(1);
// Update title if needed
if (track.title && titleElement.textContent !== track.title) {
titleElement.textContent = track.title;
}
// Show notification for completed tracks
if (track.status === 'complete') {
showStudioNotification(`π΅ "${track.title}" is ready!`, 'success');
// Update stats
updateUserStats();
// Add play functionality if audio URL is available
if (track.audio_url) {
projectElement.classList.add('playable');
projectElement.addEventListener('click', () => playStudioTrack(track));
}
} else if (track.status === 'failed') {
showStudioNotification(`β "${track.title}" failed to process`, 'error');
}
}
function updateUserStats() {
// Update the stats display with fresh data
fetch('/api/get_user_stats.php')
.then(response => response.json())
.then(data => {
if (data.success) {
updateStatsDisplay(data.data);
}
})
.catch(error => {
console.error('Error updating user stats:', error);
});
}
function updateStatsDisplay(stats) {
// Update total tracks
const totalTracksElement = document.querySelector('.stat-number');
if (totalTracksElement && stats.total_tracks !== undefined) {
totalTracksElement.textContent = stats.total_tracks;
}
// Update credits (if available)
const creditsElement = document.querySelector('.user-credits span');
if (creditsElement && stats.credits !== undefined) {
creditsElement.textContent = `${stats.credits} Credits`;
}
}
function showStudioNotification(message, type = 'info') {
// Create notification element
const notification = document.createElement('div');
notification.className = `studio-notification ${type}`;
notification.innerHTML = `
<div class="notification-content">
<i class="${getNotificationIcon(type)}"></i>
<span>${message}</span>
</div>
`;
// Add to studio container
const studioContainer = document.querySelector('.studio-container');
if (studioContainer) {
studioContainer.appendChild(notification);
}
// Show animation
setTimeout(() => {
notification.classList.add('show');
}, 100);
// Auto remove after 5 seconds
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
if (notification.parentElement) {
notification.remove();
}
}, 300);
}, 5000);
}
function getNotificationIcon(type) {
switch (type) {
case 'success': return 'fas fa-check-circle';
case 'error': return 'fas fa-exclamation-circle';
case 'warning': return 'fas fa-exclamation-triangle';
default: return 'fas fa-info-circle';
}
}
function playStudioTrack(track) {
// Check if global player is available
if (window.enhancedGlobalPlayer && typeof window.enhancedGlobalPlayer.playTrack === 'function') {
window.enhancedGlobalPlayer.playTrack(track.audio_url, track.title, 'SoundStudioPro');
showStudioNotification(`π΅ Playing "${track.title}"`, 'success');
} else {
showStudioNotification('Audio player not available. Please refresh the page.', 'error');
}
}
// Open modal functions (these should be defined in your existing code)
function openCreateMusicModal() {
// This function should be defined in your existing modal code
console.log('Opening create music modal');
}
function openAdvancedFunctionsModal() {
// This function should be defined in your existing modal code
console.log('Opening advanced functions modal');
}
// New Pro Studio Modal Functions
// Removed unavailable features: Add Vocals, Add Instrumental, Replace Section, Persona Manager
// These endpoints are not available in API.box yet
// New Pro Studio Modal Functions - Now implemented with modals
// Functions are defined in includes/pro_studio_modals.php
// Cleanup on page unload
window.addEventListener('beforeunload', function() {
if (studioUpdateInterval) {
clearInterval(studioUpdateInterval);
}
});
// Timeline Mixer JavaScript
function initializeTimelineMixer() {
console.log('ποΈ Initializing timeline mixer...');
// Transport controls
initializeTransportControls();
// Track clips
initializeTrackClips();
// Mixer controls
initializeMixerControls();
// Master meter animation
animateMasterMeter();
}
function initializeTransportControls() {
const playBtn = document.getElementById('playBtn');
const pauseBtn = document.getElementById('pauseBtn');
const stopBtn = document.getElementById('stopBtn');
const recordBtn = document.getElementById('recordBtn');
if (playBtn) {
playBtn.addEventListener('click', function() {
this.classList.add('active');
pauseBtn.classList.remove('active');
playTimeline();
});
}
if (pauseBtn) {
pauseBtn.addEventListener('click', function() {
this.classList.add('active');
playBtn.classList.remove('active');
pauseTimeline();
});
}
if (stopBtn) {
stopBtn.addEventListener('click', function() {
playBtn.classList.remove('active');
pauseBtn.classList.remove('active');
stopTimeline();
});
}
if (recordBtn) {
recordBtn.addEventListener('click', function() {
this.classList.toggle('active');
toggleRecording();
});
}
}
function initializeTrackClips() {
const clips = document.querySelectorAll('.track-clip');
clips.forEach(clip => {
clip.addEventListener('click', function() {
const audioUrl = this.getAttribute('data-audio-url');
const trackName = this.querySelector('.clip-name').textContent;
if (audioUrl) {
playTrackClip(audioUrl, trackName);
}
});
// Make clips draggable
makeClipDraggable(clip);
});
}
function initializeMixerControls() {
// Fader controls (new design)
const faders = document.querySelectorAll('.fader-knob-new');
faders.forEach(fader => {
makeFaderDraggableNew(fader);
});
// Pan controls (new design)
const panKnobs = document.querySelectorAll('.pan-knob-new');
panKnobs.forEach(knob => {
makePanDraggableNew(knob);
});
// EQ controls
const eqKnobs = document.querySelectorAll('.eq-knob');
eqKnobs.forEach(knob => {
makeEQDraggable(knob);
});
// Track control buttons
const muteBtns = document.querySelectorAll('.mute-btn');
muteBtns.forEach(btn => {
btn.addEventListener('click', function() {
this.classList.toggle('active');
toggleTrackMute(this.getAttribute('data-track'));
});
});
const soloBtns = document.querySelectorAll('.solo-btn');
soloBtns.forEach(btn => {
btn.addEventListener('click', function() {
this.classList.toggle('active');
toggleTrackSolo(this.getAttribute('data-track'));
});
});
// Initialize meters
initializeMeters();
}
function makeClipDraggable(clip) {
let isDragging = false;
let startX = 0;
let startLeft = 0;
clip.addEventListener('mousedown', function(e) {
isDragging = true;
startX = e.clientX;
startLeft = clip.offsetLeft;
clip.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
const deltaX = e.clientX - startX;
const newLeft = Math.max(0, startLeft + deltaX);
clip.style.left = newLeft + 'px';
});
document.addEventListener('mouseup', function() {
if (isDragging) {
isDragging = false;
clip.style.cursor = 'grab';
}
});
}
function makeFaderDraggableNew(fader) {
let isDragging = false;
let startY = 0;
let startBottom = 0;
const faderTrack = fader.closest('.fader-track-new');
const faderContainer = fader.closest('.mixer-fader-new');
if (!faderTrack || !faderContainer) return;
fader.addEventListener('mousedown', function(e) {
isDragging = true;
startY = e.clientY;
const currentBottom = parseFloat(getComputedStyle(fader).bottom) || 50;
startBottom = currentBottom;
e.preventDefault();
e.stopPropagation();
});
const handleMove = function(e) {
if (!isDragging) return;
const deltaY = startY - e.clientY; // Inverted for fader (up = louder)
const trackHeight = faderTrack.offsetHeight;
const knobHeight = fader.offsetHeight;
const maxBottom = trackHeight - knobHeight;
const minBottom = 0;
let newBottom = Math.max(minBottom, Math.min(maxBottom, startBottom + (deltaY / trackHeight * 100)));
fader.style.bottom = newBottom + '%';
// Convert to dB (-β to +6dB)
const percentage = newBottom / maxBottom;
let dbValue;
if (percentage <= 0.01) {
dbValue = -Infinity;
} else {
// Map 0-100% to -60dB to +6dB (logarithmic)
dbValue = (percentage * 66) - 60;
if (dbValue > 6) dbValue = 6;
}
// Update display
const valueElement = faderContainer.querySelector('.fader-value-new');
if (valueElement) {
if (dbValue === -Infinity) {
valueElement.textContent = '-β dB';
} else {
valueElement.textContent = dbValue.toFixed(1) + ' dB';
}
}
// Update audio engine
const trackId = fader.getAttribute('data-track');
if (window.dawEngine && trackId) {
// Convert dB to linear gain (0 to ~2.0)
const linearGain = dbValue === -Infinity ? 0 : Math.pow(10, dbValue / 20);
window.dawEngine.setTrackVolume(trackId, Math.max(0, Math.min(2, linearGain)));
}
};
const handleUp = function() {
if (isDragging) {
isDragging = false;
}
};
document.addEventListener('mousemove', handleMove);
document.addEventListener('mouseup', handleUp);
document.addEventListener('mouseleave', handleUp);
// Touch support
fader.addEventListener('touchstart', function(e) {
isDragging = true;
startY = e.touches[0].clientY;
const currentBottom = parseFloat(getComputedStyle(fader).bottom) || 50;
startBottom = currentBottom;
e.preventDefault();
});
document.addEventListener('touchmove', function(e) {
if (!isDragging) return;
const touch = e.touches[0];
const deltaY = startY - touch.clientY;
const trackHeight = faderTrack.offsetHeight;
const knobHeight = fader.offsetHeight;
const maxBottom = trackHeight - knobHeight;
let newBottom = Math.max(0, Math.min(maxBottom, startBottom + (deltaY / trackHeight * 100)));
fader.style.bottom = newBottom + '%';
const percentage = newBottom / maxBottom;
let dbValue = percentage <= 0.01 ? -Infinity : (percentage * 66) - 60;
if (dbValue > 6) dbValue = 6;
const valueElement = faderContainer.querySelector('.fader-value-new');
if (valueElement) {
valueElement.textContent = dbValue === -Infinity ? '-β dB' : dbValue.toFixed(1) + ' dB';
}
const trackId = fader.getAttribute('data-track');
if (window.dawEngine && trackId) {
const linearGain = dbValue === -Infinity ? 0 : Math.pow(10, dbValue / 20);
window.dawEngine.setTrackVolume(trackId, Math.max(0, Math.min(2, linearGain)));
}
e.preventDefault();
});
document.addEventListener('touchend', handleUp);
}
function makePanDraggableNew(knob) {
let isDragging = false;
let startX = 0;
let startLeft = 0;
const panTrack = knob.closest('.pan-track');
const panContainer = knob.closest('.mixer-pan-new');
if (!panTrack || !panContainer) return;
knob.addEventListener('mousedown', function(e) {
isDragging = true;
startX = e.clientX;
const currentLeft = parseFloat(getComputedStyle(knob).left) || 50;
startLeft = currentLeft;
e.preventDefault();
e.stopPropagation();
});
const handleMove = function(e) {
if (!isDragging) return;
const deltaX = e.clientX - startX;
const trackWidth = panTrack.offsetWidth;
const knobWidth = knob.offsetWidth;
const maxLeft = trackWidth - knobWidth;
const minLeft = 0;
let newLeft = Math.max(minLeft, Math.min(maxLeft, startLeft + (deltaX / trackWidth * 100)));
knob.style.left = newLeft + '%';
// Convert to pan value (-1 to +1)
const percentage = (newLeft / maxLeft) * 2 - 1; // -1 (left) to +1 (right)
const panValue = Math.max(-1, Math.min(1, percentage));
// Update display
const valueElement = panContainer.querySelector('.pan-value-new');
if (valueElement) {
if (Math.abs(panValue) < 0.05) {
valueElement.textContent = 'Center';
} else if (panValue > 0) {
valueElement.textContent = 'R' + Math.round(panValue * 100);
} else {
valueElement.textContent = 'L' + Math.round(Math.abs(panValue) * 100);
}
}
// Update audio engine
const trackId = knob.getAttribute('data-track');
if (window.dawEngine && trackId) {
window.dawEngine.setTrackPan(trackId, panValue);
}
};
const handleUp = function() {
if (isDragging) {
isDragging = false;
}
};
document.addEventListener('mousemove', handleMove);
document.addEventListener('mouseup', handleUp);
document.addEventListener('mouseleave', handleUp);
// Touch support
knob.addEventListener('touchstart', function(e) {
isDragging = true;
startX = e.touches[0].clientX;
const currentLeft = parseFloat(getComputedStyle(knob).left) || 50;
startLeft = currentLeft;
e.preventDefault();
});
document.addEventListener('touchmove', function(e) {
if (!isDragging) return;
const touch = e.touches[0];
const deltaX = touch.clientX - startX;
const trackWidth = panTrack.offsetWidth;
const knobWidth = knob.offsetWidth;
const maxLeft = trackWidth - knobWidth;
let newLeft = Math.max(0, Math.min(maxLeft, startLeft + (deltaX / trackWidth * 100)));
knob.style.left = newLeft + '%';
const percentage = (newLeft / maxLeft) * 2 - 1;
const panValue = Math.max(-1, Math.min(1, percentage));
const valueElement = panContainer.querySelector('.pan-value-new');
if (valueElement) {
if (Math.abs(panValue) < 0.05) {
valueElement.textContent = 'Center';
} else if (panValue > 0) {
valueElement.textContent = 'R' + Math.round(panValue * 100);
} else {
valueElement.textContent = 'L' + Math.round(Math.abs(panValue) * 100);
}
}
const trackId = knob.getAttribute('data-track');
if (window.dawEngine && trackId) {
window.dawEngine.setTrackPan(trackId, panValue);
}
e.preventDefault();
});
document.addEventListener('touchend', handleUp);
}
function makeEQDraggable(knob) {
let isDragging = false;
let startY = 0;
let startRotation = 0;
const currentRotation = { value: 0 };
knob.addEventListener('mousedown', function(e) {
isDragging = true;
startY = e.clientY;
startRotation = currentRotation.value;
e.preventDefault();
e.stopPropagation();
});
const handleMove = function(e) {
if (!isDragging) return;
const deltaY = startY - e.clientY; // Inverted: up = boost, down = cut
const maxRotation = 270; // Maximum rotation in degrees
const rotation = Math.max(-maxRotation, Math.min(maxRotation, startRotation + deltaY * 2));
currentRotation.value = rotation;
knob.style.transform = `rotate(${rotation}deg)`;
// Convert rotation to dB (-15dB to +15dB)
const dbValue = (rotation / maxRotation) * 15;
const valueElement = knob.querySelector('.eq-knob-value');
if (valueElement) {
valueElement.textContent = dbValue > 0 ? '+' + dbValue.toFixed(0) : dbValue.toFixed(0);
}
// Update audio engine (if EQ is implemented)
const trackId = knob.getAttribute('data-track');
const band = knob.getAttribute('data-band');
if (window.dawEngine && trackId && band) {
// EQ implementation would go here
console.log(`EQ ${band} for track ${trackId}: ${dbValue}dB`);
}
};
const handleUp = function() {
if (isDragging) {
isDragging = false;
}
};
document.addEventListener('mousemove', handleMove);
document.addEventListener('mouseup', handleUp);
document.addEventListener('mouseleave', handleUp);
}
function initializeMeters() {
// Animate meters for all tracks
setInterval(() => {
document.querySelectorAll('.meter-level-new').forEach(meter => {
// Simulate audio level (replace with actual audio analysis)
const level = Math.random() * 100;
meter.style.height = level + '%';
// Show peak indicator if level is high
const peakElement = meter.parentElement.querySelector('.meter-peak');
if (peakElement && level > 90) {
peakElement.style.height = level + '%';
peakElement.classList.add('active');
setTimeout(() => peakElement.classList.remove('active'), 100);
}
});
}, 50);
}
function playTimeline() {
console.log('π΅ Playing timeline...');
// Implementation for playing all tracks in timeline
}
function pauseTimeline() {
console.log('βΈοΈ Pausing timeline...');
// Implementation for pausing timeline
}
function stopTimeline() {
console.log('βΉοΈ Stopping timeline...');
// Implementation for stopping timeline
}
function toggleRecording() {
console.log('π΄ Toggling recording...');
// Implementation for recording
}
function playTrackClip(audioUrl, trackName) {
console.log('π΅ Playing track clip:', trackName);
// Use global player if available
if (window.enhancedGlobalPlayer && typeof window.enhancedGlobalPlayer.playTrack === 'function') {
window.enhancedGlobalPlayer.playTrack(audioUrl, trackName, 'SoundStudioPro');
} else {
console.warn('Global player not available');
}
}
function toggleTrackMute(trackId) {
console.log('π Toggling mute for track:', trackId);
// Implementation for muting tracks
}
function toggleTrackSolo(trackId) {
console.log('π§ Toggling solo for track:', trackId);
// Implementation for soloing tracks
}
function animateMasterMeter() {
const meterLevel = document.getElementById('masterLevel');
if (!meterLevel) return;
setInterval(() => {
const level = Math.random() * 100;
meterLevel.style.width = level + '%';
}, 100);
}
// Professional DAW Audio Engine
class DAWAudioEngine {
constructor() {
this.audioContext = null;
this.masterGain = null;
this.tracks = new Map();
this.isPlaying = false;
this.currentTime = 0;
this.bpm = 120;
this.metronome = null;
this.playhead = null;
this.undoStack = [];
this.redoStack = [];
this.maxUndoSteps = 50;
}
async initialize() {
try {
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
this.masterGain = this.audioContext.createGain();
this.masterGain.connect(this.audioContext.destination);
// Create metronome
this.createMetronome();
console.log('ποΈ DAW Audio Engine initialized');
return true;
} catch (error) {
console.error('Failed to initialize audio engine:', error);
return false;
}
}
createMetronome() {
const oscillator = this.audioContext.createOscillator();
const gainNode = this.audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(this.masterGain);
oscillator.frequency.setValueAtTime(1000, this.audioContext.currentTime);
gainNode.gain.setValueAtTime(0, this.audioContext.currentTime);
this.metronome = { oscillator, gainNode };
}
async loadTrack(trackId, audioUrl) {
try {
const response = await fetch(audioUrl);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);
const track = {
id: trackId,
buffer: audioBuffer,
gain: this.audioContext.createGain(),
pan: this.audioContext.createStereoPanner(),
source: null,
isMuted: false,
isSoloed: false,
volume: 1,
panValue: 0,
startTime: 0,
duration: audioBuffer.duration
};
track.gain.connect(track.pan);
track.pan.connect(this.masterGain);
this.tracks.set(trackId, track);
console.log(`π΅ Track ${trackId} loaded successfully`);
return track;
} catch (error) {
console.error(`Failed to load track ${trackId}:`, error);
return null;
}
}
playTrack(trackId, startTime = 0) {
const track = this.tracks.get(trackId);
if (!track) return;
if (track.source) {
track.source.stop();
}
track.source = this.audioContext.createBufferSource();
track.source.buffer = track.buffer;
track.source.connect(track.gain);
const playTime = this.audioContext.currentTime + startTime;
track.source.start(playTime);
console.log(`π΅ Playing track ${trackId} at ${startTime}s`);
}
stopTrack(trackId) {
const track = this.tracks.get(trackId);
if (track && track.source) {
track.source.stop();
track.source = null;
}
}
setTrackVolume(trackId, volume) {
const track = this.tracks.get(trackId);
if (track) {
track.volume = volume;
track.gain.gain.setValueAtTime(volume, this.audioContext.currentTime);
}
}
setTrackPan(trackId, pan) {
const track = this.tracks.get(trackId);
if (track) {
track.panValue = pan;
track.pan.pan.setValueAtTime(pan, this.audioContext.currentTime);
}
}
muteTrack(trackId) {
const track = this.tracks.get(trackId);
if (track) {
track.isMuted = !track.isMuted;
track.gain.gain.setValueAtTime(track.isMuted ? 0 : track.volume, this.audioContext.currentTime);
}
}
soloTrack(trackId) {
const track = this.tracks.get(trackId);
if (track) {
track.isSoloed = !track.isSoloed;
// Mute all other tracks if this track is soloed
this.tracks.forEach((otherTrack, otherId) => {
if (otherId !== trackId) {
otherTrack.gain.gain.setValueAtTime(
track.isSoloed ? 0 : (otherTrack.isMuted ? 0 : otherTrack.volume),
this.audioContext.currentTime
);
}
});
}
}
playMetronome() {
if (!this.metronome) return;
const now = this.audioContext.currentTime;
const beatInterval = 60 / this.bpm;
this.metronome.gainNode.gain.setValueAtTime(0.3, now);
this.metronome.gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.1);
setTimeout(() => {
this.playMetronome();
}, beatInterval * 1000);
}
setBPM(bpm) {
this.bpm = bpm;
document.getElementById('tempoValue').textContent = bpm;
document.getElementById('sessionBPM').textContent = bpm;
}
updatePlayhead(time) {
if (this.playhead) {
const percentage = (time / 180) * 100; // 3 minutes max
this.playhead.style.left = `${percentage}%`;
}
}
// Undo/Redo functionality
saveState() {
const state = {
tracks: Array.from(this.tracks.entries()),
currentTime: this.currentTime,
bpm: this.bpm
};
this.undoStack.push(JSON.stringify(state));
if (this.undoStack.length > this.maxUndoSteps) {
this.undoStack.shift();
}
this.redoStack = []; // Clear redo stack when new action is performed
}
undo() {
if (this.undoStack.length > 0) {
const currentState = {
tracks: Array.from(this.tracks.entries()),
currentTime: this.currentTime,
bpm: this.bpm
};
this.redoStack.push(JSON.stringify(currentState));
const previousState = JSON.parse(this.undoStack.pop());
this.restoreState(previousState);
}
}
redo() {
if (this.redoStack.length > 0) {
const currentState = {
tracks: Array.from(this.tracks.entries()),
currentTime: this.currentTime,
bpm: this.bpm
};
this.undoStack.push(JSON.stringify(currentState));
const nextState = JSON.parse(this.redoStack.pop());
this.restoreState(nextState);
}
}
restoreState(state) {
// Restore tracks
this.tracks.clear();
state.tracks.forEach(([id, trackData]) => {
this.tracks.set(id, trackData);
});
// Restore other properties
this.currentTime = state.currentTime;
this.setBPM(state.bpm);
// Update UI
this.updateUI();
}
updateUI() {
// Update all track meters, faders, etc.
this.tracks.forEach((track, id) => {
const faderValue = document.querySelector(`[data-track="${id}"] .fader-value`);
if (faderValue) {
const dbValue = Math.round((track.volume - 0.5) * 40);
faderValue.textContent = `${dbValue}dB`;
}
const panValue = document.querySelector(`[data-track="${id}"] .pan-value`);
if (panValue) {
if (track.panValue === 0) {
panValue.textContent = 'C';
} else if (track.panValue > 0) {
panValue.textContent = `R${Math.abs(Math.round(track.panValue * 100))}`;
} else {
panValue.textContent = `L${Math.abs(Math.round(track.panValue * 100))}`;
}
}
});
}
}
// Global DAW instance
let dawEngine = null;
// Initialize DAW when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
// Initialize DAW if we're on the timeline section
if (document.querySelector('.daw-container')) {
initializeProfessionalDAW();
}
});
function initializeProfessionalDAW() {
console.log('ποΈ Initializing Professional DAW...');
// Initialize audio engine
dawEngine = new DAWAudioEngine();
dawEngine.initialize().then(() => {
// Initialize all DAW features
initializeTransportControls();
initializeTrackClips();
initializeMixerControls();
initializeToolbarControls();
initializeTempoControls();
initializePlayhead();
animateMeters();
// Load existing tracks
loadExistingTracks();
});
}
function initializeTransportControls() {
const playBtn = document.getElementById('playBtn');
const pauseBtn = document.getElementById('pauseBtn');
const stopBtn = document.getElementById('stopBtn');
const recordBtn = document.getElementById('recordBtn');
if (playBtn) {
playBtn.addEventListener('click', function() {
this.classList.add('active');
pauseBtn.classList.remove('active');
playDAW();
});
}
if (pauseBtn) {
pauseBtn.addEventListener('click', function() {
this.classList.add('active');
playBtn.classList.remove('active');
pauseDAW();
});
}
if (stopBtn) {
stopBtn.addEventListener('click', function() {
playBtn.classList.remove('active');
pauseBtn.classList.remove('active');
stopDAW();
});
}
if (recordBtn) {
recordBtn.addEventListener('click', function() {
this.classList.toggle('active');
toggleRecording();
});
}
}
function initializeTrackClips() {
const clips = document.querySelectorAll('.track-clip');
clips.forEach(clip => {
clip.addEventListener('click', function() {
const audioUrl = this.getAttribute('data-audio-url');
const trackId = this.getAttribute('data-track-id');
const trackName = this.querySelector('.clip-name').textContent;
if (audioUrl && dawEngine) {
dawEngine.loadTrack(trackId, audioUrl).then(() => {
dawEngine.playTrack(trackId);
showNotification(`π΅ Playing ${trackName}`, 'success');
});
}
});
// Make clips draggable
makeClipDraggable(clip);
// Generate waveform
generateWaveform(clip);
});
}
// This function is now defined earlier in the file with the new mixer design
// Keeping this as a fallback that calls the new implementation
function initializeMixerControlsLegacy() {
// Use new mixer controls
initializeMixerControls();
}
function initializeToolbarControls() {
const saveBtn = document.getElementById('saveProject');
const loadBtn = document.getElementById('loadProject');
const exportBtn = document.getElementById('exportProject');
const undoBtn = document.getElementById('undoBtn');
const redoBtn = document.getElementById('redoBtn');
if (saveBtn) {
saveBtn.addEventListener('click', saveProject);
}
if (loadBtn) {
loadBtn.addEventListener('click', loadProject);
}
if (exportBtn) {
exportBtn.addEventListener('click', exportProject);
}
if (undoBtn) {
undoBtn.addEventListener('click', () => {
if (dawEngine) dawEngine.undo();
});
}
if (redoBtn) {
redoBtn.addEventListener('click', () => {
if (dawEngine) dawEngine.redo();
});
}
}
function initializeTempoControls() {
const tempoUp = document.getElementById('tempoUp');
const tempoDown = document.getElementById('tempoDown');
if (tempoUp) {
tempoUp.addEventListener('click', () => {
if (dawEngine) {
dawEngine.setBPM(dawEngine.bpm + 1);
}
});
}
if (tempoDown) {
tempoDown.addEventListener('click', () => {
if (dawEngine) {
dawEngine.setBPM(Math.max(60, dawEngine.bpm - 1));
}
});
}
}
function initializePlayhead() {
dawEngine.playhead = document.getElementById('playhead');
}
function makeClipDraggable(clip) {
let isDragging = false;
let startX = 0;
let startLeft = 0;
clip.addEventListener('mousedown', function(e) {
isDragging = true;
startX = e.clientX;
startLeft = clip.offsetLeft;
clip.style.cursor = 'grabbing';
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
const deltaX = e.clientX - startX;
const newLeft = Math.max(0, startLeft + deltaX);
clip.style.left = newLeft + 'px';
// Update start time
const timelineWidth = clip.parentElement.offsetWidth;
const percentage = newLeft / timelineWidth;
const startTime = percentage * 180; // 3 minutes max
clip.setAttribute('data-start-time', startTime);
});
document.addEventListener('mouseup', function() {
if (isDragging) {
isDragging = false;
clip.style.cursor = 'grab';
// Save state for undo
if (dawEngine) {
dawEngine.saveState();
}
}
});
}
function makeFaderDraggable(fader) {
let isDragging = false;
let startY = 0;
let startTop = 0;
fader.addEventListener('mousedown', function(e) {
isDragging = true;
startY = e.clientY;
startTop = fader.offsetTop;
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
const deltaY = e.clientY - startY;
const faderTrack = fader.parentElement;
const maxTop = faderTrack.offsetHeight - fader.offsetHeight;
const newTop = Math.max(0, Math.min(maxTop, startTop + deltaY));
fader.style.top = newTop + 'px';
// Update volume
const percentage = 1 - (newTop / maxTop);
const volume = Math.max(0, Math.min(1, percentage));
const dbValue = Math.round((volume - 0.5) * 40);
const valueElement = fader.parentElement.nextElementSibling;
if (valueElement) {
valueElement.textContent = dbValue + 'dB';
}
// Update audio engine
const trackId = fader.getAttribute('data-track');
if (dawEngine && trackId) {
dawEngine.setTrackVolume(trackId, volume);
}
});
document.addEventListener('mouseup', function() {
if (isDragging) {
isDragging = false;
// Save state for undo
if (dawEngine) {
dawEngine.saveState();
}
}
});
}
function makePanDraggable(knob) {
let isDragging = false;
let startAngle = 0;
let currentAngle = 0;
knob.addEventListener('mousedown', function(e) {
isDragging = true;
const rect = knob.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
startAngle = Math.atan2(e.clientY - centerY, e.clientX - centerX);
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
const rect = knob.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const angle = Math.atan2(e.clientY - centerY, e.clientX - centerX);
const deltaAngle = angle - startAngle;
const indicator = knob.querySelector('.pan-indicator');
if (indicator) {
currentAngle += deltaAngle;
indicator.style.transform = `translate(-50%, -50%) rotate(${currentAngle}rad)`;
}
// Update pan value
const panValue = Math.sin(currentAngle);
const valueElement = knob.nextElementSibling;
if (valueElement) {
if (Math.abs(panValue) < 0.1) {
valueElement.textContent = 'C';
} else if (panValue > 0) {
valueElement.textContent = 'R' + Math.abs(Math.round(panValue * 100));
} else {
valueElement.textContent = 'L' + Math.abs(Math.round(panValue * 100));
}
}
// Update audio engine
const trackId = knob.getAttribute('data-track');
if (dawEngine && trackId) {
dawEngine.setTrackPan(trackId, panValue);
}
startAngle = angle;
});
document.addEventListener('mouseup', function() {
if (isDragging) {
isDragging = false;
// Save state for undo
if (dawEngine) {
dawEngine.saveState();
}
}
});
}
function generateWaveform(clip) {
const canvas = clip.querySelector('.waveform-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
// Generate random waveform for demo
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
ctx.fillRect(0, 0, width, height);
ctx.strokeStyle = '#667eea';
ctx.lineWidth = 2;
ctx.beginPath();
for (let x = 0; x < width; x++) {
const y = height / 2 + Math.sin(x * 0.1) * height / 4 + Math.random() * 10;
if (x === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.stroke();
}
function loadExistingTracks() {
const clips = document.querySelectorAll('.track-clip');
clips.forEach(clip => {
const audioUrl = clip.getAttribute('data-audio-url');
const trackId = clip.getAttribute('data-track-id');
if (audioUrl && dawEngine) {
dawEngine.loadTrack(trackId, audioUrl);
}
});
}
function playDAW() {
if (!dawEngine) return;
dawEngine.isPlaying = true;
dawEngine.tracks.forEach((track, id) => {
const startTime = parseFloat(document.querySelector(`[data-track-id="${id}"]`).getAttribute('data-start-time'));
dawEngine.playTrack(id, startTime);
});
// Start playhead animation
animatePlayhead();
}
function pauseDAW() {
if (!dawEngine) return;
dawEngine.isPlaying = false;
dawEngine.tracks.forEach((track, id) => {
dawEngine.stopTrack(id);
});
}
function stopDAW() {
if (!dawEngine) return;
dawEngine.isPlaying = false;
dawEngine.currentTime = 0;
dawEngine.updatePlayhead(0);
dawEngine.tracks.forEach((track, id) => {
dawEngine.stopTrack(id);
});
}
function toggleRecording() {
console.log('π΄ Recording toggled');
// Implementation for recording
}
function armTrackForRecording(trackId) {
console.log(`π€ Track ${trackId} armed for recording`);
// Implementation for arming tracks
}
function saveProject() {
if (!dawEngine) return;
const projectData = {
tracks: Array.from(dawEngine.tracks.entries()),
bpm: dawEngine.bpm,
currentTime: dawEngine.currentTime
};
const blob = new Blob([JSON.stringify(projectData)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'soundstudiopro-project.json';
a.click();
URL.revokeObjectURL(url);
showNotification('πΎ Project saved successfully', 'success');
}
function loadProject() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = function(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
try {
const projectData = JSON.parse(e.target.result);
// Restore project data
showNotification('π Project loaded successfully', 'success');
} catch (error) {
showNotification('β Failed to load project', 'error');
}
};
reader.readAsText(file);
}
};
input.click();
}
function exportProject() {
if (!dawEngine) return;
// Implementation for exporting mixed audio
showNotification('π€ Exporting project...', 'info');
}
function animatePlayhead() {
if (!dawEngine || !dawEngine.isPlaying) return;
dawEngine.currentTime += 0.1;
dawEngine.updatePlayhead(dawEngine.currentTime);
requestAnimationFrame(animatePlayhead);
}
function animateMeters() {
const meters = document.querySelectorAll('.meter-level');
meters.forEach(meter => {
setInterval(() => {
const level = Math.random() * 100;
meter.style.width = level + '%';
}, 100);
});
}
function showNotification(message, type = 'info') {
// Create notification element
const notification = document.createElement('div');
notification.className = `studio-notification ${type}`;
notification.innerHTML = `
<div class="notification-content">
<i class="${getNotificationIcon(type)}"></i>
<span>${message}</span>
</div>
`;
// Add to studio container
const studioContainer = document.querySelector('.studio-container');
if (studioContainer) {
studioContainer.appendChild(notification);
}
// Show animation
setTimeout(() => {
notification.classList.add('show');
}, 100);
// Auto remove after 5 seconds
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
if (notification.parentElement) {
notification.remove();
}
}, 300);
}, 5000);
}
function getNotificationIcon(type) {
switch (type) {
case 'success': return 'fas fa-check-circle';
case 'error': return 'fas fa-exclamation-circle';
case 'warning': return 'fas fa-exclamation-triangle';
default: return 'fas fa-info-circle';
}
}
</script>
<?php
include 'includes/footer.php';
include 'includes/advanced_functions_modal.php';
include 'includes/pro_studio_modals.php';
?>