/* -*- mode: c++; c-file-style: "bsd"; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* $Id$ */

////////////////////////////////////////////////////////////////////////////////////////////////////
// Digital Amplifier. The "Hello World" LADSPA plug-in
////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>

#include "ladspa.h"


// This module contains only one signal processing block, whose descriptor is g_descriptor0
static LADSPA_Descriptor* g_descriptor0 = 0;

// Ports of the block, see below Instance_data struct
#define PORT_I1		0
#define PORT_O1		1		
#define PORT_C1         2
#define PORTCOUNT	3

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Data for ONE instance of the signal processing block, (datatype LADSPA_Data = float)
typedef struct 
{
        unsigned long	fs;                     // Sampling frecuency    
        LADSPA_Data*	port_i1;		// Input
        LADSPA_Data*	port_o1;		// Output
        LADSPA_Data*	port_c1;		// Control (gain)

} Instance_data;
////////////////////////////////////////////////////////////////////////////////////////////////////

// Dinamyc library (*.dll or *.so) initialization/finalization funcions
void my_init();
void my_fini();

// Plug-in functions called by host
static LADSPA_Handle	my_instantiate	(const LADSPA_Descriptor *des, unsigned long s_rate);
static void		my_cleanup	(LADSPA_Handle hnd);

void			my_activate	(LADSPA_Handle hnd);
void			my_deactivate	(LADSPA_Handle hnd);

static void		my_connect	(LADSPA_Handle hnd, unsigned long port, LADSPA_Data *data);
static void		my_run		(LADSPA_Handle hnd, unsigned long sample_count);

////////////////////////////////////////////////////////////////////////////////////////////////////

// Initialization/Finalization functions differ in UNIX and Windows
#ifdef WIN32
#include <windows.h>
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
        switch( ul_reason_for_call ) {
        case DLL_PROCESS_ATTACH:
                my_init();
                break;
        case DLL_THREAD_ATTACH:
                break;
        case DLL_THREAD_DETACH:
                break;
        case DLL_PROCESS_DETACH:
                my_fini();
                break;
        }
        return TRUE;
}
#elif LINUX 
void __attribute__ ((constructor)) init() { my_init(); }
void __attribute__ ((destructor))  fini() { my_fini(); }
#endif


////////////////////////////////////////////////////////////////////////////////////////////////////
// This funcion is executed when DLL is loaded into memory. Initializes LADSPA_Descriptor structure
// this plug-in has only one signal processing block so It has only one LADSPA_Description structure
void my_init() 
{
        char**			port_name;
        LADSPA_PortDescriptor*	port_prop;
        LADSPA_PortRangeHint*	port_rang;

        g_descriptor0 = (LADSPA_Descriptor*) malloc(sizeof(LADSPA_Descriptor));

        if (g_descriptor0) 
        {
                // Simplify notation
                LADSPA_Descriptor* p = g_descriptor0;

                p->UniqueID		= 1000;
                p->Properties		= LADSPA_PROPERTY_HARD_RT_CAPABLE;
                p->Label		= "amplifier";
                p->Name			= "Amplifier. Basic example of a LADSPA plug-in";
                p->Maker		= "Javier Valcarce García <javier.valcarce@gmail.com>";
                p->Copyright		= "GPL";
                p->PortCount		= PORTCOUNT;

                port_prop = (LADSPA_PortDescriptor*) calloc(PORTCOUNT, sizeof(LADSPA_PortDescriptor));
                port_rang = (LADSPA_PortRangeHint*)  calloc(PORTCOUNT, sizeof(LADSPA_PortRangeHint));
                port_name = (char**)                 calloc(PORTCOUNT, sizeof(char*));

                p->PortDescriptors	= (const LADSPA_PortDescriptor *) port_prop;     
                p->PortRangeHints	= (const LADSPA_PortRangeHint *)  port_rang;
                p->PortNames		= (const char **)                 port_name;


                //PORT_I1
                port_name[PORT_I1]	= "Input";
                port_prop[PORT_I1]	= LADSPA_PORT_INPUT  | LADSPA_PORT_AUDIO;
                //PORT_O1
                port_name[PORT_O1]	= "Output";
                port_prop[PORT_O1]	= LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
                //PORT_C1
                port_name[PORT_C1]	= "Gain";
                port_prop[PORT_C1]	= LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL;


                // Pointers to functions called by host
                p->instantiate		= my_instantiate;
                p->connect_port		= my_connect;
                p->activate		= my_activate;
                p->deactivate		= my_deactivate;
                p->cleanup		= my_cleanup;
                p->run			= my_run;
                p->run_adding		= 0;
                p->set_run_adding_gain	= 0;
        }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
// This function is executed when DLL is unloaded from memory 
void my_fini() 
{
        if (g_descriptor0) 
        {
                free((char**)                 g_descriptor0->PortNames       );
                free((LADSPA_PortDescriptor*) g_descriptor0->PortDescriptors );
                free((LADSPA_PortRangeHint*)  g_descriptor0->PortRangeHints  );
                free(g_descriptor0);
        }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
// The only Entry Point in this shared object 
EXPORT
const LADSPA_Descriptor* ladspa_descriptor(unsigned long index) 
{
        switch (index) 
        {
        case 0:
                return g_descriptor0;
        default:
                return NULL;
        }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Allocate memory for one instance of the block, ie, creates a new instance
static LADSPA_Handle my_instantiate(const LADSPA_Descriptor *des, unsigned long s_rate) 
{
        if (des != g_descriptor0)
        {
                // Error, there is only one block in this module
                return NULL;
        }

        Instance_data* ins = (Instance_data*) malloc(sizeof(Instance_data));
        memset(ins, 0, sizeof(Instance_data));

        // Sampling frecuency
        ins->fs = s_rate;

        return (LADSPA_Handle) ins;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// The opposite of instantiate, destroy instance
static void my_cleanup(LADSPA_Handle hnd) 
{
        Instance_data* ins = (Instance_data*) hnd;
        free(ins);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Initializes instance data. It must be called AFTER connect_ports()
void my_activate(LADSPA_Handle hnd)
{
        Instance_data* ins = (Instance_data*) hnd;
}


////////////////////////////////////////////////////////////////////////////////////////////////////
// The opposite of activate()
void my_deactivate(LADSPA_Handle hnd)
{
}


////////////////////////////////////////////////////////////////////////////////////////////////////
// Connect block'ports to data buffers provided by host
static void my_connect(LADSPA_Handle hnd, unsigned long port, LADSPA_Data *data) 
{
        Instance_data* ins = (Instance_data*) hnd;
	
        switch (port) 
        {
        case PORT_I1: ins->port_i1 = data; break;
        case PORT_O1: ins->port_o1 = data; break;
        case PORT_C1: ins->port_c1 = data; break;
        default: 
                assert(0);
        }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// PROCESS blocks of sample_count samples. This is the KERNEL of the plug-in
static void my_run(LADSPA_Handle hnd, unsigned long sample_count) 
{
        Instance_data* ins = (Instance_data*) hnd;	
        LADSPA_Data* x =   ins->port_i1;  // input port
        LADSPA_Data* y =   ins->port_o1;  // output port
        LADSPA_Data  g = *(ins->port_c1); // gain (input control port)
        unsigned long i;

        for (i = 0; i < sample_count; i++) 
        {
                y[i] = x[i] * g;
        }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

