📋 Planlama v1

Muzibu Frontend Ses Kalitesi Sistemi

Web Audio API ile Gerçek Zamanlı Ses İşleme

8 Ocak 2026
muzibu.com

📝 Basit Anlatım (Herkes İçin)

🎯 Ne Yapacağız?

Muzibu'da kullanıcılar müzik dinlerken 4 farklı ses kalitesi seçeneği arasından tercih yapabilecek. Bu seçim anında devreye girecek, şarkı kesintiye uğramayacak.

🎚️ Kalite Seviyeleri:

  • 🔵
    Standard: Hafif, mobil veri tasarrufu için ideal (192 kbps)
  • 🟢
    Optimized: Dengeli kalite, ses seviyesi normalize (256 kbps + Loudnorm)
  • 🟡
    EQ Balanced: Optimized + Ekstra bas ve tiz ayarı (EQ)
  • 🔴
    Ultimate: En yüksek kalite + Stereo genişletme + Tüm filtreler

🚀 Neden Frontend'de?

  • Anında değişim: Kullanıcı butona bastığında hemen uygulanır, şarkı yeniden başlamaz
  • Disk tasarrufu: Her şarkı için 4 farklı dosya oluşturmaya gerek yok (28K şarkı x 4 = 112K dosya!)
  • Eski şarkılar korunur: Zaten işlenmiş 28,208 şarkıya hiç dokunulmaz
  • Kullanıcı kontrolü: Herkes kendi zevkine ve internet hızına göre ayarlayabilir

💡 Kullanıcı Ne Yaşar?

  1. Şarkı çalarken oynatıcıda "Ses Kalitesi" butonu görür
  2. Tıkladığında 4 seçenek açılır (Standard, Optimized, EQ Balanced, Ultimate)
  3. Seçtiği anda ses kalitesi değişir (şarkı devam eder, kesinti olmaz)
  4. Tercihi kaydedilir, sonraki açılışta aynı ayar aktif olur
  5. Premium aboneler tüm seçeneklere, free kullanıcılar sadece Standard'a erişir

🔧 Teknik Detaylar (Geliştiriciler İçin)

🎵 Web Audio API Kullanımı

Modern tarayıcılarda yerleşik AudioContext kullanarak gerçek zamanlı ses işleme yapılır. HLS akışı ile entegre çalışır.

// Audio Pipeline Yapısı
Source (HLS.js) → AudioContext → [Filters] → Destination (Speaker)

// Node Chain:
MediaElementSource → GainNode → BiquadFilterNode(s) → StereoPanner → Destination

🎚️ Kalite Presets (JavaScript Object)

const QUALITY_PRESETS = {
  standard: {
    label: 'Standard',
    description: '192 kbps, filtre yok',
    bitrate: 192,
    filters: {
      gain: 1.0,           // Hiç dokunma
      loudness: false,     // Loudness normalize YOK
      eq: [],              // EQ YOK
      stereo: 0,           // Stereo genişletme YOK
      lowpass: false       // Lowpass filter YOK
    }
  },

  optimized: {
    label: 'Optimized',
    description: '256 kbps + Loudness normalize',
    bitrate: 256,
    filters: {
      gain: 1.2,           // +2dB gain (loudness normalize simülasyonu)
      loudness: true,      // Loudness normalize (Web Audio ile simüle edilir)
      eq: [],              // EQ YOK
      stereo: 0,           // Stereo genişletme YOK
      lowpass: false       // Lowpass filter YOK
    }
  },

  eq_balanced: {
    label: 'EQ Balanced',
    description: '256 kbps + Loudness + EQ (Bass/Treble)',
    bitrate: 256,
    filters: {
      gain: 1.2,
      loudness: true,
      eq: [
        { type: 'peaking', frequency: 100, Q: 1, gain: 1 },    // Bass boost +1dB
        { type: 'peaking', frequency: 8000, Q: 1, gain: -2 }   // Treble cut -2dB
      ],
      stereo: 0,
      lowpass: false
    }
  },

  ultimate: {
    label: 'Ultimate',
    description: '256 kbps + Tüm filtreler',
    bitrate: 256,
    filters: {
      gain: 1.2,
      loudness: true,
      eq: [
        { type: 'peaking', frequency: 100, Q: 1, gain: 1 },
        { type: 'peaking', frequency: 8000, Q: 1, gain: -2 }
      ],
      stereo: 0.2,         // Stereo genişletme (20% widening)
      lowpass: 14000       // 14kHz lowpass filter
    }
  }
};

🔗 Player Class Entegrasyonu

Mevcut MuzibuPlayer class'ına Web Audio pipeline eklenecek.

class MuzibuPlayer {
  constructor() {
    // AudioContext oluştur
    this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
    this.audioSource = null;
    this.gainNode = null;
    this.eqNodes = [];
    this.stereoPanner = null;
    this.lowpassFilter = null;

    // Varsayılan kalite
    this.currentQuality = localStorage.getItem('muzibu_audio_quality') || 'optimized';
  }

  setupAudioPipeline(audioElement) {
    // Source node (HLS.js'den gelen audio element)
    this.audioSource = this.audioContext.createMediaElementSource(audioElement);

    // Gain node (loudness için)
    this.gainNode = this.audioContext.createGain();

    // EQ nodes (bass/treble için)
    this.eqNodes = [];

    // Stereo panner (stereo widening için)
    this.stereoPanner = this.audioContext.createStereoPanner();

    // Lowpass filter
    this.lowpassFilter = this.audioContext.createBiquadFilter();
    this.lowpassFilter.type = 'lowpass';

    // Pipeline bağlantısı
    this.audioSource
      .connect(this.gainNode)
      .connect(this.lowpassFilter)
      .connect(this.stereoPanner)
      .connect(this.audioContext.destination);

    // İlk kalite preset'ini uygula
    this.applyQualityPreset(this.currentQuality);
  }

  applyQualityPreset(qualityLevel) {
    const preset = QUALITY_PRESETS[qualityLevel];
    if (!preset) return;

    // Gain ayarla (loudness simülasyonu)
    this.gainNode.gain.value = preset.filters.gain;

    // EQ filtreleri temizle ve yeniden oluştur
    this.eqNodes.forEach(node => node.disconnect());
    this.eqNodes = [];

    if (preset.filters.eq.length > 0) {
      let prevNode = this.gainNode;

      preset.filters.eq.forEach(eqConfig => {
        const eqNode = this.audioContext.createBiquadFilter();
        eqNode.type = eqConfig.type;
        eqNode.frequency.value = eqConfig.frequency;
        eqNode.Q.value = eqConfig.Q;
        eqNode.gain.value = eqConfig.gain;

        prevNode.disconnect();
        prevNode.connect(eqNode);
        this.eqNodes.push(eqNode);
        prevNode = eqNode;
      });

      prevNode.connect(this.lowpassFilter);
    }

    // Lowpass filter
    if (preset.filters.lowpass) {
      this.lowpassFilter.frequency.value = preset.filters.lowpass;
    } else {
      this.lowpassFilter.frequency.value = 20000; // Kapalı (20kHz = insan kulağı limiti)
    }

    // Stereo panner
    // NOT: StereoPanner sadece sol/sağ dengeleme yapar
    // Gerçek stereo widening için ChannelSplitter/Merger gerekir (daha karmaşık)
    this.stereoPanner.pan.value = preset.filters.stereo;

    // Ayarı kaydet
    localStorage.setItem('muzibu_audio_quality', qualityLevel);
    this.currentQuality = qualityLevel;

    console.log('Audio quality changed:', qualityLevel);
  }

  changeQuality(qualityLevel) {
    // Şarkı çalarken kalite değiştir (kesinti olmaz)
    this.applyQualityPreset(qualityLevel);
  }
}

🎨 Kalite Seçici UI Komponenti

Player bar'da dropdown menü ile kalite seçimi.

<!-- Player Bar'a Eklenecek -->
<div class="audio-quality-selector">
  <button class="quality-btn" @click="toggleQualityMenu">
    <i class="fas fa-sliders-h"></i>
    <span>{{ currentQualityLabel }}</span>
  </button>

  <div class="quality-menu" x-show="qualityMenuOpen" @click.away="qualityMenuOpen = false">
    <div class="quality-option" @click="changeQuality('standard')" :class="{'active': quality === 'standard'}">
      <span class="badge bg-blue-600">🔵</span>
      <div>
        <div class="font-semibold">Standard</div>
        <div class="text-xs text-slate-400">192 kbps, hafif</div>
      </div>
    </div>

    <div class="quality-option" @click="changeQuality('optimized')" :class="{'active': quality === 'optimized', 'premium-only': !isPremium}">
      <span class="badge bg-green-600">🟢</span>
      <div>
        <div class="font-semibold">Optimized</div>
        <div class="text-xs text-slate-400">256 kbps + Loudnorm</div>
      </div>
      <span v-if="!isPremium" class="badge bg-yellow-600 text-xs">Premium</span>
    </div>

    <div class="quality-option" @click="changeQuality('eq_balanced')" :class="{'active': quality === 'eq_balanced', 'premium-only': !isPremium}">
      <span class="badge bg-yellow-600">🟡</span>
      <div>
        <div class="font-semibold">EQ Balanced</div>
        <div class="text-xs text-slate-400">Optimized + EQ</div>
      </div>
      <span v-if="!isPremium" class="badge bg-yellow-600 text-xs">Premium</span>
    </div>

    <div class="quality-option" @click="changeQuality('ultimate')" :class="{'active': quality === 'ultimate', 'premium-only': !isPremium}">
      <span class="badge bg-red-600">🔴</span>
      <div>
        <div class="font-semibold">Ultimate</div>
        <div class="text-xs text-slate-400">En yüksek kalite</div>
      </div>
      <span v-if="!isPremium" class="badge bg-yellow-600 text-xs">Premium</span>
    </div>
  </div>
</div>

📁 Dosya Konumları

  • JS: public/themes/muzibu/js/player/features/audio-quality.js
  • Core: public/themes/muzibu/js/player/core/player-core.js (mevcut dosya güncellenecek)
  • UI: resources/views/themes/muzibu/layouts/partials/player.blade.php (kalite seçici ekleme)
  • CSS: public/themes/muzibu/css/player-custom.css (kalite menüsü stilleri)

📊 Yapılacaklar (Adım Adım)

1 Hazırlık: Audio Quality Modülü Oluştur

  • audio-quality.js dosyası oluştur
  • QUALITY_PRESETS object tanımla
  • AudioQualityManager class yaz
  • ✅ LocalStorage'dan ayar okuma fonksiyonu

2 Player Core: Web Audio Pipeline Ekle

  • player-core.js içinde AudioContext oluştur
  • ✅ HLS.js audio element'ini AudioContext'e bağla
  • ✅ Gain, EQ, Stereo, Lowpass node'larını zincirle
  • applyQualityPreset() metodunu implement et
  • ✅ Şarkı değiştiğinde pipeline'ı koru (kesinti olmasın)

3 UI: Kalite Seçici Dropdown Ekle

  • ✅ Player bar'a "Ses Kalitesi" butonu ekle
  • ✅ Dropdown menü komponenti (Alpine.js)
  • ✅ 4 kalite seçeneği listele
  • ✅ Aktif kaliteyi göster (badge/işaret)
  • ✅ Premium kontrolü (free kullanıcılar sadece Standard)

4 CSS: Kalite Menüsü Stilleri

  • ✅ Dropdown animasyonları (fade-in/out)
  • ✅ Hover efektleri
  • ✅ Premium badge stilleri
  • ✅ Responsive tasarım (mobil uyumlu)
  • ✅ Dark mode uyumlu

5 Test: Tüm Senaryoları Kontrol Et

  • ✅ Şarkı çalarken kalite değiştirme (kesinti olmamalı)
  • ✅ Şarkı geçişinde ayar korunuyor mu?
  • ✅ LocalStorage'a kaydediliyor mu?
  • ✅ Sayfa yenilendiğinde ayar yükleniyor mu?
  • ✅ Premium kontrolü çalışıyor mu?
  • ✅ Tüm tarayıcılarda test (Chrome, Firefox, Safari, Edge)
  • ✅ Mobil tarayıcılar (iOS Safari, Android Chrome)

6 Optimizasyon: Performans İyileştirmeleri

  • ✅ AudioContext singleton (tek instance)
  • ✅ Node'ları yeniden oluştururken disconnect/connect doğru yapılmalı
  • ✅ Memory leak kontrolü (şarkı değişiminde node'lar temizlenmeli)
  • ✅ CPU kullanımı izleme (console'da performans logları)

Avantajlar

  • Anında geçiş: Şarkı kesintiye uğramadan kalite değişir
  • Disk tasarrufu: Her şarkı için tek dosya yeterli (28K x 1 = 28K dosya)
  • Eski şarkılar korunur: 28,208 şarkıya dokunulmaz
  • Kullanıcı kontrolü: Herkes kendi tercihine göre ayarlar
  • Kolay güncelleme: Preset'leri JavaScript'te değiştirmek çok basit
  • Premium özellik: Free kullanıcılar sadece Standard, premium tüm seçeneklere erişir

⚠️ Dikkat Edilecekler

  • !
    Tarayıcı desteği: Eski tarayıcılar Web Audio API desteklemeyebilir (fallback gerekli)
  • !
    iOS autoplay: Safari'de AudioContext ilk kullanıcı etkileşiminden sonra başlar
  • !
    CPU kullanımı: Çok fazla filtre CPU'yu yorabilir (özellikle mobil)
  • !
    Memory leak: Node'lar doğru disconnect edilmezse bellek sızıntısı olur
  • !
    HLS.js entegrasyonu: Audio element AudioContext'e bağlanırken timing kritik
  • !
    Test: Tüm mobil tarayıcılarda (özellikle iOS Safari) mutlaka test edilmeli

🚫 Alternatif: Backend (FFmpeg) Çözümü (Neden Kullanmıyoruz?)

Backend Yaklaşımı:

  • Her şarkı için 4 farklı HLS dosyası oluştur (28K x 4 = 112K dosya)
  • Kullanıcı kalite seçtiğinde farklı HLS URL'i ver
  • Şarkı yeniden başlar (kesinti olur)

❌ Dezavantajlar:

  • 🔴 Disk alanı: 28K şarkı x 4 kalite = ~500GB+ ekstra alan
  • 🔴 İşlem süresi: Tüm şarkıları yeniden işlemek günler/haftalar alır
  • 🔴 CPU yükü: FFmpeg queue sistemi sürekli çalışır
  • 🔴 Kesinti: Kullanıcı kalite değiştirince şarkı baştan başlar
  • 🔴 Karmaşıklık: Backend migration, queue, storage yönetimi

✅ Frontend Neden Daha İyi:

Gerçek zamanlı ses işleme tarayıcıda yapıldığı için kullanıcı anında sonuç alır, hiçbir dosya yeniden oluşturulmaz, disk alanı boşa harcanmaz. Modern tarayıcılar Web Audio API ile profesyonel kalitede ses işleme yapabilir.

🚀 Sonraki Adımlar

📅 Uygulama Sırası:

  1. Onay al: Bu planı kullanıcıya sun, onay bekle
  2. Modül oluştur: audio-quality.js dosyasını yaz
  3. Player entegrasyonu: player-core.js güncellenecek
  4. UI ekle: Kalite seçici dropdown komponenti
  5. Test: Tüm tarayıcılarda ve mobilde test et
  6. Deploy: Production'a al

💬 Kullanıcıya Soru:

Bu planı onaylıyor musunuz?

  • ✓ Evet → Koda geçiyoruz (audio-quality.js oluşturma)
  • ✗ Hayır → Neyi değiştirmek istersiniz?