/* FFTBASS */
#include <iostream.h>
/* needed only for cout, etc. if you want it */
#include <stdio.h>
#include <stdlib.h>
#include <ugens.h>
#include <math.h>
#include <mixerr.h>
#include <Instrument.h> /* the base class for this
instrument */
#include "FFTBASS.h" /* declarations for this
instrument class */
#include <rt.h>
#include <rtdefs.h>
#include <globals.h>
/* now problem
is that for >1 chan scan, hist will show || of all channels */
/* ok-->that's not a bug, it's a feature! */
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include "../H/complexf.h"
#include "../H/byte_routines.h"
#include "../H/sfheader.h"
#include <sndlibsupport.h>
SFHEADER sfh;
int bytestoread;
extern int swap; /* defined in sys/check_byte_order.c */
struct FFTBASSFACT
{
float freq;
float mag;
};
//the STRUM
queue
strumq *curstrumq[6];
extern "C"{
void sset(float, float, float, strumq*);
void randfill(float, int, strumq*);
void filefill(float, int, strumq*);
float strum(float, strumq*);
int fft(long, long, complex[]);
}
/* Construct
an instance of this instrument and initialize some variables. */
FFTBASS :: FFTBASS() : Instrument()
{
in = NULL;
branch = 0;
first = 1;
}
/*
Destruct an instance of this instrument, freeing memory for the
input buffer.
*/
FFTBASS :: ~FFTBASS()
{
if (deleteflag == 1) {
delete strumq1;
}
delete [] in;
}
// FFTBASS
- requires randomvalues.dat to be in the same folder
//
// p0 = start; p1 = dur; p2 = amp; p3(optional) = inchan; p4(optional) = spread
//--------------------------------------------------------------
int FFTBASS :: init(float p[], int n_args)
{
float outskip, inskip, dur;
outskip = p[0];
inskip = 0;
dur = p[1];
amp = p[2];/* Here's how to handle optional pfields: */
inchan = n_args > 4 ? (int) p[3] : 0; /* default is chan 0 */
pctleft = n_args > 5 ? p[4] : 0.5; /* default is .5 *///STRUM values here
fdecay = .50; // strum fundamental decay
nydecay = 0.1; // strum Nyquist decay
amp = 1; // amplitude
squish = 1; // squish
spread = 0.5; // stereo spread
deleteflag = 1; // delete flag - see strum
nsamps = rtsetoutput(outskip, dur, this);chordtime = 2.0;
//set up strum queue
strumq1 = new strumq;
curstrumq[0] = strumq1;/* Set file pointer on audio input. */
rtsetinput(inskip, this);if (inchan >= inputchans)
die("FFTBASS", "You asked for channel %d of a %d-channel file.",
inchan, inputchans);amparray = floc(1);
if (amparray) {int lenamp = fsize(1);
tableset(dur, lenamp, amptabs);}
elseadvise("FFTBASS", "Setting phrase curve to all 1's.");
/* Set control rate counter. */
skip = (int) (SR / (float) resetval);
samps = SR*.5/2;
return nsamps;
}
/* Called by the scheduler for every time slice in which
this instrument
should run. This is where the real work of the instrument is done.
*/
int FFTBASS :: run()
{
int i, k;
float aamp, insig;
float out[2]; /* Space for only 2 output chans! */
float end = 0; /* assume channel 0 */
int incr = RTBUFSAMPS; /* must be a power of 2 */
float *fpoint, aver, *xpoint;
int channel = (int)end + .01;
int size;
int j,jj = 0;
float output[131072];
complex s[131072];
int tempo = 120;
float peak = 0;
float nstars = 40.;
float currout=0;
struct FFTBASSFACT maxes[4]={{0,0},{0,0},{0,0},{0,0}};
if (in == NULL)
in = new float [RTBUFSAMPS * inputchans];
Instrument::run();
for (k = 0; k < chunksamps; k += inputchans) {if(cursamp%samps == 0)
{rtgetin(in, this, samps);
aamp = amp; /* in case amparray == NULL */
// synchronization will be a problem. Should sample often
// and store freqs then decide on bassline based on stored freqs.
// so samps will be a lot smaller and may have to output some zeros
// in between.
fpoint = in;
size = 8192; // hard code for now
/* next is excerpt from sortout(buffer, size, end); */
for (i = 0, j = channel, aver = 0; i < size; i++, j += inputchans)aver += fpoint[i] = fpoint[j];
aver /= (float)size;
printf("size = %i, aver = %f\n", size, aver);
for (i = 0; i < size; i++)fpoint[i] -= aver; /* takes out DC bias */
xpoint = (float *)fpoint;
for (jj = 0; jj < size; jj++)
{s[jj].re = xpoint[jj]; /* sets up array of complex numbers */
s[jj].im = 0;}
fft(1, size, s);
for (jj = 0; jj < size; jj++)output[jj] = s[jj].re;
for (i = 0; i < size / 2; i++)
if (output[i] > peak)
peak = output[i];
for (i = 0; i < size / 2; i++) {currout = (nstars * output[i] / peak);
if(currout>maxes[3].mag)
{maxes[0]=maxes[1];
maxes[1]=maxes[2];
maxes[2]=maxes[3];
maxes[3].mag=currout;
maxes[3].freq= SR * (float)i / (float)size;
}else if(currout>maxes[2].mag)
{maxes[0]=maxes[1];
maxes[1]=maxes[2];
maxes[2].mag=currout;
maxes[2].freq= SR * (float)i / (float)size;}
else if(currout>maxes[1].mag)
{maxes[0]=maxes[1];
maxes[1].mag=currout;
maxes[1].freq=SR * (float)i / (float)size;}
else if(currout>maxes[0].mag)
{maxes[0].mag=currout;
maxes[0].freq=SR * (float)i / (float)size;}
}
for(j=0;j<4;++j){printf("\n%6.0f %6.0f ", maxes[j].freq, maxes[j].mag);
//check the values here. The first freq reported greater than 100
//appears to be the fundamental
if( (maxes[j].mag == 40)&&(maxes[j].freq > 100)){//if it is the first time that this value is found, save it as the fund freq
if(first){
freq = maxes[j].freq;
first = 0;}
}
}
printf("\n");
}//end if(cursamp.....//strum stuff........
interval = (int)(SR/chordtime)*(dur);
if( (cursamp % interval == 0)&&(freq > 100.0)){sset(freq, fdecay, nydecay, strumq1);
filefill(amp, squish, strumq1);
printf("Counter: %d\n", counter++);}
if (--branch < 0) {if (amparray)
aamp = tablei(cursamp, amparray, amptabs) * amp;
branch = skip;
}
/* Grab the current input sample, scaled by the amplitude multiplier. */
insig = in[k + inchan] * aamp;
/* Just copy it to the output array with no processing. */
out[0] = strum(0, strumq1) * aamp;if (outputchans == 2) {
out[1] = out[0] * (1.0 - pctleft);
out[0] *= pctleft;}
rtaddout(out);
cursamp++;}//end big for loop..........
return chunksamps;
}
/* The scheduler calls this to create an instance of this
instrument,
and to set up the bus-routing fields in the base Instrument class.
This happens for every "note" in a score.
*/
Instrument *makeFFTBASS()
{
FFTBASS *inst;
inst = new FFTBASS();
inst->set_bus_config("FFTBASS");return inst;
}