#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "kernel.h"
//
#include "os.h"
//
#include "proto.h"
#include "instrument.h"
#include "externsnd.h"
#include "midi.h"
#include "mcode.h"

// this source file handles the API for creating external voice generators


static _kernel_oserror err_too_many_voice_generators = { 1, "Too many voice generators"};
static _kernel_oserror err_failed_to_install = { 1, "Failed to install voice generator"};


typedef struct GENERATORINFO {
  SAMPLEINDEX si;
  unsigned int banki, programi;
} GENERATORINFO;

static VOICEGENERATOR *generators[MAXGENERATORS];
static GENERATORINFO info[MAXGENERATORS];

static void remove_voice_generator(int i);



void externalsnd_initialise() {

  int i;

  for (i = 0; i < MAXGENERATORS; i++)   generators[i] = NULL;
}


void externalsnd_kill() {

  int i;

  for (i = 0; i < MAXGENERATORS; i++)
    if (generators[i])  remove_voice_generator(i);
}



_kernel_oserror *externalsnd_install(unsigned int banki, unsigned int programi, VOICEGENERATOR *vg, char *name) {

  int i, unused;
  SAMPLEINDEX si;
  SAMPLEDATA *sampledata;

  unused = -1;
  for (i = 0; (i < MAXGENERATORS) && (unused == -1); i++)
    if (!generators[i])   unused = i;
  if (unused == -1)              return &err_too_many_voice_generators;

  si = instruments_new_sample(name, INFINITE_LENGTH, 1, 0, SOURCE_VOICE_GENERATOR);
  if (si == ILLEGAL_SAMPLE)      return &err_failed_to_install;
  sampledata = instruments_get_sample_ptr(si);
  if (!sampledata)               return &err_failed_to_install;
  sampledata->sampledata.voice = vg;
  if (vg->flags.monophonic)   sampledata->flags.monophonic = 1;

  instruments_map(si, banki, programi, ALL_OCTAVES, vg->frequency);
  instruments_set_patch_name(banki, programi, name);
  generators[unused] = vg;
  info[unused].si = si;
  info[unused].banki = banki;
  info[unused].programi = programi;

  return NULL;
}


_kernel_oserror *externalsnd_remove(VOICEGENERATOR *vg) {

  int i;

  for (i = 0; i < MAXGENERATORS; i++)
    if (generators[i] == vg)   remove_voice_generator(i);

  return NULL;
}


// --------------------------------------------------------------

void remove_voice_generator(int i) {

  instruments_unmap(info[i].banki, info[i].programi, ALL_OCTAVES);
  instruments_remove_sample(info[i].si);
  generators[i] = NULL;
}
