
 /* SP_PlaySubs.c
    - Functions for Playing SPO Files -
    (c) 1994-96 by Andreas R. Kleinert
    Last changes : 27.05.1996
 */


#include "spobject.h"

#include <exec/devices.h>
#include <devices/audio.h>

ULONG __saveds __asm SPO_Read( register __a1 struct SPObjectHandle *SPObjectHandle_a1);
ULONG __saveds __asm SPO_StartReplay( register __a1 struct SPObjectHandle *SPObjectHandle);
ULONG __saveds __asm SPO_ContinueReplay( register __a1 struct SPObjectHandle *SPObjectHandle_a1);
ULONG __saveds __asm SPO_FastForward( register __a1 struct SPObjectHandle *SPObjectHandle_a1);
ULONG __saveds __asm SPO_FastBackward( register __a1 struct SPObjectHandle *SPObjectHandle_a1);


ULONG __saveds __asm SPO_Read( register __a1 struct SPObjectHandle *SPObjectHandle_a1)
{
 struct SPObjectHandle *SPObjectHandle = SPObjectHandle_a1;

 ULONG retval = SPERR_NO_ERROR;
 struct TagItem __aligned xpk_pars [5];
 UBYTE          *Buf           = N;
 ULONG           BufSize       = N, xpk_errorcode;
 char filename [256], filename_spo [256];

 if(!SPObjectHandle) return(SPERR_NO_HANDLE);

 SPObjectHandle->ah_SPOHeader = AllocVec(sizeof(struct SPOHeader), (MEMF_CLEAR|MEMF_PUBLIC));
 if(!SPObjectHandle->ah_SPOHeader) return(SPERR_NO_MEMORY);

 SPObjectHandle->ah_ramhandle = AIM_GetMemList();
 if(!SPObjectHandle->ah_ramhandle) return(SPERR_NO_MEMORY);

 if(strlen(SPObjectHandle->ah_ReadName) > 4)
  {
   if(!stricmp(&SPObjectHandle->ah_ReadName[strlen(SPObjectHandle->ah_ReadName)-4], ".spo"))
    {
     strcpy(filename_spo, SPObjectHandle->ah_ReadName);
     strcpy(filename,     SPObjectHandle->ah_ReadName);
     filename[strlen(filename)-4] = (char) 0;
    }else
    {
     strcpy(filename,     SPObjectHandle->ah_ReadName);
     strcpy(filename_spo, SPObjectHandle->ah_ReadName);
     strcat(filename_spo, ".spo");
    }
  }else
  {
   strcpy(filename_spo, SPObjectHandle->ah_ReadName);
   strcat(filename_spo, ".spo");
   strcpy(filename,     SPObjectHandle->ah_ReadName);
  }

 SPObjectHandle->ah_filehandle_source = Open(filename_spo, MODE_OLDFILE);
 if(!SPObjectHandle->ah_filehandle_source) return(SPERR_NO_FILE);

 Read(SPObjectHandle->ah_filehandle_source, SPObjectHandle->ah_SPOHeader, SPOHEADER_SIZE);

 if(SPObjectHandle->ah_SPOHeader->spo_SampleBits > 8) return(SPERR_UNKNOWN_PARAMETERS);
    /* yet only 8-Bit Sample Data */

 /* Read XPK Data */

 xpk_pars[0].ti_Tag  = XPK_GetOutBuf;
 xpk_pars[0].ti_Data = (ULONG) &Buf;

 xpk_pars[1].ti_Tag  = XPK_GetOutBufLen;
 xpk_pars[1].ti_Data = (ULONG) &BufSize;

 xpk_pars[2].ti_Tag  = XPK_InName;
 xpk_pars[2].ti_Data = (ULONG) filename;

 xpk_pars[3].ti_Tag  = XPK_PassThru;
 xpk_pars[3].ti_Data = (ULONG) TRUE;

 xpk_pars[4].ti_Tag  = TAG_DONE;
 xpk_pars[4].ti_Data = N;

 xpk_errorcode = XpkUnpack(&xpk_pars[0]);
 if(!xpk_errorcode)
  {
   SPObjectHandle->ah_XpkBuffer = AllocVec(BufSize, (MEMF_CLEAR|MEMF_PUBLIC|MEMF_CHIP));
   if(SPObjectHandle->ah_XpkBuffer)
    {
     SPObjectHandle->ah_XpkBufferSize = BufSize;

     CopyMem(Buf, SPObjectHandle->ah_XpkBuffer, SPObjectHandle->ah_XpkBufferSize);
     FreeMem(Buf, BufSize);

     SPObjectHandle->ah_SampleList = SPLI_GetSampleList();
     if(SPObjectHandle->ah_SampleList) SPLI_AddSample(SPObjectHandle->ah_SampleList, SPObjectHandle->ah_XpkBuffer, SPObjectHandle->ah_XpkBufferSize, 8, SPObjectHandle->ah_SPOHeader->spo_Frequency, 64);

    }else retval = SPERR_NO_MEMORY;
  }else retval = SPERR_DECODE_ERROR;

 return(retval);
}

void __stdargs SPLI_PlayTask(void);
void __stdargs SPLI_EO_PlayTask(void);

ULONG __saveds __asm SPO_StartReplay( register __a1 struct SPObjectHandle *SPObjectHandle_a1)
{
 struct SPObjectHandle *SPObjectHandle = SPObjectHandle_a1;
 ULONG retval = SPERR_NO_ERROR;

 if(!SPObjectHandle) return(SPERR_NO_HANDLE);

 SPObjectHandle->ah_PlayTask = AllocVec(sizeof(struct Task), (MEMF_CLEAR|MEMF_PUBLIC));
 if(SPObjectHandle->ah_PlayTask)
  {
   SPObjectHandle->ah_TaskStopNext = FALSE;

   SPObjectHandle->ah_PlayTask->tc_Node.ln_Type = NT_TASK;
   SPObjectHandle->ah_PlayTask->tc_Node.ln_Name = "SPO.spobject";

   SPObjectHandle->ah_PlayTask->tc_SPLower = AllocVec(4096, (MEMF_CLEAR|MEMF_PUBLIC));
   if(SPObjectHandle->ah_PlayTask->tc_SPLower)
    {
     SPObjectHandle->ah_PlayTask->tc_SPUpper = (APTR) ((ULONG)SPObjectHandle->ah_PlayTask->tc_SPLower + (ULONG)4096);
     SPObjectHandle->ah_PlayTask->tc_SPReg   = SPObjectHandle->ah_PlayTask->tc_SPUpper;

     SPObjectHandle->ah_PlayTask->tc_UserData = SPObjectHandle;

     AddTask(SPObjectHandle->ah_PlayTask, SPLI_PlayTask, N);

     /* Get possible failure error code */

     Delay(100);
     if(!SPObjectHandle->ah_TaskRunning) retval = SPObjectHandle->ah_TaskRetVal;

    }else retval = SPERR_NO_MEMORY;

  }else retval = SPERR_NO_MEMORY;

 return(retval);
}

/* *************************************************** */
/* *						     * */
/* * Functions for a separate Player-Task            * */
/* *						     * */
/* *************************************************** */

void __stdargs SPLI_PlayTask(void)
{
 ULONG opres = N, sound_len, sound_play, sound_long, sound_rest;
 UBYTE channel, *sound_buf;
 struct IOAudio *audioreq  = N;
 struct MsgPort *audioport = N;
 struct SPObjectHandle *SPObjectHandle = N;
 APTR msg;
 struct Task *task = N;

 task = FindTask(N);

 SetTaskPri(task, 1);
 SPObjectHandle = task->tc_UserData;

 if(!SPObjectHandle)
  {
   SPObjectHandle->ah_TaskRetVal = SPERR_NO_HANDLE;
   return;
  }

 SPObjectHandle->ah_TaskRunning = TRUE;

 audioport = (struct MsgPort  *) CreatePort("SPO.spobject", N);
 if(audioport)
  {
   audioreq  = (struct IOAudio  *) CreateExtIO(audioport, sizeof(struct IOAudio));
   if(audioreq)
    {
     channel = SPObjectHandle->ah_SPOHeader->spo_Channels;

     audioreq->ioa_Request.io_Message.mn_Node.ln_Pri = 10;
     audioreq->ioa_Data                              = (APTR) &channel;
     audioreq->ioa_Length                            = 1;
     audioreq->ioa_AllocKey                          = 0;

     opres = OpenDevice("audio.device", 0, (struct IORequest *) audioreq, N);
     if(!opres)
      {
       while(!SPObjectHandle->ah_TaskStopNext)
        {
         sound_play = TRUE;
         sound_buf  = SPObjectHandle->ah_XpkBuffer;
         sound_rest = SPObjectHandle->ah_SPOHeader->spo_SampleLength;

         while(sound_play)
          {
           if(sound_rest <= 0xFFFF)
            {
             sound_len  = sound_rest;
             sound_long = FALSE;
             sound_play = FALSE;
            }else
            {
             sound_len  = 0xFFFF;
             sound_long = TRUE;

             sound_rest -= sound_len;
            }

           audioreq->ioa_Request.io_Command = CMD_WRITE;
           audioreq->ioa_Request.io_Flags   = ADIOF_PERVOL;
           audioreq->ioa_Data               = sound_buf;
           audioreq->ioa_Cycles             = 1;
           audioreq->ioa_Length             = sound_len;
           audioreq->ioa_Period             = 3579546 / SPObjectHandle->ah_SPOHeader->spo_Frequency;
           audioreq->ioa_Volume             = SPObjectHandle->ah_SPOHeader->spo_Volume;

           BeginIO((struct IORequest *) audioreq);
           WaitIO((struct IORequest *) audioreq);

           sound_buf += sound_len;
          }
        }

       audioreq->ioa_Request.io_Command = ADCMD_FINISH;
       audioreq->ioa_Request.io_Flags   = 0;
       audioreq->ioa_Data               = 0;
       audioreq->ioa_Cycles             = 0;
       audioreq->ioa_Length             = 0;
       audioreq->ioa_Period             = 0;
       audioreq->ioa_Volume             = 0;

       DoIO((struct IORequest *) audioreq);

       CloseDevice((struct IORequest *) audioreq);

      }else SPObjectHandle->ah_TaskRetVal = SPERR_NO_CHANNELS;

     DeleteExtIO((struct IORequest *) audioreq);

    }else SPObjectHandle->ah_TaskRetVal = SPERR_NO_MEMORY;

   while( msg = (APTR)GetMsg(audioport) ) ReplyMsg((APTR)msg);

   DeletePort(audioport);

  }else SPObjectHandle->ah_TaskRetVal = SPERR_NO_MEMORY;

 Forbid();

 SPObjectHandle->ah_TaskRunning  = FALSE;
 SPObjectHandle->ah_TaskStopNext = FALSE;

 Permit();
 
 Wait(1<<31); /* this signal never comes ... */
}

void __stdargs SPLI_EO_PlayTask(void)
{
 /* dummy-func */
}

ULONG __saveds __asm SPO_ContinueReplay( register __a1 struct SPObjectHandle *SPObjectHandle_a1)
{
 struct SPObjectHandle *SPObjectHandle = SPObjectHandle_a1;
 ULONG retval = SPERR_NO_ERROR;

 if(!SPObjectHandle) return(SPERR_NO_HANDLE);

 retval = SPERR_ACTION_NOT_SUPPORTED;

 return(retval);
}

ULONG __saveds __asm SPO_FastForward( register __a1 struct SPObjectHandle *SPObjectHandle_a1)
{
 struct SPObjectHandle *SPObjectHandle = SPObjectHandle_a1;
 ULONG retval = SPERR_NO_ERROR;

 if(!SPObjectHandle) return(SPERR_NO_HANDLE);

 retval = SPERR_ACTION_NOT_SUPPORTED;

 return(retval);
}

ULONG __saveds __asm SPO_FastBackward( register __a1 struct SPObjectHandle *SPObjectHandle_a1)
{
 struct SPObjectHandle *SPObjectHandle = SPObjectHandle_a1;
 ULONG retval = SPERR_NO_ERROR;

 if(!SPObjectHandle) return(SPERR_NO_HANDLE);

 retval = SPERR_ACTION_NOT_SUPPORTED;

 return(retval);
}
