mirror of
https://github.com/thestk/stk
synced 2026-01-15 14:01:52 +00:00
Version 3.2
This commit is contained in:
committed by
Stephen Sinclair
parent
4b6500d3de
commit
3f126af4e5
197
src/ADSR.cpp
Normal file
197
src/ADSR.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*******************************************/
|
||||
/* ADSR Subclass of the Envelope Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This is the traditional ADSR (Attack */
|
||||
/* Decay, Sustain, Release) ADSR. */
|
||||
/* It responds to simple KeyOn and KeyOff */
|
||||
/* messages, keeping track of it's state. */
|
||||
/* There are two tick (update value) */
|
||||
/* methods, one returns the value, and */
|
||||
/* other returns the state (0 = A, 1 = D, */
|
||||
/* 2 = S, 3 = R) */
|
||||
/*******************************************/
|
||||
|
||||
#include "ADSR.h"
|
||||
|
||||
ADSR :: ADSR() : Envelope()
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
value = (MY_FLOAT) 0.0;
|
||||
attackRate = (MY_FLOAT) 0.001;
|
||||
decayRate = (MY_FLOAT) 0.001;
|
||||
sustainLevel = (MY_FLOAT) 0.5;
|
||||
releaseRate = (MY_FLOAT) 0.01;
|
||||
state = 0;
|
||||
}
|
||||
|
||||
ADSR :: ~ADSR()
|
||||
{
|
||||
/* Nothing to do here */
|
||||
}
|
||||
|
||||
void ADSR :: keyOn()
|
||||
{
|
||||
target = (MY_FLOAT) 1.0;
|
||||
rate = attackRate;
|
||||
state = 0;
|
||||
}
|
||||
|
||||
void ADSR :: keyOff()
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
rate = releaseRate;
|
||||
state = 3;
|
||||
}
|
||||
|
||||
void ADSR :: setAttackRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("negative rates not allowed!!, correcting\n");
|
||||
attackRate = -aRate;
|
||||
}
|
||||
else attackRate = aRate;
|
||||
}
|
||||
|
||||
void ADSR :: setDecayRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("negative rates not allowed!!, correcting\n");
|
||||
decayRate = -aRate;
|
||||
}
|
||||
else decayRate = aRate;
|
||||
}
|
||||
|
||||
void ADSR :: setSustainLevel(MY_FLOAT aLevel)
|
||||
{
|
||||
if (aLevel < 0.0 ) {
|
||||
printf("Sustain level out of range!!, correcting\n");
|
||||
sustainLevel = (MY_FLOAT) 0.0;
|
||||
}
|
||||
else sustainLevel = aLevel;
|
||||
}
|
||||
|
||||
void ADSR :: setReleaseRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("negative rates not allowed!!, correcting\n");
|
||||
releaseRate = -aRate;
|
||||
}
|
||||
else releaseRate = aRate;
|
||||
}
|
||||
|
||||
void ADSR :: setAttackTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("negative times not allowed!!, correcting\n");
|
||||
attackRate = ONE_OVER_SRATE / -aTime;
|
||||
}
|
||||
else attackRate = ONE_OVER_SRATE / aTime;
|
||||
}
|
||||
|
||||
void ADSR :: setDecayTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("negative times not allowed!!, correcting\n");
|
||||
decayRate = ONE_OVER_SRATE / -aTime;
|
||||
}
|
||||
else decayRate = ONE_OVER_SRATE / aTime;
|
||||
}
|
||||
|
||||
void ADSR :: setReleaseTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("negative times not allowed!!, correcting\n");
|
||||
releaseRate = ONE_OVER_SRATE / -aTime;
|
||||
}
|
||||
else releaseRate = ONE_OVER_SRATE / aTime;
|
||||
}
|
||||
|
||||
void ADSR :: setAllTimes(MY_FLOAT attTime, MY_FLOAT decTime, MY_FLOAT susLevel, MY_FLOAT relTime)
|
||||
{
|
||||
this->setAttackTime(attTime);
|
||||
this->setDecayTime(decTime);
|
||||
this->setSustainLevel(susLevel);
|
||||
this->setReleaseTime(relTime);
|
||||
}
|
||||
|
||||
void ADSR :: setTarget(MY_FLOAT aTarget)
|
||||
{
|
||||
target = aTarget;
|
||||
if (value < target) {
|
||||
state = ATTACK;
|
||||
this->setSustainLevel(target);
|
||||
rate = attackRate;
|
||||
}
|
||||
if (value > target) {
|
||||
this->setSustainLevel(target);
|
||||
state = DECAY;
|
||||
rate = decayRate;
|
||||
}
|
||||
}
|
||||
|
||||
void ADSR :: setValue(MY_FLOAT aValue)
|
||||
{
|
||||
state = SUSTAIN;
|
||||
target = aValue;
|
||||
value = aValue;
|
||||
this->setSustainLevel(aValue);
|
||||
rate = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
MY_FLOAT ADSR :: tick()
|
||||
{
|
||||
if (state==ATTACK) {
|
||||
value += rate;
|
||||
if (value >= target) {
|
||||
value = target;
|
||||
rate = decayRate;
|
||||
target = sustainLevel;
|
||||
state = DECAY;
|
||||
}
|
||||
}
|
||||
else if (state==DECAY) {
|
||||
value -= decayRate;
|
||||
if (value <= sustainLevel) {
|
||||
value = sustainLevel;
|
||||
rate = (MY_FLOAT) 0.0;
|
||||
state = SUSTAIN;
|
||||
}
|
||||
}
|
||||
else if (state==RELEASE) {
|
||||
value -= releaseRate;
|
||||
if (value <= 0.0) {
|
||||
value = (MY_FLOAT) 0.0;
|
||||
state = 4;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
int ADSR :: informTick()
|
||||
{
|
||||
this->tick();
|
||||
return state;
|
||||
}
|
||||
|
||||
MY_FLOAT ADSR :: lastOut()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/************ Test Main ************************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
long i;
|
||||
ADSR test;
|
||||
|
||||
test.setAttackRate(0.15);
|
||||
test.keyOn();
|
||||
while(test.informTick()==ATTACK) printf("%lf\n",test.tick());
|
||||
test.setDecayRate(0.1);
|
||||
while (test.informTick()==DECAY) printf("%lf\n",test.lastOut());
|
||||
test.setReleaseRate(0.05);
|
||||
test.keyOff();
|
||||
while(test.informTick()==RELEASE) printf("%lf\n",test.lastOut());
|
||||
}
|
||||
*/
|
||||
209
src/AifWvIn.cpp
Normal file
209
src/AifWvIn.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
AifWvIn Input Class,
|
||||
by Gary P. Scavone, 2000
|
||||
|
||||
This object inherits from WvIn and is
|
||||
used to open Audio Interchange File
|
||||
Format files with 16-bit data (signed
|
||||
integer) for playback.
|
||||
|
||||
.aif files are always bif-endian.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#include "AifWvIn.h"
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
AifWvIn :: AifWvIn(char *fileName, const char *mode)
|
||||
{
|
||||
char msg[256];
|
||||
|
||||
// check mode string
|
||||
if ( strcmp(mode,"oneshot") && strcmp(mode,"looping") ) {
|
||||
sprintf(msg, "AifWvIn: constructor parameter 'mode' must be oneshot or looping only.\n");
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
|
||||
// Open the file and get header info
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "AifWvIn: Couldn't open or find file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Make sure this is an .aif format file
|
||||
char id[4];
|
||||
fseek(fd,8,SEEK_SET); // Locate form type
|
||||
fread(&id,4,1,fd);
|
||||
if (strncmp(id,"AIFF",4)) {
|
||||
fclose(fd);
|
||||
sprintf(msg, "AifWvIn: %s doesn't appear to be an AIFF file.\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
// Find "common" chunk
|
||||
INT32 chunkSize;
|
||||
fread(&id,4,1,fd);
|
||||
while (strncmp(id,"COMM",4)) {
|
||||
fread(&chunkSize,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&chunkSize);
|
||||
#endif
|
||||
fseek(fd,chunkSize,SEEK_CUR);
|
||||
fread(&id,4,1,fd);
|
||||
}
|
||||
|
||||
// Get number of channels from the header
|
||||
INT16 temp;
|
||||
fseek(fd,4,SEEK_CUR); // Jump over chunk size
|
||||
fread(&temp,2,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)&temp);
|
||||
#endif
|
||||
channels = temp;
|
||||
|
||||
// Get length of data from the header
|
||||
INT32 frames;
|
||||
fread(&frames,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&frames);
|
||||
#endif
|
||||
// length is the number of sample frames
|
||||
fileSize = frames;
|
||||
bufferSize = fileSize;
|
||||
|
||||
// Verify that the data is 16 bits per sample
|
||||
fread(&temp,2,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)&temp);
|
||||
#endif
|
||||
if (temp != 16) {
|
||||
fclose(fd);
|
||||
sprintf(msg, "AifWvIn: STK does not currently support data formats other than 16 bit signed integer.\n");
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
/* Get file sample rate from the header and set the default rate.
|
||||
* For AIFF files, this value is stored in a 10-byte, IEEE Standard
|
||||
* 754 floating point number, so we need to convert it first.
|
||||
*/
|
||||
unsigned char srate[10];
|
||||
unsigned char exp;
|
||||
unsigned long mantissa;
|
||||
unsigned long last = 0;;
|
||||
fread(&srate,10,1,fd);
|
||||
mantissa = (unsigned long) *(unsigned long *)(srate+2);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&mantissa);
|
||||
#endif
|
||||
exp = 30 - *(srate+1);
|
||||
while (exp--) {
|
||||
last = mantissa;
|
||||
mantissa >>= 1;
|
||||
}
|
||||
if (last & 0x00000001) mantissa++;
|
||||
rate = (MY_FLOAT) (mantissa/SRATE); // set default rate based on file sampling rate
|
||||
|
||||
// Find "data" chunk
|
||||
fread(&id,4,1,fd);
|
||||
while (strncmp(id,"SSND",4)) {
|
||||
fread(&chunkSize,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&chunkSize);
|
||||
#endif
|
||||
fseek(fd,chunkSize,SEEK_CUR);
|
||||
fread(&id,4,1,fd);
|
||||
}
|
||||
|
||||
// Skip over chunk size, offset, and blocksize fields
|
||||
fseek(fd,12,SEEK_CUR);
|
||||
|
||||
if ((fileSize*channels) > MAX_FILE_LOAD_SIZE) {
|
||||
printf("\nAifWvIn: The .AIF file (%s) has more than %d samples and\n",
|
||||
fileName, MAX_FILE_LOAD_SIZE);
|
||||
printf("will be loaded incrementally from disk. Normalization will be disabled.\n");
|
||||
chunking = 1;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Setup for looping or one-shot playback
|
||||
if (!strcmp(mode,"looping"))
|
||||
looping = 1;
|
||||
else // default = oneshot
|
||||
looping = 0;
|
||||
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(bufferSize+1)*channels];
|
||||
dataOffset = ftell(fd);
|
||||
this->getData(0); // Read samples into data[]
|
||||
|
||||
if (fmod(rate, 1.0) != 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
this->reset();
|
||||
|
||||
// finally, let's normalize the data by default
|
||||
this->normalize();
|
||||
}
|
||||
|
||||
AifWvIn :: ~AifWvIn()
|
||||
{
|
||||
}
|
||||
|
||||
void AifWvIn :: getData(long index)
|
||||
{
|
||||
/* Compare index to current readPointer and modify as needed.
|
||||
* The following while() loops will only execute on calls subsequent
|
||||
* to class instantiation ... and thus, only when "chunking".
|
||||
*/
|
||||
while (index < readPointer) {
|
||||
readPointer -= LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer < 0) {
|
||||
bufferSize += readPointer;
|
||||
readPointer = 0;
|
||||
}
|
||||
}
|
||||
while (index >= readPointer+bufferSize) {
|
||||
readPointer += LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer+LOAD_BUFFER_SIZE >= fileSize) {
|
||||
bufferSize = fileSize - readPointer;
|
||||
}
|
||||
}
|
||||
|
||||
fseek(fd, dataOffset+(long)(readPointer*channels*2), SEEK_SET);
|
||||
long length = bufferSize;
|
||||
int end_of_file = (readPointer+bufferSize == fileSize);
|
||||
if (!end_of_file) length += 1;
|
||||
|
||||
// Read samples into data[]. Use MY _FLOAT data structure to store INT16 samples
|
||||
INT16 *buf = (INT16 *)data;
|
||||
fread(buf, 2, length*channels, fd);
|
||||
// Convert in place (unpack) to MY_FLOAT from the end of the array
|
||||
for (int i=length*channels-1; i>=0; i--) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)(buf+i));
|
||||
#endif
|
||||
data[i] = buf[i];
|
||||
if (chunking) data[i] *= 0.00003051;
|
||||
}
|
||||
|
||||
// fill in the extra sample frame for interpolation
|
||||
if (end_of_file) {
|
||||
for (int j=0; j<channels; j++)
|
||||
if (looping)
|
||||
data[bufferSize*channels+j] = data[j];
|
||||
else
|
||||
data[bufferSize*channels+j] = data[(bufferSize-1)*channels+j];
|
||||
}
|
||||
|
||||
if (!chunking) {
|
||||
fclose(fd);
|
||||
fd = 0;
|
||||
}
|
||||
}
|
||||
192
src/AifWvOut.cpp
Normal file
192
src/AifWvOut.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
AifWvOut Output Class,
|
||||
by Gary P. Scavone, 2000
|
||||
|
||||
This object inherits from WvOut and is
|
||||
used to write Audio Interchange File
|
||||
Format files with 16-bit data (signed
|
||||
integer).
|
||||
|
||||
.aif files are always bif-endian.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#include "AifWvOut.h"
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
/******** Aiff Soundfile Header Struct *******/
|
||||
struct aiffhdr {
|
||||
char form[4]; // "FORM"
|
||||
INT32 form_size; // in bytes
|
||||
char aiff[4]; // "AIFF"
|
||||
char comm[4]; // "COMM"
|
||||
INT32 comm_size; // "COMM" chunk size (should be 18)
|
||||
INT16 num_chans; // number of channels
|
||||
unsigned long sample_frames; // sample frames of audio data
|
||||
INT16 sample_size; // always 16 for STK
|
||||
unsigned char srate[10]; // IEEE 754 floating point format
|
||||
char ssnd[4]; // "SSND"
|
||||
INT32 ssnd_size; // "SSND" chunk size
|
||||
unsigned long offset; // data offset in data block (should be 0)
|
||||
unsigned long block_size; // not used by STK (should be 0)
|
||||
};
|
||||
|
||||
FILE *openAifFile(int chans, char *fileName) {
|
||||
struct aiffhdr hdr = {"FOR",46,"AIF","COM",18,0,0,16,"0","SSN",8,0,0};
|
||||
char tempName[128];
|
||||
FILE *fd;
|
||||
char msg[256];
|
||||
INT16 i;
|
||||
unsigned long exp;
|
||||
unsigned long rate = (unsigned long) SRATE;
|
||||
|
||||
hdr.form[3] = 'M';
|
||||
hdr.aiff[3] = 'F';
|
||||
hdr.comm[3] = 'M';
|
||||
hdr.ssnd[3] = 'D';
|
||||
|
||||
hdr.num_chans = chans;
|
||||
|
||||
/*
|
||||
* For AIFF files, the sample reate is stored in a 10-byte, IEEE Standard
|
||||
* 754 floating point number, so we need to convert to that.
|
||||
*/
|
||||
memset(hdr.srate, 0, 10);
|
||||
exp = rate;
|
||||
for (i=0; i<32; i++) {
|
||||
exp >>= 1;
|
||||
if (!exp) break;
|
||||
}
|
||||
i += 16383;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)&i);
|
||||
#endif
|
||||
*(INT16 *)(hdr.srate) = (INT16) i;
|
||||
|
||||
for (i=32; i; i--) {
|
||||
if (rate & 0x80000000) break;
|
||||
rate <<= 1;
|
||||
}
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&rate);
|
||||
#endif
|
||||
*(unsigned long *)(hdr.srate+2) = (unsigned long) rate;
|
||||
|
||||
strcpy(tempName,fileName);
|
||||
if (strstr(tempName,".aif") == NULL) strcat(tempName,".aif");
|
||||
fd = fopen(tempName,"wb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "AifWvOut: Could not create soundfile: %s\n", tempName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&hdr.form_size);
|
||||
swap32((unsigned char *)&hdr.comm_size);
|
||||
swap16((unsigned char *)&hdr.num_chans);
|
||||
swap16((unsigned char *)&hdr.sample_size);
|
||||
swap32((unsigned char *)&hdr.ssnd_size);
|
||||
swap32((unsigned char *)&hdr.offset);
|
||||
swap32((unsigned char *)&hdr.block_size);
|
||||
#endif
|
||||
|
||||
printf("\nCreating soundfile: %s\n", tempName);
|
||||
|
||||
/* I found it necessary to break the fwrite() calls as
|
||||
* follows ... a single write of 54 bytes didn't work.
|
||||
*/
|
||||
fwrite(&hdr,4,5,fd);
|
||||
fwrite(&hdr.num_chans,2,1,fd);
|
||||
fwrite(&hdr.sample_frames,4,1,fd);
|
||||
fwrite(&hdr.sample_size,2,1,fd);
|
||||
fwrite(&hdr.srate,10,1,fd);
|
||||
fwrite(&hdr.ssnd,4,4,fd);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
AifWvOut :: AifWvOut(char *fileName, int chans)
|
||||
{
|
||||
char msg[256];
|
||||
if (chans < 1) {
|
||||
sprintf(msg, "AifWvOut: number of channels = %d not supported!\n", chans);
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
channels = chans;
|
||||
fd = openAifFile(chans,fileName);
|
||||
data_length = FILE_BUFFER_SIZE*channels;
|
||||
data = (INT16 *) new INT16[data_length];
|
||||
}
|
||||
|
||||
AifWvOut :: ~AifWvOut()
|
||||
{
|
||||
MY_FLOAT time;
|
||||
unsigned long bytes;
|
||||
unsigned long frames;
|
||||
|
||||
fwrite(data,2,counter,fd);
|
||||
time = (double) totalCount * ONE_OVER_SRATE;
|
||||
printf("%f Seconds Computed\n\n", time);
|
||||
|
||||
frames = (unsigned long) totalCount;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&frames);
|
||||
#endif
|
||||
fseek(fd,22,SEEK_SET); // jump to "COMM" sample_frames
|
||||
fwrite(&frames,4,1,fd);
|
||||
|
||||
bytes = totalCount*2*channels + 46;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&bytes);
|
||||
#endif
|
||||
fseek(fd,4,SEEK_SET); // jump to file size
|
||||
fwrite(&bytes,4,1,fd);
|
||||
|
||||
bytes = totalCount*2*channels + 8;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&bytes);
|
||||
#endif
|
||||
fseek(fd,42,SEEK_SET); // jump to "SSND" chunk size
|
||||
fwrite(&bytes,4,1,fd);
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
void AifWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
INT16 isample;
|
||||
|
||||
isample = (INT16) (sample * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)&isample);
|
||||
#endif
|
||||
for (int i=0;i<channels;i++)
|
||||
data[counter++] = isample;
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(data,2,data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AifWvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
for (int i=0;i<channels;i++) {
|
||||
data[counter] = (INT16) (*samples++ * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)&data[counter]);
|
||||
#endif
|
||||
counter++;
|
||||
}
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(data,2,data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
81
src/BeeThree.cpp
Normal file
81
src/BeeThree.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/******************************************/
|
||||
/* Hammond(OID) Organ Subclass */
|
||||
/* of Algorithm 8 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "BeeThree.h"
|
||||
|
||||
BeeThree :: BeeThree() : FM4Alg8()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file1[128];
|
||||
char file2[128];
|
||||
char file3[128];
|
||||
char file4[128];
|
||||
strcpy(file1, RAWWAVE_PATH);
|
||||
strcpy(file2, RAWWAVE_PATH);
|
||||
strcpy(file3, RAWWAVE_PATH);
|
||||
strcpy(file4, RAWWAVE_PATH);
|
||||
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
|
||||
strcat(file2,"rawwaves/sinewave.raw"),
|
||||
strcat(file3,"rawwaves/sinewave.raw"),
|
||||
strcat(file4,"rawwaves/fwavblnk.raw"));
|
||||
|
||||
this->setRatio(0,(MY_FLOAT) 0.999);
|
||||
this->setRatio(1,(MY_FLOAT) 1.997);
|
||||
this->setRatio(2,(MY_FLOAT) 3.006);
|
||||
this->setRatio(3,(MY_FLOAT) 6.009);
|
||||
gains[0] = __FM4Op_gains[95];
|
||||
gains[1] = __FM4Op_gains[95];
|
||||
gains[2] = __FM4Op_gains[99];
|
||||
gains[3] = __FM4Op_gains[95];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 0.003,(MY_FLOAT) 1.0,(MY_FLOAT) 0.01);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 0.003,(MY_FLOAT) 1.0,(MY_FLOAT) 0.01);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 0.003,(MY_FLOAT) 1.0,(MY_FLOAT) 0.01);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 0.001,(MY_FLOAT) 0.4,(MY_FLOAT) 0.03);
|
||||
twozero->setGain((MY_FLOAT) 0.1);
|
||||
}
|
||||
|
||||
BeeThree :: ~BeeThree()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BeeThree :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
MY_FLOAT BeeThree :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
if (modDepth > 0.0) {
|
||||
temp = (MY_FLOAT) 1.0 + (modDepth * vibWave->tick() * (MY_FLOAT) 0.1);
|
||||
waves[0]->setFreq(baseFreq * ratios[0] * temp);
|
||||
waves[1]->setFreq(baseFreq * ratios[1] * temp);
|
||||
waves[2]->setFreq(baseFreq * ratios[2] * temp);
|
||||
waves[3]->setFreq(baseFreq * ratios[3] * temp);
|
||||
}
|
||||
lastOutput = FM4Alg8 :: tick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void BeeThree :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[95];
|
||||
gains[1] = amp * __FM4Op_gains[95];
|
||||
gains[2] = amp * __FM4Op_gains[99];
|
||||
gains[3] = amp * __FM4Op_gains[95];
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("BeeThree : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
112
src/BiQuad.cpp
Normal file
112
src/BiQuad.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
BiQuad (2-pole, 2-zero) Filter Class,
|
||||
by Perry R. Cook, 1995-96.
|
||||
Modified by Julius Smith, 2000:
|
||||
setA1,setA2,setB1,setB2
|
||||
|
||||
See books on filters to understand
|
||||
more about how this works. Nothing
|
||||
out of the ordinary in this version.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#include "BiQuad.h"
|
||||
|
||||
BiQuad :: BiQuad() : Filter()
|
||||
{
|
||||
inputs = (MY_FLOAT *) malloc(2 * sizeof(MY_FLOAT));
|
||||
zeroCoeffs[0] = (MY_FLOAT) 0.0;
|
||||
zeroCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
poleCoeffs[0] = (MY_FLOAT) 0.0;
|
||||
poleCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
BiQuad :: ~BiQuad()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void BiQuad :: clear()
|
||||
{
|
||||
inputs[0] = (MY_FLOAT) 0.0;
|
||||
inputs[1] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void BiQuad :: setA1(MY_FLOAT a1)
|
||||
{
|
||||
poleCoeffs[0] = -a1;
|
||||
}
|
||||
|
||||
void BiQuad :: setA2(MY_FLOAT a2)
|
||||
{
|
||||
poleCoeffs[1] = -a2;
|
||||
}
|
||||
|
||||
void BiQuad :: setB1(MY_FLOAT b1)
|
||||
{
|
||||
zeroCoeffs[0] = b1;
|
||||
}
|
||||
|
||||
void BiQuad :: setB2(MY_FLOAT b2)
|
||||
{
|
||||
zeroCoeffs[1] = b2;
|
||||
}
|
||||
|
||||
void BiQuad :: setPoleCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
poleCoeffs[0] = coeffs[0];
|
||||
poleCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void BiQuad :: setZeroCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
zeroCoeffs[0] = coeffs[0];
|
||||
zeroCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void BiQuad :: setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson)
|
||||
{
|
||||
poleCoeffs[1] = - (reson * reson);
|
||||
poleCoeffs[0] = (MY_FLOAT) 2.0 * reson * (MY_FLOAT) cos(TWO_PI * freq / SRATE);
|
||||
}
|
||||
|
||||
void BiQuad :: setEqualGainZeroes()
|
||||
{
|
||||
zeroCoeffs[1] = (MY_FLOAT) -1.0;
|
||||
zeroCoeffs[0] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void BiQuad :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
}
|
||||
|
||||
/* Perform Filter Operation */
|
||||
MY_FLOAT BiQuad :: tick(MY_FLOAT sample)
|
||||
{
|
||||
/*
|
||||
Biquad is two pole, two zero filter. Look it up
|
||||
in your favorite DSP text. This version implements
|
||||
only 2 state variables. It takes 5 multiplies,
|
||||
4 adds, and 3 moves.
|
||||
*/
|
||||
MY_FLOAT temp;
|
||||
|
||||
temp = sample * gain;
|
||||
temp += inputs[0] * poleCoeffs[0];
|
||||
temp += inputs[1] * poleCoeffs[1];
|
||||
|
||||
lastOutput = temp;
|
||||
lastOutput += (inputs[0] * zeroCoeffs[0]);
|
||||
lastOutput += (inputs[1] * zeroCoeffs[1]);
|
||||
inputs[1] = inputs[0];
|
||||
inputs[0] = temp;
|
||||
|
||||
return lastOutput;
|
||||
|
||||
}
|
||||
|
||||
209
src/BlowHole.cpp
Normal file
209
src/BlowHole.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/***********************************************/
|
||||
/*
|
||||
Waveguide "reed" instrument model with a
|
||||
register hole and one tonehole
|
||||
|
||||
by Gary P. Scavone, 2000.
|
||||
*/
|
||||
/***********************************************/
|
||||
|
||||
#include "BlowHole.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
BlowHole :: BlowHole(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
delays = (DLineL *) new DLineL[3];
|
||||
// delays[0] is the delay line between the reed and the register vent
|
||||
delays[0].setDelay(5.0);
|
||||
// delays[1] is the delay line between the register vent and the tonehole
|
||||
delays[1].setDelay(length >> 1);
|
||||
// delays[2] is the delay line between the tonehole and the end of the bore
|
||||
delays[2].setDelay(4.0);
|
||||
reedTable = new ReedTabl;
|
||||
reedTable->setOffset((MY_FLOAT) 0.7);
|
||||
reedTable->setSlope((MY_FLOAT) -0.3);
|
||||
filter = new OneZero;
|
||||
envelope = new Envelope;
|
||||
noise = new Noise;
|
||||
|
||||
// Calculate the initial tonehole three-port scattering coefficient
|
||||
double r_b = 0.0075; /* main bore radius */
|
||||
r_th = 0.003; /* tonehole radius */
|
||||
scatter = -pow(r_th,2) / ( pow(r_th,2) + 2*pow(r_b,2) );
|
||||
|
||||
// Calculate tonehole coefficients
|
||||
MY_FLOAT te = 1.4 * r_th; /* effective length of the open hole */
|
||||
th_coeff = (te*2*SRATE - 347.23) / (te*2*SRATE + 347.23);
|
||||
tonehole = new PoleZero;
|
||||
// Start with tonehole open
|
||||
tonehole->setA1(-th_coeff);
|
||||
tonehole->setB0(th_coeff);
|
||||
tonehole->setB1(-1.0);
|
||||
|
||||
// Calculate register hole filter coefficients
|
||||
double r_rh = 0.0015; /* register vent radius */
|
||||
te = 1.4 * r_rh; /* effective length of the open hole */
|
||||
double xi = 0.0; /* series resistance term */
|
||||
double zeta = 347.23 + 2*PI*pow(r_b,2)*xi/1.1769;
|
||||
double psi = 2*PI*pow(r_b,2)*te / (PI*pow(r_rh,2));
|
||||
rh_coeff = (zeta - 2*SRATE*psi) / (zeta + 2*SRATE*psi);
|
||||
rh_gain = -347.23 / (zeta + 2*SRATE*psi);
|
||||
vent = new PoleZero;
|
||||
vent->setA1(rh_coeff);
|
||||
vent->setB0(1.0);
|
||||
vent->setB1(1.0);
|
||||
// Start with register vent closed
|
||||
vent->setGain(0.0);
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
|
||||
vibr->setFreq((MY_FLOAT) 5.735);
|
||||
outputGain = (MY_FLOAT) 1.0;
|
||||
noiseGain = (MY_FLOAT) 0.2;
|
||||
vibrGain = (MY_FLOAT) 0.01;
|
||||
}
|
||||
|
||||
BlowHole :: ~BlowHole()
|
||||
{
|
||||
delete [] delays;
|
||||
delete reedTable;
|
||||
delete filter;
|
||||
delete tonehole;
|
||||
delete vent;
|
||||
delete envelope;
|
||||
delete noise;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void BlowHole :: clear()
|
||||
{
|
||||
delays[0].clear();
|
||||
delays[1].clear();
|
||||
filter->tick((MY_FLOAT) 0.0);
|
||||
tonehole->tick((MY_FLOAT) 0.0);
|
||||
vent->tick((MY_FLOAT) 0.0);
|
||||
}
|
||||
|
||||
void BlowHole :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT new_length = (SRATE / frequency) * (MY_FLOAT) 0.5 - (MY_FLOAT) 1.5;
|
||||
new_length -= 9;
|
||||
|
||||
if (new_length <= 1.0) new_length = 1.0;
|
||||
else if (new_length >= length) new_length = length;
|
||||
delays[1].setDelay(new_length);
|
||||
}
|
||||
|
||||
void BlowHole :: setVent(MY_FLOAT newValue)
|
||||
{
|
||||
/*
|
||||
This method allows setting of the register vent "open-ness" at
|
||||
any point between "Open" (newValue = 1) and "Closed"
|
||||
(newValue = 0).
|
||||
*/
|
||||
|
||||
MY_FLOAT gain;
|
||||
|
||||
if (newValue <= 0.0) gain = 0.0;
|
||||
else if (newValue >= 1.0) gain = rh_gain;
|
||||
else gain = newValue * rh_gain;
|
||||
vent->setGain(gain);
|
||||
}
|
||||
|
||||
void BlowHole :: setTonehole(MY_FLOAT newValue)
|
||||
{
|
||||
/*
|
||||
This method allows setting of the tonehole "open-ness" at
|
||||
any point between "Open" (newValue = 1) and "Closed"
|
||||
(newValue = 0).
|
||||
*/
|
||||
MY_FLOAT new_coeff;
|
||||
|
||||
if (newValue <= 0.0) new_coeff = 0.9995;
|
||||
else if (newValue >= 1.0) new_coeff = th_coeff;
|
||||
else new_coeff = (newValue * (th_coeff - 0.9995)) + 0.9995;
|
||||
tonehole->setA1(-new_coeff);
|
||||
tonehole->setB0(new_coeff);
|
||||
}
|
||||
|
||||
void BlowHole :: startBlowing(MY_FLOAT amplitude,MY_FLOAT rate)
|
||||
{
|
||||
envelope->setRate(rate);
|
||||
envelope->setTarget(amplitude);
|
||||
}
|
||||
|
||||
void BlowHole :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
envelope->setRate(rate);
|
||||
envelope->setTarget((MY_FLOAT) 0.0);
|
||||
}
|
||||
|
||||
void BlowHole :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->startBlowing((MY_FLOAT) 0.55 + (amp * (MY_FLOAT) 0.30),amp * (MY_FLOAT) 0.005);
|
||||
outputGain = amp + (MY_FLOAT) 0.001;
|
||||
}
|
||||
|
||||
void BlowHole :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBlowing(amp * (MY_FLOAT) 0.01);
|
||||
}
|
||||
|
||||
MY_FLOAT BlowHole :: tick()
|
||||
{
|
||||
MY_FLOAT pressureDiff;
|
||||
MY_FLOAT breathPressure;
|
||||
MY_FLOAT temp;
|
||||
|
||||
// Calculate the breath pressure (envelope + noise + vibrator)
|
||||
breathPressure = envelope->tick();
|
||||
breathPressure += breathPressure * noiseGain * noise->tick();
|
||||
breathPressure += breathPressure * vibrGain * vibr->tick();
|
||||
|
||||
// Calculate the differential pressure = reflected - mouthpiece pressures
|
||||
pressureDiff = delays[0].lastOut() - breathPressure;
|
||||
|
||||
// Do two-port junction scattering for register vent
|
||||
MY_FLOAT pa = breathPressure + pressureDiff * reedTable->lookup(pressureDiff);
|
||||
MY_FLOAT pb = delays[1].lastOut();
|
||||
vent->tick(pa+pb);
|
||||
|
||||
lastOutput = delays[0].tick(vent->lastOut()+pb);
|
||||
lastOutput *= outputGain;
|
||||
|
||||
// Do three-port junction scattering (under tonehole)
|
||||
pa += vent->lastOut();
|
||||
pb = delays[2].lastOut();
|
||||
MY_FLOAT pth = tonehole->lastOut();
|
||||
temp = scatter * (pa + pb - 2 * pth);
|
||||
|
||||
delays[2].tick(filter->tick(pa + temp) * -0.95);
|
||||
delays[1].tick(pb + temp);
|
||||
tonehole->tick(pa + pb - pth + temp);
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void BlowHole :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
if (number == __SK_ReedStiffness_)
|
||||
reedTable->setSlope((MY_FLOAT) -0.44 + ((MY_FLOAT) 0.26 * value * NORM_7));
|
||||
else if (number == __SK_NoiseLevel_)
|
||||
noiseGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
//vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
this->setTonehole(value * NORM_7);
|
||||
else if (number == __SK_ModWheel_)
|
||||
//vibrGain = (value * NORM_7 * (MY_FLOAT) 0.5);
|
||||
this->setVent(value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_) {
|
||||
envelope->setValue(value * NORM_7);
|
||||
}
|
||||
else {
|
||||
printf("BlowHole : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
52
src/BowTabl.cpp
Normal file
52
src/BowTabl.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/***********************************************/
|
||||
/* Simple Bow Table Object, after Smith */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/***********************************************/
|
||||
|
||||
#include "BowTabl.h"
|
||||
|
||||
BowTabl :: BowTabl()
|
||||
{
|
||||
/* offset is a bias, really not needed unless */
|
||||
/* friction is different in each direction */
|
||||
offSet = (MY_FLOAT) 0.0;
|
||||
slope = (MY_FLOAT) 0.1; /* controls width of friction pulse, */
|
||||
/* related to bowForce */
|
||||
}
|
||||
|
||||
BowTabl :: ~BowTabl()
|
||||
{
|
||||
}
|
||||
|
||||
void BowTabl :: setOffset(MY_FLOAT aValue)
|
||||
{
|
||||
offSet = aValue;
|
||||
}
|
||||
|
||||
void BowTabl :: setSlope(MY_FLOAT aValue)
|
||||
{
|
||||
slope = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: lookup(MY_FLOAT sample)
|
||||
{
|
||||
return this->tick(sample);
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: tick(MY_FLOAT sample) /* Perform Table Lookup */
|
||||
{ /* sample is differential */
|
||||
/* string vs. bow velocity */
|
||||
MY_FLOAT input;
|
||||
input = sample + offSet; /* add bias to sample */
|
||||
input *= slope; /* scale it */
|
||||
lastOutput = (MY_FLOAT) fabs((double) input) + (MY_FLOAT) 0.75; /* below min delta, friction = 1 */
|
||||
lastOutput = (MY_FLOAT) pow(lastOutput,(MY_FLOAT) -4.0);
|
||||
// if (lastOutput < 0.0 ) lastOutput = 0.0; /* minimum friction is 0.0 */
|
||||
if (lastOutput > 1.0 ) lastOutput = (MY_FLOAT) 1.0; /* maximum friction is 1.0 */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
165
src/Bowed.cpp
Normal file
165
src/Bowed.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/******************************************/
|
||||
/* Bowed String model ala Smith */
|
||||
/* after McIntyre, Schumacher, Woodhouse */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = bowPressure */
|
||||
/* CONTROL2 = bowPosition */
|
||||
/* CONTROL3 = vibrFreq */
|
||||
/* MOD_WHEEL= vibrGain */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "Bowed.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Bowed :: Bowed(MY_FLOAT lowestFreq)
|
||||
{
|
||||
long length;
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
neckDelay = new DLineL(length);
|
||||
length >>= 1;
|
||||
bridgeDelay = new DLineL(length);
|
||||
bowTabl = new BowTabl;
|
||||
reflFilt = new OnePole;
|
||||
bodyFilt = new BiQuad;
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
|
||||
|
||||
adsr = new ADSR;
|
||||
vibrGain = (MY_FLOAT) 0.0;
|
||||
|
||||
neckDelay->setDelay((MY_FLOAT) 100.0);
|
||||
bridgeDelay->setDelay((MY_FLOAT) 29.0);
|
||||
|
||||
bowTabl->setSlope((MY_FLOAT) 3.0);
|
||||
|
||||
reflFilt->setPole((MY_FLOAT) (0.6 - (0.1 * 22050.0 / SRATE)));
|
||||
reflFilt->setGain((MY_FLOAT) 0.95);
|
||||
|
||||
bodyFilt->setFreqAndReson((MY_FLOAT) 500.0, (MY_FLOAT) 0.85);
|
||||
bodyFilt->setEqualGainZeroes();
|
||||
bodyFilt->setGain((MY_FLOAT) 0.2);
|
||||
|
||||
vibr->setFreq((MY_FLOAT) 6.12723);
|
||||
|
||||
adsr->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.005,(MY_FLOAT) 0.9,(MY_FLOAT) 0.01);
|
||||
|
||||
betaRatio = (MY_FLOAT) 0.127236;
|
||||
}
|
||||
|
||||
Bowed :: ~Bowed()
|
||||
{
|
||||
delete neckDelay;
|
||||
delete bridgeDelay;
|
||||
delete bowTabl;
|
||||
delete reflFilt;
|
||||
delete bodyFilt;
|
||||
delete vibr;
|
||||
delete adsr;
|
||||
}
|
||||
|
||||
void Bowed :: clear()
|
||||
{
|
||||
neckDelay->clear();
|
||||
bridgeDelay->clear();
|
||||
}
|
||||
|
||||
void Bowed :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseDelay = SRATE / frequency - (MY_FLOAT) 4.0; /* delay - approx. filter delay */
|
||||
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
|
||||
neckDelay->setDelay(baseDelay * ((MY_FLOAT) 1.0 - betaRatio)); /* bow to nut (finger) length */
|
||||
}
|
||||
|
||||
void Bowed :: startBowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
adsr->setRate(rate);
|
||||
adsr->keyOn();
|
||||
maxVelocity = (MY_FLOAT) 0.03 + ((MY_FLOAT) 0.2 * amplitude);
|
||||
}
|
||||
|
||||
void Bowed :: stopBowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Bowed :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->startBowing(amp,amp * (MY_FLOAT) 0.001);
|
||||
this->setFreq(freq);
|
||||
#if defined(_debug_)
|
||||
printf("Bowed : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Bowed :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBowing(((MY_FLOAT) 1.0 - amp) * (MY_FLOAT) 0.005);
|
||||
#if defined(_debug_)
|
||||
printf("Bowed : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Bowed :: setVibrato(MY_FLOAT amount)
|
||||
{
|
||||
vibrGain = amount;
|
||||
}
|
||||
|
||||
MY_FLOAT Bowed :: tick()
|
||||
{
|
||||
MY_FLOAT bowVelocity;
|
||||
MY_FLOAT bridgeRefl=(MY_FLOAT) 0,nutRefl=(MY_FLOAT) 0;
|
||||
MY_FLOAT newVel=(MY_FLOAT) 0,velDiff=(MY_FLOAT) 0,stringVel=(MY_FLOAT) 0;
|
||||
|
||||
bowVelocity = maxVelocity * adsr->tick();
|
||||
|
||||
bridgeRefl = -reflFilt->tick(
|
||||
bridgeDelay->lastOut()); /* Bridge Reflection */
|
||||
nutRefl = -neckDelay->lastOut(); /* Nut Reflection */
|
||||
stringVel = bridgeRefl + nutRefl; /* Sum is String Velocity */
|
||||
velDiff = bowVelocity - stringVel; /* Differential Velocity */
|
||||
newVel = velDiff * bowTabl->lookup(velDiff); /* Non-Lin Bow Function */
|
||||
neckDelay->tick(bridgeRefl + newVel); /* Do string */
|
||||
bridgeDelay->tick(nutRefl + newVel); /* propagations */
|
||||
|
||||
if (vibrGain > 0.0) {
|
||||
neckDelay->setDelay((baseDelay * ((MY_FLOAT) 1.0 - betaRatio)) +
|
||||
(baseDelay * vibrGain*vibr->tick()));
|
||||
}
|
||||
|
||||
lastOutput = bodyFilt->tick(bridgeDelay->lastOut());
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Bowed :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Bowed : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_BowPressure_)
|
||||
bowTabl->setSlope((MY_FLOAT) 5.0 - ((MY_FLOAT) 4.0 * value * NORM_7));
|
||||
else if (number == __SK_BowPosition_) {
|
||||
betaRatio = (MY_FLOAT) 0.027236 + ((MY_FLOAT) 0.2 * value * NORM_7);
|
||||
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
|
||||
neckDelay->setDelay(baseDelay * ((MY_FLOAT) 1.0 - betaRatio)); /* bow to nut (finger) length */
|
||||
}
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Bowed : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
314
src/BowedBar.cpp
Normal file
314
src/BowedBar.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
/*********************************************/
|
||||
/* Bowed Bar model */
|
||||
/* by Georg Essl, 1999 */
|
||||
/* For details refer to: */
|
||||
/* G.Essl, P.R.Cook: "Banded Waveguides: */
|
||||
/* Towards Physical Modelling of Bar */
|
||||
/* Percussion Instruments", ICMC'99 */
|
||||
/*********************************************/
|
||||
|
||||
#include "BowedBar.h"
|
||||
#include "SKINI11.msg"
|
||||
#include "Noise.h"
|
||||
|
||||
/* Contructor */
|
||||
BowedBar :: BowedBar()
|
||||
{
|
||||
long i;
|
||||
doPluck = 1;
|
||||
|
||||
/* Number of banded waveguide modes */
|
||||
NR_MODES = 4;
|
||||
|
||||
modes[0] = (MY_FLOAT) 1.0;
|
||||
modes[1] = (MY_FLOAT) 2.756;
|
||||
modes[2] = (MY_FLOAT) 5.404;
|
||||
modes[3] = (MY_FLOAT) 8.933;
|
||||
|
||||
for (i=0;i<4;i++) {
|
||||
gains[i] = (MY_FLOAT) pow(0.9,(double) i);
|
||||
}
|
||||
|
||||
bowTabl = new BowTabl;
|
||||
adsr = new ADSR;
|
||||
bandpass = new BiQuad[NR_MODES];
|
||||
|
||||
bowTabl->setSlope((MY_FLOAT) 3.0);
|
||||
adsr->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.005,(MY_FLOAT) 0.9,(MY_FLOAT) 0.01);
|
||||
|
||||
freq = SRATE / 100;
|
||||
length = 100;
|
||||
|
||||
bowPos = 0;
|
||||
lastBowPos = 0;
|
||||
|
||||
for(i = 0; i<NR_MODES; i++) {
|
||||
delay[i].setDelay((int)(length/modes[i]));
|
||||
delay[i].clear();
|
||||
|
||||
bandpass[i].clear();
|
||||
Zs[i][1] = 0.0;
|
||||
Zs[i][2] = 0.0;
|
||||
filtOut[i] = 0.0;
|
||||
filtIn[i] = 0.0;
|
||||
}
|
||||
|
||||
R = (MY_FLOAT) 0.97;
|
||||
GAIN = (MY_FLOAT) 0.999;
|
||||
|
||||
slope = (MY_FLOAT) 3.0;
|
||||
|
||||
this->tuneBandPasses();
|
||||
}
|
||||
|
||||
BowedBar :: ~BowedBar()
|
||||
{
|
||||
delete bowTabl;
|
||||
delete adsr;
|
||||
delete [] bandpass;
|
||||
}
|
||||
|
||||
void BowedBar :: clear()
|
||||
{
|
||||
long i;
|
||||
|
||||
for(i = 0; i<NR_MODES; i++) {
|
||||
delay[i].clear();
|
||||
|
||||
bandpass[i].clear();
|
||||
Zs[i][1] = 0.0;
|
||||
Zs[i][2] = 0.0;
|
||||
filtOut[i] = 0.0;
|
||||
filtIn[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void BowedBar :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
int i;
|
||||
freq = frequency;
|
||||
|
||||
if(freq > 1568.0) freq = 1568.0;
|
||||
|
||||
length = (int)(SRATE/freq);
|
||||
|
||||
NR_MODES = 4;
|
||||
for(i = 0; i<NR_MODES; i++) {
|
||||
if((int)(length/modes[i]) > 4)
|
||||
delay[i].setDelay((int)(length/modes[i]));
|
||||
else {
|
||||
NR_MODES = i;
|
||||
break;
|
||||
}
|
||||
/* FIX THIS BETTER!!!!! */
|
||||
delay[i].clear();
|
||||
|
||||
bandpass[i].clear();
|
||||
Zs[i][1] = 0.0;
|
||||
Zs[i][2] = 0.0;
|
||||
filtOut[i] = 0.0;
|
||||
filtIn[i] = 0.0;
|
||||
}
|
||||
|
||||
tuneBandPasses();
|
||||
}
|
||||
|
||||
void BowedBar :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp2;
|
||||
temp2 = position * PI;
|
||||
gains[0] = fabs(sin(temp2 / 2) * pow(0.9,0));
|
||||
gains[1] = fabs(sin(temp2) * pow(0.9,1));
|
||||
gains[2] = fabs(sin(temp2 * 3 / 2) * pow(0.9,2));
|
||||
gains[3] = fabs(sin(temp2 * 2) * pow(0.9,3));
|
||||
}
|
||||
|
||||
void BowedBar :: tuneBandPasses()
|
||||
{
|
||||
long i;
|
||||
|
||||
for(i=0; i<NR_MODES; i++) {
|
||||
R = 1 - 6.28318530718 * freq * modes[i] / SRATE / 2.0;
|
||||
bandpass[i].setFreqAndReson(freq * modes[i], R);
|
||||
bandpass[i].setEqualGainZeroes();
|
||||
bandpass[i].setGain((1.0-R*R)/2.0);
|
||||
filtGain[i] = (MY_FLOAT) (1.0 - (R*R))/2.0;
|
||||
coeffs[i][1] = -R * R;
|
||||
coeffs[i][0] = 2.0 * R * cos(6.28318530718 * freq * modes[i] / SRATE);
|
||||
|
||||
delay[i].clear(); //(rand()) - 16384;
|
||||
}
|
||||
}
|
||||
|
||||
void BowedBar :: startBowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
adsr->setRate(rate);
|
||||
adsr->keyOn();
|
||||
maxVelocity = (MY_FLOAT) 0.03 + ((MY_FLOAT) 0.2 * amplitude);
|
||||
maxVelocity = (MY_FLOAT) 0.03 + ((MY_FLOAT) 0.5 * amplitude);
|
||||
}
|
||||
|
||||
void BowedBar :: stopBowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void BowedBar :: pluck(MY_FLOAT amplitude)
|
||||
{
|
||||
long i,j;
|
||||
int pluckLen;
|
||||
MY_FLOAT temp;
|
||||
Noise noise;
|
||||
|
||||
pluckLen = (int)(length/modes[NR_MODES-1]);
|
||||
for (j=1;j<pluckLen/2;j++) {
|
||||
temp = amplitude*2.0*noise.tick();
|
||||
for(i=0; i<NR_MODES; i++)
|
||||
delay[i].tick(temp*j/pluckLen*gains[i]);
|
||||
}
|
||||
for (j=pluckLen/2;j>0;j--) {
|
||||
temp = amplitude*2.0*noise.tick();
|
||||
for(i=0; i<NR_MODES; i++)
|
||||
delay[i].tick(temp*j/pluckLen*gains[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void BowedBar :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
if(!doPluck) {
|
||||
for(int i=0; i<NR_MODES ; i++)
|
||||
bandpass[i].clear();
|
||||
|
||||
this->startBowing(amp,amp * (MY_FLOAT) 0.001);
|
||||
this->setFreq(freq);
|
||||
doPluck = 0;
|
||||
#if defined(_debug_)
|
||||
printf("BowedBar : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
for(int i=0; i<NR_MODES ; i++)
|
||||
bandpass[i].clear();
|
||||
this->setFreq(freq);
|
||||
this->pluck(amp);
|
||||
doPluck = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void BowedBar :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
if(!doPluck) {
|
||||
this->stopBowing(((MY_FLOAT) 1.0 - amp) * (MY_FLOAT) 0.005);
|
||||
}
|
||||
#if defined(_debug_)
|
||||
printf("BowedBar : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT BowedBar :: tick()
|
||||
{
|
||||
long k;
|
||||
MY_FLOAT input;
|
||||
MY_FLOAT data;
|
||||
|
||||
data = 0.0;
|
||||
|
||||
input = 0.0;
|
||||
|
||||
if(integration_const == 0.0)
|
||||
velinput = 0.0;
|
||||
else
|
||||
velinput = integration_const * velinput;
|
||||
|
||||
for(k=0; k<NR_MODES; k++)
|
||||
{
|
||||
velinput += GAIN * delay[k].lastOut();
|
||||
}
|
||||
|
||||
if(trackVel) {
|
||||
bowvel *= 0.9995;
|
||||
bowvel += bowTarg;
|
||||
bowTarg *= 0.995;
|
||||
}
|
||||
else
|
||||
{
|
||||
bowvel = adsr->tick()*maxVelocity;
|
||||
}
|
||||
|
||||
if(doPluck)
|
||||
{
|
||||
input = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
input = bowvel - velinput;
|
||||
|
||||
input = input * bowTabl->lookup(input);
|
||||
|
||||
input = input/(MY_FLOAT)NR_MODES;
|
||||
}
|
||||
|
||||
for(k=0; k<NR_MODES; k++)
|
||||
{
|
||||
bandpass[k].tick(input*gains[k] + GAIN * delay[k].lastOut());
|
||||
delay[k].tick(bandpass[k].lastOut());
|
||||
data += bandpass[k].lastOut();
|
||||
}
|
||||
|
||||
lastOutput = data * 4.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void BowedBar :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("BowedBar : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_BowPressure_)
|
||||
{
|
||||
bowTabl->setSlope((MY_FLOAT) 10.0 - ((MY_FLOAT) 9.0 * value * NORM_7));
|
||||
slope = (MY_FLOAT) 10.0 - ((MY_FLOAT) 9.0 * value * NORM_7);
|
||||
}
|
||||
else if (number == __SK_BowPosition_)
|
||||
{
|
||||
this->setStrikePosition(value*NORM_7);
|
||||
}
|
||||
else if (number == __SK_Balance_) {
|
||||
bowPos = value * NORM_7;
|
||||
bowTarg += 0.02 * (bowPos - lastBowPos);
|
||||
lastBowPos = bowPos;
|
||||
adsr->setTarget(bowPos);
|
||||
}
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
{
|
||||
bowPos = value * NORM_7;
|
||||
bowTarg += 0.02 * (bowPos - lastBowPos);
|
||||
lastBowPos = bowPos;
|
||||
adsr->setTarget(bowPos);
|
||||
}
|
||||
else if (number == __SK_ModWheel_)
|
||||
{
|
||||
GAIN = 0.809 + (0.2 * (value * NORM_7));
|
||||
}
|
||||
else if(number == __SK_ModFrequency_)
|
||||
{
|
||||
integration_const = value * NORM_7;
|
||||
|
||||
}
|
||||
else if(number == __SK_Sustain_) {
|
||||
if(value < 65)
|
||||
doPluck = 1;
|
||||
else
|
||||
doPluck = 0;
|
||||
}
|
||||
else if(number == __SK_Portamento_) {
|
||||
if(value < 65)
|
||||
trackVel = 0;
|
||||
else
|
||||
trackVel = 1;
|
||||
}
|
||||
else {
|
||||
printf("BowedBar : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
134
src/Brass.cpp
Normal file
134
src/Brass.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/******************************************/
|
||||
/* Waveguide Brass Instrument Model ala */
|
||||
/* Cook (TBone, HosePlayer) */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = lipTension */
|
||||
/* CONTROL2 = slideLength */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Brass.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Brass :: Brass(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
delayLine = new DLineA(length);
|
||||
lipFilter = new LipFilt;
|
||||
dcBlock = new DCBlock;
|
||||
adsr = new ADSR;
|
||||
adsr->setAllTimes((MY_FLOAT) 0.005, (MY_FLOAT) 0.001, (MY_FLOAT) 1.0, (MY_FLOAT) 0.010);
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
|
||||
this->clear();
|
||||
|
||||
vibr->setFreq((MY_FLOAT) 6.137);
|
||||
vibrGain = (MY_FLOAT) 0.05; /* breath periodic vibrato component */
|
||||
|
||||
maxPressure = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
Brass :: ~Brass()
|
||||
{
|
||||
delete delayLine;
|
||||
delete lipFilter;
|
||||
delete dcBlock;
|
||||
delete adsr;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Brass :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
lipFilter->clear();
|
||||
dcBlock->clear();
|
||||
}
|
||||
|
||||
void Brass :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
slideTarget = (SRATE / frequency * (MY_FLOAT) 2.0) + (MY_FLOAT) 3.0;
|
||||
/* fudge correction for filter delays */
|
||||
delayLine->setDelay(slideTarget); /* we'll play a harmonic */
|
||||
lipTarget = frequency;
|
||||
lipFilter->setFreq(frequency);
|
||||
}
|
||||
|
||||
void Brass :: setLip(MY_FLOAT frequency)
|
||||
{
|
||||
lipFilter->setFreq(frequency);
|
||||
}
|
||||
|
||||
void Brass :: startBlowing(MY_FLOAT amplitude,MY_FLOAT rate)
|
||||
{
|
||||
adsr->setAttackRate(rate);
|
||||
maxPressure = amplitude;
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void Brass :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setReleaseRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Brass :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->startBlowing(amp, amp * (MY_FLOAT) 0.001);
|
||||
#if defined(_debug_)
|
||||
printf("Brass : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Brass :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBlowing(amp * (MY_FLOAT) 0.005);
|
||||
#if defined(_debug_)
|
||||
printf("Brass : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT Brass :: tick()
|
||||
{
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
breathPressure = maxPressure * adsr->tick();
|
||||
breathPressure += vibrGain * vibr->tick();
|
||||
lastOutput = delayLine->tick( /* bore delay */
|
||||
dcBlock->tick( /* block DC */
|
||||
lipFilter->tick((MY_FLOAT) 0.3 * breathPressure, /* mouth input */
|
||||
(MY_FLOAT) 0.85 * delayLine->lastOut()))); /* and bore reflection */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Brass :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
#if defined(_debug_)
|
||||
printf("Brass : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_LipTension_) {
|
||||
temp = lipTarget * (MY_FLOAT) pow(4.0,(2.0*value*NORM_7) - 1.0);
|
||||
this->setLip(temp);
|
||||
}
|
||||
else if (number == __SK_SlideLength_)
|
||||
delayLine->setDelay(slideTarget * ((MY_FLOAT) 0.5 + (value * NORM_7)));
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_ )
|
||||
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Brass : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
55
src/ByteSwap.cpp
Normal file
55
src/ByteSwap.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "ByteSwap.h"
|
||||
|
||||
void swap16(unsigned char *ptr)
|
||||
{
|
||||
register unsigned char val;
|
||||
|
||||
/* Swap 1st and 2nd bytes */
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+1);
|
||||
*(ptr+1) = val;
|
||||
}
|
||||
|
||||
void swap32(unsigned char *ptr)
|
||||
{
|
||||
register unsigned char val;
|
||||
|
||||
/* Swap 1st and 4th bytes */
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+3);
|
||||
*(ptr+3) = val;
|
||||
|
||||
/* Swap 2nd and 3rd bytes */
|
||||
ptr += 1;
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+1);
|
||||
*(ptr+1) = val;
|
||||
}
|
||||
|
||||
void swap64(unsigned char *ptr)
|
||||
{
|
||||
register unsigned char val;
|
||||
|
||||
/* Swap 1st and 8th bytes */
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+7);
|
||||
*(ptr+7) = val;
|
||||
|
||||
/* Swap 2nd and 7th bytes */
|
||||
ptr += 1;
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+5);
|
||||
*(ptr+5) = val;
|
||||
|
||||
/* Swap 3rd and 6th bytes */
|
||||
ptr += 1;
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+3);
|
||||
*(ptr+3) = val;
|
||||
|
||||
/* Swap 4th and 5th bytes */
|
||||
ptr += 1;
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+1);
|
||||
*(ptr+1) = val;
|
||||
}
|
||||
129
src/Clarinet.cpp
Normal file
129
src/Clarinet.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/******************************************/
|
||||
/* Waveguide Clarinet model ala Smith */
|
||||
/* after McIntyre, Schumacher, Woodhouse */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = reedStiffns */
|
||||
/* CONTROL2 = noiseGain */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Clarinet.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Clarinet :: Clarinet(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
delayLine = new DLineL(length);
|
||||
reedTable = new ReedTabl;
|
||||
reedTable->setOffset((MY_FLOAT) 0.7);
|
||||
reedTable->setSlope((MY_FLOAT) -0.3);
|
||||
filter = new OneZero;
|
||||
envelope = new Envelope;
|
||||
noise = new Noise;
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
|
||||
vibr->setFreq((MY_FLOAT) 5.735);
|
||||
outputGain = (MY_FLOAT) 1.0;
|
||||
noiseGain = (MY_FLOAT) 0.2;
|
||||
vibrGain = (MY_FLOAT) 0.1;
|
||||
}
|
||||
|
||||
Clarinet :: ~Clarinet()
|
||||
{
|
||||
delete delayLine;
|
||||
delete reedTable;
|
||||
delete filter;
|
||||
delete envelope;
|
||||
delete noise;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Clarinet :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
filter->tick((MY_FLOAT) 0.0);
|
||||
}
|
||||
|
||||
void Clarinet :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
delayLine->setDelay /* length - approx filter delay */
|
||||
((SRATE / frequency) * (MY_FLOAT) 0.5 - (MY_FLOAT) 1.5);
|
||||
}
|
||||
|
||||
void Clarinet :: startBlowing(MY_FLOAT amplitude,MY_FLOAT rate)
|
||||
{
|
||||
envelope->setRate(rate);
|
||||
envelope->setTarget(amplitude);
|
||||
}
|
||||
|
||||
void Clarinet :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
envelope->setRate(rate);
|
||||
envelope->setTarget((MY_FLOAT) 0.0);
|
||||
}
|
||||
|
||||
void Clarinet :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->startBlowing((MY_FLOAT) 0.55 + (amp * (MY_FLOAT) 0.30),amp * (MY_FLOAT) 0.005);
|
||||
outputGain = amp + (MY_FLOAT) 0.001;
|
||||
#if defined(_debug_)
|
||||
printf("Clarinet : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Clarinet :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBlowing(amp * (MY_FLOAT) 0.01);
|
||||
#if defined(_debug_)
|
||||
printf("Clarinet : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT Clarinet :: tick()
|
||||
{
|
||||
MY_FLOAT pressureDiff;
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
breathPressure = envelope->tick();
|
||||
breathPressure += breathPressure *
|
||||
noiseGain * noise->tick();
|
||||
breathPressure += breathPressure *
|
||||
vibrGain * vibr->tick();
|
||||
pressureDiff = filter->tick(delayLine->lastOut()); /* differential pressure */
|
||||
pressureDiff = (pressureDiff * (MY_FLOAT) -0.95) - breathPressure; /* of reflected and mouth */
|
||||
lastOutput = delayLine->tick(breathPressure + /* perform scattering */
|
||||
pressureDiff * reedTable->lookup(pressureDiff)); /* in economical way */
|
||||
lastOutput *= outputGain;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Clarinet :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Clarinet : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_ReedStiffness_)
|
||||
reedTable->setSlope((MY_FLOAT) -0.44 + ((MY_FLOAT) 0.26 * value * NORM_7));
|
||||
else if (number == __SK_NoiseLevel_)
|
||||
noiseGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.5);
|
||||
else if (number == __SK_AfterTouch_Cont_) {
|
||||
envelope->setValue(value * NORM_7);
|
||||
}
|
||||
else {
|
||||
printf("Clarinet : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
490
src/Controller.cpp
Normal file
490
src/Controller.cpp
Normal file
@@ -0,0 +1,490 @@
|
||||
/******************************************/
|
||||
/*
|
||||
Controller Class,
|
||||
by Gary P. Scavone, 2000
|
||||
|
||||
This object will accept control messages
|
||||
from a variety of sources, such as a MIDI
|
||||
port, scorefile, socket connection, or
|
||||
pipe. MIDI messages are retrieved with
|
||||
the RtMidi class. All other input sources
|
||||
(scorefile, socket, or pipe) are assumed
|
||||
to provide SKINI formatted messages.
|
||||
|
||||
For each call of getNextMessage(), the
|
||||
active input devices are queried to see
|
||||
if a new control message is available.
|
||||
Only one message per call is returned, so
|
||||
a subsequent call begins querying the
|
||||
next available device "after" the previously
|
||||
handled one.
|
||||
|
||||
This class is primarily for use in STK
|
||||
main() event loops.
|
||||
|
||||
One of my original goals in creating this class
|
||||
was to simplify the message acquisition process
|
||||
by removing all threads. If the windoze
|
||||
select() function behaved just like the unix one,
|
||||
that would have been possible. Since it does not
|
||||
(it can't be used to poll STDIN), I am using a
|
||||
thread to acquire messages from STDIN, which are
|
||||
then sent via a socket connection to the message
|
||||
socket server. Perhaps in the future, I will be
|
||||
able to simplify things.
|
||||
*/
|
||||
/******************************************/
|
||||
|
||||
#include "Controller.h"
|
||||
|
||||
Controller :: Controller(int inputMask)
|
||||
{
|
||||
source = inputMask;
|
||||
default_ticks = RT_BUFFER_SIZE;
|
||||
msg_index = 0;
|
||||
num_messages = 0;
|
||||
score = new SKINI11();
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
maxfd = 0;
|
||||
char msg[256];
|
||||
struct sockaddr_in mysocket;
|
||||
FD_ZERO(&mask);
|
||||
|
||||
/*
|
||||
The fd array is used to hold the file descriptors for
|
||||
all connected sockets. This saves some time incrementing
|
||||
through file descriptors when using select().
|
||||
*/
|
||||
for (int i=0; i<16; i++)
|
||||
fd[i] = 0;
|
||||
|
||||
if ( source & STK_MIDI )
|
||||
midi_input = new RtMidi();
|
||||
|
||||
/*
|
||||
If no input source is specified, we assume the input is coming
|
||||
from a SKINI scorefile. If any input source is specified, we
|
||||
will always check STDIN, even in STK_PIPE is not specified.
|
||||
This provides a means to exit cleanly when reading MIDI or
|
||||
in case a socket connection cannot be made after STK_SOCKET has
|
||||
been specified. The current means of polling STDIN is via a
|
||||
thread.
|
||||
*/
|
||||
if (source) {
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
if (pthread_create(&stdin_thread, NULL, stdinHandler, NULL)) {
|
||||
#elif defined(__OS_Win_)
|
||||
stdin_thread = _beginthread(stdinHandler, 0, NULL);
|
||||
if (stdin_thread == 0) {
|
||||
#endif
|
||||
sprintf(msg, "Controller: unable to create stdin socket thread!\n");
|
||||
throw StkError(msg, StkError::PROCESS_THREAD);
|
||||
}
|
||||
source |= STK_SOCKET;
|
||||
}
|
||||
|
||||
/* Let the user know that they can exit the program via the console
|
||||
if necessary.
|
||||
*/
|
||||
if ( !(source & STK_PIPE) && inputMask )
|
||||
printf("\nType `Exit<cr>' to quit.\n\n");
|
||||
|
||||
if ( source & STK_SOCKET ) {
|
||||
// Set up the socket server to accept remote connections
|
||||
#if defined(__OS_Win_) // Windoze-only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
sprintf(msg, "Controller: Wrong Windoze socket library version!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the server-side socket
|
||||
local_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (local_socket < 0) {
|
||||
sprintf(msg, "Controller: Couldn't create socket!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
|
||||
mysocket.sin_family=AF_INET;
|
||||
mysocket.sin_addr.s_addr=INADDR_ANY;
|
||||
mysocket.sin_port=htons(STK_SOCKET_PORT);
|
||||
|
||||
// Bind socket to the appropriate port and interface (INADDR_ANY)
|
||||
if (bind(local_socket, (struct sockaddr *)&mysocket, sizeof(mysocket)) < 0) {
|
||||
sprintf(msg, "Controller: Couldn't bind socket!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
|
||||
// Listen for one incoming connection
|
||||
if (listen(local_socket, 1) < 0) {
|
||||
sprintf(msg, "Controller: Couldn't set up listen on socket!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
if (inputMask & STK_SOCKET)
|
||||
// Only print the message if STK_SOCKET was initially specified
|
||||
printf("Listening for a connection on port %d\n\n", STK_SOCKET_PORT);
|
||||
|
||||
FD_SET(local_socket, &mask);
|
||||
if (local_socket > maxfd) maxfd = local_socket;
|
||||
}
|
||||
#endif // __STK_REALTIME
|
||||
}
|
||||
|
||||
Controller :: ~Controller()
|
||||
{
|
||||
delete score;
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
if ( source & STK_MIDI )
|
||||
delete midi_input;
|
||||
|
||||
if ( source & STK_SOCKET ) {
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
shutdown(local_socket,0);
|
||||
pthread_cancel(stdin_thread);
|
||||
pthread_join(stdin_thread, NULL);
|
||||
#elif defined(__OS_Win_)
|
||||
TerminateThread((HANDLE)stdin_thread,0);
|
||||
closesocket(local_socket);
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
#endif // __STK_REALTIME
|
||||
}
|
||||
|
||||
int Controller :: getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
MY_FLOAT Controller :: getByte2()
|
||||
{
|
||||
return byte2;
|
||||
}
|
||||
|
||||
MY_FLOAT Controller :: getByte3()
|
||||
{
|
||||
return byte3;
|
||||
}
|
||||
|
||||
MY_FLOAT Controller :: getChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
void Controller :: setDefaultTicks(long nSamples)
|
||||
{
|
||||
default_ticks = nSamples;
|
||||
}
|
||||
|
||||
int Controller :: getNextMessage()
|
||||
{
|
||||
#if defined(__STK_REALTIME_)
|
||||
static fd_set rmask;
|
||||
static struct timeval timeout = {0, 0};
|
||||
static int device = 0;
|
||||
static int nSockets = 0;
|
||||
static int fd_thread = 0;
|
||||
int checked = 0, i;
|
||||
char msg[256];
|
||||
#endif
|
||||
|
||||
// reset message type
|
||||
type = 0;
|
||||
|
||||
if (!source) {
|
||||
// no realtime flags ... assuming scorefile input
|
||||
memset(message[msg_index], 0, MESSAGE_LENGTH);
|
||||
if ( fgets(message[msg_index], MESSAGE_LENGTH, stdin) == 0 )
|
||||
return -1;
|
||||
goto have_message;
|
||||
}
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
if (num_messages > 0)
|
||||
goto have_message;
|
||||
|
||||
while (checked < nSockets+1) {
|
||||
|
||||
if ( source & STK_SOCKET ) {
|
||||
|
||||
rmask = mask;
|
||||
if (select(maxfd+1, &rmask, (fd_set *)0, (fd_set *)0, &timeout)) {
|
||||
// there is a file descriptor set
|
||||
|
||||
// check whether there's a new socket connection available
|
||||
if ( FD_ISSET(local_socket, &rmask) ) {
|
||||
// accept and service new connection
|
||||
int remote_socket=accept(local_socket, NULL, NULL);
|
||||
if (remote_socket < 0) {
|
||||
sprintf(msg, "Controller: Couldn't accept connection request!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
if (nSockets != 0)
|
||||
// print message for connections subsequent to "piping" socket
|
||||
printf("New socket connection made.\n\n");
|
||||
|
||||
// set the socket non-blocking
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
fcntl(remote_socket, F_SETFL, O_NONBLOCK);
|
||||
#elif defined(__OS_Win_)
|
||||
unsigned long non_block = 1;
|
||||
ioctlsocket(remote_socket, FIONBIO, &non_block);
|
||||
#endif
|
||||
|
||||
fd[nSockets] = remote_socket;
|
||||
if (nSockets == 0) fd_thread = remote_socket;
|
||||
nSockets++;
|
||||
FD_SET(remote_socket, &mask);
|
||||
if ( remote_socket > maxfd) maxfd = remote_socket;
|
||||
FD_CLR(local_socket, &rmask);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// check socket connections
|
||||
while (device < nSockets) {
|
||||
if (FD_ISSET(fd[device], &rmask)) {
|
||||
// this socket has data
|
||||
i = parseSocketData(fd[device]);
|
||||
if (i == 0) {
|
||||
// the socket connection closed
|
||||
nSockets--;
|
||||
if ( nSockets == 0 )
|
||||
return -1;
|
||||
if ( nSockets == 1 && FD_ISSET(fd_thread, &mask) ) {
|
||||
// the "piping" socket is still running
|
||||
if (source & STK_MIDI) {
|
||||
printf("MIDI input still running ... type 'Exit<cr>' to quit.\n\n");
|
||||
return 0;
|
||||
}
|
||||
else if (!(source & STK_PIPE) )
|
||||
return -1;
|
||||
}
|
||||
if (device < nSockets) {
|
||||
// move descriptors down in the list
|
||||
for (int j=device; j<nSockets; j++)
|
||||
fd[j] = fd[j+1];
|
||||
}
|
||||
device++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
device++;
|
||||
|
||||
if ( !strncmp(message[msg_index], "Exit", 4) || !strncmp(message[msg_index], "exit", 4) ) {
|
||||
// we have an "Exit" message ... ignore it
|
||||
msg_index++;
|
||||
return 0;
|
||||
}
|
||||
// not an "Exit" message ... parse it
|
||||
goto have_message;
|
||||
}
|
||||
device++;
|
||||
if (++checked >= nSockets+1) break;
|
||||
}
|
||||
}
|
||||
else { // no file descriptors were set
|
||||
device += nSockets;
|
||||
checked += nSockets;
|
||||
}
|
||||
}
|
||||
|
||||
// check MIDI
|
||||
if (device >= nSockets) {
|
||||
//printf("got here, nSockets = %d, checked = %d, device = %d\n", nSockets, checked, device);
|
||||
device = 0;
|
||||
if (source & STK_MIDI) {
|
||||
if ( midi_input->nextMessage() > 0 ) {
|
||||
// get MIDI message info
|
||||
type = midi_input->getType();
|
||||
channel = midi_input->getChannel();
|
||||
byte2 = midi_input->getByteTwo();
|
||||
byte3 = midi_input->getByteThree();
|
||||
return default_ticks;
|
||||
}
|
||||
}
|
||||
if (++checked >= nSockets+1) break;
|
||||
}
|
||||
}
|
||||
// if we get here, we checked all devices but found no messages
|
||||
return default_ticks;
|
||||
|
||||
#endif // __STK_REALTIME
|
||||
|
||||
have_message:
|
||||
|
||||
//printf("%s", message[msg_index]);
|
||||
long ticks;
|
||||
score->parseThis(message[msg_index++]);
|
||||
num_messages--;
|
||||
if (msg_index >= MAX_MESSAGES) msg_index = 0;
|
||||
type = score->getType();
|
||||
if (type > 0) {
|
||||
MY_FLOAT temp = score->getDelta();
|
||||
if ( temp >= 0.0 )
|
||||
ticks = (long) (temp * SRATE);
|
||||
else
|
||||
// negative delta times specify realtime messages
|
||||
ticks = default_ticks;
|
||||
|
||||
channel = score->getChannel();
|
||||
byte2 = score->getByteTwo();
|
||||
byte3 = score->getByteThree();
|
||||
}
|
||||
else {
|
||||
// Don't tick for comments or improperly formatted messages
|
||||
ticks = 0;
|
||||
}
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
int Controller :: parseSocketData(int fd)
|
||||
{
|
||||
/*
|
||||
Parsing the socket data buffer is complicated by the fact that
|
||||
multiple and sometimes incomplete socket messages can be returned
|
||||
from a single recv() call, especially during high socket activity.
|
||||
This method will read all data available from a socket connection,
|
||||
filling the message buffer. This is necessary because the select()
|
||||
function triggers on socket activity, not on the presence of
|
||||
(buffered) data. So, whenever activity is indicated, we need to
|
||||
grab all available data.
|
||||
*/
|
||||
|
||||
static char socket_buffer[MESSAGE_LENGTH];
|
||||
int index = 0, m = 0, bufsize = 0;
|
||||
int fill_msg;
|
||||
|
||||
fill_msg = (msg_index + num_messages) % MAX_MESSAGES;
|
||||
memset(message[fill_msg], 0, MESSAGE_LENGTH);
|
||||
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
errno = 0;
|
||||
while (bufsize != -1 && errno != EAGAIN) {
|
||||
#elif defined(__OS_Win_)
|
||||
while (bufsize != SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) {
|
||||
#endif
|
||||
while (index < bufsize) {
|
||||
message[fill_msg][m++] = socket_buffer[index];
|
||||
if (socket_buffer[index++] == '\n') {
|
||||
m = 0;
|
||||
num_messages++;
|
||||
fill_msg = (msg_index + num_messages) % MAX_MESSAGES;
|
||||
memset(message[fill_msg], 0, MESSAGE_LENGTH);
|
||||
}
|
||||
}
|
||||
index = 0;
|
||||
|
||||
// receive a new socket buffer
|
||||
memset(socket_buffer, 0, MESSAGE_LENGTH);
|
||||
bufsize = recv(fd, socket_buffer, MESSAGE_LENGTH, 0);
|
||||
if (bufsize == 0) {
|
||||
FD_CLR(fd, &mask);
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(fd);
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
|
||||
void *stdinHandler(void *)
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
|
||||
void stdinHandler(void *)
|
||||
|
||||
#endif
|
||||
{
|
||||
char message[MESSAGE_LENGTH];
|
||||
char msg[256];
|
||||
int local_socket;
|
||||
struct sockaddr_in server_address;
|
||||
|
||||
#if defined(__OS_Win_) // Windoze-only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
sprintf(msg, "Controller: Wrong Windoze socket library version!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the client-side socket
|
||||
local_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (local_socket < 0) {
|
||||
sprintf(msg, "Controller: Couldn't create socket!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
|
||||
struct hostent *hostp;
|
||||
hostp = gethostbyname("localhost");
|
||||
|
||||
// Fill in the address structure
|
||||
server_address.sin_family = AF_INET;
|
||||
memcpy((void *)&server_address.sin_addr, hostp->h_addr, hostp->h_length);
|
||||
server_address.sin_port = htons(STK_SOCKET_PORT);
|
||||
|
||||
// Connect to the server
|
||||
if (connect(local_socket, (struct sockaddr *)&server_address,
|
||||
sizeof(server_address) ) < 0) {
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(local_socket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(local_socket);
|
||||
#endif
|
||||
sprintf(msg, "Controller: Couldn't connect stdin socket thread to server!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
memset(message, 0, MESSAGE_LENGTH);
|
||||
if ( fgets(message, MESSAGE_LENGTH, stdin) == 0 )
|
||||
break;
|
||||
// check for an "Exit" message
|
||||
if ( !strncmp(message, "Exit", 4) || !strncmp(message, "exit", 4) )
|
||||
break;
|
||||
|
||||
if (send(local_socket, (const char *)message, strlen(message), 0) < 0) {
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(local_socket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(local_socket);
|
||||
#endif
|
||||
sprintf(msg, "Controller: connection to socket server failed!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(local_socket);
|
||||
_endthread();
|
||||
#else
|
||||
close(local_socket);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // __STK_REALTIME
|
||||
40
src/DCBlock.cpp
Normal file
40
src/DCBlock.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/*******************************************/
|
||||
/* DC Blocking Filter */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This guy is very helpful in, uh, */
|
||||
/* blocking DC. Needed because a simple */
|
||||
/* low-pass reflection filter allows DC */
|
||||
/* to build up inside recursive */
|
||||
/* structures. */
|
||||
/*******************************************/
|
||||
|
||||
#include "DCBlock.h"
|
||||
|
||||
DCBlock :: DCBlock()
|
||||
{
|
||||
inputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
|
||||
outputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
}
|
||||
|
||||
DCBlock :: ~DCBlock()
|
||||
{
|
||||
free(inputs);
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void DCBlock :: clear()
|
||||
{
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
inputs[0] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
MY_FLOAT DCBlock :: tick(MY_FLOAT sample)
|
||||
{
|
||||
outputs[0] = sample - inputs[0] + ((MY_FLOAT) 0.99 * outputs[0]);
|
||||
inputs[0] = sample;
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
107
src/DLineA.cpp
Normal file
107
src/DLineA.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*******************************************/
|
||||
/* AllPass Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96. */
|
||||
/* Revised by Gary P. Scavone, 1999. */
|
||||
/* */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation, and */
|
||||
/* interpolates fractional length using */
|
||||
/* an all-pass filter. This version is */
|
||||
/* more efficient for computing static */
|
||||
/* length delay lines (alpha and coeff */
|
||||
/* are computed only when the length */
|
||||
/* is set, there probably is a more */
|
||||
/* efficient computational form if alpha */
|
||||
/* is changed often (each sample)). */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineA.h"
|
||||
|
||||
DLineA :: DLineA()
|
||||
{
|
||||
long i;
|
||||
// Default max delay length set to 2047.
|
||||
length = 2048;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0;
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineA :: DLineA(long max_length)
|
||||
{
|
||||
long i;
|
||||
length = max_length;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0;
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineA :: ~DLineA()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineA :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
|
||||
lastIn = (MY_FLOAT) 0;
|
||||
lastOutput = (MY_FLOAT) 0;
|
||||
}
|
||||
|
||||
void DLineA :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
MY_FLOAT outPointer;
|
||||
|
||||
if (lag > length-1) { // if delay is too big,
|
||||
printf("DLineA: Delay length too big.\n");
|
||||
printf("Setting to maximum length of %ld.\n",length-1);
|
||||
outPointer = inPoint + 1.0; // force delay to max_length
|
||||
}
|
||||
else if (lag < 0.1) {
|
||||
printf("DLineA: Delays < 0.1 not possible with current structure.\n");
|
||||
printf("Setting delay length to 0.1.\n");
|
||||
outPointer = inPoint + 0.8999999999;
|
||||
}
|
||||
else
|
||||
outPointer = inPoint - lag + 1.0; // outPoint chases inpoint
|
||||
|
||||
if (outPointer < 0)
|
||||
outPointer += length; // modulo table length
|
||||
outPoint = (long) outPointer; // Integer part of delay
|
||||
alpha = 1.0 + outPoint - outPointer; // fractional part of delay
|
||||
|
||||
if (alpha == 0.0) { // exact integer delay
|
||||
outPoint -= 1;
|
||||
if (outPoint < 0) outPoint += length;
|
||||
}
|
||||
|
||||
if (alpha<0.1) { // Hack to avoid pole/zero
|
||||
outPoint += 1; // cancellation. Keeps allpass
|
||||
if (outPoint >= length) outPoint -= length;
|
||||
alpha += (MY_FLOAT) 1.0; // delay in range of .1 to 1.1
|
||||
}
|
||||
|
||||
coeff = ((MY_FLOAT) 1.0 - alpha) /
|
||||
((MY_FLOAT) 1.0 + alpha); // coefficient for all pass
|
||||
}
|
||||
|
||||
MY_FLOAT DLineA :: tick(MY_FLOAT sample) // Take sample, yield sample
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
inputs[inPoint++] = sample; // Write input sample
|
||||
if (inPoint == length) // Increment input pointer
|
||||
inPoint -= length; // modulo length
|
||||
temp = inputs[outPoint++]; // filter input
|
||||
if (outPoint == length) // Increment output pointer
|
||||
outPoint -= length; // modulo length
|
||||
lastOutput = -coeff * lastOutput; // delayed output
|
||||
lastOutput += lastIn + (coeff * temp); // input + delayed Input
|
||||
lastIn = temp;
|
||||
return lastOutput; // save output and return
|
||||
}
|
||||
172
src/DLineL.cpp
Normal file
172
src/DLineL.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
Linearly Interpolating Delay Line
|
||||
Object by Perry R. Cook 1995-96.
|
||||
Added methods by Julius Smith, 2000.
|
||||
|
||||
This one uses a delay line of maximum
|
||||
length specified on creation, and
|
||||
linearly interpolates fractional
|
||||
length. It is designed to be more
|
||||
efficient if the delay length is not
|
||||
changed very often.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineL.h"
|
||||
|
||||
DLineL :: DLineL()
|
||||
{
|
||||
// Default max delay length set to 2047.
|
||||
length = 2048;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
currentDelay = outPoint;
|
||||
}
|
||||
|
||||
DLineL :: DLineL(long max_length)
|
||||
{
|
||||
length = max_length;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
currentDelay = outPoint;
|
||||
}
|
||||
|
||||
DLineL :: ~DLineL()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineL :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0;
|
||||
}
|
||||
|
||||
void DLineL :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
MY_FLOAT outPointer;
|
||||
|
||||
if (lag > length-1) {
|
||||
// delay is too big,
|
||||
printf("DLineL: Delay length too big.\n");
|
||||
printf("Setting to maximum length of %ld.\n",length-1);
|
||||
// force delay to max_length
|
||||
outPointer = inPoint + 1;
|
||||
currentDelay = length - 1;
|
||||
}
|
||||
else {
|
||||
// read chases write
|
||||
outPointer = inPoint - lag;
|
||||
currentDelay = lag;
|
||||
}
|
||||
|
||||
while (outPointer<0)
|
||||
// modulo maximum length
|
||||
outPointer += length;
|
||||
|
||||
// integer part
|
||||
outPoint = (long) outPointer;
|
||||
// fractional part
|
||||
alpha = outPointer - outPoint;
|
||||
omAlpha = (MY_FLOAT) 1.0 - alpha;
|
||||
}
|
||||
|
||||
MY_FLOAT DLineL :: delay(void)
|
||||
{
|
||||
return currentDelay;
|
||||
}
|
||||
|
||||
MY_FLOAT DLineL :: energy(void)
|
||||
{
|
||||
int i;
|
||||
register MY_FLOAT e = 0;
|
||||
if (inPoint>=outPoint) {
|
||||
for (i=outPoint;i<inPoint;i++) {
|
||||
register MY_FLOAT t = inputs[i];
|
||||
e += t*t;
|
||||
}
|
||||
} else {
|
||||
for (i=outPoint;i<length;i++) {
|
||||
register MY_FLOAT t = inputs[i];
|
||||
e += t*t;
|
||||
}
|
||||
for (i=0;i<inPoint;i++) {
|
||||
register MY_FLOAT t = inputs[i];
|
||||
e += t*t;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
long DLineL :: currentInPoint(void)
|
||||
{
|
||||
return inPoint;
|
||||
}
|
||||
|
||||
long DLineL :: currentOutPoint(void)
|
||||
{
|
||||
return outPoint;
|
||||
}
|
||||
|
||||
MY_FLOAT DLineL :: contentsAt(int n)
|
||||
{
|
||||
int i = n;
|
||||
if (i<0) i=0;
|
||||
if (i>= length) i = length-1;
|
||||
if (i != n) {
|
||||
fprintf(stderr,
|
||||
"DLineL: contentsAt(%d) overflows length %ld delay line\n",
|
||||
n, length);
|
||||
}
|
||||
return inputs[i];
|
||||
}
|
||||
|
||||
MY_FLOAT DLineL :: contentsAtNowMinus(int n)
|
||||
{
|
||||
/* "Now" is always where inPoint points which is not yet written. */
|
||||
/* outPoint points to "now - delay". Thus, valid values for n are 1 to delay. */
|
||||
int i = n;
|
||||
if (i<1) i=1;
|
||||
if (i>length) i = length;
|
||||
if (i != n) {
|
||||
fprintf(stderr,
|
||||
"DLineL: contentsAtNowMinus(%d) overflows length %ld delay line\n"
|
||||
"Clipped\n", n,length);
|
||||
}
|
||||
int ndx = inPoint-i;
|
||||
if (ndx < 0) { /* Check for wraparound */
|
||||
ndx += length;
|
||||
if (ndx < 0 || ndx >= length)
|
||||
fprintf(stderr,"DLineL: contentsAtNowMinus(): can't happen\n");
|
||||
}
|
||||
return inputs[ndx];
|
||||
}
|
||||
|
||||
MY_FLOAT DLineL :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[inPoint++] = sample;
|
||||
|
||||
// Check for end condition
|
||||
if (inPoint == length)
|
||||
inPoint -= length;
|
||||
|
||||
// First 1/2 of interpolation
|
||||
lastOutput = inputs[outPoint++] * omAlpha;
|
||||
// Check for end condition
|
||||
if (outPoint<length) {
|
||||
// Second 1/2 of interpolation
|
||||
lastOutput += inputs[outPoint] * alpha;
|
||||
}
|
||||
else { // if at end ...
|
||||
// Second 1/2 of interpolation
|
||||
lastOutput += inputs[0] * alpha;
|
||||
outPoint -= length;
|
||||
}
|
||||
return lastOutput;
|
||||
}
|
||||
158
src/DLineN.cpp
Normal file
158
src/DLineN.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
Non-Interpolating Delay Line
|
||||
Object by Perry R. Cook 1995-96.
|
||||
Revised by Gary Scavone, 1999.
|
||||
Added methods by Julius Smith, 2000.
|
||||
|
||||
This one uses either a delay line of
|
||||
maximum length specified on creation
|
||||
or a default length of 2047 samples.
|
||||
A non-interpolating delay line is
|
||||
typically used in non-time varying
|
||||
(reverb) applications.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineN.h"
|
||||
|
||||
DLineN :: DLineN()
|
||||
{
|
||||
// Default max delay length set to 2047.
|
||||
length = 2048;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
currentDelay = outPoint;
|
||||
}
|
||||
|
||||
DLineN :: DLineN(long max_length)
|
||||
{
|
||||
// Writing before reading allows delays from 0 to length-1.
|
||||
// Thus, if we want to allow a delay of max_length, we need
|
||||
// a delay-line of length = max_length+1.
|
||||
length = max_length+1;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
currentDelay = outPoint;
|
||||
}
|
||||
|
||||
DLineN :: ~DLineN()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineN :: clear(void)
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0;
|
||||
}
|
||||
|
||||
void DLineN :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
if (lag > length-1) {
|
||||
// delay is too big
|
||||
printf("DLineN: Delay length too big ... setting to maximum length of %ld.\n",length-1);
|
||||
// force delay to max_length
|
||||
outPoint = inPoint + 1;
|
||||
currentDelay = length - 1;
|
||||
}
|
||||
else {
|
||||
outPoint = inPoint - (long) lag; // read chases write
|
||||
currentDelay = lag;
|
||||
}
|
||||
|
||||
while (outPoint<0) outPoint += length; // modulo maximum length
|
||||
}
|
||||
|
||||
MY_FLOAT DLineN :: delay(void)
|
||||
{
|
||||
return currentDelay;
|
||||
}
|
||||
|
||||
MY_FLOAT DLineN :: energy(void)
|
||||
{
|
||||
int i;
|
||||
register MY_FLOAT e = 0;
|
||||
if (inPoint>=outPoint) {
|
||||
for (i=outPoint;i<inPoint;i++) {
|
||||
register MY_FLOAT t = inputs[i];
|
||||
e += t*t;
|
||||
}
|
||||
} else {
|
||||
for (i=outPoint;i<length;i++) {
|
||||
register MY_FLOAT t = inputs[i];
|
||||
e += t*t;
|
||||
}
|
||||
for (i=0;i<inPoint;i++) {
|
||||
register MY_FLOAT t = inputs[i];
|
||||
e += t*t;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
long DLineN :: currentInPoint(void)
|
||||
{
|
||||
return inPoint;
|
||||
}
|
||||
|
||||
long DLineN :: currentOutPoint(void)
|
||||
{
|
||||
return outPoint;
|
||||
}
|
||||
|
||||
MY_FLOAT DLineN :: contentsAt(int n)
|
||||
{
|
||||
int i = n;
|
||||
if (i<0) i=0;
|
||||
if (i>= length) i = length-1;
|
||||
if (i != n) {
|
||||
fprintf(stderr,
|
||||
"DLineN: contentsAt(%d) overflows length %ld delay line\n",
|
||||
n, length);
|
||||
}
|
||||
return inputs[i];
|
||||
}
|
||||
|
||||
MY_FLOAT DLineN :: contentsAtNowMinus(int n)
|
||||
{
|
||||
/* "Now" is always where inPoint points which is not yet written. */
|
||||
/* outPoint points to "now - delay". Thus, valid values for n are 1 to delay. */
|
||||
|
||||
int i = n;
|
||||
if (i<1) i=1;
|
||||
if (i>length) i = length;
|
||||
if (i != n) {
|
||||
fprintf(stderr,
|
||||
"DLineN: contentsAtNowMinus(%d) overflows length %ld delay line\n"
|
||||
"Clipped\n", n, length);
|
||||
}
|
||||
int ndx = inPoint-i;
|
||||
if (ndx < 0) { /* Check for wraparound */
|
||||
ndx += length;
|
||||
if (ndx < 0 || ndx >= length)
|
||||
fprintf(stderr,"DLineN: contentsAtNowMinus(): can't happen\n");
|
||||
}
|
||||
return inputs[ndx];
|
||||
}
|
||||
|
||||
MY_FLOAT DLineN :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[inPoint++] = sample;
|
||||
|
||||
// Check for end condition
|
||||
if (inPoint == length)
|
||||
inPoint -= length;
|
||||
// Read out next value
|
||||
lastOutput = inputs[outPoint++];
|
||||
|
||||
if (outPoint>=length)
|
||||
outPoint -= length;
|
||||
return lastOutput;
|
||||
}
|
||||
183
src/DrumSynt.cpp
Normal file
183
src/DrumSynt.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/*******************************************/
|
||||
/* Master Class for Drum Synthesizer */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* This instrument contains a bunch of */
|
||||
/* RawWvIn objects, run through a bunch */
|
||||
/* of one-pole filters. All the */
|
||||
/* corresponding rawwave files have been */
|
||||
/* sampled at 22050 Hz. Thus, if the */
|
||||
/* compile-time SRATE = 22050, then */
|
||||
/* no interpolation is used. Otherwise, */
|
||||
/* the rawwave data is appropriately */
|
||||
/* interpolated for the current SRATE. */
|
||||
/* You can specify the maximum Polyphony */
|
||||
/* (maximum number of simultaneous voices)*/
|
||||
/* in a #define in the .h file. */
|
||||
/* */
|
||||
/* Modified for RawWvIn class */
|
||||
/* by Gary P. Scavone (4/99) */
|
||||
/*******************************************/
|
||||
|
||||
#include "DrumSynt.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Not really General MIDI yet. Coming soon. */
|
||||
unsigned char genMIDIMap[128] = { 0,0,0,0,0,0,0,0, // 0-7
|
||||
0,0,0,0,0,0,0,0, // 8-15
|
||||
0,0,0,0,0,0,0,0, // 16-23
|
||||
0,0,0,0,0,0,0,0, // 24-31
|
||||
0,0,0,0,1,0,2,0, // 32-39
|
||||
2,3,6,3,6,4,7,4, // 40-47
|
||||
5,8,5,0,0,0,10,0, // 48-55
|
||||
9,0,0,0,0,0,0,0, // 56-63
|
||||
0,0,0,0,0,0,0,0, // 64-71
|
||||
0,0,0,0,0,0,0,0, // 72-79
|
||||
0,0,0,0,0,0,0,0, // 80-87
|
||||
0,0,0,0,0,0,0,0, // 88-95
|
||||
0,0,0,0,0,0,0,0, // 96-103
|
||||
0,0,0,0,0,0,0,0, // 104-111
|
||||
0,0,0,0,0,0,0,0, // 112-119
|
||||
0,0,0,0,0,0,0,0}; // 120-127
|
||||
|
||||
char waveNames[DRUM_NUMWAVES][16] = {
|
||||
"dope.raw",
|
||||
"bassdrum.raw",
|
||||
"snardrum.raw",
|
||||
"tomlowdr.raw",
|
||||
"tommiddr.raw",
|
||||
"tomhidrm.raw",
|
||||
"hihatcym.raw",
|
||||
"ridecymb.raw",
|
||||
"crashcym.raw",
|
||||
"cowbell1.raw",
|
||||
"tambourn.raw"
|
||||
};
|
||||
|
||||
DrumSynt :: DrumSynt() : Instrmnt()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<DRUM_POLYPHONY;i++) {
|
||||
filters[i] = new OnePole;
|
||||
sounding[i] = -1;
|
||||
}
|
||||
/* This counts the number of sounding voices */
|
||||
numSounding = 0;
|
||||
|
||||
/* Print warning about aliasing if SRATE < 22050 */
|
||||
if (SRATE < 22050) {
|
||||
printf("\nWarning: DrumSynt is designed for sampling rates of\n");
|
||||
printf("22050 Hz or greater. You will likely encounter aliasing\n");
|
||||
printf("at the current sampling rate of %.0f Hz.\n\n", SRATE);
|
||||
}
|
||||
}
|
||||
|
||||
DrumSynt :: ~DrumSynt()
|
||||
{
|
||||
int i;
|
||||
for ( i=0; i<numSounding-1; i++ ) delete waves[i];
|
||||
for ( i=0; i<DRUM_POLYPHONY; i++ ) delete filters[i];
|
||||
}
|
||||
|
||||
|
||||
void DrumSynt :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
int i, notDone;
|
||||
int noteNum;
|
||||
int vel;
|
||||
char tempString[64];
|
||||
RawWvIn *tempWv;
|
||||
OnePole *tempFilt;
|
||||
|
||||
/* Yes I know, this is tres kludgey */
|
||||
noteNum = (int) ((12*log(freq/220)/log(2.0)) + 57.01);
|
||||
vel = (int) (amp * 127);
|
||||
|
||||
#if defined(_debug_)
|
||||
printf("NoteOn: %s vel=%i\n",waveNames[genMIDIMap[noteNum]],vel);
|
||||
#endif
|
||||
|
||||
notDone = -1;
|
||||
for (i=0;i<DRUM_POLYPHONY;i++) { /* Check first to see */
|
||||
if (sounding[i] == noteNum) notDone = i; /* if there's already */
|
||||
} /* one like this sounding */
|
||||
|
||||
if (notDone<0) { /* If not, then */
|
||||
if (numSounding == DRUM_POLYPHONY) { /* If we're already */
|
||||
delete waves[0]; /* at max polyphony, */
|
||||
filters[0]->clear(); /* then */
|
||||
tempWv = waves[0];
|
||||
tempFilt = filters[0];
|
||||
for (i=0;i<DRUM_POLYPHONY-1;i++) { /* preempt oldest */
|
||||
waves[i] = waves[i+1]; /* voice and */
|
||||
filters[i] = filters[i+1]; /* ripple all down */
|
||||
}
|
||||
waves[DRUM_POLYPHONY-1] = tempWv;
|
||||
filters[DRUM_POLYPHONY-1] = tempFilt;
|
||||
} else {
|
||||
numSounding += 1; /* otherwise just add one */
|
||||
}
|
||||
|
||||
sounding[numSounding-1] = noteNum; /* allocate new wave */
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
strcpy(tempString, RAWWAVE_PATH);
|
||||
strcat(tempString,"rawwaves/");
|
||||
strcat(tempString,waveNames[genMIDIMap[noteNum]]);
|
||||
waves[numSounding-1] = new RawWvIn(tempString, "oneshot");
|
||||
if (SRATE != 22050) {
|
||||
waves[numSounding-1]->setRate((MY_FLOAT) (22050.0/SRATE));
|
||||
}
|
||||
filters[numSounding-1]->setPole((MY_FLOAT) 0.999 - ((MY_FLOAT) vel * NORM_7 * 0.6));
|
||||
filters[numSounding-1]->setGain(vel / (MY_FLOAT) 128.0);
|
||||
}
|
||||
else {
|
||||
waves[notDone]->reset();
|
||||
filters[notDone]->setPole((MY_FLOAT) 0.999 - ((MY_FLOAT) vel * NORM_7 * 0.6));
|
||||
filters[notDone]->setGain(vel / (MY_FLOAT) 128.0);
|
||||
}
|
||||
|
||||
#if defined(_debug_)
|
||||
printf("Number Sounding = %i\n",numSounding);
|
||||
for (i=0;i<numSounding;i++) printf(" %i ",sounding[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void DrumSynt :: noteOff(MY_FLOAT amp)
|
||||
{ /* Set all sounding wave filter gains low */
|
||||
int i = 0;
|
||||
|
||||
while(i<numSounding) {
|
||||
filters[i]->setGain(amp*0.01);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT DrumSynt :: tick()
|
||||
{
|
||||
int j, i = 0;
|
||||
MY_FLOAT output = 0.0;
|
||||
OnePole *tempFilt;
|
||||
|
||||
while (i < numSounding) {
|
||||
output += filters[i]->tick(waves[i]->lastOut());
|
||||
if (waves[i]->informTick() == 1) {
|
||||
delete waves[i];
|
||||
tempFilt = filters[i];
|
||||
|
||||
for (j=i;j<numSounding-1;j++) {
|
||||
sounding[j] = sounding[j+1];
|
||||
waves[j] = waves[j+1];
|
||||
filters[j] = filters[j+1];
|
||||
}
|
||||
filters[j] = tempFilt;
|
||||
filters[j]->clear();
|
||||
sounding[j] = -1;
|
||||
numSounding -= 1;
|
||||
i -= 1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
122
src/Envelope.cpp
Normal file
122
src/Envelope.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*******************************************/
|
||||
/* Envelope Class, Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is the base class for envelopes. */
|
||||
/* This one is capable of ramping state */
|
||||
/* from where it is to a target value by */
|
||||
/* a rate. It also responds to simple */
|
||||
/* KeyOn and KeyOff messages, ramping to */
|
||||
/* 1.0 on keyon and to 0.0 on keyoff. */
|
||||
/* There are two tick (update value) */
|
||||
/* methods, one returns the value, and */
|
||||
/* other returns 0 if the envelope is at */
|
||||
/* the target value (the state bit). */
|
||||
/*******************************************/
|
||||
|
||||
#include "Envelope.h"
|
||||
|
||||
Envelope :: Envelope() : Object()
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
value = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 0.001;
|
||||
state = 0;
|
||||
}
|
||||
|
||||
Envelope :: ~Envelope()
|
||||
{
|
||||
}
|
||||
|
||||
void Envelope :: keyOn()
|
||||
{
|
||||
target = (MY_FLOAT) 1.0;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: keyOff()
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("negative rates not allowed!!, correcting\n");
|
||||
rate = -aRate;
|
||||
}
|
||||
else rate = aRate;
|
||||
}
|
||||
|
||||
void Envelope :: setTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("negative times not allowed!!, correcting\n");
|
||||
rate = ONE_OVER_SRATE / -aTime ;
|
||||
}
|
||||
else rate = ONE_OVER_SRATE / aTime ;
|
||||
}
|
||||
|
||||
void Envelope :: setTarget(MY_FLOAT aTarget)
|
||||
{
|
||||
target = aTarget;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: setValue(MY_FLOAT aValue)
|
||||
{
|
||||
state = 0;
|
||||
target = aValue;
|
||||
value = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT Envelope :: tick()
|
||||
{
|
||||
if (state) {
|
||||
if (target > value) {
|
||||
value += rate;
|
||||
if (value >= target) {
|
||||
value = target;
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
value -= rate;
|
||||
if (value <= target) {
|
||||
value = target;
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
int Envelope :: informTick()
|
||||
{
|
||||
this->tick();
|
||||
return state;
|
||||
}
|
||||
|
||||
MY_FLOAT Envelope :: lastOut()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/************ Test Main ************************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
long i;
|
||||
Envelope test;
|
||||
|
||||
test.setRate(0.15);
|
||||
test.keyOn();
|
||||
for (i=0;i<10;i++) printf("%lf\n",test.tick());
|
||||
test.setRate(0.1);
|
||||
test.setTarget(0.5);
|
||||
while (test.informTick()) printf("%lf\n",test.lastOut());
|
||||
test.setRate(0.05);
|
||||
test.keyOff();
|
||||
while(test.informTick()) printf("%lf\n",test.lastOut());
|
||||
}
|
||||
*/
|
||||
67
src/FIR.cpp
Normal file
67
src/FIR.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/********************************************/
|
||||
/*
|
||||
General Finite-Impulse-Response (FIR)
|
||||
Digital Filter Class
|
||||
by Julius Smith, 1997
|
||||
*/
|
||||
/********************************************/
|
||||
|
||||
#include "FIR.h"
|
||||
|
||||
FIR :: FIR(int theLength) : Object()
|
||||
{
|
||||
length = theLength;
|
||||
coeffs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
pastInputs = (MY_FLOAT *) calloc(2*length, sizeof(MY_FLOAT));
|
||||
piOffset = length;
|
||||
}
|
||||
|
||||
FIR :: ~FIR()
|
||||
{
|
||||
free(pastInputs);
|
||||
free(coeffs);
|
||||
}
|
||||
|
||||
void FIR :: clear()
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < 2*length; i++) {
|
||||
pastInputs[i] = 0;
|
||||
}
|
||||
piOffset = length;
|
||||
}
|
||||
|
||||
void FIR :: setCoeffs(MY_FLOAT *theCoeffs)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < length; i++) {
|
||||
coeffs[i] = theCoeffs[i];
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT FIR :: tick(MY_FLOAT input) {
|
||||
int i;
|
||||
lastOutput = input*coeffs[0];
|
||||
for (i=1; i<length; i++)
|
||||
lastOutput += coeffs[i] * pastInputs[piOffset-i]; // sample 0 unused
|
||||
pastInputs[piOffset++] = input;
|
||||
if (piOffset >= 2*length) { // sample 2*length-1 unused
|
||||
piOffset = length;
|
||||
for (i=0; i<length; i++)
|
||||
pastInputs[i] = pastInputs[length+i];
|
||||
}
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
|
||||
MY_FLOAT FIR :: getDelay(MY_FLOAT freq)
|
||||
{
|
||||
return delay;
|
||||
}
|
||||
|
||||
int FIR :: getLength(void)
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
56
src/FM4Alg3.cpp
Normal file
56
src/FM4Alg3.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/******************************************/
|
||||
/* Algorithm 3 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Alg 3 is : 4--\ */
|
||||
/* 3-->2-- + -->1-->Out */
|
||||
/* */
|
||||
/* Controls: control1 = total mod index */
|
||||
/* control2 = crossfade of two */
|
||||
/* modulators */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg3.h"
|
||||
|
||||
FM4Alg3 :: FM4Alg3() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
FM4Alg3 :: ~FM4Alg3()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg3 :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
temp = vibWave->tick() * modDepth * (MY_FLOAT) 0.2;
|
||||
waves[0]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[3]);
|
||||
|
||||
temp = gains[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
waves[1]->addPhaseOffset(temp);
|
||||
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
temp = ((MY_FLOAT) 1.0 - (control2 * (MY_FLOAT) 0.5)) *
|
||||
gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
twozero->tick(temp);
|
||||
|
||||
temp += control2 * (MY_FLOAT) 0.5 * gains[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp = temp * control1;
|
||||
|
||||
waves[0]->addPhaseOffset(temp);
|
||||
temp = gains[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
|
||||
lastOutput = temp * (MY_FLOAT) 0.5;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
53
src/FM4Alg4.cpp
Normal file
53
src/FM4Alg4.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/******************************************/
|
||||
/* Algorithm 4 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Alg 4 is : 4->3--\ */
|
||||
/* 2-- + -->1-->Out */
|
||||
/* */
|
||||
/* Controls: control1 = total mod index */
|
||||
/* control2 = crossfade of two */
|
||||
/* modulators */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg4.h"
|
||||
|
||||
FM4Alg4 :: FM4Alg4() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
FM4Alg4 :: ~FM4Alg4()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg4 :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
temp = vibWave->tick() * modDepth * (MY_FLOAT) 0.2;
|
||||
waves[0]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[3]);
|
||||
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
temp = gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
twozero->tick(temp);
|
||||
waves[2]->addPhaseOffset(temp);
|
||||
temp = ((MY_FLOAT) 1.0 - (control2 * (MY_FLOAT) 0.5)) *
|
||||
gains[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
temp += control2 * (MY_FLOAT) 0.5 * gains[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp = temp * control1;
|
||||
waves[0]->addPhaseOffset(temp);
|
||||
temp = gains[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
|
||||
lastOutput = temp * (MY_FLOAT) 0.5;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
53
src/FM4Alg5.cpp
Normal file
53
src/FM4Alg5.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/******************************************/
|
||||
/* Algorithm 5 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This connection topology is 2 simple */
|
||||
/* FM Pairs summed together, like: */
|
||||
/* */
|
||||
/* Alg 5 is : 4->3--\ */
|
||||
/* + --> Out */
|
||||
/* 2->1--/ */
|
||||
/* */
|
||||
/* Controls: control1 = mod index 1 */
|
||||
/* control2 = crossfade of two */
|
||||
/* outputs */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg5.h"
|
||||
|
||||
FM4Alg5 :: FM4Alg5() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
FM4Alg5 :: ~FM4Alg5()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg5 :: tick()
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
|
||||
temp = gains[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp = temp * control1;
|
||||
waves[0]->addPhaseOffset(temp);
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
temp = gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
twozero->tick(temp);
|
||||
waves[2]->addPhaseOffset(temp);
|
||||
temp = ((MY_FLOAT) 1.0 - (control2 * (MY_FLOAT) 0.5)) *
|
||||
gains[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
temp += control2 * (MY_FLOAT) 0.5 * gains[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
|
||||
temp2 = vibWave->tick() * modDepth; /* Calculate amplitude mod */
|
||||
temp = temp * ((MY_FLOAT) 1.0 + temp2); /* and apply it to output */
|
||||
|
||||
lastOutput = temp * (MY_FLOAT) 0.5;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
58
src/FM4Alg6.cpp
Normal file
58
src/FM4Alg6.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/******************************************/
|
||||
/* Algorithm 6 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This connection topology is three */
|
||||
/* Carriers and a common Modulator */
|
||||
/* */
|
||||
/* /->1 -\ */
|
||||
/* 4-|-->2 - +-> Out */
|
||||
/* \->3 -/ */
|
||||
/* */
|
||||
/* Controls: control1 = vowel */
|
||||
/* control2 = spectral tilt */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg6.h"
|
||||
|
||||
FM4Alg6 :: FM4Alg6() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
FM4Alg6 :: ~FM4Alg6()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg6 :: tick()
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
|
||||
temp = gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
temp2 = vibWave->tick() * modDepth * (MY_FLOAT) 0.1; /* Calculate frequency mod */
|
||||
|
||||
waves[0]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp2) * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp2) * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp2) * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp2) * ratios[3]);
|
||||
|
||||
waves[0]->addPhaseOffset(temp * mods[0]);
|
||||
waves[1]->addPhaseOffset(temp * mods[1]);
|
||||
waves[2]->addPhaseOffset(temp * mods[2]);
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
twozero->tick(temp);
|
||||
temp = gains[0] * tilt[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
temp += gains[1] * tilt[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp += gains[2] * tilt[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
|
||||
return temp * (MY_FLOAT) 0.33;
|
||||
}
|
||||
|
||||
void FM4Alg6 :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
|
||||
}
|
||||
47
src/FM4Alg8.cpp
Normal file
47
src/FM4Alg8.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/******************************************/
|
||||
/* Algorithm 8 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This connection topology is simple */
|
||||
/* Additive Synthesis, like: */
|
||||
/* */
|
||||
/* 1 --. */
|
||||
/* 2 -\| */
|
||||
/* +-> Out */
|
||||
/* 3 -/| */
|
||||
/* 4 -- */
|
||||
/* */
|
||||
/* Controls: control1 = op4 (fb) gain */
|
||||
/* control2 = op3 gain */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg8.h"
|
||||
|
||||
FM4Alg8 :: FM4Alg8() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
FM4Alg8 :: ~FM4Alg8()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg8 :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
temp = control1 * (MY_FLOAT) 2.0 * gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
twozero->tick(temp);
|
||||
temp += control2 * (MY_FLOAT) 2.0 * gains[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
temp += gains[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp += gains[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
|
||||
lastOutput = temp * (MY_FLOAT) 0.125;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
179
src/FM4Op.cpp
Normal file
179
src/FM4Op.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/*******************************************/
|
||||
/* Master Class for 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains 4 waves, */
|
||||
/* 4 adsr, and various state vars. */
|
||||
/* */
|
||||
/* The basic Chowning/Stanford FM patent */
|
||||
/* expired April 1995, but there exist */
|
||||
/* follow-on patents, mostly assigned to */
|
||||
/* Yamaha. If you are of the type who */
|
||||
/* should worry about this (making money) */
|
||||
/* worry away. */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
#include "FM4Op.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
FM4Op :: FM4Op()
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
MY_FLOAT tempCoeffs[2] = {(MY_FLOAT) 0.0, (MY_FLOAT) -1.0};
|
||||
adsr[0] = new ADSR;
|
||||
adsr[1] = new ADSR;
|
||||
adsr[2] = new ADSR;
|
||||
adsr[3] = new ADSR;
|
||||
twozero = new TwoZero;
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibWave = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
|
||||
vibWave->setFreq((MY_FLOAT) 6.0); /* should make this random?? */
|
||||
modDepth = (MY_FLOAT) 0.0;
|
||||
/* We don't make the waves here yet, because */
|
||||
/* we don't know what they will be. */
|
||||
baseFreq = (MY_FLOAT) 440.0;
|
||||
ratios[0] = (MY_FLOAT) 1.0;
|
||||
ratios[1] = (MY_FLOAT) 1.0;
|
||||
ratios[2] = (MY_FLOAT) 1.0;
|
||||
ratios[3] = (MY_FLOAT) 1.0;
|
||||
gains[0] = (MY_FLOAT) 1.0;
|
||||
gains[1] = (MY_FLOAT) 1.0;
|
||||
gains[2] = (MY_FLOAT) 1.0;
|
||||
gains[3] = (MY_FLOAT) 1.0;
|
||||
twozero->setZeroCoeffs(tempCoeffs);
|
||||
twozero->setGain((MY_FLOAT) 0.0);
|
||||
control1 = (MY_FLOAT) 1.0;
|
||||
control2 = (MY_FLOAT) 1.0;
|
||||
temp = (MY_FLOAT) 1.0;
|
||||
for (i=99;i>=0;i--) {
|
||||
__FM4Op_gains[i] = temp;
|
||||
temp *= (MY_FLOAT) 0.933033;
|
||||
}
|
||||
temp = (MY_FLOAT) 1.0;
|
||||
for (i=15;i>=0;i--) {
|
||||
__FM4Op_susLevels[i] = temp;
|
||||
temp *= (MY_FLOAT) 0.707101;
|
||||
}
|
||||
temp = (MY_FLOAT) 8.498186;
|
||||
for (i=0;i<32;i++) {
|
||||
__FM4Op_attTimes[i] = temp;
|
||||
temp *= (MY_FLOAT) 0.707101;
|
||||
}
|
||||
}
|
||||
|
||||
FM4Op :: ~FM4Op()
|
||||
{
|
||||
delete adsr[0];
|
||||
delete adsr[1];
|
||||
delete adsr[2];
|
||||
delete adsr[3];
|
||||
delete waves[0];
|
||||
delete waves[1];
|
||||
delete waves[2];
|
||||
delete waves[3];
|
||||
delete vibWave;
|
||||
delete twozero;
|
||||
}
|
||||
|
||||
void FM4Op :: loadWaves(char* wave1, char* wave2, char* wave3, char* wave4)
|
||||
{
|
||||
waves[0] = new RawWvIn(wave1,"looping");
|
||||
waves[1] = new RawWvIn(wave2,"looping");
|
||||
waves[2] = new RawWvIn(wave3,"looping");
|
||||
waves[3] = new RawWvIn(wave4,"looping");
|
||||
}
|
||||
void FM4Op :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
void FM4Op :: setRatio(int whichOne, MY_FLOAT ratio)
|
||||
{
|
||||
ratios[whichOne] = ratio;
|
||||
if (ratio>0.0)
|
||||
waves[whichOne]->setFreq(baseFreq * ratio);
|
||||
else
|
||||
waves[whichOne]->setFreq(ratio);
|
||||
}
|
||||
|
||||
void FM4Op :: setGain(int whichOne, MY_FLOAT gain)
|
||||
{
|
||||
gains[whichOne]=gain;
|
||||
}
|
||||
|
||||
void FM4Op :: keyOn()
|
||||
{
|
||||
adsr[0]->keyOn();
|
||||
adsr[1]->keyOn();
|
||||
adsr[2]->keyOn();
|
||||
adsr[3]->keyOn();
|
||||
}
|
||||
|
||||
void FM4Op :: keyOff()
|
||||
{
|
||||
adsr[0]->keyOff();
|
||||
adsr[1]->keyOff();
|
||||
adsr[2]->keyOff();
|
||||
adsr[3]->keyOff();
|
||||
}
|
||||
|
||||
void FM4Op :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->keyOff();
|
||||
#if defined(_debug_)
|
||||
printf("FM4Op : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FM4Op :: setModulationSpeed(MY_FLOAT mSpeed)
|
||||
{
|
||||
vibWave->setFreq(mSpeed);
|
||||
}
|
||||
|
||||
void FM4Op :: setModulationDepth(MY_FLOAT mDepth)
|
||||
{
|
||||
modDepth = mDepth;
|
||||
}
|
||||
|
||||
void FM4Op :: setControl1(MY_FLOAT cVal)
|
||||
{
|
||||
control1 = cVal * (MY_FLOAT) 2.0;
|
||||
}
|
||||
|
||||
void FM4Op :: setControl2(MY_FLOAT cVal)
|
||||
{
|
||||
control2 = cVal * (MY_FLOAT) 2.0;
|
||||
}
|
||||
|
||||
void FM4Op :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("FM4Op : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_Breath_) /* Control Change 2 */
|
||||
this->setControl1(value * NORM_7);
|
||||
else if (number == __SK_FootControl_) /* Control Change 4 */
|
||||
this->setControl2(value * NORM_7);
|
||||
else if (number == __SK_ModFrequency_) /* Control Change 11 */
|
||||
this->setModulationSpeed(value * NORM_7 * (MY_FLOAT) 12.0); /* 0 to 12 Hz */
|
||||
else if (number == __SK_ModWheel_) /* Control Change 1 */
|
||||
this->setModulationDepth(value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_) {
|
||||
//adsr[0]->setTarget(value * NORM_7);
|
||||
adsr[1]->setTarget(value * NORM_7);
|
||||
//adsr[2]->setTarget(value * NORM_7);
|
||||
adsr[3]->setTarget(value * NORM_7);
|
||||
}
|
||||
else {
|
||||
printf("FM4Op : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
136
src/FMVoices.cpp
Normal file
136
src/FMVoices.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/******************************************/
|
||||
/* Singing Voice Synthesis Subclass */
|
||||
/* of Algorithm 6 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/******************************************/
|
||||
|
||||
#include "FMVoices.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
FMVoices :: FMVoices() : FM4Alg6()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file1[128];
|
||||
char file2[128];
|
||||
char file3[128];
|
||||
char file4[128];
|
||||
strcpy(file1, RAWWAVE_PATH);
|
||||
strcpy(file2, RAWWAVE_PATH);
|
||||
strcpy(file3, RAWWAVE_PATH);
|
||||
strcpy(file4, RAWWAVE_PATH);
|
||||
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
|
||||
strcat(file2,"rawwaves/sinewave.raw"),
|
||||
strcat(file3,"rawwaves/sinewave.raw"),
|
||||
strcat(file4,"rawwaves/fwavblnk.raw"));
|
||||
|
||||
this->setRatio(0,(MY_FLOAT) 2.00);
|
||||
this->setRatio(1,(MY_FLOAT) 4.00);
|
||||
this->setRatio(2,(MY_FLOAT) 12.0);
|
||||
this->setRatio(3,(MY_FLOAT) 1.00);
|
||||
gains[3] = __FM4Op_gains[80];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.050,(MY_FLOAT) 0.050,
|
||||
__FM4Op_susLevels[15],(MY_FLOAT) 0.050);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.050,(MY_FLOAT) 0.050,
|
||||
__FM4Op_susLevels[15],(MY_FLOAT) 0.050);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.050,(MY_FLOAT) 0.050,
|
||||
__FM4Op_susLevels[15],(MY_FLOAT) 0.050);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.010,(MY_FLOAT) 0.010,
|
||||
__FM4Op_susLevels[15],(MY_FLOAT) 0.500);
|
||||
twozero->setGain((MY_FLOAT) 0.0);
|
||||
modDepth = (MY_FLOAT) 0.005;
|
||||
currentVowel = 0;
|
||||
tilt[0] = (MY_FLOAT) 1.0;
|
||||
tilt[1] = (MY_FLOAT) 0.5;
|
||||
tilt[2] = (MY_FLOAT) 0.2;
|
||||
mods[0] = (MY_FLOAT) 1.0;
|
||||
mods[1] = (MY_FLOAT) 1.1;
|
||||
mods[2] = (MY_FLOAT) 1.1;
|
||||
baseFreq = (MY_FLOAT) 110.0;
|
||||
this->setFreq((MY_FLOAT) 110.0);
|
||||
}
|
||||
|
||||
/* #include "phonTabl.h" */
|
||||
|
||||
extern double phonGains[32][2];
|
||||
extern double phonParams[32][4][3];
|
||||
extern char phonemes[32][4];
|
||||
|
||||
void FMVoices :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT temp, temp2 = 0.0;
|
||||
int tempi, tempi2 = 0;
|
||||
|
||||
if (currentVowel < 32) {
|
||||
tempi2 = currentVowel;
|
||||
temp2 = (MY_FLOAT) 0.9;
|
||||
}
|
||||
else if (currentVowel < 64) {
|
||||
tempi2 = currentVowel - 32;
|
||||
temp2 = (MY_FLOAT) 1.0;
|
||||
}
|
||||
else if (currentVowel < 96) {
|
||||
tempi2 = currentVowel - 64;
|
||||
temp2 = (MY_FLOAT) 1.1;
|
||||
}
|
||||
else if (currentVowel <= 128) {
|
||||
tempi2 = currentVowel - 96;
|
||||
temp2 = (MY_FLOAT) 1.2;
|
||||
}
|
||||
baseFreq = frequency;
|
||||
temp = (temp2 * (MY_FLOAT) phonParams[tempi2][0][0] / baseFreq) + (MY_FLOAT) 0.5;
|
||||
tempi = (int) temp;
|
||||
this->setRatio(0,(MY_FLOAT) tempi);
|
||||
temp = (temp2 * (MY_FLOAT) phonParams[tempi2][1][0] / baseFreq) + (MY_FLOAT) 0.5;
|
||||
tempi = (int) temp;
|
||||
this->setRatio(1,(MY_FLOAT) tempi);
|
||||
temp = (temp2 * (MY_FLOAT) phonParams[tempi2][2][0] / baseFreq) + (MY_FLOAT) 0.5;
|
||||
tempi = (int) temp;
|
||||
this->setRatio(2,(MY_FLOAT) tempi);
|
||||
gains[0] = (MY_FLOAT) 1.0; // pow(10.0,phonParams[tempi2][0][2] * 0.05);
|
||||
gains[1] = (MY_FLOAT) 1.0; // pow(10.0,phonParams[tempi2][1][2] * 0.05);
|
||||
gains[2] = (MY_FLOAT) 1.0; // pow(10.0,phonParams[tempi2][2][2] * 0.05);
|
||||
}
|
||||
|
||||
void FMVoices :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
tilt[0] = amp;
|
||||
tilt[1] = amp * amp;
|
||||
tilt[2] = amp * amp * amp;
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("FMVoices : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FMVoices :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
int tempi;
|
||||
|
||||
#if defined(_debug_)
|
||||
printf("FM4Op : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_Breath_)
|
||||
gains[3] = __FM4Op_gains[(int) (value * 0.78125)];
|
||||
else if (number == __SK_FootControl_) {
|
||||
tempi = (int) value;
|
||||
currentVowel = tempi;
|
||||
this->setFreq(baseFreq);
|
||||
}
|
||||
else if (number == __SK_ModFrequency_)
|
||||
this->setModulationSpeed(value * NORM_7 * (MY_FLOAT) 12.0); /* 0 to 12 Hz */
|
||||
else if (number == __SK_ModWheel_)
|
||||
this->setModulationDepth(value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_) {
|
||||
temp = value * NORM_7;
|
||||
tilt[0] = temp;
|
||||
tilt[1] = temp * temp;
|
||||
tilt[2] = temp * temp * temp;
|
||||
}
|
||||
else {
|
||||
printf("FM4Op : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
24
src/Filter.cpp
Normal file
24
src/Filter.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*******************************************/
|
||||
/* Filter Class, by Perry R. Cook, 1995-96*/
|
||||
/* This is the base class for all filters.*/
|
||||
/* To me, most anything is a filter, but */
|
||||
/* I'll be a little less general here, and*/
|
||||
/* define a filter as something which has */
|
||||
/* input(s), output(s), and gain. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
Filter :: Filter() : Object()
|
||||
{
|
||||
}
|
||||
|
||||
Filter :: ~Filter()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Filter :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
177
src/Flute.cpp
Normal file
177
src/Flute.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/******************************************/
|
||||
/* WaveGuide Flute ala Karjalainen, */
|
||||
/* Smith, Waryznyk, etc. */
|
||||
/* with polynomial Jet ala Cook */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = jetDelay */
|
||||
/* CONTROL2 = noiseGain */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Flute.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Flute :: Flute(MY_FLOAT lowestFreq)
|
||||
{
|
||||
long length;
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
boreDelay = new DLineL(length);
|
||||
length >>= 1;
|
||||
jetDelay = new DLineL(length);
|
||||
jetTable = new JetTabl;
|
||||
filter = new OnePole;
|
||||
dcBlock = new DCBlock;
|
||||
noise = new Noise;
|
||||
adsr = new ADSR;
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
|
||||
this->clear();
|
||||
|
||||
boreDelay->setDelay((MY_FLOAT) 100.0);
|
||||
jetDelay->setDelay((MY_FLOAT) 49.0);
|
||||
|
||||
filter->setPole((MY_FLOAT) 0.7 - ((MY_FLOAT) 0.1 * (MY_FLOAT) 22050.0 / SRATE));
|
||||
filter->setGain((MY_FLOAT) -1.0);
|
||||
vibr->setFreq((MY_FLOAT) 5.925);
|
||||
adsr->setAllTimes((MY_FLOAT) 0.005, (MY_FLOAT) 0.01, (MY_FLOAT) 0.8, (MY_FLOAT) 0.010);
|
||||
endRefl = (MY_FLOAT) 0.5;
|
||||
jetRefl = (MY_FLOAT) 0.5;
|
||||
noiseGain = (MY_FLOAT) 0.15; /* Breath pressure random component */
|
||||
vibrGain = (MY_FLOAT) 0.05; /* breath periodic vibrato component */
|
||||
jetRatio = (MY_FLOAT) 0.32;
|
||||
|
||||
maxPressure = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
Flute :: ~Flute()
|
||||
{
|
||||
delete jetDelay;
|
||||
delete boreDelay;
|
||||
delete jetTable;
|
||||
delete filter;
|
||||
delete dcBlock;
|
||||
delete noise;
|
||||
delete adsr;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Flute :: clear()
|
||||
{
|
||||
jetDelay->clear();
|
||||
boreDelay->clear();
|
||||
filter->clear();
|
||||
dcBlock->clear();
|
||||
}
|
||||
|
||||
void Flute :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
lastFreq = frequency * (MY_FLOAT) 0.66666; /* we're overblowing here */
|
||||
temp = SRATE / lastFreq - (MY_FLOAT) 2.0; /* Length - approx. filter delay */
|
||||
boreDelay->setDelay(temp); /* Length of bore tube */
|
||||
jetDelay->setDelay(temp * jetRatio); /* jet delay shorter */
|
||||
}
|
||||
|
||||
void Flute :: startBlowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
adsr->setAttackRate(rate);
|
||||
maxPressure = amplitude / (MY_FLOAT) 0.8;
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void Flute :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setReleaseRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Flute :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->startBlowing((MY_FLOAT) 1.1 + (amp * (MY_FLOAT) 0.20),amp * (MY_FLOAT) 0.02);
|
||||
outputGain = amp + (MY_FLOAT) 0.001;
|
||||
#if defined(_debug_)
|
||||
printf("Flute : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Flute :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBlowing(amp * (MY_FLOAT) 0.02);
|
||||
#if defined(_debug_)
|
||||
printf("Flute : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Flute :: setJetRefl(MY_FLOAT refl)
|
||||
{
|
||||
jetRefl = refl;
|
||||
}
|
||||
|
||||
void Flute :: setEndRefl(MY_FLOAT refl)
|
||||
{
|
||||
endRefl = refl;
|
||||
}
|
||||
|
||||
void Flute :: setJetDelay(MY_FLOAT aRatio)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = SRATE / lastFreq - (MY_FLOAT) 2.0; /* Length - approx. filter delay */
|
||||
jetRatio = aRatio;
|
||||
jetDelay->setDelay(temp * aRatio); /* Scaled by ratio */
|
||||
}
|
||||
|
||||
MY_FLOAT Flute :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
MY_FLOAT pressureDiff;
|
||||
MY_FLOAT randPressure;
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
breathPressure = maxPressure * adsr->tick(); /* Breath Pressure */
|
||||
randPressure = noiseGain * noise->tick(); /* Random Deviation */
|
||||
randPressure += vibrGain * vibr->tick(); /* + breath vibrato */
|
||||
randPressure *= breathPressure; /* All scaled by Breath Pressure */
|
||||
|
||||
temp = filter->tick(boreDelay->lastOut());
|
||||
temp = dcBlock->tick(temp); /* Block DC on reflection */
|
||||
pressureDiff = breathPressure + randPressure - /* Breath Pressure */
|
||||
(jetRefl * temp); /* - reflected */
|
||||
pressureDiff = jetDelay->tick(pressureDiff); /* Jet Delay Line */
|
||||
pressureDiff = jetTable->lookup(pressureDiff) /* Non-Lin Jet + reflected */
|
||||
+ (endRefl * temp);
|
||||
lastOutput = (MY_FLOAT) 0.3 * boreDelay->tick(pressureDiff); /* Bore Delay and "bell" filter */
|
||||
|
||||
lastOutput *= outputGain;
|
||||
return lastOutput;
|
||||
|
||||
}
|
||||
|
||||
void Flute :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Flute : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_JetDelay_)
|
||||
this->setJetDelay((MY_FLOAT) 0.08 + ((MY_FLOAT) 0.48 * value * NORM_7));
|
||||
else if (number == __SK_NoiseLevel_)
|
||||
noiseGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Flute : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
139
src/FormSwep.cpp
Normal file
139
src/FormSwep.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*******************************************/
|
||||
/* Sweepable Formant (2-pole) */
|
||||
/* Filter Class, by Perry R. Cook, 1995-96*/
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. This drives*/
|
||||
/* to a target at speed set by rate. */
|
||||
/*******************************************/
|
||||
|
||||
#include "FormSwep.h"
|
||||
|
||||
FormSwep :: FormSwep() : Filter()
|
||||
{
|
||||
outputs = (MY_FLOAT *) malloc(2 * sizeof(MY_FLOAT));
|
||||
poleCoeffs[0] = (MY_FLOAT) 0.0;
|
||||
poleCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
freq = (MY_FLOAT) 0.0;
|
||||
reson = (MY_FLOAT) 0.0;
|
||||
currentGain = (MY_FLOAT) 1.0;
|
||||
currentFreq = (MY_FLOAT) 0.0;
|
||||
currentReson = (MY_FLOAT) 0.0;
|
||||
targetGain = (MY_FLOAT) 1.0;
|
||||
targetFreq = (MY_FLOAT) 0.0;
|
||||
targetReson = (MY_FLOAT) 0.0;
|
||||
deltaGain = (MY_FLOAT) 0.0;
|
||||
deltaFreq = (MY_FLOAT) 0.0;
|
||||
deltaReson = (MY_FLOAT) 0.0;
|
||||
sweepState = (MY_FLOAT) 0.0;
|
||||
sweepRate = (MY_FLOAT) 0.002;
|
||||
dirty = 0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
FormSwep :: ~FormSwep()
|
||||
{
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void FormSwep :: clear()
|
||||
{
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
outputs[1] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setPoleCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
dirty = 0;
|
||||
poleCoeffs[0] = coeffs[0];
|
||||
poleCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void FormSwep :: setFreqAndReson(MY_FLOAT aFreq, MY_FLOAT aReson)
|
||||
{
|
||||
dirty = 0;
|
||||
reson = aReson;
|
||||
freq = aFreq;
|
||||
currentReson = aReson;
|
||||
currentFreq = aFreq;
|
||||
poleCoeffs[1] = - (reson * reson);
|
||||
poleCoeffs[0] = (MY_FLOAT) 2.0 * reson * (MY_FLOAT) cos(TWO_PI * freq / SRATE);
|
||||
}
|
||||
|
||||
void FormSwep :: setStates(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = 0;
|
||||
freq = aFreq;
|
||||
reson = aReson;
|
||||
gain = aGain;
|
||||
targetFreq = aFreq;
|
||||
targetReson = aReson;
|
||||
targetGain = aGain;
|
||||
currentFreq = aFreq;
|
||||
currentReson = aReson;
|
||||
currentGain = aGain;
|
||||
}
|
||||
|
||||
void FormSwep :: setTargets(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = 1;
|
||||
targetFreq = aFreq;
|
||||
targetReson = aReson;
|
||||
targetGain = aGain;
|
||||
deltaFreq = aFreq - currentFreq;
|
||||
deltaReson = aReson - currentReson;
|
||||
deltaGain = aGain - currentGain;
|
||||
sweepState = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setSweepRate(MY_FLOAT aRate)
|
||||
{
|
||||
sweepRate = aRate;
|
||||
}
|
||||
|
||||
void FormSwep :: setSweepTime(MY_FLOAT aTime)
|
||||
{
|
||||
sweepRate = ONE_OVER_SRATE / aTime;
|
||||
}
|
||||
|
||||
void FormSwep :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT FormSwep :: tick(MY_FLOAT sample) // Perform Filter Operation
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
if (dirty) {
|
||||
sweepState += sweepRate;
|
||||
if (sweepState>= 1.0) {
|
||||
sweepState = (MY_FLOAT) 1.0;
|
||||
dirty = 0;
|
||||
currentReson = targetReson;
|
||||
reson = targetReson;
|
||||
currentFreq = targetFreq;
|
||||
freq = targetFreq;
|
||||
currentGain = targetGain;
|
||||
gain = targetGain;
|
||||
}
|
||||
else {
|
||||
currentReson = reson + (deltaReson * sweepState);
|
||||
currentFreq = freq + (deltaFreq * sweepState);
|
||||
currentGain = gain + (deltaGain * sweepState);
|
||||
}
|
||||
poleCoeffs[1] = - (currentReson * currentReson);
|
||||
poleCoeffs[0] = (MY_FLOAT) 2.0 * currentReson *
|
||||
(MY_FLOAT) cos(TWO_PI * currentFreq / SRATE);
|
||||
}
|
||||
|
||||
temp = currentGain * sample;
|
||||
temp += poleCoeffs[0] * outputs[0];
|
||||
temp += poleCoeffs[1] * outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
outputs[0] = temp;
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
|
||||
68
src/HeavyMtl.cpp
Normal file
68
src/HeavyMtl.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/******************************************/
|
||||
/* Heavy Metal Synth Subclass */
|
||||
/* of Algorithm 3 (TX81Z) Subclass of */
|
||||
/* 3 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "HeavyMtl.h"
|
||||
|
||||
HeavyMtl :: HeavyMtl() : FM4Alg3()
|
||||
{
|
||||
char file1[128];
|
||||
char file2[128];
|
||||
char file3[128];
|
||||
char file4[128];
|
||||
strcpy(file1, RAWWAVE_PATH);
|
||||
strcpy(file2, RAWWAVE_PATH);
|
||||
strcpy(file3, RAWWAVE_PATH);
|
||||
strcpy(file4, RAWWAVE_PATH);
|
||||
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
|
||||
strcat(file2,"rawwaves/sinewave.raw"),
|
||||
strcat(file3,"rawwaves/sinewave.raw"),
|
||||
strcat(file4,"rawwaves/fwavblnk.raw"));
|
||||
|
||||
this->setRatio(0,(MY_FLOAT) (1.00 * 1.000));
|
||||
this->setRatio(1,(MY_FLOAT) (4.00 * 0.999));
|
||||
this->setRatio(2,(MY_FLOAT) (3.00 * 1.001));
|
||||
this->setRatio(3,(MY_FLOAT) (0.50 * 1.002));
|
||||
gains[0] = __FM4Op_gains[92];
|
||||
gains[1] = __FM4Op_gains[76];
|
||||
gains[2] = __FM4Op_gains[91];
|
||||
gains[3] = __FM4Op_gains[68];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.001,(MY_FLOAT) 1.0,(MY_FLOAT) 0.01);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.010,(MY_FLOAT) 1.0,(MY_FLOAT) 0.50);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.010,(MY_FLOAT) 0.005,(MY_FLOAT) 1.0,(MY_FLOAT) 0.20);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.030,(MY_FLOAT) 0.010,(MY_FLOAT) 0.2,(MY_FLOAT) 0.20);
|
||||
twozero->setGain((MY_FLOAT) 2.0);
|
||||
vibWave->setFreq((MY_FLOAT) 5.5);
|
||||
modDepth = (MY_FLOAT) 0.00;
|
||||
}
|
||||
|
||||
HeavyMtl :: ~HeavyMtl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void HeavyMtl :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
void HeavyMtl :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[92];
|
||||
gains[1] = amp * __FM4Op_gains[76];
|
||||
gains[2] = amp * __FM4Op_gains[91];
|
||||
gains[3] = amp * __FM4Op_gains[68];
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("HeavyMtl : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
45
src/Instrmnt.cpp
Normal file
45
src/Instrmnt.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/******************************************/
|
||||
/* Instrument SuperClass for Toolkit96 */
|
||||
/* Perry R. Cook, Princeton University */
|
||||
/******************************************/
|
||||
|
||||
#include "Instrmnt.h"
|
||||
|
||||
Instrmnt :: Instrmnt()
|
||||
{
|
||||
}
|
||||
|
||||
Instrmnt :: ~Instrmnt()
|
||||
{
|
||||
}
|
||||
|
||||
void Instrmnt :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
printf("Warning!! Instrument Class noteOn here!! %f %f\n",freq,amp);
|
||||
}
|
||||
|
||||
void Instrmnt :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
printf("Warning!! Instrument Class noteOff here!! %f\n",amp);
|
||||
}
|
||||
|
||||
void Instrmnt :: setFreq(MY_FLOAT freq)
|
||||
{
|
||||
printf("Warning!! Instrument Class setFreq here!! %f\n",freq);
|
||||
}
|
||||
|
||||
MY_FLOAT Instrmnt :: tick()
|
||||
{
|
||||
printf("Warning!! Instrument Class tick here!!\n");
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT Instrmnt :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Instrmnt :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
printf("Warning!! Instrument Class Control Change here!! %i %f\n",number,value);
|
||||
}
|
||||
166
src/JCRev.cpp
Normal file
166
src/JCRev.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/*******************************************/
|
||||
/* JVRev Reverb Subclass */
|
||||
/* by Tim Stilson, 1998 */
|
||||
/* based on CLM JCRev */
|
||||
/* Integrated into STK by Gary Scavone */
|
||||
/* */
|
||||
/* This is based on some of the famous */
|
||||
/* Stanford CCRMA reverbs (NRev, KipRev) */
|
||||
/* all based on the Chowning/Moorer/ */
|
||||
/* Schroeder reverberators, which use */
|
||||
/* networks of simple allpass and comb */
|
||||
/* delay filters. This particular */
|
||||
/* arrangement consists of 3 allpass */
|
||||
/* filters in series, followed by 4 comb */
|
||||
/* filters in parallel, an optional */
|
||||
/* lowpass filter, and two decorrelation */
|
||||
/* delay lines in parallel at the output. */
|
||||
/*******************************************/
|
||||
|
||||
#include "JCRev.h"
|
||||
|
||||
//#define LOWPASS
|
||||
|
||||
JCRev :: JCRev(MY_FLOAT T60)
|
||||
{
|
||||
/* These are the values from CLM's JCRev.ins ... I found that the
|
||||
impulse response sounded better with the shorter delay lengths.
|
||||
--Gary Scavone, 2/1998
|
||||
int lens[9] = {4799,4999,5399,5801,1051,337,113,573,487};
|
||||
*/
|
||||
int lens[9] = {1777,1847,1993,2137,389,127,43,211,179};
|
||||
int val, i;
|
||||
|
||||
if (SRATE < 44100.0) {
|
||||
double srscale = SRATE / 44100.0;
|
||||
for (i=0; i<9; i++) {
|
||||
val = (int) floor(srscale * lens[i]);
|
||||
if ((val & 1) == 0) val++;
|
||||
while (!this->isprime(val)) val += 2;
|
||||
lens[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<3; i++)
|
||||
{
|
||||
APdelayLine[i] = new DLineN(lens[i+4] + 2);
|
||||
APdelayLine[i]->setDelay(lens[i+4]);
|
||||
}
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
CdelayLine[i] = new DLineN(lens[i] + 2);
|
||||
CdelayLine[i]->setDelay(lens[i]);
|
||||
combCoeff[i] = pow(10,(-3 * lens[i] / (T60 * SRATE)));
|
||||
// printf("combCoeff[%d] = %f\n", i, combCoeff[i]);
|
||||
}
|
||||
outLdelayLine = new DLineN(lens[7] + 2);
|
||||
outLdelayLine->setDelay(lens[7]);
|
||||
outRdelayLine = new DLineN(lens[8] + 2);
|
||||
outRdelayLine->setDelay(lens[8]);
|
||||
allPassCoeff = 0.7;
|
||||
effectMix = 0.3;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
JCRev :: ~JCRev()
|
||||
{
|
||||
delete APdelayLine[0];
|
||||
delete APdelayLine[1];
|
||||
delete APdelayLine[2];
|
||||
delete CdelayLine[0];
|
||||
delete CdelayLine[1];
|
||||
delete CdelayLine[2];
|
||||
delete CdelayLine[3];
|
||||
delete outLdelayLine;
|
||||
delete outRdelayLine;
|
||||
}
|
||||
|
||||
void JCRev :: clear()
|
||||
{
|
||||
APdelayLine[0]->clear();
|
||||
APdelayLine[1]->clear();
|
||||
APdelayLine[2]->clear();
|
||||
CdelayLine[0]->clear();
|
||||
CdelayLine[1]->clear();
|
||||
CdelayLine[2]->clear();
|
||||
CdelayLine[3]->clear();
|
||||
outRdelayLine->clear();
|
||||
outLdelayLine->clear();
|
||||
lastOutL = 0.0;
|
||||
lastOutR = 0.0;
|
||||
combsum1=0.0;
|
||||
combsum2=0.0;
|
||||
combsum=0.0;
|
||||
}
|
||||
|
||||
void JCRev :: setEffectMix(MY_FLOAT mix)
|
||||
{
|
||||
effectMix = mix;
|
||||
}
|
||||
|
||||
MY_FLOAT JCRev :: lastOutput()
|
||||
{
|
||||
return (lastOutL + lastOutR) * 0.5;
|
||||
}
|
||||
|
||||
MY_FLOAT JCRev :: lastOutputL()
|
||||
{
|
||||
return lastOutL;
|
||||
}
|
||||
|
||||
MY_FLOAT JCRev :: lastOutputR()
|
||||
{
|
||||
return lastOutR;
|
||||
}
|
||||
|
||||
MY_FLOAT JCRev :: tick(MY_FLOAT input)
|
||||
{
|
||||
MY_FLOAT temp,temp0,temp1,temp2,temp3,temp4,temp5,temp6;
|
||||
MY_FLOAT filtout;
|
||||
|
||||
temp = APdelayLine[0]->lastOut();
|
||||
temp0 = allPassCoeff * temp;
|
||||
temp0 += input;
|
||||
APdelayLine[0]->tick(temp0);
|
||||
temp0 = -(allPassCoeff * temp0) + temp;
|
||||
|
||||
temp = APdelayLine[1]->lastOut();
|
||||
temp1 = allPassCoeff * temp;
|
||||
temp1 += temp0;
|
||||
APdelayLine[1]->tick(temp1);
|
||||
temp1 = -(allPassCoeff * temp1) + temp;
|
||||
|
||||
temp = APdelayLine[2]->lastOut();
|
||||
temp2 = allPassCoeff * temp;
|
||||
temp2 += temp1;
|
||||
APdelayLine[2]->tick(temp2);
|
||||
temp2 = -(allPassCoeff * temp2) + temp;
|
||||
|
||||
temp3 = temp2 + (combCoeff[0] * CdelayLine[0]->lastOut());
|
||||
temp4 = temp2 + (combCoeff[1] * CdelayLine[1]->lastOut());
|
||||
temp5 = temp2 + (combCoeff[2] * CdelayLine[2]->lastOut());
|
||||
temp6 = temp2 + (combCoeff[3] * CdelayLine[3]->lastOut());
|
||||
|
||||
CdelayLine[0]->tick(temp3);
|
||||
CdelayLine[1]->tick(temp4);
|
||||
CdelayLine[2]->tick(temp5);
|
||||
CdelayLine[3]->tick(temp6);
|
||||
|
||||
#ifdef LOWPASS
|
||||
combsum2=combsum1;
|
||||
combsum1=combsum;
|
||||
combsum = temp3+temp4+temp5+temp6;
|
||||
filtout= 0.5*combsum1+0.25*(combsum+combsum2);
|
||||
#else
|
||||
filtout = temp3+temp4+temp5+temp6;
|
||||
#endif
|
||||
|
||||
lastOutL = effectMix * (outLdelayLine->tick(filtout));
|
||||
lastOutR = effectMix * (outRdelayLine->tick(filtout));
|
||||
temp = (1.0 - effectMix) * input;
|
||||
lastOutL += temp;
|
||||
lastOutR += temp;
|
||||
|
||||
return (lastOutL + lastOutR) * 0.5;
|
||||
|
||||
}
|
||||
43
src/JetTabl.cpp
Normal file
43
src/JetTabl.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/**********************************************/
|
||||
/* Jet Table Object by Perry R. Cook, 1995-96 */
|
||||
/* Consult Fletcher and Rossing, Karjalainen, */
|
||||
/* Cook, more, for information. */
|
||||
/* This, as with many other of my "tables", */
|
||||
/* is not a table, but is computed by poly- */
|
||||
/* nomial calculation. */
|
||||
/**********************************************/
|
||||
|
||||
#include "JetTabl.h"
|
||||
|
||||
JetTabl :: JetTabl()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
JetTabl :: ~JetTabl()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: lookup(MY_FLOAT sample)
|
||||
{
|
||||
return this->tick(sample);
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: tick(MY_FLOAT sample)
|
||||
// Perform "Table Lookup"
|
||||
// By Polynomial Calculation
|
||||
{
|
||||
// (x^3 - x) approximates sigmoid of jet
|
||||
lastOutput = sample * (sample*sample - (MY_FLOAT) 1.0);
|
||||
if (lastOutput > 1.0)
|
||||
lastOutput = (MY_FLOAT) 1.0; // Saturation at +/- 1.0
|
||||
if (lastOutput < -1.0)
|
||||
lastOutput = (MY_FLOAT) -1.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
65
src/LipFilt.cpp
Normal file
65
src/LipFilt.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/************************************************/
|
||||
/* Lip Filter Object by Perry R. Cook, 1995-96 */
|
||||
/* The lip of the brass player has dynamics */
|
||||
/* which are controlled by the mass, spring */
|
||||
/* constant, and damping of the lip. This */
|
||||
/* filter simulates that behavior and the */
|
||||
/* transmission/reflection properties as */
|
||||
/* well. See Cook TBone and HosePlayer */
|
||||
/* instruments and articles. */
|
||||
/************************************************/
|
||||
|
||||
#include "LipFilt.h"
|
||||
|
||||
LipFilt :: LipFilt()
|
||||
{
|
||||
MY_FLOAT coeffs[2];
|
||||
filter = new BiQuad;
|
||||
coeffs[0] = (MY_FLOAT) 0.0;
|
||||
coeffs[1] = (MY_FLOAT) 0.0;
|
||||
filter->setZeroCoeffs(coeffs);
|
||||
this->clear();
|
||||
}
|
||||
|
||||
LipFilt :: ~LipFilt()
|
||||
{
|
||||
delete filter;
|
||||
}
|
||||
|
||||
void LipFilt :: clear()
|
||||
{
|
||||
filter->clear();
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void LipFilt :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT coeffs[2];
|
||||
coeffs[0] = (MY_FLOAT) 2.0 * (MY_FLOAT) 0.997 *
|
||||
(MY_FLOAT) cos(TWO_PI * frequency / SRATE); /* damping should change with */
|
||||
coeffs[1] = (MY_FLOAT) (-0.997 * 0.997); /* lip parameters, but not yet.*/
|
||||
filter->setPoleCoeffs(coeffs);
|
||||
filter->setGain((MY_FLOAT) 0.03);
|
||||
}
|
||||
|
||||
/* NOTE: Here we should add lip tension */
|
||||
/* settings based on Mass/Spring/Damping */
|
||||
|
||||
MY_FLOAT LipFilt :: tick(MY_FLOAT mouthSample,MY_FLOAT boreSample)
|
||||
/* Perform "Table Lookup" By Polynomial Calculation */
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = mouthSample - boreSample; /* Differential pressure */
|
||||
temp = filter->tick(temp); /* Force -> position */
|
||||
temp = temp*temp; /* Simple position to area mapping */
|
||||
if (temp > 1.0) temp = (MY_FLOAT) 1.0; /* Saturation at + 1.0 */
|
||||
lastOutput = temp * mouthSample; /* Assume mouth input = area */
|
||||
lastOutput += ((MY_FLOAT) 1.0 - temp) * boreSample; /* and Bore reflection is compliment. */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT LipFilt :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
410
src/MD2SKINI.cpp
Normal file
410
src/MD2SKINI.cpp
Normal file
@@ -0,0 +1,410 @@
|
||||
/*******************************************/
|
||||
/* Simple Realtime MIDI to SKINI Parser */
|
||||
/* Gary P. Scavone, February 1998. */
|
||||
/* Revised for sockets, May & June 1998. */
|
||||
/* SKINI/MIDI merge added August 1999. */
|
||||
/* */
|
||||
/* This object takes MIDI from the input */
|
||||
/* stream (via the MIDIIO class), */
|
||||
/* parses it, and turns it into SKINI */
|
||||
/* messages. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RtMidi.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
int outAHere = 0;
|
||||
|
||||
// Do OS dependent declarations and includes
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_t exit_thread;
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
|
||||
#include <process.h>
|
||||
#include <winsock.h>
|
||||
|
||||
unsigned long exit_thread;
|
||||
|
||||
#endif
|
||||
|
||||
// The thread function protocols are slightly different
|
||||
// under Windoze ... but of course!
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
|
||||
void *monitorStdin(void *)
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
|
||||
void monitorStdin(void *)
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
char inputString[128];
|
||||
printf("Type 'Exit<cr>' to quit.\n");
|
||||
while (!outAHere) {
|
||||
fgets(inputString, 128, stdin);
|
||||
if (inputString[3] == 't' && inputString[1] == 'x'
|
||||
&& inputString[2] == 'i' && inputString[0] == 'E') {
|
||||
outAHere = 1;
|
||||
}
|
||||
else {
|
||||
printf(inputString);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
#elif defined(__OS_Win_)
|
||||
_endthread();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void usage(void) {
|
||||
printf("useage: MD2SKINI <flag(s)>\n\n");
|
||||
printf(" With no arguments, MD2SKINI converts MIDI input to SKINI\n");
|
||||
printf(" format and sends the output directly to stdout.\n");
|
||||
printf(" With flag = -s <hostname>, the output is sent over a socket\n");
|
||||
printf(" connection to the optional hostname (default = localhost).\n");
|
||||
printf(" With flag = -f <filename>, the output stream is simultaneously\n");
|
||||
printf(" written to the file specified by the optional <filename>\n");
|
||||
printf(" (default = test.ski).\n\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
long j, i = 1;
|
||||
MY_FLOAT byte2, byte3;
|
||||
int channel;
|
||||
int firstMessage = 1;
|
||||
int writeFileOut = 0;
|
||||
FILE *fileOut = NULL;
|
||||
RtMidi *controller;
|
||||
char hostName[256];
|
||||
char fileName[256];
|
||||
int useSocket = 0;
|
||||
int theSocket = 0;
|
||||
struct sockaddr_in saServer;
|
||||
static struct timeval timeout = {0, 10000}; // ten millisecond
|
||||
|
||||
if (argc>5) {
|
||||
usage();
|
||||
}
|
||||
|
||||
// Parse the command-line arguments.
|
||||
while (i < argc) {
|
||||
if (argv[i][0] == '-') {
|
||||
switch(argv[i][1]) {
|
||||
|
||||
case 's':
|
||||
if ((i+1 < argc) && argv[i+1][0] != '-') {
|
||||
i++;
|
||||
strcpy(hostName,argv[i]);
|
||||
}
|
||||
else strcpy(hostName,"localhost");
|
||||
useSocket = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if ((i+1 < argc) && argv[i+1][0] != '-') {
|
||||
i++;
|
||||
strcpy(fileName,argv[i]);
|
||||
if (strstr(fileName,".ski") == NULL) strcat(fileName,".ski");
|
||||
}
|
||||
else strcpy(fileName,"test.ski");
|
||||
fileOut = fopen(fileName,"wb");
|
||||
writeFileOut = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else usage();
|
||||
i++;
|
||||
}
|
||||
|
||||
MY_FLOAT dt=0.0;
|
||||
try {
|
||||
controller = new RtMidi();
|
||||
}
|
||||
catch (StkError& m) {
|
||||
m.printMessage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// If using sockets, setup the client socket
|
||||
if (useSocket) {
|
||||
|
||||
#if defined(__OS_Win_) // Stupid Windoze only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
fprintf(stderr,"\n Wrong Windoze socket library version!\n");
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the client-side socket
|
||||
theSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (theSocket < 0) {
|
||||
fprintf(stderr,"Couldn't create socket ... aborting!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
struct hostent *hostp;
|
||||
|
||||
if ((hostp = gethostbyname(hostName)) == 0) {
|
||||
fprintf(stderr,"%s: unknown host ... aborting!\n", hostName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Fill in the address structure
|
||||
saServer.sin_family = AF_INET;
|
||||
memcpy((void *)&saServer.sin_addr, hostp->h_addr, hostp->h_length);
|
||||
saServer.sin_port = htons(2001); // Port number
|
||||
|
||||
// Connect to the server
|
||||
if(connect(theSocket, (struct sockaddr *)&saServer, sizeof(saServer)) < 0) {
|
||||
fprintf(stderr,"Socket connect failed ... aborting!\n");
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(theSocket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(theSocket);
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the exit thread.
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
if (pthread_create(&exit_thread, NULL, monitorStdin, NULL)) {
|
||||
fprintf(stderr, "Unable to create exit thread ... aborting.\n");
|
||||
exit(0);
|
||||
}
|
||||
#elif defined(__OS_Win_)
|
||||
exit_thread = _beginthread(monitorStdin, 0, NULL);
|
||||
if (exit_thread == -1) {
|
||||
fprintf(stderr, "Unable to create exit thread ... aborting.\n");
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write SKINI messages to buffer 's'. This is the easiest way
|
||||
to allow this single executable to work for both socketing
|
||||
and printf's to stdout.
|
||||
*/
|
||||
char s[128];
|
||||
|
||||
while (!outAHere) {
|
||||
if (controller->nextMessage() > 0) {
|
||||
byte3 = controller->getByteThree();
|
||||
byte2 = controller->getByteTwo();
|
||||
channel = controller->getChannel();
|
||||
if (writeFileOut) dt = controller->getDeltaTime();
|
||||
if (firstMessage) { /* first MIDI message time stamp is meaningless */
|
||||
dt = 0.0;
|
||||
firstMessage = 0;
|
||||
}
|
||||
|
||||
switch(controller->getType()) {
|
||||
case __SK_NoteOn_:
|
||||
if (byte3 < 1.0) {
|
||||
sprintf(s,"NoteOff\t\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,64.0);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"NoteOff\t\t%.3f %d %.1f %.1f\n",dt,channel,byte2,64.0);
|
||||
}
|
||||
} else {
|
||||
sprintf(s,"NoteOn\t\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"NoteOn\t\t%.3f %d %.1f %.1f\n",dt,channel,byte2,byte3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_NoteOff_:
|
||||
if (byte3 < 2.0) byte3 = 64.0;
|
||||
sprintf(s,"NoteOff\t\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"NoteOff\t\t%.3f %d %.1f %.1f\n",dt,channel,byte2,byte3);
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_PolyPressure_:
|
||||
sprintf(s,"PolyPressure\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"PolyPressure\t%.3f %d %.1f %.1f\n",dt,channel,byte2,byte3);
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_ControlChange_:
|
||||
j = (int) byte2;
|
||||
switch(j) {
|
||||
case __SK_Volume_:
|
||||
sprintf(s,"Volume\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"Volume\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_ModWheel_:
|
||||
sprintf(s,"ModWheel\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"ModWheel\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Breath_:
|
||||
sprintf(s,"Breath\t\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"Breath\t\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_FootControl_:
|
||||
sprintf(s,"FootControl\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"FootControl\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Portamento_:
|
||||
sprintf(s,"Portamento\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"Portamento\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Balance_:
|
||||
sprintf(s,"Balance\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"Balance\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Pan_:
|
||||
sprintf(s,"Pan\t\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"Pan\t\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Sustain_:
|
||||
sprintf(s,"Sustain\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"Sustain\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Expression_:
|
||||
sprintf(s,"Expression\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"Expression\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sprintf(s,"ControlChange\t%.3f %d %ld %.1f\n",0.0,channel,j,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"ControlChange\t%.3f %d %ld %.1f\n",dt,channel,j,byte3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_ProgramChange_:
|
||||
j = (int) byte2;
|
||||
sprintf(s,"ProgramChange\t%.3f %d %ld\n",0.0,channel,j);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"ProgramChange\t%.3f %d %ld\n",dt,channel,j);
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_ChannelPressure_:
|
||||
sprintf(s,"ChannelPressure\t%.3f %d %.1f\n",0.0,channel,byte2);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"ChannelPressure\t%.3f %d %.1f\n",dt,channel,byte2);
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_PitchBend_:
|
||||
sprintf(s,"PitchBend\t%.3f %d %f\n",0.0,channel,byte2);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"PitchBend\t%.3f %d %f\n",dt,channel,byte2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(s,"// Unknown\t%.3f %d %f %f\n",0.0,channel,byte2,byte3);
|
||||
if (writeFileOut) {
|
||||
fprintf(fileOut,"// Unknown\t\t%.3f %d %f %f\n",dt,channel,byte2,byte3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (useSocket) {
|
||||
if (send(theSocket, s, strlen(s), 0) < 0) {
|
||||
fprintf(stderr,"Socket connection failed ... aborting.\n");
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(theSocket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(theSocket);
|
||||
#endif
|
||||
outAHere = 1;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("%s", s);
|
||||
fflush(stdout);
|
||||
}
|
||||
memset(s, 0, sizeof(s));
|
||||
} else {
|
||||
// With Irix 5.3, you can no longer use the usleep()
|
||||
// function. And in Windoze, you can't use the select()
|
||||
// function to do timings. I love supporting multiple
|
||||
// platforms!
|
||||
#if defined(__OS_Win_)
|
||||
Sleep ( (DWORD) 5);
|
||||
#else
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 10000; // 0.01 seconds
|
||||
select(0, NULL, NULL, NULL, &timeout);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(s,"Exiting MD2SKINI process ... bye!\n");
|
||||
if (useSocket) {
|
||||
send(theSocket, s, strlen(s), 0);
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(theSocket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(theSocket);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
printf("%s", s);
|
||||
fflush(stdout);
|
||||
}
|
||||
if (writeFileOut) {
|
||||
printf("Wrote SKINI output to file %s.\n", fileName);
|
||||
fclose(fileOut);
|
||||
}
|
||||
delete controller;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
52
src/Makefile
Normal file
52
src/Makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
# stklib Makefile - for Linux or SGI with GNU Makefile utilities
|
||||
|
||||
LIBRARY = stklib.a
|
||||
AR = ar -qsc
|
||||
RM = /bin/rm
|
||||
INCLUDE = -I../include
|
||||
|
||||
OS = $(shell uname)
|
||||
|
||||
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
|
||||
Filter.o OneZero.o OnePole.o PoleZero.o DCBlock.o FIR.o \
|
||||
TwoZero.o TwoPole.o BiQuad.o DLineA.o DLineL.o DLineN.o \
|
||||
BowTabl.o JetTabl.o ReedTabl.o LipFilt.o TablLook.o \
|
||||
\
|
||||
Instrmnt.o Modal4.o ModalBar.o Shakers.o \
|
||||
Plucked.o Plucked2.o Mandolin.o Bowed.o Clarinet.o \
|
||||
Flute.o Brass.o BlowHole.o BowedBar.o \
|
||||
FM4Op.o FM4Alg3.o FM4Alg4.o FM4Alg5.o FM4Alg6.o FM4Alg8.o \
|
||||
Rhodey.o Wurley.o TubeBell.o HeavyMtl.o \
|
||||
PercFlut.o BeeThree.o DrumSynt.o Moog1.o \
|
||||
Sampler.o SamplFlt.o Simple.o SingWave.o \
|
||||
VoicForm.o FMVoices.o FormSwep.o Modulatr.o VoicMang.o \
|
||||
\
|
||||
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o RawWvOut.o AifWvOut.o \
|
||||
WvIn.o SndWvIn.o WavWvIn.o MatWvIn.o RawWvIn.o AifWvIn.o \
|
||||
StrmWvIn.o StrmWvOut.o \
|
||||
RtWvOut.o RtAudio.o RtWvIn.o RtMidi.o RtDuplex.o \
|
||||
Reverb.o PRCRev.o JCRev.o NRev.o \
|
||||
\
|
||||
SKINI11.o Controller.o ByteSwap.o StkError.o
|
||||
|
||||
ifeq ($(OS),IRIX) # These are for SGI
|
||||
CC = CC -D__OS_IRIX_
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Linux) # These are for Linux
|
||||
CC = g++ -O3 -Wall -D__OS_Linux_
|
||||
endif
|
||||
|
||||
%.o : %.cpp
|
||||
$(CC) $(INCLUDE) -c $(<) -o $@
|
||||
|
||||
debug all: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(O_FILES)
|
||||
/bin/rm -f $(LIBRARY)
|
||||
$(AR) $(LIBRARY) $(O_FILES)
|
||||
ranlib -t $(LIBRARY)
|
||||
|
||||
clean :
|
||||
rm *.o
|
||||
rm $(LIBRARY)
|
||||
152
src/Mandolin.cpp
Normal file
152
src/Mandolin.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/********************************************/
|
||||
/* Commuted Mandolin Subclass of enhanced */
|
||||
/* dual plucked-string model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = bodySize */
|
||||
/* CONTROL2 = pluckPosition */
|
||||
/* CONTROL3 = loopGain */
|
||||
/* MOD_WHEEL= deTuning */
|
||||
/* */
|
||||
/* Note: Commuted Synthesis, as with many */
|
||||
/* other WaveGuide techniques, is covered */
|
||||
/* by patents, granted, pending, and/or */
|
||||
/* applied-for. Many are assigned to the */
|
||||
/* Board of Trustees, Stanford University. */
|
||||
/* For information, contact the Office of */
|
||||
/* Technology Licensing, Stanford U. */
|
||||
/********************************************/
|
||||
|
||||
#include "Mandolin.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Mandolin :: Mandolin(MY_FLOAT lowestFreq) : Plucked2(lowestFreq)
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char temp[128];
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[0] = new RawWvIn(strcat(temp,"rawwaves/mand1.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[1] = new RawWvIn(strcat(temp,"rawwaves/mand2.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[2] = new RawWvIn(strcat(temp,"rawwaves/mand3.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[3] = new RawWvIn(strcat(temp,"rawwaves/mand4.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[4] = new RawWvIn(strcat(temp,"rawwaves/mand5.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[5] = new RawWvIn(strcat(temp,"rawwaves/mand6.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[6] = new RawWvIn(strcat(temp,"rawwaves/mand7.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[7] = new RawWvIn(strcat(temp,"rawwaves/mand8.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[8] = new RawWvIn(strcat(temp,"rawwaves/mand9.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[9] = new RawWvIn(strcat(temp,"rawwaves/mand10.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[10] = new RawWvIn(strcat(temp,"rawwaves/mand11.raw"),"oneshot");
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[11] = new RawWvIn(strcat(temp,"rawwaves/mand12.raw"),"oneshot");
|
||||
directBody = 1.0;
|
||||
mic = 0;
|
||||
dampTime = 0;
|
||||
waveDone = 1;
|
||||
}
|
||||
|
||||
Mandolin :: ~Mandolin()
|
||||
{
|
||||
}
|
||||
|
||||
void Mandolin :: pluck(MY_FLOAT amplitude)
|
||||
{ /* this function gets interesting here, */
|
||||
/* because pluck may be longer than */
|
||||
/* string length, so we just reset the */
|
||||
/* soundfile and add in the pluck in */
|
||||
/* the tick method. */
|
||||
soundfile[mic]->reset();
|
||||
pluckAmp = amplitude;
|
||||
/* Set Pick Position which puts zeroes at pos*length */
|
||||
combDelay->setDelay((MY_FLOAT) 0.5 * pluckPos * lastLength);
|
||||
dampTime = (long) lastLength; /* See tick method below */
|
||||
waveDone = 0;
|
||||
}
|
||||
|
||||
void Mandolin :: pluck(MY_FLOAT amplitude, MY_FLOAT position)
|
||||
{
|
||||
pluckPos = position; /* pluck position is zeroes at pos*length */
|
||||
this->pluck(amplitude);
|
||||
}
|
||||
|
||||
void Mandolin :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->pluck(amp);
|
||||
#if defined(_debug_)
|
||||
printf("Mandolin : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mandolin :: setBodySize(MY_FLOAT size)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<12;i++) {
|
||||
soundfile[i]->setRate(size);
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT Mandolin :: tick()
|
||||
{
|
||||
MY_FLOAT temp = (MY_FLOAT) 0;
|
||||
if (!waveDone) {
|
||||
waveDone = soundfile[mic]->informTick(); /* as long as it goes . . . */
|
||||
temp = soundfile[mic]->lastOut() * pluckAmp; /* scaled pluck excitation */
|
||||
temp = temp - combDelay->tick(temp); /* with comb filtering */
|
||||
}
|
||||
if (dampTime>=0) { /* Damping hack to help avoid */
|
||||
dampTime -= 1; /* overflow on replucking */
|
||||
lastOutput = delayLine->tick( /* Calculate 1st delay */
|
||||
filter->tick( /* filterered reflection */
|
||||
temp + /* plus pluck excitation */
|
||||
(delayLine->lastOut() * (MY_FLOAT) 0.7)));
|
||||
lastOutput += delayLine2->tick( /* and 2nd delay */
|
||||
filter2->tick( /* just like the 1st */
|
||||
temp +
|
||||
(delayLine2->lastOut() * (MY_FLOAT) 0.7)));
|
||||
}
|
||||
else { /* No damping hack after 1 period */
|
||||
lastOutput = delayLine->tick( /* Calculate 1st delay */
|
||||
filter->tick( /* filtered reflection */
|
||||
temp + /* plus pluck excitation */
|
||||
(delayLine->lastOut() * loopGain)));
|
||||
lastOutput += delayLine2->tick( /* and 2nd delay */
|
||||
filter2->tick( /* just like the 1st */
|
||||
temp +
|
||||
(delayLine2->lastOut() * loopGain)));
|
||||
}
|
||||
lastOutput *= (MY_FLOAT) 0.3;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Mandolin :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Mandolin : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_BodySize_)
|
||||
this->setBodySize(value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 2.0);
|
||||
else if (number == __SK_PickPosition_)
|
||||
this->setPluckPos(value * (MY_FLOAT) NORM_7);
|
||||
else if (number == __SK_StringDamping_)
|
||||
this->setBaseLoopGain((MY_FLOAT) 0.97 + (value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.03));
|
||||
else if (number == __SK_StringDetune_)
|
||||
this->setDetune((MY_FLOAT) 1.0 - (value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.1));
|
||||
else if (number == __SK_AfterTouch_)
|
||||
this->pluck(value * (MY_FLOAT) NORM_7);
|
||||
else if (number == 411) {
|
||||
mic = (int) value % 12;
|
||||
}
|
||||
else {
|
||||
printf("Mandolin : Undefined Control Number!! %i\n",number);
|
||||
}
|
||||
}
|
||||
235
src/MatWvIn.cpp
Normal file
235
src/MatWvIn.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/*******************************************/
|
||||
/* MatWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to open Matlab MAT-file data */
|
||||
/* (doubles) files for playback. In */
|
||||
/* order for this class to work, the */
|
||||
/* MAT-file must contain a single array */
|
||||
/* (matrix) of double-precision floating */
|
||||
/* point values (can be multi-channel). */
|
||||
/* It does not work for any other data */
|
||||
/* formats. */
|
||||
/* */
|
||||
/* MAT-file data is either big- or */
|
||||
/* little-endian, which can be determined */
|
||||
/* from the header. */
|
||||
/*******************************************/
|
||||
|
||||
#include "MatWvIn.h"
|
||||
#include "ByteSwap.h"
|
||||
|
||||
MatWvIn :: MatWvIn(char *fileName, char *mode)
|
||||
{
|
||||
char msg[256];
|
||||
|
||||
// check mode string
|
||||
if ( strcmp(mode,"oneshot") && strcmp(mode,"looping") ) {
|
||||
sprintf(msg, "MatWvIn: constructor parameter 'mode' must be oneshot or looping only.\n");
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
|
||||
// Open the file and get header info
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "MatWvIn: Couldn't open or find MAT-file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Make sure this is a version 5 MAT-file format and find its endian-ness
|
||||
char head[4];
|
||||
fseek(fd,0,SEEK_SET);
|
||||
fread(&head,4,1,fd); // If any of the first 4 characters of the header = 0,
|
||||
if (strstr(head,"0")) { // then this is a Version 4 MAT-file.
|
||||
fclose(fd);
|
||||
sprintf(msg, "MatWvIn: %s appears to be a Version 4 \nMAT-file, which is not currently supported.\n",
|
||||
fileName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
char mi[2];
|
||||
doSwap = 0;
|
||||
fseek(fd,126,SEEK_SET); // Locate "M" and "I" characters in header
|
||||
fread(&mi,2,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
if (!strncmp(mi,"MI",2)) {
|
||||
doSwap = 1;
|
||||
} else if (strncmp(mi,"IM",2)) {
|
||||
fclose(fd);
|
||||
sprintf(msg, "MatWvIn: %s doesn't appear to be a MAT-file.\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
#else
|
||||
if (!strncmp(mi,"IM",2)) {
|
||||
doSwap = 1;
|
||||
} else if (strncmp(mi,"MI",2)) {
|
||||
fclose(fd);
|
||||
sprintf(msg, "MatWvIn: %s doesn't appear to be a MAT-file.\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check the data element type
|
||||
INT32 datatype;
|
||||
fread(&datatype,4,1,fd);
|
||||
if (doSwap) swap32((unsigned char *)&datatype);
|
||||
if (datatype != 14) {
|
||||
fclose(fd);
|
||||
sprintf(msg, "MatWvIn: I'm expecting a single array (or matrix) data element.\n");
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
// Check the array data type
|
||||
INT32 tmp;
|
||||
INT32 size;
|
||||
fseek(fd,168,SEEK_SET);
|
||||
fread(&tmp,4,1,fd);
|
||||
if (doSwap) swap32((unsigned char *)&tmp);
|
||||
if (tmp == 1) { // array name > 4 characters
|
||||
fread(&tmp,4,1,fd); // get array name length
|
||||
if (doSwap) swap32((unsigned char *)&tmp);
|
||||
size = (INT32) ceil((float)tmp/8);
|
||||
fseek(fd,size*8,SEEK_CUR); // jump over array name
|
||||
}
|
||||
else { // array name <= 4 characters, compressed data element
|
||||
fseek(fd,4,SEEK_CUR);
|
||||
}
|
||||
fread(&tmp,4,1,fd);
|
||||
if (doSwap) swap32((unsigned char *)&tmp);
|
||||
if (tmp != 9) {
|
||||
fclose(fd);
|
||||
sprintf(msg, "MatWvIn: I'm expecting the array data to be in double precision floating-point format.\n");
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
// Get number of rows from the header
|
||||
INT32 rows;
|
||||
fseek(fd,160,SEEK_SET);
|
||||
fread(&rows,4,1,fd);
|
||||
if (doSwap) swap32((unsigned char *)&rows);
|
||||
|
||||
// Get number of columns from the header
|
||||
INT32 columns;
|
||||
fread(&columns,4,1,fd); // columns
|
||||
if (doSwap) swap32((unsigned char *)&columns);
|
||||
|
||||
// Make channels = smaller of rows or columns
|
||||
if (rows < columns) {
|
||||
channels = rows;
|
||||
fileSize = columns;
|
||||
interleaved = 1;
|
||||
}
|
||||
else {
|
||||
channels = columns;
|
||||
fileSize = rows;
|
||||
interleaved = 0;
|
||||
}
|
||||
bufferSize = fileSize;
|
||||
|
||||
if ((fileSize*channels) > MAX_FILE_LOAD_SIZE) {
|
||||
printf("\nMatWvIn: The MAT-file (%s) has more than %d samples and\n",
|
||||
fileName, MAX_FILE_LOAD_SIZE);
|
||||
printf("will be loaded incrementally from disk. Normalization will be disabled.\n");
|
||||
chunking = 1;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Setup for looping or one-shot playback
|
||||
if (!strcmp(mode,"looping"))
|
||||
looping = 1;
|
||||
else // default = oneshot
|
||||
looping = 0;
|
||||
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(bufferSize+1)*channels];
|
||||
|
||||
// Move read pointer to the data in the file
|
||||
INT32 headsize;
|
||||
fseek(fd,132,SEEK_SET);
|
||||
fread(&headsize,4,1,fd); // file size from 132nd byte
|
||||
if (doSwap) swap32((unsigned char *)&headsize);
|
||||
headsize -= fileSize * 8 * channels;
|
||||
fseek(fd,headsize,SEEK_CUR);
|
||||
dataOffset = ftell(fd);
|
||||
|
||||
this->getData(0); // Read samples into data[]
|
||||
|
||||
rate = (MY_FLOAT) 1.0;
|
||||
interpolate = 0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
this->reset();
|
||||
}
|
||||
|
||||
MatWvIn :: ~MatWvIn()
|
||||
{
|
||||
}
|
||||
|
||||
void MatWvIn :: getData(long index)
|
||||
{
|
||||
/* Compare index to current readPointer and modify as needed.
|
||||
* The following while() loops will only execute on calls subsequent
|
||||
* to class instantiation ... and thus, only when "chunking".
|
||||
*/
|
||||
while (index < readPointer) {
|
||||
readPointer -= LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer < 0) {
|
||||
bufferSize += readPointer;
|
||||
readPointer = 0;
|
||||
}
|
||||
}
|
||||
while (index >= readPointer+bufferSize) {
|
||||
readPointer += LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer+LOAD_BUFFER_SIZE >= fileSize) {
|
||||
bufferSize = fileSize - readPointer;
|
||||
}
|
||||
}
|
||||
|
||||
long length = bufferSize;
|
||||
int end_of_file = (readPointer+bufferSize == fileSize);
|
||||
if (!end_of_file) length += 1;
|
||||
|
||||
// Read samples into data[]. Use MY _FLOAT data structure to store doubles
|
||||
double *buf = (double *)data;
|
||||
if (interleaved) {
|
||||
fseek(fd, dataOffset+(long)(readPointer*channels*8), SEEK_SET);
|
||||
fread(data, 8, length*channels, fd);
|
||||
for (int i=length*channels-1; i>=0; i--) {
|
||||
if (doSwap)
|
||||
swap64((unsigned char *)(buf+i));
|
||||
data[i] = buf[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
long i = 0;
|
||||
long j = 0;
|
||||
double temp;
|
||||
fseek(fd, dataOffset+(long)(readPointer*8), SEEK_SET);
|
||||
while (j < channels) {
|
||||
fread(&temp,8,1,fd);
|
||||
if (doSwap) swap64((unsigned char *)&temp);
|
||||
data[channels*i+j] = (MY_FLOAT) temp;
|
||||
i++;
|
||||
if (i>=length) {
|
||||
i = 0;
|
||||
j++;
|
||||
fseek(fd, dataOffset+(long)(((j*fileSize)+readPointer)*8), SEEK_SET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fill in the extra sample frame for interpolation
|
||||
if (end_of_file) {
|
||||
for (int j=0; j<channels; j++)
|
||||
if (looping)
|
||||
data[bufferSize*channels+j] = data[j];
|
||||
else
|
||||
data[bufferSize*channels+j] = data[(bufferSize-1)*channels+j];
|
||||
}
|
||||
|
||||
if (!chunking) {
|
||||
fclose(fd);
|
||||
fd = 0;
|
||||
}
|
||||
}
|
||||
196
src/MatWvOut.cpp
Normal file
196
src/MatWvOut.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/*******************************************/
|
||||
/* Matlab MAT-file Output Class, */
|
||||
/* by Gary P. Scavone, 1999. */
|
||||
/* This object creates a Matlab MAT-file */
|
||||
/* structure with a numeric array */
|
||||
/* subelement and fills it with buffers */
|
||||
/* of samples (doubles). */
|
||||
/* */
|
||||
/* When originally created, the Matlab */
|
||||
/* MAT-file format was not public and I */
|
||||
/* had to reverse-engineer the format. */
|
||||
/* Matlab finally released the format in */
|
||||
/* the Spring of 1999, and this class was */
|
||||
/* updated to more closely adhere to */
|
||||
/* specifications. */
|
||||
/*******************************************/
|
||||
|
||||
#include "MatWvOut.h"
|
||||
|
||||
/******** Matlab Matfile Header Struct *******/
|
||||
struct matheaderform {
|
||||
char heading[124]; // Header text field
|
||||
INT16 hff[2]; // Header flag fields
|
||||
INT32 adf[11]; // Array data format fields
|
||||
// There's more, but it's of variable length
|
||||
};
|
||||
|
||||
FILE *openMatFile(int chans,char *fileName) {
|
||||
struct matheaderform hdr;
|
||||
FILE *fd;
|
||||
char tempName[128];
|
||||
char arrayName[128];
|
||||
char msg[256];
|
||||
int i;
|
||||
INT32 tmp, headsize, namelen;
|
||||
|
||||
strcpy(hdr.heading,"MATLAB 5.0 MAT-file, Generated using the Synthesis ToolKit (STK). By Gary P. Scavone, CCRMA, Stanford University, 1999.");
|
||||
|
||||
for (i=strlen(hdr.heading);i<124;i++) hdr.heading[i] = ' ';
|
||||
|
||||
// Header Flag Fields
|
||||
hdr.hff[0] = (INT16) 0x0100; // Version field
|
||||
hdr.hff[1] = (INT16) 'M'; // Endian indicator field ("MI")
|
||||
hdr.hff[1] <<= 8;
|
||||
hdr.hff[1] += 'I';
|
||||
|
||||
hdr.adf[0] = (INT32) 14; // Matlab array data type value
|
||||
hdr.adf[1] = (INT32) 0; // Size of file after this point to end (in bytes)
|
||||
// Don't know size yet.
|
||||
|
||||
// Numeric Array Subelements (4):
|
||||
// 1. Array Flags
|
||||
hdr.adf[2] = (INT32) 6; // Matlab 32-bit unsigned integer data type value
|
||||
hdr.adf[3] = (INT32) 8; // 8 bytes of data to follow
|
||||
hdr.adf[4] = (INT32) 6; // Double-precision array, no array flags set
|
||||
hdr.adf[5] = (INT32) 0; // 4 bytes undefined
|
||||
// 2. Array Dimensions
|
||||
hdr.adf[6] = (INT32) 5; // Matlab 32-bit signed integer data type value
|
||||
hdr.adf[7] = (INT32) 8; // 8 bytes of data to follow (2D array)
|
||||
hdr.adf[8] = (INT32) chans; // This is the number of rows
|
||||
hdr.adf[9] = (INT32) 0; // This is the number of columns
|
||||
|
||||
// 3. Array Name
|
||||
// We'll use fileName for the matlab array name (as well as the file name).
|
||||
// If fileName is 4 characters or less, we have to use a compressed data element
|
||||
// format for the array name data element. Otherwise, the array name must
|
||||
// be formatted in 8-byte increments (up to 31 characters + NULL).
|
||||
namelen = strlen(fileName);
|
||||
if (strstr(fileName,".mat")) namelen -= 4;
|
||||
if (namelen > 31) { // Check length of array name
|
||||
namelen = 31;
|
||||
printf("File name too long for MATLAB array name.\n");
|
||||
printf("Using first 31 characters only.\n");
|
||||
}
|
||||
|
||||
strncpy(arrayName,fileName,namelen);
|
||||
if (namelen > 4) {
|
||||
hdr.adf[10] = 1; // Matlab 8-bit signed integer data type value
|
||||
}
|
||||
else { // Compressed data element format
|
||||
hdr.adf[10] = namelen;
|
||||
hdr.adf[10] <<=16;
|
||||
hdr.adf[10] += 1;
|
||||
}
|
||||
headsize = 40; // Number of bytes in data element so far
|
||||
|
||||
// Format file name
|
||||
strcpy(tempName,fileName);
|
||||
if (strstr(tempName,".mat")==NULL) strcat(tempName,".mat");
|
||||
|
||||
// Open file and write fixed header information
|
||||
fd = fopen(tempName,"w+b");
|
||||
if (!fd) {
|
||||
sprintf(msg, "MatWvOut: Could not create soundfile: %s\n", tempName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
arrayName[namelen] = '\0';
|
||||
printf("\nCreating MAT-file (%s) with MATLAB array: %s\n", tempName, arrayName);
|
||||
fwrite(&hdr,sizeof(char),172,fd); // Write the fixed portion of the header
|
||||
|
||||
// Write MATLAB array name
|
||||
if (namelen > 4) {
|
||||
fwrite(&namelen,sizeof(INT32),1,fd); // Size of array name in bytes (chars)
|
||||
fwrite(arrayName,sizeof(char),namelen,fd);
|
||||
tmp = (INT32) ceil((float)namelen/8);
|
||||
fseek(fd,tmp*8-namelen,SEEK_CUR);
|
||||
headsize += tmp*8;
|
||||
}
|
||||
else { // Compressed data element format
|
||||
fwrite(arrayName,sizeof(char),namelen,fd);
|
||||
tmp = 4-namelen;
|
||||
fseek(fd,tmp,SEEK_CUR);
|
||||
}
|
||||
|
||||
// Finish writing known header information
|
||||
tmp = 9; // Matlab IEEE 754 double data type
|
||||
fwrite(&tmp,sizeof(INT32),1,fd);
|
||||
tmp = 0; // Size of real part subelement in bytes (8 per sample)
|
||||
fwrite(&tmp,sizeof(INT32),1,fd);
|
||||
headsize += 8; // Total number of bytes in data element so far
|
||||
|
||||
fseek(fd,132,SEEK_SET);
|
||||
fwrite(&headsize,sizeof(INT32),1,fd); // Write header size ... will update at end
|
||||
fseek(fd,0,SEEK_END);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
MatWvOut :: MatWvOut(char *fileName, int chans)
|
||||
{
|
||||
char msg[256];
|
||||
if (chans < 1) {
|
||||
sprintf(msg, "MatWvOut: number of channels = %d not supported!\n", chans);
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
channels = chans;
|
||||
fd = openMatFile(channels,fileName);
|
||||
data_length = FILE_BUFFER_SIZE*channels;
|
||||
matdata = (double *) new double[data_length];
|
||||
}
|
||||
|
||||
MatWvOut :: ~MatWvOut()
|
||||
{
|
||||
double temp;
|
||||
INT32 headsize, temp1;
|
||||
|
||||
fwrite(matdata,sizeof(double),counter,fd);
|
||||
temp = (double) totalCount * ONE_OVER_SRATE;
|
||||
printf("%f Seconds Computed\n\n", temp);
|
||||
|
||||
fseek(fd,164,SEEK_SET); // jump to number of columns
|
||||
fwrite(&totalCount,sizeof(INT32),1,fd);
|
||||
|
||||
fseek(fd,132,SEEK_SET); // jump to header size
|
||||
fread(&headsize,sizeof(INT32),1,fd);
|
||||
temp1 = headsize;
|
||||
headsize += (INT32) (totalCount * 8 * channels);
|
||||
fseek(fd,132,SEEK_SET);
|
||||
// Write file size (minus some header info)
|
||||
fwrite(&headsize,sizeof(INT32),1,fd);
|
||||
|
||||
fseek(fd,temp1+132,SEEK_SET); // jumpt to data size (in bytes)
|
||||
temp1 = totalCount * 8 * channels;
|
||||
fwrite(&temp1,sizeof(INT32),1,fd);
|
||||
fclose(fd);
|
||||
|
||||
if (matdata) {
|
||||
delete [ ] matdata;
|
||||
matdata = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MatWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
for (int i=0;i<channels;i++)
|
||||
matdata[counter++] = (double) (sample);
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(matdata,sizeof(double),data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MatWvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
for (int i=0;i<channels;i++)
|
||||
matdata[counter++] = (double) *samples++;
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(matdata,sizeof(double),data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
202
src/Modal4.cpp
Normal file
202
src/Modal4.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
Four Resonance Modal Synthesis Instrument
|
||||
by Perry R. Cook, 1995-2000
|
||||
|
||||
This instrument contains an excitation
|
||||
wavetable, an envelope, an oscillator,
|
||||
and four resonances (Non-Sweeping BiQuad
|
||||
Filters).
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#include "Modal4.h"
|
||||
|
||||
Modal4 :: Modal4()
|
||||
{
|
||||
envelope = new Envelope;
|
||||
// We don't make the excitation wave here yet,
|
||||
// because we don't know what it's going to be.
|
||||
filters[0] = new BiQuad;
|
||||
filters[1] = new BiQuad;
|
||||
filters[2] = new BiQuad;
|
||||
filters[3] = new BiQuad;
|
||||
onepole = new OnePole;
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
|
||||
vibr->setFreq((MY_FLOAT) 6.0);
|
||||
vibrGain = (MY_FLOAT) 0.0; // zero gain by default
|
||||
|
||||
directGain = (MY_FLOAT) 0.0;
|
||||
masterGain = (MY_FLOAT) 1.0;
|
||||
baseFreq = (MY_FLOAT) 440.0;
|
||||
this->setRatioAndReson(0,(MY_FLOAT) 1.00,(MY_FLOAT) 0.9997); /* Set some */
|
||||
this->setRatioAndReson(1,(MY_FLOAT) 1.30,(MY_FLOAT) 0.9997); /* silly */
|
||||
this->setRatioAndReson(2,(MY_FLOAT) 1.77,(MY_FLOAT) 0.9997); /* default */
|
||||
this->setRatioAndReson(3,(MY_FLOAT) 2.37,(MY_FLOAT) 0.9997); /* values here */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.01);
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.01);
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.01);
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.01);
|
||||
this->clear();
|
||||
filters[0]->setEqualGainZeroes();
|
||||
filters[1]->setEqualGainZeroes();
|
||||
filters[2]->setEqualGainZeroes();
|
||||
filters[3]->setEqualGainZeroes();
|
||||
stickHardness = (MY_FLOAT) 0.5;
|
||||
strikePosition = (MY_FLOAT) 0.561;
|
||||
}
|
||||
|
||||
Modal4 :: ~Modal4()
|
||||
{
|
||||
delete envelope;
|
||||
delete filters[0];
|
||||
delete filters[1];
|
||||
delete filters[2];
|
||||
delete filters[3];
|
||||
delete onepole;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Modal4 :: clear()
|
||||
{
|
||||
onepole->clear();
|
||||
filters[0]->clear();
|
||||
filters[1]->clear();
|
||||
filters[2]->clear();
|
||||
filters[3]->clear();
|
||||
}
|
||||
|
||||
void Modal4 :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
this->setRatioAndReson(0,ratios[0],resons[0]);
|
||||
this->setRatioAndReson(1,ratios[1],resons[1]);
|
||||
this->setRatioAndReson(2,ratios[2],resons[2]);
|
||||
this->setRatioAndReson(3,ratios[3],resons[3]);
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void Modal4 :: setRatioAndReson(int whichOne, MY_FLOAT ratio,MY_FLOAT reson)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
if (ratio*baseFreq < SRATE_OVER_TWO) {
|
||||
ratios[whichOne] = ratio;
|
||||
}
|
||||
else {
|
||||
temp = ratio;
|
||||
while (temp*baseFreq > SRATE_OVER_TWO) temp *= (MY_FLOAT) 0.5;
|
||||
ratios[whichOne] = temp;
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : Aliasing would occur here, correcting.\n");
|
||||
#endif
|
||||
}
|
||||
resons[whichOne] = reson;
|
||||
if (ratio < 0)
|
||||
temp = -ratio;
|
||||
else
|
||||
temp = ratio*baseFreq;
|
||||
|
||||
filters[whichOne]->setFreqAndReson(temp,reson);
|
||||
}
|
||||
|
||||
void Modal4 :: setMasterGain(MY_FLOAT aGain)
|
||||
{
|
||||
masterGain = aGain;
|
||||
}
|
||||
|
||||
void Modal4 :: setDirectGain(MY_FLOAT aGain)
|
||||
{
|
||||
directGain = aGain;
|
||||
}
|
||||
|
||||
void Modal4 :: setFiltGain(int whichOne, MY_FLOAT gain)
|
||||
{
|
||||
filters[whichOne]->setGain(gain);
|
||||
}
|
||||
|
||||
void Modal4 :: strike(MY_FLOAT amplitude)
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
|
||||
envelope->setRate((MY_FLOAT) 1.0);
|
||||
envelope->setTarget(amplitude);
|
||||
onepole->setPole((MY_FLOAT) 1.0 - amplitude);
|
||||
envelope->tick();
|
||||
wave->reset();
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
if (ratios[i] < 0)
|
||||
temp = -ratios[i];
|
||||
else
|
||||
temp = ratios[i] * baseFreq;
|
||||
filters[i]->setFreqAndReson(temp,resons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Modal4 :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->strike(amp);
|
||||
this->setFreq(freq);
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This calls damp, but inverts the meaning of amplitude
|
||||
* (high amplitude means fast damping).
|
||||
*/
|
||||
void Modal4 :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->damp((MY_FLOAT) 1.0 - (amp * (MY_FLOAT) 0.03));
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Modal4 :: damp(MY_FLOAT amplitude)
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
if (ratios[i] < 0)
|
||||
temp = -ratios[i];
|
||||
else
|
||||
temp = ratios[i] * baseFreq;
|
||||
filters[i]->setFreqAndReson(temp,resons[i]*amplitude);
|
||||
}
|
||||
}
|
||||
|
||||
void Modal4 :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Modal4 :: tick()
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
|
||||
temp = masterGain * onepole->tick(wave->tick() * envelope->tick());
|
||||
temp2 = filters[0]->tick(temp);
|
||||
temp2 += filters[1]->tick(temp);
|
||||
temp2 += filters[2]->tick(temp);
|
||||
temp2 += filters[3]->tick(temp);
|
||||
temp2 = temp2 - (temp2 * directGain);
|
||||
temp2 += directGain * temp;
|
||||
|
||||
if (vibrGain != 0.0) {
|
||||
// Calculate AM and apply to master out
|
||||
temp = (MY_FLOAT) 1.0 + (vibr->tick() * vibrGain);
|
||||
temp2 = temp * temp2;
|
||||
}
|
||||
|
||||
lastOutput = temp2 * (MY_FLOAT) 2.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
149
src/ModalBar.cpp
Normal file
149
src/ModalBar.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
ModalBar SubClass of Modal4 Instrument
|
||||
by Perry R. Cook, 1999-2000
|
||||
|
||||
Controls: CONTROL1 = stickHardness
|
||||
CONTROL2 = strikePosition
|
||||
CONTROL3 = Mode Presets
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#include "ModalBar.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
ModalBar :: ModalBar() : Modal4()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
wave = new RawWvIn(strcat(file,"rawwaves/marmstk1.raw"),"oneshot");
|
||||
wave->setRate((MY_FLOAT) 0.5); /* normal stick */
|
||||
|
||||
this->setRatioAndReson(0, (MY_FLOAT) 1.00,(MY_FLOAT) 0.9996); /* Set all 132.0 */
|
||||
this->setRatioAndReson(1, (MY_FLOAT) 3.99,(MY_FLOAT) 0.9994); /* of our 523.0 */
|
||||
this->setRatioAndReson(2,(MY_FLOAT) 10.65,(MY_FLOAT) 0.9994); /* default 1405.0 */
|
||||
this->setRatioAndReson(3,-(MY_FLOAT) 2443.0,(MY_FLOAT) 0.999); /* resonances 2443.0 */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.04); /* and */
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.01); /* gains */
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.01); /* for each */
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.008); /* resonance */
|
||||
directGain = (MY_FLOAT) 0.1;
|
||||
}
|
||||
|
||||
ModalBar :: ~ModalBar()
|
||||
{
|
||||
delete wave;
|
||||
}
|
||||
|
||||
void ModalBar :: setStickHardness(MY_FLOAT hardness)
|
||||
{
|
||||
stickHardness = hardness;
|
||||
wave->setRate((MY_FLOAT) (0.25 * (MY_FLOAT) pow(4.0,stickHardness)));
|
||||
masterGain = (MY_FLOAT) 0.1 + ((MY_FLOAT) 1.8 * stickHardness);
|
||||
}
|
||||
|
||||
void ModalBar :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp2 = position * PI;
|
||||
strikePosition = position; /* Hack only first three modes */
|
||||
temp = (MY_FLOAT) sin(temp2);
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.12 * temp); /* 1st mode function of pos. */
|
||||
temp = (MY_FLOAT) sin(0.05 + (3.9 * temp2));
|
||||
this->setFiltGain(1,(MY_FLOAT) -0.03 * temp); /* 2nd mode function of pos. */
|
||||
temp = (MY_FLOAT) sin(-0.05 + (11 * temp2));
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.11 * temp); /* 3rd mode function of pos. */
|
||||
}
|
||||
|
||||
void ModalBar :: setModalPreset(int which)
|
||||
{
|
||||
/* presets:
|
||||
* first line: relative modal frequencies (negative number is
|
||||
* a fixed mode that doesn't scale with frequency
|
||||
* second line: resonances of the modes
|
||||
* third line: mode volumes
|
||||
* fourth line: stickHardness, strikePosition, and direct stick
|
||||
* gain (mixed directly into the output
|
||||
*/
|
||||
int i, temp;
|
||||
MY_FLOAT presets[9][4][4] = {
|
||||
{{1.0, 3.99, 10.65, -2443}, // Marimba
|
||||
{0.9996, 0.9994, 0.9994, 0.999},
|
||||
{0.04, 0.01, 0.01, 0.008},
|
||||
{0.429688, 0.445312, 0.093750}},
|
||||
{{1.0, 2.01, 3.9, 14.37}, // Vibraphone
|
||||
{0.99995, 0.99991, 0.99992, 0.9999},
|
||||
{0.025, 0.015, 0.015, 0.015 },
|
||||
{0.390625,0.570312,0.078125}},
|
||||
{{1.0, 4.08, 6.669, -3725.0}, // Agogo
|
||||
{0.999, 0.999, 0.999, 0.999},
|
||||
{0.06, 0.05, 0.03, 0.02},
|
||||
{0.609375,0.359375,0.140625}},
|
||||
{{1.0, 2.777, 7.378, 15.377}, // Wood1
|
||||
{0.996, 0.994, 0.994, 0.99},
|
||||
{0.04, 0.01, 0.01, 0.008},
|
||||
{0.460938,0.375000,0.046875}},
|
||||
{{1.0, 2.777, 7.378, 15.377}, // Reso
|
||||
{0.99996, 0.99994, 0.99994, 0.9999},
|
||||
{0.02, 0.005, 0.005, 0.004},
|
||||
{0.453125,0.250000,0.101562}},
|
||||
{{1.0, 1.777, 2.378, 3.377}, // Wood2
|
||||
{0.996, 0.994, 0.994, 0.99},
|
||||
{0.04, 0.01, 0.01, 0.008},
|
||||
{0.312500,0.445312,0.109375}},
|
||||
{{1.0, 1.004, 1.013, 2.377}, // Beats
|
||||
{0.9999, 0.9999, 0.9999, 0.999},
|
||||
{0.02, 0.005, 0.005, 0.004},
|
||||
{0.398438,0.296875,0.070312}},
|
||||
{{1.0, 4.0, -1320.0, -3960.0}, // 2Fix
|
||||
{0.9996, 0.999, 0.9994, 0.999},
|
||||
{0.04, 0.01, 0.01, 0.008},
|
||||
{0.453125,0.453125,0.070312}},
|
||||
{{1.0, 1.217, 1.475, 1.729}, // Clump
|
||||
{0.999, 0.999, 0.999, 0.999},
|
||||
{0.03, 0.03, 0.03, 0.03 },
|
||||
{0.390625,0.570312,0.078125}},
|
||||
};
|
||||
|
||||
temp = (which % 9);
|
||||
for (i=0; i<4; i++) {
|
||||
this->setRatioAndReson(i, presets[temp][0][i], presets[temp][1][i]);
|
||||
this->setFiltGain(i,presets[temp][2][i]);
|
||||
}
|
||||
this->setStickHardness(presets[temp][3][0]);
|
||||
this->setStrikePosition(presets[temp][3][1]);
|
||||
directGain = presets[temp][3][2];
|
||||
|
||||
if (temp == 1) // vibraphone
|
||||
vibrGain = 0.2;
|
||||
else
|
||||
vibrGain = 0.0;
|
||||
}
|
||||
|
||||
void ModalBar :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("ModalBar : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_StickHardness_)
|
||||
this->setStickHardness(value * NORM_7);
|
||||
else if (number == __SK_StrikePosition_)
|
||||
this->setStrikePosition(value * NORM_7);
|
||||
else if (number == __SK_ProphesyRibbon_)
|
||||
this->setModalPreset((int) value);
|
||||
else if (number == __SK_ModWheel_)
|
||||
directGain = value * NORM_7;
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
envelope->setTarget(value * NORM_7);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq(value * NORM_7 * 12.0);
|
||||
else if (number == 1024) { // HACKED Poop message
|
||||
printf("StickHard=%f StrikePos=%f directGain=%f\n",
|
||||
stickHardness, strikePosition, directGain);
|
||||
}
|
||||
else {
|
||||
printf("ModalBar : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
85
src/Modulatr.cpp
Normal file
85
src/Modulatr.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*******************************************/
|
||||
/* Modulator Class, Perry R. Cook, 1995-96*/
|
||||
/* This Object combines random and */
|
||||
/* periodic modulations to give a nice */
|
||||
/* natural human modulation function. */
|
||||
/*******************************************/
|
||||
|
||||
#define POLE_POS (MY_FLOAT) 0.999
|
||||
#define RND_SCALE (MY_FLOAT) 10.0
|
||||
|
||||
#include "Modulatr.h"
|
||||
|
||||
Modulatr :: Modulatr()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibwave = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
|
||||
vibwave->setFreq((MY_FLOAT) 6.0);
|
||||
vibAmt = (MY_FLOAT) 0.04;
|
||||
noise = new SubNoise(330);
|
||||
rndAmt = (MY_FLOAT) 0.005;
|
||||
onepole = new OnePole;
|
||||
onepole->setPole(POLE_POS);
|
||||
onepole->setGain(rndAmt * RND_SCALE);
|
||||
}
|
||||
|
||||
Modulatr :: ~Modulatr()
|
||||
{
|
||||
delete vibwave;
|
||||
delete noise;
|
||||
delete onepole;
|
||||
}
|
||||
|
||||
void Modulatr :: reset()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void Modulatr :: setVibFreq(MY_FLOAT vibFreq)
|
||||
{
|
||||
vibwave->setFreq(vibFreq);
|
||||
}
|
||||
|
||||
void Modulatr :: setVibAmt(MY_FLOAT vibAmount)
|
||||
{
|
||||
vibAmt = vibAmount;
|
||||
}
|
||||
|
||||
void Modulatr :: setRndAmt(MY_FLOAT rndAmount)
|
||||
{
|
||||
rndAmt = rndAmount;
|
||||
onepole->setGain(RND_SCALE * rndAmt);
|
||||
}
|
||||
|
||||
MY_FLOAT Modulatr :: tick()
|
||||
{
|
||||
lastOutput = vibAmt * vibwave->tick(); /* Compute periodic and */
|
||||
lastOutput += onepole->tick(noise->tick()); /* random modulations */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT Modulatr :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
Modulatr testMod;
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
for (i=0;i<20000;i++) {
|
||||
data = testMod.tick() * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
111
src/Moog1.cpp
Normal file
111
src/Moog1.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/******************************************/
|
||||
/* Test Sampler Subclass of */
|
||||
/* Sampling Synthesizer Class */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = filterQ */
|
||||
/* CONTROL2 = filterRate */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Moog1.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Moog1 :: Moog1() : SamplFlt()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char temp[128];
|
||||
char file[128];
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
strcpy(file,temp);
|
||||
attacks[0] = new RawWvIn(strcat(file,"rawwaves/mandpluk.raw"),"oneshot");
|
||||
strcpy(file,temp);
|
||||
loops[0] = new RawWvIn(strcat(file,"rawwaves/impuls20.raw"),"looping");
|
||||
strcpy(file,temp);
|
||||
loops[1] = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping"); /* Steal one for vibrato */
|
||||
loops[1]->setFreq((MY_FLOAT) 6.122);
|
||||
adsr->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.5,(MY_FLOAT) 0.6,(MY_FLOAT) 0.250);
|
||||
filterQ = (MY_FLOAT) 0.85;
|
||||
filterRate = (MY_FLOAT) 0.0001;
|
||||
modDepth = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
Moog1 :: ~Moog1()
|
||||
{
|
||||
delete attacks[0];
|
||||
delete loops[0];
|
||||
delete loops[1];
|
||||
}
|
||||
|
||||
void Moog1 :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
attacks[0]->setFreq(baseFreq * (MY_FLOAT) 0.01);
|
||||
loops[0]->setFreq(baseFreq);
|
||||
}
|
||||
|
||||
void Moog1 :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
attackGain = amp * (MY_FLOAT) 0.5;
|
||||
loopGain = amp;
|
||||
|
||||
temp = filterQ + (MY_FLOAT) 0.05;
|
||||
filters[0]->setStates((MY_FLOAT) 2000.0,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
|
||||
filters[1]->setStates((MY_FLOAT) 2000.0,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
|
||||
temp = filterQ + (MY_FLOAT) 0.099;
|
||||
filters[0]->setTargets((MY_FLOAT) freq,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
|
||||
filters[1]->setTargets((MY_FLOAT) freq,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
|
||||
filters[0]->setSweepRate(filterRate * (MY_FLOAT) 22050.0 / SRATE);
|
||||
filters[1]->setSweepRate(filterRate * (MY_FLOAT) 22050.0 / SRATE);
|
||||
#if defined(_debug_)
|
||||
printf("Moog1 : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Moog1 :: setModulationSpeed(MY_FLOAT mSpeed)
|
||||
{
|
||||
loops[1]->setFreq(mSpeed);
|
||||
}
|
||||
|
||||
void Moog1 :: setModulationDepth(MY_FLOAT mDepth)
|
||||
{
|
||||
modDepth = mDepth * (MY_FLOAT) 0.5;
|
||||
}
|
||||
|
||||
void Moog1 :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Moog1 : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_FilterQ_)
|
||||
filterQ = (MY_FLOAT) 0.80 + ((MY_FLOAT) 0.1 * value * NORM_7);
|
||||
else if (number == __SK_FilterSweepRate_)
|
||||
filterRate = (value * NORM_7 * (MY_FLOAT) 0.0002);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
this->setModulationSpeed(value * NORM_7 * (MY_FLOAT) 12.0);
|
||||
else if (number == __SK_ModWheel_)
|
||||
this->setModulationDepth(value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Moog1 : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT Moog1 :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
if (modDepth!=0.0) {
|
||||
temp = loops[1]->tick() * modDepth;
|
||||
loops[0]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp));
|
||||
}
|
||||
lastOutput = SamplFlt :: tick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
140
src/NRev.cpp
Normal file
140
src/NRev.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/******************************************/
|
||||
/* NRev Reverb Subclass */
|
||||
/* by Tim Stilson, 1998 */
|
||||
/* based on CLM NRev */
|
||||
/* Integrated into STK by Gary Scavone */
|
||||
/* */
|
||||
/* This is based on some of the famous */
|
||||
/* Stanford CCRMA reverbs (NRev, KipRev) */
|
||||
/* all based on the the Chowning/Moorer/ */
|
||||
/* Schroeder reverberators, which use */
|
||||
/* networks of simple allpass and comb */
|
||||
/* delay filters. This particular */
|
||||
/* arrangement consists of 6 comb */
|
||||
/* filters in parallel, followed by 3 */
|
||||
/* allpass filters, a lowpass filter, */
|
||||
/* and another allpass in series, */
|
||||
/* followed by two allpass filters in */
|
||||
/* parallel with corresponding right and */
|
||||
/* left outputs. */
|
||||
/******************************************/
|
||||
|
||||
#include "NRev.h"
|
||||
|
||||
NRev :: NRev(MY_FLOAT T60)
|
||||
{
|
||||
int lens[15]={1433,1601,1867,2053,2251,2399,347,113,37,59,53,43,37,29,19};
|
||||
double srscale= SRATE / 25641.0;
|
||||
int val;
|
||||
int i;
|
||||
|
||||
for (i=0; i<15; i++)
|
||||
{
|
||||
val = (int)floor(srscale*lens[i]);
|
||||
if ((val & 1) == 0) val++;
|
||||
while (!this->isprime(val)) val+=2;
|
||||
lens[i]=val;
|
||||
}
|
||||
for (i=0; i<6; i++)
|
||||
{
|
||||
CdelayLine[i] = new DLineN((long) (lens[i]) + 2);
|
||||
CdelayLine[i]->setDelay((long) (lens[i]));
|
||||
combCoef[i] = pow(10,(-3 * lens[i] / (T60 * SRATE)));
|
||||
}
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
APdelayLine[i] = new DLineN((long) (lens[i+6]) + 2);
|
||||
APdelayLine[i]->setDelay((long) (lens[i+6]));
|
||||
}
|
||||
|
||||
allPassCoeff = 0.7;
|
||||
effectMix = 0.3;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
NRev :: ~NRev()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<6; i++) delete CdelayLine[i];
|
||||
for (i=0; i<8; i++) delete APdelayLine[i];
|
||||
}
|
||||
|
||||
void NRev :: clear()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<6; i++) CdelayLine[i]->clear();
|
||||
for (i=0; i<8; i++) APdelayLine[i]->clear();
|
||||
lastOutL = 0.0;
|
||||
lastOutR = 0.0;
|
||||
lpLastout = 0.0;
|
||||
}
|
||||
|
||||
void NRev :: setEffectMix(MY_FLOAT mix)
|
||||
{
|
||||
effectMix = mix;
|
||||
}
|
||||
|
||||
MY_FLOAT NRev :: lastOutput()
|
||||
{
|
||||
return (lastOutL + lastOutR) * 0.5;
|
||||
}
|
||||
|
||||
MY_FLOAT NRev :: lastOutputL()
|
||||
{
|
||||
return lastOutL;
|
||||
}
|
||||
|
||||
MY_FLOAT NRev :: lastOutputR()
|
||||
{
|
||||
return lastOutR;
|
||||
}
|
||||
|
||||
MY_FLOAT NRev :: tick(MY_FLOAT input)
|
||||
{
|
||||
// FPU underflow checks seem to make things much
|
||||
// worse here, so I won't do them.
|
||||
MY_FLOAT temp,temp0,temp1,temp2,temp3;
|
||||
int i;
|
||||
|
||||
temp0 = 0.0;
|
||||
for (i=0; i<6; i++)
|
||||
{
|
||||
temp = input + (combCoef[i] * CdelayLine[i]->lastOut());
|
||||
temp0 += CdelayLine[i]->tick(temp);
|
||||
}
|
||||
for (i=0; i<3; i++)
|
||||
{
|
||||
temp = APdelayLine[i]->lastOut();
|
||||
temp1 = allPassCoeff * temp;
|
||||
temp1 += temp0;
|
||||
APdelayLine[i]->tick(temp1);
|
||||
temp0 = -(allPassCoeff * temp1) + temp;
|
||||
}
|
||||
lpLastout = 0.7*lpLastout + 0.3*temp0; // onepole LP filter
|
||||
temp = APdelayLine[3]->lastOut();
|
||||
temp1 = allPassCoeff * temp;
|
||||
temp1 += lpLastout;
|
||||
APdelayLine[3]->tick(temp1);
|
||||
temp1 = -(allPassCoeff * temp1) + temp;
|
||||
|
||||
temp = APdelayLine[4]->lastOut();
|
||||
temp2 = allPassCoeff * temp;
|
||||
temp2 += temp1;
|
||||
APdelayLine[4]->tick(temp2);
|
||||
lastOutL = effectMix*(-(allPassCoeff * temp2) + temp);
|
||||
|
||||
temp = APdelayLine[5]->lastOut();
|
||||
temp3 = allPassCoeff * temp;
|
||||
temp3 += temp1;
|
||||
APdelayLine[5]->tick(temp3);
|
||||
lastOutR = effectMix*(-(allPassCoeff * temp3) + temp);
|
||||
|
||||
temp = (1.0 - effectMix) * input;
|
||||
lastOutL += temp;
|
||||
lastOutR += temp;
|
||||
|
||||
return (lastOutL + lastOutR) * 0.5;
|
||||
|
||||
}
|
||||
37
src/Noise.cpp
Normal file
37
src/Noise.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*******************************************/
|
||||
/* Noise Generator Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* White noise as often as you like. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Noise.h"
|
||||
#ifdef __OS_NeXT_
|
||||
#include <libc.h>
|
||||
#endif
|
||||
|
||||
Noise :: Noise() : Object()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
Noise :: ~Noise()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Noise :: tick()
|
||||
{
|
||||
#if defined(__OS_Win_) /* For Windoze */
|
||||
lastOutput = (MY_FLOAT) (rand() - (int)RANDLIMIT_OVER_TWO);
|
||||
#else /* This is for Linux, NeXT and SGI */
|
||||
lastOutput = (MY_FLOAT) (random() - (int)RANDLIMIT_OVER_TWO);
|
||||
#endif
|
||||
|
||||
lastOutput *= (MY_FLOAT) ONE_OVER_RANDLIMIT;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT Noise :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
24
src/Object.cpp
Normal file
24
src/Object.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*********************************************/
|
||||
/* Object Class, by Perry R. Cook, 1995-99 */
|
||||
/* */
|
||||
/* This is mostly here for compatibility */
|
||||
/* with Objective C. We'll also stick */
|
||||
/* global defines here, so everyone will */
|
||||
/* see them. */
|
||||
/*********************************************/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
/* This is just here for compatibility and convenience,
|
||||
so there's no need to do any real calculations.
|
||||
I do set up some redefinable variables in Object.h.
|
||||
*/
|
||||
|
||||
Object :: Object()
|
||||
{
|
||||
}
|
||||
|
||||
Object :: ~Object()
|
||||
{
|
||||
}
|
||||
|
||||
101
src/OnePole.cpp
Normal file
101
src/OnePole.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
One Pole Filter Class,
|
||||
by Perry R. Cook, 1995-96.
|
||||
Added methods by Julius Smith, 2000.
|
||||
|
||||
The parameter gain is an additional
|
||||
gain parameter applied to the filter
|
||||
on top of the normalization that takes
|
||||
place automatically. So the net max
|
||||
gain through the system equals the
|
||||
value of gain. sgain is the combina-
|
||||
tion of gain and the normalization
|
||||
parameter, so if you set the poleCoeff
|
||||
to alpha, sgain is always set to
|
||||
gain * (1.0 - fabs(alpha)).
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#include "OnePole.h"
|
||||
|
||||
OnePole :: OnePole() : Filter()
|
||||
{
|
||||
poleCoeff = (MY_FLOAT) 0.9;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
sgain = (MY_FLOAT) 0.1;
|
||||
outputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
OnePole :: OnePole(MY_FLOAT thePole) : Filter()
|
||||
{
|
||||
poleCoeff = thePole;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
sgain = (MY_FLOAT) 1.0 - fabs(thePole);
|
||||
outputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
OnePole :: ~OnePole()
|
||||
{
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void OnePole :: clear()
|
||||
{
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void OnePole :: setB0(MY_FLOAT aValue)
|
||||
{
|
||||
sgain = aValue;
|
||||
}
|
||||
|
||||
void OnePole :: setNum(MY_FLOAT *values)
|
||||
{
|
||||
sgain = values[0];
|
||||
}
|
||||
|
||||
void OnePole :: setA1(MY_FLOAT aValue)
|
||||
{
|
||||
poleCoeff = -aValue;
|
||||
}
|
||||
|
||||
void OnePole :: setDen(MY_FLOAT *values)
|
||||
{
|
||||
poleCoeff = -values[0];
|
||||
}
|
||||
|
||||
void OnePole :: setPole(MY_FLOAT aValue)
|
||||
{
|
||||
poleCoeff = aValue;
|
||||
// Normalize gain to 1.0 max
|
||||
if (poleCoeff > (MY_FLOAT) 0.0)
|
||||
sgain = gain * ((MY_FLOAT) 1.0 - poleCoeff);
|
||||
else
|
||||
sgain = gain * ((MY_FLOAT) 1.0 + poleCoeff);
|
||||
}
|
||||
|
||||
void OnePole :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
|
||||
// Normalize gain to 1.0 max
|
||||
if (poleCoeff > (MY_FLOAT) 0.0)
|
||||
sgain = gain * ((MY_FLOAT) 1.0 - poleCoeff);
|
||||
else
|
||||
sgain = gain * ((MY_FLOAT) 1.0 + poleCoeff);
|
||||
}
|
||||
|
||||
// Perform Filter Operation
|
||||
MY_FLOAT OnePole :: tick(MY_FLOAT sample)
|
||||
{
|
||||
outputs[0] = (sgain * sample) + (poleCoeff * outputs[0]);
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
64
src/OneZero.cpp
Normal file
64
src/OneZero.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*******************************************/
|
||||
/* One Zero Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* The parameter gain is an additional */
|
||||
/* gain parameter applied to the filter */
|
||||
/* on top of the normalization that takes */
|
||||
/* place automatically. So the net max */
|
||||
/* gain through the system equals the */
|
||||
/* value of gain. sgain is the combina- */
|
||||
/* tion of gain and the normalization */
|
||||
/* parameter, so if you set the poleCoeff */
|
||||
/* to alpha, sgain is always set to */
|
||||
/* gain / (1.0 - fabs(alpha)). */
|
||||
/*******************************************/
|
||||
|
||||
#include "OneZero.h"
|
||||
|
||||
OneZero :: OneZero()
|
||||
{
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
zeroCoeff = (MY_FLOAT) 1.0;
|
||||
sgain = (MY_FLOAT) 0.5;
|
||||
inputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
}
|
||||
|
||||
OneZero :: ~OneZero()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void OneZero :: clear()
|
||||
{
|
||||
inputs[0] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void OneZero :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
if (zeroCoeff > 0.0) // Normalize gain to 1.0 max
|
||||
sgain = gain / ((MY_FLOAT) 1.0 + zeroCoeff);
|
||||
else
|
||||
sgain = gain / ((MY_FLOAT) 1.0 - zeroCoeff);
|
||||
}
|
||||
|
||||
void OneZero :: setCoeff(MY_FLOAT aValue)
|
||||
{
|
||||
zeroCoeff = aValue;
|
||||
if (zeroCoeff > 0.0) // Normalize gain to 1.0 max
|
||||
sgain = gain / ((MY_FLOAT) 1.0 + zeroCoeff);
|
||||
else
|
||||
sgain = gain / ((MY_FLOAT) 1.0 - zeroCoeff);
|
||||
}
|
||||
|
||||
MY_FLOAT OneZero :: tick(MY_FLOAT sample) // Perform Filter Operation
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = sgain * sample;
|
||||
lastOutput = (inputs[0] * zeroCoeff) + temp;
|
||||
inputs[0] = temp;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
113
src/PRCRev.cpp
Normal file
113
src/PRCRev.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*******************************************/
|
||||
/* PRCRev, a simple reverb unit */
|
||||
/* by Perry Cook, 1996. */
|
||||
/* Incorporated into the Reverb superclass */
|
||||
/* by Gary Scavone, 1998. */
|
||||
/* */
|
||||
/* This is based on some of the famous */
|
||||
/* Stanford CCRMA reverbs (NRev, KipRev) */
|
||||
/* all based on the the Chowning/Moorer/ */
|
||||
/* Schroeder reverberators, which use */
|
||||
/* networks of simple allpass and comb */
|
||||
/* delay filters. This particular */
|
||||
/* structure consists of 2 allpass units */
|
||||
/* in series followed by 2 comb filters in */
|
||||
/* parallel. */
|
||||
/*******************************************/
|
||||
|
||||
#include "PRCRev.h"
|
||||
|
||||
PRCRev :: PRCRev(MY_FLOAT T60)
|
||||
{
|
||||
int lens[4]={353,1097,1777,2137};
|
||||
double srscale = SRATE / 44100.0;
|
||||
int val, i;
|
||||
|
||||
if (SRATE < 44100.0) {
|
||||
for (i=0; i<4; i++) {
|
||||
val = (int) floor(srscale * lens[i]);
|
||||
if ((val & 1) == 0) val++;
|
||||
while (!this->isprime(val)) val += 2;
|
||||
lens[i] = val;
|
||||
}
|
||||
}
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
APdelayLine[i] = new DLineN(lens[i] + 2);
|
||||
APdelayLine[i]->setDelay(lens[i]);
|
||||
CdelayLine[i] = new DLineN(lens[i+2] + 2);
|
||||
CdelayLine[i]->setDelay(lens[i+2]);
|
||||
combCoeff[i] = pow(10,(-3 * lens[i+2] / (T60 * SRATE)));
|
||||
}
|
||||
|
||||
allPassCoeff = (MY_FLOAT) 0.7;
|
||||
effectMix = (MY_FLOAT) 0.5;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
PRCRev :: ~PRCRev()
|
||||
{
|
||||
delete APdelayLine[0];
|
||||
delete APdelayLine[1];
|
||||
delete CdelayLine[0];
|
||||
delete CdelayLine[1];
|
||||
}
|
||||
|
||||
void PRCRev :: clear()
|
||||
{
|
||||
APdelayLine[0]->clear();
|
||||
APdelayLine[1]->clear();
|
||||
CdelayLine[0]->clear();
|
||||
CdelayLine[1]->clear();
|
||||
lastOutL = (MY_FLOAT) 0.0;
|
||||
lastOutR = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void PRCRev :: setEffectMix(MY_FLOAT mix)
|
||||
{
|
||||
effectMix = mix;
|
||||
}
|
||||
|
||||
MY_FLOAT PRCRev :: lastOutput()
|
||||
{
|
||||
return (lastOutL + lastOutR) * (MY_FLOAT) 0.5;
|
||||
}
|
||||
|
||||
MY_FLOAT PRCRev :: lastOutputL()
|
||||
{
|
||||
return lastOutL;
|
||||
}
|
||||
|
||||
MY_FLOAT PRCRev :: lastOutputR()
|
||||
{
|
||||
return lastOutR;
|
||||
}
|
||||
|
||||
MY_FLOAT PRCRev :: tick(MY_FLOAT input)
|
||||
{
|
||||
MY_FLOAT temp,temp0,temp1,temp2,temp3;
|
||||
|
||||
temp = APdelayLine[0]->lastOut();
|
||||
temp0 = allPassCoeff * temp;
|
||||
temp0 += input;
|
||||
APdelayLine[0]->tick(temp0);
|
||||
temp0 = -(allPassCoeff * temp0) + temp;
|
||||
|
||||
temp = APdelayLine[1]->lastOut();
|
||||
temp1 = allPassCoeff * temp;
|
||||
temp1 += temp0;
|
||||
APdelayLine[1]->tick(temp1);
|
||||
temp1 = -(allPassCoeff * temp1) + temp;
|
||||
|
||||
temp2 = temp1 + (combCoeff[0] * CdelayLine[0]->lastOut());
|
||||
temp3 = temp1 + (combCoeff[1] * CdelayLine[1]->lastOut());
|
||||
|
||||
lastOutL = effectMix * (CdelayLine[0]->tick(temp2));
|
||||
lastOutR = effectMix * (CdelayLine[1]->tick(temp3));
|
||||
temp = (MY_FLOAT) (1.0 - effectMix) * input;
|
||||
lastOutL += temp;
|
||||
lastOutR += temp;
|
||||
|
||||
return (lastOutL + lastOutR) * (MY_FLOAT) 0.5;
|
||||
|
||||
}
|
||||
63
src/PercFlut.cpp
Normal file
63
src/PercFlut.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/******************************************/
|
||||
/* Percussive Flute Subclass */
|
||||
/* of Algorithm 4 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "PercFlut.h"
|
||||
|
||||
PercFlut :: PercFlut() : FM4Alg4()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file1[128];
|
||||
char file2[128];
|
||||
char file3[128];
|
||||
char file4[128];
|
||||
strcpy(file1, RAWWAVE_PATH);
|
||||
strcpy(file2, RAWWAVE_PATH);
|
||||
strcpy(file3, RAWWAVE_PATH);
|
||||
strcpy(file4, RAWWAVE_PATH);
|
||||
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
|
||||
strcat(file2,"rawwaves/sinewave.raw"),
|
||||
strcat(file3,"rawwaves/sinewave.raw"),
|
||||
strcat(file4,"rawwaves/fwavblnk.raw"));
|
||||
|
||||
this->setRatio(0,(MY_FLOAT) (1.50 * 1.000));
|
||||
this->setRatio(1,(MY_FLOAT) (3.00 * 0.995));
|
||||
this->setRatio(2,(MY_FLOAT) (2.99 * 1.005));
|
||||
this->setRatio(3,(MY_FLOAT) (6.00 * 0.997));
|
||||
gains[0] = __FM4Op_gains[99];
|
||||
gains[1] = __FM4Op_gains[71];
|
||||
gains[2] = __FM4Op_gains[93];
|
||||
gains[3] = __FM4Op_gains[85];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.05,(MY_FLOAT) 0.05,
|
||||
__FM4Op_susLevels[14],(MY_FLOAT) 0.05);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.50,
|
||||
__FM4Op_susLevels[13],(MY_FLOAT) 0.5);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.30,
|
||||
__FM4Op_susLevels[11],(MY_FLOAT) 0.05);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.05,
|
||||
__FM4Op_susLevels[13],(MY_FLOAT) 0.01);
|
||||
twozero->setGain((MY_FLOAT) 0.0);
|
||||
modDepth = (MY_FLOAT) 0.005;
|
||||
}
|
||||
|
||||
void PercFlut :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
}
|
||||
|
||||
void PercFlut :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[99] * 0.5;
|
||||
gains[1] = amp * __FM4Op_gains[71] * 0.5;
|
||||
gains[2] = amp * __FM4Op_gains[93] * 0.5;
|
||||
gains[3] = amp * __FM4Op_gains[85] * 0.5;
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("PercFlut : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
84
src/Plucked.cpp
Normal file
84
src/Plucked.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/******************************************/
|
||||
/* Karplus-Strong plucked string model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* There exist at least two patents, */
|
||||
/* assigned to Stanford, bearing the */
|
||||
/* names of Karplus and/or Strong. */
|
||||
/******************************************/
|
||||
|
||||
#include "Plucked.h"
|
||||
|
||||
Plucked :: Plucked(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
loopGain = (MY_FLOAT) 0.999;
|
||||
delayLine = new DLineA(length);
|
||||
loopFilt = new OneZero;
|
||||
pickFilt = new OnePole;
|
||||
noise = new Noise;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
Plucked :: ~Plucked()
|
||||
{
|
||||
delete delayLine;
|
||||
delete loopFilt;
|
||||
delete pickFilt;
|
||||
delete noise;
|
||||
}
|
||||
|
||||
void Plucked :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
loopFilt->clear();
|
||||
pickFilt->clear();
|
||||
}
|
||||
|
||||
void Plucked :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT delay;
|
||||
delay = (SRATE / frequency) - (MY_FLOAT) 0.5; /* length - delays */
|
||||
delayLine->setDelay(delay);
|
||||
loopGain = (MY_FLOAT) 0.995 + (frequency * (MY_FLOAT) 0.000005);
|
||||
if (loopGain>1.0) loopGain = (MY_FLOAT) 0.99999;
|
||||
}
|
||||
|
||||
void Plucked :: pluck(MY_FLOAT amplitude)
|
||||
{
|
||||
long i;
|
||||
pickFilt->setPole((MY_FLOAT) 0.999 - (amplitude * (MY_FLOAT) 0.15));
|
||||
pickFilt->setGain(amplitude * (MY_FLOAT) 0.5);
|
||||
for (i=0;i<length;i++)
|
||||
// fill delay with noise additively with current contents
|
||||
delayLine->tick(delayLine->lastOut() * (MY_FLOAT) 0.6
|
||||
+ pickFilt->tick(noise->tick()));
|
||||
|
||||
}
|
||||
|
||||
void Plucked :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->pluck(amp);
|
||||
#if defined(_debug_)
|
||||
printf("Plucked : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Plucked :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
loopGain = (MY_FLOAT) 1.0 - amp;
|
||||
#if defined(_debug_)
|
||||
printf("Plucked : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT Plucked :: tick()
|
||||
{
|
||||
/* check this out */
|
||||
/* here's the whole inner loop of the instrument!! */
|
||||
lastOutput = delayLine->tick(loopFilt->tick(delayLine->lastOut() * loopGain));
|
||||
lastOutput *= (MY_FLOAT) 3.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
90
src/Plucked2.cpp
Normal file
90
src/Plucked2.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/******************************************/
|
||||
/* Enhanced (Jaffe-Smith, Smith, others) */
|
||||
/* Karplus-Strong plucked model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* This is the super-class, with no */
|
||||
/* excitation specified. So this one by */
|
||||
/* itself doesn't make any sound. */
|
||||
/******************************************/
|
||||
|
||||
#include "Plucked2.h"
|
||||
|
||||
Plucked2 :: Plucked2(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
baseLoopGain = (MY_FLOAT) 0.995;
|
||||
loopGain = (MY_FLOAT) 0.999;
|
||||
delayLine = new DLineA(length);
|
||||
delayLine2 = new DLineA(length);
|
||||
combDelay = new DLineL(length);
|
||||
filter = new OneZero;
|
||||
filter2 = new OneZero;
|
||||
pluckAmp = (MY_FLOAT) 0.3;
|
||||
pluckPos = (MY_FLOAT) 0.4;
|
||||
detuning = (MY_FLOAT) 0.995;
|
||||
lastFreq = lowestFreq * (MY_FLOAT) 2.0;
|
||||
lastLength = length * (MY_FLOAT) 0.5;
|
||||
}
|
||||
|
||||
Plucked2 :: ~Plucked2()
|
||||
{
|
||||
delete delayLine;
|
||||
delete delayLine2;
|
||||
delete combDelay;
|
||||
delete filter;
|
||||
delete filter2;
|
||||
}
|
||||
|
||||
void Plucked2 :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
delayLine2->clear();
|
||||
combDelay->clear();
|
||||
filter->clear();
|
||||
filter2->clear();
|
||||
}
|
||||
|
||||
void Plucked2 :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
lastFreq = frequency;
|
||||
lastLength = ((MY_FLOAT) SRATE / lastFreq); /* length - delays */
|
||||
delayLine->setDelay((lastLength / detuning) - (MY_FLOAT) 0.5);
|
||||
delayLine2->setDelay((lastLength * detuning) - (MY_FLOAT) 0.5);
|
||||
loopGain = baseLoopGain + (frequency * (MY_FLOAT) 0.000005);
|
||||
if (loopGain>1.0) loopGain = (MY_FLOAT) 0.99999;
|
||||
}
|
||||
|
||||
void Plucked2 :: setDetune(MY_FLOAT detune)
|
||||
{
|
||||
detuning = detune;
|
||||
delayLine->setDelay((lastLength / detuning) - (MY_FLOAT) 0.5);
|
||||
delayLine2->setDelay((lastLength * detuning) - (MY_FLOAT) 0.5);
|
||||
}
|
||||
|
||||
void Plucked2 :: setFreqAndDetune(MY_FLOAT frequency,MY_FLOAT detune)
|
||||
{
|
||||
lastFreq = frequency;
|
||||
detuning = detune;
|
||||
this->setFreq(frequency);
|
||||
}
|
||||
|
||||
void Plucked2 :: setPluckPos(MY_FLOAT position)
|
||||
{
|
||||
pluckPos = position;
|
||||
}
|
||||
|
||||
void Plucked2 :: setBaseLoopGain(MY_FLOAT aGain)
|
||||
{
|
||||
baseLoopGain = aGain;
|
||||
loopGain = baseLoopGain + (lastFreq * (MY_FLOAT) 0.000005);
|
||||
if (loopGain>1.0) loopGain = (MY_FLOAT) 0.99999;
|
||||
}
|
||||
|
||||
void Plucked2 :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
loopGain = ((MY_FLOAT) 1.0 - amp) * (MY_FLOAT) 0.5;
|
||||
#if defined(_debug_)
|
||||
printf("Plucked2 : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
68
src/PoleZero.cpp
Normal file
68
src/PoleZero.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*******************************************/
|
||||
/* PoleZero (1-pole, 1-zero) Filter Class */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. Nothing */
|
||||
/* out of the ordinary in this version. */
|
||||
/*******************************************/
|
||||
|
||||
#include "PoleZero.h"
|
||||
|
||||
PoleZero :: PoleZero() : Filter()
|
||||
{
|
||||
inputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
|
||||
outputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
|
||||
b0Coeff = (MY_FLOAT) 1.0;
|
||||
b1Coeff = (MY_FLOAT) 0.0;
|
||||
a1Coeff = (MY_FLOAT) 0.0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
PoleZero :: ~PoleZero()
|
||||
{
|
||||
free(inputs);
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void PoleZero :: clear()
|
||||
{
|
||||
inputs[0] = (MY_FLOAT) 0.0;
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void PoleZero :: setA1(MY_FLOAT coeff)
|
||||
{
|
||||
a1Coeff = coeff;
|
||||
}
|
||||
|
||||
void PoleZero :: setB0(MY_FLOAT coeff)
|
||||
{
|
||||
b0Coeff = coeff;
|
||||
}
|
||||
|
||||
void PoleZero :: setB1(MY_FLOAT coeff)
|
||||
{
|
||||
b1Coeff = coeff;
|
||||
}
|
||||
|
||||
void PoleZero :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
}
|
||||
|
||||
// PoleZero is one pole, one zero filter
|
||||
// Look it up in your favorite DSP text
|
||||
MY_FLOAT PoleZero :: tick(MY_FLOAT sample)
|
||||
{
|
||||
MY_FLOAT in_sample = gain*sample;
|
||||
|
||||
lastOutput = b0Coeff*in_sample + b1Coeff*inputs[0] - a1Coeff*outputs[0];
|
||||
inputs[0] = in_sample;
|
||||
outputs[0] = lastOutput;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
134
src/RawWvIn.cpp
Normal file
134
src/RawWvIn.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*******************************************/
|
||||
/* RawWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 2000 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to open raw 16-bit data (signed */
|
||||
/* integer) files for playback. */
|
||||
/* */
|
||||
/* STK RawWave files are assumed to be */
|
||||
/* monaural and big-endian. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RawWvIn.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
RawWvIn :: RawWvIn(char *fileName, const char *mode)
|
||||
{
|
||||
char msg[256];
|
||||
|
||||
// check mode string
|
||||
if ( strcmp(mode,"oneshot") && strcmp(mode,"looping") ) {
|
||||
sprintf(msg, "RawWvIn: constructor parameter 'mode' must be oneshot or looping only.\n");
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
|
||||
// Use the system call "stat" to determine the file length
|
||||
struct stat filestat;
|
||||
if (stat(fileName, &filestat) == -1) {
|
||||
// Opening file failed
|
||||
sprintf(msg, "RawWvIn: Couldn't stat or find file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
fileSize = (long) filestat.st_size / 2; // length in 2-byte samples
|
||||
bufferSize = fileSize;
|
||||
|
||||
if (fileSize > MAX_FILE_LOAD_SIZE) {
|
||||
printf("\nRawWvIn: The .WAV file (%s) has more than %d samples and\n",
|
||||
fileName, MAX_FILE_LOAD_SIZE);
|
||||
printf("will be loaded incrementally from disk. Normalization will be disabled.\n");
|
||||
chunking = 1;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Open the file and read samples into data[]
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "RawWvIn: Couldn't open or find file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Setup for looping or one-shot playback
|
||||
if (!strcmp(mode,"looping"))
|
||||
looping = 1;
|
||||
else // default = oneshot
|
||||
looping = 0;
|
||||
|
||||
channels = 1; // All STK rawwave files are mono
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(bufferSize+1)*channels];
|
||||
|
||||
fseek(fd,0,SEEK_SET);
|
||||
dataOffset = 0;
|
||||
this->getData(0); // Read samples into data[]
|
||||
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 1.0;
|
||||
interpolate = 0;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
this->reset();
|
||||
|
||||
// finally, let's normalize the data by default
|
||||
this->normalize();
|
||||
}
|
||||
|
||||
RawWvIn :: ~RawWvIn()
|
||||
{
|
||||
}
|
||||
|
||||
void RawWvIn :: getData(long index)
|
||||
{
|
||||
/* Compare index to current readPointer and modify as needed.
|
||||
* The following while() loops will only execute on calls subsequent
|
||||
* to class instantiation ... and thus, only when "chunking".
|
||||
*/
|
||||
while (index < readPointer) {
|
||||
readPointer -= LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer < 0) {
|
||||
bufferSize += readPointer;
|
||||
readPointer = 0;
|
||||
}
|
||||
}
|
||||
while (index >= readPointer+bufferSize) {
|
||||
readPointer += LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer+LOAD_BUFFER_SIZE >= fileSize) {
|
||||
bufferSize = fileSize - readPointer;
|
||||
}
|
||||
}
|
||||
|
||||
fseek(fd, (long)(readPointer*2), SEEK_SET);
|
||||
long length = bufferSize;
|
||||
int end_of_file = (readPointer+bufferSize == fileSize);
|
||||
if (!end_of_file) length += 1;
|
||||
|
||||
// Read samples into data[]. Use MY _FLOAT data structure to store INT16 samples
|
||||
INT16 *buf = (INT16 *)data;
|
||||
fread(buf, length, 2, fd);
|
||||
// Convert in place (unpack) to MY_FLOAT from the end of the array
|
||||
for (int i=length-1; i>=0; i--) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)(buf+i));
|
||||
#endif
|
||||
data[i] = buf[i];
|
||||
if (chunking) data[i] *= 0.00003051;
|
||||
}
|
||||
|
||||
// fill in the extra sample frame for interpolation
|
||||
if (end_of_file) {
|
||||
if (looping)
|
||||
data[bufferSize] = data[0];
|
||||
else
|
||||
data[bufferSize] = data[(bufferSize-1)];
|
||||
}
|
||||
|
||||
if (!chunking) {
|
||||
fclose(fd);
|
||||
fd = 0;
|
||||
}
|
||||
}
|
||||
77
src/RawWvOut.cpp
Normal file
77
src/RawWvOut.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*******************************************/
|
||||
/* RawWvOut Output Class */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This object spits samples into a raw */
|
||||
/* 16-bit data (signed integer) file. */
|
||||
/* */
|
||||
/* STK RawWave files are assumed to be */
|
||||
/* monaural and big-endian. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RawWvOut.h"
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
RawWvOut :: RawWvOut(char *fileName, int chans)
|
||||
{
|
||||
char tempName[128];
|
||||
char msg[128];
|
||||
|
||||
if (chans != 1) {
|
||||
sprintf(msg, "RawWvOut: STK rawwave files are always monaural (channels = %d not supported)!\n", chans);
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
channels = chans;
|
||||
strcpy(tempName,fileName);
|
||||
if (strstr(tempName,".raw") == NULL) strcat(tempName,".raw");
|
||||
fd = fopen(tempName,"wb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "RawWvOut: Could not create soundfile: %s\n", tempName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
printf("\nCreating soundfile: %s\n", tempName);
|
||||
data_length = FILE_BUFFER_SIZE*channels;
|
||||
data = (INT16 *) new INT16[data_length];
|
||||
}
|
||||
|
||||
RawWvOut :: ~RawWvOut()
|
||||
{
|
||||
double temp;
|
||||
|
||||
fwrite(data,2,counter,fd);
|
||||
temp = (double) totalCount * ONE_OVER_SRATE;
|
||||
printf("%f Seconds Computed\n\n", temp);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
void RawWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
data[counter] = (INT16) (sample * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)&data[counter]);
|
||||
#endif
|
||||
counter++;
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(data,2,data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RawWvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
data[counter] = (INT16) (*samples * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)&data[counter]);
|
||||
#endif
|
||||
counter++;
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(data,2,data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
51
src/ReedTabl.cpp
Normal file
51
src/ReedTabl.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/**********************************************/
|
||||
/* One break point linear reed table object */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* Consult McIntyre, Schumacher, & Woodhouse */
|
||||
/* Smith, Hirschman, Cook, Scavone, */
|
||||
/* more for information. */
|
||||
/**********************************************/
|
||||
|
||||
#include "ReedTabl.h"
|
||||
|
||||
ReedTabl :: ReedTabl() : Object()
|
||||
{
|
||||
offSet = (MY_FLOAT) 0.6; /* Offset is a bias, related to reed rest position */
|
||||
slope = (MY_FLOAT) -0.8; /* Slope corresponds loosely to reed stiffness */
|
||||
}
|
||||
|
||||
ReedTabl :: ~ReedTabl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ReedTabl :: setOffset(MY_FLOAT aValue)
|
||||
{
|
||||
offSet = aValue; /* Offset is a bias, related to reed rest position */
|
||||
}
|
||||
|
||||
void ReedTabl :: setSlope(MY_FLOAT aValue)
|
||||
{
|
||||
slope = aValue; /* Slope corresponds loosely to reed stiffness */
|
||||
}
|
||||
|
||||
MY_FLOAT ReedTabl :: lookup(MY_FLOAT deltaP)
|
||||
{
|
||||
return this->tick(deltaP);
|
||||
}
|
||||
|
||||
MY_FLOAT ReedTabl :: tick(MY_FLOAT deltaP)
|
||||
/* Perform "Table Lookup" by direct clipped */
|
||||
/* linear function calculation */
|
||||
{ /* deltaP is differential reed pressure */
|
||||
lastOutput = offSet + (slope * deltaP); /* compute basic non-linearity */
|
||||
if (lastOutput > 1.0) lastOutput = (MY_FLOAT) 1.0; /* if other way, reed slams shut */
|
||||
if (lastOutput < -1.0) lastOutput = (MY_FLOAT) -1.0; /* if all the way open, acts like open end */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT ReedTabl :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
43
src/Reverb.cpp
Normal file
43
src/Reverb.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/********************************************/
|
||||
/* Reverb Abstract Class, */
|
||||
/* by Tim Stilson, 1998 */
|
||||
/* */
|
||||
/* Integrated into STK by Gary Scavone */
|
||||
/* with T60 argument. */
|
||||
/********************************************/
|
||||
|
||||
#include "Reverb.h"
|
||||
|
||||
Reverb :: Reverb()
|
||||
{
|
||||
}
|
||||
|
||||
Reverb :: ~Reverb()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Reverb :: tick(MY_FLOAT sample)
|
||||
{
|
||||
printf("Warning: Using virtual function Reverb :: tick()\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Reverb :: setEffectMix(MY_FLOAT mix)
|
||||
{
|
||||
}
|
||||
|
||||
int Reverb :: isprime(int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (val == 2) return 1;
|
||||
if (val & 1)
|
||||
{
|
||||
for (i=3; i<(int)sqrt((double)val)+1; i+=2)
|
||||
{
|
||||
if ((val%i) == 0) return 0;
|
||||
}
|
||||
return 1; /* prime */
|
||||
}
|
||||
else return 0; /* even */
|
||||
}
|
||||
66
src/Rhodey.cpp
Normal file
66
src/Rhodey.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/******************************************/
|
||||
/* Fender Rhodes Electric Piano Subclass */
|
||||
/* of Algorithm 5 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "Rhodey.h"
|
||||
|
||||
Rhodey :: Rhodey() : FM4Alg5()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file1[128];
|
||||
char file2[128];
|
||||
char file3[128];
|
||||
char file4[128];
|
||||
strcpy(file1, RAWWAVE_PATH);
|
||||
strcpy(file2, RAWWAVE_PATH);
|
||||
strcpy(file3, RAWWAVE_PATH);
|
||||
strcpy(file4, RAWWAVE_PATH);
|
||||
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
|
||||
strcat(file2,"rawwaves/sinewave.raw"),
|
||||
strcat(file3,"rawwaves/sinewave.raw"),
|
||||
strcat(file4,"rawwaves/fwavblnk.raw"));
|
||||
this->setRatio(0,(MY_FLOAT) 1.0);
|
||||
this->setRatio(1,(MY_FLOAT) 0.5);
|
||||
this->setRatio(2,(MY_FLOAT) 1.0);
|
||||
this->setRatio(3,(MY_FLOAT) 15.0);
|
||||
gains[0] = __FM4Op_gains[99];
|
||||
gains[1] = __FM4Op_gains[90];
|
||||
gains[2] = __FM4Op_gains[99];
|
||||
gains[3] = __FM4Op_gains[67];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.00,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.25,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
twozero->setGain((MY_FLOAT) 1.0);
|
||||
}
|
||||
|
||||
Rhodey :: ~Rhodey()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Rhodey :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency * (MY_FLOAT) 2.0;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
void Rhodey :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[99];
|
||||
gains[1] = amp * __FM4Op_gains[90];
|
||||
gains[2] = amp * __FM4Op_gains[99];
|
||||
gains[3] = amp * __FM4Op_gains[67];
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("Rhodey : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
1810
src/RtAudio.cpp
Normal file
1810
src/RtAudio.cpp
Normal file
File diff suppressed because it is too large
Load Diff
102
src/RtDuplex.cpp
Normal file
102
src/RtDuplex.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
/*******************************************/
|
||||
/* Real-Time Duplex Input/Output Class, */
|
||||
/* by Gary P. Scavone, 1999-2000 */
|
||||
/* */
|
||||
/* This object opens the sound i/o */
|
||||
/* device, reads buffers in from it, and */
|
||||
/* pokes buffers of samples out to it. */
|
||||
/* */
|
||||
/* At the moment, duplex mode is possible */
|
||||
/* only on Linux (OSS), IRIX, and */
|
||||
/* Windows95/98 platforms. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RtDuplex.h"
|
||||
|
||||
#if (defined(__STK_REALTIME_) )
|
||||
|
||||
RtDuplex :: RtDuplex(int chans, MY_FLOAT srate, int device)
|
||||
{
|
||||
// We'll let RTSoundIO deal with channel and srate limitations.
|
||||
channels = chans;
|
||||
sound_dev = new RtAudio(channels, srate, "duplex", device);
|
||||
writeCounter = 0;
|
||||
gain = 0.00003052;
|
||||
data_length = RT_BUFFER_SIZE*channels;
|
||||
indata = (INT16 *) new INT16[data_length+10];
|
||||
outdata = (INT16 *) new INT16[data_length+10];
|
||||
insamples = new MY_FLOAT[channels];
|
||||
#if (defined(__STK_REALTIME_) && defined(__OS_IRIX_))
|
||||
// This is necessary under IRIX because it scales the input by 0.5
|
||||
// when using single-channel input.
|
||||
if (channels == 1) gain *= 2;
|
||||
#endif
|
||||
// Read half a buffer to get started
|
||||
readCounter = data_length / 2;
|
||||
sound_dev->recordBuffer(&indata[readCounter],(data_length/2));
|
||||
}
|
||||
|
||||
RtDuplex :: ~RtDuplex()
|
||||
{
|
||||
sound_dev->playBuffer(outdata,writeCounter);
|
||||
writeCounter = 0;
|
||||
while (writeCounter<data_length) {
|
||||
outdata[writeCounter++] = 0;
|
||||
}
|
||||
sound_dev->playBuffer(outdata,writeCounter);
|
||||
sound_dev->playBuffer(outdata,writeCounter); // Are these extra writes necessary?
|
||||
sound_dev->playBuffer(outdata,writeCounter);
|
||||
delete [ ] insamples;
|
||||
delete [ ] indata;
|
||||
delete [ ] outdata;
|
||||
delete sound_dev;
|
||||
}
|
||||
|
||||
MY_FLOAT RtDuplex :: tick(MY_FLOAT outsample)
|
||||
{
|
||||
// We offset the data read and data write calls by RT_BUFFER_SIZE / 2
|
||||
if (readCounter >= data_length) {
|
||||
sound_dev->recordBuffer(indata,data_length);
|
||||
readCounter = 0;
|
||||
}
|
||||
*insamples = (MY_FLOAT) indata[readCounter++];
|
||||
if (channels > 1) {
|
||||
int i;
|
||||
for (i=1;i<channels;i++)
|
||||
*insamples += (MY_FLOAT) indata[readCounter++];
|
||||
*insamples /= i;
|
||||
}
|
||||
*insamples *= gain;
|
||||
|
||||
for (int i=0;i<channels;i++)
|
||||
outdata[writeCounter++] = (short) (outsample * 32000.0);
|
||||
|
||||
if (writeCounter >= data_length) {
|
||||
sound_dev->playBuffer(outdata,data_length);
|
||||
writeCounter = 0;
|
||||
}
|
||||
return *insamples;
|
||||
}
|
||||
|
||||
MY_MULTI RtDuplex :: mtick(MY_MULTI outsamples)
|
||||
{
|
||||
int i;
|
||||
// We offset the data read and data write calls by RT_BUFFER_SIZE / 2
|
||||
if (readCounter >= data_length) {
|
||||
sound_dev->recordBuffer(indata,data_length);
|
||||
readCounter = 0;
|
||||
}
|
||||
for (i=0;i<channels;i++)
|
||||
insamples[i] = (MY_FLOAT) (indata[readCounter++]*gain);
|
||||
|
||||
for (i=0;i<channels;i++)
|
||||
outdata[writeCounter++] = (short) (*outsamples++ * 32000.0);
|
||||
|
||||
if (writeCounter >= data_length) {
|
||||
sound_dev->playBuffer(outdata,data_length);
|
||||
writeCounter = 0;
|
||||
}
|
||||
return insamples;
|
||||
}
|
||||
|
||||
#endif
|
||||
1078
src/RtMidi.cpp
Normal file
1078
src/RtMidi.cpp
Normal file
File diff suppressed because it is too large
Load Diff
146
src/RtWvIn.cpp
Normal file
146
src/RtWvIn.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/*******************************************/
|
||||
/* RtWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 1999-2000 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to read in realtime 16-bit data */
|
||||
/* from a computer's audio port. */
|
||||
/* */
|
||||
/* NOTE: This object is NOT intended for */
|
||||
/* use in achieving simultaneous realtime */
|
||||
/* audio input/output (together with */
|
||||
/* RtWvOut). Under certain circumstances */
|
||||
/* such a scheme is possible, though you */
|
||||
/* should definitely know what you are */
|
||||
/* doing before trying. For safer "full- */
|
||||
/* duplex" operation, use the RtDuplex */
|
||||
/* class. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RtWvIn.h"
|
||||
|
||||
RtWvIn :: RtWvIn(int chans, MY_FLOAT srate, int device)
|
||||
{
|
||||
chunking = 1;
|
||||
looping = 0;
|
||||
sound_dev = new RtAudio(chans, srate, "record", device);
|
||||
channels = chans;
|
||||
bufferSize = RT_BUFFER_SIZE;
|
||||
data = 0;
|
||||
rtdata = (INT16 *) new INT16[(bufferSize+1)*channels];
|
||||
|
||||
lastSamples = (INT16 *) new INT16[channels];
|
||||
for (int i=0;i<channels;i++) {
|
||||
lastSamples[i] = (INT16) 0.0;
|
||||
}
|
||||
|
||||
this->getData(0);
|
||||
|
||||
rate = (MY_FLOAT) srate / SRATE;
|
||||
if (fmod(rate, 1.0) > 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
this->reset();
|
||||
|
||||
gain = 0.00003052;
|
||||
#if (defined(__STK_REALTIME_) && defined(__OS_IRIX_))
|
||||
// This is necessary under IRIX because it scales the input by 0.5
|
||||
// when using single-channel input.
|
||||
if (channels == 1) gain *= 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
RtWvIn :: ~RtWvIn()
|
||||
{
|
||||
delete sound_dev;
|
||||
if (rtdata) {
|
||||
delete [ ] rtdata;
|
||||
rtdata = 0;
|
||||
}
|
||||
if (lastSamples) {
|
||||
delete [ ] lastSamples;
|
||||
lastSamples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RtWvIn :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
// Negative rates not allowed for realtime input
|
||||
rate = fabs(aRate);
|
||||
|
||||
if (fmod(rate, 1.0) != 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
}
|
||||
|
||||
void RtWvIn :: addTime(MY_FLOAT aTime)
|
||||
{
|
||||
// Negative time shift no allowed for realtime input
|
||||
time += fabs(aTime);
|
||||
}
|
||||
|
||||
void RtWvIn :: setLooping(int aLoopStatus)
|
||||
{
|
||||
// No looping for realtime data.
|
||||
looping = 0;
|
||||
}
|
||||
|
||||
long RtWvIn :: getSize()
|
||||
{
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
void RtWvIn :: getData(long index)
|
||||
{
|
||||
static long temp = RT_BUFFER_SIZE*channels;
|
||||
sound_dev->recordBuffer(&rtdata[channels],temp);
|
||||
|
||||
/* Fill in the extra sample frame for interpolation.
|
||||
* We do this by pre-pending the last sample frame
|
||||
* from the previous input buffer to the current one.
|
||||
*/
|
||||
for (int i=0;i<channels;i++) {
|
||||
rtdata[i] = lastSamples[i];
|
||||
lastSamples[i] = rtdata[temp+i];
|
||||
}
|
||||
}
|
||||
|
||||
int RtWvIn :: informTick()
|
||||
{
|
||||
static MY_FLOAT alpha;
|
||||
static long index;
|
||||
|
||||
if (time >= bufferSize) {
|
||||
this->getData(0);
|
||||
while (time >= bufferSize)
|
||||
time -= bufferSize;
|
||||
}
|
||||
|
||||
// integer part of time address
|
||||
index = (long) time;
|
||||
|
||||
if (interpolate) {
|
||||
// fractional part of time address
|
||||
alpha = time - (MY_FLOAT) index;
|
||||
index *= channels;
|
||||
for (int i=0;i<channels;i++) {
|
||||
// Do linear interpolation
|
||||
lastOutput[i] = (MY_FLOAT) rtdata[index];
|
||||
lastOutput[i] += alpha * ((MY_FLOAT) rtdata[index+channels] - lastOutput[i]);
|
||||
lastOutput[i] *= gain;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
index *= channels;
|
||||
for (int i=0;i<channels;i++) {
|
||||
lastOutput[i] = rtdata[index++];
|
||||
lastOutput[i] *= gain;
|
||||
}
|
||||
}
|
||||
|
||||
// increment time, which can be negative
|
||||
time += rate;
|
||||
|
||||
return finished;
|
||||
}
|
||||
81
src/RtWvOut.cpp
Normal file
81
src/RtWvOut.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*******************************************/
|
||||
/* Real-Time Audio Output Class, */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* Revised by Gary P. Scavone, 2000 */
|
||||
/* */
|
||||
/* This object opens a realtime soundout */
|
||||
/* device, and pokes buffers of samples */
|
||||
/* into it. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RtWvOut.h"
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
RtWvOut :: RtWvOut(int chans, int device)
|
||||
{
|
||||
// We'll let RTSoundIO deal with channel and srate limitations.
|
||||
channels = chans;
|
||||
sound_dev = new RtAudio(channels, SRATE, "play", device);
|
||||
data_length = RT_BUFFER_SIZE*channels;
|
||||
// Add a few extra samples for good measure
|
||||
data = (INT16 *) new INT16[data_length+10];
|
||||
}
|
||||
|
||||
RtWvOut :: ~RtWvOut()
|
||||
{
|
||||
sound_dev->playBuffer(data,counter);
|
||||
counter = 0;
|
||||
while (counter<data_length) {
|
||||
data[counter++] = 0;
|
||||
}
|
||||
sound_dev->playBuffer(data,counter);
|
||||
sound_dev->playBuffer(data,counter); // Are these extra writes necessary?
|
||||
sound_dev->playBuffer(data,counter);
|
||||
delete sound_dev;
|
||||
}
|
||||
|
||||
void RtWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
for (int i=0;i<channels;i++)
|
||||
data[counter++] = (INT16) (sample * 32000.0);
|
||||
|
||||
if (counter >= data_length) {
|
||||
sound_dev->playBuffer(data,data_length);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RtWvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
for (int i=0;i<channels;i++)
|
||||
data[counter++] = (INT16) (*samples++ * 32000.0);
|
||||
|
||||
if (counter >= data_length) {
|
||||
sound_dev->playBuffer(data,data_length);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//windows stop and start methods ... because windoze sucks
|
||||
#if (defined(__OS_Win_) )
|
||||
|
||||
void RtWvOut :: stopPlay() {
|
||||
sound_dev->stopPlay();
|
||||
}
|
||||
|
||||
void RtWvOut :: startPlay() {
|
||||
sound_dev->startPlay();
|
||||
}
|
||||
|
||||
void RtWvOut :: stopRecord() {
|
||||
sound_dev->stopRecord();
|
||||
}
|
||||
|
||||
void RtWvOut :: startRecord() {
|
||||
sound_dev->startRecord();
|
||||
}
|
||||
|
||||
#endif // extra windoze crap
|
||||
|
||||
#endif
|
||||
344
src/SKINI11.cpp
Normal file
344
src/SKINI11.cpp
Normal file
@@ -0,0 +1,344 @@
|
||||
/******************************************/
|
||||
/* 3nd generation SKINI Text File Reader */
|
||||
/* Class, by Perry R. Cook, 1999 */
|
||||
/* This Object can open a SKINI File */
|
||||
/* and parse it. The file spec is mine */
|
||||
/* and mine alone, but it's all text so */
|
||||
/* that should help you figuring it out. */
|
||||
/* */
|
||||
/* SKINI (Synthesis toolKit Instrument */
|
||||
/* Network Interface) is like MIDI, but */
|
||||
/* allows for floating point control */
|
||||
/* changes, note numbers, etc. Example: */
|
||||
/* noteOn 60.01 111.132 plays a sharp */
|
||||
/* middle C with a velocity of 111.132 */
|
||||
/* See SKINI11.txt for more information */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "SKINI11.h"
|
||||
|
||||
SKINI11 :: SKINI11(char *fileName) /* Constructor for reading SKINI files */
|
||||
{ /* Use nextMessage() method */
|
||||
myFile = fopen(fileName,"r");
|
||||
if ((int) myFile < 0) printf("SKINI11: Can't open SKINI score file\n");
|
||||
this->nextMessage();
|
||||
}
|
||||
|
||||
SKINI11 :: SKINI11() /* Constructor to use this object for parsing */
|
||||
{ /* SKINI Strings (coming over socket for example */
|
||||
} /* Use parseThis() method with string argument */
|
||||
|
||||
SKINI11 :: ~SKINI11()
|
||||
{
|
||||
}
|
||||
|
||||
/***************** SOME HANDY ROUTINES *******************/
|
||||
|
||||
#include "SKINI11.tbl"
|
||||
|
||||
#define __SK_MAX_FIELDS_ 5
|
||||
#define __SK_MAX_SIZE_ 32
|
||||
|
||||
short ignore(char aChar)
|
||||
{
|
||||
short ignoreIt = 0;
|
||||
if (aChar == 0) ignoreIt = 1; // Null String Termination
|
||||
if (aChar == '\n') ignoreIt = 1; // Carraige Return???
|
||||
if (aChar == '/') ignoreIt = 2; // Comment Line
|
||||
return ignoreIt;
|
||||
}
|
||||
|
||||
short delimit(char aChar)
|
||||
{
|
||||
if (aChar == ' ' || // Space
|
||||
aChar == ',' || // Or Comma
|
||||
aChar == '\t') // Or Tab
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
short nextChar(char* aString)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<__SK_MAX_SIZE_;i++) {
|
||||
if ( aString[i] != ' ' && // Space
|
||||
aString[i] != ',' && // Or Comma
|
||||
aString[i] != '\t' ) // Or Tab
|
||||
return i;
|
||||
}
|
||||
return 1024;
|
||||
}
|
||||
|
||||
int subStrings(char *aString,
|
||||
char someStrings[__SK_MAX_FIELDS_][__SK_MAX_SIZE_],
|
||||
int somePointrs[__SK_MAX_FIELDS_],
|
||||
char *remainderString)
|
||||
{
|
||||
int notDone,howMany,point,temp;
|
||||
notDone = 1;
|
||||
howMany = 0;
|
||||
point = 0;
|
||||
temp = nextChar(aString);
|
||||
if (temp >= __SK_MAX_SIZE_) {
|
||||
notDone = 0;
|
||||
printf("Confusion here: Ignoring this line\n");
|
||||
printf("%s\n",aString);
|
||||
return howMany;
|
||||
}
|
||||
point = temp;
|
||||
somePointrs[howMany] = point;
|
||||
temp = 0;
|
||||
while (notDone) {
|
||||
if (aString[point] == '\n') {
|
||||
notDone = 0;
|
||||
}
|
||||
else {
|
||||
someStrings[howMany][temp++] = aString[point++];
|
||||
if (temp >= __SK_MAX_SIZE_) {
|
||||
howMany = 0;
|
||||
return howMany;
|
||||
}
|
||||
if (delimit(aString[point]) || aString[point] == '\n') {
|
||||
someStrings[howMany][temp] = 0;
|
||||
howMany += 1;
|
||||
if (howMany < __SK_MAX_FIELDS_) {
|
||||
temp = nextChar(&aString[point]);
|
||||
point += temp;
|
||||
somePointrs[howMany-1] = point;
|
||||
temp = 0;
|
||||
}
|
||||
else {
|
||||
temp = 0;
|
||||
somePointrs[howMany-1] = point;
|
||||
while(aString[point] != '\n')
|
||||
remainderString[temp++] = aString[point++];
|
||||
remainderString[temp] = aString[point];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// printf("Got: %i Strings:\n",howMany);
|
||||
// for (temp=0;temp<howMany;temp++)
|
||||
// printf("%s\n",someStrings[temp]);
|
||||
return howMany;
|
||||
|
||||
}
|
||||
|
||||
/**************** THE ENCHILLADA !!!! **********************/
|
||||
/*** This function parses a single string (if it can) ****/
|
||||
/*** of SKINI message, setting the appropriate variables ***/
|
||||
/*************************************************************/
|
||||
|
||||
long SKINI11 :: parseThis(char* aString)
|
||||
{
|
||||
int which,aField;
|
||||
int temp,temp2;
|
||||
char someStrings[__SK_MAX_FIELDS_][__SK_MAX_SIZE_];
|
||||
int somePointrs[__SK_MAX_FIELDS_];
|
||||
|
||||
temp = nextChar(aString);
|
||||
if ((which = ignore(aString[temp]))) {
|
||||
if (which == 2) printf("// CommentLine: %s\n",aString);
|
||||
messageType = 0;
|
||||
return messageType;
|
||||
}
|
||||
else {
|
||||
temp = subStrings(aString,someStrings,somePointrs,remainderString);
|
||||
if (temp > 0)
|
||||
which = 0;
|
||||
aField = 0;
|
||||
strcpy(msgTypeString,someStrings[aField]);
|
||||
while ((which < __SK_MaxMsgTypes_) &&
|
||||
(strcmp(msgTypeString,
|
||||
skini_msgs[which].messageString))) {
|
||||
which += 1;
|
||||
}
|
||||
if (which >= __SK_MaxMsgTypes_) {
|
||||
messageType = -1;
|
||||
printf("Couldn't parse this message field: =%s\n %s\n",
|
||||
msgTypeString,aString);
|
||||
return messageType;
|
||||
}
|
||||
else {
|
||||
messageType = skini_msgs[which].type;
|
||||
// printf("Message Token = %s type = %i\n", msgTypeString,messageType);
|
||||
}
|
||||
aField += 1;
|
||||
|
||||
if (someStrings[0][0] == '=') {
|
||||
deltaTime = (MY_FLOAT) atof(&someStrings[aField][1]);
|
||||
deltaTime = -deltaTime;
|
||||
}
|
||||
else {
|
||||
deltaTime = (MY_FLOAT) atof(someStrings[aField]);
|
||||
}
|
||||
// printf("DeltaTime = %f\n",deltaTime);
|
||||
aField += 1;
|
||||
|
||||
channel = atoi(someStrings[aField]);
|
||||
// printf("Channel = %i\n",channel);
|
||||
aField += 1;
|
||||
|
||||
if (skini_msgs[which].data2 != NOPE) {
|
||||
if (skini_msgs[which].data2 == SK_INT) {
|
||||
byteTwoInt = atoi(someStrings[aField]);
|
||||
byteTwo = (MY_FLOAT) byteTwoInt;
|
||||
}
|
||||
else if (skini_msgs[which].data2 == SK_DBL) {
|
||||
byteTwo = (MY_FLOAT) atof(someStrings[aField]);
|
||||
byteTwoInt = (long) byteTwo;
|
||||
}
|
||||
else if (skini_msgs[which].data2 == SK_STR) {
|
||||
temp = somePointrs[aField-1]; /* Hack Danger Here, Why -1??? */
|
||||
temp2 = 0;
|
||||
while (aString[temp] != '\n') {
|
||||
remainderString[temp2++] = aString[temp++];
|
||||
}
|
||||
remainderString[temp2] = 0;
|
||||
}
|
||||
else {
|
||||
byteTwoInt = skini_msgs[which].data2;
|
||||
byteTwo = (MY_FLOAT) byteTwoInt;
|
||||
aField -= 1;
|
||||
}
|
||||
|
||||
aField += 1;
|
||||
if (skini_msgs[which].data3 != NOPE) {
|
||||
if (skini_msgs[which].data3 == SK_INT) {
|
||||
byteThreeInt = atoi(someStrings[aField]);
|
||||
byteThree = (MY_FLOAT) byteThreeInt;
|
||||
}
|
||||
else if (skini_msgs[which].data3 == SK_DBL) {
|
||||
byteThree = (MY_FLOAT) atof(someStrings[aField]);
|
||||
byteThreeInt = (long) byteThree;
|
||||
}
|
||||
else if (skini_msgs[which].data3 == SK_STR) {
|
||||
temp = somePointrs[aField-1]; /* Hack Danger Here, Why -1??? */
|
||||
temp2 = 0;
|
||||
while (aString[temp] != '\n') {
|
||||
remainderString[temp2++] = aString[temp++];
|
||||
}
|
||||
remainderString[temp2] = 0;
|
||||
}
|
||||
else {
|
||||
byteThreeInt = skini_msgs[which].data3;
|
||||
byteThree = (MY_FLOAT) byteThreeInt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
byteThreeInt = byteTwoInt;
|
||||
byteThree = byteTwo;
|
||||
}
|
||||
}
|
||||
}
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI11 :: nextMessage()
|
||||
{
|
||||
int notDone;
|
||||
char inputString[1024];
|
||||
|
||||
notDone = 1;
|
||||
while (notDone) {
|
||||
notDone = 0;
|
||||
if (!fgets(inputString,1024,myFile)) {
|
||||
printf("//End of Score. Thanks for using SKINI0.9 Bye Bye!!\n");
|
||||
messageType = -1;
|
||||
return messageType;
|
||||
}
|
||||
else if (parseThis(inputString) == 0) {
|
||||
notDone = 1;
|
||||
}
|
||||
}
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI11 :: getType()
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI11 :: getChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI11 :: getDelta()
|
||||
{
|
||||
return deltaTime;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI11 :: getByteTwo()
|
||||
{
|
||||
return byteTwo;
|
||||
}
|
||||
|
||||
long SKINI11 :: getByteTwoInt()
|
||||
{
|
||||
return byteTwoInt;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI11 :: getByteThree()
|
||||
{
|
||||
return byteThree;
|
||||
}
|
||||
|
||||
long SKINI11 :: getByteThreeInt()
|
||||
{
|
||||
return byteThreeInt;
|
||||
}
|
||||
|
||||
char* SKINI11 :: getRemainderString()
|
||||
{
|
||||
return remainderString;
|
||||
}
|
||||
|
||||
char* SKINI11 :: getMessageTypeString()
|
||||
{
|
||||
return msgTypeString;
|
||||
}
|
||||
|
||||
char sk_tempString[1024];
|
||||
|
||||
char* SKINI11 :: whatsThisType(long type)
|
||||
{
|
||||
int i = 0;
|
||||
sk_tempString[0] = 0;
|
||||
for (i=0;i<__SK_MaxMsgTypes_;i++) {
|
||||
if (type == skini_msgs[i].type) {
|
||||
strcat(sk_tempString,skini_msgs[i].messageString);
|
||||
strcat(sk_tempString,",");
|
||||
}
|
||||
}
|
||||
return sk_tempString;
|
||||
}
|
||||
|
||||
char* SKINI11 :: whatsThisController(long contNum)
|
||||
{
|
||||
int i = 0;
|
||||
sk_tempString[0] = 0;
|
||||
for (i=0;i<__SK_MaxMsgTypes_;i++) {
|
||||
if (skini_msgs[i].type == __SK_ControlChange_
|
||||
&& contNum == skini_msgs[i].data2) {
|
||||
strcat(sk_tempString,skini_msgs[i].messageString);
|
||||
strcat(sk_tempString,",");
|
||||
}
|
||||
}
|
||||
return sk_tempString;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main(int argc,char *argv[])
|
||||
{
|
||||
SKINI11 testFile(argv[1]);
|
||||
|
||||
while(testFile.nextMessage() > 0) ;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
130
src/SKINI11.tbl
Normal file
130
src/SKINI11.tbl
Normal file
@@ -0,0 +1,130 @@
|
||||
|
||||
#include "SKINI11.msg"
|
||||
|
||||
#define __SK_MaxMsgTypes_ 128
|
||||
|
||||
struct SKINISpec { char messageString[32];
|
||||
long type;
|
||||
long data2;
|
||||
long data3;
|
||||
};
|
||||
|
||||
/* SEE COMMENT BLOCK AT BOTTOM FOR FIELDS AND USES */
|
||||
/* MessageString ,type, ch?, data2 , data3 */
|
||||
|
||||
struct SKINISpec skini_msgs[__SK_MaxMsgTypes_] =
|
||||
{
|
||||
{"NoteOff" , __SK_NoteOff_, SK_DBL, SK_DBL},
|
||||
{"NoteOn" , __SK_NoteOn_, SK_DBL, SK_DBL},
|
||||
{"PolyPressure" , __SK_PolyPressure_, SK_DBL, SK_DBL},
|
||||
{"ControlChange" , __SK_ControlChange_, SK_INT, SK_DBL},
|
||||
{"ProgramChange" , __SK_ProgramChange_, SK_DBL, SK_DBL},
|
||||
{"AfterTouch" , __SK_AfterTouch_, SK_DBL, NOPE},
|
||||
{"ChannelPressure" ,__SK_ChannelPressure_, SK_DBL, NOPE},
|
||||
{"PitchWheel" , __SK_PitchWheel_, SK_DBL, NOPE},
|
||||
{"PitchBend" , __SK_PitchBend_, SK_DBL, NOPE},
|
||||
|
||||
{"Clock" , __SK_Clock_, NOPE, NOPE},
|
||||
{"Undefined" , 249, NOPE, NOPE},
|
||||
{"SongStart" , __SK_SongStart_, NOPE, NOPE},
|
||||
{"Continue" , __SK_Continue_, NOPE, NOPE},
|
||||
{"SongStop" , __SK_SongStop_, NOPE, NOPE},
|
||||
{"Undefined" , 253, NOPE, NOPE},
|
||||
{"ActiveSensing" , __SK_ActiveSensing_, NOPE, NOPE},
|
||||
{"SystemReset" , __SK_SystemReset_, NOPE, NOPE},
|
||||
|
||||
{"Volume" , __SK_ControlChange_, __SK_Volume_ , SK_DBL},
|
||||
{"ModWheel" , __SK_ControlChange_, __SK_ModWheel_ , SK_DBL},
|
||||
{"Modulation" , __SK_ControlChange_, __SK_Modulation_ , SK_DBL},
|
||||
{"Breath" , __SK_ControlChange_, __SK_Breath_ , SK_DBL},
|
||||
{"FootControl" , __SK_ControlChange_, __SK_FootControl_ , SK_DBL},
|
||||
{"Portamento" , __SK_ControlChange_, __SK_Portamento_ , SK_DBL},
|
||||
{"Balance" , __SK_ControlChange_, __SK_Balance_ , SK_DBL},
|
||||
{"Pan" , __SK_ControlChange_, __SK_Pan_ , SK_DBL},
|
||||
{"Sustain" , __SK_ControlChange_, __SK_Sustain_ , SK_DBL},
|
||||
{"Damper" , __SK_ControlChange_, __SK_Damper_ , SK_DBL},
|
||||
{"Expression" , __SK_ControlChange_, __SK_Expression_ , SK_DBL},
|
||||
|
||||
{"NoiseLevel" , __SK_ControlChange_, __SK_NoiseLevel_ , SK_DBL},
|
||||
{"PickPosition" , __SK_ControlChange_, __SK_PickPosition_ , SK_DBL},
|
||||
{"StringDamping" , __SK_ControlChange_, __SK_StringDamping_ , SK_DBL},
|
||||
{"StringDetune" , __SK_ControlChange_, __SK_StringDetune_ , SK_DBL},
|
||||
{"BodySize" , __SK_ControlChange_, __SK_BodySize_ , SK_DBL},
|
||||
{"BowPressure" , __SK_ControlChange_, __SK_BowPressure_ , SK_DBL},
|
||||
{"BowPosition" , __SK_ControlChange_, __SK_BowPosition_ , SK_DBL},
|
||||
{"BowBeta" , __SK_ControlChange_, __SK_BowBeta_ , SK_DBL},
|
||||
|
||||
{"ReedStiffness" , __SK_ControlChange_, __SK_ReedStiffness_ , SK_DBL},
|
||||
{"ReedRestPos" , __SK_ControlChange_, __SK_ReedRestPos_ , SK_DBL},
|
||||
{"FluteEmbouchure" , __SK_ControlChange_, __SK_FluteEmbouchure_, SK_DBL},
|
||||
{"LipTension" , __SK_ControlChange_, __SK_LipTension_ , SK_DBL},
|
||||
{"StrikePosition" , __SK_ControlChange_, __SK_StrikePosition_, SK_DBL},
|
||||
{"StickHardness" , __SK_ControlChange_, __SK_StickHardness_ , SK_DBL},
|
||||
|
||||
{"TrillDepth" , __SK_ControlChange_, __SK_TrillDepth_ , SK_DBL},
|
||||
{"TrillSpeed" , __SK_ControlChange_, __SK_TrillSpeed_ , SK_DBL},
|
||||
|
||||
{"Strumming" , __SK_ControlChange_, __SK_Strumming_ , 127 },
|
||||
{"NotStrumming" , __SK_ControlChange_, __SK_Strumming_ , 0 },
|
||||
|
||||
{"PlayerSkill" , __SK_ControlChange_, __SK_PlayerSkill_ , SK_DBL},
|
||||
|
||||
{"Chord" , __SK_Chord_ , SK_DBL , SK_STR },
|
||||
{"ChordOff" , __SK_ChordOff_ , SK_DBL , NOPE },
|
||||
|
||||
{"ShakerInst" , __SK_ControlChange_, __SK_ShakerInst_ , SK_DBL},
|
||||
{"Maraca" , __SK_ControlChange_, __SK_ShakerInst_ , 0 },
|
||||
{"Sekere" , __SK_ControlChange_, __SK_ShakerInst_ , 1 },
|
||||
{"Cabasa" , __SK_ControlChange_, __SK_ShakerInst_ , 2 },
|
||||
{"Bamboo" , __SK_ControlChange_, __SK_ShakerInst_ , 3 },
|
||||
{"Waterdrp" , __SK_ControlChange_, __SK_ShakerInst_ , 4 },
|
||||
{"Tambourn" , __SK_ControlChange_, __SK_ShakerInst_ , 5 },
|
||||
{"Sleighbl" , __SK_ControlChange_, __SK_ShakerInst_ , 6 },
|
||||
{"Guiro" , __SK_ControlChange_, __SK_ShakerInst_ , 7 },
|
||||
|
||||
{"OpenFile" , 256, SK_STR , NOPE},
|
||||
{"SetPath" , 257, SK_STR , NOPE},
|
||||
|
||||
{"FilePath" , __SK_SINGER_FilePath_, SK_STR , NOPE},
|
||||
{"Frequency" , __SK_SINGER_Frequency_, SK_STR , NOPE},
|
||||
{"NoteName" , __SK_SINGER_NoteName_, SK_STR , NOPE},
|
||||
{"VocalShape" , __SK_SINGER_Shape_ , SK_STR , NOPE},
|
||||
{"Glottis" , __SK_SINGER_Glot_ , SK_STR , NOPE},
|
||||
{"VoicedUnVoiced" , __SK_SINGER_VoicedUnVoiced_, SK_DBL , SK_STR},
|
||||
{"Synthesize" , __SK_SINGER_Synthesize_, SK_STR , NOPE},
|
||||
{"Silence" , __SK_SINGER_Silence_, SK_STR , NOPE},
|
||||
{"VibratoAmt" , __SK_ControlChange_ ,__SK_SINGER_VibratoAmt_,SK_DBL},
|
||||
{"RndVibAmt" , __SK_SINGER_RndVibAmt_ ,SK_STR, NOPE},
|
||||
{"VibFreq" , __SK_ControlChange_ ,__SK_SINGER_VibFreq_ ,SK_DBL}
|
||||
};
|
||||
|
||||
|
||||
/** FORMAT: *************************************************************/
|
||||
/* */
|
||||
/* MessageStr$ ,type, data2, data3, */
|
||||
/* */
|
||||
/* type is the message type sent back from the SKINI line parser. */
|
||||
/* data<n> is either */
|
||||
/* NOPE : field not used, specifically, there aren't going */
|
||||
/* to be any more fields on this line. So if there */
|
||||
/* is is NOPE in data2, data3 won't even be checked */
|
||||
/* SK_INT : byte (actually scanned as 32 bit signed integer) */
|
||||
/* If it's a MIDI data field which is required to */
|
||||
/* be an integer, like a controller number, it's */
|
||||
/* 0-127. Otherwise) get creative with SK_INTs */
|
||||
/* SK_DBL : double precision floating point. SKINI uses these */
|
||||
/* in the MIDI context for note numbers with micro */
|
||||
/* tuning, velocities, controller values, etc. */
|
||||
/* SK_STR : only valid in final field. This allows (nearly) */
|
||||
/* arbitrary message types to be supported by simply */
|
||||
/* scanning the string to EndOfLine and then passing */
|
||||
/* it to a more intellegent handler. For example, */
|
||||
/* MIDI SYSEX (system exclusive) messages of up to */
|
||||
/* 256bytes can be read as space-delimited integers */
|
||||
/* into the 1K SK_STR buffer. Longer bulk dumps, */
|
||||
/* soundfiles, etc. should be handled as a new */
|
||||
/* message type pointing to a FileName stored in the */
|
||||
/* SK_STR field, or as a new type of multi-line */
|
||||
/* message. */
|
||||
/* */
|
||||
/*************************************************************************/
|
||||
48
src/SamplFlt.cpp
Normal file
48
src/SamplFlt.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*******************************************/
|
||||
/* Swept Filter SubClass of Sampling */
|
||||
/* Synthesizer, by Perry R. Cook, 1995-96*/
|
||||
/* This instrument inherits up to 5 */
|
||||
/* attack waves, 5 looped waves, an ADSR */
|
||||
/* envelope, and adds a 4 pole swept */
|
||||
/* filter. */
|
||||
/*******************************************/
|
||||
|
||||
#include "SamplFlt.h"
|
||||
|
||||
SamplFlt :: SamplFlt() : Sampler()
|
||||
{
|
||||
MY_FLOAT tempCoeffs[2] = {(MY_FLOAT) 0.0,(MY_FLOAT) -1.0};
|
||||
twozeroes[0] = new TwoZero;
|
||||
twozeroes[0]->setZeroCoeffs(tempCoeffs);
|
||||
twozeroes[0]->setGain((MY_FLOAT) 1.0);
|
||||
twozeroes[1] = new TwoZero;
|
||||
twozeroes[1]->setZeroCoeffs(tempCoeffs);
|
||||
twozeroes[1]->setGain((MY_FLOAT) 1.0);
|
||||
filters[0] = new FormSwep;
|
||||
filters[0]->setTargets((MY_FLOAT) 0.0,(MY_FLOAT) 0.7,(MY_FLOAT) 0.5);
|
||||
filters[1] = new FormSwep;
|
||||
filters[1]->setTargets((MY_FLOAT) 0.0,(MY_FLOAT) 0.7,(MY_FLOAT) 0.5);
|
||||
}
|
||||
|
||||
SamplFlt :: ~SamplFlt()
|
||||
{
|
||||
delete filters[0];
|
||||
delete filters[1];
|
||||
delete twozeroes[0];
|
||||
delete twozeroes[1];
|
||||
}
|
||||
|
||||
MY_FLOAT SamplFlt :: tick()
|
||||
{
|
||||
MY_FLOAT output;
|
||||
output = Sampler :: tick();
|
||||
output = twozeroes[0]->tick(output);
|
||||
output = filters[0]->tick(output);
|
||||
output = twozeroes[1]->tick(output);
|
||||
output = filters[1]->tick(output);
|
||||
return output;
|
||||
}
|
||||
|
||||
void SamplFlt :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
}
|
||||
63
src/Sampler.cpp
Normal file
63
src/Sampler.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*******************************************/
|
||||
/* Master Class for Sampling Synthesizer */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains up to 5 */
|
||||
/* attack waves, 5 looped waves, and */
|
||||
/* an ADSR envelope. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Sampler.h"
|
||||
|
||||
Sampler :: Sampler()
|
||||
{
|
||||
adsr = new ADSR;
|
||||
/* We don't make the waves here yet, because */
|
||||
/* we don't know what they will be. */
|
||||
baseFreq = (MY_FLOAT) 440.0;
|
||||
filter = new OnePole;
|
||||
attackGain = (MY_FLOAT) 0.25;
|
||||
loopGain = (MY_FLOAT) 0.25;
|
||||
whichOne = 0;
|
||||
}
|
||||
|
||||
Sampler :: ~Sampler()
|
||||
{
|
||||
delete adsr;
|
||||
delete filter;
|
||||
}
|
||||
|
||||
void Sampler :: keyOn()
|
||||
{
|
||||
adsr->keyOn();
|
||||
attacks[0]->reset();
|
||||
}
|
||||
|
||||
void Sampler :: keyOff()
|
||||
{
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Sampler :: noteOff(MY_FLOAT amplitude)
|
||||
{
|
||||
this->keyOff();
|
||||
#if defined(_debug_)
|
||||
printf("Sampler : NoteOff: Amp=%lf\n",amplitude);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Sampler :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Sampler :: tick()
|
||||
{
|
||||
lastOutput = attackGain * attacks[whichOne]->tick();
|
||||
lastOutput += loopGain * loops[whichOne]->tick();
|
||||
lastOutput = filter->tick(lastOutput);
|
||||
lastOutput *= adsr->tick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Sampler :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
}
|
||||
842
src/Shakers.cpp
Normal file
842
src/Shakers.cpp
Normal file
@@ -0,0 +1,842 @@
|
||||
/**********************************************************/
|
||||
/* PhISEM (Physically Informed Stochastic Event Modeling */
|
||||
/* by Perry R. Cook, Princeton, February 1997 */
|
||||
/* */
|
||||
/* Meta-model that simulates all of: */
|
||||
/* Maraca Simulation by Perry R. Cook, Princeton, 1996-7 */
|
||||
/* Sekere Simulation by Perry R. Cook, Princeton, 1996-7 */
|
||||
/* Cabasa Simulation by Perry R. Cook, Princeton, 1996-7 */
|
||||
/* Bamboo Windchime Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Water Drops Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Tambourine Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Sleighbells Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Guiro Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
/* PhOLIES (Physically-Oriented Library of */
|
||||
/* Imitated Environmental Sounds), Perry Cook, 1997-9 */
|
||||
/* */
|
||||
/* Stix1 (walking on brittle sticks) */
|
||||
/* Crunch1 (like new fallen snow, or not) */
|
||||
/* Wrench (basic socket wrench, friend of guiro) */
|
||||
/* Sandpapr (sandpaper) */
|
||||
/**********************************************************/
|
||||
|
||||
#include "Object.h"
|
||||
#ifdef __OS_NeXT_
|
||||
#include <libc.h>
|
||||
#endif
|
||||
|
||||
int my_random(int max) // Return Random Int Between 0 and max
|
||||
{
|
||||
long temp;
|
||||
#if defined(__OS_Win_) /* For Windoze */
|
||||
temp = (long) rand();
|
||||
#else /* This is for unix */
|
||||
temp = random() >> 16;
|
||||
#endif
|
||||
temp = temp * (long) max;
|
||||
temp = temp >> 15;
|
||||
return (int) temp;
|
||||
}
|
||||
|
||||
MY_FLOAT float_random(MY_FLOAT max) // Return random float between 0.0 and max
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = (MY_FLOAT) my_random(32767);
|
||||
temp = temp * 0.0000305185;
|
||||
temp = temp * max;
|
||||
return temp;
|
||||
}
|
||||
|
||||
MY_FLOAT noise_tick() // Return random MY_FLOAT float between -1.0 and 1.0
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = my_random(32767) - 16384;
|
||||
temp *= 0.0000610352;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/************************* MARACA *****************************/
|
||||
#define MARA_SOUND_DECAY 0.95
|
||||
#define MARA_SYSTEM_DECAY 0.999
|
||||
//#define MARA_GAIN 25.0
|
||||
#define MARA_GAIN 20.0
|
||||
#define MARA_NUM_BEANS 25
|
||||
#define MARA_CENTER_FREQ 3200.0
|
||||
#define MARA_RESON 0.96
|
||||
/*********************** SEKERE *****************************/
|
||||
#define SEKE_SOUND_DECAY 0.96
|
||||
#define SEKE_SYSTEM_DECAY 0.999
|
||||
//#define SEKE_GAIN 30.0
|
||||
#define SEKE_GAIN 20.0
|
||||
#define SEKE_NUM_BEANS 64
|
||||
#define SEKE_CENTER_FREQ 5500.0
|
||||
#define SEKE_RESON 0.6
|
||||
/*********************** SANDPAPER **************************/
|
||||
#define SANDPAPR_SOUND_DECAY 0.999
|
||||
#define SANDPAPR_SYSTEM_DECAY 0.999
|
||||
//#define SANDPAPR_GAIN 1.0
|
||||
#define SANDPAPR_GAIN 0.5
|
||||
#define SANDPAPR_NUM_GRAINS 128
|
||||
#define SANDPAPR_CENTER_FREQ 4500.0
|
||||
#define SANDPAPR_RESON 0.6
|
||||
/************************ CABASA *****************************/
|
||||
#define CABA_SOUND_DECAY 0.96
|
||||
#define CABA_SYSTEM_DECAY 0.997
|
||||
//#define CABA_GAIN 150.0
|
||||
#define CABA_GAIN 40.0
|
||||
#define CABA_NUM_BEADS 512
|
||||
#define CABA_CENTER_FREQ 3000.0
|
||||
#define CABA_RESON 0.7
|
||||
/************************ Bamboo Wind Chimes *****************/
|
||||
#define BAMB_SOUND_DECAY 0.95
|
||||
//#define BAMB_SYSTEM_DECAY 0.99995
|
||||
#define BAMB_SYSTEM_DECAY 0.9999
|
||||
#define BAMB_GAIN 2.0
|
||||
#define BAMB_NUM_TUBES 1.25
|
||||
#define BAMB_CENTER_FREQ0 2800.0
|
||||
#define BAMB_CENTER_FREQ1 0.8 * 2800.0
|
||||
#define BAMB_CENTER_FREQ2 1.2 * 2800.0
|
||||
#define BAMB_RESON 0.995
|
||||
/******************* Water Drops ****************************/
|
||||
#define WUTR_SOUND_DECAY 0.95
|
||||
//#define WUTR_SYSTEM_DECAY 0.999
|
||||
#define WUTR_SYSTEM_DECAY 0.996
|
||||
#define WUTR_GAIN 1.0
|
||||
//#define WUTR_NUM_SOURCES 4
|
||||
#define WUTR_NUM_SOURCES 10
|
||||
#define WUTR_CENTER_FREQ0 450.0
|
||||
#define WUTR_CENTER_FREQ1 600.0
|
||||
#define WUTR_CENTER_FREQ2 750.0
|
||||
#define WUTR_RESON 0.9985
|
||||
#define WUTR_FREQ_SWEEP 1.0001
|
||||
/****************** TAMBOURINE *****************************/
|
||||
#define TAMB_SOUND_DECAY 0.95
|
||||
#define TAMB_SYSTEM_DECAY 0.9985
|
||||
//#define TAMB_GAIN 10.0
|
||||
#define TAMB_GAIN 5.0
|
||||
#define TAMB_NUM_TIMBRELS 32
|
||||
#define TAMB_SHELL_FREQ 2300
|
||||
#define TAMB_SHELL_GAIN 0.1
|
||||
#define TAMB_SHELL_RESON 0.96
|
||||
#define TAMB_CYMB_FREQ1 5600
|
||||
#define TAMB_CYMB_FREQ2 8100
|
||||
#define TAMB_CYMB_RESON 0.99
|
||||
/********************** SLEIGHBELLS *************************/
|
||||
#define SLEI_SOUND_DECAY 0.97
|
||||
#define SLEI_SYSTEM_DECAY 0.9994
|
||||
//#define SLEI_GAIN 2.0
|
||||
#define SLEI_GAIN 1.0
|
||||
#define SLEI_NUM_BELLS 32
|
||||
#define SLEI_CYMB_FREQ0 2500
|
||||
#define SLEI_CYMB_FREQ1 5300
|
||||
#define SLEI_CYMB_FREQ2 6500
|
||||
#define SLEI_CYMB_FREQ3 8300
|
||||
#define SLEI_CYMB_FREQ4 9800
|
||||
#define SLEI_CYMB_RESON 0.99
|
||||
/*************************** GUIRO ***********************/
|
||||
#define GUIR_SOUND_DECAY 0.95
|
||||
#define GUIR_GAIN 10.0
|
||||
#define GUIR_NUM_PARTS 128
|
||||
#define GUIR_GOURD_FREQ 2500.0
|
||||
#define GUIR_GOURD_RESON 0.97
|
||||
#define GUIR_GOURD_FREQ2 4000.0
|
||||
#define GUIR_GOURD_RESON2 0.97
|
||||
/************************** WRENCH ***********************/
|
||||
#define WRENCH_SOUND_DECAY 0.95
|
||||
#define WRENCH_GAIN 5
|
||||
#define WRENCH_NUM_PARTS 128
|
||||
#define WRENCH_FREQ 3200.0
|
||||
#define WRENCH_RESON 0.99
|
||||
#define WRENCH_FREQ2 8000.0
|
||||
#define WRENCH_RESON2 0.992
|
||||
/************************ COKECAN **************************/
|
||||
#define COKECAN_SOUND_DECAY 0.97
|
||||
#define COKECAN_SYSTEM_DECAY 0.999
|
||||
//#define COKECAN_GAIN 1.0
|
||||
#define COKECAN_GAIN 0.8
|
||||
#define COKECAN_NUM_PARTS 48
|
||||
#define COKECAN_HELMFREQ 370
|
||||
#define COKECAN_HELM_RES 0.99
|
||||
#define COKECAN_METLFREQ0 1025
|
||||
#define COKECAN_METLFREQ1 1424
|
||||
#define COKECAN_METLFREQ2 2149
|
||||
#define COKECAN_METLFREQ3 3596
|
||||
#define COKECAN_METL_RES 0.992
|
||||
/************************************************************/
|
||||
/* PhOLIES (Physically-Oriented Library of */
|
||||
/* Imitated Environmental Sounds), Perry Cook, 1997-8 */
|
||||
/************************************************************/
|
||||
|
||||
/*********************** STIX1 *****************************/
|
||||
#define STIX1_SOUND_DECAY 0.96
|
||||
#define STIX1_SYSTEM_DECAY 0.998
|
||||
#define STIX1_GAIN 30.0
|
||||
#define STIX1_NUM_BEANS 2
|
||||
#define STIX1_CENTER_FREQ 5500.0
|
||||
#define STIX1_RESON 0.6
|
||||
/************************ Crunch1 ***************************/
|
||||
#define CRUNCH1_SOUND_DECAY 0.95
|
||||
#define CRUNCH1_SYSTEM_DECAY 0.99806
|
||||
//#define CRUNCH1_GAIN 30.0
|
||||
#define CRUNCH1_GAIN 20.0
|
||||
#define CRUNCH1_NUM_BEADS 7
|
||||
#define CRUNCH1_CENTER_FREQ 800.0
|
||||
#define CRUNCH1_RESON 0.95
|
||||
|
||||
/************ THE ACTUAL CLASS ITSELF *********************/
|
||||
|
||||
#include "Shakers.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Shakers :: Shakers() : Instrmnt()
|
||||
{
|
||||
int i;
|
||||
|
||||
instType = 0;
|
||||
shakeEnergy = 0.0;
|
||||
num_freqs = 0;
|
||||
sndLevel = 0.0;
|
||||
|
||||
for (i=0;i<MAX_FREQS;i++) {
|
||||
inputs[i] = 0.0;
|
||||
outputs[i][0] = 0.0;
|
||||
outputs[i][1] = 0.0;
|
||||
coeffs[i][0] = 0.0;
|
||||
coeffs[i][1] = 0.0;
|
||||
gains[i] = 0.0;
|
||||
center_freqs[i] = 0.0;
|
||||
resons[i] = 0.0;
|
||||
freq_rand[i] = 0.0;
|
||||
freqalloc[i] = 0;
|
||||
}
|
||||
|
||||
soundDecay = 0.0;
|
||||
systemDecay = 0.0;
|
||||
num_objects = 0.0;
|
||||
collLikely = 0.0;
|
||||
totalEnergy = 0.0;
|
||||
ratchet=0.0;
|
||||
ratchetDelta=0.0005;
|
||||
finalZ[0] = 0.0;
|
||||
finalZ[1] = 0.0;
|
||||
finalZ[2] = 0.0;
|
||||
finalZCoeffs[0] = 1.0;
|
||||
finalZCoeffs[1] = 0.0;
|
||||
finalZCoeffs[2] = 0.0;
|
||||
|
||||
this->setupNum(instType);
|
||||
}
|
||||
|
||||
Shakers :: ~Shakers()
|
||||
{
|
||||
}
|
||||
|
||||
#define MAX_SHAKE 2000.0
|
||||
|
||||
#define NUM_INST 13
|
||||
|
||||
char instrs[NUM_INST][16] =
|
||||
{"Maraca", "Cabasa", "Sekere", "Guiro",
|
||||
"Waterdrp", "Bamboo", "Tambourn", "Sleighbl",
|
||||
"Stix1", "Crunch1", "Wrench", "SandPapr", "CokeCan"};
|
||||
|
||||
int Shakers :: setupName(char* instr)
|
||||
{
|
||||
int i, which = 0;
|
||||
|
||||
for (i=0;i<NUM_INST;i++) {
|
||||
if (!strcmp(instr,instrs[i]))
|
||||
which = i;
|
||||
}
|
||||
#if defined(_debug_)
|
||||
printf("Shakers: Setting Instrument to %s\n",instrs[which]);
|
||||
#endif
|
||||
return this->setupNum(which);
|
||||
}
|
||||
|
||||
void Shakers :: setFinalZs(MY_FLOAT z0, MY_FLOAT z1, MY_FLOAT z2) {
|
||||
finalZCoeffs[0] = z0;
|
||||
finalZCoeffs[1] = z1;
|
||||
finalZCoeffs[2] = z2;
|
||||
}
|
||||
|
||||
void Shakers :: setDecays(MY_FLOAT sndDecay, MY_FLOAT sysDecay) {
|
||||
soundDecay = sndDecay;
|
||||
systemDecay = sysDecay;
|
||||
}
|
||||
|
||||
int Shakers :: setFreqAndReson(int which, MY_FLOAT freq, MY_FLOAT reson) {
|
||||
if (which < MAX_FREQS) {
|
||||
resons[which] = reson;
|
||||
center_freqs[which] = freq;
|
||||
t_center_freqs[which] = freq;
|
||||
coeffs[which][1] = reson * reson;
|
||||
coeffs[which][0] = -reson * 2.0 * cos(freq * TWO_PI / SRATE);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
int Shakers :: setupNum(int inst)
|
||||
{
|
||||
int i, rv = 0;
|
||||
MY_FLOAT temp;
|
||||
|
||||
if (inst==1) { // cabasa_setup();
|
||||
rv = inst;
|
||||
num_objects = CABA_NUM_BEADS;
|
||||
defObjs[inst] = CABA_NUM_BEADS;
|
||||
setDecays(CABA_SOUND_DECAY, CABA_SYSTEM_DECAY);
|
||||
defDecays[inst] = CABA_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.97;
|
||||
num_freqs = 1;
|
||||
baseGain = CABA_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0] = temp;
|
||||
freqalloc[0] = 0;
|
||||
setFreqAndReson(0,CABA_CENTER_FREQ,CABA_RESON);
|
||||
setFinalZs(1.0,-1.0,0.0);
|
||||
}
|
||||
else if (inst==2) { // sekere_setup();
|
||||
rv = inst;
|
||||
num_objects = SEKE_NUM_BEANS;
|
||||
defObjs[inst] = SEKE_NUM_BEANS;
|
||||
this->setDecays(SEKE_SOUND_DECAY,SEKE_SYSTEM_DECAY);
|
||||
defDecays[inst] = SEKE_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.94;
|
||||
num_freqs = 1;
|
||||
baseGain = SEKE_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0] = temp;
|
||||
freqalloc[0] = 0;
|
||||
this->setFreqAndReson(0,SEKE_CENTER_FREQ,SEKE_RESON);
|
||||
this->setFinalZs(1.0, 0.0, -1.0);
|
||||
}
|
||||
else if (inst==3) { // guiro_setup();
|
||||
rv = inst;
|
||||
num_objects = GUIR_NUM_PARTS;
|
||||
defObjs[inst] = GUIR_NUM_PARTS;
|
||||
setDecays(GUIR_SOUND_DECAY,1.0);
|
||||
defDecays[inst] = 0.9999;
|
||||
decayScale[inst] = 1.0;
|
||||
num_freqs = 2;
|
||||
baseGain = GUIR_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp;
|
||||
gains[1]=temp;
|
||||
freqalloc[0] = 0;
|
||||
freqalloc[1] = 0;
|
||||
freq_rand[0] = 0.0;
|
||||
freq_rand[1] = 0.0;
|
||||
setFreqAndReson(0,GUIR_GOURD_FREQ,GUIR_GOURD_RESON);
|
||||
setFreqAndReson(1,GUIR_GOURD_FREQ2,GUIR_GOURD_RESON2);
|
||||
ratchet = 0;
|
||||
ratchetPos = 10;
|
||||
}
|
||||
else if (inst==4) { // wuter_setup();
|
||||
rv = inst;
|
||||
num_objects = WUTR_NUM_SOURCES;
|
||||
defObjs[inst] = WUTR_NUM_SOURCES;
|
||||
setDecays(WUTR_SOUND_DECAY,WUTR_SYSTEM_DECAY);
|
||||
defDecays[inst] = WUTR_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.8;
|
||||
num_freqs = 3;
|
||||
baseGain = WUTR_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp;
|
||||
gains[1]=temp;
|
||||
gains[2]=temp;
|
||||
freqalloc[0] = 1;
|
||||
freqalloc[1] = 1;
|
||||
freqalloc[2] = 1;
|
||||
freq_rand[0] = 0.2;
|
||||
freq_rand[1] = 0.2;
|
||||
freq_rand[2] = 0.2;
|
||||
setFreqAndReson(0,WUTR_CENTER_FREQ0,WUTR_RESON);
|
||||
setFreqAndReson(1,WUTR_CENTER_FREQ0,WUTR_RESON);
|
||||
setFreqAndReson(2,WUTR_CENTER_FREQ0,WUTR_RESON);
|
||||
setFinalZs(1.0,0.0,0.0);
|
||||
}
|
||||
else if (inst==5) { // bamboo_setup();
|
||||
rv = inst;
|
||||
num_objects = BAMB_NUM_TUBES;
|
||||
defObjs[inst] = BAMB_NUM_TUBES;
|
||||
setDecays(BAMB_SOUND_DECAY, BAMB_SYSTEM_DECAY);
|
||||
defDecays[inst] = BAMB_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.7;
|
||||
num_freqs = 3;
|
||||
baseGain = BAMB_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp;
|
||||
gains[1]=temp;
|
||||
gains[2]=temp;
|
||||
freqalloc[0] = 1;
|
||||
freqalloc[1] = 1;
|
||||
freqalloc[2] = 1;
|
||||
freq_rand[0] = 0.2;
|
||||
freq_rand[1] = 0.2;
|
||||
freq_rand[2] = 0.2;
|
||||
setFreqAndReson(0,BAMB_CENTER_FREQ0,BAMB_RESON);
|
||||
setFreqAndReson(1,BAMB_CENTER_FREQ1,BAMB_RESON);
|
||||
setFreqAndReson(2,BAMB_CENTER_FREQ2,BAMB_RESON);
|
||||
setFinalZs(1.0,0.0,0.0);
|
||||
}
|
||||
else if (inst==6) { // tambourine_setup();
|
||||
rv = inst;
|
||||
num_objects = TAMB_NUM_TIMBRELS;
|
||||
defObjs[inst] = TAMB_NUM_TIMBRELS;
|
||||
setDecays(TAMB_SOUND_DECAY,TAMB_SYSTEM_DECAY);
|
||||
defDecays[inst] = TAMB_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.95;
|
||||
num_freqs = 3;
|
||||
baseGain = TAMB_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp*TAMB_SHELL_GAIN;
|
||||
gains[1]=temp*0.8;
|
||||
gains[2]=temp;
|
||||
freqalloc[0] = 0;
|
||||
freqalloc[1] = 1;
|
||||
freqalloc[2] = 1;
|
||||
freq_rand[0] = 0.0;
|
||||
freq_rand[1] = 0.05;
|
||||
freq_rand[2] = 0.05;
|
||||
setFreqAndReson(0,TAMB_SHELL_FREQ,TAMB_SHELL_RESON);
|
||||
setFreqAndReson(1,TAMB_CYMB_FREQ1,TAMB_CYMB_RESON);
|
||||
setFreqAndReson(2,TAMB_CYMB_FREQ2,TAMB_CYMB_RESON);
|
||||
setFinalZs(1.0,0.0,-1.0);
|
||||
}
|
||||
else if (inst==7) { // sleighbell_setup();
|
||||
rv = inst;
|
||||
num_objects = SLEI_NUM_BELLS;
|
||||
defObjs[inst] = SLEI_NUM_BELLS;
|
||||
setDecays(SLEI_SOUND_DECAY,SLEI_SYSTEM_DECAY);
|
||||
defDecays[inst] = SLEI_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.9;
|
||||
num_freqs = 5;
|
||||
baseGain = SLEI_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp;
|
||||
gains[1]=temp;
|
||||
gains[2]=temp;
|
||||
gains[3]=temp*0.5;
|
||||
gains[4]=temp*0.3;
|
||||
for (i=0;i<num_freqs;i++) {
|
||||
freqalloc[i] = 1;
|
||||
freq_rand[i] = 0.03;
|
||||
}
|
||||
setFreqAndReson(0,SLEI_CYMB_FREQ0,SLEI_CYMB_RESON);
|
||||
setFreqAndReson(1,SLEI_CYMB_FREQ1,SLEI_CYMB_RESON);
|
||||
setFreqAndReson(2,SLEI_CYMB_FREQ2,SLEI_CYMB_RESON);
|
||||
setFreqAndReson(3,SLEI_CYMB_FREQ3,SLEI_CYMB_RESON);
|
||||
setFreqAndReson(4,SLEI_CYMB_FREQ4,SLEI_CYMB_RESON);
|
||||
setFinalZs(1.0,0.0,-1.0);
|
||||
}
|
||||
else if (inst==8) { // stix1_setup();
|
||||
rv = inst;
|
||||
num_objects = STIX1_NUM_BEANS;
|
||||
defObjs[inst] = STIX1_NUM_BEANS;
|
||||
setDecays(STIX1_SOUND_DECAY,STIX1_SYSTEM_DECAY);
|
||||
defDecays[inst] = STIX1_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.96;
|
||||
num_freqs = 1;
|
||||
baseGain = STIX1_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp;
|
||||
freqalloc[0] = 0;
|
||||
setFreqAndReson(0,STIX1_CENTER_FREQ,STIX1_RESON);
|
||||
setFinalZs(1.0,0.0,-1.0);
|
||||
}
|
||||
else if (inst==9) { // crunch1_setup();
|
||||
rv = inst;
|
||||
num_objects = CRUNCH1_NUM_BEADS;
|
||||
defObjs[inst] = CRUNCH1_NUM_BEADS;
|
||||
setDecays(CRUNCH1_SOUND_DECAY,CRUNCH1_SYSTEM_DECAY);
|
||||
defDecays[inst] = CRUNCH1_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.96;
|
||||
num_freqs = 1;
|
||||
baseGain = CRUNCH1_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp;
|
||||
freqalloc[0] = 0;
|
||||
setFreqAndReson(0,CRUNCH1_CENTER_FREQ,CRUNCH1_RESON);
|
||||
setFinalZs(1.0,-1.0,0.0);
|
||||
}
|
||||
else if (inst==10) { // wrench_setup();
|
||||
rv = inst;
|
||||
num_objects = WRENCH_NUM_PARTS;
|
||||
defObjs[inst] = WRENCH_NUM_PARTS;
|
||||
setDecays(WRENCH_SOUND_DECAY,1.0);
|
||||
defDecays[inst] = 0.9999;
|
||||
decayScale[inst] = 0.98;
|
||||
num_freqs = 2;
|
||||
baseGain = WRENCH_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp;
|
||||
gains[1]=temp;
|
||||
freqalloc[0] = 0;
|
||||
freqalloc[1] = 0;
|
||||
freq_rand[0] = 0.0;
|
||||
freq_rand[1] = 0.0;
|
||||
setFreqAndReson(0,WRENCH_FREQ,WRENCH_RESON);
|
||||
setFreqAndReson(1,WRENCH_FREQ2,WRENCH_RESON2);
|
||||
ratchet = 0;
|
||||
ratchetPos = 10;
|
||||
}
|
||||
else if (inst==11) { // sandpapr_setup();
|
||||
rv = inst;
|
||||
num_objects = SANDPAPR_NUM_GRAINS;
|
||||
defObjs[inst] = SANDPAPR_NUM_GRAINS;
|
||||
this->setDecays(SANDPAPR_SOUND_DECAY,SANDPAPR_SYSTEM_DECAY);
|
||||
defDecays[inst] = SANDPAPR_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.97;
|
||||
num_freqs = 1;
|
||||
baseGain = SANDPAPR_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0] = temp;
|
||||
freqalloc[0] = 0;
|
||||
this->setFreqAndReson(0,SANDPAPR_CENTER_FREQ,SANDPAPR_RESON);
|
||||
this->setFinalZs(1.0, 0.0, -1.0);
|
||||
}
|
||||
else if (inst==12) { // cokecan_setup();
|
||||
rv = inst;
|
||||
num_objects = COKECAN_NUM_PARTS;
|
||||
defObjs[inst] = COKECAN_NUM_PARTS;
|
||||
setDecays(COKECAN_SOUND_DECAY,COKECAN_SYSTEM_DECAY);
|
||||
defDecays[inst] = COKECAN_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.95;
|
||||
num_freqs = 5;
|
||||
baseGain = COKECAN_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp;
|
||||
gains[1]=temp*1.8;
|
||||
gains[2]=temp*1.8;
|
||||
gains[3]=temp*1.8;
|
||||
gains[4]=temp*1.8;
|
||||
freqalloc[0] = 0;
|
||||
freqalloc[1] = 0;
|
||||
freqalloc[2] = 0;
|
||||
freqalloc[3] = 0;
|
||||
freqalloc[4] = 0;
|
||||
setFreqAndReson(0,COKECAN_HELMFREQ,COKECAN_HELM_RES);
|
||||
setFreqAndReson(1,COKECAN_METLFREQ0,COKECAN_METL_RES);
|
||||
setFreqAndReson(2,COKECAN_METLFREQ1,COKECAN_METL_RES);
|
||||
setFreqAndReson(3,COKECAN_METLFREQ2,COKECAN_METL_RES);
|
||||
setFreqAndReson(4,COKECAN_METLFREQ3,COKECAN_METL_RES);
|
||||
setFinalZs(1.0,0.0,-1.0);
|
||||
}
|
||||
else { // maraca_setup(); inst == 0 or other
|
||||
num_objects = MARA_NUM_BEANS;
|
||||
defObjs[0] = MARA_NUM_BEANS;
|
||||
setDecays(MARA_SOUND_DECAY,MARA_SYSTEM_DECAY);
|
||||
defDecays[0] = MARA_SYSTEM_DECAY;
|
||||
decayScale[inst] = 0.9;
|
||||
num_freqs = 1;
|
||||
baseGain = MARA_GAIN;
|
||||
temp = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
gains[0]=temp;
|
||||
freqalloc[0] = 0;
|
||||
setFreqAndReson(0,MARA_CENTER_FREQ,MARA_RESON);
|
||||
setFinalZs(1.0,-1.0,0.0);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void Shakers :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
// Yep ... pretty kludgey, but it works!
|
||||
int noteNum = (int) ((12*log(freq/220)/log(2.0)) + 57.01) % 32;
|
||||
if (instType != noteNum) instType = this->setupNum(noteNum);
|
||||
//shakeEnergy = amp * MAX_SHAKE * 0.1;
|
||||
shakeEnergy += amp * MAX_SHAKE * 0.1;
|
||||
if (shakeEnergy > MAX_SHAKE) shakeEnergy = MAX_SHAKE;
|
||||
if (instType==10 || instType==3) ratchetPos += 1;
|
||||
#if defined(_debug_)
|
||||
printf("Shakers : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Shakers :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
shakeEnergy = 0.0;
|
||||
if (instType==10 || instType==3) ratchetPos = 0;
|
||||
}
|
||||
|
||||
#define MIN_ENERGY 0.3
|
||||
|
||||
MY_FLOAT Shakers :: tick()
|
||||
{
|
||||
MY_FLOAT data;
|
||||
MY_FLOAT temp_rand;
|
||||
int i;
|
||||
|
||||
if (instType==4) {
|
||||
if (shakeEnergy > MIN_ENERGY) {
|
||||
lastOutput = wuter_tick();
|
||||
lastOutput *= 0.0001;
|
||||
}
|
||||
else {
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
}
|
||||
else if (instType==10 || instType==3) {
|
||||
if (ratchetPos > 0) {
|
||||
ratchet -= (ratchetDelta + (0.002*totalEnergy));
|
||||
if (ratchet < 0.0) {
|
||||
ratchet = 1.0;
|
||||
ratchetPos -= 1;
|
||||
}
|
||||
totalEnergy = ratchet;
|
||||
lastOutput = ratchet_tick();
|
||||
lastOutput *= 0.0001;
|
||||
}
|
||||
else lastOutput = 0.0;
|
||||
}
|
||||
else {
|
||||
// MY_FLOAT generic_tick() {
|
||||
if (shakeEnergy > MIN_ENERGY) {
|
||||
shakeEnergy *= systemDecay; // Exponential system decay
|
||||
if (float_random(1024.0) < num_objects) {
|
||||
sndLevel += shakeEnergy;
|
||||
for (i=0;i<num_freqs;i++) {
|
||||
if (freqalloc[i]) {
|
||||
temp_rand = t_center_freqs[i] * (1.0 + (freq_rand[i] * noise_tick()));
|
||||
coeffs[i][0] = -resons[i] * 2.0 * cos(temp_rand * TWO_PI / SRATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
inputs[0] = sndLevel * noise_tick(); // Actual Sound is Random
|
||||
for (i=1; i<num_freqs; i++) {
|
||||
inputs[i] = inputs[0];
|
||||
}
|
||||
sndLevel *= soundDecay; // Exponential Sound decay
|
||||
finalZ[2] = finalZ[1];
|
||||
finalZ[1] = finalZ[0];
|
||||
finalZ[0] = 0;
|
||||
for (i=0;i<num_freqs;i++) {
|
||||
inputs[i] -= outputs[i][0]*coeffs[i][0]; // Do
|
||||
inputs[i] -= outputs[i][1]*coeffs[i][1]; // resonant
|
||||
outputs[i][1] = outputs[i][0]; // filter
|
||||
outputs[i][0] = inputs[i]; // calculations
|
||||
finalZ[0] += gains[i] * outputs[i][1];
|
||||
}
|
||||
data = finalZCoeffs[0] * finalZ[0]; // Extra zero(s) for shape
|
||||
data += finalZCoeffs[1] * finalZ[1]; // Extra zero(s) for shape
|
||||
data += finalZCoeffs[2] * finalZ[2]; // Extra zero(s) for shape
|
||||
if (data > 10000.0) data = 10000.0;
|
||||
if (data < -10000.0) data = -10000.0;
|
||||
lastOutput = data * 0.0001;
|
||||
}
|
||||
else lastOutput = 0.0;
|
||||
}
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Shakers :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
int i;
|
||||
#if defined(_debug_)
|
||||
printf("Shakers : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_ShakerEnergy_) { // control_change #2
|
||||
#if defined(_debug_)
|
||||
printf("shaking \n");
|
||||
#endif
|
||||
shakeEnergy += value * NORM_7 * MAX_SHAKE * 0.1;
|
||||
if (shakeEnergy > MAX_SHAKE) shakeEnergy = MAX_SHAKE;
|
||||
if (instType==10 || instType==3) {
|
||||
ratchetPos = (int) fabs(value - lastRatchetPos);
|
||||
ratchetDelta = 0.0002 * ratchetPos;
|
||||
lastRatchetPos = (int) value;
|
||||
}
|
||||
}
|
||||
else if (number == __SK_ShakerDamping_) { // control_change #11
|
||||
#if defined(_debug_)
|
||||
printf("setting decay\n");
|
||||
#endif
|
||||
//systemDecay = 0.998 + (value * NORM_7 * 0.002);
|
||||
if (instType != 3 && instType != 10) {
|
||||
systemDecay = defDecays[instType] + ((value - 64.0) * decayScale[instType] * (1.0 - defDecays[instType]) / 64.0 );
|
||||
gains[0] = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
for (i=1;i<num_freqs;i++) gains[i] = gains[0];
|
||||
if (instType == 6) { // tambourine
|
||||
gains[0] *= TAMB_SHELL_GAIN;
|
||||
gains[1] *= 0.8;
|
||||
}
|
||||
else if (instType == 7) { // sleighbell
|
||||
gains[3] *= 0.5;
|
||||
gains[4] *= 0.3;
|
||||
}
|
||||
else if (instType == 12) { // cokecan
|
||||
for (i=1;i<num_freqs;i++) gains[i] *= 1.8;
|
||||
}
|
||||
for (i=0;i<num_freqs;i++) gains[i] *= ((128-value)/100.0 + 0.36);
|
||||
}
|
||||
}
|
||||
else if (number == __SK_ShakerNumObjects_) { // control_change #4
|
||||
#if defined(_debug_)
|
||||
printf("setting number of objects\n");
|
||||
#endif
|
||||
if (instType == 5) // bamboo
|
||||
num_objects = (MY_FLOAT) (value * defObjs[instType] / 64.0) + 0.3;
|
||||
else
|
||||
num_objects = (MY_FLOAT) (value * defObjs[instType] / 64.0) + 1.1;
|
||||
gains[0] = log(num_objects) * baseGain / (MY_FLOAT) num_objects;
|
||||
for (i=1;i<num_freqs;i++) gains[i] = gains[0];
|
||||
if (instType == 6) { // tambourine
|
||||
gains[0] *= TAMB_SHELL_GAIN;
|
||||
gains[1] *= 0.8;
|
||||
}
|
||||
else if (instType == 7) { // sleighbell
|
||||
gains[3] *= 0.5;
|
||||
gains[4] *= 0.3;
|
||||
}
|
||||
else if (instType == 12) { // cokecan
|
||||
for (i=1;i<num_freqs;i++) gains[i] *= 1.8;
|
||||
}
|
||||
if (instType != 3 && instType != 10) {
|
||||
// reverse calculate decay setting
|
||||
MY_FLOAT temp = 64.0 * (systemDecay-defDecays[instType])/(decayScale[instType]*(1-defDecays[instType])) + 64.0;
|
||||
// scale gains by decay setting
|
||||
for (i=0;i<num_freqs;i++) gains[i] *= ((128-temp)/100.0 + 0.36);
|
||||
}
|
||||
}
|
||||
else if (number == __SK_ModWheel_) { // control_change #1
|
||||
#if defined(_debug_)
|
||||
printf("setting resonance %i freq. to %f\n",i,temp);
|
||||
#endif
|
||||
for (i=0;i<num_freqs;i++) {
|
||||
if (instType == 6 || instType == 2 || instType == 7) // limit range a bit for tambourine
|
||||
temp = center_freqs[i] * pow (1.008,value-64);
|
||||
else
|
||||
temp = center_freqs[i] * pow (1.015,value-64);
|
||||
t_center_freqs[i] = temp;
|
||||
|
||||
coeffs[i][0] = -resons[i] * 2.0 * cos(temp * TWO_PI / SRATE);
|
||||
coeffs[i][1] = resons[i]*resons[i];
|
||||
}
|
||||
}
|
||||
else if (number == __SK_AfterTouch_Cont_) { // control_change #128
|
||||
#if defined(_debug_)
|
||||
printf("shaking \n");
|
||||
#endif
|
||||
shakeEnergy += value * NORM_7 * MAX_SHAKE * 0.1;
|
||||
if (shakeEnergy > MAX_SHAKE) shakeEnergy = MAX_SHAKE;
|
||||
if (instType==10 || instType==3) {
|
||||
ratchetPos = (int) fabs(value - lastRatchetPos);
|
||||
ratchetDelta = 0.0002 * ratchetPos;
|
||||
lastRatchetPos = (int) value;
|
||||
}
|
||||
}
|
||||
else if (number == __SK_ShakerInst_) { // control_change #1071
|
||||
instType = (int) (value + 0.5); // Just to be safe
|
||||
this->setupNum(instType);
|
||||
}
|
||||
else {
|
||||
printf("Shakers : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/**************** KLUDGE-O-MATIC-O-RAMA **************/
|
||||
|
||||
MY_FLOAT Shakers :: wuter_tick() {
|
||||
MY_FLOAT data;
|
||||
int j;
|
||||
shakeEnergy *= systemDecay; // Exponential system decay
|
||||
if (my_random(32767) < num_objects) {
|
||||
sndLevel = shakeEnergy;
|
||||
j = my_random(3);
|
||||
if (j == 0) {
|
||||
center_freqs[0] = WUTR_CENTER_FREQ1 * (0.75 + (0.25 * noise_tick()));
|
||||
gains[0] = fabs(noise_tick());
|
||||
}
|
||||
else if (j == 1) {
|
||||
center_freqs[1] = WUTR_CENTER_FREQ1 * (1.0 + (0.25 * noise_tick()));
|
||||
gains[1] = fabs(noise_tick());
|
||||
}
|
||||
else {
|
||||
center_freqs[2] = WUTR_CENTER_FREQ1 * (1.25 + (0.25 * noise_tick()));
|
||||
gains[2] = fabs(noise_tick());
|
||||
}
|
||||
}
|
||||
|
||||
gains[0] *= resons[0];
|
||||
if (gains[0] > 0.001) {
|
||||
center_freqs[0] *= WUTR_FREQ_SWEEP;
|
||||
coeffs[0][0] = -resons[0] * 2.0 *
|
||||
cos(center_freqs[0] * TWO_PI / SRATE);
|
||||
}
|
||||
gains[1] *= resons[1];
|
||||
if (gains[1] > 0.001) {
|
||||
center_freqs[1] *= WUTR_FREQ_SWEEP;
|
||||
coeffs[1][0] = -resons[1] * 2.0 *
|
||||
cos(center_freqs[1] * TWO_PI / SRATE);
|
||||
}
|
||||
gains[2] *= resons[2];
|
||||
if (gains[2] > 0.001) {
|
||||
center_freqs[2] *= WUTR_FREQ_SWEEP;
|
||||
coeffs[2][0] = -resons[2] * 2.0 *
|
||||
cos(center_freqs[2] * TWO_PI / SRATE);
|
||||
}
|
||||
|
||||
sndLevel *= soundDecay; // Each (all) event(s)
|
||||
// decay(s) exponentially
|
||||
inputs[0] = sndLevel;
|
||||
inputs[0] *= noise_tick(); // Actual Sound is Random
|
||||
inputs[1] = inputs[0] * gains[1];
|
||||
inputs[2] = inputs[0] * gains[2];
|
||||
inputs[0] *= gains[0];
|
||||
inputs[0] -= outputs[0][0]*coeffs[0][0];
|
||||
inputs[0] -= outputs[0][1]*coeffs[0][1];
|
||||
outputs[0][1] = outputs[0][0];
|
||||
outputs[0][0] = inputs[0];
|
||||
data = gains[0]*outputs[0][0];
|
||||
inputs[1] -= outputs[1][0]*coeffs[1][0];
|
||||
inputs[1] -= outputs[1][1]*coeffs[1][1];
|
||||
outputs[1][1] = outputs[1][0];
|
||||
outputs[1][0] = inputs[1];
|
||||
data += gains[1]*outputs[1][0];
|
||||
inputs[2] -= outputs[2][0]*coeffs[2][0];
|
||||
inputs[2] -= outputs[2][1]*coeffs[2][1];
|
||||
outputs[2][1] = outputs[2][0];
|
||||
outputs[2][0] = inputs[2];
|
||||
data += gains[2]*outputs[2][0];
|
||||
|
||||
finalZ[2] = finalZ[1];
|
||||
finalZ[1] = finalZ[0];
|
||||
finalZ[0] = data * 4;
|
||||
|
||||
data = finalZ[2] - finalZ[0];
|
||||
return data;
|
||||
}
|
||||
|
||||
MY_FLOAT Shakers :: ratchet_tick() {
|
||||
MY_FLOAT data;
|
||||
if (my_random(1024) < num_objects) {
|
||||
sndLevel += 512 * ratchet * totalEnergy;
|
||||
}
|
||||
inputs[0] = sndLevel;
|
||||
inputs[0] *= noise_tick() * ratchet;
|
||||
sndLevel *= soundDecay;
|
||||
|
||||
inputs[1] = inputs[0];
|
||||
inputs[0] -= outputs[0][0]*coeffs[0][0];
|
||||
inputs[0] -= outputs[0][1]*coeffs[0][1];
|
||||
outputs[0][1] = outputs[0][0];
|
||||
outputs[0][0] = inputs[0];
|
||||
inputs[1] -= outputs[1][0]*coeffs[1][0];
|
||||
inputs[1] -= outputs[1][1]*coeffs[1][1];
|
||||
outputs[1][1] = outputs[1][0];
|
||||
outputs[1][0] = inputs[1];
|
||||
|
||||
finalZ[2] = finalZ[1];
|
||||
finalZ[1] = finalZ[0];
|
||||
finalZ[0] = gains[0]*outputs[0][1] + gains[1]*outputs[1][1];
|
||||
data = finalZ[0] - finalZ[2];
|
||||
return data;
|
||||
}
|
||||
|
||||
114
src/Simple.cpp
Normal file
114
src/Simple.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/*******************************************/
|
||||
/* Master Class for Simple Instrument */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains 1 looped */
|
||||
/* wave, 1 noise source, 1 biquad filter */
|
||||
/* 1 one-pole filter, and 1 ADSR envelope */
|
||||
/*******************************************/
|
||||
|
||||
#include "Simple.h"
|
||||
|
||||
Simple :: Simple()
|
||||
{
|
||||
MY_FLOAT coeffs[2];
|
||||
adsr = new ADSR;
|
||||
baseFreq = (MY_FLOAT) 440.0;
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
loop = new RawWvIn(strcat(file,"rawwaves/impuls10.raw"),"looping");
|
||||
filter = new OnePole;
|
||||
noise = new Noise;
|
||||
bqpoles = new TwoPole;
|
||||
bqzeroes = new TwoZero;
|
||||
coeffs[0] = 0;
|
||||
coeffs[1] = -1;
|
||||
bqzeroes->setZeroCoeffs(coeffs);
|
||||
filter->setPole(0.5);
|
||||
this->setFreq(baseFreq);
|
||||
loopGain = 0.5;
|
||||
}
|
||||
|
||||
Simple :: ~Simple()
|
||||
{
|
||||
delete adsr;
|
||||
delete loop;
|
||||
delete filter;
|
||||
delete bqzeroes;
|
||||
delete bqpoles;
|
||||
}
|
||||
|
||||
void Simple :: keyOn()
|
||||
{
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void Simple :: keyOff()
|
||||
{
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Simple :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->keyOn();
|
||||
this->setFreq(freq);
|
||||
filter->setGain(amp);
|
||||
#if defined(_debug_)
|
||||
printf("Simple : NoteOn: Freq= %lf, Amp=%lf\n",freq, amp);
|
||||
#endif
|
||||
}
|
||||
void Simple :: noteOff(MY_FLOAT amplitude)
|
||||
{
|
||||
this->keyOff();
|
||||
#if defined(_debug_)
|
||||
printf("Simple : NoteOff: Amp=%lf\n",amplitude);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Simple :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
#define R 0.98
|
||||
|
||||
MY_FLOAT coeffs[2];
|
||||
coeffs[0] = 2 * R * cos(TWO_PI * ONE_OVER_SRATE * frequency);
|
||||
coeffs[1] = - R * R;
|
||||
bqpoles->setPoleCoeffs(coeffs);
|
||||
bqpoles->setGain(1.0 - R);
|
||||
loop->setFreq(frequency);
|
||||
}
|
||||
|
||||
MY_FLOAT Simple :: tick()
|
||||
{
|
||||
lastOutput = loopGain * loop->tick();
|
||||
bqzeroes->tick(bqpoles->tick(noise->tick()));
|
||||
lastOutput += (1.0 - loopGain) * bqzeroes->lastOut();
|
||||
lastOutput = filter->tick(lastOutput);
|
||||
lastOutput *= adsr->tick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
#include "SKINI11.msg"
|
||||
|
||||
void Simple :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Simple : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_Breath_)
|
||||
filter->setPole(0.99 * (1.0 - (value * NORM_7 * 2.0)));
|
||||
else if (number == __SK_NoiseLevel_)
|
||||
loopGain = 1.0 - (NORM_7 * value);
|
||||
else if (number == __SK_ModFrequency_) {
|
||||
adsr->setAttackRate(value * NORM_7);
|
||||
adsr->setDecayRate(value * NORM_7);
|
||||
adsr->setReleaseRate(value * NORM_7);
|
||||
}
|
||||
else if (number == __SK_ModWheel_)
|
||||
printf("Mod Wheel Unimplemented\n");
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Simple : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
260
src/SingWave.cpp
Normal file
260
src/SingWave.cpp
Normal file
@@ -0,0 +1,260 @@
|
||||
/*******************************************/
|
||||
/* "Singing" Looped Soundfile Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This Object contains all that's needed */
|
||||
/* to make a pitched musical sound, like */
|
||||
/* a simple voice or violin. In general, */
|
||||
/* it will not be used alone (because of */
|
||||
/* of munchinification effects from pitch */
|
||||
/* shifting. It will be used as an */
|
||||
/* excitation source for other instruments*/
|
||||
/*******************************************/
|
||||
|
||||
#include "SingWave.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
SingWave :: SingWave(char *fileName)
|
||||
{
|
||||
FILE *fd;
|
||||
char msg[256];
|
||||
|
||||
// Use the system call "stat" to determine the file length
|
||||
struct stat filestat;
|
||||
if (stat(fileName, &filestat) == -1)
|
||||
{ /* Opening file failed */
|
||||
sprintf(msg, "SingWave: Couldn't stat or find file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
length = (long) filestat.st_size / 2; // length in 2-byte samples
|
||||
|
||||
// Open the file and read samples into data[]
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "SingWave: Couldn't open or find file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
fseek(fd,0,0);
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(length+1)];
|
||||
|
||||
// Read samples into data[]. Use MY _FLOAT data structure to store INT16 samples
|
||||
INT16 *buf = (INT16 *)data;
|
||||
fseek(fd,0,SEEK_SET); // Only here to bypass bug in Linux glibc 2.1x (RedHat 6.0)
|
||||
fread(buf,length,2,fd);
|
||||
// Convert in place (unpack) to MY_FLOAT from the end of the array
|
||||
for (int i=length-1; i>=0; i--) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)(buf+i));
|
||||
#endif
|
||||
data[i] = buf[i];
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
data[length] = data[length-1];
|
||||
mytime = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 1.0;
|
||||
sweepRate = (MY_FLOAT) 0.001;
|
||||
modulator = new Modulatr;
|
||||
modulator->setVibFreq((MY_FLOAT) 6.0);
|
||||
modulator->setVibAmt((MY_FLOAT) 0.04);
|
||||
modulator->setRndAmt((MY_FLOAT) 0.005);
|
||||
envelope = new Envelope;
|
||||
pitchEnvelope = new Envelope;
|
||||
this->setFreq((MY_FLOAT) 75.0);
|
||||
pitchEnvelope->setRate((MY_FLOAT) 1.0);
|
||||
this->tick();
|
||||
this->tick();
|
||||
pitchEnvelope->setRate(sweepRate * rate);
|
||||
}
|
||||
|
||||
SingWave :: ~SingWave()
|
||||
{
|
||||
delete modulator;
|
||||
delete envelope;
|
||||
delete pitchEnvelope;
|
||||
free(data);
|
||||
}
|
||||
|
||||
void SingWave :: reset()
|
||||
{
|
||||
mytime = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void SingWave :: normalize()
|
||||
{
|
||||
long i;
|
||||
MY_FLOAT max = (MY_FLOAT) 0.0;
|
||||
for (i=0;i<=length;i++)
|
||||
if (fabs(data[i]) > max)
|
||||
max = (MY_FLOAT) fabs((double) data[i]);
|
||||
if (max > 0.0) {
|
||||
max = (MY_FLOAT) 1.0 / max;
|
||||
for (i=0;i<=length;i++)
|
||||
data[i] *= max;
|
||||
}
|
||||
}
|
||||
|
||||
void SingWave :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
MY_FLOAT max = (MY_FLOAT) 0.0;
|
||||
for (i=0;i<=length;i++)
|
||||
if (fabs(data[i]) > max)
|
||||
max = (MY_FLOAT) fabs((double) data[i]);
|
||||
if (max > 0.0) {
|
||||
max = (MY_FLOAT) 1.0 / max;
|
||||
max *= newPeak;
|
||||
for (i=0;i<=length;i++)
|
||||
data[i] *= max;
|
||||
}
|
||||
}
|
||||
|
||||
void SingWave :: setFreq(MY_FLOAT aFreq)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = rate;
|
||||
rate = length * ONE_OVER_SRATE * aFreq;
|
||||
temp -= rate;
|
||||
if (temp<0) temp = -temp;
|
||||
pitchEnvelope->setTarget(rate);
|
||||
pitchEnvelope->setRate(sweepRate * temp);
|
||||
}
|
||||
|
||||
void SingWave :: setVibFreq(MY_FLOAT vibFreq)
|
||||
{
|
||||
modulator->setVibFreq(vibFreq);
|
||||
}
|
||||
|
||||
void SingWave :: setVibAmt(MY_FLOAT vibAmount)
|
||||
{
|
||||
modulator->setVibAmt(vibAmount);
|
||||
}
|
||||
|
||||
void SingWave :: setRndAmt(MY_FLOAT rndAmount)
|
||||
{
|
||||
modulator->setRndAmt(rndAmount);
|
||||
}
|
||||
|
||||
void SingWave :: setSweepRate(MY_FLOAT swpRate)
|
||||
{
|
||||
sweepRate = swpRate;
|
||||
}
|
||||
|
||||
void SingWave :: setGainRate(MY_FLOAT gainRate)
|
||||
{
|
||||
envelope->setRate(gainRate);
|
||||
}
|
||||
|
||||
void SingWave :: setGainTarget(MY_FLOAT aTarget)
|
||||
{
|
||||
envelope->setTarget(aTarget);
|
||||
}
|
||||
|
||||
void SingWave :: noteOn()
|
||||
{
|
||||
envelope->keyOn();
|
||||
}
|
||||
|
||||
void SingWave :: noteOff()
|
||||
{
|
||||
envelope->keyOff();
|
||||
}
|
||||
|
||||
MY_FLOAT SingWave :: tick()
|
||||
{
|
||||
long temp;
|
||||
MY_FLOAT alpha, temp_rate;
|
||||
|
||||
temp_rate = pitchEnvelope->tick();
|
||||
mytime += temp_rate; /* Update current time */
|
||||
mytime += temp_rate * modulator->tick(); /* Add vibratos */
|
||||
|
||||
while (mytime >= length) { /* Check for end of sound */
|
||||
mytime -= length; /* loop back to beginning */
|
||||
}
|
||||
while (mytime < 0.0) { /* Check for end of sound */
|
||||
mytime += length; /* loop back to beginning */
|
||||
}
|
||||
|
||||
temp = (long) mytime; /* Integer part of time address */
|
||||
alpha = mytime - (MY_FLOAT) temp; /* fractional part of time address */
|
||||
|
||||
lastOutput = alpha * data[temp+1]; /* Do linear */
|
||||
lastOutput += ((MY_FLOAT) 1.0 - alpha) * data[temp]; /* interpolation */
|
||||
lastOutput *= envelope->tick();
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT SingWave :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
SingWave ahhWave("rawwaves/ahh.raw");
|
||||
SingWave eeeWave("rawwaves/eee.raw");
|
||||
SingWave oooWave("rawwaves/ooo.raw");
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i,j;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
ahhWave.normalize();
|
||||
ahhWave.noteOn();
|
||||
for (j=0;j<6;j++) {
|
||||
ahhWave.setFreq(100 * pow(2.0,j*0.25));
|
||||
for (i=0;i<10000;i++) {
|
||||
data = ahhWave.tick() * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
}
|
||||
ahhWave.noteOff();
|
||||
for (i=0;i<5000;i++) {
|
||||
data = ahhWave.tick() * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
eeeWave.normalize();
|
||||
eeeWave.noteOn();
|
||||
for (j=0;j<6;j++) {
|
||||
eeeWave.setFreq(100 * pow(2.0,j*0.25));
|
||||
for (i=0;i<10000;i++) {
|
||||
data = eeeWave.tick() * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
}
|
||||
eeeWave.noteOff();
|
||||
for (i=0;i<5000;i++) {
|
||||
data = eeeWave.tick() * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
oooWave.normalize();
|
||||
oooWave.noteOn();
|
||||
for (j=0;j<6;j++) {
|
||||
oooWave.setFreq(100 * pow(2.0,j*0.25));
|
||||
for (i=0;i<10000;i++) {
|
||||
data = oooWave.tick() * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
}
|
||||
oooWave.noteOff();
|
||||
for (i=0;i<5000;i++) {
|
||||
data = oooWave.tick() * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
172
src/SndWvIn.cpp
Normal file
172
src/SndWvIn.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
/*******************************************/
|
||||
/* SndWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 2000 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to open NeXT/Sun .snd 16-bit data */
|
||||
/* (signed integer) files for playback. */
|
||||
/* */
|
||||
/* .snd files are always big-endian. */
|
||||
/*******************************************/
|
||||
|
||||
#include "SndWvIn.h"
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
SndWvIn :: SndWvIn(char *fileName, const char *mode)
|
||||
{
|
||||
char msg[256];
|
||||
|
||||
// check mode string
|
||||
if ( strcmp(mode,"oneshot") && strcmp(mode,"looping") ) {
|
||||
sprintf(msg, "SndWvIn: constructor parameter 'mode' must be oneshot or looping only.\n");
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
|
||||
// Open the file and get header info
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "SndWvIn: Couldn't open or find file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Make sure this is a .snd format file
|
||||
char magic[4];
|
||||
fseek(fd,0,SEEK_SET); // Locate magic number in header
|
||||
fread(magic,4,1,fd);
|
||||
if (strncmp(magic,".snd",4)) {
|
||||
fclose(fd);
|
||||
sprintf(msg, "SndWvIn: %s doesn't appear to be an SND file.\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
// Check that the data is not compressed
|
||||
INT32 format;
|
||||
fseek(fd,12,SEEK_SET); // Locate format
|
||||
fread(&format,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&format);
|
||||
#endif
|
||||
if (format != 3) { // 16-bit linear PCM = 3
|
||||
fclose(fd);
|
||||
sprintf(msg, "SndWvIn: STK does not currently support data formats other than 16 bit signed integer.\n");
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
// Get file sample rate from the header and set the default rate
|
||||
INT32 srate;
|
||||
fread(&srate,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&srate);
|
||||
#endif
|
||||
rate = (MY_FLOAT) (srate/SRATE);
|
||||
|
||||
// Get number of channels from the header
|
||||
INT32 chans;
|
||||
fread(&chans,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&chans);
|
||||
#endif
|
||||
channels = chans;
|
||||
|
||||
fseek(fd,4,SEEK_SET);
|
||||
fread(&dataOffset,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&dataOffset);
|
||||
#endif
|
||||
|
||||
// Get length of data from the header
|
||||
fread(&fileSize,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&fileSize);
|
||||
#endif
|
||||
// fileSize is the number of sample frames
|
||||
fileSize /= 2 * channels;
|
||||
bufferSize = fileSize;
|
||||
|
||||
if ((fileSize*channels) > MAX_FILE_LOAD_SIZE) {
|
||||
printf("\nSndWvIn: The .SND file (%s) has more than %d samples and\n",
|
||||
fileName, MAX_FILE_LOAD_SIZE);
|
||||
printf("will be loaded incrementally from disk. Normalization will be disabled.\n");
|
||||
chunking = 1;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Setup for looping or one-shot playback
|
||||
if (!strcmp(mode,"looping"))
|
||||
looping = 1;
|
||||
else // default = oneshot
|
||||
looping = 0;
|
||||
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(bufferSize+1)*channels];
|
||||
this->getData(0); // Read samples into data[]
|
||||
|
||||
if (fmod(rate, 1.0) != 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
this->reset();
|
||||
|
||||
// finally, let's normalize the data by default
|
||||
this->normalize();
|
||||
}
|
||||
|
||||
SndWvIn :: ~SndWvIn()
|
||||
{
|
||||
}
|
||||
|
||||
void SndWvIn :: getData(long index)
|
||||
{
|
||||
/* Compare index to current readPointer and modify as needed.
|
||||
* The following while() loops will only execute on calls subsequent
|
||||
* to class instantiation ... and thus, only when "chunking".
|
||||
*/
|
||||
while (index < readPointer) {
|
||||
readPointer -= LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer < 0) {
|
||||
bufferSize += readPointer;
|
||||
readPointer = 0;
|
||||
}
|
||||
}
|
||||
while (index >= readPointer+bufferSize) {
|
||||
readPointer += LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer+LOAD_BUFFER_SIZE >= fileSize) {
|
||||
bufferSize = fileSize - readPointer;
|
||||
}
|
||||
}
|
||||
|
||||
fseek(fd, dataOffset+(long)(readPointer*channels*2), SEEK_SET);
|
||||
long length = bufferSize;
|
||||
int end_of_file = (readPointer+bufferSize == fileSize);
|
||||
if (!end_of_file) length += 1;
|
||||
|
||||
// Read samples into data[]. Use MY _FLOAT data structure to store INT16 samples
|
||||
INT16 *buf = (INT16 *)data;
|
||||
fread(buf, length*channels, 2, fd);
|
||||
// Convert in place (unpack) to MY_FLOAT from the end of the array
|
||||
for (int i=length*channels-1; i>=0; i--) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)(buf+i));
|
||||
#endif
|
||||
data[i] = buf[i];
|
||||
if (chunking) data[i] *= 0.00003051;
|
||||
}
|
||||
|
||||
// fill in the extra sample frame for interpolation
|
||||
if (end_of_file) {
|
||||
for (int j=0; j<channels; j++)
|
||||
if (looping)
|
||||
data[bufferSize*channels+j] = data[j];
|
||||
else
|
||||
data[bufferSize*channels+j] = data[(bufferSize-1)*channels+j];
|
||||
}
|
||||
|
||||
if (!chunking) {
|
||||
fclose(fd);
|
||||
fd = 0;
|
||||
}
|
||||
}
|
||||
121
src/SndWvOut.cpp
Normal file
121
src/SndWvOut.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
/***********************************************/
|
||||
/*
|
||||
NeXT (.snd) and Sun (.au) Soundfile Output Class
|
||||
by Perry R. Cook, 1996
|
||||
Revised by Gary P. Scavone, 1999-2000
|
||||
|
||||
This one opens a NeXT .snd file, and
|
||||
even knows how to byte-swap!
|
||||
*/
|
||||
/***********************************************/
|
||||
|
||||
#include "SndWvOut.h"
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
/******** NeXT Soundfile Header Struct *******/
|
||||
struct headerform {
|
||||
char pref[4];
|
||||
INT32 hdr_length;
|
||||
INT32 file_length;
|
||||
INT32 mode;
|
||||
INT32 samp_rate;
|
||||
INT32 num_channels;
|
||||
char comment[16];
|
||||
};
|
||||
|
||||
FILE *openNeXTFile(int chans, char *fileName) {
|
||||
struct headerform hdr = {".sn",40,0,3,(INT32) SRATE,1,"Created by STK"};
|
||||
char tempName[128];
|
||||
FILE *fd;
|
||||
char msg[256];
|
||||
|
||||
hdr.pref[3] = 'd';
|
||||
|
||||
strcpy(tempName,fileName);
|
||||
if (strstr(tempName,".snd") == NULL) strcat(tempName,".snd");
|
||||
hdr.num_channels = chans;
|
||||
fd = fopen(tempName,"wb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "SndWvOut: Could not create soundfile: %s\n", tempName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32 ((unsigned char *)&hdr.hdr_length);
|
||||
swap32 ((unsigned char *)&hdr.file_length);
|
||||
swap32 ((unsigned char *)&hdr.mode);
|
||||
swap32 ((unsigned char *)&hdr.samp_rate);
|
||||
swap32 ((unsigned char *)&hdr.num_channels);
|
||||
#endif
|
||||
|
||||
printf("\nCreating soundfile: %s\n", tempName);
|
||||
fwrite(&hdr,4,10,fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
SndWvOut :: SndWvOut(char *fileName, int chans)
|
||||
{
|
||||
char msg[256];
|
||||
if (chans < 1) {
|
||||
sprintf(msg, "SndWvOut: number of channels = %d not supported!\n", chans);
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
channels = chans;
|
||||
fd = openNeXTFile(channels,fileName);
|
||||
data_length = FILE_BUFFER_SIZE*channels;
|
||||
data = (INT16 *) new INT16[data_length];
|
||||
}
|
||||
|
||||
SndWvOut :: ~SndWvOut()
|
||||
{
|
||||
double temp;
|
||||
|
||||
fwrite(data,2,counter,fd);
|
||||
temp = (double) totalCount * ONE_OVER_SRATE;
|
||||
printf("%f Seconds Computed\n\n", temp);
|
||||
|
||||
totalCount *= 2*channels;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32 ((unsigned char *)&totalCount);
|
||||
#endif
|
||||
fseek(fd,8,SEEK_SET); // jump to data size
|
||||
fwrite(&totalCount,4,1,fd);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
void SndWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
INT16 isample;
|
||||
|
||||
isample = (INT16) (sample * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)&isample);
|
||||
#endif
|
||||
for (int i=0;i<channels;i++)
|
||||
data[counter++] = isample;
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(data,2,data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SndWvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
for (int i=0;i<channels;i++) {
|
||||
data[counter] = (INT16) (*samples++ * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)&data[counter]);
|
||||
#endif
|
||||
counter++;
|
||||
}
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(data,2,data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
28
src/StkError.cpp
Normal file
28
src/StkError.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/*************************************************/
|
||||
/*
|
||||
STK Error Handling Class
|
||||
by Gary P. Scavone, 2000.
|
||||
|
||||
This is a fairly abstract exception handling
|
||||
class. There could be sub-classes to take
|
||||
care of more specific error conditions ... or not.
|
||||
*/
|
||||
/*************************************************/
|
||||
|
||||
#include "StkError.h"
|
||||
|
||||
StkError :: StkError(const char *p, TYPE tipe)
|
||||
{
|
||||
type = tipe;
|
||||
strncpy(errormsg, p, 256);
|
||||
}
|
||||
|
||||
StkError :: ~StkError()
|
||||
{
|
||||
}
|
||||
|
||||
void StkError :: printMessage()
|
||||
{
|
||||
printf("\n%s\n", errormsg);
|
||||
}
|
||||
|
||||
389
src/StrmWvIn.cpp
Normal file
389
src/StrmWvIn.cpp
Normal file
@@ -0,0 +1,389 @@
|
||||
/******************************************/
|
||||
/*
|
||||
StrmWvIn Audio Input Class,
|
||||
by Gary P. Scavone, 2000
|
||||
|
||||
This object inherits from WvIn and is used
|
||||
to accept 16-bit data (signed integer) via
|
||||
a socket connection (streamed audio).
|
||||
Streamed data must be in big-endian format,
|
||||
which conforms to network byte ordering.
|
||||
|
||||
This class starts a socket server, which
|
||||
waits for a remote connection. Actual data
|
||||
reading and buffering takes place in a thread.
|
||||
*/
|
||||
/******************************************/
|
||||
|
||||
#include "StrmWvIn.h"
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
#define NUM_STREAM_IN_FRAGMENTS 10
|
||||
#define STK_STREAM_PORT 2005
|
||||
|
||||
char *stream_buffer;
|
||||
int local_socket = 0;
|
||||
int g_nfrags_filled = 0;
|
||||
int g_thread_done = 0;
|
||||
|
||||
// Do OS dependent declarations and includes
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
|
||||
pthread_t strm_thread;
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
#define MUTEX_LOCK(A) pthread_mutex_lock(A)
|
||||
#define MUTEX_UNLOCK(A) pthread_mutex_unlock(A)
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
#include <process.h>
|
||||
#include <winsock.h>
|
||||
|
||||
unsigned long strm_thread;
|
||||
CRITICAL_SECTION mutex;
|
||||
|
||||
#define MUTEX_LOCK(A) EnterCriticalSection(A)
|
||||
#define MUTEX_UNLOCK(A) LeaveCriticalSection(A)
|
||||
|
||||
#endif
|
||||
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
|
||||
void *streamInThread(void * chan)
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
|
||||
void streamInThread(void * chan)
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
extern char *stream_buffer;
|
||||
|
||||
int remote_socket;
|
||||
char msg[256];
|
||||
int fd, i = -1, writefrag = 0;
|
||||
long fill_size = RT_BUFFER_SIZE * (int)chan * 2; // bytes
|
||||
fd_set mask, rmask;
|
||||
struct sockaddr_in mysocket;
|
||||
static struct timeval timeout = {0, 10000}; // ten milliseconds
|
||||
|
||||
#if defined(__OS_Win_) // Windoze-only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
sprintf(msg, "StrmWvIn: Wrong Windoze socket library version!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the server-side socket
|
||||
local_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (local_socket < 0) {
|
||||
sprintf(msg, "StrmWvIn: Couldn't create socket!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
|
||||
mysocket.sin_family=AF_INET;
|
||||
mysocket.sin_addr.s_addr=INADDR_ANY;
|
||||
mysocket.sin_port=htons(STK_STREAM_PORT);
|
||||
|
||||
/* Bind socket to the appropriate port and interface (INADDR_ANY) */
|
||||
if (bind(local_socket, (struct sockaddr *)&mysocket, sizeof(mysocket)) < 0) {
|
||||
sprintf(msg, "StrmWvIn: Couldn't bind socket!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
|
||||
/* Listen for one incoming connection */
|
||||
if (listen(local_socket, 1) < 0) {
|
||||
sprintf(msg, "StrmWvIn: Couldn't set up listen on socket!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
printf("\nStrmWvIn listening for a connection on port %d\n", STK_STREAM_PORT);
|
||||
|
||||
remote_socket=accept(local_socket, NULL, NULL);
|
||||
if (remote_socket < 0) {
|
||||
sprintf(msg, "StrmWvIn: Couldn't accept connection request!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
printf(" ... connection made!\n");
|
||||
|
||||
FD_ZERO(&mask);
|
||||
fd = remote_socket;
|
||||
FD_SET(fd, &mask);
|
||||
|
||||
for (;;) {
|
||||
rmask = mask;
|
||||
// select will block until data is available for reading
|
||||
select(fd+1, &rmask, (fd_set *)0, (fd_set *)0, NULL);
|
||||
if (FD_ISSET(fd, &rmask)) { // data is available
|
||||
MUTEX_LOCK(&mutex);
|
||||
// don't fill if we're ahead
|
||||
if (g_nfrags_filled < NUM_STREAM_IN_FRAGMENTS) {
|
||||
#if defined(__OS_Win_)
|
||||
// Yet again, we have to make an extra special effort to get things to work
|
||||
// under windoze ... why do I waste my time supporting this shitty OS?
|
||||
// The windoze recv() call doesn't allow the use of the MSG_WAITALL flag.
|
||||
// The following scheme should work but could cause even worse performance if
|
||||
// we're in an underrun situation.
|
||||
int j;
|
||||
i = recv(fd, &stream_buffer[fill_size*writefrag], fill_size, 0);
|
||||
if (i == SOCKET_ERROR) i = 0;
|
||||
while (i < fill_size && i > 0) {
|
||||
j = recv(fd, &stream_buffer[fill_size*writefrag+i], fill_size-i, 0);
|
||||
if (j == 0 || j == SOCKET_ERROR) {
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
i += j;
|
||||
}
|
||||
#else
|
||||
i = recv(fd, &stream_buffer[fill_size*writefrag], fill_size, MSG_WAITALL);
|
||||
#endif
|
||||
if (i==0) {
|
||||
printf("The remote StrmWvIn socket connection has closed!\n");
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(fd);
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
g_thread_done = 1;
|
||||
MUTEX_UNLOCK(&mutex);
|
||||
break;
|
||||
}
|
||||
g_nfrags_filled++;
|
||||
if (++writefrag == NUM_STREAM_IN_FRAGMENTS)
|
||||
writefrag = 0;
|
||||
MUTEX_UNLOCK(&mutex);
|
||||
}
|
||||
else { // wait a little
|
||||
MUTEX_UNLOCK(&mutex);
|
||||
#if defined(__OS_Win_)
|
||||
// the windoze select function doesn't work as a timer
|
||||
Sleep((DWORD) 10);
|
||||
#else
|
||||
// reset the timeout values because of linux "select" implementation
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 10000; // 0.01 seconds
|
||||
select(0, NULL, NULL, NULL, &timeout);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can only get here if the remote socket shuts down
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(local_socket);
|
||||
WSACleanup();
|
||||
_endthread();
|
||||
#else
|
||||
close(local_socket);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
StrmWvIn :: StrmWvIn(int chans, MY_FLOAT srate)
|
||||
{
|
||||
char msg[256];
|
||||
long buffer_size = RT_BUFFER_SIZE * NUM_STREAM_IN_FRAGMENTS * chans * 2;
|
||||
chunking = 1;
|
||||
looping = 0;
|
||||
|
||||
stream_buffer = (char *) new char[buffer_size];
|
||||
memset(stream_buffer, 0, buffer_size);
|
||||
|
||||
// start the input stream thread
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
if (pthread_create(&strm_thread, NULL, streamInThread, (void *)chans)) {
|
||||
sprintf(msg, "StrmWvIn: unable to create input stream thread!\n");
|
||||
throw StkError(msg, StkError::PROCESS_THREAD);
|
||||
}
|
||||
#elif defined(__OS_Win_)
|
||||
InitializeCriticalSection(&mutex);
|
||||
strm_thread = _beginthread(streamInThread, 0, (void *)chans);
|
||||
if (strm_thread == 0) {
|
||||
sprintf(msg, "StrmWvIn: unable to create input stream thread!\n");
|
||||
throw StkError(msg, StkError::PROCESS_THREAD);
|
||||
}
|
||||
#endif
|
||||
|
||||
channels = chans;
|
||||
bufferSize = RT_BUFFER_SIZE;
|
||||
data = 0;
|
||||
strmdata = (INT16 *) new INT16[(bufferSize+1)*channels];
|
||||
|
||||
lastSamples = (INT16 *) new INT16[channels];
|
||||
for (int i=0;i<channels;i++) {
|
||||
lastSamples[i] = (INT16) 0.0;
|
||||
}
|
||||
|
||||
this->getData(0);
|
||||
|
||||
rate = (MY_FLOAT) srate / SRATE;
|
||||
if (fmod(rate, 1.0) > 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
this->reset();
|
||||
}
|
||||
|
||||
StrmWvIn :: ~StrmWvIn()
|
||||
{
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
shutdown(local_socket,0);
|
||||
pthread_cancel(strm_thread);
|
||||
pthread_join(strm_thread, NULL);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
#elif defined(__OS_Win_)
|
||||
closesocket(local_socket);
|
||||
WSACleanup();
|
||||
TerminateThread((HANDLE)strm_thread,0);
|
||||
DeleteCriticalSection(&mutex);
|
||||
#endif
|
||||
|
||||
if (strmdata) {
|
||||
delete [ ] strmdata;
|
||||
strmdata = 0;
|
||||
}
|
||||
if (stream_buffer) {
|
||||
delete [] stream_buffer;
|
||||
stream_buffer = 0;
|
||||
}
|
||||
if (lastSamples) {
|
||||
delete [ ] lastSamples;
|
||||
lastSamples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void StrmWvIn :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
// Negative rates not allowed for realtime input
|
||||
rate = fabs(aRate);
|
||||
|
||||
if (fmod(rate, 1.0) != 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
}
|
||||
|
||||
void StrmWvIn :: addTime(MY_FLOAT aTime)
|
||||
{
|
||||
// Negative time shift no allowed for realtime input
|
||||
time += fabs(aTime);
|
||||
}
|
||||
|
||||
void StrmWvIn :: setLooping(int aLoopStatus)
|
||||
{
|
||||
// No looping for realtime data.
|
||||
looping = 0;
|
||||
}
|
||||
|
||||
long StrmWvIn :: getSize()
|
||||
{
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
void StrmWvIn :: getData(long index)
|
||||
{
|
||||
/* We have two potential courses of action should this method
|
||||
* be called and the stream_buffer isn't sufficiently filled.
|
||||
* One solution is to fill the data buffer with zeros and return.
|
||||
* The other solution is to wait until the necessary data exists.
|
||||
* I chose the latter, as it works for both streamed files
|
||||
* (non-realtime data transport) and realtime playback (given
|
||||
* adequate network bandwidth and speed).
|
||||
*/
|
||||
static int readfrag = 0, i;
|
||||
static struct timeval timer = {0, 10000}; // ten milliseconds
|
||||
long temp = RT_BUFFER_SIZE*channels;
|
||||
|
||||
/* wait until data is ready */
|
||||
while (g_nfrags_filled == 0) {
|
||||
#if defined(__OS_Win_)
|
||||
// the windoze select function doesn't work as a timer
|
||||
Sleep((DWORD) 10);
|
||||
#else
|
||||
timer.tv_sec = 0;
|
||||
timer.tv_usec = 10000; // 0.01 seconds
|
||||
select(0, NULL, NULL, NULL, &timer);
|
||||
#endif
|
||||
if (g_thread_done) {
|
||||
finished = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy data from stream_buffer to strmdata */
|
||||
MUTEX_LOCK(&mutex);
|
||||
memcpy(&strmdata[channels], &stream_buffer[readfrag*temp*2], temp*2);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
for (i=0; i<temp+channels; i++)
|
||||
swap16((unsigned char *) (strmdata+i));
|
||||
#endif
|
||||
g_nfrags_filled--;
|
||||
if (++readfrag == NUM_STREAM_IN_FRAGMENTS)
|
||||
readfrag = 0;
|
||||
MUTEX_UNLOCK(&mutex);
|
||||
|
||||
/* Fill in the extra sample frame for interpolation.
|
||||
* We do this by pre-pending the last sample frame
|
||||
* from the previous input buffer to the current one.
|
||||
*/
|
||||
for (i=0;i<channels;i++) {
|
||||
strmdata[i] = lastSamples[i];
|
||||
lastSamples[i] = strmdata[temp+i];
|
||||
}
|
||||
|
||||
if (g_thread_done && g_nfrags_filled == 0) finished = 1;
|
||||
}
|
||||
|
||||
int StrmWvIn :: informTick()
|
||||
{
|
||||
static MY_FLOAT alpha;
|
||||
static long index;
|
||||
|
||||
if (finished) return finished;
|
||||
|
||||
if (time >= bufferSize) {
|
||||
this->getData(0);
|
||||
while (time >= bufferSize)
|
||||
time -= bufferSize;
|
||||
}
|
||||
|
||||
// integer part of time address
|
||||
index = (long) time;
|
||||
|
||||
if (interpolate) {
|
||||
// fractional part of time address
|
||||
alpha = time - (MY_FLOAT) index;
|
||||
index *= channels;
|
||||
for (int i=0;i<channels;i++) {
|
||||
// Do linear interpolation
|
||||
lastOutput[i] = (MY_FLOAT) strmdata[index];
|
||||
lastOutput[i] += alpha * ((MY_FLOAT) strmdata[index+channels] - lastOutput[i]);
|
||||
lastOutput[i] *= 0.00003051;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
index *= channels;
|
||||
for (int i=0;i<channels;i++) {
|
||||
lastOutput[i] = strmdata[index++];
|
||||
lastOutput[i] *= 0.00003051;
|
||||
}
|
||||
}
|
||||
|
||||
// increment time, which can be negative
|
||||
time += rate;
|
||||
|
||||
return finished;
|
||||
}
|
||||
168
src/StrmWvOut.cpp
Normal file
168
src/StrmWvOut.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/******************************************/
|
||||
/*
|
||||
StrmWvOut Audio Output Class,
|
||||
by Gary P. Scavone, 2000
|
||||
|
||||
This object inherits from WvOut and is used
|
||||
to send 16-bit data (signed integer) via
|
||||
a socket connection (streamed audio).
|
||||
Streamed data must be in big-endian format,
|
||||
which conforms to network byte ordering.
|
||||
|
||||
This class connects to a socket server, the
|
||||
port and IP address of which must be specified
|
||||
as constructor arguments. No data buffering
|
||||
is currently implemented. The class simply
|
||||
fires off a buffer of data over the socket
|
||||
connection as soon as it is filled.
|
||||
*/
|
||||
/******************************************/
|
||||
|
||||
#include "StrmWvOut.h"
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
#include <winsock.h>
|
||||
|
||||
#endif
|
||||
|
||||
StrmWvOut :: StrmWvOut(int port, const char *hostname, int chans)
|
||||
{
|
||||
char msg[256];
|
||||
struct sockaddr_in server_address;
|
||||
|
||||
if (chans < 1) {
|
||||
sprintf(msg, "StrmWvOut: number of channels (%d) must be one or greater.\n", chans);
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
|
||||
channels = chans;
|
||||
|
||||
#if defined(__OS_Win_) // Windoze-only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
sprintf(msg, "StrmWvOut: Wrong Windoze socket library version!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the client-side socket
|
||||
local_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (local_socket < 0) {
|
||||
sprintf(msg, "StrmWvOut: Couldn't create socket!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
|
||||
struct hostent *hostp;
|
||||
|
||||
if ((hostp = gethostbyname(hostname)) == 0) {
|
||||
sprintf(msg, "StrmWvOut: unknown host (%s)!\n", hostname);
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET_IPADDR);
|
||||
}
|
||||
|
||||
// Fill in the address structure
|
||||
server_address.sin_family = AF_INET;
|
||||
memcpy((void *)&server_address.sin_addr, hostp->h_addr, hostp->h_length);
|
||||
server_address.sin_port = htons(port);
|
||||
|
||||
// Connect to the server
|
||||
if (connect(local_socket, (struct sockaddr *)&server_address,
|
||||
sizeof(server_address) ) < 0) {
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(local_socket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(local_socket);
|
||||
#endif
|
||||
sprintf(msg, "StrmWvOut: Couldn't connect to socket server!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
|
||||
data_length = RT_BUFFER_SIZE*channels; // samples
|
||||
// Add a few extra samples for good measure
|
||||
data = (INT16 *) new INT16[data_length+10];
|
||||
}
|
||||
|
||||
StrmWvOut :: ~StrmWvOut()
|
||||
{
|
||||
while (counter<data_length) {
|
||||
data[counter++] = 0;
|
||||
}
|
||||
send(local_socket, (const char *)data, data_length*2, 0);
|
||||
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(local_socket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(local_socket);
|
||||
#endif
|
||||
}
|
||||
|
||||
void StrmWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
static INT16 isample;
|
||||
|
||||
isample = (INT16) (sample * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)&isample);
|
||||
#endif
|
||||
for (int i=0;i<channels;i++)
|
||||
data[counter++] = isample;
|
||||
|
||||
if (counter >= data_length) {
|
||||
if (send(local_socket, (const char *)data, data_length*2, 0) < 0) {
|
||||
char msg[256];
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(local_socket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(local_socket);
|
||||
#endif
|
||||
sprintf(msg, "StrmWvOut: connection to socket server failed!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void StrmWvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
for (int i=0;i<channels;i++) {
|
||||
data[counter] = (INT16) (*samples++ * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)&data[counter]);
|
||||
#endif
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (counter >= data_length) {
|
||||
if (send(local_socket, (const char *)data, data_length*2, 0) < 0) {
|
||||
char msg[256];
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(local_socket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(local_socket);
|
||||
#endif
|
||||
sprintf(msg, "StrmWvOut: connection to socket server failed!\n");
|
||||
throw StkError(msg, StkError::PROCESS_SOCKET);
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
52
src/SubNoise.cpp
Normal file
52
src/SubNoise.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*******************************************/
|
||||
/* SubSampled Noise Generator Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* White noise as often as you like. */
|
||||
/*******************************************/
|
||||
|
||||
#include "SubNoise.h"
|
||||
|
||||
SubNoise :: SubNoise() : Noise()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
howOften = 15;
|
||||
counter = 15;
|
||||
}
|
||||
|
||||
SubNoise :: ~SubNoise()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SubNoise :: SubNoise(int subSample) : Noise()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
howOften = subSample-1;
|
||||
counter = subSample-1;
|
||||
}
|
||||
|
||||
MY_FLOAT SubNoise :: tick()
|
||||
{
|
||||
if (!counter) {
|
||||
lastOutput = Noise::tick();
|
||||
counter = howOften;
|
||||
}
|
||||
else counter -= 1;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void SubNoise :: setHowOften(int howOft)
|
||||
{
|
||||
howOften = howOft;
|
||||
}
|
||||
|
||||
/************ Test Main ************************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
long i;
|
||||
SubNoise test(5);
|
||||
for (i=0;i<100;i++) printf("%lf\n",test.tick());
|
||||
}
|
||||
*/
|
||||
|
||||
98
src/TablLook.cpp
Normal file
98
src/TablLook.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/********************************************/
|
||||
/* Table Lookup Class, */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This class loads a table of floating */
|
||||
/* point doubles, which are assumed to be */
|
||||
/* in big-endian format. Linear */
|
||||
/* interpolation is performed for */
|
||||
/* fractional lookup indexes. */
|
||||
/********************************************/
|
||||
|
||||
#include "TablLook.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
TablLook :: TablLook(char *fileName)
|
||||
{
|
||||
char msg[256];
|
||||
|
||||
// Use the system call "stat" to determine the file length
|
||||
struct stat filestat;
|
||||
if (stat(fileName, &filestat) == -1)
|
||||
{ /* Opening file failed */
|
||||
sprintf(msg, "TablLook: Couldn't stat or find file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
length = (long) filestat.st_size / 8; // length in 8-byte samples
|
||||
|
||||
// Open the file and read samples into data[]
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "TablLook: Couldn't open or find file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
data = (MY_FLOAT *) new MY_FLOAT[length];
|
||||
|
||||
// Read samples into data[]
|
||||
long i = 0;
|
||||
double temp;
|
||||
while (fread(&temp,8,1,fd)) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap64((unsigned char *)&temp);
|
||||
#endif
|
||||
data[i++] = (MY_FLOAT) temp;
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
TablLook :: ~TablLook()
|
||||
{
|
||||
delete [ ] data;
|
||||
}
|
||||
|
||||
long TablLook :: getLength()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
MY_FLOAT TablLook :: tick(MY_FLOAT index)
|
||||
{
|
||||
static MY_FLOAT alpha;
|
||||
static long temp;
|
||||
|
||||
if (index > length-1) {
|
||||
fprintf(stderr, "TablLook: Index (%f) exceeds table length ... sticking at end!.",
|
||||
index);
|
||||
index = length-1;
|
||||
}
|
||||
if (index < 0.0) {
|
||||
fprintf(stderr,"TablLook: Index (%f) is less than zero ... setting to zero\n",
|
||||
index);
|
||||
index = 0.0;
|
||||
}
|
||||
|
||||
// Index OK (in range 0 to length-1)
|
||||
temp = (long) index; // Integer part of index
|
||||
alpha = index - (MY_FLOAT) temp; // Fractional part of index
|
||||
if (alpha > 0.0) { // Do linear interpolation
|
||||
lastOutput = data[temp];
|
||||
lastOutput += (alpha*(data[temp+1] - lastOutput));
|
||||
}
|
||||
else lastOutput = data[temp];
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT TablLook :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
62
src/TubeBell.cpp
Normal file
62
src/TubeBell.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/******************************************/
|
||||
/* Tubular Bell (Orch. Chime) Subclass */
|
||||
/* of Algorithm 5 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "TubeBell.h"
|
||||
|
||||
TubeBell :: TubeBell() : FM4Alg5()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file1[128];
|
||||
char file2[128];
|
||||
char file3[128];
|
||||
char file4[128];
|
||||
strcpy(file1, RAWWAVE_PATH);
|
||||
strcpy(file2, RAWWAVE_PATH);
|
||||
strcpy(file3, RAWWAVE_PATH);
|
||||
strcpy(file4, RAWWAVE_PATH);
|
||||
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
|
||||
strcat(file2,"rawwaves/sinewave.raw"),
|
||||
strcat(file3,"rawwaves/sinewave.raw"),
|
||||
strcat(file4,"rawwaves/fwavblnk.raw"));
|
||||
|
||||
this->setRatio(0,(MY_FLOAT) (1.0 * 0.995));
|
||||
this->setRatio(1,(MY_FLOAT) (1.414 * 0.995));
|
||||
this->setRatio(2,(MY_FLOAT) (1.0 * 1.005));
|
||||
this->setRatio(3,(MY_FLOAT) (1.414 * 1.000));
|
||||
gains[0] = __FM4Op_gains[94];
|
||||
gains[1] = __FM4Op_gains[76];
|
||||
gains[2] = __FM4Op_gains[99];
|
||||
gains[3] = __FM4Op_gains[71];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 4.0,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 4.0,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 2.0,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.004,(MY_FLOAT) 4.0,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
twozero->setGain((MY_FLOAT) 0.5);
|
||||
vibWave->setFreq((MY_FLOAT) 2.0);
|
||||
}
|
||||
|
||||
void TubeBell :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
void TubeBell :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[94];
|
||||
gains[1] = amp * __FM4Op_gains[76];
|
||||
gains[2] = amp * __FM4Op_gains[99];
|
||||
gains[3] = amp * __FM4Op_gains[71];
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("TubeBell : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
60
src/TwoPole.cpp
Normal file
60
src/TwoPole.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************/
|
||||
/* Two Pole Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. Nothing */
|
||||
/* out of the ordinary in this version. */
|
||||
/*******************************************/
|
||||
|
||||
#include "TwoPole.h"
|
||||
|
||||
TwoPole :: TwoPole() : Filter()
|
||||
{
|
||||
outputs = (MY_FLOAT *) malloc(2 * sizeof(MY_FLOAT));
|
||||
poleCoeffs[0] = (MY_FLOAT) 0.0;
|
||||
poleCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
TwoPole :: ~TwoPole()
|
||||
{
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void TwoPole :: clear()
|
||||
{
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
outputs[1] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void TwoPole :: setPoleCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
poleCoeffs[0] = coeffs[0];
|
||||
poleCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void TwoPole :: setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson)
|
||||
{
|
||||
poleCoeffs[1] = - (reson * reson);
|
||||
poleCoeffs[0] = (MY_FLOAT) 2.0 * reson * cos(TWO_PI * (double) freq / SRATE);
|
||||
}
|
||||
|
||||
void TwoPole :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT TwoPole :: tick(MY_FLOAT sample) // Perform Filter Operation
|
||||
{ // TwoPole is a two pole filter (duh!)
|
||||
MY_FLOAT temp; // Look it up in your favorite DSP text
|
||||
temp = sample * gain;
|
||||
temp += poleCoeffs[0] * outputs[0];
|
||||
temp += poleCoeffs[1] * outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
outputs[0] = temp;
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
53
src/TwoZero.cpp
Normal file
53
src/TwoZero.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*******************************************/
|
||||
/* Two Zero Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. Nothing */
|
||||
/* out of the ordinary in this version. */
|
||||
/*******************************************/
|
||||
|
||||
#include "TwoZero.h"
|
||||
|
||||
TwoZero :: TwoZero() : Filter()
|
||||
{
|
||||
inputs = (MY_FLOAT *) malloc(2 * sizeof(MY_FLOAT));
|
||||
zeroCoeffs[0] = (MY_FLOAT) 0.0;
|
||||
zeroCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
TwoZero :: ~TwoZero()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void TwoZero :: clear()
|
||||
{
|
||||
inputs[0] = (MY_FLOAT) 0.0;
|
||||
inputs[1] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void TwoZero :: setZeroCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
zeroCoeffs[0] = coeffs[0];
|
||||
zeroCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void TwoZero :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT TwoZero :: tick(MY_FLOAT sample) // Perform Filter Operation
|
||||
{ // TwoZero is a two zero filter (duh!)
|
||||
// Look it up in your favorite DSP text
|
||||
lastOutput = zeroCoeffs[0] * inputs[0];
|
||||
lastOutput += zeroCoeffs[1] * inputs[1];
|
||||
inputs[1] = inputs[0];
|
||||
inputs[0] = gain * sample;
|
||||
lastOutput += inputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
232
src/VoicForm.cpp
Normal file
232
src/VoicForm.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
/*******************************************/
|
||||
/* 4 Formant Synthesis Instrument */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains an excitation */
|
||||
/* singing wavetable (looping wave with */
|
||||
/* random and periodic vibrato, smoothing */
|
||||
/* on frequency, etc.), excitation noise, */
|
||||
/* and four sweepable complex resonances. */
|
||||
/* */
|
||||
/* Measured Formant data (from me) is */
|
||||
/* included, and enough data is there to */
|
||||
/* support either parallel or cascade */
|
||||
/* synthesis. In the floating point case */
|
||||
/* cascade synthesis is the most natural */
|
||||
/* so that's what you'll find here. */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
#include "VoicForm.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
VoicForm :: VoicForm() : Instrmnt()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
voiced = new SingWave(strcat(file,"rawwaves/impuls20.raw"));
|
||||
voiced->normalize();
|
||||
voiced->setGainRate((MY_FLOAT) 0.001);
|
||||
voiced->setGainTarget((MY_FLOAT) 0.0);
|
||||
|
||||
noise = new Noise;
|
||||
|
||||
filters[0] = new FormSwep;
|
||||
filters[1] = new FormSwep;
|
||||
filters[2] = new FormSwep;
|
||||
filters[3] = new FormSwep;
|
||||
filters[0]->setSweepRate((MY_FLOAT) 0.001);
|
||||
filters[1]->setSweepRate((MY_FLOAT) 0.001);
|
||||
filters[2]->setSweepRate((MY_FLOAT) 0.001);
|
||||
filters[3]->setSweepRate((MY_FLOAT) 0.001);
|
||||
|
||||
onezero = new OneZero;
|
||||
onezero->setCoeff((MY_FLOAT) -0.9);
|
||||
onepole = new OnePole;
|
||||
onepole->setPole((MY_FLOAT) 0.9);
|
||||
|
||||
noiseEnv = new Envelope;
|
||||
noiseEnv->setRate((MY_FLOAT) 0.001);
|
||||
noiseEnv->setTarget((MY_FLOAT) 0.0);
|
||||
|
||||
this->setPhoneme("eee");
|
||||
this->clear();
|
||||
}
|
||||
|
||||
VoicForm :: ~VoicForm()
|
||||
{
|
||||
delete voiced;
|
||||
delete noise;
|
||||
delete filters[0];
|
||||
delete filters[1];
|
||||
delete filters[2];
|
||||
delete filters[3];
|
||||
delete onezero;
|
||||
delete onepole;
|
||||
delete noiseEnv;
|
||||
}
|
||||
|
||||
void VoicForm :: clear()
|
||||
{
|
||||
onezero->clear();
|
||||
onepole->clear();
|
||||
filters[0]->clear();
|
||||
filters[1]->clear();
|
||||
filters[2]->clear();
|
||||
filters[3]->clear();
|
||||
}
|
||||
|
||||
void VoicForm :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
if ((frequency * 22) > SRATE) {
|
||||
printf("This note is too high!!\n");
|
||||
frequency = SRATE / 22;
|
||||
}
|
||||
lastFreq = frequency;
|
||||
temp = fabs(1500 - frequency) + 200;
|
||||
lastGain = 10000.0 / temp / temp;
|
||||
voiced->setFreq(frequency);
|
||||
}
|
||||
|
||||
void VoicForm :: setFormantAll(int whichOne, MY_FLOAT freq,MY_FLOAT reson,MY_FLOAT gain)
|
||||
{
|
||||
filters[whichOne]->setTargets(freq,reson,gain);
|
||||
}
|
||||
|
||||
#include "phontabl.h"
|
||||
|
||||
int VoicForm :: setPhoneme(char *phoneme)
|
||||
{
|
||||
int i=0,found=0;
|
||||
|
||||
while(i<32 && !found) {
|
||||
if (!strcmp(phonemes[i],phoneme)) {
|
||||
found = 1;
|
||||
this->setFormantAll(0,(MY_FLOAT) phonParams[i][0][0],(MY_FLOAT) phonParams[i][0][1],(MY_FLOAT) pow(10.0,phonParams[i][0][2] / 20.0));
|
||||
this->setFormantAll(1,(MY_FLOAT) phonParams[i][1][0],(MY_FLOAT) phonParams[i][1][1],(MY_FLOAT) 1.0);
|
||||
this->setFormantAll(2,(MY_FLOAT) phonParams[i][2][0],(MY_FLOAT) phonParams[i][2][1],(MY_FLOAT) 1.0);
|
||||
this->setFormantAll(3,(MY_FLOAT) phonParams[i][3][0],(MY_FLOAT) phonParams[i][3][1],(MY_FLOAT) 1.0);
|
||||
this->setVoicedUnVoiced((MY_FLOAT) phonGains[i][0],(MY_FLOAT) phonGains[i][1]);
|
||||
printf("Found Formant: %s (number %i)\n",phoneme,i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!found) printf("Phoneme %s not found\n",phoneme);
|
||||
return found;
|
||||
}
|
||||
|
||||
void VoicForm :: setVoiced(MY_FLOAT vGain)
|
||||
{
|
||||
voiced->setGainTarget(vGain);
|
||||
}
|
||||
|
||||
void VoicForm :: setUnVoiced(MY_FLOAT nGain)
|
||||
{
|
||||
noiseEnv->setTarget(nGain);
|
||||
}
|
||||
|
||||
void VoicForm :: setVoicedUnVoiced(MY_FLOAT vGain, MY_FLOAT nGain)
|
||||
{
|
||||
this->setVoiced(vGain);
|
||||
this->setUnVoiced(nGain);
|
||||
}
|
||||
|
||||
void VoicForm :: setFiltSweepRate(int whichOne,MY_FLOAT rate)
|
||||
{
|
||||
filters[whichOne]->setSweepRate(rate);
|
||||
}
|
||||
|
||||
void VoicForm :: setPitchSweepRate(MY_FLOAT rate)
|
||||
{
|
||||
voiced->setSweepRate(rate);
|
||||
}
|
||||
|
||||
void VoicForm :: speak()
|
||||
{
|
||||
voiced->noteOn();
|
||||
}
|
||||
|
||||
void VoicForm :: quiet()
|
||||
{
|
||||
voiced->noteOff();
|
||||
noiseEnv->setTarget((MY_FLOAT) 0.0);
|
||||
}
|
||||
|
||||
void VoicForm :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
voiced->setGainTarget(amp);
|
||||
onepole->setPole((MY_FLOAT) 0.95 - (amp * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.2));
|
||||
}
|
||||
|
||||
void VoicForm :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->quiet();
|
||||
}
|
||||
|
||||
MY_FLOAT VoicForm :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = onepole->tick(onezero->tick(voiced->tick()));
|
||||
temp += noiseEnv->tick() * noise->tick();
|
||||
lastOutput = filters[0]->tick(temp);
|
||||
lastOutput = filters[1]->tick(lastOutput);
|
||||
lastOutput = filters[2]->tick(lastOutput);
|
||||
lastOutput = filters[3]->tick(lastOutput);
|
||||
lastOutput *= lastGain;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void VoicForm :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("VoicForm : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_Breath_) {
|
||||
this->setVoiced((MY_FLOAT) 1.0 - (value *(MY_FLOAT) NORM_7));
|
||||
this->setUnVoiced((MY_FLOAT) 0.01 * value * (MY_FLOAT) NORM_7);
|
||||
}
|
||||
else if (number == __SK_FootControl_) {
|
||||
MY_FLOAT temp = 0.0;
|
||||
int tempi = (int) value;
|
||||
if (tempi < 32) {
|
||||
tempi = tempi;
|
||||
temp = (MY_FLOAT) 0.9;
|
||||
}
|
||||
else if (tempi < 64) {
|
||||
tempi = tempi - 32;
|
||||
temp = (MY_FLOAT) 1.0;
|
||||
}
|
||||
else if (tempi < 96) {
|
||||
tempi = tempi - 64;
|
||||
temp = (MY_FLOAT) 1.1;
|
||||
}
|
||||
else if (tempi <= 128) {
|
||||
tempi = tempi - 96;
|
||||
temp = (MY_FLOAT) 1.2;
|
||||
}
|
||||
this->setFormantAll(0,temp*(MY_FLOAT) phonParams[tempi][0][0],
|
||||
(MY_FLOAT) phonParams[tempi][0][1],
|
||||
(MY_FLOAT) pow(10.0,phonParams[tempi][0][2] / 20.0));
|
||||
this->setFormantAll(1,temp*(MY_FLOAT) phonParams[tempi][1][0],
|
||||
(MY_FLOAT) phonParams[tempi][1][1],(MY_FLOAT) 1.0);
|
||||
this->setFormantAll(2,temp*(MY_FLOAT) phonParams[tempi][2][0],
|
||||
(MY_FLOAT) phonParams[tempi][2][1],(MY_FLOAT) 1.0);
|
||||
this->setFormantAll(3,temp*(MY_FLOAT) phonParams[tempi][3][0],
|
||||
(MY_FLOAT) phonParams[tempi][3][1],(MY_FLOAT) 1.0);
|
||||
this->setVoicedUnVoiced(phonGains[tempi][0],phonGains[tempi][1]);
|
||||
}
|
||||
else if (number == __SK_ModFrequency_)
|
||||
voiced->setVibFreq(value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 12.0); /* 0 to 12 Hz */
|
||||
else if (number == __SK_ModWheel_)
|
||||
voiced->setVibAmt(value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.2);
|
||||
else if (number == __SK_AfterTouch_Cont_) {
|
||||
this->setVoiced(value*NORM_7);
|
||||
onepole->setPole((MY_FLOAT) 0.99 - (value *(MY_FLOAT) NORM_7 * (MY_FLOAT) 0.2));
|
||||
//onepole->setPole((MY_FLOAT) 0.5 - (value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.2));
|
||||
}
|
||||
else {
|
||||
printf("VoicForm : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
286
src/VoicMang.cpp
Normal file
286
src/VoicMang.cpp
Normal file
@@ -0,0 +1,286 @@
|
||||
/******************************************/
|
||||
/* Simple Voice Manager (Mangler) */
|
||||
/* for ToolKit96, 1996 Perry R. Cook */
|
||||
/* Princeton University */
|
||||
/* */
|
||||
/* Make one of these by telling it the */
|
||||
/* maximum number of voices you'll want, */
|
||||
/* and also what flavor instrument */
|
||||
/* group it will be mangling. Pipe SKINI*/
|
||||
/* messages into it and it will return */
|
||||
/* the mixed channel signal each tick. */
|
||||
/* For multi-channel (multi-timbral), */
|
||||
/* make one for each channel and mix */
|
||||
/* their outputs. */
|
||||
/* */
|
||||
/* Each note on returns a unique tag, */
|
||||
/* (credits to the NeXT MusicKit here), */
|
||||
/* so you can send control changes to */
|
||||
/* unique instances of instruments */
|
||||
/* within an ensemble. */
|
||||
/* */
|
||||
/* SKINI (Synthesis toolKit Instrument */
|
||||
/* Network Interface) is like MIDI, but */
|
||||
/* allows for floating point control */
|
||||
/* changes, note numbers, etc. Example: */
|
||||
/* noteOn 60.01 111.132 plays a sharp */
|
||||
/* middle C with a velocity of 111.132 */
|
||||
/* See SKINI09.txt for more information */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "VoicMang.h"
|
||||
#include "Mandolin.h"
|
||||
#include "Plucked.h"
|
||||
#include "Clarinet.h"
|
||||
#include "Flute.h"
|
||||
#include "Brass.h"
|
||||
#include "Bowed.h"
|
||||
#include "Rhodey.h"
|
||||
#include "Wurley.h"
|
||||
#include "TubeBell.h"
|
||||
#include "HeavyMtl.h"
|
||||
#include "PercFlut.h"
|
||||
#include "BeeThree.h"
|
||||
#include "Moog1.h"
|
||||
|
||||
VoicMang :: VoicMang(int maxVoices, char *instrType)
|
||||
{
|
||||
int i;
|
||||
max_voices = maxVoices;
|
||||
if (max_voices > __VMang_MAX_) {
|
||||
printf("You ask for too many voices, setting to %i\n",__VMang_MAX_);
|
||||
max_voices = __VMang_MAX_;
|
||||
}
|
||||
if (!strcmp(instrType,"Mandolin")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new Mandolin((MY_FLOAT) 50.0);
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"Plucked")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new Plucked(50.0);
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"Clarinet")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new Clarinet(50.0);
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"Flute")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new Flute(50.0);
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"Brass")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new Brass(50.0);
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"Bowed")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new Bowed(50.0);
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"Rhodey")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new Rhodey;
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"Wurley")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new Wurley;
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"TubeBell")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new TubeBell;
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"HeavyMtl")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new HeavyMtl;
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"PercFlut")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new PercFlut;
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"BeeThree")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new BeeThree;
|
||||
mute_time = 1000;
|
||||
}
|
||||
else if (!strcmp(instrType,"Moog1")) {
|
||||
for (i=0;i<max_voices;i++)
|
||||
instrument[i] = new Moog1;
|
||||
mute_time = 1000;
|
||||
}
|
||||
|
||||
pitch_bend = (MY_FLOAT) 1.0;
|
||||
newTag = 1;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
notesOn[i] = -1;
|
||||
voicesOn[i] = 0;
|
||||
freqBases[i] = (MY_FLOAT) 1.0;
|
||||
frequencies[i] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
VoicMang :: ~VoicMang()
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<max_voices;i++)
|
||||
delete instrument[i];
|
||||
}
|
||||
|
||||
long VoicMang :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
MY_FLOAT temp = 0.0;
|
||||
temp = freq / (MY_FLOAT) 220.0;
|
||||
temp = (MY_FLOAT) (log(temp) / log(2.0));
|
||||
temp = (temp * (MY_FLOAT) 12.0) + 57;
|
||||
return this->noteOn(temp,amp);
|
||||
}
|
||||
|
||||
#define ONE_OVER_12 0.083333
|
||||
|
||||
long VoicMang :: noteOnN(MY_FLOAT note_num, MY_FLOAT amp)
|
||||
{
|
||||
int i,gotOne;
|
||||
MY_FLOAT freq;
|
||||
freq = (MY_FLOAT) 220.0 * pow(2.0,(note_num - 57.0) * ONE_OVER_12);
|
||||
gotOne = 0;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
if (notesOn[i] < 0) { /* find a dormant instrument */
|
||||
voicesOn[i] = newTag;
|
||||
newTag += 1;
|
||||
notesOn[i] = (int) (note_num + (MY_FLOAT) 0.5); /* Nearest Neighbor MIDI Note# */
|
||||
instrument[i]->noteOn(freq,amp*(MY_FLOAT) NORM_7);
|
||||
frequencies[i] = freq;
|
||||
gotOne = 1;
|
||||
i = max_voices;
|
||||
}
|
||||
}
|
||||
if (!gotOne) { /* if can't find a free one */
|
||||
return -1; /* report back */
|
||||
}
|
||||
return newTag-1;
|
||||
}
|
||||
|
||||
long VoicMang :: oldestVoice()
|
||||
{
|
||||
int i;
|
||||
long temp2,gotOne;
|
||||
temp2 = newTag;
|
||||
gotOne = -1;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
temp2 = voicesOn[i];
|
||||
if (temp2 > 0 && temp2 < newTag) {
|
||||
gotOne = temp2;
|
||||
}
|
||||
}
|
||||
return gotOne;
|
||||
}
|
||||
|
||||
long VoicMang :: noteOffN(int note_num, MY_FLOAT amp)
|
||||
{
|
||||
int i,gotOne;
|
||||
gotOne = -1;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
if (notesOn[i]==note_num) {
|
||||
instrument[i]->noteOff(amp * (MY_FLOAT) NORM_7);
|
||||
gotOne = voicesOn[i];
|
||||
voicesOn[i] = -mute_time - 2;
|
||||
}
|
||||
}
|
||||
return gotOne;
|
||||
}
|
||||
|
||||
void VoicMang :: noteOffT(long tag, MY_FLOAT amp)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
if (voicesOn[i]==tag) {
|
||||
instrument[i]->noteOff(amp * (MY_FLOAT) NORM_7);
|
||||
voicesOn[i] = -mute_time - 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoicMang :: kill(long tag)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
if (voicesOn[i]==tag) {
|
||||
instrument[i]->noteOff((MY_FLOAT) 1.0);
|
||||
voicesOn[i] = 0;
|
||||
notesOn[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoicMang :: pitchBend(MY_FLOAT value)
|
||||
{
|
||||
int i;
|
||||
pitch_bend = value;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
freqBases[i] = pitch_bend;
|
||||
instrument[i]->setFreq(freqBases[i]*frequencies[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void VoicMang :: pitchBendT(long tag, MY_FLOAT value)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
if (voicesOn[i] == tag) {
|
||||
freqBases[i] = value;
|
||||
instrument[i]->setFreq(freqBases[i]*frequencies[i]);
|
||||
i = max_voices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT VoicMang :: tick()
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
temp = (MY_FLOAT) 0.0;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
if (voicesOn[i] != 0) {
|
||||
temp += instrument[i]->tick();
|
||||
}
|
||||
if (voicesOn[i] < 0) {
|
||||
voicesOn[i] += 1;
|
||||
if (voicesOn[i] == 0) {
|
||||
notesOn[i] = -1;
|
||||
frequencies[i] = (MY_FLOAT) 0.0;
|
||||
freqBases[i] = (MY_FLOAT) 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
void VoicMang :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
instrument[i]->controlChange(number,value);
|
||||
}
|
||||
}
|
||||
|
||||
void VoicMang :: controlChangeT(long tag, int number, MY_FLOAT value)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<max_voices;i++) {
|
||||
if (voicesOn[i] == tag) {
|
||||
instrument[i]->controlChange(number,value);
|
||||
i = max_voices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
204
src/WavWvIn.cpp
Normal file
204
src/WavWvIn.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*******************************************/
|
||||
/* WavWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 2000 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to open DOS/Windows .wav 16-bit */
|
||||
/* data (signed integer) files for */
|
||||
/* playback. */
|
||||
/* */
|
||||
/* .wav files are always little-endian. */
|
||||
/*******************************************/
|
||||
|
||||
#include "WavWvIn.h"
|
||||
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
WavWvIn :: WavWvIn(char *fileName, const char *mode)
|
||||
{
|
||||
char msg[256];
|
||||
|
||||
// check mode string
|
||||
if ( strcmp(mode,"oneshot") && strcmp(mode,"looping") ) {
|
||||
sprintf(msg, "WavWvIn: constructor parameter 'mode' must be oneshot or looping only.\n");
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
|
||||
// Open the file and get header info
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "WavWvIn: Couldn't open or find file (%s).\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Make sure this is a .wav format file
|
||||
char id[4];
|
||||
fseek(fd,8,SEEK_SET); // Locate wave id
|
||||
fread(&id,4,1,fd);
|
||||
if (strncmp(id,"WAVE",4)) {
|
||||
fclose(fd);
|
||||
sprintf(msg, "WavWvIn: %s doesn't appear to be a WAV file.\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
// Find "format" chunk ... it must come before the "data" chunk
|
||||
INT32 chunkSize;
|
||||
fread(&id,4,1,fd);
|
||||
while (strncmp(id,"fmt ",4)) {
|
||||
fread(&chunkSize,4,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&chunkSize);
|
||||
#endif
|
||||
fseek(fd,chunkSize,SEEK_CUR);
|
||||
fread(&id,4,1,fd);
|
||||
}
|
||||
|
||||
// Check that the data is not compressed
|
||||
INT16 format_tag;
|
||||
fseek(fd,4,SEEK_CUR); // Locate format tag ... jump over chunkSize
|
||||
fread(&format_tag,2,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)&format_tag);
|
||||
#endif
|
||||
if (format_tag != 1) { // PCM = 1
|
||||
fclose(fd);
|
||||
sprintf(msg, "WavWvIn: %s contains compressed data, which is not supported.\n", fileName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
// Get number of channels from the header
|
||||
INT16 temp;
|
||||
fread(&temp,2,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)&temp);
|
||||
#endif
|
||||
channels = temp;
|
||||
|
||||
// Get file sample rate from the header and set the default rate
|
||||
INT32 srate;
|
||||
fread(&srate,4,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&srate);
|
||||
#endif
|
||||
rate = (MY_FLOAT) (srate/SRATE); // set default rate based on file sampling rate
|
||||
|
||||
// Verify that the data is 16 bits per sample
|
||||
fseek(fd,6,SEEK_CUR); // Locate bits_per_sample info
|
||||
fread(&temp,2,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)&temp);
|
||||
#endif
|
||||
if (temp != 16) {
|
||||
fclose(fd);
|
||||
sprintf(msg, "WavWvIn: STK does not currently support data formats other than 16 bit signed integer.\n");
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
// Find "data" chunk ... it must come after the "fmt" chunk
|
||||
fread(&id,4,1,fd);
|
||||
while (strncmp(id,"data",4)) {
|
||||
fread(&chunkSize,4,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&chunkSize);
|
||||
#endif
|
||||
fseek(fd,chunkSize,SEEK_CUR);
|
||||
fread(&id,4,1,fd);
|
||||
}
|
||||
|
||||
// Get length of data from the header
|
||||
INT32 bytes;
|
||||
fread(&bytes,4,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&bytes);
|
||||
#endif
|
||||
// length is the number of sample frames
|
||||
fileSize = bytes / 2 / channels;
|
||||
bufferSize = fileSize;
|
||||
|
||||
if ((fileSize*channels) > MAX_FILE_LOAD_SIZE) {
|
||||
printf("\nWavWvIn: The .WAV file (%s) has more than %d samples and\n",
|
||||
fileName, MAX_FILE_LOAD_SIZE);
|
||||
printf("will be loaded incrementally from disk. Normalization will be disabled.\n");
|
||||
chunking = 1;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Setup for looping or one-shot playback
|
||||
if (!strcmp(mode,"looping"))
|
||||
looping = 1;
|
||||
else // default = oneshot
|
||||
looping = 0;
|
||||
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(bufferSize+1)*channels];
|
||||
dataOffset = ftell(fd);
|
||||
this->getData(0); // Read samples into data[]
|
||||
|
||||
if (fmod(rate, 1.0) != 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
this->reset();
|
||||
|
||||
// finally, let's normalize the data by default
|
||||
this->normalize();
|
||||
}
|
||||
|
||||
WavWvIn :: ~WavWvIn()
|
||||
{
|
||||
}
|
||||
|
||||
void WavWvIn :: getData(long index)
|
||||
{
|
||||
/* Compare index to current readPointer and modify as needed.
|
||||
* The following while() loops will only execute on calls subsequent
|
||||
* to class instantiation ... and thus, only when "chunking".
|
||||
*/
|
||||
while (index < readPointer) {
|
||||
readPointer -= LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer < 0) {
|
||||
bufferSize += readPointer;
|
||||
readPointer = 0;
|
||||
}
|
||||
}
|
||||
while (index >= readPointer+bufferSize) {
|
||||
readPointer += LOAD_BUFFER_SIZE;
|
||||
bufferSize = LOAD_BUFFER_SIZE;
|
||||
if (readPointer+LOAD_BUFFER_SIZE >= fileSize) {
|
||||
bufferSize = fileSize - readPointer;
|
||||
}
|
||||
}
|
||||
|
||||
fseek(fd, dataOffset+(long)(readPointer*channels*2), SEEK_SET);
|
||||
long length = bufferSize;
|
||||
int end_of_file = (readPointer+bufferSize == fileSize);
|
||||
if (!end_of_file) length += 1;
|
||||
|
||||
// Read samples into data[]. Use MY _FLOAT data structure to store INT16 samples
|
||||
INT16 *buf = (INT16 *)data;
|
||||
fread(buf, 2, length*channels, fd);
|
||||
// Convert in place (unpack) to MY_FLOAT from the end of the array
|
||||
for (int i=length*channels-1; i>=0; i--) {
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *)(buf+i));
|
||||
#endif
|
||||
data[i] = buf[i];
|
||||
if (chunking) data[i] *= 0.00003051;
|
||||
}
|
||||
|
||||
// fill in the extra sample frame for interpolation
|
||||
if (end_of_file) {
|
||||
for (int j=0; j<channels; j++)
|
||||
if (looping)
|
||||
data[bufferSize*channels+j] = data[j];
|
||||
else
|
||||
data[bufferSize*channels+j] = data[(bufferSize-1)*channels+j];
|
||||
}
|
||||
|
||||
if (!chunking) {
|
||||
fclose(fd);
|
||||
fd = 0;
|
||||
}
|
||||
}
|
||||
144
src/WavWvOut.cpp
Normal file
144
src/WavWvOut.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/*******************************************/
|
||||
/* Wave file Output Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* revised by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This Object opens a DOS/Windows .wav */
|
||||
/* 16bit data (signed integers) file, and */
|
||||
/* poke buffers of samples into it. */
|
||||
/*******************************************/
|
||||
|
||||
#include "WavWvOut.h"
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
#include "ByteSwap.h"
|
||||
#endif
|
||||
|
||||
/******** Wav Soundfile Header Struct *******/
|
||||
struct wavehdr {
|
||||
char riff[4]; // "RIFF"
|
||||
INT32 file_size; // in bytes
|
||||
char wave[4]; // "WAVE"
|
||||
char fmt[4]; // "fmt "
|
||||
INT32 block_size; // in bytes (16 for PCM)
|
||||
INT16 format_tag; // 1=PCM, 257=Mu-Law, 258=A-Law, 259=ADPCM
|
||||
INT16 num_chans; // 1=mono, 2=stereo
|
||||
INT32 srate;
|
||||
INT32 bytes_per_sec;
|
||||
INT16 bytes_per_samp; // 2=16-bit mono, 4=16-bit stereo
|
||||
INT16 bits_per_samp;
|
||||
char data[4]; // "data"
|
||||
INT32 dlength; // in bytes
|
||||
};
|
||||
|
||||
FILE *openWAVFile(int chans,char *fileName) {
|
||||
struct wavehdr hdr = {"RIF",44,"WAV","fmt",
|
||||
16,1,1,(INT32) SRATE,(INT32) SRATE*2,2,16,"dat",0};
|
||||
char tempName[128];
|
||||
FILE *fd;
|
||||
char msg[256];
|
||||
|
||||
hdr.riff[3] = 'F';
|
||||
hdr.wave[3] = 'E';
|
||||
hdr.fmt[3] = ' ';
|
||||
hdr.data[3] = 'a';
|
||||
|
||||
strcpy(tempName,fileName);
|
||||
if (strstr(tempName,".wav") == NULL) strcat(tempName,".wav");
|
||||
hdr.num_chans = chans;
|
||||
hdr.bytes_per_sec = (long) SRATE*2*chans;
|
||||
hdr.bytes_per_samp = 2*chans;
|
||||
hdr.bits_per_samp = 16;
|
||||
fd = fopen(tempName,"wb");
|
||||
if (!fd) {
|
||||
sprintf(msg, "WavWvOut: Could not create soundfile: %s\n", tempName);
|
||||
throw StkError(msg, StkError::FILE_ERROR);
|
||||
}
|
||||
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&hdr.file_size);
|
||||
swap32((unsigned char *)&hdr.block_size);
|
||||
swap16((unsigned char *)&hdr.format_tag);
|
||||
swap16((unsigned char *)&hdr.num_chans);
|
||||
swap32((unsigned char *)&hdr.srate);
|
||||
swap32((unsigned char *)&hdr.bytes_per_sec);
|
||||
swap16((unsigned char *)&hdr.bytes_per_samp);
|
||||
swap16((unsigned char *)&hdr.bits_per_samp);
|
||||
#endif
|
||||
|
||||
printf("\nCreating soundfile: %s\n", tempName);
|
||||
fwrite(&hdr,4,11,fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
WavWvOut :: WavWvOut(char *fileName, int chans)
|
||||
{
|
||||
char msg[256];
|
||||
if (chans < 1) {
|
||||
sprintf(msg, "WavWvOut: number of channels = %d not supported!\n", chans);
|
||||
throw StkError(msg, StkError::FUNCTION_SYNTAX);
|
||||
}
|
||||
channels = chans;
|
||||
fd = openWAVFile(chans,fileName);
|
||||
data_length = FILE_BUFFER_SIZE*channels;
|
||||
data = (INT16 *) new INT16[data_length];
|
||||
}
|
||||
|
||||
WavWvOut :: ~WavWvOut()
|
||||
{
|
||||
MY_FLOAT time;
|
||||
INT32 bytes;
|
||||
|
||||
fwrite(data,2,counter,fd);
|
||||
time = (double) totalCount * ONE_OVER_SRATE;
|
||||
printf("%f Seconds Computed\n\n", time);
|
||||
|
||||
bytes = totalCount*2*channels;
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&bytes);
|
||||
#endif
|
||||
fseek(fd,40,SEEK_SET); // jump to data length
|
||||
fwrite(&bytes,4,1,fd);
|
||||
|
||||
bytes = totalCount*2*channels + 44;
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *)&bytes);
|
||||
#endif
|
||||
fseek(fd,4,SEEK_SET); // jump to file size
|
||||
fwrite(&bytes,4,1,fd);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
void WavWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
static INT16 isample;
|
||||
|
||||
isample = (INT16) (sample * 32000.0);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)&isample);
|
||||
#endif
|
||||
for (int i=0;i<channels;i++)
|
||||
data[counter++] = isample;
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(data,2,data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WavWvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
for (int i=0;i<channels;i++) {
|
||||
data[counter] = (INT16) (*samples++ * 32000.0);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)&data[counter]);
|
||||
#endif
|
||||
counter++;
|
||||
}
|
||||
|
||||
totalCount++;
|
||||
if (counter == data_length) {
|
||||
fwrite(data,2,data_length,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
62
src/Wurley.cpp
Normal file
62
src/Wurley.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/******************************************/
|
||||
/* Wurlitzer Electric Piano Subclass */
|
||||
/* of Algorithm 5 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "Wurley.h"
|
||||
|
||||
Wurley :: Wurley() : FM4Alg5()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file1[128];
|
||||
char file2[128];
|
||||
char file3[128];
|
||||
char file4[128];
|
||||
strcpy(file1, RAWWAVE_PATH);
|
||||
strcpy(file2, RAWWAVE_PATH);
|
||||
strcpy(file3, RAWWAVE_PATH);
|
||||
strcpy(file4, RAWWAVE_PATH);
|
||||
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
|
||||
strcat(file2,"rawwaves/sinewave.raw"),
|
||||
strcat(file3,"rawwaves/sinewave.raw"),
|
||||
strcat(file4,"rawwaves/fwavblnk.raw"));
|
||||
|
||||
this->setRatio(0,(MY_FLOAT) 1.0);
|
||||
this->setRatio(1,(MY_FLOAT) 4.0);
|
||||
this->setRatio(2,(MY_FLOAT) -510.0);
|
||||
this->setRatio(3,(MY_FLOAT) -510.0);
|
||||
gains[0] = __FM4Op_gains[99];
|
||||
gains[1] = __FM4Op_gains[82];
|
||||
gains[2] = __FM4Op_gains[92];
|
||||
gains[3] = __FM4Op_gains[68]; /* Originally 78, but sounded stinky */
|
||||
twozero->setGain((MY_FLOAT) 2.0);
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.25,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.15,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
vibWave->setFreq((MY_FLOAT) 8.0);
|
||||
}
|
||||
|
||||
void Wurley :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(ratios[2]); /* Note here a 'fixed resonance' */
|
||||
waves[3]->setFreq(ratios[3]);
|
||||
}
|
||||
|
||||
void Wurley :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[99];
|
||||
gains[1] = amp * __FM4Op_gains[82];
|
||||
gains[2] = amp * __FM4Op_gains[82]; /* Originally 92 */
|
||||
gains[3] = amp * __FM4Op_gains[68]; /* Originally 78 */
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("Wurley : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
282
src/WvIn.cpp
Normal file
282
src/WvIn.cpp
Normal file
@@ -0,0 +1,282 @@
|
||||
/********************************************/
|
||||
/*
|
||||
Audio Data Input Base Class
|
||||
by Gary P. Scavone, 1999-2000
|
||||
|
||||
This class can handle multi-channel
|
||||
input. Multi-channel input is
|
||||
interleaved in the vector "data".
|
||||
Actual data input occurs in the
|
||||
subclasses of WvIn.
|
||||
|
||||
Currently, STK is only supporting a few data
|
||||
types (16-bit integer .snd, .wav, .raw, and
|
||||
.aif files and 64-bit double MAT-files). In
|
||||
order to support more formats AND to make the
|
||||
writing of subclasses easier, a format ENUM
|
||||
could be defined and a generalized getData()
|
||||
function written within this WvIn class. Then,
|
||||
most subclasses of WvIn would only have to
|
||||
setup the appropriate parameters and all
|
||||
other processing would happen here.
|
||||
*/
|
||||
/********************************************/
|
||||
|
||||
#include "WvIn.h"
|
||||
#include <stdio.h>
|
||||
|
||||
WvIn :: WvIn()
|
||||
{
|
||||
fd = 0;
|
||||
chunking = 0;
|
||||
readPointer = 0;
|
||||
fileSize = 0;
|
||||
}
|
||||
|
||||
WvIn :: ~WvIn()
|
||||
{
|
||||
if (fd) {
|
||||
fclose(fd);
|
||||
fd = 0;
|
||||
}
|
||||
if (data) {
|
||||
delete [ ] data;
|
||||
data = 0;
|
||||
}
|
||||
if (lastOutput) {
|
||||
delete [ ] lastOutput;
|
||||
lastOutput = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WvIn :: reset()
|
||||
{
|
||||
finished = 0;
|
||||
time = (MY_FLOAT) 0.0;
|
||||
for (int i=0;i<channels;i++) {
|
||||
lastOutput[i] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void WvIn :: normalize()
|
||||
{
|
||||
/* Do nothing for streamed input ... cannot be normalized */
|
||||
if (chunking) return;
|
||||
|
||||
this->normalize((MY_FLOAT) 1.0);
|
||||
}
|
||||
|
||||
// Normalize all channels equally by the greatest magnitude in all of data
|
||||
void WvIn :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
/* Do nothing for streamed input ... cannot be normalized */
|
||||
if (chunking) return;
|
||||
|
||||
long i;
|
||||
MY_FLOAT max = (MY_FLOAT) 0.0;
|
||||
|
||||
for (i=0;i<channels*bufferSize;i++) {
|
||||
if (fabs(data[i]) > max)
|
||||
max = (MY_FLOAT) fabs((double) data[i]);
|
||||
}
|
||||
if (max > 0.0) {
|
||||
max = (MY_FLOAT) 1.0 / max;
|
||||
max *= newPeak;
|
||||
for (i=0;i<=channels*bufferSize;i++)
|
||||
data[i] *= max;
|
||||
}
|
||||
}
|
||||
|
||||
void WvIn :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
|
||||
// If negative rate and at beginning of sound, move pointer to end of sound.
|
||||
if ( (rate < 0) && (time == 0.0) ) time += rate + fileSize;
|
||||
|
||||
if (fmod(rate, 1.0) != 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
}
|
||||
|
||||
void WvIn :: setFreq(MY_FLOAT aFreq)
|
||||
{
|
||||
// This is a looping frequency.
|
||||
if (looping) {
|
||||
rate = fileSize * (MY_FLOAT) ONE_OVER_SRATE * aFreq;
|
||||
if (fmod(rate, 1.0) != 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WvIn :: addTime(MY_FLOAT aTime)
|
||||
{
|
||||
// Add an absolute time in samples
|
||||
time += aTime;
|
||||
|
||||
while (time < 0.0)
|
||||
time += fileSize;
|
||||
while (time >= fileSize)
|
||||
time -= fileSize;
|
||||
}
|
||||
|
||||
void WvIn :: addPhase(MY_FLOAT anAngle)
|
||||
{
|
||||
// Add a time in cycles (one cycle = fileSize) ... for looping.
|
||||
if (looping) {
|
||||
time += fileSize * anAngle;
|
||||
|
||||
while (time < 0.0)
|
||||
time += fileSize;
|
||||
while (time >= fileSize)
|
||||
time -= fileSize;
|
||||
}
|
||||
}
|
||||
|
||||
void WvIn :: addPhaseOffset(MY_FLOAT anAngle)
|
||||
{
|
||||
// Add a phase offset in cycles, where 1.0 = fileSize (looping).
|
||||
if (looping)
|
||||
phaseOffset = fileSize * anAngle;
|
||||
}
|
||||
|
||||
void WvIn :: setInterpolate(int anInterpStatus)
|
||||
{
|
||||
interpolate = anInterpStatus;
|
||||
}
|
||||
|
||||
void WvIn :: setLooping(int aLoopStatus)
|
||||
{
|
||||
time = (MY_FLOAT) 0.0;
|
||||
looping = aLoopStatus;
|
||||
|
||||
if (looping && !chunking) {
|
||||
for (int i=0;i<channels;i++)
|
||||
data[bufferSize*channels+i] = data[i];
|
||||
}
|
||||
else {
|
||||
for (int i=0;i<channels;i++)
|
||||
data[bufferSize*channels+i] = data[(bufferSize-1)*channels+i];
|
||||
}
|
||||
}
|
||||
|
||||
long WvIn :: getSize()
|
||||
{
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
void WvIn :: getData(long index)
|
||||
{
|
||||
// implemented in subclasses
|
||||
}
|
||||
|
||||
int WvIn :: isFinished()
|
||||
{
|
||||
return finished;
|
||||
}
|
||||
|
||||
MY_FLOAT WvIn :: tick()
|
||||
{
|
||||
this->informTick();
|
||||
if (channels > 1) {
|
||||
MY_FLOAT tempout = 0.0;
|
||||
for (int i=0;i<channels;i++)
|
||||
tempout += lastOutput[i];
|
||||
tempout /= channels;
|
||||
return tempout;
|
||||
}
|
||||
else
|
||||
return *lastOutput;
|
||||
}
|
||||
|
||||
MY_MULTI WvIn :: mtick()
|
||||
{
|
||||
this->informTick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
int WvIn :: informTick()
|
||||
{
|
||||
static MY_FLOAT temp, alpha;
|
||||
static long index;
|
||||
|
||||
if (finished) return finished;
|
||||
|
||||
if (looping) {
|
||||
// Check limits of time address ... if necessary, recalculate modulo fileSize.
|
||||
while (time < 0.0)
|
||||
time += fileSize;
|
||||
while (time >= fileSize)
|
||||
time -= fileSize;
|
||||
|
||||
if (phaseOffset) {
|
||||
temp = time + phaseOffset;
|
||||
while (temp < 0.0)
|
||||
temp += fileSize;
|
||||
while (temp >= fileSize)
|
||||
temp -= fileSize;
|
||||
}
|
||||
else {
|
||||
temp = time;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// oneshot: if out of bounds, we're done
|
||||
if ( (time < 0.0) || (time >= fileSize) ) {
|
||||
finished = 1;
|
||||
return finished;
|
||||
}
|
||||
temp = time;
|
||||
}
|
||||
|
||||
if (chunking) {
|
||||
// check the time address vs. our current buffer limits
|
||||
if ( (temp < readPointer) || (temp >= readPointer+bufferSize) )
|
||||
this->getData((long) temp);
|
||||
// adjust index for current buffer
|
||||
temp -= readPointer;
|
||||
}
|
||||
|
||||
// integer part of time address
|
||||
index = (long) temp;
|
||||
|
||||
if (interpolate) {
|
||||
// fractional part of time address
|
||||
alpha = temp - (MY_FLOAT) index;
|
||||
index *= channels;
|
||||
for (int i=0;i<channels;i++) {
|
||||
// Do linear interpolation
|
||||
lastOutput[i] = data[index];
|
||||
lastOutput[i] += (alpha * (data[index+channels] - lastOutput[i]));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
index *= channels;
|
||||
for (int i=0;i<channels;i++) {
|
||||
lastOutput[i] = data[index++];
|
||||
}
|
||||
}
|
||||
|
||||
// increment time, which can be negative
|
||||
time += rate;
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
MY_FLOAT WvIn :: lastOut()
|
||||
{
|
||||
if (channels > 1) {
|
||||
MY_FLOAT tempout = 0.0;
|
||||
for (int i=0;i<channels;i++)
|
||||
tempout += lastOutput[i];
|
||||
tempout /= channels;
|
||||
return tempout;
|
||||
}
|
||||
else
|
||||
return *lastOutput;
|
||||
}
|
||||
|
||||
MY_MULTI WvIn :: mlastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
51
src/WvOut.cpp
Normal file
51
src/WvOut.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/********************************************/
|
||||
/* WvOut Abstract Class, */
|
||||
/* by Tim Stilson, 1996 */
|
||||
/* revised by Gary P. Scavone, 1999-2000 */
|
||||
/* */
|
||||
/* This class can handle multi-channel */
|
||||
/* data via the mtick() method. */
|
||||
/* */
|
||||
/* Currently, WvOut and its subclasses are */
|
||||
/* non-interpolating. Thus, the output */
|
||||
/* rate is always SRATE (defined in */
|
||||
/* Object.h). A future upgrade could add */
|
||||
/* interpolation functionality to allow */
|
||||
/* output rates different than the STK */
|
||||
/* internal processing rate (SRATE). */
|
||||
/********************************************/
|
||||
|
||||
#include "WvOut.h"
|
||||
|
||||
WvOut :: WvOut()
|
||||
{
|
||||
data = 0;
|
||||
counter = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
WvOut :: ~WvOut()
|
||||
{
|
||||
if (data) {
|
||||
delete [ ] data;
|
||||
data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
long WvOut :: getCounter()
|
||||
{
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
MY_FLOAT WvOut :: getTime()
|
||||
{
|
||||
return (MY_FLOAT) totalCount * ONE_OVER_SRATE;
|
||||
}
|
||||
|
||||
void WvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
}
|
||||
|
||||
void WvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
}
|
||||
229
src/mandplyr.cpp
Normal file
229
src/mandplyr.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
/********************************************/
|
||||
/* MandPlyr Player Expert Object to control*/
|
||||
/* commuted dual plucked-string model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/********************************************/
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "Mandolin.h"
|
||||
#include "mandplyr.h"
|
||||
#include "VoicMang.h"
|
||||
#include "Noise.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
MandPlyr :: MandPlyr() : Instrmnt()
|
||||
{
|
||||
short i;
|
||||
strings = new VoicMang(NUM_STRINGS,"Mandolin");
|
||||
noise = new Noise;
|
||||
strumming = 0;
|
||||
strumRate = (long) (SRATE * 0.1); // ( 1/(0.1) = 10Hz)
|
||||
strumCount = 0;
|
||||
skill = (MY_FLOAT) 0.90;
|
||||
for (i=0;i<NUM_STRINGS;i++) {
|
||||
nums[i] = 0;
|
||||
amps[i] = (MY_FLOAT) 0;
|
||||
tags[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
MandPlyr :: ~MandPlyr()
|
||||
{
|
||||
delete strings;
|
||||
delete noise;
|
||||
}
|
||||
|
||||
void MandPlyr :: noteOnN(short num, MY_FLOAT amp)
|
||||
{
|
||||
long temp;
|
||||
short i,notDone;
|
||||
MY_FLOAT isErr,errDir;
|
||||
short error = 0;
|
||||
|
||||
errDir = noise->tick();
|
||||
if (errDir < 0)
|
||||
isErr = -errDir;
|
||||
else
|
||||
isErr = errDir;
|
||||
if (isErr < (0.4 * (1.0 - skill))) { /* Should we err here? */
|
||||
error = 1;
|
||||
if (strumming < 1) {
|
||||
strumming = 2;
|
||||
strumCount = strumRate;
|
||||
}
|
||||
if (errDir < 0.0) error = -1; /* random error +/- 1/2 step */
|
||||
}
|
||||
|
||||
|
||||
i = 0;
|
||||
notDone = 1;
|
||||
while (notDone && i<NUM_STRINGS) {
|
||||
if (tags[i] < 0) {
|
||||
nums[i] = num;
|
||||
amps[i] = amp;
|
||||
tags[i] = strings->noteOnN((MY_FLOAT) num + error,amp);
|
||||
notDone = 0;
|
||||
if (tags[i]<0) {
|
||||
printf("Must Reallocate a note\n");
|
||||
notDone = 1;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (notDone) {
|
||||
temp = strings->oldestVoice();
|
||||
i = 0;
|
||||
while (notDone && i<NUM_STRINGS) {
|
||||
if (tags[i] < 0) {
|
||||
strings->kill(temp);
|
||||
nums[i] = num;
|
||||
amps[i] = amp;
|
||||
tags[i] = strings->noteOnN((MY_FLOAT) num + error,amp);
|
||||
notDone = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (notDone) printf("Can't allocate a new note\n");
|
||||
}
|
||||
|
||||
void MandPlyr :: noteOffN(short num,MY_FLOAT amp)
|
||||
{
|
||||
long temp;
|
||||
short i;
|
||||
temp = strings->noteOffN(num,amp);
|
||||
if (temp>0) { // Usual Case
|
||||
for (i=0;i<NUM_STRINGS;i++) {
|
||||
if (tags[i] == temp) {
|
||||
tags[i] = -1;
|
||||
nums[i] = 0;
|
||||
amps[i] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // In case note already off
|
||||
for (i=0;i<NUM_STRINGS;i++) { // from strumming
|
||||
if (nums[i] == num) { // Just clear its entry
|
||||
strings->noteOffT(num,amp);
|
||||
tags[i] = -1;
|
||||
nums[i] = 0;
|
||||
amps[i] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strumming == 2) strumming = 0;
|
||||
}
|
||||
|
||||
MY_FLOAT MandPlyr :: tick()
|
||||
{
|
||||
short i;
|
||||
MY_FLOAT temp2;
|
||||
if (strumming > 0) {
|
||||
strumCount -= 1;
|
||||
if (strumCount <= 0) {
|
||||
for (i=0;i<NUM_STRINGS;i++) {
|
||||
if (tags[i] > 0) {
|
||||
strings->kill(tags[i]);
|
||||
temp2 = (MY_FLOAT) fabs(noise->tick());
|
||||
if (temp2 > 0.2 * (1.0 - skill))
|
||||
tags[i] = strings->noteOnN(nums[i],amps[i]);
|
||||
}
|
||||
}
|
||||
strumCount = strumRate;
|
||||
strumCount = strumCount +
|
||||
(long) (strumCount * (noise->tick() * (1.0 - skill)));
|
||||
if (strumming == 2) strumming = 0;
|
||||
}
|
||||
}
|
||||
for (i=0;i<NUM_STRINGS;i++) {
|
||||
if (tags[i] < -1) {
|
||||
tags[i] += 1;
|
||||
if (tags[i] == -1) {
|
||||
tags[i] = strings->noteOnN(nums[i],amps[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastOutput = strings->tick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
|
||||
/* Some very basic Mandolin Chords */
|
||||
/* Base Strings: G D A E */
|
||||
/* G Chord: G D B G */
|
||||
/* C Chord: G E C G */
|
||||
/* D Chord: A D A F# */
|
||||
/* E Chord: G# E B G# */
|
||||
/* A Chord: A E C# A */
|
||||
/* B Chord: B D# B F# */
|
||||
|
||||
#define NUM_CHORDS 6
|
||||
|
||||
void MandPlyr :: playChord(MY_FLOAT amp, char *chordString)
|
||||
{
|
||||
short i;
|
||||
char chordStr[NUM_CHORDS+1] = {"GCDEAB"};
|
||||
short chords[NUM_CHORDS][4] = {
|
||||
{55,62,71,79},
|
||||
{55,64,72,79},
|
||||
{57,62,69,78},
|
||||
{56,64,71,80},
|
||||
{57,64,73,81},
|
||||
{59,63,71,78} };
|
||||
short whichChord = -1;
|
||||
|
||||
for (i=0;i<4;i++)
|
||||
if (tags[i] >= 0) strings->noteOffT(tags[i],amp);
|
||||
|
||||
for (i=0;i<NUM_CHORDS;i++) {
|
||||
if (chordString[0]==chordStr[i])
|
||||
whichChord = i;
|
||||
}
|
||||
|
||||
if (chordString[0] == 0) {
|
||||
}
|
||||
else {
|
||||
if (whichChord == -1) {
|
||||
printf("I don't know this chord: %s\n",chordString);
|
||||
}
|
||||
else {
|
||||
for (i=0;i<4;i++) {
|
||||
nums[i] = chords[whichChord][i];
|
||||
tags[i] = -2 - (i * 10 * (200 - (int) amp));
|
||||
amps[i] = amp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MandPlyr :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("MandPlyr : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
|
||||
if (number == __SK_BodySize_)
|
||||
strings->controlChange(number,value);
|
||||
else if (number == __SK_PickPosition_)
|
||||
strings->controlChange(number,value);
|
||||
else if (number == __SK_StringDamping_)
|
||||
strings->controlChange(number,value);
|
||||
else if (number == __SK_StringDetune_)
|
||||
strings->controlChange(number,value);
|
||||
|
||||
else if (number == __SK_Strumming_) {
|
||||
if (value < 0.5)
|
||||
strumming = 0;
|
||||
else
|
||||
strumming = 1;
|
||||
}
|
||||
else if (number == __SK_NotStrumming_)
|
||||
strumming = 0;
|
||||
else if (number == __SK_PlayerSkill_)
|
||||
skill = value * (MY_FLOAT) NORM_7;
|
||||
else if (number == __SK_StrumSpeed_)
|
||||
strumRate = (long) (SRATE * value * NORM_7); // (0 - 1Hz.)
|
||||
else {
|
||||
printf("MandPlyr : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user