/*
   Risc os Digital Signal Processor
  (C) 2017 A.V.Bartram

  v0.22

  THIS SOFTWARE IS PROVIDED  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  IN NO EVENT SHALL A.V.Bartram BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL
  ,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO
  ),PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS
  ;OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "kernel.h"
#include "swis.h"
#include "cmodulehdr.h"
#include "synth.h"

extern void buffer_fill_veneer();

// TODO SWI handling
// TODO Legacy mode envelope


/*
 * RDSP : Based on the C Module example.
 * Risc os Digital Signal Processor.
 *
 * TODO
 * It will respond to SWIs in the range 0x88000 + [0..63], or as otherwise
 * specified in the Module Header description CModuleHdr.
 *
 */

/* SharedSound SWI numbers */
#define SharedSound_InstallHandler	0x4B440
#define SharedSound_SampleRate		0x4B446
#define SharedSound_RemoveHandler	0x4B441

#define  TM                     "RSynth"
#define  UNKNOWN_CMD_SERVICE    4
#define  UNUSED(x)              (x = x)

static _kernel_oserror tm_error = { 0x88000, "*** " TM " error ***" };

static int rstart_refcount = 0;
static int sound_handler_id;
static int unknown_cmd_count;
static int other_service_call_count;
static int xxx;

// Instance of the syntheiser
RISC_SYNTH g_synth;

// TODO: Rate must be a member of the synthesiser as well as a timestretch
// constant.
static int g_rate = 0;

static int g_initialised = 0;

// For diagnostics
static int g_verbose = 0;

// For increased BBC Micro compatibility
// n.b. At the moment this will be limited to the envelope command
//      Sound channel zero and SOUND command have reasonable defaults.
static int g_legacy = 0;

// SOUND 1,-,100,100 override
static int g_bell = 0;

// Move to synth.h
typedef unsigned char* BYTE;

int HandleRStart(void)
{
  rstart_refcount++;

  if (g_initialised)
  {
    if (g_verbose)
      printf("Already '*rstart'ed. Reference count increased\n");

    return 0;
  }

  extern RISC_SYNTH g_synth;
  _kernel_swi_regs regs;
  _kernel_oserror *err;

  int i;
    // Ensure synth channel is zero - TODO - call synthInit
  memset(&g_synth, 0, sizeof(RISC_SYNTH));
  g_synth.m_compressor = 255; // OFF - SHOULD START AT 1
  g_synth.m_masterVolume = 128;
  g_synth.m_compressorSpeed = 4;
  for (i = 0; i < MAX_POLY; ++i)
  {
    g_synth.m_channel[i].m_lpf.cutoff = 255;
    g_synth.m_channel[i].m_lpf.resonance = 0;
    g_synth.m_channel[i].m_dco.m_sample.m_data = NULL;
    g_synth.m_channel[i].m_dco.m_sample.m_dataLength = 0;
  }
    g_synth.tonetable = _toneTable;
    g_synth.sampleFreqTable = _sampleFreqTable;
    for (i = 0; i < 256; ++i)
      g_synth.m_sample[i].m_data = NULL;

    // Default to 1/2 second and 100/256 feedback
    g_synth.m_effects.m_delayLine.m_record = 50 * 441;
    g_synth.m_effects.m_delayLine.m_play = 0;
    g_synth.m_effects.m_delayLine.m_feedback = 100;

	/* Try to register sharedsound handler, return nonzero on failure */

	/* First load SharedSound if it isn't already loaded
	   A *command is the easiest way to do this (usually in your programs !Run file, but this demo doesn't have one) */
	system("RMEnsure SharedSound 0.00 IfThere System:Modules.SSound Then RMLoad System:Modules.SSound");
	/* Now check whether it is loaded, so we can print a more friendly error message than 'SWI xxx not found' */
	regs.r[0] = 18;
	regs.r[1] = (int) "SharedSound";
	if ((err = _kernel_swi(OS_Module,&regs,&regs)))
	{
		printf("Error: SharedSound module not loaded, and not in System:Modules!\n");
		return 1;
	 }

  /* Request 44 khz audio. This should succeed on all modern platforms */
  /* So in most cases scaling our output buffers will not be required */
	/* Get sample rate we have been assigned */
	regs.r[0] = 0; // Override system handler
	regs.r[1] = 44100*1024;
	_kernel_swi(SharedSound_SampleRate,&regs,&regs);
	g_rate = regs.r[1];

    if (g_verbose)
	  printf("RDSP: Shared sound running at %d / 1024 Hz\n", regs.r[1]);

    if (regs.r[1] != 45158400)
    {
      printf("RDSP: Warning! RDSP currently only supports 44 Khz audio\n");
      printf("RDSP:          Sounds and samples will not play at correct pitch.\n");
      printf("RDSP: RISC OS has returned %d / 1024 Hz for shared sound\n", regs.r[1]);
    }

	/* Now we can register our handler */
	regs.r[0] = (int) buffer_fill_veneer;
	regs.r[1] = (int)&g_synth;
	regs.r[2] = 1;
	regs.r[3] = (int) "RDSP Alpha";
	regs.r[4] = 0;
	if ((err = _kernel_swi(SharedSound_InstallHandler,&regs,&regs)))
	{
		printf("Error: SharedSound_InstallHandler returned error %d, %s\n",err->errnum,err->errmess);
		return 1;
	}
	sound_handler_id = regs.r[0];
	/* Install error handlers */
//	atexit(shutdown_sharedsound);
//	regs.r[0] = 1;
//	regs.r[1] = (int) error_handler;
//	regs.r[2] = 0;
//	_kernel_swi(OS_Claim,&regs,&regs);


   g_initialised = 1;

   if (g_verbose)
     printf("Shared sound installed ok\n");

	return 0;
}

void HandleRStop(void)
{

	 _kernel_swi_regs regs;
	 int i = 0;
	 extern RISC_SYNTH g_synth;

    if (g_initialised == 0)
      return;

    rstart_refcount--;
    if (rstart_refcount > 0)
    {
      if (g_verbose)
        printf("Rstop reference count decreased. Now %d\n", rstart_refcount);
        return;
    }

	/* Deregister sharedsound handler */
	if(sound_handler_id)
	{
		regs.r[0] = sound_handler_id;
		_kernel_swi(SharedSound_RemoveHandler,&regs,&regs);
		sound_handler_id = 0;
	 }


	regs.r[0] = 7;
	regs.r[1] = (int)&rosesound_entry;
	regs.r[2] = 0;
//	_kernel_swi(OS_Release,&regs,&regs);

	/* Remove error handler */
//	regs.r[0] = 1;
//	regs.r[1] = (int) error_handler;
//	regs.r[2] = 0;
 //	_kernel_swi(OS_Release,&regs,&regs);

 // Free up any samples that were loaded
 for (i = 0; i < 256; ++i)
 {
   if (g_synth.m_sample[i].m_data != NULL)
   {
     free(g_synth.m_sample[i].m_data);
     g_synth.m_sample[i].m_data = NULL;
   }
 }

  if (g_verbose)
	   printf("Shut down\n");
  g_initialised = 0;
}


int HandleRSound(_kernel_swi_regs *registers)
{
  extern RISC_SYNTH g_synth;
  int    error = 0;
  int    channel = (registers->r[0]-1) & MAX_POLY_MASK;

  // *rsound <channel> <flags> <wave | instrument> <volume> <pitch> <duration>

  g_synth.m_channel[channel].m_mode = registers->r[1];

  // Check if a waveform is required or an instrument/envelope is to
  // be played.
  if (isdigit(((char*)registers->r[2])[0]))
  {
    int wave =  atoi((char*)registers->r[2]);

    if (wave <= 0xff)
      g_synth.m_channel[channel].m_wave = wave;
    else
    {
      // Is a sample required to be played?
      wave = wave - 0x100;
      if (wave < 0x200)
      {
        g_synth.m_channel[channel].m_wave = 0;
        g_synth.m_channel[channel].m_dco.m_osc_lookup = 0;
        g_synth.m_channel[channel].m_dco.m_sample_lookup_msw = 0;
        g_synth.m_channel[channel].m_dco.m_sample.m_dataLength = g_synth.m_sample[wave].m_length;
        g_synth.m_channel[channel].m_dco.m_sample.m_data = g_synth.m_sample[wave].m_data;
        g_synth.m_channel[channel].m_dco.m_sample.m_loop = g_synth.m_sample[wave].m_loop;
        g_synth.m_channel[channel].m_dco.m_sample.m_loopBack = g_synth.m_sample[wave].m_loopBack;

      }
    }

    g_synth.m_channel[channel].m_adr.m_flags = 0;
    g_synth.m_channel[channel].m_adr.m_counterSpeed = 0;
    g_synth.m_channel[channel].m_amp = registers->r[3];

    g_synth.m_channel[channel].m_tone = registers->r[4];
    g_synth.m_channel[channel].m_adsr.m_stage = 0;
    g_synth.m_channel[channel].m_adsr.m_stageCounter = 0;
    g_synth.m_channel[channel].m_adsr.m_endState = 3;
    g_synth.m_channel[channel].m_adsr.m_counterSpeed = 1;
    g_synth.m_channel[channel].m_adsr.m_numADSR[0] = 1;
    g_synth.m_channel[channel].m_adsr.m_numADSR[1] = 0;
    g_synth.m_channel[channel].m_adsr.m_numADSR[2] = registers->r[5];
    g_synth.m_channel[channel].m_adsr.m_numADSR[3] = 1;
    g_synth.m_channel[channel].m_adsr.m_stepADSR[0] = 1;
    g_synth.m_channel[channel].m_adsr.m_stepADSR[1] = 0;
    g_synth.m_channel[channel].m_adsr.m_stepADSR[2] = 0;
    g_synth.m_channel[channel].m_adsr.m_stepADSR[3] = 1;
    g_synth.m_channel[channel].m_adsr.m_targetADSR[0] = 0;
    g_synth.m_channel[channel].m_adsr.m_targetADSR[1] = 0;
    g_synth.m_channel[channel].m_adsr.m_targetADSR[2] = 0;
    g_synth.m_channel[channel].m_adsr.m_targetADSR[3] = 0;

  }
  else
  {

    // Find the instrument in the table
    int found = 0;
    int i = 0;
    while ((!found) && (i < 256))
    {
      if (strcmp(g_synth.m_instrument[i].m_name, (char*)registers->r[2]) == 0)
        found = 1;
      else
        ++i;
    }

    if (found)
    {
      // Attack, decay and release are portions of duration
      int duration =  registers->r[5];  // map to sustain
      int volume = registers->r[3];
      int targetVolume = 0;
      int attackDelta = 0;
      int attackSteps = 0;
      int attackTarget = 0;
      int decayDelta = 0;
      int decaySteps = 0;
      int decayTarget = 0;
      int waveform = g_synth.m_instrument[i].m_wave;
      g_synth.m_channel[channel].m_amp = 0;
      if (waveform <= 255)
        g_synth.m_channel[channel].m_wave = waveform;
      else
      {
        // Waveform corresponds to sample number - 0x100
        int wave = waveform - 0x100;
        g_synth.m_channel[channel].m_wave = 0;
        g_synth.m_channel[channel].m_dco.m_osc_lookup = 0;
        g_synth.m_channel[channel].m_dco.m_sample_lookup_msw = 0;
        g_synth.m_channel[channel].m_dco.m_sample.m_dataLength = g_synth.m_sample[wave].m_length;
        g_synth.m_channel[channel].m_dco.m_sample.m_data = g_synth.m_sample[wave].m_data;
        g_synth.m_channel[channel].m_dco.m_sample.m_loop = g_synth.m_sample[wave].m_loop;
        g_synth.m_channel[channel].m_dco.m_sample.m_loopBack = g_synth.m_sample[wave].m_loopBack;
      }
      g_synth.m_channel[channel].m_tone = registers->r[4];
      g_synth.m_channel[channel].m_adsr.m_counterSpeed = 1;
      g_synth.m_channel[channel].m_adsr.m_stage = 0;
      g_synth.m_channel[channel].m_adsr.m_stageCounter = 0;
      g_synth.m_channel[channel].m_adsr.m_endState = 4;

      g_synth.m_channel[channel].m_adsr.m_flags = g_synth.m_instrument[i].m_options;
      // Four stage envelope

      // I need a logarithmic curve here
      // the division is lossy and you can't have a plucking sound
      // unless there is a curve.
      // Also: ADSR uses a fixed point fraction to operate with 16 bits
      //       for the fractional part of the number.

      if (g_synth.m_instrument[i].m_decay >
          g_synth.m_instrument[i].m_sustain)
          targetVolume = (g_synth.m_instrument[i].m_decay * volume) >> 8;
      else
          targetVolume = (g_synth.m_instrument[i].m_sustain * volume) >> 8;

      if ((targetVolume != 0) && (g_synth.m_instrument[i].m_attack != 0))
      {
        // The attack and decay should not be volume levels
        // but relative to volume
        // I have changed the ADSR (not asr)
        // to allow target volumes to be reached
        // before changing state.


        attackDelta = (targetVolume << 16 ) / g_synth.m_instrument[i].m_attack;
        if (attackDelta == 0)
          attackDelta = 1; // Not likely now.

        attackTarget = targetVolume;

        attackSteps = MAX_STEPS;
      }
      else
      {
        attackDelta = volume << 16;
        attackSteps = 1;
      }


      // ADSR runs with a 16 bit fractional step stored in accumulators
      g_synth.m_channel[channel].m_adsr.m_stepADSR[0] = attackDelta;
      g_synth.m_channel[channel].m_adsr.m_numADSR[0] = attackSteps;
      g_synth.m_channel[channel].m_adsr.m_targetADSR[0] = attackTarget;

      // Decay is rate. Sustain is proportion of volume
      if (g_synth.m_instrument[i].m_decay >
                   g_synth.m_instrument[i].m_sustain)
      {

        decaySteps = MAX_STEPS;

        decayDelta = -65536;


        // Sustain is a proportion of volume
        decayTarget = (volume * g_synth.m_instrument[i].m_sustain) >> 8;

      }
      else
      {
        decayTarget = 0;
        decayDelta = 0;
        decaySteps = 0;
      }


      g_synth.m_channel[channel].m_adsr.m_stepADSR[1] =decayDelta;
      g_synth.m_channel[channel].m_adsr.m_numADSR[1] = decaySteps;
      g_synth.m_channel[channel].m_adsr.m_targetADSR[1] = decayTarget;

      g_synth.m_channel[channel].m_adsr.m_stepADSR[2] = 0;
      g_synth.m_channel[channel].m_adsr.m_numADSR[2] = duration;
      g_synth.m_channel[channel].m_adsr.m_targetADSR[2] = 0;

      g_synth.m_channel[channel].m_adsr.m_numADSR[3] = g_synth.m_instrument[i].m_release * 2;
      g_synth.m_channel[channel].m_adsr.m_targetADSR[3] = 0;
      {

        // volume * g_synth.m_instrument[i].m_sustain * 256

        // 256 = 65536   // allowing for volume - min = 256
        // 1   = 16777216 (up to depending on volume) - max = 65536
        int timestep =  g_synth.m_instrument[i].m_release == 0 ? 1 : g_synth.m_instrument[i].m_release ;
        int susvolume = (volume * g_synth.m_instrument[i].m_sustain) * 256;
        int stepSize = (susvolume / timestep) >> 1;

        if (stepSize == 0)
          stepSize = 1;

        g_synth.m_channel[channel].m_adsr.m_stepADSR[3] = stepSize * -1;

      }

      // 3 Stage Envelope
      g_synth.m_channel[channel].m_adr.m_stage = 0;
      g_synth.m_channel[channel].m_adr.m_stageCounter = 0;
      g_synth.m_channel[channel].m_adr.m_endState = 4;

      g_synth.m_channel[channel].m_adr.m_counterSpeed = g_synth.m_instrument[i].m_steptime;
      g_synth.m_channel[channel].m_adr.m_flags = g_synth.m_instrument[i].m_options;
      g_synth.m_channel[channel].m_adr.m_stepADSR[0] = g_synth.m_instrument[i].m_asrAttackDelta;
      g_synth.m_channel[channel].m_adr.m_stepADSR[1] = 0;
      g_synth.m_channel[channel].m_adr.m_stepADSR[2] = g_synth.m_instrument[i].m_asrSustainDelta;
      g_synth.m_channel[channel].m_adr.m_stepADSR[3] = g_synth.m_instrument[i].m_asrReleaseDelta;

      g_synth.m_channel[channel].m_adr.m_numADSR[0] =  g_synth.m_instrument[i].m_asrStepsAttack;
      g_synth.m_channel[channel].m_adr.m_numADSR[1] =  0;
      g_synth.m_channel[channel].m_adr.m_numADSR[2] =  g_synth.m_instrument[i].m_asrStepsSustain;
      g_synth.m_channel[channel].m_adr.m_numADSR[3] =  g_synth.m_instrument[i].m_asrStepsRelease;

      g_synth.m_channel[channel].m_lpf.cutoff =  g_synth.m_instrument[i].m_cutoff;
      g_synth.m_channel[channel].m_lpf.resonance = g_synth.m_instrument[i].m_res;



    }
    else
    {
      error = 1;
    }

  }

  if (g_synth.m_channel[channel].m_wave >= 0x01 && g_synth.m_channel[channel].m_wave <= 0x1f)
  {
    // 711 = 22050 / 31 i.e. for half of sample rate when wave = 31 width = 22050 or 100%
     g_synth.m_channel[channel].m_pulse_width = 711 * g_synth.m_channel[channel].m_wave;
  }

  g_synth.m_channel[channel].m_prng = 1;     // Maybe move to initialisation
    g_synth.m_channel[channel].m_noise_throttle = 0;


return error;
}

void HandleRFilter(_kernel_swi_regs *registers)
{
  extern RISC_SYNTH g_synth;
  int channel = (registers->r[0]-1) & MAX_POLY_MASK;

   g_synth.m_channel[channel].m_lpf.cutoff = registers->r[1];
   g_synth.m_channel[channel].m_lpf.resonance = registers->r[2];

}

void HandleREnvelope(_kernel_swi_regs *registers)
{
  extern RISC_SYNTH g_synth;
  int entry = (registers->r[0] & 0xff);
  char *name = (char*)(registers->r[1]);
  int wave =  (registers->r[2] & 0x1ff);
  int cutoff = ((registers->r[3]) & 0xff00) >> 8;
  int resonance = ((registers->r[3]) & 0xff);
  int options = (registers->r[4] & 0xff00) >> 8;
  int steptime =  (registers->r[4] & 0xff);
  int asrStepsAttack = (registers->r[5] & 0xff0000) >> 16;
  int asrStepsSustain = (registers->r[5] & 0xff00) >> 8;
  int asrStepsRelease = (registers->r[5] & 0xff);
  int asrDeltaAttack = (registers->r[6] & 0xff0000) >> 16;
  int asrDeltaSustain = (registers->r[6] & 0xff00) >> 8;
  int asrDeltaRelease = (registers->r[6] & 0xff);
  int adsrDeltaAttack = (registers->r[7] & 0xff000000) >> 24;
  int adsrDeltaDecay = (registers->r[7] & 0x00ff0000) >> 16;
  int adsrDeltaSustain = (registers->r[7] & 0xff00) >> 8;
  int adsrDeltaRelease = (registers->r[7] & 0xff);
  INSTRUMENT_TABLE *instrument = (g_synth.m_instrument)+entry;

  if ((name != NULL) && (strlen(name) < 15))
  {
    strcpy(instrument->m_name, name);
  }

  instrument->m_wave = wave;
  instrument->m_options = options;
  instrument->m_steptime = steptime;
  instrument->m_cutoff = cutoff;
  instrument->m_res = resonance;
  instrument->m_asrStepsAttack = asrStepsAttack;
  instrument->m_asrStepsSustain = asrStepsSustain;
  instrument->m_asrStepsRelease = asrStepsRelease;
  instrument->m_asrAttackDelta =  ((signed char)asrDeltaAttack);
  instrument->m_asrSustainDelta = ((signed char)asrDeltaSustain);
  instrument->m_asrReleaseDelta = ((signed char)asrDeltaRelease);
  instrument->m_attack = adsrDeltaAttack;
  instrument->m_decay = adsrDeltaDecay;
  instrument->m_sustain = adsrDeltaSustain;
  instrument->m_release = adsrDeltaRelease;

}

void HandleRFX(_kernel_swi_regs *registers)
{
  if ((registers->r[0] >= 0) &&
      (registers->r[0] <= 15))
  {
    extern RISC_SYNTH g_synth;
    g_synth.m_effects.m_mode = registers->r[0];
  }
}

void HandleRFXMix(_kernel_swi_regs *registers)
{
  if ((registers->r[0] >= 1) &&
      (registers->r[0] <= 8))
  {
    extern RISC_SYNTH g_synth;
    g_synth.m_effectChannel[registers->r[0]-1] =
                                             registers->r[1];
  }
}

void HandleRDelay(_kernel_swi_regs *registers)
{
    extern RISC_SYNTH g_synth;

    if ((registers->r[0] < 147) && (registers->r[1] < 256))
    {
      g_synth.m_effects.m_delayLine.m_record = registers->r[0] * 441;
      g_synth.m_effects.m_delayLine.m_play = 0;
      g_synth.m_effects.m_delayLine.m_feedback = registers->r[1];
    }
}

int HandleRLoad(_kernel_swi_regs *registers)
{
  int error = 0;
  extern RISC_SYNTH g_synth;
  int sampleID = registers->r[0];
  char *wav_file = (char*)registers->r[1];
  int i;
  int found = 0;

  if (g_initialised == 0)
  {
    error = 1;
    return error;
  }

  // No channel must be playing when this function is called
  for (i = 0; i < 8; ++i)
  {
    if (g_synth.m_channel[i].m_adsr.m_stage !=  g_synth.m_channel[i].m_adsr.m_endState)
      found = 1;
  }
  if (found)
  {
    error = 1;
  }
  else
  {
    FILE *fptr;
    int length = 0;
    // Header for valid wave file RIFF<chunk size>Wavefmt,16 bit, mono,
    // 44khz
    unsigned char wave_header_44[] = {0x52,0x49,0x46,0x46,0x68,0x40,0x40,0x00,
                                       0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,
                                       0x12,0x00,0x00,0x00,0x01,0x00,0x01,0x00,
                                       0x44,0xac,0x00,0x00,0x88,0x58,0x01,0x00,
                                       0x02,0x00,0x10,0x00,0x00,0x00,0x64,0x61,
                                       0x74,0x61};

    // to scan with hex
    unsigned char wave_header_22[] = {0x52,0x49,0x46,0x46,0xf2,0x04,0x02,0x00,
                                       0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,
                                       0x12,0x00,0x00,0x00,0x01,0x00,0x01,0x00,
                                       0x22,0x56,0x00,0x00,0x88,0x58,0x01,0x00,
                                       0x02,0x00,0x10,0x00,0x00,0x00,0x64,0x61,
                                       0x74,0x61};

    #define VALID_HEADER_SIZE 42

    unsigned char wave_header[VALID_HEADER_SIZE];

    int result = 1;

    // verify file & header
    if ((fptr = fopen(wav_file, "rb")) == NULL)
    {
       result = 0;
       error = 1;
    }

    if (result == 1)
    {
		// read header (RIFF)
        result = 0;
        fread(wave_header, sizeof(unsigned char), 4, fptr);

        if ((memcmp(wave_header_44,
                                              wave_header,
                                              4) == 0))
        {
            result = 1;
        }

    }
    if (result == 1)
    {
        int i = 30;
		int founddata = 0;

		while ((i < 50) && (!founddata))
		{
    		char tmp_buffer[4] = {0};
			// try offset
			fseek(fptr, i, SEEK_SET);

			fread(tmp_buffer, 1, 4, fptr);

			if (strncmp(tmp_buffer, "data", 4) == 0)
			{
				founddata = 1;
			}

			i++;
		}

		if (founddata)
		{
	        // read header
		    fread(&length, sizeof(int), 1, fptr);
		}
		else
		{
			result = 0;
		}


    }


    // TODO If sample is not 44khz 16 bit then normalize on load
    //      i.e. convert to 16 bit 44khz (avoids complexity and processing
    //           later).

    if (result)
    {
      if (g_synth.m_sample[sampleID].m_data != NULL)
      {
        free(g_synth.m_sample[sampleID].m_data);
      }

      g_synth.m_sample[sampleID].m_data = (short*)malloc(length);
      g_synth.m_sample[sampleID].m_length = length / sizeof(short);
      if (g_synth.m_sample[sampleID].m_data == NULL)
      {
        error = 1;
      }
      else
      {

        fread(g_synth.m_sample[sampleID].m_data, sizeof(short),
              g_synth.m_sample[sampleID].m_length, fptr);

        g_synth.m_sample[sampleID].m_loop = 0;
        g_synth.m_sample[sampleID].m_loopBack = 0;
      }
    }
    // For now just report that the length could be read
    if (fptr != NULL)
        fclose(fptr);
  }

  return error;
}

void HandleRList()
{
  extern RISC_SYNTH g_synth;
  int i;

  // List all envelopes
  printf("number,name,wave,options,steptime,cut-off,res,steps,delta,attack,decay,sustain ,release\n");
  for (i = 0; i < 256; ++i)
  {
    if (strcmp(g_synth.m_instrument[i].m_name, "") != 0)
    {
      printf("%d, %s,%d,%d,%d,%d,%d,%d %d %d,%d %d %d,%d,%d,%d,%d\n",
      i,
      g_synth.m_instrument[i].m_name,
      g_synth.m_instrument[i].m_wave,
      g_synth.m_instrument[i].m_options,
      g_synth.m_instrument[i].m_steptime,
      g_synth.m_instrument[i].m_cutoff,
      g_synth.m_instrument[i].m_res,
      g_synth.m_instrument[i].m_asrStepsAttack,
      g_synth.m_instrument[i].m_asrStepsSustain,
      g_synth.m_instrument[i].m_asrStepsRelease,
      g_synth.m_instrument[i].m_asrAttackDelta,
      g_synth.m_instrument[i].m_asrSustainDelta,
      g_synth.m_instrument[i].m_asrReleaseDelta,
      g_synth.m_instrument[i].m_attack,
      g_synth.m_instrument[i].m_decay,
      g_synth.m_instrument[i].m_sustain,
      g_synth.m_instrument[i].m_release);
    }
  }
}

void HandleRVolume(_kernel_swi_regs *registers)
{
  extern RISC_SYNTH g_synth;

  g_synth.m_masterVolume = registers->r[0];
}

void HandleRSampleLoop(_kernel_swi_regs *registers)
{
  extern RISC_SYNTH g_synth;
  int sampleID = registers->r[0];
  int loopPoint = registers->r[1];
  int loopTo = registers->r[2];

  if ((loopTo < loopPoint) && (loopTo > 0) && (loopPoint > 0))
  {
    if (loopPoint <= g_synth.m_sample[sampleID].m_length)
    {
        g_synth.m_sample[sampleID].m_loop = loopPoint;
        g_synth.m_sample[sampleID].m_loopBack = loopTo;
    }
  }
}

void HandleRBell(_kernel_swi_regs *registers)
{
  extern RISC_SYNTH g_synth;

  // To turn off set bell to 0
  if (g_synth.m_sample[registers->r[0]].m_length != 0)
    g_bell = registers->r[0];

  if (registers->r[0] == 0)
    g_bell = 0;


}




// End SWI implementation


typedef enum
{
  RSTART = 0,
  RSTOP = 1,
  RFILTER = 2,
  RSOUND = 3,
  RENVELOPE = 4,
  RFXMIX = 5,
  RFX = 6,
  RDELAY = 7,
  RLOAD = 8,
  RVERBOSE = 9,
  RLEGACY = 10,
  RADVANCED = 11,
  RLIST = 12,
  RVOLUME = 13,
  RLISTEN = 14,
  RNOLISTEN = 15,
  RSAVE = 16,
  RCOMPRESSOR = 17,
  RSAMPLELOOP = 18,
  RBELL = 19,
  RPAN = 20,
  RDRIVE = 21,
  RCHORUS = 22,
  RUNKNOWN = 65
} STAR_COMMAND;

_kernel_oserror *rs_swi(int swi_no, _kernel_swi_regs *r, void *private_word)
{
  UNUSED(private_word);

  #define SWI_BASE 0x59B00
  switch (swi_no)
  {
    case (SWI_BASE + RSTART):
      HandleRStart();
      break;
    case (SWI_BASE + RSTOP):
      HandleRStop();
      break;
    case (SWI_BASE + RFILTER):
      HandleRFilter(r);
      break;
    case (SWI_BASE + RSOUND):
      HandleRSound(r);
      break;
    case (SWI_BASE + RENVELOPE):
      HandleREnvelope(r);
      break;
    case (SWI_BASE + RFXMIX):
      HandleRFXMix(r);
      break;
    case (SWI_BASE + RFX):
      HandleRFX(r);
      break;
    case (SWI_BASE + RDELAY):
      HandleRDelay(r);
      break;
    case (SWI_BASE + RLOAD):
      HandleRLoad(r);
      break;
    case (SWI_BASE + RVERBOSE):
      g_verbose = 1;
      break;
    case (SWI_BASE + RLEGACY):
      break;
    case (SWI_BASE + RADVANCED):
      break;
    case (SWI_BASE + RLIST):
      break;
    case (SWI_BASE + RVOLUME):
      HandleRVolume(r);
      break;
    case (SWI_BASE + RLISTEN):
      break;
    case (SWI_BASE + RNOLISTEN):
      break;
    case (SWI_BASE + RSAVE):
      break;
    case (SWI_BASE + RCOMPRESSOR):
      break;
    case (SWI_BASE + RPAN):
      break;
    case (SWI_BASE + RDRIVE):
      break;
    case (SWI_BASE + RCHORUS):
      break;
    default:
      break;

  };

  return 0;
}

typedef enum
{
  ERROR_NONE,
  ERROR_UNKNOWN_COMMAND,
  ERROR_MISSING_PARAMETER,
  ERROR_OUT_OF_RANGE
} COMMAND_ERROR;

// Command format table
typedef enum
{
  ET_STRING,
  ET_INTEGER,
  ET_HEX,
  ET_END
} ELEMENT_TYPE;

typedef struct
{
  ELEMENT_TYPE m_type;
  int          m_minRange;
  int          m_maxRange;
} COMMAND_PARAM;

#define MAX_COMMAND 256
#define MAX_PARAM   8
typedef struct
{
  char *m_name;
  STAR_COMMAND m_cmdid;
  COMMAND_PARAM m_param[9];
} COMMAND_STRUCT;

#define _EMPTY {ET_END, 0, 0}
#define _EMPTY_8 _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY
#define _EMPTY_2 _EMPTY, _EMPTY
#define _EMPTY_5 _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY
#define _EMPTY_6 _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY
#define _EMPTY_7 _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY, _EMPTY

COMMAND_STRUCT m_commands[] = {
  { "*rstart", RSTART, {{ET_END, 0,0}, _EMPTY_8}},
  { "*rstop", RSTOP, {{ET_END, 0,0}, _EMPTY_8}},
  { "*rfilter", RFILTER, {{ET_INTEGER, 1, 8}, {ET_INTEGER , 0, 255}, {ET_INTEGER, 0, 12}, _EMPTY_5}},
  { "*rsound", RSOUND, {{ET_INTEGER, 1, 8}, {ET_INTEGER, 0, 2}, {ET_STRING, 0, 0}, {ET_INTEGER, 0, 255 }, {ET_INTEGER, 0, 364}, {ET_INTEGER, 0, 0xffffff}, _EMPTY_2}},
  //                           Env No                 Name        wave       Cutoff-res
  { "*renvelope", RENVELOPE, {{ET_HEX, 0, 255}, {ET_STRING, 0,0}, {ET_HEX, 0, 0xff},  {ET_HEX, 0, 0xffff},
  //  options,ASR steptime       steptime          ASR steps
  {ET_HEX, 0, 0xffffff}, {ET_HEX, 0, 0xffffff},
  // ASR delta                ADSR
  {ET_HEX, 0, 0xffffff}, {ET_HEX, 0, 0}, _EMPTY}},
  { "*rfxmix", RFXMIX, {{ET_INTEGER, 1, 8}, {ET_INTEGER, 0, 1}, _EMPTY_7}},
  { "*rfx", RFX, {{ET_INTEGER, 1, 8}, _EMPTY_8}},
  { "*rdelay", RDELAY, {{ET_INTEGER, 0, 255}, {ET_INTEGER, 0, 255}, _EMPTY_7}},
  { "*rload", RLOAD, {{ET_INTEGER, 0,255}, {ET_STRING, 0,0}, _EMPTY_7}},
  { "*rverbose", RVERBOSE, {{ET_END, 0,0}, _EMPTY_8}},
  { "*rlegacy", RLEGACY, {{ET_END, 0,0}, _EMPTY_8}},
  { "*radvanced", RADVANCED, {{ET_END, 0,0}, _EMPTY_8}},
  { "*rlist", RLIST, {{ET_END, 0,0}, _EMPTY_8}},
  { "*rvolume", RVOLUME, {{ET_INTEGER, 0, 255}, _EMPTY_8}},
  { "*rlisten", RLISTEN, {{ET_INTEGER, 1, 32768}, _EMPTY_8}},
  { "*rnolisten", RNOLISTEN, {{ET_END, 0,0}, _EMPTY_8}},
  { "*rsave", RSAVE,  {{ET_STRING, 0, 0}, _EMPTY_8}},
  { "*rcompressor", RCOMPRESSOR, {{ET_INTEGER, 16, 256}, _EMPTY_8}},
  { "*rsampleloop", RSAMPLELOOP, {{ET_INTEGER, 0, 255}, {ET_INTEGER, 0,0xfffffff}, {ET_INTEGER, 0, 0xfffffff}, _EMPTY_6}},
  { "*rbell", RBELL, {{ET_INTEGER, 0, 255}, _EMPTY_8}},
  // Not implemented yet.

  { "*rpan", RPAN, {{ET_INTEGER, 1, 8}, {ET_INTEGER, -127, 128}, _EMPTY_7}},


  { "*rdrive", RDRIVE, {{ET_INTEGER, 0, 255}, {ET_INTEGER, 0, 64}, _EMPTY_7}},
  { "*rchorus", RCHORUS, {{ET_INTEGER, 0, 255}, {ET_INTEGER, 0, 255}, {ET_INTEGER, 0, 65}, _EMPTY_6}},
  { NULL, RUNKNOWN, {{ET_END, 0,0}, _EMPTY_8}}
};

COMMAND_ERROR GetCommand(int cmd_no, const char *arg_list,
                STAR_COMMAND *command,
                _kernel_swi_regs *regs)
{
  int i = 0;
  int found = 0;
  COMMAND_ERROR err = ERROR_UNKNOWN_COMMAND;
  char cmd_buffer[4096];
  char *cmdToken = cmd_buffer;

  // TODO size checks etc.
  cmd_buffer[0] = '\0';
  strcpy(cmd_buffer+1, arg_list);

   int j = 0;
   i = cmd_no;
   *command = m_commands[i].m_cmdid;
   err = ERROR_NONE;
   found = 1;
   while ((m_commands[i].m_param[j].m_type != ET_END) &&
          (err == ERROR_NONE) && j < 9)
   {
     switch (m_commands[i].m_param[j].m_type)
     {
         case ET_STRING:
             // workaround possibly strtok in GCC is broken
             // Will revise when I move to DDE
           cmdToken = strtok(cmdToken+strlen(cmdToken)+1, " \t\n");

           if (cmdToken == NULL)
             err = ERROR_MISSING_PARAMETER;
           else
             regs->r[j] =(int)cmdToken;
             break;
         case ET_INTEGER:
           cmdToken = strtok(cmdToken+strlen(cmdToken)+1, " \t\n");

           if (cmdToken == NULL)
             err = ERROR_MISSING_PARAMETER;
           else
           {
             int value = atoi(cmdToken);
             if (((value < m_commands[i].m_param[j].m_minRange) ||
                  (value > m_commands[i].m_param[j].m_maxRange)) &&
                  (m_commands[i].m_param[j].m_maxRange !=
                   m_commands[i].m_param[j].m_minRange))
             {
               err = ERROR_OUT_OF_RANGE;
             }
             else
               regs->r[j] =value;
           }
           break;
         case ET_HEX:
           cmdToken = strtok(cmdToken+strlen(cmdToken)+1, " \t\n");

           if (cmdToken == NULL)
             err = ERROR_MISSING_PARAMETER;
           else
           {
             int value = 0;
             sscanf(cmdToken, "%x", &value);

             if (((value < m_commands[i].m_param[j].m_minRange) ||
                  (value > m_commands[i].m_param[j].m_maxRange)) &&
                  (m_commands[i].m_param[j].m_maxRange !=
                   m_commands[i].m_param[j].m_minRange))
             {
               err = ERROR_OUT_OF_RANGE;
             }
             else
               regs->r[j] =value;
           }
           break;
         default:
       //  printf("default %d\n, ", m_commands[i].m_param[j].m_type);
           break;
        }
        ++j;
      }


  return err;
}


int snd = 0;
long store[4] = {0};

_kernel_oserror *rs_cmd(const char *arg_string, int argc, int cmd_no, void *pw)
{
    COMMAND_ERROR error = ERROR_UNKNOWN_COMMAND;
    STAR_COMMAND command;
    _kernel_swi_regs regs;
    const char *s = arg_string;
    int i;
    UNUSED(pw);

    error = GetCommand(cmd_no, arg_string, &command, &regs);

    // TODO: Try populating kernel error and see what appears on screen
    if (g_verbose)
    {
      switch (error)
      {
         case ERROR_NONE:
          break;
        case ERROR_UNKNOWN_COMMAND:
          printf("Command not implemented\n");
          break;
        case ERROR_MISSING_PARAMETER:
          printf("Missing Parameter\n");
          break;
        case ERROR_OUT_OF_RANGE:
          printf("Parameter value out of range\n");
          break;
        default:
          break;

      }
    }

   {
     extern RISC_SYNTH g_synth;
    // printf("debug = %d\n", g_synth.debug);
     }
     // Next can call SWI implementation
    switch (command)
    {
      case RSTART:
        HandleRStart();
        break;
      case RSTOP:
        HandleRStop();
        break;
      case RSOUND:
        HandleRSound(&regs);
        break;
      case RFILTER:
        HandleRFilter(&regs);
        break;
      case RENVELOPE:
        HandleREnvelope(&regs);
        break;
      case RFX:
        HandleRFX(&regs);
        break;
      case RFXMIX:
        HandleRFXMix(&regs);
        break;
      case RPAN:
        // TODO
        break;
      case RDELAY:
        HandleRDelay(&regs);
        break;
      case RLOAD:
      {
        int error =  HandleRLoad(&regs);
        if (g_verbose)
        {
          if (error == 0)
            printf("Sample loaded successfully");
          else
            printf("Sample load failed\n");
        }
        break;
      }
      case RVERBOSE:
        g_verbose = 1;
        break;
      case RLEGACY:
        printf("Legacy mode is not support in this RDSP release.\n");
        break;
      case RADVANCED:
        g_legacy = 0;
        break;
      case RLIST:
        HandleRList();
        break;
      case RVOLUME:
        HandleRVolume(&regs);
        break;
      case RSAMPLELOOP:
        HandleRSampleLoop(&regs);
        break;
      case RBELL:
        HandleRBell(&regs);
      default:
        break;

    }

    return 0;
}

void rs_service(int service_number, _kernel_swi_regs *regs, void *private_word)
{
    UNUSED(private_word);
/*
 *  In general, it is a Bad Thing to use printf inside an arbitrary
 *  service call handler (e.g. in one that catches errors - call 6 -
 *  as this one does. Therefore we merely count what's happening and
 * print it out when the TestCModule's SWI is called.
 */
    if (service_number == UNKNOWN_CMD_SERVICE)
        ++unknown_cmd_count;
    else
      ++other_service_call_count;

    if (regs->r[1] == 8)
    {
      if (regs->r[2] == 8)
      {
        snd++;
        store[0] = ((unsigned char*)regs->r[3])[0];
        store[1] = ((unsigned char*)regs->r[3])[1];
        store[2] = ((unsigned char*)regs->r[3])[2];
      }
    }
}

_kernel_oserror *rs_initialise(const char *cmd_tail, int podule_base, void *private_word)
{
    _kernel_swi_regs regs;
    UNUSED(cmd_tail);
    UNUSED(podule_base);
    //    UNUSED(private_word);

 // Now claim OS WORD 7. Vector is 7 for OS WORD itself
	regs.r[0] = 7;
	regs.r[1] = (int)&rosesound_entry;
	regs.r[2] = (int)private_word;
 	_kernel_swi(OS_Claim,&regs,&regs);

    unknown_cmd_count = other_service_call_count = 0;
    return NULL;
}

_kernel_oserror *rs_finalise(int fatal, int podule_base, void *private_word)
{
    _kernel_swi_regs regs;
    UNUSED(fatal);
    UNUSED(podule_base);
    //    UNUSED(private_word);

 // Now claim OS WORD 7. Vector is 7 for OS WORD itself
	regs.r[0] = 7;
	regs.r[1] = (int)&rosesound_entry;
	regs.r[2] = (int)private_word;
 	_kernel_swi(OS_Release,&regs,&regs);

    // Unloading force refcount to 0
    g_verbose = 0;
    rstart_refcount = 0;
    HandleRStop();

    unknown_cmd_count = other_service_call_count = 0;
    return NULL;
}

// Handler for OS_WORD 7 & 8
int rosesound_handler( _kernel_swi_regs *r, void *pw)
{


  if (r->r[0] == 7)
  {
      int frequency = 0;
      int amplitude = 0;
      int wave = 0;
      int bellon = 0;
      _kernel_swi_regs regs;
      char wavestr[255];
      unsigned char *paramBlock = (unsigned char*)(r->r[1]);
      wavestr[0] = 0;
      // Raise this on a forum thread for discussion on ROOL tomorrow.

      // LSB MSB - sound uses 16 bit values
      // As per Rick's post
      // Make semi-backwards compatible
      // channel flags wave/instrument volume pitch duration


      //
      // pitch can go through all values - If you Start at &0100 you get full
      // range
      // Duration is up to 65536
      //
      // Samples can be indexed by negative pitches
      // So the wave parameter becomes the sample number selector
      // i.e. SOUND &21, &00FF, 100, 100
      // Plays sample 0 at pitch 1 for 1 second
      // To play instrument 1 on channel 1 I can split the last byte
      // So volume can be 16 value logarithmic for negative numbers
      // If TT = 255 Then treat this as square wave for legacy VDU 7 etc
      // SOUND <PFSC>,<TTVV>, <IRNN>, <Duration>
      // P = Pan
      // F = flags &10 = Sync, &20 = mute, &40 = xor
      // S = sound &00 = wave &10 = Envelop, &20 = Sample,
      // I = cutoff (if zero then this is open as optional) bits 16,15,14,13
      // R = resonance bits (12,11,10)
      // N = note bits 1 to 9

      //   n.b. This allows The sample to be used for an instrument
      //        i.e. The sample will loop over the ADSR.
      // C = Channel &01 to &08
      // TT = Tone = Wave, Sample number or instrument
      // VV = volume
      //
      // n.b. revise *RLOAD to <filename> <instrument name> <loop point> <slot>
      // *RLEGACY will set pitch range to start at BBC Micro range
      //          and map envelope parameters to legacy parameters.

    amplitude = paramBlock[2];

    if (paramBlock[0] & 0x20)
    {
      wave = (((int)paramBlock[3]) + 256) & 0x1ff;
      sprintf(wavestr, "%d", wave);
    }
    else
    if (paramBlock[0] & 0x10)
    {
      extern RISC_SYNTH g_synth;

      strcpy(wavestr, g_synth.m_instrument[paramBlock[3]&0xff].m_name);
    }
    else
    {
       // If SOUND channel,-15
       // default to square wave
      if (paramBlock[3] == 0xff)
      {
        // Unless bell override is active
        if (g_bell && (paramBlock[0] == 1) && (paramBlock[4] == 100))
        {
          sprintf(wavestr, "%d", g_bell+0x100);
          bellon = 1;
        }
        else
          strcpy(wavestr, "31");

      }
      // If wave field is set to zero use amplitude field as envelope selector
      // and set amplitude to 0xff
      else if ((paramBlock[3] == 0x00) && (paramBlock[2] > 0))
      {
        strcpy(wavestr, g_synth.m_instrument[paramBlock[2]&0xff].m_name);
        amplitude = 0xff;
      }
      else
         sprintf(wavestr, "%d", paramBlock[3]);



       if ((paramBlock[3] == 0xff) && (paramBlock[2] > 0xf0))
       {
         amplitude = 255 - (((paramBlock[2] & 0x0f)-1) * 0x10);
       }
    }

    // Channel 0 through the SOUND command will map to noise.
    // and choose a matching noise
    if ((paramBlock[0] & 0x0f) == 0)
    {
      int table[] = {212, 164,116,0};
      if ((paramBlock[4] & 0x7) < 4)
      {
        strcpy(wavestr, "8");

      }
      else
      {
        strcpy(wavestr, "128");
      }
      if ((paramBlock[4] & 3) < 3)
      {
        frequency = table[paramBlock[4] & 3];
      }
      else
      {
        // Sync to channel 1
        frequency =g_synth.m_channel[0].m_tone;
      }
    }
    else
    {
      frequency = ((int)paramBlock[4]) | (((int)(paramBlock[5]&1)) << 8);
    }

    regs.r[0] = paramBlock[0] & 0x0f;
    regs.r[1] = (paramBlock[1] & 0x0f) << 4;
    regs.r[2] = (int)wavestr;
    regs.r[3] = amplitude;
    // TODO: Consider mapping 255 to 2^31 (i.e. 68 years)
    // TODO: How do I get a module to respond to <interrupt>
    // As per BBC sound command - duration is in 20ths of a second.
    if (bellon)
    {
      regs.r[4] = 208;
      regs.r[5] = g_synth.m_sample[g_bell].m_length / 441;
    }
    else
    {
      regs.r[4] = frequency;
      regs.r[5] = ((int)paramBlock[6]) | (((int)paramBlock[7]) << 8) * 5;
    }

    {
      // Not sure if linear is better.
      int cutoffvalue[] = {255,2,3,4,6,8,11,16,23,32,45,64,90,128,181,255};
      int resvalue[] = {0,2,4,6,7,8,10,12};
      int cutoff = cutoffvalue[(paramBlock[5]&0xf0)>>4];
      int res = resvalue[(paramBlock[5]&0x0e) >> 1];
      _kernel_swi_regs filterParam;

      filterParam.r[0] = paramBlock[0] & 0x0f;
      filterParam.r[1] = cutoff;
      filterParam.r[2] = res;
      HandleRFilter(&filterParam);
    }

    if (strcmp(wavestr, "") != 0)
      HandleRSound(&regs);


    return 0;
    }

    // OS Word 8 - for the new envelope model and not
    //             for the legacy mode option
    //             <env-number 7 bit. bit 8=0 wave, 1 sample> <wave>
    //             <cutoff |resonance> <options)
    //        <ASR steptime>
    //        <ASR steps section 2>
    //        <ASR steps section 1 & 3>
    //        <ASR delta-attack>
    //        <ASR delta-sustain>
    //        <ASR delta-release>
    //               <Attack> <Decay> <sustain> <release>
    // To fit this in the BASIC command I will trade off some flexibility
    // cut off resonance can be reduced to 4 bit values
    //

    // Just realised. I could make the ADSR proportional to the sound call
    // So ADSR are fractions of total (A+D+S+R) and the duration parameter will
    // do something.
    if (r->r[0] == 8)
    {
 //       if (g_legacy == 0)
        {
          _kernel_swi_regs regs;
          unsigned char *paramBlock = (unsigned char*)(r->r[1]);
          int i;
          char name[255];
          // User just needs to know this is a range of min to max
          // 1.414 ^ n
          int cutoffvalue[] = {1,2,3,4,6,8,11,16,23,32,45,64,90,128,181,255};

          // Could consider an offset value somewhere?
          //

          int cutoff, resonance;
          int options, steptime;
          int attack, decay, sustain, release;
          int adr1step, adr2step, adr3step;
          int adr1delta, adr2delta, adr3delta;
          //for (i = 0; i < 14; ++i)
          //printf("param block = %d = %d", i, paramBlock[i]);
          //printf("\n");

          sprintf(name, "envelope%d", paramBlock[0]);

          cutoff = cutoffvalue[((paramBlock[2] & 0xf0) >> 4)];
          resonance = paramBlock[2] & 0x0f;

          options = paramBlock[3];
          steptime = paramBlock[4];

          adr1step = paramBlock[5];
          adr2step = paramBlock[6];
          adr3step = paramBlock[5];
          adr1delta = paramBlock[7];
          adr2delta = paramBlock[8];
          adr3delta = paramBlock[9];

          attack = paramBlock[10];
          decay = paramBlock[11];
          sustain = paramBlock[12];
          release = paramBlock[13];

          regs.r[0] = (paramBlock[0] & 0x7F);
          regs.r[1] = (int)name;
          regs.r[2] = (int)(paramBlock[1]) + ((((int)paramBlock[0]) & 0x80)<<1) ;

          regs.r[3] = (cutoff << 8) | resonance;
          regs.r[4] = ((int)(options << 8)) | (int)steptime;
          regs.r[5] = (adr1step << 16) | (adr2step << 8) | adr1step;
          regs.r[6] = (adr1delta << 16) | (adr2delta << 8) | adr3delta;
          regs.r[7] = (attack << 24) | (decay << 16) | (sustain << 8) | release;
          HandleREnvelope(&regs);
        }
//        else
  /*      {
          // I need to re-interpret further - so do not deliver legacy
          // mode in 1st release of alpha.
          //
          extern RISC_SYNTH g_synth;
          unsigned char *paramBlock = (unsigned char*)(r->r[1]);
          INSTRUMENT_TABLE *instrument = (g_synth.m_instrument)+paramBlock[0];
          int i;
          char name[255];

          int steptime;
          int options = 0;
          int attack, decay, sustain, release;
          int adr1step, adr2step, adr3step;
          int adr1delta, adr2delta, adr3delta;

          sprintf(name, "envelope%d", paramBlock[0]);

          if (paramBlock[1] & 128)
            options = 0;
          else
            options = 0x80;

          // Legacy mode locks the 3 stage envelope to pitch
          options += 0x10;

          steptime = paramBlock[1] & 0x7f;

          if ((name != NULL) && (strlen(name) < 15))
          {
            strcpy(instrument->m_name, name);
          }

          instrument->m_wave = 0x1f;
          instrument->m_options = options;
          instrument->m_steptime = steptime;
          instrument->m_cutoff = 255;
          instrument->m_res = 0;

          adr1step = paramBlock[5];
          adr2step = paramBlock[6];
          adr3step = paramBlock[7];
          adr1delta = paramBlock[2];
          adr2delta = paramBlock[3];
          adr3delta = paramBlock[4];

          instrument->m_asrStepsAttack = paramBlock[5];
          instrument->m_asrStepsSustain = paramBlock[6];
          instrument->m_asrStepsRelease = paramBlock[7];
          instrument->m_asrAttackDelta =  ((signed char)paramBlock[2]);
          instrument->m_asrSustainDelta = ((signed char)paramBlock[3]);
          instrument->m_asrReleaseDelta = ((signed char)paramBlock[4]);
          instrument->m_attack  = (unsigned char)paramBlock[12];
          instrument->m_decay   = (unsigned char)paramBlock[13];
          instrument->m_sustain = 0x80;
          instrument->m_release = ((signed char)paramBlock[11]);

        }*/
    }
  return 1;
}



