Version 4.2.1

This commit is contained in:
Gary Scavone
2009-03-24 23:02:14 -04:00
committed by Stephen Sinclair
parent a6381b9d38
commit 2cbce2d8bd
275 changed files with 8949 additions and 6906 deletions

View File

@@ -11,7 +11,7 @@
envelope value reaches 0.0 in the
ADSR::RELEASE state.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -153,7 +153,7 @@ int ADSR :: getState(void) const
return state_;
}
StkFloat ADSR :: tick()
StkFloat ADSR :: computeSample()
{
switch (state_) {
@@ -187,13 +187,3 @@ StkFloat ADSR :: tick()
lastOutput_ = value_;
return value_;
}
StkFloat *ADSR :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Generator::tick( vector, vectorSize );
}
StkFrames& ADSR :: tick( StkFrames& frames, unsigned int channel )
{
return Generator::tick( frames, channel );
}

View File

@@ -19,7 +19,7 @@
to \e keyOn and \e keyOff messages by ramping to
1.0 on keyOn and to 0.0 on keyOff.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -79,7 +79,7 @@ void Asymp :: setTarget(StkFloat target)
constant_ = ( 1.0 - factor_ ) * target_;
}
StkFloat Asymp :: tick(void)
StkFloat Asymp :: computeSample(void)
{
if (state_) {
@@ -104,12 +104,3 @@ StkFloat Asymp :: tick(void)
return value_;
}
StkFloat *Asymp :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Generator::tick( vector, vectorSize );
}
StkFrames& Asymp :: tick( StkFrames& frames, unsigned int channel )
{
return Generator::tick( frames, channel );
}

View File

@@ -31,8 +31,7 @@
#include "BandedWG.h"
#include "SKINI.msg"
#include "Noise.h"
#include <math.h>
#include <cmath>
BandedWG :: BandedWG()
{
@@ -264,7 +263,7 @@ void BandedWG :: noteOff(StkFloat amplitude)
#endif
}
StkFloat BandedWG :: tick()
StkFloat BandedWG :: computeSample()
{
int k;
@@ -308,16 +307,6 @@ StkFloat BandedWG :: tick()
return lastOutput_;
}
StkFloat *BandedWG :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& BandedWG :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void BandedWG :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

View File

@@ -28,7 +28,7 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -79,12 +79,12 @@ void BeeThree :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat BeeThree :: tick()
StkFloat BeeThree :: computeSample()
{
register StkFloat temp;
if (modDepth_ > 0.0) {
temp = 1.0 + (modDepth_ * vibrato_->tick() * 0.1);
temp = 1.0 + (modDepth_ * vibrato_.tick() * 0.1);
waves_[0]->setFrequency(baseFrequency_ * temp * ratios_[0]);
waves_[1]->setFrequency(baseFrequency_ * temp * ratios_[1]);
waves_[2]->setFrequency(baseFrequency_ * temp * ratios_[2]);
@@ -103,12 +103,4 @@ StkFloat BeeThree :: tick()
return lastOutput_;
}
StkFloat *BeeThree :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& BeeThree :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

View File

@@ -8,12 +8,12 @@
frequency response while maintaining a constant
filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "BiQuad.h"
#include <math.h>
#include <cmath>
BiQuad :: BiQuad() : Filter()
{
@@ -100,9 +100,9 @@ StkFloat BiQuad :: lastOut(void) const
return Filter::lastOut();
}
StkFloat BiQuad :: tick(StkFloat sample)
StkFloat BiQuad :: computeSample( StkFloat input )
{
inputs_[0] = gain_ * sample;
inputs_[0] = gain_ * input;
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];
@@ -113,9 +113,9 @@ StkFloat BiQuad :: tick(StkFloat sample)
return outputs_[0];
}
StkFloat *BiQuad :: tick(StkFloat *vector, unsigned int vectorSize)
StkFloat BiQuad :: tick( StkFloat input )
{
return Filter::tick( vector, vectorSize );
return this->computeSample( input );
}
StkFrames& BiQuad :: tick( StkFrames& frames, unsigned int channel )

105
src/Blit.cpp Normal file
View File

@@ -0,0 +1,105 @@
/***************************************************/
/*! \class Blit
\brief STK band-limited impulse train class.
This class generates a band-limited impulse train using a
closed-form algorithm reported by Stilson and Smith in "Alias-Free
Digital Synthesis of Classic Analog Waveforms", 1996. The user
can specify both the fundamental frequency of the impulse train
and the number of harmonics contained in the resulting signal.
The signal is normalized so that the peak value is +/-1.0.
If nHarmonics is 0, then the signal will contain all harmonics up
to half the sample rate. Note, however, that this setting may
produce aliasing in the signal when the frequency is changing (no
automatic modification of the number of harmonics is performed by
the setFrequency() function).
Original code by Robin Davies, 2005.
Revisions by Gary Scavone for STK, 2005.
*/
/***************************************************/
#include "Blit.h"
#include <cmath>
#include <limits>
Blit:: Blit( StkFloat frequency )
{
nHarmonics_ = 0;
this->setFrequency( frequency );
this->reset();
}
Blit :: ~Blit()
{
}
void Blit :: reset()
{
phase_ = 0.0;
lastOutput_ = 0;
}
void Blit :: setFrequency( StkFloat frequency )
{
#if defined(_STK_DEBUG_)
errorString_ << "Blit::setFrequency: frequency = " << frequency << '.';
handleError( StkError::DEBUG_WARNING );
#endif
p_ = Stk::sampleRate() / frequency;
rate_ = PI / p_;
this->updateHarmonics();
}
void Blit :: setHarmonics( unsigned int nHarmonics )
{
nHarmonics_ = nHarmonics;
this->updateHarmonics();
}
void Blit :: updateHarmonics( void )
{
if ( nHarmonics_ <= 0 ) {
unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ );
m_ = 2 * maxHarmonics + 1;
}
else
m_ = 2 * nHarmonics_ + 1;
#if defined(_STK_DEBUG_)
errorString_ << "Blit::updateHarmonics: nHarmonics_ = " << nHarmonics_ << ", m_ = " << m_ << '.';
handleError( StkError::DEBUG_WARNING );
#endif
}
StkFloat Blit :: computeSample( void )
{
// The code below implements the SincM algorithm of Stilson and
// Smith with an additional scale factor of P / M applied to
// normalize the output.
// A fully optimized version of this code would replace the two sin
// calls with a pair of fast sin oscillators, for which stable fast
// two-multiply algorithms are well known. In the spirit of STK,
// which favors clarity over performance, the optimization has not
// been made here.
// Avoid a divide by zero at the sinc peak, which has a limiting
// value of 1.0.
StkFloat denominator = sin( phase_ );
if ( denominator <= std::numeric_limits<StkFloat>::epsilon() ) {
lastOutput_ = 1.0;
} else {
lastOutput_ = sin( m_ * phase_ );
lastOutput_ /= m_ * denominator;
}
phase_ += rate_;
if ( phase_ >= PI ) phase_ -= PI;
return lastOutput_;
}

125
src/BlitSaw.cpp Normal file
View File

@@ -0,0 +1,125 @@
/***************************************************/
/*! \class BlitSaw
\brief STK band-limited sawtooth wave class.
This class generates a band-limited sawtooth waveform using a
closed-form algorithm reported by Stilson and Smith in "Alias-Free
Digital Synthesis of Classic Analog Waveforms", 1996. The user
can specify both the fundamental frequency of the sawtooth and the
number of harmonics contained in the resulting signal.
If nHarmonics is 0, then the signal will contain all harmonics up
to half the sample rate. Note, however, that this setting may
produce aliasing in the signal when the frequency is changing (no
automatic modification of the number of harmonics is performed by
the setFrequency() function).
Based on initial code of Robin Davies, 2005.
Modified algorithm code by Gary Scavone, 2005.
*/
/***************************************************/
#include "BlitSaw.h"
#include <cmath>
#include <limits>
BlitSaw:: BlitSaw( StkFloat frequency )
{
nHarmonics_ = 0;
this->reset();
this->setFrequency( frequency );
}
BlitSaw :: ~BlitSaw()
{
}
void BlitSaw :: reset()
{
phase_ = 0.0f;
state_ = 0.0;
lastOutput_ = 0;
}
void BlitSaw :: setFrequency( StkFloat frequency )
{
#if defined(_STK_DEBUG_)
errorString_ << "BlitSaw::setFrequency: frequency = " << frequency << '.';
handleError( StkError::DEBUG_WARNING );
#endif
p_ = Stk::sampleRate() / frequency;
C2_ = 1 / p_;
rate_ = PI * C2_;
this->updateHarmonics();
}
void BlitSaw :: setHarmonics( unsigned int nHarmonics )
{
nHarmonics_ = nHarmonics;
this->updateHarmonics();
// I found that the initial DC offset could be minimized with an
// initial state setting as given below. This initialization should
// only happen before starting the oscillator for the first time
// (but after setting the frequency and number of harmonics). I
// struggled a bit to decide where best to put this and finally
// settled on here. In general, the user shouldn't be messing with
// the number of harmonics once the oscillator is running because
// this is automatically taken care of in the setFrequency()
// function. (GPS - 1 October 2005)
state_ = -0.5 * a_;
}
void BlitSaw :: updateHarmonics( void )
{
if ( nHarmonics_ <= 0 ) {
unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ );
m_ = 2 * maxHarmonics + 1;
}
else
m_ = 2 * nHarmonics_ + 1;
a_ = m_ / p_;
#if defined(_STK_DEBUG_)
errorString_ << "BlitSaw::updateHarmonics: nHarmonics_ = " << nHarmonics_ << ", m_ = " << m_ << '.';
handleError( StkError::DEBUG_WARNING );
#endif
}
StkFloat BlitSaw :: computeSample( void )
{
// The code below implements the BLIT algorithm of Stilson and
// Smith, followed by a summation and filtering operation to produce
// a sawtooth waveform. After experimenting with various approaches
// to calculate the average value of the BLIT over one period, I
// found that an estimate of C2_ = 1.0 / period (in samples) worked
// most consistently. A "leaky integrator" is then applied to the
// difference of the BLIT output and C2_. (GPS - 1 October 2005)
// A fully optimized version of this code would replace the two sin
// calls with a pair of fast sin oscillators, for which stable fast
// two-multiply algorithms are well known. In the spirit of STK,
// which favors clarity over performance, the optimization has
// not been made here.
// Avoid a divide by zero, or use of a denormalized divisor
// at the sinc peak, which has a limiting value of m_ / p_.
StkFloat denominator = sin( phase_ );
if ( fabs(denominator) <= std::numeric_limits<StkFloat>::epsilon() )
lastOutput_ = a_;
else {
lastOutput_ = sin( m_ * phase_ );
lastOutput_ /= p_ * denominator;
}
lastOutput_ += state_ - C2_;
state_ = lastOutput_ * 0.995;
phase_ += rate_;
if ( phase_ >= PI ) phase_ -= PI;
return lastOutput_;
}

122
src/BlitSquare.cpp Normal file
View File

@@ -0,0 +1,122 @@
/***************************************************/
/*! \class BlitSquare
\brief STK band-limited square wave class.
This class generates a band-limited square wave signal. It is
derived in part from the approach reported by Stilson and Smith in
"Alias-Free Digital Synthesis of Classic Analog Waveforms", 1996.
The algorithm implemented in this class uses a SincM function with
an even M value to achieve a bipolar bandlimited impulse train.
This signal is then integrated to achieve a square waveform. The
integration process has an associated DC offset but that is
subtracted off the output signal.
The user can specify both the fundamental frequency of the
waveform and the number of harmonics contained in the resulting
signal.
If nHarmonics is 0, then the signal will contain all harmonics up
to half the sample rate. Note, however, that this setting may
produce aliasing in the signal when the frequency is changing (no
automatic modification of the number of harmonics is performed by
the setFrequency() function).
Based on initial code of Robin Davies, 2005.
Modified algorithm code by Gary Scavone, 2005.
*/
/***************************************************/
#include "BlitSquare.h"
#include <cmath>
#include <limits>
BlitSquare:: BlitSquare( StkFloat frequency )
{
nHarmonics_ = 0;
this->setFrequency( frequency );
this->reset();
}
BlitSquare :: ~BlitSquare()
{
}
void BlitSquare :: reset()
{
phase_ = 0.0;
lastOutput_ = 0;
}
void BlitSquare :: setFrequency( StkFloat frequency )
{
#if defined(_STK_DEBUG_)
errorString_ << "BlitSquare::setFrequency: frequency = " << frequency << '.';
handleError( StkError::DEBUG_WARNING );
#endif
// By using an even value of the parameter M, we get a bipolar blit
// waveform at half the blit frequency. Thus, we need to scale the
// frequency value here by 2.0. (GPS, 2005).
p_ = 2.0 * Stk::sampleRate() / frequency;
rate_ = PI / p_;
this->updateHarmonics();
}
void BlitSquare :: setHarmonics( unsigned int nHarmonics )
{
nHarmonics_ = nHarmonics;
this->updateHarmonics();
}
void BlitSquare :: updateHarmonics( void )
{
// Make sure we end up with an even value of the parameter M here.
if ( nHarmonics_ <= 0 ) {
unsigned int maxHarmonics = (unsigned int) floor( 0.5 * p_ );
m_ = 2 * maxHarmonics;
}
else
m_ = 2 * nHarmonics_;
// This offset value was derived empirically. (GPS, 2005)
offset_ = 1.0 - 0.5 * m_ / p_;
#if defined(_STK_DEBUG_)
errorString_ << "BlitSquare::updateHarmonics: nHarmonics_ = " << nHarmonics_ << ", m_ = " << m_ << '.';
handleError( StkError::DEBUG_WARNING );
#endif
}
StkFloat BlitSquare :: computeSample( void )
{
StkFloat temp = lastOutput_;
// A fully optimized version of this would replace the two sin calls
// with a pair of fast sin oscillators, for which stable fast
// two-multiply algorithms are well known. In the spirit of STK,
// which favors clarity over performance, the optimization has
// not been made here.
// Avoid a divide by zero, or use of a denomralized divisor
// at the sinc peak, which has a limiting value of 1.0.
StkFloat denominator = sin( phase_ );
if ( fabs( denominator ) < std::numeric_limits<StkFloat>::epsilon() ) {
// Inexact comparison safely distinguishes betwen *close to zero*, and *close to PI*.
if ( phase_ < 0.1f || phase_ > TWO_PI - 0.1f )
lastOutput_ = 1.0;
else
lastOutput_ = -1.0;
}
else {
lastOutput_ = sin( m_ * phase_ );
lastOutput_ /= p_ * denominator;
}
lastOutput_ += temp;
phase_ += rate_;
if ( phase_ >= TWO_PI ) phase_ -= TWO_PI;
return lastOutput_ - offset_;
}

View File

@@ -12,7 +12,7 @@
- Vibrato Gain = 1
- Volume = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -25,9 +25,7 @@ BlowBotl :: BlowBotl()
{
dcBlock_.setBlockZero();
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
vibrato_->setFrequency( 5.925 );
vibrato_.setFrequency( 5.925 );
vibratoGain_ = 0.0;
resonator_.setResonance(500.0, __BOTTLE_RADIUS_, true);
@@ -39,7 +37,6 @@ BlowBotl :: BlowBotl()
BlowBotl :: ~BlowBotl()
{
delete vibrato_;
}
void BlowBotl :: clear()
@@ -94,7 +91,7 @@ void BlowBotl :: noteOff(StkFloat amplitude)
#endif
}
StkFloat BlowBotl :: tick()
StkFloat BlowBotl :: computeSample()
{
StkFloat breathPressure;
StkFloat randPressure;
@@ -102,7 +99,7 @@ StkFloat BlowBotl :: tick()
// Calculate the breath pressure (envelope + vibrato)
breathPressure = maxPressure_ * adsr_.tick();
breathPressure += vibratoGain_ * vibrato_->tick();
breathPressure += vibratoGain_ * vibrato_.tick();
pressureDiff = breathPressure - resonator_.lastOut();
@@ -116,16 +113,6 @@ StkFloat BlowBotl :: tick()
return lastOutput_;
}
StkFloat *BlowBotl :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& BlowBotl :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void BlowBotl :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;
@@ -143,7 +130,7 @@ void BlowBotl :: controlChange(int number, StkFloat value)
if (number == __SK_NoiseLevel_) // 4
noiseGain_ = norm * 30.0;
else if (number == __SK_ModFrequency_) // 11
vibrato_->setFrequency( norm * 12.0 );
vibrato_.setFrequency( norm * 12.0 );
else if (number == __SK_ModWheel_) // 1
vibratoGain_ = norm * 0.4;
else if (number == __SK_AfterTouch_Cont_) // 128

View File

@@ -29,7 +29,7 @@
- Register State = 1
- Breath Pressure = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -77,9 +77,7 @@ BlowHole :: BlowHole(StkFloat lowestFrequency)
// Start with register vent closed
vent_.setGain(0.0);
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
vibrato_->setFrequency((StkFloat) 5.735);
vibrato_.setFrequency((StkFloat) 5.735);
outputGain_ = 1.0;
noiseGain_ = 0.2;
vibratoGain_ = 0.01;
@@ -87,7 +85,6 @@ BlowHole :: BlowHole(StkFloat lowestFrequency)
BlowHole :: ~BlowHole()
{
delete vibrato_;
}
void BlowHole :: clear()
@@ -187,7 +184,7 @@ void BlowHole :: noteOff(StkFloat amplitude)
#endif
}
StkFloat BlowHole :: tick()
StkFloat BlowHole :: computeSample()
{
StkFloat pressureDiff;
StkFloat breathPressure;
@@ -196,7 +193,7 @@ StkFloat BlowHole :: tick()
// Calculate the breath pressure (envelope + noise + vibrato)
breathPressure = envelope_.tick();
breathPressure += breathPressure * noiseGain_ * noise_.tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_->tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
// Calculate the differential pressure = reflected - mouthpiece pressures
pressureDiff = delays_[0].lastOut() - breathPressure;
@@ -222,16 +219,6 @@ StkFloat BlowHole :: tick()
return lastOutput_;
}
StkFloat *BlowHole :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& BlowHole :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void BlowHole :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

View File

@@ -5,7 +5,7 @@
This class implements a simple bowed string
non-linear function, as described by Smith (1986).
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -32,7 +32,7 @@ void BowTable :: setSlope(StkFloat slope)
slope_ = slope;
}
StkFloat BowTable :: tick(StkFloat input)
StkFloat BowTable :: computeSample(StkFloat input)
{
// The input represents differential string vs. bow velocity.
StkFloat sample;
@@ -49,12 +49,3 @@ StkFloat BowTable :: tick(StkFloat input)
return lastOutput_;
}
StkFloat *BowTable :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Function::tick( vector, vectorSize );
}
StkFrames& BowTable :: tick( StkFrames& frames, unsigned int channel )
{
return Function::tick( frames, channel );
}

View File

@@ -17,7 +17,7 @@
- Vibrato Gain = 1
- Volume = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -37,9 +37,7 @@ Bowed :: Bowed(StkFloat lowestFrequency)
bowTable_.setSlope(3.0 );
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
vibrato_->setFrequency( 6.12723 );
vibrato_.setFrequency( 6.12723 );
vibratoGain_ = 0.0;
stringFilter_.setPole( 0.6 - (0.1 * 22050.0 / Stk::sampleRate()) );
@@ -58,7 +56,6 @@ Bowed :: Bowed(StkFloat lowestFrequency)
Bowed :: ~Bowed()
{
delete vibrato_;
}
void Bowed :: clear()
@@ -122,7 +119,7 @@ void Bowed :: setVibrato(StkFloat gain)
vibratoGain_ = gain;
}
StkFloat Bowed :: tick()
StkFloat Bowed :: computeSample()
{
StkFloat bowVelocity;
StkFloat bridgeRefl;
@@ -143,7 +140,7 @@ StkFloat Bowed :: tick()
if ( vibratoGain_ > 0.0 ) {
neckDelay_.setDelay( (baseDelay_ * (1.0 - betaRatio_) ) +
(baseDelay_ * vibratoGain_ * vibrato_->tick()) );
(baseDelay_ * vibratoGain_ * vibrato_.tick()) );
}
lastOutput_ = bodyFilter_.tick( bridgeDelay_.lastOut() );
@@ -151,16 +148,6 @@ StkFloat Bowed :: tick()
return lastOutput_;
}
StkFloat *Bowed :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Bowed :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Bowed :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;
@@ -183,7 +170,7 @@ void Bowed :: controlChange(int number, StkFloat value)
neckDelay_.setDelay( baseDelay_ * (1.0 - betaRatio_) );
}
else if (number == __SK_ModFrequency_) // 11
vibrato_->setFrequency( norm * 12.0 );
vibrato_.setFrequency( norm * 12.0 );
else if (number == __SK_ModWheel_) // 1
vibratoGain_ = ( norm * 0.4 );
else if (number == __SK_AfterTouch_Cont_) // 128

View File

@@ -16,13 +16,13 @@
- Vibrato Gain = 1
- Volume = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "Brass.h"
#include "SKINI.msg"
#include <math.h>
#include <cmath>
Brass :: Brass(StkFloat lowestFrequency)
{
@@ -35,9 +35,7 @@ Brass :: Brass(StkFloat lowestFrequency)
adsr_.setAllTimes( 0.005, 0.001, 1.0, 0.010);
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
vibrato_->setFrequency( 6.137 );
vibrato_.setFrequency( 6.137 );
vibratoGain_ = 0.0;
this->clear();
@@ -50,7 +48,6 @@ Brass :: Brass(StkFloat lowestFrequency)
Brass :: ~Brass()
{
delete vibrato_;
}
void Brass :: clear()
@@ -123,10 +120,10 @@ void Brass :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Brass :: tick()
StkFloat Brass :: computeSample()
{
StkFloat breathPressure = maxPressure_ * adsr_.tick();
breathPressure += vibratoGain_ * vibrato_->tick();
breathPressure += vibratoGain_ * vibrato_.tick();
StkFloat mouthPressure = 0.3 * breathPressure;
StkFloat borePressure = 0.85 * delayLine_.lastOut();
@@ -142,16 +139,6 @@ StkFloat Brass :: tick()
return lastOutput_;
}
StkFloat *Brass :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Brass :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Brass :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;
@@ -173,7 +160,7 @@ void Brass :: controlChange(int number, StkFloat value)
else if (number == __SK_SlideLength_) // 4
delayLine_.setDelay( slideTarget_ * (0.5 + norm) );
else if (number == __SK_ModFrequency_) // 11
vibrato_->setFrequency( norm * 12.0 );
vibrato_.setFrequency( norm * 12.0 );
else if (number == __SK_ModWheel_ ) // 1
vibratoGain_ = norm * 0.4;
else if (number == __SK_AfterTouch_Cont_) // 128

View File

@@ -4,7 +4,7 @@
This class implements a chorus effect.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -19,11 +19,8 @@ Chorus :: Chorus(StkFloat baseDelay)
delayLine_[1].setDelay( baseDelay );
baseLength_ = baseDelay;
// Concatenate the STK rawwave path to the rawwave file
mods_[0] = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
mods_[1] = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
mods_[0]->setFrequency(0.2);
mods_[1]->setFrequency(0.222222);
mods_[0].setFrequency(0.2);
mods_[1].setFrequency(0.222222);
modDepth_ = 0.05;
effectMix_ = 0.5;
this->clear();
@@ -31,8 +28,6 @@ Chorus :: Chorus(StkFloat baseDelay)
Chorus :: ~Chorus()
{
delete mods_[0];
delete mods_[1];
}
void Chorus :: clear()
@@ -50,27 +45,17 @@ void Chorus :: setModDepth(StkFloat depth)
void Chorus :: setModFrequency(StkFloat frequency)
{
mods_[0]->setFrequency(frequency);
mods_[1]->setFrequency(frequency * 1.1111);
mods_[0].setFrequency(frequency);
mods_[1].setFrequency(frequency * 1.1111);
}
StkFloat Chorus :: tick(StkFloat input)
StkFloat Chorus :: computeSample(StkFloat input)
{
delayLine_[0].setDelay( baseLength_ * 0.707 * (1.0 + mods_[0]->tick()) );
delayLine_[1].setDelay( baseLength_ * 0.5 * (1.0 - mods_[1]->tick()) );
delayLine_[0].setDelay( baseLength_ * 0.707 * (1.0 + modDepth_ * mods_[0].tick()) );
delayLine_[1].setDelay( baseLength_ * 0.5 * (1.0 - modDepth_ * mods_[1].tick()) );
lastOutput_[0] = input * (1.0 - effectMix_);
lastOutput_[0] += effectMix_ * delayLine_[0].tick(input);
lastOutput_[1] = input * (1.0 - effectMix_);
lastOutput_[1] += effectMix_ * delayLine_[1].tick(input);
return Effect::lastOut();
}
StkFloat *Chorus :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Effect::tick( vector, vectorSize );
}
StkFrames& Chorus :: tick( StkFrames& frames, unsigned int channel )
{
return Effect::tick( frames, channel );
}

View File

@@ -18,7 +18,7 @@
- Vibrato Gain = 1
- Breath Pressure = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -33,9 +33,7 @@ Clarinet :: Clarinet(StkFloat lowestFrequency)
reedTable_.setOffset((StkFloat) 0.7);
reedTable_.setSlope((StkFloat) -0.3);
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
vibrato_->setFrequency((StkFloat) 5.735);
vibrato_.setFrequency((StkFloat) 5.735);
outputGain_ = (StkFloat) 1.0;
noiseGain_ = (StkFloat) 0.2;
vibratoGain_ = (StkFloat) 0.1;
@@ -43,7 +41,6 @@ Clarinet :: Clarinet(StkFloat lowestFrequency)
Clarinet :: ~Clarinet()
{
delete vibrato_;
}
void Clarinet :: clear()
@@ -102,7 +99,7 @@ void Clarinet :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Clarinet :: tick()
StkFloat Clarinet :: computeSample()
{
StkFloat pressureDiff;
StkFloat breathPressure;
@@ -110,7 +107,7 @@ StkFloat Clarinet :: tick()
// Calculate the breath pressure (envelope + noise + vibrato)
breathPressure = envelope_.tick();
breathPressure += breathPressure * noiseGain_ * noise_.tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_->tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
// Perform commuted loss filtering.
pressureDiff = -0.95 * filter_.tick(delayLine_.lastOut());
@@ -127,16 +124,6 @@ StkFloat Clarinet :: tick()
return lastOutput_;
}
StkFloat *Clarinet :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Clarinet :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Clarinet :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;
@@ -156,7 +143,7 @@ void Clarinet :: controlChange(int number, StkFloat value)
else if (number == __SK_NoiseLevel_) // 4
noiseGain_ = (norm * (StkFloat) 0.4);
else if (number == __SK_ModFrequency_) // 11
vibrato_->setFrequency((norm * (StkFloat) 12.0));
vibrato_.setFrequency((norm * (StkFloat) 12.0));
else if (number == __SK_ModWheel_) // 1
vibratoGain_ = (norm * (StkFloat) 0.5);
else if (number == __SK_AfterTouch_Cont_) // 128

View File

@@ -14,7 +14,7 @@
used in fixed delay-length applications, such
as for reverberation.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -167,9 +167,9 @@ StkFloat Delay :: nextOut(void)
return inputs_[outPoint_];
}
StkFloat Delay :: tick(StkFloat sample)
StkFloat Delay :: computeSample( StkFloat input )
{
inputs_[inPoint_++] = sample;
inputs_[inPoint_++] = input;
// Check for end condition
if (inPoint_ == inputs_.size())
@@ -184,9 +184,9 @@ StkFloat Delay :: tick(StkFloat sample)
return outputs_[0];
}
StkFloat *Delay :: tick(StkFloat *vector, unsigned int vectorSize)
StkFloat Delay :: tick( StkFloat input )
{
return Filter::tick( vector, vectorSize );
return computeSample( input );
}
StkFrames& Delay :: tick( StkFrames& frames, unsigned int channel )

View File

@@ -2,23 +2,20 @@
/*! \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.
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.
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 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -109,6 +106,11 @@ void DelayA :: setDelay(StkFloat delay)
((StkFloat) 1.0 + alpha_); // coefficient for all pass
}
StkFloat DelayA :: getDelay(void) const
{
return delay_;
}
StkFloat DelayA :: nextOut(void)
{
if ( doNextOut_ ) {
@@ -121,9 +123,9 @@ StkFloat DelayA :: nextOut(void)
return nextOutput_;
}
StkFloat DelayA :: tick(StkFloat sample)
StkFloat DelayA :: computeSample( StkFloat input )
{
inputs_[inPoint_++] = sample;
inputs_[inPoint_++] = input;
// Increment input pointer modulo length.
if (inPoint_ == inputs_.size())
@@ -139,13 +141,3 @@ StkFloat DelayA :: tick(StkFloat sample)
return outputs_[0];
}
StkFloat *DelayA :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Filter::tick( vector, vectorSize );
}
StkFrames& DelayA :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );
}

View File

@@ -18,7 +18,7 @@
order Lagrange interpolators can typically
improve (minimize) this attenuation characteristic.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -110,9 +110,9 @@ StkFloat DelayL :: nextOut(void)
return nextOutput_;
}
StkFloat DelayL :: tick(StkFloat sample)
StkFloat DelayL :: computeSample( StkFloat input )
{
inputs_[inPoint_++] = sample;
inputs_[inPoint_++] = input;
// Increment input pointer modulo length.
if (inPoint_ == inputs_.size())
@@ -128,12 +128,3 @@ StkFloat DelayL :: tick(StkFloat sample)
return outputs_[0];
}
StkFloat *DelayL :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Filter::tick( vector, vectorSize );
}
StkFrames& DelayL :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );
}

View File

@@ -3,7 +3,7 @@
\brief STK drum sample player class.
This class implements a drum sampling
synthesizer using WvIn objects and one-pole
synthesizer using FileWvIn objects and one-pole
filters. The drum rawwave files are sampled
at 22050 Hz, but will be appropriately
interpolated for other sample rates. You can
@@ -11,12 +11,12 @@
of simultaneous voices) via a #define in the
Drummer.h.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "Drummer.h"
#include <math.h>
#include <cmath>
// Not really General MIDI yet.
unsigned char genMIDIMap[128] =
@@ -55,20 +55,14 @@ char waveNames[DRUM_NUMWAVES][16] =
Drummer :: Drummer() : Instrmnt()
{
for ( int i=0; i<DRUM_POLYPHONY; i++ ) {
filters_[i] = new OnePole;
sounding_[i] = -1;
}
// This counts the number of sounding voices.
nSounding_ = 0;
soundOrder_ = std::vector<int> (DRUM_POLYPHONY, -1);
soundNumber_ = std::vector<int> (DRUM_POLYPHONY, -1);
}
Drummer :: ~Drummer()
{
int i;
for ( i=0; i<nSounding_; i++ ) delete waves_[i];
for ( i=0; i<DRUM_POLYPHONY; i++ ) delete filters_[i];
}
void Drummer :: noteOn(StkFloat instrument, StkFloat amplitude)
@@ -91,97 +85,86 @@ void Drummer :: noteOn(StkFloat instrument, StkFloat amplitude)
}
// Yes, this is tres kludgey.
int noteNum = (int) ( ( 12*log(instrument/220.0)/log(2.0) ) + 57.01 );
int noteNumber = (int) ( ( 12 * log( instrument / 220.0 ) / log( 2.0 ) ) + 57.01 );
// Check first to see if there's already one like this sounding.
int i, waveIndex = -1;
for ( i=0; i<DRUM_POLYPHONY; i++ ) {
if (sounding_[i] == noteNum) waveIndex = i;
}
if ( waveIndex >= 0 ) {
// Reset this sound.
waves_[waveIndex]->reset();
filters_[waveIndex]->setPole( 0.999 - (gain * 0.6) );
filters_[waveIndex]->setGain( gain );
}
else {
if (nSounding_ == DRUM_POLYPHONY) {
// If we're already at maximum polyphony, then preempt the oldest voice.
delete waves_[0];
filters_[0]->clear();
OnePole *tempFilt = filters_[0];
// Re-order the list.
for ( i=0; i<DRUM_POLYPHONY-1; i++ ) {
waves_[i] = waves_[i+1];
filters_[i] = filters_[i+1];
// If we already have a wave of this note number loaded, just reset
// it. Otherwise, look first for an unused wave or preempt the
// oldest if already at maximum polyphony.
int iWave;
for ( iWave=0; iWave<DRUM_POLYPHONY; iWave++ ) {
if ( soundNumber_[iWave] == noteNumber ) {
if ( waves_[iWave].isFinished() ) {
soundOrder_[iWave] = nSounding_;
nSounding_++;
}
waves_[DRUM_POLYPHONY-1] = 0;
filters_[DRUM_POLYPHONY-1] = tempFilt;
waves_[iWave].reset();
filters_[iWave].setPole( 0.999 - (gain * 0.6) );
filters_[iWave].setGain( gain );
break;
}
else
nSounding_ += 1;
}
if ( iWave == DRUM_POLYPHONY ) { // This note number is not currently loaded.
if ( nSounding_ < DRUM_POLYPHONY ) {
for ( iWave=0; iWave<DRUM_POLYPHONY; iWave++ )
if ( soundOrder_[iWave] < 0 ) break;
nSounding_ += 1;
}
else {
for ( iWave=0; iWave<DRUM_POLYPHONY; iWave++ )
if ( soundOrder_[iWave] == 0 ) break;
// Re-order the list.
for ( int j=0; j<DRUM_POLYPHONY; j++ ) {
if ( soundOrder_[j] > soundOrder_[iWave] )
soundOrder_[j] -= 1;
}
}
soundOrder_[iWave] = nSounding_ - 1;
soundNumber_[iWave] = noteNumber;
sounding_[nSounding_-1] = noteNum;
// Concatenate the STK rawwave path to the rawwave file
waves_[nSounding_-1] = new WvIn( (Stk::rawwavePath() + waveNames[genMIDIMap[noteNum]]).c_str(), true );
if (Stk::sampleRate() != 22050.0)
waves_[nSounding_-1]->setRate( 22050.0 / Stk::sampleRate() );
filters_[nSounding_-1]->setPole( 0.999 - (gain * 0.6) );
filters_[nSounding_-1]->setGain( gain );
waves_[iWave].openFile( (Stk::rawwavePath() + waveNames[ genMIDIMap[ noteNumber ] ]).c_str(), true );
if ( Stk::sampleRate() != 22050.0 )
waves_[iWave].setRate( 22050.0 / Stk::sampleRate() );
filters_[iWave].setPole( 0.999 - (gain * 0.6) );
filters_[iWave].setGain( gain );
}
#if defined(_STK_DEBUG_)
errorString_ << "Drummer::noteOn: number sounding = " << nSounding_ << '\n';
for (i=0; i<nSounding_; i++) errorString_ << sounding_[i] << " ";
for ( int i=0; i<nSounding_; i++ ) errorString_ << soundNumber_[i] << " ";
errorString_ << '\n';
handleError( StkError::DEBUG_WARNING );
#endif
}
void Drummer :: noteOff(StkFloat amplitude)
void Drummer :: noteOff( StkFloat amplitude )
{
// Set all sounding wave filter gains low.
int i = 0;
while ( i < nSounding_ ) filters_[i++]->setGain( amplitude * 0.01 );
while ( i < nSounding_ ) filters_[i++].setGain( amplitude * 0.01 );
}
StkFloat Drummer :: tick()
StkFloat Drummer :: computeSample()
{
OnePole *tempFilt;
int j, i = 0;
lastOutput_ = 0.0;
while (i < nSounding_) {
if ( waves_[i]->isFinished() ) {
delete waves_[i];
tempFilt = filters_[i];
// Re-order the list.
for ( j=i; j<nSounding_-1; j++ ) {
sounding_[j] = sounding_[j+1];
waves_[j] = waves_[j+1];
filters_[j] = filters_[j+1];
if ( nSounding_ == 0 ) return lastOutput_;
for ( int i=0; i<DRUM_POLYPHONY; i++ ) {
if ( soundOrder_[i] >= 0 ) {
if ( waves_[i].isFinished() ) {
// Re-order the list.
for ( int j=0; j<DRUM_POLYPHONY; j++ ) {
if ( soundOrder_[j] > soundOrder_[i] )
soundOrder_[j] -= 1;
}
soundOrder_[i] = -1;
nSounding_--;
}
filters_[j] = tempFilt;
filters_[j]->clear();
sounding_[j] = -1;
nSounding_ -= 1;
i -= 1;
else
lastOutput_ += filters_[i].tick( waves_[i].tick() );
}
else
lastOutput_ += filters_[i]->tick( waves_[i]->tick() );
i++;
}
return lastOutput_;
}
StkFloat *Drummer :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Drummer :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

View File

@@ -4,7 +4,7 @@
This class implements an echo effect.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -54,20 +54,10 @@ void Echo :: setDelay( unsigned long delay )
delayLine_.setDelay( size );
}
StkFloat Echo :: tick(StkFloat input)
StkFloat Echo :: computeSample(StkFloat input)
{
lastOutput_[0] = effectMix_ * delayLine_.tick(input);
lastOutput_[0] += input * (1.0 - effectMix_);
lastOutput_[1] = lastOutput_[0];
return lastOutput_[0];
}
StkFloat *Echo :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Effect::tick( vector, vectorSize );
}
StkFrames& Echo :: tick( StkFrames& frames, unsigned int channel )
{
return Effect::tick( frames, channel );
}

View File

@@ -5,7 +5,7 @@
This class provides common functionality for
STK effects subclasses.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -51,37 +51,34 @@ StkFloat Effect :: lastOutRight() const
return lastOutput_[1];
}
StkFloat *Effect :: tick(StkFloat *vector, unsigned int vectorSize)
StkFloat Effect :: tick( StkFloat input )
{
for (unsigned int i=0; i<vectorSize; i++)
vector[i] = tick(vector[i]);
return vector;
return computeSample( input );
}
StkFrames& Effect :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "Effect::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
if ( channel >= frames.channels() ) {
errorString_ << "Effect::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = tick( frames[i] );
frames[i] = computeSample( frames[i] );
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick( frames[index] );
frames[index] = computeSample( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[iStart + i] = tick( frames[iStart + i] );
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = computeSample( frames[iStart] );
}
return frames;

View File

@@ -9,7 +9,7 @@
\e keyOff messages, ramping to 1.0 on
keyOn and to 0.0 on keyOff.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -23,8 +23,28 @@ Envelope :: Envelope(void) : Generator()
state_ = 0;
}
Envelope :: Envelope ( const Envelope& e )
{
target_ = 0.0;
value_ = 0.0;
rate_ = 0.001;
state_ = 0;
}
Envelope :: ~Envelope(void)
{
{
}
Envelope& Envelope :: operator= ( const Envelope& e )
{
if ( this != &e ) {
target_ = e.target_;
value_ = e.value_;
rate_ = e.rate_;
state_ = e.state_;
}
return *this;
}
void Envelope :: keyOn(void)
@@ -79,7 +99,7 @@ int Envelope :: getState(void) const
return state_;
}
StkFloat Envelope :: tick(void)
StkFloat Envelope :: computeSample(void )
{
if (state_) {
if (target_ > value_) {
@@ -101,13 +121,3 @@ StkFloat Envelope :: tick(void)
lastOutput_ = value_;
return value_;
}
StkFloat *Envelope :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Generator::tick( vector, vectorSize );
}
StkFrames& Envelope :: tick( StkFrames& frames, unsigned int channel )
{
return Generator::tick( frames, channel );
}

View File

@@ -19,7 +19,7 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -37,9 +37,7 @@ FM :: FM( unsigned int operators )
twozero_.setB2( -1.0 );
twozero_.setGain( 0.0 );
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
vibrato_->setFrequency( 6.0 );
vibrato_.setFrequency( 6.0 );
unsigned int j;
adsr_.resize( nOperators_ );
@@ -77,8 +75,6 @@ FM :: FM( unsigned int operators )
FM :: ~FM()
{
delete vibrato_;
for (unsigned int i=0; i<nOperators_; i++ ) {
delete waves_[i];
delete adsr_[i];
@@ -137,7 +133,7 @@ void FM :: setGain(unsigned int waveIndex, StkFloat gain)
void FM :: setModulationSpeed(StkFloat mSpeed)
{
vibrato_->setFrequency( mSpeed );
vibrato_.setFrequency( mSpeed );
}
void FM :: setModulationDepth(StkFloat mDepth)

View File

@@ -26,7 +26,7 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -123,12 +123,12 @@ void FMVoices :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat FMVoices :: tick()
StkFloat FMVoices :: computeSample()
{
register StkFloat temp, temp2;
temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
temp2 = vibrato_->tick() * modDepth_ * 0.1;
temp2 = vibrato_.tick() * modDepth_ * 0.1;
waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[0]);
waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[1]);
@@ -148,16 +148,6 @@ StkFloat FMVoices :: tick()
return lastOutput_;
}
StkFloat *FMVoices :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& FMVoices :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void FMVoices :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

721
src/FileRead.cpp Normal file
View File

@@ -0,0 +1,721 @@
/***************************************************/
/*! \class FileRead
\brief STK audio file input class.
This class provides input support for various
audio file formats. Multi-channel (>2)
soundfiles are supported. The file data is
returned via an external StkFrames object
passed to the read() function. This class
does not store its own copy of the file data,
rather the data is read directly from disk.
FileRead currently supports uncompressed WAV,
AIFF/AIFC, SND (AU), MAT-file (Matlab), and
STK RAW file formats. Signed integer (8-,
16-, and 32-bit) and floating-point (32- and
64-bit) data types are supported. Compressed
data types are not supported.
STK RAW files have no header and are assumed
to contain a monophonic stream of 16-bit
signed integers in big-endian byte order at a
sample rate of 22050 Hz. MAT-file data should
be saved in an array with each data channel
filling a matrix row. The sample rate for
MAT-files is assumed to be 44100 Hz.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "FileRead.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <cmath>
FileRead :: FileRead()
: fd_(0)
{
}
FileRead :: FileRead( std::string fileName, bool typeRaw )
: fd_(0)
{
open( fileName, typeRaw );
}
FileRead :: ~FileRead()
{
if ( fd_ )
fclose( fd_ );
}
void FileRead :: close( void )
{
if ( fd_ ) fclose( fd_ );
fd_ = 0;
wavFile_ = false;
}
bool FileRead :: isOpen( void )
{
if ( fd_ ) return true;
else return false;
}
void FileRead :: open( std::string fileName, bool typeRaw )
{
// If another file is open, close it.
close();
// Try to open the file.
fd_ = fopen( fileName.c_str(), "rb" );
if ( !fd_ ) {
errorString_ << "FileRead::open: could not open or find file (" << fileName << ")!";
handleError( StkError::FILE_NOT_FOUND );
}
// Attempt to determine file type from header (unless RAW).
bool result = false;
if ( typeRaw )
result = getRawInfo( fileName.c_str() );
else {
char header[12];
if ( fread( &header, 4, 3, fd_ ) != 3 ) goto error;
if ( !strncmp( header, "RIFF", 4 ) &&
!strncmp( &header[8], "WAVE", 4 ) )
result = getWavInfo( fileName.c_str() );
else if ( !strncmp( header, ".snd", 4 ) )
result = getSndInfo( fileName.c_str() );
else if ( !strncmp( header, "FORM", 4 ) &&
( !strncmp( &header[8], "AIFF", 4 ) || !strncmp(&header[8], "AIFC", 4) ) )
result = getAifInfo( fileName.c_str() );
else {
if ( fseek( fd_, 126, SEEK_SET ) == -1 ) goto error;
if ( fread( &header, 2, 1, fd_ ) != 1 ) goto error;
if ( !strncmp( header, "MI", 2 ) ||
!strncmp( header, "IM", 2 ) )
result = getMatInfo( fileName.c_str() );
else {
errorString_ << "FileRead::open: file (" << fileName << ") format unknown.";
handleError( StkError::FILE_UNKNOWN_FORMAT );
}
}
}
// If here, we had a file type candidate but something else went wrong.
if ( result == false )
handleError( StkError::FILE_ERROR );
// Check for empty files.
if ( fileSize_ == 0 ) {
errorString_ << "FileRead::open: file (" << fileName << ") data size is zero!";
handleError( StkError::FILE_ERROR );
}
return;
error:
errorString_ << "FileRead::open: error reading file (" << fileName << ")!";
handleError( StkError::FILE_ERROR );
}
bool FileRead :: getRawInfo( const char *fileName )
{
// Use the system call "stat" to determine the file length.
struct stat filestat;
if ( stat(fileName, &filestat) == -1 ) {
errorString_ << "FileRead: Could not stat RAW file (" << fileName << ").";
return false;
}
// STK rawwave files have no header and are assumed to contain a
// monophonic stream of 16-bit signed integers in big-endian byte
// order at a sample rate of 22050 Hz.
channels_ = 1;
fileSize_ = (long) filestat.st_size / 2; // length in 2-byte samples
dataOffset_ = 0;
fileRate_ = 22050.0;
dataType_ = STK_SINT16;
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
}
bool FileRead :: getWavInfo( const char *fileName )
{
// Find "format" chunk ... it must come before the "data" chunk.
char id[4];
SINT32 chunkSize;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
while ( strncmp(id, "fmt ", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Check that the data is not compressed.
unsigned short format_tag;
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; // Read fmt chunk size.
if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&format_tag);
swap32((unsigned char *)&chunkSize);
#endif
if ( format_tag == 0xFFFE ) { // WAVE_FORMAT_EXTENSIBLE
dataOffset_ = ftell(fd_);
if ( fseek(fd_, 14, SEEK_CUR) == -1 ) goto error;
unsigned short extSize;
if ( fread(&extSize, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&extSize);
#endif
if ( extSize == 0 ) goto error;
if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error;
if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&format_tag);
#endif
if ( fseek(fd_, dataOffset_, SEEK_SET) == -1 ) goto error;
}
if (format_tag != 1 && format_tag != 3 ) { // PCM = 1, FLOAT = 3
errorString_ << "FileRead: "<< fileName << " contains an unsupported data format type (" << format_tag << ").";
return false;
}
// Get number of channels from the header.
SINT16 temp;
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
channels_ = (unsigned int ) temp;
// Get file sample rate from the header.
SINT32 srate;
if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&srate);
#endif
fileRate_ = (StkFloat) srate;
// Determine the data type.
dataType_ = 0;
if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error; // Locate bits_per_sample info.
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
if ( format_tag == 1 ) {
if (temp == 8)
dataType_ = STK_SINT8;
else if (temp == 16)
dataType_ = STK_SINT16;
else if (temp == 32)
dataType_ = STK_SINT32;
}
else if ( format_tag == 3 ) {
if (temp == 32)
dataType_ = STK_FLOAT32;
else if (temp == 64)
dataType_ = STK_FLOAT64;
}
if ( dataType_ == 0 ) {
errorString_ << "FileRead: " << temp << " bits per sample with data format " << format_tag << " are not supported (" << fileName << ").";
return false;
}
// Jump over any remaining part of the "fmt" chunk.
if ( fseek(fd_, chunkSize-16, SEEK_CUR) == -1 ) goto error;
// Find "data" chunk ... it must come after the "fmt" chunk.
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
while ( strncmp(id, "data", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
chunkSize += chunkSize % 2; // chunk sizes must be even
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Get length of data from the header.
SINT32 bytes;
if ( fread(&bytes, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fileSize_ = 8 * bytes / temp / channels_; // sample frames
dataOffset_ = ftell(fd_);
byteswap_ = false;
#ifndef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
wavFile_ = true;
return true;
error:
errorString_ << "FileRead: error reading WAV file (" << fileName << ").";
return false;
}
bool FileRead :: getSndInfo( const char *fileName )
{
// Determine the data type.
UINT32 format;
if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error; // Locate format
if ( fread(&format, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&format);
#endif
if (format == 2) dataType_ = STK_SINT8;
else if (format == 3) dataType_ = STK_SINT16;
else if (format == 4) dataType_ = STK_SINT24;
else if (format == 5) dataType_ = STK_SINT32;
else if (format == 6) dataType_ = STK_FLOAT32;
else if (format == 7) dataType_ = STK_FLOAT64;
else {
errorString_ << "FileRead: data format in file " << fileName << " is not supported.";
return false;
}
// Get file sample rate from the header.
UINT32 srate;
if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&srate);
#endif
fileRate_ = (StkFloat) srate;
// Get number of channels from the header.
UINT32 chans;
if ( fread(&chans, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&chans);
#endif
channels_ = chans;
if ( fseek(fd_, 4, SEEK_SET) == -1 ) goto error;
if ( fread(&dataOffset_, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&dataOffset_);
#endif
// Get length of data from the header.
if ( fread(&fileSize_, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&fileSize_);
#endif
// Convert to sample frames.
if ( dataType_ == STK_SINT8 )
fileSize_ /= channels_;
if ( dataType_ == STK_SINT16 )
fileSize_ /= 2 * channels_;
else if ( dataType_ == STK_SINT24 )
fileSize_ /= 3 * channels_;
else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
fileSize_ /= 4 * channels_;
else if ( dataType_ == STK_FLOAT64 )
fileSize_ /= 8 * channels_;
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
error:
errorString_ << "FileRead: Error reading SND file (" << fileName << ").";
return false;
}
bool FileRead :: getAifInfo( const char *fileName )
{
bool aifc = false;
char id[4];
// Determine whether this is AIFF or AIFC.
if ( fseek(fd_, 8, SEEK_SET) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
if ( !strncmp(id, "AIFC", 4) ) aifc = true;
// Find "common" chunk
SINT32 chunkSize;
if ( fread(&id, 4, 1, fd_) != 1) goto error;
while ( strncmp(id, "COMM", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
chunkSize += chunkSize % 2; // chunk sizes must be even
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Get number of channels from the header.
SINT16 temp;
if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error; // Jump over chunk size
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
channels_ = temp;
// Get length of data from the header.
SINT32 frames;
if ( fread(&frames, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&frames);
#endif
fileSize_ = frames; // sample frames
// Read the number of bits per sample.
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
// Get file sample rate from the header. For AIFF files, this value
// is stored in a 10-byte, IEEE Standard 754 floating point number,
// so we need to convert it first.
unsigned char srate[10];
unsigned char exp;
unsigned long mantissa;
unsigned long last;
if ( fread(&srate, 10, 1, fd_) != 1 ) goto error;
mantissa = (unsigned long) *(unsigned long *)(srate+2);
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&mantissa);
#endif
exp = 30 - *(srate+1);
last = 0;
while (exp--) {
last = mantissa;
mantissa >>= 1;
}
if (last & 0x00000001) mantissa++;
fileRate_ = (StkFloat) mantissa;
// Determine the data format.
dataType_ = 0;
if ( aifc == false ) {
if ( temp <= 8 ) dataType_ = STK_SINT8;
else if ( temp <= 16 ) dataType_ = STK_SINT16;
else if ( temp <= 24 ) dataType_ = STK_SINT24;
else if ( temp <= 32 ) dataType_ = STK_SINT32;
}
else {
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
if ( !strncmp(id, "NONE", 4) ) {
if ( temp <= 8 ) dataType_ = STK_SINT8;
else if ( temp <= 16 ) dataType_ = STK_SINT16;
else if ( temp <= 24 ) dataType_ = STK_SINT24;
else if ( temp <= 32 ) dataType_ = STK_SINT32;
}
else if ( (!strncmp(id, "fl32", 4) || !strncmp(id, "FL32", 4)) && temp == 32 ) dataType_ = STK_FLOAT32;
else if ( (!strncmp(id, "fl64", 4) || !strncmp(id, "FL64", 4)) && temp == 64 ) dataType_ = STK_FLOAT64;
}
if ( dataType_ == 0 ) {
errorString_ << "FileRead: AIFF/AIFC file (" << fileName << ") has unsupported data type (" << id << ").";
return false;
}
// Start at top to find data (SSND) chunk ... chunk order is undefined.
if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error;
// Find data (SSND) chunk
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
while ( strncmp(id, "SSND", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
chunkSize += chunkSize % 2; // chunk sizes must be even
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Skip over chunk size, offset, and blocksize fields
if ( fseek(fd_, 12, SEEK_CUR) == -1 ) goto error;
dataOffset_ = ftell(fd_);
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
error:
errorString_ << "FileRead: Error reading AIFF file (" << fileName << ").";
return false;
}
bool FileRead :: getMatInfo( const char *fileName )
{
// MAT-file formatting information is available at:
// http://www.mathworks.com/access/helpdesk/help/pdf_doc/matlab/matfile_format.pdf
// Verify this is a version 5 MAT-file format.
char head[4];
if ( fseek(fd_, 0, SEEK_SET) == -1 ) goto error;
if ( fread(&head, 4, 1, fd_) != 1 ) goto error;
// If any of the first 4 characters of the header = 0, then this is
// a Version 4 MAT-file.
if ( strstr(head, "0") ) {
errorString_ << "FileRead: " << fileName << " appears to be a Version 4 MAT-file, which is not currently supported.";
return false;
}
// Determine the endian-ness of the file.
char mi[2];
byteswap_ = false;
// Locate "M" and "I" characters in header.
if ( fseek(fd_, 126, SEEK_SET) == -1 ) goto error;
if ( fread(&mi, 2, 1, fd_) != 1) goto error;
#ifdef __LITTLE_ENDIAN__
if ( !strncmp(mi, "MI", 2) )
byteswap_ = true;
else if ( strncmp(mi, "IM", 2) ) goto error;
#else
if ( !strncmp(mi, "IM", 2))
byteswap_ = true;
else if ( strncmp(mi, "MI", 2) ) goto error;
#endif
// Check the data element type
SINT32 datatype;
if ( fread(&datatype, 4, 1, fd_) != 1 ) goto error;
if ( byteswap_ ) swap32((unsigned char *)&datatype);
if (datatype != 14) {
errorString_ << "FileRead: The file does not contain a single Matlab array (or matrix) data element.";
return false;
}
// Determine the array data type.
SINT32 tmp;
SINT32 size;
if ( fseek(fd_, 168, SEEK_SET) == -1 ) goto error;
if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&tmp);
if (tmp == 1) { // array name > 4 characters
if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error; // get array name length
if (byteswap_) swap32((unsigned char *)&tmp);
size = (SINT32) ceil((float)tmp / 8);
if ( fseek(fd_, size*8, SEEK_CUR) == -1 ) goto error; // jump over array name
}
else { // array name <= 4 characters, compressed data element
if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error;
}
if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&tmp);
if ( tmp == 1 ) dataType_ = STK_SINT8;
else if ( tmp == 3 ) dataType_ = STK_SINT16;
else if ( tmp == 5 ) dataType_ = STK_SINT32;
else if ( tmp == 7 ) dataType_ = STK_FLOAT32;
else if ( tmp == 9 ) dataType_ = STK_FLOAT64;
else {
errorString_ << "FileRead: The MAT-file array data format (" << tmp << ") is not supported.";
return false;
}
// Get number of rows from the header.
SINT32 rows;
if ( fseek(fd_, 160, SEEK_SET) == -1 ) goto error;
if ( fread(&rows, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&rows);
// Get number of columns from the header.
SINT32 columns;
if ( fread(&columns, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&columns);
// Assume channels = smaller of rows or columns.
if (rows < columns) {
channels_ = rows;
fileSize_ = columns;
}
else {
errorString_ << "FileRead: Transpose the MAT-file array so that audio channels fill matrix rows (not columns).";
return false;
}
// Move read pointer to the data in the file.
SINT32 headsize;
if ( fseek(fd_, 132, SEEK_SET) == -1 ) goto error;
if ( fread(&headsize, 4, 1, fd_) != 1 ) goto error; // file size from 132nd byte
if (byteswap_) swap32((unsigned char *)&headsize);
headsize -= fileSize_ * 8 * channels_;
if ( fseek(fd_, headsize, SEEK_CUR) == -1 ) goto error;
dataOffset_ = ftell(fd_);
// Assume MAT-files have 44100 Hz sample rate.
fileRate_ = 44100.0;
return true;
error:
errorString_ << "FileRead: Error reading MAT-file (" << fileName << ").";
return false;
}
void FileRead :: read( StkFrames& buffer, unsigned long startFrame, bool doNormalize )
{
// Make sure we have an open file.
if ( fd_ == 0 ) {
errorString_ << "FileRead::read: a file is not open!";
Stk::handleError( StkError::WARNING );
return;
}
// Check the buffer size.
unsigned int nFrames = buffer.frames();
if ( nFrames == 0 ) {
errorString_ << "FileRead::read: StkFrames buffer size is zero ... no data read!";
Stk::handleError( StkError::WARNING );
return;
}
if ( buffer.channels() != channels_ ) {
errorString_ << "FileRead::read: StkFrames argument has incompatible number of channels!";
Stk::handleError( StkError::FUNCTION_ARGUMENT );
}
// Check for file end.
if ( startFrame + nFrames >= fileSize_ )
nFrames = fileSize_ - startFrame;
long i, nSamples = (long) ( nFrames * channels_ );
unsigned long offset = startFrame * channels_;
// Read samples into StkFrames data buffer.
if ( dataType_ == STK_SINT16 ) {
SINT16 *buf = (SINT16 *) &buffer[0];
if ( fseek( fd_, dataOffset_+(offset*2), SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples * 2, 1, fd_ ) != 1 ) goto error;
if ( byteswap_ ) {
SINT16 *ptr = buf;
for ( i=nSamples-1; i>=0; i-- )
swap16( (unsigned char *) ptr++ );
}
if ( doNormalize ) {
StkFloat gain = 1.0 / 32768.0;
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i] * gain;
}
else {
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
}
else if ( dataType_ == STK_SINT32 ) {
SINT32 *buf = (SINT32 *) &buffer[0];
if ( fseek( fd_, dataOffset_+(offset*4 ), SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error;
if ( byteswap_ ) {
SINT32 *ptr = buf;
for ( i=nSamples-1; i>=0; i-- )
swap32( (unsigned char *) ptr++ );
}
if ( doNormalize ) {
StkFloat gain = 1.0 / 2147483648.0;
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i] * gain;
}
else {
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
}
else if ( dataType_ == STK_FLOAT32 ) {
FLOAT32 *buf = (FLOAT32 *) &buffer[0];
if ( fseek( fd_, dataOffset_+(offset*4), SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error;
if ( byteswap_ ) {
FLOAT32 *ptr = buf;
for ( i=nSamples-1; i>=0; i-- )
swap32( (unsigned char *) ptr++ );
}
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
else if ( dataType_ == STK_FLOAT64 ) {
FLOAT64 *buf = (FLOAT64 *) &buffer[0];
if ( fseek( fd_, dataOffset_+(offset*8), SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples * 8, 1, fd_ ) != 1 ) goto error;
if ( byteswap_ ) {
FLOAT64 *ptr = buf;
for ( i=nSamples-1; i>=0; i-- )
swap64( (unsigned char *) ptr++ );
}
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
else if ( dataType_ == STK_SINT8 && wavFile_ ) { // 8-bit WAV data is unsigned!
unsigned char *buf = (unsigned char *) &buffer[0];
if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples, 1, fd_) != 1 ) goto error;
if ( doNormalize ) {
StkFloat gain = 1.0 / 128.0;
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = ( buf[i] - 128 ) * gain;
}
else {
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i] - 128.0;
}
}
else if ( dataType_ == STK_SINT8 ) { // signed 8-bit data
char *buf = (char *) &buffer[0];
if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error;
if ( fread( buf, nSamples, 1, fd_ ) != 1 ) goto error;
if ( doNormalize ) {
StkFloat gain = 1.0 / 128.0;
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i] * gain;
}
else {
for ( i=nSamples-1; i>=0; i-- )
buffer[i] = buf[i];
}
}
else if ( dataType_ == STK_SINT24 ) {
// 24-bit values are harder to import efficiently since there is
// no native 24-bit type. The following routine works but is much
// less efficient that that used for the other data types.
SINT32 buf;
StkFloat gain = 1.0 / 8388608.0;
if ( fseek(fd_, dataOffset_+(offset*3), SEEK_SET ) == -1 ) goto error;
for ( i=0; i<nSamples; i++ ) {
if ( fread( &buf, 3, 1, fd_ ) != 1 ) goto error;
buf >>= 8;
if ( byteswap_ )
swap32( (unsigned char *) &buf );
if ( doNormalize )
buffer[i] = buf * gain;
else
buffer[i] = buf;
}
}
buffer.setDataRate( fileRate_ );
return;
error:
errorString_ << "FileRead: Error reading file data.";
handleError( StkError::FILE_ERROR);
}

701
src/FileWrite.cpp Normal file
View File

@@ -0,0 +1,701 @@
/***************************************************/
/*! \class FileWrite
\brief STK audio file output class.
This class provides output support for various
audio file formats.
FileWrite writes samples to an audio file. It supports
multi-channel data.
FileWrite currently supports uncompressed WAV, AIFF, AIFC, SND
(AU), MAT-file (Matlab), and STK RAW file formats. Signed integer
(8-, 16-, and 32-bit) and floating- point (32- and 64-bit) data
types are supported. STK RAW files use 16-bit integers by
definition. MAT-files will always be written as 64-bit floats.
If a data type specification does not match the specified file
type, the data type will automatically be modified. Compressed
data types are not supported.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "FileWrite.h"
#include <cmath>
const FileWrite::FILE_TYPE FileWrite :: FILE_RAW = 1;
const FileWrite::FILE_TYPE FileWrite :: FILE_WAV = 2;
const FileWrite::FILE_TYPE FileWrite :: FILE_SND = 3;
const FileWrite::FILE_TYPE FileWrite :: FILE_AIF = 4;
const FileWrite::FILE_TYPE FileWrite :: FILE_MAT = 5;
// WAV header structure. See ftp://ftp.isi.edu/in-notes/rfc2361.txt
// for information regarding format codes.
struct wavhdr {
char riff[4]; // "RIFF"
SINT32 file_size; // in bytes
char wave[4]; // "WAVE"
char fmt[4]; // "fmt "
SINT32 chunk_size; // in bytes (16 for PCM)
SINT16 format_tag; // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law
SINT16 num_chans; // 1=mono, 2=stereo
SINT32 sample_rate;
SINT32 bytes_per_sec;
SINT16 bytes_per_samp; // 2=16-bit mono, 4=16-bit stereo
SINT16 bits_per_samp;
char data[4]; // "data"
SINT32 data_length; // in bytes
};
// SND (AU) header structure (NeXT and Sun).
struct sndhdr {
char pref[4];
SINT32 hdr_length;
SINT32 data_length;
SINT32 format;
SINT32 sample_rate;
SINT32 num_channels;
char comment[16];
};
// AIFF/AIFC header structure ... only the part common to both
// formats.
struct aifhdr {
char form[4]; // "FORM"
SINT32 form_size; // in bytes
char aiff[4]; // "AIFF" or "AIFC"
char comm[4]; // "COMM"
SINT32 comm_size; // "COMM" chunk size (18 for AIFF, 24 for AIFC)
SINT16 num_chans; // number of channels
unsigned long sample_frames; // sample frames of audio data
SINT16 sample_size; // in bits
unsigned char srate[10]; // IEEE 754 floating point format
};
struct aifssnd {
char ssnd[4]; // "SSND"
SINT32 ssnd_size; // "SSND" chunk size
unsigned long offset; // data offset in data block (should be 0)
unsigned long block_size; // not used by STK (should be 0)
};
// MAT-file 5 header structure.
struct mathdr {
char heading[124]; // Header text field
SINT16 hff[2]; // Header flag fields
SINT32 adf[11]; // Array data format fields
// There's more, but it's of variable length
};
FileWrite :: FileWrite()
: fd_( 0 )
{
}
FileWrite::FileWrite( std::string fileName, unsigned int nChannels, FILE_TYPE type, Stk::StkFormat format )
: fd_( 0 )
{
this->open( fileName, nChannels, type, format );
}
FileWrite :: ~FileWrite()
{
this->close();
}
void FileWrite :: close( void )
{
if ( fd_ == 0 ) return;
if ( fileType_ == FILE_RAW )
fclose( fd_ );
else if ( fileType_ == FILE_WAV )
this->closeWavFile();
else if ( fileType_ == FILE_SND )
this->closeSndFile();
else if ( fileType_ == FILE_AIF )
this->closeAifFile();
else if ( fileType_ == FILE_MAT )
this->closeMatFile();
fd_ = 0;
}
bool FileWrite :: isOpen( void )
{
if ( fd_ ) return true;
else return false;
}
void FileWrite :: open( std::string fileName, unsigned int nChannels, FileWrite::FILE_TYPE type, Stk::StkFormat format )
{
// Call close() in case another file is already open.
this->close();
if ( nChannels < 1 ) {
errorString_ << "FileWrite::open: then channels argument must be greater than zero!";
handleError( StkError::FUNCTION_ARGUMENT );
}
channels_ = nChannels;
fileType_ = type;
if ( format != STK_SINT8 && format != STK_SINT16 &&
format != STK_SINT32 && format != STK_FLOAT32 &&
format != STK_FLOAT64 ) {
errorString_ << "FileWrite::open: unknown data type (" << format << ") specified!";
handleError( StkError::FUNCTION_ARGUMENT );
}
dataType_ = format;
bool result = false;
if ( fileType_ == FILE_RAW ) {
if ( channels_ != 1 ) {
errorString_ << "FileWrite::open: STK RAW files are, by definition, always monaural (channels = " << nChannels << " not supported)!";
handleError( StkError::FUNCTION_ARGUMENT );
}
result = setRawFile( fileName.c_str() );
}
else if ( fileType_ == FILE_WAV )
result = setWavFile( fileName.c_str() );
else if ( fileType_ == FILE_SND )
result = setSndFile( fileName.c_str() );
else if ( fileType_ == FILE_AIF )
result = setAifFile( fileName.c_str() );
else if ( fileType_ == FILE_MAT )
result = setMatFile( fileName.c_str() );
else {
errorString_ << "FileWrite::open: unknown file type (" << fileType_ << ") specified!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( result == false )
handleError( StkError::FILE_ERROR );
frameCounter_ = 0;
}
bool FileWrite :: setRawFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".raw") == NULL) strcat(name, ".raw");
fd_ = fopen(name, "wb");
if ( !fd_ ) {
errorString_ << "FileWrite: could not create RAW file: " << name << '.';
return false;
}
if ( dataType_ != STK_SINT16 ) {
dataType_ = STK_SINT16;
errorString_ << "FileWrite: using 16-bit signed integer data format for file " << name << '.';
handleError( StkError::DEBUG_WARNING );
}
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
errorString_ << "FileWrite: creating RAW file: " << name;
handleError( StkError::STATUS );
return true;
}
bool FileWrite :: setWavFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".wav") == NULL) strcat(name, ".wav");
fd_ = fopen(name, "wb");
if ( !fd_ ) {
errorString_ << "FileWrite: could not create WAV file: " << name;
return false;
}
struct wavhdr hdr = {"RIF", 44, "WAV", "fmt", 16, 1, 1,
(SINT32) Stk::sampleRate(), 0, 2, 16, "dat", 0};
hdr.riff[3] = 'F';
hdr.wave[3] = 'E';
hdr.fmt[3] = ' ';
hdr.data[3] = 'a';
hdr.num_chans = (SINT16) channels_;
if ( dataType_ == STK_SINT8 )
hdr.bits_per_samp = 8;
else if ( dataType_ == STK_SINT16 )
hdr.bits_per_samp = 16;
else if ( dataType_ == STK_SINT32 )
hdr.bits_per_samp = 32;
else if ( dataType_ == STK_FLOAT32 ) {
hdr.format_tag = 3;
hdr.bits_per_samp = 32;
}
else if ( dataType_ == STK_FLOAT64 ) {
hdr.format_tag = 3;
hdr.bits_per_samp = 64;
}
hdr.bytes_per_samp = (SINT16) (channels_ * hdr.bits_per_samp / 8);
hdr.bytes_per_sec = (SINT32) (hdr.sample_rate * hdr.bytes_per_samp);
byteswap_ = false;
#ifndef __LITTLE_ENDIAN__
byteswap_ = true;
swap32((unsigned char *)&hdr.file_size);
swap32((unsigned char *)&hdr.chunk_size);
swap16((unsigned char *)&hdr.format_tag);
swap16((unsigned char *)&hdr.num_chans);
swap32((unsigned char *)&hdr.sample_rate);
swap32((unsigned char *)&hdr.bytes_per_sec);
swap16((unsigned char *)&hdr.bytes_per_samp);
swap16((unsigned char *)&hdr.bits_per_samp);
#endif
if ( fwrite(&hdr, 4, 11, fd_) != 11 ) {
errorString_ << "FileWrite: could not write WAV header for file " << name << '.';
return false;
}
errorString_ << "FileWrite: creating WAV file: " << name;
handleError( StkError::STATUS );
return true;
}
void FileWrite :: closeWavFile( void )
{
int bytes_per_sample = 1;
if ( dataType_ == STK_SINT16 )
bytes_per_sample = 2;
else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
bytes_per_sample = 4;
else if ( dataType_ == STK_FLOAT64 )
bytes_per_sample = 8;
SINT32 bytes = frameCounter_ * channels_ * bytes_per_sample;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fseek(fd_, 40, SEEK_SET); // jump to data length
fwrite(&bytes, 4, 1, fd_);
bytes = frameCounter_ * channels_ * bytes_per_sample + 44;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fseek(fd_, 4, SEEK_SET); // jump to file size
fwrite(&bytes, 4, 1, fd_);
fclose( fd_ );
}
bool FileWrite :: setSndFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".snd") == NULL) strcat(name, ".snd");
fd_ = fopen(name, "wb");
if ( !fd_ ) {
errorString_ << "FileWrite: could not create SND file: " << name;
return false;
}
struct sndhdr hdr = {".sn", 40, 0, 3, (SINT32) Stk::sampleRate(), 1, "Created by STK"};
hdr.pref[3] = 'd';
hdr.num_channels = channels_;
if ( dataType_ == STK_SINT8 )
hdr.format = 2;
else if ( dataType_ == STK_SINT16 )
hdr.format = 3;
else if ( dataType_ == STK_SINT32 )
hdr.format = 5;
else if ( dataType_ == STK_FLOAT32 )
hdr.format = 6;
else if ( dataType_ == STK_FLOAT64 )
hdr.format = 7;
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
swap32 ((unsigned char *)&hdr.hdr_length);
swap32 ((unsigned char *)&hdr.format);
swap32 ((unsigned char *)&hdr.sample_rate);
swap32 ((unsigned char *)&hdr.num_channels);
#endif
if ( fwrite(&hdr, 4, 10, fd_) != 10 ) {
errorString_ << "FileWrite: Could not write SND header for file " << name << '.';
return false;
}
errorString_ << "FileWrite: creating SND file: " << name;
handleError( StkError::STATUS );
return true;
}
void FileWrite :: closeSndFile( void )
{
int bytes_per_sample = 1;
if ( dataType_ == STK_SINT16 )
bytes_per_sample = 2;
else if ( dataType_ == STK_SINT32 )
bytes_per_sample = 4;
else if ( dataType_ == STK_FLOAT32 )
bytes_per_sample = 4;
else if ( dataType_ == STK_FLOAT64 )
bytes_per_sample = 8;
SINT32 bytes = frameCounter_ * bytes_per_sample * channels_;
#ifdef __LITTLE_ENDIAN__
swap32 ((unsigned char *)&bytes);
#endif
fseek(fd_, 8, SEEK_SET); // jump to data size
fwrite(&bytes, 4, 1, fd_);
fclose(fd_);
}
bool FileWrite :: setAifFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".aif") == NULL) strcat(name, ".aif");
fd_ = fopen(name, "wb");
if ( !fd_ ) {
errorString_ << "FileWrite: could not create AIF file: " << name;
return false;
}
// Common parts of AIFF/AIFC header.
struct aifhdr hdr = {"FOR", 46, "AIF", "COM", 18, 0, 0, 16, "0"};
struct aifssnd ssnd = {"SSN", 8, 0, 0};
hdr.form[3] = 'M';
hdr.aiff[3] = 'F';
hdr.comm[3] = 'M';
ssnd.ssnd[3] = 'D';
hdr.num_chans = channels_;
if ( dataType_ == STK_SINT8 )
hdr.sample_size = 8;
else if ( dataType_ == STK_SINT16 )
hdr.sample_size = 16;
else if ( dataType_ == STK_SINT32 )
hdr.sample_size = 32;
else if ( dataType_ == STK_FLOAT32 ) {
hdr.aiff[3] = 'C';
hdr.sample_size = 32;
hdr.comm_size = 24;
}
else if ( dataType_ == STK_FLOAT64 ) {
hdr.aiff[3] = 'C';
hdr.sample_size = 64;
hdr.comm_size = 24;
}
// For AIFF files, the sample rate is stored in a 10-byte,
// IEEE Standard 754 floating point number, so we need to
// convert to that.
SINT16 i;
unsigned long exp;
unsigned long rate = (unsigned long) Stk::sampleRate();
memset(hdr.srate, 0, 10);
exp = rate;
for (i=0; i<32; i++) {
exp >>= 1;
if (!exp) break;
}
i += 16383;
#ifdef __LITTLE_ENDIAN__
swap16((unsigned char *)&i);
#endif
*(SINT16 *)(hdr.srate) = (SINT16) i;
for (i=32; i; i--) {
if (rate & 0x80000000) break;
rate <<= 1;
}
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&rate);
#endif
*(unsigned long *)(hdr.srate+2) = (unsigned long) rate;
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
swap32((unsigned char *)&hdr.form_size);
swap32((unsigned char *)&hdr.comm_size);
swap16((unsigned char *)&hdr.num_chans);
swap16((unsigned char *)&hdr.sample_size);
swap32((unsigned char *)&ssnd.ssnd_size);
swap32((unsigned char *)&ssnd.offset);
swap32((unsigned char *)&ssnd.block_size);
#endif
// The structure boundaries don't allow a single write of 54 bytes.
if ( fwrite(&hdr, 4, 5, fd_) != 5 ) goto error;
if ( fwrite(&hdr.num_chans, 2, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.sample_frames, 4, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.sample_size, 2, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.srate, 10, 1, fd_) != 1 ) goto error;
if ( dataType_ == STK_FLOAT32 ) {
char type[4] = {'f','l','3','2'};
char zeroes[2] = { 0, 0 };
if ( fwrite(&type, 4, 1, fd_) != 1 ) goto error;
if ( fwrite(&zeroes, 2, 1, fd_) != 1 ) goto error;
}
else if ( dataType_ == STK_FLOAT64 ) {
char type[4] = {'f','l','6','4'};
char zeroes[2] = { 0, 0 };
if ( fwrite(&type, 4, 1, fd_) != 1 ) goto error;
if ( fwrite(&zeroes, 2, 1, fd_) != 1 ) goto error;
}
if ( fwrite(&ssnd, 4, 4, fd_) != 4 ) goto error;
errorString_ << "FileWrite: creating AIF file: " << name;
handleError( StkError::STATUS );
return true;
error:
errorString_ << "FileWrite: could not write AIF header for file: " << name;
return false;
}
void FileWrite :: closeAifFile( void )
{
unsigned long frames = (unsigned long) frameCounter_;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&frames);
#endif
fseek(fd_, 22, SEEK_SET); // jump to "COMM" sample_frames
fwrite(&frames, 4, 1, fd_);
int bytes_per_sample = 1;
if ( dataType_ == STK_SINT16 )
bytes_per_sample = 2;
else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
bytes_per_sample = 4;
else if ( dataType_ == STK_FLOAT64 )
bytes_per_sample = 8;
unsigned long bytes = frameCounter_ * bytes_per_sample * channels_ + 46;
if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fseek(fd_, 4, SEEK_SET); // jump to file size
fwrite(&bytes, 4, 1, fd_);
bytes = frameCounter_ * bytes_per_sample * channels_ + 8;
if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 )
fseek(fd_, 48, SEEK_SET); // jump to "SSND" chunk size
else
fseek(fd_, 42, SEEK_SET); // jump to "SSND" chunk size
fwrite(&bytes, 4, 1, fd_);
fclose( fd_ );
}
bool FileWrite :: setMatFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".mat") == NULL) strcat(name, ".mat");
fd_ = fopen(name, "w+b");
if ( !fd_ ) {
errorString_ << "FileWrite: could not create MAT file: " << name;
return false;
}
if ( dataType_ != STK_FLOAT64 ) {
dataType_ = STK_FLOAT64;
errorString_ << "FileWrite: using 64-bit floating-point data format for file " << name << '.';
handleError( StkError::DEBUG_WARNING );
}
struct mathdr hdr;
strcpy(hdr.heading,"MATLAB 5.0 MAT-file, Generated using the Synthesis ToolKit in C++ (STK). By Perry R. Cook and Gary P. Scavone.");
int i;
for (i=strlen(hdr.heading);i<124;i++) hdr.heading[i] = ' ';
// Header Flag Fields
hdr.hff[0] = (SINT16) 0x0100; // Version field
hdr.hff[1] = (SINT16) 'M'; // Endian indicator field ("MI")
hdr.hff[1] <<= 8;
hdr.hff[1] += 'I';
hdr.adf[0] = (SINT32) 14; // Matlab array data type value
hdr.adf[1] = (SINT32) 0; // Size of file after this point to end (in bytes)
// Don't know size yet.
// Numeric Array Subelements (4):
// 1. Array Flags
hdr.adf[2] = (SINT32) 6; // Matlab 32-bit unsigned integer data type value
hdr.adf[3] = (SINT32) 8; // 8 bytes of data to follow
hdr.adf[4] = (SINT32) 6; // Double-precision array, no array flags set
hdr.adf[5] = (SINT32) 0; // 4 bytes undefined
// 2. Array Dimensions
hdr.adf[6] = (SINT32) 5; // Matlab 32-bit signed integer data type value
hdr.adf[7] = (SINT32) 8; // 8 bytes of data to follow (2D array)
hdr.adf[8] = (SINT32) channels_; // This is the number of rows
hdr.adf[9] = (SINT32) 0; // This is the number of columns
// 3. Array Name
// We'll use fileName for the matlab array name (as well as the file name).
// If fileName is 4 characters or less, we have to use a compressed data element
// format for the array name data element. Otherwise, the array name must
// be formatted in 8-byte increments (up to 31 characters + NULL).
SINT32 namelength = (SINT32) strlen(fileName);
if (strstr(fileName, ".mat")) namelength -= 4;
if (namelength > 31) namelength = 31; // Truncate name to 31 characters.
char arrayName[64];
strncpy(arrayName, fileName, namelength);
arrayName[namelength] = '\0';
if (namelength > 4) {
hdr.adf[10] = (SINT32) 1; // Matlab 8-bit signed integer data type value
}
else { // Compressed data element format
hdr.adf[10] = namelength;
hdr.adf[10] <<= 16;
hdr.adf[10] += 1;
}
SINT32 headsize = 40; // Number of bytes in data element so far.
// Write the fixed portion of the header
if ( fwrite(&hdr, 172, 1, fd_) != 1 ) goto error;
// Write MATLAB array name
SINT32 tmp;
if (namelength > 4) {
if ( fwrite(&namelength, 4, 1, fd_) != 1) goto error;
if ( fwrite(arrayName, namelength, 1, fd_) != 1 ) goto error;
tmp = (SINT32) ceil((float)namelength / 8);
if ( fseek(fd_, tmp*8-namelength, SEEK_CUR) == -1 ) goto error;
headsize += tmp * 8;
}
else { // Compressed data element format
if ( fwrite(arrayName, namelength, 1, fd_) != 1 ) goto error;
tmp = 4 - namelength;
if ( fseek(fd_, tmp, SEEK_CUR) == -1 ) goto error;
}
// Finish writing known header information
tmp = 9; // Matlab IEEE 754 double data type
if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
tmp = 0; // Size of real part subelement in bytes (8 per sample)
if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
headsize += 8; // Total number of bytes in data element so far
if ( fseek(fd_, 132, SEEK_SET) == -1 ) goto error;
if ( fwrite(&headsize, 4, 1, fd_) != 1 ) goto error; // Write header size ... will update at end
if ( fseek(fd_, 0, SEEK_END) == -1 ) goto error;
byteswap_ = false;
errorString_ << "FileWrite: creating MAT-file (" << name << ") containing MATLAB array: " << arrayName;
handleError( StkError::STATUS );
return true;
error:
errorString_ << "FileWrite: could not write MAT-file header for file " << name << '.';
return false;
}
void FileWrite :: closeMatFile( void )
{
fseek(fd_, 164, SEEK_SET); // jump to number of columns
fwrite(&frameCounter_, 4, 1, fd_);
SINT32 headsize, temp;
fseek(fd_, 132, SEEK_SET); // jump to header size
fread(&headsize, 4, 1, fd_);
temp = headsize;
headsize += (SINT32) (frameCounter_ * 8 * channels_);
fseek(fd_, 132, SEEK_SET);
// Write file size (minus some header info)
fwrite(&headsize, 4, 1, fd_);
fseek(fd_, temp+132, SEEK_SET); // jumpt to data size (in bytes)
temp = frameCounter_ * 8 * channels_;
fwrite(&temp, 4, 1, fd_);
fclose(fd_);
}
void FileWrite :: write( StkFrames& buffer )
{
if ( fd_ == 0 ) {
errorString_ << "FileWrite::write(): a file has not yet been opened!";
handleError( StkError::WARNING );
return;
}
if ( buffer.channels() != channels_ ) {
errorString_ << "FileWrite::write(): number of channels in the StkFrames argument does not match that specified to open() function!";
handleError( StkError::FUNCTION_ARGUMENT );
return;
}
unsigned long nSamples = buffer.size();
if ( dataType_ == STK_SINT16 ) {
SINT16 sample;
for ( unsigned long k=0; k<nSamples; k++ ) {
sample = (SINT16) (buffer[k] * 32767.0);
//sample = ((SINT16) (( buffer[k] + 1.0 ) * 32767.5 + 0.5)) - 32768;
if ( byteswap_ ) swap16( (unsigned char *)&sample );
if ( fwrite(&sample, 2, 1, fd_) != 1 ) goto error;
}
}
else if ( dataType_ == STK_SINT8 ) {
if ( fileType_ == FILE_WAV ) { // 8-bit WAV data is unsigned!
unsigned char sample;
for ( unsigned long k=0; k<nSamples; k++ ) {
sample = (unsigned char) (buffer[k] * 127.0 + 128.0);
if ( fwrite(&sample, 1, 1, fd_) != 1 ) goto error;
}
}
else {
signed char sample;
for ( unsigned long k=0; k<nSamples; k++ ) {
sample = (signed char) (buffer[k] * 127.0);
//sample = ((signed char) (( buffer[k] + 1.0 ) * 127.5 + 0.5)) - 128;
if ( fwrite(&sample, 1, 1, fd_) != 1 ) goto error;
}
}
}
else if ( dataType_ == STK_SINT32 ) {
SINT32 sample;
for ( unsigned long k=0; k<nSamples; k++ ) {
sample = (SINT32) (buffer[k] * 2147483647.0);
//sample = ((SINT32) (( buffer[k] + 1.0 ) * 2147483647.5 + 0.5)) - 2147483648;
if ( byteswap_ ) swap32( (unsigned char *)&sample );
if ( fwrite(&sample, 4, 1, fd_) != 1 ) goto error;
}
}
else if ( dataType_ == STK_FLOAT32 ) {
FLOAT32 sample;
for ( unsigned long k=0; k<nSamples; k++ ) {
sample = (FLOAT32) (buffer[k]);
if ( byteswap_ ) swap32( (unsigned char *)&sample );
if ( fwrite(&sample, 4, 1, fd_) != 1 ) goto error;
}
}
else if ( dataType_ == STK_FLOAT64 ) {
FLOAT64 sample;
for ( unsigned long k=0; k<nSamples; k++ ) {
sample = (FLOAT64) (buffer[k]);
if ( byteswap_ ) swap64( (unsigned char *)&sample );
if ( fwrite(&sample, 8, 1, fd_) != 1 ) goto error;
}
}
frameCounter_ += buffer.frames();
return;
error:
errorString_ << "FileWrite::write(): error writing data to file!";
handleError( StkError::FILE_ERROR );
}

211
src/FileWvIn.cpp Normal file
View File

@@ -0,0 +1,211 @@
/***************************************************/
/*! \class FileWvIn
\brief STK audio file input class.
This class inherits from WvIn. It provides a "tick-level"
interface to the FileRead class. It also provides variable-rate
"playback" functionality. Audio file support is provided by the
FileRead class. Linear interpolation is used for fractional "read
rates".
FileWvIn supports multi-channel data. It is important to distinguish
the tick() methods, which return samples produced by averaging
across sample frames, from the tickFrame() methods, which return
references to multi-channel sample frames.
FileWvIn will either load the entire content of an audio file into
local memory or incrementally read file data from disk in chunks.
This behavior is controlled by the optional constructor arguments
\e chunkThreshold and \e chunkSize. File sizes greater than \e
chunkThreshold (in sample frames) will be read incrementally in
chunks of \e chunkSize each (also in sample frames).
When the end of a file is reached, subsequent calls to the tick()
functions return zero-valued data.
See the FileRead class for a description of the supported audio
file formats.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "FileWvIn.h"
#include <cmath>
FileWvIn :: FileWvIn( unsigned long chunkThreshold, unsigned long chunkSize )
: finished_(true), interpolate_(false), time_(0.0),
chunkThreshold_(chunkThreshold), chunkSize_(chunkSize)
{
}
FileWvIn :: FileWvIn( std::string fileName, bool raw, bool doNormalize,
unsigned long chunkThreshold, unsigned long chunkSize )
: finished_(true), interpolate_(false), time_(0.0),
chunkThreshold_(chunkThreshold), chunkSize_(chunkSize)
{
openFile( fileName, raw, doNormalize );
}
FileWvIn :: ~FileWvIn()
{
this->closeFile();
}
void FileWvIn :: closeFile( void )
{
if ( file_.isOpen() ) file_.close();
finished_ = true;
}
void FileWvIn :: openFile( std::string fileName, bool raw, bool doNormalize )
{
// Call close() in case another file is already open.
this->closeFile();
// Attempt to open the file ... an error might be thrown here.
file_.open( fileName, raw );
// Determine whether chunking or not.
if ( file_.fileSize() > chunkThreshold_ ) {
chunking_ = true;
chunkPointer_ = 0;
data_.resize( chunkSize_, file_.channels() );
if ( doNormalize ) normalizing_ = true;
else normalizing_ = false;
}
else {
chunking_ = false;
data_.resize( (size_t) file_.fileSize(), file_.channels() );
}
// Load all or part of the data.
file_.read( data_, 0, doNormalize );
// Resize our lastOutputs container.
lastOutputs_.resize( 1, file_.channels() );
// Set default rate based on file sampling rate.
this->setRate( data_.dataRate() / Stk::sampleRate() );
if ( doNormalize & !chunking_ ) this->normalize();
this->reset();
}
void FileWvIn :: reset(void)
{
time_ = (StkFloat) 0.0;
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = 0.0;
finished_ = false;
}
void FileWvIn :: normalize(void)
{
this->normalize( 1.0 );
}
// Normalize all channels equally by the greatest magnitude in all of the data.
void FileWvIn :: normalize( StkFloat peak )
{
// When chunking, the "normalization" scaling is performed by FileRead.
if ( chunking_ ) return;
size_t i;
StkFloat max = 0.0;
for ( i=0; i<data_.size(); i++ ) {
if ( fabs( data_[i] ) > max )
max = (StkFloat) fabs((double) data_[i]);
}
if (max > 0.0) {
max = 1.0 / max;
max *= peak;
for ( i=0; i<data_.size(); i++ )
data_[i] *= max;
}
}
void FileWvIn :: setRate( StkFloat rate )
{
rate_ = rate;
// If negative rate and at beginning of sound, move pointer to end
// of sound.
if ( (rate_ < 0) && (time_ == 0.0) ) time_ = file_.fileSize() - 1.0;
if ( fmod( rate_, 1.0 ) != 0.0 ) interpolate_ = true;
else interpolate_ = false;
}
void FileWvIn :: addTime( StkFloat time )
{
// Add an absolute time in samples
time_ += time;
if ( time_ < 0.0 ) time_ = 0.0;
if ( time_ > file_.fileSize() - 1.0 ) {
time_ = file_.fileSize() - 1.0;
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = 0.0;
finished_ = true;
}
}
StkFloat FileWvIn :: lastOut( void ) const
{
if ( finished_ ) return 0.0;
return WvIn :: lastOut();
}
void FileWvIn :: computeFrame( void )
{
if ( finished_ ) return;
if ( time_ < 0.0 || time_ > (StkFloat) ( file_.fileSize() - 1.0 ) ) {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = 0.0;
finished_ = true;
return;
}
StkFloat tyme = time_;
if ( chunking_ ) {
// Check the time address vs. our current buffer limits.
if ( ( time_ < (StkFloat) chunkPointer_ ) ||
( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) ) {
while ( time_ < (StkFloat) chunkPointer_ ) { // negative rate
chunkPointer_ -= chunkSize_ - 1; // overlap chunks by one frame
if ( chunkPointer_ < 0 ) chunkPointer_ = 0;
}
while ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) { // positive rate
chunkPointer_ += chunkSize_ - 1; // overlap chunks by one frame
if ( chunkPointer_ + chunkSize_ > file_.fileSize() ) // at end of file
chunkPointer_ = file_.fileSize() - chunkSize_;
}
// Load more data.
file_.read( data_, chunkPointer_, normalizing_ );
}
// Adjust index for the current buffer.
tyme -= chunkPointer_;
}
if ( interpolate_ ) {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = data_.interpolate( tyme, i );
}
else {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = data_( (size_t) tyme, i );
}
// Increment time, which can be negative.
time_ += rate_;
}

152
src/FileWvOut.cpp Normal file
View File

@@ -0,0 +1,152 @@
/***************************************************/
/*! \class FileWvOut
\brief STK audio file output class.
This class inherits from WvOut. It provides a "tick-level"
interface to the FileWrite class.
FileWvOut writes samples to an audio file and supports
multi-channel data. It is important to distinguish the tick()
methods, which output single samples to all channels in a sample
frame, from the tickFrame() methods, which take a pointer or
reference to multi-channel sample frame data.
See the FileWrite class for a description of the supported audio
file formats.
Currently, FileWvOut is non-interpolating and the output rate is
always Stk::sampleRate().
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "FileWvOut.h"
FileWvOut :: FileWvOut( unsigned int bufferFrames )
:bufferFrames_( bufferFrames )
{
}
FileWvOut::FileWvOut( std::string fileName, unsigned int nChannels, FileWrite::FILE_TYPE type, Stk::StkFormat format, unsigned int bufferFrames )
:bufferFrames_( bufferFrames )
{
this->openFile( fileName, nChannels, type, format );
}
FileWvOut :: ~FileWvOut()
{
this->closeFile();
}
void FileWvOut :: closeFile( void )
{
if ( file_.isOpen() ) {
// Output any remaining samples in the buffer before closing.
if ( bufferIndex_ > 0 ) {
data_.resize( bufferIndex_, data_.channels() );
file_.write( data_ );
}
file_.close();
frameCounter_ = 0;
}
}
void FileWvOut :: openFile( std::string fileName,
unsigned int nChannels,
FileWrite::FILE_TYPE type,
Stk::StkFormat format )
{
closeFile();
if ( nChannels < 1 ) {
errorString_ << "FileWvOut::openFile: the channels argument must be greater than zero!";
handleError( StkError::FUNCTION_ARGUMENT );
}
// An StkError can be thrown by the FileWrite class here.
file_.open( fileName, nChannels, type, format );
// Allocate new memory if necessary.
data_.resize( bufferFrames_, nChannels );
bufferIndex_ = 0;
iData_ = 0;
}
void FileWvOut :: incrementFrame( void )
{
frameCounter_++;
bufferIndex_++;
if ( bufferIndex_ == bufferFrames_ ) {
file_.write( data_ );
bufferIndex_ = 0;
iData_ = 0;
}
}
void FileWvOut :: computeSample( const StkFloat sample )
{
if ( !file_.isOpen() ) {
errorString_ << "FileWvOut::computeSample(): no file open!";
handleError( StkError::WARNING );
return;
}
unsigned int nChannels = data_.channels();
StkFloat input = sample;
clipTest( input );
for ( unsigned int j=0; j<nChannels; j++ )
data_[iData_++] = input;
this->incrementFrame();
}
void FileWvOut :: computeFrames( const StkFrames& frames )
{
if ( !file_.isOpen() ) {
errorString_ << "FileWvOut::computeFrames(): no file open!";
handleError( StkError::WARNING );
return;
}
if ( data_.channels() != frames.channels() ) {
errorString_ << "FileWvOut::computeFrames(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
unsigned int j, nChannels = data_.channels();
if ( nChannels == 1 || frames.interleaved() ) {
unsigned int iFrames = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[iFrames++];
clipTest( data_[iData_++] );
}
this->incrementFrame();
}
}
else { // non-interleaved frames
unsigned long hop = frames.frames();
unsigned int index;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
index = i;
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[index];
clipTest( data_[iData_++] );
index += hop;
}
this->incrementFrame();
}
}
}

View File

@@ -2,7 +2,7 @@
/*! \class Filter
\brief STK filter class.
This class implements a generic structure which
This class implements a generic structure that
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
@@ -23,7 +23,7 @@
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 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -76,7 +76,7 @@ void Filter :: clear(void)
outputs_[i] = 0.0;
}
void Filter :: setCoefficients( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients )
void Filter :: setCoefficients( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients, bool clearState )
{
// Check the arguments.
if ( bCoefficients.size() == 0 || aCoefficients.size() == 0 ) {
@@ -107,7 +107,7 @@ void Filter :: setCoefficients( std::vector<StkFloat> &bCoefficients, std::vecto
for ( unsigned int i=0; i<a_.size(); i++ ) a_[i] = aCoefficients[i];
}
this->clear();
if ( clearState ) this->clear();
// Scale coefficients by a[0] if necessary
if ( a_[0] != 1.0 ) {
@@ -117,7 +117,7 @@ void Filter :: setCoefficients( std::vector<StkFloat> &bCoefficients, std::vecto
}
}
void Filter :: setNumerator( std::vector<StkFloat> &bCoefficients )
void Filter :: setNumerator( std::vector<StkFloat> &bCoefficients, bool clearState )
{
// Check the argument.
if ( bCoefficients.size() == 0 ) {
@@ -134,10 +134,10 @@ void Filter :: setNumerator( std::vector<StkFloat> &bCoefficients )
for ( unsigned int i=0; i<b_.size(); i++ ) b_[i] = bCoefficients[i];
}
this->clear();
if ( clearState ) this->clear();
}
void Filter :: setDenominator( std::vector<StkFloat> &aCoefficients )
void Filter :: setDenominator( std::vector<StkFloat> &aCoefficients, bool clearState )
{
// Check the argument.
if ( aCoefficients.size() == 0 ) {
@@ -159,7 +159,7 @@ void Filter :: setDenominator( std::vector<StkFloat> &aCoefficients )
for ( unsigned int i=0; i<a_.size(); i++ ) a_[i] = aCoefficients[i];
}
this->clear();
if ( clearState ) this->clear();
// Scale coefficients by a[0] if necessary
if ( a_[0] != 1.0 ) {
@@ -184,12 +184,12 @@ StkFloat Filter :: lastOut(void) const
return outputs_[0];
}
StkFloat Filter :: tick(StkFloat sample)
StkFloat Filter :: tick( StkFloat input )
{
unsigned int i;
outputs_[0] = 0.0;
inputs_[0] = gain_ * sample;
inputs_[0] = gain_ * input;
for (i=b_.size()-1; i>0; i--) {
outputs_[0] += b_[i] * inputs_[i];
inputs_[i] = inputs_[i-1];
@@ -204,18 +204,11 @@ StkFloat Filter :: tick(StkFloat sample)
return outputs_[0];
}
StkFloat *Filter :: tick(StkFloat *vector, unsigned int vectorSize)
{
for (unsigned int i=0; i<vectorSize; i++)
vector[i] = tick(vector[i]);
return vector;
}
StkFrames& Filter :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "Filter::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
if ( channel >= frames.channels() ) {
errorString_ << "Filter::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
@@ -225,16 +218,16 @@ StkFrames& Filter :: tick( StkFrames& frames, unsigned int channel )
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[iStart + i] = tick( frames[iStart + i] );
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = tick( frames[iStart] );
}
return frames;

View File

@@ -18,7 +18,7 @@
- Vibrato Gain = 1
- Breath Pressure = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -35,14 +35,15 @@ Flute :: Flute(StkFloat lowestFrequency)
jetDelay_.setMaximumDelay( length_ );
jetDelay_.setDelay( 49.0 );
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
vibrato_->setFrequency( 5.925 );
vibrato_.setFrequency( 5.925 );
this->clear();
filter_.setPole( 0.7 - ((StkFloat) 0.1 * 22050.0 / Stk::sampleRate() ) );
filter_.setGain( -1.0 );
dcBlock_.setBlockZero();
adsr_.setAllTimes( 0.005, 0.01, 0.8, 0.010);
endReflection_ = 0.5;
jetReflection_ = 0.5;
@@ -56,7 +57,6 @@ Flute :: Flute(StkFloat lowestFrequency)
Flute :: ~Flute()
{
delete vibrato_;
}
void Flute :: clear()
@@ -141,18 +141,18 @@ void Flute :: setJetDelay(StkFloat aRatio)
jetDelay_.setDelay(temp * aRatio); // Scaled by ratio.
}
StkFloat Flute :: tick()
StkFloat Flute :: computeSample()
{
StkFloat pressureDiff;
StkFloat breathPressure;
// Calculate the breath pressure (envelope + noise + vibrato)
breathPressure = maxPressure_ * adsr_.tick();
breathPressure += breathPressure * noiseGain_ * noise_.tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_->tick();
breathPressure += breathPressure * ( noiseGain_ * noise_.tick() + vibratoGain_ * vibrato_.tick() );
//breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
StkFloat temp = filter_.tick( boreDelay_.lastOut() );
temp = dcBlock_.tick(temp); // Block DC on reflection.
temp = dcBlock_.tick( temp ); // Block DC on reflection.
pressureDiff = breathPressure - (jetReflection_ * temp);
pressureDiff = jetDelay_.tick( pressureDiff );
@@ -163,16 +163,6 @@ StkFloat Flute :: tick()
return lastOutput_;
}
StkFloat *Flute :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Flute :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Flute :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;
@@ -192,7 +182,7 @@ void Flute :: controlChange(int number, StkFloat value)
else if (number == __SK_NoiseLevel_) // 4
noiseGain_ = ( norm * 0.4);
else if (number == __SK_ModFrequency_) // 11
vibrato_->setFrequency( norm * 12.0);
vibrato_.setFrequency( norm * 12.0);
else if (number == __SK_ModWheel_) // 1
vibratoGain_ = ( norm * 0.4 );
else if (number == __SK_AfterTouch_Cont_) // 128

View File

@@ -8,7 +8,7 @@
It provides methods for controlling the sweep
rate and target frequency.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -87,12 +87,12 @@ void FormSwep :: setSweepTime(StkFloat time)
if ( sweepRate_ < 0.0 ) sweepRate_ = 0.0;
}
StkFloat FormSwep :: tick(StkFloat sample)
StkFloat FormSwep :: computeSample( StkFloat input )
{
if (dirty_) {
sweepState_ += sweepRate_;
if ( sweepState_ >= 1.0 ) {
sweepState_ = (StkFloat) 1.0;
sweepState_ = 1.0;
dirty_ = false;
radius_ = targetRadius_;
frequency_ = targetFrequency_;
@@ -106,15 +106,6 @@ StkFloat FormSwep :: tick(StkFloat sample)
BiQuad::setResonance( frequency_, radius_, true );
}
return BiQuad::tick( sample );
return BiQuad::computeSample( input );
}
StkFloat *FormSwep :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Filter::tick( vector, vectorSize );
}
StkFrames& FormSwep :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );
}

View File

@@ -6,7 +6,7 @@
implement tables or other types of input to output function
mappings.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -21,37 +21,34 @@ Function :: ~Function()
{
}
StkFloat *Function :: tick(StkFloat *vector, unsigned int vectorSize)
StkFloat Function :: tick( StkFloat input )
{
for (unsigned int i=0; i<vectorSize; i++)
vector[i] = tick( vector[i] );
return vector;
return computeSample( input );
}
StkFrames& Function :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "Function::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
if ( channel >= frames.channels() ) {
errorString_ << "Function::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = tick( frames[i] );
frames[i] = computeSample( frames[i] );
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick( frames[index] );
frames[index] = computeSample( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[iStart + i] = tick( frames[iStart + i] );
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = computeSample( frames[iStart] );
}
return frames;

View File

@@ -3,9 +3,9 @@
\brief STK abstract unit generator parent class.
This class provides common functionality for
STK unit generator source subclasses.
STK unit generator sample-source subclasses.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -20,37 +20,34 @@ Generator :: ~Generator()
{
}
StkFloat *Generator :: tick(StkFloat *vector, unsigned int vectorSize)
StkFloat Generator :: tick( void )
{
for (unsigned int i=0; i<vectorSize; i++)
vector[i] = tick();
return vector;
return computeSample();
}
StkFrames& Generator :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "Generator::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
if ( channel >= frames.channels() ) {
errorString_ << "Generator::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = tick();
frames[i] = computeSample();
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick();
frames[index] = computeSample();
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[iStart + i] = tick();
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = computeSample();
}
return frames;

275
src/Granulate.cpp Normal file
View File

@@ -0,0 +1,275 @@
/***************************************************/
/*! \class Granulate
\brief STK granular synthesis class.
This class implements a real-time granular synthesis algorithm
that operates on an input soundfile. Currently, only monophonic
files are supported. Various functions are provided to allow
control over voice and grain parameters.
The functionality of this class is based on the program MacPod by
Chris Rolfe and Damian Keller, though there are likely to be a
number of differences in the actual implementation.
by Gary Scavone, 2005.
*/
/***************************************************/
#include "Granulate.h"
#include "FileRead.h"
Granulate :: Granulate( void )
{
this->setGrainParameters(); // use default values
this->setRandomFactor();
gStretch_ = 0;
stretchCounter_ = 0;
gain_ = 1.0;
}
Granulate :: Granulate( unsigned int nVoices, std::string fileName, bool typeRaw )
{
this->setGrainParameters(); // use default values
this->setRandomFactor();
gStretch_ = 0;
stretchCounter_ = 0;
this->openFile( fileName, typeRaw );
this->setVoices( nVoices );
}
Granulate :: ~Granulate()
{
}
void Granulate :: setStretch( unsigned int stretchFactor )
{
if ( stretchFactor <= 1 )
gStretch_ = 0;
else if ( gStretch_ >= 1000 )
gStretch_ = 1000;
else
gStretch_ = stretchFactor - 1;
}
void Granulate :: setGrainParameters( unsigned int duration, unsigned int rampPercent,
int offset, unsigned int delay )
{
gDuration_ = duration;
if ( gDuration_ == 0 ) {
gDuration_ = 1;
errorString_ << "Granulate::setGrainParameters: duration argument cannot be zero ... setting to 1 millisecond.";
handleError( StkError::WARNING );
}
gRampPercent_ = rampPercent;
if ( gRampPercent_ > 100 ) {
gRampPercent_ = 100;
errorString_ << "Granulate::setGrainParameters: rampPercent argument cannot be greater than 100 ... setting to 100.";
handleError( StkError::WARNING );
}
gOffset_ = offset;
gDelay_ = delay;
}
void Granulate :: setRandomFactor( StkFloat randomness )
{
if ( randomness < 0.0 ) gRandomFactor_ = 0.0;
else if ( randomness > 1.0 ) gRandomFactor_ = 0.97;
gRandomFactor_ = 0.97 * randomness;
};
void Granulate :: openFile( std::string fileName, bool typeRaw )
{
// Attempt to load the soundfile data.
FileRead file( fileName, typeRaw );
if ( file.channels() != 1 ) {
errorString_ << "Granulate::openFile: this class currently only supports monophonic soundfiles.";
handleError( StkError::FUNCTION_ARGUMENT );
}
data_.resize( file.fileSize(), file.channels() );
file.read( data_ );
this->reset();
#if defined(_STK_DEBUG_)
errorString_ << "Granulate::openFile: file = " << fileName << ", file frames = " << file.fileSize() << '.';
handleError( StkError::DEBUG_WARNING );
#endif
}
void Granulate :: reset()
{
gPointer_ = 0;
// Reset grain parameters.
unsigned int count, nVoices = grains_.size();
for ( unsigned int i=0; i<grains_.size(); i++ ) {
grains_[i].repeats = 0;
count = (unsigned int ) ( i * gDuration_ * 0.001 * Stk::sampleRate() / nVoices );
grains_[i].counter = count;
grains_[i].state = GRAIN_STOPPED;
}
lastOutput_ = 0.0;
}
void Granulate :: setVoices( unsigned int nVoices )
{
#if defined(_STK_DEBUG_)
errorString_ << "Granulate::setGrains: nGrains = " << nGrains << ", existing grains = " << grains_.size() << '.';
handleError( StkError::DEBUG_WARNING );
#endif
unsigned int oldSize = grains_.size();
grains_.resize( nVoices );
// Initialize new grain voices.
unsigned int count;
for ( unsigned int i=oldSize; i<nVoices; i++ ) {
grains_[i].repeats = 0;
count = (unsigned int ) ( i * gDuration_ * 0.001 * Stk::sampleRate() / nVoices );
grains_[i].counter = count;
grains_[i].state = GRAIN_STOPPED;
}
gain_ = 1.0 / grains_.size();
}
void Granulate :: calculateGrain( Granulate::Grain& grain )
{
if ( grain.repeats > 0 ) {
grain.repeats--;
grain.pointer = grain.startPointer;
if ( grain.attackCount > 0 ) {
grain.eScaler = 0.0;
grain.eRate = -grain.eRate;
grain.counter = grain.attackCount;
grain.state = GRAIN_FADEIN;
}
else {
grain.counter = grain.sustainCount;
grain.state = GRAIN_SUSTAIN;
}
return;
}
// Calculate duration and envelope parameters.
StkFloat seconds = gDuration_ * 0.001;
seconds += ( seconds * gRandomFactor_ * noise.tick() );
unsigned int count = (unsigned long) ( seconds * Stk::sampleRate() );
grain.attackCount = (unsigned int) ( gRampPercent_ * 0.005 * count );
grain.decayCount = grain.attackCount;
grain.sustainCount = count - 2 * grain.attackCount;
grain.eScaler = 0.0;
if ( grain.attackCount > 0 ) {
grain.eRate = 1.0 / grain.attackCount;
grain.counter = grain.attackCount;
grain.state = GRAIN_FADEIN;
}
else {
grain.counter = grain.sustainCount;
grain.state = GRAIN_SUSTAIN;
}
// Calculate delay parameter.
seconds = gDelay_ * 0.001;
seconds += ( seconds * gRandomFactor_ * noise.tick() );
count = (unsigned long) ( seconds * Stk::sampleRate() );
grain.delayCount = count;
// Save stretch parameter.
grain.repeats = gStretch_;
// Calculate offset parameter.
seconds = gOffset_ * 0.001;
seconds += ( seconds * gRandomFactor_ * noise.tick() );
int offset = (int) ( seconds * Stk::sampleRate() );
grain.pointer = gPointer_ + offset;
while ( grain.pointer >= data_.frames() ) grain.pointer -= data_.frames();
if ( grain.pointer < 0 ) grain.pointer = 0;
grain.startPointer = grain.pointer;
}
StkFloat Granulate :: computeSample( void )
{
lastOutput_ = 0.0;
if ( data_.size() == 0 ) return lastOutput_;
StkFloat sample;
for ( unsigned int i=0; i<grains_.size(); i++ ) {
if ( grains_[i].counter == 0 ) { // Update the grain state.
switch ( grains_[i].state ) {
case GRAIN_STOPPED:
// We're done waiting between grains ... setup for new grain
this->calculateGrain( grains_[i] );
break;
case GRAIN_FADEIN:
// We're done ramping up the envelope
if ( grains_[i].sustainCount > 0 ) {
grains_[i].counter = grains_[i].sustainCount;
grains_[i].state = GRAIN_SUSTAIN;
break;
}
// else no sustain state (i.e. perfect triangle window)
case GRAIN_SUSTAIN:
// We're done with flat part of envelope ... setup to ramp down
if ( grains_[i].decayCount > 0 ) {
grains_[i].counter = grains_[i].decayCount;
grains_[i].eRate = -grains_[i].eRate;
grains_[i].state = GRAIN_FADEOUT;
break;
}
// else no fade out state (gRampPercent = 0)
case GRAIN_FADEOUT:
// We're done ramping down ... setup for wait between grains
if ( grains_[i].delayCount > 0 ) {
grains_[i].counter = grains_[i].delayCount;
grains_[i].state = GRAIN_STOPPED;
break;
}
// else no delay (gDelay = 0)
this->calculateGrain( grains_[i] );
}
}
// Accumulate the grain outputs.
if ( grains_[i].state > 0 ) {
sample = data_[ grains_[i].pointer++ ];
if ( grains_[i].state == GRAIN_FADEIN || grains_[i].state == GRAIN_FADEOUT ) {
sample *= grains_[i].eScaler;
grains_[i].eScaler += grains_[i].eRate;
}
lastOutput_ += sample;
// Check pointer limits.
if ( grains_[i].pointer >= data_.frames() )
grains_[i].pointer = 0;
}
// Decrement counter for all states.
grains_[i].counter--;
}
// Increment our global file pointer at the stretch rate.
if ( stretchCounter_++ == gStretch_ ) {
gPointer_++;
if ( (unsigned long) gPointer_ >= data_.frames() ) gPointer_ = 0;
stretchCounter_ = 0;
}
return lastOutput_ * gain_;
}

View File

@@ -22,7 +22,7 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -52,7 +52,7 @@ HevyMetl :: HevyMetl()
adsr_[3]->setAllTimes( 0.030, 0.010, 0.2, 0.20);
twozero_.setGain( 2.0 );
vibrato_->setFrequency( 5.5 );
vibrato_.setFrequency( 5.5 );
modDepth_ = 0.0;
}
@@ -75,11 +75,11 @@ void HevyMetl :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat HevyMetl :: tick()
StkFloat HevyMetl :: computeSample()
{
register StkFloat temp;
temp = vibrato_->tick() * modDepth_ * 0.2;
temp = vibrato_.tick() * modDepth_ * 0.2;
waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[0]);
waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[1]);
waves_[2]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[2]);
@@ -101,14 +101,3 @@ StkFloat HevyMetl :: tick()
lastOutput_ = temp * 0.5;
return lastOutput_;
}
StkFloat *HevyMetl :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& HevyMetl :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

275
src/InetWvIn.cpp Normal file
View File

@@ -0,0 +1,275 @@
/***************************************************/
/*! \class InetWvIn
\brief STK internet streaming input class.
This Wvin subclass reads streamed audio data over a network via a
TCP or UDP socket connection. The data is assumed in big-endian,
or network, byte order. Only a single socket connection is
supported.
InetWvIn supports multi-channel data. It is important to
distinguish the tick() methods, which return samples produced by
averaging across sample frames, from the tickFrame() methods,
which return references or pointers to multi-channel sample
frames.
This class implements a socket server. When using the TCP
protocol, the server "listens" for a single remote connection
within the InetWvIn::start() function. For the UDP protocol, no
attempt is made to verify packet delivery or order. The default
data type for the incoming stream is signed 16-bit integers,
though any of the defined StkFormats are permissible.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "InetWvIn.h"
extern "C" THREAD_RETURN THREAD_TYPE inputThread( void * ptr )
{
ThreadInfo *info = (ThreadInfo *)ptr;
while ( !info->finished ) {
((InetWvIn *) info->object)->receive();
}
return 0;
}
InetWvIn :: InetWvIn( unsigned long bufferFrames, unsigned int nBuffers )
:soket_(0), buffer_(0), bufferFrames_(bufferFrames), bufferBytes_(0), nBuffers_(nBuffers), connected_(false)
{
threadInfo_.finished = false;
threadInfo_.object = (void *) this;
// Start the input thread.
if ( !thread_.start( &inputThread, &threadInfo_ ) ) {
errorString_ << "InetWvIn(): unable to start input thread in constructor!";
handleError( StkError::PROCESS_THREAD );
}
}
InetWvIn :: ~InetWvIn()
{
// Close down the thread.
connected_ = false;
threadInfo_.finished = true;
if ( soket_ ) delete soket_;
if ( buffer_ ) delete [] buffer_;
}
void InetWvIn :: listen( int port, unsigned int nChannels,
Stk::StkFormat format, Socket::ProtocolType protocol )
{
mutex_.lock();
if ( connected_ ) delete soket_;
if ( nChannels < 1 ) {
errorString_ << "InetWvIn()::listen(): the channel argument (" << nChannels << ") must be greater than zero.";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( format == STK_SINT16 ) dataBytes_ = 2;
else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataBytes_ = 4;
else if ( format == STK_FLOAT64 ) dataBytes_ = 8;
else if ( format == STK_SINT8 ) dataBytes_ = 1;
else {
errorString_ << "InetWvIn(): unknown data type specified (" << format << ").";
handleError( StkError::FUNCTION_ARGUMENT );
}
dataType_ = format;
unsigned long bufferBytes = bufferFrames_ * nBuffers_ * nChannels * dataBytes_;
if ( bufferBytes > bufferBytes_ ) {
if ( buffer_) delete [] buffer_;
buffer_ = (char *) new char[ bufferBytes ];
bufferBytes_ = bufferBytes;
}
data_.resize( bufferFrames_, nChannels );
lastOutputs_.resize( 1, nChannels, 0.0 );
bufferCounter_ = 0;
writePoint_ = 0;
readPoint_ = 0;
bytesFilled_ = 0;
if ( protocol == Socket::PROTO_TCP ) {
TcpServer *socket = new TcpServer( port );
errorString_ << "InetWvIn:listen(): waiting for TCP connection on port " << socket->port() << " ... ";
handleError( StkError::STATUS );
fd_ = socket->accept();
if ( fd_ < 0) {
errorString_ << "InetWvIn::listen(): Error accepting TCP connection request!";
handleError( StkError::PROCESS_SOCKET );
}
errorString_ << "InetWvIn::listen(): TCP socket connection made!";
handleError( StkError::STATUS );
soket_ = (Socket *) socket;
}
else {
soket_ = new UdpSocket( port );
fd_ = soket_->id();
}
connected_ = true;
mutex_.unlock();
}
void InetWvIn :: 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();
unsigned long unfilled = bufferBytes_ - bytesFilled_;
if ( unfilled > 0 ) {
// There's room in our buffer for more data.
unsigned long endPoint = writePoint_ + unfilled;
if ( endPoint > bufferBytes_ ) unfilled -= endPoint - bufferBytes_;
int i = soket_->readBuffer( fd_, (void *)&buffer_[writePoint_], unfilled, 0 );
//int i = Socket::readBuffer( fd_, (void *)&buffer_[writePoint_], unfilled, 0 );
if ( i <= 0 ) {
errorString_ << "InetWvIn::receive(): the remote InetWvIn socket has closed.";
handleError( StkError::STATUS );
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 InetWvIn :: 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.
unsigned long bytes = data_.size() * dataBytes_;
while ( connected_ && bytesFilled_ < bytes )
Stk::sleep( 10 );
if ( !connected_ && bytesFilled_ == 0 ) return 0;
bytes = ( bytesFilled_ < bytes ) ? bytesFilled_ : bytes;
// Copy samples from buffer to data.
StkFloat gain;
long samples = bytes / dataBytes_;
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] = (StkFloat) *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] = (StkFloat) *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] = (StkFloat) *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] = (StkFloat) *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] = (StkFloat) *buf++;
data_[i] *= gain;
}
}
readPoint_ += bytes;
if ( readPoint_ == bufferBytes_ )
readPoint_ = 0;
bytesFilled_ -= bytes;
if ( bytesFilled_ < 0 )
bytesFilled_ = 0;
mutex_.unlock();
return samples / data_.channels();
}
bool InetWvIn :: isConnected( void )
{
if ( bytesFilled_ > 0 || bufferCounter_ > 0 )
return true;
else
return connected_;
}
void InetWvIn :: computeFrame( void )
{
// If no connection and we've output all samples in the queue, return.
if ( !connected_ && bytesFilled_ == 0 && bufferCounter_ == 0 ) return;
if ( bufferCounter_ == 0 )
bufferCounter_ = readData();
unsigned int nChannels = lastOutputs_.channels();
long temp = (bufferFrames_ - bufferCounter_) * nChannels;
for ( unsigned int i=0; i<nChannels; i++ )
lastOutputs_[i] = data_[temp++];
bufferCounter_--;
if ( bufferCounter_ < 0 )
bufferCounter_ = 0;
return;
}

230
src/InetWvOut.cpp Normal file
View File

@@ -0,0 +1,230 @@
/***************************************************/
/*! \class InetWvOut
\brief STK internet streaming output class.
This WvOut subclass can stream data over a network via a TCP or
UDP socket connection. The data is converted to big-endian byte
order, if necessary, before being transmitted.
InetWvOut supports multi-channel data. 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 reference 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
StkFormats are permissible.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "InetWvOut.h"
#include "TcpClient.h"
#include "UdpSocket.h"
InetWvOut :: InetWvOut( unsigned long packetFrames )
: buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
{
}
InetWvOut :: InetWvOut( int port, Socket::ProtocolType protocol, std::string hostname,
unsigned int nChannels, Stk::StkFormat format, unsigned long packetFrames )
: buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
{
connect( port, protocol, hostname, nChannels, format );
}
InetWvOut :: ~InetWvOut()
{
disconnect();
if ( soket_ ) delete soket_;
if ( buffer_ ) delete [] buffer_;
}
void InetWvOut :: connect( int port, Socket::ProtocolType protocol, std::string hostname,
unsigned int nChannels, Stk::StkFormat format )
{
if ( soket_ && soket_->isValid( soket_->id() ) )
disconnect();
if ( nChannels == 0 ) {
errorString_ << "InetWvOut::connect: the channel argument (" << nChannels << ") must be greater than zero!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( format == STK_SINT8 ) dataBytes_ = 1;
else if ( format == STK_SINT16 ) dataBytes_ = 2;
else if ( format == STK_SINT32 || format == STK_FLOAT32 ) dataBytes_ = 4;
else if ( format == STK_FLOAT64 ) dataBytes_ = 8;
else {
errorString_ << "InetWvOut::connect: unknown data type specified (" << format << ").";
handleError( StkError::FUNCTION_ARGUMENT );
}
dataType_ = format;
if ( protocol == Socket::PROTO_TCP ) {
soket_ = new TcpClient( port, hostname );
}
else {
// For UDP sockets, the sending and receiving sockets cannot have
// the same port number. Since the port argument corresponds to
// the destination port, we will associate this socket instance
// with a different port number (arbitrarily determined as port -
// 1).
UdpSocket *socket = new UdpSocket( port - 1 );
socket->setDestination( port, hostname );
soket_ = (Socket *) socket;
}
// Allocate new memory if necessary.
data_.resize( bufferFrames_, nChannels );
unsigned long bufferBytes = dataBytes_ * bufferFrames_ * nChannels;
if ( bufferBytes > bufferBytes_ ) {
if ( buffer_) delete [] buffer_;
buffer_ = (char *) new char[ bufferBytes ];
bufferBytes_ = bufferBytes;
}
frameCounter_ = 0;
bufferIndex_ = 0;
iData_ = 0;
}
void InetWvOut :: disconnect(void)
{
if ( soket_ ) {
writeData( bufferIndex_ );
soket_->close( soket_->id() );
delete soket_;
soket_ = 0;
}
}
void InetWvOut :: writeData( unsigned long frames )
{
unsigned long samples = frames * data_.channels();
if ( dataType_ == STK_SINT8 ) {
signed char *ptr = (signed char *) buffer_;
for ( unsigned long k=0; k<samples; k++ ) {
this->clipTest( data_[k] );
*ptr++ = (signed char) (data_[k] * 127.0);
}
}
else if ( dataType_ == STK_SINT16 ) {
SINT16 *ptr = (SINT16 *) buffer_;
for ( unsigned long k=0; k<samples; k++ ) {
this->clipTest( data_[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<samples; k++ ) {
this->clipTest( data_[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<samples; k++ ) {
this->clipTest( data_[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<samples; k++ ) {
this->clipTest( data_[k] );
*ptr = (FLOAT64) data_[k];
#ifdef __LITTLE_ENDIAN__
swap64 ((unsigned char *)ptr);
#endif
ptr++;
}
}
long bytes = dataBytes_ * samples;
if ( soket_->writeBuffer( (const void *)buffer_, bytes, 0 ) < 0 ) {
errorString_ << "InetWvOut: connection to socket server failed!";
handleError( StkError::PROCESS_SOCKET );
}
}
void InetWvOut :: incrementFrame( void )
{
frameCounter_++;
bufferIndex_++;
if ( bufferIndex_ == bufferFrames_ ) {
writeData( bufferFrames_ );
bufferIndex_ = 0;
iData_ = 0;
}
}
void InetWvOut :: computeSample( const StkFloat sample )
{
if ( !soket_ || !soket_->isValid( soket_->id() ) ) return;
unsigned int nChannels = data_.channels();
StkFloat input = sample;
clipTest( input );
for ( unsigned int j=0; j<nChannels; j++ )
data_[iData_++] = input;
this->incrementFrame();
}
void InetWvOut :: computeFrames( const StkFrames& frames )
{
if ( !soket_ || !soket_->isValid( soket_->id() ) ) return;
if ( data_.channels() != frames.channels() ) {
errorString_ << "InetWvOut::computeFrames(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
unsigned int j, nChannels = data_.channels();
if ( nChannels == 1 || frames.interleaved() ) {
unsigned int iFrames = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[iFrames++];
clipTest( data_[iData_++] );
}
this->incrementFrame();
}
}
else { // non-interleaved frames
unsigned long hop = frames.frames();
unsigned int index;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
index = i;
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[index];
clipTest( data_[iData_++] );
index += hop;
}
this->incrementFrame();
}
}
}

View File

@@ -5,7 +5,7 @@
This class provides a common interface for
all STK instruments.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -41,18 +41,15 @@ StkFloat Instrmnt :: lastOutRight(void) const
return 0.5 * lastOutput_;
}
StkFloat *Instrmnt :: tick(StkFloat *vector, unsigned int vectorSize)
StkFloat Instrmnt :: tick( void )
{
for (unsigned int i=0; i<vectorSize; i++)
vector[i] = tick();
return vector;
return computeSample();
}
StkFrames& Instrmnt :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "Instrmnt::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
if ( channel >= frames.channels() ) {
errorString_ << "Instrmnt::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
@@ -62,16 +59,16 @@ StkFrames& Instrmnt :: tick( StkFrames& frames, unsigned int channel )
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick();
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[iStart + i] = tick();
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = tick();
}
return frames;

View File

@@ -10,7 +10,7 @@
filters, and two decorrelation delay lines in
parallel at the output.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -78,7 +78,7 @@ void JCRev :: setT60( StkFloat T60 )
combCoefficient_[i] = pow(10.0, (-3.0 * combDelays_[i].getDelay() / (T60 * Stk::sampleRate())));
}
StkFloat JCRev :: tick(StkFloat input)
StkFloat JCRev :: computeSample(StkFloat input)
{
StkFloat temp, temp0, temp1, temp2, temp3, temp4, temp5, temp6;
StkFloat filtout;
@@ -121,13 +121,3 @@ StkFloat JCRev :: tick(StkFloat input)
return Effect::lastOut();
}
StkFloat *JCRev :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Effect::tick( vector, vectorSize );
}
StkFrames& JCRev :: tick( StkFrames& frames, unsigned int channel )
{
return Effect::tick( frames, channel );
}

View File

@@ -9,7 +9,7 @@
Consult Fletcher and Rossing, Karjalainen,
Cook, and others for more information.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -23,7 +23,7 @@ JetTable :: ~JetTable()
{
}
StkFloat JetTable :: tick( StkFloat input )
StkFloat JetTable :: computeSample( StkFloat input )
{
// Perform "table lookup" using a polynomial
// calculation (x^3 - x), which approximates
@@ -37,13 +37,3 @@ StkFloat JetTable :: tick( StkFloat input )
lastOutput_ = (StkFloat) -1.0;
return lastOutput_;
}
StkFloat *JetTable :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Function::tick( vector, vectorSize );
}
StkFrames& JetTable :: tick( StkFrames& frames, unsigned int channel )
{
return Function::tick( frames, channel );
}

View File

@@ -6,14 +6,14 @@ RM = /bin/rm
OBJECT_PATH = @object_path@
vpath %.o $(OBJECT_PATH)
OBJECTS = Stk.o Generator.o Noise.o SubNoise.o \
Envelope.o ADSR.o Asymp.o Modulate.o SingWave.o \
WvIn.o WaveLoop.o WvOut.o \
OBJECTS = Stk.o Generator.o Noise.o SubNoise.o Blit.o BlitSaw.o BlitSquare.o \
Envelope.o ADSR.o Asymp.o Modulate.o SingWave.o SineWave.o Granulate.o \
FileRead.o FileWrite.o WvIn.o FileWvIn.o WaveLoop.o WvOut.o FileWvOut.o \
Filter.o OneZero.o OnePole.o PoleZero.o TwoZero.o TwoPole.o \
BiQuad.o FormSwep.o Delay.o DelayL.o DelayA.o \
Effect.o PRCRev.o JCRev.o NRev.o \
Chorus.o Echo.o PitShift.o \
Function.o Table.o ReedTable.o JetTable.o BowTable.o \
Function.o ReedTable.o JetTable.o BowTable.o \
Voicer.o Vector3D.o Sphere.o \
\
Instrmnt.o Clarinet.o BlowHole.o Saxofony.o Flute.o Brass.o BlowBotl.o \
@@ -42,7 +42,7 @@ CFLAGS += @warn@ $(INCLUDE)
REALTIME = @realtime@
ifeq ($(REALTIME),yes)
OBJECTS += RtMidi.o RtAudio.o RtWvOut.o RtWvIn.o RtDuplex.o TcpWvOut.o TcpWvIn.o Thread.o Mutex.o Socket.o
OBJECTS += RtMidi.o RtAudio.o RtWvOut.o RtWvIn.o RtDuplex.o InetWvOut.o InetWvIn.o Thread.o Mutex.o Socket.o TcpClient.o TcpServer.o UdpSocket.o
DEFS += @audio_apis@
endif

View File

@@ -23,7 +23,7 @@
- String Detuning = 1
- Microphone Position = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -34,18 +34,18 @@ Mandolin :: Mandolin(StkFloat lowestFrequency)
: PluckTwo(lowestFrequency)
{
// Concatenate the STK rawwave path to the rawwave files
soundfile_[0] = new WvIn( (Stk::rawwavePath() + "mand1.raw").c_str(), true );
soundfile_[1] = new WvIn( (Stk::rawwavePath() + "mand2.raw").c_str(), true );
soundfile_[2] = new WvIn( (Stk::rawwavePath() + "mand3.raw").c_str(), true );
soundfile_[3] = new WvIn( (Stk::rawwavePath() + "mand4.raw").c_str(), true );
soundfile_[4] = new WvIn( (Stk::rawwavePath() + "mand5.raw").c_str(), true );
soundfile_[5] = new WvIn( (Stk::rawwavePath() + "mand6.raw").c_str(), true );
soundfile_[6] = new WvIn( (Stk::rawwavePath() + "mand7.raw").c_str(), true );
soundfile_[7] = new WvIn( (Stk::rawwavePath() + "mand8.raw").c_str(), true );
soundfile_[8] = new WvIn( (Stk::rawwavePath() + "mand9.raw").c_str(), true );
soundfile_[9] = new WvIn( (Stk::rawwavePath() + "mand10.raw").c_str(), true );
soundfile_[10] = new WvIn( (Stk::rawwavePath() + "mand11.raw").c_str(), true );
soundfile_[11] = new WvIn( (Stk::rawwavePath() + "mand12.raw").c_str(), true );
soundfile_[0] = new FileWvIn( (Stk::rawwavePath() + "mand1.raw").c_str(), true );
soundfile_[1] = new FileWvIn( (Stk::rawwavePath() + "mand2.raw").c_str(), true );
soundfile_[2] = new FileWvIn( (Stk::rawwavePath() + "mand3.raw").c_str(), true );
soundfile_[3] = new FileWvIn( (Stk::rawwavePath() + "mand4.raw").c_str(), true );
soundfile_[4] = new FileWvIn( (Stk::rawwavePath() + "mand5.raw").c_str(), true );
soundfile_[5] = new FileWvIn( (Stk::rawwavePath() + "mand6.raw").c_str(), true );
soundfile_[6] = new FileWvIn( (Stk::rawwavePath() + "mand7.raw").c_str(), true );
soundfile_[7] = new FileWvIn( (Stk::rawwavePath() + "mand8.raw").c_str(), true );
soundfile_[8] = new FileWvIn( (Stk::rawwavePath() + "mand9.raw").c_str(), true );
soundfile_[9] = new FileWvIn( (Stk::rawwavePath() + "mand10.raw").c_str(), true );
soundfile_[10] = new FileWvIn( (Stk::rawwavePath() + "mand11.raw").c_str(), true );
soundfile_[11] = new FileWvIn( (Stk::rawwavePath() + "mand12.raw").c_str(), true );
mic_ = 0;
dampTime_ = 0;
@@ -120,7 +120,7 @@ void Mandolin :: setBodySize(StkFloat size)
soundfile_[i]->setRate( rate );
}
StkFloat Mandolin :: tick()
StkFloat Mandolin :: computeSample()
{
StkFloat temp = 0.0;
if ( !waveDone_ ) {
@@ -150,16 +150,6 @@ StkFloat Mandolin :: tick()
return lastOutput_;
}
StkFloat *Mandolin :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Mandolin :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Mandolin :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

View File

@@ -241,7 +241,7 @@ void Mesh2D :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Mesh2D :: tick(StkFloat input)
StkFloat Mesh2D :: inputTick( StkFloat input )
{
if ( counter_ & 1 ) {
vxp1_[xInput_][yInput_] += input;
@@ -258,7 +258,7 @@ StkFloat Mesh2D :: tick(StkFloat input)
return lastOutput_;
}
StkFloat Mesh2D :: tick()
StkFloat Mesh2D :: computeSample()
{
lastOutput_ = ((counter_ & 1) ? this->tick1() : this->tick0());
counter_++;
@@ -362,16 +362,6 @@ StkFloat Mesh2D :: tick1()
return outsamp;
}
StkFloat *Mesh2D :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Mesh2D :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Mesh2D :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

View File

@@ -28,7 +28,7 @@
This class is primarily for use in STK example programs but it is
generic enough to work in many other contexts.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -264,7 +264,7 @@ bool Messager :: startSocketInput( int port )
// Create the socket server.
try {
data_.socket = new Socket( port );
data_.socket = new TcpServer( port );
}
catch ( StkError& ) {
return false;
@@ -290,14 +290,9 @@ bool Messager :: startSocketInput( int port )
return true;
}
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOS__))
#include <sys/socket.h>
#include <sys/types.h>
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
#include <sys/time.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
THREAD_RETURN THREAD_TYPE socketHandler(void *ptr)

View File

@@ -21,7 +21,7 @@
MidiFileIn :: MidiFileIn( std::string fileName )
{
// Attempt to open the file.
file_.open( fileName.c_str(), std::ios::in );
file_.open( fileName.c_str(), std::ios::in | std::ios::binary );
if ( !file_ ) {
errorString_ << "MidiFileIn: error opening or finding file (" << fileName << ").";
handleError( StkError::FILE_NOT_FOUND );
@@ -90,7 +90,8 @@ MidiFileIn :: MidiFileIn( std::string fileName )
// code, we can initialize the "tick time" using a default tempo of
// 120 beats per minute. We will then check for tempo meta-events
// afterward.
for ( unsigned int i=0; i<nTracks_; i++ ) {
unsigned int i;
for ( i=0; i<nTracks_; i++ ) {
if ( !file_.read( chunkType, 4 ) ) goto error;
if ( strncmp( chunkType, "MTrk", 4 ) ) goto error;
if ( !file_.read( buffer, 4 ) ) goto error;
@@ -249,7 +250,8 @@ unsigned long MidiFileIn :: getNextEvent( std::vector<unsigned char> *event, uns
file_.seekg( position, std::ios_base::beg );
break;
case 0xF0 || 0xF7: // The start or continuation of a Sysex event
case 0xF0:
case 0xF7: // The start or continuation of a Sysex event
trackStatus_[track] = 0;
event->push_back( c );
position = file_.tellg();
@@ -278,7 +280,8 @@ unsigned long MidiFileIn :: getNextEvent( std::vector<unsigned char> *event, uns
}
// Read the rest of the event into the event vector.
for ( unsigned long i=0; i<bytes; i++ ) {
unsigned long i;
for ( i=0; i<bytes; i++ ) {
if ( !file_.read( (char *)&c, 1 ) ) goto error;
event->push_back( c );
}

View File

@@ -7,7 +7,7 @@
(non-sweeping BiQuad filters), where N is set
during instantiation.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -32,11 +32,8 @@ Modal :: Modal(unsigned int modes)
filters_[i]->setEqualGainZeroes();
}
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( Stk::rawwavePath() + "sinewave.raw", true );
// Set some default values.
vibrato_->setFrequency( 6.0 );
vibrato_.setFrequency( 6.0 );
vibratoGain_ = 0.0;
directGain_ = 0.0;
masterGain_ = 1.0;
@@ -50,8 +47,6 @@ Modal :: Modal(unsigned int modes)
Modal :: ~Modal()
{
delete vibrato_;
for (unsigned int i=0; i<nModes_; i++ ) {
delete filters_[i];
}
@@ -190,7 +185,7 @@ void Modal :: damp(StkFloat amplitude)
}
}
StkFloat Modal :: tick()
StkFloat Modal :: computeSample()
{
StkFloat temp = masterGain_ * onepole_.tick( wave_->tick() * envelope_.tick() );
@@ -203,20 +198,10 @@ StkFloat Modal :: tick()
if (vibratoGain_ != 0.0) {
// Calculate AM and apply to master out
temp = 1.0 + (vibrato_->tick() * vibratoGain_);
temp = 1.0 + (vibrato_.tick() * vibratoGain_);
temp2 = temp * temp2;
}
lastOutput_ = temp2;
return lastOutput_;
}
StkFloat *Modal :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Modal :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

View File

@@ -9,9 +9,9 @@
Control Change Numbers:
- Stick Hardness = 2
- Stick Position = 4
- Vibrato Gain = 1
- Vibrato Gain = 8
- Vibrato Frequency = 11
- Direct Stick Mix = 8
- Direct Stick Mix = 1
- Volume = 128
- Modal Presets = 16
- Marimba = 0
@@ -24,19 +24,19 @@
- Two Fixed = 7
- Clump = 8
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "ModalBar.h"
#include "SKINI.msg"
#include <math.h>
#include <cmath>
ModalBar :: ModalBar()
: Modal()
{
// Concatenate the STK rawwave path to the rawwave file
wave_ = new WvIn( (Stk::rawwavePath() + "marmstk1.raw").c_str(), true );
wave_ = new FileWvIn( (Stk::rawwavePath() + "marmstk1.raw").c_str(), true );
wave_->setRate( 0.5 * 22050.0 / Stk::sampleRate() );
// Set the resonances for preset 0 (marimba).
@@ -177,11 +177,11 @@ void ModalBar :: controlChange(int number, StkFloat value)
else if (number == __SK_ProphesyRibbon_) // 16
this->setPreset((int) value);
else if (number == __SK_Balance_) // 8
directGain_ = norm;
else if (number == __SK_ModWheel_) // 1
vibratoGain_ = norm * 0.3;
else if (number == __SK_ModWheel_) // 1
directGain_ = norm;
else if (number == __SK_ModFrequency_) // 11
vibrato_->setFrequency( norm * 12.0 );
vibrato_.setFrequency( norm * 12.0 );
else if (number == __SK_AfterTouch_Cont_) // 128
envelope_.setTarget( norm );
else {

View File

@@ -6,7 +6,7 @@
modulations to give a nice, natural human
modulation function.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -14,9 +14,7 @@
Modulate :: Modulate()
{
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
vibrato_->setFrequency( 6.0 );
vibrato_.setFrequency( 6.0 );
vibratoGain_ = 0.04;
noise_.setRate( 330 );
@@ -28,7 +26,6 @@ Modulate :: Modulate()
Modulate :: ~Modulate()
{
delete vibrato_;
}
void Modulate :: reset()
@@ -38,7 +35,7 @@ void Modulate :: reset()
void Modulate :: setVibratoRate(StkFloat rate)
{
vibrato_->setFrequency( rate );
vibrato_.setFrequency( rate );
}
void Modulate :: setVibratoGain(StkFloat gain)
@@ -52,21 +49,11 @@ void Modulate :: setRandomGain(StkFloat gain)
filter_.setGain( randomGain_ );
}
StkFloat Modulate :: tick()
StkFloat Modulate :: computeSample()
{
// Compute periodic and random modulations.
lastOutput_ = vibratoGain_ * vibrato_->tick();
lastOutput_ = vibratoGain_ * vibrato_.tick();
lastOutput_ += filter_.tick( noise_.tick() );
return lastOutput_;
}
StkFloat *Modulate :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Generator::tick( vector, vectorSize );
}
StkFrames& Modulate :: tick( StkFrames& frames, unsigned int channel )
{
return Generator::tick( frames, channel );
}

View File

@@ -14,7 +14,7 @@
- Vibrato Gain = 1
- Gain = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -24,7 +24,7 @@
Moog :: Moog()
{
// Concatenate the STK rawwave path to the rawwave file
attacks_.push_back( new WvIn( (Stk::rawwavePath() + "mandpluk.raw").c_str(), true ) );
attacks_.push_back( new FileWvIn( (Stk::rawwavePath() + "mandpluk.raw").c_str(), true ) );
loops_.push_back ( new WaveLoop( (Stk::rawwavePath() + "impuls20.raw").c_str(), true ) );
loops_.push_back ( new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true ) ); // vibrato
loops_[1]->setFrequency( 6.122 );
@@ -92,7 +92,7 @@ void Moog :: setModulationDepth(StkFloat mDepth)
modDepth_ = mDepth * 0.5;
}
StkFloat Moog :: tick()
StkFloat Moog :: computeSample()
{
StkFloat temp;
@@ -110,16 +110,6 @@ StkFloat Moog :: tick()
return lastOutput_ * 3.0;
}
StkFloat *Moog :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Moog :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Moog :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

View File

@@ -7,7 +7,7 @@
systems, the pthread library is used. Under
Windows, critical sections are used.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/

View File

@@ -12,7 +12,7 @@
filters in parallel with corresponding right
and left outputs.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -69,7 +69,7 @@ void NRev :: setT60( StkFloat T60 )
combCoefficient_[i] = pow(10.0, (-3.0 * combDelays_[i].getDelay() / (T60 * Stk::sampleRate())));
}
StkFloat NRev :: tick(StkFloat input)
StkFloat NRev :: computeSample(StkFloat input)
{
StkFloat temp, temp0, temp1, temp2, temp3;
int i;
@@ -112,15 +112,4 @@ StkFloat NRev :: tick(StkFloat input)
lastOutput_[1] += temp;
return Effect::lastOut();
}
StkFloat *NRev :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Effect::tick( vector, vectorSize );
}
StkFrames& NRev :: tick( StkFrames& frames, unsigned int channel )
{
return Effect::tick( frames, channel );
}

View File

@@ -6,7 +6,7 @@
C rand() function. The quality of the rand()
function varies from one OS to another.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -40,20 +40,10 @@ void Noise :: setSeed( unsigned int seed )
srand( seed );
}
StkFloat Noise :: tick()
StkFloat Noise :: computeSample()
{
lastOutput_ = (StkFloat) (2.0 * rand() / (RAND_MAX + 1.0) );
lastOutput_ -= 1.0;
return lastOutput_;
}
StkFloat *Noise :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Generator::tick( vector, vectorSize );
}
StkFrames& Noise :: tick( StkFrames& frames, unsigned int channel )
{
return Generator::tick( frames, channel );
}

View File

@@ -8,7 +8,7 @@
the real axis of the z-plane while maintaining
a constant peak filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -82,20 +82,15 @@ StkFloat OnePole :: lastOut(void) const
return Filter::lastOut();
}
StkFloat OnePole :: tick(StkFloat sample)
StkFloat OnePole :: tick( StkFloat input )
{
inputs_[0] = gain_ * sample;
inputs_[0] = gain_ * input;
outputs_[0] = b_[0] * inputs_[0] - a_[1] * outputs_[1];
outputs_[1] = outputs_[0];
return outputs_[0];
}
StkFloat *OnePole :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Filter::tick( vector, vectorSize );
}
StkFrames& OnePole :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );

View File

@@ -8,7 +8,7 @@
along the real axis of the z-plane while
maintaining a constant filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -81,20 +81,15 @@ StkFloat OneZero :: lastOut(void) const
return Filter::lastOut();
}
StkFloat OneZero :: tick(StkFloat sample)
StkFloat OneZero :: tick( StkFloat input )
{
inputs_[0] = gain_ * sample;
inputs_[0] = gain_ * input;
outputs_[0] = b_[1] * inputs_[1] + b_[0] * inputs_[0];
inputs_[1] = inputs_[0];
return outputs_[0];
}
StkFloat *OneZero :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Filter::tick( vector, vectorSize );
}
StkFrames& OneZero :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );

View File

@@ -10,7 +10,7 @@
two series allpass units and two parallel comb
filters.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -68,7 +68,7 @@ void PRCRev :: setT60( StkFloat T60 )
combCoefficient_[1] = pow(10.0, (-3.0 * combDelays_[1].getDelay() / (T60 * Stk::sampleRate())));
}
StkFloat PRCRev :: tick(StkFloat input)
StkFloat PRCRev :: computeSample(StkFloat input)
{
StkFloat temp, temp0, temp1, temp2, temp3;
@@ -94,15 +94,5 @@ StkFloat PRCRev :: tick(StkFloat input)
lastOutput_[1] += temp;
return Effect::lastOut();
}
StkFloat *PRCRev :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Effect::tick( vector, vectorSize );
}
StkFrames& PRCRev :: tick( StkFrames& frames, unsigned int channel )
{
return Effect::tick( frames, channel );
}

View File

@@ -22,7 +22,7 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -78,11 +78,11 @@ void PercFlut :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat PercFlut :: tick()
StkFloat PercFlut :: computeSample()
{
register StkFloat temp;
temp = vibrato_->tick() * modDepth_ * 0.2;
temp = vibrato_.tick() * modDepth_ * 0.2;
waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[0]);
waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[1]);
waves_[2]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[2]);
@@ -104,13 +104,3 @@ StkFloat PercFlut :: tick()
lastOutput_ = temp * 0.5;
return lastOutput_;
}
StkFloat *PercFlut :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& PercFlut :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

View File

@@ -6,7 +6,7 @@
set of 32 static phoneme formant parameters
and provide access to those values.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/

View File

@@ -5,12 +5,12 @@
This class implements a simple pitch shifter
using delay lines.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "PitShift.h"
#include <math.h>
#include <cmath>
const int maxDelay = 5024;
@@ -55,7 +55,7 @@ void PitShift :: setShift(StkFloat shift)
}
}
StkFloat PitShift :: tick(StkFloat input)
StkFloat PitShift :: computeSample(StkFloat input)
{
// Calculate the two delay length values, keeping them within the
// range 12 to maxDelay-12.
@@ -83,15 +83,6 @@ StkFloat PitShift :: tick(StkFloat input)
lastOutput_[0] *= effectMix_;
lastOutput_[0] += (1.0 - effectMix_) * input;
lastOutput_[1] = lastOutput_[0];
return lastOutput_[0];
}
StkFloat *PitShift :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Effect::tick( vector, vectorSize );
}
StkFrames& PitShift :: tick( StkFrames& frames, unsigned int channel )
{
return Effect::tick( frames, channel );
}

View File

@@ -14,7 +14,7 @@
use possibly subject to patents held by
Stanford University, Yamaha, and others.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/

View File

@@ -13,7 +13,7 @@
Stanford, bearing the names of Karplus and/or
Strong.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -112,20 +112,10 @@ void Plucked :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Plucked :: tick()
StkFloat Plucked :: computeSample()
{
// Here's the whole inner loop of the instrument!!
lastOutput_ = delayLine_.tick( loopFilter_.tick( delayLine_.lastOut() * loopGain_ ) );
lastOutput_ *= 3.0;
return lastOutput_;
}
StkFloat *Plucked :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Plucked :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

View File

@@ -8,7 +8,7 @@
filter with a given coefficient. Another
method is provided to create a DC blocking filter.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -79,9 +79,9 @@ StkFloat PoleZero :: lastOut(void) const
return Filter::lastOut();
}
StkFloat PoleZero :: tick(StkFloat sample)
StkFloat PoleZero :: tick( StkFloat input )
{
inputs_[0] = gain_ * sample;
inputs_[0] = gain_ * input;
outputs_[0] = b_[0] * inputs_[0] + b_[1] * inputs_[1] - a_[1] * outputs_[1];
inputs_[1] = inputs_[0];
outputs_[1] = outputs_[0];
@@ -89,11 +89,6 @@ StkFloat PoleZero :: tick(StkFloat sample)
return outputs_[0];
}
StkFloat *PoleZero :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Filter::tick( vector, vectorSize );
}
StkFrames& PoleZero :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );

View File

@@ -13,7 +13,7 @@
Smith (1986), Hirschman, Cook, Scavone, and
others for more information.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -39,7 +39,7 @@ void ReedTable :: setSlope(StkFloat slope)
slope_ = slope;
}
StkFloat ReedTable :: tick(StkFloat input)
StkFloat ReedTable :: computeSample(StkFloat input)
{
// The input is differential pressure across the reed.
lastOutput_ = offset_ + (slope_ * input);
@@ -55,12 +55,3 @@ StkFloat ReedTable :: tick(StkFloat input)
return lastOutput_;
}
StkFloat *ReedTable :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Function::tick( vector, vectorSize );
}
StkFrames& ReedTable :: tick( StkFrames& frames, unsigned int channel )
{
return Function::tick( frames, channel );
}

View File

@@ -13,7 +13,7 @@
- Zero Radii = 1
- Envelope Gain = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -112,23 +112,13 @@ void Resonate :: setEqualGainZeroes()
filter_.setEqualGainZeroes();
}
StkFloat Resonate :: tick()
StkFloat Resonate :: computeSample()
{
lastOutput_ = filter_.tick( noise_.tick() );
lastOutput_ *= adsr_.tick();
return lastOutput_;
}
StkFloat *Resonate :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Resonate :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Resonate :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

View File

@@ -26,7 +26,7 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -56,14 +56,14 @@ Rhodey :: Rhodey()
adsr_[3]->setAllTimes( 0.001, 0.25, 0.0, 0.04);
twozero_.setGain( 1.0 );
}
}
Rhodey :: ~Rhodey()
{
}
void Rhodey :: setFrequency(StkFloat frequency)
{
{
baseFrequency_ = frequency * 2.0;
for (unsigned int i=0; i<nOperators_; i++ )
@@ -85,7 +85,7 @@ void Rhodey :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat Rhodey :: tick()
StkFloat Rhodey :: computeSample()
{
StkFloat temp, temp2;
@@ -102,19 +102,9 @@ StkFloat Rhodey :: tick()
temp += control2_ * 0.5 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
// Calculate amplitude modulation and apply it to output.
temp2 = vibrato_->tick() * modDepth_;
temp2 = vibrato_.tick() * modDepth_;
temp = temp * (1.0 + temp2);
lastOutput_ = temp * 0.5;
return lastOutput_;
}
StkFloat *Rhodey :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Rhodey :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@
methods, which take/return pointers to
multi-channel sample frames.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/

View File

@@ -8,7 +8,7 @@
RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
RtMidi: realtime MIDI i/o C++ classes
Copyright (c) 2003-2004 Gary P. Scavone
Copyright (c) 2003-2005 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
@@ -35,7 +35,7 @@
*/
/**********************************************************************/
// RtMidi: Version 1.0.2, 21 September 2004
// RtMidi: Version 1.0.4, 14 October 2005
#include "RtMidi.h"
#include <sstream>
@@ -270,6 +270,14 @@ void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef
else size = 3;
}
else if ( status == 0xF3 ) size = 2;
else if ( status == 0xF8 ) {
size = 1;
if ( data->ignoreFlags & 0x02 ) {
// A MIDI timing tick message and we're ignoring it.
size = 0;
iByte += 3;
}
}
else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
// A MIDI active sensing message and we're ignoring it.
size = 0;
@@ -620,8 +628,10 @@ void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
#if defined(__LINUX_ALSASEQ__)
// The ALSA Sequencer API is based on the use of a callback function for
// MIDI input. We convert the system specific time stamps to delta
// time values.
// MIDI input.
//
// Thanks to Pedro Lopez-Cabanillas for help with the ALSA sequencer
// time stamps and other assorted fixes!!!
#include <pthread.h>
#include <sys/time.h>
@@ -640,6 +650,7 @@ struct AlsaMidiData {
unsigned char *buffer;
pthread_t thread;
unsigned long long lastTime;
int queue_id; // an input queue is needed to get timestamped events
};
#define PORT_TYPE( pinfo, bits ) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
@@ -656,11 +667,10 @@ extern "C" void *alsaMidiHandler( void *ptr )
long nBytes;
unsigned long long time, lastTime;
unsigned char lastStatus = 0;
bool continueSysex = false;
RtMidiIn::MidiMessage message;
snd_seq_event_t *ev;
struct timeval tv;
int result;
apiData->bufferSize = 32;
result = snd_midi_event_new( 0, &apiData->coder );
@@ -669,13 +679,14 @@ extern "C" void *alsaMidiHandler( void *ptr )
std::cerr << "\nRtMidiIn::alsaMidiHandler: error initializing MIDI event parser!\n\n";
return 0;
}
unsigned char *buffer = (unsigned char *) malloc(apiData->bufferSize);
unsigned char *buffer = (unsigned char *) malloc( apiData->bufferSize );
if ( buffer == NULL ) {
data->doInput = false;
std::cerr << "\nRtMidiIn::alsaMidiHandler: error initializing buffer memory!\n\n";
return 0;
}
snd_midi_event_init( apiData->coder );
snd_midi_event_no_status( apiData->coder, 1 ); // suppress running status messages
while ( data->doInput ) {
@@ -699,7 +710,7 @@ extern "C" void *alsaMidiHandler( void *ptr )
// This is a bit weird, but we now have to decode an ALSA MIDI
// event (back) into MIDI bytes. We'll ignore non-MIDI types.
message.bytes.clear();
switch (ev->type) {
switch ( ev->type ) {
case SND_SEQ_EVENT_PORT_SUBSCRIBED:
#if defined(__RTMIDI_DEBUG__)
@@ -715,6 +726,9 @@ extern "C" void *alsaMidiHandler( void *ptr )
case SND_SEQ_EVENT_QFRAME: // MIDI time code
if ( data->ignoreFlags & 0x02 ) break;
case SND_SEQ_EVENT_TICK: // MIDI timing tick
if ( data->ignoreFlags & 0x02 ) break;
case SND_SEQ_EVENT_SENSING: // Active sensing
if ( data->ignoreFlags & 0x04 ) break;
@@ -722,8 +736,8 @@ extern "C" void *alsaMidiHandler( void *ptr )
if ( (data->ignoreFlags & 0x01) ) break;
if ( ev->data.ext.len > apiData->bufferSize ) {
apiData->bufferSize = ev->data.ext.len;
free(buffer);
buffer = (unsigned char *) malloc(apiData->bufferSize);
free( buffer );
buffer = (unsigned char *) malloc( apiData->bufferSize );
if ( buffer == NULL ) {
data->doInput = false;
std::cerr << "\nRtMidiIn::alsaMidiHandler: error resizing buffer memory!\n\n";
@@ -739,25 +753,41 @@ extern "C" void *alsaMidiHandler( void *ptr )
#endif
break;
}
message.bytes.assign( buffer, &buffer[nBytes] );
// Save last status byte in case of running status.
if ( message.bytes[0] & 0x80 ) lastStatus = message.bytes[0];
else if ( lastStatus ) message.bytes.insert( message.bytes.begin(), lastStatus );
// I found the ALSA sequencer documentation to be very inadequate,
// especially regarding timestamps. So, I ignore the event
// timestamp and use system time to determine ours.
// The ALSA sequencer has a maximum buffer size for MIDI sysex
// events of 256 bytes. If a device sends sysex messages larger
// than this, they are segmented into 256 byte chunks. So,
// we'll watch for this and concatenate sysex chunks into a
// single sysex message if necessary.
if ( !continueSysex )
message.bytes.assign( buffer, &buffer[nBytes] );
else
message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
if ( ev->type == SND_SEQ_EVENT_SYSEX && message.bytes.back() == 0xF7 )
continueSysex = false;
else {
continueSysex = true;
break;
}
// Calculate the time stamp:
message.timeStamp = 0.0;
(void)gettimeofday(&tv, (struct timezone *)NULL);
time = (tv.tv_sec * 1000000) + tv.tv_usec;
// Method 1: Use the system time.
//(void)gettimeofday(&tv, (struct timezone *)NULL);
//time = (tv.tv_sec * 1000000) + tv.tv_usec;
// Method 2: Use the ALSA sequencer event time data.
// (thanks to Pedro Lopez-Cabanillas!).
time = ( ev->time.time.tv_sec * 1000000 ) + ( ev->time.time.tv_nsec/1000 );
lastTime = time;
time -= apiData->lastTime;
apiData->lastTime = lastTime;
if ( data->firstMessage == true )
data->firstMessage = false;
else {
else
message.timeStamp = time * 0.000001;
}
}
snd_seq_free_event(ev);
@@ -776,6 +806,7 @@ extern "C" void *alsaMidiHandler( void *ptr )
}
}
if ( buffer ) free( buffer );
snd_midi_event_free( apiData->coder );
apiData->coder = 0;
return 0;
@@ -785,7 +816,7 @@ void RtMidiIn :: initialize( void )
{
// Set up the ALSA sequencer client.
snd_seq_t *seq;
int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_INPUT, 0);
int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
if ( result < 0 ) {
errorString_ = "RtMidiIn::initialize: error creating ALSA sequencer input client object.";
error( RtError::DRIVER_ERROR );
@@ -800,6 +831,16 @@ void RtMidiIn :: initialize( void )
data->vport = -1;
apiData_ = (void *) data;
inputData_.apiData = (void *) data;
// Create the input queue
data->queue_id = snd_seq_alloc_named_queue(seq, "RtMidi Queue");
// Set arbitrary tempo (mm=100) and resolution (240)
snd_seq_queue_tempo_t *qtempo;
snd_seq_queue_tempo_alloca(&qtempo);
snd_seq_queue_tempo_set_tempo(qtempo, 600000);
snd_seq_queue_tempo_set_ppq(qtempo, 240);
snd_seq_set_queue_tempo(data->seq, data->queue_id, qtempo);
snd_seq_drain_output(data->seq);
}
// This function is used to count or get the pinfo structure for a given port number.
@@ -859,9 +900,21 @@ void RtMidiIn :: openPort( unsigned int portNumber )
sender.port = snd_seq_port_info_get_port( pinfo );
receiver.client = snd_seq_client_id( data->seq );
if ( data->vport < 0 ) {
data->vport = snd_seq_create_simple_port( data->seq, "RtMidi Input",
SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_MIDI_GENERIC );
snd_seq_port_info_set_client( pinfo, 0 );
snd_seq_port_info_set_port( pinfo, 0 );
snd_seq_port_info_set_capability( pinfo,
SND_SEQ_PORT_CAP_WRITE |
SND_SEQ_PORT_CAP_SUBS_WRITE );
snd_seq_port_info_set_type( pinfo,
SND_SEQ_PORT_TYPE_MIDI_GENERIC |
SND_SEQ_PORT_TYPE_APPLICATION );
snd_seq_port_info_set_midi_channels(pinfo, 16);
snd_seq_port_info_set_timestamping(pinfo, 1);
snd_seq_port_info_set_timestamp_real(pinfo, 1);
snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
snd_seq_port_info_set_name(pinfo, "RtMidi Input");
data->vport = snd_seq_create_port(data->seq, pinfo);
if ( data->vport < 0 ) {
errorString_ = "RtMidiIn::openPort: ALSA error creating input port.";
error( RtError::DRIVER_ERROR );
@@ -874,19 +927,20 @@ void RtMidiIn :: openPort( unsigned int portNumber )
snd_seq_port_subscribe_malloc( &data->subscription );
snd_seq_port_subscribe_set_sender(data->subscription, &sender);
snd_seq_port_subscribe_set_dest(data->subscription, &receiver);
snd_seq_port_subscribe_set_time_update(data->subscription, 1);
snd_seq_port_subscribe_set_time_real(data->subscription, 1);
if ( snd_seq_subscribe_port(data->seq, data->subscription) ) {
errorString_ = "RtMidiIn::openPort: ALSA error making port connection.";
error( RtError::DRIVER_ERROR );
}
if ( inputData_.doInput == false ) {
// Start the input queue
snd_seq_start_queue( data->seq, data->queue_id, NULL );
snd_seq_drain_output( data->seq );
// Start our MIDI input thread.
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setschedpolicy(&attr, SCHED_RR);
pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
inputData_.doInput = true;
int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
@@ -907,9 +961,20 @@ void RtMidiIn :: openVirtualPort()
{
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
if ( data->vport < 0 ) {
data->vport = snd_seq_create_simple_port( data->seq, "RtMidi Input",
SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_MIDI_GENERIC );
snd_seq_port_info_t *pinfo;
snd_seq_port_info_alloca( &pinfo );
snd_seq_port_info_set_capability( pinfo,
SND_SEQ_PORT_CAP_WRITE |
SND_SEQ_PORT_CAP_SUBS_WRITE );
snd_seq_port_info_set_type( pinfo,
SND_SEQ_PORT_TYPE_MIDI_GENERIC |
SND_SEQ_PORT_TYPE_APPLICATION );
snd_seq_port_info_set_midi_channels(pinfo, 16);
snd_seq_port_info_set_timestamping(pinfo, 1);
snd_seq_port_info_set_timestamp_real(pinfo, 1);
snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
snd_seq_port_info_set_name(pinfo, "RtMidi Input");
data->vport = snd_seq_create_port(data->seq, pinfo);
if ( data->vport < 0 ) {
errorString_ = "RtMidiIn::openVirtualPort: ALSA error creating virtual port.";
@@ -918,11 +983,14 @@ void RtMidiIn :: openVirtualPort()
}
if ( inputData_.doInput == false ) {
// Start the input queue
snd_seq_start_queue( data->seq, data->queue_id, NULL );
snd_seq_drain_output( data->seq );
// Start our MIDI input thread.
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setschedpolicy(&attr, SCHED_RR);
pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
inputData_.doInput = true;
int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
@@ -943,6 +1011,9 @@ void RtMidiIn :: closePort( void )
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
snd_seq_unsubscribe_port( data->seq, data->subscription );
snd_seq_port_subscribe_free( data->subscription );
// Stop the input queue
snd_seq_stop_queue( data->seq, data->queue_id, NULL );
snd_seq_drain_output( data->seq );
connected_ = false;
}
}
@@ -961,6 +1032,7 @@ RtMidiIn :: ~RtMidiIn()
// Cleanup.
if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
snd_seq_free_queue( data->seq, data->queue_id );
snd_seq_close( data->seq );
delete data;
}
@@ -1316,6 +1388,12 @@ extern "C" void *irixMidiHandler( void *ptr )
}
}
else if ( status == 0xF3 ) size = 2;
else if ( status == 0xF8 ) {
if ( !(data->ignoreFlags & 0x02) ) {
// A MIDI timing tick message and we're not ignoring it.
size = 1;
}
}
else if ( status == 0xFE ) { // MIDI active sensing
if ( !(data->ignoreFlags & 0x04) )
size = 1;
@@ -1657,6 +1735,10 @@ static void CALLBACK midiInputCallback( HMIDIOUT hmin,
nBytes = 3;
}
else if ( status == 0xF3 ) nBytes = 2;
else if ( status == 0xF8 && (data->ignoreFlags & 0x02) ) {
// A MIDI timing tick message and we're ignoring it.
return;
}
else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
// A MIDI active sensing message and we're ignoring it.
return;

View File

@@ -2,68 +2,63 @@
/*! \class RtWvIn
\brief STK realtime audio (blocking) input class.
This class provides a simplified interface to
RtAudio for realtime audio input. It is a
protected subclass of WvIn.
This class provides a simplified interface to RtAudio for realtime
audio input. It is a protected subclass of WvIn. Because this
class makes use of RtAudio's blocking output routines, its
performance is less robust on systems where the audio API is
callback-based (Macintosh CoreAudio and Windows ASIO).
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.
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 references or pointers to multi-channel
sample frames.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "RtWvIn.h"
RtWvIn :: RtWvIn(int nChannels, StkFloat sampleRate, int device, int bufferFrames, int nBuffers )
RtWvIn :: RtWvIn( unsigned int nChannels, StkFloat sampleRate, int device, int bufferFrames, int nBuffers )
: stopped_( true ), bufferIndex_( 0 )
{
channels_ = nChannels;
int size = bufferFrames;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
audio_ = 0;
adc_ = 0;
try {
audio_ = new RtAudio();
adc_ = new RtAudio();
}
catch (RtError &error) {
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
}
// Now open a stream and get the buffer pointer.
// Allocate the adc and get the buffer pointer.
try {
audio_->openStream(0, 0, device, channels_, format,
(int)sampleRate, &size, nBuffers);
data_ = (StkFloat *) audio_->getStreamBuffer();
adc_->openStream( 0, 0, device, (int)nChannels, format,
(int)sampleRate, &size, nBuffers );
buffer_ = (StkFloat *) adc_->getStreamBuffer();
}
catch (RtError &error) {
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
}
bufferSize_ = size;
lastOutputs_ = (StkFloat *) new StkFloat[channels_];
for (unsigned int i=0; i<channels_; i++) lastOutputs_[i] = 0.0;
counter_ = 0;
stopped_ = true;
bufferFrames_ = size;
lastOutputs_.resize( 1, nChannels );
}
RtWvIn :: ~RtWvIn()
{
if ( !stopped_ )
audio_->stopStream();
delete audio_;
data_ = 0; // RtAudio deletes the buffer itself.
if ( !stopped_ ) adc_->stopStream();
adc_->closeStream();
delete adc_;
}
void RtWvIn :: start()
{
if ( stopped_ ) {
audio_->startStream();
adc_->startStream();
stopped_ = false;
}
}
@@ -71,68 +66,29 @@ void RtWvIn :: start()
void RtWvIn :: stop()
{
if ( !stopped_ ) {
audio_->stopStream();
adc_->stopStream();
stopped_ = true;
}
}
StkFloat RtWvIn :: lastOut(void) const
void RtWvIn :: computeFrame( void )
{
return WvIn::lastOut();
}
if ( stopped_ ) this->start();
StkFloat RtWvIn :: tick(void)
{
this->tickFrame();
return lastOut();
}
StkFloat *RtWvIn :: tick(StkFloat *vector, unsigned int vectorSize)
{
return WvIn::tick( vector, vectorSize );
}
StkFrames& RtWvIn :: tick( StkFrames& frames, unsigned int channel )
{
return WvIn::tick( frames, channel );
}
const StkFloat *RtWvIn :: lastFrame() const
{
return lastOutputs_;
}
const StkFloat *RtWvIn :: tickFrame(void)
{
if ( stopped_ )
this->start();
if (counter_ == 0) {
if ( bufferIndex_ == 0) {
try {
audio_->tickStream();
adc_->tickStream();
}
catch (RtError &error) {
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
}
}
long temp = counter_ * channels_;
for (unsigned int i=0; i<channels_; i++)
lastOutputs_[i] = data_[temp++];
long iBuffer = bufferIndex_ * lastOutputs_.size();
for (unsigned int i=0; i<lastOutputs_.size(); i++)
lastOutputs_[i] = buffer_[iBuffer++];
counter_++;
if (counter_ >= (long) bufferSize_)
counter_ = 0;
return lastOutputs_;
}
StkFloat *RtWvIn :: tickFrame(StkFloat *frameVector, unsigned int frames)
{
return WvIn::tickFrame( frameVector, frames );
}
StkFrames& RtWvIn :: tickFrame( StkFrames& frames )
{
return WvIn::tickFrame( frames );
bufferIndex_++;
if ( bufferIndex_ >= bufferFrames_ )
bufferIndex_ = 0;
}

View File

@@ -2,35 +2,34 @@
/*! \class RtWvOut
\brief STK realtime audio (blocking) output class.
This class provides a simplified interface to
RtAudio for realtime audio output. It is a
protected subclass of WvOut.
This class provides a simplified interface to RtAudio for realtime
audio output. It is a subclass of WvOut. Because this class
makes use of RtAudio's blocking output routines, its performance
is less robust on systems where the audio API is callback-based
(Macintosh CoreAudio and Windows ASIO).
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
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 take a pointer or reference to multi-channel sample
frame data.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "RtWvOut.h"
#include <iostream>
RtWvOut :: RtWvOut( unsigned int nChannels, StkFloat sampleRate, int device, int bufferFrames, int nBuffers )
: stopped_( true ), nChannels_(nChannels), bufferIndex_( 0 ), iBuffer_( 0 )
{
// We'll let RtAudio deal with channel and srate limitations.
channels_ = nChannels;
bufferSize_ = bufferFrames;
// We'll let RtAudio deal with channel and sample rate limitations.
int size = bufferFrames;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
audio_ = 0;
dac_ = 0;
try {
audio_ = new RtAudio();
dac_ = new RtAudio();
}
catch (RtError &error) {
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
@@ -38,28 +37,28 @@ RtWvOut :: RtWvOut( unsigned int nChannels, StkFloat sampleRate, int device, int
// Now open a stream and get the buffer pointer.
try {
audio_->openStream(device, (int)channels_, 0, 0, format,
(int)sampleRate, &bufferSize_, nBuffers);
dataPtr_ = (StkFloat *) audio_->getStreamBuffer();
dac_->openStream( device, (int)nChannels, 0, 0, format,
(int)sampleRate, &size, nBuffers );
buffer_ = (StkFloat *) dac_->getStreamBuffer();
}
catch (RtError &error) {
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
}
stopped_ = true;
bufferFrames_ = size;
}
RtWvOut :: ~RtWvOut()
{
if ( !stopped_ )
audio_->stopStream();
delete audio_;
if ( !stopped_ ) dac_->stopStream();
dac_->closeStream();
delete dac_;
}
void RtWvOut :: start()
{
if ( stopped_ ) {
audio_->startStream();
dac_->startStream();
stopped_ = false;
}
}
@@ -67,162 +66,80 @@ void RtWvOut :: start()
void RtWvOut :: stop()
{
if ( !stopped_ ) {
audio_->stopStream();
dac_->stopStream();
stopped_ = true;
}
}
unsigned long RtWvOut :: getFrames( void ) const
void RtWvOut :: incrementFrame( void )
{
return totalCount_;
}
frameCounter_++;
bufferIndex_++;
StkFloat RtWvOut :: getTime( void ) const
{
return (StkFloat) totalCount_ / Stk::sampleRate();
}
void RtWvOut :: tick( const StkFloat sample )
{
if ( stopped_ )
start();
StkFloat input = sample;
this->clipTest( input );
for ( unsigned int j=0; j<channels_; j++ )
dataPtr_[counter_*channels_+j] = input;
counter_++;
totalCount_++;
if ( counter_ >= (unsigned int )bufferSize_ ) {
if ( bufferIndex_ == bufferFrames_ ) {
try {
audio_->tickStream();
dac_->tickStream();
}
catch (RtError &error) {
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
}
counter_ = 0;
bufferIndex_ = 0;
iBuffer_ = 0;
}
}
void RtWvOut :: tick( const StkFloat *vector, unsigned int vectorSize )
void RtWvOut :: computeSample( const StkFloat sample )
{
for (unsigned int i=0; i<vectorSize; i++)
tick( vector[i] );
if ( stopped_ ) start();
StkFloat input = sample;
clipTest( input );
for ( unsigned int j=0; j<nChannels_; j++ )
buffer_[iBuffer_++] = input;
this->incrementFrame();
}
void RtWvOut :: tick( const StkFrames& frames, unsigned int channel )
void RtWvOut :: computeFrames( const StkFrames& frames )
{
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "RtWvOut::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
if ( stopped_ ) start();
if ( frames.channels() != nChannels_ ) {
errorString_ << "RtWvOut::computeFrames(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( stopped_ )
start();
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
tick( frames[i] );
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
tick( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
tick( frames[iStart + i] );
}
}
void RtWvOut :: tickFrame( const StkFloat *frameVector, unsigned int frames )
{
if ( stopped_ )
start();
StkFloat sample;
for ( unsigned int i=0; i<frames; i++ ) {
for ( unsigned int j=0; j<channels_; j++ ) {
sample = frameVector[i*channels_+j];
this->clipTest( sample );
dataPtr_[counter_*channels_+j] = sample;
}
counter_++;
totalCount_++;
if ( counter_ >= (unsigned int)bufferSize_ ) {
try {
audio_->tickStream();
}
catch (RtError &error) {
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
}
counter_ = 0;
}
}
}
void RtWvOut :: tickFrame( const StkFrames& frames )
{
if ( channels_ != frames.channels() ) {
errorString_ << "RtWvOut::tickFrame(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( stopped_ )
start();
unsigned int j;
StkFloat sample;
if ( channels_ == 1 || frames.interleaved() ) {
unsigned long iFrames = 0, iData = counter_;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<channels_; j++ ) {
sample = frames[iFrames++];
this->clipTest( sample );
dataPtr_[iData++] = sample;
}
counter_++;
totalCount_++;
if ( nChannels_ == 1 || frames.interleaved() ) {
if ( counter_ >= (unsigned int)bufferSize_ ) {
try {
audio_->tickStream();
}
catch (RtError &error) {
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
}
counter_ = 0;
unsigned int iFrames = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<nChannels_; j++ ) {
buffer_[iBuffer_] = frames[iFrames++];
clipTest( buffer_[iBuffer_++] );
}
this->incrementFrame();
}
}
else {
unsigned int hop = frames.frames();
unsigned long iData = counter_;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<channels_; j++ ) {
sample = frames[i + j*hop];
this->clipTest( sample );
dataPtr_[iData++] = sample;
}
counter_++;
totalCount_++;
else { // non-interleaved frames
if ( counter_ >= (unsigned int)bufferSize_ ) {
try {
audio_->tickStream();
}
catch (RtError &error) {
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
}
counter_ = 0;
unsigned long hop = frames.frames();
unsigned int index;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
index = i;
for ( j=0; j<nChannels_; j++ ) {
buffer_[iBuffer_] = frames[index];
clipTest( buffer_[iBuffer_++] );
index += hop;
}
this->incrementFrame();
}
}
}

View File

@@ -5,7 +5,7 @@
This instrument provides an ADSR envelope, a one-pole filter, and
structures for an arbitrary number of attack and loop waves.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/

View File

@@ -31,7 +31,7 @@
- Vibrato Gain = 1
- Breath Pressure = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -51,9 +51,7 @@ Saxofony :: Saxofony(StkFloat lowestFrequency)
reedTable_.setOffset( 0.7 );
reedTable_.setSlope( 0.3 );
// Concatenate the STK rawwave path to the rawwave file
vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
vibrato_->setFrequency((StkFloat) 5.735);
vibrato_.setFrequency((StkFloat) 5.735);
outputGain_ = 0.3;
noiseGain_ = 0.2;
@@ -62,7 +60,6 @@ Saxofony :: Saxofony(StkFloat lowestFrequency)
Saxofony :: ~Saxofony()
{
delete vibrato_;
}
void Saxofony :: clear()
@@ -138,7 +135,7 @@ void Saxofony :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Saxofony :: tick()
StkFloat Saxofony :: computeSample()
{
StkFloat pressureDiff;
StkFloat breathPressure;
@@ -147,7 +144,7 @@ StkFloat Saxofony :: tick()
// Calculate the breath pressure (envelope + noise + vibrato)
breathPressure = envelope_.tick();
breathPressure += breathPressure * noiseGain_ * noise_.tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_->tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
temp = -0.95 * filter_.tick( delays_[0].lastOut() );
lastOutput_ = temp - delays_[1].lastOut();
@@ -159,16 +156,6 @@ StkFloat Saxofony :: tick()
return lastOutput_;
}
StkFloat *Saxofony :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Saxofony :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Saxofony :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;
@@ -188,7 +175,7 @@ void Saxofony :: controlChange(int number, StkFloat value)
else if (number == __SK_NoiseLevel_) // 4
noiseGain_ = ( norm * 0.4 );
else if (number == 29) // 29
vibrato_->setFrequency( norm * 12.0 );
vibrato_.setFrequency( norm * 12.0 );
else if (number == __SK_ModWheel_) // 1
vibratoGain_ = ( norm * 0.5 );
else if (number == __SK_AfterTouch_Cont_) // 128

View File

@@ -53,7 +53,7 @@
/***************************************************/
#include "Stk.h"
#include <math.h>
#include <cmath>
int my_random(int max) // Return Random Int Between 0 and max
{
@@ -816,7 +816,7 @@ void Shakers :: noteOff(StkFloat amplitude)
const StkFloat MIN_ENERGY = 0.3;
StkFloat Shakers :: tick()
StkFloat Shakers :: computeSample()
{
StkFloat data;
StkFloat temp_rand;
@@ -887,16 +887,6 @@ StkFloat Shakers :: tick()
return lastOutput_;
}
StkFloat *Shakers :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Shakers :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Shakers :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

View File

@@ -13,7 +13,7 @@
- Envelope Rate = 11
- Gain = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -73,7 +73,7 @@ void Simple :: setFrequency(StkFloat frequency)
loop_->setFrequency( frequency );
}
StkFloat Simple :: tick()
StkFloat Simple :: computeSample()
{
lastOutput_ = loopGain_ * loop_->tick();
biquad_.tick( noise_.tick() );
@@ -83,16 +83,6 @@ StkFloat Simple :: tick()
return lastOutput_;
}
StkFloat *Simple :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Simple :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Simple :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

103
src/SineWave.cpp Normal file
View File

@@ -0,0 +1,103 @@
/***************************************************/
/*! \class SineWave
\brief STK sinusoid oscillator class.
This class computes and saves a static sine "table" that can be
shared by multiple instances. It has an interface similar to the
WaveLoop class but inherits from the Generator class. Output
values are computed using linear interpolation.
The "table" length, set in SineWave.h, is 2048 samples by default.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "SineWave.h"
#include <cmath>
StkFrames SineWave :: table_;
SineWave :: SineWave( void )
: time_(0.0), rate_(1.0), phaseOffset_(0.0)
{
if ( table_.empty() ) {
table_.resize( TABLE_SIZE + 1, 1 );
StkFloat temp = 1.0 / TABLE_SIZE;
for ( unsigned long i=0; i<=TABLE_SIZE; i++ )
table_[i] = sin( TWO_PI * i * temp );
}
}
SineWave :: ~SineWave()
{
}
void SineWave :: reset(void)
{
time_ = 0.0;
lastOutput_ = 0;
}
void SineWave :: setFrequency( StkFloat frequency )
{
// This is a looping frequency.
this->setRate( TABLE_SIZE * frequency / Stk::sampleRate() );
}
void SineWave :: addTime( StkFloat time )
{
// Add an absolute time in samples.
time_ += time;
while ( time_ < 0.0 )
time_ += TABLE_SIZE;
while ( time_ >= TABLE_SIZE )
time_ -= TABLE_SIZE;
}
void SineWave :: addPhase( StkFloat angle )
{
// Add a time in cycles (one cycle = TABLE_SIZE).
time_ += TABLE_SIZE * angle;
while ( time_ < 0.0 )
time_ += TABLE_SIZE;
while ( time_ >= TABLE_SIZE )
time_ -= TABLE_SIZE;
}
void SineWave :: addPhaseOffset( StkFloat angle )
{
// Add a phase offset in cycles, where 1.0 = TABLE_SIZE.
phaseOffset_ = TABLE_SIZE * angle;
}
StkFloat SineWave :: computeSample( void )
{
// Check limits of time address ... if necessary, recalculate modulo
// TABLE_SIZE.
while ( time_ < 0.0 )
time_ += TABLE_SIZE;
while ( time_ >= TABLE_SIZE )
time_ -= TABLE_SIZE;
StkFloat tyme;
if ( phaseOffset_ ) {
tyme = time_ + phaseOffset_;
while ( tyme < 0.0 )
tyme += TABLE_SIZE;
while ( tyme >= TABLE_SIZE )
tyme -= TABLE_SIZE;
}
else {
tyme = time_;
}
lastOutput_ = table_.interpolate( tyme );
// Increment time, which can be negative.
time_ += rate_;
return lastOutput_;
}

View File

@@ -9,7 +9,7 @@
from pitch shifting. It will be used as an
excitation source for other instruments.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -22,21 +22,19 @@ SingWave :: SingWave( std::string fileName, bool raw)
rate_ = 1.0;
sweepRate_ = 0.001;
modulator_ = new Modulate();
modulator_->setVibratoRate( 6.0 );
modulator_->setVibratoGain( 0.04 );
modulator_->setRandomGain( 0.005 );
modulator_.setVibratoRate( 6.0 );
modulator_.setVibratoGain( 0.04 );
modulator_.setRandomGain( 0.005 );
this->setFrequency( 75.0 );
pitchEnvelope_.setRate( 1.0 );
this->tick();
this->tick();
this->computeSample();
this->computeSample();
pitchEnvelope_.setRate( sweepRate_ * rate_ );
}
SingWave :: ~SingWave()
{
delete wave_;
delete modulator_;
}
void SingWave :: reset()
@@ -67,17 +65,17 @@ void SingWave :: setFrequency(StkFloat frequency)
void SingWave :: setVibratoRate(StkFloat rate)
{
modulator_->setVibratoRate( rate );
modulator_.setVibratoRate( rate );
}
void SingWave :: setVibratoGain(StkFloat gain)
{
modulator_->setVibratoGain(gain);
modulator_.setVibratoGain(gain);
}
void SingWave :: setRandomGain(StkFloat gain)
{
modulator_->setRandomGain(gain);
modulator_.setRandomGain(gain);
}
void SingWave :: setSweepRate(StkFloat rate)
@@ -105,25 +103,15 @@ void SingWave :: noteOff()
envelope_.keyOff();
}
StkFloat SingWave :: tick()
StkFloat SingWave :: computeSample()
{
// Set the wave rate.
StkFloat newRate = pitchEnvelope_.tick();
newRate += newRate * modulator_->tick();
newRate += newRate * modulator_.tick();
wave_->setRate( newRate );
lastOutput_ = wave_->tick();
lastOutput_ *= envelope_.tick();
return lastOutput_;
}
StkFloat *SingWave :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Generator::tick( vector, vectorSize );
}
StkFrames& SingWave :: tick( StkFrames& frames, unsigned int channel )
{
return Generator::tick( frames, channel );
}

View File

@@ -13,7 +13,7 @@
Stanford, bearing the names of Karplus and/or
Strong.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -98,7 +98,7 @@ void Sitar :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Sitar :: tick()
StkFloat Sitar :: computeSample()
{
if ( fabs(targetDelay_ - delay_) > 0.001 ) {
if ( targetDelay_ < delay_ )
@@ -113,13 +113,3 @@ StkFloat Sitar :: tick()
return lastOutput_;
}
StkFloat *Sitar :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Sitar :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

View File

@@ -19,7 +19,7 @@
See also SKINI.txt.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -173,6 +173,11 @@ long Skini :: parseString( std::string& line, Message& message )
case SK_STR: // Must be the last field.
message.remainder = tokens[iValue+3];
return message.type;
default: // MIDI extension message
message.intValues[iValue] = dataType;
message.floatValues[iValue] = (StkFloat) message.intValues[iValue];
iValue--;
}
if ( ++iValue == 1 )

View File

@@ -1,171 +1,46 @@
/***************************************************/
/*! \class Socket
\brief STK TCP socket client/server class.
\brief STK internet socket abstract base 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.
This class provides common functionality for TCP and UDP internet
socket server and client subclasses.
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 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#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>
#include <netinet/tcp.h>
#elif defined(__OS_WINDOWS__)
#include <winsock.h>
#endif
Socket :: Socket( int port )
Socket :: Socket()
{
soket_ = -1;
server_ = true;
port_ = 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) {
errorString_ << "Socket: Incompatible Windows socket library version!";
handleError( StkError::PROCESS_SOCKET );
}
#endif
// Create the server-side socket
soket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (soket_ < 0) {
errorString_ << "Socket: Couldn't create socket server!";
handleError( StkError::PROCESS_SOCKET );
}
int flag = 1;
int result = setsockopt( soket_, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int) );
if (result < 0) {
errorString_ << "Socket: Error setting socket options!";
handleError( 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 ) {
errorString_ << "Socket: Couldn't bind socket!";
handleError( StkError::PROCESS_SOCKET );
}
// Listen for incoming connection(s)
if ( listen(soket_, 1) < 0 ) {
errorString_ << "Socket: Couldn't start server listening!";
handleError( StkError::PROCESS_SOCKET );
}
}
Socket :: Socket(int port, const char *hostname )
{
soket_ = -1;
server_ = false;
port_ = port;
#if defined(__OS_WINDOWS__) // windoze-only stuff
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1,1);
WSAStartup(wVersionRequested, &wsaData);
if (wsaData.wVersion != wVersionRequested) {
errorString_ << "Socket: Incompatible Windows socket library version!";
handleError( StkError::PROCESS_SOCKET );
}
#endif
// Create a socket client connection.
connect( port, hostname );
port_ = -1;
}
Socket :: ~Socket()
{
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
this->close( soket_ );
::close( soket_ );
#if defined(__OS_WINDOWS__)
#elif defined(__OS_WINDOWS__)
::closesocket( soket_ );
WSACleanup();
#endif
}
int Socket :: connect( int port, const char *hostname )
void Socket :: close( int socket )
{
// This method is for client connections only!
if ( server_ == true ) return -1;
if ( !isValid( socket ) ) return;
// Close an existing connection if it exists.
if ( isValid( soket_ ) ) this->close();
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
// Create the client-side socket
soket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (soket_ < 0) {
errorString_ << "Socket: Couldn't create socket client!";
handleError( StkError::PROCESS_SOCKET );
}
::close( socket );
int flag = 1;
int result = setsockopt( soket_, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int) );
if (result < 0) {
errorString_ << "Socket: Error setting socket options!";
handleError( StkError::PROCESS_SOCKET );
}
#elif defined(__OS_WINDOWS__)
struct hostent *hostp;
if ( (hostp = gethostbyname(hostname)) == 0 ) {
errorString_ << "Socket: unknown host (" << hostname << ")!";
handleError( StkError::PROCESS_SOCKET_IPADDR );
}
::closesocket( socket );
// 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) {
errorString_ << "Socket: Couldn't connect to socket server!";
handleError( StkError::PROCESS_SOCKET );
}
return soket_;
#endif
}
int Socket :: id( void ) const
@@ -178,14 +53,6 @@ int Socket :: port( void ) const
return port_;
}
int Socket :: accept( void )
{
if ( server_ )
return ::accept( soket_, NULL, NULL );
else
return -1;
}
bool Socket :: isValid( int socket )
{
return socket != -1;
@@ -209,48 +76,15 @@ void Socket :: setBlocking( int socket, bool enable )
#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 );
}

View File

@@ -17,13 +17,13 @@
- String Sustain = 11
- String Stretch = 1
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "StifKarp.h"
#include "SKINI.msg"
#include <math.h>
#include <cmath>
StifKarp :: StifKarp(StkFloat lowestFrequency)
{
@@ -180,7 +180,7 @@ void StifKarp :: noteOff(StkFloat amplitude)
#endif
}
StkFloat StifKarp :: tick()
StkFloat StifKarp :: computeSample()
{
StkFloat temp = delayLine_.lastOut() * loopGain_;
@@ -196,16 +196,6 @@ StkFloat StifKarp :: tick()
return lastOutput_;
}
StkFloat *StifKarp :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& StifKarp :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void StifKarp :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;

View File

@@ -8,7 +8,7 @@
provides error handling and byte-swapping
functions.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -18,9 +18,12 @@ StkFloat Stk :: srate_ = (StkFloat) SRATE;
std::string Stk :: rawwavepath_ = RAWWAVE_PATH;
const Stk::StkFormat Stk :: STK_SINT8 = 0x1;
const Stk::StkFormat Stk :: STK_SINT16 = 0x2;
const Stk::StkFormat Stk :: STK_SINT24 = 0x4;
const Stk::StkFormat Stk :: STK_SINT32 = 0x8;
const Stk::StkFormat Stk :: STK_FLOAT32 = 0x10;
const Stk::StkFormat Stk :: STK_FLOAT64 = 0x20;
bool Stk :: showWarnings_ = false;
bool Stk :: printErrors_ = true;
Stk :: Stk(void)
{
@@ -123,60 +126,186 @@ void Stk :: handleError( const char *message, StkError::Type type )
void Stk :: handleError( std::string message, StkError::Type type )
{
if (type == StkError::WARNING || type == StkError::STATUS )
if ( type == StkError::WARNING || type == StkError::STATUS ) {
if ( !showWarnings_ ) return;
std::cerr << '\n' << message << '\n' << std::endl;
}
else if (type == StkError::DEBUG_WARNING) {
#if defined(_STK_DEBUG_)
std::cerr << '\n' << message << '\n' << std::endl;
#endif
}
else {
// Print error message before throwing.
std::cerr << '\n' << message << '\n' << std::endl;
if ( printErrors_ ) {
// Print error message before throwing.
std::cerr << '\n' << message << '\n' << std::endl;
}
throw StkError(message, type);
}
}
//
// StkFrames definitions
//
StkFrames :: StkFrames( unsigned int nFrames, unsigned int nChannels, bool interleaved )
: nFrames_( nFrames ), nChannels_( nChannels ), interleaved_( interleaved )
{
if ( nChannels == 0 ) {
std::string message = "StkFrames::StkFrames: nChannels argument should be 1 or greater (even if nFrames = 0) ... correcting to one channel!";
Stk::handleError( message, StkError::WARNING );
nChannels_ = 1;
}
size_ = nFrames_ * nChannels_;
if ( size_ > 0 ) data_.resize( size_, 0.0 );
bufferSize_ = size_;
if ( size_ > 0 ) {
data_ = (StkFloat *) calloc( size_, sizeof( StkFloat ) );
#if defined(_STK_DEBUG_)
if ( data_ == NULL ) {
std::string error = "StkFrames: memory allocation error in constructor!";
Stk::handleError( error, StkError::MEMORY_ALLOCATION );
}
#endif
}
else data_ = 0;
dataRate_ = Stk::sampleRate();
}
StkFrames :: StkFrames( const StkFloat& value, unsigned int nFrames, unsigned int nChannels, bool interleaved )
: nFrames_( nFrames ), nChannels_( nChannels ), interleaved_( interleaved )
{
if ( nChannels == 0 ) {
std::string message = "StkFrames::StkFrames: nChannels argument should be 1 or greater (even if nFrames = 0) ... correcting to one channel!";
Stk::handleError( message, StkError::WARNING );
nChannels_ = 1;
}
size_ = nFrames_ * nChannels_;
if ( size_ > 0 ) data_.resize( size_, value );
bufferSize_ = size_;
if ( size_ > 0 ) {
data_ = (StkFloat *) malloc( size_ * sizeof( StkFloat ) );
#if defined(_STK_DEBUG_)
if ( data_ == NULL ) {
std::string error = "StkFrames: memory allocation error in constructor!";
Stk::handleError( error, StkError::MEMORY_ALLOCATION );
}
#endif
for ( long i=0; i<(long)size_; i++ ) data_[i] = value;
}
else data_ = 0;
dataRate_ = Stk::sampleRate();
}
void StkFrames :: resize( unsigned int nFrames, unsigned int nChannels, StkFloat value )
StkFrames :: ~StkFrames()
{
if ( data_ ) free( data_ );
}
bool StkFrames :: empty() const
{
if ( size_ > 0 ) return false;
else return true;
}
void StkFrames :: resize( size_t nFrames, unsigned int nChannels )
{
nFrames_ = nFrames;
nChannels_ = nChannels;
if ( nChannels == 0 ) {
std::string message = "StkFrames::resize(): nChannels argument should be 1 or greater (even if nFrames = 0) ... correcting to one channel!";
Stk::handleError( message, StkError::WARNING );
nChannels_ = 1;
}
size_t newSize = nFrames_ * nChannels_;
if ( size_ != newSize ) {
size_ = newSize;
data_.resize( size_, value );
size_ = nFrames_ * nChannels_;
if ( size_ > bufferSize_ ) {
if ( data_ ) free( data_ );
data_ = (StkFloat *) malloc( size_ * sizeof( StkFloat ) );
#if defined(_STK_DEBUG_)
if ( data_ == NULL ) {
std::string error = "StkFrames::resize: memory allocation error!";
Stk::handleError( error, StkError::MEMORY_ALLOCATION );
}
#endif
bufferSize_ = size_;
}
}
void StkFrames :: resize( size_t nFrames, unsigned int nChannels, StkFloat value )
{
this->resize( nFrames, nChannels );
for ( size_t i=0; i<size_; i++ ) data_[i] = value;
}
StkFloat& StkFrames :: operator[] ( size_t n )
{
#if defined(_STK_DEBUG_)
if ( n >= size_ ) {
std::ostringstream error;
error << "StkFrames::operator[]: invalid index (" << n << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
return data_[n];
}
StkFloat StkFrames :: operator[] ( size_t n ) const
{
#if defined(_STK_DEBUG_)
if ( n >= size_ ) {
std::ostringstream error;
error << "StkFrames::operator[]: invalid index (" << n << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
return data_[n];
}
StkFloat& StkFrames :: operator() ( size_t frame, unsigned int channel )
{
#if defined(_STK_DEBUG_)
if ( frame >= nFrames_ || channel >= nChannels_ ) {
std::ostringstream error;
error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
if ( interleaved_ )
return data_[ frame * nChannels_ + channel ];
else
return data_[ channel * nFrames_ + frame ];
}
StkFloat StkFrames :: operator() ( size_t frame, unsigned int channel ) const
{
#if defined(_STK_DEBUG_)
if ( frame >= nFrames_ || channel >= nChannels_ ) {
std::ostringstream error;
error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
if ( interleaved_ )
return data_[ frame * nChannels_ + channel ];
else
return data_[ channel * nFrames_ + frame ];
}
StkFloat StkFrames :: interpolate( StkFloat frame, unsigned int channel ) const
{
#if defined(_STK_DEBUG_)
if ( frame >= (StkFloat) nFrames_ || channel >= nChannels_ ) {
std::ostringstream error;
error << "StkFrames::interpolate: invalid frame (" << frame << ") or channel (" << channel << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
size_t iIndex = ( size_t ) frame; // integer part of index
StkFloat output, alpha = frame - (StkFloat) iIndex; // fractional part of index
if ( interleaved_ ) {
iIndex = iIndex * nChannels_ + channel;
output = data_[ iIndex ];
output += ( alpha * ( data_[ iIndex + nChannels_ ] - output ) );
}
else {
iIndex += channel * nFrames_;
output = data_[ iIndex ];
output += ( alpha * ( data_[ iIndex++ ] - output ) );
}
return output;
}

View File

@@ -6,48 +6,42 @@
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 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "SubNoise.h"
SubNoise :: SubNoise(int subRate) : Noise()
{
rate_ = subRate;
SubNoise :: SubNoise( int subRate ) : Noise()
{
if ( subRate <= 0 ) {
errorString_ << "SubNoise: subRate argument is negative ... setting to 16!";
handleError( StkError::WARNING );
rate_ = 16;
}
// Precompute an output.
Noise::computeSample();
counter_ = rate_;
}
SubNoise :: ~SubNoise()
{
}
int SubNoise :: subRate(void) const
void SubNoise :: setRate( int subRate )
{
return rate_;
}
void SubNoise :: setRate(int subRate)
{
if (subRate > 0)
if ( subRate > 0 )
rate_ = subRate;
}
StkFloat SubNoise :: tick()
StkFloat SubNoise :: computeSample()
{
if ( ++counter_ > rate_ ) {
Noise::tick();
counter_ = 1;
if ( counter_-- == 0 ) {
Noise::computeSample();
counter_ = rate_;
}
return lastOutput_;
}
StkFloat *SubNoise :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Generator::tick( vector, vectorSize );
}
StkFrames& SubNoise :: tick( StkFrames& frames, unsigned int channel )
{
return Generator::tick( frames, channel );
}

View File

@@ -1,100 +0,0 @@
/***************************************************/
/*! \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 - 2004.
*/
/***************************************************/
#include "Table.h"
#include <fstream>
#include <sys/stat.h>
Table :: Table( std::string fileName)
{
// Use the system call "stat" to determine the file length
struct stat filestat;
if ( stat( fileName.c_str(), &filestat ) == -1 ) {
errorString_ << "Table: Couldn't stat or find file (" << fileName << ").";
handleError( 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.c_str(),"rb");
if (!fd) {
errorString_ << "Table::Table: unable to open or find file (" << fileName << ")";
handleError( StkError::FILE_NOT_FOUND );
}
data_.resize( length_, 0.0 );
// 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++] = (StkFloat) temp;
}
fclose(fd);
lastOutput_ = 0.0;
}
Table :: ~Table()
{
}
long Table :: getLength() const
{
return length_;
}
StkFloat Table :: tick(StkFloat index)
{
StkFloat alpha;
long temp;
if ( index > length_-1 ) {
errorString_ << "Table: Index (" << index << ") exceeds table length ... sticking at end!\n";
handleError( StkError::WARNING );
index = length_-1;
}
else if (index < 0.0) {
errorString_ << "Table: Index (" << index << ") is less than zero ... setting to zero!\n";
handleError( StkError::WARNING );
index = 0.0;
}
// Index in range 0 to length-1
temp = (long) index; // Integer part of index
alpha = index - (StkFloat) 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_;
}
StkFloat *Table :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Function::tick( vector, vectorSize );
}
StkFrames& Table :: tick( StkFrames& frames, unsigned int channel )
{
return Function::tick( frames, channel );
}

100
src/TcpClient.cpp Normal file
View File

@@ -0,0 +1,100 @@
/***************************************************/
/*! \class TcpClient
\brief STK TCP socket client class.
This class provides a uniform cross-platform TCP socket client
interface. Methods are provided for reading or writing data
buffers to/from connections.
TCP sockets are reliable and connection-oriented. A TCP socket
client must be connected to a TCP server before data can be sent
or received. Data delivery is guaranteed in order, without loss,
error, or duplication. That said, TCP transmissions tend to be
slower than those using the UDP protocol and data sent with
multiple \e write() calls can be arbitrarily combined by the
underlying system.
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 - 2005.
*/
/***************************************************/
#include "TcpClient.h"
TcpClient :: TcpClient(int port, std::string hostname )
{
#if defined(__OS_WINDOWS__) // windoze-only stuff
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1,1);
WSAStartup(wVersionRequested, &wsaData);
if (wsaData.wVersion != wVersionRequested) {
errorString_ << "TcpClient: Incompatible Windows socket library version!";
handleError( StkError::PROCESS_SOCKET );
}
#endif
// Create a socket client connection.
connect( port, hostname );
}
TcpClient :: ~TcpClient()
{
}
int TcpClient :: connect( int port, std::string hostname )
{
// Close any existing connections.
this->close( soket_ );
// Create the client-side socket
soket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (soket_ < 0) {
errorString_ << "TcpClient: Couldn't create socket client!";
handleError( StkError::PROCESS_SOCKET );
}
int flag = 1;
int result = setsockopt( soket_, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int) );
if (result < 0) {
errorString_ << "TcpClient: Error setting socket options!";
handleError( StkError::PROCESS_SOCKET );
}
struct hostent *hostp;
if ( (hostp = gethostbyname( hostname.c_str() )) == 0 ) {
errorString_ << "TcpClient: unknown host (" << hostname << ")!";
handleError( 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) {
errorString_ << "TcpClient: Couldn't connect to socket server!";
handleError( StkError::PROCESS_SOCKET );
}
return soket_;
}
int TcpClient :: writeBuffer(const void *buffer, long bufferSize, int flags )
{
if ( !isValid( soket_ ) ) return -1;
return send( soket_, (const char *)buffer, bufferSize, flags );
}
int TcpClient :: readBuffer(void *buffer, long bufferSize, int flags )
{
if ( !isValid( soket_ ) ) return -1;
return recv( soket_, (char *)buffer, bufferSize, flags );
}

95
src/TcpServer.cpp Normal file
View File

@@ -0,0 +1,95 @@
/***************************************************/
/*! \class TcpServer
\brief STK TCP socket server class.
This class provides a uniform cross-platform TCP socket server
interface. Methods are provided for reading or writing data
buffers to/from connections.
TCP sockets are reliable and connection-oriented. A TCP socket
server must accept a connection from a TCP client before data can
be sent or received. Data delivery is guaranteed in order,
without loss, error, or duplication. That said, TCP transmissions
tend to be slower than those using the UDP protocol and data sent
with multiple \e write() calls can be arbitrarily combined by the
underlying system.
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 - 2005.
*/
/***************************************************/
#include "TcpServer.h"
TcpServer :: TcpServer( int 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) {
errorString_ << "TcpServer: Incompatible Windows socket library version!";
handleError( StkError::PROCESS_SOCKET );
}
#endif
// Create the server-side socket
soket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (soket_ < 0) {
errorString_ << "TcpServer: Couldn't create socket server!";
handleError( StkError::PROCESS_SOCKET );
}
int flag = 1;
int result = setsockopt( soket_, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int) );
if (result < 0) {
errorString_ << "TcpServer: Error setting socket options!";
handleError( StkError::PROCESS_SOCKET );
}
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( port );
// Bind socket to the appropriate port and interface (INADDR_ANY)
if ( bind( soket_, (struct sockaddr *)&address, sizeof(address) ) < 0 ) {
errorString_ << "TcpServer: Couldn't bind socket!";
handleError( StkError::PROCESS_SOCKET );
}
// Listen for incoming connection(s)
if ( listen( soket_, 1 ) < 0 ) {
errorString_ << "TcpServer: Couldn't start server listening!";
handleError( StkError::PROCESS_SOCKET );
}
port_ = port;
}
TcpServer :: ~TcpServer()
{
}
int TcpServer :: accept( void )
{
return ::accept( soket_, NULL, NULL );
}
int TcpServer :: writeBuffer(const void *buffer, long bufferSize, int flags )
{
if ( !isValid( soket_ ) ) return -1;
return send( soket_, (const char *)buffer, bufferSize, flags );
}
int TcpServer :: readBuffer(void *buffer, long bufferSize, int flags )
{
if ( !isValid( soket_ ) ) return -1;
return recv( soket_, (char *)buffer, bufferSize, flags );
}

View File

@@ -1,336 +0,0 @@
/***************************************************/
/*! \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
StkFormats are permissible.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
*/
/***************************************************/
#include "TcpWvIn.h"
const int 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 ) {
((TcpWvIn *) info->object)->receive();
}
return 0;
}
TcpWvIn :: TcpWvIn( int port )
{
init( port );
}
TcpWvIn :: ~TcpWvIn()
{
// Close down the thread.
connected_ = false;
threadInfo_.finished = true;
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_ ) ) {
errorString_ << "TcpWvIn::init: unable to start input thread!";
handleError( StkError::PROCESS_THREAD );
}
}
void TcpWvIn :: listen(unsigned int nChannels, Stk::StkFormat format)
{
mutex_.lock();
if ( connected_ ) {
soket_->close(fd_);
}
if ( nChannels < 1 ) {
errorString_ << "TcpWvOut::listen: the channel argument (" << nChannels << ") must be greater than zero.";
handleError( 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 {
errorString_ << "TcpWvIn::listen: unknown data type specified (" << format << ").";
handleError( 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_ = (StkFloat *) new StkFloat[CHUNK_SIZE*channels_];
if ( lastOutputs_ ) delete [] lastOutputs_;
lastOutputs_ = (StkFloat *) new StkFloat[channels_];
}
WvIn::reset();
counter_ = 0;
writePoint_ = 0;
bytesFilled_ = 0;
// Accept a connection.
errorString_ << "TcpWvIn: listening for connection on port " << soket_->port() << " ... ";
handleError( StkError::STATUS );
fd_ = soket_->accept();
if ( fd_ < 0) {
errorString_ << "TcpWvIn: Could not accept connection request!";
handleError( StkError::PROCESS_SOCKET );
}
errorString_ << "TcpWvIn::listen: connection made!";
handleError( StkError::STATUS );
// 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 ) {
errorString_ << "TcpWvIn::receive: the remote TcpWvIn socket connection has closed.";
handleError( StkError::STATUS );
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] = (StkFloat) *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] = (StkFloat) *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] = (StkFloat) *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] = (StkFloat) *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] = (StkFloat) *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 StkFloat *TcpWvIn :: lastFrame(void) const
{
return lastOutputs_;
}
StkFloat TcpWvIn :: lastOut(void) const
{
return WvIn::lastOut();
}
StkFloat TcpWvIn :: tick(void)
{
return WvIn::tick();
}
StkFloat *TcpWvIn :: tick(StkFloat *vector, unsigned int vectorSize)
{
return WvIn::tick( vector, vectorSize );
}
StkFrames& TcpWvIn :: tick( StkFrames& frames, unsigned int channel )
{
return WvIn::tick( frames, channel );
}
const StkFloat *TcpWvIn :: tickFrame(void)
{
// If no connection and we've output all samples in the queue, return.
if ( !connected_ && bytesFilled_ == 0 && counter_ == 0 ) return lastOutputs_;
if (counter_ == 0)
counter_ = readData();
long temp = (CHUNK_SIZE - counter_) * channels_;
for (unsigned int i=0; i<channels_; i++)
lastOutputs_[i] = data_[temp++];
counter_--;
if ( counter_ < 0 )
counter_ = 0;
return lastOutputs_;
}
StkFloat *TcpWvIn :: tickFrame(StkFloat *frameVector, unsigned int frames)
{
return WvIn::tickFrame( frameVector, frames );
}
StkFrames& TcpWvIn :: tickFrame( StkFrames& frames )
{
return WvIn::tickFrame( frames );
}

View File

@@ -1,280 +0,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 StkFormats are permissible.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
*/
/***************************************************/
#include "TcpWvOut.h"
#include <string.h>
TcpWvOut :: TcpWvOut()
{
buffer_ = 0;
soket_ = 0;
}
TcpWvOut :: TcpWvOut(int port, const char *hostname, unsigned int nChannels, Stk::StkFormat 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::StkFormat format)
{
if ( soket_ && soket_->isValid( soket_->id() ) )
disconnect();
if (nChannels < 1) {
errorString_ << "TcpWvOut::connect: the channel argument (" << nChannels << ") must be greater than zero!";
handleError( 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 {
errorString_ << "TcpWvOut::connect: unknown data type specified (" << format << ").";
handleError( 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_ ) {
data_.resize( 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( unsigned long frames )
{
if ( dataType_ == STK_SINT8 ) {
signed char *ptr = (signed char *) buffer_;
for ( unsigned long k=0; k<frames*channels_; k++ ) {
this->clipTest( data_[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++ ) {
this->clipTest( data_[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++ ) {
this->clipTest( data_[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++ ) {
this->clipTest( data_[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++ ) {
this->clipTest( data_[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 ) {
errorString_ << "TcpWvOut: connection to socket server failed!";
handleError( StkError::PROCESS_SOCKET );
}
}
unsigned long TcpWvOut :: getFrames( void ) const
{
return totalCount_;
}
StkFloat TcpWvOut :: getTime( void ) const
{
return (StkFloat) totalCount_ / Stk::sampleRate();
}
void TcpWvOut :: tick( const StkFloat sample )
{
if ( !soket_ || !soket_->isValid( soket_->id() ) ) 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 StkFloat *vector, unsigned int vectorSize )
{
if ( !soket_ || !soket_->isValid( soket_->id() ) ) return;
for (unsigned int i=0; i<vectorSize; i++)
tick( vector[i] );
}
void TcpWvOut :: tick( const StkFrames& frames, unsigned int channel )
{
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "TcpWvOut::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( !soket_ || !soket_->isValid( soket_->id() ) ) return;
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
tick( frames[i] );
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
tick( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
tick( frames[iStart + i] );
}
}
void TcpWvOut :: tickFrame( const StkFloat *frameVector, unsigned int frames )
{
if ( !soket_ || !soket_->isValid( soket_->id() ) ) 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;
}
}
}
void TcpWvOut :: tickFrame( const StkFrames& frames )
{
if ( channels_ != frames.channels() ) {
errorString_ << "TcpWvOut::tickFrame(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( !soket_ || !soket_->isValid( soket_->id() ) ) return;
unsigned int j;
if ( channels_ == 1 || frames.interleaved() ) {
unsigned long iFrames = 0, iData = counter_;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<channels_; j++ ) {
data_[iData++] = frames[iFrames++];
}
counter_++;
totalCount_++;
if ( counter_ == BUFFER_SIZE ) {
writeData( BUFFER_SIZE );
counter_ = 0;
}
}
}
else {
unsigned int hop = frames.frames();
unsigned long iData = counter_;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<channels_; j++ ) {
data_[iData++] = frames[i + j*hop];
}
counter_++;
totalCount_++;
if ( counter_ == BUFFER_SIZE ) {
writeData( BUFFER_SIZE );
counter_ = 0;
}
}
}
}

View File

@@ -7,7 +7,7 @@
systems, the pthread library is used. Under Windows,
the Windows thread library is used.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/

View File

@@ -26,7 +26,7 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -56,7 +56,7 @@ TubeBell :: TubeBell()
adsr_[3]->setAllTimes( 0.004, 4.0, 0.0, 0.04);
twozero_.setGain( 0.5 );
vibrato_->setFrequency( 2.0 );
vibrato_.setFrequency( 2.0 );
}
TubeBell :: ~TubeBell()
@@ -78,7 +78,7 @@ void TubeBell :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat TubeBell :: tick()
StkFloat TubeBell :: computeSample()
{
StkFloat temp, temp2;
@@ -95,19 +95,9 @@ StkFloat TubeBell :: tick()
temp += control2_ * 0.5 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
// Calculate amplitude modulation and apply it to output.
temp2 = vibrato_->tick() * modDepth_;
temp2 = vibrato_.tick() * modDepth_;
temp = temp * (1.0 + temp2);
lastOutput_ = temp * 0.5;
return lastOutput_;
}
StkFloat *TubeBell :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& TubeBell :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

View File

@@ -8,7 +8,7 @@
frequency response while maintaining a nearly
constant filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -75,9 +75,9 @@ StkFloat TwoPole :: lastOut(void) const
return Filter::lastOut();
}
StkFloat TwoPole :: tick(StkFloat sample)
StkFloat TwoPole :: tick( StkFloat input )
{
inputs_[0] = gain_ * sample;
inputs_[0] = gain_ * input;
outputs_[0] = b_[0] * inputs_[0] - a_[2] * outputs_[2] - a_[1] * outputs_[1];
outputs_[2] = outputs_[1];
outputs_[1] = outputs_[0];
@@ -85,11 +85,6 @@ StkFloat TwoPole :: tick(StkFloat sample)
return outputs_[0];
}
StkFloat *TwoPole :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Filter::tick( vector, vectorSize );
}
StkFrames& TwoPole :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );

View File

@@ -8,7 +8,7 @@
frequency response while maintaining a
constant filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -76,9 +76,9 @@ StkFloat TwoZero :: lastOut(void) const
return Filter::lastOut();
}
StkFloat TwoZero :: tick(StkFloat sample)
StkFloat TwoZero :: tick( StkFloat input )
{
inputs_[0] = gain_ * sample;
inputs_[0] = gain_ * input;
outputs_[0] = b_[2] * inputs_[2] + b_[1] * inputs_[1] + b_[0] * inputs_[0];
inputs_[2] = inputs_[1];
inputs_[1] = inputs_[0];
@@ -86,11 +86,6 @@ StkFloat TwoZero :: tick(StkFloat sample)
return outputs_[0];
}
StkFloat *TwoZero :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Filter::tick( vector, vectorSize );
}
StkFrames& TwoZero :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );

104
src/UdpSocket.cpp Normal file
View File

@@ -0,0 +1,104 @@
/***************************************************/
/*! \class UdpSocket
\brief STK UDP socket server/client class.
This class provides a uniform cross-platform UDP socket
server/client interface. Methods are provided for reading or
writing data buffers. The constructor creates a UDP socket and
binds it to the specified port. Note that only one socket can be
bound to a given port on the same machine.
UDP sockets provide unreliable, connection-less service. Messages
can be lost, duplicated, or received out of order. That said,
data transmission tends to be faster than with TCP connections and
datagrams are not potentially combined by the underlying system.
The user is responsible for checking the values returned by the
read/write methods. Values less than or equal to zero indicate
the occurence of an error.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "UdpSocket.h"
UdpSocket :: UdpSocket(int port )
{
validAddress_ = false;
#if defined(__OS_WINDOWS__) // windoze-only stuff
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1,1);
WSAStartup(wVersionRequested, &wsaData);
if (wsaData.wVersion != wVersionRequested) {
errorString_ << "UdpSocket: Incompatible Windows socket library version!";
handleError( StkError::PROCESS_SOCKET );
}
#endif
// Create the UDP socket
soket_ = ::socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if ( soket_ < 0 ) {
errorString_ << "UdpSocket: Couldn't create UDP socket!";
handleError( StkError::PROCESS_SOCKET );
}
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( port );
// Bind socket to the appropriate port and interface (INADDR_ANY)
if ( bind(soket_, (struct sockaddr *)&address, sizeof(address)) < 0 ) {
errorString_ << "UdpSocket: Couldn't bind socket in constructor!";
handleError( StkError::PROCESS_SOCKET );
}
port_ = port;
}
UdpSocket :: ~UdpSocket()
{
}
void UdpSocket :: setDestination( int port, std::string hostname )
{
this->setAddress( &address_, port, hostname );
validAddress_ = true;
}
void UdpSocket :: setAddress( struct sockaddr_in *address, int port, std::string hostname )
{
struct hostent *hostp;
if ( (hostp = gethostbyname( hostname.c_str() )) == 0 ) {
errorString_ << "UdpSocket::setAddress: unknown host (" << hostname << ")!";
handleError( StkError::PROCESS_SOCKET_IPADDR );
}
// Fill in the address structure
address->sin_family = AF_INET;
memcpy((void *)&address->sin_addr, hostp->h_addr, hostp->h_length);
address->sin_port = htons( port );
}
int UdpSocket :: writeBuffer( const void *buffer, long bufferSize, int flags )
{
if ( !isValid( soket_ ) || !validAddress_ ) return -1;
return sendto( soket_, (const char *)buffer, bufferSize, flags, (struct sockaddr *)&address_, sizeof(address_) );
}
int UdpSocket :: readBuffer( void *buffer, long bufferSize, int flags )
{
if ( !isValid( soket_ ) ) return -1;
return recvfrom( soket_, (char *)buffer, bufferSize, flags, NULL, NULL );
}
int UdpSocket :: writeBufferTo( const void *buffer, long bufferSize, int port, std::string hostname, int flags )
{
if ( !isValid( soket_ ) ) return -1;
struct sockaddr_in address;
this->setAddress( &address, port, hostname );
return sendto( soket_, (const char *)buffer, bufferSize, flags, (struct sockaddr *)&address, sizeof(address) );
}

View File

@@ -49,7 +49,7 @@ StkFloat Vector3D :: getLength()
void Vector3D :: setXYZ(StkFloat x, StkFloat y, StkFloat z)
{
myX_ = z;
myX_ = x;
myY_ = y;
myZ_ = z;
};

View File

@@ -21,7 +21,7 @@
- Vibrato Gain = 1
- Loudness (Spectral Tilt) = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -29,7 +29,7 @@
#include "Phonemes.h"
#include "SKINI.msg"
#include <math.h>
#include <cmath>
VoicForm :: VoicForm() : Instrmnt()
{
@@ -65,7 +65,7 @@ void VoicForm :: clear()
}
}
void VoicForm :: setFrequency(StkFloat frequency)
void VoicForm :: setFrequency( StkFloat frequency )
{
StkFloat freakency = frequency;
if ( frequency <= 0.0 ) {
@@ -77,7 +77,7 @@ void VoicForm :: setFrequency(StkFloat frequency)
voiced_->setFrequency( freakency );
}
bool VoicForm :: setPhoneme(const char *phoneme )
bool VoicForm :: setPhoneme( const char *phoneme )
{
bool found = false;
unsigned int i = 0;
@@ -155,34 +155,24 @@ void VoicForm :: noteOff(StkFloat amplitude)
this->quiet();
}
StkFloat VoicForm :: tick()
StkFloat VoicForm :: computeSample()
{
StkFloat 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);
StkFloat 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_);
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_;
}
StkFloat *VoicForm :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& VoicForm :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void VoicForm :: controlChange(int number, StkFloat value)
{

View File

@@ -25,7 +25,7 @@
an ensemble. Alternately, control changes can
be sent to all voices on a given channel.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -55,7 +55,7 @@ void Voicer :: addInstrument( Instrmnt *instrument, int channel )
void Voicer :: removeInstrument( Instrmnt *instrument )
{
bool found = false;
std::vector< Voicer::Voice>::iterator i;
std::vector< Voicer::Voice >::iterator i;
for ( i=voices_.begin(); i!=voices_.end(); ++i ) {
if ( (*i).instrument != instrument ) continue;
voices_.erase( i );

View File

@@ -2,142 +2,187 @@
/*! \class WaveLoop
\brief STK waveform oscillator class.
This class inherits from WvIn and provides
audio file looping functionality.
This class inherits from FileWvIn and provides audio file looping
functionality. Any audio file that can be loaded by FileRead can
be looped using this class.
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.
WaveLoop supports multi-channel data. It is important to
distinguish the tick() methods, which return samples produced by
averaging across sample frames, from the tickFrame() methods,
which return references or pointers to multi-channel sample
frames.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "WaveLoop.h"
#include <cmath>
WaveLoop :: WaveLoop( std::string fileName, bool raw )
: WvIn( fileName, raw ), phaseOffset_(0.0)
WaveLoop :: WaveLoop( unsigned long chunkThreshold, unsigned long chunkSize )
: FileWvIn( chunkThreshold, chunkSize ), phaseOffset_(0.0)
{
// 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];
}
}
WaveLoop :: WaveLoop( std::string fileName, bool raw, bool doNormalize,
unsigned long chunkThreshold, unsigned long chunkSize )
: FileWvIn( chunkThreshold, chunkSize ), phaseOffset_(0.0)
{
this->openFile( fileName, raw, doNormalize );
}
WaveLoop :: ~WaveLoop()
{
}
void WaveLoop :: readData( unsigned long index )
void WaveLoop :: openFile( std::string fileName, bool raw, bool doNormalize )
{
WvIn::readData( index );
// Call close() in case another file is already open.
this->closeFile();
// 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];
// Attempt to open the file ... an error might be thrown here.
file_.open( fileName, raw );
// Determine whether chunking or not.
if ( file_.fileSize() > chunkThreshold_ ) {
chunking_ = true;
chunkPointer_ = 0;
data_.resize( chunkSize_, file_.channels() );
if ( doNormalize ) normalizing_ = true;
else normalizing_ = false;
}
else {
chunking_ = false;
data_.resize( file_.fileSize() + 1, file_.channels() );
}
// Load all or part of the data.
file_.read( data_, 0, doNormalize );
if ( chunking_ ) { // If chunking, save the first sample frame for later.
firstFrame_.resize( 1, data_.channels() );
for ( unsigned int i=0; i<data_.channels(); i++ )
firstFrame_[i] = data_[i];
}
else { // If not chunking, copy the first sample frame to the last.
for ( unsigned int i=0; i<data_.channels(); i++ )
data_( data_.frames() - 1, i ) = data_[i];
}
// Resize our lastOutputs container.
lastOutputs_.resize( 1, file_.channels() );
// Set default rate based on file sampling rate.
this->setRate( data_.dataRate() / Stk::sampleRate() );
if ( doNormalize & !chunking_ ) this->normalize();
this->reset();
}
void WaveLoop :: setFrequency(StkFloat frequency)
void WaveLoop :: setRate( StkFloat rate )
{
rate_ = rate;
if ( fmod( rate_, 1.0 ) != 0.0 ) interpolate_ = true;
else interpolate_ = false;
}
void WaveLoop :: setFrequency( StkFloat frequency )
{
// This is a looping frequency.
rate_ = fileSize_ * frequency / Stk::sampleRate();
this->setRate( file_.fileSize() * frequency / Stk::sampleRate() );
}
void WaveLoop :: addTime(StkFloat time)
void WaveLoop :: addTime( StkFloat time )
{
// Add an absolute time in samples
// Add an absolute time in samples.
time_ += time;
while (time_ < 0.0)
time_ += fileSize_;
while (time_ >= fileSize_)
time_ -= fileSize_;
StkFloat fileSize = file_.fileSize();
while ( time_ < 0.0 )
time_ += fileSize;
while ( time_ >= fileSize )
time_ -= fileSize;
}
void WaveLoop :: addPhase(StkFloat angle)
void WaveLoop :: addPhase( StkFloat angle )
{
// Add a time in cycles (one cycle = fileSize).
time_ += fileSize_ * angle;
StkFloat fileSize = file_.fileSize();
time_ += fileSize * angle;
while (time_ < 0.0)
time_ += fileSize_;
while (time_ >= fileSize_)
time_ -= fileSize_;
while ( time_ < 0.0 )
time_ += fileSize;
while ( time_ >= fileSize )
time_ -= fileSize;
}
void WaveLoop :: addPhaseOffset(StkFloat angle)
void WaveLoop :: addPhaseOffset( StkFloat angle )
{
// Add a phase offset in cycles, where 1.0 = fileSize.
phaseOffset_ = fileSize_ * angle;
phaseOffset_ = file_.fileSize() * angle;
}
const StkFloat *WaveLoop :: tickFrame(void)
void WaveLoop :: computeFrame( void )
{
register StkFloat tyme, alpha;
register unsigned long i, index;
// Check limits of time address ... if necessary, recalculate modulo
// fileSize.
StkFloat fileSize = file_.fileSize();
while ( time_ < 0.0 )
time_ += fileSize;
while ( time_ >= fileSize )
time_ -= fileSize;
// Check limits of time address ... if necessary, recalculate modulo fileSize.
while (time_ < 0.0)
time_ += fileSize_;
while (time_ >= fileSize_)
time_ -= fileSize_;
if (phaseOffset_) {
StkFloat tyme;
if ( phaseOffset_ ) {
tyme = time_ + phaseOffset_;
while (tyme < 0.0)
tyme += fileSize_;
while (tyme >= fileSize_)
tyme -= fileSize_;
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);
if ( ( time_ < (StkFloat) chunkPointer_ ) ||
( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) ) {
while ( time_ < (StkFloat) chunkPointer_ ) { // negative rate
chunkPointer_ -= chunkSize_ - 1; // overlap chunks by one frame
if ( chunkPointer_ < 0 ) chunkPointer_ = 0;
}
while ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) { // positive rate
chunkPointer_ += chunkSize_ - 1; // overlap chunks by one frame
if ( chunkPointer_ + chunkSize_ > file_.fileSize() ) { // at end of file
chunkPointer_ = file_.fileSize() - chunkSize_ + 1; // leave extra frame at end of buffer
// Now fill extra frame with first frame data.
for ( unsigned int j=0; j<firstFrame_.channels(); j++ )
data_( data_.frames() - 1, j ) = firstFrame_[j];
}
}
// Load more data.
file_.read( data_, chunkPointer_, normalizing_ );
}
// 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 - (StkFloat) index;
index *= channels_;
for (i=0; i<channels_; i++) {
lastOutputs_[i] = data_[index];
lastOutputs_[i] += (alpha * (data_[index+channels_] - lastOutputs_[i]));
index++;
if ( interpolate_ ) {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = data_.interpolate( tyme, i );
}
if (chunking_) {
// Scale outputs by gain.
for (i=0; i<channels_; i++) lastOutputs_[i] *= gain_;
else {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = data_( (size_t) tyme, i );
}
// Increment time, which can be negative.
time_ += rate_;
return lastOutputs_;
}
StkFloat *WaveLoop :: tickFrame(StkFloat *frameVector, unsigned int frames)
{
return WvIn::tickFrame( frameVector, frames );
}
StkFrames& WaveLoop :: tickFrame( StkFrames& frames )
{
return WvIn::tickFrame( frames );
}

View File

@@ -18,7 +18,7 @@
#include "Whistle.h"
#include "SKINI.msg"
#include <math.h>
#include <cmath>
const int CAN_RADIUS = 100;
const int PEA_RADIUS = 30;
@@ -35,9 +35,7 @@ const StkFloat ENV_RATE = 0.001;
Whistle :: Whistle()
{
// Concatenate the STK rawwave path to the rawwave file
sine_ = new WaveLoop( ( Stk::rawwavePath() + "sinewave.raw").c_str(), true );
sine_->setFrequency( 2800.0 );
sine_.setFrequency( 2800.0 );
can_.setRadius( CAN_RADIUS );
can_.setPosition(0, 0, 0); // set can location
@@ -71,7 +69,9 @@ Whistle :: Whistle()
Whistle :: ~Whistle()
{
delete sine_;
#ifdef WHISTLE_ANIMATION
printf("Exit, Whistle bye bye!!\n");
#endif
}
void Whistle :: clear()
@@ -124,7 +124,7 @@ void Whistle :: noteOff(StkFloat amplitude)
int frameCount = 0;
StkFloat Whistle :: tick()
StkFloat Whistle :: computeSample()
{
StkFloat soundMix, tempFreq;
StkFloat envOut = 0, temp, temp1, temp2, tempX, tempY;
@@ -163,7 +163,7 @@ StkFloat Whistle :: tick()
tempFreq = 1.0 + fippleFreqMod_*(0.25-temp) + blowFreqMod_*(envOut-1.0);
tempFreq *= baseFrequency_;
sine_->setFrequency(tempFreq);
sine_.setFrequency(tempFreq);
tempVectorP_ = pea_.getPosition();
temp = can_.isInside(tempVectorP_);
@@ -211,22 +211,12 @@ StkFloat Whistle :: tick()
}
temp = envOut * envOut * gain / 2;
soundMix = temp * ( sine_->tick() + ( noiseGain_*noise_.tick() ) );
soundMix = temp * ( sine_.tick() + ( noiseGain_*noise_.tick() ) );
lastOutput_ = 0.25 * soundMix; // should probably do one-zero filter here
return lastOutput_;
}
StkFloat *Whistle :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Whistle :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}
void Whistle :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;
@@ -241,18 +231,21 @@ void Whistle :: controlChange(int number, StkFloat value)
handleError( StkError::WARNING );
}
if (number == __SK_NoiseLevel_) // 4
if ( number == __SK_NoiseLevel_ ) // 4
noiseGain_ = 0.25 * norm;
else if (number == __SK_ModFrequency_) // 11
else if ( number == __SK_ModFrequency_ ) // 11
fippleFreqMod_ = norm;
else if (number == __SK_ModWheel_) // 1
else if ( number == __SK_ModWheel_ ) // 1
fippleGainMod_ = norm;
else if (number == __SK_AfterTouch_Cont_) // 128
else if ( number == __SK_AfterTouch_Cont_ ) // 128
envelope_.setTarget( norm * 2.0 );
else if (number == __SK_Breath_) // 2
else if ( number == __SK_Breath_ ) // 2
blowFreqMod_ = norm * 0.5;
else if (number == __SK_Sustain_) // 64
if (value < 1.0) subSample_ = 1;
else if ( number == __SK_Sustain_ ) { // 64
subSample_ = (int) value;
if ( subSample_ < 1.0 ) subSample_ = 1;
envelope_.setRate( ENV_RATE / subSample_ );
}
else {
errorString_ << "Whistle::controlChange: undefined control number (" << number << ")!";
handleError( StkError::WARNING );

View File

@@ -26,7 +26,7 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
@@ -56,7 +56,7 @@ Wurley :: Wurley()
adsr_[3]->setAllTimes( 0.001, 0.15, 0.0, 0.04);
twozero_.setGain( 2.0 );
vibrato_->setFrequency( 8.0 );
vibrato_.setFrequency( 8.0 );
}
Wurley :: ~Wurley()
@@ -87,7 +87,7 @@ void Wurley :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat Wurley :: tick()
StkFloat Wurley :: computeSample()
{
StkFloat temp, temp2;
@@ -104,19 +104,10 @@ StkFloat Wurley :: tick()
temp += control2_ * 0.5 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
// Calculate amplitude modulation and apply it to output.
temp2 = vibrato_->tick() * modDepth_;
temp2 = vibrato_.tick() * modDepth_;
temp = temp * (1.0 + temp2);
lastOutput_ = temp * 0.5;
return lastOutput_;
}
StkFloat *Wurley :: tick(StkFloat *vector, unsigned int vectorSize)
{
return Instrmnt::tick( vector, vectorSize );
}
StkFrames& Wurley :: tick( StkFrames& frames, unsigned int channel )
{
return Instrmnt::tick( frames, channel );
}

View File

@@ -1,841 +1,57 @@
/***************************************************/
/*! \class WvIn
\brief STK audio data input base class.
\brief STK audio input abstract base class.
This class provides input support for various
audio file formats. It also serves as a base
class for "realtime" streaming subclasses.
This class provides common functionality for a variety of audio
data input subclasses.
WvIn loads the contents of an audio file for
subsequent output. Linear interpolation is
used for fractional "read rates".
WvIn supports multi-channel data. It is important to distinguish
the tick() methods, which return samples produced by averaging
across sample frames, from the tickFrame() methods, which return
references or pointers to multi-channel sample frames.
WvIn 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.
Both interleaved and non-interleaved data is supported via the use
of StkFrames objects.
Small files are completely read into local
memory during instantiation. Large files are
read incrementally from disk. The file size
threshold and the increment size values are
defined in WvIn.h.
When the end of a file is reached, subsequent
calls to the tick() functions return the data
values at the end of the file.
WvIn currently supports WAV, AIFF, SND (AU),
MAT-file (Matlab), and STK RAW file formats.
Signed integer (8-, 16-, and 32-bit) and floating-
point (32- and 64-bit) data types are supported.
Compressed data types are not supported. If using
MAT-files, data should be saved in an array with
each data channel filling a matrix row. The sample
rate for MAT-files is assumed to be 44100 Hz.
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "WvIn.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <math.h>
#include <cmath>
WvIn :: WvIn()
{
init();
}
WvIn :: WvIn( std::string fileName, bool raw, bool doNormalize )
{
init();
openFile( fileName, raw, doNormalize );
}
WvIn :: ~WvIn()
{
if (fd_)
fclose(fd_);
if (data_)
delete [] data_;
if (lastOutputs_)
delete [] lastOutputs_;
}
void WvIn :: init( void )
StkFloat WvIn :: lastOut( void ) const
{
fd_ = 0;
data_ = 0;
lastOutputs_ = 0;
chunking_ = false;
finished_ = true;
interpolate_ = false;
bufferSize_ = 0;
channels_ = 0;
time_ = 0.0;
}
if ( lastOutputs_.empty() ) return 0.0;
void WvIn :: closeFile( void )
{
if ( fd_ ) fclose( fd_ );
finished_ = true;
}
void WvIn :: openFile( std::string fileName, bool raw, bool doNormalize )
{
closeFile();
// Try to open the file.
fd_ = fopen(fileName.c_str(), "rb");
if (!fd_) {
errorString_ << "WvIn::openFile: could not open or find file (" << fileName << ")!";
handleError( StkError::FILE_NOT_FOUND );
}
unsigned long lastChannels = channels_;
unsigned long samples, lastSamples = (bufferSize_+1)*channels_;
bool result = false;
if ( raw )
result = getRawInfo( fileName.c_str() );
else {
char header[12];
if ( fread(&header, 4, 3, fd_) != 3 ) goto error;
if ( !strncmp(header, "RIFF", 4) &&
!strncmp(&header[8], "WAVE", 4) )
result = getWavInfo( fileName.c_str() );
else if ( !strncmp(header, ".snd", 4) )
result = getSndInfo( fileName.c_str() );
else if ( !strncmp(header, "FORM", 4) &&
(!strncmp(&header[8], "AIFF", 4) || !strncmp(&header[8], "AIFC", 4) ) )
result = getAifInfo( fileName.c_str() );
else {
if ( fseek(fd_, 126, SEEK_SET) == -1 ) goto error;
if ( fread(&header, 2, 1, fd_) != 1 ) goto error;
if (!strncmp(header, "MI", 2) ||
!strncmp(header, "IM", 2) )
result = getMatInfo( fileName.c_str() );
else {
errorString_ << "WvIn::openFile: file (" << fileName << ") format unknown.";
handleError( StkError::FILE_UNKNOWN_FORMAT );
}
}
}
if ( result == false )
handleError( StkError::FILE_ERROR );
if ( fileSize_ == 0 ) {
errorString_ << "WvIn::openFile: file (" << fileName << ") data size is zero!";
handleError( StkError::FILE_ERROR );
}
// Allocate new memory if necessary.
samples = (bufferSize_+1)*channels_;
if ( lastSamples < samples ) {
if ( data_ ) delete [] data_;
data_ = (StkFloat *) new StkFloat[samples];
}
if ( lastChannels < channels_ ) {
if ( lastOutputs_ ) delete [] lastOutputs_;
lastOutputs_ = (StkFloat *) new StkFloat[channels_];
}
if ( fmod(rate_, 1.0) != 0.0 ) interpolate_ = true;
chunkPointer_ = 0;
reset();
readData( 0 ); // Load file data.
if ( doNormalize ) normalize();
finished_ = false;
return;
error:
errorString_ << "WvIn::openFile: error reading file (" << fileName << ")!";
handleError( StkError::FILE_ERROR );
}
bool WvIn :: getRawInfo( const char *fileName )
{
// Use the system call "stat" to determine the file length.
struct stat filestat;
if ( stat(fileName, &filestat) == -1 ) {
errorString_ << "WvIn: Could not stat RAW file (" << fileName << ").";
return false;
}
fileSize_ = (long) filestat.st_size / 2; // length in 2-byte samples
bufferSize_ = fileSize_;
if (fileSize_ > CHUNK_THRESHOLD) {
chunking_ = true;
bufferSize_ = CHUNK_SIZE;
gain_ = 1.0 / 32768.0;
}
// STK rawwave files have no header and are assumed to contain a
// monophonic stream of 16-bit signed integers in big-endian byte
// order with a sample rate of 22050 Hz.
channels_ = 1;
dataOffset_ = 0;
rate_ = (StkFloat) 22050.0 / Stk::sampleRate();
fileRate_ = 22050.0;
interpolate_ = false;
dataType_ = STK_SINT16;
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
}
bool WvIn :: getWavInfo( const char *fileName )
{
// Find "format" chunk ... it must come before the "data" chunk.
char id[4];
SINT32 chunkSize;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
while ( strncmp(id, "fmt ", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Check that the data is not compressed.
SINT16 format_tag;
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; // Read fmt chunk size.
if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&format_tag);
swap32((unsigned char *)&chunkSize);
#endif
if (format_tag != 1 && format_tag != 3 ) { // PCM = 1, FLOAT = 3
errorString_ << "WvIn: "<< fileName << " contains an unsupported data format type (" << format_tag << ").";
return false;
}
// Get number of channels from the header.
SINT16 temp;
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
channels_ = (unsigned int ) temp;
// Get file sample rate from the header.
SINT32 srate;
if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&srate);
#endif
fileRate_ = (StkFloat) srate;
// Set default rate based on file sampling rate.
rate_ = (StkFloat) ( srate / Stk::sampleRate() );
// Determine the data type.
dataType_ = 0;
if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error; // Locate bits_per_sample info.
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
if ( format_tag == 1 ) {
if (temp == 8)
dataType_ = STK_SINT8;
else if (temp == 16)
dataType_ = STK_SINT16;
else if (temp == 32)
dataType_ = STK_SINT32;
}
else if ( format_tag == 3 ) {
if (temp == 32)
dataType_ = STK_FLOAT32;
else if (temp == 64)
dataType_ = STK_FLOAT64;
}
if ( dataType_ == 0 ) {
errorString_ << "WvIn: " << temp << " bits per sample with data format " << format_tag << " are not supported (" << fileName << ").";
return false;
}
// Jump over any remaining part of the "fmt" chunk.
if ( fseek(fd_, chunkSize-16, SEEK_CUR) == -1 ) goto error;
// Find "data" chunk ... it must come after the "fmt" chunk.
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
while ( strncmp(id, "data", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Get length of data from the header.
SINT32 bytes;
if ( fread(&bytes, 4, 1, fd_) != 1 ) goto error;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fileSize_ = 8 * bytes / temp / channels_; // sample frames
bufferSize_ = fileSize_;
if (fileSize_ > CHUNK_THRESHOLD) {
chunking_ = true;
bufferSize_ = CHUNK_SIZE;
}
dataOffset_ = ftell(fd_);
byteswap_ = false;
#ifndef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
error:
errorString_ << "WvIn: error reading WAV file (" << fileName << ").";
return false;
}
bool WvIn :: getSndInfo( const char *fileName )
{
// Determine the data type.
SINT32 format;
if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error; // Locate format
if ( fread(&format, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&format);
#endif
if (format == 2) dataType_ = STK_SINT8;
else if (format == 3) dataType_ = STK_SINT16;
else if (format == 5) dataType_ = STK_SINT32;
else if (format == 6) dataType_ = STK_FLOAT32;
else if (format == 7) dataType_ = STK_FLOAT64;
else {
errorString_ << "WvIn: data format in file " << fileName << " is not supported.";
return false;
}
// Get file sample rate from the header.
SINT32 srate;
if ( fread(&srate, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&srate);
#endif
fileRate_ = (StkFloat) srate;
// Set default rate based on file sampling rate.
rate_ = (StkFloat) ( srate / sampleRate() );
// Get number of channels from the header.
SINT32 chans;
if ( fread(&chans, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&chans);
#endif
channels_ = chans;
if ( fseek(fd_, 4, SEEK_SET) == -1 ) goto error;
if ( fread(&dataOffset_, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&dataOffset_);
#endif
// Get length of data from the header.
if ( fread(&fileSize_, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&fileSize_);
#endif
fileSize_ /= 2 * channels_; // Convert to sample frames.
bufferSize_ = fileSize_;
if (fileSize_ > CHUNK_THRESHOLD) {
chunking_ = true;
bufferSize_ = CHUNK_SIZE;
}
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
error:
errorString_ << "WvIn: Error reading SND file (" << fileName << ").";
return false;
}
bool WvIn :: getAifInfo( const char *fileName )
{
bool aifc = false;
char id[4];
// Determine whether this is AIFF or AIFC.
if ( fseek(fd_, 8, SEEK_SET) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
if ( !strncmp(id, "AIFC", 4) ) aifc = true;
// Find "common" chunk
SINT32 chunkSize;
if ( fread(&id, 4, 1, fd_) != 1) goto error;
while ( strncmp(id, "COMM", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Get number of channels from the header.
SINT16 temp;
if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error; // Jump over chunk size
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
channels_ = temp;
// Get length of data from the header.
SINT32 frames;
if ( fread(&frames, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&frames);
#endif
fileSize_ = frames; // sample frames
bufferSize_ = fileSize_;
if (fileSize_ > CHUNK_THRESHOLD) {
chunking_ = true;
bufferSize_ = CHUNK_SIZE;
}
// Read the number of bits per sample.
if ( fread(&temp, 2, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap16((unsigned char *)&temp);
#endif
// Get file sample rate from the header. For AIFF files, this value
// is stored in a 10-byte, IEEE Standard 754 floating point number,
// so we need to convert it first.
unsigned char srate[10];
unsigned char exp;
unsigned long mantissa;
unsigned long last;
if ( fread(&srate, 10, 1, fd_) != 1 ) goto error;
mantissa = (unsigned long) *(unsigned long *)(srate+2);
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&mantissa);
#endif
exp = 30 - *(srate+1);
last = 0;
while (exp--) {
last = mantissa;
mantissa >>= 1;
}
if (last & 0x00000001) mantissa++;
fileRate_ = (StkFloat) mantissa;
// Set default rate based on file sampling rate.
rate_ = (StkFloat) ( fileRate_ / sampleRate() );
// Determine the data format.
dataType_ = 0;
if ( aifc == false ) {
if ( temp == 8 ) dataType_ = STK_SINT8;
else if ( temp == 16 ) dataType_ = STK_SINT16;
else if ( temp == 32 ) dataType_ = STK_SINT32;
}
else {
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
if ( (!strncmp(id, "fl32", 4) || !strncmp(id, "FL32", 4)) && temp == 32 ) dataType_ = STK_FLOAT32;
else if ( (!strncmp(id, "fl64", 4) || !strncmp(id, "FL64", 4)) && temp == 64 ) dataType_ = STK_FLOAT64;
}
if ( dataType_ == 0 ) {
errorString_ << "WvIn: " << temp << " bits per sample in file " << fileName << " are not supported.";
return false;
}
// Start at top to find data (SSND) chunk ... chunk order is undefined.
if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error;
// Find data (SSND) chunk
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
while ( strncmp(id, "SSND", 4) ) {
if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&chunkSize);
#endif
if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error;
if ( fread(&id, 4, 1, fd_) != 1 ) goto error;
}
// Skip over chunk size, offset, and blocksize fields
if ( fseek(fd_, 12, SEEK_CUR) == -1 ) goto error;
dataOffset_ = ftell(fd_);
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
return true;
error:
errorString_ << "WvIn: Error reading AIFF file (" << fileName << ").";
return false;
}
bool WvIn :: getMatInfo( const char *fileName )
{
// Verify this is a version 5 MAT-file format.
char head[4];
if ( fseek(fd_, 0, SEEK_SET) == -1 ) goto error;
if ( fread(&head, 4, 1, fd_) != 1 ) goto error;
// If any of the first 4 characters of the header = 0, then this is
// a Version 4 MAT-file.
if ( strstr(head, "0") ) {
errorString_ << "WvIn: " << fileName << " appears to be a Version 4 MAT-file, which is not currently supported.";
return false;
}
// Determine the endian-ness of the file.
char mi[2];
byteswap_ = false;
// Locate "M" and "I" characters in header.
if ( fseek(fd_, 126, SEEK_SET) == -1 ) goto error;
if ( fread(&mi, 2, 1, fd_) != 1) goto error;
#ifdef __LITTLE_ENDIAN__
if ( !strncmp(mi, "MI", 2) )
byteswap_ = true;
else if ( strncmp(mi, "IM", 2) ) goto error;
#else
if ( !strncmp(mi, "IM", 2))
byteswap_ = true;
else if ( strncmp(mi, "MI", 2) ) goto error;
#endif
// Check the data element type
SINT32 datatype;
if ( fread(&datatype, 4, 1, fd_) != 1 ) goto error;
if ( byteswap_ ) swap32((unsigned char *)&datatype);
if (datatype != 14) {
errorString_ << "WvIn: The file does not contain a single Matlab array (or matrix) data element.";
return false;
}
// Determine the array data type.
SINT32 tmp;
SINT32 size;
if ( fseek(fd_, 168, SEEK_SET) == -1 ) goto error;
if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&tmp);
if (tmp == 1) { // array name > 4 characters
if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error; // get array name length
if (byteswap_) swap32((unsigned char *)&tmp);
size = (SINT32) ceil((float)tmp / 8);
if ( fseek(fd_, size*8, SEEK_CUR) == -1 ) goto error; // jump over array name
}
else { // array name <= 4 characters, compressed data element
if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error;
}
if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&tmp);
if ( tmp == 1 ) dataType_ = STK_SINT8;
else if ( tmp == 3 ) dataType_ = STK_SINT16;
else if ( tmp == 5 ) dataType_ = STK_SINT32;
else if ( tmp == 7 ) dataType_ = STK_FLOAT32;
else if ( tmp == 9 ) dataType_ = STK_FLOAT64;
else {
errorString_ << "WvIn: The MAT-file array data format (" << tmp << ") is not supported.";
return false;
}
// Get number of rows from the header.
SINT32 rows;
if ( fseek(fd_, 160, SEEK_SET) == -1 ) goto error;
if ( fread(&rows, 4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&rows);
// Get number of columns from the header.
SINT32 columns;
if ( fread(&columns,4, 1, fd_) != 1 ) goto error;
if (byteswap_) swap32((unsigned char *)&columns);
// Assume channels = smaller of rows or columns.
if (rows < columns) {
channels_ = rows;
fileSize_ = columns;
}
else {
errorString_ << "WvIn: Transpose the MAT-file array so that audio channels fill matrix rows (not columns).";
return false;
}
bufferSize_ = fileSize_;
if (fileSize_ > CHUNK_THRESHOLD) {
chunking_ = true;
bufferSize_ = CHUNK_SIZE;
}
// Move read pointer to the data in the file.
SINT32 headsize;
if ( fseek(fd_, 132, SEEK_SET) == -1 ) goto error;
if ( fread(&headsize, 4, 1, fd_) != 1 ) goto error; // file size from 132nd byte
if (byteswap_) swap32((unsigned char *)&headsize);
headsize -= fileSize_ * 8 * channels_;
if ( fseek(fd_, headsize, SEEK_CUR) == -1 ) goto error;
dataOffset_ = ftell(fd_);
// Assume MAT-files have 44100 Hz sample rate.
fileRate_ = 44100.0;
// Set default rate based on file sampling rate.
rate_ = (StkFloat) ( fileRate_ / sampleRate() );
return true;
error:
errorString_ << "WvIn: Error reading MAT-file (" << fileName << ").";
return false;
}
void WvIn :: readData( unsigned long index )
{
while (index < (unsigned long)chunkPointer_) {
// Negative rate.
chunkPointer_ -= CHUNK_SIZE;
bufferSize_ = CHUNK_SIZE;
if (chunkPointer_ < 0) {
bufferSize_ += chunkPointer_;
chunkPointer_ = 0;
}
}
while (index >= chunkPointer_+bufferSize_) {
// Positive rate.
chunkPointer_ += CHUNK_SIZE;
bufferSize_ = CHUNK_SIZE;
if ( (unsigned long)chunkPointer_+CHUNK_SIZE >= fileSize_) {
bufferSize_ = fileSize_ - chunkPointer_;
}
}
long i, length = bufferSize_;
bool endfile = (chunkPointer_+bufferSize_ == fileSize_);
if ( !endfile ) length += 1;
// Read samples into data[]. Use StkFloat data structure
// to store samples.
if ( dataType_ == STK_SINT16 ) {
SINT16 *buf = (SINT16 *)data_;
if (fseek(fd_, dataOffset_+(long)(chunkPointer_*channels_*2), SEEK_SET) == -1) goto error;
if (fread(buf, length*channels_, 2, fd_) != 2 ) goto error;
if ( byteswap_ ) {
SINT16 *ptr = buf;
for (i=length*channels_-1; i>=0; i--)
swap16((unsigned char *)(ptr++));
}
for (i=length*channels_-1; i>=0; i--)
data_[i] = buf[i];
}
else if ( dataType_ == STK_SINT32 ) {
SINT32 *buf = (SINT32 *)data_;
if (fseek(fd_, dataOffset_+(long)(chunkPointer_*channels_*4), SEEK_SET) == -1) goto error;
if (fread(buf, length*channels_, 4, fd_) != 4 ) goto error;
if ( byteswap_ ) {
SINT32 *ptr = buf;
for (i=length*channels_-1; i>=0; i--)
swap32((unsigned char *)(ptr++));
}
for (i=length*channels_-1; i>=0; i--)
data_[i] = buf[i];
}
else if ( dataType_ == STK_FLOAT32 ) {
FLOAT32 *buf = (FLOAT32 *)data_;
if (fseek(fd_, dataOffset_+(long)(chunkPointer_*channels_*4), SEEK_SET) == -1) goto error;
if (fread(buf, length*channels_, 4, fd_) != 4 ) goto error;
if ( byteswap_ ) {
FLOAT32 *ptr = buf;
for (i=length*channels_-1; i>=0; i--)
swap32((unsigned char *)(ptr++));
}
for (i=length*channels_-1; i>=0; i--)
data_[i] = buf[i];
}
else if ( dataType_ == STK_FLOAT64 ) {
FLOAT64 *buf = (FLOAT64 *)data_;
if (fseek(fd_, dataOffset_+(long)(chunkPointer_*channels_*8), SEEK_SET) == -1) goto error;
if (fread(buf, length*channels_, 8, fd_) != 8 ) goto error;
if ( byteswap_ ) {
FLOAT64 *ptr = buf;
for (i=length*channels_-1; i>=0; i--)
swap64((unsigned char *)(ptr++));
}
for (i=length*channels_-1; i>=0; i--)
data_[i] = buf[i];
}
else if ( dataType_ == STK_SINT8 ) {
unsigned char *buf = (unsigned char *)data_;
if (fseek(fd_, dataOffset_+(long)(chunkPointer_*channels_), SEEK_SET) == -1) goto error;
if (fread(buf, length*channels_, 1, fd_) != 1 ) goto error;
for (i=length*channels_-1; i>=0; i--)
data_[i] = buf[i] - 128.0; // 8-bit WAV data is unsigned!
}
// If at end of file, repeat last sample frame for interpolation.
if ( endfile ) {
for (unsigned int j=0; j<channels_; j++)
data_[bufferSize_*channels_+j] = data_[(bufferSize_-1)*channels_+j];
}
if (!chunking_) {
fclose(fd_);
fd_ = 0;
}
return;
error:
errorString_ << "WvIn: Error reading file data.";
handleError( StkError::FILE_ERROR);
}
void WvIn :: reset(void)
{
time_ = (StkFloat) 0.0;
for ( unsigned int i=0; i<channels_; i++ )
lastOutputs_[i] = 0.0;
finished_ = false;
}
void WvIn :: normalize(void)
{
this->normalize( 1.0 );
}
// Normalize all channels equally by the greatest magnitude in all of the data.
void WvIn :: normalize( StkFloat peak )
{
if (chunking_) {
if ( dataType_ == STK_SINT8 ) gain_ = peak / 128.0;
else if ( dataType_ == STK_SINT16 ) gain_ = peak / 32768.0;
else if ( dataType_ == STK_SINT32 ) gain_ = peak / 2147483648.0;
else if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) gain_ = peak;
return;
}
unsigned long i;
StkFloat max = 0.0;
for (i=0; i<channels_*bufferSize_; i++) {
if (fabs(data_[i]) > max)
max = (StkFloat) fabs((double) data_[i]);
}
if (max > 0.0) {
max = 1.0 / max;
max *= peak;
for (i=0;i<=channels_*bufferSize_;i++)
data_[i] *= max;
}
}
unsigned long WvIn :: getSize(void) const
{
return fileSize_;
}
unsigned int WvIn :: getChannels(void) const
{
return channels_;
}
StkFloat WvIn :: getFileRate(void) const
{
return fileRate_;
}
void WvIn :: setRate(StkFloat aRate)
{
rate_ = aRate;
// If negative rate and at beginning of sound, move pointer to end
// of sound.
if ( (rate_ < 0) && (time_ == 0.0) ) time_ += rate_ + fileSize_;
if (fmod(rate_, 1.0) != 0.0) interpolate_ = true;
else interpolate_ = false;
}
void WvIn :: addTime(StkFloat aTime)
{
// Add an absolute time in samples
time_ += aTime;
if (time_ < 0.0) time_ = 0.0;
if (time_ >= fileSize_) {
time_ = fileSize_;
finished_ = true;
}
}
void WvIn :: setInterpolate(bool doInterpolate)
{
interpolate_ = doInterpolate;
}
bool WvIn :: isFinished(void) const
{
return finished_;
}
const StkFloat *WvIn :: lastFrame(void) const
{
return lastOutputs_;
}
StkFloat WvIn :: lastOut(void) const
{
if ( channels_ == 1 )
return *lastOutputs_;
if ( lastOutputs_.size() == 1 )
return lastOutputs_[0];
StkFloat output = 0.0;
for ( unsigned int i=0; i<channels_; i++ ) {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ ) {
output += lastOutputs_[i];
}
return output / channels_;
return output / lastOutputs_.size();
}
StkFloat WvIn :: tick(void)
StkFloat WvIn :: tick( void )
{
this->tickFrame();
return this->lastOut();
}
StkFloat *WvIn :: tick(StkFloat *vector, unsigned int vectorSize)
{
for ( unsigned int i=0; i<vectorSize; i++ )
vector[i] = tick();
return vector;
computeFrame();
return lastOut();
}
StkFrames& WvIn :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "WvIn::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
if ( channel >= frames.channels() ) {
errorString_ << "WvIn::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
@@ -845,103 +61,56 @@ StkFrames& WvIn :: tick( StkFrames& frames, unsigned int channel )
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick();
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[iStart + i] = tick();
frames[iStart++] = tick();
}
return frames;
}
const StkFloat *WvIn :: tickFrame(void)
{
if (finished_) return lastOutputs_;
register StkFloat 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_;
}
// Integer part of time address.
register unsigned long index = (unsigned long) tyme;
register unsigned long i;
if (interpolate_) {
// Linear interpolation ... fractional part of time address.
register StkFloat alpha = tyme - (StkFloat) index;
index *= channels_;
for (i=0; i<channels_; i++) {
lastOutputs_[i] = data_[index];
lastOutputs_[i] += (alpha * (data_[index+channels_] - lastOutputs_[i]));
index++;
}
}
else {
index *= channels_;
for (i=0; i<channels_; i++)
lastOutputs_[i] = data_[index++];
}
if (chunking_) {
// Scale outputs by gain.
for (i=0; i<channels_; i++) lastOutputs_[i] *= gain_;
}
// Increment time, which can be negative.
time_ += rate_;
if ( time_ < 0.0 || time_ >= fileSize_ )
finished_ = true;
return lastOutputs_;
}
StkFloat *WvIn :: tickFrame(StkFloat *frameVector, unsigned int frames)
{
unsigned int j;
for ( unsigned int i=0; i<frames; i++ ) {
this->tickFrame();
for ( j=0; j<channels_; j++ )
frameVector[i*channels_+j] = lastOutputs_[j];
}
return frameVector;
}
StkFrames& WvIn :: tickFrame( StkFrames& frames )
{
if ( channels_ != frames.channels() ) {
unsigned int nChannels = lastOutputs_.channels();
if ( nChannels == 0 ) {
errorString_ << "WvIn::tickFrame(): no data has been loaded!";
handleError( StkError::WARNING );
return frames;
}
if ( nChannels != frames.channels() ) {
errorString_ << "WvIn::tickFrame(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
unsigned int j;
if ( channels_ > 1 && frames.interleaved() == false ) {
unsigned int jump = frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ ) {
this->tickFrame();
for ( j=0; j<channels_; j++ )
frames[i*channels_+j*jump] = lastOutputs_[j];
}
}
else {
if ( nChannels == 1 || frames.interleaved() ) {
unsigned int counter = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
this->tickFrame();
for ( j=0; j<channels_; j++ )
this->computeFrame();
for ( j=0; j<nChannels; j++ )
frames[counter++] = lastOutputs_[j];
}
}
else { // non-interleaved data
unsigned int hop = frames.frames();
unsigned int index;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
this->computeFrame();
index = i;
for ( j=0; j<nChannels; j++ ) {
frames[index] = lastOutputs_[j];
index += hop;
}
}
}
return frames;
}

View File

@@ -1,737 +1,49 @@
/***************************************************/
/*! \class WvOut
\brief STK audio data output base class.
\brief STK audio output abstract base class.
This class provides output support for various
audio file formats. It also serves as a base
class for "realtime" streaming subclasses.
This class provides common functionality for a variety of audio
data output subclasses.
WvOut writes samples to an audio file. It
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.
WvOut supports multi-channel data. It is important to distinguish
the tick() methods, which output single samples to all channels in
a sample frame, from the tickFrame() methods, which take a pointer
or reference to multi-channel sample frame data.
WvOut currently supports uncompressed WAV,
AIFF, AIFC, SND (AU), MAT-file (Matlab), and
STK RAW file formats. Signed integer (8-,
16-, and 32-bit) and floating- point (32- and
64-bit) data types are supported. STK RAW
files use 16-bit integers by definition.
MAT-files will always be written as 64-bit
floats. If a data type specification does not
match the specified file type, the data type
will automatically be modified. Compressed
data types are not supported.
Both interleaved and non-interleaved data is supported via the use
of StkFrames objects.
Currently, WvOut is non-interpolating and the
output rate is always Stk::sampleRate().
Currently, WvOut is non-interpolating and the output rate is
always Stk::sampleRate().
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "WvOut.h"
#include <math.h>
const WvOut::FILE_TYPE WvOut :: WVOUT_RAW = 1;
const WvOut::FILE_TYPE WvOut :: WVOUT_WAV = 2;
const WvOut::FILE_TYPE WvOut :: WVOUT_SND = 3;
const WvOut::FILE_TYPE WvOut :: WVOUT_AIF = 4;
const WvOut::FILE_TYPE WvOut :: WVOUT_MAT = 5;
// WAV header structure. See ftp://ftp.isi.edu/in-notes/rfc2361.txt
// for information regarding format codes.
struct wavhdr {
char riff[4]; // "RIFF"
SINT32 file_size; // in bytes
char wave[4]; // "WAVE"
char fmt[4]; // "fmt "
SINT32 chunk_size; // in bytes (16 for PCM)
SINT16 format_tag; // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law
SINT16 num_chans; // 1=mono, 2=stereo
SINT32 sample_rate;
SINT32 bytes_per_sec;
SINT16 bytes_per_samp; // 2=16-bit mono, 4=16-bit stereo
SINT16 bits_per_samp;
char data[4]; // "data"
SINT32 data_length; // in bytes
};
// SND (AU) header structure (NeXT and Sun).
struct sndhdr {
char pref[4];
SINT32 hdr_length;
SINT32 data_length;
SINT32 format;
SINT32 sample_rate;
SINT32 num_channels;
char comment[16];
};
// AIFF/AIFC header structure ... only the part common to both
// formats.
struct aifhdr {
char form[4]; // "FORM"
SINT32 form_size; // in bytes
char aiff[4]; // "AIFF" or "AIFC"
char comm[4]; // "COMM"
SINT32 comm_size; // "COMM" chunk size (18 for AIFF, 24 for AIFC)
SINT16 num_chans; // number of channels
unsigned long sample_frames; // sample frames of audio data
SINT16 sample_size; // in bits
unsigned char srate[10]; // IEEE 754 floating point format
};
struct aifssnd {
char ssnd[4]; // "SSND"
SINT32 ssnd_size; // "SSND" chunk size
unsigned long offset; // data offset in data block (should be 0)
unsigned long block_size; // not used by STK (should be 0)
};
// MAT-file 5 header structure.
struct mathdr {
char heading[124]; // Header text field
SINT16 hff[2]; // Header flag fields
SINT32 adf[11]; // Array data format fields
// There's more, but it's of variable length
};
WvOut :: WvOut()
: frameCounter_(0), clipping_(false)
{
this->init();
}
WvOut::WvOut( const char *fileName, unsigned int nChannels, FILE_TYPE type, Stk::StkFormat format )
{
this->init();
this->openFile( fileName, nChannels, type, format );
}
WvOut :: ~WvOut()
{
this->closeFile();
}
void WvOut :: init()
unsigned long WvOut :: getFrameCount( void ) const
{
fd_ = 0;
fileType_ = 0;
dataType_ = 0;
channels_ = 0;
counter_ = 0;
totalCount_ = 0;
clipping_ = false;
}
void WvOut :: closeFile( void )
{
if ( fd_ ) {
// If there's an existing file, close it first.
this->writeData( counter_ );
if ( fileType_ == WVOUT_RAW )
fclose( fd_ );
else if ( fileType_ == WVOUT_WAV )
this->closeWavFile();
else if ( fileType_ == WVOUT_SND )
this->closeSndFile();
else if ( fileType_ == WVOUT_AIF )
this->closeAifFile();
else if ( fileType_ == WVOUT_MAT )
this->closeMatFile();
fd_ = 0;
errorString_ << "WvOut: file closed, "<< getTime() << " seconds of data written.";
handleError( StkError::WARNING );
totalCount_ = 0;
}
}
void WvOut :: openFile( const char *fileName, unsigned int nChannels, WvOut::FILE_TYPE type, Stk::StkFormat format )
{
closeFile();
if ( nChannels < 1 ) {
errorString_ << "WvOut::openFile: then channels argument must be greater than zero!";
handleError( StkError::FUNCTION_ARGUMENT );
}
unsigned int lastChannels = channels_;
channels_ = nChannels;
fileType_ = type;
if ( format != STK_SINT8 && format != STK_SINT16 &&
format != STK_SINT32 && format != STK_FLOAT32 &&
format != STK_FLOAT64 ) {
errorString_ << "WvOut::openFile: unknown data type (" << format << ") specified!";
handleError( StkError::FUNCTION_ARGUMENT );
}
dataType_ = format;
bool result = false;
if ( fileType_ == WVOUT_RAW ) {
if ( channels_ != 1 ) {
errorString_ << "WvOut::openFile: STK RAW files are, by definition, always monaural (channels = " << nChannels << " not supported)!";
handleError( StkError::FUNCTION_ARGUMENT );
}
result = setRawFile( fileName );
}
else if ( fileType_ == WVOUT_WAV )
result = setWavFile( fileName );
else if ( fileType_ == WVOUT_SND )
result = setSndFile( fileName );
else if ( fileType_ == WVOUT_AIF )
result = setAifFile( fileName );
else if ( fileType_ == WVOUT_MAT )
result = setMatFile( fileName );
else {
errorString_ << "WvOut::openFile: unknown file type (" << fileType_ << ") specified!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( result == false )
handleError( StkError::FILE_ERROR );
// Allocate new memory if necessary.
if ( lastChannels < channels_ ) {
data_.resize( BUFFER_SIZE * channels_ );
}
counter_ = 0;
}
bool WvOut :: setRawFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".raw") == NULL) strcat(name, ".raw");
fd_ = fopen(name, "wb");
if ( !fd_ ) {
errorString_ << "WvOut: could not create RAW file: " << name << '.';
return false;
}
if ( dataType_ != STK_SINT16 ) {
dataType_ = STK_SINT16;
errorString_ << "WvOut: using 16-bit signed integer data format for file " << name << '.';
handleError( StkError::WARNING );
}
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
#endif
errorString_ << "WvOut: creating RAW file: " << name;
handleError( StkError::WARNING );
return true;
}
bool WvOut :: setWavFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".wav") == NULL) strcat(name, ".wav");
fd_ = fopen(name, "wb");
if ( !fd_ ) {
errorString_ << "WvOut: could not create WAV file: " << name;
return false;
}
struct wavhdr hdr = {"RIF", 44, "WAV", "fmt", 16, 1, 1,
(SINT32) Stk::sampleRate(), 0, 2, 16, "dat", 0};
hdr.riff[3] = 'F';
hdr.wave[3] = 'E';
hdr.fmt[3] = ' ';
hdr.data[3] = 'a';
hdr.num_chans = (SINT16) channels_;
if ( dataType_ == STK_SINT8 )
hdr.bits_per_samp = 8;
else if ( dataType_ == STK_SINT16 )
hdr.bits_per_samp = 16;
else if ( dataType_ == STK_SINT32 )
hdr.bits_per_samp = 32;
else if ( dataType_ == STK_FLOAT32 ) {
hdr.format_tag = 3;
hdr.bits_per_samp = 32;
}
else if ( dataType_ == STK_FLOAT64 ) {
hdr.format_tag = 3;
hdr.bits_per_samp = 64;
}
hdr.bytes_per_samp = (SINT16) (channels_ * hdr.bits_per_samp / 8);
hdr.bytes_per_sec = (SINT32) (hdr.sample_rate * hdr.bytes_per_samp);
byteswap_ = false;
#ifndef __LITTLE_ENDIAN__
byteswap_ = true;
swap32((unsigned char *)&hdr.file_size);
swap32((unsigned char *)&hdr.chunk_size);
swap16((unsigned char *)&hdr.format_tag);
swap16((unsigned char *)&hdr.num_chans);
swap32((unsigned char *)&hdr.sample_rate);
swap32((unsigned char *)&hdr.bytes_per_sec);
swap16((unsigned char *)&hdr.bytes_per_samp);
swap16((unsigned char *)&hdr.bits_per_samp);
#endif
if ( fwrite(&hdr, 4, 11, fd_) != 11 ) {
errorString_ << "WvOut: could not write WAV header for file " << name << '.';
return false;
}
errorString_ << "WvOut: creating WAV file: " << name;
handleError( StkError::WARNING );
return true;
}
void WvOut :: closeWavFile( void )
{
int bytes_per_sample = 1;
if ( dataType_ == STK_SINT16 )
bytes_per_sample = 2;
else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
bytes_per_sample = 4;
else if ( dataType_ == STK_FLOAT64 )
bytes_per_sample = 8;
SINT32 bytes = totalCount_ * channels_ * bytes_per_sample;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fseek(fd_, 40, SEEK_SET); // jump to data length
fwrite(&bytes, 4, 1, fd_);
bytes = totalCount_ * channels_ * bytes_per_sample + 44;
#ifndef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fseek(fd_, 4, SEEK_SET); // jump to file size
fwrite(&bytes, 4, 1, fd_);
fclose( fd_ );
}
bool WvOut :: setSndFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".snd") == NULL) strcat(name, ".snd");
fd_ = fopen(name, "wb");
if ( !fd_ ) {
errorString_ << "WvOut: could not create SND file: " << name;
return false;
}
struct sndhdr hdr = {".sn", 40, 0, 3, (SINT32) Stk::sampleRate(), 1, "Created by STK"};
hdr.pref[3] = 'd';
hdr.num_channels = channels_;
if ( dataType_ == STK_SINT8 )
hdr.format = 2;
else if ( dataType_ == STK_SINT16 )
hdr.format = 3;
else if ( dataType_ == STK_SINT32 )
hdr.format = 5;
else if ( dataType_ == STK_FLOAT32 )
hdr.format = 6;
else if ( dataType_ == STK_FLOAT64 )
hdr.format = 7;
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
swap32 ((unsigned char *)&hdr.hdr_length);
swap32 ((unsigned char *)&hdr.format);
swap32 ((unsigned char *)&hdr.sample_rate);
swap32 ((unsigned char *)&hdr.num_channels);
#endif
if ( fwrite(&hdr, 4, 10, fd_) != 10 ) {
errorString_ << "WvOut: Could not write SND header for file " << name << '.';
return false;
}
errorString_ << "WvOut: creating SND file: " << name;
handleError( StkError::WARNING );
return true;
}
void WvOut :: closeSndFile( void )
{
int bytes_per_sample = 1;
if ( dataType_ == STK_SINT16 )
bytes_per_sample = 2;
else if ( dataType_ == STK_SINT32 )
bytes_per_sample = 4;
else if ( dataType_ == STK_FLOAT32 )
bytes_per_sample = 4;
else if ( dataType_ == STK_FLOAT64 )
bytes_per_sample = 8;
SINT32 bytes = totalCount_ * bytes_per_sample * channels_;
#ifdef __LITTLE_ENDIAN__
swap32 ((unsigned char *)&bytes);
#endif
fseek(fd_, 8, SEEK_SET); // jump to data size
fwrite(&bytes, 4, 1, fd_);
fclose(fd_);
}
bool WvOut :: setAifFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".aif") == NULL) strcat(name, ".aif");
fd_ = fopen(name, "wb");
if ( !fd_ ) {
errorString_ << "WvOut: could not create AIF file: " << name;
return false;
}
// Common parts of AIFF/AIFC header.
struct aifhdr hdr = {"FOR", 46, "AIF", "COM", 18, 0, 0, 16, "0"};
struct aifssnd ssnd = {"SSN", 8, 0, 0};
hdr.form[3] = 'M';
hdr.aiff[3] = 'F';
hdr.comm[3] = 'M';
ssnd.ssnd[3] = 'D';
hdr.num_chans = channels_;
if ( dataType_ == STK_SINT8 )
hdr.sample_size = 8;
else if ( dataType_ == STK_SINT16 )
hdr.sample_size = 16;
else if ( dataType_ == STK_SINT32 )
hdr.sample_size = 32;
else if ( dataType_ == STK_FLOAT32 ) {
hdr.aiff[3] = 'C';
hdr.sample_size = 32;
hdr.comm_size = 24;
}
else if ( dataType_ == STK_FLOAT64 ) {
hdr.aiff[3] = 'C';
hdr.sample_size = 64;
hdr.comm_size = 24;
}
// For AIFF files, the sample rate is stored in a 10-byte,
// IEEE Standard 754 floating point number, so we need to
// convert to that.
SINT16 i;
unsigned long exp;
unsigned long rate = (unsigned long) Stk::sampleRate();
memset(hdr.srate, 0, 10);
exp = rate;
for (i=0; i<32; i++) {
exp >>= 1;
if (!exp) break;
}
i += 16383;
#ifdef __LITTLE_ENDIAN__
swap16((unsigned char *)&i);
#endif
*(SINT16 *)(hdr.srate) = (SINT16) i;
for (i=32; i; i--) {
if (rate & 0x80000000) break;
rate <<= 1;
}
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&rate);
#endif
*(unsigned long *)(hdr.srate+2) = (unsigned long) rate;
byteswap_ = false;
#ifdef __LITTLE_ENDIAN__
byteswap_ = true;
swap32((unsigned char *)&hdr.form_size);
swap32((unsigned char *)&hdr.comm_size);
swap16((unsigned char *)&hdr.num_chans);
swap16((unsigned char *)&hdr.sample_size);
swap32((unsigned char *)&ssnd.ssnd_size);
swap32((unsigned char *)&ssnd.offset);
swap32((unsigned char *)&ssnd.block_size);
#endif
// The structure boundaries don't allow a single write of 54 bytes.
if ( fwrite(&hdr, 4, 5, fd_) != 5 ) goto error;
if ( fwrite(&hdr.num_chans, 2, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.sample_frames, 4, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.sample_size, 2, 1, fd_) != 1 ) goto error;
if ( fwrite(&hdr.srate, 10, 1, fd_) != 1 ) goto error;
if ( dataType_ == STK_FLOAT32 ) {
char type[4] = {'f','l','3','2'};
char zeroes[2] = { 0, 0 };
if ( fwrite(&type, 4, 1, fd_) != 1 ) goto error;
if ( fwrite(&zeroes, 2, 1, fd_) != 1 ) goto error;
}
else if ( dataType_ == STK_FLOAT64 ) {
char type[4] = {'f','l','6','4'};
char zeroes[2] = { 0, 0 };
if ( fwrite(&type, 4, 1, fd_) != 1 ) goto error;
if ( fwrite(&zeroes, 2, 1, fd_) != 1 ) goto error;
}
if ( fwrite(&ssnd, 4, 4, fd_) != 4 ) goto error;
errorString_ << "WvOut: creating AIF file: " << name;
handleError( StkError::WARNING );
return true;
error:
errorString_ << "WvOut: could not write AIF header for file: " << name;
return false;
}
void WvOut :: closeAifFile( void )
{
unsigned long frames = (unsigned long) totalCount_;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&frames);
#endif
fseek(fd_, 22, SEEK_SET); // jump to "COMM" sample_frames
fwrite(&frames, 4, 1, fd_);
int bytes_per_sample = 1;
if ( dataType_ == STK_SINT16 )
bytes_per_sample = 2;
else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
bytes_per_sample = 4;
else if ( dataType_ == STK_FLOAT64 )
bytes_per_sample = 8;
unsigned long bytes = totalCount_ * bytes_per_sample * channels_ + 46;
if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
fseek(fd_, 4, SEEK_SET); // jump to file size
fwrite(&bytes, 4, 1, fd_);
bytes = totalCount_ * bytes_per_sample * channels_ + 8;
if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
#ifdef __LITTLE_ENDIAN__
swap32((unsigned char *)&bytes);
#endif
if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 )
fseek(fd_, 48, SEEK_SET); // jump to "SSND" chunk size
else
fseek(fd_, 42, SEEK_SET); // jump to "SSND" chunk size
fwrite(&bytes, 4, 1, fd_);
fclose( fd_ );
}
bool WvOut :: setMatFile( const char *fileName )
{
char name[8192];
strncpy(name, fileName, 8192);
if ( strstr(name, ".mat") == NULL) strcat(name, ".mat");
fd_ = fopen(name, "w+b");
if ( !fd_ ) {
errorString_ << "WvOut: could not create MAT file: " << name;
return false;
}
if ( dataType_ != STK_FLOAT64 ) {
dataType_ = STK_FLOAT64;
errorString_ << "WvOut: using 64-bit floating-point data format for file " << name << '.';
handleError( StkError::WARNING );
}
struct mathdr hdr;
strcpy(hdr.heading,"MATLAB 5.0 MAT-file, Generated using the Synthesis ToolKit in C++ (STK). By Perry R. Cook and Gary P. Scavone, 1995-2004.");
int i;
for (i=strlen(hdr.heading);i<124;i++) hdr.heading[i] = ' ';
// Header Flag Fields
hdr.hff[0] = (SINT16) 0x0100; // Version field
hdr.hff[1] = (SINT16) 'M'; // Endian indicator field ("MI")
hdr.hff[1] <<= 8;
hdr.hff[1] += 'I';
hdr.adf[0] = (SINT32) 14; // Matlab array data type value
hdr.adf[1] = (SINT32) 0; // Size of file after this point to end (in bytes)
// Don't know size yet.
// Numeric Array Subelements (4):
// 1. Array Flags
hdr.adf[2] = (SINT32) 6; // Matlab 32-bit unsigned integer data type value
hdr.adf[3] = (SINT32) 8; // 8 bytes of data to follow
hdr.adf[4] = (SINT32) 6; // Double-precision array, no array flags set
hdr.adf[5] = (SINT32) 0; // 4 bytes undefined
// 2. Array Dimensions
hdr.adf[6] = (SINT32) 5; // Matlab 32-bit signed integer data type value
hdr.adf[7] = (SINT32) 8; // 8 bytes of data to follow (2D array)
hdr.adf[8] = (SINT32) channels_; // This is the number of rows
hdr.adf[9] = (SINT32) 0; // This is the number of columns
// 3. Array Name
// We'll use fileName for the matlab array name (as well as the file name).
// If fileName is 4 characters or less, we have to use a compressed data element
// format for the array name data element. Otherwise, the array name must
// be formatted in 8-byte increments (up to 31 characters + NULL).
SINT32 namelength = (SINT32) strlen(fileName);
if (strstr(fileName, ".mat")) namelength -= 4;
if (namelength > 31) namelength = 31; // Truncate name to 31 characters.
char arrayName[64];
strncpy(arrayName, fileName, namelength);
arrayName[namelength] = '\0';
if (namelength > 4) {
hdr.adf[10] = (SINT32) 1; // Matlab 8-bit signed integer data type value
}
else { // Compressed data element format
hdr.adf[10] = namelength;
hdr.adf[10] <<= 16;
hdr.adf[10] += 1;
}
SINT32 headsize = 40; // Number of bytes in data element so far.
// Write the fixed portion of the header
if ( fwrite(&hdr, 172, 1, fd_) != 1 ) goto error;
// Write MATLAB array name
SINT32 tmp;
if (namelength > 4) {
if ( fwrite(&namelength, 4, 1, fd_) != 1) goto error;
if ( fwrite(arrayName, namelength, 1, fd_) != 1 ) goto error;
tmp = (SINT32) ceil((float)namelength / 8);
if ( fseek(fd_, tmp*8-namelength, SEEK_CUR) == -1 ) goto error;
headsize += tmp * 8;
}
else { // Compressed data element format
if ( fwrite(arrayName, namelength, 1, fd_) != 1 ) goto error;
tmp = 4 - namelength;
if ( fseek(fd_, tmp, SEEK_CUR) == -1 ) goto error;
}
// Finish writing known header information
tmp = 9; // Matlab IEEE 754 double data type
if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
tmp = 0; // Size of real part subelement in bytes (8 per sample)
if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
headsize += 8; // Total number of bytes in data element so far
if ( fseek(fd_, 132, SEEK_SET) == -1 ) goto error;
if ( fwrite(&headsize, 4, 1, fd_) != 1 ) goto error; // Write header size ... will update at end
if ( fseek(fd_, 0, SEEK_END) == -1 ) goto error;
byteswap_ = false;
printf("\nCreating MAT-file (%s) containing MATLAB array: %s\n", name, arrayName);
errorString_ << "WvOut: creating MAT-file (" << name << ") containing MATLAB array: " << arrayName;
handleError( StkError::WARNING );
return true;
error:
errorString_ << "WvOut: could not write MAT-file header for file " << name << '.';
return false;
}
void WvOut :: closeMatFile( void )
{
fseek(fd_, 164, SEEK_SET); // jump to number of columns
fwrite(&totalCount_, 4, 1, fd_);
SINT32 headsize, temp;
fseek(fd_, 132, SEEK_SET); // jump to header size
fread(&headsize, 4, 1, fd_);
temp = headsize;
headsize += (SINT32) (totalCount_ * 8 * channels_);
fseek(fd_, 132, SEEK_SET);
// Write file size (minus some header info)
fwrite(&headsize, 4, 1, fd_);
fseek(fd_, temp+132, SEEK_SET); // jumpt to data size (in bytes)
temp = totalCount_ * 8 * channels_;
fwrite(&temp, 4, 1, fd_);
fclose(fd_);
}
unsigned long WvOut :: getFrames( void ) const
{
return totalCount_;
return frameCounter_;
}
StkFloat WvOut :: getTime( void ) const
{
return (StkFloat) totalCount_ / Stk::sampleRate();
return (StkFloat) frameCounter_ / Stk::sampleRate();
}
void WvOut :: writeData( unsigned long frames )
StkFloat& WvOut :: clipTest( StkFloat& sample )
{
if ( dataType_ == STK_SINT8 ) {
if ( fileType_ == WVOUT_WAV ) { // 8-bit WAV data is unsigned!
unsigned char sample;
for ( unsigned long k=0; k<frames*channels_; k++ ) {
this->clipTest( data_[k] );
sample = (unsigned char) (data_[k] * 127.0 + 128.0);
if ( fwrite(&sample, 1, 1, fd_) != 1 ) goto error;
}
}
else {
signed char sample;
for ( unsigned long k=0; k<frames*channels_; k++ ) {
this->clipTest( data_[k] );
sample = (signed char) (data_[k] * 127.0);
//sample = ((signed char) (( data_[k] + 1.0 ) * 127.5 + 0.5)) - 128;
if ( fwrite(&sample, 1, 1, fd_) != 1 ) goto error;
}
}
}
else if ( dataType_ == STK_SINT16 ) {
SINT16 sample;
for ( unsigned long k=0; k<frames*channels_; k++ ) {
this->clipTest( data_[k] );
sample = (SINT16) (data_[k] * 32767.0);
//sample = ((SINT16) (( data_[k] + 1.0 ) * 32767.5 + 0.5)) - 32768;
if ( byteswap_ ) swap16( (unsigned char *)&sample );
if ( fwrite(&sample, 2, 1, fd_) != 1 ) goto error;
}
}
else if ( dataType_ == STK_SINT32 ) {
SINT32 sample;
for ( unsigned long k=0; k<frames*channels_; k++ ) {
this->clipTest( data_[k] );
sample = (SINT32) (data_[k] * 2147483647.0);
//sample = ((SINT32) (( data_[k] + 1.0 ) * 2147483647.5 + 0.5)) - 2147483648;
if ( byteswap_ ) swap32( (unsigned char *)&sample );
if ( fwrite(&sample, 4, 1, fd_) != 1 ) goto error;
}
}
else if ( dataType_ == STK_FLOAT32 ) {
FLOAT32 sample;
for ( unsigned long k=0; k<frames*channels_; k++ ) {
this->clipTest( data_[k] );
sample = (FLOAT32) (data_[k]);
if ( byteswap_ ) swap32( (unsigned char *)&sample );
if ( fwrite(&sample, 4, 1, fd_) != 1 ) goto error;
}
}
else if ( dataType_ == STK_FLOAT64 ) {
FLOAT64 sample;
for ( unsigned long k=0; k<frames*channels_; k++ ) {
this->clipTest( data_[k] );
sample = (FLOAT64) (data_[k]);
if ( byteswap_ ) swap64( (unsigned char *)&sample );
if ( fwrite(&sample, 8, 1, fd_) != 1 ) goto error;
}
}
return;
error:
errorString_ << "WvOut::writeData: error writing data to file!";
handleError( StkError::FILE_ERROR );
}
void WvOut :: clipTest( StkFloat& sample )
{
register bool clip = false;
bool clip = false;
if ( sample > 1.0 ) {
sample = 1.0;
clip = true;
@@ -744,141 +56,45 @@ void WvOut :: clipTest( StkFloat& sample )
if ( clip == true && clipping_ == false ) {
// First occurrence of clipping since instantiation or reset.
clipping_ = true;
errorString_ << "WvOut::writeData: data value(s) outside +-1.0 detected ... clamping at outer bound!";
errorString_ << "WvOut: data value(s) outside +-1.0 detected ... clamping at outer bound!";
handleError( StkError::WARNING );
}
return sample;
}
void WvOut :: tick( const StkFloat sample )
{
if ( !fd_ ) {
errorString_ << "WvOut::tickFrame(): no file open!";
handleError( StkError::WARNING );
return;
}
for ( unsigned int j=0; j<channels_; j++ )
data_[counter_*channels_+j] = sample;
counter_++;
totalCount_++;
if ( counter_ == BUFFER_SIZE ) {
this->writeData( BUFFER_SIZE );
counter_ = 0;
}
}
void WvOut :: tick( const StkFloat *vector, unsigned int vectorSize )
{
if ( !fd_ ) {
errorString_ << "WvOut::tickFrame(): no file open!";
handleError( StkError::WARNING );
return;
}
for (unsigned int i=0; i<vectorSize; i++)
tick( vector[i] );
this->computeSample( sample );
}
void WvOut :: tick( const StkFrames& frames, unsigned int channel )
{
if ( !fd_ ) {
errorString_ << "WvOut::tickFrame(): no file open!";
handleError( StkError::WARNING );
return;
}
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "WvOut::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
if ( channel >= frames.channels() ) {
errorString_ << "WvOut::tick(): channel argument (" << channel << ") is incompatible with StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
tick( frames[i] );
computeSample( frames[i] );
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
tick( frames[index] );
computeSample( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
tick( frames[iStart + i] );
}
}
void WvOut :: tickFrame( const StkFloat *frameVector, unsigned int frames )
{
if ( !fd_ ) {
errorString_ << "WvOut::tickFrame(): no file open!";
handleError( StkError::WARNING );
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 ) {
this->writeData( BUFFER_SIZE );
counter_ = 0;
}
computeSample( frames[iStart++] );
}
}
void WvOut :: tickFrame( const StkFrames& frames )
{
if ( !fd_ ) {
errorString_ << "WvOut::tickFrame(): no file open!";
handleError( StkError::WARNING );
return;
}
if ( channels_ != frames.channels() ) {
errorString_ << "WvOut::tickFrame(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
unsigned int j;
if ( channels_ == 1 || frames.interleaved() ) {
unsigned long iFrames = 0, iData = counter_;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<channels_; j++ ) {
data_[iData++] = frames[iFrames++];
}
counter_++;
totalCount_++;
if ( counter_ == BUFFER_SIZE ) {
this->writeData( BUFFER_SIZE );
counter_ = 0;
}
}
}
else {
unsigned int hop = frames.frames();
unsigned long iData = counter_;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<channels_; j++ ) {
data_[iData++] = frames[i + j*hop];
}
counter_++;
totalCount_++;
if ( counter_ == BUFFER_SIZE ) {
this->writeData( BUFFER_SIZE );
counter_ = 0;
}
}
}
this->computeFrames( frames );
}