//   mlhpirecordstream.h
//
//   A class for recording Microsoft WAV files.
//
//   (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com>
//
//    $Id: mlhpirecordstream.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 MLHPIRECORDSTREAM_H
#define MLHPIRECORDSTREAM_H

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <QtGui/QWidget>
#include <QtCore/QString>
#include <QtCore/QDateTime>
#include <QtCore/QTimer>

#include <mlwavefile.h>
#include <mlhpisoundcard.h>

#define DEBUG_VAR "_MLHPIRECORDSTREAM"
#define XRUN_VAR "_RSOUND_XRUN"

#include <asihpi/hpi.h>
#define AUDIO_SIZE 32768
#define MLHPIRECORDSTREAM_CLOCK_INTERVAL 100

/**
 * @short An object for recording Microsoft WAV files
 * @author Fred Gleason <fredg@wava.com>
 *
 * RRecordStream implements a virtual device for recording Microsoft WAV
 * files.  It supports AudioScience HPI audio hardware.
 * It is capable of recording PCM8, PCM16 and (if the underlying hardware
 * supports it) MPEG-1 formatted files.
 *
 * If the environmental variable '_RRECORDSTREAM' is defined in the 
 * environment, RRecordStream print debugging information to stdout. 
 **/
class MLHPIRecordStream : public QObject,public MLWaveFile
{
  Q_OBJECT

  public:
  /**
   * Possible machine states.
   **/
  enum RecordState {Recording=0,RecordReady=1,Paused=2,Stopped=3,
		    RecordStarted=4};

  /**
   * Possible error codes from openWave().
   **/
  enum Error {Ok=0,NoFile=1,NoStream=2,AlreadyOpen=3};

  /**
   * Instantiates the virtual device.
   * @param hpi_handle Pointer to HPI subsystem handle.
   * @param parent Parent object.
   * @param name Name of object.
   **/
   MLHPIRecordStream(MLHPISoundCard *card,QWidget *parent=0,const char *name=0);

  /**
   * Destroy an MLHPIRecordStream object.
   **/
   ~MLHPIRecordStream();

  /**
   * Return a descriptive string for the corresponding error number.
   **/
   QString errorString(MLHPIRecordStream::Error err);

  /**
   * Loads a wave file into the virtual device, using the previously
   * assigned name.  Returns '0' successful, otherwise an error code.
   * @param stream Number of output stream allocated, or -1 if error.
   **/
   MLHPIRecordStream::Error createWave(bool inc_hdr);

   /**
    * Closes the file and frees any resources associated with it.
    **/
   void closeWave();

  /**
   * This is an overloaded version of the above function.
   **/
   MLHPIRecordStream::Error createWave(QString filename,bool inc_hdr);

  /**
   * Determine if a given audio data format is supported.
   * @param card The card number to interrogate.
   * @param stream The stream number of the stream.
   * Returns True = format supported, False = format no supported.
   **/
   bool formatSupported(MLWaveFile::Format format);

  /**
   * This is an overloaded version of the above method, that tests for
   * format support of the currently loaded file.
   * Returns True = format supported, False = format no supported.
   **/
   bool formatSupported();

  /**
   * Returns the adapter card number the virtual device is set to use.
   **/
   int getCard() const;

  /**
   * Returns the adapter stream number the virtual device is set to use.
   **/
   int getStream() const;

  /**
   * Returns true if a record vox device is available, otherwise false.
   **/
   bool haveInputVOX() const;

  /**
   * Returns the current machine state.
   **/
   MLHPIRecordStream::RecordState getState();

   /**
    * Returns the current transport position.
    **/
   int getPosition() const;


  signals:
  /**
   * Emitted whenever the stop status changes
   * @param state true=stream is stopped,  false =  stream is recording or 
   * paused.
   **/
   void isStopped(bool state);

  /**
   * Emitted whenever the virtual machine enters 'RecordReady' mode.
   **/
   void ready();

  /**
   * Emitted whenever the virtual machine enters 'Record' mode.
   **/
   void recording();

  /**
   * Emitted whenever the virtual machine actually begins recording.  In some
   * cases (e.g. a VOX event), recording may start some time after the
   * machine is placed into 'Record' mode.
   **/
   void recordStart();

  /**
   * Emitted whenever the virtual machine enters 'Pause' mode.
   **/
   void paused();

  /**
   * Emitted whenever the virtual machine enters 'Stop' mde.
   **/
   void stopped();

  /**
   * Emitted periodically whenever the machine is in 'record' mode.  This
   * can be used to implement a record timer.
   * @param samples Number of samples recorded since beginning of file.
   **/
   void position(int samples);

  /**
   * Emitted whenever the state of the machine changes.
   * @param card The card number.
   * @param stream The stream number.
   * @param state The new machine state.
   **/
   void stateChanged(int card,int stream,int state);

  public slots:
  /**
   * Set the adapter card number to use.
   * @param card The adapter card number.
   **/
   void setCard(int card);

  /**
   * Set the adapter stream number to use.
   * @param card The adapter stream number.
   **/
   void setStream(int stream);

  /**
   * Put the virtual machine into 'RecordReady' mode.  This creates the
   * WAV file, activates the input metering and does everything else
   * needed to record except actually write sample data into the WAV file.
   **/
   bool recordReady();

  /**
   * Put the virtual machine into 'Record' mode.  If the machine is not
   * already in RecordReady mode, it will first be placed into it.
   **/
   void record();

  /**
   * Put the virtual machine into 'Pause' mode.
   **/
   void pause();

  /**
   * Put the virtual machine into 'Stop' mode.
   **/
   void stop();

  /**
   * Set the VOX threhold level.
   * @param gain Threhold level in 1/100 of a dB below digital zero.
   **/
   void setInputVOX(int gain);

  /**
   * Set the length of recording.  0 = record until told to stop.
   * (NOTE:  the machine will be placed into 'pause' mode at the expiration
   * of this time, NOT stop!)
   * @param length Length of recording in milliseconds.
   **/
   void setRecordLength(int length);

  private slots:
   void tickClock();

 private:
  bool GetStream();
  void FreeStream();
  MLHPISoundCard *sound_card;
  bool debug;
  bool xrun;
  QTimer *clock;
  int card_number;
  int stream_number;
  bool is_recording;
  bool is_ready;
  bool is_paused;
  bool stopping;
  bool record_started;
  QTimer *length_timer;
  int record_length;
  unsigned audio_ptr;
  unsigned char abuf[AUDIO_SIZE];
  unsigned left_to_write;
  HPI_HISTREAM hpi_stream;
  HW16 state;
  HW32 buffer_size;
  HW32 data_recorded;
  HW32 samples_recorded;
  HW32 reserved;
  HW32 fragment_size;
  int fragment_time;
  HW8 *pdata;
  HPI_FORMAT format;
#if HPI_VER < 0x00030500
  HPI_DATA hpi_data;
#endif
  bool is_open;
};


#endif  // MLHPIRECORDSTREAM_H

