#include "DeepPluckOutputMeter.h"

#include <algorithm>
#include <cmath>

namespace deeppluck
{
void DeepPluckOutputMeter::reset() noexcept
{
    left.store (0.0f, std::memory_order_release);
    right.store (0.0f, std::memory_order_release);
}

void DeepPluckOutputMeter::publishOne (std::atomic<float>& destination, float peak) noexcept
{
    if (! std::isfinite (peak)) peak = 0.0f;
    peak = std::clamp (peak, 0.0f, 4.0f);
    auto current = destination.load (std::memory_order_relaxed);
    while (peak > current
           && ! destination.compare_exchange_weak (current, peak,
                                                   std::memory_order_release,
                                                   std::memory_order_relaxed))
    {
    }
}

void DeepPluckOutputMeter::publish (float leftPeak, float rightPeak) noexcept
{
    publishOne (left, leftPeak);
    publishOne (right, rightPeak);
}

std::array<float, 2> DeepPluckOutputMeter::consume() noexcept
{
    return { left.exchange (0.0f, std::memory_order_acq_rel),
             right.exchange (0.0f, std::memory_order_acq_rel) };
}

bool DeepPluckOutputMeter::isLockFree() const noexcept
{
    return left.is_lock_free() && right.is_lock_free();
}
}
