#include < libc.h>
#include < iostream.h>
#include < fstream.h>
#include < stdio.h>
#define SRATE 8192
#define DOUBLE_TO_SHORT(x) ((int)((x)*32768.0))
#define MAX(x,y) (x> y)?x:y
typedef struct _DelayLine {
short *data;
int length;
short *pointer;
short *end;
} DelayLine;
static DelayLine *initDelayLine(int len) {
DelayLine *dl = (DelayLine *)calloc(len, sizeof(DelayLine));
dl-> length = len;
if (len > 0)
dl-> data = (short *)calloc(len, len * sizeof(short));
else
dl-> data = 0;
dl-> pointer = dl-> data;
dl-> end = dl-> data + len - 1;
return dl;
}
static void freeDelayLine(DelayLine *dl) {
if (dl && dl-> data)
free(dl-> data);
dl-> data = 0;
free(dl);
}
inline static void setDelayLine(DelayLine *dl, double *values, double scale) {
int i;
for (i=0; i< dl-> length; i++)
dl-> data[i] = DOUBLE_TO_SHORT(scale * values[i]);
}
/* lg_dl_update(dl, insamp);
* Places "nut-reflected" sample from upper delay-line into
* current lower delay-line pointer location (which represents
* x = 0 position). The pointer is then incremented (i.e. the
* wave travels one sample to the left), turning the previous
* position into an "effective" x = L position for the next
* iteration.
*/
static inline void lg_dl_update(DelayLine *dl, short insamp) {
register short *ptr = dl-> pointer;
*ptr = insamp;
ptr++;
if (ptr > dl-> end)
ptr = dl-> data;
dl-> pointer = ptr;
}
/* rg_dl_update(dl, insamp);
* Decrements current upper delay-line pointer position (i.e.
* the wave travels one sample to the right), moving it to the
* "effective" x = 0 position for the next iteration. The
* "bridge-reflected" sample from lower delay-line is then placed
* into this position.
*/
static inline void rg_dl_update(DelayLine *dl, short insamp) {
register short *ptr = dl-> pointer;
ptr--;
if (ptr < dl-> data)
ptr = dl-> end;
*ptr = insamp;
dl-> pointer = ptr;
}
/* dl_access(dl, position);
* Returns sample "position" samples into delay-line's past.
* Position "0" points to the most recently inserted sample.
*/
static inline short dl_access(DelayLine *dl, int position) {
short *outloc = dl-> pointer + position;
while (outloc < dl-> data)
outloc += dl-> length;
while (outloc > dl-> end)
outloc -= dl-> length;
return *outloc;
}
/*
* Right-going delay line:
* --> ----> ----> ---
* x=0
* (pointer)
* Left-going delay line:
* --< ----< ----< ---
* x=0
* (pointer)
*/
/* rg_dl_access(dl, position);
* Returns spatial sample at location "position", where position zero
* is equal to the current upper delay-line pointer position (x = 0).
* In a right-going delay-line, position increases to the right, and
* delay increases to the right => left = past and right = future.
*/
static inline short rg_dl_access(DelayLine *dl, int position) {
return dl_access(dl, position);
}
/* lg_dl_access(dl, position);
* Returns spatial sample at location "position", where position zero
* is equal to the current lower delay-line pointer position (x = 0).
* In a left-going delay-line, position increases to the right, and
* delay DEcreases to the right => left = future and right = past.
*/
static inline short lg_dl_access(DelayLine *dl, int position) {
return dl_access(dl, position);
}
static DelayLine *upper_rail,*lower_rail;
static inline int initString(double amplitude, double pitch,
double pick, double pickup) {
int i, rail_length = SRATE/pitch/2 + 1;
/*
* Round pick position to nearest spatial sample.
* A pick position at x = 0 is not allowed.
*/
int pickSample = MAX(rail_length * pick, 1);
double upslope = amplitude/pickSample;
double downslope = amplitude/(rail_length - pickSample - 1);
double initial_shape[rail_length];
upper_rail = initDelayLine(rail_length);
lower_rail = initDelayLine(rail_length);
#ifdef DEBUG
initial_shape[pickSample] = 1;
#else
for (i = 0; i < pickSample; i++)
initial_shape[i] = upslope * i;
for (i = pickSample; i < rail_length; i++)
initial_shape[i] = downslope * (rail_length - 1 - i);
#endif
/*
* Initial conditions for the ideal plucked string.
* "Past history" is measured backward from the end of the array.
*/
setDelayLine(lower_rail, initial_shape, 0.5);
setDelayLine(upper_rail, initial_shape, 0.5);
return pickup * rail_length;
}
static inline void freeString(void) {
freeDelayLine(upper_rail);
freeDelayLine(lower_rail);
}
static inline short bridgeReflection(int insamp) {
static short state = 0; /* filter memory */
/* Implement a one-pole lowpass with feedback coefficient = 0.5 */
/* outsamp = 0.5 * outsamp + 0.5 * insamp */
//short outsamp = (state > > 1) + (insamp > > 1);
short outsamp = .1* outsamp + .9 * insamp;
state = outsamp;
return outsamp;
}
static inline short nextStringSample(int pickup_loc) {
short yp0,ym0,ypM,ymM;
short outsamp, outsamp1;
/* Output at pickup location */
outsamp = rg_dl_access(upper_rail, pickup_loc);
outsamp1 = lg_dl_access(lower_rail, pickup_loc);
outsamp += outsamp1;
ym0 = lg_dl_access(lower_rail, 1); /* Sample traveling into "bridge" */
ypM = rg_dl_access(upper_rail, upper_rail-> length - 2); /* Sample to "nut" */
ymM = -ypM; /* Inverting reflection at rigid nut */
yp0 = -bridgeReflection(ym0); /* Reflection at yielding bridge */
/* String state update */
rg_dl_update(upper_rail, yp0); /* Decrement pointer and then update */
lg_dl_update(lower_rail, ymM); /* Update and then increment pointer */
return outsamp;
}
/* Utility for writing a mono sound to a sound file on a NeXT machine */
//#include < sound/sound.h>
static int writeSound(char *name, short *soundData, int sampleCount) {
int i, err;
short *data;
// SNDSoundStruct *sound;
// SNDAlloc(&sound, sampleCount * sizeof(short), SND_FORMAT_LINEAR_16,
// SRATE,1,4);
// data = (short *) ((char *)sound + sound-> dataLocation);
// for (i = 0; i < sampleCount; i++)
// data[i] = soundData[i];
// ofstream output(name);
FILE *fpt = fopen(name,"w");
for(int i=0; i< sampleCount; i++) {
//output > > soundData[i] > > endl;
//printf("%i ",soundData[i]);
fprintf(fpt,"%i ",soundData[i]);
}
fclose(fpt);
return err;
}
static void writeString(void) {
int i, sampleCount = upper_rail-> length;
short data[sampleCount];
for (i = 0; i < sampleCount; i++)
data[i] = rg_dl_access(upper_rail,i);
writeSound("upper.snd", data, sampleCount);
for (i = 0; i < sampleCount; i++)
data[i] = lg_dl_access(lower_rail,i);
writeSound("lower.snd", data, sampleCount);
for (i = 0; i < sampleCount; i++)
data[i] = rg_dl_access(upper_rail, i) + lg_dl_access(lower_rail, i);
writeSound("string.raw", data, sampleCount);
}
void main (int argc, char *argv[]) {
int i, sampleCount;
short *data;
double amp, duration, pitch, pick, pickup, writesample;
int pickupSample;
if (argc != 8) {
cerr < < "Usage: " < < argv[0]
< < " amp(< 1.0) pitch(Hz) pickPosition(< 1.0) "
< < "pickupPosition(< 1.0) duration(sec) writeSamp out.snd\n";
cerr < < "example: %s .5 100 .1 .2 1 -1 test.snd" < < endl;
exit(1);
}
sscanf(argv[1],"%lf",&);
sscanf(argv[2],"%lf",&pitch);
sscanf(argv[3],"%lf",&pick);
sscanf(argv[4],"%lf",&pickup);
sscanf(argv[5],"%lf",&duration);
sscanf(argv[6],"%lf",&writesample);
sampleCount = duration * SRATE;
cout < < "samples: " < < sampleCount < < endl;
// data = (short *) malloc(sampleCount * sizeof(short));
data = new short[sampleCount];
pickupSample = initString(amp, pitch, pick, pickup);
for (i = 0; i < sampleCount; i++) {
if (i == writesample) {
printf("Writing string snapshot at sample %d\n",i);
writeString();
}
data[i] = nextStringSample(pickupSample);
}
writeSound(argv[7], data, sampleCount);
freeString();
exit(0);
}