//   mlhpiplaystream.h
//
//   A class for playing Microsoft WAV files.
//
//   (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com>
//
//    $Id: mlhpiplaystream.h,v 1.3 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 MLHPIPLAYSTREAM_H
#define MLHPIPLAYSTREAM_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>

#include <asihpi/hpi.h>
#define MAX_FRAGMENT_SIZE 192000
#define FRAGMENT_TIME 50
#define TIMESCALE_LOW_LIMIT 800
#define TIMESCALE_HIGH_LIMIT 1200
//#define RPLAYSTREAM_SHOW_SLOTS yes

/**
 * @short An object for playing Microsoft WAV files
 * @author Fred Gleason <fredg@wava.com>
 *
 * RPlayStream implements a virtual device for playing Microsoft WAV
 * files.  It supports AudioScience HPI audio hardware as well as devices
 * using the Advanced Linux Sound Architecture (ALSA).
 * It is capable of playing PCM8, PCM16 and (if the underlying hardware
 * supports it) MPEG-1 formatted files.
 **/
class MLHPIPlayStream : public QObject,public MLWaveFile
{
  Q_OBJECT

  public:
  /**
   * Defines the current state of the machine.
   **/
  enum State {Stopped=0,Playing=1,Paused=2};

  /**
   * 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.
   **/
   MLHPIPlayStream(MLHPISoundCard *card,QWidget *parent=0,const char *name=0);

  /**
   * Destroys the virtual device.
   **/
   ~MLHPIPlayStream();

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

  /**
   * Determine if a given audio data format is supported.
   * @param format = The format to test for.
   * 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();

  /**
   * Loads a wave file into the virtual device, using the previously
   * assigned name.  Returns '0' successful, otherwise an error code.
   **/
   MLHPIPlayStream::Error openWave();

  /**
   * This is an overloaded version of the above function.
   **/
   MLHPIPlayStream::Error openWave(QString filename);

  /**
   * Unloads the loaded WAV file from the vitual device.
   **/
   void closeWave();

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

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

  /**
   * Returns the current configured playout speed, in tenths of a percent.
   **/
   int getSpeed() const;

  /**
   * Sets the playout speed of the machine.
   * @param speed The playout speed, in tenths of percent.
   * @param pitch True = allow pitch to shift in proportion to
   * speed change, false = don't.
   * @param rate True = Allow output sample rate to vary in
   * proportion to speed change, false = don't.
   * 
   * Returns: True if successful, false if parameter combination not
   * supported by the underlying hardware.
   *
   * NOTE: Not all adapters support all combinations of parameters.  In
   * particular, ASI4000 series adapters cannot vary playout
   * speed without varying both pitch and sample rate in proportion, which
   * can cause problems when using IEC958-type output devices.  
   **/
   bool setSpeed(int speed,bool pitch=false,bool rate=false);

  /**
   * Returns the current device state.
   **/
   MLHPIPlayStream::State getState() const;

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

  /**
   * Emitted whenever the virtual machine enters 'play' mode.
   **/
   void played();

  /**
   * 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 'play' mode.  The
   * can be used to implement a playback progress indicator.
   * @param samples Number of samples played 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);

  /**
   * Put the virtual machine into 'play' mode.
   **/
   bool play();

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

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

   /**
    * Get the current play position.
    **/
   int currentPosition();

  /**
   * Set the playback position in the WAV file.  Any subsequent playout
   * will start from this location.
   * @param samples Location in sample in the WAV file.
   **/
   bool setPosition(unsigned samples);

  /**
   * Set the length of playout.  0 = play until told to stop or the end
   * of the file is reached.  (NOTE: the machine will be placed into
   * 'pause' mode at the expiration of this time, NOT stop!)
   * @param length Length of playout in milliseconds.
   **/
   void setPlayLength(int length);

   void tickClock();

  private:
   void Drained();
   int GetStream();
   void FreeStream();
   MLHPISoundCard *sound_card;
   MLHPIPlayStream::State stream_state;
   QString wave_name;
   QTimer *clock;
   int card_number;
   int stream_number;
   bool is_open;
   bool playing;
   bool is_paused;
   bool repositioned;
   bool stopping;
   unsigned audio_ptr;
   unsigned left_to_write;
   unsigned read_bytes;

   unsigned samples_skipped;
   int play_length;
   QTimer *play_timer;
   QTime start_time;
   int play_speed;
   bool pitch_can_vary;
   bool rate_can_vary;
   HPI_HOSTREAM hpi_stream;
   HW16 state;
   HW32 buffer_size;
   HW32 data_to_play;
   HW32 samples_played;
   HW32 reserved;
   int fragment_time;
   HW8 *pdata;
   HPI_FORMAT format;
#if HPI_VER < 0x00030500
   HPI_DATA hpi_data;
#endif
   HW32 fragment_size;
   bool restart_transport;
   int samples_pending;
   unsigned current_position;
};


#endif  // MLHPIPLAYSTREAM_H
