#include <exec/exec.h>
#include <dos/dos.h>
#include <libraries/iffparse.h>
#include <iffp/8svx.h>
#include "extproc.h"

#define ID_VHDR MAKE_ID('V','H','D','R')
#define ID_8SVX MAKE_ID('8','S','V','X')
#define ID_BODY MAKE_ID('B','O','D','Y')
#define ID_CHAN MAKE_ID('C','H','A','N')

#define LOAD    1
#define SAVE    2

BOOL Load_Sample(VOID);
BOOL Save_Sample(VOID);
void Make_Stereo(void);
BYTE * Make_Separate(void);

struct sam_info *sample;
char *filename;
ULONG action;

/*typedef struct {
    ULONG oneShotHiSamples,     / * # samples in the high octave 1-shot part * /
          repeatHiSamples,      / * # samples in the high octave repeat part * /
          samplesPerHiCycle;    / * # samples/cycle in high octave, else 0 * /
    UWORD samplesPerSec;        / * data sampling rate * /
    UBYTE ctOctave,             / * # of octaves of waveforms * /
          sCompression;         / * data compression technique used * /
    Fixed volume;               / * playback nominal volume from 0 to Unity
                                 * (full volume). Map this value into
                                 * the output hardware's dynamic range.
                                 * /
    } Voice8Header;*/

ULONG main(int argc, char *argv[])
{
    if (argc != 5) return(0);

    if (atol(argv[1]) != FILER_MAGIC) return(FERR_NOTMAGIC);

    action = atol(argv[2]);
    sample = (struct sam_info *)atol(argv[3]);
    filename = (char *) argv[4];

    printf("%d\t%d\t%s\n", action, sample, filename);

    if (action == FACT_LOAD)
    {
        if (Load_Sample())
        {
            printf("waveform... %ld\tlength... %ld\tfreq... %ld\tvolume... %ld\n",sample->waveform,sample->length,sample->def_freq,sample->def_vol);
            printf("Loaded ... Exiting from IFF filer\n");
            return (FERR_NOERR);
        }
        else return (FERR_GENERAL);
    }

    if (action == FACT_SAVE)
    {
        if (Save_Sample())
        {
            printf("Saved ... Exiting from IFF filer\n");
            return (FERR_NOERR);
        }
        else return (FERR_GENERAL);
    }
}

BOOL Load_Sample(VOID)
{
    ULONG n=0;
    struct StoredProperty *vhdrsp, *bodysp, *chansp;
    Voice8Header *data;
    BOOL loaded = FALSE;
    BPTR file;
    APTR newmem;

    /*find the requested file*/
    if (file = Open(filename,MODE_OLDFILE))
    {
        printf("Finding IFF FORM... ");
        struct IFFHandle *iff;
        if (iff = (struct IFFHandle *)AllocIFF())
        {
            iff->iff_Stream = file;
            InitIFFasDOS (iff);
            if (!OpenIFF (iff, IFFF_READ))
            {
                PropChunk (iff, ID_8SVX, ID_VHDR);
                PropChunk (iff, ID_8SVX, ID_BODY);
                PropChunk (iff, ID_8SVX, ID_CHAN);
                StopOnExit (iff, ID_8SVX, ID_FORM);
                ParseIFF (iff, IFFPARSE_SCAN);

                if ((vhdrsp = FindProp (iff, ID_8SVX, ID_VHDR)) && (bodysp = FindProp (iff, ID_8SVX, ID_BODY)))
                {
                    if (bodysp->sp_Size)
                    {
                        printf("Found VHDR, and BODY ");
                        data = vhdrsp->sp_Data;
                        if (data->sCompression == sCmpNone)
                        {
                            if (newmem = AllocMem(bodysp->sp_Size, MEMF_PUBLIC));
                            {
                                if (sample->length) /*Free old waveform*/
                                {
                                    FreeMem(sample->waveform,sample->length);
                                    printf("FreeMem oldwaveform\t%d bytes at %d\n",sample->length,sample->waveform);
                                }

                                sample->length = bodysp->sp_Size;
                                sample->def_freq = data->samplesPerSec;
                                sample->def_vol = data->volume;
                                sample->waveform = (BYTE *)newmem;
                                sample->type = STYPE_M8;
                                if (data->repeatHiSamples)
                                {
                                    sample->loop = TRUE;
                                    sample->loop_begin = data->oneShotHiSamples;
                                    sample->loop_length = data->repeatHiSamples;
                                }
                                else
                                {
                                    sample->loop = FALSE;
                                    sample->loop_begin = 0;
                                    sample->loop_length = 0;
                                }
                                if (chansp = FindProp (iff, ID_8SVX, ID_CHAN))
                                {
                                    ULONG *chanval = chansp->sp_Data;
                                    printf("\nCHAN... %d\n",*chanval);
                                    if (*chanval == 6) /*stereo sample*/
                                        sample->type = STYPE_S8;
                                }

                                CopyMem (bodysp->sp_Data, sample->waveform, sample->length);

                                printf("Repeat start = %d ",data->oneShotHiSamples);
                                printf("Repeat length = %d\n",data->repeatHiSamples);
                                loaded = TRUE;
                            }
                        }
                    }
                }
                CloseIFF (iff);
            }
            FreeIFF (iff);
        }
        Close(file);
    }
    if (sample->type == STYPE_S8) Make_Stereo();
    return(loaded);
}

void Make_Stereo(void)
{
    if (!sample->length) return();

    BYTE *oldwave = sample->waveform;

    if (sample->waveform = AllocMem(sample->length, MEMF_PUBLIC | MEMF_CLEAR))
    {
        printf("Making stereo...\n");
        BYTE *dest = sample->waveform +1;
        for (BYTE *src = oldwave; dest < (sample->waveform + sample->length); *dest = *src, dest +=2, src++);
        dest = sample->waveform;
        for (BYTE *src = oldwave +(sample->length /2); dest < (sample->waveform + sample->length); *dest = *src, dest +=2, src++);
        FreeMem(oldwave, sample->length);
    }
    else
    {
        sample->waveform = oldwave;
    }
}

BYTE * Make_Separate(void)
{
    if (!sample->length) return(NULL);

    BYTE *savebuf = NULL;

    if (savebuf = AllocMem(sample->length, MEMF_PUBLIC | MEMF_CLEAR))
    {
        printf("Separating stereo...\n");
        BYTE *dest = savebuf;
        for (BYTE *src = sample->waveform +1; src < (sample->waveform + sample->length); *dest = *src, dest++, src+=2);
        dest = savebuf + (sample->length /2);
        for (BYTE *src = sample->waveform; src < (sample->waveform + sample->length); *dest = *src, dest ++, src+=2);
    }
    return(savebuf);
}

BOOL Save_Sample(VOID)
{
    ULONG n=0;
    BYTE *savebuf = NULL, *buf;
    Voice8Header data;
    BOOL saved = FALSE;
    BPTR file;

    if ((sample->type != STYPE_M8) && (sample->type != STYPE_S8)) return(FALSE);

    data.oneShotHiSamples = sample->loop_begin;
    data.repeatHiSamples = sample->loop_length;
    data.samplesPerHiCycle;
    data.samplesPerSec = sample->def_freq;
    data.ctOctave = 1;
    data.sCompression =0;
    data.volume = sample->def_vol;

    /*find the requested file*/
    if (file = Open(filename,MODE_NEWFILE))
    {
        struct IFFHandle *iff;
        if (iff = (struct IFFHandle *)AllocIFF())
        {
            iff->iff_Stream = file;
            InitIFFasDOS (iff);
            if (!OpenIFF (iff, IFFF_WRITE))
            {
                printf("Opened iffparse for writes... ");
                if (!PushChunk (iff, ID_8SVX, ID_FORM, IFFSIZE_UNKNOWN))
                {
                    printf("Creating FORM, ");
                    if (!PushChunk (iff, ID_8SVX, ID_VHDR, sizeof (Voice8Header)))
                    {
                        printf("VHDR, ");
                        if (WriteChunkBytes (iff, &data, sizeof (Voice8Header)))
                        {
                            printf("writing VHDR... ");
                            if (!PopChunk (iff))
                            {
                                printf("written, ");
                                saved = TRUE;
                            }
                        }
                    }

                    if (sample->type == STYPE_S8)
                    {
                        savebuf = Make_Separate();
                        ULONG type = 6;

                        if (!PushChunk (iff, ID_8SVX, ID_CHAN, 4))
                        {
                            printf("CHAN, ");
                            if (!WriteChunkBytes (iff, &type, 4))
                                saved = FALSE;
                            else
                            {
                                printf("writing CHAN. ");
                                if (PopChunk (iff))
                                    saved = FALSE;
                            }
                        }
                        else
                            saved = FALSE;
                    }

                    if (saved && !PushChunk (iff, ID_8SVX, ID_BODY, sample->length))
                    {
                        printf("BODY, ");
                        if (savebuf) buf = savebuf; else buf = sample->waveform;
                        if (!WriteChunkBytes (iff, buf, sample->length))
                            saved = FALSE;
                        else
                        {
                            printf("writing BODY. ");
                            if (PopChunk (iff))
                                saved = FALSE;
                        }
                    }
                    else
                        saved = FALSE;

                    if (savebuf) FreeMem(savebuf, sample->length);
                }
                CloseIFF (iff);
            }
            FreeIFF (iff);
        }
        Close(file);
    }
    printf("\n");
    return(saved);
}
