/*
 * JUDAS V2.0 sample handling
 */




/*
 * This is something interesting...the sample pointer might go this many bytes
 * over the sample end while in the mixing inner loop. Here's the formula:
 *
 *         maximum_playspeed / minimum_mixspeed (round upwards for safety)
 * bytes = ---------------------------------------------------------------
 *                       iterations_in_mixing_inner_loop
 *
 * Maximum playspeed is 535232 (highest speed in linear freq. table), minimum
 * mixspeed is 5000 and there are 16 iterations.
 * And, of course, because there can be 16bit samples the number of bytes must
 * be multiplied with 2.
 */
#define SAFETYAREA 3456

SAMPLE *judas_allocsample(int length);
void judas_freesample(SAMPLE *smp);
void judas_playsample(SAMPLE *smp, unsigned chnum, unsigned frequency, unsigned char volume, unsigned char panning);
void judas_ipcorrect(SAMPLE *smp);
void judas_stopsample(unsigned chnum);
void judas_preventdistortion(unsigned channels);
void judas_setmastervolume(unsigned chnum, unsigned char mastervol);
void judas_setmusicmastervolume(unsigned musicchannels, unsigned char mastervol);
void judas_setsfxmastervolume(unsigned musicchannels, unsigned char mastervol);

SAMPLE *judas_allocsample(int length)
{
        SAMPLE *smp;

        judas_error = JUDAS_OUT_OF_MEMORY;
        length += SAFETYAREA;
        smp = (SAMPLE *)locked_malloc(sizeof (SAMPLE));
        if (!smp) return NULL;
        smp->start = locked_malloc(length);
        if (!smp->start)
        {
                judas_freesample(smp);
                return NULL;
        }
        smp->repeat = NULL;
        smp->end = NULL;
        judas_error = JUDAS_OK;
        return smp;
}

void judas_freesample(SAMPLE *smp)
{
        int c;
        CHANNEL *chptr;

        if (!smp) return;
        if (smp == &fakesample) return;
        /*
         * Go thru all channels; if that sample is playing then stop the
         * channel; we don't want a crash or audible shit!
         */
        chptr = &judas_channel[0];
        for (c = CHANNELS; c > 0; c--)
        {
                if (chptr->smp == smp)
                {
                        chptr->smp = NULL;
                        chptr->voicemode = VM_OFF;
                }
                chptr++;
        }
        /*
         * Free the sample data and then the sample structure itself
         */
        if (smp->start) locked_free(smp->start);
        locked_free(smp);
}

void judas_ipcorrect(SAMPLE *smp)
{
        if (!smp) return;
        if (smp == &fakesample) return;

        if (smp->voicemode & VM_LOOP)
        {
                int count, lcount = smp->end - smp->repeat;
                unsigned char *src = &smp->repeat[0], *dest = &smp->end[0];

                if (!src) return;
                if (!dest) return;

                if (smp->voicemode & VM_16BIT) count = SAFETYAREA;
                else count = SAFETYAREA / 2;
                while (count)
                {
                        if (lcount <= 0)
                        {
                                lcount = smp->end - smp->repeat;
                                src = &smp->repeat[0];
                        }
                        *dest++ = *src++;
                        lcount--;
                        count--;
                }
        }
        else
        {
                if (!smp->end) return;
                if (smp->voicemode & VM_16BIT) memset(&smp->end[0], 0, SAFETYAREA);
                else memset(&smp->end[0], 0, SAFETYAREA / 2);
        }
}

void judas_playsample(SAMPLE *smp, unsigned chnum, unsigned frequency, unsigned char volume, unsigned char panning)
{
        CHANNEL *chptr;

        if (!smp) return;
        if (smp == &fakesample) return;
        if (chnum >= CHANNELS) return;
        chptr = &judas_channel[chnum];
        chptr->voicemode = VM_OFF;
        chptr->pos = smp->start;
        chptr->repeat = smp->repeat;
        chptr->end = smp->end;
        chptr->smp = smp;
        chptr->fractpos = 0;
        chptr->freq = frequency;
        chptr->vol = volume;
        chptr->panning = panning;
        chptr->voicemode = smp->voicemode;
}

void judas_stopsample(unsigned chnum)
{
        CHANNEL *chptr;

        if (chnum >= CHANNELS) return;
        chptr = &judas_channel[chnum];
        chptr->voicemode = VM_OFF;
        chptr->smp = NULL;
}

void judas_preventdistortion(unsigned active_channels)
{
        int count;
        unsigned char mastervol;

        if (active_channels < 2) mastervol = 255;
        else mastervol = 256 / active_channels;
        for (count = 0; count < CHANNELS; count++)
        {
                judas_setmastervolume(count, mastervol);
        }
}

void judas_setmastervolume(unsigned chnum, unsigned char mastervol)
{
        CHANNEL *chptr;

        if (chnum >= CHANNELS) return;
        chptr = &judas_channel[chnum];
        chptr->mastervol = mastervol;
}

void judas_setmusicmastervolume(unsigned musicchannels, unsigned char mastervol)
{
        CHANNEL *chptr = &judas_channel[0];
        int count;

        if (musicchannels > CHANNELS) musicchannels = CHANNELS;
        for (count = 0; count < musicchannels; count++)
        {
                chptr->mastervol = mastervol;
                chptr++;
        }
}

void judas_setsfxmastervolume(unsigned musicchannels, unsigned char mastervol)
{
        CHANNEL *chptr;
        int count;

        if (musicchannels >= CHANNELS) return;
        chptr = &judas_channel[musicchannels];
        for (count = musicchannels; count < CHANNELS; count++)
        {
                chptr->mastervol = mastervol;
                chptr++;
        }
}
