/* Freebirth
 * Copyright (C) 1999 topher lafata <topher@topher.com>,
 *		      Jake Donham <jake@bitmechanic.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */



#include "delay.h"
#include <stdlib.h>
#include <string.h>

#define SAMPLE_RATE 44100

void delay_next_buffer(delay *this)
{
  this->next = 1;
}

sample *delay_get_buffer(delay *this)
{
  int i;
  
  sample *i_buf;

  if (this->delay_size == 0)/*pass the signal through */
    return this->input->get_buffer(this->input);

  if (this->next) {
    this->next = 0;
    i_buf = this->input->get_buffer(this->input);
    for(i = 0; i < TBASS_BUFF_SIZE;i++)
      {
	sample s;
	if(this->d_index >= this->delay_size)
	  this->d_index = 0;
      
	this->buffer[i] = this->delay_buffer[this->d_index];
	s = i_buf[i] + (long)this->delay_buffer[this->d_index] * 
	  this->feedback / MAX_FEEDBACK;
	this->delay_buffer[this->d_index] = s;
	this->d_index++;
      }
  }

  return this->buffer;
}

void delay_set_time(delay *this,double delay_time_milli)
{

  this->delay_time_milli = delay_time_milli;
  this->delay_size = delay_time_milli * SAMPLE_RATE / 1000;
  if(this->delay_size > this->biggest_size)
    {

       this->delay_buffer = realloc(this->delay_buffer,sizeof(sample) * 
				   this->delay_size);
      memset(this->delay_buffer + this->biggest_size,
	     0,sizeof(sample) * (this->delay_size - this->biggest_size));
      this->biggest_size = this->delay_size;
    }
}

void delay_set_feedback(delay *this,int feedback)
{
  this->feedback = feedback;
}



static sample_producer **get_children(delay *this)
{
  return &(this->input);
}

static char **get_header(delay *this)
{
  static char *header[] = {
    "int $n_i = ((delay *)$t)->d_index;",
    "int $n_size = ((delay *)$t)->delay_size;",
    "int $n_feedback = ((delay *)$t)->feedback;",
    "sample *$n_buf = ((delay *)$t)->delay_buffer;",
    NULL
  };
  return header;
}

static char **get_code(delay *this)
{
  static char *code[] = {
    "if ($n_i >= $n_size)",
    "  $n_i = 0;",
    "$o = $n_buf[$n_i];",
    "$n_buf[$n_i] = $i0 + $n_buf[$n_i] * $n_feedback / MAX_FEEDBACK;",
    "$n_i++;",
    NULL
  };
  return code;
}

static char **get_footer(delay *this)
{
  static char *footer[] = {
    "((delay *)$t)->d_index = $n_i;",
    NULL
  };
  return footer;
}

delay *delay_new(double delay_time_milli,int feedback, sample_producer *input)
{
  delay *out = (delay *)malloc(sizeof(delay));
  
  out->get_buffer       = delay_get_buffer;
  out->next_buffer      = delay_next_buffer;
  out->get_children	= get_children;
  out->get_header	= get_header;
  out->get_code		= get_code;
  out->get_footer	= get_footer;
  out->next = 0;
  out->input            = input;
  out->unused		= NULL;
  out->feedback         = feedback;
  out->delay_time_milli = delay_time_milli;
  out->delay_size       = delay_time_milli * SAMPLE_RATE / 1000;



  out->delay_buffer     = (sample  *)malloc(sizeof(sample)*out->delay_size);
  memset(out->delay_buffer,0,sizeof(sample)*out->delay_size);
  out->buffer           = (sample *)malloc(sizeof(sample) * TBASS_BUFF_SIZE);
  memset(out->buffer,0,sizeof(sample) * TBASS_BUFF_SIZE);
  out->d_index          = 0;
  out->biggest_size = out->delay_size; 
  return out;
}

/*
  Local Variables:
  mode: font-lock
  End:
*/
