mirror of
https://github.com/thestk/stk
synced 2026-01-18 23:21:53 +00:00
Version 4.4.0
This commit is contained in:
committed by
Stephen Sinclair
parent
d199342e86
commit
eccd8c9981
169
src/Voicer.cpp
169
src/Voicer.cpp
@@ -2,54 +2,54 @@
|
||||
/*! \class Voicer
|
||||
\brief STK voice manager class.
|
||||
|
||||
This class can be used to manage a group of
|
||||
STK instrument classes. Individual voices can
|
||||
be controlled via unique note tags.
|
||||
Instrument groups can be controlled by channel
|
||||
number.
|
||||
This class can be used to manage a group of STK instrument
|
||||
classes. Individual voices can be controlled via unique note
|
||||
tags. Instrument groups can be controlled by group number.
|
||||
|
||||
A previously constructed STK instrument class
|
||||
is linked with a voice manager using the
|
||||
addInstrument() function. An optional channel
|
||||
number argument can be specified to the
|
||||
addInstrument() function as well (default
|
||||
channel = 0). The voice manager does not
|
||||
delete any instrument instances ... it is the
|
||||
responsibility of the user to allocate and
|
||||
deallocate all instruments.
|
||||
A previously constructed STK instrument class is linked with a
|
||||
voice manager using the addInstrument() function. An optional
|
||||
group number argument can be specified to the addInstrument()
|
||||
function as well (default group = 0). The voice manager does not
|
||||
delete any instrument instances ... it is the responsibility of
|
||||
the user to allocate and deallocate all instruments.
|
||||
|
||||
The tick() function returns the mix of all
|
||||
sounding voices. Each noteOn returns a unique
|
||||
tag (credits to the NeXT MusicKit), so you can
|
||||
send control changes to specific voices within
|
||||
an ensemble. Alternately, control changes can
|
||||
be sent to all voices on a given channel.
|
||||
The tick() function returns the mix of all sounding voices. Each
|
||||
noteOn returns a unique tag (credits to the NeXT MusicKit), so you
|
||||
can send control changes to specific voices within an ensemble.
|
||||
Alternately, control changes can be sent to all voices in a given
|
||||
group.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "Voicer.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace stk {
|
||||
|
||||
Voicer :: Voicer( StkFloat decayTime )
|
||||
{
|
||||
tags_ = 23456;
|
||||
muteTime_ = (int) ( decayTime * Stk::sampleRate() );
|
||||
lastFrame_.resize( 1, 1, 0.0 );
|
||||
}
|
||||
|
||||
Voicer :: ~Voicer()
|
||||
{
|
||||
}
|
||||
|
||||
void Voicer :: addInstrument( Instrmnt *instrument, int channel )
|
||||
void Voicer :: addInstrument( Instrmnt *instrument, int group )
|
||||
{
|
||||
Voicer::Voice voice;
|
||||
voice.instrument = instrument;
|
||||
voice.channel = channel;
|
||||
voice.group = group;
|
||||
voice.noteNumber = -1;
|
||||
voices_.push_back( voice );
|
||||
|
||||
// Check output channels and resize lastFrame_ if necessary.
|
||||
if ( instrument->channelsOut() > lastFrame_.channels() ) {
|
||||
unsigned int startChannel = lastFrame_.channels();
|
||||
lastFrame_.resize( 1, instrument->channelsOut() );
|
||||
for ( unsigned int i=startChannel; i<lastFrame_.size(); i++ )
|
||||
lastFrame_[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: removeInstrument( Instrmnt *instrument )
|
||||
@@ -63,23 +63,32 @@ void Voicer :: removeInstrument( Instrmnt *instrument )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !found ) {
|
||||
if ( found ) {
|
||||
// Check output channels and resize lastFrame_ if necessary.
|
||||
unsigned int maxChannels = 1;
|
||||
for ( i=voices_.begin(); i!=voices_.end(); ++i ) {
|
||||
if ( (*i).instrument->channelsOut() > maxChannels ) maxChannels = (*i).instrument->channelsOut();
|
||||
}
|
||||
if ( maxChannels < lastFrame_.channels() )
|
||||
lastFrame_.resize( 1, maxChannels );
|
||||
}
|
||||
else {
|
||||
errorString_ << "Voicer::removeInstrument: instrument pointer not found in current voices!";
|
||||
handleError( StkError::WARNING );
|
||||
}
|
||||
}
|
||||
|
||||
long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int channel )
|
||||
long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int group )
|
||||
{
|
||||
unsigned int i;
|
||||
StkFloat frequency = (StkFloat) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
|
||||
for ( i=0; i<voices_.size(); i++ ) {
|
||||
if (voices_[i].noteNumber < 0 && voices_[i].channel == channel) {
|
||||
voices_[i].tag = tags_++;
|
||||
voices_[i].channel = channel;
|
||||
if (voices_[i].noteNumber < 0 && voices_[i].group == group) {
|
||||
voices_[i].tag = tags_++;
|
||||
voices_[i].group = group;
|
||||
voices_[i].noteNumber = noteNumber;
|
||||
voices_[i].frequency = frequency;
|
||||
voices_[i].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
|
||||
voices_[i].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
|
||||
voices_[i].sounding = 1;
|
||||
return voices_[i].tag;
|
||||
}
|
||||
@@ -88,7 +97,7 @@ long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int channel )
|
||||
// All voices are sounding, so interrupt the oldest voice.
|
||||
int voice = -1;
|
||||
for ( i=0; i<voices_.size(); i++ ) {
|
||||
if ( voices_[i].channel == channel ) {
|
||||
if ( voices_[i].group == group ) {
|
||||
if ( voice == -1 ) voice = i;
|
||||
else if ( voices_[i].tag < voices_[voice].tag ) voice = (int) i;
|
||||
}
|
||||
@@ -96,7 +105,7 @@ long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int channel )
|
||||
|
||||
if ( voice >= 0 ) {
|
||||
voices_[voice].tag = tags_++;
|
||||
voices_[voice].channel = channel;
|
||||
voices_[voice].group = group;
|
||||
voices_[voice].noteNumber = noteNumber;
|
||||
voices_[voice].frequency = frequency;
|
||||
voices_[voice].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
|
||||
@@ -107,10 +116,10 @@ long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int channel )
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Voicer :: noteOff( StkFloat noteNumber, StkFloat amplitude, int channel )
|
||||
void Voicer :: noteOff( StkFloat noteNumber, StkFloat amplitude, int group )
|
||||
{
|
||||
for ( unsigned int i=0; i<voices_.size(); i++ ) {
|
||||
if ( voices_[i].noteNumber == noteNumber && voices_[i].channel == channel ) {
|
||||
if ( voices_[i].noteNumber == noteNumber && voices_[i].group == group ) {
|
||||
voices_[i].instrument->noteOff( amplitude * ONE_OVER_128 );
|
||||
voices_[i].sounding = -muteTime_;
|
||||
}
|
||||
@@ -128,11 +137,11 @@ void Voicer :: noteOff( long tag, StkFloat amplitude )
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: setFrequency( StkFloat noteNumber, int channel )
|
||||
void Voicer :: setFrequency( StkFloat noteNumber, int group )
|
||||
{
|
||||
StkFloat frequency = (StkFloat) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
|
||||
for ( unsigned int i=0; i<voices_.size(); i++ ) {
|
||||
if ( voices_[i].channel == channel ) {
|
||||
if ( voices_[i].group == group ) {
|
||||
voices_[i].noteNumber = noteNumber;
|
||||
voices_[i].frequency = frequency;
|
||||
voices_[i].instrument->setFrequency( frequency );
|
||||
@@ -153,7 +162,7 @@ void Voicer :: setFrequency( long tag, StkFloat noteNumber )
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: pitchBend( StkFloat value, int channel )
|
||||
void Voicer :: pitchBend( StkFloat value, int group )
|
||||
{
|
||||
StkFloat pitchScaler;
|
||||
if ( value < 64.0 )
|
||||
@@ -161,7 +170,7 @@ void Voicer :: pitchBend( StkFloat value, int channel )
|
||||
else
|
||||
pitchScaler = pow(2.0, (value-64.0)/64.0);
|
||||
for ( unsigned int i=0; i<voices_.size(); i++ ) {
|
||||
if ( voices_[i].channel == channel )
|
||||
if ( voices_[i].group == group )
|
||||
voices_[i].instrument->setFrequency( (StkFloat) (voices_[i].frequency * pitchScaler) );
|
||||
}
|
||||
}
|
||||
@@ -181,10 +190,10 @@ void Voicer :: pitchBend( long tag, StkFloat value )
|
||||
}
|
||||
}
|
||||
|
||||
void Voicer :: controlChange( int number, StkFloat value, int channel )
|
||||
void Voicer :: controlChange( int number, StkFloat value, int group )
|
||||
{
|
||||
for ( unsigned int i=0; i<voices_.size(); i++ ) {
|
||||
if ( voices_[i].channel == channel )
|
||||
if ( voices_[i].group == group )
|
||||
voices_[i].instrument->controlChange( number, value );
|
||||
}
|
||||
}
|
||||
@@ -207,72 +216,4 @@ void Voicer :: silence( void )
|
||||
}
|
||||
}
|
||||
|
||||
StkFloat Voicer :: tick()
|
||||
{
|
||||
lastOutput_ = lastOutputLeft_ = lastOutputRight_ = 0.0;
|
||||
for ( unsigned int i=0; i<voices_.size(); i++ ) {
|
||||
if ( voices_[i].sounding != 0 ) {
|
||||
lastOutput_ += voices_[i].instrument->tick();
|
||||
lastOutputLeft_ += voices_[i].instrument->lastOutLeft();
|
||||
lastOutputRight_ += voices_[i].instrument->lastOutRight();
|
||||
}
|
||||
if ( voices_[i].sounding < 0 ) {
|
||||
voices_[i].sounding++;
|
||||
if ( voices_[i].sounding == 0 )
|
||||
voices_[i].noteNumber = -1;
|
||||
}
|
||||
}
|
||||
return lastOutput_ / voices_.size();
|
||||
}
|
||||
|
||||
StkFloat *Voicer :: tick(StkFloat *vector, unsigned int vectorSize)
|
||||
{
|
||||
for (unsigned int i=0; i<vectorSize; i++)
|
||||
vector[i] = tick();
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
StkFrames& Voicer :: tick( StkFrames& frames, unsigned int channel )
|
||||
{
|
||||
if ( channel == 0 || frames.channels() < channel ) {
|
||||
errorString_ << "Voicer::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
|
||||
handleError( StkError::FUNCTION_ARGUMENT );
|
||||
}
|
||||
|
||||
if ( frames.channels() == 1 ) {
|
||||
for ( unsigned int i=0; i<frames.frames(); i++ )
|
||||
frames[i] = tick();
|
||||
}
|
||||
else if ( frames.interleaved() ) {
|
||||
unsigned int hop = frames.channels();
|
||||
unsigned int index = channel - 1;
|
||||
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();
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
StkFloat Voicer :: lastOut() const
|
||||
{
|
||||
return lastOutput_;
|
||||
}
|
||||
|
||||
StkFloat Voicer :: lastOutLeft() const
|
||||
{
|
||||
return lastOutputLeft_;
|
||||
}
|
||||
|
||||
StkFloat Voicer :: lastOutRight() const
|
||||
{
|
||||
return lastOutputRight_;
|
||||
}
|
||||
|
||||
} // stk namespace
|
||||
|
||||
Reference in New Issue
Block a user