#include <stdlib.h>
#include <string.h>

#include <math.h>

#include "lv2.h"

#ifdef WIN32
#define SYMBOL_EXPORT __declspec(dllexport)
#else
#define SYMBOL_EXPORT
#endif

#define AMP_URI       "http://plugin.org.uk/swh-plugins/amp";
#define AMP_GAIN      0
#define AMP_INPUT     1
#define AMP_OUTPUT    2

static LV2_Descriptor *ampDescriptor = NULL;

typedef struct {
	float *gain;
	float *input;
	float *output;
} Amp;

static void cleanupAmp(LV2_Handle instance) {
	free(instance);
}

static void connectPortAmp(LV2_Handle instance, unsigned long port,
			   void *data) {
	Amp *plugin = (Amp *)instance;

	switch (port) {
	case AMP_GAIN:
		plugin->gain = data;
		break;
	case AMP_INPUT:
		plugin->input = data;
		break;
	case AMP_OUTPUT:
		plugin->output = data;
		break;
	}
}

static LV2_Handle instantiateAmp(const LV2_Descriptor *descriptor,
	    unsigned long s_rate, const char *path , const LV2_Host_Feature **features) {
	Amp *plugin_data = (Amp *)malloc(sizeof(Amp));

	return (LV2_Handle)plugin_data;
}

#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f)

static void runAmp(LV2_Handle instance, unsigned long sample_count) {
	Amp *plugin_data = (Amp *)instance;

	const float gain = *(plugin_data->gain);
	const float * const input = plugin_data->input;
	float * const output = plugin_data->output;

	unsigned long pos;
	float coef = DB_CO(gain);

	for (pos = 0; pos < sample_count; pos++) {
		output[pos] = input[pos] * coef;
	}
}

static void init() {
	ampDescriptor =
	 (LV2_Descriptor *)malloc(sizeof(LV2_Descriptor));

	ampDescriptor->URI = AMP_URI;
	ampDescriptor->activate = NULL;
	ampDescriptor->cleanup = cleanupAmp;
	ampDescriptor->connect_port = connectPortAmp;
	ampDescriptor->deactivate = NULL;
	ampDescriptor->instantiate = instantiateAmp;
	ampDescriptor->run = runAmp;
}

SYMBOL_EXPORT
const LV2_Descriptor *lv2_descriptor(unsigned long index) {
	if (!ampDescriptor) init();

	switch (index) {
	case 0:
		return ampDescriptor;
	default:
		return NULL;
	}
}