//=========================================================
//  MusE
//  Linux Music Editor
//  $Id: plugin.h,v 1.1.1.1 2003/10/29 10:06:36 wschweer Exp $
//
//  (C) Copyright 2000 Werner Schweer (ws@seh.de)
//=========================================================

#ifndef __PLUGIN_H__
#define __PLUGIN_H__

#include <qmainwindow.h>
#include <qstring.h>
#include <qwidget.h>
#include <list>
#include <vector>
#include "ladspa.h"
#include "globals.h"
#include <qdialog.h>
#include <qfileinfo.h>

class Xml;
class QWidget;
// class QLabel;
class Slider;
class QListView;
class QToolButton;
class DoubleLabel;

//---------------------------------------------------------
//   Plugin
//---------------------------------------------------------

class Plugin {
      int _references;
      int _instNo;
      QFileInfo fi;
      LADSPA_Descriptor_Function ladspa;
      const LADSPA_Descriptor *plugin;
      int _inports;
      int _outports;
      bool _inPlaceCapable;

   public:
      Plugin(QFileInfo* f,
         LADSPA_Descriptor_Function df, const LADSPA_Descriptor* d, bool inPlace);

      QString label() const    { return QString(plugin->Label); }
      QString name() const     { return QString(plugin->Name); }
      unsigned long id() const { return plugin->UniqueID; }
      QString maker() const    { return QString(plugin->Maker); }
      QString copyright() const { return QString(plugin->Copyright); }
      QString lib() const      { return fi.baseName(); }
      QString path() const     { return fi.dirPath(); }
      int references() const   { return _references; }
      int incReferences(int n) { return _references += n; }
      int instNo()             { return _instNo++;        }

      LADSPA_Handle instantiate() {
            return plugin->instantiate(plugin, sampleRate);
            }
      void activate(LADSPA_Handle handle) {
            if (plugin->activate)
                  plugin->activate(handle);
            }
      void connectPort(LADSPA_Handle handle, int port, float* value) {
            plugin->connect_port(handle, port, value);
            }
      void apply(LADSPA_Handle handle, int n) {
            plugin->run(handle, n);
            }
      int ports() { return plugin->PortCount; }
      LADSPA_PortDescriptor portd(int k) const {
            return plugin->PortDescriptors[k];
            }
      LADSPA_PortRangeHint range(int i) const {
            return plugin->PortRangeHints[i];
            }
      const char* portName(int i) {
            return plugin->PortNames[i];
            }
      int inports() const  { return _inports; }
      int outports() const { return _outports; }
      bool inPlaceCapable() const { return _inPlaceCapable; }
      };

typedef std::list<Plugin>::iterator iPlugin;

//---------------------------------------------------------
//   PluginList
//---------------------------------------------------------

class PluginList : public std::list<Plugin> {
   public:
      void add(QFileInfo* fi, LADSPA_Descriptor_Function df,
         const LADSPA_Descriptor* d, bool inPlaceOk) {
            push_back(Plugin(fi, df, d, inPlaceOk));
            }
      Plugin* find(const QString&, const QString&);
      PluginList() {}
      };

//---------------------------------------------------------
//   Port
//---------------------------------------------------------

struct Port {
      int idx;
      float val;
      float tmpVal;
      };

//---------------------------------------------------------
//   GuiParam
//---------------------------------------------------------

struct GuiParam {
      enum {
            GUI_SLIDER, GUI_SWITCH
            };
      int type;
      int hint;
//      QLabel* label;     // value label
      DoubleLabel* label;
      QWidget* actuator;  // Slider or Toggle Button (SWITCH)
      };


class PluginI;

//---------------------------------------------------------
//   PluginGui
//---------------------------------------------------------

class PluginGui : public QMainWindow {
      Q_OBJECT

      PluginI* plugin;        // plugin instance
      GuiParam* params;
      QToolButton* onOff;

   private slots:
      void parameterChanged(int);
      void load();
      void save();
      void bypassToggled(bool);
      void parameterChanged(double, int);

   public:
      PluginGui(PluginI*);
      void setOn(bool);
      };

//---------------------------------------------------------
//   PluginI
//    plugin instance
//---------------------------------------------------------

#define AUDIO_IN (LADSPA_PORT_AUDIO  | LADSPA_PORT_INPUT)
#define AUDIO_OUT (LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT)

class PluginI {
      Plugin* _plugin;
      int instances;

      LADSPA_Handle* handle;         // per instance
      Port* controls;

      int controlPorts;
      PluginGui* _gui;
      bool _on;
      bool initControlValues;
      QString _name;
      QString _label;

      void init();
      void makeGui();

   public:
      PluginI();
      ~PluginI();

      Plugin* plugin() const { return _plugin; }
      bool on() const        { return _on; }
      void setOn(bool val)   { _on = val; }
      PluginGui* gui() const { return _gui; }

      bool initPluginInstance(Plugin*, int channels);

      void connect(int ports, float** src, float** dst);
      void apply(int n);

      void activate();
      QString label() const          { return _label; }
      QString name() const           { return _name; }
      QString lib() const            { return _plugin->lib(); }

      void writeConfiguration(int level, Xml& xml);
      bool readConfiguration(Xml& xml, bool readPreset=false);
      bool loadControl(Xml& xml);
      bool setControl(const QString& s, double val);
      void showGui();
      void showGui(bool);
      bool guiVisible();
      int parameters() const           { return controlPorts; }
      void setParam(int i, double val) { controls[i].tmpVal = val; }
      double param(int i) const        { return controls[i].val; }
      const char* paramName(int i)     { return _plugin->portName(controls[i].idx); }
      LADSPA_PortDescriptor portd(int i) const { return _plugin->portd(controls[i].idx); }
      LADSPA_PortRangeHint range(int i) const { return _plugin->range(controls[i].idx); }
      bool isAudioIn(int k) {
            return (_plugin->portd(k) & AUDIO_IN) == AUDIO_IN;
            }
      bool isAudioOut(int k) {
            return (_plugin->portd(k) & AUDIO_OUT) == AUDIO_OUT;
            }
      bool inPlaceCapable() const { return _plugin->inPlaceCapable(); }
      };

//---------------------------------------------------------
//   Pipeline
//    chain of connected efx inserts
//---------------------------------------------------------

const int PipelineDepth = 4;

class Pipeline : public std::vector<PluginI*> {
   public:
      Pipeline();
      void insert(PluginI* p, int index);
      void remove(int index);
      void removeAll();
      bool isOn(int idx) const;
      void setOn(int, bool);
      QString label(int idx) const;
      QString name(int idx) const;
      void showGui(int, bool);
      bool guiVisible(int);
      void apply(int ports, unsigned long nframes, float** buffer);
      void move(int idx, bool up);
      bool empty(int idx) const;
//      bool empty() const { return std::vector<PluginI*>::empty(); }
      };

typedef Pipeline::iterator iPluginI;
typedef Pipeline::const_iterator ciPluginI;

//---------------------------------------------------------
//   PluginDialog
//---------------------------------------------------------

class PluginDialog : public QDialog {
      QListView* pList;

      Q_OBJECT

   public:
      PluginDialog(QWidget* parent=0, const char* name=0, bool modal=true);
      static Plugin* getPlugin(QWidget* parent);
      Plugin* value();
      };

extern void initPlugins();
extern PluginList plugins;

#endif

