#include "ringmod.h"

using Xybrid::Effects::RingMod;
using namespace Xybrid::Data;

#include "util/strings.h"

#include "nodelib/basics.h"
using namespace Xybrid::NodeLib;

#include "data/audioframe.h"
#include "data/porttypes.h"

#include "config/pluginregistry.h"
using namespace Xybrid::Config;

#include "audio/audioengine.h"
using namespace Xybrid::Audio;

#include "ui/patchboard/nodeobject.h"
#include "ui/gadgets/layoutgadget.h"
#include "ui/gadgets/togglegadget.h"
#include "ui/gadgets/knobgadget.h"
using namespace Xybrid::UI;

#include <cmath>

#include <QCborMap>

// clazy:excludeall=non-pod-global-static
RegisterPlugin(RingMod, {
    i->id = "fx:ringmod";
    i->displayName = "Ring Mod";
    i->category = "Effect";
})

RingMod::RingMod() { }

void RingMod::init() {
    addPort(Port::Input, Port::Audio, 0)->name = "carrier";
    addPort(Port::Input, Port::Audio, 1)->name = "modulator";

    addPort(Port::Output, Port::Audio, 0);
}

void RingMod::reset() {
    //
}

void RingMod::process() {
    auto c = std::static_pointer_cast<AudioPort>(port(Port::Input, Port::Audio, 0));
    auto m = std::static_pointer_cast<AudioPort>(port(Port::Input, Port::Audio, 1));
    auto out = std::static_pointer_cast<AudioPort>(port(Port::Output, Port::Audio, 0));
    c->pull();
    m->pull();
    out->pull();

    auto ts = audioEngine->curTickSize();
    for (size_t f = 0; f < ts; f++) {
        AudioFrame fc = (*c)[f];
        AudioFrame fm = (*m)[f];
        if (am) fm = {std::abs(fm.l), std::abs(fm.r)};

        (*out)[f] = AudioFrame::lerp(fc, fc*fm, mix);
    }
}

void RingMod::saveData(QCborMap& m) const {
    m[qs("mix")] = mix;
    m[qs("am")] = am;
}

void RingMod::loadData(const QCborMap& m) {
    mix = m.value("mix").toDouble(mix);
    am = m.value("am").toBool(am);
}

void RingMod::onGadgetCreated() {
    if (!obj) return;
    auto l = new LayoutGadget(obj);

    l->setMetrics(3, 4);
    KnobGadget::autoPercent(l, mix)->setLabel(qs("Mix"))->setDefault(1.0);
    (new ToggleGadget(l))->bind(am)->setToolTip("AM mode", {1.0, 0.0})->setColor({127, 255, 127});
}
