// bake_render — the offline pass: one programmed note through a voice engine built for
// this render alone, summed into an interleaved buffer.
//
// Never touches a live engine and never runs on the audio thread. Takes its SampleData BY
// VALUE for the reason this directory's CLAUDE.md records.

#pragma once

#include <cstdint>
#include <vector>

#include "core/instrument/bake/bake_plan.h"
#include "core/instrument/engine/play_params.h"

namespace reasampler::instrument::bake {

using audio::AudioSample;

struct BakeAudio {
    std::vector<AudioSample> interleaved;  // [f0c0, f0c1, f1c0, …]
    int channelCount = 0;                  // 0 = nothing rendered
    int sampleRate = 0;

    std::int64_t frameCount() const {
        return channelCount > 0
                   ? static_cast<std::int64_t>(interleaved.size()) / channelCount
                   : 0;
    }
    bool empty() const { return frameCount() == 0; }
};

// Renders `plan` through `sample`'s own voice path and then the master stage the processor
// runs after the engine: `masterGainLinear`, then the limiter when `limiterEnabled` — see
// bake_render.cpp for why both print here rather than in the processor. `limiterEnabled`
// false yields the pre-limiter render. The result is the plan's captured window: the
// lead-in frames are rendered and dropped. An unplayable sample yields an empty result.
BakeAudio renderBake(SampleData sample, const BakePlan& plan, double masterGainLinear,
                     bool limiterEnabled);

}  // namespace reasampler::instrument::bake
