Project Goal: Develop a local Python GUI application to master AI-generated EDM tracks. Target Agent: Claude-Code (or similar AI coding assistant). Tech Stack: customtkinter, pedalboard, demucs, numpy, pyloudnorm.
Phase 1: Project Scaffolding & Environment Setup

Objective: Establish the file structure, install dependencies, and create a "Hello World" GUI to verify the stack.
1.1. Initialize Project Structure

    1.1.1. Create the root directory named SunoRemaster.

    1.1.2. Create the following subdirectories:

        assets/ (for icons and images).

        src/ (source code root).

        src/engine/ (backend logic).

        src/ui/ (frontend components).

        temp/ (for intermediate audio files).

    1.1.3. Create empty placeholder files:

        src/main.py (entry point).

        src/ui/app.py (main GUI class).

        src/engine/processor.py (DSP logic).

        src/engine/presets.py (configuration data).

        src/utils.py (helper functions).

1.2. Dependency Management

    1.2.1. Create a requirements.txt file in the root directory.

    1.2.2. Add the following libraries to requirements.txt:

        customtkinter (GUI).

        pedalboard (Audio Effects).

        demucs (Stem Separation).

        numpy & scipy (Math/Signal Processing).

        pyloudnorm (Loudness Measurement).

        soundfile (Audio I/O).

        pygame (Simple Audio Playback).

    1.2.3. Create a virtual environment (python -m venv venv) and install requirements.

    1.2.4. Verify demucs installation (ensure Torch dependencies are resolved).

1.3. Basic GUI Shell

    1.3.1. In src/ui/app.py, define the class SunoRemasterApp inheriting from ctk.CTk.

    1.3.2. Set the window geometry to 800x600 and title to "SunoRemaster Tool v1.0".

    1.3.3. Set the appearance mode: ctk.set_appearance_mode("Dark").

    1.3.4. In src/main.py, instantiate SunoRemasterApp and call .mainloop().

    1.3.5. Run src/main.py to verify a blank dark window appears.

Phase 2: The Audio Engine (Headless Logic)

Objective: Build the DSP logic in isolation before connecting it to the UI.
2.1. Preset Data Structure

    2.1.1. In src/engine/presets.py, create a dictionary named GENRE_PRESETS.

    2.1.2. Populate the dictionary with keys: Techno, Trance, Psytrance, Organic House, Progressive House, Complextro, Dubstep, EDM, Deep House, Tech House, Custom.

    2.1.3. For each key, define the parameters (Target LUFS, Mono Cutoff Hz, Sidechain Strength, Transient Boost Amount). Refer to FDS Section 4.3 for values.

2.2. Stem Separation Wrapper

    2.2.1. In src/engine/processor.py, create a class AudioEngine.

    2.2.2. Implement the method separate_stems(self, input_path).

    2.2.3. Use subprocess or demucs.api to run separation.

    2.2.4. Ensure separated files are saved to the temp/ directory.

    2.2.5. Return a dictionary of paths: {'drums': path, 'bass': path, 'other': path, 'vocals': path}.

2.3. DSP Module: Matrix Math (NumPy)

    2.3.1. Implement apply_sidechain(bass_array, kick_array, strength) in processor.py.

        Logic: Calculate RMS envelope of kick -> Invert it -> Multiply by bass.

    2.3.2. Implement make_bass_mono(audio_array, cutoff_freq) using scipy.signal logic.

        Logic: Split Mid/Side -> Highpass the Side channel -> Recombine.

    2.3.3. Create a unit test tests/test_dsp_numpy.py to verify array shapes remain correct after processing.

2.4. DSP Module: Pedalboard Chains

    2.4.1. Implement apply_mastering_chain(audio, samplerate, preset_data).

    2.4.2. Construct a Pedalboard object containing:

        HighpassFilter (cleanup).

        Compressor (glue).

        Limiter (final loudness).

    2.4.3. Connect preset_data values (e.g., threshold) to the plugin parameters.

Phase 3: GUI Implementation (The Visuals)

Objective: Build the visual zones A, B, and C as defined in the FDS.
3.1. Zone A: Header & Input Frame

    3.1.1. Create src/ui/header_frame.py.

    3.1.2. Add a CTkEntry widget to display the file path (state=disabled).

    3.1.3. Add a "Load WAV" CTkButton linked to filedialog.askopenfilename.

    3.1.4. Add a "Play Original" CTkButton (placeholder logic for now).

    3.1.5. Add validation: Ensure selected file ends with .wav or .mp3.

3.2. Zone B: Controls & Presets Frame

    3.2.1. Create src/ui/controls_frame.py.

    3.2.2. Add a CTkOptionMenu for Genres, populated by GENRE_PRESETS.keys().

    3.2.3. Add CTkCheckBox widgets for the 6 processing modules:

        Stem Separation

        AI De-Haze

        Mono Bass

        Auto-Sidechain

        Transient Shaper

        Final Limiting

    3.2.4. Implement logic: If "Auto-Sidechain" is checked, force "Stem Separation" to be checked and disabled (grayed out).

3.3. Zone C: Status & Execution Frame

    3.3.1. Create src/ui/status_frame.py.

    3.3.2. Add a CTkProgressBar (initialize at 0.0).

    3.3.3. Add a CTkTextbox for logs (state=disabled, creating a read-only console).

    3.3.4. Add the primary action button: PROCESS (green accent color).

    3.3.5. Add the output button: SAVE MASTER (initially disabled).

Phase 4: Threading & Integration

Objective: Connect the UI to the Engine without freezing the application.
4.1. The Worker Thread

    4.1.1. Create src/engine/worker.py.

    4.1.2. Define class ProcessingThread(threading.Thread).

    4.1.3. Define __init__ to accept file_path, selected_preset, and active_checkboxes.

    4.1.4. Setup a queue.Queue to transmit messages from Thread to UI.

    4.1.5. message format: {"type": "progress", "value": 50} or {"type": "log", "text": "Loading..."}.

4.2. Main Thread Polling

    4.2.1. In SunoRemasterApp, implement check_queue() method.

    4.2.2. Use .after(100, self.check_queue) to run this method continuously.

    4.2.3. Implement handlers:

        If type == "progress": Update Progress Bar value.

        If type == "log": Append text to Status Textbox.

        If type == "done": Enable the "Save Master" button.

        If type == "error": Show a CTkMessagebox or alert.

4.3. Execution Logic

    4.3.1. In worker.py, instantiate AudioEngine.

    4.3.2. Call the DSP functions sequentially based on active_checkboxes.

    4.3.3. Implement "Fake" progress updates for demucs (e.g., increment 1% every second while waiting) or parse Demucs stdout if possible.

Phase 5: Refinement & I/O

Objective: Polish the logic and handle file saving/loading.
5.1. File Saving

    5.1.1. Implement the "Save Master" button callback in app.py.

    5.1.2. Open filedialog.asksaveasfilename.

    5.1.3. Use shutil.copy to move the final result from temp/ to the user's selected path.

    5.1.4. Auto-generate the default filename: {OriginalFilename}_{Genre}_Mastered.wav.

5.2. Audio Playback (Preview)

    5.2.1. Implement play_audio(path) in src/utils.py using pygame.mixer or sounddevice.

    5.2.2. Link "Play Original" to the source file.

    5.2.3. Link "Play Result" (next to Save button) to the temp output file.

    5.2.4. Ensure playback stops if the user clicks "Process" again.

5.3. Cleanup Logic

    5.3.1. Implement cleanup_temp_files() in src/utils.py.

    5.3.2. Use atexit library to call this function when the app closes, ensuring temp/ is emptied.

Phase 6: Final Polish & Testing

Objective: Final styling and functional verification.
6.1. Styling

    6.1.1. Adjust UI padding (padx, pady) to ensure elements breathe.

    6.1.2. Apply consistent fonts (e.g., Roboto Medium for headers).

    6.1.3. Add an .ico file for the window icon (if on Windows).

6.2. Functional Testing Checklist

    6.2.1. Test 1: Load a non-audio file (Expect: Error message, no crash).

    6.2.2. Test 2: Run "Techno" preset with all checkboxes checked (Expect: Full 60s+ process, temp files created).

    6.2.3. Test 3: Run "Organic House" with only "Limiting" checked (Expect: Fast process, no stem separation).

    6.2.4. Test 4: Verify that the output file is louder than the input (using external player).
