Files
SonicForgeStudio/.kilo/plans/1785323991986-mastering-module-plan.md
T

9.8 KiB
Raw Blame History

Implementation Plan: Ozone Mastering Module

Nguồn DUY NHẤT để tạo giao diện

Toàn bộ giao diện của Mastering Modal được lấy TRỰC TIẾP từ HTML trong md/45_MASTERING_MODULE.md dòng 74885.

Không thiết kế giao diện mới. Không suy luận UI. Lấy chính xác:

  • Cấu trúc HTML: copy verbatim từ spec, chuyển sang JSX (className thay class, onChange thay onchange, v.v.)
  • CSS styles: copy verbatim từ spec (oz-panel, oz-card, oz-card-active, knob-dial, knob-pointer, gradient backgrounds)
  • JavaScript logic: port verbatim từ spec vào React hooks (useState thay ozState, useRef thay DOM refs, useEffect thay event listeners)
  • Web Audio DSP graph: copy y hệt node graph + connection từ spec (BiquadFilterNode, GainNode, DynamicsCompressorNode, AnalyserNode)
  • Canvas renderers: copy y hệt drawing logic từ spec (frequency grid, FFT fill, EQ curve, polar vectorscope, VU meter gradient)

Goal

Dịch spec HTML md/45_MASTERING_MODULE.md (lines 74885) thành MasteringModal React component trong app.jsx.

Ánh xạ HTML → React (chi tiết từ spec)

HTML lines 74118: Dependencies & Styles

Spec Action
<script src="cdn.tailwindcss.com"> Đã có trong index.html:9
<link FA 6.4.0> Đã có trong index.html:10 (dùng lucide thay FA, giữ nguyên)
<link Google Fonts Inter> Đã có font-family trong index.html style
CSS .oz-panel oz-card oz-card-active knob-* scrollbar Thêm vào index.html <style> block
CSS .font-mono { JetBrains Mono } Thêm vào index.html <style>

→ Sửa app/templates/index.html: append ~30 dòng CSS class (oz-panel, oz-card, knob-dial, scrollbar tối)


HTML lines 121161: Header Bar

Spec Element React JSX Mapping
Logo .fa-atom + "OZONE ADVANCED" <div> với cùng class & lucide icon wand-2 thay FA
Play/Stop buttons + preset select JSX nguyên bản, class giữ nguyên
Target LUFS text JSX nguyên bản

→ Trong MasteringModal return JSX, copy verbatim HTML, chỉ thay .fa-* → lucide i tương ứng.


HTML lines 163213: Module Chain Strip

Spec Element React
#cardDynamicEq + power toggle + icon JSX với onClick → set activeModule('eq')
#cardImager + power toggle + icon JSX với onClick → set activeModule('imager')
#cardMaximizer + power toggle + icon JSX với onClick → set activeModule('maximizer')
Empty add-module slot .border-dashed JSX verbatim
oz-card-active class toggle className={\oz-card ${ozState.activeModule==='eq' ? 'oz-card-active' : ''}`}`

HTML lines 216325: Dynamic EQ View

Spec Element React
#viewDynamicEq container className={ozState.activeModule === 'eq' ? '' : 'hidden'}
#eqCanvas <canvas ref={el => canvasRefs.current.eq = el}>
4-band knobs (Low/Mid1/Mid2/High) Mỗi band là <div> với .knob-container, data-param, pointer events
Knob dial HTML .knob-dial > .knob-pointer JSX verbatim + inline transform: rotate(Xdeg)
Band labels & freq text JSX verbatim

Knob interaction (spec lines 794843): port pointerdown/move/up logic vào useEffect với .knob-container querySelectorAll, update ozState[param] + gọi updateAudioGraphValues.


HTML lines 327363: Stereo Imager View

Spec Element React
#viewImager className={ozState.activeModule === 'imager' ? '' : 'hidden'}
#imagerCanvas (polar vectorscope) <canvas ref={...}>
4-band width sliders #w1Slider#w4Slider <input type="range" value={ozState.w1} onChange={...}>
Value spans #w1Val#w4Val <span>{ozState.w1}%</span>

HTML lines 366421: Maximizer View

Spec Element React
#viewMaximizer className={ozState.activeModule === 'maximizer' ? '' : 'hidden'}
Maximizer gain knob (.knob-dial w-24 h-24) JSX verbatim, pointer events
Ceiling level text <span>{ozState.ceiling.toFixed(2)} dB</span>
Upward compress knob JSX verbatim + pointer events
Soft clipper knob JSX verbatim + pointer events
Transient emphasis knob JSX verbatim + pointer events

HTML lines 425480: Right Sidebar (I/O Meters + Utilities)

Spec Element React
#inPeakText / #outPeakText <span>{inPeak.toFixed(1)} dB</span> etc.
#inMeterCanvas / #outMeterCanvas <canvas ref={...}>
Bypass / Gain Match / Codec / Dither buttons JSX verbatim
Module active state checkboxes (power toggles) Thêm onClick set ozState.eqActive etc. + gọi updateAudioGraphValues

HTML lines 484585: Audio Engine (JavaScript → React)

Spec Function React Mapping
ozState object const [ozState, setOzState] = useState({...}) — values copy verbatim
initOzoneAudioEngine() useEffect on mount: tạo AudioContext (dùng window.SonicAudio?.getAudioContext() nếu có), tạo AnalyserNode (fftSize=2048), BiquadFilter nodes (lowshelf 100Hz, peaking 822Hz Q0.7, peaking 3.2kHz Q1.2, highshelf 10kHz), GainNode boost, DynamicsCompressorNode (threshold -0.1, knee 0, ratio 20, attack 0.001, release 0.05), outputAnalyser
Node graph connection inputAnalyser → eqLow → eqMid1 → eqMid2 → eqHigh → boostGain → compressor → outputAnalyser → destination
updateAudioGraphValues() Copy verbatim logic: eqLowFilter.gain.setTargetAtTime(ozState.eqActive ? ozState.eqLowGain : 0, now, 0.01) etc.
startAudioDemo() Copy verbatim: create 4-second stereo buffer, kick/snare/synth oscillator, loop playback
stopAudioDemo() Copy verbatim: sourceNode.stop(); sourceNode.disconnect();

HTML lines 586791: Canvas Renderers (JavaScript → React)

Spec Canvas React Mapping
eqCanvas (lines 680738) useEffect với requestAnimationFrame loop: draw freq grid lines, FFT spectrum bar fill từ outputAnalyser.getByteFrequencyData, draw composite EQ curve
imagerCanvas (lines 742765) requestAnimationFrame: draw polar circle guides + random scatter dots with ozState.w3 width
inMeterCanvas/outMeterCanvas (lines 769787) requestAnimationFrame: renderMeterBar() with linear gradient green→yellow→red, dBFS numeric readout
resizeAll() useEffect + window.addEventListener('resize', resizeAll)

HTML lines 793882: Interactions & Init (JavaScript → React)

Spec React
setupKnobs() (lines 794843) useEffect on mount: query .knob-container, attach pointerdown/move/up, update UI rotation + ozState + updateAudioGraphValues
setupModuleNavigation() (lines 846868) Inline JSX click handlers thay vì event listeners
window.addEventListener('load', ...) (lines 871882) useEffect on mount: init audio engine, setup event handlers, start canvas renderers

Task List

Task 1: Append CSS classes vào app/templates/index.html

Thêm ~30 dòng CSS vào <style> block (index.html:28-245):

  • .oz-panel oz-card oz-card-active
  • .knob-container .knob-dial .knob-pointer
  • Scrollbar dark theme
  • .font-mono JetBrains Mono override
  • Gradient panel backgrounds

Task 2: Thêm state + menu item trong app.jsx

  • showMasteringModal state (dòng 7708)
  • Menu item "Mastering Suite" (dòng 15585)
  • Render MasteringModal (dòng 18664)

Task 3: Viết MasteringModal component trong app.jsx (trước dòng 6694)

~500 dòng gồm:

3a. State: ozState (activeModule, gains, widths, maximizer params), isPlaying, canvasRefs, audioRefs

3b. useEffect (mount): initOzoneAudioEngine() — copy verbatim từ spec lines 529-584, dùng window.SonicAudio?.getAudioContext() fallback

3c. useEffect (mount): setupKnobs() — port pointer events từ spec lines 794-843, gọi updateAudioGraphValues() khi giá trị thay đổi

3d. useEffect (mount + deps): Canvas render loop — port startCanvasRenderers() từ spec lines 650-791, sử dụng ozState thay vì global

3e. useEffect (cleanup): Stop audio + disconnect nodes khi unmount

3f. JSX return: ~250 dòng JSX, dịch sát spec HTML lines 121-480:

  • Overlay modal container fixed inset-0 z-[100] bg-black/60 backdrop-blur-sm
  • Bên trong: flex flex-col container với h-[90vh] w-[90vw] max-w-[1400px]
  • Header bar (logo, transport, preset select, LUFS)
  • Module chain strip (3 module cards + add slot, oz-card-active toggle)
  • Main workspace:
    • Sub toolbar (Delta listen, IRC mode select, Learn Input Gain)
    • viewDynamicEq (EQ canvas + 4-band knob panel, show khi activeModule==='eq')
    • viewImager (vectorscope canvas + 4-band sliders, show khi activeModule==='imager')
    • viewMaximizer (gain knob, upward comp, soft clip, transient knobs, show khi activeModule==='maximizer')
  • Right sidebar I/O meters (in/out peak text, meter canvases, bypass/gain match/codec/dither buttons)
  • Close button (góc trên phải)

Task 4: Build & Verify

npm run build

Kiểm tra: mở app → menu → "Mastering Suite" → modal hiển thị, Play Reference Loop phát âm thanh, canvas vẽ, knobs kéo được.

Files Affected

File Lines Change
app/templates/index.html +30 Thêm CSS classes (oz-panel, oz-card, knob-dial, scrollbar)
app/static/js/app.jsx ~dòng 6690 + 7708 + 15585 + 18664 Thêm MasteringModal component + state + menu item + render

Skipped (PONYTALL)

  • Real M/S processing: phase 1 chỉ UI + vectorscope viz. Thêm actual M/S khi user upload file stereo thật.
  • Delta Listen / Gain Match / Codec / Dither: UI button renders, DSP stubbed. Thêm sau.
  • Drag-drop module reorder: spec define UX. Phase 1: fixed chain.
  • Preset save/load: UI dropdown + defaults. Backend integration sau.