#ifndef __ENGINE_H__
# define __ENGINE_H__   1

# ifndef _NDEFINES_H__
#  error "include <naudio\ndefines.h> first"
# endif

#define PSG_ENGINE      0
#define F_PSG_ENGINE    1
#define PP_ENGINE       2
#define STE_ENGINE      3
#define Q_STE_ENGINE    4
#define TT_ENGINE       5        /* future */
#define Q_TT_ENGINE     6        /* future */
#define FALCON_ENGINE   7
#define Q_FALCON_ENGINE 8
#define FALCON2_ENGINE  9
#define FALCON16_ENGINE 10       /* future */

# define NAUDIO_MAX_VOL 0x40

#define MAX_ENGINES     14       /* maximum number of engines possible */
#define MAX_CHANNELS    8

#define NTRACKER        0
#define SAMPLES         1

#define UNSIGNED        1
#define STEREO          2              /* future */
#define BIT16           4              /* future */
#define SIGNED          (! UNSIGNED)
#define MONO            (! STEREO)
#define BIT8            (! BIT16)


typedef struct
{
   sbyte play;                /* signed! negative == play */
   byte  rsv;                 /* reserve sample */
   byte  *data;
   lword end,
         step1;
   word  step2,
         incr1,
         incr2;
   byte  unuse,
         vol;
   lword aux1;
   word  aux2,                /* 10 bytes for the user for samples   */
         aux3,                /* else used by the play_segment code  */
         aux4;
   int  (*fill)();            /* returns Z (0), on success           */
} channel;



typedef struct
{
   void     *sample_area,
            *engine_area;
   byte     version,
            revision;
   void     (*user_refresh)();
   channel  *p_channels;
   channel  *channels;
   word     n_channels,
            n1_channels,
            n2_channels;
   void     *vtab;
   byte     *voice1,
            *dactab;
   lword    nullsample;
   word     r_frq;
   lword    e_frq,
            n_irqs,
            n2_irqs;
   sbyte    e_type,
            e_state;
   byte     s_type,
            hardware,
            cpu,
            no_hack,
            use_bclr,
            is_tos4;
   word     ipl;
   void     (**fab)(),
            (**init)(),
            (**done)(),
            (**start)(),
            (**stop)(),
            (**replay)(),
            (**patch)(),
            (**halt)(),
            (**cont)();
   size_t   (**mem_e)(),
            (**mem_s)();
   lword    (**calc)();
   byte     **no_tab;
   lword    e_len,
            s_len;
   byte     max_channels,
            save_aer,
            save_ier,
            save_imr,
            save_ctl,
            save_dta,
            dta,
            save_conterm;
   lword    save_timer,
            new_timer;
   byte     ctl,
            falc_out;
   word     save_chip[ 11],
            save_codec[ 10];
} engine_control;


int   init_dac             _C_PROTO(( int channels));
void  engine_pp            _C_PROTO(( void));
void  engine_psg           _C_PROTO(( void));
void  engine_fpsg          _C_PROTO(( void));
void  engine_ste           _C_PROTO(( void));
void  engine_falcon        _C_PROTO(( int broken));
void  engine_falcon2       _C_PROTO(( int broken));
void  engine_qfalcon       _C_PROTO(( int broken));

void  engine_tabs          _C_PROTO(( word, byte *nos));
void  engine_builders      _C_PROTO(( word, void (*)(), void (*)(),
                                            void (*)() ));
void  engine_calcers       _C_PROTO(( word, size_t (*)(), size_t (*)(),
                                            lword (*)() ));
void  engine_halters       _C_PROTO(( word, void (*)(), void (*)() ));
void  engine_starters      _C_PROTO(( word, void (*)(), void (*)() ));
void  engine_routines      _C_PROTO(( word, void (*)(), void (*)() ));
lword engine_build         _C_PROTO(( void (*routine)(), lword frq,
                                      word ref_frq, int type, int round));
int   engine_set_channels  _C_PROTO(( int channels));
void  engine_destroy       _C_PROTO(( void));

int   naudio_engine        _C_PROTO(( int purpose));
int   naudio_best_engine   _C_PROTO(( void));
lword naudio_good_frq      _C_PROTO(( int refresh_type, int target_type));
void  naudio_init          _C_PROTO(( void));
void  naudio_all           _C_PROTO(( void));
void  naudio_some          _C_PROTO(( void));
int   naudio_start         _C_PROTO(( int force));
void  naudio_stop          _C_PROTO(( void));
void  naudio_halt          _C_PROTO(( void));
void  naudio_cont          _C_PROTO(( void));
int   naudio_set_channels  _C_PROTO(( int channels));

#define naudio_done        engine_destroy


channel *channel_alloc     _C_PROTO(( void));
void    channel_calc_incr  _C_PROTO(( channel *p, long frq));
#define channel_start( p)  ((p)->play = -1)
#define channel_toggle( p) ((p)->play = (p)->play ? 0 : -1)
#define channel_stop( p)   ((p)->play = 0)
#define channel_free( p)   ((p)->rsv  = 0)
#define channel_delete( p) ((p)->end  = (p)->rsv = 0)
#define channel_set( p, xdata, xlen, xincr1, xincr2, xvol, xoffset, f)  \
   do                                                                   \
   {                                                                    \
      (p)->play  = (p)->step1 = (p)->step2 = (p)->aux3 =                \
                   (p)->aux1 = (p)->aux2 = 0;                           \
      (p)->data  = (xdata);                                             \
      (p)->end   = (xlen) + (xoffset);                                  \
      (p)->step1 = (xoffset);                                           \
      (p)->incr1 = (xincr1);                                            \
      (p)->incr2 = (xincr2);                                            \
      (p)->vol   = (xvol);                                              \
      (p)->fill  = (f);                                                 \
   }                                                                    \
   while( 0)


void  _hack_system         _C_PROTO(( void));
void  _unhack_system       _C_PROTO(( void));
void  _hack_spurious       _C_PROTO(( void));
void  init_vol_8s          _C_PROTO(( void));
void  init_vol_8u          _C_PROTO(( void));
void  init_vol_16s         _C_PROTO(( void));
void  init_vol_16u         _C_PROTO(( void));

/* you can't call any of these directly, but they might be used as
   parameters.
 */
void  engine_nreplay(), engine_freplay();
void  n_patch_psg(),   n_patch_fpsg(), n_patch_pp(),  n_patch_ste(),
      n_patch_qste(),  n_patch_tt(),  n_patch_qtt(),  n_patch_falcon(),
      n_mix_qfalcon(), n_mix_falcon();



#endif
