mirror of
https://github.com/thestk/stk
synced 2026-01-14 05:21:53 +00:00
Version 4.2.1
This commit is contained in:
committed by
Stephen Sinclair
parent
a6381b9d38
commit
2cbce2d8bd
14
src/ADSR.cpp
14
src/ADSR.cpp
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
105
src/Blit.cpp
Normal 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
125
src/BlitSaw.cpp
Normal 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
122
src/BlitSquare.cpp
Normal 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_;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
139
src/Drummer.cpp
139
src/Drummer.cpp
@@ -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 );
|
||||
}
|
||||
|
||||
14
src/Echo.cpp
14
src/Echo.cpp
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
10
src/FM.cpp
10
src/FM.cpp
@@ -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)
|
||||
|
||||
@@ -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
721
src/FileRead.cpp
Normal 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
701
src/FileWrite.cpp
Normal 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
211
src/FileWvIn.cpp
Normal 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
152
src/FileWvOut.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
275
src/Granulate.cpp
Normal 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_;
|
||||
}
|
||||
|
||||
@@ -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
275
src/InetWvIn.cpp
Normal 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
230
src/InetWvOut.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
16
src/Moog.cpp
16
src/Moog.cpp
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
|
||||
15
src/NRev.cpp
15
src/NRev.cpp
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
698
src/RtAudio.cpp
698
src/RtAudio.cpp
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
|
||||
146
src/RtMidi.cpp
146
src/RtMidi.cpp
@@ -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;
|
||||
|
||||
116
src/RtWvIn.cpp
116
src/RtWvIn.cpp
@@ -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;
|
||||
}
|
||||
|
||||
221
src/RtWvOut.cpp
221
src/RtWvOut.cpp
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
103
src/SineWave.cpp
Normal 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_;
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 )
|
||||
|
||||
198
src/Socket.cpp
198
src/Socket.cpp
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
187
src/Stk.cpp
187
src/Stk.cpp
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
100
src/Table.cpp
100
src/Table.cpp
@@ -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
100
src/TcpClient.cpp
Normal 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
95
src/TcpServer.cpp
Normal 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 );
|
||||
}
|
||||
336
src/TcpWvIn.cpp
336
src/TcpWvIn.cpp
@@ -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 );
|
||||
}
|
||||
280
src/TcpWvOut.cpp
280
src/TcpWvOut.cpp
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
104
src/UdpSocket.cpp
Normal 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) );
|
||||
}
|
||||
@@ -49,7 +49,7 @@ StkFloat Vector3D :: getLength()
|
||||
|
||||
void Vector3D :: setXYZ(StkFloat x, StkFloat y, StkFloat z)
|
||||
{
|
||||
myX_ = z;
|
||||
myX_ = x;
|
||||
myY_ = y;
|
||||
myZ_ = z;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 );
|
||||
|
||||
209
src/WaveLoop.cpp
209
src/WaveLoop.cpp
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
927
src/WvIn.cpp
927
src/WvIn.cpp
@@ -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;
|
||||
}
|
||||
|
||||
844
src/WvOut.cpp
844
src/WvOut.cpp
@@ -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 );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user