/* BASSLINE - creates a bass line. Uses an array of chord structs accessed *
externally. Receives the start time, index of current chord, and tempo. *
Gets chord and calls strum func for each beat (determined by SR, tempo *
instrument dur.

Veronica Morales 8/01
*/


#include <stdlib.h>
#include <iostream.h>
#include <stdio.h>
#include <ugens.h>
#include <mixerr.h>
#include <Instrument.h>
#include "BASSLINE.h"
#include <rt.h>
#include <rtdefs.h>
#include <globals.h>

strumq *curstrumq[6];

//struct list of current chords....
extern struct chord curchord[MAXCHORDS];

extern "C" {

void sset(float, float, float, strumq*);
void randfill(float, int, strumq*);
void filefill(float, int, strumq*);
float strum(float, strumq*);
float getnextpitch(int, int);

}

BASSLINE::BASSLINE() : Instrument()
{

in = NULL;

}

BASSLINE::~BASSLINE()
{

if (deleteflag == 1) {
delete strumq1;

}

}

// BASSLINE - requires randomvalues.dat to be in the same folder
//
// p0 = start; p2 = chordindex; p3 = tempo
//--------------------------------------------------------------

int BASSLINE::init(float p[], int n_args)
{

float outskip, dur;
float eight = 0.5, whole = 4.0, half = 2.0, quarter = 1.0;
int tempo;

//STRUM values here
fdecay = .50; // strum fundamental decay
nydecay = 0.1; // strum Nyquist decay
amp = 40000; // amplitude
squish = 1; // squish
spread = 0.5; // stereo spread
deleteflag = 1; // delete flag - see strum

//BASSLINE values here...
outskip = p[0]; // start time for instrument
chordindex = (int)p[1]; // index for array of struct chords
tempo = (int)p[2]; // tempo

// if tempo is 120 beats/min, then tempo is also
// 120/60 beats/sec. Hence, to get a proper
// interval, need to change it when tempo changes.

SRdivisor = tempo/60;

dur = 60.0/tempo; // duration of play
j = 0;

// grab chord duration from array
chordtime = (int)curchord[chordindex].dur;

// rtcmix stuff
rtsetoutput(outskip, chordtime*dur, this);
strumq1 = new strumq;
curstrumq[0] = strumq1;

//get freq of chord root pitch
freq = cpspch( (curchord[chordindex].root * 0.01) - 1.0 );
sset(freq, fdecay, nydecay, strumq1);
filefill(amp, squish, strumq1);

amptable = floc(1);

if (amptable) {

int amplen = fsize(1);
tableset(dur, amplen, amptabs);

}
else

advise("BASSLINE", "Setting phrase curve to all 1's.");

skip = (int)(SR / (float)resetval);

return(nsamps);

} //end init

int BASSLINE::run()
{

int i, branch, rsamps;
float aamp, out[2];

Instrument::run();

aamp = 1.0; /* in case amptable == NULL */
branch = 0;

interval = (int)(SR/SRdivisor);

for (i = 0; i < chunksamps; i++) {

if (--branch < 0) {

if (amptable)

aamp = tablei(cursamp, amptable, amptabs);

branch = skip;

}
out[0] = strum(0, strumq1) * aamp;

if(cursamp % interval == 0){

if(cursamp == 0){

//get new frequency.....
octpitch = getnextpitch(chordindex, j);
freq = cpspch( octpitch-2.0 );
j++; //increment j for next chord pitch

}
else{

octpitch = getnextpitch(chordindex, j);
freq = cpspch( octpitch-2.0 );
j++; //increment j for next chord pitch
if (j == 4)
j = 0;

}

//strum stuff........
sset(freq, fdecay, nydecay, strumq1);
filefill(amp, squish, strumq1);

} //end if

if (outputchans == 2) { /* split stereo files between the channels */

out[1] = (1.0 - spread) * out[0];
out[0] *= spread;

}
rtaddout(out);
cursamp++;

}//end for...chunksamps

return i;

}//end run

Instrument*
makeBASSLINE()
{

BASSLINE *inst;

inst = new BASSLINE();
inst->set_bus_config("BASSLINE");

return inst;

}