![]() 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/private_html/includes/ |
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Get user's tracks for the timeline
require_once '../config/database.php';
$pdo = getDBConnection();
$stmt = $pdo->prepare("SELECT * FROM music_tracks WHERE user_id = ? AND status = 'complete' ORDER BY created_at DESC LIMIT 10");
$stmt->execute([$_SESSION['user_id']]);
$timelineTracks = $stmt->fetchAll();
?>
<!-- Professional Timeline Mixer Component -->
<div class="timeline-mixer-container">
<!-- Transport Controls -->
<div class="transport-controls">
<div class="transport-left">
<button class="transport-btn" 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" id="recordBtn">
<i class="fas fa-circle"></i>
</button>
</div>
<div class="transport-center">
<div class="time-display">
<span id="currentTime">00:00</span>
<span class="time-separator">/</span>
<span id="totalTime">00:00</span>
</div>
<div class="tempo-display">
<span class="tempo-label">BPM</span>
<span id="tempoValue">120</span>
</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>
</div>
</div>
<!-- Timeline Header -->
<div class="timeline-header">
<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>
</div>
<!-- Timeline Tracks -->
<div class="timeline-tracks">
<div class="track-list">
<?php if (empty($timelineTracks)): ?>
<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 ($timelineTracks 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']; ?>">
<i class="fas fa-volume-mute"></i>
</button>
<button class="track-btn solo-btn" data-track="<?php echo $track['id']; ?>">
<i class="fas fa-headphones"></i>
</button>
<button class="track-btn record-btn" data-track="<?php echo $track['id']; ?>">
<i class="fas fa-circle"></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($track['audio_url']); ?>"
data-duration="<?php echo $track['duration'] ?? 30; ?>"
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>
</div>
<!-- Track Mixer -->
<div class="track-mixer">
<div class="mixer-fader">
<div class="fader-track">
<div class="fader-knob" data-track="<?php echo $track['id']; ?>"></div>
</div>
<div class="fader-value">0dB</div>
</div>
<div class="mixer-pan">
<div class="pan-knob" data-track="<?php echo $track['id']; ?>">
<div class="pan-indicator"></div>
</div>
<div class="pan-value">C</div>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- Master Mixer -->
<div class="master-mixer">
<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>
</div>
</div>
<style>
/* 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);
}
/* Transport Controls */
.transport-controls {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem 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);
}
.time-display {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.8rem;
font-weight: 700;
color: #e2e8f0;
}
.time-separator {
color: #667eea;
}
.tempo-display {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.4rem;
color: #a0aec0;
}
.tempo-label {
font-weight: 600;
}
/* Timeline Header */
.timeline-header {
background: rgba(255, 255, 255, 0.03);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
padding: 1rem 2rem;
}
.timeline-ruler {
position: relative;
height: 40px;
background: rgba(255, 255, 255, 0.02);
border-radius: 5px;
}
.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;
}
/* Timeline Tracks */
.timeline-tracks {
max-height: 400px;
overflow-y: auto;
}
.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: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 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 */
.track-mixer {
display: flex;
flex-direction: column;
gap: 1rem;
align-items: center;
}
.mixer-fader {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.fader-track {
width: 20px;
height: 100px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
position: relative;
cursor: pointer;
}
.fader-knob {
position: absolute;
bottom: 20px;
left: -5px;
width: 30px;
height: 20px;
background: linear-gradient(45deg, #667eea, #764ba2);
border-radius: 15px;
cursor: pointer;
transition: all 0.3s ease;
}
.fader-knob:hover {
transform: scale(1.1);
box-shadow: 0 0 10px rgba(102, 126, 234, 0.4);
}
.fader-value {
font-size: 1rem;
color: #a0aec0;
font-weight: 600;
}
.mixer-pan {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
.pan-knob {
width: 40px;
height: 40px;
border: 2px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
background: rgba(255, 255, 255, 0.05);
position: relative;
cursor: pointer;
transition: all 0.3s ease;
}
.pan-knob:hover {
border-color: rgba(102, 126, 234, 0.5);
background: rgba(102, 126, 234, 0.1);
}
.pan-indicator {
position: absolute;
top: 50%;
left: 50%;
width: 4px;
height: 20px;
background: #667eea;
transform: translate(-50%, -50%);
border-radius: 2px;
}
.pan-value {
font-size: 1rem;
color: #a0aec0;
font-weight: 600;
}
/* Master Mixer */
.master-mixer {
background: rgba(255, 255, 255, 0.05);
border-top: 1px solid rgba(255, 255, 255, 0.1);
padding: 1.5rem 2rem;
}
.master-section {
display: flex;
align-items: center;
gap: 2rem;
}
.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;
}
.meter-bar {
width: 100%;
height: 20px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
overflow: hidden;
position: relative;
}
.meter-level {
height: 100%;
background: linear-gradient(90deg, #48bb78, #ed8936, #f56565);
width: 0%;
transition: width 0.1s ease;
}
/* Empty Timeline */
.empty-timeline {
text-align: center;
padding: 4rem 2rem;
color: #a0aec0;
}
.empty-timeline i {
font-size: 4rem;
margin-bottom: 1rem;
color: #667eea;
}
.empty-timeline p {
font-size: 1.6rem;
margin-bottom: 2rem;
}
/* Responsive Design */
@media (max-width: 768px) {
.track-row {
grid-template-columns: 1fr;
gap: 1rem;
}
.track-mixer {
flex-direction: row;
justify-content: center;
}
.transport-controls {
flex-direction: column;
gap: 1rem;
}
.transport-center {
order: -1;
}
}
</style>
<script>
// Timeline Mixer JavaScript
document.addEventListener('DOMContentLoaded', function() {
initializeTimelineMixer();
});
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');
playBtn.addEventListener('click', function() {
this.classList.add('active');
pauseBtn.classList.remove('active');
playTimeline();
});
pauseBtn.addEventListener('click', function() {
this.classList.add('active');
playBtn.classList.remove('active');
pauseTimeline();
});
stopBtn.addEventListener('click', function() {
playBtn.classList.remove('active');
pauseBtn.classList.remove('active');
stopTimeline();
});
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
const faders = document.querySelectorAll('.fader-knob');
faders.forEach(fader => {
makeFaderDraggable(fader);
});
// Pan controls
const panKnobs = document.querySelectorAll('.pan-knob');
panKnobs.forEach(knob => {
makePanDraggable(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'));
});
});
}
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 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 fader value
const percentage = 1 - (newTop / maxTop);
const dbValue = Math.round((percentage - 0.5) * 40);
const valueElement = fader.parentElement.nextElementSibling;
if (valueElement) {
valueElement.textContent = dbValue + 'dB';
}
});
document.addEventListener('mouseup', function() {
isDragging = false;
});
}
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.round((currentAngle / (2 * Math.PI)) * 100);
const valueElement = knob.nextElementSibling;
if (valueElement) {
if (panValue === 0) {
valueElement.textContent = 'C';
} else if (panValue > 0) {
valueElement.textContent = 'R' + Math.abs(panValue);
} else {
valueElement.textContent = 'L' + Math.abs(panValue);
}
}
startAngle = angle;
});
document.addEventListener('mouseup', function() {
isDragging = false;
});
}
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);
}
</script>