Skip to main content
This guide covers the technical details of working with the ZZAR codebase.

Project Structure

ZZAR is organized into several core modules:
ZZAR/
├── ZZAR.py                          # Application entry point
├── requirements.txt                 # Python dependencies
├── ZZAR.spec                        # PyInstaller build configuration
├── src/                             # Source code
│   ├── audio_converter.py           # Audio format conversion
│   ├── audio_matcher.py             # Audio matching/fingerprinting
│   ├── audio_player.py              # Audio playback
│   ├── bnk_handler.py               # BNK SoundBank handling
│   ├── bnk_indexer.py               # BNK file indexing
│   ├── bnk_mod_helper.py            # BNK modification utilities
│   ├── config_manager.py            # Application configuration
│   ├── fingerprint_database.py      # Audio fingerprint database
│   ├── mod_package_manager.py       # .zzar mod package management
│   ├── pck_extractor.py             # PCK archive extraction
│   ├── pck_indexer.py               # PCK file indexing
│   ├── pck_packer.py                # PCK archive packing
│   ├── persistent_mod_manager.py    # Persistent mod state
│   ├── sound_database.py            # Sound metadata database
│   ├── temp_cache_manager.py        # Temporary cache management
│   ├── wwise_wrapper.py             # Wwise audio encoding
│   └── gui/                         # PyQt5 GUI components
│       ├── main_qml.py              # Main application window
│       ├── qml/                     # QML UI files
│       ├── components/              # Reusable QML components
│       ├── assets/                  # Images, icons, logos
│       ├── translations/            # i18n translation files
│       ├── backend/                 # Python-QML bridge classes
│       └── connectors/              # Backend connectors
├── scripts/                         # Utility scripts
│   ├── speaker_cluster.py           # Voice character clustering
│   └── fix_translations.py          # Translation file management
├── setup_wwise.py                   # Wwise installation script
├── setup_windows_audio_tools.py     # Windows audio tools setup
├── start_gui.bat                    # Windows launcher
└── start_gui.sh                     # Linux launcher

Core Architecture

Audio Processing Pipeline

ZZAR processes Zenless Zone Zero audio files through this pipeline:
  1. Extraction (pck_extractor.py, pck_indexer.py)
    • Read .pck archive files
    • Extract .bnk SoundBank files
    • Index WEM audio files inside BNK archives
  2. Conversion (audio_converter.py, wwise_wrapper.py)
    • Convert between MP3, WAV, and WEM formats
    • Use Wwise for game-compatible WEM encoding
    • Use FFmpeg/vgmstream for decoding
  3. Modification (bnk_handler.py, mod_package_manager.py)
    • Replace WEM files in BNK archives
    • Rebuild BNK with modified audio
    • Package changes into .zzar mod files
  4. Packing (pck_packer.py)
    • Rebuild .pck archives with modified BNK files
    • Install mods to game directory

GUI Architecture

ZZAR uses PyQt5 with QML for the interface:
  • Python Backend - Core logic and game file manipulation
  • QML Frontend - Declarative UI components
  • Bridge Classes (gui/backend/) - Connect Python to QML using Qt signals/slots

Coding Standards

Python Code Style

Follow these conventions when writing Python code:
  • PEP 8 - Use standard Python style guidelines
  • 4 spaces for indentation (no tabs)
  • Snake case for functions and variables (extract_wem_file)
  • Pascal case for classes (ModPackageManager)
  • Docstrings for all public functions and classes
Example:
def extract_wem_file(bnk_path: Path, wem_id: int) -> bytes:
    """
    Extract a WEM audio file from a BNK archive.
    
    Args:
        bnk_path: Path to the .bnk file
        wem_id: WEM file ID to extract
        
    Returns:
        Raw bytes of the WEM file
        
    Raises:
        FileNotFoundError: If BNK file doesn't exist
        ValueError: If WEM ID not found in archive
    """
    indexer = BNKIndexer(bnk_path.read_bytes())
    wem_list = indexer.parse_didx()
    return indexer.extract_wem(wem_id)

QML Code Style

  • 2 spaces for indentation
  • Camel case for properties (audioFile)
  • Pascal case for component names (AudioBrowserView)
  • Comments for complex UI logic

File Organization

  • Keep related functionality together in modules
  • Use Path from pathlib instead of string paths
  • Handle platform differences (Windows/Linux) explicitly
Example:
import sys
from pathlib import Path

if sys.platform.startswith('win'):
    # Windows-specific code
    tool_path = Path('tools/audio/ffmpeg.exe')
else:
    # Linux-specific code
    tool_path = Path('/usr/bin/ffmpeg')

Testing

Manual Testing

Before submitting changes, test these workflows:
  1. Audio Browser
    • Browse game audio files
    • Preview WEM playback
    • Search and filter functionality
  2. Mod Creation
    • Replace audio files
    • Export as .zzar package
    • Verify mod structure
  3. Mod Installation
    • Install .zzar mods
    • Enable/disable mods
    • Handle conflicts between mods
  4. Audio Conversion
    • Convert MP3 → WEM
    • Convert WAV → WEM
    • Convert WEM → WAV

Platform Testing

Test on both platforms when possible:
  • Windows - Native Wwise, no Wine needed
  • Linux - Wwise via Wine, GStreamer audio

Contributing Workflow

1

Create a Branch

Create a feature branch for your changes:
git checkout -b feature/your-feature-name
Use descriptive branch names:
  • feature/add-audio-preview
  • fix/bnk-extraction-crash
  • docs/update-readme
2

Make Your Changes

Write code following the coding standards above. Test your changes thoroughly.
3

Commit Your Changes

Write clear, descriptive commit messages:
git add .
git commit -m "Add audio preview functionality to browser"
Good commit messages:
  • “Fix BNK extraction crash on corrupted files”
  • “Add Spanish translation support”
  • “Update PyInstaller spec for Linux dependencies”
Bad commit messages:
  • “fix bug”
  • “update”
  • “asdf”
4

Push and Create Pull Request

Push your branch and create a pull request:
git push origin feature/your-feature-name
Go to GitHub and create a pull request with:
  • Clear description of changes
  • Any related issue numbers
  • Screenshots for UI changes
  • Testing notes

Translation Support

ZZAR supports multiple languages through Qt’s translation system.

Adding Translations

  1. Extract translatable strings:
python scripts/fix_translations.py
  1. Edit .ts files in src/gui/translations/:
    • zzar_en.ts - English (source)
    • zzar_es.ts - Spanish
    • Add new language files as needed
  2. Use Qt Linguist or edit XML directly to provide translations
  3. Test translations by changing system language

Making Code Translatable

Use self.tr() in Python classes:
class AudioBrowser(QObject):
    def show_error(self):
        message = self.tr("Failed to load audio file")
        QMessageBox.critical(None, self.tr("Error"), message)
Use qsTr() in QML:
Text {
    text: qsTr("Audio Browser")
}

Utility Scripts

Speaker Clustering (scripts/speaker_cluster.py)

Identify voice characters in ZZZ audio using MFCC clustering:
python scripts/speaker_cluster.py
This script:
  • Extracts voice clips from game files
  • Computes audio features (MFCC, F0, spectral stats)
  • Clusters speakers using hierarchical clustering
  • Outputs speaker groups for tagging

Translation Fixer (scripts/fix_translations.py)

Maintain translation files:
python scripts/fix_translations.py
This script:
  • Runs lupdate on QML files
  • Extracts self.tr() calls from Python
  • Injects entries into .ts files
  • Removes obsolete translations

Resources

Getting Help

If you need help:
  1. Check existing GitHub Issues
  2. Ask in the project’s discussion forum
  3. Reach out to maintainers

Build docs developers (and LLMs) love