Aestra

Coding Style Guide

Aestra follows a consistent C++17 coding style enforced by clang-format (LLVM-based). This guide covers naming conventions, formatting rules, and best practices.

Quick Reference

Element Convention Example
Classes/Structs PascalCase AudioEngine, TrackManager
Functions/Methods camelCase initialize(), setSampleRate()
Member variables camelCase with trailing _ sampleRate_, bufferSize_
Constants SCREAMING_SNAKE_CASE MAX_CHANNELS, DEFAULT_SAMPLE_RATE
Enums PascalCase values AudioState::Playing
Namespaces lowercase Aestra::core, Aestra::audio
Files PascalCase AudioEngine.h, TrackManager.cpp
Private members Leading underscore or trailing _ internalState_

Formatting

Formatting is enforced automatically by clang-format via pre-commit hooks. Run manually:

clang-format -i Source/**/*.cpp AestraAudio/**/*.cpp AestraUI/**/*.cpp

Key rules (from .clang-format):

Include Order

// 1. Corresponding header
#include "AudioEngine.h"

// 2. Aestra project headers
#include "AestraCore/Logger.h"
#include "AestraAudio/Types.h"

// 3. Third-party libraries
#include <rtaudio/RtAudio.h>

// 4. Standard library
#include <atomic>
#include <cstdint>
#include <memory>
#include <string>

Header Guards

Use #pragma once:

#pragma once

#include <cstdint>

namespace Aestra {
namespace audio {

class AudioEngine {
    // ...
};

} // namespace audio
} // namespace Aestra

Class Structure

Organize class members in this order:

class AudioEngine {
public:
    // Types and enums
    enum class State { Stopped, Playing, Paused };

    // Constructors / destructor
    AudioEngine();
    ~AudioEngine();

    // Public interface
    bool initialize(const AudioConfig& config);
    void start();
    void stop();

protected:
    // Protected members

private:
    // Private methods
    void processAudio(float* buffer, int frames);

    // Private data members
    State state_ = State::Stopped;
    uint32_t sampleRate_ = 48000;
};

Real-Time Audio Constraints

The audio thread has strict requirements:

// Good: Lock-free, allocation-free audio callback
void AudioEngine::processAudio(float* buffer, int frames) {
    // Read commands from lock-free queue
    AudioCommand cmd;
    while (commandQueue_.pop(cmd)) {
        handleCommand(cmd);  // Must also be RT-safe
    }

    // Process audio (no allocations, no locks)
    mixer_.mix(buffer, frames);
}

Error Handling

std::optional<AudioDevice> getDefaultDevice();
bool initialize(const AudioConfig& config);

Documentation

Use /** */ Doxygen-style comments for public APIs:

/**
 * @brief Initialize the audio engine with the given configuration.
 * @param config Audio configuration (sample rate, buffer size, etc.)
 * @return true on success, false if the audio device cannot be opened.
 *
 * Must be called before start(). If initialization fails, check
 * lastError() for details.
 */
bool initialize(const AudioConfig& config);

Commit Messages

Follow conventional commits:

type(scope): subject

body (optional)

Closes #issue

Types: feat, fix, docs, style, refactor, test, chore

Examples:

feat(audio): add ASIO exclusive mode support
fix(ui): resolve click-through on dropdown menus
docs: update architecture overview for plugin system

Pre-Commit Hooks

Install hooks to enforce style automatically:

# Windows
pwsh -File scripts/install-hooks.ps1
# Linux
bash scripts/install-hooks.sh

The hooks run:

Resources


Last updated: March 2026