/*ProfiPacket - packet radio terminal program
  Copyright (C) 1999  Alexander Feigl

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  Author:

  Alexander Feigl
  Burachstraße 51

  D-88250 Weingarten

  Mail : Alexander.Feigl@gmx.de
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /*HAVE_CONFIG_H*/

#define BUFFER_SIZE 1638400
#define MIXING_RATE 48000

#define SAMPLE_TRUMPET 0
#define TRUMPET_SIZE 11518
#define TRUMPET_ONCE 11380
#define TRUMPET_LOOP 128

#define SAMPLE_VIBES 1
#define VIBES_SIZE 7680
#define VIBES_ONCE 7552
#define VIBES_LOOP 128

#define SAMPLE_SINUS32 64
#define SINUS32_SIZE 32
#define SINUS32_ONCE 0
#define SINUS32_LOOP 32

#define SAMPLE_SINUS16 65
#define SINUS16_SIZE 16
#define SINUS16_ONCE 0
#define SINUS16_LOOP 16


#ifdef __GNUC__
#define _storage_text_ __attribute__ ((section(".text")))
#else
#define _storage_text_
#endif

#include "GUIProtos.h"
#include "global.h"
#include "QSO.h"
#include "Server.h"
#include "Audio.h"
#include "Preferences.h"
#include "Util.h"
#include "Main.h"

#ifdef AmigaOS


extern void *AudioTasks[MAX_EFFECT];

#include "sysdeps/amiga/amigafork.h"

#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/semaphores.h>
#include <exec/tasks.h>
#include <exec/execbase.h>
#include <devices/ahi.h>
#include <devices/audio.h>
#include <dos/exall.h>
#include <datatypes/soundclass.h>
#include <clib/exec_protos.h>
#include <clib/datatypes_protos.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#ifdef __GNUC__
#include <inline/exec.h>
#include <inline/datatypes.h>
#include <inline/dos.h>
extern void *SysBase;
void *DataTypesBase=NULL;
extern void *DOSBase;
#undef DoDTMethod
#endif /* __GNUC__*/
extern Object **AudioObjects;
#endif /*AmigaOS*/

#ifdef LINUX

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termio.h>

#include <linux/soundcard.h>

#endif LINUX


const static signed int _storage_text_ LinkFail_Melody[]=
     {SAMPLE_TRUMPET,
      440,40,440,30,440,10,440,40,523,30,494,10,494,30,
      440,10,440,30,415,10,440,60,-1,-1
     };

const static signed int _storage_text_ Westminster_Melody[]=
     {SAMPLE_VIBES,
      330,15,415,15,370,15,247,30,330,15,370,15,415,15,
      330,30,415,15,330,15,370,15,247,30,247,15,370,15,
      415,15,330,30,-1,-1
     };

const static signed int _storage_text_ Becher_Melody[]=
     {SAMPLE_VIBES,
      440,30,440,30,392,30,349,30,466,30,466,30,440,30,
      392,30,523,30,440,30,349,30,523,30,523,45,588,15,
      466,60,-1,-1
     };

const static signed int _storage_text_ CtrlG_Melody[]=
     {SAMPLE_VIBES,
      523,30,262,30,-1,-1
     };

const static signed int _storage_text_ RingRing_Melody[]=
     {SAMPLE_VIBES,
      262,20,330,20,392,20,523,60,587,60,494,20,440,20,
      392,20,440,30,494,10,440,20,392,40,0,20,
      262,20,294,20,330,20,392,60,440,60,392,30,294,10,
      294,20,294,80,0,40,
      392,20,330,20,392,20,523,60,440,60,392,20,330,20,
      262,20,262,60,294,60,330,20,294,20,330,20,392,60,
      440,60,294,20,330,30,294,10,262,80,
      -1,-1
     };

const static signed int _storage_text_ MailHere_Melody[]=
     {SAMPLE_VIBES,
      494,30,0,15,554,15,494,30,415,60,
      0,30,494,30,0,15,554,15,494,30,415,60,
      0,30,740,60,740,30,622,60,0,30,659,60,659,30,494,60,
      0,30,554,60,554,30,659,30,0,15,622,15,554,30,
      494,30,0,15,554,15,494,30,415,60,0,30,
      554,60,554,30,659,30,0,15,622,15,554,30,
      494,30,0,15,554,15,494,30,415,60,
      0,30,740,60,740,30,880,30,0,15,740,15,622,30,659,60,
      0,30,830,60,0,30,659,30,494,30,415,30,494,30,
      0,15,440,15,370,30,330,180,
      -1,-1
     };
 
 
const static signed int _storage_text_ HighBeep_Melody[]=
     {SAMPLE_SINUS32,523,3,-1,-1};
     
const static signed int _storage_text_ LowBeep_Melody[]=
     {SAMPLE_SINUS32,262,3,-1,-1};
     
const static signed int _storage_text_ LinkBeep_Melody[]=
     {SAMPLE_SINUS32,294,3,0,3,494,3,-1,-1};

const static signed int _storage_text_ SpyBeep_Melody[]=
     {SAMPLE_SINUS16,1000,3,-1,-1};

const static signed char _storage_text_ Sinus32_Sample[32]=
     {
      0,25,49,71,90,106,117,125,127,
      125,117,106,90,71,49,25,0,
      -25,-49,-71,-90,-106,-117,-125,-127,
      -125,-117,-106,-90,-71,-49,-25};

const static signed char _storage_text_ Sinus16_Sample[16]=
     {0,49,90,117,127,117,90,49,0,-49,-90,-117,-127,-117,-90,-49};



const static signed int _storage_text_ *Effect_Table[]=
     {
      Westminster_Melody,
      HighBeep_Melody,
      LowBeep_Melody,
      Becher_Melody,
      LinkBeep_Melody,
      CtrlG_Melody,
      RingRing_Melody,
      LinkFail_Melody,
      SpyBeep_Melody,
      MailHere_Melody
     };

const static signed char Effect_Prios[]=
     {
      80,
      50,
      50,
      85,
      60,
      70,
      100,
      80,
      30,
      80
     };

struct AudioPlay
 {
  unsigned long  effect;                /* effect nr*/
  unsigned long  effecttarget;          /* audio output */
  unsigned long  effecttype;            /* type of effect */
  void          *effectptr;             /* pointer to effect */
 };



struct AudioStruct

 {
  unsigned long effect;

  int (*AudioInit)(struct AudioStruct *astruct);
  void (*AudioDeinit)(struct AudioStruct *astruct);
  void (*AudioPlay)(struct AudioStruct *astruct,int rate,int duration);
  int (*AudioSetInst)(struct AudioStruct *astruct);

  const char *InstrumentOnce;
  const char *InstrumentLoop;
  unsigned long InstrumentOnceSize;
  unsigned long InstrumentLoopSize;
  unsigned long InstrumentSamples; 
  
#ifdef LINUX
  int DSPFile;
  unsigned char *samplebuffer;
  int inbuffer; 
#endif /*Linux*/

#ifdef AmigaOS
  unsigned long      NextRequest;
  struct MsgPort    *AHIPort;
  struct AHIRequest *AHIRequest[4];
  unsigned char     *AudioBuffers[4];
  struct MsgPort    *AudioPort;
  struct IOAudio    *AudioRequest[4];
  unsigned long      StartedAudio;
  struct AHIRequest *AHILink;
  int                InBuffer;
  char              *ChipInstrument;
#endif /*AmigaOS*/

 };


static const unsigned char _storage_text_ Trumpet_Sample[TRUMPET_SIZE]=
#include "Trumpet.h"

static const unsigned char _storage_text_ Vibes_Sample[VIBES_SIZE]= 
#include "Vibes.h"

/* Prototypes */

static void AUDIO_PlayMelody(struct AudioStruct *astruct,const signed int mel[] );
static int AUDIO_SetInstr(struct AudioStruct *astruct,int num);




static int AUDIO_SetInstr(struct AudioStruct *astruct,int num)
 {
  switch (num)
   {
    case SAMPLE_TRUMPET:
     {
      astruct->InstrumentOnce=Trumpet_Sample;
      astruct->InstrumentLoop=Trumpet_Sample+TRUMPET_ONCE;
      astruct->InstrumentOnceSize=TRUMPET_ONCE;
      astruct->InstrumentLoopSize=TRUMPET_LOOP;
      astruct->InstrumentSamples=32;
      break;
     }
    case SAMPLE_VIBES:
     {
      astruct->InstrumentOnce=Vibes_Sample;
      astruct->InstrumentLoop=Vibes_Sample+VIBES_ONCE;
      astruct->InstrumentOnceSize=VIBES_ONCE;
      astruct->InstrumentLoopSize=VIBES_LOOP;
      astruct->InstrumentSamples=32;
      break;
     }
    case SAMPLE_SINUS32:
      astruct->InstrumentOnce=NULL;
      astruct->InstrumentLoop=(unsigned char *) Sinus32_Sample;
      astruct->InstrumentOnceSize=0;
      astruct->InstrumentLoopSize=32;
      astruct->InstrumentSamples=32;
      break;
    case SAMPLE_SINUS16:
      astruct->InstrumentOnce=NULL;
      astruct->InstrumentLoop=(unsigned char *) Sinus16_Sample;
      astruct->InstrumentOnceSize=0;
      astruct->InstrumentLoopSize=16;
      astruct->InstrumentSamples=16;
      break;
   }
  if (astruct->AudioSetInst!=NULL) return (astruct->AudioSetInst(astruct));
  return(0);
 }







/************************* AMIGA audio interface ******************/

#ifdef AmigaOS

/* Amiga datatypes interface*/

static void AUDIO_PlayDT(Object *pobject)
 {
  signed long psignal;
  void *ptask;

  psignal=AllocSignal(-1);
  if (psignal==-1) return;

  ptask=FindTask(NULL);

  SetDTAttrs(pobject,NULL,NULL,SDTA_SignalTask,(ULONG) ptask,SDTA_SignalBit,1<<psignal,TAG_DONE);
  DoDTMethod(pobject,NULL,NULL,DTM_TRIGGER,NULL,STM_PLAY,NULL);
  Wait(1<<psignal);
  FreeSignal(psignal);
  return;
 }

static void AUDIO_LoadObject(unsigned char *fname,Object **optr)
 {
  Object *obptr;
  unsigned long dummy;

  obptr=NewDTObject(fname,DTA_SourceType,DTST_FILE,
                          DTA_GroupID,GID_SOUND,
                          SDTA_Volume,64,
                          SDTA_Cycles,1,
                          TAG_DONE);

  if (obptr==NULL) return;

  if (GetDTAttrs(obptr,SDTA_SignalTask,(ULONG) &dummy,TAG_DONE)!=1)
   {
    DisposeDTObject(obptr);
   }

  *optr=obptr;
 }



/* Amiga audio.device interface */


static void ADEV_AudioDeinit(struct AudioStruct *astruct)
 {
  if (astruct->ChipInstrument)
   {
    FreeVec(astruct->ChipInstrument);
   }

  CloseDevice((struct IORequest *) astruct->AudioRequest[0]);
   {
    unsigned long i;
    for (i=0;i<2;++i)
     {
      DeleteIORequest(astruct->AudioRequest[i]);
     }
   }
  DeleteMsgPort(astruct->AudioPort);
 }

static const unsigned char ADev_AllocArray[]={1,2,3,4};

static int ADEV_SetInstrument(struct AudioStruct *astruct)
 {
  if (astruct->ChipInstrument!=NULL)
   {
    FreeVec(astruct->ChipInstrument);
    astruct->ChipInstrument=NULL;
   }
  if ((astruct->ChipInstrument=
      AllocVec(astruct->InstrumentOnceSize+astruct->InstrumentLoopSize,
               MEMF_PUBLIC|MEMF_CHIP))==NULL)
   {
    return (-1);
   }
   {
    const unsigned char *sptr;
    unsigned char *dptr;
    int i;

    sptr=astruct->InstrumentOnce;
    dptr=astruct->ChipInstrument;
    i=astruct->InstrumentOnceSize;

    while (i>0) {*(dptr++)=*(sptr++);--i; }

    sptr=astruct->InstrumentLoop;
    i=astruct->InstrumentLoopSize;
    while (i>0) {*(dptr++)=*(sptr++);--i; }

   }
  CacheClearE(astruct->ChipInstrument,astruct->InstrumentOnceSize+
              astruct->InstrumentLoopSize,CACRF_ClearD);
  return(0);
 }

static int ADEV_AudioInit(struct AudioStruct *astruct)
 {
  astruct->ChipInstrument=NULL;

  astruct->AudioPort=CreateMsgPort();
  if (astruct->AudioPort==NULL)
   {
    return(1);             /* error return */
   }

   {
    unsigned long i;
    for (i=0;i<2;++i)
     {

      astruct->AudioRequest[i]=CreateIORequest(astruct->AudioPort,
                              sizeof(struct IOAudio));
      if (astruct->AudioRequest[i]==NULL)
       {
        while (i>0)
         {
          DeleteIORequest(astruct->AudioRequest[i-1]);
          --i;
         }
        DeleteMsgPort(astruct->AudioPort);
        return(1);             /* error return */
       }
     }
   }


 astruct->AudioRequest[0]->ioa_Request.io_Message.mn_Node.ln_Pri=
    Effect_Prios[astruct->effect];
 astruct->AudioRequest[1]->ioa_Request.io_Message.mn_Node.ln_Pri=
    Effect_Prios[astruct->effect];

 astruct->AudioRequest[0]->ioa_Data=(void *) ADev_AllocArray;
 astruct->AudioRequest[0]->ioa_Length=4;

 if (OpenDevice(((UBYTE *) "audio.device"),0,
                    ((struct IORequest *) astruct->AudioRequest[0]),ADIOF_NOWAIT))
  {
   unsigned long i;
   for (i=0;i<2;++i)
    {
     DeleteIORequest(astruct->AudioRequest[i]);
    }
   DeleteMsgPort(astruct->AudioPort);
   return(1);
  }


  astruct->AudioRequest[1]->ioa_Request.io_Device=
    astruct->AudioRequest[0]->ioa_Request.io_Device;
  astruct->AudioRequest[1]->ioa_Request.io_Unit=
    astruct->AudioRequest[0]->ioa_Request.io_Unit;
  astruct->AudioRequest[1]->ioa_AllocKey=
    astruct->AudioRequest[0]->ioa_AllocKey;


  return(0);
 }

#define AUDIO_CalcConstant 3579545
extern void workaround_SendIO(struct IORequest *ior);


static void ADEV_ToneOut(struct AudioStruct *astruct,int rate,int duration)
 {


  int onecycle,loopcycle,onesize,loopsize,xrate,xvol,totsize;

  xrate=rate;
  xvol=64;
  onesize=astruct->InstrumentOnceSize;
  loopsize=astruct->InstrumentLoopSize;
  onecycle=1;

  if (xrate==0)
   {
    xvol=0;
    xrate=20000;
    onesize=0;
    onecycle=0;
   }

  if (onesize==0) onecycle=0;

  totsize=(duration*xrate)/1000;

  if (totsize>onesize)
   {
    loopcycle=(totsize-onesize*onecycle)/loopsize;
   }
   else
   {
    loopcycle=0;
    onesize=totsize;
   }

  if (onecycle)
   {
    astruct->AudioRequest[0]->ioa_Request.io_Command=CMD_WRITE;
    astruct->AudioRequest[0]->ioa_Data=astruct->ChipInstrument;
    astruct->AudioRequest[0]->ioa_Length=onesize;
    astruct->AudioRequest[0]->ioa_Period=AUDIO_CalcConstant/xrate;
    astruct->AudioRequest[0]->ioa_Volume=xvol;
    astruct->AudioRequest[0]->ioa_Cycles=onecycle;
    astruct->AudioRequest[0]->ioa_Request.io_Flags=ADIOF_PERVOL;
    workaround_SendIO((struct IORequest *) astruct->AudioRequest[0]);
   }

  if (loopcycle)
   {
    astruct->AudioRequest[1]->ioa_Request.io_Command=CMD_WRITE;
    astruct->AudioRequest[1]->ioa_Data=astruct->ChipInstrument+
                                       astruct->InstrumentOnceSize;
    astruct->AudioRequest[1]->ioa_Length=loopsize;
    astruct->AudioRequest[1]->ioa_Period=AUDIO_CalcConstant/xrate;
    astruct->AudioRequest[1]->ioa_Volume=xvol;
    astruct->AudioRequest[1]->ioa_Cycles=loopcycle;
    astruct->AudioRequest[1]->ioa_Request.io_Flags=ADIOF_PERVOL;
    workaround_SendIO((struct IORequest *) astruct->AudioRequest[1]);
   }



  if (onecycle)
   {
    WaitIO((struct IORequest *) astruct->AudioRequest[0]);
   }

  if (loopcycle)
   {
    WaitIO((struct IORequest *) astruct->AudioRequest[1]);
   }


 }


/* Amiga AHI interface */


static void AHI_AudioDeinit(struct AudioStruct *astruct)
 {

  while (astruct->StartedAudio)
   {
    if (!(astruct->StartedAudio&(1<<astruct->NextRequest)))
     {
      astruct->NextRequest=(astruct->NextRequest+1)%4;
      continue;
     }
    WaitIO((struct IORequest *) astruct->AHIRequest[astruct->NextRequest]);
    astruct->StartedAudio&=(1<<astruct->NextRequest)^0xffffffff;
   }



   {
    unsigned long i;
    for (i=0;i<4;++i)
     {
      FreeVec(astruct->AudioBuffers[i]);
     }
   }

  CloseDevice((struct IORequest *) astruct->AHIRequest[0]);
   {
    unsigned long i;
    for (i=0;i<4;++i)
     {
      DeleteIORequest(astruct->AHIRequest[i]); 
     }
   }
  DeleteMsgPort(astruct->AHIPort);  
 }
 
static int AHI_AudioInit(struct AudioStruct *astruct)
 {
  astruct->AHIPort=CreateMsgPort();
  if (astruct->AHIPort==NULL)
   {
    return(1);             /* error return */
   }

   {
    unsigned long i;
    for (i=0;i<4;++i)
     {

      astruct->AHIRequest[i]=CreateIORequest(astruct->AHIPort,
                              sizeof(struct AHIRequest));
      if (astruct->AHIRequest[i]==NULL)
       {
        while (i>0)
         {
          DeleteIORequest(astruct->AHIRequest[i-1]);
          --i;
         }
        DeleteMsgPort(astruct->AHIPort);
        return(1);             /* error return */
       }
     }
   }



 astruct->AHIRequest[0]->ahir_Version=4;
 astruct->AHIRequest[1]->ahir_Version=4;
 astruct->AHIRequest[2]->ahir_Version=4;
 astruct->AHIRequest[3]->ahir_Version=4;

 if (OpenDevice(((UBYTE *) "ahi.device"),AHI_DEFAULT_UNIT,
                    ((struct IORequest *) astruct->AHIRequest[0]),0))
  {
   unsigned long i;
   for (i=0;i<4;++i)
    {
     DeleteIORequest(astruct->AHIRequest[i]);
    }
   DeleteMsgPort(astruct->AHIPort);
   return(1);
  }

  {
   unsigned long i;
   for (i=1;i<4;++i)
    {
     astruct->AHIRequest[i]->ahir_Std.io_Device=astruct->AHIRequest[0]->ahir_Std.io_Device;
     astruct->AHIRequest[i]->ahir_Std.io_Unit=astruct->AHIRequest[0]->ahir_Std.io_Unit;
    }
  }

  {
   unsigned long i;
   for (i=0;i<4;++i)
    {
     astruct->AudioBuffers[i]=AllocVec(BUFFER_SIZE,MEMF_PUBLIC);
     if (astruct->AudioBuffers[i]==NULL)
      {
       while (i>0)
        {
         i--;
         FreeVec(astruct->AudioBuffers[i]);
        }
       CloseDevice( (struct IORequest *) astruct->AHIRequest[0]);
       for (i=0;i<4;++i)
        {
         DeleteIORequest(astruct->AHIRequest[i]);
        }
       DeleteMsgPort(astruct->AHIPort);
       return(1);
      }
    }
  }

  astruct->StartedAudio=0;
  astruct->NextRequest=0;
  astruct->AHILink=0;
  astruct->InBuffer=0;

  return(0);
 }


static void AHI_FlushBuffer(struct AudioStruct *astruct,int rate)
 {
  unsigned long cr;

  cr=astruct->NextRequest;

  astruct->AHIRequest[cr]->ahir_Std.io_Command=CMD_WRITE;
  astruct->AHIRequest[cr]->ahir_Std.io_Data=
      astruct->AudioBuffers[astruct->NextRequest];
  astruct->AHIRequest[cr]->ahir_Std.io_Length=astruct->InBuffer;
  astruct->AHIRequest[cr]->ahir_Std.io_Offset=0;
  astruct->AHIRequest[cr]->ahir_Type=AHIST_M8S;
  astruct->AHIRequest[cr]->ahir_Frequency=rate;
  astruct->AHIRequest[cr]->ahir_Volume=0x10000;
  astruct->AHIRequest[cr]->ahir_Position=0x8000;
  astruct->AHIRequest[cr]->ahir_Link=astruct->AHILink;

  DoIO((struct IORequest *) astruct->AHIRequest[cr]);
  astruct->AHILink=astruct->AHIRequest[cr];
  astruct->StartedAudio|=(1<<cr);
  astruct->NextRequest++;
  astruct->NextRequest%=4;

  if (astruct->StartedAudio&(1<<astruct->NextRequest))
   {
    WaitIO((struct IORequest *) astruct->AHIRequest[astruct->NextRequest]);
    astruct->StartedAudio&=(1<<astruct->NextRequest)^0xffffffff;
   }

  astruct->InBuffer=0;
 }



static void AHI_SampleOut(struct AudioStruct *astruct,const unsigned char out[],int length,int rate)
 {
  char *cbuf;
  const char *optr;
  int olen;

  cbuf=astruct->AudioBuffers[astruct->NextRequest];
  olen=length;
  optr=out;

  while (olen>0)
   {
    *(cbuf+astruct->InBuffer)=*(optr++);
    olen--;
    ++astruct->InBuffer;
    if (astruct->InBuffer==BUFFER_SIZE)
     {
      AHI_FlushBuffer(astruct,rate);
      cbuf=astruct->AudioBuffers[astruct->NextRequest];
     }
   }
 }

static void AHI_ToneOut(struct AudioStruct *astruct,int rate,int duration)
 {
  signed long outbytes;

  int size_o,size_l;


  if (rate==0)
   {
    outbytes=(duration*1000)/1000;
    while (outbytes>0)
     {
      *(astruct->AudioBuffers[astruct->NextRequest]+astruct->InBuffer)=0;
      ++astruct->InBuffer;
      if (astruct->InBuffer==BUFFER_SIZE)
       {
        AHI_FlushBuffer(astruct,1000);
       }
      --outbytes;
     }
    AHI_FlushBuffer(astruct,1000);
    return;
   }

  outbytes=(duration*rate)/1000;

  size_o=astruct->InstrumentOnceSize;
  size_l=astruct->InstrumentLoopSize;


  if (size_o>0)
   {
    AHI_SampleOut(astruct,astruct->InstrumentOnce,
                  (size_o>outbytes)?outbytes:size_o,rate);

    outbytes-=size_o;
   }

  while (outbytes>0)

   {
    AHI_SampleOut(astruct,astruct->InstrumentLoop,
                  (size_l>outbytes)?outbytes:size_l,rate);
    outbytes-=size_l;
   }
  AHI_FlushBuffer(astruct,rate);
 }


 

#endif /*AmigaOS*/











/************************* Linux audio interface ******************/

#ifdef LINUX

static void LIN_SampleOut(struct AudioStruct *astruct,const unsigned char out[],int len,int rate)
 {
  signed long downsamp=0;
  unsigned long i=0;
  
  while (i<len)
   {
    *(astruct->samplebuffer+astruct->inbuffer)=out[i];
    ++astruct->inbuffer;
    if (astruct->inbuffer==BUFFER_SIZE)
     {
      write(astruct->DSPFile,astruct->samplebuffer,astruct->inbuffer);
      astruct->inbuffer=0;
     }
    downsamp+=rate;
    if (downsamp>=MIXING_RATE)
     {
      downsamp-=MIXING_RATE;
      ++i;
     }
   }
   
 }

static void LIN_ToneOut(struct AudioStruct *astruct,int rate,
         int duration) 
 {
  signed long outbytes;
  
  int size_o,size_l;
  
  
  if (rate==0)
   {
    outbytes=(duration*MIXING_RATE)/1000;
    while (outbytes>0)
     {
      *(astruct->samplebuffer+astruct->inbuffer)=0;
      ++astruct->inbuffer;
      if (astruct->inbuffer==BUFFER_SIZE)
       {
        write(astruct->DSPFile,astruct->samplebuffer,astruct->inbuffer);
        astruct->inbuffer=0;
       }
      --outbytes;
     }
    return;
   }
  
  outbytes=(duration*rate)/1000;
  
  size_o=astruct->InstrumentOnceSize;
  size_l=astruct->InstrumentLoopSize;
  
  
  if (size_o>0)
   {
    LIN_SampleOut(astruct,astruct->InstrumentOnce,
                  (size_o>outbytes)?outbytes:size_o,rate);

    outbytes-=size_o;
   }
   
  while (outbytes>0)

   {
    LIN_SampleOut(astruct,astruct->InstrumentLoop,
                  (size_l>outbytes)?outbytes:size_l,rate);
    outbytes-=size_l;
   }
  
 }
 
static void LIN_FlushBuffers(struct AudioStruct *astruct)
 {
  if (astruct->inbuffer!=0)
   {
    write(astruct->DSPFile,astruct->samplebuffer,astruct->inbuffer);
    astruct->inbuffer=0;
   }
 }

static int LIN_AudioInit(struct AudioStruct *astruct)
 {
  int integ;
  
  
  astruct->DSPFile=open("/dev/dsp",O_WRONLY);

  if (ioctl(astruct->DSPFile,SNDCTL_DSP_RESET,NULL))
   {
    close(astruct->DSPFile);
    return(1);
   }
  
   {
    /*set rate */
    integ=MIXING_RATE;
    if (ioctl(astruct->DSPFile,SNDCTL_DSP_SPEED,&integ))
     {
      close(astruct->DSPFile);
      return(1);
     }
    /*set channels*/
    integ=1;
    if (ioctl(astruct->DSPFile,SNDCTL_DSP_STEREO,&integ))
     {
      close(astruct->DSPFile);
      return(1);
     }
    integ=1;
    if (ioctl(astruct->DSPFile,SNDCTL_DSP_CHANNELS,&integ))
     {
      close(astruct->DSPFile);
      return(1);
     }
    /*set format*/
    integ=8;
    if (ioctl(astruct->DSPFile,SNDCTL_DSP_SAMPLESIZE,&integ))
     {
      close(astruct->DSPFile);
      return(1);
     }
    integ=AFMT_S8;
    if (ioctl(astruct->DSPFile,SNDCTL_DSP_SETFMT,&integ))
     {
      close(astruct->DSPFile);
      return(1);
     }    
   }

   astruct->inbuffer=0;
   astruct->samplebuffer=(void *) malloc(BUFFER_SIZE);
   
   
  return(0);
 }
 
static void LIN_AudioDeinit(struct AudioStruct *astruct)
 {
  LIN_FlushBuffers(astruct);
  /*ioctl(astruct->DSPFile,SNDCTL_DSP_SYNC,NULL);
  ioctl(astruct->DSPFile,SNDCTL_DSP_RESET,NULL);*/
  close(astruct->DSPFile);
  }

#endif LINUX









static void AUDIO_PlayMelody(struct AudioStruct *astruct,const signed int mel[] )
 {
  const signed int *melptr;
  
  
  melptr=mel;
  
  if (AUDIO_SetInstr(astruct,*(melptr++))) return;
  
  while (1) 
   {
    int per,freq,dur;
    
    per=*(melptr++);
    dur=*(melptr++)*22;
    if (per==-1) return;
    freq=per*astruct->InstrumentSamples;
    astruct->AudioPlay(astruct,freq,dur*9/10);
    astruct->AudioPlay(astruct,0,dur/10);
   }
 
 }

static void AUDIO_PlayEffect(struct AudioPlay *peffect)
 {
  struct AudioStruct astruct;
#ifdef AmigaOS

  switch (peffect->effecttarget)
   {
    case AUDIOTARG_AUDIODEV:
      /*Initalize audio.device driver*/
      astruct.AudioInit=ADEV_AudioInit;
      astruct.AudioDeinit=ADEV_AudioDeinit;
      astruct.AudioPlay=ADEV_ToneOut;
      astruct.AudioSetInst=ADEV_SetInstrument;
      break;
    case AUDIOTARG_AHI:
      /*Initalize AHI driver*/
      astruct.AudioInit=AHI_AudioInit;
      astruct.AudioDeinit=AHI_AudioDeinit;
      astruct.AudioPlay=AHI_ToneOut;
      astruct.AudioSetInst=NULL;
      break;
    default:
      return;
   }

  if (peffect->effecttype==AUDIOTYPE_DATATYPE)
   {
    if (peffect->effectptr!=NULL) AUDIO_PlayDT(peffect->effectptr);
    return;
   }

  astruct.effect=peffect->effect;

#endif /*AmigaOS*/


#ifdef LINUX

  astruct.AudioInit=LIN_AudioInit;
  astruct.AudioDeinit=LIN_AudioDeinit;
  astruct.AudioPlay=LIN_ToneOut;
  astruct.AudioSetInst=NULL;

#endif /*LINUX*/


  if (astruct.AudioInit(&astruct)) return;
  AUDIO_PlayMelody(&astruct,Effect_Table[peffect->effect]);
  astruct.AudioDeinit(&astruct);

  return;                   /* OK return */
 }


#ifdef AmigaOS

static void AUDIO_StopEffect(struct AudioPlay *peffect)
 {
  AudioTasks[peffect->effect]=NULL;
 }


static int AUDIO_PlayReal(int effect)
 {
  struct AudioPlay eff;
  void *proc;

  eff.effect=effect-1;
  eff.effecttarget=Preferences.AudioEffects[eff.effect].EffectTarget;
  eff.effecttype=Preferences.AudioEffects[eff.effect].EffectType;
  eff.effectptr=NULL;

  if (eff.effecttype==AUDIOTYPE_DATATYPE)
   {
    eff.effectptr=*(AudioObjects+eff.effect);
   }

  Forbid();
  if (AudioTasks[eff.effect]==NULL)
   {
    if (!(proc=AmigaFork(AUDIO_PlayEffect,AUDIO_StopEffect,&eff,sizeof(eff),1,"ProfiPacket SFX Task")))
     {
      Permit();
      return(-1);
     }
    AudioTasks[eff.effect]=proc;
   }
  Permit();
  return(0);
 }


void AUDIO_Init(void)
 {
  DataTypesBase=OpenLibrary("datatypes.library",39);
  if (DataTypesBase!=NULL)
   {
    AudioObjects=AllocVec(32*sizeof(void *),MEMF_CLEAR);
    if (AudioObjects!=NULL)
     {
      int i;
      for (i=0;i<MAX_EFFECT;++i)
       {
        if (Preferences.AudioEffects[i].EffectType==
             AUDIOTYPE_DATATYPE)
         {
          AUDIO_LoadObject(Preferences.AudioEffects[i].EffectPath,AudioObjects+i);
         }
       }
     }
   }

 }


void AUDIO_Cleanup(void)
 {
  Object **ap;
  unsigned long i;

  for (i=0;i<MAX_EFFECT;++i)
   {
    while (AudioTasks[i]!=NULL)
     {
      Delay(10);
     }



   }

  if (AudioObjects!=NULL)
   {
    ap=AudioObjects;

    for (i=0;i<32;++i,++ap)
     {
      if (*ap!=NULL)
       {
        DisposeDTObject(*ap);
        *ap=NULL;
       }
     }
    FreeVec(AudioObjects);
    AudioObjects=NULL;
   }
  if (DataTypesBase!=NULL)
   {
    CloseLibrary(DataTypesBase);
    DataTypesBase=NULL;
   }
 }

#endif /*AmigaOS*/

#ifdef LINUX
void AUDIO_Init(void)
 {
 }

void AUDIO_Cleanup(void)
 {
 }

static int AUDIO_PlayReal(int effect)
 {
  struct AudioPlay eff;
  int pid;
  


  eff.effect=effect-1;
  eff.effecttarget=Preferences.AudioEffects[eff.effect].EffectTarget;
  eff.effecttype=Preferences.AudioEffects[eff.effect].EffectType;
  eff.effectptr=NULL;


  pid=fork();
  if (pid==-1) return (-1);
  if (pid==0) 
   {
    AUDIO_PlayEffect(&eff);
    exit(0);
   }
  return(0);
 }


#endif /*LINUX*/

int AUDIO_Effect(int effect,struct QSO *qso)
 {
  int effi;
  effi=effect;
  if (qso!=NULL)
   {
    effi=SERV_AskAudio(qso,effi);
   }
  if (effi==-1) return(-1);

  if (effect<1) return(-1);
  if (effect>MAX_EFFECT) return(-1);

  if (!UTIL_TestTimeRange(
           Preferences.AudioEffects[effect-1].EffectStart,
           0,
           Preferences.AudioEffects[effect-1].EffectStop,
           59)) return(-1);

  switch (Preferences.AudioEffects[effect-1].EffectLevel)
   {
    case AUDIOLEVL_NEVER:
      return(-1);
    case AUDIOLEVL_NOMESSAGE:
      if (MAIN_GetConnectMsgNr()!=0) return(-1);
    case AUDIOLEVL_AUTOMESSAGE:
      if (CMessageNr!=0) return(-1);
    case AUDIOLEVL_EVER:
      break;
   }

  return(AUDIO_PlayReal(effi));
 }

int AUDIO_Effect_C(int effect,int channel)
 {
  struct QSO *qso;
  if ( (channel<1) || (channel>MaxChannel) ) return(-1);
  qso=QSOs+(channel-1);
  return(AUDIO_Effect(effect,qso));
 }



