// SPDX-License-Identifier: Unlicense

#include "api.h"

#ifdef SHR3D_SFX_CORE_EXTENSION_V2

#include <stdio.h>

static constexpr f32 default_drive = 0.1f;

static f32 distortion(const f32 x)
{
  return (x >= 0.0f ? 1.0f - expf(-x) : -1.0f + expf(x));
}

struct DistortionInstance final : SfxCoreExtensionV2Instance
{
  f32 drive = default_drive;

  ProcessBlockResult processBlock(f32** inBlock, f32** /*outBlock*/, const i32 blockSize) override
  {
    const f32 drive_ = 1.0f + drive * 100.0f;

    for (i32 i = 0; i < blockSize; ++i)
    {
      inBlock[0][i] = distortion(inBlock[0][i] * drive_);
      inBlock[1][i] = distortion(inBlock[1][i] * drive_);
    }

    return ProcessBlockResult::ProcessedInInBlock;
  }

  f32 getParameter(const i32 index) const override
  {
    switch (index)
    {
    case 0:
      return drive;
    default:
      unreachable();
    }
  }

  void setParameter(const i32 index, const f32 value) override
  {
    switch (index)
    {
    case 0:
      drive = value;
      break;
    default:
      unreachable();
    }
  }

  void getParameterDisplay(const i32 index, char* text) override
  {
    switch (index)
    {
    case 0:
      sprintf(text, "%8.2f", drive);
      break;
    default:
      unreachable();
    }
  }

  void resetParameter(const i32 index) override
  {
    switch (index)
    {
    case 0:
      drive = default_drive;
      break;
    default:
      unreachable();
    }
  }
};

static struct Distortion final : SfxCoreExtensionV2Base
{
  Distortion()
  {
    RegisterSfxCoreExtensionV2(u8"Distortion", this);
  }

  i32 getParameterCount() const override
  {
    return 1;
  }

  const char8_t* getParameterLabel(const i32 index) override
  {
    switch (index)
    {
    case 0:
      return u8"";
    default:
      unreachable();
    }
  }

  const char8_t* getParameterName(const i32 index) override
  {
    switch (index)
    {
    case 0:
      return u8"Drive";
    default:
      unreachable();
    }
  }

  SfxCoreExtensionV2Instance* getInstance(const i32 instance) override
  {
    static SfxCoreExtensionV2Instance* instances[ExtensionV2MaxInstanceCount];
    assert(instance < ARRAY_SIZE(instances));

    if (instances[instance] == nullptr)
      instances[instance] = new DistortionInstance;

    return instances[instance];
  }
} distortion_;

#endif // SHR3D_SFX_CORE_EXTENSION_V2
