//   mlhpisoundcard.h
//
//   Sound card subsystem for the HPI Library.
//
//   (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com>
//
//    $Id: mlhpisoundcard.h,v 1.4 2010/11/22 13:11:41 cvs Exp $
//
//   This program is free software; you can redistribute it and/or modify
//   it under the terms of the GNU General Public License version 2 as
//   published by the Free Software Foundation.
//
//   This program is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public
//   License along with this program; if not, write to the Free Software
//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//

#ifndef MLHPISOUNDCARD_H
#define MLHPISOUNDCARD_H

#define METER_INTERVAL 20

#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QTimer>

#include <mlhpiinformation.h>

#include <asihpi/hpi.h>
extern HPI_HSUBSYS *hpi_subsys;

/*
 * Definitions
 */
#define MLHPISOUNDCARD_HPI_MAX_LEVEL 2400
#define MLHPISOUNDCARD_HPI_MIN_LEVEL 0

/**
 * @short A driver-independent abstraction of a system's audio adapters.
 * @author Fred Gleason <fredg@wava.com>
 *
 * MLHPISoundCard attempts to provide a driver-independent view of the audio
 * adapters present on the system.  At present, it supports adapters using
 * AudioScience Corporation's Hardware Programming Interface (HPI).
 **/
class MLHPISoundCard : public QObject
{
  Q_OBJECT;

  public:
  /**
   * Specify the type of fade used in an AutoFade event.
   **/
   enum FadeProfile {Linear=0,Log=1};

  /**
   * Specify an audio channel.  Mono=Left.
   **/
   enum Channel {Left=0,Right=1};

  /**
   * Specify a mode for a stereo audio channel.
   **/
   enum ChannelMode {Normal=0,Swap=1,LeftOnly=2,RightOnly=3};

  /**
   * Specify the type of audio device.
   **/
   enum DeviceClass {RecordDevice=0,PlayDevice=1};

  /**
   * Specify the type of audio driver.
   **/
   enum Driver {Alsa=0,Hpi=1,Jack=2};

   /**
    * Clock Source Types
    */
   enum ClockSource {Internal=0,AesEbu=1,SpDiff=2,WordClock=4};

   /**
    * Mixer Source Nodes
    **/
   enum SourceNode {SourceBase=100, // HPI_SOURCENODE_BASE
		    OStream=101,    // HPI_SOURCENODE_OSTREAM
		    LineIn=102,     // HPI_SOURCENODE_LINEIN
		    AesEbuIn=103,   // HPI_SOURCENODE_AESEBU_IN
		    Tuner=104,      // HPI_SOURCENODE_TUNER
		    RfIn=105,       // HPI_SOURCENODE_RF
		    Clock=106,      // HPI_SOURCENODE_CLOCK_SOURCE
		    Raw=107,        // HPI_SOURCENODE_RAW_BITSTREAM
		    Mic=108         // HPI_SOURCENODE_MICROPHONE
   };

   /**
    * Mixer Destination Nodes
    **/
   enum DestNode {DestBase=200,     // HPI_DESTNODE_BASE
		  IStream=201,      // HPI_DESTNODE_ISTREAM
		  LineOut=202,      // HPI_DESTNODE_LINEOUT
		  AesEbuOut=203,    // HPI_DESTNODE_AESEBU_OUT
		  RfOut=204,        // HPI_DESTNODE_RF
		  Speaker=205       // HPI_DESTNODE_SPEAKER
   };

   enum TunerBand {Fm=0,FmStereo=1,Am=2,Tv=3};

   enum Subcarrier {Mpx=0,Rds=1};

   //
   // Card Info Methods
   // 
  /**
   * Create a MLHPISoundCard object.
   **/
   MLHPISoundCard(QObject *parent=0,const char *name=0);

  /**
   * Destroy a MLHPISoundCard object.
   **/
   ~MLHPISoundCard();

  /**
   * Returns the driver being used
   **/
   Driver driver() const;

  /**
   * Returns the number of audio adapters recognized by MLHPISoundCard.
   **/
   int getCardQuantity() const;

  /**
   * Determine the number of input streams supported by a particular 
   * audio adapter.
   * @param card The card number to interrogate.
   * Returns the number of input streams.
   **/
   int getCardInputStreams(int card) const;

  /**
   * Determine the number of output streams supported by a particular 
   * audio adapter.
   * @param card The card number to interrogate.
   * Returns the number of output streams.
   **/
   int getCardOutputStreams(int card) const;

  /**
   * Determine the number of input ports supported by a particular 
   * audio adapter.
   * @param card The card number to interrogate.
   * Returns the number of input ports.
   **/
   int getCardInputPorts(int card) const;

  /**
   * Determine the number of output ports supported by a particular 
   * audio adapter.
   * @param card The card number to interrogate.
   * Returns the number of output ports.
   **/
   int getCardOutputPorts(int card) const;

  /**
   * Get card information data.  The exact meaning of this is dependent upon
   * the specific audio driver being utilized.
   * @param card The card number to interrogate.
   * Returns pointer to the data.
   **/
   const void *getCardInfo(int card) const;

  /**
   * Get a description, suitable for displaying in a QListBox or other display
   * widget, of a particular audio adapter.
   * @param card The card number to interrogate.
   * Returns the audio adapter description.
   **/
   QString getCardDescription(int card) const;

  /**
   * Get a description, suitable for displaying in a QListBox or other display
   * widget, of one of a particular audio adapter's input streams.
   * @param card The card number to interrogate.
   * @param stream The stream number of the stream.
   * Returns the audio adapter input stream description.
   **/
   QString getInputStreamDescription(int card,int stream) const;

  /**
   * Get a description, suitable for displaying in a QListBox or other display
   * widget, of one of a particular audio adapter's output streams.
   * @param card The card number to interrogate.
   * @param stream The stream number of the stream.
   * Returns the audio adapter output stream description.
   **/
   QString getOutputStreamDescription(int card,int stream) const;

  /**
   * Get a description, suitable for displaying in a QListBox or other display
   * widget, of one of a particular audio adapter's input ports.
   * @param card The card number to interrogate.
   * @param port The stream number of the port.
   * Returns the audio adapter input port description.
   **/
   QString getInputPortDescription(int card,int port) const;

  /**
   * Get a description, suitable for displaying in a QListBox or other display
   * widget, of one of a particular audio adapter's output ports.
   * @param card The card number to interrogate.
   * @param port The stream number of the port.
   * Returns the audio adapter output port description.
   **/
   QString getOutputPortDescription(int card,int port) const;

  /**
   * Set the source of the sample clock used by the card.
   * @param src = The clock source to use.
   **/
   void setClockSource(int card,MLHPISoundCard::ClockSource src);

   /**
    * Determine if TSX timescaling is supported on this adapter.
    * @param card The card number.
    **/
   bool haveTimescaling(int card) const;

   //
   // Mixer Methods
   //
   /**
    * Determine if an input volume control exists.
    * @param card The card number of the control
    * @param stream The stream number of the control
    * @param port The port number of the control
    **/
   bool haveInputVolume(int card,int stream,int port) const;

   /**
    * Determine if an output volume control exists.
    * @param card The card number of the control
    * @param stream The stream number of the control
    * @param port The port number of the control
    **/
   bool haveOutputVolume(int card,int stream,int port) const;

   /**
    * Determine if an input level control exists.
    * @param card The card number of the control
    * @param port The port number of the control
    **/
   bool haveInputLevel(int card,int port) const;

   /**
    * Determine if an output level control exists.
    * @param card The card number of the control
    * @param port The port number of the control
    **/
   bool haveOutputLevel(int card,int port) const;

   /**
    * Determine if an input stream meter exists.
    * @param card The card number of the control
    * @param stream The stream number of the control
    **/
   bool haveInputStreamMeter(int card,int stream) const;


   /**
    * Determine if an output stream meter exists.
    * @param card The card number of the control
    * @param stream The stream number of the control
    **/
   bool haveOutputStreamMeter(int card,int stream) const;

   /**
    * Determine if an input port meter exists.
    * @param card The card number of the control
    * @param port The port number of the control
    **/
   bool haveInputPortMeter(int card,int port) const;

   /**
    * Determine if an output port meter exists.
    * @param card The card number of the control
    * @param port The port number of the control
    **/
   bool haveOutputPortMeter(int card,int port) const;

   /**
    * Determine if an associated tuner exists.
    * @param card The card number of the tuner
    * @param port The port number of the tuner
    **/
   bool haveTuner(int card,int port) const;

   MLHPISoundCard::TunerBand tunerBand(int card,int port);
   void setTunerBand(int card,int port,MLHPISoundCard::TunerBand band);
   int tunerFrequency(int card,int port);
   void setTunerFrequency(int card,int port,int freq);
   bool tunerSubcarrier(int card,int port,MLHPISoundCard::Subcarrier sub);
   int tunerLowFrequency(int card,int port,MLHPISoundCard::TunerBand band);
   int tunerHighFrequency(int card,int port,MLHPISoundCard::TunerBand band);

   /**
    * Get the peak level of the left input stream meter, resetting
    * the peak level in the process.
    * NOTE: This method should only be used with active metering disabled!
    * @param card The card number of the meter
    * @param stream The stream number of the meter
    * @param level Pointer to a array of two elements to hold the levels.
    **/
   bool inputStreamMeter(int card,int stream,short *level);

   /**
    * Get the peak level of the left output stream meter, resetting
    * the peak level in the process.
    * NOTE: This method should only be used with active metering disabled!
    * @param card The card number of the meter
    * @param stream The stream number of the meter
    * @param level Pointer to a array of two elements to hold the levels.
    **/
   bool outputStreamMeter(int card,int stream,short *level);

   /**
    * Get the peak level of the left input port meter, resetting
    * the peak level in the process.
    * NOTE: This method should only be used with active metering disabled!
    * @param card The card number of the meter
    * @param port The port number of the meter
    * @param level Pointer to a array of two elements to hold the levels.
    **/
   bool inputPortMeter(int card,int port,short *level);

   /**
    * Get the peak level of the left output port meter, resetting
    * the peak level in the process.
    * NOTE: This method should only be used with active metering disabled!
    * @param card The card number of the meter
    * @param port The port number of the meter
    * @param level Pointer to a array of two elements to hold the levels.
    **/
   bool outputPortMeter(int card,int port,short *level);

   /**
    * Determine if an input mode control exists.
    * @param card The card number of the control
    * @param stream The stream number of the control
    **/
   bool haveInputMode(int card,int stream) const;

   /**
    * Determine if an output mode control exists.
    * @param card The card number of the control
    * @param stream The stream number of the control
    **/
   bool haveOutputMode(int card,int stream) const;

   /**
    * Determine if an input VOX device exists.
    * @param card The card number of the device
    * @param stream The stream number of the device
    **/
   bool haveInputStreamVOX(int card,int stream) const;

   /**
    * Determine if an input port Mux device exists.
    * @param card The card number of the device
    * @param port The port number of the device
    **/
   bool haveInputPortMux(int card,int port) const;

   /**
    * Determine what sources are available for an input port Mux device.
    * @param card The card number of the device
    * @param port The port number of the device
    * @param node The source node
    **/
   bool queryInputPortMux(int card,int port,SourceNode node) const;
 
   /**
    * Determine if an input stream Mux device exists.
    * @param card The card number of the device
    * @param stream The stream number of the device
    **/
   bool haveInputStreamMux(int card,int stream) const;

   /**
    * Determine the current setting of an input volume control.
    * @param card The card number of the control
    * @param stream The stream number of the control
    * @param port The port number of the control
    * Returns: the current control setting, in 1/100 of a dB below FS.
    **/
   int getInputVolume(int card,int stream,int port);

   /**
    * Determine the current setting of an output volume control.
    * @param card The card number of the control
    * @param stream The stream number of the control
    * @param port The port number of the control
    * Returns: the current control setting, in 1/100 of a dB below FS.
    **/
   int getOutputVolume(int card,int stream,int port);

   /**
    * Determine the current setting of an input level control.
    * @param card The card number of the control
    * @param port The port number of the control
    * Returns: the current control setting, in 1/100 of a dBu
    **/
   int getInputLevel(int card,int port);

   /**
    * Determine the current setting of an output level control.
    * @param card The card number of the control
    * @param port The port number of the control
    * Returns: the current control setting, in 1/100 of a dBu
    **/
   int getOutputLevel(int card,int port);

   /**
    * Get the current input setting for an input port Mux control.
    * @param card The card number of the control
    * @param port The port number of the control
    * Returns: the current control setting
    **/
   MLHPISoundCard::SourceNode getInputPortMux(int card,int port);

   /**
    * Set the current input setting for an input port Mux control.
    * @param card The card number of the control
    * @param port The port number of the control
    * @param node The node to set the Mux to
    **/
   bool setInputPortMux(int card,int port,MLHPISoundCard::SourceNode node);

   /**
    * Get the current fade profile for the sound subsystem
    **/
   MLHPISoundCard::FadeProfile getFadeProfile() const;

   /**
    * Returns the current error status for the corresponding AES/EBU Port
    * @param card The card number of the control
    * @param port The port number of the control
    * Returns Error Codes, OR'd together as follows:
    *   HPI_AESEBU_ERROR_NOT_LOCKED 
    *   HPI_AESEBU_ERROR_POOR_QUALITY
    *   HPI_AESEBU_ERROR_PARITY_ERROR
    *   HPI_AESEBU_ERROR_BIPHASE_VIOLATION
    *   HPI_AESEBU_ERROR_VALIDITY
    **/
   unsigned short getInputPortError(int card,int port);

   /**
    * Set the current fade profile for the sound subsystem
    **/
   void setFadeProfile(MLHPISoundCard::FadeProfile profile);

  signals:
   /**
    * Signals a change in the current error status of the indicated AES/EBU
    * port.  Emitted whenever the error state changes.
    * @param card The card number of the control
    * @param port The port number of the control
    **/
   void inputPortError(int card,int port);
   void leftInputStreamMeter(int card,int stream,int level);
   void leftOutputStreamMeter(int card,int stream,int level);
   void rightInputStreamMeter(int card,int stream,int level);
   void rightOutputStreamMeter(int card,int stream,int level);
   void leftInputPortMeter(int card,int port,int level);
   void leftOutputPortMeter(int card,int port,int level);
   void rightInputPortMeter(int card,int port,int level);
   void rightOutputPortMeter(int card,int port,int level);
   void inputMode(int card,int stream,MLHPISoundCard::ChannelMode mode);
   void outputMode(int card,int stream,MLHPISoundCard::ChannelMode mode);
   void tunerSubcarrierChanged(MLHPISoundCard::Subcarrier car,bool state);

  public slots:
   void setInputVolume(int card,int stream,int level);
   void setOutputVolume(int card,int stream,int port,int level);
   void fadeOutputVolume(int card,int stream,int port,int level,int length);
   void setInputLevel(int card,int port,int level);
   void setOutputLevel(int card,int port,int level);
   void setInputMode(int card,int stream,MLHPISoundCard::ChannelMode mode);
   void setOutputMode(int card,int stream,MLHPISoundCard::ChannelMode mode);
   void setInputStreamVOX(int card,int stream,short gain);
   bool havePassthroughVolume(int card,int in_port,int out_port);
   bool setPassthroughVolume(int card,int in_port,int out_port,int level);

  private slots:
   void clock();

  private:
   void HPIProbe();
   HW16 card_input_streams[HPI_MAX_ADAPTERS];
   HW16 card_output_streams[HPI_MAX_ADAPTERS];
   HW16 card_input_ports[HPI_MAX_ADAPTERS];
   HW16 card_output_ports[HPI_MAX_ADAPTERS];
   QString card_description[HPI_MAX_ADAPTERS];
   QString input_stream_description[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   QString output_stream_description[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   QString input_port_description[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   QString output_port_description[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   bool input_stream_volume[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS][HPI_MAX_NODES];
   bool output_stream_volume[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS][HPI_MAX_NODES];
   bool input_port_level[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   bool output_port_level[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   bool input_stream_meter[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   bool output_stream_meter[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   bool input_port_meter[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   bool output_port_meter[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   bool input_stream_mode[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   bool output_stream_mode[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   bool input_stream_vox[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   bool input_port_mux[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   bool input_port_mux_type[HPI_MAX_ADAPTERS][HPI_MAX_NODES][2];
   bool passthrough_port_volume[HPI_MAX_ADAPTERS][HPI_MAX_NODES]
     [HPI_MAX_NODES];
   HW16 input_mux_index[HPI_MAX_ADAPTERS][HPI_MAX_NODES][2];
   bool input_stream_mux[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   bool input_port_aesebu[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   HW16 input_port_aesebu_error[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   bool timescale_support[HPI_MAX_ADAPTERS];
   int card_quantity;
   QTimer *clock_timer;
   MLHPISoundCard::FadeProfile fade_type;
   HPI_HMIXER hpi_mixer[HPI_MAX_ADAPTERS];
   HPI_HCONTROL clock_source_control[HPI_MAX_ADAPTERS];
   HPI_HCONTROL input_stream_volume_control[HPI_MAX_ADAPTERS]
     [HPI_MAX_STREAMS][HPI_MAX_NODES];
   HPI_HCONTROL output_stream_volume_control[HPI_MAX_ADAPTERS]
     [HPI_MAX_STREAMS][HPI_MAX_NODES];
   HPI_HCONTROL input_port_level_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   HPI_HCONTROL output_port_level_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   HPI_HCONTROL input_stream_meter_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   HPI_HCONTROL output_stream_meter_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   HPI_HCONTROL input_port_meter_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   HPI_HCONTROL output_port_meter_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   HPI_HCONTROL input_stream_mode_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   HPI_HCONTROL output_stream_mode_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   HPI_HCONTROL input_stream_vox_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   bool input_mux_type[HPI_MAX_ADAPTERS];
   HPI_HCONTROL input_mux_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
   HPI_HCONTROL passthrough_port_volume_control[HPI_MAX_ADAPTERS]
				[HPI_MAX_NODES][HPI_MAX_NODES];
   HPI_HCONTROL input_port_aesebu_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES];
   HW16 hpi_fade_type;
   short 
     input_stream_meter_peak[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS][HPI_MAX_CHANNELS];
   short 
     output_stream_meter_peak[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS][HPI_MAX_CHANNELS];
   short input_port_meter_peak[HPI_MAX_ADAPTERS][HPI_MAX_NODES][HPI_MAX_CHANNELS];
   short output_port_meter_peak[HPI_MAX_ADAPTERS][HPI_MAX_NODES][HPI_MAX_CHANNELS];
   MLHPIInformation hpi_info[HPI_MAX_ADAPTERS];
};


#endif  // MLHPISOUNDCARD_H
