Giriş Yap Ücretsiz Başla
Mastering Reçetesi · BETA

Parçanı bırak, tam ayarları al

"Mastering yap" demiyoruz — hangi frekansta kaç dB, hangi oranla, hangi eşikle, hangi limiter tavanıyla. Ölçümden türetilmiş somut bir işlem zinciri ve platform bazlı export hedefleri.

Dosya sunucuya yüklenmez Frekans · Q · kazanç hazır Kurtarılamaz kusurları söyler

Ses dosyası

Dosyayı sürükle veya tıkla MP3 · WAV · FLAC · OGG · M4A — önerilen en fazla 60 MB
Dosya seçilmedi

Reçete özeti —

Önce bunları oku

İşlem zinciri ölçümden türetildi

EQ hamleleri —

Uygulama sırası

Platform export hedefleri loudness & tepe

Aynı miksi farklı platformlar için ayrı ayrı export etmek en doğrusudur. "Uygulanacak kazanç" sütunu, ölçülen loudness değerinden o hedefe gitmek için gereken kazanç değişimidir.

Uzman yorumu model

Nasıl okunur

EQ hamleleri ölçülen bant enerjisi dengesinden (bas / orta / tiz oranları), DC kaymasından ve sıfır geçiş oranından türetilir. Spektrumun kendisi ölçülmez — bant oranları kullanılır. Bu yüzden frekanslar başlangıç noktasıdır, körü körüne uygulanacak kesin değerler değil: kulağınla doğrula.

Kompresör ayarları crest faktöründen (tepe ile RMS arasındaki fark) hesaplanır. Crest düşükse parça zaten sıkıştırılmıştır — motor kompresör eklemeyi önermez.

Kırpma ve faz tersliği mastering ile düzeltilemez. Bu kusurlar tespit edilirse motor reçeteyi "önce kaynağı düzelt" adımıyla başlatır ve puanı sıfıra yakın verir.

Mastering'de "doğru ayar" diye bir şey yok, türe göre makul aralık var. Pop vokal için çalışan EQ eğrisi rock gitarı boğar. Mastering Reçetesi seçtiğin türe göre başlangıç değerleri verir: alt kesim frekansı, öne çıkarılacak bantlar, kompresör oranı ve saldırı/bırakma süreleri, limiter tavanı.

Reçete neyi içerir?

Bu değerler neden "başlangıç"?

Her kaydın spektrumu farklıdır. Reçete seni boş tuvalden kurtarır ama kulağının son söz söylemesi gerekir. Değerleri uyguladıktan sonra Yayın Doktoru ile LUFS ve kırpma kontrolü yapmak, döngüyü kapatır.

Sık sorulan sorular

Mastering'i AI yapabilir mi?
Otomatik mastering hızlı ve makul sonuç verir ama tür karakterini yakalamakta zorlanır. Reçete sana hangi değerlerin neden seçildiğini göstererek kulağını geliştirir.
Limiter tavanı kaç olmalı?
Streaming için −1.0 dBTP standarttır. −0.3 gibi yüksek değerler, platformun kodlayıcısında inter-sample clipping üretebilir.
WAV 16 bit mi 24 bit mi?
Dağıtım için 24 bit / 44.1 kHz tercih edilir; platformlar kendi tarafında indirger. 16 bit kullanacaksan dither ekle.
Ücretsiz mi?
Evet, giriş yapmadan kullanabilirsin.

İlgili araçlar

Zoneus Tools tarayıcıda çalışan ücretsiz müzik araçlarıdır; ses dosyaların sunucuya yüklenmez. Tüm araçlara göz at.

/*! * Zoneus Lab — tarayıcı içi ses ölçüm motoru (paylaşılan) * ------------------------------------------------------ * Ses dosyası ASLA sunucuya gitmez; yalnızca sayısal özet gönderilir. * Bu dosya tek doğruluk kaynağıdır: tools/analiz.php, tools/platform.php, * tools/mastering.php ve ileride eklenecek ölçüm araçları buradan beslenir. * * Dışa açılan yüzey (window.ZSLab): * coz(file) → Promise * olc(buf,file,ext,onProg) → {olcum, egri, dosya} * lufsHesapla(chans,sr,n) → LUFS (ITU-R BS.1770 yakınlaştırması) * tempoBul(data,sr,n) → {bpm, conf} * kancaHesap(egri,sure) → sn | null * egriCiz(canvas,egri) → enerji eğrisi çizimi * ring(puan,renk,boy) → SVG puan halkası (HTML) * barRenk(p) → eşik renkleri * esc / fmt / tl → yardımcılar * * Ölçülen büyüklükler (olcum): * sure_sn, ornekleme, kanal, bitrate_kbps, format, tepe_db, rms_db, lufs, * crest_db, kirpma_adet, kirpma_orani, dc_offset, mono_korelasyon, zcr, * bas_enerji, orta_enerji, tiz_enerji, sessizlik_basi_ms, sessizlik_sonu_ms, * bpm, bpm_guven, ilk15_enerji_orani, son10_enerji_orani, zirve_konumu, * enerji_degiskenligi, kirpma_bolge, tepe_bolge */ window.ZSLab = (function () { 'use strict'; var MAX_SANIYE = 480; // en fazla 8 dakika ölçülür (bellek güvenliği) var EGRI_PENCERE = 120; // enerji eğrisi pencere sayısı var _actx = null; /* ─────────────── yardımcılar ─────────────── */ function esc(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (m) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[m]; }); } function fmt(n, d) { d = (d == null ? 1 : d); if (n == null || isNaN(n)) return '—'; return (Math.round(n * Math.pow(10, d)) / Math.pow(10, d)).toFixed(d); } /** 3725 → "3:42" */ function tl(sn) { sn = Math.max(0, Math.round(sn || 0)); var d = Math.floor(sn / 60), s = sn % 60; return d + ':' + (s < 10 ? '0' : '') + s; } function dpr() { return window.devicePixelRatio || 1; } /* ─────────────── ses çözme ─────────────── */ function ctx() { if (!_actx) _actx = new (window.AudioContext || window.webkitAudioContext)(); return _actx; } function coz(file) { return new Promise(function (res, rej) { var reader = new FileReader(); reader.onerror = function () { rej(new Error('Dosya okunamadı.')); }; reader.onload = function () { var c = ctx(); var p; try { p = c.decodeAudioData(reader.result.slice(0)); } catch (e) { p = null; } if (!p || !p.then) { // eski tarayıcı: callback tabanlı API try { c.decodeAudioData(reader.result.slice(0), function (buf) { res(buf); }, function () { rej(new Error('Dosya çözülemedi — WAV veya MP3 deneyin.')); }); } catch (e2) { rej(new Error('Dosya çözülemedi — WAV veya MP3 deneyin.')); } return; } p.then(res).catch(function () { rej(new Error('Dosya çözülemedi — WAV veya MP3 deneyin.')); }); }; reader.readAsArrayBuffer(file); }); } /* ─────────────── ≈LUFS: ITU-R BS.1770 ─────────────── */ function lufsHesapla(chans, sr, n) { // Sahne 1: yüksek raf (+4 dB ≈ 1.5 kHz üstü) — standart 48 kHz katsayıları var b1 = [1.53512485958697, -2.69169618940638, 1.19839281085285]; var a1 = [1, -1.69065929318241, 0.73248077421585]; // Sahne 2: yüksek geçiren (≈38 Hz) var b2 = [1, -2, 1]; var a2 = [1, -1.99004745483398, 0.99007225036621]; var blockLen = Math.max(1, Math.floor(sr * 0.4)); // 400 ms var hop = Math.max(1, Math.floor(sr * 0.1)); // 100 ms (%75 örtüşme) if (n < blockLen) return -99; var totalBlocks = Math.floor((n - blockLen) / hop) + 1; var maxBlocks = 4000; var blockStep = Math.max(1, Math.ceil(totalBlocks / maxBlocks)); var nb = Math.ceil(totalBlocks / blockStep); var blocks = new Float64Array(Math.max(1, nb)); for (var c = 0; c < chans.length; c++) { var d = chans[c]; var x1 = 0, x2 = 0, y1 = 0, y2 = 0, u1 = 0, u2 = 0, w1 = 0, w2 = 0; // kayan pencere: halka tamponu + koşan toplam (tam BS.1770, O(1)/örnek) var ring = new Float64Array(blockLen), pos = 0, run = 0, seen = 0, blkIdx = 0; for (var i = 0; i < n; i++) { var x = d[i] || 0; var v1 = b1[0] * x + b1[1] * x1 + b1[2] * x2 - a1[1] * y1 - a1[2] * y2; x2 = x1; x1 = x; y2 = y1; y1 = v1; var v2 = b2[0] * v1 + b2[1] * u1 + b2[2] * u2 - a2[1] * w1 - a2[2] * w2; u2 = u1; u1 = v1; w2 = w1; w1 = v2; var sq = v2 * v2; run -= ring[pos]; ring[pos] = sq; run += sq; pos++; if (pos >= blockLen) pos = 0; seen++; if (seen >= blockLen && ((seen - blockLen) % hop) === 0) { var bi = (blkIdx / blockStep) | 0; if (blkIdx % blockStep === 0 && bi < nb) blocks[bi] += run / blockLen; // kanal güçleri toplanır blkIdx++; } } } var loud = []; for (var k = 0; k < blocks.length; k++) { if (blocks[k] <= 0) continue; var lv = -0.691 + 10 * Math.log10(blocks[k]); if (lv > -70) loud.push(lv); // mutlak eşik } if (!loud.length) return -99; var ort = loud.reduce(function (a, b) { return a + b; }, 0) / loud.length; var gated = loud.filter(function (x) { return x > ort - 10; }); // göreli eşik if (!gated.length) gated = loud; var lin = gated.reduce(function (a, b) { return a + Math.pow(10, b / 10); }, 0) / gated.length; return -0.691 + 10 * Math.log10(lin); } /* ─────────────── BPM: onset zarfı + otokorelasyon ─────────────── */ function tempoBul(data, sr, n) { var maxLen = Math.min(n, sr * 60); var start = Math.max(0, Math.floor((n - maxLen) / 2)); var d = data.subarray ? data.subarray(start, start + maxLen) : data; var frame = Math.floor(sr * 0.01), hop = frame, nF = Math.floor(d.length / hop); if (nF < 40) return { bpm: 0, conf: 0 }; var env = new Float32Array(nF); for (var i = 0; i < nF; i++) { var s = 0, o = i * hop; for (var j = 0; j < frame; j++) { var v = d[o + j] || 0; s += v * v; } env[i] = Math.sqrt(s / frame); } var on = new Float32Array(nF); for (var i2 = 1; i2 < nF; i2++) { var dd = env[i2] - env[i2 - 1]; on[i2] = dd > 0 ? dd : 0; } var minLag = Math.floor(60 / 200 * 100), maxLag = Math.floor(60 / 60 * 100); var best = -1, bestLag = minLag, map = []; for (var lag = minLag; lag <= maxLag; lag++) { var c = 0, norm = 0; for (var i3 = 0; i3 < nF - lag; i3++) { c += on[i3] * on[i3 + lag]; norm += on[i3] * on[i3]; } var sc = norm ? c / norm : 0; sc *= 1 - Math.abs((60 / (lag * 0.01)) - 120) / 400; map.push({ lag: lag, score: sc }); if (sc > best) { best = sc; bestLag = lag; } } map.sort(function (a, b) { return b.score - a.score; }); var bpm = Math.round(60 / ((map[0] || { lag: bestLag }).lag * 0.01)); if (bpm > 160 && bpm / 2 >= 60) bpm = Math.round(bpm / 2); if (bpm < 70 && bpm * 2 <= 200) bpm = Math.round(bpm * 2); return { bpm: bpm, conf: Math.max(15, Math.min(99, Math.round(best * 120))) }; } /* ─────────────── ana ölçüm ─────────────── */ /** * @param {AudioBuffer} buf * @param {File} file * @param {string} ext * @param {function(number,string)=} onProg ilerleme (0-100, mesaj) * @returns {{olcum:Object, egri:number[], dosya:Object}} */ function olc(buf, file, ext, onProg) { var P = function (p, m) { if (typeof onProg === 'function') onProg(p, m); }; P(30, 'Ölçümler alınıyor…'); var sr = buf.sampleRate, chs = buf.numberOfChannels, dur = buf.duration; var MAXS = Math.min(buf.length, Math.floor(sr * MAX_SANIYE)); var L = buf.getChannelData(0); var R = chs > 1 ? buf.getChannelData(1) : null; var n = Math.min(MAXS, L.length); // ── tek geçiş: tepe, RMS, DC, kırpma, korelasyon, ZCR, bant enerjisi ── var peak = 0, sumSq = 0, dcSum = 0, clip = 0, zc = 0, prev = 0; var sLL = 0, sRR = 0, sLR = 0; var bLow = 0, bMid = 0, bHigh = 0; var a1 = 1 - Math.exp(-2 * Math.PI * 200 / sr), a2 = 1 - Math.exp(-2 * Math.PI * 4000 / sr); var lp1 = 0, lp2 = 0; var cnt = 0; // kırpma / tepe konumları (saniye cinsinden kaba dağılım) var ilkKirpmaSn = -1, sonKirpmaSn = -1, ilkTepeSn = -1; for (var i = 0; i < n; i++) { var l = L[i] || 0, r = R ? (R[i] || 0) : l; var m = (l + r) * 0.5; var al = Math.abs(l), ar = Math.abs(r); var am = al > ar ? al : ar; if (am > peak) { peak = am; ilkTepeSn = i / sr; } sumSq += m * m; dcSum += m; cnt++; if (am >= 0.999) { clip++; if (ilkKirpmaSn < 0) ilkKirpmaSn = i / sr; sonKirpmaSn = i / sr; } if ((m >= 0) !== (prev >= 0)) zc++; prev = m; sLL += l * l; sRR += r * r; sLR += l * r; lp1 += a1 * (m - lp1); var low = lp1; var rest = m - lp1; lp2 += a2 * (rest - lp2); var mid = lp2; var high = rest - lp2; bLow += low * low; bMid += mid * mid; bHigh += high * high; } var rms = Math.sqrt(sumSq / Math.max(1, cnt)); var dc = dcSum / Math.max(1, cnt); var peakDb = peak > 0 ? 20 * Math.log10(peak) : -99; var rmsDb = rms > 0 ? 20 * Math.log10(rms) : -99; var crest = Math.max(0, peakDb - rmsDb); var zcr = zc / Math.max(1, cnt); var clipRatio = clip / Math.max(1, cnt); var bTot = bLow + bMid + bHigh || 1; var bLowP = bLow / bTot, bMidP = bMid / bTot, bHighP = bHigh / bTot; var denom = Math.sqrt(Math.max(1e-9, sLL * sRR)); var kor = denom > 0 ? sLR / denom : 0; if (kor > 1) kor = 1; if (kor < -1) kor = -1; P(52, 'Enerji eğrisi çıkarılıyor…'); // ── enerji eğrisi ── var W = EGRI_PENCERE, winLen = Math.floor(n / W), egri = [], winRms = []; for (var w = 0; w < W; w++) { var s0 = w * winLen, e0 = Math.min(n, s0 + winLen), sq = 0, c = 0; var st2 = Math.max(1, Math.floor((e0 - s0) / 4000)); for (var j = s0; j < e0; j += st2) { var mm = (L[j] || 0) + (R ? (R[j] || 0) : 0); mm *= 0.5; sq += mm * mm; c++; } winRms.push(Math.sqrt(sq / Math.max(1, c))); } var maxW = Math.max.apply(null, winRms) || 1; for (var w2 = 0; w2 < W; w2++) egri.push(winRms[w2] / maxW); // ── sessizlik başlangıç/bitiş (eşik: tepe-60 dB) ── var thr = maxW * Math.pow(10, -60 / 20) * 4; var sessBas = 0, sessSon = 0; for (var a = 0; a < W; a++) { if (winRms[a] > thr) { sessBas = Math.round((a / W) * dur * 1000); break; } } for (var b = W - 1; b >= 0; b--) { if (winRms[b] > thr) { sessSon = Math.round(((W - 1 - b) / W) * dur * 1000); break; } } // ── ilk 15 sn / son 10 sn enerji oranları ── var ortW = winRms.reduce(function (x, y) { return x + y; }, 0) / W || 1; var i15 = Math.max(1, Math.round(15 / dur * W)), i10 = Math.max(1, Math.round(10 / dur * W)); var s15 = 0; for (var k = 0; k < i15 && k < W; k++) s15 += winRms[k]; var s10 = 0; for (var k2 = W - 1; k2 >= W - i10 && k2 >= 0; k2--) s10 += winRms[k2]; var ilk15 = (s15 / Math.min(i15, W)) / ortW, son10 = (s10 / Math.min(i10, W)) / ortW; // ── ilk 3 saniye enerjisi (kısa video / TikTok için kritik) ── var i3 = Math.max(1, Math.round(3 / dur * W)); var s3 = 0; for (var k3 = 0; k3 < i3 && k3 < W; k3++) s3 += winRms[k3]; var ilk3 = (s3 / Math.min(i3, W)) / ortW; // ── zirve konumu ve değişkenlik ── var maxIx = 0; for (var z = 0; z < W; z++) { if (winRms[z] > winRms[maxIx]) maxIx = z; } var zirve = W > 1 ? maxIx / (W - 1) : 0; var varSum = 0; for (var v = 0; v < W; v++) { var d2 = winRms[v] - ortW; varSum += d2 * d2; } var degiskenlik = ortW > 0 ? Math.sqrt(varSum / W) / ortW : 0; P(74, 'Loudness ölçülüyor (BS.1770)…'); var lufs = lufsHesapla([L].concat(R ? [R] : []), sr, n); P(88, 'Tempo tespit ediliyor…'); var bpmR = tempoBul(L, sr, n); var bitrate = Math.round(file.size * 8 / Math.max(1, dur) / 1000); var format = (ext || '').toUpperCase(); var olcum = { sure_sn: Math.round(dur * 1000) / 1000, ornekleme: sr, kanal: chs, bitrate_kbps: bitrate, format: format, tepe_db: Math.round(peakDb * 100) / 100, rms_db: Math.round(rmsDb * 100) / 100, lufs: Math.round(lufs * 10) / 10, crest_db: Math.round(crest * 10) / 10, kirpma_adet: clip, kirpma_orani: Math.round(clipRatio * 1e6) / 1e6, dc_offset: Math.round(dc * 1e5) / 1e5, mono_korelasyon: Math.round(kor * 1000) / 1000, zcr: Math.round(zcr * 1e4) / 1e4, bas_enerji: Math.round(bLowP * 1000) / 1000, orta_enerji: Math.round(bMidP * 1000) / 1000, tiz_enerji: Math.round(bHighP * 1000) / 1000, sessizlik_basi_ms: sessBas, sessizlik_sonu_ms: sessSon, bpm: bpmR.bpm, bpm_guven: bpmR.conf, ilk3_enerji_orani: Math.round(ilk3 * 1000) / 1000, ilk15_enerji_orani: Math.round(ilk15 * 1000) / 1000, son10_enerji_orani: Math.round(son10 * 1000) / 1000, zirve_konumu: Math.round(zirve * 1000) / 1000, enerji_degiskenligi: Math.round(degiskenlik * 1000) / 1000, kirpma_ilk_sn: ilkKirpmaSn >= 0 ? Math.round(ilkKirpmaSn * 10) / 10 : -1, kirpma_son_sn: sonKirpmaSn >= 0 ? Math.round(sonKirpmaSn * 10) / 10 : -1, tepe_ilk_sn: ilkTepeSn >= 0 ? Math.round(ilkTepeSn * 10) / 10 : -1, olculen_sn: Math.round((n / sr) * 10) / 10 }; P(100, 'Ölçümler tamam.'); return { olcum: olcum, egri: egri, dosya: { ad: file.name, boyut: file.size, uzanti: format } }; } /* ─────────────── kanca / zirve konumu ─────────────── */ /** İlk belirgin enerji yükselişinin saniyesi (yoksa null). */ function kancaHesap(egri, sure) { if (!egri || !egri.length || !sure) return null; var ort = egri.reduce(function (a, b) { return a + b; }, 0) / egri.length; var thr = ort * 1.18; for (var i = 0; i < egri.length; i++) { if (egri[i] >= thr) return Math.round((i / egri.length) * sure); } return null; } /* ─────────────── çizim ─────────────── */ function egriCiz(cv, e, secenek) { if (!cv || !e || !e.length) return; var o = secenek || {}; var renk = o.renk || '#c9a227'; var zemin = o.zemin || 'rgba(235,190,55,'; var d = dpr(); var w = cv.clientWidth, h = cv.clientHeight; if (!w || !h) return; cv.width = w * d; cv.height = h * d; var g = cv.getContext('2d'); g.setTransform(d, 0, 0, d, 0, 0); g.clearRect(0, 0, w, h); var ort = e.reduce(function (a, b) { return a + b; }, 0) / e.length; g.strokeStyle = 'rgba(120,115,100,.28)'; g.lineWidth = 1; g.setLineDash([4, 4]); g.beginPath(); g.moveTo(0, h - h * ort); g.lineTo(w, h - h * ort); g.stroke(); g.setLineDash([]); var grd = g.createLinearGradient(0, 0, 0, h); grd.addColorStop(0, zemin + '.55)'); grd.addColorStop(1, zemin + '.05)'); g.beginPath(); g.moveTo(0, h); for (var i = 0; i < e.length; i++) { var x = (i / (e.length - 1)) * w; var y = h - Math.max(2, e[i] * h * 0.94); g.lineTo(x, y); } g.lineTo(w, h); g.closePath(); g.fillStyle = grd; g.fill(); g.beginPath(); for (var i2 = 0; i2 < e.length; i2++) { var x2 = (i2 / (e.length - 1)) * w, y2 = h - Math.max(2, e[i2] * h * 0.94); if (i2 === 0) g.moveTo(x2, y2); else g.lineTo(x2, y2); } g.strokeStyle = renk; g.lineWidth = 2; g.stroke(); // isaretli saniyeler (dikey çizgiler) if (o.isaretler && o.isaretler.length && o.sure) { o.isaretler.forEach(function (mk) { if (mk.sn == null || mk.sn < 0) return; var px = (mk.sn / o.sure) * w; if (px < 0 || px > w) return; g.strokeStyle = mk.renk || 'rgba(192,57,43,.55)'; g.lineWidth = 1.5; g.setLineDash([3, 3]); g.beginPath(); g.moveTo(px, 0); g.lineTo(px, h); g.stroke(); g.setLineDash([]); }); } } /* ─────────────── görsel parçalar ─────────────── */ function ring(puan, renk, boy) { boy = boy || 118; var r = boy * 0.44, c = 2 * Math.PI * r; var p = Math.min(100, Math.max(0, puan == null ? 0 : puan)); var off = c * (1 - p / 100); var cx = boy / 2; return '
' + '' + '' + '
' + (puan == null ? '—' : puan) + '/ 100
'; } function barRenk(p) { return p >= 78 ? '#1f7a4d' : (p >= 58 ? '#c9a227' : (p >= 35 ? '#e07b39' : '#c0392b')); } /** Kısa çubuk listesi HTML'i (kırılım tabloları için ortak). */ function cubuklar(kirilim) { if (!kirilim || !kirilim.length) return ''; var h = '
'; kirilim.forEach(function (k) { var p = Math.max(0, Math.min(100, k.puan || 0)); h += '
' + esc(k.etiket) + '' + (k.guven != null ? 'güven %' + Math.round(k.guven * 100) + ' · ' : '') + fmt(p, 1) + '/100
' + '
'; }); return h + '
'; } /** Sıralı aksiyon listesi HTML'i. */ function aksiyonlar(liste) { if (!liste || !liste.length) return ''; var h = '
'; liste.forEach(function (a, n) { h += '
' + (n + 1) + '
' + '
' + esc(a.baslik) + '

' + esc(a.detay) + '

' + '' + (a.kaynak === 'olcum' ? 'ölçüm' : 'model') + '
'; }); return h + '
'; } return { MAX_SANIYE: MAX_SANIYE, coz: coz, ctx: ctx, olc: olc, lufsHesapla: lufsHesapla, tempoBul: tempoBul, kancaHesap: kancaHesap, egriCiz: egriCiz, ring: ring, barRenk: barRenk, cubuklar: cubuklar, aksiyonlar: aksiyonlar, esc: esc, fmt: fmt, tl: tl }; })();