
/**************************************************************************/
/*				   Mem.c				  */
/*Contains code for reading an entire sample into memory at once	  */
/*This is used when it isn't practical to read the sound sample from      */
/*disk as it is played (e.g. when the sample is on a floppy).             */
/*Data is read in in blocks that are the same size as the buffer size	  */
/*(optionally) specified by the user using the -b flag, thereby not       */
/*requiring the user to have a block of contiguous memory as large as	  */
/*the sample.								  */
/*The memory blocks are stored as a linked list;  there are two linked	  */
/*lists, one for each channel of a stereo sample (the list for the left   */
/*channel is used if a mono sample is being played)			  */
/**************************************************************************/

#include <exec/types.h>
#include <dos/dos.h>
#include <dos/dosextens.h>

#include <proto/dos.h>
#include <proto/exec.h>

#include "dsound.h"

typedef struct memBlock
{
   struct memBlock *next;  /*The next memory block in the list*/
   ULONG blockLength;	   /*The size of this memory block*/
} memBlock;

/*The linked-list head pointers for each channel*/
memBlock *left=NULL;
memBlock *right=NULL;

/*Read the sample (pointed to by file) into memory*/
void storeLeft(BPTR file,ULONG length,ULONG blockLength)
{
   memBlock *temp;
   memBlock *lastLeft;

   /*Loop while there's data to be stored...*/
   while(length!=0)
   {
      /*Get the amount of data to be read next (max of blockLength bytes)*/
      blockLength=MIN(blockLength,length);

      /*Allocate the memory*/
      temp=(memBlock *)AllocMem(blockLength+8,0L);

      /*Exit if there was a problem*/
      if(temp==NULL)
      {
	 WriteMsg("Couldn't allocate needed memory\n");
	 cleanup(500);
      }

      /*Get the length of the data block*/
      temp->blockLength=blockLength;
      temp->next=NULL;

      if(left==NULL)
	 left=lastLeft=temp;  /*First block of data...*/
      else
      {        /* Add another block to the end of the list*/
	 lastLeft->next=temp;
	 lastLeft=temp;
      }

      /*Actually read the data, now that the allocated memory block*/
      /*is in place*/
      Read(file,lastLeft+1,blockLength);

      /*Subtract the amount read from the total yet to read*/
      length-=blockLength;
   }

   return;
}

/*Delete any remaining memory blocks associated with the left channel*/
void deleteLeft(void)
{
   memBlock *temp,*next;

   next=left;

   /*Loop until we run out of memory blocks*/
   while(next!=NULL)
   {
      /*Get the next block*/
      temp=next;
      next=temp->next;

      /*Free the current block*/
      FreeMem(temp,temp->blockLength+8);
   }

   return;
}

/*Get the next available block of sample data associated with the */
/*left channel*/
void getLeft(APTR dest)
{
   memBlock *temp;

   /*If there is no data left, do nothing*/
   if(dest==NULL || left == NULL)
      return;

   /*Copy the sample data from the memory block to the destination buffer*/
   CopyMem(left+1,dest,left->blockLength);

   /*Set the next block as the head of the list*/
   temp=left;
   left=left->next;

   /*Free the memory whose contents we just copied*/
   FreeMem(temp,temp->blockLength+8);

   return;
}

/*Read the sample (pointed to by file) into memory*/
void storeRight(BPTR file,ULONG length,ULONG blockLength)
{
   memBlock *temp;
   memBlock *lastRight;

   /*Loop while there's data to be stored...*/
   while(length!=0)
   {
      /*Get the amount of data to be read next (max of blockLength bytes)*/
      blockLength=MIN(blockLength,length);

      /*Allocate the memory*/
      temp=(memBlock *)AllocMem(blockLength+8,0L);

      /*Exit if there was a problem*/
      if(temp==NULL)
      {
	 WriteMsg("Couldn't allocate needed memory\n");
	 cleanup(500);
      }

      /*Get the length of the data block*/
      temp->blockLength=blockLength;
      temp->next=NULL;

      if(right==NULL)
	 right=lastRight=temp;	/*First block of data...*/
      else
      {        /* Add another block to the end of the list*/
	 lastRight->next=temp;
	 lastRight=temp;
      }

      /*Actually read the data, now that the allocated memory block*/
      /*is in place*/
      Read(file,lastRight+1,blockLength);

      /*Subtract the amount read from the total yet to read*/
      length-=blockLength;
   }

   return;
}

/*Delete any remaining memory blocks associated with the right channel*/
void deleteRight(void)
{
   memBlock *temp,*next;

   next=right;

   /*Loop until we run out of memory blocks*/
   while(next!=NULL)
   {
      /*Get the next block*/
      temp=next;
      next=temp->next;

      /*Free the current block*/
      FreeMem(temp,temp->blockLength+8);
   }

   return;
}

/*Get the next available block of sample data associated with the */
/*right channel*/
void getRight(APTR dest)
{
   memBlock *temp;

   /*If there is no data right, do nothing*/
   if(dest==NULL || right == NULL)
      return;

   /*Copy the sample data from the memory block to the destination buffer*/
   CopyMem(right+1,dest,right->blockLength);

   /*Set the next block as the head of the list*/
   temp=right;
   right=right->next;

   /*Free the memory whose contents we just copied*/
   FreeMem(temp,temp->blockLength+8);

   return;
}

