
/*     Convert any known sample format (datatypes!) to ADPCM    */
/* Written in 1995 by Christian Buchner. This is Public Domain. */

/* Note: TAB SIZE = 4 */

/* History:

   added version string (still V1.0)
   improved datatypes error output (->V1.1)

*/

/* Includes */

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/datatypes.h>
#include <clib/alib_stdio_protos.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <datatypes/datatypes.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/soundclass.h>
#include <string.h>
#include <stdarg.h>


/* Version string */

UBYTE Version[]="$VER: X2ADPCM 1.1 "__AMIGADATE__" by Christian Buchner";


/*******************************************************************************/

extern __asm ULONG CompressADPCM2(		register __a0 UBYTE *Source,
										register __d0 ULONG Length,
										register __a1 UBYTE *Destination,
										register __d1 ULONG JoinCode	);

extern __asm ULONG CompressADPCM3(		register __a0 UBYTE *Source,
										register __d0 ULONG Length,
										register __a1 UBYTE *Destination,
										register __d1 ULONG JoinCode	);

/*******************************************************************************/


#define INPUT_SIZE 16384


/* Library bases */

struct DosLibrary *DOSBase;
struct Library *DataTypesBase;
struct IntuitionBase *IntuitionBase;


UBYTE *Template="FROM/A,TO/K/A,BITS/K/N";

struct ArgArray
{
	UBYTE *aa_From;
	UBYTE *aa_To;
	ULONG *aa_Bits;
};

struct ArgArray AA;
struct RDArgs *RDArgs;
UBYTE ProgName[60];

/*******************************************************************************/


/* void __saveds main() */

LONG __saveds main()
{
	ULONG Bits=2;
	
	if (DOSBase=(struct DosLibrary*)OpenLibrary("dos.library",37))
	{
		if (DataTypesBase=OpenLibrary("datatypes.library",39))
		{
			if (!GetProgramName(ProgName,sizeof(ProgName))) strcpy(ProgName,"CDRipper");
			
			if (!(RDArgs=ReadArgs(Template,(LONG *)&AA,0)))
			{
				PrintFault(IoErr(),ProgName);
			}
			else
			{
				if (AA.aa_Bits) Bits= *AA.aa_Bits;
				
				if (Bits != 2 && Bits != 3)
				{
					Printf("Illegal bit number. Use 2 for ADPCM2 and 3 for ADPCM3.\n");
				}
				else
				{
					Object *Sound;
					
					if (Sound=NewDTObject(AA.aa_From, DTA_GroupID, GID_SOUND, TAG_DONE))
					{
						UBYTE *Sample;
						ULONG Length;
						ULONG Period;
						
						if (GetDTAttrs(Sound, SDTA_Sample, &Sample, SDTA_SampleLength, &Length, SDTA_Period, &Period, TAG_DONE) != 3)
						{
							Printf("Cannot get sample attributes!\n");
						}
						else
						{
							UBYTE *ADPCMBuffer;
							ULONG ADPCMLen;
							
							if (Bits==2) ADPCMLen=(INPUT_SIZE+3)/4;
							if (Bits==3) ADPCMLen=(INPUT_SIZE+7)/8*3;
							
							if (!(ADPCMBuffer=AllocVec(ADPCMLen,MEMF_ANY|MEMF_CLEAR)))
							{
								Printf("No memory for ADPCM buffer!\n");
							}
							else
							{
								BPTR OutFile;
								
								if (!(OutFile=Open(AA.aa_To,MODE_NEWFILE)))
								{
									Printf("Cannot open '%s' for output: ",AA.aa_To);
									PrintFault(IoErr(),NULL);
								}
								else
								{
									ULONG Frequency=(*(struct ExecBase**)(4))->ex_EClockFrequency*5/Period;
									ULONG Offset;
									ULONG JoinCode=0;
									
									if (Bits==2) Write(OutFile,"ADPCM2", 6);
									if (Bits==3) Write(OutFile,"ADPCM3", 6);
									
									Write(OutFile,&Frequency, sizeof(Frequency));
									
									for (Offset=0; Offset<Length; )
									{
										ULONG Left=Length-Offset;
										ULONG Do = Left < INPUT_SIZE ?
												   Left : INPUT_SIZE;
										
										Printf("\rCompressing/Saving (%02ld%%)",100*Offset/Length);
										
										if (Bits==2) ADPCMLen=(Do+3)/4;
										if (Bits==3) ADPCMLen=(Do+7)/8*3;
										
										if (Bits==2) JoinCode=CompressADPCM2(Sample+Offset, Do, ADPCMBuffer, JoinCode);
										if (Bits==3) JoinCode=CompressADPCM3(Sample+Offset, Do, ADPCMBuffer, JoinCode);
										
										Write(OutFile, ADPCMBuffer, ADPCMLen);
										
										Offset+=Do;
										
										if (CheckSignal(SIGBREAKF_CTRL_C))
										{
											PrintFault(ERROR_BREAK,NULL);
											break;
										}
									}
									Printf("\rCompressing/Saving finished\n",100*(Length-Offset)/Length);
									
									Close(OutFile);
								}
								FreeVec(ADPCMBuffer);
							}
						}
						DisposeDTObject(Sound);
					}
					else
					{
						LONG Error=IoErr();
						
						if (Error>=2000)
						{
							Printf("%s: ",AA.aa_From);
							Printf(GetDTString(Error),AA.aa_From);
							Printf("\n");
						}
						else
						{
							PrintFault(Error, AA.aa_From);
						}
					}
				}
				FreeArgs(RDArgs);
			}
			CloseLibrary(DataTypesBase);
		}
		CloseLibrary((struct Library*)DOSBase);
	}
}


/*******************************************************************************/

/* Show a message to the user */

void __stdargs Message(UBYTE *Msg,...)
{
	va_list Arg;
	struct EasyStruct Req={sizeof(struct EasyStruct),0,"X2ADPCM message",0,"Okay"};
	Req.es_TextFormat=Msg;
	va_start(Arg,Msg);
	
	if (IntuitionBase)
	{
		EasyRequestArgs(NULL,&Req,0,Arg);
	}
	else
	{
		VPrintf(Msg,Arg);
		Printf("\n");
	}
	
	va_end(Arg);
}
