Example #1
0
void SynthEvent::updateProperties()
{
    _type = _instrument->waveform;

    bool doOSC2 = !hasParent && _instrument->osc2active; // multi oscillator ?

    if ( doOSC2 ) // note we don't dispose osc2 during this events lifetime
        createOSC2( position, length, _instrument );

    applyModules( _instrument );        // modules
    BaseSynthEvent::updateProperties(); // base method

    if ( doOSC2 )
        _osc2->_cancel = false;
}
Example #2
0
void SynthEvent::setFrequency( float aFrequency, bool allOscillators, bool storeAsBaseFrequency )
{
    _frequency = aFrequency;
    _phaseIncr = aFrequency / AudioEngineProps::SAMPLE_RATE;

    // store as base frequency (acts as a reference "return point" for pitch shifting modules)
    if ( storeAsBaseFrequency )
        _baseFrequency = aFrequency;

    if ( _type == WaveForms::KARPLUS_STRONG )
        initKarplusStrong();

    // update properties of secondary oscillator, note that OSC2 can
    // have a pitch that deviates from the first oscillator
    // as such we multiply it by the deviation of the new frequency
    if ( allOscillators && _osc2 != 0 )
    {
        //float multiplier = aFrequency / currentFreq;
        //_osc2->setFrequency( _osc2->_frequency * multiplier, true, storeAsBaseFrequency );
        createOSC2( position, length, _instrument );
    }
}
Example #3
0
/**
 * @param aInstrument pointer to the SynthInstrument containing the rendering properties for the SynthEvent
 * @param aFrequency  frequency in Hz for the note to be rendered
 * @param aPosition   offset in the sequencer where this event starts playing / becomes audible
 * @param aLength     length of the event (in sequencer steps)
 * @param aHasParent  when true, this SynthEvent will be merged into the buffer of its parent instead of being
 *                    added to the Sequencer as an individual event, this makes rendering of its parent event
 *                    draw more CPU as its rendering multiple buffers, but after merging it consumes less memory
 *                    than two individual buffers would, it also omits the need of having float SynthEvents
 *                    to be mixed by the Sequencer
 * @param aIsSequenced whether this event is sequenced and only audible in a specific sequence range
 */
void SynthEvent::init( SynthInstrument *aInstrument, float aFrequency, int aPosition,
                       int aLength, bool aIsSequenced, bool aHasParent )
{
    _ringBuffer      = 0;
    _ringBufferSize  = 0;
    _osc2            = 0;
    _frequency       = aFrequency;
    _baseFrequency   = aFrequency;
    _queuedFrequency = 0;
    hasParent        = aHasParent;

    // constants used by waveform generators

    TWO_PI_OVER_SR         = TWO_PI / AudioEngineProps::SAMPLE_RATE;
    pwr                    = PI / 1.05;
    pwAmp                  = 0.075;
    _pwmValue              = 0.0;
    _phase                 = 0.0;
    _type                  = aInstrument->waveform;

    // starting/stopping a waveform mid cycle can cause nasty pops, this is used for a smoother inaudible fade in
    _fadeInDuration  = BufferUtility::millisecondsToBuffer( 20, AudioEngineProps::SAMPLE_RATE );
    _fadeOutDuration = BufferUtility::millisecondsToBuffer( 30, AudioEngineProps::SAMPLE_RATE );

    // create the secondary oscillator

    if ( !hasParent && aInstrument->osc2active )
       createOSC2( position, length, aInstrument );

    // base class invocation
    BaseSynthEvent::init( aInstrument, aFrequency, aPosition, aLength, aIsSequenced );

    // modules

    _arpeggiator = 0;
    applyModules( aInstrument );
}
Example #4
0
/**
 * @param aPosition position in the sequencer where this event starts playing
 * @param aLength length (in sequencer steps) of this event
 * @param aInstrument the SynthInstrument whose properties will be used for synthesizing this event
 * @param aState which oscillator(s) to update 0 = all, 1 = oscillator 1, 2 = oscillator 2
 *               this is currently rudimentary as both oscillators are rendered and merged into one
 *               this is here for either legacy purposes or when performance improvements can be gained
 */
void SynthEvent::updateProperties( int aPosition, float aLength, SynthInstrument *aInstrument, int aState )
{
    bool updateLFO1 = true;//( aState == 0 || aState == 1 );
    bool updateOSC2 = true;//( aState == 0 || aState == 2 );

    _type    = aInstrument->waveform;
    position = aPosition;
    length   = aLength;

    _adsr->cloneEnvelopes( aInstrument->adsr );

    // secondary oscillator

    if ( updateOSC2 && aInstrument->osc2active )
        createOSC2( aPosition, aLength, aInstrument );
    else
        destroyOSC2();

    // modules

    applyModules( aInstrument );

    if ( updateLFO1 )
    {
        if ( _caching /*&& !_cachingCompleted */)
        {
            if ( _osc2 != 0 && _osc2->_caching )
                _osc2->_cancel = true;

            _cancel = true;
        }
        else {
            calculateBuffers();
        }
    }
}
Example #5
0
/**
 * @param aInstrument pointer to the SynthInstrument containing the rendering properties for the SynthEvent
 * @param aFrequency  frequency in Hz for the note to be rendered
 * @param aPosition   offset in the sequencer where this event starts playing / becomes audible
 * @param aLength     length of the event (in sequencer steps)
 * @param aHasParent  when true, this SynthEvent will be merged into the buffer of its parent instead of being
 *                    added to the Sequencer as an individual event, this makes rendering of its parent event
 *                    draw more CPU as its rendering multiple buffers, but after merging it consumes less memory
 *                    than two individual buffers would, it also omits the need of having float SynthEvents
 *                    to be mixed by the Sequencer
 * @param aIsSequenced whether this event is sequenced and only audible in a specific sequence range
 */
void SynthEvent::init( SynthInstrument *aInstrument, float aFrequency, int aPosition,
                       int aLength, bool aHasParent, bool aIsSequenced )
{
    _destroyableBuffer = true;  // always unique and managed by this instance !
    _instrument        = aInstrument;
    _adsr              = _instrument->adsr->clone();

    // when instrument has no fixed length and the decay is short
    // we deactivate the decay envelope completely (for now)
    if ( !aIsSequenced && _adsr->getDecay() < .75 )
        _adsr->setDecay( 0 );

    _buffer         = 0;
    _ringBuffer     = 0;
    _ringBufferSize = 0;
    _locked         = false;
    _frequency      = aFrequency;
    _baseFrequency  = aFrequency;

    position        = aPosition;
    length          = aLength;
    hasParent       = aHasParent;

    isSequenced            = aIsSequenced;
    _queuedForDeletion     = false;
    _deleteMe              = false;
    _cancel                = false; // whether we should cancel caching
    _caching               = false;
    _cachingCompleted      = false; // whether we're done caching
    _autoCache             = false; // we'll cache sequentially instead
    _type                  = aInstrument->waveform;
    _osc2                  = 0;
    _volume                = aInstrument->volume;
    _sampleLength          = 0;
    _cacheWriteIndex       = 0;

    // constants used by waveform generators

    TWO_PI_OVER_SR         = TWO_PI / AudioEngineProps::SAMPLE_RATE;
    pwr                    = PI / 1.05;
    pwAmp                  = 0.075;
    EnergyDecayFactor      = 0.990f; // TODO make this settable ?
    _pwmValue              = 0.0;
    _phase                 = 0.0;

    // secondary oscillator, note different constructor
    // to omit going into recursion!

    if ( !hasParent && aInstrument->osc2active )
       createOSC2( position, length, aInstrument );

    setFrequency( aFrequency );

    // modules

    _arpeggiator = 0;
    applyModules( aInstrument );

    // buffer

    _hasMinLength = isSequenced; // a sequenced event has no early cancel
    calculateBuffers();

    // add the event to the sequencer so it can be heard
    // note that OSC2 contents aren't added to the sequencer
    // individually as their render is invoked by their parent,
    // writing directly into their parent buffer (saves memory overhead)

    if ( isSequenced )
    {
        if ( !hasParent )
            aInstrument->audioEvents->push_back( this );
    }
    else {
        if ( !hasParent )
            aInstrument->liveEvents->push_back( this );
    }
}