
/*
 * lback.c - perform a complete backup of all samplesand programs of the S2000
 *
 * Copyright (c) 2002-2004 Frank Neumann <franky@users.sourceforge.net>
 *
 */

#include <stdio.h>

#include "lakai.h"

int main(int argc, char *argv[])
{
	int i, j, idx, numprogs, numsamps, numkeygroups, res;
	FILE *fp1, *lfp;
	unsigned char *buf;
	unsigned long slocat, slngth, shdrlength;
	LHANDLE hd1;
	LakaiStatus lst;
	LakaiProgramList lp;
	LakaiSampleList ls;
	LakaiProgram lpr;
	LakaiKeygroup lkg;
	unsigned char shdrdata[1024];  /* TODO: How much really? */
	unsigned char progdata[1024];  /* ..".. */
	unsigned char kgrpdata[1024];  /* ..".. */ 
	unsigned char miscdata[1024];  /* ..".. */ 
	unsigned char fname[32];
	
	if (argc != 3 )
	{
		fprintf(stderr, "Usage: %s <devname> <listfile>\n", argv[0]);
		exit(1);
	}

	fprintf(stderr, "\n= Phase 0: Initializing =\n");
	lakai_init();

	hd1 = lakai_open(argv[1]);
	if (hd1 < 0)
	{
		fprintf(stderr, "Open failed.\n");
		exit(5);
	}

	/* list file: this one contains the file names of samples and programs,
	 * IN THE ORDER IN WHICH THEY HAVE TO BE RESTORED (this is important)
	 */
	lfp = fopen(argv[2], "w");
	if (!lfp)
	{
		fprintf(stderr, "Unable to open list file '%s' for writing\n", argv[2]);
		lakai_close(hd1);
		exit(5);
	}

	fprintf(lfp, "# Lakai list file. This file was auto-generated by the Lakai lakbak\n");
	fprintf(lfp, "# program. If you modify it, better know what you are doing.\n");
	fprintf(lfp, "#\n");

	/* TEST: get misc data.. */
	res = lakai_get_miscdata(hd1, miscdata);
//	fprintf(stderr, "Got %d bytes of misc data\n", res);
	/* TODO: Write out misc data to a file? */
	

#if 1
	fprintf(stderr, "\n= Phase 1: Restoring sample data =\n");
//	fprintf(stderr, "############ GET SAMPLE NAMES: #############\n");
	numsamps = lakai_get_sample_list(hd1, &ls);
	if (numsamps > 0)
	{
		fprintf(lfp, "# Samples (and sample header) files: %d samples\n", numsamps);
		fprintf(lfp, "#\n");
		fprintf(stderr, "Found %d sample names\n", numsamps);
#if 0
		for (i = 0; i < numsamps; i++)
			fprintf(stderr, "%03d: %s\n", i, ls.samplenames[i]);
#endif
//	fprintf(stderr, "Beginning restore...\n");

		for (i = 0; i < numsamps; i++)
		{
//			fprintf(stderr, "%03d: %s\n", i, ls.samplenames[i]);
//			fprintf(stderr, "\r- Getting sample header data...\n");
			shdrlength = lakai_get_sample_header(hd1, i, shdrdata);
//			fprintf(stderr, "Got %d bytes of sample header data\n", shdrlength);
			fprintf(stderr, "Retrieving sample #%d...", i);
			slocat = (shdrdata[25] * 16777216 + 
						 shdrdata[24] * 65536 +
						 shdrdata[23] * 256 + 
						 shdrdata[22]) * 2;
			slngth = (shdrdata[29] * 16777216 + 
						 shdrdata[28] * 65536 +
						 shdrdata[27] * 256 + 
						 shdrdata[26]) * 2;

//			fprintf(stderr, "\r- Sample start address: %ld\n", slocat);
//			fprintf(stderr, "\r- Sample length: %ld\n", slngth);

//			fprintf(stderr, "\r- Getting sample data...\n");
			buf = (unsigned char *)malloc(slngth);
			if (!buf)
			{
				fprintf(stderr, "Unable to malloc %d bytes sample buffer\n", slngth);
				exit(5);
			}
			memset(buf, 0xea, slngth);
			res = lakai_get_sample(hd1, i, buf, 0, slngth);

			/* Put together filename, replace " " by "_" */
			for (idx = 0; idx < strlen(ls.samplenames[i]); idx++)
			{
				if (ls.samplenames[i][idx] == ' ')
					fname[idx] = '_';
				else
					fname[idx] = ls.samplenames[i][idx];
			}
			fname[idx] = '\0';
			strcat (fname, ".s");
				
//	printf("Fname: '%s'\n", ls.samplenames[i]);
			fp1 = fopen(fname, "w");
			fwrite(shdrdata, shdrlength, 1, fp1);
			fwrite(buf, slngth, 1, fp1);
			fclose(fp1);
			free(buf);
			fprintf(lfp, "SAMP %s\n", fname);
			fprintf(stderr, "done (file '%s', %d bytes).\n", fname, slngth);
		}
	}
	else /* numsamps == 0 */
	{
		fprintf(stderr, "-- No resident sample names found. --\n");
		fprintf(lfp, "# Samples (and sample header) files: NONE\n");
		fprintf(lfp, "#\n");
	}

	lakai_free_sample_list(&ls);

	fprintf(lfp, "#\n");
#endif

	fprintf(stderr, "\n= Phase 2: Restoring program data =\n");
	/* restore all programs */
	numprogs = lakai_get_program_list(hd1, &lp);
	if (numprogs > 0)
	{
		fprintf(lfp, "# Program (and keygroup) files: %d programs\n", numprogs);
		fprintf(lfp, "#\n");
		fprintf(stderr, "Found %d program names\n", numprogs);
		for (i = 0; i < numprogs; i++)
		{
			fprintf(stderr, "Retrieving program #%d...", i);
			res = lakai_get_program(hd1, i, progdata);
			
			for (idx = 0; idx < strlen(lp.prognames[i]); idx++)
			{
				if (lp.prognames[i][idx] == ' ')
					fname[idx] = '_';
				else
					fname[idx] = lp.prognames[i][idx];
			}
			fname[idx] = '\0';
			strcat (fname, ".p");

			/* retrieve the # of keygroups in this program */
			numkeygroups = progdata[42];
//			fprintf(stderr, "%03d: %s, %d keygroups\n", i, lp.prognames[i], numkeygroups);
				
			fp1 = fopen(fname, "w");
			fwrite(progdata, res, 1, fp1);

			for (j = 0; j < numkeygroups; j++)
			{
				res = lakai_get_keygroup(hd1, i, j, kgrpdata);
//				fprintf(stderr, "got %d bytes for keygroup %d\n", res, j);
				fwrite(kgrpdata, res, 1, fp1);
			}
			fclose(fp1);
			fprintf(lfp, "PROG %s\n", fname);
			fprintf(stderr, "done (file '%s', %d keygroups).\n", fname, numkeygroups);
		}
	}
	else  /* numprogs == 0 */
	{
		fprintf(stderr, "-- No resident program names found. --\n");
		fprintf(lfp, "# Program (and keygroup) files: NONE\n");
		fprintf(lfp, "#\n");
	}

	lakai_free_program_list(&lp);

	fprintf(stderr, "\n= Phase 3: Closing down =\n");
	
	/* This is a little asymmetric, but the user has to switch back to "normal" mode
	 * whenever he wants to be able to access the sampler through standard MIDI
	 */
	lakai_setmode(hd1, LAKAI_MODE_NORMAL);

	lakai_close(hd1);
	fclose(lfp);
	fprintf(stderr, "= Done. =\n");
	
	exit(0);
}

