mirror of
https://github.com/thestk/stk
synced 2026-01-15 14:01:52 +00:00
Version 4.1
This commit is contained in:
committed by
Stephen Sinclair
parent
81475b04c5
commit
2f09fcd019
380
src/ADSR.cpp
380
src/ADSR.cpp
@@ -1,190 +1,190 @@
|
||||
/***************************************************/
|
||||
/*! \class ADSR
|
||||
\brief STK ADSR envelope class.
|
||||
|
||||
This Envelope subclass implements a
|
||||
traditional ADSR (Attack, Decay,
|
||||
Sustain, Release) envelope. It
|
||||
responds to simple keyOn and keyOff
|
||||
messages, keeping track of its state.
|
||||
The \e state = ADSR::DONE after the
|
||||
envelope value reaches 0.0 in the
|
||||
ADSR::RELEASE state.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "ADSR.h"
|
||||
#include <stdio.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 = ATTACK;
|
||||
}
|
||||
|
||||
ADSR :: ~ADSR()
|
||||
{
|
||||
}
|
||||
|
||||
void ADSR :: keyOn()
|
||||
{
|
||||
target = (MY_FLOAT) 1.0;
|
||||
rate = attackRate;
|
||||
state = ATTACK;
|
||||
}
|
||||
|
||||
void ADSR :: keyOff()
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
rate = releaseRate;
|
||||
state = RELEASE;
|
||||
}
|
||||
|
||||
void ADSR :: setAttackRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("ADSR: negative rates not allowed ... correcting!\n");
|
||||
attackRate = -aRate;
|
||||
}
|
||||
else attackRate = aRate;
|
||||
}
|
||||
|
||||
void ADSR :: setDecayRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("ADSR: negative rates not allowed ... correcting!\n");
|
||||
decayRate = -aRate;
|
||||
}
|
||||
else decayRate = aRate;
|
||||
}
|
||||
|
||||
void ADSR :: setSustainLevel(MY_FLOAT aLevel)
|
||||
{
|
||||
if (aLevel < 0.0 ) {
|
||||
printf("ADSR: 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("ADSR: negative rates not allowed ... correcting!\n");
|
||||
releaseRate = -aRate;
|
||||
}
|
||||
else releaseRate = aRate;
|
||||
}
|
||||
|
||||
void ADSR :: setAttackTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("ADSR: negative rates not allowed ... correcting!\n");
|
||||
attackRate = 1.0 / ( -aTime * Stk::sampleRate() );
|
||||
}
|
||||
else attackRate = 1.0 / ( aTime * Stk::sampleRate() );
|
||||
}
|
||||
|
||||
void ADSR :: setDecayTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("ADSR: negative times not allowed ... correcting!\n");
|
||||
decayRate = 1.0 / ( -aTime * Stk::sampleRate() );
|
||||
}
|
||||
else decayRate = 1.0 / ( aTime * Stk::sampleRate() );
|
||||
}
|
||||
|
||||
void ADSR :: setReleaseTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("ADSR: negative times not allowed ... correcting!\n");
|
||||
releaseRate = 1.0 / ( -aTime * Stk::sampleRate() );
|
||||
}
|
||||
else releaseRate = 1.0 / ( aTime * Stk::sampleRate() );
|
||||
}
|
||||
|
||||
void ADSR :: setAllTimes(MY_FLOAT aTime, MY_FLOAT dTime, MY_FLOAT sLevel, MY_FLOAT rTime)
|
||||
{
|
||||
this->setAttackTime(aTime);
|
||||
this->setDecayTime(dTime);
|
||||
this->setSustainLevel(sLevel);
|
||||
this->setReleaseTime(rTime);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int ADSR :: getState(void) const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
MY_FLOAT ADSR :: tick()
|
||||
{
|
||||
switch (state) {
|
||||
|
||||
case ATTACK:
|
||||
value += rate;
|
||||
if (value >= target) {
|
||||
value = target;
|
||||
rate = decayRate;
|
||||
target = sustainLevel;
|
||||
state = DECAY;
|
||||
}
|
||||
break;
|
||||
|
||||
case DECAY:
|
||||
value -= decayRate;
|
||||
if (value <= sustainLevel) {
|
||||
value = sustainLevel;
|
||||
rate = (MY_FLOAT) 0.0;
|
||||
state = SUSTAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case RELEASE:
|
||||
value -= releaseRate;
|
||||
if (value <= 0.0) {
|
||||
value = (MY_FLOAT) 0.0;
|
||||
state = DONE;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
MY_FLOAT *ADSR :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class ADSR
|
||||
\brief STK ADSR envelope class.
|
||||
|
||||
This Envelope subclass implements a
|
||||
traditional ADSR (Attack, Decay,
|
||||
Sustain, Release) envelope. It
|
||||
responds to simple keyOn and keyOff
|
||||
messages, keeping track of its state.
|
||||
The \e state = ADSR::DONE after the
|
||||
envelope value reaches 0.0 in the
|
||||
ADSR::RELEASE state.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "ADSR.h"
|
||||
#include <stdio.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 = ATTACK;
|
||||
}
|
||||
|
||||
ADSR :: ~ADSR()
|
||||
{
|
||||
}
|
||||
|
||||
void ADSR :: keyOn()
|
||||
{
|
||||
target = (MY_FLOAT) 1.0;
|
||||
rate = attackRate;
|
||||
state = ATTACK;
|
||||
}
|
||||
|
||||
void ADSR :: keyOff()
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
rate = releaseRate;
|
||||
state = RELEASE;
|
||||
}
|
||||
|
||||
void ADSR :: setAttackRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("ADSR: negative rates not allowed ... correcting!\n");
|
||||
attackRate = -aRate;
|
||||
}
|
||||
else attackRate = aRate;
|
||||
}
|
||||
|
||||
void ADSR :: setDecayRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("ADSR: negative rates not allowed ... correcting!\n");
|
||||
decayRate = -aRate;
|
||||
}
|
||||
else decayRate = aRate;
|
||||
}
|
||||
|
||||
void ADSR :: setSustainLevel(MY_FLOAT aLevel)
|
||||
{
|
||||
if (aLevel < 0.0 ) {
|
||||
printf("ADSR: 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("ADSR: negative rates not allowed ... correcting!\n");
|
||||
releaseRate = -aRate;
|
||||
}
|
||||
else releaseRate = aRate;
|
||||
}
|
||||
|
||||
void ADSR :: setAttackTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("ADSR: negative rates not allowed ... correcting!\n");
|
||||
attackRate = 1.0 / ( -aTime * Stk::sampleRate() );
|
||||
}
|
||||
else attackRate = 1.0 / ( aTime * Stk::sampleRate() );
|
||||
}
|
||||
|
||||
void ADSR :: setDecayTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("ADSR: negative times not allowed ... correcting!\n");
|
||||
decayRate = 1.0 / ( -aTime * Stk::sampleRate() );
|
||||
}
|
||||
else decayRate = 1.0 / ( aTime * Stk::sampleRate() );
|
||||
}
|
||||
|
||||
void ADSR :: setReleaseTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("ADSR: negative times not allowed ... correcting!\n");
|
||||
releaseRate = 1.0 / ( -aTime * Stk::sampleRate() );
|
||||
}
|
||||
else releaseRate = 1.0 / ( aTime * Stk::sampleRate() );
|
||||
}
|
||||
|
||||
void ADSR :: setAllTimes(MY_FLOAT aTime, MY_FLOAT dTime, MY_FLOAT sLevel, MY_FLOAT rTime)
|
||||
{
|
||||
this->setAttackTime(aTime);
|
||||
this->setDecayTime(dTime);
|
||||
this->setSustainLevel(sLevel);
|
||||
this->setReleaseTime(rTime);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int ADSR :: getState(void) const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
MY_FLOAT ADSR :: tick()
|
||||
{
|
||||
switch (state) {
|
||||
|
||||
case ATTACK:
|
||||
value += rate;
|
||||
if (value >= target) {
|
||||
value = target;
|
||||
rate = decayRate;
|
||||
target = sustainLevel;
|
||||
state = DECAY;
|
||||
}
|
||||
break;
|
||||
|
||||
case DECAY:
|
||||
value -= decayRate;
|
||||
if (value <= sustainLevel) {
|
||||
value = sustainLevel;
|
||||
rate = (MY_FLOAT) 0.0;
|
||||
state = SUSTAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case RELEASE:
|
||||
value -= releaseRate;
|
||||
if (value <= 0.0) {
|
||||
value = (MY_FLOAT) 0.0;
|
||||
state = DONE;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
MY_FLOAT *ADSR :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
127
src/BandedWG.cpp
127
src/BandedWG.cpp
@@ -38,7 +38,7 @@ BandedWG :: BandedWG()
|
||||
{
|
||||
doPluck = true;
|
||||
|
||||
delay = new Delay[MAX_BANDED_MODES];
|
||||
delay = new DelayL[MAX_BANDED_MODES];
|
||||
bandpass = new BiQuad[MAX_BANDED_MODES];
|
||||
|
||||
bowTabl = new BowTabl;
|
||||
@@ -58,6 +58,8 @@ BandedWG :: BandedWG()
|
||||
|
||||
bowVelocity = 0.0;
|
||||
bowTarget = 0.0;
|
||||
|
||||
strikeAmp = 0.0;
|
||||
}
|
||||
|
||||
BandedWG :: ~BandedWG()
|
||||
@@ -88,8 +90,10 @@ void BandedWG :: setPreset(int preset)
|
||||
modes[2] = (MY_FLOAT) 10.7184986595;
|
||||
modes[3] = (MY_FLOAT) 18.0697050938;
|
||||
|
||||
for (i=0; i<presetModes; i++)
|
||||
gains[i] = (MY_FLOAT) pow(0.999,(double) i);
|
||||
for (i=0; i<presetModes; i++) {
|
||||
basegains[i] = (MY_FLOAT) pow(0.999,(double) i+1);
|
||||
excitation[i] = 1.0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -102,40 +106,58 @@ void BandedWG :: setPreset(int preset)
|
||||
modes[4] = (MY_FLOAT) 9.38;
|
||||
// modes[5] = (MY_FLOAT) 12.22;
|
||||
|
||||
for (i=0; i<presetModes; i++)
|
||||
gains[i] = (MY_FLOAT) pow(0.999,(double) i);
|
||||
for (i=0; i<presetModes; i++) {
|
||||
basegains[i] = (MY_FLOAT) pow(0.999,(double) i+1);
|
||||
excitation[i] = 1.0;
|
||||
}
|
||||
/*
|
||||
baseGain = (MY_FLOAT) 0.99999;
|
||||
for (i=0; i<presetModes; i++)
|
||||
baseGain = (MY_FLOAT) 0.99999;
|
||||
for (i=0; i<presetModes; i++)
|
||||
gains[i]= (MY_FLOAT) pow(baseGain, delay[i].getDelay()+i);
|
||||
*/
|
||||
|
||||
break;
|
||||
|
||||
case 3: // Tibetan Prayer Bowl (ICMC'02)
|
||||
presetModes = 12;
|
||||
modes[0]=0.996108344;
|
||||
basegains[0]=0.999925960128219;
|
||||
excitation[0]=11.900357/10.0;
|
||||
modes[1]=1.0038916562;
|
||||
basegains[1]=0.999925960128219;
|
||||
excitation[1]=11.900357/10.;
|
||||
modes[2]=2.979178;
|
||||
basegains[2]=0.999982774366897;
|
||||
excitation[2]=10.914886/10.;
|
||||
modes[3]=2.99329767;
|
||||
basegains[3]=0.999982774366897;
|
||||
excitation[3]=10.914886/10.;
|
||||
modes[4]=5.704452;
|
||||
basegains[4]=1.0; //0.999999999999999999987356406352;
|
||||
excitation[4]=42.995041/10.;
|
||||
modes[5]=5.704452;
|
||||
basegains[5]=1.0; //0.999999999999999999987356406352;
|
||||
excitation[5]=42.995041/10.;
|
||||
modes[6]=8.9982;
|
||||
basegains[6]=1.0; //0.999999999999999999996995497558225;
|
||||
excitation[6]=40.063034/10.;
|
||||
modes[7]=9.01549726;
|
||||
basegains[7]=1.0; //0.999999999999999999996995497558225;
|
||||
excitation[7]=40.063034/10.;
|
||||
modes[8]=12.83303;
|
||||
basegains[8]=0.999965497558225;
|
||||
excitation[8]=7.063034/10.;
|
||||
modes[9]=12.807382;
|
||||
basegains[9]=0.999965497558225;
|
||||
excitation[9]=7.063034/10.;
|
||||
modes[10]=17.2808219;
|
||||
basegains[10]=0.9999999999999999999965497558225;
|
||||
excitation[10]=57.063034/10.;
|
||||
modes[11]=21.97602739726;
|
||||
basegains[11]=0.999999999999999965497558225;
|
||||
excitation[11]=57.063034/10.;
|
||||
|
||||
case 3: // Tibetan Prayer Bowl
|
||||
presetModes = 17;
|
||||
modes[0] = (MY_FLOAT) 1.0;
|
||||
modes[1] = (MY_FLOAT) 1.135;
|
||||
modes[2] = (MY_FLOAT) 2.329;
|
||||
modes[3] = (MY_FLOAT) 3.210;
|
||||
modes[4] = (MY_FLOAT) 6.046;
|
||||
modes[5] = (MY_FLOAT) 6.106;
|
||||
modes[6] = (MY_FLOAT) 6.419;
|
||||
modes[7] = (MY_FLOAT) 9.689;
|
||||
modes[8] = (MY_FLOAT) 12.212;
|
||||
modes[9] = (MY_FLOAT) 13.869;
|
||||
modes[10] = (MY_FLOAT) 15.735;
|
||||
modes[11] = (MY_FLOAT) 15.795;
|
||||
modes[12] = (MY_FLOAT) 18.601;
|
||||
modes[13] = (MY_FLOAT) 18.661;
|
||||
modes[14] = (MY_FLOAT) 19.363;
|
||||
modes[15] = (MY_FLOAT) 23.901;
|
||||
modes[16] = (MY_FLOAT) 32.470;
|
||||
|
||||
for (i=0; i<presetModes; i++)
|
||||
gains[i]=0.9995;
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
default: // Uniform Bar
|
||||
presetModes = 4;
|
||||
@@ -144,8 +166,10 @@ void BandedWG :: setPreset(int preset)
|
||||
modes[2] = (MY_FLOAT) 5.404;
|
||||
modes[3] = (MY_FLOAT) 8.933;
|
||||
|
||||
for (i=0; i<presetModes; i++)
|
||||
gains[i] = (MY_FLOAT) pow(0.9,(double) i);
|
||||
for (i=0; i<presetModes; i++) {
|
||||
basegains[i] = (MY_FLOAT) pow(0.9,(double) i+1);
|
||||
excitation[i] = 1.0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -165,19 +189,24 @@ void BandedWG :: setFrequency(MY_FLOAT frequency)
|
||||
|
||||
MY_FLOAT radius;
|
||||
MY_FLOAT base = Stk::sampleRate() / freakency;
|
||||
int length;
|
||||
MY_FLOAT length;
|
||||
for (int i=0; i<presetModes; i++) {
|
||||
// Calculate the delay line lengths for each mode.
|
||||
length = (int) (base / modes[i]);
|
||||
if ( length > 2)
|
||||
length = (int)(base / modes[i]);
|
||||
if ( length > 2.0) {
|
||||
delay[i].setDelay( length );
|
||||
gains[i]=basegains[i];
|
||||
// gains[i]=(MY_FLOAT) pow(basegains[i], 1/((MY_FLOAT)delay[i].getDelay()));
|
||||
// cerr << gains[i];
|
||||
}
|
||||
else {
|
||||
nModes = i;
|
||||
break;
|
||||
}
|
||||
// cerr << endl;
|
||||
|
||||
// Set the bandpass filter resonances
|
||||
radius = 1.0 - PI * freakency * modes[i] / Stk::sampleRate();
|
||||
radius = 1.0 - PI * 32 / Stk::sampleRate(); //freakency * modes[i] / Stk::sampleRate()/32;
|
||||
if ( radius < 0.0 ) radius = 0.0;
|
||||
bandpass[i].setResonance(freakency * modes[i], radius, true);
|
||||
|
||||
@@ -191,7 +220,7 @@ void BandedWG :: setFrequency(MY_FLOAT frequency)
|
||||
|
||||
void BandedWG :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
strikePosition = (int)(delay[0].getDelay() * position / 2);
|
||||
strikePosition = (int)(delay[0].getDelay() * position / 2.0);
|
||||
}
|
||||
|
||||
void BandedWG :: startBowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
@@ -209,8 +238,13 @@ void BandedWG :: stopBowing(MY_FLOAT rate)
|
||||
|
||||
void BandedWG :: pluck(MY_FLOAT amplitude)
|
||||
{
|
||||
int j;
|
||||
MY_FLOAT min_len = delay[nModes-1].getDelay();
|
||||
for (int i=0; i<nModes; i++)
|
||||
delay[i].tick( amplitude / nModes );
|
||||
for(j=0; j<(int)(delay[i].getDelay()/min_len); j++)
|
||||
delay[i].tick( excitation[i]*amplitude / nModes /*/ (delay[i].getDelay()/min_len)*/);
|
||||
|
||||
/* strikeAmp += amplitude;*/
|
||||
}
|
||||
|
||||
void BandedWG :: noteOn(MY_FLOAT frequency, MY_FLOAT amplitude)
|
||||
@@ -240,11 +274,13 @@ void BandedWG :: noteOff(MY_FLOAT amplitude)
|
||||
MY_FLOAT BandedWG :: tick()
|
||||
{
|
||||
int k;
|
||||
MY_FLOAT velocityInput = 0.0;
|
||||
|
||||
MY_FLOAT input = 0.0;
|
||||
if ( doPluck )
|
||||
if ( doPluck ) {
|
||||
input = 0.0;
|
||||
// input = strikeAmp/nModes;
|
||||
// strikeAmp = 0.0;
|
||||
}
|
||||
else {
|
||||
if (integrationConstant == 0.0)
|
||||
velocityInput = 0.0;
|
||||
@@ -315,9 +351,12 @@ void BandedWG :: controlChange(int number, MY_FLOAT value)
|
||||
adsr->setTarget(norm);
|
||||
}
|
||||
else if (number == __SK_ModWheel_) { // 1
|
||||
baseGain = 0.9989999999 + (0.001 * norm );
|
||||
// baseGain = 0.9989999999 + (0.001 * norm );
|
||||
baseGain = 0.8999999999999999 + (0.1 * norm);
|
||||
// cerr << "Yuck!" << endl;
|
||||
for (int i=0; i<nModes; i++)
|
||||
gains[i]=(MY_FLOAT) pow(baseGain, delay[i].getDelay()+i);
|
||||
gains[i]=(MY_FLOAT) basegains[i]*baseGain;
|
||||
// gains[i]=(MY_FLOAT) pow(baseGain, (int)((MY_FLOAT)delay[i].getDelay()+i));
|
||||
}
|
||||
else if (number == __SK_ModFrequency_) // 11
|
||||
integrationConstant = norm;
|
||||
@@ -330,7 +369,7 @@ void BandedWG :: controlChange(int number, MY_FLOAT value)
|
||||
else trackVelocity = true;
|
||||
}
|
||||
else if (number == __SK_ProphesyRibbon_) // 16
|
||||
this->setPreset((int) value);
|
||||
this->setPreset((int) value);
|
||||
else
|
||||
cerr << "BandedWG: Undefined Control Number (" << number << ")!!" << endl;
|
||||
|
||||
|
||||
@@ -45,10 +45,10 @@ BeeThree :: BeeThree()
|
||||
for ( i=0; i<4; i++ )
|
||||
strcpy( files[i], RAWWAVE_PATH);
|
||||
|
||||
strcat(files[0], "rawwaves/sinewave.raw");
|
||||
strcat(files[1], "rawwaves/sinewave.raw");
|
||||
strcat(files[2], "rawwaves/sinewave.raw");
|
||||
strcat(files[3], "rawwaves/fwavblnk.raw");
|
||||
strcat(files[0], "sinewave.raw");
|
||||
strcat(files[1], "sinewave.raw");
|
||||
strcat(files[2], "sinewave.raw");
|
||||
strcat(files[3], "fwavblnk.raw");
|
||||
|
||||
for ( i=0; i<4; i++ )
|
||||
waves[i] = new WaveLoop( files[i], TRUE );
|
||||
|
||||
240
src/BiQuad.cpp
240
src/BiQuad.cpp
@@ -1,120 +1,120 @@
|
||||
/***************************************************/
|
||||
/*! \class BiQuad
|
||||
\brief STK biquad (two-pole, two-zero) filter class.
|
||||
|
||||
This protected Filter subclass implements a
|
||||
two-pole, two-zero digital filter. A method
|
||||
is provided for creating a resonance in the
|
||||
frequency response while maintaining a constant
|
||||
filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "BiQuad.h"
|
||||
#include <math.h>
|
||||
|
||||
BiQuad :: BiQuad() : Filter()
|
||||
{
|
||||
MY_FLOAT B[3] = {1.0, 0.0, 0.0};
|
||||
MY_FLOAT A[3] = {1.0, 0.0, 0.0};
|
||||
Filter::setCoefficients( 3, B, 3, A );
|
||||
}
|
||||
|
||||
BiQuad :: ~BiQuad()
|
||||
{
|
||||
}
|
||||
|
||||
void BiQuad :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void BiQuad :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void BiQuad :: setB1(MY_FLOAT b1)
|
||||
{
|
||||
b[1] = b1;
|
||||
}
|
||||
|
||||
void BiQuad :: setB2(MY_FLOAT b2)
|
||||
{
|
||||
b[2] = b2;
|
||||
}
|
||||
|
||||
void BiQuad :: setA1(MY_FLOAT a1)
|
||||
{
|
||||
a[1] = a1;
|
||||
}
|
||||
|
||||
void BiQuad :: setA2(MY_FLOAT a2)
|
||||
{
|
||||
a[2] = a2;
|
||||
}
|
||||
|
||||
void BiQuad :: setResonance(MY_FLOAT frequency, MY_FLOAT radius, bool normalize)
|
||||
{
|
||||
a[2] = radius * radius;
|
||||
a[1] = -2.0 * radius * cos(TWO_PI * frequency / Stk::sampleRate());
|
||||
|
||||
if ( normalize ) {
|
||||
// Use zeros at +- 1 and normalize the filter peak gain.
|
||||
b[0] = 0.5 - 0.5 * a[2];
|
||||
b[1] = 0.0;
|
||||
b[2] = -b[0];
|
||||
}
|
||||
}
|
||||
|
||||
void BiQuad :: setNotch(MY_FLOAT frequency, MY_FLOAT radius)
|
||||
{
|
||||
// This method does not attempt to normalize the filter gain.
|
||||
b[2] = radius * radius;
|
||||
b[1] = (MY_FLOAT) -2.0 * radius * cos(TWO_PI * (double) frequency / Stk::sampleRate());
|
||||
}
|
||||
|
||||
void BiQuad :: setEqualGainZeroes()
|
||||
{
|
||||
b[0] = 1.0;
|
||||
b[1] = 0.0;
|
||||
b[2] = -1.0;
|
||||
}
|
||||
|
||||
void BiQuad :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT BiQuad :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT BiQuad :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT BiQuad :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[0] * inputs[0] + b[1] * inputs[1] + b[2] * inputs[2];
|
||||
outputs[0] -= a[2] * outputs[2] + a[1] * outputs[1];
|
||||
inputs[2] = inputs[1];
|
||||
inputs[1] = inputs[0];
|
||||
outputs[2] = outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *BiQuad :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class BiQuad
|
||||
\brief STK biquad (two-pole, two-zero) filter class.
|
||||
|
||||
This protected Filter subclass implements a
|
||||
two-pole, two-zero digital filter. A method
|
||||
is provided for creating a resonance in the
|
||||
frequency response while maintaining a constant
|
||||
filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "BiQuad.h"
|
||||
#include <math.h>
|
||||
|
||||
BiQuad :: BiQuad() : Filter()
|
||||
{
|
||||
MY_FLOAT B[3] = {1.0, 0.0, 0.0};
|
||||
MY_FLOAT A[3] = {1.0, 0.0, 0.0};
|
||||
Filter::setCoefficients( 3, B, 3, A );
|
||||
}
|
||||
|
||||
BiQuad :: ~BiQuad()
|
||||
{
|
||||
}
|
||||
|
||||
void BiQuad :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void BiQuad :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void BiQuad :: setB1(MY_FLOAT b1)
|
||||
{
|
||||
b[1] = b1;
|
||||
}
|
||||
|
||||
void BiQuad :: setB2(MY_FLOAT b2)
|
||||
{
|
||||
b[2] = b2;
|
||||
}
|
||||
|
||||
void BiQuad :: setA1(MY_FLOAT a1)
|
||||
{
|
||||
a[1] = a1;
|
||||
}
|
||||
|
||||
void BiQuad :: setA2(MY_FLOAT a2)
|
||||
{
|
||||
a[2] = a2;
|
||||
}
|
||||
|
||||
void BiQuad :: setResonance(MY_FLOAT frequency, MY_FLOAT radius, bool normalize)
|
||||
{
|
||||
a[2] = radius * radius;
|
||||
a[1] = -2.0 * radius * cos(TWO_PI * frequency / Stk::sampleRate());
|
||||
|
||||
if ( normalize ) {
|
||||
// Use zeros at +- 1 and normalize the filter peak gain.
|
||||
b[0] = 0.5 - 0.5 * a[2];
|
||||
b[1] = 0.0;
|
||||
b[2] = -b[0];
|
||||
}
|
||||
}
|
||||
|
||||
void BiQuad :: setNotch(MY_FLOAT frequency, MY_FLOAT radius)
|
||||
{
|
||||
// This method does not attempt to normalize the filter gain.
|
||||
b[2] = radius * radius;
|
||||
b[1] = (MY_FLOAT) -2.0 * radius * cos(TWO_PI * (double) frequency / Stk::sampleRate());
|
||||
}
|
||||
|
||||
void BiQuad :: setEqualGainZeroes()
|
||||
{
|
||||
b[0] = 1.0;
|
||||
b[1] = 0.0;
|
||||
b[2] = -1.0;
|
||||
}
|
||||
|
||||
void BiQuad :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT BiQuad :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT BiQuad :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT BiQuad :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[0] * inputs[0] + b[1] * inputs[1] + b[2] * inputs[2];
|
||||
outputs[0] -= a[2] * outputs[2] + a[1] * outputs[1];
|
||||
inputs[2] = inputs[1];
|
||||
inputs[1] = inputs[0];
|
||||
outputs[2] = outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *BiQuad :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
316
src/BlowBotl.cpp
316
src/BlowBotl.cpp
@@ -1,158 +1,158 @@
|
||||
/***************************************************/
|
||||
/*! \class BlowBotl
|
||||
\brief STK blown bottle instrument class.
|
||||
|
||||
This class implements a helmholtz resonator
|
||||
(biquad filter) with a polynomial jet
|
||||
excitation (a la Cook).
|
||||
|
||||
Control Change Numbers:
|
||||
- Noise Gain = 4
|
||||
- Vibrato Frequency = 11
|
||||
- Vibrato Gain = 1
|
||||
- Volume = 128
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "BlowBotl.h"
|
||||
#include "SKINI.msg"
|
||||
#include <string.h>
|
||||
|
||||
#define __BOTTLE_RADIUS_ 0.999
|
||||
|
||||
BlowBotl :: BlowBotl()
|
||||
{
|
||||
jetTable = new JetTabl();
|
||||
|
||||
dcBlock = new PoleZero();
|
||||
dcBlock->setBlockZero();
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency( 5.925 );
|
||||
vibratoGain = 0.0;
|
||||
|
||||
resonator = new BiQuad();
|
||||
resonator->setResonance(500.0, __BOTTLE_RADIUS_, true);
|
||||
|
||||
adsr = new ADSR();
|
||||
adsr->setAllTimes( 0.005, 0.01, 0.8, 0.010);
|
||||
|
||||
noise = new Noise();
|
||||
noiseGain = 20.0;
|
||||
|
||||
maxPressure = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
BlowBotl :: ~BlowBotl()
|
||||
{
|
||||
delete jetTable;
|
||||
delete resonator;
|
||||
delete dcBlock;
|
||||
delete noise;
|
||||
delete adsr;
|
||||
delete vibrato;
|
||||
}
|
||||
|
||||
void BlowBotl :: clear()
|
||||
{
|
||||
resonator->clear();
|
||||
}
|
||||
|
||||
void BlowBotl :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT freakency = frequency;
|
||||
if ( frequency <= 0.0 ) {
|
||||
cerr << "BlowBotl: setFrequency parameter is less than or equal to zero!" << endl;
|
||||
freakency = 220.0;
|
||||
}
|
||||
|
||||
resonator->setResonance( freakency, __BOTTLE_RADIUS_, true );
|
||||
}
|
||||
|
||||
void BlowBotl :: startBlowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
adsr->setAttackRate(rate);
|
||||
maxPressure = amplitude;
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void BlowBotl :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setReleaseRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void BlowBotl :: noteOn(MY_FLOAT frequency, MY_FLOAT amplitude)
|
||||
{
|
||||
setFrequency(frequency);
|
||||
startBlowing( 1.1 + (amplitude * 0.20), amplitude * 0.02);
|
||||
outputGain = amplitude + 0.001;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "BlowBotl: NoteOn frequency = " << frequency << ", amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BlowBotl :: noteOff(MY_FLOAT amplitude)
|
||||
{
|
||||
this->stopBlowing(amplitude * 0.02);
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "BlowBotl: NoteOff amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT BlowBotl :: tick()
|
||||
{
|
||||
MY_FLOAT breathPressure;
|
||||
MY_FLOAT randPressure;
|
||||
MY_FLOAT pressureDiff;
|
||||
|
||||
// Calculate the breath pressure (envelope + vibrato)
|
||||
breathPressure = maxPressure * adsr->tick();
|
||||
breathPressure += vibratoGain * vibrato->tick();
|
||||
|
||||
pressureDiff = breathPressure - resonator->lastOut();
|
||||
|
||||
randPressure = noiseGain * noise->tick();
|
||||
randPressure *= breathPressure;
|
||||
randPressure *= (1.0 + pressureDiff);
|
||||
|
||||
resonator->tick( breathPressure + randPressure - ( jetTable->tick( pressureDiff ) * pressureDiff ) );
|
||||
lastOutput = 0.2 * outputGain * dcBlock->tick( pressureDiff );
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void BlowBotl :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT norm = value * ONE_OVER_128;
|
||||
if ( norm < 0 ) {
|
||||
norm = 0.0;
|
||||
cerr << "BlowBotl: Control value less than zero!" << endl;
|
||||
}
|
||||
else if ( norm > 1.0 ) {
|
||||
norm = 1.0;
|
||||
cerr << "BlowBotl: Control value greater than 128.0!" << endl;
|
||||
}
|
||||
|
||||
if (number == __SK_NoiseLevel_) // 4
|
||||
noiseGain = norm * 30.0;
|
||||
else if (number == __SK_ModFrequency_) // 11
|
||||
vibrato->setFrequency( norm * 12.0 );
|
||||
else if (number == __SK_ModWheel_) // 1
|
||||
vibratoGain = norm * 0.4;
|
||||
else if (number == __SK_AfterTouch_Cont_) // 128
|
||||
adsr->setTarget( norm );
|
||||
else
|
||||
cerr << "BlowBotl: Undefined Control Number (" << number << ")!!" << endl;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "BlowBotl: controlChange number = " << number << ", value = " << value << endl;
|
||||
#endif
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class BlowBotl
|
||||
\brief STK blown bottle instrument class.
|
||||
|
||||
This class implements a helmholtz resonator
|
||||
(biquad filter) with a polynomial jet
|
||||
excitation (a la Cook).
|
||||
|
||||
Control Change Numbers:
|
||||
- Noise Gain = 4
|
||||
- Vibrato Frequency = 11
|
||||
- Vibrato Gain = 1
|
||||
- Volume = 128
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "BlowBotl.h"
|
||||
#include "SKINI.msg"
|
||||
#include <string.h>
|
||||
|
||||
#define __BOTTLE_RADIUS_ 0.999
|
||||
|
||||
BlowBotl :: BlowBotl()
|
||||
{
|
||||
jetTable = new JetTabl();
|
||||
|
||||
dcBlock = new PoleZero();
|
||||
dcBlock->setBlockZero();
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(file,"sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency( 5.925 );
|
||||
vibratoGain = 0.0;
|
||||
|
||||
resonator = new BiQuad();
|
||||
resonator->setResonance(500.0, __BOTTLE_RADIUS_, true);
|
||||
|
||||
adsr = new ADSR();
|
||||
adsr->setAllTimes( 0.005, 0.01, 0.8, 0.010);
|
||||
|
||||
noise = new Noise();
|
||||
noiseGain = 20.0;
|
||||
|
||||
maxPressure = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
BlowBotl :: ~BlowBotl()
|
||||
{
|
||||
delete jetTable;
|
||||
delete resonator;
|
||||
delete dcBlock;
|
||||
delete noise;
|
||||
delete adsr;
|
||||
delete vibrato;
|
||||
}
|
||||
|
||||
void BlowBotl :: clear()
|
||||
{
|
||||
resonator->clear();
|
||||
}
|
||||
|
||||
void BlowBotl :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT freakency = frequency;
|
||||
if ( frequency <= 0.0 ) {
|
||||
cerr << "BlowBotl: setFrequency parameter is less than or equal to zero!" << endl;
|
||||
freakency = 220.0;
|
||||
}
|
||||
|
||||
resonator->setResonance( freakency, __BOTTLE_RADIUS_, true );
|
||||
}
|
||||
|
||||
void BlowBotl :: startBlowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
adsr->setAttackRate(rate);
|
||||
maxPressure = amplitude;
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void BlowBotl :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setReleaseRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void BlowBotl :: noteOn(MY_FLOAT frequency, MY_FLOAT amplitude)
|
||||
{
|
||||
setFrequency(frequency);
|
||||
startBlowing( 1.1 + (amplitude * 0.20), amplitude * 0.02);
|
||||
outputGain = amplitude + 0.001;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "BlowBotl: NoteOn frequency = " << frequency << ", amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BlowBotl :: noteOff(MY_FLOAT amplitude)
|
||||
{
|
||||
this->stopBlowing(amplitude * 0.02);
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "BlowBotl: NoteOff amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT BlowBotl :: tick()
|
||||
{
|
||||
MY_FLOAT breathPressure;
|
||||
MY_FLOAT randPressure;
|
||||
MY_FLOAT pressureDiff;
|
||||
|
||||
// Calculate the breath pressure (envelope + vibrato)
|
||||
breathPressure = maxPressure * adsr->tick();
|
||||
breathPressure += vibratoGain * vibrato->tick();
|
||||
|
||||
pressureDiff = breathPressure - resonator->lastOut();
|
||||
|
||||
randPressure = noiseGain * noise->tick();
|
||||
randPressure *= breathPressure;
|
||||
randPressure *= (1.0 + pressureDiff);
|
||||
|
||||
resonator->tick( breathPressure + randPressure - ( jetTable->tick( pressureDiff ) * pressureDiff ) );
|
||||
lastOutput = 0.2 * outputGain * dcBlock->tick( pressureDiff );
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void BlowBotl :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT norm = value * ONE_OVER_128;
|
||||
if ( norm < 0 ) {
|
||||
norm = 0.0;
|
||||
cerr << "BlowBotl: Control value less than zero!" << endl;
|
||||
}
|
||||
else if ( norm > 1.0 ) {
|
||||
norm = 1.0;
|
||||
cerr << "BlowBotl: Control value greater than 128.0!" << endl;
|
||||
}
|
||||
|
||||
if (number == __SK_NoiseLevel_) // 4
|
||||
noiseGain = norm * 30.0;
|
||||
else if (number == __SK_ModFrequency_) // 11
|
||||
vibrato->setFrequency( norm * 12.0 );
|
||||
else if (number == __SK_ModWheel_) // 1
|
||||
vibratoGain = norm * 0.4;
|
||||
else if (number == __SK_AfterTouch_Cont_) // 128
|
||||
adsr->setTarget( norm );
|
||||
else
|
||||
cerr << "BlowBotl: Undefined Control Number (" << number << ")!!" << endl;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "BlowBotl: controlChange number = " << number << ", value = " << value << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ BlowHole :: BlowHole(MY_FLOAT lowestFrequency)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE );
|
||||
vibrato = new WaveLoop( strcat(file,"sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency((MY_FLOAT) 5.735);
|
||||
outputGain = (MY_FLOAT) 1.0;
|
||||
noiseGain = (MY_FLOAT) 0.2;
|
||||
@@ -234,11 +234,11 @@ void BlowHole :: controlChange(int number, MY_FLOAT value)
|
||||
MY_FLOAT norm = value * ONE_OVER_128;
|
||||
if ( norm < 0 ) {
|
||||
norm = 0.0;
|
||||
cerr << "Clarinet: Control value less than zero!" << endl;
|
||||
cerr << "BlowHole: Control value less than zero!" << endl;
|
||||
}
|
||||
else if ( norm > 1.0 ) {
|
||||
norm = 1.0;
|
||||
cerr << "Clarinet: Control value greater than 128.0!" << endl;
|
||||
cerr << "BlowHole: Control value greater than 128.0!" << endl;
|
||||
}
|
||||
|
||||
if (number == __SK_ReedStiffness_) // 2
|
||||
|
||||
126
src/BowTabl.cpp
126
src/BowTabl.cpp
@@ -1,63 +1,63 @@
|
||||
/***************************************************/
|
||||
/*! \class BowTabl
|
||||
\brief STK bowed string table class.
|
||||
|
||||
This class implements a simple bowed string
|
||||
non-linear function, as described by Smith (1986).
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "BowTabl.h"
|
||||
#include <math.h>
|
||||
|
||||
BowTabl :: BowTabl()
|
||||
{
|
||||
offSet = (MY_FLOAT) 0.0;
|
||||
slope = (MY_FLOAT) 0.1;
|
||||
}
|
||||
|
||||
BowTabl :: ~BowTabl()
|
||||
{
|
||||
}
|
||||
|
||||
void BowTabl :: setOffset(MY_FLOAT aValue)
|
||||
{
|
||||
offSet = aValue;
|
||||
}
|
||||
|
||||
void BowTabl :: setSlope(MY_FLOAT aValue)
|
||||
{
|
||||
slope = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: tick(MY_FLOAT input)
|
||||
{
|
||||
// The input represents differential string vs. bow velocity.
|
||||
MY_FLOAT sample;
|
||||
sample = input + offSet; // add bias to input
|
||||
sample *= slope; // then scale it
|
||||
lastOutput = (MY_FLOAT) fabs((double) sample) + (MY_FLOAT) 0.75;
|
||||
lastOutput = (MY_FLOAT) pow( lastOutput,(MY_FLOAT) -4.0 );
|
||||
|
||||
// Set minimum friction to 0.0
|
||||
//if (lastOutput < 0.0 ) lastOutput = 0.0;
|
||||
// Set maximum friction to 1.0.
|
||||
if (lastOutput > 1.0 ) lastOutput = (MY_FLOAT) 1.0;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *BowTabl :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class BowTabl
|
||||
\brief STK bowed string table class.
|
||||
|
||||
This class implements a simple bowed string
|
||||
non-linear function, as described by Smith (1986).
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "BowTabl.h"
|
||||
#include <math.h>
|
||||
|
||||
BowTabl :: BowTabl()
|
||||
{
|
||||
offSet = (MY_FLOAT) 0.0;
|
||||
slope = (MY_FLOAT) 0.1;
|
||||
}
|
||||
|
||||
BowTabl :: ~BowTabl()
|
||||
{
|
||||
}
|
||||
|
||||
void BowTabl :: setOffset(MY_FLOAT aValue)
|
||||
{
|
||||
offSet = aValue;
|
||||
}
|
||||
|
||||
void BowTabl :: setSlope(MY_FLOAT aValue)
|
||||
{
|
||||
slope = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: tick(MY_FLOAT input)
|
||||
{
|
||||
// The input represents differential string vs. bow velocity.
|
||||
MY_FLOAT sample;
|
||||
sample = input + offSet; // add bias to input
|
||||
sample *= slope; // then scale it
|
||||
lastOutput = (MY_FLOAT) fabs((double) sample) + (MY_FLOAT) 0.75;
|
||||
lastOutput = (MY_FLOAT) pow( lastOutput,(MY_FLOAT) -4.0 );
|
||||
|
||||
// Set minimum friction to 0.0
|
||||
//if (lastOutput < 0.0 ) lastOutput = 0.0;
|
||||
// Set maximum friction to 1.0.
|
||||
if (lastOutput > 1.0 ) lastOutput = (MY_FLOAT) 1.0;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *BowTabl :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ Bowed :: Bowed(MY_FLOAT lowestFrequency)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE );
|
||||
vibrato = new WaveLoop( strcat(file,"sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency((MY_FLOAT) 6.12723);
|
||||
vibratoGain = (MY_FLOAT) 0.0;
|
||||
|
||||
@@ -55,6 +55,9 @@ Bowed :: Bowed(MY_FLOAT lowestFrequency)
|
||||
adsr->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.005,(MY_FLOAT) 0.9,(MY_FLOAT) 0.01);
|
||||
|
||||
betaRatio = (MY_FLOAT) 0.127236;
|
||||
|
||||
// Necessary to initialize internal variables.
|
||||
setFrequency( 220.0 );
|
||||
}
|
||||
|
||||
Bowed :: ~Bowed()
|
||||
|
||||
@@ -41,13 +41,16 @@ Brass :: Brass(MY_FLOAT lowestFrequency)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE );
|
||||
vibrato = new WaveLoop( strcat(file,"sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency( 6.137 );
|
||||
vibratoGain = 0.0;
|
||||
|
||||
this->clear();
|
||||
maxPressure = (MY_FLOAT) 0.0;
|
||||
lipTarget = 0.0;
|
||||
|
||||
// Necessary to initialize variables.
|
||||
setFrequency( 220.0 );
|
||||
}
|
||||
|
||||
Brass :: ~Brass()
|
||||
|
||||
@@ -21,9 +21,9 @@ Chorus :: Chorus(MY_FLOAT baseDelay)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char path[128];
|
||||
strcpy(path, RAWWAVE_PATH);
|
||||
mods[0] = new WaveLoop( strcat(path,"rawwaves/sinewave.raw"), TRUE );
|
||||
mods[0] = new WaveLoop( strcat(path,"sinewave.raw"), TRUE );
|
||||
strcpy(path, RAWWAVE_PATH);
|
||||
mods[1] = new WaveLoop( strcat(path,"rawwaves/sinewave.raw"), TRUE );
|
||||
mods[1] = new WaveLoop( strcat(path,"sinewave.raw"), TRUE );
|
||||
mods[0]->setFrequency(0.2);
|
||||
mods[1]->setFrequency(0.222222);
|
||||
modDepth = 0.05;
|
||||
|
||||
332
src/Clarinet.cpp
332
src/Clarinet.cpp
@@ -1,166 +1,166 @@
|
||||
/***************************************************/
|
||||
/*! \class Clarinet
|
||||
\brief STK clarinet physical model class.
|
||||
|
||||
This class implements a simple clarinet
|
||||
physical model, as discussed by Smith (1986),
|
||||
McIntyre, Schumacher, Woodhouse (1983), and
|
||||
others.
|
||||
|
||||
This is a digital waveguide model, making its
|
||||
use possibly subject to patents held by Stanford
|
||||
University, Yamaha, and others.
|
||||
|
||||
Control Change Numbers:
|
||||
- Reed Stiffness = 2
|
||||
- Noise Gain = 4
|
||||
- Vibrato Frequency = 11
|
||||
- Vibrato Gain = 1
|
||||
- Breath Pressure = 128
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Clarinet.h"
|
||||
#include "SKINI.msg"
|
||||
#include <string.h>
|
||||
|
||||
Clarinet :: Clarinet(MY_FLOAT lowestFrequency)
|
||||
{
|
||||
length = (long) (Stk::sampleRate() / lowestFrequency + 1);
|
||||
delayLine = new DelayL( (MY_FLOAT)(length / 2.0), 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 path[128];
|
||||
strcpy(path, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(path,"rawwaves/sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency((MY_FLOAT) 5.735);
|
||||
outputGain = (MY_FLOAT) 1.0;
|
||||
noiseGain = (MY_FLOAT) 0.2;
|
||||
vibratoGain = (MY_FLOAT) 0.1;
|
||||
}
|
||||
|
||||
Clarinet :: ~Clarinet()
|
||||
{
|
||||
delete delayLine;
|
||||
delete reedTable;
|
||||
delete filter;
|
||||
delete envelope;
|
||||
delete noise;
|
||||
delete vibrato;
|
||||
}
|
||||
|
||||
void Clarinet :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
filter->tick((MY_FLOAT) 0.0);
|
||||
}
|
||||
|
||||
void Clarinet :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT freakency = frequency;
|
||||
if ( frequency <= 0.0 ) {
|
||||
cerr << "Clarinet: setFrequency parameter is less than or equal to zero!" << endl;
|
||||
freakency = 220.0;
|
||||
}
|
||||
|
||||
// Delay = length - approximate filter delay.
|
||||
MY_FLOAT delay = (Stk::sampleRate() / freakency) * 0.5 - 1.5;
|
||||
if (delay <= 0.0) delay = 0.3;
|
||||
else if (delay > length) delay = length;
|
||||
delayLine->setDelay(delay);
|
||||
}
|
||||
|
||||
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 frequency, MY_FLOAT amplitude)
|
||||
{
|
||||
this->setFrequency(frequency);
|
||||
this->startBlowing((MY_FLOAT) 0.55 + (amplitude * (MY_FLOAT) 0.30), amplitude * (MY_FLOAT) 0.005);
|
||||
outputGain = amplitude + (MY_FLOAT) 0.001;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "Clarinet: NoteOn frequency = " << frequency << ", amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Clarinet :: noteOff(MY_FLOAT amplitude)
|
||||
{
|
||||
this->stopBlowing(amplitude * (MY_FLOAT) 0.01);
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "Clarinet: NoteOff amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT Clarinet :: tick()
|
||||
{
|
||||
MY_FLOAT pressureDiff;
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
// Calculate the breath pressure (envelope + noise + vibrato)
|
||||
breathPressure = envelope->tick();
|
||||
breathPressure += breathPressure * noiseGain * noise->tick();
|
||||
breathPressure += breathPressure * vibratoGain * vibrato->tick();
|
||||
|
||||
// Perform commuted loss filtering.
|
||||
pressureDiff = -0.95 * filter->tick(delayLine->lastOut());
|
||||
|
||||
// Calculate pressure difference of reflected and mouthpiece pressures.
|
||||
pressureDiff = pressureDiff - breathPressure;
|
||||
|
||||
// Perform non-linear scattering using pressure difference in reed function.
|
||||
lastOutput = delayLine->tick(breathPressure + pressureDiff * reedTable->tick(pressureDiff));
|
||||
|
||||
// Apply output gain.
|
||||
lastOutput *= outputGain;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Clarinet :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT norm = value * ONE_OVER_128;
|
||||
if ( norm < 0 ) {
|
||||
norm = 0.0;
|
||||
cerr << "Clarinet: Control value less than zero!" << endl;
|
||||
}
|
||||
else if ( norm > 1.0 ) {
|
||||
norm = 1.0;
|
||||
cerr << "Clarinet: Control value greater than 128.0!" << endl;
|
||||
}
|
||||
|
||||
if (number == __SK_ReedStiffness_) // 2
|
||||
reedTable->setSlope((MY_FLOAT) -0.44 + ( (MY_FLOAT) 0.26 * norm ));
|
||||
else if (number == __SK_NoiseLevel_) // 4
|
||||
noiseGain = (norm * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_ModFrequency_) // 11
|
||||
vibrato->setFrequency((norm * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_) // 1
|
||||
vibratoGain = (norm * (MY_FLOAT) 0.5);
|
||||
else if (number == __SK_AfterTouch_Cont_) // 128
|
||||
envelope->setValue(norm);
|
||||
else
|
||||
cerr << "Clarinet: Undefined Control Number (" << number << ")!!" << endl;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "Clarinet: controlChange number = " << number << ", value = " << value << endl;
|
||||
#endif
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class Clarinet
|
||||
\brief STK clarinet physical model class.
|
||||
|
||||
This class implements a simple clarinet
|
||||
physical model, as discussed by Smith (1986),
|
||||
McIntyre, Schumacher, Woodhouse (1983), and
|
||||
others.
|
||||
|
||||
This is a digital waveguide model, making its
|
||||
use possibly subject to patents held by Stanford
|
||||
University, Yamaha, and others.
|
||||
|
||||
Control Change Numbers:
|
||||
- Reed Stiffness = 2
|
||||
- Noise Gain = 4
|
||||
- Vibrato Frequency = 11
|
||||
- Vibrato Gain = 1
|
||||
- Breath Pressure = 128
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Clarinet.h"
|
||||
#include "SKINI.msg"
|
||||
#include <string.h>
|
||||
|
||||
Clarinet :: Clarinet(MY_FLOAT lowestFrequency)
|
||||
{
|
||||
length = (long) (Stk::sampleRate() / lowestFrequency + 1);
|
||||
delayLine = new DelayL( (MY_FLOAT)(length / 2.0), 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 path[128];
|
||||
strcpy(path, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(path,"sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency((MY_FLOAT) 5.735);
|
||||
outputGain = (MY_FLOAT) 1.0;
|
||||
noiseGain = (MY_FLOAT) 0.2;
|
||||
vibratoGain = (MY_FLOAT) 0.1;
|
||||
}
|
||||
|
||||
Clarinet :: ~Clarinet()
|
||||
{
|
||||
delete delayLine;
|
||||
delete reedTable;
|
||||
delete filter;
|
||||
delete envelope;
|
||||
delete noise;
|
||||
delete vibrato;
|
||||
}
|
||||
|
||||
void Clarinet :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
filter->tick((MY_FLOAT) 0.0);
|
||||
}
|
||||
|
||||
void Clarinet :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT freakency = frequency;
|
||||
if ( frequency <= 0.0 ) {
|
||||
cerr << "Clarinet: setFrequency parameter is less than or equal to zero!" << endl;
|
||||
freakency = 220.0;
|
||||
}
|
||||
|
||||
// Delay = length - approximate filter delay.
|
||||
MY_FLOAT delay = (Stk::sampleRate() / freakency) * 0.5 - 1.5;
|
||||
if (delay <= 0.0) delay = 0.3;
|
||||
else if (delay > length) delay = length;
|
||||
delayLine->setDelay(delay);
|
||||
}
|
||||
|
||||
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 frequency, MY_FLOAT amplitude)
|
||||
{
|
||||
this->setFrequency(frequency);
|
||||
this->startBlowing((MY_FLOAT) 0.55 + (amplitude * (MY_FLOAT) 0.30), amplitude * (MY_FLOAT) 0.005);
|
||||
outputGain = amplitude + (MY_FLOAT) 0.001;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "Clarinet: NoteOn frequency = " << frequency << ", amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Clarinet :: noteOff(MY_FLOAT amplitude)
|
||||
{
|
||||
this->stopBlowing(amplitude * (MY_FLOAT) 0.01);
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "Clarinet: NoteOff amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT Clarinet :: tick()
|
||||
{
|
||||
MY_FLOAT pressureDiff;
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
// Calculate the breath pressure (envelope + noise + vibrato)
|
||||
breathPressure = envelope->tick();
|
||||
breathPressure += breathPressure * noiseGain * noise->tick();
|
||||
breathPressure += breathPressure * vibratoGain * vibrato->tick();
|
||||
|
||||
// Perform commuted loss filtering.
|
||||
pressureDiff = -0.95 * filter->tick(delayLine->lastOut());
|
||||
|
||||
// Calculate pressure difference of reflected and mouthpiece pressures.
|
||||
pressureDiff = pressureDiff - breathPressure;
|
||||
|
||||
// Perform non-linear scattering using pressure difference in reed function.
|
||||
lastOutput = delayLine->tick(breathPressure + pressureDiff * reedTable->tick(pressureDiff));
|
||||
|
||||
// Apply output gain.
|
||||
lastOutput *= outputGain;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Clarinet :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT norm = value * ONE_OVER_128;
|
||||
if ( norm < 0 ) {
|
||||
norm = 0.0;
|
||||
cerr << "Clarinet: Control value less than zero!" << endl;
|
||||
}
|
||||
else if ( norm > 1.0 ) {
|
||||
norm = 1.0;
|
||||
cerr << "Clarinet: Control value greater than 128.0!" << endl;
|
||||
}
|
||||
|
||||
if (number == __SK_ReedStiffness_) // 2
|
||||
reedTable->setSlope((MY_FLOAT) -0.44 + ( (MY_FLOAT) 0.26 * norm ));
|
||||
else if (number == __SK_NoiseLevel_) // 4
|
||||
noiseGain = (norm * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_ModFrequency_) // 11
|
||||
vibrato->setFrequency((norm * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_) // 1
|
||||
vibratoGain = (norm * (MY_FLOAT) 0.5);
|
||||
else if (number == __SK_AfterTouch_Cont_) // 128
|
||||
envelope->setValue(norm);
|
||||
else
|
||||
cerr << "Clarinet: Undefined Control Number (" << number << ")!!" << endl;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "Clarinet: controlChange number = " << number << ", value = " << value << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
0
src/Debug/.placeholder
Normal file
0
src/Debug/.placeholder
Normal file
323
src/Delay.cpp
323
src/Delay.cpp
@@ -1,159 +1,164 @@
|
||||
/***************************************************/
|
||||
/*! \class Delay
|
||||
\brief STK non-interpolating delay line class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a non-interpolating digital delay-line.
|
||||
A fixed maximum length of 4095 and a delay
|
||||
of zero is set using the default constructor.
|
||||
Alternatively, the delay and maximum length
|
||||
can be set during instantiation with an
|
||||
overloaded constructor.
|
||||
|
||||
A non-interpolating delay line is typically
|
||||
used in fixed delay-length applications, such
|
||||
as for reverberation.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Delay.h"
|
||||
#include <iostream.h>
|
||||
|
||||
Delay :: Delay()
|
||||
{
|
||||
// Default max delay length set to 4095.
|
||||
length = 4096;
|
||||
delete [] inputs;
|
||||
inputs = new MY_FLOAT[length];
|
||||
this->clear();
|
||||
|
||||
inPoint = 0;
|
||||
outPoint = 0;
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
Delay :: Delay(long theDelay, long maxDelay)
|
||||
{
|
||||
// Writing before reading allows delays from 0 to length-1.
|
||||
// If we want to allow a delay of maxDelay, we need a
|
||||
// delay-line of length = maxDelay+1.
|
||||
length = maxDelay+1;
|
||||
|
||||
// We need to delete the previously allocated inputs.
|
||||
delete [] inputs;
|
||||
inputs = new MY_FLOAT[length];
|
||||
this->clear();
|
||||
|
||||
inPoint = 0;
|
||||
this->setDelay(theDelay);
|
||||
}
|
||||
|
||||
Delay :: ~Delay()
|
||||
{
|
||||
}
|
||||
|
||||
void Delay :: clear(void)
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = 0.0;
|
||||
outputs[0] = 0.0;
|
||||
}
|
||||
|
||||
void Delay :: setDelay(long theDelay)
|
||||
{
|
||||
if (theDelay > length-1) { // The value is too big.
|
||||
cerr << "Delay: setDelay(" << theDelay << ") too big!" << endl;
|
||||
// Force delay to maxLength.
|
||||
outPoint = inPoint + 1;
|
||||
delay = length - 1;
|
||||
}
|
||||
else if (theDelay < 0 ) {
|
||||
cerr << "Delay: setDelay(" << theDelay << ") less than zero!" << endl;
|
||||
outPoint = inPoint;
|
||||
delay = 0;
|
||||
}
|
||||
else {
|
||||
outPoint = inPoint - (long) theDelay; // read chases write
|
||||
delay = theDelay;
|
||||
}
|
||||
|
||||
while (outPoint < 0) outPoint += length; // modulo maximum length
|
||||
}
|
||||
|
||||
long Delay :: getDelay(void) const
|
||||
{
|
||||
return (long)delay;
|
||||
}
|
||||
|
||||
MY_FLOAT Delay :: energy(void) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
MY_FLOAT Delay :: contentsAt(long tapDelay) const
|
||||
{
|
||||
long i = tapDelay;
|
||||
if (i < 1) {
|
||||
cerr << "Delay: contentsAt(" << tapDelay << ") too small!" << endl;
|
||||
i=1;
|
||||
}
|
||||
else if (i > delay) {
|
||||
cerr << "Delay: contentsAt(" << tapDelay << ") too big!" << endl;
|
||||
i = (long) delay;
|
||||
}
|
||||
|
||||
long tap = inPoint - tapDelay;
|
||||
if (tap < 0) // Check for wraparound.
|
||||
tap += length;
|
||||
|
||||
return inputs[tap];
|
||||
}
|
||||
|
||||
MY_FLOAT Delay :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT Delay :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[inPoint++] = sample;
|
||||
|
||||
// Check for end condition
|
||||
if (inPoint == length)
|
||||
inPoint -= length;
|
||||
|
||||
// Read out next value
|
||||
outputs[0] = inputs[outPoint++];
|
||||
|
||||
if (outPoint>=length)
|
||||
outPoint -= length;
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *Delay :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class Delay
|
||||
\brief STK non-interpolating delay line class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a non-interpolating digital delay-line.
|
||||
A fixed maximum length of 4095 and a delay
|
||||
of zero is set using the default constructor.
|
||||
Alternatively, the delay and maximum length
|
||||
can be set during instantiation with an
|
||||
overloaded constructor.
|
||||
|
||||
A non-interpolating delay line is typically
|
||||
used in fixed delay-length applications, such
|
||||
as for reverberation.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Delay.h"
|
||||
#include <iostream.h>
|
||||
|
||||
Delay :: Delay()
|
||||
{
|
||||
// Default max delay length set to 4095.
|
||||
length = 4096;
|
||||
delete [] inputs;
|
||||
inputs = new MY_FLOAT[length];
|
||||
this->clear();
|
||||
|
||||
inPoint = 0;
|
||||
outPoint = 0;
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
Delay :: Delay(long theDelay, long maxDelay)
|
||||
{
|
||||
// Writing before reading allows delays from 0 to length-1.
|
||||
// If we want to allow a delay of maxDelay, we need a
|
||||
// delay-line of length = maxDelay+1.
|
||||
length = maxDelay+1;
|
||||
|
||||
// We need to delete the previously allocated inputs.
|
||||
delete [] inputs;
|
||||
inputs = new MY_FLOAT[length];
|
||||
this->clear();
|
||||
|
||||
inPoint = 0;
|
||||
this->setDelay(theDelay);
|
||||
}
|
||||
|
||||
Delay :: ~Delay()
|
||||
{
|
||||
}
|
||||
|
||||
void Delay :: clear(void)
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = 0.0;
|
||||
outputs[0] = 0.0;
|
||||
}
|
||||
|
||||
void Delay :: setDelay(long theDelay)
|
||||
{
|
||||
if (theDelay > length-1) { // The value is too big.
|
||||
cerr << "Delay: setDelay(" << theDelay << ") too big!" << endl;
|
||||
// Force delay to maxLength.
|
||||
outPoint = inPoint + 1;
|
||||
delay = length - 1;
|
||||
}
|
||||
else if (theDelay < 0 ) {
|
||||
cerr << "Delay: setDelay(" << theDelay << ") less than zero!" << endl;
|
||||
outPoint = inPoint;
|
||||
delay = 0;
|
||||
}
|
||||
else {
|
||||
outPoint = inPoint - (long) theDelay; // read chases write
|
||||
delay = theDelay;
|
||||
}
|
||||
|
||||
while (outPoint < 0) outPoint += length; // modulo maximum length
|
||||
}
|
||||
|
||||
long Delay :: getDelay(void) const
|
||||
{
|
||||
return (long)delay;
|
||||
}
|
||||
|
||||
MY_FLOAT Delay :: energy(void) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
MY_FLOAT Delay :: contentsAt(long tapDelay) const
|
||||
{
|
||||
long i = tapDelay;
|
||||
if (i < 0) {
|
||||
cerr << "Delay: contentsAt(" << tapDelay << ") too small!" << endl;
|
||||
i = 0;
|
||||
}
|
||||
else if (i > delay) {
|
||||
cerr << "Delay: contentsAt(" << tapDelay << ") too big!" << endl;
|
||||
i = (long) delay;
|
||||
}
|
||||
|
||||
long tap = inPoint - i;
|
||||
if (tap < 0) // Check for wraparound.
|
||||
tap += length;
|
||||
|
||||
return inputs[tap];
|
||||
}
|
||||
|
||||
MY_FLOAT Delay :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT Delay :: nextOut(void) const
|
||||
{
|
||||
return inputs[outPoint];
|
||||
}
|
||||
|
||||
MY_FLOAT Delay :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[inPoint++] = sample;
|
||||
|
||||
// Check for end condition
|
||||
if (inPoint == length)
|
||||
inPoint -= length;
|
||||
|
||||
// Read out next value
|
||||
outputs[0] = inputs[outPoint++];
|
||||
|
||||
if (outPoint>=length)
|
||||
outPoint -= length;
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *Delay :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
246
src/DelayA.cpp
246
src/DelayA.cpp
@@ -1,117 +1,129 @@
|
||||
/***************************************************/
|
||||
/*! \class DelayA
|
||||
\brief STK allpass interpolating delay line class.
|
||||
|
||||
This Delay subclass implements a fractional-
|
||||
length digital delay-line using a first-order
|
||||
allpass filter. A fixed maximum length
|
||||
of 4095 and a delay of 0.5 is set using the
|
||||
default constructor. Alternatively, the
|
||||
delay and maximum length can be set during
|
||||
instantiation with an overloaded constructor.
|
||||
|
||||
An allpass filter has unity magnitude gain but
|
||||
variable phase delay properties, making it useful
|
||||
in achieving fractional delays without affecting
|
||||
a signal's frequency magnitude response. In
|
||||
order to achieve a maximally flat phase delay
|
||||
response, the minimum delay possible in this
|
||||
implementation is limited to a value of 0.5.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "DelayA.h"
|
||||
#include <iostream.h>
|
||||
|
||||
DelayA :: DelayA()
|
||||
{
|
||||
this->setDelay( 0.5 );
|
||||
apInput = 0.0;
|
||||
}
|
||||
|
||||
DelayA :: DelayA(MY_FLOAT theDelay, long maxDelay)
|
||||
{
|
||||
// Writing before reading allows delays from 0 to length-1.
|
||||
length = maxDelay+1;
|
||||
|
||||
if ( length > 4096 ) {
|
||||
// We need to delete the previously allocated inputs.
|
||||
delete [] inputs;
|
||||
inputs = new MY_FLOAT[length];
|
||||
this->clear();
|
||||
}
|
||||
|
||||
inPoint = 0;
|
||||
this->setDelay(theDelay);
|
||||
}
|
||||
|
||||
DelayA :: ~DelayA()
|
||||
{
|
||||
}
|
||||
|
||||
void DelayA :: clear()
|
||||
{
|
||||
Delay::clear();
|
||||
apInput = 0.0;
|
||||
}
|
||||
|
||||
void DelayA :: setDelay(MY_FLOAT theDelay)
|
||||
{
|
||||
MY_FLOAT outPointer;
|
||||
|
||||
if (theDelay > length-1) {
|
||||
cerr << "DelayA: setDelay(" << theDelay << ") too big!" << endl;
|
||||
// Force delay to maxLength
|
||||
outPointer = inPoint + 1.0;
|
||||
delay = length - 1;
|
||||
}
|
||||
else if (theDelay < 0.5) {
|
||||
cerr << "DelayA: setDelay(" << theDelay << ") less than 0.5 not possible!" << endl;
|
||||
outPointer = inPoint + 0.4999999999;
|
||||
delay = 0.5;
|
||||
}
|
||||
else {
|
||||
outPointer = inPoint - theDelay + 1.0; // outPoint chases inpoint
|
||||
delay = theDelay;
|
||||
}
|
||||
|
||||
if (outPointer < 0)
|
||||
outPointer += length; // modulo maximum length
|
||||
|
||||
outPoint = (long) outPointer; // integer part
|
||||
alpha = 1.0 + outPoint - outPointer; // fractional part
|
||||
|
||||
if (alpha < 0.5) {
|
||||
// The optimal range for alpha is about 0.5 - 1.5 in order to
|
||||
// achieve the flattest phase delay response.
|
||||
outPoint += 1;
|
||||
if (outPoint >= length) outPoint -= length;
|
||||
alpha += (MY_FLOAT) 1.0;
|
||||
}
|
||||
|
||||
coeff = ((MY_FLOAT) 1.0 - alpha) /
|
||||
((MY_FLOAT) 1.0 + alpha); // coefficient for all pass
|
||||
}
|
||||
|
||||
MY_FLOAT DelayA :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[inPoint++] = sample;
|
||||
|
||||
// Increment input pointer modulo length.
|
||||
if (inPoint == length)
|
||||
inPoint -= length;
|
||||
|
||||
// Take delay-line output and increment modulo length.
|
||||
MY_FLOAT temp = inputs[outPoint++];
|
||||
if (outPoint == length)
|
||||
outPoint -= length;
|
||||
|
||||
// Do allpass interpolation delay.
|
||||
outputs[0] = -coeff * outputs[0];
|
||||
outputs[0] += apInput + (coeff * temp);
|
||||
apInput = temp;
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class DelayA
|
||||
\brief STK allpass interpolating delay line class.
|
||||
|
||||
This Delay subclass implements a fractional-
|
||||
length digital delay-line using a first-order
|
||||
allpass filter. A fixed maximum length
|
||||
of 4095 and a delay of 0.5 is set using the
|
||||
default constructor. Alternatively, the
|
||||
delay and maximum length can be set during
|
||||
instantiation with an overloaded constructor.
|
||||
|
||||
An allpass filter has unity magnitude gain but
|
||||
variable phase delay properties, making it useful
|
||||
in achieving fractional delays without affecting
|
||||
a signal's frequency magnitude response. In
|
||||
order to achieve a maximally flat phase delay
|
||||
response, the minimum delay possible in this
|
||||
implementation is limited to a value of 0.5.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "DelayA.h"
|
||||
#include <iostream.h>
|
||||
|
||||
DelayA :: DelayA()
|
||||
{
|
||||
this->setDelay( 0.5 );
|
||||
apInput = 0.0;
|
||||
doNextOut = true;
|
||||
}
|
||||
|
||||
DelayA :: DelayA(MY_FLOAT theDelay, long maxDelay)
|
||||
{
|
||||
// Writing before reading allows delays from 0 to length-1.
|
||||
length = maxDelay+1;
|
||||
|
||||
if ( length > 4096 ) {
|
||||
// We need to delete the previously allocated inputs.
|
||||
delete [] inputs;
|
||||
inputs = new MY_FLOAT[length];
|
||||
this->clear();
|
||||
}
|
||||
|
||||
inPoint = 0;
|
||||
this->setDelay(theDelay);
|
||||
doNextOut = true;
|
||||
}
|
||||
|
||||
DelayA :: ~DelayA()
|
||||
{
|
||||
}
|
||||
|
||||
void DelayA :: clear()
|
||||
{
|
||||
Delay::clear();
|
||||
apInput = 0.0;
|
||||
}
|
||||
|
||||
void DelayA :: setDelay(MY_FLOAT theDelay)
|
||||
{
|
||||
MY_FLOAT outPointer;
|
||||
|
||||
if (theDelay > length-1) {
|
||||
cerr << "DelayA: setDelay(" << theDelay << ") too big!" << endl;
|
||||
// Force delay to maxLength
|
||||
outPointer = inPoint + 1.0;
|
||||
delay = length - 1;
|
||||
}
|
||||
else if (theDelay < 0.5) {
|
||||
cerr << "DelayA: setDelay(" << theDelay << ") less than 0.5 not possible!" << endl;
|
||||
outPointer = inPoint + 0.4999999999;
|
||||
delay = 0.5;
|
||||
}
|
||||
else {
|
||||
outPointer = inPoint - theDelay + 1.0; // outPoint chases inpoint
|
||||
delay = theDelay;
|
||||
}
|
||||
|
||||
if (outPointer < 0)
|
||||
outPointer += length; // modulo maximum length
|
||||
|
||||
outPoint = (long) outPointer; // integer part
|
||||
alpha = 1.0 + outPoint - outPointer; // fractional part
|
||||
|
||||
if (alpha < 0.5) {
|
||||
// The optimal range for alpha is about 0.5 - 1.5 in order to
|
||||
// achieve the flattest phase delay response.
|
||||
outPoint += 1;
|
||||
if (outPoint >= length) outPoint -= length;
|
||||
alpha += (MY_FLOAT) 1.0;
|
||||
}
|
||||
|
||||
coeff = ((MY_FLOAT) 1.0 - alpha) /
|
||||
((MY_FLOAT) 1.0 + alpha); // coefficient for all pass
|
||||
}
|
||||
|
||||
MY_FLOAT DelayA :: nextOut(void)
|
||||
{
|
||||
if ( doNextOut ) {
|
||||
// Do allpass interpolation delay.
|
||||
nextOutput = -coeff * outputs[0];
|
||||
nextOutput += apInput + (coeff * inputs[outPoint]);
|
||||
doNextOut = false;
|
||||
}
|
||||
|
||||
return nextOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT DelayA :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[inPoint++] = sample;
|
||||
|
||||
// Increment input pointer modulo length.
|
||||
if (inPoint == length)
|
||||
inPoint -= length;
|
||||
|
||||
outputs[0] = nextOut();
|
||||
doNextOut = true;
|
||||
|
||||
// Save the allpass input and increment modulo length.
|
||||
apInput = inputs[outPoint++];
|
||||
if (outPoint == length)
|
||||
outPoint -= length;
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
226
src/DelayL.cpp
226
src/DelayL.cpp
@@ -1,107 +1,119 @@
|
||||
/***************************************************/
|
||||
/*! \class DelayL
|
||||
\brief STK linear interpolating delay line class.
|
||||
|
||||
This Delay subclass implements a fractional-
|
||||
length digital delay-line using first-order
|
||||
linear interpolation. A fixed maximum length
|
||||
of 4095 and a delay of zero is set using the
|
||||
default constructor. Alternatively, the
|
||||
delay and maximum length can be set during
|
||||
instantiation with an overloaded constructor.
|
||||
|
||||
Linear interpolation is an efficient technique
|
||||
for achieving fractional delay lengths, though
|
||||
it does introduce high-frequency signal
|
||||
attenuation to varying degrees depending on the
|
||||
fractional delay setting. The use of higher
|
||||
order Lagrange interpolators can typically
|
||||
improve (minimize) this attenuation characteristic.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "DelayL.h"
|
||||
#include <iostream.h>
|
||||
|
||||
DelayL :: DelayL()
|
||||
{
|
||||
}
|
||||
|
||||
DelayL :: DelayL(MY_FLOAT theDelay, long maxDelay)
|
||||
{
|
||||
// Writing before reading allows delays from 0 to length-1.
|
||||
length = maxDelay+1;
|
||||
|
||||
if ( length > 4096 ) {
|
||||
// We need to delete the previously allocated inputs.
|
||||
delete [] inputs;
|
||||
inputs = new MY_FLOAT[length];
|
||||
this->clear();
|
||||
}
|
||||
|
||||
inPoint = 0;
|
||||
this->setDelay(theDelay);
|
||||
}
|
||||
|
||||
DelayL :: ~DelayL()
|
||||
{
|
||||
}
|
||||
|
||||
void DelayL :: setDelay(MY_FLOAT theDelay)
|
||||
{
|
||||
MY_FLOAT outPointer;
|
||||
|
||||
if (theDelay > length-1) {
|
||||
cerr << "DelayL: setDelay(" << theDelay << ") too big!" << endl;
|
||||
// Force delay to maxLength
|
||||
outPointer = inPoint + 1.0;
|
||||
delay = length - 1;
|
||||
}
|
||||
else if (theDelay < 0 ) {
|
||||
cerr << "DelayL: setDelay(" << theDelay << ") less than zero!" << endl;
|
||||
outPointer = inPoint;
|
||||
delay = 0;
|
||||
}
|
||||
else {
|
||||
outPointer = inPoint - theDelay; // read chases write
|
||||
delay = theDelay;
|
||||
}
|
||||
|
||||
while (outPointer < 0)
|
||||
outPointer += length; // modulo maximum length
|
||||
|
||||
outPoint = (long) outPointer; // integer part
|
||||
alpha = outPointer - outPoint; // fractional part
|
||||
omAlpha = (MY_FLOAT) 1.0 - alpha;
|
||||
}
|
||||
|
||||
MY_FLOAT DelayL :: getDelay(void) const
|
||||
{
|
||||
return delay;
|
||||
}
|
||||
|
||||
MY_FLOAT DelayL :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[inPoint++] = sample;
|
||||
|
||||
// Check for end condition
|
||||
if (inPoint == length)
|
||||
inPoint -= length;
|
||||
|
||||
// First 1/2 of interpolation
|
||||
outputs[0] = inputs[outPoint++] * omAlpha;
|
||||
// Check for end condition
|
||||
if (outPoint < length) {
|
||||
// Second 1/2 of interpolation
|
||||
outputs[0] += inputs[outPoint] * alpha;
|
||||
}
|
||||
else { // if at end ...
|
||||
// Second 1/2 of interpolation
|
||||
outputs[0] += inputs[0] * alpha;
|
||||
outPoint -= length;
|
||||
}
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class DelayL
|
||||
\brief STK linear interpolating delay line class.
|
||||
|
||||
This Delay subclass implements a fractional-
|
||||
length digital delay-line using first-order
|
||||
linear interpolation. A fixed maximum length
|
||||
of 4095 and a delay of zero is set using the
|
||||
default constructor. Alternatively, the
|
||||
delay and maximum length can be set during
|
||||
instantiation with an overloaded constructor.
|
||||
|
||||
Linear interpolation is an efficient technique
|
||||
for achieving fractional delay lengths, though
|
||||
it does introduce high-frequency signal
|
||||
attenuation to varying degrees depending on the
|
||||
fractional delay setting. The use of higher
|
||||
order Lagrange interpolators can typically
|
||||
improve (minimize) this attenuation characteristic.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "DelayL.h"
|
||||
#include <iostream.h>
|
||||
|
||||
DelayL :: DelayL()
|
||||
{
|
||||
doNextOut = true;
|
||||
}
|
||||
|
||||
DelayL :: DelayL(MY_FLOAT theDelay, long maxDelay)
|
||||
{
|
||||
// Writing before reading allows delays from 0 to length-1.
|
||||
length = maxDelay+1;
|
||||
|
||||
if ( length > 4096 ) {
|
||||
// We need to delete the previously allocated inputs.
|
||||
delete [] inputs;
|
||||
inputs = new MY_FLOAT[length];
|
||||
this->clear();
|
||||
}
|
||||
|
||||
inPoint = 0;
|
||||
this->setDelay(theDelay);
|
||||
doNextOut = true;
|
||||
}
|
||||
|
||||
DelayL :: ~DelayL()
|
||||
{
|
||||
}
|
||||
|
||||
void DelayL :: setDelay(MY_FLOAT theDelay)
|
||||
{
|
||||
MY_FLOAT outPointer;
|
||||
|
||||
if (theDelay > length-1) {
|
||||
cerr << "DelayL: setDelay(" << theDelay << ") too big!" << endl;
|
||||
// Force delay to maxLength
|
||||
outPointer = inPoint + 1.0;
|
||||
delay = length - 1;
|
||||
}
|
||||
else if (theDelay < 0 ) {
|
||||
cerr << "DelayL: setDelay(" << theDelay << ") less than zero!" << endl;
|
||||
outPointer = inPoint;
|
||||
delay = 0;
|
||||
}
|
||||
else {
|
||||
outPointer = inPoint - theDelay; // read chases write
|
||||
delay = theDelay;
|
||||
}
|
||||
|
||||
while (outPointer < 0)
|
||||
outPointer += length; // modulo maximum length
|
||||
|
||||
outPoint = (long) outPointer; // integer part
|
||||
alpha = outPointer - outPoint; // fractional part
|
||||
omAlpha = (MY_FLOAT) 1.0 - alpha;
|
||||
}
|
||||
|
||||
MY_FLOAT DelayL :: getDelay(void) const
|
||||
{
|
||||
return delay;
|
||||
}
|
||||
|
||||
MY_FLOAT DelayL :: nextOut(void)
|
||||
{
|
||||
if ( doNextOut ) {
|
||||
// First 1/2 of interpolation
|
||||
nextOutput = inputs[outPoint] * omAlpha;
|
||||
// Second 1/2 of interpolation
|
||||
if (outPoint+1 < length)
|
||||
nextOutput += inputs[outPoint+1] * alpha;
|
||||
else
|
||||
nextOutput += inputs[0] * alpha;
|
||||
doNextOut = false;
|
||||
}
|
||||
|
||||
return nextOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT DelayL :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[inPoint++] = sample;
|
||||
|
||||
// Increment input pointer modulo length.
|
||||
if (inPoint == length)
|
||||
inPoint -= length;
|
||||
|
||||
outputs[0] = nextOut();
|
||||
doNextOut = true;
|
||||
|
||||
// Increment output pointer modulo length.
|
||||
if (++outPoint >= length)
|
||||
outPoint -= length;
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
@@ -125,7 +125,6 @@ void Drummer :: noteOn(MY_FLOAT instrument, MY_FLOAT amplitude)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char path[128];
|
||||
strcpy(path, RAWWAVE_PATH);
|
||||
strcat(path, "rawwaves/");
|
||||
strcat(path, waveNames[genMIDIMap[noteNum]]);
|
||||
waves[nSounding-1] = new WvIn(path, TRUE);
|
||||
if (Stk::sampleRate() != 22050.0)
|
||||
|
||||
228
src/Envelope.cpp
228
src/Envelope.cpp
@@ -1,114 +1,114 @@
|
||||
/***************************************************/
|
||||
/*! \class Envelope
|
||||
\brief STK envelope base class.
|
||||
|
||||
This class implements a simple envelope
|
||||
generator which is capable of ramping to
|
||||
a target value by a specified \e rate.
|
||||
It also responds to simple \e keyOn and
|
||||
\e keyOff messages, ramping to 1.0 on
|
||||
keyOn and to 0.0 on keyOff.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Envelope.h"
|
||||
#include <stdio.h>
|
||||
|
||||
Envelope :: Envelope(void) : Stk()
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
value = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 0.001;
|
||||
state = 0;
|
||||
}
|
||||
|
||||
Envelope :: ~Envelope(void)
|
||||
{
|
||||
}
|
||||
|
||||
void Envelope :: keyOn(void)
|
||||
{
|
||||
target = (MY_FLOAT) 1.0;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: keyOff(void)
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("Envelope: negative rates not allowed ... correcting!\n");
|
||||
rate = -aRate;
|
||||
}
|
||||
else
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
void Envelope :: setTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("Envelope: negative times not allowed ... correcting!\n");
|
||||
rate = 1.0 / (-aTime * Stk::sampleRate());
|
||||
}
|
||||
else
|
||||
rate = 1.0 / (aTime * Stk::sampleRate());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int Envelope :: getState(void) const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
MY_FLOAT Envelope :: tick(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
MY_FLOAT *Envelope :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
MY_FLOAT Envelope :: lastOut(void) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/*! \class Envelope
|
||||
\brief STK envelope base class.
|
||||
|
||||
This class implements a simple envelope
|
||||
generator which is capable of ramping to
|
||||
a target value by a specified \e rate.
|
||||
It also responds to simple \e keyOn and
|
||||
\e keyOff messages, ramping to 1.0 on
|
||||
keyOn and to 0.0 on keyOff.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Envelope.h"
|
||||
#include <stdio.h>
|
||||
|
||||
Envelope :: Envelope(void) : Stk()
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
value = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 0.001;
|
||||
state = 0;
|
||||
}
|
||||
|
||||
Envelope :: ~Envelope(void)
|
||||
{
|
||||
}
|
||||
|
||||
void Envelope :: keyOn(void)
|
||||
{
|
||||
target = (MY_FLOAT) 1.0;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: keyOff(void)
|
||||
{
|
||||
target = (MY_FLOAT) 0.0;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("Envelope: negative rates not allowed ... correcting!\n");
|
||||
rate = -aRate;
|
||||
}
|
||||
else
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
void Envelope :: setTime(MY_FLOAT aTime)
|
||||
{
|
||||
if (aTime < 0.0) {
|
||||
printf("Envelope: negative times not allowed ... correcting!\n");
|
||||
rate = 1.0 / (-aTime * Stk::sampleRate());
|
||||
}
|
||||
else
|
||||
rate = 1.0 / (aTime * Stk::sampleRate());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int Envelope :: getState(void) const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
MY_FLOAT Envelope :: tick(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
MY_FLOAT *Envelope :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
MY_FLOAT Envelope :: lastOut(void) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ FM :: FM(int operators)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file.
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE );
|
||||
vibrato = new WaveLoop( strcat(file,"sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency(6.0);
|
||||
|
||||
int i;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#include "FMVoices.h"
|
||||
#include "SKINI.msg"
|
||||
#include "phontabl.tbl"
|
||||
#include "Phonemes.h"
|
||||
#include <string.h>
|
||||
|
||||
FMVoices :: FMVoices()
|
||||
@@ -45,10 +45,10 @@ FMVoices :: FMVoices()
|
||||
for ( i=0; i<4; i++ )
|
||||
strcpy( files[i], RAWWAVE_PATH);
|
||||
|
||||
strcat(files[0], "rawwaves/sinewave.raw");
|
||||
strcat(files[1], "rawwaves/sinewave.raw");
|
||||
strcat(files[2], "rawwaves/sinewave.raw");
|
||||
strcat(files[3], "rawwaves/fwavblnk.raw");
|
||||
strcat(files[0], "sinewave.raw");
|
||||
strcat(files[1], "sinewave.raw");
|
||||
strcat(files[2], "sinewave.raw");
|
||||
strcat(files[3], "fwavblnk.raw");
|
||||
|
||||
for ( i=0; i<4; i++ )
|
||||
waves[i] = new WaveLoop( files[i], TRUE );
|
||||
@@ -82,40 +82,37 @@ FMVoices :: ~FMVoices()
|
||||
{
|
||||
}
|
||||
|
||||
extern double phonGains[32][2];
|
||||
extern double phonParams[32][4][3];
|
||||
extern char phonemes[32][4];
|
||||
|
||||
void FMVoices :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT temp, temp2 = 0.0;
|
||||
int tempi, tempi2 = 0;
|
||||
int tempi = 0;
|
||||
unsigned int i = 0;
|
||||
|
||||
if (currentVowel < 32) {
|
||||
tempi2 = currentVowel;
|
||||
i = currentVowel;
|
||||
temp2 = (MY_FLOAT) 0.9;
|
||||
}
|
||||
else if (currentVowel < 64) {
|
||||
tempi2 = currentVowel - 32;
|
||||
i = currentVowel - 32;
|
||||
temp2 = (MY_FLOAT) 1.0;
|
||||
}
|
||||
else if (currentVowel < 96) {
|
||||
tempi2 = currentVowel - 64;
|
||||
i = currentVowel - 64;
|
||||
temp2 = (MY_FLOAT) 1.1;
|
||||
}
|
||||
else if (currentVowel <= 128) {
|
||||
tempi2 = currentVowel - 96;
|
||||
i = currentVowel - 96;
|
||||
temp2 = (MY_FLOAT) 1.2;
|
||||
}
|
||||
|
||||
baseFrequency = frequency;
|
||||
temp = (temp2 * (MY_FLOAT) phonParams[tempi2][0][0] / baseFrequency) + 0.5;
|
||||
temp = (temp2 * Phonemes::formantFrequency(i, 0) / baseFrequency) + 0.5;
|
||||
tempi = (int) temp;
|
||||
this->setRatio(0,(MY_FLOAT) tempi);
|
||||
temp = (temp2 * (MY_FLOAT) phonParams[tempi2][1][0] / baseFrequency) + 0.5;
|
||||
temp = (temp2 * Phonemes::formantFrequency(i, 1) / baseFrequency) + 0.5;
|
||||
tempi = (int) temp;
|
||||
this->setRatio(1,(MY_FLOAT) tempi);
|
||||
temp = (temp2 * (MY_FLOAT) phonParams[tempi2][2][0] / baseFrequency) + 0.5;
|
||||
temp = (temp2 * Phonemes::formantFrequency(i, 2) / baseFrequency) + 0.5;
|
||||
tempi = (int) temp;
|
||||
this->setRatio(2, (MY_FLOAT) tempi);
|
||||
gains[0] = 1.0;
|
||||
@@ -174,7 +171,7 @@ void FMVoices :: controlChange(int number, MY_FLOAT value)
|
||||
|
||||
|
||||
if (number == __SK_Breath_) // 2
|
||||
gains[3] = __FM_gains[(int) ( norm * 100.0 )];
|
||||
gains[3] = __FM_gains[(int) ( norm * 99.9 )];
|
||||
else if (number == __SK_FootControl_) { // 4
|
||||
currentVowel = (int) (norm * 128.0);
|
||||
this->setFrequency(baseFrequency);
|
||||
|
||||
488
src/Filter.cpp
488
src/Filter.cpp
@@ -1,244 +1,244 @@
|
||||
/***************************************************/
|
||||
/*! \class Filter
|
||||
\brief STK filter class.
|
||||
|
||||
This class implements a generic structure which
|
||||
can be used to create a wide range of filters.
|
||||
It can function independently or be subclassed
|
||||
to provide more specific controls based on a
|
||||
particular filter type.
|
||||
|
||||
In particular, this class implements the standard
|
||||
difference equation:
|
||||
|
||||
a[0]*y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb] -
|
||||
a[1]*y[n-1] - ... - a[na]*y[n-na]
|
||||
|
||||
If a[0] is not equal to 1, the filter coeffcients
|
||||
are normalized by a[0].
|
||||
|
||||
The \e gain parameter is applied at the filter
|
||||
input and does not affect the coefficient values.
|
||||
The default gain value is 1.0. This structure
|
||||
results in one extra multiply per computed sample,
|
||||
but allows easy control of the overall filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Filter.h"
|
||||
#include <stdio.h>
|
||||
|
||||
Filter :: Filter()
|
||||
{
|
||||
// The default constructor should setup for pass-through.
|
||||
gain = 1.0;
|
||||
nB = 1;
|
||||
nA = 1;
|
||||
b = new MY_FLOAT[nB];
|
||||
b[0] = 1.0;
|
||||
a = new MY_FLOAT[nA];
|
||||
a[0] = 1.0;
|
||||
|
||||
inputs = new MY_FLOAT[nB];
|
||||
outputs = new MY_FLOAT[nA];
|
||||
this->clear();
|
||||
}
|
||||
|
||||
Filter :: Filter(int nb, MY_FLOAT *bCoefficients, int na, MY_FLOAT *aCoefficients)
|
||||
{
|
||||
char message[256];
|
||||
|
||||
// Check the arguments.
|
||||
if ( nb < 1 || na < 1 ) {
|
||||
sprintf(message, "Filter: nb (%d) and na (%d) must be >= 1!", nb, na);
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if ( aCoefficients[0] == 0.0 ) {
|
||||
sprintf(message, "Filter: a[0] coefficient cannot == 0!");
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
gain = 1.0;
|
||||
nB = nb;
|
||||
nA = na;
|
||||
b = new MY_FLOAT[nB];
|
||||
a = new MY_FLOAT[nA];
|
||||
|
||||
inputs = new MY_FLOAT[nB];
|
||||
outputs = new MY_FLOAT[nA];
|
||||
this->clear();
|
||||
|
||||
this->setCoefficients(nB, bCoefficients, nA, aCoefficients);
|
||||
}
|
||||
|
||||
Filter :: ~Filter()
|
||||
{
|
||||
delete [] b;
|
||||
delete [] a;
|
||||
delete [] inputs;
|
||||
delete [] outputs;
|
||||
}
|
||||
|
||||
void Filter :: clear(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<nB; i++)
|
||||
inputs[i] = 0.0;
|
||||
for (i=0; i<nA; i++)
|
||||
outputs[i] = 0.0;
|
||||
}
|
||||
|
||||
void Filter :: setCoefficients(int nb, MY_FLOAT *bCoefficients, int na, MY_FLOAT *aCoefficients)
|
||||
{
|
||||
int i;
|
||||
char message[256];
|
||||
|
||||
// Check the arguments.
|
||||
if ( nb < 1 || na < 1 ) {
|
||||
sprintf(message, "Filter: nb (%d) and na (%d) must be >= 1!", nb, na);
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if ( aCoefficients[0] == 0.0 ) {
|
||||
sprintf(message, "Filter: a[0] coefficient cannot == 0!");
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if (nb != nB) {
|
||||
delete [] b;
|
||||
delete [] inputs;
|
||||
nB = nb;
|
||||
b = new MY_FLOAT[nB];
|
||||
inputs = new MY_FLOAT[nB];
|
||||
for (i=0; i<nB; i++) inputs[i] = 0.0;
|
||||
}
|
||||
|
||||
if (na != nA) {
|
||||
delete [] a;
|
||||
delete [] outputs;
|
||||
nA = na;
|
||||
a = new MY_FLOAT[nA];
|
||||
outputs = new MY_FLOAT[nA];
|
||||
for (i=0; i<nA; i++) outputs[i] = 0.0;
|
||||
}
|
||||
|
||||
for (i=0; i<nB; i++)
|
||||
b[i] = bCoefficients[i];
|
||||
for (i=0; i<nA; i++)
|
||||
a[i] = aCoefficients[i];
|
||||
|
||||
// scale coefficients by a[0] if necessary
|
||||
if (a[0] != 1.0) {
|
||||
for (i=0; i<nB; i++)
|
||||
b[i] /= a[0];
|
||||
for (i=0; i<nA; i++)
|
||||
a[i] /= a[0];
|
||||
}
|
||||
}
|
||||
|
||||
void Filter :: setNumerator(int nb, MY_FLOAT *bCoefficients)
|
||||
{
|
||||
int i;
|
||||
char message[256];
|
||||
|
||||
// Check the arguments.
|
||||
if ( nb < 1 ) {
|
||||
sprintf(message, "Filter: nb (%d) must be >= 1!", nb);
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if (nb != nB) {
|
||||
delete [] b;
|
||||
delete [] inputs;
|
||||
nB = nb;
|
||||
b = new MY_FLOAT[nB];
|
||||
inputs = new MY_FLOAT[nB];
|
||||
for (i=0; i<nB; i++) inputs[i] = 0.0;
|
||||
}
|
||||
|
||||
for (i=0; i<nB; i++)
|
||||
b[i] = bCoefficients[i];
|
||||
}
|
||||
|
||||
void Filter :: setDenominator(int na, MY_FLOAT *aCoefficients)
|
||||
{
|
||||
int i;
|
||||
char message[256];
|
||||
|
||||
// Check the arguments.
|
||||
if ( na < 1 ) {
|
||||
sprintf(message, "Filter: na (%d) must be >= 1!", na);
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if ( aCoefficients[0] == 0.0 ) {
|
||||
sprintf(message, "Filter: a[0] coefficient cannot == 0!");
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if (na != nA) {
|
||||
delete [] a;
|
||||
delete [] outputs;
|
||||
nA = na;
|
||||
a = new MY_FLOAT[nA];
|
||||
outputs = new MY_FLOAT[nA];
|
||||
for (i=0; i<nA; i++) outputs[i] = 0.0;
|
||||
}
|
||||
|
||||
for (i=0; i<nA; i++)
|
||||
a[i] = aCoefficients[i];
|
||||
|
||||
// scale coefficients by a[0] if necessary
|
||||
if (a[0] != 1.0) {
|
||||
for (i=0; i<nB; i++)
|
||||
b[i] /= a[0];
|
||||
for (i=0; i<nA; i++)
|
||||
a[i] /= a[0];
|
||||
}
|
||||
}
|
||||
|
||||
void Filter :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
gain = theGain;
|
||||
}
|
||||
|
||||
MY_FLOAT Filter :: getGain(void) const
|
||||
{
|
||||
return gain;
|
||||
}
|
||||
|
||||
MY_FLOAT Filter :: lastOut(void) const
|
||||
{
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT Filter :: tick(MY_FLOAT sample)
|
||||
{
|
||||
int i;
|
||||
|
||||
outputs[0] = 0.0;
|
||||
inputs[0] = gain * sample;
|
||||
for (i=nB-1; i>0; i--) {
|
||||
outputs[0] += b[i] * inputs[i];
|
||||
inputs[i] = inputs[i-1];
|
||||
}
|
||||
outputs[0] += b[0] * inputs[0];
|
||||
|
||||
for (i=nA-1; i>0; i--) {
|
||||
outputs[0] += -a[i] * outputs[i];
|
||||
outputs[i] = outputs[i-1];
|
||||
}
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *Filter :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class Filter
|
||||
\brief STK filter class.
|
||||
|
||||
This class implements a generic structure which
|
||||
can be used to create a wide range of filters.
|
||||
It can function independently or be subclassed
|
||||
to provide more specific controls based on a
|
||||
particular filter type.
|
||||
|
||||
In particular, this class implements the standard
|
||||
difference equation:
|
||||
|
||||
a[0]*y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb] -
|
||||
a[1]*y[n-1] - ... - a[na]*y[n-na]
|
||||
|
||||
If a[0] is not equal to 1, the filter coeffcients
|
||||
are normalized by a[0].
|
||||
|
||||
The \e gain parameter is applied at the filter
|
||||
input and does not affect the coefficient values.
|
||||
The default gain value is 1.0. This structure
|
||||
results in one extra multiply per computed sample,
|
||||
but allows easy control of the overall filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Filter.h"
|
||||
#include <stdio.h>
|
||||
|
||||
Filter :: Filter()
|
||||
{
|
||||
// The default constructor should setup for pass-through.
|
||||
gain = 1.0;
|
||||
nB = 1;
|
||||
nA = 1;
|
||||
b = new MY_FLOAT[nB];
|
||||
b[0] = 1.0;
|
||||
a = new MY_FLOAT[nA];
|
||||
a[0] = 1.0;
|
||||
|
||||
inputs = new MY_FLOAT[nB];
|
||||
outputs = new MY_FLOAT[nA];
|
||||
this->clear();
|
||||
}
|
||||
|
||||
Filter :: Filter(int nb, MY_FLOAT *bCoefficients, int na, MY_FLOAT *aCoefficients)
|
||||
{
|
||||
char message[256];
|
||||
|
||||
// Check the arguments.
|
||||
if ( nb < 1 || na < 1 ) {
|
||||
sprintf(message, "Filter: nb (%d) and na (%d) must be >= 1!", nb, na);
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if ( aCoefficients[0] == 0.0 ) {
|
||||
sprintf(message, "Filter: a[0] coefficient cannot == 0!");
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
gain = 1.0;
|
||||
nB = nb;
|
||||
nA = na;
|
||||
b = new MY_FLOAT[nB];
|
||||
a = new MY_FLOAT[nA];
|
||||
|
||||
inputs = new MY_FLOAT[nB];
|
||||
outputs = new MY_FLOAT[nA];
|
||||
this->clear();
|
||||
|
||||
this->setCoefficients(nB, bCoefficients, nA, aCoefficients);
|
||||
}
|
||||
|
||||
Filter :: ~Filter()
|
||||
{
|
||||
delete [] b;
|
||||
delete [] a;
|
||||
delete [] inputs;
|
||||
delete [] outputs;
|
||||
}
|
||||
|
||||
void Filter :: clear(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<nB; i++)
|
||||
inputs[i] = 0.0;
|
||||
for (i=0; i<nA; i++)
|
||||
outputs[i] = 0.0;
|
||||
}
|
||||
|
||||
void Filter :: setCoefficients(int nb, MY_FLOAT *bCoefficients, int na, MY_FLOAT *aCoefficients)
|
||||
{
|
||||
int i;
|
||||
char message[256];
|
||||
|
||||
// Check the arguments.
|
||||
if ( nb < 1 || na < 1 ) {
|
||||
sprintf(message, "Filter: nb (%d) and na (%d) must be >= 1!", nb, na);
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if ( aCoefficients[0] == 0.0 ) {
|
||||
sprintf(message, "Filter: a[0] coefficient cannot == 0!");
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if (nb != nB) {
|
||||
delete [] b;
|
||||
delete [] inputs;
|
||||
nB = nb;
|
||||
b = new MY_FLOAT[nB];
|
||||
inputs = new MY_FLOAT[nB];
|
||||
for (i=0; i<nB; i++) inputs[i] = 0.0;
|
||||
}
|
||||
|
||||
if (na != nA) {
|
||||
delete [] a;
|
||||
delete [] outputs;
|
||||
nA = na;
|
||||
a = new MY_FLOAT[nA];
|
||||
outputs = new MY_FLOAT[nA];
|
||||
for (i=0; i<nA; i++) outputs[i] = 0.0;
|
||||
}
|
||||
|
||||
for (i=0; i<nB; i++)
|
||||
b[i] = bCoefficients[i];
|
||||
for (i=0; i<nA; i++)
|
||||
a[i] = aCoefficients[i];
|
||||
|
||||
// scale coefficients by a[0] if necessary
|
||||
if (a[0] != 1.0) {
|
||||
for (i=0; i<nB; i++)
|
||||
b[i] /= a[0];
|
||||
for (i=0; i<nA; i++)
|
||||
a[i] /= a[0];
|
||||
}
|
||||
}
|
||||
|
||||
void Filter :: setNumerator(int nb, MY_FLOAT *bCoefficients)
|
||||
{
|
||||
int i;
|
||||
char message[256];
|
||||
|
||||
// Check the arguments.
|
||||
if ( nb < 1 ) {
|
||||
sprintf(message, "Filter: nb (%d) must be >= 1!", nb);
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if (nb != nB) {
|
||||
delete [] b;
|
||||
delete [] inputs;
|
||||
nB = nb;
|
||||
b = new MY_FLOAT[nB];
|
||||
inputs = new MY_FLOAT[nB];
|
||||
for (i=0; i<nB; i++) inputs[i] = 0.0;
|
||||
}
|
||||
|
||||
for (i=0; i<nB; i++)
|
||||
b[i] = bCoefficients[i];
|
||||
}
|
||||
|
||||
void Filter :: setDenominator(int na, MY_FLOAT *aCoefficients)
|
||||
{
|
||||
int i;
|
||||
char message[256];
|
||||
|
||||
// Check the arguments.
|
||||
if ( na < 1 ) {
|
||||
sprintf(message, "Filter: na (%d) must be >= 1!", na);
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if ( aCoefficients[0] == 0.0 ) {
|
||||
sprintf(message, "Filter: a[0] coefficient cannot == 0!");
|
||||
handleError( message, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if (na != nA) {
|
||||
delete [] a;
|
||||
delete [] outputs;
|
||||
nA = na;
|
||||
a = new MY_FLOAT[nA];
|
||||
outputs = new MY_FLOAT[nA];
|
||||
for (i=0; i<nA; i++) outputs[i] = 0.0;
|
||||
}
|
||||
|
||||
for (i=0; i<nA; i++)
|
||||
a[i] = aCoefficients[i];
|
||||
|
||||
// scale coefficients by a[0] if necessary
|
||||
if (a[0] != 1.0) {
|
||||
for (i=0; i<nB; i++)
|
||||
b[i] /= a[0];
|
||||
for (i=0; i<nA; i++)
|
||||
a[i] /= a[0];
|
||||
}
|
||||
}
|
||||
|
||||
void Filter :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
gain = theGain;
|
||||
}
|
||||
|
||||
MY_FLOAT Filter :: getGain(void) const
|
||||
{
|
||||
return gain;
|
||||
}
|
||||
|
||||
MY_FLOAT Filter :: lastOut(void) const
|
||||
{
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT Filter :: tick(MY_FLOAT sample)
|
||||
{
|
||||
int i;
|
||||
|
||||
outputs[0] = 0.0;
|
||||
inputs[0] = gain * sample;
|
||||
for (i=nB-1; i>0; i--) {
|
||||
outputs[0] += b[i] * inputs[i];
|
||||
inputs[i] = inputs[i-1];
|
||||
}
|
||||
outputs[0] += b[0] * inputs[0];
|
||||
|
||||
for (i=nA-1; i>0; i--) {
|
||||
outputs[0] += -a[i] * outputs[i];
|
||||
outputs[i] = outputs[i-1];
|
||||
}
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *Filter :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ Flute :: Flute(MY_FLOAT lowestFrequency)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE );
|
||||
vibrato = new WaveLoop( strcat(file,"sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency( 5.925 );
|
||||
|
||||
this->clear();
|
||||
@@ -57,6 +57,7 @@ Flute :: Flute(MY_FLOAT lowestFrequency)
|
||||
jetRatio = (MY_FLOAT) 0.32;
|
||||
|
||||
maxPressure = (MY_FLOAT) 0.0;
|
||||
lastFrequency = 220.0;
|
||||
}
|
||||
|
||||
Flute :: ~Flute()
|
||||
@@ -184,7 +185,7 @@ void Flute :: controlChange(int number, MY_FLOAT value)
|
||||
}
|
||||
|
||||
if (number == __SK_JetDelay_) // 2
|
||||
this->setJetDelay( 0.08 + (0.48 * norm) );
|
||||
this->setJetDelay( (MY_FLOAT) (0.08 + (0.48 * norm)) );
|
||||
else if (number == __SK_NoiseLevel_) // 4
|
||||
noiseGain = ( norm * 0.4);
|
||||
else if (number == __SK_ModFrequency_) // 11
|
||||
|
||||
236
src/FormSwep.cpp
236
src/FormSwep.cpp
@@ -1,118 +1,118 @@
|
||||
/***************************************************/
|
||||
/*! \class FormSwep
|
||||
\brief STK sweepable formant filter class.
|
||||
|
||||
This public BiQuad filter subclass implements
|
||||
a formant (resonance) which can be "swept"
|
||||
over time from one frequency setting to another.
|
||||
It provides methods for controlling the sweep
|
||||
rate and target frequency.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "FormSwep.h"
|
||||
|
||||
FormSwep :: FormSwep() : BiQuad()
|
||||
{
|
||||
frequency = (MY_FLOAT) 0.0;
|
||||
radius = (MY_FLOAT) 0.0;
|
||||
targetGain = (MY_FLOAT) 1.0;
|
||||
targetFrequency = (MY_FLOAT) 0.0;
|
||||
targetRadius = (MY_FLOAT) 0.0;
|
||||
deltaGain = (MY_FLOAT) 0.0;
|
||||
deltaFrequency = (MY_FLOAT) 0.0;
|
||||
deltaRadius = (MY_FLOAT) 0.0;
|
||||
sweepState = (MY_FLOAT) 0.0;
|
||||
sweepRate = (MY_FLOAT) 0.002;
|
||||
dirty = false;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
FormSwep :: ~FormSwep()
|
||||
{
|
||||
}
|
||||
|
||||
void FormSwep :: setResonance(MY_FLOAT aFrequency, MY_FLOAT aRadius)
|
||||
{
|
||||
dirty = false;
|
||||
radius = aRadius;
|
||||
frequency = aFrequency;
|
||||
|
||||
BiQuad::setResonance( frequency, radius, true );
|
||||
}
|
||||
|
||||
void FormSwep :: setStates(MY_FLOAT aFrequency, MY_FLOAT aRadius, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = false;
|
||||
|
||||
if ( frequency != aFrequency || radius != aRadius )
|
||||
BiQuad::setResonance( aFrequency, aRadius, true );
|
||||
|
||||
frequency = aFrequency;
|
||||
radius = aRadius;
|
||||
gain = aGain;
|
||||
targetFrequency = aFrequency;
|
||||
targetRadius = aRadius;
|
||||
targetGain = aGain;
|
||||
}
|
||||
|
||||
void FormSwep :: setTargets(MY_FLOAT aFrequency, MY_FLOAT aRadius, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = true;
|
||||
startFrequency = frequency;
|
||||
startRadius = radius;
|
||||
startGain = gain;
|
||||
targetFrequency = aFrequency;
|
||||
targetRadius = aRadius;
|
||||
targetGain = aGain;
|
||||
deltaFrequency = aFrequency - frequency;
|
||||
deltaRadius = aRadius - radius;
|
||||
deltaGain = aGain - gain;
|
||||
sweepState = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setSweepRate(MY_FLOAT aRate)
|
||||
{
|
||||
sweepRate = aRate;
|
||||
if ( sweepRate > 1.0 ) sweepRate = 1.0;
|
||||
if ( sweepRate < 0.0 ) sweepRate = 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setSweepTime(MY_FLOAT aTime)
|
||||
{
|
||||
sweepRate = 1.0 / ( aTime * Stk::sampleRate() );
|
||||
if ( sweepRate > 1.0 ) sweepRate = 1.0;
|
||||
if ( sweepRate < 0.0 ) sweepRate = 0.0;
|
||||
}
|
||||
|
||||
MY_FLOAT FormSwep :: tick(MY_FLOAT sample)
|
||||
{
|
||||
if (dirty) {
|
||||
sweepState += sweepRate;
|
||||
if ( sweepState >= 1.0 ) {
|
||||
sweepState = (MY_FLOAT) 1.0;
|
||||
dirty = false;
|
||||
radius = targetRadius;
|
||||
frequency = targetFrequency;
|
||||
gain = targetGain;
|
||||
}
|
||||
else {
|
||||
radius = startRadius + (deltaRadius * sweepState);
|
||||
frequency = startFrequency + (deltaFrequency * sweepState);
|
||||
gain = startGain + (deltaGain * sweepState);
|
||||
}
|
||||
BiQuad::setResonance( frequency, radius, true );
|
||||
}
|
||||
|
||||
return BiQuad::tick( sample );
|
||||
}
|
||||
|
||||
MY_FLOAT *FormSwep :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class FormSwep
|
||||
\brief STK sweepable formant filter class.
|
||||
|
||||
This public BiQuad filter subclass implements
|
||||
a formant (resonance) which can be "swept"
|
||||
over time from one frequency setting to another.
|
||||
It provides methods for controlling the sweep
|
||||
rate and target frequency.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "FormSwep.h"
|
||||
|
||||
FormSwep :: FormSwep() : BiQuad()
|
||||
{
|
||||
frequency = (MY_FLOAT) 0.0;
|
||||
radius = (MY_FLOAT) 0.0;
|
||||
targetGain = (MY_FLOAT) 1.0;
|
||||
targetFrequency = (MY_FLOAT) 0.0;
|
||||
targetRadius = (MY_FLOAT) 0.0;
|
||||
deltaGain = (MY_FLOAT) 0.0;
|
||||
deltaFrequency = (MY_FLOAT) 0.0;
|
||||
deltaRadius = (MY_FLOAT) 0.0;
|
||||
sweepState = (MY_FLOAT) 0.0;
|
||||
sweepRate = (MY_FLOAT) 0.002;
|
||||
dirty = false;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
FormSwep :: ~FormSwep()
|
||||
{
|
||||
}
|
||||
|
||||
void FormSwep :: setResonance(MY_FLOAT aFrequency, MY_FLOAT aRadius)
|
||||
{
|
||||
dirty = false;
|
||||
radius = aRadius;
|
||||
frequency = aFrequency;
|
||||
|
||||
BiQuad::setResonance( frequency, radius, true );
|
||||
}
|
||||
|
||||
void FormSwep :: setStates(MY_FLOAT aFrequency, MY_FLOAT aRadius, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = false;
|
||||
|
||||
if ( frequency != aFrequency || radius != aRadius )
|
||||
BiQuad::setResonance( aFrequency, aRadius, true );
|
||||
|
||||
frequency = aFrequency;
|
||||
radius = aRadius;
|
||||
gain = aGain;
|
||||
targetFrequency = aFrequency;
|
||||
targetRadius = aRadius;
|
||||
targetGain = aGain;
|
||||
}
|
||||
|
||||
void FormSwep :: setTargets(MY_FLOAT aFrequency, MY_FLOAT aRadius, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = true;
|
||||
startFrequency = frequency;
|
||||
startRadius = radius;
|
||||
startGain = gain;
|
||||
targetFrequency = aFrequency;
|
||||
targetRadius = aRadius;
|
||||
targetGain = aGain;
|
||||
deltaFrequency = aFrequency - frequency;
|
||||
deltaRadius = aRadius - radius;
|
||||
deltaGain = aGain - gain;
|
||||
sweepState = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setSweepRate(MY_FLOAT aRate)
|
||||
{
|
||||
sweepRate = aRate;
|
||||
if ( sweepRate > 1.0 ) sweepRate = 1.0;
|
||||
if ( sweepRate < 0.0 ) sweepRate = 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setSweepTime(MY_FLOAT aTime)
|
||||
{
|
||||
sweepRate = 1.0 / ( aTime * Stk::sampleRate() );
|
||||
if ( sweepRate > 1.0 ) sweepRate = 1.0;
|
||||
if ( sweepRate < 0.0 ) sweepRate = 0.0;
|
||||
}
|
||||
|
||||
MY_FLOAT FormSwep :: tick(MY_FLOAT sample)
|
||||
{
|
||||
if (dirty) {
|
||||
sweepState += sweepRate;
|
||||
if ( sweepState >= 1.0 ) {
|
||||
sweepState = (MY_FLOAT) 1.0;
|
||||
dirty = false;
|
||||
radius = targetRadius;
|
||||
frequency = targetFrequency;
|
||||
gain = targetGain;
|
||||
}
|
||||
else {
|
||||
radius = startRadius + (deltaRadius * sweepState);
|
||||
frequency = startFrequency + (deltaFrequency * sweepState);
|
||||
gain = startGain + (deltaGain * sweepState);
|
||||
}
|
||||
BiQuad::setResonance( frequency, radius, true );
|
||||
}
|
||||
|
||||
return BiQuad::tick( sample );
|
||||
}
|
||||
|
||||
MY_FLOAT *FormSwep :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -39,10 +39,10 @@ HevyMetl :: HevyMetl()
|
||||
for ( i=0; i<4; i++ )
|
||||
strcpy( files[i], RAWWAVE_PATH);
|
||||
|
||||
strcat(files[0], "rawwaves/sinewave.raw");
|
||||
strcat(files[1], "rawwaves/sinewave.raw");
|
||||
strcat(files[2], "rawwaves/sinewave.raw");
|
||||
strcat(files[3], "rawwaves/fwavblnk.raw");
|
||||
strcat(files[0], "sinewave.raw");
|
||||
strcat(files[1], "sinewave.raw");
|
||||
strcat(files[2], "sinewave.raw");
|
||||
strcat(files[3], "fwavblnk.raw");
|
||||
|
||||
for ( i=0; i<4; i++ )
|
||||
waves[i] = new WaveLoop( files[i], TRUE );
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
/***************************************************/
|
||||
/*! \class Instrmnt
|
||||
\brief STK instrument abstract base class.
|
||||
|
||||
This class provides a common interface for
|
||||
all STK instruments.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Instrmnt.h"
|
||||
|
||||
Instrmnt :: Instrmnt()
|
||||
{
|
||||
}
|
||||
|
||||
Instrmnt :: ~Instrmnt()
|
||||
{
|
||||
}
|
||||
|
||||
void Instrmnt :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
cerr << "Instrmnt: virtual setFrequency function call!" << endl;
|
||||
}
|
||||
|
||||
MY_FLOAT Instrmnt :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *Instrmnt :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
void Instrmnt :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class Instrmnt
|
||||
\brief STK instrument abstract base class.
|
||||
|
||||
This class provides a common interface for
|
||||
all STK instruments.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Instrmnt.h"
|
||||
|
||||
Instrmnt :: Instrmnt()
|
||||
{
|
||||
}
|
||||
|
||||
Instrmnt :: ~Instrmnt()
|
||||
{
|
||||
}
|
||||
|
||||
void Instrmnt :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
cerr << "Instrmnt: virtual setFrequency function call!" << endl;
|
||||
}
|
||||
|
||||
MY_FLOAT Instrmnt :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *Instrmnt :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
void Instrmnt :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
}
|
||||
|
||||
106
src/JetTabl.cpp
106
src/JetTabl.cpp
@@ -1,53 +1,53 @@
|
||||
/***************************************************/
|
||||
/*! \class JetTabl
|
||||
\brief STK jet table class.
|
||||
|
||||
This class implements a flue jet non-linear
|
||||
function, computed by a polynomial calculation.
|
||||
Contrary to the name, this is not a "table".
|
||||
|
||||
Consult Fletcher and Rossing, Karjalainen,
|
||||
Cook, and others for more information.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "JetTabl.h"
|
||||
|
||||
JetTabl :: JetTabl()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
JetTabl :: ~JetTabl()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: tick( MY_FLOAT input )
|
||||
{
|
||||
// Perform "table lookup" using a polynomial
|
||||
// calculation (x^3 - x), which approximates
|
||||
// the jet sigmoid behavior.
|
||||
lastOutput = input * (input * input - (MY_FLOAT) 1.0);
|
||||
|
||||
// Saturate at +/- 1.0.
|
||||
if (lastOutput > 1.0)
|
||||
lastOutput = (MY_FLOAT) 1.0;
|
||||
if (lastOutput < -1.0)
|
||||
lastOutput = (MY_FLOAT) -1.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *JetTabl :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class JetTabl
|
||||
\brief STK jet table class.
|
||||
|
||||
This class implements a flue jet non-linear
|
||||
function, computed by a polynomial calculation.
|
||||
Contrary to the name, this is not a "table".
|
||||
|
||||
Consult Fletcher and Rossing, Karjalainen,
|
||||
Cook, and others for more information.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "JetTabl.h"
|
||||
|
||||
JetTabl :: JetTabl()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
JetTabl :: ~JetTabl()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: tick( MY_FLOAT input )
|
||||
{
|
||||
// Perform "table lookup" using a polynomial
|
||||
// calculation (x^3 - x), which approximates
|
||||
// the jet sigmoid behavior.
|
||||
lastOutput = input * (input * input - (MY_FLOAT) 1.0);
|
||||
|
||||
// Saturate at +/- 1.0.
|
||||
if (lastOutput > 1.0)
|
||||
lastOutput = (MY_FLOAT) 1.0;
|
||||
if (lastOutput < -1.0)
|
||||
lastOutput = (MY_FLOAT) -1.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *JetTabl :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
53
src/Makefile
53
src/Makefile
@@ -1,53 +0,0 @@
|
||||
# libstk Makefile - for Linux or SGI with GNU Makefile utilities
|
||||
|
||||
LIBRARY = libstk.a
|
||||
AR = ar -qsc
|
||||
RM = /bin/rm
|
||||
INCLUDE = -I../include
|
||||
|
||||
OS = $(shell uname)
|
||||
|
||||
O_FILES = Stk.o Noise.o SubNoise.o Envelope.o ADSR.o \
|
||||
Filter.o OneZero.o OnePole.o PoleZero.o \
|
||||
TwoZero.o TwoPole.o BiQuad.o FormSwep.o \
|
||||
Delay.o DelayL.o DelayA.o \
|
||||
Reverb.o PRCRev.o JCRev.o NRev.o \
|
||||
Table.o JetTabl.o ReedTabl.o BowTabl.o Modulate.o \
|
||||
WvIn.o WaveLoop.o WvOut.o \
|
||||
Chorus.o Echo.o PitShift.o \
|
||||
RtAudio.o RtWvOut.o RtWvIn.o RtDuplex.o \
|
||||
Socket.o Thread.o TcpWvOut.o TcpWvIn.o \
|
||||
\
|
||||
Instrmnt.o Clarinet.o BlowHole.o Saxofony.o Flute.o Brass.o BlowBotl.o \
|
||||
Bowed.o Plucked.o StifKarp.o Sitar.o PluckTwo.o Mandolin.o \
|
||||
FM.o Rhodey.o Wurley.o TubeBell.o HevyMetl.o PercFlut.o BeeThree.o FMVoices.o \
|
||||
Sampler.o Moog.o Simple.o Drummer.o Shakers.o Modal.o ModalBar.o BandedWG.o \
|
||||
Mesh2D.o Resonate.o SKINI.o Messager.o RtMidi.o
|
||||
|
||||
ifeq ($(OS),IRIX) # These are for SGI
|
||||
CC = CC -D__OS_IRIX__
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Linux) # These are for Linux
|
||||
ifeq ($(strip $(SOUNDDRIVER)),)
|
||||
SOUNDDRIVER = __LINUX_OSS__
|
||||
endif
|
||||
ifeq ($(strip $(RAWWAVES)),)
|
||||
RAWWAVES = "../../"
|
||||
endif
|
||||
CC = g++ -O3 -Wall -D__LITTLE_ENDIAN__ -D$(SOUNDDRIVER) -DRAWWAVE_PATH=$(RAWWAVES)
|
||||
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)
|
||||
70
src/Makefile.in
Normal file
70
src/Makefile.in
Normal file
@@ -0,0 +1,70 @@
|
||||
### libstk Makefile - for various flavors of unix
|
||||
|
||||
LIBRARY = libstk.a
|
||||
AR = ar -qc
|
||||
RM = /bin/rm
|
||||
OBJECT_PATH = @object_path@
|
||||
vpath %.o $(OBJECT_PATH)
|
||||
|
||||
OBJECTS = Stk.o Noise.o SubNoise.o Envelope.o ADSR.o \
|
||||
WvIn.o WaveLoop.o WvOut.o \
|
||||
Filter.o OneZero.o OnePole.o PoleZero.o TwoZero.o TwoPole.o \
|
||||
BiQuad.o FormSwep.o Delay.o DelayL.o DelayA.o \
|
||||
Reverb.o PRCRev.o JCRev.o NRev.o \
|
||||
Chorus.o Echo.o PitShift.o \
|
||||
Table.o ReedTabl.o JetTabl.o BowTabl.o \
|
||||
Modulate.o SingWave.o Voicer.o \
|
||||
Vector3D.o Sphere.o \
|
||||
\
|
||||
Instrmnt.o Clarinet.o BlowHole.o Saxofony.o Flute.o Brass.o BlowBotl.o \
|
||||
Bowed.o Plucked.o StifKarp.o Sitar.o PluckTwo.o Mandolin.o Mesh2D.o \
|
||||
FM.o Rhodey.o Wurley.o TubeBell.o HevyMetl.o PercFlut.o BeeThree.o FMVoices.o \
|
||||
Sampler.o Moog.o Simple.o Drummer.o Shakers.o \
|
||||
Modal.o ModalBar.o BandedWG.o Resonate.o VoicForm.o Phonemes.o Whistle.o \
|
||||
\
|
||||
Messager.o SKINI.o
|
||||
|
||||
|
||||
INCLUDE = @include@
|
||||
ifeq ($(strip $(INCLUDE)),)
|
||||
vpath %.h ../include
|
||||
INCLUDE = -I../include
|
||||
else
|
||||
vpath %.h ../include $(INCLUDE)
|
||||
INCLUDE = -I../include -I@include@
|
||||
endif
|
||||
|
||||
CC = @CXX@
|
||||
DEFS = @byte_order@
|
||||
DEFS += @debug@
|
||||
CFLAGS = @cflags@
|
||||
CFLAGS += @warn@ $(INCLUDE)
|
||||
|
||||
REALTIME = @realtime@
|
||||
ifeq ($(REALTIME),yes)
|
||||
OBJECTS += RtMidi.o RtAudio.o RtWvOut.o RtWvIn.o TcpWvOut.o TcpWvIn.o Thread.o Socket.o
|
||||
DEFS += @sound_api@
|
||||
DEFS += @midiator@
|
||||
endif
|
||||
|
||||
RAWWAVES = @rawwaves@
|
||||
ifeq ($(strip $(RAWWAVES)), )
|
||||
RAWWAVES = ../rawwaves/
|
||||
endif
|
||||
DEFS += -DRAWWAVE_PATH=\"$(RAWWAVES)\"
|
||||
|
||||
%.o : %.cpp
|
||||
$(CC) $(CFLAGS) $(DEFS) -c $(<) -o $(OBJECT_PATH)/$@
|
||||
|
||||
all : $(LIBRARY)
|
||||
|
||||
$(LIBRARY) : $(OBJECTS)
|
||||
/bin/rm -f $(LIBRARY)
|
||||
$(AR) $(LIBRARY) $(OBJECT_PATH)/*.o
|
||||
ranlib $(LIBRARY)
|
||||
|
||||
$(OBJECTS) : Stk.h
|
||||
|
||||
clean :
|
||||
-rm $(OBJECT_PATH)/*.o
|
||||
-rm $(LIBRARY)
|
||||
@@ -38,29 +38,29 @@ Mandolin :: Mandolin(MY_FLOAT lowestFrequency)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char temp[128];
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[0] = new WvIn( strcat(temp,"rawwaves/mand1.raw"), TRUE );
|
||||
soundfile[0] = new WvIn( strcat(temp,"mand1.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[1] = new WvIn( strcat(temp,"rawwaves/mand2.raw"), TRUE );
|
||||
soundfile[1] = new WvIn( strcat(temp,"mand2.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[2] = new WvIn( strcat(temp,"rawwaves/mand3.raw"), TRUE );
|
||||
soundfile[2] = new WvIn( strcat(temp,"mand3.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[3] = new WvIn( strcat(temp,"rawwaves/mand4.raw"), TRUE );
|
||||
soundfile[3] = new WvIn( strcat(temp,"mand4.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[4] = new WvIn( strcat(temp,"rawwaves/mand5.raw"), TRUE );
|
||||
soundfile[4] = new WvIn( strcat(temp,"mand5.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[5] = new WvIn( strcat(temp,"rawwaves/mand6.raw"), TRUE );
|
||||
soundfile[5] = new WvIn( strcat(temp,"mand6.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[6] = new WvIn( strcat(temp,"rawwaves/mand7.raw"), TRUE );
|
||||
soundfile[6] = new WvIn( strcat(temp,"mand7.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[7] = new WvIn( strcat(temp,"rawwaves/mand8.raw"), TRUE );
|
||||
soundfile[7] = new WvIn( strcat(temp,"mand8.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[8] = new WvIn( strcat(temp,"rawwaves/mand9.raw"), TRUE );
|
||||
soundfile[8] = new WvIn( strcat(temp,"mand9.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[9] = new WvIn( strcat(temp,"rawwaves/mand10.raw"), TRUE );
|
||||
soundfile[9] = new WvIn( strcat(temp,"mand10.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[10] = new WvIn( strcat(temp,"rawwaves/mand11.raw"), TRUE );
|
||||
soundfile[10] = new WvIn( strcat(temp,"mand11.raw"), TRUE );
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
soundfile[11] = new WvIn( strcat(temp,"rawwaves/mand12.raw"), TRUE );
|
||||
soundfile[11] = new WvIn( strcat(temp,"mand12.raw"), TRUE );
|
||||
directBody = 1.0;
|
||||
mic = 0;
|
||||
dampTime = 0;
|
||||
|
||||
779
src/Messager.cpp
779
src/Messager.cpp
@@ -1,385 +1,394 @@
|
||||
/***************************************************/
|
||||
/*! \class Messager
|
||||
\brief STK input control message parser.
|
||||
|
||||
This class reads and parses control messages
|
||||
from a variety of sources, such as a MIDI
|
||||
port, scorefile, socket connection, or pipe.
|
||||
MIDI messages are retrieved using the RtMidi
|
||||
class. All other input sources (scorefile,
|
||||
socket, or pipe) are assumed to provide SKINI
|
||||
formatted messages.
|
||||
|
||||
For each call to nextMessage(), the active
|
||||
input sources are queried to see if a new
|
||||
control message is available.
|
||||
|
||||
This class is primarily for use in STK main()
|
||||
event loops.
|
||||
|
||||
One of the 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 sends these
|
||||
messages via a socket connection to the
|
||||
message socket server. Perhaps in the future,
|
||||
it will be possible to simplify things.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Messager.h"
|
||||
#include <string.h>
|
||||
#include <iostream.h>
|
||||
|
||||
#define STK_MIDI 0x0001
|
||||
#define STK_PIPE 0x0002
|
||||
#define STK_SOCKET 0x0004
|
||||
|
||||
#define STK_SOCKET_PORT 2001
|
||||
|
||||
Messager :: Messager(int inputMask)
|
||||
{
|
||||
sources = inputMask;
|
||||
rtDelta = RT_BUFFER_SIZE;
|
||||
messageIndex = 0;
|
||||
nMessages = 0;
|
||||
skini = new SKINI();
|
||||
|
||||
#if defined(__STK_REALTIME__)
|
||||
// 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 if 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,
|
||||
// which sends its data via a socket connection to the socket
|
||||
// server.
|
||||
if ( sources ) {
|
||||
|
||||
if ( sources & STK_MIDI )
|
||||
midi = new RtMidi();
|
||||
|
||||
// If STK_PIPE is not specified, let the users know they can exit
|
||||
// the program via the console if necessary.
|
||||
if ( !(sources & STK_PIPE) && sources )
|
||||
cout << "\nType `Exit<cr>' to quit.\n" << endl;
|
||||
|
||||
sources |= STK_SOCKET;
|
||||
soket = new Socket(STK_SOCKET_PORT);
|
||||
if (inputMask & STK_SOCKET)
|
||||
printf("\nSocket server listening for connection(s) on port %d ...\n\n", STK_SOCKET_PORT);
|
||||
|
||||
nSockets = 0;
|
||||
maxfd = 0;
|
||||
FD_ZERO(&mask);
|
||||
int d = soket->socket();
|
||||
FD_SET(d, &mask);
|
||||
if (d > maxfd) maxfd = d;
|
||||
|
||||
// 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;
|
||||
|
||||
// Start the stdin input thread.
|
||||
thread = new Thread();
|
||||
if ( !thread->start( (THREAD_FUNCTION)&stdinHandler, NULL ) ) {
|
||||
sprintf(error, "Messager: Unable to start stdin input thread!");
|
||||
handleError( error, StkError::PROCESS_THREAD );
|
||||
}
|
||||
}
|
||||
#endif // __STK_REALTIME__
|
||||
}
|
||||
|
||||
Messager :: ~Messager()
|
||||
{
|
||||
delete skini;
|
||||
|
||||
#if defined(__STK_REALTIME__)
|
||||
|
||||
if ( sources & STK_MIDI )
|
||||
delete midi;
|
||||
|
||||
if ( sources & STK_SOCKET ) {
|
||||
delete soket;
|
||||
delete thread;
|
||||
}
|
||||
#endif // __STK_REALTIME__
|
||||
}
|
||||
|
||||
long Messager :: getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
MY_FLOAT Messager :: getByteTwo() const
|
||||
{
|
||||
return byte2;
|
||||
}
|
||||
|
||||
MY_FLOAT Messager :: getByteThree() const
|
||||
{
|
||||
return byte3;
|
||||
}
|
||||
|
||||
long Messager :: getChannel() const
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
void Messager :: setRtDelta(long nSamples)
|
||||
{
|
||||
if ( nSamples > 0 )
|
||||
rtDelta = nSamples;
|
||||
else
|
||||
cerr << "Messager: setRtDelta(" << nSamples << ") less than or equal to zero!" << endl;
|
||||
}
|
||||
|
||||
long Messager :: getDelta() const
|
||||
{
|
||||
return delta;
|
||||
}
|
||||
|
||||
long Messager :: nextMessage()
|
||||
{
|
||||
if (nMessages > 0 ) nMessages--;
|
||||
type = 0;
|
||||
|
||||
if ( !sources ) {
|
||||
// No realtime flags ... assuming scorefile input.
|
||||
memset(message[messageIndex], 0, MESSAGE_LENGTH);
|
||||
if ( fgets(message[messageIndex], MESSAGE_LENGTH, stdin) == 0 ) {
|
||||
delta = 0;
|
||||
return -1; // end of file
|
||||
}
|
||||
nMessages++;
|
||||
}
|
||||
#if defined(__STK_REALTIME__)
|
||||
else if (nMessages == 0) {
|
||||
if ( midiMessage() ) return type;
|
||||
if ( !socketMessage() ) return type;
|
||||
}
|
||||
#endif
|
||||
|
||||
skini->parseThis(message[messageIndex++]);
|
||||
if (messageIndex >= MAX_MESSAGES) messageIndex = 0;
|
||||
type = skini->getType();
|
||||
if (type <= 0) {
|
||||
// Don't tick for comments or improperly formatted messages.
|
||||
nMessages--;
|
||||
delta = 0;
|
||||
type = 0;
|
||||
return type;
|
||||
}
|
||||
|
||||
channel = skini->getChannel();
|
||||
byte2 = skini->getByteTwo();
|
||||
byte3 = skini->getByteThree();
|
||||
|
||||
MY_FLOAT temp = skini->getDelta();
|
||||
if ( temp >= 0.0 )
|
||||
delta = (long) (temp * Stk::sampleRate());
|
||||
else
|
||||
// Ignore negative delta times (absolute time).
|
||||
delta = rtDelta;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
#if defined(__STK_REALTIME__)
|
||||
bool Messager :: midiMessage( void )
|
||||
{
|
||||
if (sources & STK_MIDI) {
|
||||
if ( midi->nextMessage() > 0 ) {
|
||||
// get MIDI message info
|
||||
type = midi->getType();
|
||||
channel = midi->getChannel();
|
||||
byte2 = midi->getByteTwo();
|
||||
byte3 = midi->getByteThree();
|
||||
nMessages++;
|
||||
delta = rtDelta;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Messager :: socketMessage()
|
||||
{
|
||||
register fd_set rmask;
|
||||
static struct timeval timeout = {0, 0};
|
||||
|
||||
rmask = mask;
|
||||
if ( select(maxfd+1, &rmask, (fd_set *)0, (fd_set *)0, &timeout) ) {
|
||||
// A file descriptor is set.
|
||||
|
||||
// Check if there's a new socket connection available.
|
||||
if ( FD_ISSET(soket->socket(), &rmask) ) {
|
||||
// Accept and service new connection.
|
||||
int newfd = soket->accept();
|
||||
if ( newfd < 0 ) {
|
||||
sprintf(error, "Messager: Couldn't accept connection request!");
|
||||
handleError(error, StkError::WARNING);
|
||||
}
|
||||
|
||||
// We assume the first connection will occur for the stdin
|
||||
// thread socket. Since this connection is "hidden" from
|
||||
// the user, only print connected messages for subsequent
|
||||
// connections.
|
||||
if (nSockets == 0)
|
||||
pipefd = newfd;
|
||||
else
|
||||
cout << "New socket connection made.\n" << endl;
|
||||
|
||||
// Set the socket to non-blocking mode.
|
||||
Socket::setBlocking( newfd, false );
|
||||
|
||||
// Save the descriptor and update the masks.
|
||||
fd[nSockets++] = newfd;
|
||||
FD_SET(newfd, &mask);
|
||||
if ( newfd > maxfd) maxfd = newfd;
|
||||
FD_CLR(soket->socket(), &rmask);
|
||||
}
|
||||
|
||||
// Check client socket connections.
|
||||
unsigned int client = 0;
|
||||
while ( client < nSockets ) {
|
||||
if ( !FD_ISSET(fd[client], &rmask) )
|
||||
client++;
|
||||
else {
|
||||
// This connection has data.
|
||||
if ( !readSocket( fd[client] ) ) {
|
||||
// The socket connection closed.
|
||||
nSockets--;
|
||||
if ( nSockets == 0 ) {
|
||||
type = -1;
|
||||
return false;
|
||||
}
|
||||
if ( nSockets == 1 && FD_ISSET(pipefd, &mask) ) {
|
||||
// The "piping" socket is still running.
|
||||
if (sources & STK_MIDI) {
|
||||
cout << "MIDI input still running ... type 'Exit<cr>' to quit.\n" << endl;
|
||||
}
|
||||
else if (!(sources & STK_PIPE) ) {
|
||||
// The user didn't specify this connection, so quit now.
|
||||
type = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (client < nSockets) {
|
||||
// Move descriptors down in the list.
|
||||
for (unsigned int j=client; j<nSockets; j++)
|
||||
fd[j] = fd[j+1];
|
||||
}
|
||||
delta = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !strncmp(message[messageIndex], "Exit", 4) || !strncmp(message[messageIndex], "exit", 4) ) {
|
||||
// We have an "Exit" message ... don't try to parse it.
|
||||
messageIndex++;
|
||||
nMessages--;
|
||||
delta = 0;
|
||||
return false;
|
||||
}
|
||||
// Not an "Exit" message ... parse it.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, we checked all devices but found no messages.
|
||||
delta = rtDelta;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#endif
|
||||
|
||||
bool Messager :: readSocket(int fd)
|
||||
{
|
||||
// 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.
|
||||
char buffer[MESSAGE_LENGTH];
|
||||
int index = 0, m = 0, bufferSize = 0;
|
||||
int nextMessage;
|
||||
|
||||
nextMessage = (messageIndex + nMessages) % MAX_MESSAGES;
|
||||
memset(message[nextMessage], 0, MESSAGE_LENGTH);
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
errno = 0;
|
||||
while (bufferSize != -1 && errno != EAGAIN) {
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
while (bufferSize != SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) {
|
||||
#endif
|
||||
while (index < bufferSize) {
|
||||
message[nextMessage][m++] = buffer[index];
|
||||
if (buffer[index++] == '\n') {
|
||||
m = 0;
|
||||
nMessages++;
|
||||
nextMessage = (messageIndex + nMessages) % MAX_MESSAGES;
|
||||
memset(message[nextMessage], 0, MESSAGE_LENGTH);
|
||||
}
|
||||
}
|
||||
index = 0;
|
||||
|
||||
// Receive a new socket buffer.
|
||||
memset(buffer, 0, MESSAGE_LENGTH);
|
||||
bufferSize = Socket::readBuffer(fd, buffer, MESSAGE_LENGTH, 0);
|
||||
if (bufferSize == 0) {
|
||||
FD_CLR(fd, &mask);
|
||||
Socket::close( fd );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
THREAD_RETURN THREAD_TYPE stdinHandler(void *)
|
||||
{
|
||||
char message[MESSAGE_LENGTH];
|
||||
|
||||
Socket *s;
|
||||
try {
|
||||
s = new Socket( STK_SOCKET_PORT, "localhost" );
|
||||
}
|
||||
catch (StkError &) {
|
||||
fprintf(stderr, "Messager: Couldn't create stdin input thread!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 ( s->writeBuffer( (void *)message, strlen(message), 0) < 0 ) {
|
||||
fprintf(stderr, "Messager: stdin thread connection to socket server failed!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete s;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // __STK_REALTIME__
|
||||
/***************************************************/
|
||||
/*! \class Messager
|
||||
\brief STK input control message parser.
|
||||
|
||||
This class reads and parses control messages
|
||||
from a variety of sources, such as a MIDI
|
||||
port, scorefile, socket connection, or pipe.
|
||||
MIDI messages are retrieved using the RtMidi
|
||||
class. All other input sources (scorefile,
|
||||
socket, or pipe) are assumed to provide SKINI
|
||||
formatted messages.
|
||||
|
||||
For each call to nextMessage(), the active
|
||||
input sources are queried to see if a new
|
||||
control message is available.
|
||||
|
||||
This class is primarily for use in STK main()
|
||||
event loops.
|
||||
|
||||
One of the 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 sends these
|
||||
messages via a socket connection to the
|
||||
message socket server. Perhaps in the future,
|
||||
it will be possible to simplify things.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Messager.h"
|
||||
#include <string.h>
|
||||
#include <iostream.h>
|
||||
|
||||
int socket_port = 2001;
|
||||
|
||||
Messager :: Messager(int inputMask, int port)
|
||||
{
|
||||
sources = inputMask;
|
||||
rtDelta = RT_BUFFER_SIZE;
|
||||
messageIndex = 0;
|
||||
nMessages = 0;
|
||||
skini = new SKINI();
|
||||
|
||||
#if defined(__STK_REALTIME__)
|
||||
// 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 if 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,
|
||||
// which sends its data via a socket connection to the socket
|
||||
// server.
|
||||
if ( sources ) {
|
||||
|
||||
if ( sources & STK_MIDI ) {
|
||||
// Attempt to open a MIDI device, but don't throw an exception
|
||||
// if other input sources are specified.
|
||||
try {
|
||||
midi = new RtMidi();
|
||||
}
|
||||
catch (StkError &exception) {
|
||||
if ( sources == STK_MIDI ) {
|
||||
throw exception;
|
||||
}
|
||||
// Disable the MIDI input and keep going.
|
||||
sources &= ~STK_MIDI;
|
||||
}
|
||||
}
|
||||
|
||||
// If STK_PIPE is not specified, let the users know they can exit
|
||||
// the program via the console if necessary.
|
||||
if ( !(sources & STK_PIPE) && sources )
|
||||
cout << "\nType `Exit<cr>' to quit.\n" << endl;
|
||||
|
||||
sources |= STK_SOCKET;
|
||||
socket_port = port;
|
||||
soket = new Socket(port);
|
||||
if (inputMask & STK_SOCKET)
|
||||
printf("\nSocket server listening for connection(s) on port %d ...\n\n", port);
|
||||
|
||||
nSockets = 0;
|
||||
maxfd = 0;
|
||||
FD_ZERO(&mask);
|
||||
int d = soket->socket();
|
||||
FD_SET(d, &mask);
|
||||
if (d > maxfd) maxfd = d;
|
||||
|
||||
// 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;
|
||||
|
||||
// Start the stdin input thread.
|
||||
thread = new Thread();
|
||||
if ( !thread->start( (THREAD_FUNCTION)&stdinHandler, NULL ) ) {
|
||||
sprintf(error, "Messager: Unable to start stdin input thread!");
|
||||
handleError( error, StkError::PROCESS_THREAD );
|
||||
}
|
||||
}
|
||||
#endif // __STK_REALTIME__
|
||||
}
|
||||
|
||||
Messager :: ~Messager()
|
||||
{
|
||||
delete skini;
|
||||
|
||||
#if defined(__STK_REALTIME__)
|
||||
|
||||
if ( sources & STK_MIDI )
|
||||
delete midi;
|
||||
|
||||
if ( sources & STK_SOCKET ) {
|
||||
delete soket;
|
||||
delete thread;
|
||||
}
|
||||
#endif // __STK_REALTIME__
|
||||
}
|
||||
|
||||
long Messager :: getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
MY_FLOAT Messager :: getByteTwo() const
|
||||
{
|
||||
return byte2;
|
||||
}
|
||||
|
||||
MY_FLOAT Messager :: getByteThree() const
|
||||
{
|
||||
return byte3;
|
||||
}
|
||||
|
||||
long Messager :: getChannel() const
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
void Messager :: setRtDelta(long nSamples)
|
||||
{
|
||||
if ( nSamples > 0 )
|
||||
rtDelta = nSamples;
|
||||
else
|
||||
cerr << "Messager: setRtDelta(" << nSamples << ") less than or equal to zero!" << endl;
|
||||
}
|
||||
|
||||
long Messager :: getDelta() const
|
||||
{
|
||||
return delta;
|
||||
}
|
||||
|
||||
long Messager :: nextMessage()
|
||||
{
|
||||
if (nMessages > 0 ) nMessages--;
|
||||
type = 0;
|
||||
|
||||
if ( !sources ) {
|
||||
// No realtime flags ... assuming scorefile input.
|
||||
memset(message[messageIndex], 0, MESSAGE_LENGTH);
|
||||
if ( fgets(message[messageIndex], MESSAGE_LENGTH, stdin) == 0 ) {
|
||||
delta = 0;
|
||||
return -1; // end of file
|
||||
}
|
||||
nMessages++;
|
||||
}
|
||||
#if defined(__STK_REALTIME__)
|
||||
else if (nMessages == 0) {
|
||||
if ( midiMessage() ) return type;
|
||||
if ( !socketMessage() ) return type;
|
||||
}
|
||||
#endif
|
||||
|
||||
skini->parseThis(message[messageIndex++]);
|
||||
if (messageIndex >= MAX_MESSAGES) messageIndex = 0;
|
||||
type = skini->getType();
|
||||
if (type <= 0) {
|
||||
// Don't tick for comments or improperly formatted messages.
|
||||
nMessages--;
|
||||
delta = 0;
|
||||
type = 0;
|
||||
return type;
|
||||
}
|
||||
|
||||
channel = skini->getChannel();
|
||||
byte2 = skini->getByteTwo();
|
||||
byte3 = skini->getByteThree();
|
||||
|
||||
MY_FLOAT temp = skini->getDelta();
|
||||
if ( temp >= 0.0 )
|
||||
delta = (long) (temp * Stk::sampleRate());
|
||||
else
|
||||
// Ignore negative delta times (absolute time).
|
||||
delta = rtDelta;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
#if defined(__STK_REALTIME__)
|
||||
bool Messager :: midiMessage( void )
|
||||
{
|
||||
if (sources & STK_MIDI) {
|
||||
if ( midi->nextMessage() > 0 ) {
|
||||
// get MIDI message info
|
||||
type = midi->getType();
|
||||
channel = midi->getChannel();
|
||||
byte2 = midi->getByteTwo();
|
||||
byte3 = midi->getByteThree();
|
||||
nMessages++;
|
||||
delta = rtDelta;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Messager :: socketMessage()
|
||||
{
|
||||
register fd_set rmask;
|
||||
static struct timeval timeout = {0, 0};
|
||||
|
||||
rmask = mask;
|
||||
if ( select(maxfd+1, &rmask, (fd_set *)0, (fd_set *)0, &timeout) ) {
|
||||
// A file descriptor is set.
|
||||
|
||||
// Check if there's a new socket connection available.
|
||||
if ( FD_ISSET(soket->socket(), &rmask) ) {
|
||||
// Accept and service new connection.
|
||||
int newfd = soket->accept();
|
||||
if ( newfd < 0 ) {
|
||||
sprintf(error, "Messager: Couldn't accept connection request!");
|
||||
handleError(error, StkError::WARNING);
|
||||
}
|
||||
|
||||
// We assume the first connection will occur for the stdin
|
||||
// thread socket. Since this connection is "hidden" from
|
||||
// the user, only print connected messages for subsequent
|
||||
// connections.
|
||||
if (nSockets == 0)
|
||||
pipefd = newfd;
|
||||
else
|
||||
cout << "New socket connection made.\n" << endl;
|
||||
|
||||
// Set the socket to non-blocking mode.
|
||||
Socket::setBlocking( newfd, false );
|
||||
|
||||
// Save the descriptor and update the masks.
|
||||
fd[nSockets++] = newfd;
|
||||
FD_SET(newfd, &mask);
|
||||
if ( newfd > maxfd) maxfd = newfd;
|
||||
FD_CLR(soket->socket(), &rmask);
|
||||
}
|
||||
|
||||
// Check client socket connections.
|
||||
unsigned int client = 0;
|
||||
while ( client < nSockets ) {
|
||||
if ( !FD_ISSET(fd[client], &rmask) )
|
||||
client++;
|
||||
else {
|
||||
// This connection has data.
|
||||
if ( !readSocket( fd[client] ) ) {
|
||||
// The socket connection closed.
|
||||
nSockets--;
|
||||
if ( nSockets == 0 ) {
|
||||
type = -1;
|
||||
return false;
|
||||
}
|
||||
if ( nSockets == 1 && FD_ISSET(pipefd, &mask) ) {
|
||||
// The "piping" socket is still running.
|
||||
if (sources & STK_MIDI) {
|
||||
cout << "MIDI input still running ... type 'Exit<cr>' to quit.\n" << endl;
|
||||
}
|
||||
else if (!(sources & STK_PIPE) ) {
|
||||
// The user didn't specify this connection, so quit now.
|
||||
type = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (client < nSockets) {
|
||||
// Move descriptors down in the list.
|
||||
for (unsigned int j=client; j<nSockets; j++)
|
||||
fd[j] = fd[j+1];
|
||||
}
|
||||
delta = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !strncmp(message[messageIndex], "Exit", 4) || !strncmp(message[messageIndex], "exit", 4) ) {
|
||||
// We have an "Exit" message ... don't try to parse it.
|
||||
messageIndex++;
|
||||
nMessages--;
|
||||
delta = 0;
|
||||
return false;
|
||||
}
|
||||
// Not an "Exit" message ... parse it.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, we checked all devices but found no messages.
|
||||
delta = rtDelta;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#endif
|
||||
|
||||
bool Messager :: readSocket(int fd)
|
||||
{
|
||||
// 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.
|
||||
char buffer[MESSAGE_LENGTH];
|
||||
int index = 0, m = 0, bufferSize = 0;
|
||||
int nextMessage;
|
||||
|
||||
nextMessage = (messageIndex + nMessages) % MAX_MESSAGES;
|
||||
memset(message[nextMessage], 0, MESSAGE_LENGTH);
|
||||
|
||||
#if ( defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__) )
|
||||
errno = 0;
|
||||
while (bufferSize != -1 && errno != EAGAIN) {
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
while (bufferSize != SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) {
|
||||
#endif
|
||||
while (index < bufferSize) {
|
||||
message[nextMessage][m++] = buffer[index];
|
||||
if (buffer[index++] == '\n') {
|
||||
m = 0;
|
||||
nMessages++;
|
||||
nextMessage = (messageIndex + nMessages) % MAX_MESSAGES;
|
||||
memset(message[nextMessage], 0, MESSAGE_LENGTH);
|
||||
}
|
||||
}
|
||||
index = 0;
|
||||
|
||||
// Receive a new socket buffer.
|
||||
memset(buffer, 0, MESSAGE_LENGTH);
|
||||
bufferSize = Socket::readBuffer(fd, buffer, MESSAGE_LENGTH, 0);
|
||||
if (bufferSize == 0) {
|
||||
FD_CLR(fd, &mask);
|
||||
Socket::close( fd );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
THREAD_RETURN THREAD_TYPE stdinHandler(void *)
|
||||
{
|
||||
char message[MESSAGE_LENGTH];
|
||||
|
||||
Socket *s;
|
||||
try {
|
||||
s = new Socket( socket_port, "localhost" );
|
||||
}
|
||||
catch (StkError &) {
|
||||
fprintf(stderr, "Messager: Couldn't create stdin input thread!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 ( s->writeBuffer( (void *)message, strlen(message), 0) < 0 ) {
|
||||
fprintf(stderr, "Messager: stdin thread connection to socket server failed!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete s;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // __STK_REALTIME__
|
||||
|
||||
@@ -41,7 +41,7 @@ Modal :: Modal(int modes)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE);
|
||||
vibrato = new WaveLoop( strcat(file,"sinewave.raw"), TRUE);
|
||||
|
||||
// Set some default values.
|
||||
vibrato->setFrequency( 6.0 );
|
||||
|
||||
@@ -39,7 +39,7 @@ ModalBar :: ModalBar()
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
wave = new WvIn( strcat(file,"rawwaves/marmstk1.raw"), TRUE );
|
||||
wave = new WvIn( strcat(file,"marmstk1.raw"), TRUE );
|
||||
wave->setRate((MY_FLOAT) 0.5 * 22050.0 / Stk::sampleRate() );
|
||||
|
||||
// Set the resonances for preset 0 (marimba).
|
||||
|
||||
@@ -18,7 +18,7 @@ Modulate :: Modulate()
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE );
|
||||
vibrato = new WaveLoop( strcat(file,"sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency( 6.0 );
|
||||
vibratoGain = 0.04;
|
||||
|
||||
@@ -57,7 +57,7 @@ void Modulate :: setRandomGain(MY_FLOAT aGain)
|
||||
filter->setGain( randomGain );
|
||||
}
|
||||
|
||||
MY_FLOAT Modulate :: tick()
|
||||
MY_FLOAT Modulate :: tick()
|
||||
{
|
||||
// Compute periodic and random modulations.
|
||||
lastOutput = vibratoGain * vibrato->tick();
|
||||
@@ -65,6 +65,14 @@ MY_FLOAT Modulate :: tick()
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *Modulate :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
MY_FLOAT Modulate :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
|
||||
@@ -30,11 +30,11 @@ Moog :: Moog()
|
||||
char file[128];
|
||||
strcpy(temp, RAWWAVE_PATH);
|
||||
strcpy(file,temp);
|
||||
attacks[0] = new WvIn( strcat(file,"rawwaves/mandpluk.raw"), TRUE );
|
||||
attacks[0] = new WvIn( strcat(file,"mandpluk.raw"), TRUE );
|
||||
strcpy(file,temp);
|
||||
loops[0] = new WaveLoop( strcat(file,"rawwaves/impuls20.raw"), TRUE );
|
||||
loops[0] = new WaveLoop( strcat(file,"impuls20.raw"), TRUE );
|
||||
strcpy(file,temp);
|
||||
loops[1] = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE ); // vibrato
|
||||
loops[1] = new WaveLoop( strcat(file,"sinewave.raw"), TRUE ); // vibrato
|
||||
loops[1]->setFrequency((MY_FLOAT) 6.122);
|
||||
|
||||
filters[0] = new FormSwep();
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
/***************************************************/
|
||||
/*! \class Noise
|
||||
\brief STK noise generator.
|
||||
|
||||
Generic random number generation using the
|
||||
C rand() function. The quality of the rand()
|
||||
function varies from one OS to another.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Noise.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
Noise :: Noise() : Stk()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
Noise :: ~Noise()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Noise :: tick()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) (2.0 * rand() / (RAND_MAX + 1.0) );
|
||||
lastOutput -= 1.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *Noise :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
MY_FLOAT Noise :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/*! \class Noise
|
||||
\brief STK noise generator.
|
||||
|
||||
Generic random number generation using the
|
||||
C rand() function. The quality of the rand()
|
||||
function varies from one OS to another.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Noise.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
Noise :: Noise() : Stk()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
Noise :: ~Noise()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Noise :: tick()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) (2.0 * rand() / (RAND_MAX + 1.0) );
|
||||
lastOutput -= 1.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *Noise :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
MY_FLOAT Noise :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
|
||||
198
src/OnePole.cpp
198
src/OnePole.cpp
@@ -1,99 +1,99 @@
|
||||
/***************************************************/
|
||||
/*! \class OnePole
|
||||
\brief STK one-pole filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a one-pole digital filter. A method is
|
||||
provided for setting the pole position along
|
||||
the real axis of the z-plane while maintaining
|
||||
a constant peak filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "OnePole.h"
|
||||
|
||||
OnePole :: OnePole() : Filter()
|
||||
{
|
||||
MY_FLOAT B = 0.1;
|
||||
MY_FLOAT A[2] = {1.0, -0.9};
|
||||
Filter::setCoefficients( 1, &B, 2, A );
|
||||
}
|
||||
|
||||
OnePole :: OnePole(MY_FLOAT thePole) : Filter()
|
||||
{
|
||||
MY_FLOAT B;
|
||||
MY_FLOAT A[2] = {1.0, -0.9};
|
||||
|
||||
// Normalize coefficients for peak unity gain.
|
||||
if (thePole > 0.0)
|
||||
B = (MY_FLOAT) (1.0 - thePole);
|
||||
else
|
||||
B = (MY_FLOAT) (1.0 + thePole);
|
||||
|
||||
A[1] = -thePole;
|
||||
Filter::setCoefficients( 1, &B, 2, A );
|
||||
}
|
||||
|
||||
OnePole :: ~OnePole()
|
||||
{
|
||||
}
|
||||
|
||||
void OnePole :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void OnePole :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void OnePole :: setA1(MY_FLOAT a1)
|
||||
{
|
||||
a[1] = a1;
|
||||
}
|
||||
|
||||
void OnePole :: setPole(MY_FLOAT thePole)
|
||||
{
|
||||
// Normalize coefficients for peak unity gain.
|
||||
if (thePole > 0.0)
|
||||
b[0] = (MY_FLOAT) (1.0 - thePole);
|
||||
else
|
||||
b[0] = (MY_FLOAT) (1.0 + thePole);
|
||||
|
||||
a[1] = -thePole;
|
||||
}
|
||||
|
||||
void OnePole :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT OnePole :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT OnePole :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT OnePole :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[0] * inputs[0] - a[1] * outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *OnePole :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class OnePole
|
||||
\brief STK one-pole filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a one-pole digital filter. A method is
|
||||
provided for setting the pole position along
|
||||
the real axis of the z-plane while maintaining
|
||||
a constant peak filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "OnePole.h"
|
||||
|
||||
OnePole :: OnePole() : Filter()
|
||||
{
|
||||
MY_FLOAT B = 0.1;
|
||||
MY_FLOAT A[2] = {1.0, -0.9};
|
||||
Filter::setCoefficients( 1, &B, 2, A );
|
||||
}
|
||||
|
||||
OnePole :: OnePole(MY_FLOAT thePole) : Filter()
|
||||
{
|
||||
MY_FLOAT B;
|
||||
MY_FLOAT A[2] = {1.0, -0.9};
|
||||
|
||||
// Normalize coefficients for peak unity gain.
|
||||
if (thePole > 0.0)
|
||||
B = (MY_FLOAT) (1.0 - thePole);
|
||||
else
|
||||
B = (MY_FLOAT) (1.0 + thePole);
|
||||
|
||||
A[1] = -thePole;
|
||||
Filter::setCoefficients( 1, &B, 2, A );
|
||||
}
|
||||
|
||||
OnePole :: ~OnePole()
|
||||
{
|
||||
}
|
||||
|
||||
void OnePole :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void OnePole :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void OnePole :: setA1(MY_FLOAT a1)
|
||||
{
|
||||
a[1] = a1;
|
||||
}
|
||||
|
||||
void OnePole :: setPole(MY_FLOAT thePole)
|
||||
{
|
||||
// Normalize coefficients for peak unity gain.
|
||||
if (thePole > 0.0)
|
||||
b[0] = (MY_FLOAT) (1.0 - thePole);
|
||||
else
|
||||
b[0] = (MY_FLOAT) (1.0 + thePole);
|
||||
|
||||
a[1] = -thePole;
|
||||
}
|
||||
|
||||
void OnePole :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT OnePole :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT OnePole :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT OnePole :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[0] * inputs[0] - a[1] * outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *OnePole :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
198
src/OneZero.cpp
198
src/OneZero.cpp
@@ -1,99 +1,99 @@
|
||||
/***************************************************/
|
||||
/*! \class OneZero
|
||||
\brief STK one-zero filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a one-zero digital filter. A method is
|
||||
provided for setting the zero position
|
||||
along the real axis of the z-plane while
|
||||
maintaining a constant filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "OneZero.h"
|
||||
|
||||
OneZero :: OneZero() : Filter()
|
||||
{
|
||||
MY_FLOAT B[2] = {0.5, 0.5};
|
||||
MY_FLOAT A = 1.0;
|
||||
Filter::setCoefficients( 2, B, 1, &A );
|
||||
}
|
||||
|
||||
OneZero :: OneZero(MY_FLOAT theZero) : Filter()
|
||||
{
|
||||
MY_FLOAT B[2];
|
||||
MY_FLOAT A = 1.0;
|
||||
|
||||
// Normalize coefficients for unity gain.
|
||||
if (theZero > 0.0)
|
||||
B[0] = 1.0 / ((MY_FLOAT) 1.0 + theZero);
|
||||
else
|
||||
B[0] = 1.0 / ((MY_FLOAT) 1.0 - theZero);
|
||||
|
||||
B[1] = -theZero * B[0];
|
||||
Filter::setCoefficients( 2, B, 1, &A );
|
||||
}
|
||||
|
||||
OneZero :: ~OneZero(void)
|
||||
{
|
||||
}
|
||||
|
||||
void OneZero :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void OneZero :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void OneZero :: setB1(MY_FLOAT b1)
|
||||
{
|
||||
b[1] = b1;
|
||||
}
|
||||
|
||||
void OneZero :: setZero(MY_FLOAT theZero)
|
||||
{
|
||||
// Normalize coefficients for unity gain.
|
||||
if (theZero > 0.0)
|
||||
b[0] = 1.0 / ((MY_FLOAT) 1.0 + theZero);
|
||||
else
|
||||
b[0] = 1.0 / ((MY_FLOAT) 1.0 - theZero);
|
||||
|
||||
b[1] = -theZero * b[0];
|
||||
}
|
||||
|
||||
void OneZero :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT OneZero :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT OneZero :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT OneZero :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[1] * inputs[1] + b[0] * inputs[0];
|
||||
inputs[1] = inputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *OneZero :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class OneZero
|
||||
\brief STK one-zero filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a one-zero digital filter. A method is
|
||||
provided for setting the zero position
|
||||
along the real axis of the z-plane while
|
||||
maintaining a constant filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "OneZero.h"
|
||||
|
||||
OneZero :: OneZero() : Filter()
|
||||
{
|
||||
MY_FLOAT B[2] = {0.5, 0.5};
|
||||
MY_FLOAT A = 1.0;
|
||||
Filter::setCoefficients( 2, B, 1, &A );
|
||||
}
|
||||
|
||||
OneZero :: OneZero(MY_FLOAT theZero) : Filter()
|
||||
{
|
||||
MY_FLOAT B[2];
|
||||
MY_FLOAT A = 1.0;
|
||||
|
||||
// Normalize coefficients for unity gain.
|
||||
if (theZero > 0.0)
|
||||
B[0] = 1.0 / ((MY_FLOAT) 1.0 + theZero);
|
||||
else
|
||||
B[0] = 1.0 / ((MY_FLOAT) 1.0 - theZero);
|
||||
|
||||
B[1] = -theZero * B[0];
|
||||
Filter::setCoefficients( 2, B, 1, &A );
|
||||
}
|
||||
|
||||
OneZero :: ~OneZero(void)
|
||||
{
|
||||
}
|
||||
|
||||
void OneZero :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void OneZero :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void OneZero :: setB1(MY_FLOAT b1)
|
||||
{
|
||||
b[1] = b1;
|
||||
}
|
||||
|
||||
void OneZero :: setZero(MY_FLOAT theZero)
|
||||
{
|
||||
// Normalize coefficients for unity gain.
|
||||
if (theZero > 0.0)
|
||||
b[0] = 1.0 / ((MY_FLOAT) 1.0 + theZero);
|
||||
else
|
||||
b[0] = 1.0 / ((MY_FLOAT) 1.0 - theZero);
|
||||
|
||||
b[1] = -theZero * b[0];
|
||||
}
|
||||
|
||||
void OneZero :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT OneZero :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT OneZero :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT OneZero :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[1] * inputs[1] + b[0] * inputs[0];
|
||||
inputs[1] = inputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *OneZero :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -39,10 +39,10 @@ PercFlut :: PercFlut()
|
||||
for ( i=0; i<4; i++ )
|
||||
strcpy( files[i], RAWWAVE_PATH);
|
||||
|
||||
strcat(files[0], "rawwaves/sinewave.raw");
|
||||
strcat(files[1], "rawwaves/sinewave.raw");
|
||||
strcat(files[2], "rawwaves/sinewave.raw");
|
||||
strcat(files[3], "rawwaves/fwavblnk.raw");
|
||||
strcat(files[0], "sinewave.raw");
|
||||
strcat(files[1], "sinewave.raw");
|
||||
strcat(files[2], "sinewave.raw");
|
||||
strcat(files[3], "fwavblnk.raw");
|
||||
|
||||
for ( i=0; i<4; i++ )
|
||||
waves[i] = new WaveLoop( files[i], TRUE );
|
||||
|
||||
279
src/Phonemes.cpp
Normal file
279
src/Phonemes.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
/***************************************************/
|
||||
/*! \class Phonemes
|
||||
\brief STK phonemes table.
|
||||
|
||||
This class does nothing other than declare a
|
||||
set of 32 static phoneme formant parameters
|
||||
and provide access to those values.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Phonemes.h"
|
||||
#include <iostream.h>
|
||||
|
||||
const char Phonemes :: phonemeNames[32][4] =
|
||||
{"eee", "ihh", "ehh", "aaa",
|
||||
"ahh", "aww", "ohh", "uhh",
|
||||
"uuu", "ooo", "rrr", "lll",
|
||||
"mmm", "nnn", "nng", "ngg",
|
||||
"fff", "sss", "thh", "shh",
|
||||
"xxx", "hee", "hoo", "hah",
|
||||
"bbb", "ddd", "jjj", "ggg",
|
||||
"vvv", "zzz", "thz", "zhh"
|
||||
};
|
||||
|
||||
const MY_FLOAT Phonemes :: phonemeGains[32][2] =
|
||||
{{1.0, 0.0}, // eee
|
||||
{1.0, 0.0}, // ihh
|
||||
{1.0, 0.0}, // ehh
|
||||
{1.0, 0.0}, // aaa
|
||||
|
||||
{1.0, 0.0}, // ahh
|
||||
{1.0, 0.0}, // aww
|
||||
{1.0, 0.0}, // ohh
|
||||
{1.0, 0.0}, // uhh
|
||||
|
||||
{1.0, 0.0}, // uuu
|
||||
{1.0, 0.0}, // ooo
|
||||
{1.0, 0.0}, // rrr
|
||||
{1.0, 0.0}, // lll
|
||||
|
||||
{1.0, 0.0}, // mmm
|
||||
{1.0, 0.0}, // nnn
|
||||
{1.0, 0.0}, // nng
|
||||
{1.0, 0.0}, // ngg
|
||||
|
||||
{0.0, 0.7}, // fff
|
||||
{0.0, 0.7}, // sss
|
||||
{0.0, 0.7}, // thh
|
||||
{0.0, 0.7}, // shh
|
||||
|
||||
{0.0, 0.7}, // xxx
|
||||
{0.0, 0.1}, // hee
|
||||
{0.0, 0.1}, // hoo
|
||||
{0.0, 0.1}, // hah
|
||||
|
||||
{1.0, 0.1}, // bbb
|
||||
{1.0, 0.1}, // ddd
|
||||
{1.0, 0.1}, // jjj
|
||||
{1.0, 0.1}, // ggg
|
||||
|
||||
{1.0, 1.0}, // vvv
|
||||
{1.0, 1.0}, // zzz
|
||||
{1.0, 1.0}, // thz
|
||||
{1.0, 1.0} // zhh
|
||||
};
|
||||
|
||||
const MY_FLOAT Phonemes :: phonemeParameters[32][4][3] =
|
||||
{{ { 273, 0.996, 10}, // eee (beet)
|
||||
{2086, 0.945, -16},
|
||||
{2754, 0.979, -12},
|
||||
{3270, 0.440, -17}},
|
||||
{ { 385, 0.987, 10}, // ihh (bit)
|
||||
{2056, 0.930, -20},
|
||||
{2587, 0.890, -20},
|
||||
{3150, 0.400, -20}},
|
||||
{ { 515, 0.977, 10}, // ehh (bet)
|
||||
{1805, 0.810, -10},
|
||||
{2526, 0.875, -10},
|
||||
{3103, 0.400, -13}},
|
||||
{ { 773, 0.950, 10}, // aaa (bat)
|
||||
{1676, 0.830, -6},
|
||||
{2380, 0.880, -20},
|
||||
{3027, 0.600, -20}},
|
||||
|
||||
{ { 770, 0.950, 0}, // ahh (father)
|
||||
{1153, 0.970, -9},
|
||||
{2450, 0.780, -29},
|
||||
{3140, 0.800, -39}},
|
||||
{ { 637, 0.910, 0}, // aww (bought)
|
||||
{ 895, 0.900, -3},
|
||||
{2556, 0.950, -17},
|
||||
{3070, 0.910, -20}},
|
||||
{ { 637, 0.910, 0}, // ohh (bone) NOTE:: same as aww (bought)
|
||||
{ 895, 0.900, -3},
|
||||
{2556, 0.950, -17},
|
||||
{3070, 0.910, -20}},
|
||||
{ { 561, 0.965, 0}, // uhh (but)
|
||||
{1084, 0.930, -10},
|
||||
{2541, 0.930, -15},
|
||||
{3345, 0.900, -20}},
|
||||
|
||||
{ { 515, 0.976, 0}, // uuu (foot)
|
||||
{1031, 0.950, -3},
|
||||
{2572, 0.960, -11},
|
||||
{3345, 0.960, -20}},
|
||||
{ { 349, 0.986, -10}, // ooo (boot)
|
||||
{ 918, 0.940, -20},
|
||||
{2350, 0.960, -27},
|
||||
{2731, 0.950, -33}},
|
||||
{ { 394, 0.959, -10}, // rrr (bird)
|
||||
{1297, 0.780, -16},
|
||||
{1441, 0.980, -16},
|
||||
{2754, 0.950, -40}},
|
||||
{ { 462, 0.990, +5}, // lll (lull)
|
||||
{1200, 0.640, -10},
|
||||
{2500, 0.200, -20},
|
||||
{3000, 0.100, -30}},
|
||||
|
||||
{ { 265, 0.987, -10}, // mmm (mom)
|
||||
{1176, 0.940, -22},
|
||||
{2352, 0.970, -20},
|
||||
{3277, 0.940, -31}},
|
||||
{ { 204, 0.980, -10}, // nnn (nun)
|
||||
{1570, 0.940, -15},
|
||||
{2481, 0.980, -12},
|
||||
{3133, 0.800, -30}},
|
||||
{ { 204, 0.980, -10}, // nng (sang) NOTE:: same as nnn
|
||||
{1570, 0.940, -15},
|
||||
{2481, 0.980, -12},
|
||||
{3133, 0.800, -30}},
|
||||
{ { 204, 0.980, -10}, // ngg (bong) NOTE:: same as nnn
|
||||
{1570, 0.940, -15},
|
||||
{2481, 0.980, -12},
|
||||
{3133, 0.800, -30}},
|
||||
|
||||
{ {1000, 0.300, 0}, // fff
|
||||
{2800, 0.860, -10},
|
||||
{7425, 0.740, 0},
|
||||
{8140, 0.860, 0}},
|
||||
{ {0, 0.000, 0}, // sss
|
||||
{2000, 0.700, -15},
|
||||
{5257, 0.750, -3},
|
||||
{7171, 0.840, 0}},
|
||||
{ { 100, 0.900, 0}, // thh
|
||||
{4000, 0.500, -20},
|
||||
{5500, 0.500, -15},
|
||||
{8000, 0.400, -20}},
|
||||
{ {2693, 0.940, 0}, // shh
|
||||
{4000, 0.720, -10},
|
||||
{6123, 0.870, -10},
|
||||
{7755, 0.750, -18}},
|
||||
|
||||
{ {1000, 0.300, -10}, // xxx NOTE:: Not Really Done Yet
|
||||
{2800, 0.860, -10},
|
||||
{7425, 0.740, 0},
|
||||
{8140, 0.860, 0}},
|
||||
{ { 273, 0.996, -40}, // hee (beet) (noisy eee)
|
||||
{2086, 0.945, -16},
|
||||
{2754, 0.979, -12},
|
||||
{3270, 0.440, -17}},
|
||||
{ { 349, 0.986, -40}, // hoo (boot) (noisy ooo)
|
||||
{ 918, 0.940, -10},
|
||||
{2350, 0.960, -17},
|
||||
{2731, 0.950, -23}},
|
||||
{ { 770, 0.950, -40}, // hah (father) (noisy ahh)
|
||||
{1153, 0.970, -3},
|
||||
{2450, 0.780, -20},
|
||||
{3140, 0.800, -32}},
|
||||
|
||||
{ {2000, 0.700, -20}, // bbb NOTE:: Not Really Done Yet
|
||||
{5257, 0.750, -15},
|
||||
{7171, 0.840, -3},
|
||||
{9000, 0.900, 0}},
|
||||
{ { 100, 0.900, 0}, // ddd NOTE:: Not Really Done Yet
|
||||
{4000, 0.500, -20},
|
||||
{5500, 0.500, -15},
|
||||
{8000, 0.400, -20}},
|
||||
{ {2693, 0.940, 0}, // jjj NOTE:: Not Really Done Yet
|
||||
{4000, 0.720, -10},
|
||||
{6123, 0.870, -10},
|
||||
{7755, 0.750, -18}},
|
||||
{ {2693, 0.940, 0}, // ggg NOTE:: Not Really Done Yet
|
||||
{4000, 0.720, -10},
|
||||
{6123, 0.870, -10},
|
||||
{7755, 0.750, -18}},
|
||||
|
||||
{ {2000, 0.700, -20}, // vvv NOTE:: Not Really Done Yet
|
||||
{5257, 0.750, -15},
|
||||
{7171, 0.840, -3},
|
||||
{9000, 0.900, 0}},
|
||||
{ { 100, 0.900, 0}, // zzz NOTE:: Not Really Done Yet
|
||||
{4000, 0.500, -20},
|
||||
{5500, 0.500, -15},
|
||||
{8000, 0.400, -20}},
|
||||
{ {2693, 0.940, 0}, // thz NOTE:: Not Really Done Yet
|
||||
{4000, 0.720, -10},
|
||||
{6123, 0.870, -10},
|
||||
{7755, 0.750, -18}},
|
||||
{ {2693, 0.940, 0}, // zhh NOTE:: Not Really Done Yet
|
||||
{4000, 0.720, -10},
|
||||
{6123, 0.870, -10},
|
||||
{7755, 0.750, -18}}
|
||||
};
|
||||
|
||||
Phonemes :: Phonemes(void)
|
||||
{
|
||||
}
|
||||
|
||||
Phonemes :: ~Phonemes(void)
|
||||
{
|
||||
}
|
||||
|
||||
const char *Phonemes :: name( unsigned int index )
|
||||
{
|
||||
if ( index > 31 ) {
|
||||
cerr << "Phonemes: name index is greater than 31!" << endl;
|
||||
return 0;
|
||||
}
|
||||
return phonemeNames[index];
|
||||
}
|
||||
|
||||
MY_FLOAT Phonemes :: voiceGain( unsigned int index )
|
||||
{
|
||||
if ( index > 31 ) {
|
||||
cerr << "Phonemes: voiceGain index is greater than 31!" << endl;
|
||||
return 0.0;
|
||||
}
|
||||
return phonemeGains[index][0];
|
||||
}
|
||||
|
||||
MY_FLOAT Phonemes :: noiseGain( unsigned int index )
|
||||
{
|
||||
if ( index > 31 ) {
|
||||
cerr << "Phonemes: noiseGain index is greater than 31!" << endl;
|
||||
return 0.0;
|
||||
}
|
||||
return phonemeGains[index][1];
|
||||
}
|
||||
|
||||
MY_FLOAT Phonemes :: formantFrequency( unsigned int index, unsigned int partial )
|
||||
{
|
||||
if ( index > 31 ) {
|
||||
cerr << "Phonemes: formantFrequency index is greater than 31!" << endl;
|
||||
return 0.0;
|
||||
}
|
||||
if ( partial > 3 ) {
|
||||
cerr << "Phonemes: formantFrequency partial is greater than 3!" << endl;
|
||||
return 0.0;
|
||||
}
|
||||
return phonemeParameters[index][partial][0];
|
||||
}
|
||||
|
||||
MY_FLOAT Phonemes :: formantRadius( unsigned int index, unsigned int partial )
|
||||
{
|
||||
if ( index > 31 ) {
|
||||
cerr << "Phonemes: formantRadius index is greater than 31!" << endl;
|
||||
return 0.0;
|
||||
}
|
||||
if ( partial > 3 ) {
|
||||
cerr << "Phonemes: formantRadius partial is greater than 3!" << endl;
|
||||
return 0.0;
|
||||
}
|
||||
return phonemeParameters[index][partial][1];
|
||||
}
|
||||
|
||||
MY_FLOAT Phonemes :: formantGain( unsigned int index, unsigned int partial )
|
||||
{
|
||||
if ( index > 31 ) {
|
||||
cerr << "Phonemes: formantGain index is greater than 31!" << endl;
|
||||
return 0.0;
|
||||
}
|
||||
if ( partial > 3 ) {
|
||||
cerr << "Phonemes: formantGain partial is greater than 3!" << endl;
|
||||
return 0.0;
|
||||
}
|
||||
return phonemeParameters[index][partial][2];
|
||||
}
|
||||
@@ -29,6 +29,13 @@ PitShift :: ~PitShift()
|
||||
delete delayLine[1];
|
||||
}
|
||||
|
||||
void PitShift :: clear()
|
||||
{
|
||||
delayLine[0]->clear();
|
||||
delayLine[1]->clear();
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void PitShift :: setEffectMix(MY_FLOAT mix)
|
||||
{
|
||||
effectMix = mix;
|
||||
|
||||
194
src/PoleZero.cpp
194
src/PoleZero.cpp
@@ -1,97 +1,97 @@
|
||||
/***************************************************/
|
||||
/*! \class PoleZero
|
||||
\brief STK one-pole, one-zero filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a one-pole, one-zero digital filter. A
|
||||
method is provided for creating an allpass
|
||||
filter with a given coefficient. Another
|
||||
method is provided to create a DC blocking filter.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "PoleZero.h"
|
||||
|
||||
PoleZero :: PoleZero() : Filter()
|
||||
{
|
||||
// Default setting for pass-through.
|
||||
MY_FLOAT B[2] = {1.0, 0.0};
|
||||
MY_FLOAT A[2] = {1.0, 0.0};
|
||||
Filter::setCoefficients( 2, B, 2, A );
|
||||
}
|
||||
|
||||
PoleZero :: ~PoleZero()
|
||||
{
|
||||
}
|
||||
|
||||
void PoleZero :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void PoleZero :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void PoleZero :: setB1(MY_FLOAT b1)
|
||||
{
|
||||
b[1] = b1;
|
||||
}
|
||||
|
||||
void PoleZero :: setA1(MY_FLOAT a1)
|
||||
{
|
||||
a[1] = a1;
|
||||
}
|
||||
|
||||
void PoleZero :: setAllpass(MY_FLOAT coefficient)
|
||||
{
|
||||
b[0] = coefficient;
|
||||
b[1] = 1.0;
|
||||
a[0] = 1.0; // just in case
|
||||
a[1] = coefficient;
|
||||
}
|
||||
|
||||
void PoleZero :: setBlockZero(MY_FLOAT thePole)
|
||||
{
|
||||
b[0] = 1.0;
|
||||
b[1] = -1.0;
|
||||
a[0] = 1.0; // just in case
|
||||
a[1] = -thePole;
|
||||
}
|
||||
|
||||
void PoleZero :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT PoleZero :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT PoleZero :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT PoleZero :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[0] * inputs[0] + b[1] * inputs[1] - a[1] * outputs[1];
|
||||
inputs[1] = inputs[0];
|
||||
outputs[1] = outputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *PoleZero :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/*! \class PoleZero
|
||||
\brief STK one-pole, one-zero filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a one-pole, one-zero digital filter. A
|
||||
method is provided for creating an allpass
|
||||
filter with a given coefficient. Another
|
||||
method is provided to create a DC blocking filter.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "PoleZero.h"
|
||||
|
||||
PoleZero :: PoleZero() : Filter()
|
||||
{
|
||||
// Default setting for pass-through.
|
||||
MY_FLOAT B[2] = {1.0, 0.0};
|
||||
MY_FLOAT A[2] = {1.0, 0.0};
|
||||
Filter::setCoefficients( 2, B, 2, A );
|
||||
}
|
||||
|
||||
PoleZero :: ~PoleZero()
|
||||
{
|
||||
}
|
||||
|
||||
void PoleZero :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void PoleZero :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void PoleZero :: setB1(MY_FLOAT b1)
|
||||
{
|
||||
b[1] = b1;
|
||||
}
|
||||
|
||||
void PoleZero :: setA1(MY_FLOAT a1)
|
||||
{
|
||||
a[1] = a1;
|
||||
}
|
||||
|
||||
void PoleZero :: setAllpass(MY_FLOAT coefficient)
|
||||
{
|
||||
b[0] = coefficient;
|
||||
b[1] = 1.0;
|
||||
a[0] = 1.0; // just in case
|
||||
a[1] = coefficient;
|
||||
}
|
||||
|
||||
void PoleZero :: setBlockZero(MY_FLOAT thePole)
|
||||
{
|
||||
b[0] = 1.0;
|
||||
b[1] = -1.0;
|
||||
a[0] = 1.0; // just in case
|
||||
a[1] = -thePole;
|
||||
}
|
||||
|
||||
void PoleZero :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT PoleZero :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT PoleZero :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT PoleZero :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[0] * inputs[0] + b[1] * inputs[1] - a[1] * outputs[1];
|
||||
inputs[1] = inputs[0];
|
||||
outputs[1] = outputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *PoleZero :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
|
||||
142
src/ReedTabl.cpp
142
src/ReedTabl.cpp
@@ -1,71 +1,71 @@
|
||||
/***************************************************/
|
||||
/*! \class ReedTabl
|
||||
\brief STK reed table class.
|
||||
|
||||
This class implements a simple one breakpoint,
|
||||
non-linear reed function, as described by
|
||||
Smith (1986). This function is based on a
|
||||
memoryless non-linear spring model of the reed
|
||||
(the reed mass is ignored) which saturates when
|
||||
the reed collides with the mouthpiece facing.
|
||||
|
||||
See McIntyre, Schumacher, & Woodhouse (1983),
|
||||
Smith (1986), Hirschman, Cook, Scavone, and
|
||||
others for more information.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "ReedTabl.h"
|
||||
|
||||
ReedTabl :: ReedTabl()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void ReedTabl :: setSlope(MY_FLOAT aValue)
|
||||
{
|
||||
slope = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT ReedTabl :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT ReedTabl :: tick(MY_FLOAT input)
|
||||
{
|
||||
// The input is differential pressure across the reed.
|
||||
lastOutput = offSet + (slope * input);
|
||||
|
||||
// If output is > 1, the reed has slammed shut and the
|
||||
// reflection function value saturates at 1.0.
|
||||
if (lastOutput > 1.0) lastOutput = (MY_FLOAT) 1.0;
|
||||
|
||||
// This is nearly impossible in a physical system, but
|
||||
// a reflection function value of -1.0 corresponds to
|
||||
// an open end (and no discontinuity in bore profile).
|
||||
if (lastOutput < -1.0) lastOutput = (MY_FLOAT) -1.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *ReedTabl :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/*! \class ReedTabl
|
||||
\brief STK reed table class.
|
||||
|
||||
This class implements a simple one breakpoint,
|
||||
non-linear reed function, as described by
|
||||
Smith (1986). This function is based on a
|
||||
memoryless non-linear spring model of the reed
|
||||
(the reed mass is ignored) which saturates when
|
||||
the reed collides with the mouthpiece facing.
|
||||
|
||||
See McIntyre, Schumacher, & Woodhouse (1983),
|
||||
Smith (1986), Hirschman, Cook, Scavone, and
|
||||
others for more information.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "ReedTabl.h"
|
||||
|
||||
ReedTabl :: ReedTabl()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void ReedTabl :: setSlope(MY_FLOAT aValue)
|
||||
{
|
||||
slope = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT ReedTabl :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT ReedTabl :: tick(MY_FLOAT input)
|
||||
{
|
||||
// The input is differential pressure across the reed.
|
||||
lastOutput = offSet + (slope * input);
|
||||
|
||||
// If output is > 1, the reed has slammed shut and the
|
||||
// reflection function value saturates at 1.0.
|
||||
if (lastOutput > 1.0) lastOutput = (MY_FLOAT) 1.0;
|
||||
|
||||
// This is nearly impossible in a physical system, but
|
||||
// a reflection function value of -1.0 corresponds to
|
||||
// an open end (and no discontinuity in bore profile).
|
||||
if (lastOutput < -1.0) lastOutput = (MY_FLOAT) -1.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *ReedTabl :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
|
||||
0
src/Release/.placeholder
Normal file
0
src/Release/.placeholder
Normal file
@@ -43,10 +43,10 @@ Rhodey :: Rhodey()
|
||||
for ( i=0; i<4; i++ )
|
||||
strcpy( files[i], RAWWAVE_PATH);
|
||||
|
||||
strcat(files[0], "rawwaves/sinewave.raw");
|
||||
strcat(files[1], "rawwaves/sinewave.raw");
|
||||
strcat(files[2], "rawwaves/sinewave.raw");
|
||||
strcat(files[3], "rawwaves/fwavblnk.raw");
|
||||
strcat(files[0], "sinewave.raw");
|
||||
strcat(files[1], "sinewave.raw");
|
||||
strcat(files[2], "sinewave.raw");
|
||||
strcat(files[3], "fwavblnk.raw");
|
||||
|
||||
for ( i=0; i<4; i++ )
|
||||
waves[i] = new WaveLoop( files[i], TRUE );
|
||||
|
||||
12083
src/RtAudio.cpp
12083
src/RtAudio.cpp
File diff suppressed because it is too large
Load Diff
306
src/RtDuplex.cpp
306
src/RtDuplex.cpp
@@ -1,153 +1,153 @@
|
||||
/***************************************************/
|
||||
/*! \class RtDuplex
|
||||
\brief STK realtime audio input/output class.
|
||||
|
||||
This class provides a simplified interface to
|
||||
RtAudio for realtime audio input/output. It
|
||||
is also possible to achieve duplex operation
|
||||
using separate RtWvIn and RtWvOut classes, but
|
||||
this class ensures better input/output
|
||||
syncronization.
|
||||
|
||||
RtDuplex supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which output
|
||||
single samples to all channels in a sample frame
|
||||
and return samples produced by averaging across
|
||||
sample frames, from the tickFrame() methods, which
|
||||
take/return pointers to multi-channel sample frames.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "RtDuplex.h"
|
||||
|
||||
RtDuplex :: RtDuplex(int nChannels, MY_FLOAT sampleRate, int device, int bufferFrames, int nBuffers )
|
||||
{
|
||||
channels = nChannels;
|
||||
bufferSize = bufferFrames;
|
||||
RtAudio::RTAUDIO_FORMAT format = ( sizeof(MY_FLOAT) == 8 ) ? RtAudio::RTAUDIO_FLOAT64 : RtAudio::RTAUDIO_FLOAT32;
|
||||
try {
|
||||
audio = new RtAudio(&stream, device, channels, device, channels, format,
|
||||
(int)sampleRate, &bufferSize, nBuffers);
|
||||
data = (MY_FLOAT *) audio->getStreamBuffer(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
for (unsigned int i=0; i<channels; i++) lastOutput[i] = 0.0;
|
||||
counter = 0;
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
RtDuplex :: ~RtDuplex()
|
||||
{
|
||||
if ( !stopped )
|
||||
audio->stopStream(stream);
|
||||
delete audio;
|
||||
delete [] lastOutput;
|
||||
data = 0; // RtAudio deletes the buffer itself.
|
||||
}
|
||||
|
||||
void RtDuplex :: start()
|
||||
{
|
||||
if ( stopped ) {
|
||||
audio->startStream(stream);
|
||||
stopped = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RtDuplex :: stop()
|
||||
{
|
||||
if ( !stopped ) {
|
||||
audio->stopStream(stream);
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT RtDuplex :: lastOut(void) const
|
||||
{
|
||||
if ( channels == 1 )
|
||||
return *lastOutput;
|
||||
|
||||
MY_FLOAT output = 0.0;
|
||||
for (unsigned int i=0; i<channels; i++ ) {
|
||||
output += lastOutput[i];
|
||||
}
|
||||
return output / channels;
|
||||
}
|
||||
|
||||
MY_FLOAT RtDuplex :: tick(const MY_FLOAT sample)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
if (counter == 0) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long temp = counter * channels;
|
||||
for (unsigned int i=0; i<channels; i++) {
|
||||
lastOutput[i] = data[temp];
|
||||
data[temp++] = sample;
|
||||
}
|
||||
|
||||
counter++;
|
||||
if (counter >= (long) bufferSize)
|
||||
counter = 0;
|
||||
|
||||
return lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT *RtDuplex :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for ( unsigned int i=0; i<vectorSize; i++ )
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
const MY_FLOAT *RtDuplex :: lastFrame() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *RtDuplex :: tickFrame(MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
unsigned int i;
|
||||
unsigned long temp;
|
||||
for (unsigned int j=0; j<frames; j++ ) {
|
||||
if (counter == 0) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
}
|
||||
|
||||
temp = counter * channels;
|
||||
for (i=0; i<channels; i++) {
|
||||
lastOutput[i] = data[temp];
|
||||
data[temp++] = frameVector[j*channels+i];
|
||||
frameVector[j*channels+i] = lastOutput[i];
|
||||
}
|
||||
|
||||
counter++;
|
||||
if (counter >= (long) bufferSize)
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
return frameVector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class RtDuplex
|
||||
\brief STK realtime audio input/output class.
|
||||
|
||||
This class provides a simplified interface to
|
||||
RtAudio for realtime audio input/output. It
|
||||
is also possible to achieve duplex operation
|
||||
using separate RtWvIn and RtWvOut classes, but
|
||||
this class ensures better input/output
|
||||
syncronization.
|
||||
|
||||
RtDuplex supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which output
|
||||
single samples to all channels in a sample frame
|
||||
and return samples produced by averaging across
|
||||
sample frames, from the tickFrame() methods, which
|
||||
take/return pointers to multi-channel sample frames.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "RtDuplex.h"
|
||||
|
||||
RtDuplex :: RtDuplex(int nChannels, MY_FLOAT sampleRate, int device, int bufferFrames, int nBuffers )
|
||||
{
|
||||
channels = nChannels;
|
||||
bufferSize = bufferFrames;
|
||||
RtAudio::RTAUDIO_FORMAT format = ( sizeof(MY_FLOAT) == 8 ) ? RtAudio::RTAUDIO_FLOAT64 : RtAudio::RTAUDIO_FLOAT32;
|
||||
try {
|
||||
audio = new RtAudio(&stream, device, channels, device, channels, format,
|
||||
(int)sampleRate, &bufferSize, nBuffers);
|
||||
data = (MY_FLOAT *) audio->getStreamBuffer(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
for (unsigned int i=0; i<channels; i++) lastOutput[i] = 0.0;
|
||||
counter = 0;
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
RtDuplex :: ~RtDuplex()
|
||||
{
|
||||
if ( !stopped )
|
||||
audio->stopStream(stream);
|
||||
delete audio;
|
||||
delete [] lastOutput;
|
||||
data = 0; // RtAudio deletes the buffer itself.
|
||||
}
|
||||
|
||||
void RtDuplex :: start()
|
||||
{
|
||||
if ( stopped ) {
|
||||
audio->startStream(stream);
|
||||
stopped = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RtDuplex :: stop()
|
||||
{
|
||||
if ( !stopped ) {
|
||||
audio->stopStream(stream);
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT RtDuplex :: lastOut(void) const
|
||||
{
|
||||
if ( channels == 1 )
|
||||
return *lastOutput;
|
||||
|
||||
MY_FLOAT output = 0.0;
|
||||
for (unsigned int i=0; i<channels; i++ ) {
|
||||
output += lastOutput[i];
|
||||
}
|
||||
return output / channels;
|
||||
}
|
||||
|
||||
MY_FLOAT RtDuplex :: tick(const MY_FLOAT sample)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
if (counter == 0) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long temp = counter * channels;
|
||||
for (unsigned int i=0; i<channels; i++) {
|
||||
lastOutput[i] = data[temp];
|
||||
data[temp++] = sample;
|
||||
}
|
||||
|
||||
counter++;
|
||||
if (counter >= (long) bufferSize)
|
||||
counter = 0;
|
||||
|
||||
return lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT *RtDuplex :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for ( unsigned int i=0; i<vectorSize; i++ )
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
const MY_FLOAT *RtDuplex :: lastFrame() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *RtDuplex :: tickFrame(MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
unsigned int i;
|
||||
unsigned long temp;
|
||||
for (unsigned int j=0; j<frames; j++ ) {
|
||||
if (counter == 0) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
}
|
||||
|
||||
temp = counter * channels;
|
||||
for (i=0; i<channels; i++) {
|
||||
lastOutput[i] = data[temp];
|
||||
data[temp++] = frameVector[j*channels+i];
|
||||
frameVector[j*channels+i] = lastOutput[i];
|
||||
}
|
||||
|
||||
counter++;
|
||||
if (counter >= (long) bufferSize)
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
return frameVector;
|
||||
}
|
||||
|
||||
2160
src/RtMidi.cpp
2160
src/RtMidi.cpp
File diff suppressed because it is too large
Load Diff
242
src/RtWvIn.cpp
242
src/RtWvIn.cpp
@@ -1,121 +1,121 @@
|
||||
/***************************************************/
|
||||
/*! \class RtWvIn
|
||||
\brief STK realtime audio input class.
|
||||
|
||||
This class provides a simplified interface to
|
||||
RtAudio for realtime audio input. It is a
|
||||
protected subclass of WvIn.
|
||||
|
||||
RtWvIn supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which return
|
||||
samples produced by averaging across sample
|
||||
frames, from the tickFrame() methods, which
|
||||
return pointers to multi-channel sample frames.
|
||||
For single-channel data, these methods return
|
||||
equivalent values.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "RtWvIn.h"
|
||||
|
||||
RtWvIn :: RtWvIn(int nChannels, MY_FLOAT sampleRate, int device, int bufferFrames, int nBuffers )
|
||||
{
|
||||
channels = nChannels;
|
||||
int size = bufferFrames;
|
||||
RtAudio::RTAUDIO_FORMAT format = ( sizeof(MY_FLOAT) == 8 ) ? RtAudio::RTAUDIO_FLOAT64 : RtAudio::RTAUDIO_FLOAT32;
|
||||
try {
|
||||
audio = new RtAudio(&stream, 0, 0, device, channels, format,
|
||||
(int)sampleRate, &size, nBuffers);
|
||||
data = (MY_FLOAT *) audio->getStreamBuffer(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
|
||||
bufferSize = size;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
for (unsigned int i=0; i<channels; i++) lastOutput[i] = 0.0;
|
||||
counter = 0;
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
RtWvIn :: ~RtWvIn()
|
||||
{
|
||||
if ( !stopped )
|
||||
audio->stopStream(stream);
|
||||
delete audio;
|
||||
data = 0; // RtAudio deletes the buffer itself.
|
||||
}
|
||||
|
||||
void RtWvIn :: start()
|
||||
{
|
||||
if ( stopped ) {
|
||||
audio->startStream(stream);
|
||||
stopped = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RtWvIn :: stop()
|
||||
{
|
||||
if ( !stopped ) {
|
||||
audio->stopStream(stream);
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT RtWvIn :: lastOut(void) const
|
||||
{
|
||||
return WvIn::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT RtWvIn :: tick(void)
|
||||
{
|
||||
tickFrame();
|
||||
return lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT *RtWvIn :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for ( unsigned int i=0; i<vectorSize; i++ )
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
const MY_FLOAT *RtWvIn :: lastFrame() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
const MY_FLOAT *RtWvIn :: tickFrame(void)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
if (counter == 0) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
}
|
||||
|
||||
long temp = counter * channels;
|
||||
for (unsigned int i=0; i<channels; i++)
|
||||
lastOutput[i] = data[temp++];
|
||||
|
||||
counter++;
|
||||
if (counter >= (long) bufferSize)
|
||||
counter = 0;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *RtWvIn :: tickFrame(MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
return WvIn::tickFrame( frameVector, frames );
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class RtWvIn
|
||||
\brief STK realtime audio input class.
|
||||
|
||||
This class provides a simplified interface to
|
||||
RtAudio for realtime audio input. It is a
|
||||
protected subclass of WvIn.
|
||||
|
||||
RtWvIn supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which return
|
||||
samples produced by averaging across sample
|
||||
frames, from the tickFrame() methods, which
|
||||
return pointers to multi-channel sample frames.
|
||||
For single-channel data, these methods return
|
||||
equivalent values.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "RtWvIn.h"
|
||||
|
||||
RtWvIn :: RtWvIn(int nChannels, MY_FLOAT sampleRate, int device, int bufferFrames, int nBuffers )
|
||||
{
|
||||
channels = nChannels;
|
||||
int size = bufferFrames;
|
||||
RtAudio::RTAUDIO_FORMAT format = ( sizeof(MY_FLOAT) == 8 ) ? RtAudio::RTAUDIO_FLOAT64 : RtAudio::RTAUDIO_FLOAT32;
|
||||
try {
|
||||
audio = new RtAudio(&stream, 0, 0, device, channels, format,
|
||||
(int)sampleRate, &size, nBuffers);
|
||||
data = (MY_FLOAT *) audio->getStreamBuffer(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
|
||||
bufferSize = size;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
for (unsigned int i=0; i<channels; i++) lastOutput[i] = 0.0;
|
||||
counter = 0;
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
RtWvIn :: ~RtWvIn()
|
||||
{
|
||||
if ( !stopped )
|
||||
audio->stopStream(stream);
|
||||
delete audio;
|
||||
data = 0; // RtAudio deletes the buffer itself.
|
||||
}
|
||||
|
||||
void RtWvIn :: start()
|
||||
{
|
||||
if ( stopped ) {
|
||||
audio->startStream(stream);
|
||||
stopped = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RtWvIn :: stop()
|
||||
{
|
||||
if ( !stopped ) {
|
||||
audio->stopStream(stream);
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT RtWvIn :: lastOut(void) const
|
||||
{
|
||||
return WvIn::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT RtWvIn :: tick(void)
|
||||
{
|
||||
tickFrame();
|
||||
return lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT *RtWvIn :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for ( unsigned int i=0; i<vectorSize; i++ )
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
const MY_FLOAT *RtWvIn :: lastFrame() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
const MY_FLOAT *RtWvIn :: tickFrame(void)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
if (counter == 0) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
}
|
||||
|
||||
long temp = counter * channels;
|
||||
for (unsigned int i=0; i<channels; i++)
|
||||
lastOutput[i] = data[temp++];
|
||||
|
||||
counter++;
|
||||
if (counter >= (long) bufferSize)
|
||||
counter = 0;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *RtWvIn :: tickFrame(MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
return WvIn::tickFrame( frameVector, frames );
|
||||
}
|
||||
|
||||
250
src/RtWvOut.cpp
250
src/RtWvOut.cpp
@@ -1,125 +1,125 @@
|
||||
/***************************************************/
|
||||
/*! \class RtWvOut
|
||||
\brief STK realtime audio output class.
|
||||
|
||||
This class provides a simplified interface to
|
||||
RtAudio for realtime audio output. It is a
|
||||
protected subclass of WvOut.
|
||||
|
||||
RtWvOut supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which output
|
||||
single samples to all channels in a sample
|
||||
frame, from the tickFrame() method, which
|
||||
takes a pointer to multi-channel sample
|
||||
frame data.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "RtWvOut.h"
|
||||
#include <stdio.h>
|
||||
|
||||
RtWvOut :: RtWvOut(unsigned int nChannels, MY_FLOAT sampleRate, int device, int bufferFrames, int nBuffers )
|
||||
{
|
||||
// We'll let RtAudio deal with channel and srate limitations.
|
||||
channels = nChannels;
|
||||
bufferSize = bufferFrames;
|
||||
RtAudio::RTAUDIO_FORMAT format = ( sizeof(MY_FLOAT) == 8 ) ? RtAudio::RTAUDIO_FLOAT64 : RtAudio::RTAUDIO_FLOAT32;
|
||||
try {
|
||||
audio = new RtAudio(&stream, device, (int)channels, 0, 0, format,
|
||||
(int)sampleRate, &bufferSize, nBuffers);
|
||||
data = (MY_FLOAT *) audio->getStreamBuffer(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
RtWvOut :: ~RtWvOut()
|
||||
{
|
||||
if ( !stopped )
|
||||
audio->stopStream(stream);
|
||||
delete audio;
|
||||
data = 0; // RtAudio deletes the buffer itself.
|
||||
}
|
||||
|
||||
void RtWvOut :: start()
|
||||
{
|
||||
if ( stopped ) {
|
||||
audio->startStream(stream);
|
||||
stopped = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RtWvOut :: stop()
|
||||
{
|
||||
if ( !stopped ) {
|
||||
audio->stopStream(stream);
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long RtWvOut :: getFrames( void ) const
|
||||
{
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
MY_FLOAT RtWvOut :: getTime( void ) const
|
||||
{
|
||||
return (MY_FLOAT) totalCount / Stk::sampleRate();
|
||||
}
|
||||
|
||||
void RtWvOut :: tick(const MY_FLOAT sample)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
for ( unsigned int j=0; j<channels; j++ )
|
||||
data[counter*channels+j] = sample;
|
||||
|
||||
counter++;
|
||||
totalCount++;
|
||||
|
||||
if ( counter >= (unsigned int )bufferSize ) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RtWvOut :: tick(const MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
tick( vector[i] );
|
||||
}
|
||||
|
||||
void RtWvOut :: tickFrame(const MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
for ( unsigned int i=0; i<frames; i++ ) {
|
||||
for ( unsigned int j=0; j<channels; j++ ) {
|
||||
data[counter*channels+j] = frameVector[i*channels+j];
|
||||
}
|
||||
counter++;
|
||||
|
||||
if ( counter >= (unsigned int)bufferSize ) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/*! \class RtWvOut
|
||||
\brief STK realtime audio output class.
|
||||
|
||||
This class provides a simplified interface to
|
||||
RtAudio for realtime audio output. It is a
|
||||
protected subclass of WvOut.
|
||||
|
||||
RtWvOut supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which output
|
||||
single samples to all channels in a sample
|
||||
frame, from the tickFrame() method, which
|
||||
takes a pointer to multi-channel sample
|
||||
frame data.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "RtWvOut.h"
|
||||
#include <stdio.h>
|
||||
|
||||
RtWvOut :: RtWvOut(unsigned int nChannels, MY_FLOAT sampleRate, int device, int bufferFrames, int nBuffers )
|
||||
{
|
||||
// We'll let RtAudio deal with channel and srate limitations.
|
||||
channels = nChannels;
|
||||
bufferSize = bufferFrames;
|
||||
RtAudio::RTAUDIO_FORMAT format = ( sizeof(MY_FLOAT) == 8 ) ? RtAudio::RTAUDIO_FLOAT64 : RtAudio::RTAUDIO_FLOAT32;
|
||||
try {
|
||||
audio = new RtAudio(&stream, device, (int)channels, 0, 0, format,
|
||||
(int)sampleRate, &bufferSize, nBuffers);
|
||||
data = (MY_FLOAT *) audio->getStreamBuffer(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
RtWvOut :: ~RtWvOut()
|
||||
{
|
||||
if ( !stopped )
|
||||
audio->stopStream(stream);
|
||||
delete audio;
|
||||
data = 0; // RtAudio deletes the buffer itself.
|
||||
}
|
||||
|
||||
void RtWvOut :: start()
|
||||
{
|
||||
if ( stopped ) {
|
||||
audio->startStream(stream);
|
||||
stopped = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RtWvOut :: stop()
|
||||
{
|
||||
if ( !stopped ) {
|
||||
audio->stopStream(stream);
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long RtWvOut :: getFrames( void ) const
|
||||
{
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
MY_FLOAT RtWvOut :: getTime( void ) const
|
||||
{
|
||||
return (MY_FLOAT) totalCount / Stk::sampleRate();
|
||||
}
|
||||
|
||||
void RtWvOut :: tick(const MY_FLOAT sample)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
for ( unsigned int j=0; j<channels; j++ )
|
||||
data[counter*channels+j] = sample;
|
||||
|
||||
counter++;
|
||||
totalCount++;
|
||||
|
||||
if ( counter >= (unsigned int )bufferSize ) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RtWvOut :: tick(const MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
tick( vector[i] );
|
||||
}
|
||||
|
||||
void RtWvOut :: tickFrame(const MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
if ( stopped )
|
||||
start();
|
||||
|
||||
for ( unsigned int i=0; i<frames; i++ ) {
|
||||
for ( unsigned int j=0; j<channels; j++ ) {
|
||||
data[counter*channels+j] = frameVector[i*channels+j];
|
||||
}
|
||||
counter++;
|
||||
|
||||
if ( counter >= (unsigned int)bufferSize ) {
|
||||
try {
|
||||
audio->tickStream(stream);
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessage(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
700
src/SKINI.cpp
700
src/SKINI.cpp
@@ -1,350 +1,350 @@
|
||||
/***************************************************/
|
||||
/*! \class SKINI
|
||||
\brief STK SKINI parsing class
|
||||
|
||||
This class parses SKINI formatted text
|
||||
messages. It can be used to parse individual
|
||||
messages or it can be passed an entire file.
|
||||
The file specification is Perry's and his
|
||||
alone, but it's all text so it shouldn't be to
|
||||
hard to figure out.
|
||||
|
||||
SKINI (Synthesis toolKit Instrument Network
|
||||
Interface) is like MIDI, but allows for
|
||||
floating-point control changes, note numbers,
|
||||
etc. The following example causes a sharp
|
||||
middle C to be played with a velocity of 111.132:
|
||||
|
||||
noteOn 60.01 111.13
|
||||
|
||||
See also SKINI.txt.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "SKINI.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Constructor for use when parsing SKINI strings (coming over socket
|
||||
// for example. Use parseThis() method with string pointer.
|
||||
SKINI :: SKINI()
|
||||
{
|
||||
}
|
||||
|
||||
// Constructor for reading SKINI files ... use nextMessage() method.
|
||||
SKINI :: SKINI(char *fileName)
|
||||
{
|
||||
char msg[256];
|
||||
|
||||
myFile = fopen(fileName,"r");
|
||||
if ((int) myFile < 0) {
|
||||
sprintf(msg, "SKINI: Could not open or find file (%s).", fileName);
|
||||
handleError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
this->nextMessage();
|
||||
}
|
||||
|
||||
SKINI :: ~SKINI()
|
||||
{
|
||||
}
|
||||
|
||||
/***************** SOME HANDY ROUTINES *******************/
|
||||
|
||||
#include "SKINI.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 SKINI :: 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 = 0;
|
||||
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[aField][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 SKINI :: nextMessage()
|
||||
{
|
||||
int notDone;
|
||||
char inputString[1024];
|
||||
|
||||
notDone = 1;
|
||||
while (notDone) {
|
||||
notDone = 0;
|
||||
if (!fgets(inputString,1024,myFile)) {
|
||||
printf("// End of Score. Thanks for using SKINI!!\n");
|
||||
messageType = -1;
|
||||
return messageType;
|
||||
}
|
||||
else if (parseThis(inputString) == 0) {
|
||||
notDone = 1;
|
||||
}
|
||||
}
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI :: getType() const
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI :: getChannel() const
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI :: getDelta() const
|
||||
{
|
||||
return deltaTime;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI :: getByteTwo() const
|
||||
{
|
||||
return byteTwo;
|
||||
}
|
||||
|
||||
long SKINI :: getByteTwoInt() const
|
||||
{
|
||||
return byteTwoInt;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI :: getByteThree() const
|
||||
{
|
||||
return byteThree;
|
||||
}
|
||||
|
||||
long SKINI :: getByteThreeInt() const
|
||||
{
|
||||
return byteThreeInt;
|
||||
}
|
||||
|
||||
const char* SKINI :: getRemainderString()
|
||||
{
|
||||
return remainderString;
|
||||
}
|
||||
|
||||
const char* SKINI :: getMessageTypeString()
|
||||
{
|
||||
return msgTypeString;
|
||||
}
|
||||
|
||||
const char* SKINI :: whatsThisType(long type)
|
||||
{
|
||||
int i = 0;
|
||||
whatString[0] = 0;
|
||||
for ( i=0; i<__SK_MaxMsgTypes_; i++ ) {
|
||||
if ( type == skini_msgs[i].type ) {
|
||||
strcat(whatString, skini_msgs[i].messageString);
|
||||
strcat(whatString, ",");
|
||||
}
|
||||
}
|
||||
return whatString;
|
||||
}
|
||||
|
||||
const char* SKINI :: whatsThisController(long contNum)
|
||||
{
|
||||
int i = 0;
|
||||
whatString[0] = 0;
|
||||
for ( i=0; i<__SK_MaxMsgTypes_; i++) {
|
||||
if ( skini_msgs[i].type == __SK_ControlChange_
|
||||
&& contNum == skini_msgs[i].data2) {
|
||||
strcat(whatString, skini_msgs[i].messageString);
|
||||
strcat(whatString, ",");
|
||||
}
|
||||
}
|
||||
return whatString;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************/
|
||||
/*! \class SKINI
|
||||
\brief STK SKINI parsing class
|
||||
|
||||
This class parses SKINI formatted text
|
||||
messages. It can be used to parse individual
|
||||
messages or it can be passed an entire file.
|
||||
The file specification is Perry's and his
|
||||
alone, but it's all text so it shouldn't be to
|
||||
hard to figure out.
|
||||
|
||||
SKINI (Synthesis toolKit Instrument Network
|
||||
Interface) is like MIDI, but allows for
|
||||
floating-point control changes, note numbers,
|
||||
etc. The following example causes a sharp
|
||||
middle C to be played with a velocity of 111.132:
|
||||
|
||||
noteOn 60.01 111.13
|
||||
|
||||
See also SKINI.txt.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "SKINI.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Constructor for use when parsing SKINI strings (coming over socket
|
||||
// for example. Use parseThis() method with string pointer.
|
||||
SKINI :: SKINI()
|
||||
{
|
||||
}
|
||||
|
||||
// Constructor for reading SKINI files ... use nextMessage() method.
|
||||
SKINI :: SKINI(char *fileName)
|
||||
{
|
||||
char msg[256];
|
||||
|
||||
myFile = fopen(fileName,"r");
|
||||
if ((int) myFile < 0) {
|
||||
sprintf(msg, "SKINI: Could not open or find file (%s).", fileName);
|
||||
handleError(msg, StkError::FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
this->nextMessage();
|
||||
}
|
||||
|
||||
SKINI :: ~SKINI()
|
||||
{
|
||||
}
|
||||
|
||||
/***************** SOME HANDY ROUTINES *******************/
|
||||
|
||||
#include "SKINI.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 SKINI :: 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 = 0;
|
||||
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[aField][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 SKINI :: nextMessage()
|
||||
{
|
||||
int notDone;
|
||||
char inputString[1024];
|
||||
|
||||
notDone = 1;
|
||||
while (notDone) {
|
||||
notDone = 0;
|
||||
if (!fgets(inputString,1024,myFile)) {
|
||||
printf("// End of Score. Thanks for using SKINI!!\n");
|
||||
messageType = -1;
|
||||
return messageType;
|
||||
}
|
||||
else if (parseThis(inputString) == 0) {
|
||||
notDone = 1;
|
||||
}
|
||||
}
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI :: getType() const
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI :: getChannel() const
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI :: getDelta() const
|
||||
{
|
||||
return deltaTime;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI :: getByteTwo() const
|
||||
{
|
||||
return byteTwo;
|
||||
}
|
||||
|
||||
long SKINI :: getByteTwoInt() const
|
||||
{
|
||||
return byteTwoInt;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI :: getByteThree() const
|
||||
{
|
||||
return byteThree;
|
||||
}
|
||||
|
||||
long SKINI :: getByteThreeInt() const
|
||||
{
|
||||
return byteThreeInt;
|
||||
}
|
||||
|
||||
const char* SKINI :: getRemainderString()
|
||||
{
|
||||
return remainderString;
|
||||
}
|
||||
|
||||
const char* SKINI :: getMessageTypeString()
|
||||
{
|
||||
return msgTypeString;
|
||||
}
|
||||
|
||||
const char* SKINI :: whatsThisType(long type)
|
||||
{
|
||||
int i = 0;
|
||||
whatString[0] = 0;
|
||||
for ( i=0; i<__SK_MaxMsgTypes_; i++ ) {
|
||||
if ( type == skini_msgs[i].type ) {
|
||||
strcat(whatString, skini_msgs[i].messageString);
|
||||
strcat(whatString, ",");
|
||||
}
|
||||
}
|
||||
return whatString;
|
||||
}
|
||||
|
||||
const char* SKINI :: whatsThisController(long contNum)
|
||||
{
|
||||
int i = 0;
|
||||
whatString[0] = 0;
|
||||
for ( i=0; i<__SK_MaxMsgTypes_; i++) {
|
||||
if ( skini_msgs[i].type == __SK_ControlChange_
|
||||
&& contNum == skini_msgs[i].data2) {
|
||||
strcat(whatString, skini_msgs[i].messageString);
|
||||
strcat(whatString, ",");
|
||||
}
|
||||
}
|
||||
return whatString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ Saxofony :: Saxofony(MY_FLOAT lowestFrequency)
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char path[128];
|
||||
strcpy(path, RAWWAVE_PATH);
|
||||
vibrato = new WaveLoop( strcat(path,"rawwaves/sinewave.raw"), TRUE );
|
||||
vibrato = new WaveLoop( strcat(path,"sinewave.raw"), TRUE );
|
||||
vibrato->setFrequency((MY_FLOAT) 5.735);
|
||||
|
||||
outputGain = (MY_FLOAT) 0.3;
|
||||
|
||||
2250
src/Shakers.cpp
2250
src/Shakers.cpp
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,7 @@ Simple :: Simple()
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
loop = new WaveLoop( strcat(file,"rawwaves/impuls10.raw"), TRUE );
|
||||
loop = new WaveLoop( strcat(file,"impuls10.raw"), TRUE );
|
||||
|
||||
filter = new OnePole(0.5);
|
||||
noise = new Noise;
|
||||
|
||||
128
src/SingWave.cpp
Normal file
128
src/SingWave.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/***************************************************/
|
||||
/*! \class SingWave
|
||||
\brief STK "singing" looped soundfile class.
|
||||
|
||||
This class contains all that is needed to make
|
||||
a pitched musical sound, like a simple voice
|
||||
or violin. In general, it will not be used
|
||||
alone because of munchkinification effects
|
||||
from pitch shifting. It will be used as an
|
||||
excitation source for other instruments.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "SingWave.h"
|
||||
|
||||
SingWave :: SingWave(const char *fileName, bool raw)
|
||||
{
|
||||
// An exception could be thrown here.
|
||||
wave = new WaveLoop( fileName, raw );
|
||||
|
||||
rate = 1.0;
|
||||
sweepRate = 0.001;
|
||||
modulator = new Modulate();
|
||||
modulator->setVibratoRate( 6.0 );
|
||||
modulator->setVibratoGain( 0.04 );
|
||||
modulator->setRandomGain( 0.005 );
|
||||
envelope = new Envelope;
|
||||
pitchEnvelope = new Envelope;
|
||||
setFrequency( 75.0 );
|
||||
pitchEnvelope->setRate( 1.0 );
|
||||
this->tick();
|
||||
this->tick();
|
||||
pitchEnvelope->setRate( sweepRate * rate );
|
||||
}
|
||||
|
||||
SingWave :: ~SingWave()
|
||||
{
|
||||
delete wave;
|
||||
delete modulator;
|
||||
delete envelope;
|
||||
delete pitchEnvelope;
|
||||
}
|
||||
|
||||
void SingWave :: reset()
|
||||
{
|
||||
wave->reset();
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void SingWave :: normalize()
|
||||
{
|
||||
wave->normalize();
|
||||
}
|
||||
|
||||
void SingWave :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
wave->normalize( newPeak );
|
||||
}
|
||||
|
||||
void SingWave :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT temp = rate;
|
||||
rate = wave->getSize() * frequency / Stk::sampleRate();
|
||||
temp -= rate;
|
||||
if ( temp < 0) temp = -temp;
|
||||
pitchEnvelope->setTarget( rate );
|
||||
pitchEnvelope->setRate( sweepRate * temp );
|
||||
}
|
||||
|
||||
void SingWave :: setVibratoRate(MY_FLOAT aRate)
|
||||
{
|
||||
modulator->setVibratoRate( aRate );
|
||||
}
|
||||
|
||||
void SingWave :: setVibratoGain(MY_FLOAT gain)
|
||||
{
|
||||
modulator->setVibratoGain(gain);
|
||||
}
|
||||
|
||||
void SingWave :: setRandomGain(MY_FLOAT gain)
|
||||
{
|
||||
modulator->setRandomGain(gain);
|
||||
}
|
||||
|
||||
void SingWave :: setSweepRate(MY_FLOAT aRate)
|
||||
{
|
||||
sweepRate = aRate;
|
||||
}
|
||||
|
||||
void SingWave :: setGainRate(MY_FLOAT aRate)
|
||||
{
|
||||
envelope->setRate(aRate);
|
||||
}
|
||||
|
||||
void SingWave :: setGainTarget(MY_FLOAT target)
|
||||
{
|
||||
envelope->setTarget(target);
|
||||
}
|
||||
|
||||
void SingWave :: noteOn()
|
||||
{
|
||||
envelope->keyOn();
|
||||
}
|
||||
|
||||
void SingWave :: noteOff()
|
||||
{
|
||||
envelope->keyOff();
|
||||
}
|
||||
|
||||
MY_FLOAT SingWave :: tick()
|
||||
{
|
||||
// Set the wave rate.
|
||||
MY_FLOAT newRate = pitchEnvelope->tick();
|
||||
newRate += newRate * modulator->tick();
|
||||
wave->setRate( newRate );
|
||||
|
||||
lastOutput = wave->tick();
|
||||
lastOutput *= envelope->tick();
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT SingWave :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
@@ -1,11 +1,21 @@
|
||||
/******************************************/
|
||||
/* Karplus-Strong Sitar1 string model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* There exist at least two patents, */
|
||||
/* assigned to Stanford, bearing the */
|
||||
/* names of Karplus and/or Strong. */
|
||||
/******************************************/
|
||||
/***************************************************/
|
||||
/*! \class Sitar
|
||||
\brief STK sitar string model class.
|
||||
|
||||
This class implements a sitar plucked string
|
||||
physical model based on the Karplus-Strong
|
||||
algorithm.
|
||||
|
||||
This is a digital waveguide model, making its
|
||||
use possibly subject to patents held by
|
||||
Stanford University, Yamaha, and others.
|
||||
There exist at least two patents, assigned to
|
||||
Stanford, bearing the names of Karplus and/or
|
||||
Strong.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Sitar.h"
|
||||
#include <math.h>
|
||||
|
||||
481
src/Socket.cpp
481
src/Socket.cpp
@@ -1,240 +1,241 @@
|
||||
/***************************************************/
|
||||
/*! \class Socket
|
||||
\brief STK TCP socket client/server class.
|
||||
|
||||
This class provides a uniform cross-platform
|
||||
TCP socket client or socket server interface.
|
||||
Methods are provided for reading or writing
|
||||
data buffers to/from connections. This class
|
||||
also provides a number of static functions for
|
||||
use with external socket descriptors.
|
||||
|
||||
The user is responsible for checking the values
|
||||
returned by the read/write methods. Values
|
||||
less than or equal to zero indicate a closed
|
||||
or lost connection or the occurence of an error.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Socket.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
#include <winsock.h>
|
||||
|
||||
#endif
|
||||
|
||||
Socket :: Socket( int port )
|
||||
{
|
||||
soket = -1;
|
||||
server = true;
|
||||
poort = port;
|
||||
|
||||
// Create a socket server.
|
||||
#if defined(__OS_WINDOWS__) // windoze-only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
sprintf( msg, "Socket: Incompatible Windows socket library version!" );
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the server-side socket
|
||||
soket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (soket < 0) {
|
||||
sprintf(msg, "Socket: Couldn't create socket server!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
|
||||
struct sockaddr_in mysocket;
|
||||
mysocket.sin_family=AF_INET;
|
||||
mysocket.sin_addr.s_addr=INADDR_ANY;
|
||||
mysocket.sin_port=htons( port );
|
||||
|
||||
// Bind socket to the appropriate port and interface (INADDR_ANY)
|
||||
if (bind(soket, (struct sockaddr *)&mysocket, sizeof(mysocket)) < 0) {
|
||||
sprintf(msg, "Socket: Couldn't bind socket!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
|
||||
// Listen for incoming connection(s)
|
||||
if ( listen(soket, 1) < 0 ) {
|
||||
sprintf(msg, "Socket: Couldn't start server listening!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
}
|
||||
|
||||
Socket :: Socket(int port, const char *hostname )
|
||||
{
|
||||
soket = -1;
|
||||
server = false;
|
||||
poort = port;
|
||||
|
||||
#if defined(__OS_WINDOWS__) // windoze-only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
sprintf( msg, "Socket: Incompatible Windows socket library version!" );
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create a socket client connection.
|
||||
connect( port, hostname );
|
||||
}
|
||||
|
||||
Socket :: ~Socket()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
::close( soket );
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
::closesocket( soket );
|
||||
WSACleanup();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int Socket :: connect( int port, const char *hostname )
|
||||
{
|
||||
// This method is for client connections only!
|
||||
if ( server == true ) return -1;
|
||||
|
||||
// Close an existing connection if it exists.
|
||||
if ( isValid( soket ) ) this->close();
|
||||
|
||||
// Create the client-side socket
|
||||
soket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (soket < 0) {
|
||||
sprintf(msg, "Socket: Couldn't create socket client!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
|
||||
struct hostent *hostp;
|
||||
if ( (hostp = gethostbyname(hostname)) == 0 ) {
|
||||
sprintf(msg, "Socket: unknown host (%s)!", hostname);
|
||||
handleError( msg, StkError::PROCESS_SOCKET_IPADDR );
|
||||
}
|
||||
|
||||
// Fill in the address structure
|
||||
struct sockaddr_in server_address;
|
||||
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(soket, (struct sockaddr *)&server_address,
|
||||
sizeof(server_address) ) < 0) {
|
||||
sprintf(msg, "Socket: Couldn't connect to socket server!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
|
||||
return soket;
|
||||
}
|
||||
|
||||
int Socket :: socket( void ) const
|
||||
{
|
||||
return soket;
|
||||
}
|
||||
|
||||
int Socket :: port( void ) const
|
||||
{
|
||||
return poort;
|
||||
}
|
||||
|
||||
int Socket :: accept( void )
|
||||
{
|
||||
if ( server )
|
||||
return ::accept( soket, NULL, NULL );
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Socket :: isValid( int socket )
|
||||
{
|
||||
return socket != -1;
|
||||
}
|
||||
|
||||
void Socket :: setBlocking( int socket, bool enable )
|
||||
{
|
||||
if ( !isValid( socket ) ) return;
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
int tmp = ::fcntl(socket, F_GETFL, 0);
|
||||
if ( tmp >= 0 )
|
||||
tmp = ::fcntl( socket, F_SETFL, enable ? (tmp &~ O_NONBLOCK) : (tmp | O_NONBLOCK) );
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
unsigned long non_block = !enable;
|
||||
ioctlsocket( socket, FIONBIO, &non_block );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void Socket :: close( void )
|
||||
{
|
||||
if ( !isValid( soket ) ) return;
|
||||
this->close( soket );
|
||||
soket = -1;
|
||||
}
|
||||
|
||||
void Socket :: close( int socket )
|
||||
{
|
||||
if ( !isValid( socket ) ) return;
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
::close( socket );
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
::closesocket( socket );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int Socket :: writeBuffer(const void *buffer, long bufferSize, int flags )
|
||||
{
|
||||
if ( !isValid( soket ) ) return -1;
|
||||
return send( soket, (const char *)buffer, bufferSize, flags );
|
||||
}
|
||||
|
||||
int Socket :: writeBuffer(int socket, const void *buffer, long bufferSize, int flags )
|
||||
{
|
||||
if ( !isValid( socket ) ) return -1;
|
||||
return send( socket, (const char *)buffer, bufferSize, flags );
|
||||
}
|
||||
|
||||
int Socket :: readBuffer(void *buffer, long bufferSize, int flags )
|
||||
{
|
||||
if ( !isValid( soket ) ) return -1;
|
||||
return recv( soket, (char *)buffer, bufferSize, flags );
|
||||
}
|
||||
|
||||
int Socket :: readBuffer(int socket, void *buffer, long bufferSize, int flags )
|
||||
{
|
||||
if ( !isValid( socket ) ) return -1;
|
||||
return recv( socket, (char *)buffer, bufferSize, flags );
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class Socket
|
||||
\brief STK TCP socket client/server class.
|
||||
|
||||
This class provides a uniform cross-platform
|
||||
TCP socket client or socket server interface.
|
||||
Methods are provided for reading or writing
|
||||
data buffers to/from connections. This class
|
||||
also provides a number of static functions for
|
||||
use with external socket descriptors.
|
||||
|
||||
The user is responsible for checking the values
|
||||
returned by the read/write methods. Values
|
||||
less than or equal to zero indicate a closed
|
||||
or lost connection or the occurence of an error.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Socket.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
#include <winsock.h>
|
||||
|
||||
#endif
|
||||
|
||||
Socket :: Socket( int port )
|
||||
{
|
||||
soket = -1;
|
||||
server = true;
|
||||
poort = port;
|
||||
|
||||
// Create a socket server.
|
||||
#if defined(__OS_WINDOWS__) // windoze-only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
sprintf( msg, "Socket: Incompatible Windows socket library version!" );
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the server-side socket
|
||||
soket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (soket < 0) {
|
||||
sprintf(msg, "Socket: Couldn't create socket server!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
|
||||
struct sockaddr_in mysocket;
|
||||
mysocket.sin_family=AF_INET;
|
||||
mysocket.sin_addr.s_addr=INADDR_ANY;
|
||||
mysocket.sin_port=htons( port );
|
||||
|
||||
// Bind socket to the appropriate port and interface (INADDR_ANY)
|
||||
if (bind(soket, (struct sockaddr *)&mysocket, sizeof(mysocket)) < 0) {
|
||||
sprintf(msg, "Socket: Couldn't bind socket!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
|
||||
// Listen for incoming connection(s)
|
||||
if ( listen(soket, 1) < 0 ) {
|
||||
sprintf(msg, "Socket: Couldn't start server listening!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
}
|
||||
|
||||
Socket :: Socket(int port, const char *hostname )
|
||||
{
|
||||
soket = -1;
|
||||
server = false;
|
||||
poort = port;
|
||||
|
||||
#if defined(__OS_WINDOWS__) // windoze-only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
sprintf( msg, "Socket: Incompatible Windows socket library version!" );
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create a socket client connection.
|
||||
connect( port, hostname );
|
||||
}
|
||||
|
||||
Socket :: ~Socket()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
::close( soket );
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
::closesocket( soket );
|
||||
WSACleanup();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int Socket :: connect( int port, const char *hostname )
|
||||
{
|
||||
// This method is for client connections only!
|
||||
if ( server == true ) return -1;
|
||||
|
||||
// Close an existing connection if it exists.
|
||||
if ( isValid( soket ) ) this->close();
|
||||
|
||||
// Create the client-side socket
|
||||
soket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (soket < 0) {
|
||||
sprintf(msg, "Socket: Couldn't create socket client!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
|
||||
struct hostent *hostp;
|
||||
if ( (hostp = gethostbyname(hostname)) == 0 ) {
|
||||
sprintf(msg, "Socket: unknown host (%s)!", hostname);
|
||||
handleError( msg, StkError::PROCESS_SOCKET_IPADDR );
|
||||
}
|
||||
|
||||
// Fill in the address structure
|
||||
struct sockaddr_in server_address;
|
||||
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(soket, (struct sockaddr *)&server_address,
|
||||
sizeof(server_address) ) < 0) {
|
||||
sprintf(msg, "Socket: Couldn't connect to socket server!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
|
||||
return soket;
|
||||
}
|
||||
|
||||
int Socket :: socket( void ) const
|
||||
{
|
||||
return soket;
|
||||
}
|
||||
|
||||
int Socket :: port( void ) const
|
||||
{
|
||||
return poort;
|
||||
}
|
||||
|
||||
int Socket :: accept( void )
|
||||
{
|
||||
if ( server )
|
||||
return ::accept( soket, NULL, NULL );
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Socket :: isValid( int socket )
|
||||
{
|
||||
return socket != -1;
|
||||
}
|
||||
|
||||
void Socket :: setBlocking( int socket, bool enable )
|
||||
{
|
||||
if ( !isValid( socket ) ) return;
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
int tmp = ::fcntl(socket, F_GETFL, 0);
|
||||
if ( tmp >= 0 )
|
||||
tmp = ::fcntl( socket, F_SETFL, enable ? (tmp &~ O_NONBLOCK) : (tmp | O_NONBLOCK) );
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
unsigned long non_block = !enable;
|
||||
ioctlsocket( socket, FIONBIO, &non_block );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void Socket :: close( void )
|
||||
{
|
||||
if ( !isValid( soket ) ) return;
|
||||
this->close( soket );
|
||||
soket = -1;
|
||||
}
|
||||
|
||||
void Socket :: close( int socket )
|
||||
{
|
||||
if ( !isValid( socket ) ) return;
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
::close( socket );
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
::closesocket( socket );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int Socket :: writeBuffer(const void *buffer, long bufferSize, int flags )
|
||||
{
|
||||
if ( !isValid( soket ) ) return -1;
|
||||
return send( soket, (const char *)buffer, bufferSize, flags );
|
||||
}
|
||||
|
||||
int Socket :: writeBuffer(int socket, const void *buffer, long bufferSize, int flags )
|
||||
{
|
||||
if ( !isValid( socket ) ) return -1;
|
||||
return send( socket, (const char *)buffer, bufferSize, flags );
|
||||
}
|
||||
|
||||
int Socket :: readBuffer(void *buffer, long bufferSize, int flags )
|
||||
{
|
||||
if ( !isValid( soket ) ) return -1;
|
||||
return recv( soket, (char *)buffer, bufferSize, flags );
|
||||
}
|
||||
|
||||
int Socket :: readBuffer(int socket, void *buffer, long bufferSize, int flags )
|
||||
{
|
||||
if ( !isValid( socket ) ) return -1;
|
||||
return recv( socket, (char *)buffer, bufferSize, flags );
|
||||
}
|
||||
|
||||
104
src/Sphere.cpp
Normal file
104
src/Sphere.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/***************************************************/
|
||||
/*! \class Sphere
|
||||
\brief STK sphere class.
|
||||
|
||||
This class implements a spherical ball with
|
||||
radius, mass, position, and velocity parameters.
|
||||
|
||||
by Perry R. Cook, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Sphere.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
Sphere::Sphere(double initRadius)
|
||||
{
|
||||
myRadius = initRadius;
|
||||
myMass = 1.0;
|
||||
myPosition = new Vector3D(0, 0, 0);
|
||||
myVelocity = new Vector3D(0, 0, 0);
|
||||
};
|
||||
|
||||
Sphere::~Sphere()
|
||||
{
|
||||
delete myPosition;
|
||||
delete myVelocity;
|
||||
}
|
||||
|
||||
void Sphere::setPosition(double anX, double aY, double aZ)
|
||||
{
|
||||
myPosition->setXYZ(anX, aY, aZ);
|
||||
};
|
||||
|
||||
void Sphere::setVelocity(double anX, double aY, double aZ)
|
||||
{
|
||||
myVelocity->setXYZ(anX, aY, aZ);
|
||||
};
|
||||
|
||||
void Sphere::setRadius(double aRadius)
|
||||
{
|
||||
myRadius = aRadius;
|
||||
};
|
||||
|
||||
void Sphere::setMass(double aMass)
|
||||
{
|
||||
myMass = aMass;
|
||||
};
|
||||
|
||||
Vector3D* Sphere::getPosition()
|
||||
{
|
||||
return myPosition;
|
||||
};
|
||||
|
||||
Vector3D* Sphere::getRelativePosition(Vector3D* aPosition)
|
||||
{
|
||||
workingVector.setXYZ(aPosition->getX() - myPosition->getX(),
|
||||
aPosition->getY() - myPosition->getY(),
|
||||
aPosition->getZ() - myPosition->getZ());
|
||||
return &workingVector;
|
||||
};
|
||||
|
||||
double Sphere::getVelocity(Vector3D* aVelocity)
|
||||
{
|
||||
aVelocity->setXYZ(myVelocity->getX(), myVelocity->getY(), myVelocity->getZ());
|
||||
return myVelocity->getLength();
|
||||
};
|
||||
|
||||
double Sphere::isInside(Vector3D *aPosition)
|
||||
{
|
||||
// Return directed distance from aPosition to spherical boundary ( <
|
||||
// 0 if inside).
|
||||
double distance;
|
||||
Vector3D *tempVector;
|
||||
|
||||
tempVector = this->getRelativePosition(aPosition);
|
||||
distance = tempVector->getLength();
|
||||
return distance - myRadius;
|
||||
};
|
||||
|
||||
double Sphere::getRadius()
|
||||
{
|
||||
return myRadius;
|
||||
};
|
||||
|
||||
double Sphere::getMass()
|
||||
{
|
||||
return myMass;
|
||||
};
|
||||
|
||||
void Sphere::addVelocity(double anX, double aY, double aZ)
|
||||
{
|
||||
myVelocity->setX(myVelocity->getX() + anX);
|
||||
myVelocity->setY(myVelocity->getY() + aY);
|
||||
myVelocity->setZ(myVelocity->getZ() + aZ);
|
||||
}
|
||||
|
||||
void Sphere::tick(double timeIncrement)
|
||||
{
|
||||
myPosition->setX(myPosition->getX() + (timeIncrement * myVelocity->getX()));
|
||||
myPosition->setY(myPosition->getY() + (timeIncrement * myVelocity->getY()));
|
||||
myPosition->setZ(myPosition->getZ() + (timeIncrement * myVelocity->getZ()));
|
||||
};
|
||||
|
||||
286
src/Stk.cpp
286
src/Stk.cpp
@@ -1,143 +1,143 @@
|
||||
/***************************************************/
|
||||
/*! \class Stk
|
||||
\brief STK base class
|
||||
|
||||
Nearly all STK classes inherit from this class.
|
||||
The global sample rate can be queried and
|
||||
modified via Stk. In addition, this class
|
||||
provides error handling and byte-swapping
|
||||
functions.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Stk.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
MY_FLOAT Stk :: srate = (MY_FLOAT) SRATE;
|
||||
const Stk::STK_FORMAT Stk :: STK_SINT8 = 1;
|
||||
const Stk::STK_FORMAT Stk :: STK_SINT16 = 2;
|
||||
const Stk::STK_FORMAT Stk :: STK_SINT32 = 8;
|
||||
const Stk::STK_FORMAT Stk :: STK_FLOAT32 = 16;
|
||||
const Stk::STK_FORMAT Stk :: STK_FLOAT64 = 32;
|
||||
|
||||
Stk :: Stk(void)
|
||||
{
|
||||
}
|
||||
|
||||
Stk :: ~Stk(void)
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Stk :: sampleRate(void)
|
||||
{
|
||||
return srate;
|
||||
}
|
||||
|
||||
void Stk :: setSampleRate(MY_FLOAT newRate)
|
||||
{
|
||||
if (newRate > 0)
|
||||
srate = newRate;
|
||||
}
|
||||
|
||||
void Stk :: swap16(unsigned char *ptr)
|
||||
{
|
||||
register unsigned char val;
|
||||
|
||||
// Swap 1st and 2nd bytes
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+1);
|
||||
*(ptr+1) = val;
|
||||
}
|
||||
|
||||
void Stk :: 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 Stk :: 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;
|
||||
}
|
||||
|
||||
#if defined(__OS_IRIX__) || defined(__OS_LINUX__)
|
||||
#include <unistd.h>
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
void Stk :: sleep(unsigned long milliseconds)
|
||||
{
|
||||
#if defined(__OS_WINDOWS__)
|
||||
Sleep((DWORD) milliseconds);
|
||||
#elif defined(__OS_IRIX__) || defined(__OS_LINUX__)
|
||||
usleep( (unsigned long) (milliseconds * 1000.0) );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Stk :: handleError( const char *message, StkError::TYPE type )
|
||||
{
|
||||
if (type == StkError::WARNING)
|
||||
fprintf(stderr, "\n%s\n\n", message);
|
||||
else if (type == StkError::DEBUG_WARNING) {
|
||||
#if defined(_STK_DEBUG_)
|
||||
fprintf(stderr, "\n%s\n\n", message);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// Print error message before throwing.
|
||||
fprintf(stderr, "\n%s\n\n", message);
|
||||
throw StkError(message, type);
|
||||
}
|
||||
}
|
||||
|
||||
StkError :: StkError(const char *p, TYPE tipe)
|
||||
: type(tipe)
|
||||
{
|
||||
strncpy(message, p, 256);
|
||||
}
|
||||
|
||||
StkError :: ~StkError(void)
|
||||
{
|
||||
}
|
||||
|
||||
void StkError :: printMessage(void)
|
||||
{
|
||||
printf("\n%s\n\n", message);
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class Stk
|
||||
\brief STK base class
|
||||
|
||||
Nearly all STK classes inherit from this class.
|
||||
The global sample rate can be queried and
|
||||
modified via Stk. In addition, this class
|
||||
provides error handling and byte-swapping
|
||||
functions.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Stk.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
MY_FLOAT Stk :: srate = (MY_FLOAT) SRATE;
|
||||
const Stk::STK_FORMAT Stk :: STK_SINT8 = 1;
|
||||
const Stk::STK_FORMAT Stk :: STK_SINT16 = 2;
|
||||
const Stk::STK_FORMAT Stk :: STK_SINT32 = 8;
|
||||
const Stk::STK_FORMAT Stk :: STK_FLOAT32 = 16;
|
||||
const Stk::STK_FORMAT Stk :: STK_FLOAT64 = 32;
|
||||
|
||||
Stk :: Stk(void)
|
||||
{
|
||||
}
|
||||
|
||||
Stk :: ~Stk(void)
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Stk :: sampleRate(void)
|
||||
{
|
||||
return srate;
|
||||
}
|
||||
|
||||
void Stk :: setSampleRate(MY_FLOAT newRate)
|
||||
{
|
||||
if (newRate > 0)
|
||||
srate = newRate;
|
||||
}
|
||||
|
||||
void Stk :: swap16(unsigned char *ptr)
|
||||
{
|
||||
register unsigned char val;
|
||||
|
||||
// Swap 1st and 2nd bytes
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+1);
|
||||
*(ptr+1) = val;
|
||||
}
|
||||
|
||||
void Stk :: 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 Stk :: 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;
|
||||
}
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
#include <unistd.h>
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
void Stk :: sleep(unsigned long milliseconds)
|
||||
{
|
||||
#if defined(__OS_WINDOWS__)
|
||||
Sleep((DWORD) milliseconds);
|
||||
#elif (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
usleep( (unsigned long) (milliseconds * 1000.0) );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Stk :: handleError( const char *message, StkError::TYPE type )
|
||||
{
|
||||
if (type == StkError::WARNING)
|
||||
fprintf(stderr, "\n%s\n\n", message);
|
||||
else if (type == StkError::DEBUG_WARNING) {
|
||||
#if defined(_STK_DEBUG_)
|
||||
fprintf(stderr, "\n%s\n\n", message);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// Print error message before throwing.
|
||||
fprintf(stderr, "\n%s\n\n", message);
|
||||
throw StkError(message, type);
|
||||
}
|
||||
}
|
||||
|
||||
StkError :: StkError(const char *p, TYPE tipe)
|
||||
: type(tipe)
|
||||
{
|
||||
strncpy(message, p, 256);
|
||||
}
|
||||
|
||||
StkError :: ~StkError(void)
|
||||
{
|
||||
}
|
||||
|
||||
void StkError :: printMessage(void)
|
||||
{
|
||||
printf("\n%s\n\n", message);
|
||||
}
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
/***************************************************/
|
||||
/*! \class SubNoise
|
||||
\brief STK sub-sampled noise generator.
|
||||
|
||||
Generates a new random number every "rate" ticks
|
||||
using the C rand() function. The quality of the
|
||||
rand() function varies from one OS to another.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "SubNoise.h"
|
||||
|
||||
SubNoise :: SubNoise(int subRate) : Noise()
|
||||
{
|
||||
rate = subRate;
|
||||
counter = rate;
|
||||
}
|
||||
SubNoise :: ~SubNoise()
|
||||
{
|
||||
}
|
||||
|
||||
int SubNoise :: subRate(void) const
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
void SubNoise :: setRate(int subRate)
|
||||
{
|
||||
if (subRate > 0)
|
||||
rate = subRate;
|
||||
}
|
||||
|
||||
MY_FLOAT SubNoise :: tick()
|
||||
{
|
||||
if ( ++counter > rate ) {
|
||||
Noise::tick();
|
||||
counter = 1;
|
||||
}
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class SubNoise
|
||||
\brief STK sub-sampled noise generator.
|
||||
|
||||
Generates a new random number every "rate" ticks
|
||||
using the C rand() function. The quality of the
|
||||
rand() function varies from one OS to another.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "SubNoise.h"
|
||||
|
||||
SubNoise :: SubNoise(int subRate) : Noise()
|
||||
{
|
||||
rate = subRate;
|
||||
counter = rate;
|
||||
}
|
||||
SubNoise :: ~SubNoise()
|
||||
{
|
||||
}
|
||||
|
||||
int SubNoise :: subRate(void) const
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
void SubNoise :: setRate(int subRate)
|
||||
{
|
||||
if (subRate > 0)
|
||||
rate = subRate;
|
||||
}
|
||||
|
||||
MY_FLOAT SubNoise :: tick()
|
||||
{
|
||||
if ( ++counter > rate ) {
|
||||
Noise::tick();
|
||||
counter = 1;
|
||||
}
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
212
src/Table.cpp
212
src/Table.cpp
@@ -1,106 +1,106 @@
|
||||
/***************************************************/
|
||||
/*! \class Table
|
||||
\brief STK table lookup class.
|
||||
|
||||
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.
|
||||
|
||||
An StkError will be thrown if the table file
|
||||
is not found.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Table.h"
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <iostream.h>
|
||||
|
||||
Table :: Table(char *fileName)
|
||||
{
|
||||
char message[256];
|
||||
|
||||
// Use the system call "stat" to determine the file length
|
||||
struct stat filestat;
|
||||
if ( stat(fileName, &filestat) == -1 ) {
|
||||
sprintf(message, "Table: Couldn't stat or find file (%s).", fileName);
|
||||
handleError( message, 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(message, "Table: Couldn't open or find file (%s).", fileName);
|
||||
handleError( message, 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;
|
||||
}
|
||||
|
||||
Table :: ~Table()
|
||||
{
|
||||
delete [ ] data;
|
||||
}
|
||||
|
||||
long Table :: getLength() const
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
MY_FLOAT Table :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT Table :: tick(MY_FLOAT index)
|
||||
{
|
||||
MY_FLOAT alpha;
|
||||
long temp;
|
||||
|
||||
if (index > length-1) {
|
||||
cerr << "Table: Index (" << index << ") exceeds table length ... sticking at end!" << endl;
|
||||
index = length-1;
|
||||
}
|
||||
else if (index < 0.0) {
|
||||
cerr << "Table: Index (" << index << ") is less than zero ... setting to zero!" << endl;
|
||||
index = 0.0;
|
||||
}
|
||||
|
||||
// Index 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 *Table :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class Table
|
||||
\brief STK table lookup class.
|
||||
|
||||
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.
|
||||
|
||||
An StkError will be thrown if the table file
|
||||
is not found.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Table.h"
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <iostream.h>
|
||||
|
||||
Table :: Table(char *fileName)
|
||||
{
|
||||
char message[256];
|
||||
|
||||
// Use the system call "stat" to determine the file length
|
||||
struct stat filestat;
|
||||
if ( stat(fileName, &filestat) == -1 ) {
|
||||
sprintf(message, "Table: Couldn't stat or find file (%s).", fileName);
|
||||
handleError( message, 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(message, "Table: Couldn't open or find file (%s).", fileName);
|
||||
handleError( message, 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;
|
||||
}
|
||||
|
||||
Table :: ~Table()
|
||||
{
|
||||
delete [ ] data;
|
||||
}
|
||||
|
||||
long Table :: getLength() const
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
MY_FLOAT Table :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT Table :: tick(MY_FLOAT index)
|
||||
{
|
||||
MY_FLOAT alpha;
|
||||
long temp;
|
||||
|
||||
if (index > length-1) {
|
||||
cerr << "Table: Index (" << index << ") exceeds table length ... sticking at end!" << endl;
|
||||
index = length-1;
|
||||
}
|
||||
else if (index < 0.0) {
|
||||
cerr << "Table: Index (" << index << ") is less than zero ... setting to zero!" << endl;
|
||||
index = 0.0;
|
||||
}
|
||||
|
||||
// Index 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 *Table :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
648
src/TcpWvIn.cpp
648
src/TcpWvIn.cpp
@@ -1,323 +1,325 @@
|
||||
/***************************************************/
|
||||
/*! \class TcpWvIn
|
||||
\brief STK internet streaming input class.
|
||||
|
||||
This protected Wvin subclass can read streamed
|
||||
data over a network via a TCP socket connection.
|
||||
The data is assumed in big-endian, or network,
|
||||
byte order.
|
||||
|
||||
TcpWvIn supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which return
|
||||
samples produced by averaging across sample
|
||||
frames, from the tickFrame() methods, which
|
||||
return pointers to multi-channel sample frames.
|
||||
For single-channel data, these methods return
|
||||
equivalent values.
|
||||
|
||||
This class starts a socket server, which waits
|
||||
for a single remote connection. The default
|
||||
data type for the incoming stream is signed
|
||||
16-bit integers, though any of the defined
|
||||
STK_FORMATs are permissible.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "TcpWvIn.h"
|
||||
|
||||
#define N_BUFFERS 10
|
||||
|
||||
// Do OS dependent includes
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
extern "C" THREAD_RETURN THREAD_TYPE inputThread(void * ptr)
|
||||
{
|
||||
thread_info *info = (thread_info *)ptr;
|
||||
|
||||
while ( !info->finished ) {
|
||||
Thread::test();
|
||||
((TcpWvIn *) info->object)->receive();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TcpWvIn :: TcpWvIn( int port )
|
||||
{
|
||||
init( port );
|
||||
}
|
||||
|
||||
TcpWvIn :: ~TcpWvIn()
|
||||
{
|
||||
// Close down the thread.
|
||||
connected = false;
|
||||
threadInfo.finished = true;
|
||||
thread->wait( -1 );
|
||||
delete thread;
|
||||
|
||||
delete soket;
|
||||
|
||||
if (buffer)
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
void TcpWvIn :: init( int port )
|
||||
{
|
||||
buffer = 0;
|
||||
bufferBytes = 0;
|
||||
connected = false;
|
||||
|
||||
// Start socket server ... an error can be thrown from the Socket class.
|
||||
soket = new Socket( port );
|
||||
|
||||
thread = new Thread();
|
||||
threadInfo.finished = false;
|
||||
threadInfo.object = (void *) this;
|
||||
|
||||
// Start the input thread.
|
||||
if ( !thread->start( &inputThread, &threadInfo ) ) {
|
||||
sprintf(msg, "TcpWvIn: Unable to start input thread!");
|
||||
handleError( msg, StkError::PROCESS_THREAD );
|
||||
}
|
||||
}
|
||||
|
||||
void TcpWvIn :: listen(unsigned int nChannels, Stk::STK_FORMAT format)
|
||||
{
|
||||
mutex.lock();
|
||||
|
||||
if ( connected ) {
|
||||
soket->close(fd);
|
||||
}
|
||||
|
||||
if (nChannels < 1) {
|
||||
sprintf(msg, "TcpWvOut: the channel argument (%d) must be greater than zero.", nChannels);
|
||||
handleError( msg, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
unsigned int lastChannels = channels;
|
||||
channels = nChannels;
|
||||
|
||||
if ( format == STK_SINT16 ) dataSize = 2;
|
||||
else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataSize = 4;
|
||||
else if ( format == STK_FLOAT64 ) dataSize = 8;
|
||||
else if ( format == STK_SINT8 ) dataSize = 1;
|
||||
else {
|
||||
sprintf( msg, "TcpWvIn: Unknown data type specified (%ld).", format );
|
||||
handleError(msg, StkError::FUNCTION_ARGUMENT);
|
||||
}
|
||||
dataType = format;
|
||||
|
||||
int lastBufferBytes = bufferBytes;
|
||||
bufferBytes = CHUNK_SIZE * N_BUFFERS * channels * dataSize;
|
||||
|
||||
// Allocate new memory if necessary.
|
||||
if ( lastBufferBytes < bufferBytes ) {
|
||||
if ( buffer) delete [] buffer;
|
||||
buffer = (char *) new char[bufferBytes];
|
||||
}
|
||||
if ( lastChannels < channels ) {
|
||||
if ( data ) delete [] data;
|
||||
data = (MY_FLOAT *) new MY_FLOAT[CHUNK_SIZE*channels];
|
||||
if ( lastOutput ) delete [] lastOutput;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
}
|
||||
|
||||
WvIn::reset();
|
||||
counter = 0;
|
||||
writePoint = 0;
|
||||
bytesFilled = 0;
|
||||
|
||||
// Accept a connection.
|
||||
printf("Listening for connection on port %d ... ", soket->port());
|
||||
fd = soket->accept();
|
||||
if ( fd < 0) {
|
||||
sprintf( msg, "TcpWvIn: Couldn't accept connection request!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
printf(" connection made!\n\n");
|
||||
|
||||
// Start input thread.
|
||||
connected = true;
|
||||
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void TcpWvIn :: receive( void )
|
||||
{
|
||||
if ( !connected ) {
|
||||
Stk::sleep(100);
|
||||
return;
|
||||
}
|
||||
|
||||
fd_set mask;
|
||||
FD_ZERO(&mask);
|
||||
FD_SET(fd, &mask);
|
||||
|
||||
// The select function will block until data is available for reading.
|
||||
select(fd+1, &mask, (fd_set *)0, (fd_set *)0, NULL);
|
||||
|
||||
if (FD_ISSET(fd, &mask)) {
|
||||
mutex.lock();
|
||||
long unfilled = bufferBytes - bytesFilled;
|
||||
if ( unfilled > 0 ) {
|
||||
// There's room in our buffer for more data.
|
||||
long endPoint = writePoint + unfilled;
|
||||
if ( endPoint > bufferBytes ) unfilled -= endPoint - bufferBytes;
|
||||
int i = Socket::readBuffer(fd, (void *)&buffer[writePoint], unfilled, 0);
|
||||
if ( i <= 0 ) {
|
||||
printf("The remote TcpWvIn socket connection has closed.\n\n");
|
||||
connected = false;
|
||||
mutex.unlock();
|
||||
return;
|
||||
}
|
||||
bytesFilled += i;
|
||||
writePoint += i;
|
||||
if (writePoint == bufferBytes)
|
||||
writePoint = 0;
|
||||
mutex.unlock();
|
||||
}
|
||||
else {
|
||||
// Sleep 10 milliseconds AFTER unlocking mutex.
|
||||
mutex.unlock();
|
||||
Stk::sleep( 10 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int TcpWvIn :: readData( void )
|
||||
{
|
||||
// We have two potential courses of action should this method
|
||||
// be called and the input 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).
|
||||
|
||||
// Wait until data is ready.
|
||||
long bytes = CHUNK_SIZE * channels * dataSize;
|
||||
while ( connected && bytesFilled < bytes )
|
||||
Stk::sleep( 10 );
|
||||
|
||||
if ( !connected && bytesFilled == 0 ) return 0;
|
||||
bytes = ( bytesFilled < bytes ) ? bytesFilled : bytes;
|
||||
|
||||
// Copy samples from buffer to data.
|
||||
long samples = bytes / dataSize;
|
||||
mutex.lock();
|
||||
if ( dataType == STK_SINT16 ) {
|
||||
gain = 1.0 / 32767.0;
|
||||
SINT16 *buf = (SINT16 *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *) buf);
|
||||
#endif
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
data[i] *= gain;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_SINT32 ) {
|
||||
gain = 1.0 / 2147483647.0;
|
||||
SINT32 *buf = (SINT32 *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *) buf);
|
||||
#endif
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
data[i] *= gain;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_FLOAT32 ) {
|
||||
FLOAT32 *buf = (FLOAT32 *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *) buf);
|
||||
#endif
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_FLOAT64 ) {
|
||||
FLOAT64 *buf = (FLOAT64 *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap64((unsigned char *) buf);
|
||||
#endif
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_SINT8 ) {
|
||||
gain = 1.0 / 127.0;
|
||||
signed char *buf = (signed char *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
data[i] *= gain;
|
||||
}
|
||||
}
|
||||
|
||||
readPoint += bytes;
|
||||
if ( readPoint == bufferBytes )
|
||||
readPoint = 0;
|
||||
bytesFilled -= bytes;
|
||||
if ( bytesFilled < 0 )
|
||||
bytesFilled = 0;
|
||||
|
||||
mutex.unlock();
|
||||
return samples / channels;
|
||||
}
|
||||
|
||||
bool TcpWvIn :: isConnected(void)
|
||||
{
|
||||
if ( bytesFilled > 0 || counter > 0 )
|
||||
return true;
|
||||
else
|
||||
return connected;
|
||||
}
|
||||
|
||||
const MY_FLOAT *TcpWvIn :: lastFrame(void) const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT TcpWvIn :: lastOut(void) const
|
||||
{
|
||||
return WvIn::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT TcpWvIn :: tick(void)
|
||||
{
|
||||
return WvIn::tick();
|
||||
}
|
||||
|
||||
MY_FLOAT *TcpWvIn :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
return WvIn::tick( vector, vectorSize );
|
||||
}
|
||||
|
||||
const MY_FLOAT *TcpWvIn :: tickFrame(void)
|
||||
{
|
||||
// If no connection and we've output all samples in the queue, return.
|
||||
if ( !connected && bytesFilled == 0 && counter == 0 ) return lastOutput;
|
||||
|
||||
if (counter == 0)
|
||||
counter = readData();
|
||||
|
||||
long temp = (CHUNK_SIZE - counter) * channels;
|
||||
for (unsigned int i=0; i<channels; i++)
|
||||
lastOutput[i] = data[temp++];
|
||||
|
||||
counter--;
|
||||
if ( counter < 0 )
|
||||
counter = 0;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *TcpWvIn :: tickFrame(MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
return WvIn::tickFrame( frameVector, frames );
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class TcpWvIn
|
||||
\brief STK internet streaming input class.
|
||||
|
||||
This protected Wvin subclass can read streamed
|
||||
data over a network via a TCP socket connection.
|
||||
The data is assumed in big-endian, or network,
|
||||
byte order.
|
||||
|
||||
TcpWvIn supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which return
|
||||
samples produced by averaging across sample
|
||||
frames, from the tickFrame() methods, which
|
||||
return pointers to multi-channel sample frames.
|
||||
For single-channel data, these methods return
|
||||
equivalent values.
|
||||
|
||||
This class starts a socket server, which waits
|
||||
for a single remote connection. The default
|
||||
data type for the incoming stream is signed
|
||||
16-bit integers, though any of the defined
|
||||
STK_FORMATs are permissible.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "TcpWvIn.h"
|
||||
|
||||
#define N_BUFFERS 10
|
||||
|
||||
// Do OS dependent includes
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
extern "C" THREAD_RETURN THREAD_TYPE inputThread(void * ptr)
|
||||
{
|
||||
thread_info *info = (thread_info *)ptr;
|
||||
|
||||
while ( !info->finished ) {
|
||||
Thread::test();
|
||||
((TcpWvIn *) info->object)->receive();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TcpWvIn :: TcpWvIn( int port )
|
||||
{
|
||||
init( port );
|
||||
}
|
||||
|
||||
TcpWvIn :: ~TcpWvIn()
|
||||
{
|
||||
// Close down the thread.
|
||||
connected = false;
|
||||
threadInfo.finished = true;
|
||||
thread->wait( -1 );
|
||||
delete thread;
|
||||
|
||||
delete soket;
|
||||
|
||||
if (buffer)
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
void TcpWvIn :: init( int port )
|
||||
{
|
||||
buffer = 0;
|
||||
bufferBytes = 0;
|
||||
connected = false;
|
||||
|
||||
// Start socket server ... an error can be thrown from the Socket class.
|
||||
soket = new Socket( port );
|
||||
|
||||
thread = new Thread();
|
||||
threadInfo.finished = false;
|
||||
threadInfo.object = (void *) this;
|
||||
|
||||
// Start the input thread.
|
||||
if ( !thread->start( &inputThread, &threadInfo ) ) {
|
||||
sprintf(msg, "TcpWvIn: Unable to start input thread!");
|
||||
handleError( msg, StkError::PROCESS_THREAD );
|
||||
}
|
||||
}
|
||||
|
||||
void TcpWvIn :: listen(unsigned int nChannels, Stk::STK_FORMAT format)
|
||||
{
|
||||
mutex.lock();
|
||||
|
||||
if ( connected ) {
|
||||
soket->close(fd);
|
||||
}
|
||||
|
||||
if (nChannels < 1) {
|
||||
sprintf(msg, "TcpWvOut: the channel argument (%d) must be greater than zero.", nChannels);
|
||||
handleError( msg, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
unsigned int lastChannels = channels;
|
||||
channels = nChannels;
|
||||
|
||||
if ( format == STK_SINT16 ) dataSize = 2;
|
||||
else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataSize = 4;
|
||||
else if ( format == STK_FLOAT64 ) dataSize = 8;
|
||||
else if ( format == STK_SINT8 ) dataSize = 1;
|
||||
else {
|
||||
sprintf( msg, "TcpWvIn: Unknown data type specified (%ld).", format );
|
||||
handleError(msg, StkError::FUNCTION_ARGUMENT);
|
||||
}
|
||||
dataType = format;
|
||||
|
||||
int lastBufferBytes = bufferBytes;
|
||||
bufferBytes = CHUNK_SIZE * N_BUFFERS * channels * dataSize;
|
||||
|
||||
// Allocate new memory if necessary.
|
||||
if ( lastBufferBytes < bufferBytes ) {
|
||||
if ( buffer) delete [] buffer;
|
||||
buffer = (char *) new char[bufferBytes];
|
||||
}
|
||||
if ( lastChannels < channels ) {
|
||||
if ( data ) delete [] data;
|
||||
data = (MY_FLOAT *) new MY_FLOAT[CHUNK_SIZE*channels];
|
||||
if ( lastOutput ) delete [] lastOutput;
|
||||
lastOutput = (MY_FLOAT *) new MY_FLOAT[channels];
|
||||
}
|
||||
|
||||
WvIn::reset();
|
||||
counter = 0;
|
||||
writePoint = 0;
|
||||
bytesFilled = 0;
|
||||
|
||||
// Accept a connection.
|
||||
printf("Listening for connection on port %d ... ", soket->port());
|
||||
fd = soket->accept();
|
||||
if ( fd < 0) {
|
||||
sprintf( msg, "TcpWvIn: Couldn't accept connection request!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
printf(" connection made!\n\n");
|
||||
|
||||
// Start input thread.
|
||||
connected = true;
|
||||
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void TcpWvIn :: receive( void )
|
||||
{
|
||||
if ( !connected ) {
|
||||
Stk::sleep(100);
|
||||
return;
|
||||
}
|
||||
|
||||
fd_set mask;
|
||||
FD_ZERO(&mask);
|
||||
FD_SET(fd, &mask);
|
||||
|
||||
// The select function will block until data is available for reading.
|
||||
select(fd+1, &mask, (fd_set *)0, (fd_set *)0, NULL);
|
||||
|
||||
if (FD_ISSET(fd, &mask)) {
|
||||
mutex.lock();
|
||||
long unfilled = bufferBytes - bytesFilled;
|
||||
if ( unfilled > 0 ) {
|
||||
// There's room in our buffer for more data.
|
||||
long endPoint = writePoint + unfilled;
|
||||
if ( endPoint > bufferBytes ) unfilled -= endPoint - bufferBytes;
|
||||
int i = Socket::readBuffer(fd, (void *)&buffer[writePoint], unfilled, 0);
|
||||
if ( i <= 0 ) {
|
||||
printf("The remote TcpWvIn socket connection has closed.\n\n");
|
||||
connected = false;
|
||||
mutex.unlock();
|
||||
return;
|
||||
}
|
||||
bytesFilled += i;
|
||||
writePoint += i;
|
||||
if (writePoint == bufferBytes)
|
||||
writePoint = 0;
|
||||
mutex.unlock();
|
||||
}
|
||||
else {
|
||||
// Sleep 10 milliseconds AFTER unlocking mutex.
|
||||
mutex.unlock();
|
||||
Stk::sleep( 10 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int TcpWvIn :: readData( void )
|
||||
{
|
||||
// We have two potential courses of action should this method
|
||||
// be called and the input 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).
|
||||
|
||||
// Wait until data is ready.
|
||||
long bytes = CHUNK_SIZE * channels * dataSize;
|
||||
while ( connected && bytesFilled < bytes )
|
||||
Stk::sleep( 10 );
|
||||
|
||||
if ( !connected && bytesFilled == 0 ) return 0;
|
||||
bytes = ( bytesFilled < bytes ) ? bytesFilled : bytes;
|
||||
|
||||
// Copy samples from buffer to data.
|
||||
long samples = bytes / dataSize;
|
||||
mutex.lock();
|
||||
if ( dataType == STK_SINT16 ) {
|
||||
gain = 1.0 / 32767.0;
|
||||
SINT16 *buf = (SINT16 *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16((unsigned char *) buf);
|
||||
#endif
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
data[i] *= gain;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_SINT32 ) {
|
||||
gain = 1.0 / 2147483647.0;
|
||||
SINT32 *buf = (SINT32 *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *) buf);
|
||||
#endif
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
data[i] *= gain;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_FLOAT32 ) {
|
||||
FLOAT32 *buf = (FLOAT32 *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32((unsigned char *) buf);
|
||||
#endif
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_FLOAT64 ) {
|
||||
FLOAT64 *buf = (FLOAT64 *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap64((unsigned char *) buf);
|
||||
#endif
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_SINT8 ) {
|
||||
gain = 1.0 / 127.0;
|
||||
signed char *buf = (signed char *) (buffer+readPoint);
|
||||
for (int i=0; i<samples; i++ ) {
|
||||
data[i] = (MY_FLOAT) *buf++;
|
||||
data[i] *= gain;
|
||||
}
|
||||
}
|
||||
|
||||
readPoint += bytes;
|
||||
if ( readPoint == bufferBytes )
|
||||
readPoint = 0;
|
||||
bytesFilled -= bytes;
|
||||
if ( bytesFilled < 0 )
|
||||
bytesFilled = 0;
|
||||
|
||||
mutex.unlock();
|
||||
return samples / channels;
|
||||
}
|
||||
|
||||
bool TcpWvIn :: isConnected(void)
|
||||
{
|
||||
if ( bytesFilled > 0 || counter > 0 )
|
||||
return true;
|
||||
else
|
||||
return connected;
|
||||
}
|
||||
|
||||
const MY_FLOAT *TcpWvIn :: lastFrame(void) const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT TcpWvIn :: lastOut(void) const
|
||||
{
|
||||
return WvIn::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT TcpWvIn :: tick(void)
|
||||
{
|
||||
return WvIn::tick();
|
||||
}
|
||||
|
||||
MY_FLOAT *TcpWvIn :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
return WvIn::tick( vector, vectorSize );
|
||||
}
|
||||
|
||||
const MY_FLOAT *TcpWvIn :: tickFrame(void)
|
||||
{
|
||||
// If no connection and we've output all samples in the queue, return.
|
||||
if ( !connected && bytesFilled == 0 && counter == 0 ) return lastOutput;
|
||||
|
||||
if (counter == 0)
|
||||
counter = readData();
|
||||
|
||||
long temp = (CHUNK_SIZE - counter) * channels;
|
||||
for (unsigned int i=0; i<channels; i++)
|
||||
lastOutput[i] = data[temp++];
|
||||
|
||||
counter--;
|
||||
if ( counter < 0 )
|
||||
counter = 0;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT *TcpWvIn :: tickFrame(MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
return WvIn::tickFrame( frameVector, frames );
|
||||
}
|
||||
|
||||
408
src/TcpWvOut.cpp
408
src/TcpWvOut.cpp
@@ -1,204 +1,204 @@
|
||||
/***************************************************/
|
||||
/*! \class TcpWvOut
|
||||
\brief STK internet streaming output class.
|
||||
|
||||
This protected WvOut subclass can stream
|
||||
data over a network via a TCP socket connection.
|
||||
The data is converted to big-endian byte order,
|
||||
if necessary, before being transmitted.
|
||||
|
||||
TcpWvOut supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which output
|
||||
single samples to all channels in a sample
|
||||
frame, from the tickFrame() method, which
|
||||
takes a pointer to multi-channel sample
|
||||
frame data.
|
||||
|
||||
This class connects to a socket server, the
|
||||
port and IP address of which must be specified
|
||||
as constructor arguments. The default data
|
||||
type is signed 16-bit integers but any of the
|
||||
defined STK_FORMATs are permissible.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "TcpWvOut.h"
|
||||
#include <string.h>
|
||||
|
||||
TcpWvOut :: TcpWvOut()
|
||||
{
|
||||
buffer = 0;
|
||||
soket = 0;
|
||||
}
|
||||
|
||||
TcpWvOut :: TcpWvOut(int port, const char *hostname, unsigned int nChannels, Stk::STK_FORMAT format)
|
||||
{
|
||||
buffer = 0;
|
||||
soket = 0;
|
||||
connect( port, hostname, nChannels, format );
|
||||
}
|
||||
|
||||
TcpWvOut :: ~TcpWvOut()
|
||||
{
|
||||
disconnect();
|
||||
delete soket;
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
void TcpWvOut :: connect(int port, const char *hostname, unsigned int nChannels, Stk::STK_FORMAT format)
|
||||
{
|
||||
if ( soket && soket->isValid( soket->socket() ) )
|
||||
disconnect();
|
||||
|
||||
if (nChannels < 1) {
|
||||
sprintf(msg, "TcpWvOut: the channel argument (%d) must be greater than zero.", nChannels);
|
||||
handleError( msg, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
unsigned int lastChannels = channels;
|
||||
channels = nChannels;
|
||||
|
||||
if ( format == STK_SINT8 ) dataSize = 1;
|
||||
else if ( format == STK_SINT16 ) dataSize = 2;
|
||||
else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataSize = 4;
|
||||
else if ( format == STK_FLOAT64 ) dataSize = 8;
|
||||
else {
|
||||
sprintf( msg, "TcpWvOut: Unknown data type specified (%ld).", format );
|
||||
handleError(msg, StkError::FUNCTION_ARGUMENT);
|
||||
}
|
||||
dataType = format;
|
||||
|
||||
if ( !soket )
|
||||
soket = new Socket( port, hostname );
|
||||
else
|
||||
soket->connect( port, hostname );
|
||||
|
||||
// Allocate new memory if necessary.
|
||||
if ( lastChannels < channels ) {
|
||||
if ( data ) delete [] data;
|
||||
data = (MY_FLOAT *) new MY_FLOAT[BUFFER_SIZE*channels];
|
||||
if ( buffer) delete [] buffer;
|
||||
long bytes = dataSize * BUFFER_SIZE * channels;
|
||||
buffer = (char *) new char[bytes];
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
void TcpWvOut :: disconnect(void)
|
||||
{
|
||||
if ( soket ) {
|
||||
writeData( counter );
|
||||
soket->close();
|
||||
}
|
||||
}
|
||||
|
||||
void TcpWvOut :: writeData( long frames )
|
||||
{
|
||||
if ( dataType == STK_SINT8 ) {
|
||||
signed char *ptr = (signed char *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ )
|
||||
*ptr++ = (signed char) (data[k] * 127.0);
|
||||
}
|
||||
else if ( dataType == STK_SINT16 ) {
|
||||
SINT16 *ptr = (SINT16 *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ ) {
|
||||
*ptr = (SINT16) (data[k] * 32767.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)ptr);
|
||||
#endif
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_SINT32 ) {
|
||||
SINT32 *ptr = (SINT32 *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ ) {
|
||||
*ptr = (SINT32) (data[k] * 2147483647.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32 ((unsigned char *)ptr);
|
||||
#endif
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_FLOAT32 ) {
|
||||
FLOAT32 *ptr = (FLOAT32 *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ ) {
|
||||
*ptr = (FLOAT32) data[k];
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32 ((unsigned char *)ptr);
|
||||
#endif
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_FLOAT64 ) {
|
||||
FLOAT64 *ptr = (FLOAT64 *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ ) {
|
||||
*ptr = (FLOAT64) data[k];
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap64 ((unsigned char *)ptr);
|
||||
#endif
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
long bytes = dataSize * frames * channels;
|
||||
if ( soket->writeBuffer( (const void *)buffer, bytes, 0 ) < 0 ) {
|
||||
sprintf(msg, "TcpWvOut: connection to socket server failed!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long TcpWvOut :: getFrames( void ) const
|
||||
{
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
MY_FLOAT TcpWvOut :: getTime( void ) const
|
||||
{
|
||||
return (MY_FLOAT) totalCount / Stk::sampleRate();
|
||||
}
|
||||
|
||||
void TcpWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
if ( !soket || !soket->isValid( soket->socket() ) ) return;
|
||||
|
||||
for ( unsigned int j=0; j<channels; j++ )
|
||||
data[counter*channels+j] = sample;
|
||||
|
||||
counter++;
|
||||
totalCount++;
|
||||
|
||||
if ( counter == BUFFER_SIZE ) {
|
||||
writeData( BUFFER_SIZE );
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TcpWvOut :: tick(const MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
if ( !soket || !soket->isValid( soket->socket() ) ) return;
|
||||
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
tick( vector[i] );
|
||||
}
|
||||
|
||||
void TcpWvOut :: tickFrame(const MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
if ( !soket || !soket->isValid( soket->socket() ) ) return;
|
||||
|
||||
unsigned int j;
|
||||
for ( unsigned int i=0; i<frames; i++ ) {
|
||||
for ( j=0; j<channels; j++ ) {
|
||||
data[counter*channels+j] = frameVector[i*channels+j];
|
||||
}
|
||||
counter++;
|
||||
totalCount++;
|
||||
|
||||
if ( counter == BUFFER_SIZE ) {
|
||||
writeData( BUFFER_SIZE );
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class TcpWvOut
|
||||
\brief STK internet streaming output class.
|
||||
|
||||
This protected WvOut subclass can stream
|
||||
data over a network via a TCP socket connection.
|
||||
The data is converted to big-endian byte order,
|
||||
if necessary, before being transmitted.
|
||||
|
||||
TcpWvOut supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which output
|
||||
single samples to all channels in a sample
|
||||
frame, from the tickFrame() method, which
|
||||
takes a pointer to multi-channel sample
|
||||
frame data.
|
||||
|
||||
This class connects to a socket server, the
|
||||
port and IP address of which must be specified
|
||||
as constructor arguments. The default data
|
||||
type is signed 16-bit integers but any of the
|
||||
defined STK_FORMATs are permissible.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "TcpWvOut.h"
|
||||
#include <string.h>
|
||||
|
||||
TcpWvOut :: TcpWvOut()
|
||||
{
|
||||
buffer = 0;
|
||||
soket = 0;
|
||||
}
|
||||
|
||||
TcpWvOut :: TcpWvOut(int port, const char *hostname, unsigned int nChannels, Stk::STK_FORMAT format)
|
||||
{
|
||||
buffer = 0;
|
||||
soket = 0;
|
||||
connect( port, hostname, nChannels, format );
|
||||
}
|
||||
|
||||
TcpWvOut :: ~TcpWvOut()
|
||||
{
|
||||
disconnect();
|
||||
delete soket;
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
void TcpWvOut :: connect(int port, const char *hostname, unsigned int nChannels, Stk::STK_FORMAT format)
|
||||
{
|
||||
if ( soket && soket->isValid( soket->socket() ) )
|
||||
disconnect();
|
||||
|
||||
if (nChannels < 1) {
|
||||
sprintf(msg, "TcpWvOut: the channel argument (%d) must be greater than zero.", nChannels);
|
||||
handleError( msg, StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
unsigned int lastChannels = channels;
|
||||
channels = nChannels;
|
||||
|
||||
if ( format == STK_SINT8 ) dataSize = 1;
|
||||
else if ( format == STK_SINT16 ) dataSize = 2;
|
||||
else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataSize = 4;
|
||||
else if ( format == STK_FLOAT64 ) dataSize = 8;
|
||||
else {
|
||||
sprintf( msg, "TcpWvOut: Unknown data type specified (%ld).", format );
|
||||
handleError(msg, StkError::FUNCTION_ARGUMENT);
|
||||
}
|
||||
dataType = format;
|
||||
|
||||
if ( !soket )
|
||||
soket = new Socket( port, hostname );
|
||||
else
|
||||
soket->connect( port, hostname );
|
||||
|
||||
// Allocate new memory if necessary.
|
||||
if ( lastChannels < channels ) {
|
||||
if ( data ) delete [] data;
|
||||
data = (MY_FLOAT *) new MY_FLOAT[BUFFER_SIZE*channels];
|
||||
if ( buffer) delete [] buffer;
|
||||
long bytes = dataSize * BUFFER_SIZE * channels;
|
||||
buffer = (char *) new char[bytes];
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
void TcpWvOut :: disconnect(void)
|
||||
{
|
||||
if ( soket ) {
|
||||
writeData( counter );
|
||||
soket->close();
|
||||
}
|
||||
}
|
||||
|
||||
void TcpWvOut :: writeData( long frames )
|
||||
{
|
||||
if ( dataType == STK_SINT8 ) {
|
||||
signed char *ptr = (signed char *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ )
|
||||
*ptr++ = (signed char) (data[k] * 127.0);
|
||||
}
|
||||
else if ( dataType == STK_SINT16 ) {
|
||||
SINT16 *ptr = (SINT16 *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ ) {
|
||||
*ptr = (SINT16) (data[k] * 32767.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap16 ((unsigned char *)ptr);
|
||||
#endif
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_SINT32 ) {
|
||||
SINT32 *ptr = (SINT32 *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ ) {
|
||||
*ptr = (SINT32) (data[k] * 2147483647.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32 ((unsigned char *)ptr);
|
||||
#endif
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_FLOAT32 ) {
|
||||
FLOAT32 *ptr = (FLOAT32 *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ ) {
|
||||
*ptr = (FLOAT32) data[k];
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap32 ((unsigned char *)ptr);
|
||||
#endif
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else if ( dataType == STK_FLOAT64 ) {
|
||||
FLOAT64 *ptr = (FLOAT64 *) buffer;
|
||||
for ( unsigned long k=0; k<frames*channels; k++ ) {
|
||||
*ptr = (FLOAT64) data[k];
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
swap64 ((unsigned char *)ptr);
|
||||
#endif
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
long bytes = dataSize * frames * channels;
|
||||
if ( soket->writeBuffer( (const void *)buffer, bytes, 0 ) < 0 ) {
|
||||
sprintf(msg, "TcpWvOut: connection to socket server failed!");
|
||||
handleError( msg, StkError::PROCESS_SOCKET );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long TcpWvOut :: getFrames( void ) const
|
||||
{
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
MY_FLOAT TcpWvOut :: getTime( void ) const
|
||||
{
|
||||
return (MY_FLOAT) totalCount / Stk::sampleRate();
|
||||
}
|
||||
|
||||
void TcpWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
if ( !soket || !soket->isValid( soket->socket() ) ) return;
|
||||
|
||||
for ( unsigned int j=0; j<channels; j++ )
|
||||
data[counter*channels+j] = sample;
|
||||
|
||||
counter++;
|
||||
totalCount++;
|
||||
|
||||
if ( counter == BUFFER_SIZE ) {
|
||||
writeData( BUFFER_SIZE );
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TcpWvOut :: tick(const MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
if ( !soket || !soket->isValid( soket->socket() ) ) return;
|
||||
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
tick( vector[i] );
|
||||
}
|
||||
|
||||
void TcpWvOut :: tickFrame(const MY_FLOAT *frameVector, unsigned int frames)
|
||||
{
|
||||
if ( !soket || !soket->isValid( soket->socket() ) ) return;
|
||||
|
||||
unsigned int j;
|
||||
for ( unsigned int i=0; i<frames; i++ ) {
|
||||
for ( j=0; j<channels; j++ ) {
|
||||
data[counter*channels+j] = frameVector[i*channels+j];
|
||||
}
|
||||
counter++;
|
||||
totalCount++;
|
||||
|
||||
if ( counter == BUFFER_SIZE ) {
|
||||
writeData( BUFFER_SIZE );
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
278
src/Thread.cpp
278
src/Thread.cpp
@@ -1,139 +1,139 @@
|
||||
/***************************************************/
|
||||
/*! \class Thread
|
||||
\brief STK thread class.
|
||||
|
||||
This class provides a uniform interface for
|
||||
cross-platform thread use. On Linux and IRIX
|
||||
systems, the pthread library is used. Under Windows,
|
||||
the Windows thread library is used.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Thread.h"
|
||||
#include<iostream.h>
|
||||
|
||||
Thread :: Thread()
|
||||
{
|
||||
thread = 0;
|
||||
}
|
||||
|
||||
Thread :: ~Thread()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
pthread_cancel(thread);
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
if ( thread )
|
||||
TerminateThread((HANDLE)thread, 0);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Thread :: start( THREAD_FUNCTION routine, void * ptr )
|
||||
{
|
||||
bool result = false;
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
if ( pthread_create(&thread, NULL, *routine, ptr) == 0 )
|
||||
result = true;
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
unsigned thread_id;
|
||||
thread = _beginthreadex(NULL, 0, routine, ptr, 0, &thread_id);
|
||||
if ( thread ) result = true;
|
||||
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Thread :: wait( long milliseconds )
|
||||
{
|
||||
bool result = false;
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
pthread_cancel(thread);
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
DWORD timeout, retval;
|
||||
if ( milliseconds < 0 ) timeout = INFINITE;
|
||||
else timeout = milliseconds;
|
||||
retval = WaitForSingleObject( (HANDLE)thread, timeout );
|
||||
if ( retval == WAIT_OBJECT_0 ) {
|
||||
CloseHandle( (HANDLE)thread );
|
||||
thread = 0;
|
||||
result = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
void Thread :: test(void)
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
pthread_testcancel();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Mutex :: Mutex()
|
||||
{
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
InitializeCriticalSection(&mutex);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
Mutex :: ~Mutex()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
DeleteCriticalSection(&mutex);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex :: lock()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
EnterCriticalSection(&mutex);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex :: unlock()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__))
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
LeaveCriticalSection(&mutex);
|
||||
|
||||
#endif
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class Thread
|
||||
\brief STK thread class.
|
||||
|
||||
This class provides a uniform interface for
|
||||
cross-platform thread use. On Linux and IRIX
|
||||
systems, the pthread library is used. Under Windows,
|
||||
the Windows thread library is used.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Thread.h"
|
||||
#include<iostream.h>
|
||||
|
||||
Thread :: Thread()
|
||||
{
|
||||
thread = 0;
|
||||
}
|
||||
|
||||
Thread :: ~Thread()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
pthread_cancel(thread);
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
if ( thread )
|
||||
TerminateThread((HANDLE)thread, 0);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Thread :: start( THREAD_FUNCTION routine, void * ptr )
|
||||
{
|
||||
bool result = false;
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
if ( pthread_create(&thread, NULL, *routine, ptr) == 0 )
|
||||
result = true;
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
unsigned thread_id;
|
||||
thread = _beginthreadex(NULL, 0, routine, ptr, 0, &thread_id);
|
||||
if ( thread ) result = true;
|
||||
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Thread :: wait( long milliseconds )
|
||||
{
|
||||
bool result = false;
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
pthread_cancel(thread);
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
DWORD timeout, retval;
|
||||
if ( milliseconds < 0 ) timeout = INFINITE;
|
||||
else timeout = milliseconds;
|
||||
retval = WaitForSingleObject( (HANDLE)thread, timeout );
|
||||
if ( retval == WAIT_OBJECT_0 ) {
|
||||
CloseHandle( (HANDLE)thread );
|
||||
thread = 0;
|
||||
result = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
void Thread :: test(void)
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
pthread_testcancel();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Mutex :: Mutex()
|
||||
{
|
||||
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
InitializeCriticalSection(&mutex);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
Mutex :: ~Mutex()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
DeleteCriticalSection(&mutex);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex :: lock()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
EnterCriticalSection(&mutex);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex :: unlock()
|
||||
{
|
||||
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
#elif defined(__OS_WINDOWS__)
|
||||
|
||||
LeaveCriticalSection(&mutex);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ TubeBell :: TubeBell()
|
||||
for ( i=0; i<4; i++ )
|
||||
strcpy( files[i], RAWWAVE_PATH);
|
||||
|
||||
strcat(files[0], "rawwaves/sinewave.raw");
|
||||
strcat(files[1], "rawwaves/sinewave.raw");
|
||||
strcat(files[2], "rawwaves/sinewave.raw");
|
||||
strcat(files[3], "rawwaves/fwavblnk.raw");
|
||||
strcat(files[0], "sinewave.raw");
|
||||
strcat(files[1], "sinewave.raw");
|
||||
strcat(files[2], "sinewave.raw");
|
||||
strcat(files[3], "fwavblnk.raw");
|
||||
|
||||
for ( i=0; i<4; i++ )
|
||||
waves[i] = new WaveLoop( files[i], TRUE );
|
||||
|
||||
186
src/TwoPole.cpp
186
src/TwoPole.cpp
@@ -1,93 +1,93 @@
|
||||
/***************************************************/
|
||||
/*! \class TwoPole
|
||||
\brief STK two-pole filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a two-pole digital filter. A method is
|
||||
provided for creating a resonance in the
|
||||
frequency response while maintaining a nearly
|
||||
constant filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "TwoPole.h"
|
||||
#include <math.h>
|
||||
|
||||
TwoPole :: TwoPole() : Filter()
|
||||
{
|
||||
MY_FLOAT B = 1.0;
|
||||
MY_FLOAT A[3] = {1.0, 0.0, 0.0};
|
||||
Filter::setCoefficients( 1, &B, 3, A );
|
||||
}
|
||||
|
||||
TwoPole :: ~TwoPole()
|
||||
{
|
||||
}
|
||||
|
||||
void TwoPole :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void TwoPole :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void TwoPole :: setA1(MY_FLOAT a1)
|
||||
{
|
||||
a[1] = a1;
|
||||
}
|
||||
|
||||
void TwoPole :: setA2(MY_FLOAT a2)
|
||||
{
|
||||
a[2] = a2;
|
||||
}
|
||||
|
||||
void TwoPole :: setResonance(MY_FLOAT frequency, MY_FLOAT radius, bool normalize)
|
||||
{
|
||||
a[2] = radius * radius;
|
||||
a[1] = (MY_FLOAT) -2.0 * radius * cos(TWO_PI * frequency / Stk::sampleRate());
|
||||
|
||||
if ( normalize ) {
|
||||
// Normalize the filter gain ... not terribly efficient.
|
||||
MY_FLOAT real = 1 - radius + (a[2] - radius) * cos(TWO_PI * 2 * frequency / Stk::sampleRate());
|
||||
MY_FLOAT imag = (a[2] - radius) * sin(TWO_PI * 2 * frequency / Stk::sampleRate());
|
||||
b[0] = sqrt( pow(real, 2) + pow(imag, 2) );
|
||||
}
|
||||
}
|
||||
|
||||
void TwoPole :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT TwoPole :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT TwoPole :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT TwoPole :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[0] * inputs[0] - a[2] * outputs[2] - a[1] * outputs[1];
|
||||
outputs[2] = outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *TwoPole :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class TwoPole
|
||||
\brief STK two-pole filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a two-pole digital filter. A method is
|
||||
provided for creating a resonance in the
|
||||
frequency response while maintaining a nearly
|
||||
constant filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "TwoPole.h"
|
||||
#include <math.h>
|
||||
|
||||
TwoPole :: TwoPole() : Filter()
|
||||
{
|
||||
MY_FLOAT B = 1.0;
|
||||
MY_FLOAT A[3] = {1.0, 0.0, 0.0};
|
||||
Filter::setCoefficients( 1, &B, 3, A );
|
||||
}
|
||||
|
||||
TwoPole :: ~TwoPole()
|
||||
{
|
||||
}
|
||||
|
||||
void TwoPole :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void TwoPole :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void TwoPole :: setA1(MY_FLOAT a1)
|
||||
{
|
||||
a[1] = a1;
|
||||
}
|
||||
|
||||
void TwoPole :: setA2(MY_FLOAT a2)
|
||||
{
|
||||
a[2] = a2;
|
||||
}
|
||||
|
||||
void TwoPole :: setResonance(MY_FLOAT frequency, MY_FLOAT radius, bool normalize)
|
||||
{
|
||||
a[2] = radius * radius;
|
||||
a[1] = (MY_FLOAT) -2.0 * radius * cos(TWO_PI * frequency / Stk::sampleRate());
|
||||
|
||||
if ( normalize ) {
|
||||
// Normalize the filter gain ... not terribly efficient.
|
||||
MY_FLOAT real = 1 - radius + (a[2] - radius) * cos(TWO_PI * 2 * frequency / Stk::sampleRate());
|
||||
MY_FLOAT imag = (a[2] - radius) * sin(TWO_PI * 2 * frequency / Stk::sampleRate());
|
||||
b[0] = sqrt( pow(real, 2) + pow(imag, 2) );
|
||||
}
|
||||
}
|
||||
|
||||
void TwoPole :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT TwoPole :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT TwoPole :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT TwoPole :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[0] * inputs[0] - a[2] * outputs[2] - a[1] * outputs[1];
|
||||
outputs[2] = outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *TwoPole :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
188
src/TwoZero.cpp
188
src/TwoZero.cpp
@@ -1,94 +1,94 @@
|
||||
/***************************************************/
|
||||
/*! \class TwoZero
|
||||
\brief STK two-zero filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a two-zero digital filter. A method is
|
||||
provided for creating a "notch" in the
|
||||
frequency response while maintaining a
|
||||
constant filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "TwoZero.h"
|
||||
#include <math.h>
|
||||
|
||||
TwoZero :: TwoZero() : Filter()
|
||||
{
|
||||
MY_FLOAT B[3] = {1.0, 0.0, 0.0};
|
||||
MY_FLOAT A = 1.0;
|
||||
Filter::setCoefficients( 3, B, 1, &A );
|
||||
}
|
||||
|
||||
TwoZero :: ~TwoZero()
|
||||
{
|
||||
}
|
||||
|
||||
void TwoZero :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void TwoZero :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void TwoZero :: setB1(MY_FLOAT b1)
|
||||
{
|
||||
b[1] = b1;
|
||||
}
|
||||
|
||||
void TwoZero :: setB2(MY_FLOAT b2)
|
||||
{
|
||||
b[2] = b2;
|
||||
}
|
||||
|
||||
void TwoZero :: setNotch(MY_FLOAT frequency, MY_FLOAT radius)
|
||||
{
|
||||
b[2] = radius * radius;
|
||||
b[1] = (MY_FLOAT) -2.0 * radius * cos(TWO_PI * (double) frequency / Stk::sampleRate());
|
||||
|
||||
// Normalize the filter gain.
|
||||
if (b[1] > 0.0) // Maximum at z = 0.
|
||||
b[0] = 1.0 / (1.0+b[1]+b[2]);
|
||||
else // Maximum at z = -1.
|
||||
b[0] = 1.0 / (1.0-b[1]+b[2]);
|
||||
b[1] *= b[0];
|
||||
b[2] *= b[0];
|
||||
}
|
||||
|
||||
void TwoZero :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT TwoZero :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT TwoZero :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT TwoZero :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[2] * inputs[2] + b[1] * inputs[1] + b[0] * inputs[0];
|
||||
inputs[2] = inputs[1];
|
||||
inputs[1] = inputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *TwoZero :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
/***************************************************/
|
||||
/*! \class TwoZero
|
||||
\brief STK two-zero filter class.
|
||||
|
||||
This protected Filter subclass implements
|
||||
a two-zero digital filter. A method is
|
||||
provided for creating a "notch" in the
|
||||
frequency response while maintaining a
|
||||
constant filter gain.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "TwoZero.h"
|
||||
#include <math.h>
|
||||
|
||||
TwoZero :: TwoZero() : Filter()
|
||||
{
|
||||
MY_FLOAT B[3] = {1.0, 0.0, 0.0};
|
||||
MY_FLOAT A = 1.0;
|
||||
Filter::setCoefficients( 3, B, 1, &A );
|
||||
}
|
||||
|
||||
TwoZero :: ~TwoZero()
|
||||
{
|
||||
}
|
||||
|
||||
void TwoZero :: clear(void)
|
||||
{
|
||||
Filter::clear();
|
||||
}
|
||||
|
||||
void TwoZero :: setB0(MY_FLOAT b0)
|
||||
{
|
||||
b[0] = b0;
|
||||
}
|
||||
|
||||
void TwoZero :: setB1(MY_FLOAT b1)
|
||||
{
|
||||
b[1] = b1;
|
||||
}
|
||||
|
||||
void TwoZero :: setB2(MY_FLOAT b2)
|
||||
{
|
||||
b[2] = b2;
|
||||
}
|
||||
|
||||
void TwoZero :: setNotch(MY_FLOAT frequency, MY_FLOAT radius)
|
||||
{
|
||||
b[2] = radius * radius;
|
||||
b[1] = (MY_FLOAT) -2.0 * radius * cos(TWO_PI * (double) frequency / Stk::sampleRate());
|
||||
|
||||
// Normalize the filter gain.
|
||||
if (b[1] > 0.0) // Maximum at z = 0.
|
||||
b[0] = 1.0 / (1.0+b[1]+b[2]);
|
||||
else // Maximum at z = -1.
|
||||
b[0] = 1.0 / (1.0-b[1]+b[2]);
|
||||
b[1] *= b[0];
|
||||
b[2] *= b[0];
|
||||
}
|
||||
|
||||
void TwoZero :: setGain(MY_FLOAT theGain)
|
||||
{
|
||||
Filter::setGain(theGain);
|
||||
}
|
||||
|
||||
MY_FLOAT TwoZero :: getGain(void) const
|
||||
{
|
||||
return Filter::getGain();
|
||||
}
|
||||
|
||||
MY_FLOAT TwoZero :: lastOut(void) const
|
||||
{
|
||||
return Filter::lastOut();
|
||||
}
|
||||
|
||||
MY_FLOAT TwoZero :: tick(MY_FLOAT sample)
|
||||
{
|
||||
inputs[0] = gain * sample;
|
||||
outputs[0] = b[2] * inputs[2] + b[1] * inputs[1] + b[0] * inputs[0];
|
||||
inputs[2] = inputs[1];
|
||||
inputs[1] = inputs[0];
|
||||
|
||||
return outputs[0];
|
||||
}
|
||||
|
||||
MY_FLOAT *TwoZero :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick(vector[i]);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
72
src/Vector3D.cpp
Normal file
72
src/Vector3D.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/***************************************************/
|
||||
/*! \class Vector3D
|
||||
\brief STK 3D vector class.
|
||||
|
||||
This class implements a three-dimensional vector.
|
||||
|
||||
by Perry R. Cook, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Vector3D.h"
|
||||
#include <math.h>
|
||||
|
||||
Vector3D :: Vector3D(double initX, double initY, double initZ)
|
||||
{
|
||||
myX = initX;
|
||||
myY = initY;
|
||||
myZ = initZ;
|
||||
}
|
||||
|
||||
Vector3D :: ~Vector3D()
|
||||
{
|
||||
}
|
||||
|
||||
double Vector3D :: getX()
|
||||
{
|
||||
return myX;
|
||||
}
|
||||
|
||||
double Vector3D :: getY()
|
||||
{
|
||||
return myY;
|
||||
}
|
||||
|
||||
double Vector3D :: getZ()
|
||||
{
|
||||
return myZ;
|
||||
}
|
||||
|
||||
double Vector3D :: getLength()
|
||||
{
|
||||
double temp;
|
||||
temp = myX * myX;
|
||||
temp += myY * myY;
|
||||
temp += myZ * myZ;
|
||||
temp = sqrt(temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
void Vector3D :: setXYZ(double anX, double aY, double aZ)
|
||||
{
|
||||
myX = anX;
|
||||
myY = aY;
|
||||
myZ = aZ;
|
||||
};
|
||||
|
||||
void Vector3D :: setX(double aval)
|
||||
{
|
||||
myX = aval;
|
||||
}
|
||||
|
||||
void Vector3D :: setY(double aval)
|
||||
{
|
||||
myY = aval;
|
||||
}
|
||||
|
||||
void Vector3D :: setZ(double aval)
|
||||
{
|
||||
myZ = aval;
|
||||
}
|
||||
|
||||
|
||||
248
src/VoicForm.cpp
Normal file
248
src/VoicForm.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
/***************************************************/
|
||||
/*! \class VoicForm
|
||||
\brief Four formant synthesis instrument.
|
||||
|
||||
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 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.
|
||||
|
||||
Control Change Numbers:
|
||||
- Voiced/Unvoiced Mix = 2
|
||||
- Vowel/Phoneme Selection = 4
|
||||
- Vibrato Frequency = 11
|
||||
- Vibrato Gain = 1
|
||||
- Loudness (Spectral Tilt) = 128
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "VoicForm.h"
|
||||
#include "Phonemes.h"
|
||||
#include "SKINI.msg"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
VoicForm :: VoicForm() : Instrmnt()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
voiced = new SingWave( strcat(file,"impuls20.raw"), TRUE );
|
||||
voiced->setGainRate( 0.001 );
|
||||
voiced->setGainTarget( 0.0 );
|
||||
|
||||
noise = new Noise;
|
||||
|
||||
for ( int i=0; i<4; i++ ) {
|
||||
filters[i] = new FormSwep;
|
||||
filters[i]->setSweepRate( 0.001 );
|
||||
}
|
||||
|
||||
onezero = new OneZero;
|
||||
onezero->setZero( -0.9 );
|
||||
onepole = new OnePole;
|
||||
onepole->setPole( 0.9 );
|
||||
|
||||
noiseEnv = new Envelope;
|
||||
noiseEnv->setRate( 0.001 );
|
||||
noiseEnv->setTarget( 0.0 );
|
||||
|
||||
this->setPhoneme( "eee" );
|
||||
this->clear();
|
||||
}
|
||||
|
||||
VoicForm :: ~VoicForm()
|
||||
{
|
||||
delete voiced;
|
||||
delete noise;
|
||||
delete onezero;
|
||||
delete onepole;
|
||||
delete noiseEnv;
|
||||
for ( int i=0; i<4; i++ ) {
|
||||
delete filters[i];
|
||||
}
|
||||
}
|
||||
|
||||
void VoicForm :: clear()
|
||||
{
|
||||
onezero->clear();
|
||||
onepole->clear();
|
||||
for ( int i=0; i<4; i++ ) {
|
||||
filters[i]->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void VoicForm :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT freakency = frequency;
|
||||
if ( frequency <= 0.0 ) {
|
||||
cerr << "VoicForm: setFrequency parameter is less than or equal to zero!" << endl;
|
||||
freakency = 220.0;
|
||||
}
|
||||
|
||||
voiced->setFrequency( freakency );
|
||||
}
|
||||
|
||||
bool VoicForm :: setPhoneme(const char *phoneme )
|
||||
{
|
||||
bool found = false;
|
||||
unsigned int i = 0;
|
||||
while( i < 32 && !found ) {
|
||||
if ( !strcmp( Phonemes::name(i), phoneme ) ) {
|
||||
found = true;
|
||||
filters[0]->setTargets( Phonemes::formantFrequency(i, 0), Phonemes::formantRadius(i, 0), pow(10.0, Phonemes::formantGain(i, 0 ) / 20.0) );
|
||||
filters[1]->setTargets( Phonemes::formantFrequency(i, 1), Phonemes::formantRadius(i, 1), pow(10.0, Phonemes::formantGain(i, 1 ) / 20.0) );
|
||||
filters[2]->setTargets( Phonemes::formantFrequency(i, 2), Phonemes::formantRadius(i, 2), pow(10.0, Phonemes::formantGain(i, 2 ) / 20.0) );
|
||||
filters[3]->setTargets( Phonemes::formantFrequency(i, 3), Phonemes::formantRadius(i, 3), pow(10.0, Phonemes::formantGain(i, 3 ) / 20.0) );
|
||||
setVoiced( Phonemes::voiceGain( i ) );
|
||||
setUnVoiced( Phonemes::noiseGain( i ) );
|
||||
#if defined(_STK_DEBUG_)
|
||||
cout << "VoicForm: found formant " << phoneme << " (number " << i << ")" << endl;
|
||||
#endif
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
cerr << "VoicForm: phoneme " << phoneme << " not found!" << endl;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void VoicForm :: setVoiced(MY_FLOAT vGain)
|
||||
{
|
||||
voiced->setGainTarget(vGain);
|
||||
}
|
||||
|
||||
void VoicForm :: setUnVoiced(MY_FLOAT nGain)
|
||||
{
|
||||
noiseEnv->setTarget(nGain);
|
||||
}
|
||||
|
||||
void VoicForm :: setFilterSweepRate(int whichOne, MY_FLOAT rate)
|
||||
{
|
||||
if ( whichOne < 0 || whichOne > 3 ) {
|
||||
cerr << "VoicForm: setFilterSweepRate filter argument outside range 0-3!" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
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( 0.0 );
|
||||
}
|
||||
|
||||
void VoicForm :: noteOn(MY_FLOAT frequency, MY_FLOAT amplitude)
|
||||
{
|
||||
setFrequency(frequency);
|
||||
voiced->setGainTarget(amplitude);
|
||||
onepole->setPole( 0.97 - (amplitude * 0.2) );
|
||||
}
|
||||
|
||||
void VoicForm :: noteOff(MY_FLOAT amplitude)
|
||||
{
|
||||
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(temp);
|
||||
lastOutput += filters[2]->tick(temp);
|
||||
lastOutput += filters[3]->tick(temp);
|
||||
/*
|
||||
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);
|
||||
*/
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void VoicForm :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT norm = value * ONE_OVER_128;
|
||||
if ( norm < 0 ) {
|
||||
norm = 0.0;
|
||||
cerr << "VoicForm: Control value less than zero!" << endl;
|
||||
}
|
||||
else if ( norm > 1.0 ) {
|
||||
norm = 1.0;
|
||||
cerr << "VoicForm: Control value greater than 128.0!" << endl;
|
||||
}
|
||||
|
||||
if (number == __SK_Breath_) { // 2
|
||||
this->setVoiced( 1.0 - norm );
|
||||
this->setUnVoiced( 0.01 * norm );
|
||||
}
|
||||
else if (number == __SK_FootControl_) { // 4
|
||||
MY_FLOAT temp = 0.0;
|
||||
unsigned int i = (int) value;
|
||||
if (i < 32) {
|
||||
temp = 0.9;
|
||||
}
|
||||
else if (i < 64) {
|
||||
i -= 32;
|
||||
temp = 1.0;
|
||||
}
|
||||
else if (i < 96) {
|
||||
i -= 64;
|
||||
temp = 1.1;
|
||||
}
|
||||
else if (i < 128) {
|
||||
i -= 96;
|
||||
temp = 1.2;
|
||||
}
|
||||
else if (i == 128) {
|
||||
i = 0;
|
||||
temp = 1.4;
|
||||
}
|
||||
filters[0]->setTargets( temp * Phonemes::formantFrequency(i, 0), Phonemes::formantRadius(i, 0), pow(10.0, Phonemes::formantGain(i, 0 ) / 20.0) );
|
||||
filters[1]->setTargets( temp * Phonemes::formantFrequency(i, 1), Phonemes::formantRadius(i, 1), pow(10.0, Phonemes::formantGain(i, 1 ) / 20.0) );
|
||||
filters[2]->setTargets( temp * Phonemes::formantFrequency(i, 2), Phonemes::formantRadius(i, 2), pow(10.0, Phonemes::formantGain(i, 2 ) / 20.0) );
|
||||
filters[3]->setTargets( temp * Phonemes::formantFrequency(i, 3), Phonemes::formantRadius(i, 3), pow(10.0, Phonemes::formantGain(i, 3 ) / 20.0) );
|
||||
setVoiced( Phonemes::voiceGain( i ) );
|
||||
setUnVoiced( Phonemes::noiseGain( i ) );
|
||||
}
|
||||
else if (number == __SK_ModFrequency_) // 11
|
||||
voiced->setVibratoRate( norm * 12.0); // 0 to 12 Hz
|
||||
else if (number == __SK_ModWheel_) // 1
|
||||
voiced->setVibratoGain( norm * 0.2);
|
||||
else if (number == __SK_AfterTouch_Cont_) { // 128
|
||||
setVoiced( norm );
|
||||
onepole->setPole( 0.97 - ( norm * 0.2) );
|
||||
}
|
||||
else
|
||||
cerr << "VoicForm: Undefined Control Number (" << number << ")!!" << endl;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "VoicForm: controlChange number = " << number << ", value = " << value << endl;
|
||||
#endif
|
||||
}
|
||||
254
src/Voicer.cpp
Normal file
254
src/Voicer.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
/***************************************************/
|
||||
/*! \class Voicer
|
||||
\brief STK voice manager class.
|
||||
|
||||
This class can be used to manage a group of
|
||||
STK instrument classes. Individual voices can
|
||||
be controlled via unique note tags.
|
||||
Instrument groups can be controlled by channel
|
||||
number.
|
||||
|
||||
A previously constructed STK instrument class
|
||||
is linked with a voice manager using the
|
||||
addInstrument() function. An optional channel
|
||||
number argument can be specified to the
|
||||
addInstrument() function as well (default
|
||||
channel = 0). The voice manager does not
|
||||
delete any instrument instances ... it is the
|
||||
responsibility of the user to allocate and
|
||||
deallocate all instruments.
|
||||
|
||||
The tick() function returns the mix of all
|
||||
sounding voices. Each noteOn returns a unique
|
||||
tag (credits to the NeXT MusicKit), so you can
|
||||
send control changes to specific voices within
|
||||
an ensemble. Alternately, control changes can
|
||||
be sent to all voices on a given channel.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Voicer.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
Voicer :: Voicer( int maxInstruments, MY_FLOAT decayTime )
|
||||
{
|
||||
nVoices = 0;
|
||||
maxVoices = maxInstruments;
|
||||
voices = (Voice *) new Voice[maxVoices];
|
||||
tags = 23456;
|
||||
muteTime = (int) ( decayTime * Stk::sampleRate() );
|
||||
}
|
||||
|
||||
Voicer :: ~Voicer()
|
||||
{
|
||||
delete [] voices;
|
||||
//free( voices );
|
||||
}
|
||||
|
||||
void Voicer :: addInstrument( Instrmnt *instrument, int channel )
|
||||
{
|
||||
//voices = (Voice *) realloc( (void *) voices, nVoices+1 * sizeof( Voice ) );
|
||||
if ( nVoices == maxVoices ) {
|
||||
cerr << "Voicer: Maximum number of voices already added!!" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
voices[nVoices].instrument = instrument;
|
||||
voices[nVoices].tag = 0;
|
||||
voices[nVoices].channel = channel;
|
||||
voices[nVoices].noteNumber = -1;
|
||||
voices[nVoices].frequency = 0.0;
|
||||
voices[nVoices].sounding = 0;
|
||||
nVoices++;
|
||||
}
|
||||
|
||||
void Voicer :: removeInstrument( Instrmnt *instrument )
|
||||
{
|
||||
bool found = false;
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].instrument == instrument ) found = true;
|
||||
if ( found && i+1 < nVoices ) {
|
||||
voices[i].instrument = voices[i+1].instrument;
|
||||
voices[i].tag = voices[i+1].tag;
|
||||
voices[i].noteNumber = voices[i+1].noteNumber;
|
||||
voices[i].frequency = voices[i+1].frequency;
|
||||
voices[i].sounding = voices[i+1].sounding;
|
||||
voices[i].channel = voices[i+1].channel;
|
||||
}
|
||||
}
|
||||
|
||||
if ( found )
|
||||
nVoices--;
|
||||
//voices = (Voice *) realloc( voices, --nVoices * sizeof( Voice ) );
|
||||
|
||||
}
|
||||
|
||||
long Voicer :: noteOn(MY_FLOAT noteNumber, MY_FLOAT amplitude, int channel )
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT frequency = (MY_FLOAT) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
|
||||
for ( i=0; i<nVoices; i++ ) {
|
||||
if (voices[i].noteNumber < 0 && voices[i].channel == channel) {
|
||||
voices[i].tag = tags++;
|
||||
voices[i].channel = channel;
|
||||
voices[i].noteNumber = noteNumber;
|
||||
voices[i].frequency = frequency;
|
||||
voices[i].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
|
||||
voices[i].sounding = 1;
|
||||
return voices[i].tag;
|
||||
}
|
||||
}
|
||||
|
||||
// All voices are sounding, so interrupt the oldest voice.
|
||||
int voice = -1;
|
||||
for ( i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].channel == channel ) {
|
||||
if ( voice == -1 ) voice = i;
|
||||
else if ( voices[i].tag < voices[voice].tag ) voice = i;
|
||||
}
|
||||
}
|
||||
|
||||
if ( voice >= 0 ) {
|
||||
voices[voice].tag = tags++;
|
||||
voices[voice].channel = channel;
|
||||
voices[voice].noteNumber = noteNumber;
|
||||
voices[voice].frequency = frequency;
|
||||
voices[voice].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
|
||||
voices[voice].sounding = 1;
|
||||
return voices[voice].tag;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Voicer :: noteOff( MY_FLOAT noteNumber, MY_FLOAT amplitude, int channel )
|
||||
{
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].noteNumber == noteNumber && voices[i].channel == channel ) {
|
||||
voices[i].instrument->noteOff( amplitude * ONE_OVER_128 );
|
||||
voices[i].sounding = -muteTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: noteOff( long tag, MY_FLOAT amplitude )
|
||||
{
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].tag == tag ) {
|
||||
voices[i].instrument->noteOff( amplitude * ONE_OVER_128 );
|
||||
voices[i].sounding = -muteTime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: setFrequency( MY_FLOAT noteNumber, int channel )
|
||||
{
|
||||
MY_FLOAT frequency = (MY_FLOAT) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].channel == channel ) {
|
||||
voices[i].noteNumber = noteNumber;
|
||||
voices[i].frequency = frequency;
|
||||
voices[i].instrument->setFrequency( frequency );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: setFrequency( long tag, MY_FLOAT noteNumber )
|
||||
{
|
||||
MY_FLOAT frequency = (MY_FLOAT) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].tag == tag ) {
|
||||
voices[i].noteNumber = noteNumber;
|
||||
voices[i].frequency = frequency;
|
||||
voices[i].instrument->setFrequency( frequency );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: pitchBend( MY_FLOAT value, int channel )
|
||||
{
|
||||
MY_FLOAT pitchScaler;
|
||||
if ( value < 64.0 )
|
||||
pitchScaler = pow(0.5, (64.0-value)/64.0);
|
||||
else
|
||||
pitchScaler = pow(2.0, (value-64.0)/64.0);
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].channel == channel )
|
||||
voices[i].instrument->setFrequency( (MY_FLOAT) (voices[i].frequency * pitchScaler) );
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: pitchBend( long tag, MY_FLOAT value )
|
||||
{
|
||||
MY_FLOAT pitchScaler;
|
||||
if ( value < 64.0 )
|
||||
pitchScaler = pow(0.5, (64.0-value)/64.0);
|
||||
else
|
||||
pitchScaler = pow(2.0, (value-64.0)/64.0);
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].tag == tag ) {
|
||||
voices[i].instrument->setFrequency( (MY_FLOAT) (voices[i].frequency * pitchScaler) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: controlChange( int number, MY_FLOAT value, int channel )
|
||||
{
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].channel == channel )
|
||||
voices[i].instrument->controlChange( number, value );
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: controlChange( long tag, int number, MY_FLOAT value )
|
||||
{
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].tag == tag ) {
|
||||
voices[i].instrument->controlChange( number, value );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: silence( void )
|
||||
{
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].sounding > 0 )
|
||||
voices[i].instrument->noteOff( 0.5 );
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT Voicer :: tick()
|
||||
{
|
||||
lastOutput = 0.0;
|
||||
for ( int i=0; i<nVoices; i++ ) {
|
||||
if ( voices[i].sounding != 0 )
|
||||
lastOutput += voices[i].instrument->tick();
|
||||
if ( voices[i].sounding < 0 ) {
|
||||
voices[i].sounding++;
|
||||
if ( voices[i].sounding == 0 )
|
||||
voices[i].noteNumber = -1;
|
||||
}
|
||||
}
|
||||
return lastOutput / nVoices;
|
||||
}
|
||||
|
||||
MY_FLOAT *Voicer :: tick(MY_FLOAT *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
MY_FLOAT Voicer :: lastOut() const
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
260
src/WaveLoop.cpp
260
src/WaveLoop.cpp
@@ -1,130 +1,130 @@
|
||||
/***************************************************/
|
||||
/*! \class WaveLoop
|
||||
\brief STK waveform oscillator class.
|
||||
|
||||
This class inherits from WvIn and provides
|
||||
audio file looping functionality.
|
||||
|
||||
WaveLoop supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which return
|
||||
samples produced by averaging across sample
|
||||
frames, from the tickFrame() methods, which
|
||||
return pointers to multi-channel sample frames.
|
||||
For single-channel data, these methods return
|
||||
equivalent values.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "WaveLoop.h"
|
||||
#include <math.h>
|
||||
|
||||
WaveLoop :: WaveLoop( const char *fileName, bool raw )
|
||||
: WvIn( fileName, raw ), phaseOffset(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
WaveLoop :: ~WaveLoop()
|
||||
{
|
||||
}
|
||||
|
||||
void WaveLoop :: readData( unsigned long index )
|
||||
{
|
||||
WvIn::readData( index );
|
||||
|
||||
// If at end of file, redo extra sample frame for looping.
|
||||
if (chunkPointer+bufferSize == fileSize) {
|
||||
for (unsigned int j=0; j<channels; j++)
|
||||
data[bufferSize*channels+j] = data[j];
|
||||
}
|
||||
}
|
||||
|
||||
void WaveLoop :: setFrequency(MY_FLOAT aFrequency)
|
||||
{
|
||||
// This is a looping frequency.
|
||||
rate = fileSize * aFrequency / sampleRate();
|
||||
}
|
||||
|
||||
void WaveLoop :: addTime(MY_FLOAT aTime)
|
||||
{
|
||||
// Add an absolute time in samples
|
||||
time += aTime;
|
||||
|
||||
while (time < 0.0)
|
||||
time += fileSize;
|
||||
while (time >= fileSize)
|
||||
time -= fileSize;
|
||||
}
|
||||
|
||||
void WaveLoop :: addPhase(MY_FLOAT anAngle)
|
||||
{
|
||||
// Add a time in cycles (one cycle = fileSize).
|
||||
time += fileSize * anAngle;
|
||||
|
||||
while (time < 0.0)
|
||||
time += fileSize;
|
||||
while (time >= fileSize)
|
||||
time -= fileSize;
|
||||
}
|
||||
|
||||
void WaveLoop :: addPhaseOffset(MY_FLOAT anAngle)
|
||||
{
|
||||
// Add a phase offset in cycles, where 1.0 = fileSize.
|
||||
phaseOffset = fileSize * anAngle;
|
||||
}
|
||||
|
||||
const MY_FLOAT *WaveLoop :: tickFrame(void)
|
||||
{
|
||||
register MY_FLOAT tyme, alpha;
|
||||
register unsigned long i, index;
|
||||
|
||||
// Check limits of time address ... if necessary, recalculate modulo fileSize.
|
||||
while (time < 0.0)
|
||||
time += fileSize;
|
||||
while (time >= fileSize)
|
||||
time -= fileSize;
|
||||
|
||||
if (phaseOffset) {
|
||||
tyme = time + phaseOffset;
|
||||
while (tyme < 0.0)
|
||||
tyme += fileSize;
|
||||
while (tyme >= fileSize)
|
||||
tyme -= fileSize;
|
||||
}
|
||||
else {
|
||||
tyme = time;
|
||||
}
|
||||
|
||||
if (chunking) {
|
||||
// Check the time address vs. our current buffer limits.
|
||||
if ( (tyme < chunkPointer) || (tyme >= chunkPointer+bufferSize) )
|
||||
this->readData((long) tyme);
|
||||
// Adjust index for the current buffer.
|
||||
tyme -= chunkPointer;
|
||||
}
|
||||
|
||||
// Always do linear interpolation here ... integer part of time address.
|
||||
index = (unsigned long) tyme;
|
||||
|
||||
// Fractional part of time address.
|
||||
alpha = tyme - (MY_FLOAT) index;
|
||||
index *= channels;
|
||||
for (i=0; i<channels; i++) {
|
||||
lastOutput[i] = data[index];
|
||||
lastOutput[i] += (alpha * (data[index+channels] - lastOutput[i]));
|
||||
index++;
|
||||
}
|
||||
|
||||
if (chunking) {
|
||||
// Scale outputs by gain.
|
||||
for (i=0; i<channels; i++) lastOutput[i] *= gain;
|
||||
}
|
||||
|
||||
// Increment time, which can be negative.
|
||||
time += rate;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/*! \class WaveLoop
|
||||
\brief STK waveform oscillator class.
|
||||
|
||||
This class inherits from WvIn and provides
|
||||
audio file looping functionality.
|
||||
|
||||
WaveLoop supports multi-channel data in
|
||||
interleaved format. It is important to
|
||||
distinguish the tick() methods, which return
|
||||
samples produced by averaging across sample
|
||||
frames, from the tickFrame() methods, which
|
||||
return pointers to multi-channel sample frames.
|
||||
For single-channel data, these methods return
|
||||
equivalent values.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "WaveLoop.h"
|
||||
#include <math.h>
|
||||
|
||||
WaveLoop :: WaveLoop( const char *fileName, bool raw )
|
||||
: WvIn( fileName, raw ), phaseOffset(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
WaveLoop :: ~WaveLoop()
|
||||
{
|
||||
}
|
||||
|
||||
void WaveLoop :: readData( unsigned long index )
|
||||
{
|
||||
WvIn::readData( index );
|
||||
|
||||
// If at end of file, redo extra sample frame for looping.
|
||||
if (chunkPointer+bufferSize == fileSize) {
|
||||
for (unsigned int j=0; j<channels; j++)
|
||||
data[bufferSize*channels+j] = data[j];
|
||||
}
|
||||
}
|
||||
|
||||
void WaveLoop :: setFrequency(MY_FLOAT aFrequency)
|
||||
{
|
||||
// This is a looping frequency.
|
||||
rate = fileSize * aFrequency / sampleRate();
|
||||
}
|
||||
|
||||
void WaveLoop :: addTime(MY_FLOAT aTime)
|
||||
{
|
||||
// Add an absolute time in samples
|
||||
time += aTime;
|
||||
|
||||
while (time < 0.0)
|
||||
time += fileSize;
|
||||
while (time >= fileSize)
|
||||
time -= fileSize;
|
||||
}
|
||||
|
||||
void WaveLoop :: addPhase(MY_FLOAT anAngle)
|
||||
{
|
||||
// Add a time in cycles (one cycle = fileSize).
|
||||
time += fileSize * anAngle;
|
||||
|
||||
while (time < 0.0)
|
||||
time += fileSize;
|
||||
while (time >= fileSize)
|
||||
time -= fileSize;
|
||||
}
|
||||
|
||||
void WaveLoop :: addPhaseOffset(MY_FLOAT anAngle)
|
||||
{
|
||||
// Add a phase offset in cycles, where 1.0 = fileSize.
|
||||
phaseOffset = fileSize * anAngle;
|
||||
}
|
||||
|
||||
const MY_FLOAT *WaveLoop :: tickFrame(void)
|
||||
{
|
||||
register MY_FLOAT tyme, alpha;
|
||||
register unsigned long i, index;
|
||||
|
||||
// Check limits of time address ... if necessary, recalculate modulo fileSize.
|
||||
while (time < 0.0)
|
||||
time += fileSize;
|
||||
while (time >= fileSize)
|
||||
time -= fileSize;
|
||||
|
||||
if (phaseOffset) {
|
||||
tyme = time + phaseOffset;
|
||||
while (tyme < 0.0)
|
||||
tyme += fileSize;
|
||||
while (tyme >= fileSize)
|
||||
tyme -= fileSize;
|
||||
}
|
||||
else {
|
||||
tyme = time;
|
||||
}
|
||||
|
||||
if (chunking) {
|
||||
// Check the time address vs. our current buffer limits.
|
||||
if ( (tyme < chunkPointer) || (tyme >= chunkPointer+bufferSize) )
|
||||
this->readData((long) tyme);
|
||||
// Adjust index for the current buffer.
|
||||
tyme -= chunkPointer;
|
||||
}
|
||||
|
||||
// Always do linear interpolation here ... integer part of time address.
|
||||
index = (unsigned long) tyme;
|
||||
|
||||
// Fractional part of time address.
|
||||
alpha = tyme - (MY_FLOAT) index;
|
||||
index *= channels;
|
||||
for (i=0; i<channels; i++) {
|
||||
lastOutput[i] = data[index];
|
||||
lastOutput[i] += (alpha * (data[index+channels] - lastOutput[i]));
|
||||
index++;
|
||||
}
|
||||
|
||||
if (chunking) {
|
||||
// Scale outputs by gain.
|
||||
for (i=0; i<channels; i++) lastOutput[i] *= gain;
|
||||
}
|
||||
|
||||
// Increment time, which can be negative.
|
||||
time += rate;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
|
||||
259
src/Whistle.cpp
Normal file
259
src/Whistle.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
/***************************************************/
|
||||
/*! \class Whistle
|
||||
\brief STK police/referee whistle instrument class.
|
||||
|
||||
This class implements a hybrid physical/spectral
|
||||
model of a police whistle (a la Cook).
|
||||
|
||||
Control Change Numbers:
|
||||
- Noise Gain = 4
|
||||
- Fipple Modulation Frequency = 11
|
||||
- Fipple Modulation Gain = 1
|
||||
- Blowing Frequency Modulation = 2
|
||||
- Volume = 128
|
||||
|
||||
by Perry R. Cook 1996 - 2002.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Whistle.h"
|
||||
#include "SKINI.msg"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define CAN_RADIUS 100
|
||||
#define PEA_RADIUS 30
|
||||
#define BUMP_RADIUS 5
|
||||
|
||||
#define NORM_CAN_LOSS 0.97
|
||||
#define SLOW_CAN_LOSS 0.90
|
||||
#define GRAVITY 20.0
|
||||
// GRAVITY WAS 6.0
|
||||
|
||||
#define NORM_TICK_SIZE 0.004
|
||||
#define SLOW_TICK_SIZE 0.0001
|
||||
|
||||
#define ENV_RATE 0.001
|
||||
|
||||
Whistle :: Whistle()
|
||||
{
|
||||
tempVector = new Vector3D(0,0,0);
|
||||
can = new Sphere(CAN_RADIUS);
|
||||
pea = new Sphere(PEA_RADIUS);
|
||||
bumper = new Sphere(BUMP_RADIUS);
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char path[128];
|
||||
strcpy(path, RAWWAVE_PATH);
|
||||
sine = new WaveLoop( strcat(path,"sinewave.raw"), TRUE );
|
||||
sine->setFrequency(2800.0);
|
||||
|
||||
can->setPosition(0, 0, 0); // set can location
|
||||
can->setVelocity(0, 0, 0); // and the velocity
|
||||
|
||||
onepole.setPole(0.95); // 0.99
|
||||
|
||||
bumper->setPosition(0.0, CAN_RADIUS-BUMP_RADIUS, 0);
|
||||
bumper->setPosition(0.0, CAN_RADIUS-BUMP_RADIUS, 0);
|
||||
pea->setPosition(0, CAN_RADIUS/2, 0);
|
||||
pea->setVelocity(35, 15, 0);
|
||||
|
||||
envelope.setRate(ENV_RATE);
|
||||
envelope.keyOn();
|
||||
|
||||
fippleFreqMod = 0.5;
|
||||
fippleGainMod = 0.5;
|
||||
blowFreqMod = 0.25;
|
||||
noiseGain = 0.125;
|
||||
maxPressure = (MY_FLOAT) 0.0;
|
||||
baseFrequency = 2000;
|
||||
|
||||
tickSize = NORM_TICK_SIZE;
|
||||
canLoss = NORM_CAN_LOSS;
|
||||
|
||||
subSample = 1;
|
||||
subSampCount = subSample;
|
||||
}
|
||||
|
||||
Whistle :: ~Whistle()
|
||||
{
|
||||
delete tempVector;
|
||||
delete can;
|
||||
delete pea;
|
||||
delete bumper;
|
||||
delete sine;
|
||||
}
|
||||
|
||||
void Whistle :: clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Whistle :: setFrequency(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT freakency = frequency * 4; // the whistle is a transposing instrument
|
||||
if ( frequency <= 0.0 ) {
|
||||
cerr << "Whistle: setFrequency parameter is less than or equal to zero!" << endl;
|
||||
freakency = 220.0;
|
||||
}
|
||||
|
||||
baseFrequency = freakency;
|
||||
}
|
||||
|
||||
void Whistle :: startBlowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
envelope.setRate(ENV_RATE);
|
||||
envelope.setTarget(amplitude);
|
||||
}
|
||||
|
||||
void Whistle :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
envelope.setRate(rate);
|
||||
envelope.keyOff();
|
||||
}
|
||||
|
||||
void Whistle :: noteOn(MY_FLOAT frequency, MY_FLOAT amplitude)
|
||||
{
|
||||
setFrequency(frequency);
|
||||
startBlowing(amplitude*2.0 ,amplitude * 0.2);
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "Whistle: NoteOn frequency = " << frequency << ", amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Whistle :: noteOff(MY_FLOAT amplitude)
|
||||
{
|
||||
this->stopBlowing(amplitude * 0.02);
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "Whistle: NoteOff amplitude = " << amplitude << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
int frameCount = 0;
|
||||
|
||||
MY_FLOAT Whistle :: tick()
|
||||
{
|
||||
MY_FLOAT soundMix, tempFreq;
|
||||
double envOut = 0, temp, temp1, temp2, tempX, tempY;
|
||||
double phi, cosphi, sinphi;
|
||||
double gain = 0.5, mod = 0.0;
|
||||
|
||||
if (--subSampCount <= 0) {
|
||||
tempVectorP = pea->getPosition();
|
||||
subSampCount = subSample;
|
||||
temp = bumper->isInside(tempVectorP);
|
||||
#ifdef WHISTLE_ANIMATION
|
||||
frameCount += 1;
|
||||
if (frameCount >= (1470 / subSample)) {
|
||||
frameCount = 0;
|
||||
printf("%f %f %f\n",tempVectorP->getX(),tempVectorP->getY(),envOut);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
envOut = envelope.tick();
|
||||
|
||||
if (temp < (BUMP_RADIUS + PEA_RADIUS)) {
|
||||
tempX = envOut * tickSize * 2000 * noise.tick();
|
||||
tempY = -envOut * tickSize * 1000 * (1.0 + noise.tick());
|
||||
pea->addVelocity(tempX,tempY,0);
|
||||
pea->tick(tickSize);
|
||||
}
|
||||
|
||||
mod = exp(-temp * 0.01); // exp. distance falloff of fipple/pea effect
|
||||
temp = onepole.tick(mod); // smooth it a little
|
||||
gain = (1.0 - (fippleGainMod*0.5)) + (2.0 * fippleGainMod * temp);
|
||||
gain *= gain; // squared distance/gain
|
||||
// tempFreq = 1.0 // Normalized Base Freq
|
||||
// + (fippleFreqMod * 0.25) - (fippleFreqMod * temp) // fippleModulation
|
||||
// - (blowFreqMod) + (blowFreqMod * envOut); // blowingModulation
|
||||
// short form of above
|
||||
tempFreq = 1.0 + fippleFreqMod*(0.25-temp) + blowFreqMod*(envOut-1.0);
|
||||
tempFreq *= baseFrequency;
|
||||
|
||||
sine->setFrequency(tempFreq);
|
||||
|
||||
tempVectorP = pea->getPosition();
|
||||
temp = can->isInside(tempVectorP);
|
||||
temp = -temp; // We know (hope) it's inside, just how much??
|
||||
if (temp < (PEA_RADIUS * 1.25)) {
|
||||
pea->getVelocity(tempVector); // This is the can/pea collision
|
||||
tempX = tempVectorP->getX(); // calculation. Could probably
|
||||
tempY = tempVectorP->getY(); // simplify using tables, etc.
|
||||
phi = -atan2(tempY,tempX);
|
||||
cosphi = cos(phi);
|
||||
sinphi = sin(phi);
|
||||
temp1 = (cosphi*tempVector->getX()) - (sinphi*tempVector->getY());
|
||||
temp2 = (sinphi*tempVector->getX()) + (cosphi*tempVector->getY());
|
||||
temp1 = -temp1;
|
||||
tempX = (cosphi*temp1) + (sinphi*temp2);
|
||||
tempY = (-sinphi*temp1) + (cosphi*temp2);
|
||||
pea->setVelocity(tempX, tempY, 0);
|
||||
pea->tick(tickSize);
|
||||
pea->setVelocity(tempX*canLoss, tempY*canLoss, 0);
|
||||
pea->tick(tickSize);
|
||||
}
|
||||
|
||||
temp = tempVectorP->getLength();
|
||||
if (temp > 0.01) {
|
||||
tempX = tempVectorP->getX();
|
||||
tempY = tempVectorP->getY();
|
||||
phi = atan2(tempY,tempX);
|
||||
phi += 0.3 * temp / CAN_RADIUS;
|
||||
cosphi = cos(phi);
|
||||
sinphi = sin(phi);
|
||||
tempX = 3.0 * temp * cosphi;
|
||||
tempY = 3.0 * temp * sinphi;
|
||||
}
|
||||
else {
|
||||
tempX = 0.0;
|
||||
tempY = 0.0;
|
||||
}
|
||||
|
||||
temp = (0.9 + 0.1*subSample*noise.tick()) * envOut * 0.6 * tickSize;
|
||||
pea->addVelocity(temp * tempX,
|
||||
(temp*tempY) - (GRAVITY*tickSize),0);
|
||||
pea->tick(tickSize);
|
||||
|
||||
// bumper->tick(0.0);
|
||||
}
|
||||
|
||||
temp = envOut * envOut * gain / 2;
|
||||
soundMix = temp * (sine->tick() + (noiseGain*noise.tick()));
|
||||
lastOutput = 0.25 * soundMix; // should probably do one-zero filter here
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Whistle :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT norm = value * ONE_OVER_128;
|
||||
if ( norm < 0 ) {
|
||||
norm = 0.0;
|
||||
cerr << "Whistle: Control value less than zero!" << endl;
|
||||
}
|
||||
else if ( norm > 1.0 ) {
|
||||
norm = 1.0;
|
||||
cerr << "Whistle: Control value greater than 128.0!" << endl;
|
||||
}
|
||||
|
||||
if (number == __SK_NoiseLevel_) // 4
|
||||
noiseGain = 0.25 * norm;
|
||||
else if (number == __SK_ModFrequency_) // 11
|
||||
fippleFreqMod = norm;
|
||||
else if (number == __SK_ModWheel_) // 1
|
||||
fippleGainMod = norm;
|
||||
else if (number == __SK_AfterTouch_Cont_) // 128
|
||||
envelope.setTarget( norm * 2.0 );
|
||||
else if (number == __SK_Breath_) // 2
|
||||
blowFreqMod = norm * 0.5;
|
||||
else if (number == __SK_Sustain_) // 64
|
||||
if (value < 1.0) subSample = 1;
|
||||
else
|
||||
cerr << "Whistle: Undefined Control Number (" << number << ")!!" << endl;
|
||||
|
||||
#if defined(_STK_DEBUG_)
|
||||
cerr << "Whistle: controlChange number = " << number << ", value = " << value << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ Wurley :: Wurley()
|
||||
for ( i=0; i<4; i++ )
|
||||
strcpy( files[i], RAWWAVE_PATH);
|
||||
|
||||
strcat(files[0], "rawwaves/sinewave.raw");
|
||||
strcat(files[1], "rawwaves/sinewave.raw");
|
||||
strcat(files[2], "rawwaves/sinewave.raw");
|
||||
strcat(files[3], "rawwaves/fwavblnk.raw");
|
||||
strcat(files[0], "sinewave.raw");
|
||||
strcat(files[1], "sinewave.raw");
|
||||
strcat(files[2], "sinewave.raw");
|
||||
strcat(files[3], "fwavblnk.raw");
|
||||
|
||||
for ( i=0; i<4; i++ )
|
||||
waves[i] = new WaveLoop( files[i], TRUE );
|
||||
|
||||
1758
src/WvIn.cpp
1758
src/WvIn.cpp
File diff suppressed because it is too large
Load Diff
1511
src/WvOut.cpp
1511
src/WvOut.cpp
File diff suppressed because it is too large
Load Diff
257
src/asio/asio.cpp
Normal file
257
src/asio/asio.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
Steinberg Audio Stream I/O API
|
||||
(c) 1996, Steinberg Soft- und Hardware GmbH
|
||||
|
||||
asio.cpp
|
||||
|
||||
asio functions entries which translate the
|
||||
asio interface to the asiodrvr class methods
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "asiosys.h" // platform definition
|
||||
#include "asio.h"
|
||||
|
||||
#if MAC
|
||||
#include "asiodrvr.h"
|
||||
|
||||
#pragma export on
|
||||
|
||||
AsioDriver *theAsioDriver = 0;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
long main()
|
||||
{
|
||||
return 'ASIO';
|
||||
}
|
||||
|
||||
#elif WINDOWS
|
||||
|
||||
#include "windows.h"
|
||||
#include "iasiodrv.h"
|
||||
#include "asiodrivers.h"
|
||||
|
||||
IASIO *theAsioDriver = 0;
|
||||
extern AsioDrivers *asioDrivers;
|
||||
|
||||
#elif SGI || SUN || BEOS || LINUX
|
||||
#include "asiodrvr.h"
|
||||
static AsioDriver *theAsioDriver = 0;
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
ASIOError ASIOInit(ASIODriverInfo *info)
|
||||
{
|
||||
#if MAC || SGI || SUN || BEOS || LINUX
|
||||
if(theAsioDriver)
|
||||
{
|
||||
delete theAsioDriver;
|
||||
theAsioDriver = 0;
|
||||
}
|
||||
info->driverVersion = 0;
|
||||
strcpy(info->name, "No ASIO Driver");
|
||||
theAsioDriver = getDriver();
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
strcpy(info->errorMessage, "Not enough memory for the ASIO driver!");
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
if(!theAsioDriver->init(info->sysRef))
|
||||
{
|
||||
theAsioDriver->getErrorMessage(info->errorMessage);
|
||||
delete theAsioDriver;
|
||||
theAsioDriver = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
strcpy(info->errorMessage, "No ASIO Driver Error");
|
||||
theAsioDriver->getDriverName(info->name);
|
||||
info->driverVersion = theAsioDriver->getDriverVersion();
|
||||
return ASE_OK;
|
||||
|
||||
#else
|
||||
|
||||
info->driverVersion = 0;
|
||||
strcpy(info->name, "No ASIO Driver");
|
||||
if(theAsioDriver) // must be loaded!
|
||||
{
|
||||
if(!theAsioDriver->init(info->sysRef))
|
||||
{
|
||||
theAsioDriver->getErrorMessage(info->errorMessage);
|
||||
theAsioDriver = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
|
||||
strcpy(info->errorMessage, "No ASIO Driver Error");
|
||||
theAsioDriver->getDriverName(info->name);
|
||||
info->driverVersion = theAsioDriver->getDriverVersion();
|
||||
return ASE_OK;
|
||||
}
|
||||
return ASE_NotPresent;
|
||||
|
||||
#endif // !MAC
|
||||
}
|
||||
|
||||
ASIOError ASIOExit(void)
|
||||
{
|
||||
if(theAsioDriver)
|
||||
{
|
||||
#if WINDOWS
|
||||
asioDrivers->removeCurrentDriver();
|
||||
#else
|
||||
delete theAsioDriver;
|
||||
#endif
|
||||
}
|
||||
theAsioDriver = 0;
|
||||
return ASE_OK;
|
||||
}
|
||||
|
||||
ASIOError ASIOStart(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->start();
|
||||
}
|
||||
|
||||
ASIOError ASIOStop(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->stop();
|
||||
}
|
||||
|
||||
ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
*numInputChannels = *numOutputChannels = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getChannels(numInputChannels, numOutputChannels);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
*inputLatency = *outputLatency = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getLatencies(inputLatency, outputLatency);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
*minSize = *maxSize = *preferredSize = *granularity = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity);
|
||||
}
|
||||
|
||||
ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->canSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->getSampleRate(currentRate);
|
||||
}
|
||||
|
||||
ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->setSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
*numSources = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getClockSources(clocks, numSources);
|
||||
}
|
||||
|
||||
ASIOError ASIOSetClockSource(long reference)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->setClockSource(reference);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->getSamplePosition(sPos, tStamp);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
info->channelGroup = -1;
|
||||
info->type = ASIOSTInt16MSB;
|
||||
strcpy(info->name, "None");
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->getChannelInfo(info);
|
||||
}
|
||||
|
||||
ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
|
||||
long bufferSize, ASIOCallbacks *callbacks)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
{
|
||||
ASIOBufferInfo *info = bufferInfos;
|
||||
for(long i = 0; i < numChannels; i++, info++)
|
||||
info->buffers[0] = info->buffers[1] = 0;
|
||||
return ASE_NotPresent;
|
||||
}
|
||||
return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks);
|
||||
}
|
||||
|
||||
ASIOError ASIODisposeBuffers(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->disposeBuffers();
|
||||
}
|
||||
|
||||
ASIOError ASIOControlPanel(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->controlPanel();
|
||||
}
|
||||
|
||||
ASIOError ASIOFuture(long selector, void *opt)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->future(selector, opt);
|
||||
}
|
||||
|
||||
ASIOError ASIOOutputReady(void)
|
||||
{
|
||||
if(!theAsioDriver)
|
||||
return ASE_NotPresent;
|
||||
return theAsioDriver->outputReady();
|
||||
}
|
||||
|
||||
#if MAC
|
||||
} // extern "C"
|
||||
#pragma export off
|
||||
#endif
|
||||
|
||||
|
||||
955
src/asio/asio.h
Normal file
955
src/asio/asio.h
Normal file
@@ -0,0 +1,955 @@
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
Steinberg Audio Stream I/O API
|
||||
(c) 1997 - 1999, Steinberg Soft- und Hardware GmbH
|
||||
|
||||
ASIO Interface Specification v 2.0
|
||||
|
||||
basic concept is an i/o synchronous double-buffer scheme:
|
||||
|
||||
on bufferSwitch(index == 0), host will read/write:
|
||||
|
||||
after ASIOStart(), the
|
||||
read first input buffer A (index 0)
|
||||
| will be invalid (empty)
|
||||
* ------------------------
|
||||
|------------------------|-----------------------|
|
||||
| | |
|
||||
| Input Buffer A (0) | Input Buffer B (1) |
|
||||
| | |
|
||||
|------------------------|-----------------------|
|
||||
| | |
|
||||
| Output Buffer A (0) | Output Buffer B (1) |
|
||||
| | |
|
||||
|------------------------|-----------------------|
|
||||
* -------------------------
|
||||
| before calling ASIOStart(),
|
||||
write host will have filled output
|
||||
buffer B (index 1) already
|
||||
|
||||
*please* take special care of proper statement of input
|
||||
and output latencies (see ASIOGetLatencies()), these
|
||||
control sequencer sync accuracy
|
||||
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
|
||||
prototypes summary:
|
||||
|
||||
ASIOError ASIOInit(ASIODriverInfo *info);
|
||||
ASIOError ASIOExit(void);
|
||||
ASIOError ASIOStart(void);
|
||||
ASIOError ASIOStop(void);
|
||||
ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);
|
||||
ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);
|
||||
ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);
|
||||
ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);
|
||||
ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);
|
||||
ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);
|
||||
ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);
|
||||
ASIOError ASIOSetClockSource(long reference);
|
||||
ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);
|
||||
ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);
|
||||
ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
|
||||
long bufferSize, ASIOCallbacks *callbacks);
|
||||
ASIOError ASIODisposeBuffers(void);
|
||||
ASIOError ASIOControlPanel(void);
|
||||
void *ASIOFuture(long selector, void *params);
|
||||
ASIOError ASIOOutputReady(void);
|
||||
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef __ASIO_H
|
||||
#define __ASIO_H
|
||||
|
||||
// force 4 byte alignment
|
||||
#if defined(_MSC_VER) && !defined(__MWERKS__)
|
||||
#pragma pack(push,4)
|
||||
#elif PRAGMA_ALIGN_SUPPORTED
|
||||
#pragma options align = native
|
||||
#endif
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Type definitions
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
// number of samples data type is 64 bit integer
|
||||
#if NATIVE_INT64
|
||||
typedef long long int ASIOSamples;
|
||||
#else
|
||||
typedef struct ASIOSamples {
|
||||
unsigned long hi;
|
||||
unsigned long lo;
|
||||
} ASIOSamples;
|
||||
#endif
|
||||
|
||||
// Timestamp data type is 64 bit integer,
|
||||
// Time format is Nanoseconds.
|
||||
#if NATIVE_INT64
|
||||
typedef long long int ASIOTimeStamp ;
|
||||
#else
|
||||
typedef struct ASIOTimeStamp {
|
||||
unsigned long hi;
|
||||
unsigned long lo;
|
||||
} ASIOTimeStamp;
|
||||
#endif
|
||||
|
||||
// Samplerates are expressed in IEEE 754 64 bit double float,
|
||||
// native format as host computer
|
||||
#if IEEE754_64FLOAT
|
||||
typedef double ASIOSampleRate;
|
||||
#else
|
||||
typedef struct ASIOSampleRate {
|
||||
char ieee[8];
|
||||
} ASIOSampleRate;
|
||||
#endif
|
||||
|
||||
// Boolean values are expressed as long
|
||||
typedef long ASIOBool;
|
||||
enum {
|
||||
ASIOFalse = 0,
|
||||
ASIOTrue = 1
|
||||
};
|
||||
|
||||
// Sample Types are expressed as long
|
||||
typedef long ASIOSampleType;
|
||||
enum {
|
||||
ASIOSTInt16MSB = 0,
|
||||
ASIOSTInt24MSB = 1, // used for 20 bits as well
|
||||
ASIOSTInt32MSB = 2,
|
||||
ASIOSTFloat32MSB = 3, // IEEE 754 32 bit float
|
||||
ASIOSTFloat64MSB = 4, // IEEE 754 64 bit double float
|
||||
|
||||
// these are used for 32 bit data buffer, with different alignment of the data inside
|
||||
// 32 bit PCI bus systems can be more easily used with these
|
||||
ASIOSTInt32MSB16 = 8, // 32 bit data with 18 bit alignment
|
||||
ASIOSTInt32MSB18 = 9, // 32 bit data with 18 bit alignment
|
||||
ASIOSTInt32MSB20 = 10, // 32 bit data with 20 bit alignment
|
||||
ASIOSTInt32MSB24 = 11, // 32 bit data with 24 bit alignment
|
||||
|
||||
ASIOSTInt16LSB = 16,
|
||||
ASIOSTInt24LSB = 17, // used for 20 bits as well
|
||||
ASIOSTInt32LSB = 18,
|
||||
ASIOSTFloat32LSB = 19, // IEEE 754 32 bit float, as found on Intel x86 architecture
|
||||
ASIOSTFloat64LSB = 20, // IEEE 754 64 bit double float, as found on Intel x86 architecture
|
||||
|
||||
// these are used for 32 bit data buffer, with different alignment of the data inside
|
||||
// 32 bit PCI bus systems can more easily used with these
|
||||
ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment
|
||||
ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment
|
||||
ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment
|
||||
ASIOSTInt32LSB24 = 27 // 32 bit data with 24 bit alignment
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Error codes
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
typedef long ASIOError;
|
||||
enum {
|
||||
ASE_OK = 0, // This value will be returned whenever the call succeeded
|
||||
ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls
|
||||
ASE_NotPresent = -1000, // hardware input or output is not present or available
|
||||
ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function)
|
||||
ASE_InvalidParameter, // input parameter invalid
|
||||
ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode
|
||||
ASE_SPNotAdvancing, // hardware is not running when sample position is inquired
|
||||
ASE_NoClock, // sample clock or rate cannot be determined or is not present
|
||||
ASE_NoMemory // not enough memory for completing the request
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Time Info support
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
typedef struct ASIOTimeCode
|
||||
{
|
||||
double speed; // speed relation (fraction of nominal speed)
|
||||
// optional; set to 0. or 1. if not supported
|
||||
ASIOSamples timeCodeSamples; // time in samples
|
||||
unsigned long flags; // some information flags (see below)
|
||||
char future[64];
|
||||
} ASIOTimeCode;
|
||||
|
||||
typedef enum ASIOTimeCodeFlags
|
||||
{
|
||||
kTcValid = 1,
|
||||
kTcRunning = 1 << 1,
|
||||
kTcReverse = 1 << 2,
|
||||
kTcOnspeed = 1 << 3,
|
||||
kTcStill = 1 << 4,
|
||||
|
||||
kTcSpeedValid = 1 << 8
|
||||
} ASIOTimeCodeFlags;
|
||||
|
||||
typedef struct AsioTimeInfo
|
||||
{
|
||||
double speed; // absolute speed (1. = nominal)
|
||||
ASIOTimeStamp systemTime; // system time related to samplePosition, in nanoseconds
|
||||
// on mac, must be derived from Microseconds() (not UpTime()!)
|
||||
// on windows, must be derived from timeGetTime()
|
||||
ASIOSamples samplePosition;
|
||||
ASIOSampleRate sampleRate; // current rate
|
||||
unsigned long flags; // (see below)
|
||||
char reserved[12];
|
||||
} AsioTimeInfo;
|
||||
|
||||
typedef enum AsioTimeInfoFlags
|
||||
{
|
||||
kSystemTimeValid = 1, // must always be valid
|
||||
kSamplePositionValid = 1 << 1, // must always be valid
|
||||
kSampleRateValid = 1 << 2,
|
||||
kSpeedValid = 1 << 3,
|
||||
|
||||
kSampleRateChanged = 1 << 4,
|
||||
kClockSourceChanged = 1 << 5
|
||||
} AsioTimeInfoFlags;
|
||||
|
||||
typedef struct ASIOTime // both input/output
|
||||
{
|
||||
long reserved[4]; // must be 0
|
||||
struct AsioTimeInfo timeInfo; // required
|
||||
struct ASIOTimeCode timeCode; // optional, evaluated if (timeCode.flags & kTcValid)
|
||||
} ASIOTime;
|
||||
|
||||
/*
|
||||
|
||||
using time info:
|
||||
it is recommended to use the new method with time info even if the asio
|
||||
device does not support timecode; continuous calls to ASIOGetSamplePosition
|
||||
and ASIOGetSampleRate are avoided, and there is a more defined relationship
|
||||
between callback time and the time info.
|
||||
|
||||
see the example below.
|
||||
to initiate time info mode, after you have received the callbacks pointer in
|
||||
ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo
|
||||
as the argument. if this returns 1, host has accepted time info mode.
|
||||
now host expects the new callback bufferSwitchTimeInfo to be used instead
|
||||
of the old bufferSwitch method. the ASIOTime structure is assumed to be valid
|
||||
and accessible until the callback returns.
|
||||
|
||||
using time code:
|
||||
if the device supports reading time code, it will call host's asioMessage callback
|
||||
with kAsioSupportsTimeCode as the selector. it may then fill the according
|
||||
fields and set the kTcValid flag.
|
||||
host will call the future method with the kAsioEnableTimeCodeRead selector when
|
||||
it wants to enable or disable tc reading by the device. you should also support
|
||||
the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example).
|
||||
|
||||
note:
|
||||
the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions.
|
||||
as a matter of convention, the relationship between the sample
|
||||
position counter and the time code at buffer switch time is
|
||||
(ignoring offset between tc and sample pos when tc is running):
|
||||
|
||||
on input: sample 0 -> input buffer sample 0 -> time code 0
|
||||
on output: sample 0 -> output buffer sample 0 -> time code 0
|
||||
|
||||
this means that for 'real' calculations, one has to take into account
|
||||
the according latencies.
|
||||
|
||||
example:
|
||||
|
||||
ASIOTime asioTime;
|
||||
|
||||
in createBuffers()
|
||||
{
|
||||
memset(&asioTime, 0, sizeof(ASIOTime));
|
||||
AsioTimeInfo* ti = &asioTime.timeInfo;
|
||||
ti->sampleRate = theSampleRate;
|
||||
ASIOTimeCode* tc = &asioTime.timeCode;
|
||||
tc->speed = 1.;
|
||||
timeInfoMode = false;
|
||||
canTimeCode = false;
|
||||
if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1)
|
||||
{
|
||||
timeInfoMode = true;
|
||||
#if kCanTimeCode
|
||||
if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1)
|
||||
canTimeCode = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void switchBuffers(long doubleBufferIndex, bool processNow)
|
||||
{
|
||||
if(timeInfoMode)
|
||||
{
|
||||
AsioTimeInfo* ti = &asioTime.timeInfo;
|
||||
ti->flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
|
||||
ti->systemTime = theNanoSeconds;
|
||||
ti->samplePosition = theSamplePosition;
|
||||
if(ti->sampleRate != theSampleRate)
|
||||
ti->flags |= kSampleRateChanged;
|
||||
ti->sampleRate = theSampleRate;
|
||||
|
||||
#if kCanTimeCode
|
||||
if(canTimeCode && timeCodeEnabled)
|
||||
{
|
||||
ASIOTimeCode* tc = &asioTime.timeCode;
|
||||
tc->timeCodeSamples = tcSamples; // tc in samples
|
||||
tc->flags = kTcValid | kTcRunning | kTcOnspeed; // if so...
|
||||
}
|
||||
ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);
|
||||
#else
|
||||
callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse);
|
||||
}
|
||||
|
||||
ASIOError ASIOFuture(long selector, void *params)
|
||||
{
|
||||
switch(selector)
|
||||
{
|
||||
case kAsioEnableTimeCodeRead:
|
||||
timeCodeEnabled = true;
|
||||
return ASE_SUCCESS;
|
||||
case kAsioDisableTimeCodeRead:
|
||||
timeCodeEnabled = false;
|
||||
return ASE_SUCCESS;
|
||||
case kAsioCanTimeInfo:
|
||||
return ASE_SUCCESS;
|
||||
#if kCanTimeCode
|
||||
case kAsioCanTimeCode:
|
||||
return ASE_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
return ASE_NotPresent;
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// application's audio stream handler callbacks
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
typedef struct ASIOCallbacks
|
||||
{
|
||||
void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess);
|
||||
// bufferSwitch indicates that both input and output are to be processed.
|
||||
// the current buffer half index (0 for A, 1 for B) determines
|
||||
// - the output buffer that the host should start to fill. the other buffer
|
||||
// will be passed to output hardware regardless of whether it got filled
|
||||
// in time or not.
|
||||
// - the input buffer that is now filled with incoming data. Note that
|
||||
// because of the synchronicity of i/o, the input always has at
|
||||
// least one buffer latency in relation to the output.
|
||||
// directProcess suggests to the host whether it should immedeately
|
||||
// start processing (directProcess == ASIOTrue), or whether its process
|
||||
// should be deferred because the call comes from a very low level
|
||||
// (for instance, a high level priority interrupt), and direct processing
|
||||
// would cause timing instabilities for the rest of the system. If in doubt,
|
||||
// directProcess should be set to ASIOFalse.
|
||||
// Note: bufferSwitch may be called at interrupt time for highest efficiency.
|
||||
|
||||
void (*sampleRateDidChange) (ASIOSampleRate sRate);
|
||||
// gets called when the AudioStreamIO detects a sample rate change
|
||||
// If sample rate is unknown, 0 is passed (for instance, clock loss
|
||||
// when externally synchronized).
|
||||
|
||||
long (*asioMessage) (long selector, long value, void* message, double* opt);
|
||||
// generic callback for various purposes, see selectors below.
|
||||
// note this is only present if the asio version is 2 or higher
|
||||
|
||||
ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess);
|
||||
// new callback with time info. makes ASIOGetSamplePosition() and various
|
||||
// calls to ASIOGetSampleRate obsolete,
|
||||
// and allows for timecode sync etc. to be preferred; will be used if
|
||||
// the driver calls asioMessage with selector kAsioSupportsTimeInfo.
|
||||
} ASIOCallbacks;
|
||||
|
||||
// asioMessage selectors
|
||||
enum
|
||||
{
|
||||
kAsioSelectorSupported = 1, // selector in <value>, returns 1L if supported,
|
||||
// 0 otherwise
|
||||
kAsioEngineVersion, // returns engine (host) asio implementation version,
|
||||
// 2 or higher
|
||||
kAsioResetRequest, // request driver reset. if accepted, this
|
||||
// will close the driver (ASIO_Exit() ) and
|
||||
// re-open it again (ASIO_Init() etc). some
|
||||
// drivers need to reconfigure for instance
|
||||
// when the sample rate changes, or some basic
|
||||
// changes have been made in ASIO_ControlPanel().
|
||||
// returns 1L; note the request is merely passed
|
||||
// to the application, there is no way to determine
|
||||
// if it gets accepted at this time (but it usually
|
||||
// will be).
|
||||
kAsioBufferSizeChange, // not yet supported, will currently always return 0L.
|
||||
// for now, use kAsioResetRequest instead.
|
||||
// once implemented, the new buffer size is expected
|
||||
// in <value>, and on success returns 1L
|
||||
kAsioResyncRequest, // the driver went out of sync, such that
|
||||
// the timestamp is no longer valid. this
|
||||
// is a request to re-start the engine and
|
||||
// slave devices (sequencer). returns 1 for ok,
|
||||
// 0 if not supported.
|
||||
kAsioLatenciesChanged, // the drivers latencies have changed. The engine
|
||||
// will refetch the latencies.
|
||||
kAsioSupportsTimeInfo, // if host returns true here, it will expect the
|
||||
// callback bufferSwitchTimeInfo to be called instead
|
||||
// of bufferSwitch
|
||||
kAsioSupportsTimeCode, // supports time code reading/writing
|
||||
|
||||
kAsioSupportsInputMonitor, // supports input monitoring
|
||||
|
||||
kAsioNumMessageSelectors
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// (De-)Construction
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
typedef struct ASIODriverInfo
|
||||
{
|
||||
long asioVersion; // currently, 2
|
||||
long driverVersion; // driver specific
|
||||
char name[32];
|
||||
char errorMessage[124];
|
||||
void *sysRef; // on input: system reference
|
||||
// (Windows: application main window handle, Mac & SGI: 0)
|
||||
} ASIODriverInfo;
|
||||
|
||||
ASIOError ASIOInit(ASIODriverInfo *info);
|
||||
/* Purpose:
|
||||
Initialize the AudioStreamIO.
|
||||
Parameter:
|
||||
info: pointer to an ASIODriver structure:
|
||||
- asioVersion:
|
||||
- on input, the host version. *** Note *** this is 0 for earlier asio
|
||||
implementations, and the asioMessage callback is implemeted
|
||||
only if asioVersion is 2 or greater. sorry but due to a design fault
|
||||
the driver doesn't have access to the host version in ASIOInit :-(
|
||||
added selector for host (engine) version in the asioMessage callback
|
||||
so we're ok from now on.
|
||||
- on return, asio implementation version.
|
||||
older versions are 1
|
||||
if you support this version (namely, ASIO_outputReady() )
|
||||
this should be 2 or higher. also see the note in
|
||||
ASIO_getTimeStamp() !
|
||||
- version: on return, the driver version (format is driver specific)
|
||||
- name: on return, a null-terminated string containing the driver's name
|
||||
- error message: on return, should contain a user message describing
|
||||
the type of error that occured during ASIOInit(), if any.
|
||||
- sysRef: platform specific
|
||||
Returns:
|
||||
If neither input nor output is present ASE_NotPresent
|
||||
will be returned.
|
||||
ASE_NoMemory, ASE_HWMalfunction are other possible error conditions
|
||||
*/
|
||||
|
||||
ASIOError ASIOExit(void);
|
||||
/* Purpose:
|
||||
Terminates the AudioStreamIO.
|
||||
Parameter:
|
||||
None.
|
||||
Returns:
|
||||
If neither input nor output is present ASE_NotPresent
|
||||
will be returned.
|
||||
Notes: this implies ASIOStop() and ASIODisposeBuffers(),
|
||||
meaning that no host callbacks must be accessed after ASIOExit().
|
||||
*/
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Start/Stop
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
ASIOError ASIOStart(void);
|
||||
/* Purpose:
|
||||
Start input and output processing synchronously.
|
||||
This will
|
||||
- reset the sample counter to zero
|
||||
- start the hardware (both input and output)
|
||||
The first call to the hosts' bufferSwitch(index == 0) then tells
|
||||
the host to read from input buffer A (index 0), and start
|
||||
processing to output buffer A while output buffer B (which
|
||||
has been filled by the host prior to calling ASIOStart())
|
||||
is possibly sounding (see also ASIOGetLatencies())
|
||||
Parameter:
|
||||
None.
|
||||
Returns:
|
||||
If neither input nor output is present, ASE_NotPresent
|
||||
will be returned.
|
||||
If the hardware fails to start, ASE_HWMalfunction will be returned.
|
||||
Notes:
|
||||
There is no restriction on the time that ASIOStart() takes
|
||||
to perform (that is, it is not considered a realtime trigger).
|
||||
*/
|
||||
|
||||
ASIOError ASIOStop(void);
|
||||
/* Purpose:
|
||||
Stops input and output processing altogether.
|
||||
Parameter:
|
||||
None.
|
||||
Returns:
|
||||
If neither input nor output is present ASE_NotPresent
|
||||
will be returned.
|
||||
Notes:
|
||||
On return from ASIOStop(), the driver must in no
|
||||
case call the hosts' bufferSwitch() routine.
|
||||
*/
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Inquiry methods and sample rate
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);
|
||||
/* Purpose:
|
||||
Returns number of individual input/output channels.
|
||||
Parameter:
|
||||
numInputChannels will hold the number of available input channels
|
||||
numOutputChannels will hold the number of available output channels
|
||||
Returns:
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
If only inputs, or only outputs are available, the according
|
||||
other parameter will be zero, and ASE_OK is returned.
|
||||
*/
|
||||
|
||||
ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);
|
||||
/* Purpose:
|
||||
Returns the input and output latencies. This includes
|
||||
device specific delays, like FIFOs etc.
|
||||
Parameter:
|
||||
inputLatency will hold the 'age' of the first sample frame
|
||||
in the input buffer when the hosts reads it in bufferSwitch()
|
||||
(this is theoretical, meaning it does not include the overhead
|
||||
and delay between the actual physical switch, and the time
|
||||
when bufferSitch() enters).
|
||||
This will usually be the size of one block in sample frames, plus
|
||||
device specific latencies.
|
||||
|
||||
outputLatency will specify the time between the buffer switch,
|
||||
and the time when the next play buffer will start to sound.
|
||||
The next play buffer is defined as the one the host starts
|
||||
processing after (or at) bufferSwitch(), indicated by the
|
||||
index parameter (0 for buffer A, 1 for buffer B).
|
||||
It will usually be either one block, if the host writes directly
|
||||
to a dma buffer, or two or more blocks if the buffer is 'latched' by
|
||||
the driver. As an example, on ASIOStart(), the host will have filled
|
||||
the play buffer at index 1 already; when it gets the callback (with
|
||||
the parameter index == 0), this tells it to read from the input
|
||||
buffer 0, and start to fill the play buffer 0 (assuming that now
|
||||
play buffer 1 is already sounding). In this case, the output
|
||||
latency is one block. If the driver decides to copy buffer 1
|
||||
at that time, and pass it to the hardware at the next slot (which
|
||||
is most commonly done, but should be avoided), the output latency
|
||||
becomes two blocks instead, resulting in a total i/o latency of at least
|
||||
3 blocks. As memory access is the main bottleneck in native dsp processing,
|
||||
and to acheive less latency, it is highly recommended to try to avoid
|
||||
copying (this is also why the driver is the owner of the buffers). To
|
||||
summarize, the minimum i/o latency can be acheived if the input buffer
|
||||
is processed by the host into the output buffer which will physically
|
||||
start to sound on the next time slice. Also note that the host expects
|
||||
the bufferSwitch() callback to be accessed for each time slice in order
|
||||
to retain sync, possibly recursively; if it fails to process a block in
|
||||
time, it will suspend its operation for some time in order to recover.
|
||||
Returns:
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
*/
|
||||
|
||||
ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);
|
||||
/* Purpose:
|
||||
Returns min, max, and preferred buffer sizes for input/output
|
||||
Parameter:
|
||||
minSize will hold the minimum buffer size
|
||||
maxSize will hold the maxium possible buffer size
|
||||
preferredSize will hold the preferred buffer size (a size which
|
||||
best fits performance and hardware requirements)
|
||||
granularity will hold the granularity at which buffer sizes
|
||||
may differ. Usually, the buffer size will be a power of 2;
|
||||
in this case, granularity will hold -1 on return, signalling
|
||||
possible buffer sizes starting from minSize, increased in
|
||||
powers of 2 up to maxSize.
|
||||
Returns:
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
Notes:
|
||||
When minimum and maximum buffer size are equal,
|
||||
the preferred buffer size has to be the same value as well; granularity
|
||||
should be 0 in this case.
|
||||
*/
|
||||
|
||||
ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);
|
||||
/* Purpose:
|
||||
Inquires the hardware for the available sample rates.
|
||||
Parameter:
|
||||
sampleRate is the rate in question.
|
||||
Returns:
|
||||
If the inquired sample rate is not supported, ASE_NoClock will be returned.
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
*/
|
||||
ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);
|
||||
/* Purpose:
|
||||
Get the current sample Rate.
|
||||
Parameter:
|
||||
currentRate will hold the current sample rate on return.
|
||||
Returns:
|
||||
If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned.
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
Notes:
|
||||
*/
|
||||
|
||||
ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);
|
||||
/* Purpose:
|
||||
Set the hardware to the requested sample Rate. If sampleRate == 0,
|
||||
enable external sync.
|
||||
Parameter:
|
||||
sampleRate: on input, the requested rate
|
||||
Returns:
|
||||
If sampleRate is unknown ASE_NoClock will be returned.
|
||||
If the current clock is external, and sampleRate is != 0,
|
||||
ASE_InvalidMode will be returned
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
Notes:
|
||||
*/
|
||||
|
||||
typedef struct ASIOClockSource
|
||||
{
|
||||
long index; // as used for ASIOSetClockSource()
|
||||
long associatedChannel; // for instance, S/PDIF or AES/EBU
|
||||
long associatedGroup; // see channel groups (ASIOGetChannelInfo())
|
||||
ASIOBool isCurrentSource; // ASIOTrue if this is the current clock source
|
||||
char name[32]; // for user selection
|
||||
} ASIOClockSource;
|
||||
|
||||
ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);
|
||||
/* Purpose:
|
||||
Get the available external audio clock sources
|
||||
Parameter:
|
||||
clocks points to an array of ASIOClockSource structures:
|
||||
- index: this is used to identify the clock source
|
||||
when ASIOSetClockSource() is accessed, should be
|
||||
an index counting from zero
|
||||
- associatedInputChannel: the first channel of an associated
|
||||
input group, if any.
|
||||
- associatedGroup: the group index of that channel.
|
||||
groups of channels are defined to seperate for
|
||||
instance analog, S/PDIF, AES/EBU, ADAT connectors etc,
|
||||
when present simultaniously. Note that associated channel
|
||||
is enumerated according to numInputs/numOutputs, means it
|
||||
is independant from a group (see also ASIOGetChannelInfo())
|
||||
inputs are associated to a clock if the physical connection
|
||||
transfers both data and clock (like S/PDIF, AES/EBU, or
|
||||
ADAT inputs). if there is no input channel associated with
|
||||
the clock source (like Word Clock, or internal oscillator), both
|
||||
associatedChannel and associatedGroup should be set to -1.
|
||||
- isCurrentSource: on exit, ASIOTrue if this is the current clock
|
||||
source, ASIOFalse else
|
||||
- name: a null-terminated string for user selection of the available sources.
|
||||
numSources:
|
||||
on input: the number of allocated array members
|
||||
on output: the number of available clock sources, at least
|
||||
1 (internal clock generator).
|
||||
Returns:
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
Notes:
|
||||
*/
|
||||
|
||||
ASIOError ASIOSetClockSource(long index);
|
||||
/* Purpose:
|
||||
Set the audio clock source
|
||||
Parameter:
|
||||
index as obtained from an inquiry to ASIOGetClockSources()
|
||||
Returns:
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
If the clock can not be selected because an input channel which
|
||||
carries the current clock source is active, ASE_InvalidMode
|
||||
*may* be returned (this depends on the properties of the driver
|
||||
and/or hardware).
|
||||
Notes:
|
||||
Should *not* return ASE_NoClock if there is no clock signal present
|
||||
at the selected source; this will be inquired via ASIOGetSampleRate().
|
||||
It should call the host callback procedure sampleRateHasChanged(),
|
||||
if the switch causes a sample rate change, or if no external clock
|
||||
is present at the selected source.
|
||||
*/
|
||||
|
||||
ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);
|
||||
/* Purpose:
|
||||
Inquires the sample position/time stamp pair.
|
||||
Parameter:
|
||||
sPos will hold the sample position on return. The sample
|
||||
position is reset to zero when ASIOStart() gets called.
|
||||
tStamp will hold the system time when the sample position
|
||||
was latched.
|
||||
Returns:
|
||||
If no input/output is present, ASE_NotPresent will be returned.
|
||||
If there is no clock, ASE_SPNotAdvancing will be returned.
|
||||
Notes:
|
||||
|
||||
in order to be able to synchronise properly,
|
||||
the sample position / time stamp pair must refer to the current block,
|
||||
that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch()
|
||||
callback and expect the time for the current block. thus, when requested
|
||||
in the very first bufferSwitch after ASIO_Start(), the sample position
|
||||
should be zero, and the time stamp should refer to the very time where
|
||||
the stream was started. it also means that the sample position must be
|
||||
block aligned. the driver must ensure proper interpolation if the system
|
||||
time can not be determined for the block position. the driver is responsible
|
||||
for precise time stamps as it usually has most direct access to lower
|
||||
level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies()
|
||||
are essential for precise media synchronization!
|
||||
*/
|
||||
|
||||
typedef struct ASIOChannelInfo
|
||||
{
|
||||
long channel; // on input, channel index
|
||||
ASIOBool isInput; // on input
|
||||
ASIOBool isActive; // on exit
|
||||
long channelGroup; // dto
|
||||
ASIOSampleType type; // dto
|
||||
char name[32]; // dto
|
||||
} ASIOChannelInfo;
|
||||
|
||||
ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);
|
||||
/* Purpose:
|
||||
retreive information about the nature of a channel
|
||||
Parameter:
|
||||
info: pointer to a ASIOChannelInfo structure with
|
||||
- channel: on input, the channel index of the channel in question.
|
||||
- isInput: on input, ASIOTrue if info for an input channel is
|
||||
requested, else output
|
||||
- channelGroup: on return, the channel group that the channel
|
||||
belongs to. For drivers which support different types of
|
||||
channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces,
|
||||
there should be a reasonable grouping of these types. Groups
|
||||
are always independant form a channel index, that is, a channel
|
||||
index always counts from 0 to numInputs/numOutputs regardless
|
||||
of the group it may belong to.
|
||||
There will always be at least one group (group 0). Please
|
||||
also note that by default, the host may decide to activate
|
||||
channels 0 and 1; thus, these should belong to the most
|
||||
useful type (analog i/o, if present).
|
||||
- type: on return, contains the sample type of the channel
|
||||
- isActive: on return, ASIOTrue if channel is active as it was
|
||||
installed by ASIOCreateBuffers(), ASIOFalse else
|
||||
- name: describing the type of channel in question. Used to allow
|
||||
for user selection, and enabling of specific channels. examples:
|
||||
"Analog In", "SPDIF Out" etc
|
||||
Returns:
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
Notes:
|
||||
If possible, the string should be organised such that the first
|
||||
characters are most significantly describing the nature of the
|
||||
port, to allow for identification even if the view showing the
|
||||
port name is too small to display more than 8 characters, for
|
||||
instance.
|
||||
*/
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Buffer preparation
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
typedef struct ASIOBufferInfo
|
||||
{
|
||||
ASIOBool isInput; // on input: ASIOTrue: input, else output
|
||||
long channelNum; // on input: channel index
|
||||
void *buffers[2]; // on output: double buffer addresses
|
||||
} ASIOBufferInfo;
|
||||
|
||||
ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
|
||||
long bufferSize, ASIOCallbacks *callbacks);
|
||||
|
||||
/* Purpose:
|
||||
Allocates input/output buffers for all input and output channels to be activated.
|
||||
Parameter:
|
||||
bufferInfos is a pointer to an array of ASIOBufferInfo structures:
|
||||
- isInput: on input, ASIOTrue if the buffer is to be allocated
|
||||
for an input, output buffer else
|
||||
- channelNum: on input, the index of the channel in question
|
||||
(counting from 0)
|
||||
- buffers: on exit, 2 pointers to the halves of the channels' double-buffer.
|
||||
the size of the buffer(s) of course depend on both the ASIOSampleType
|
||||
as obtained from ASIOGetChannelInfo(), and bufferSize
|
||||
numChannels is the sum of all input and output channels to be created;
|
||||
thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo
|
||||
structures.
|
||||
bufferSize selects one of the possible buffer sizes as obtained from
|
||||
ASIOGetBufferSizes().
|
||||
callbacks is a pointer to an ASIOCallbacks structure.
|
||||
Returns:
|
||||
If not enough memory is available ASE_NoMemory will be returned.
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
If bufferSize is not supported, or one or more of the bufferInfos elements
|
||||
contain invalid settings, ASE_InvalidMode will be returned.
|
||||
Notes:
|
||||
If individual channel selection is not possible but requested,
|
||||
the driver has to handle this. namely, bufferSwitch() will only
|
||||
have filled buffers of enabled outputs. If possible, processing
|
||||
and buss activities overhead should be avoided for channels which
|
||||
were not enabled here.
|
||||
*/
|
||||
|
||||
ASIOError ASIODisposeBuffers(void);
|
||||
/* Purpose:
|
||||
Releases all buffers for the device.
|
||||
Parameter:
|
||||
None.
|
||||
Returns:
|
||||
If no buffer were ever prepared, ASE_InvalidMode will be returned.
|
||||
If no input/output is present ASE_NotPresent will be returned.
|
||||
Notes:
|
||||
This implies ASIOStop().
|
||||
*/
|
||||
|
||||
ASIOError ASIOControlPanel(void);
|
||||
/* Purpose:
|
||||
request the driver to start a control panel component
|
||||
for device specific user settings. This will not be
|
||||
accessed on some platforms (where the component is accessed
|
||||
instead).
|
||||
Parameter:
|
||||
None.
|
||||
Returns:
|
||||
If no panel is available ASE_NotPresent will be returned.
|
||||
Actually, the return code is ignored.
|
||||
Notes:
|
||||
if the user applied settings which require a re-configuration
|
||||
of parts or all of the enigine and/or driver (such as a change of
|
||||
the block size), the asioMessage callback can be used (see
|
||||
ASIO_Callbacks).
|
||||
*/
|
||||
|
||||
ASIOError ASIOFuture(long selector, void *params);
|
||||
/* Purpose:
|
||||
various
|
||||
Parameter:
|
||||
selector: operation Code as to be defined. zero is reserved for
|
||||
testing purposes.
|
||||
params: depends on the selector; usually pointer to a structure
|
||||
for passing and retreiving any type and amount of parameters.
|
||||
Returns:
|
||||
the return value is also selector dependant. if the selector
|
||||
is unknown, ASE_InvalidParameter should be returned to prevent
|
||||
further calls with this selector. on success, ASE_SUCCESS
|
||||
must be returned (note: ASE_OK is *not* sufficient!)
|
||||
Notes:
|
||||
see selectors defined below.
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
kAsioEnableTimeCodeRead = 1, // no arguments
|
||||
kAsioDisableTimeCodeRead, // no arguments
|
||||
kAsioSetInputMonitor, // ASIOInputMonitor* in params
|
||||
kAsioTransport, // ASIOTransportParameters* in params
|
||||
kAsioSetInputGain, // ASIOChannelControls* in params, apply gain
|
||||
kAsioGetInputMeter, // ASIOChannelControls* in params, fill meter
|
||||
kAsioSetOutputGain, // ASIOChannelControls* in params, apply gain
|
||||
kAsioGetOutputMeter, // ASIOChannelControls* in params, fill meter
|
||||
kAsioCanInputMonitor, // no arguments for kAsioCanXXX selectors
|
||||
kAsioCanTimeInfo,
|
||||
kAsioCanTimeCode,
|
||||
kAsioCanTransport,
|
||||
kAsioCanInputGain,
|
||||
kAsioCanInputMeter,
|
||||
kAsioCanOutputGain,
|
||||
kAsioCanOutputMeter
|
||||
};
|
||||
|
||||
typedef struct ASIOInputMonitor
|
||||
{
|
||||
long input; // this input was set to monitor (or off), -1: all
|
||||
long output; // suggested output for monitoring the input (if so)
|
||||
long gain; // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB)
|
||||
ASIOBool state; // ASIOTrue => on, ASIOFalse => off
|
||||
long pan; // suggested pan, 0 => all left, 0x7fffffff => right
|
||||
} ASIOInputMonitor;
|
||||
|
||||
typedef struct ASIOChannelControls
|
||||
{
|
||||
long channel; // on input, channel index
|
||||
ASIOBool isInput; // on input
|
||||
long gain; // on input, ranges 0 thru 0x7fffffff
|
||||
long meter; // on return, ranges 0 thru 0x7fffffff
|
||||
char future[32];
|
||||
} ASIOChannelControls;
|
||||
|
||||
typedef struct ASIOTransportParameters
|
||||
{
|
||||
long command; // see enum below
|
||||
ASIOSamples samplePosition;
|
||||
long track;
|
||||
long trackSwitches[16]; // 512 tracks on/off
|
||||
char future[64];
|
||||
} ASIOTransportParameters;
|
||||
|
||||
enum
|
||||
{
|
||||
kTransStart = 1,
|
||||
kTransStop,
|
||||
kTransLocate, // to samplePosition
|
||||
kTransPunchIn,
|
||||
kTransPunchOut,
|
||||
kTransArmOn, // track
|
||||
kTransArmOff, // track
|
||||
kTransMonitorOn, // track
|
||||
kTransMonitorOff, // track
|
||||
kTransArm, // trackSwitches
|
||||
kTransMonitor // trackSwitches
|
||||
};
|
||||
|
||||
ASIOError ASIOOutputReady(void);
|
||||
/* Purpose:
|
||||
this tells the driver that the host has completed processing
|
||||
the output buffers. if the data format required by the hardware
|
||||
differs from the supported asio formats, but the hardware
|
||||
buffers are DMA buffers, the driver will have to convert
|
||||
the audio stream data; as the bufferSwitch callback is
|
||||
usually issued at dma block switch time, the driver will
|
||||
have to convert the *previous* host buffer, which increases
|
||||
the output latency by one block.
|
||||
when the host finds out that ASIOOutputReady() returns
|
||||
true, it will issue this call whenever it completed
|
||||
output processing. then the driver can convert the
|
||||
host data directly to the dma buffer to be played next,
|
||||
reducing output latency by one block.
|
||||
another way to look at it is, that the buffer switch is called
|
||||
in order to pass the *input* stream to the host, so that it can
|
||||
process the input into the output, and the output stream is passed
|
||||
to the driver when the host has completed its process.
|
||||
Parameter:
|
||||
None
|
||||
Returns:
|
||||
only if the above mentioned scenario is given, and a reduction
|
||||
of output latency can be acheived by this mechanism, should
|
||||
ASE_OK be returned. otherwise (and usually), ASE_NotPresent
|
||||
should be returned in order to prevent further calls to this
|
||||
function. note that the host may want to determine if it is
|
||||
to use this when the system is not yet fully initialized, so
|
||||
ASE_OK should always be returned if the mechanism makes sense.
|
||||
Notes:
|
||||
please remeber to adjust ASIOGetLatencies() according to
|
||||
whether ASIOOutputReady() was ever called or not, if your
|
||||
driver supports this scenario.
|
||||
also note that the engine may fail to call ASIO_OutputReady()
|
||||
in time in overload cases. as already mentioned, bufferSwitch
|
||||
should be called for every block regardless of whether a block
|
||||
could be processed in time.
|
||||
*/
|
||||
|
||||
// restore old alignment
|
||||
#if defined(_MSC_VER) && !defined(__MWERKS__)
|
||||
#pragma pack(pop)
|
||||
#elif PRAGMA_ALIGN_SUPPORTED
|
||||
#pragma options align = reset
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
186
src/asio/asiodrivers.cpp
Normal file
186
src/asio/asiodrivers.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#include <string.h>
|
||||
#include "asiodrivers.h"
|
||||
|
||||
AsioDrivers* asioDrivers = 0;
|
||||
|
||||
bool loadAsioDriver(char *name);
|
||||
|
||||
bool loadAsioDriver(char *name)
|
||||
{
|
||||
if(!asioDrivers)
|
||||
asioDrivers = new AsioDrivers();
|
||||
if(asioDrivers)
|
||||
return asioDrivers->loadDriver(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
#if MAC
|
||||
|
||||
bool resolveASIO(unsigned long aconnID);
|
||||
|
||||
AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio')
|
||||
{
|
||||
connID = -1;
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
AsioDrivers::~AsioDrivers()
|
||||
{
|
||||
removeCurrentDriver();
|
||||
}
|
||||
|
||||
bool AsioDrivers::getCurrentDriverName(char *name)
|
||||
{
|
||||
if(curIndex >= 0)
|
||||
return getName(curIndex, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
|
||||
{
|
||||
for(long i = 0; i < getNumFragments() && i < maxDrivers; i++)
|
||||
getName(i, names[i]);
|
||||
return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers;
|
||||
}
|
||||
|
||||
bool AsioDrivers::loadDriver(char *name)
|
||||
{
|
||||
char dname[64];
|
||||
unsigned long newID;
|
||||
|
||||
for(long i = 0; i < getNumFragments(); i++)
|
||||
{
|
||||
if(getName(i, dname) && !strcmp(name, dname))
|
||||
{
|
||||
if(newInstance(i, &newID))
|
||||
{
|
||||
if(resolveASIO(newID))
|
||||
{
|
||||
if(connID != -1)
|
||||
removeInstance(curIndex, connID);
|
||||
curIndex = i;
|
||||
connID = newID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AsioDrivers::removeCurrentDriver()
|
||||
{
|
||||
if(connID != -1)
|
||||
removeInstance(curIndex, connID);
|
||||
connID = -1;
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
#elif WINDOWS
|
||||
|
||||
#include "iasiodrv.h"
|
||||
|
||||
extern IASIO* theAsioDriver;
|
||||
|
||||
AsioDrivers::AsioDrivers() : AsioDriverList()
|
||||
{
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
AsioDrivers::~AsioDrivers()
|
||||
{
|
||||
}
|
||||
|
||||
bool AsioDrivers::getCurrentDriverName(char *name)
|
||||
{
|
||||
if(curIndex >= 0)
|
||||
return asioGetDriverName(curIndex, name, 32) == 0 ? true : false;
|
||||
name[0] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
|
||||
{
|
||||
for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++)
|
||||
asioGetDriverName(i, names[i], 32);
|
||||
return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers;
|
||||
}
|
||||
|
||||
bool AsioDrivers::loadDriver(char *name)
|
||||
{
|
||||
char dname[64];
|
||||
char curName[64];
|
||||
|
||||
for(long i = 0; i < asioGetNumDev(); i++)
|
||||
{
|
||||
if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname))
|
||||
{
|
||||
curName[0] = 0;
|
||||
getCurrentDriverName(curName); // in case we fail...
|
||||
removeCurrentDriver();
|
||||
|
||||
if(!asioOpenDriver(i, (void **)&theAsioDriver))
|
||||
{
|
||||
curIndex = i;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
theAsioDriver = 0;
|
||||
if(curName[0] && strcmp(dname, curName))
|
||||
loadDriver(curName); // try restore
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AsioDrivers::removeCurrentDriver()
|
||||
{
|
||||
if(curIndex != -1)
|
||||
asioCloseDriver(curIndex);
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
#elif SGI || BEOS
|
||||
|
||||
#include "asiolist.h"
|
||||
|
||||
AsioDrivers::AsioDrivers()
|
||||
: AsioDriverList()
|
||||
{
|
||||
curIndex = -1;
|
||||
}
|
||||
|
||||
AsioDrivers::~AsioDrivers()
|
||||
{
|
||||
}
|
||||
|
||||
bool AsioDrivers::getCurrentDriverName(char *name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AsioDrivers::loadDriver(char *name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AsioDrivers::removeCurrentDriver()
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
#error implement me
|
||||
#endif
|
||||
41
src/asio/asiodrivers.h
Normal file
41
src/asio/asiodrivers.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef __AsioDrivers__
|
||||
#define __AsioDrivers__
|
||||
|
||||
#include "ginclude.h"
|
||||
|
||||
#if MAC
|
||||
#include "CodeFragments.hpp"
|
||||
|
||||
class AsioDrivers : public CodeFragments
|
||||
|
||||
#elif WINDOWS
|
||||
#include <windows.h>
|
||||
#include "asiolist.h"
|
||||
|
||||
class AsioDrivers : public AsioDriverList
|
||||
|
||||
#elif SGI || BEOS
|
||||
#include "asiolist.h"
|
||||
|
||||
class AsioDrivers : public AsioDriverList
|
||||
|
||||
#else
|
||||
#error implement me
|
||||
#endif
|
||||
|
||||
{
|
||||
public:
|
||||
AsioDrivers();
|
||||
~AsioDrivers();
|
||||
|
||||
bool getCurrentDriverName(char *name);
|
||||
long getDriverNames(char **names, long maxDrivers);
|
||||
bool loadDriver(char *name);
|
||||
void removeCurrentDriver();
|
||||
long getCurrentDriverIndex() {return curIndex;}
|
||||
protected:
|
||||
unsigned long connID;
|
||||
long curIndex;
|
||||
};
|
||||
|
||||
#endif
|
||||
76
src/asio/asiodrvr.h
Normal file
76
src/asio/asiodrvr.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Steinberg Audio Stream I/O API
|
||||
(c) 1996, Steinberg Soft- und Hardware GmbH
|
||||
charlie (May 1996)
|
||||
|
||||
asiodrvr.h
|
||||
c++ superclass to implement asio functionality. from this,
|
||||
you can derive whatever required
|
||||
*/
|
||||
|
||||
#ifndef _asiodrvr_
|
||||
#define _asiodrvr_
|
||||
|
||||
// cpu and os system we are running on
|
||||
#include "asiosys.h"
|
||||
// basic "C" interface
|
||||
#include "asio.h"
|
||||
|
||||
class AsioDriver;
|
||||
extern AsioDriver *getDriver(); // for generic constructor
|
||||
|
||||
#if WINDOWS
|
||||
#include <windows.h>
|
||||
#include "combase.h"
|
||||
#include "iasiodrv.h"
|
||||
class AsioDriver : public IASIO ,public CUnknown
|
||||
{
|
||||
public:
|
||||
AsioDriver(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
// Factory method
|
||||
static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
// IUnknown
|
||||
virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject);
|
||||
|
||||
#else
|
||||
|
||||
class AsioDriver
|
||||
{
|
||||
public:
|
||||
AsioDriver();
|
||||
#endif
|
||||
virtual ~AsioDriver();
|
||||
|
||||
virtual ASIOBool init(void* sysRef);
|
||||
virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero
|
||||
virtual long getDriverVersion();
|
||||
virtual void getErrorMessage(char *string); // max 124 bytes incl.
|
||||
|
||||
virtual ASIOError start();
|
||||
virtual ASIOError stop();
|
||||
|
||||
virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);
|
||||
virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);
|
||||
virtual ASIOError getBufferSize(long *minSize, long *maxSize,
|
||||
long *preferredSize, long *granularity);
|
||||
|
||||
virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);
|
||||
virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);
|
||||
virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);
|
||||
virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);
|
||||
virtual ASIOError setClockSource(long reference);
|
||||
|
||||
virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);
|
||||
virtual ASIOError getChannelInfo(ASIOChannelInfo *info);
|
||||
|
||||
virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
|
||||
long bufferSize, ASIOCallbacks *callbacks);
|
||||
virtual ASIOError disposeBuffers();
|
||||
|
||||
virtual ASIOError controlPanel();
|
||||
virtual ASIOError future(long selector, void *opt);
|
||||
virtual ASIOError outputReady();
|
||||
};
|
||||
#endif
|
||||
268
src/asio/asiolist.cpp
Normal file
268
src/asio/asiolist.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
#include <windows.h>
|
||||
#include "iasiodrv.h"
|
||||
#include "asiolist.h"
|
||||
|
||||
#define ASIODRV_DESC "description"
|
||||
#define INPROC_SERVER "InprocServer32"
|
||||
#define ASIO_PATH "software\\asio"
|
||||
#define COM_CLSID "clsid"
|
||||
|
||||
// ******************************************************************
|
||||
// Local Functions
|
||||
// ******************************************************************
|
||||
static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize)
|
||||
{
|
||||
HKEY hkEnum,hksub,hkpath;
|
||||
char databuf[512];
|
||||
LONG cr,rc = -1;
|
||||
DWORD datatype,datasize;
|
||||
DWORD index;
|
||||
OFSTRUCT ofs;
|
||||
HFILE hfile;
|
||||
BOOL found = FALSE;
|
||||
|
||||
CharLowerBuff(clsidstr,strlen(clsidstr));
|
||||
if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {
|
||||
|
||||
index = 0;
|
||||
while (cr == ERROR_SUCCESS && !found) {
|
||||
cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512);
|
||||
if (cr == ERROR_SUCCESS) {
|
||||
CharLowerBuff(databuf,strlen(databuf));
|
||||
if (!(strcmp(databuf,clsidstr))) {
|
||||
if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
|
||||
if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {
|
||||
datatype = REG_SZ; datasize = (DWORD)dllpathsize;
|
||||
cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);
|
||||
if (cr == ERROR_SUCCESS) {
|
||||
memset(&ofs,0,sizeof(OFSTRUCT));
|
||||
ofs.cBytes = sizeof(OFSTRUCT);
|
||||
hfile = OpenFile(dllpath,&ofs,OF_EXIST);
|
||||
if (hfile) rc = 0;
|
||||
}
|
||||
RegCloseKey(hkpath);
|
||||
}
|
||||
RegCloseKey(hksub);
|
||||
}
|
||||
found = TRUE; // break out
|
||||
}
|
||||
}
|
||||
}
|
||||
RegCloseKey(hkEnum);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv)
|
||||
{
|
||||
HKEY hksub;
|
||||
char databuf[256];
|
||||
char dllpath[MAXPATHLEN];
|
||||
WORD wData[100];
|
||||
CLSID clsid;
|
||||
DWORD datatype,datasize;
|
||||
LONG cr,rc;
|
||||
|
||||
if (!lpdrv) {
|
||||
if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
|
||||
|
||||
datatype = REG_SZ; datasize = 256;
|
||||
cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize);
|
||||
if (cr == ERROR_SUCCESS) {
|
||||
rc = findDrvPath (databuf,dllpath,MAXPATHLEN);
|
||||
if (rc == 0) {
|
||||
lpdrv = new ASIODRVSTRUCT[1];
|
||||
if (lpdrv) {
|
||||
memset(lpdrv,0,sizeof(ASIODRVSTRUCT));
|
||||
lpdrv->drvID = drvID;
|
||||
MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100);
|
||||
if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) {
|
||||
memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID));
|
||||
}
|
||||
|
||||
datatype = REG_SZ; datasize = 256;
|
||||
cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize);
|
||||
if (cr == ERROR_SUCCESS) {
|
||||
strcpy(lpdrv->drvname,databuf);
|
||||
}
|
||||
else strcpy(lpdrv->drvname,keyname);
|
||||
}
|
||||
}
|
||||
}
|
||||
RegCloseKey(hksub);
|
||||
}
|
||||
}
|
||||
else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next);
|
||||
|
||||
return lpdrv;
|
||||
}
|
||||
|
||||
static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv)
|
||||
{
|
||||
IASIO *iasio;
|
||||
|
||||
if (lpdrv != 0) {
|
||||
deleteDrvStruct(lpdrv->next);
|
||||
if (lpdrv->asiodrv) {
|
||||
iasio = (IASIO *)lpdrv->asiodrv;
|
||||
iasio->Release();
|
||||
}
|
||||
delete lpdrv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv)
|
||||
{
|
||||
while (lpdrv) {
|
||||
if (lpdrv->drvID == drvID) return lpdrv;
|
||||
lpdrv = lpdrv->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// ******************************************************************
|
||||
|
||||
|
||||
// ******************************************************************
|
||||
// AsioDriverList
|
||||
// ******************************************************************
|
||||
AsioDriverList::AsioDriverList ()
|
||||
{
|
||||
HKEY hkEnum = 0;
|
||||
char keyname[MAXDRVNAMELEN];
|
||||
LPASIODRVSTRUCT pdl;
|
||||
LONG cr;
|
||||
DWORD index = 0;
|
||||
BOOL fin = FALSE;
|
||||
|
||||
numdrv = 0;
|
||||
lpdrvlist = 0;
|
||||
|
||||
cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);
|
||||
while (cr == ERROR_SUCCESS) {
|
||||
if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {
|
||||
lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist);
|
||||
}
|
||||
else fin = TRUE;
|
||||
}
|
||||
if (hkEnum) RegCloseKey(hkEnum);
|
||||
|
||||
pdl = lpdrvlist;
|
||||
while (pdl) {
|
||||
numdrv++;
|
||||
pdl = pdl->next;
|
||||
}
|
||||
|
||||
if (numdrv) CoInitialize(0); // initialize COM
|
||||
}
|
||||
|
||||
AsioDriverList::~AsioDriverList ()
|
||||
{
|
||||
if (numdrv) {
|
||||
deleteDrvStruct(lpdrvlist);
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LONG AsioDriverList::asioGetNumDev (VOID)
|
||||
{
|
||||
return (LONG)numdrv;
|
||||
}
|
||||
|
||||
|
||||
LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
long rc;
|
||||
|
||||
if (!asiodrv) return DRVERR_INVALID_PARAM;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
if (!lpdrv->asiodrv) {
|
||||
rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv);
|
||||
if (rc == S_OK) {
|
||||
lpdrv->asiodrv = *asiodrv;
|
||||
return 0;
|
||||
}
|
||||
// else if (rc == REGDB_E_CLASSNOTREG)
|
||||
// strcpy (info->messageText, "Driver not registered in the Registration Database!");
|
||||
}
|
||||
else rc = DRVERR_DEVICE_ALREADY_OPEN;
|
||||
}
|
||||
else rc = DRVERR_DEVICE_NOT_FOUND;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
LONG AsioDriverList::asioCloseDriver (int drvID)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
IASIO *iasio;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
if (lpdrv->asiodrv) {
|
||||
iasio = (IASIO *)lpdrv->asiodrv;
|
||||
iasio->Release();
|
||||
lpdrv->asiodrv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
|
||||
if (!drvname) return DRVERR_INVALID_PARAM;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) {
|
||||
strcpy(drvname,lpdrv->drvname);
|
||||
}
|
||||
else {
|
||||
memcpy(drvname,lpdrv->drvname,drvnamesize-4);
|
||||
drvname[drvnamesize-4] = '.';
|
||||
drvname[drvnamesize-3] = '.';
|
||||
drvname[drvnamesize-2] = '.';
|
||||
drvname[drvnamesize-1] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return DRVERR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
|
||||
if (!dllpath) return DRVERR_INVALID_PARAM;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) {
|
||||
strcpy(dllpath,lpdrv->dllpath);
|
||||
return 0;
|
||||
}
|
||||
dllpath[0] = 0;
|
||||
return DRVERR_INVALID_PARAM;
|
||||
}
|
||||
return DRVERR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid)
|
||||
{
|
||||
LPASIODRVSTRUCT lpdrv = 0;
|
||||
|
||||
if (!clsid) return DRVERR_INVALID_PARAM;
|
||||
|
||||
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
|
||||
memcpy(clsid,&lpdrv->clsid,sizeof(CLSID));
|
||||
return 0;
|
||||
}
|
||||
return DRVERR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
46
src/asio/asiolist.h
Normal file
46
src/asio/asiolist.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef __asiolist__
|
||||
#define __asiolist__
|
||||
|
||||
#define DRVERR -5000
|
||||
#define DRVERR_INVALID_PARAM DRVERR-1
|
||||
#define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2
|
||||
#define DRVERR_DEVICE_NOT_FOUND DRVERR-3
|
||||
|
||||
#define MAXPATHLEN 512
|
||||
#define MAXDRVNAMELEN 128
|
||||
|
||||
struct asiodrvstruct
|
||||
{
|
||||
int drvID;
|
||||
CLSID clsid;
|
||||
char dllpath[MAXPATHLEN];
|
||||
char drvname[MAXDRVNAMELEN];
|
||||
LPVOID asiodrv;
|
||||
struct asiodrvstruct *next;
|
||||
};
|
||||
|
||||
typedef struct asiodrvstruct ASIODRVSTRUCT;
|
||||
typedef ASIODRVSTRUCT *LPASIODRVSTRUCT;
|
||||
|
||||
class AsioDriverList {
|
||||
public:
|
||||
AsioDriverList();
|
||||
~AsioDriverList();
|
||||
|
||||
LONG asioOpenDriver (int,VOID **);
|
||||
LONG asioCloseDriver (int);
|
||||
|
||||
// nice to have
|
||||
LONG asioGetNumDev (VOID);
|
||||
LONG asioGetDriverName (int,char *,int);
|
||||
LONG asioGetDriverPath (int,char *,int);
|
||||
LONG asioGetDriverCLSID (int,CLSID *);
|
||||
|
||||
// or use directly access
|
||||
LPASIODRVSTRUCT lpdrvlist;
|
||||
int numdrv;
|
||||
};
|
||||
|
||||
typedef class AsioDriverList *LPASIODRIVERLIST;
|
||||
|
||||
#endif
|
||||
82
src/asio/asiosys.h
Normal file
82
src/asio/asiosys.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef __asiosys__
|
||||
#define __asiosys__
|
||||
|
||||
#ifdef WIN32
|
||||
#undef MAC
|
||||
#define PPC 0
|
||||
#define WINDOWS 1
|
||||
#define SGI 0
|
||||
#define SUN 0
|
||||
#define LINUX 0
|
||||
#define BEOS 0
|
||||
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#elif BEOS
|
||||
#define MAC 0
|
||||
#define PPC 0
|
||||
#define WINDOWS 0
|
||||
#define PC 0
|
||||
#define SGI 0
|
||||
#define SUN 0
|
||||
#define LINUX 0
|
||||
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
void DEBUGGERMESSAGE(char *string);
|
||||
#else
|
||||
#define DEBUGGERMESSAGE(a)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif SGI
|
||||
#define MAC 0
|
||||
#define PPC 0
|
||||
#define WINDOWS 0
|
||||
#define PC 0
|
||||
#define SUN 0
|
||||
#define LINUX 0
|
||||
#define BEOS 0
|
||||
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
void DEBUGGERMESSAGE(char *string);
|
||||
#else
|
||||
#define DEBUGGERMESSAGE(a)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else // MAC
|
||||
|
||||
#define MAC 1
|
||||
#define PPC 1
|
||||
#define WINDOWS 0
|
||||
#define PC 0
|
||||
#define SGI 0
|
||||
#define SUN 0
|
||||
#define LINUX 0
|
||||
#define BEOS 0
|
||||
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
void DEBUGGERMESSAGE(char *string);
|
||||
#else
|
||||
#define DEBUGGERMESSAGE(a)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
38
src/asio/ginclude.h
Normal file
38
src/asio/ginclude.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef __gInclude__
|
||||
#define __gInclude__
|
||||
|
||||
#if SGI
|
||||
#undef BEOS
|
||||
#undef MAC
|
||||
#undef WINDOWS
|
||||
//
|
||||
#define ASIO_BIG_ENDIAN 1
|
||||
#define ASIO_CPU_MIPS 1
|
||||
#elif defined WIN32
|
||||
#undef BEOS
|
||||
#undef MAC
|
||||
#undef SGI
|
||||
#define WINDOWS 1
|
||||
#define ASIO_LITTLE_ENDIAN 1
|
||||
#define ASIO_CPU_X86 1
|
||||
#elif BEOS
|
||||
#undef MAC
|
||||
#undef SGI
|
||||
#undef WINDOWS
|
||||
#define ASIO_LITTLE_ENDIAN 1
|
||||
#define ASIO_CPU_X86 1
|
||||
//
|
||||
#else
|
||||
#define MAC 1
|
||||
#undef BEOS
|
||||
#undef WINDOWS
|
||||
#undef SGI
|
||||
#define ASIO_BIG_ENDIAN 1
|
||||
#define ASIO_CPU_PPC 1
|
||||
#endif
|
||||
|
||||
// always
|
||||
#define NATIVE_INT64 0
|
||||
#define IEEE754_64FLOAT 1
|
||||
|
||||
#endif // __gInclude__
|
||||
37
src/asio/iasiodrv.h
Normal file
37
src/asio/iasiodrv.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "asiosys.h"
|
||||
#include "asio.h"
|
||||
|
||||
/* Forward Declarations */
|
||||
|
||||
#ifndef __ASIODRIVER_FWD_DEFINED__
|
||||
#define __ASIODRIVER_FWD_DEFINED__
|
||||
typedef interface IASIO IASIO;
|
||||
#endif /* __ASIODRIVER_FWD_DEFINED__ */
|
||||
|
||||
interface IASIO : public IUnknown
|
||||
{
|
||||
|
||||
virtual ASIOBool init(void *sysHandle) = 0;
|
||||
virtual void getDriverName(char *name) = 0;
|
||||
virtual long getDriverVersion() = 0;
|
||||
virtual void getErrorMessage(char *string) = 0;
|
||||
virtual ASIOError start() = 0;
|
||||
virtual ASIOError stop() = 0;
|
||||
virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0;
|
||||
virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0;
|
||||
virtual ASIOError getBufferSize(long *minSize, long *maxSize,
|
||||
long *preferredSize, long *granularity) = 0;
|
||||
virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0;
|
||||
virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0;
|
||||
virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0;
|
||||
virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0;
|
||||
virtual ASIOError setClockSource(long reference) = 0;
|
||||
virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0;
|
||||
virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0;
|
||||
virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
|
||||
long bufferSize, ASIOCallbacks *callbacks) = 0;
|
||||
virtual ASIOError disposeBuffers() = 0;
|
||||
virtual ASIOError controlPanel() = 0;
|
||||
virtual ASIOError future(long selector,void *opt) = 0;
|
||||
virtual ASIOError outputReady() = 0;
|
||||
};
|
||||
Reference in New Issue
Block a user