Esempio n. 1
0
/**
 * will only occur for a sequenced BaseSynthEvent
 */
void BaseSynthEvent::mixBuffer( AudioBuffer* outputBuffer, int bufferPos,
                                int minBufferPosition, int maxBufferPosition,
                                bool loopStarted, int loopOffset, bool useChannelRange )
{
    lock();

    // over the max position ? read from the start ( implies that sequence has started loop )
    if ( bufferPos > maxBufferPosition )
    {
        if ( useChannelRange )
            bufferPos -= maxBufferPosition;

        else if ( !loopStarted )
            return;
    }

    int bufferEndPos = bufferPos + AudioEngineProps::BUFFER_SIZE;

    if (( bufferPos >= _sampleStart || bufferEndPos > _sampleStart ) &&
          bufferPos < _sampleEnd )
    {
        lastWriteIndex  = _sampleStart > bufferPos ? 0 : bufferPos - _sampleStart;
        int writeOffset = _sampleStart > bufferPos ? _sampleStart - bufferPos : 0;

        // render the snippet
        _synthInstrument->synthesizer->render( _buffer, this );

        // note we merge using MAX_PHASE as mix volume (event volume was applied during synthesis)
        outputBuffer->mergeBuffers( _buffer, 0, writeOffset, MAX_PHASE );

        // reset of event properties at end of write
        if ( lastWriteIndex >= _sampleLength )
            calculateBuffers();
    }

    if ( loopStarted && bufferPos >= loopOffset )
    {
        bufferPos = minBufferPosition + loopOffset;

        if ( bufferPos >= _sampleStart && bufferPos <= _sampleEnd )
        {
            lastWriteIndex = 0; // render the snippet from the start

            // TODO: specify range in ::render method ? this would avoid unnecessary buffer merging ;)

            _synthInstrument->synthesizer->render( _buffer, this );    // overwrites old buffer contents

            // note we merge using MAX_PHASE as mix volume (event volume was applied during synthesis)
            outputBuffer->mergeBuffers( _buffer, 0, loopOffset, MAX_PHASE );

            // reset of event properties at end of write
            if ( lastWriteIndex >= _sampleLength )
                calculateBuffers();
        }
    }
    unlock();
}
Esempio n. 2
0
/**
 * @param aInstrument pointer to the SynthInstrument containing the rendering properties for the BaseSynthEvent
 * @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 aIsSequenced whether this event is sequenced and only audible in a specific sequence range
 */
void BaseSynthEvent::init( SynthInstrument *aInstrument, float aFrequency, int aPosition,
                       int aLength, bool aIsSequenced )
{
    _destroyableBuffer = true;  // synth event buffer is always unique and managed by this instance !
    _instrument        = aInstrument;
    _adsr              = aInstrument->adsr != 0 ? aInstrument->adsr->clone() : new ADSR();

    // 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;
    _locked                = false;
    position               = aPosition;
    length                 = aLength;
    isSequenced            = aIsSequenced;
    _queuedForDeletion     = false;
    _deleteMe              = false;
    _update                = false;
    _cancel                = false;       // whether we should cancel caching
    _hasMinLength          = isSequenced; // a sequenced event has no early cancel
    _caching               = false;
    _cachingCompleted      = false; // whether we're done caching
    _autoCache             = false; // we'll cache sequentially instead
    _rendering             = false;
    _volume                = aInstrument->volume;
    _sampleLength          = 0;
    _cacheWriteIndex       = 0;

    setFrequency( aFrequency );

    calculateBuffers();
    addToSequencer();
}
Esempio n. 3
0
/**
 * @param aInstrument pointer to the SynthInstrument containing the rendering properties for the BaseSynthEvent
 * @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 isSequenced whether this event is sequenced and only audible in a specific sequence range
 */
void BaseSynthEvent::init( SynthInstrument* aInstrument, float aFrequency,
                           int aPosition, float aLength, bool isSequenced )
{
    instanceId         = ++INSTANCE_COUNT;
    _destroyableBuffer = true;  // synth event buffer is always unique and managed by this instance !
    _instrument        = aInstrument;
    _synthInstrument   = aInstrument; // convenience reference (typecast to SynthInstrument)

    position           = aPosition;
    length             = aLength;

    cachedProps.ADSRenvelope     = 0.0;
    cachedProps.arpeggioPosition = 0;
    cachedProps.arpeggioStep     = 0;

    int maxOscillatorAmount = 8; // let's assume a max amount of oscillators of 8 here
    cachedProps.oscillatorPhases.reserve( maxOscillatorAmount );

    for ( int i = 0; i < maxOscillatorAmount; ++i )
        cachedProps.oscillatorPhases.push_back( 0.0 );

    this->isSequenced  = isSequenced;
    _queuedForDeletion = false;
    _deleteMe          = false;
    _hasMinLength      = isSequenced; // a sequenced event has no early cancel
    _sampleLength      = 0;
    lastWriteIndex     = 0;

    setFrequency( aFrequency );

    calculateBuffers();
    addToSequencer();
}
Esempio n. 4
0
void BaseSynthEvent::unlock()
{
    _locked = false;

    if ( _updateAfterUnlock )
        calculateBuffers();

    _updateAfterUnlock = false;
}
Esempio n. 5
0
void ScopeGUI::resizedGUI()
{	
	initBuffers();
	
	if(audioBuffer.size() > 0)
	{
		calculateBuffers();
	}
}
Esempio n. 6
0
/**
 * actual updating of the properties, requested by invalidateProperties
 * this operation might potentially delete objects that could be in
 * use during a rendering operation, as such it is invoked from the render
 */
void BaseSynthEvent::updateProperties()
{
    // ADSR envelopes

    _adsr->cloneEnvelopes( _instrument->adsr );
    calculateBuffers();

    _update = false; // we're in sync now :)
    _cancel = false;
}
Esempio n. 7
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();
        }
    }
}
Esempio n. 8
0
/**
 * will only occur for a sequenced BaseSynthEvent
 */
void BaseSynthEvent::mixBuffer( AudioBuffer* outputBuffer, int bufferPos,
                                int minBufferPosition, int maxBufferPosition,
                                bool loopStarted, int loopOffset, bool useChannelRange )
{
    // is EVENT_CACHING is enabled, read from cached buffer

    if ( AudioEngineProps::EVENT_CACHING )
    {
        BaseAudioEvent::mixBuffer( outputBuffer, bufferPos, minBufferPosition, maxBufferPosition,
                                   loopStarted, loopOffset, useChannelRange );
    }
    else
    {
        // EVENT_CACHING is disabled, synthesize on the fly

        lock();

        // over the max position ? read from the start ( implies that sequence has started loop )
        if ( bufferPos >= maxBufferPosition )
        {
            if ( useChannelRange )
                bufferPos -= maxBufferPosition;

            else if ( !loopStarted )
                bufferPos -= ( maxBufferPosition - minBufferPosition );
        }

        int bufferEndPos = bufferPos + AudioEngineProps::BUFFER_SIZE;

        if (( bufferPos >= _sampleStart || bufferEndPos > _sampleStart ) &&
              bufferPos < _sampleEnd )
        {
            // render the snippet
            _cacheWriteIndex = _sampleStart > bufferPos ? 0 : bufferPos - _sampleStart;
            int writeOffset  = _sampleStart > bufferPos ? _sampleStart - bufferPos : 0;

            render( _buffer ); // overwrites old buffer contents
            outputBuffer->mergeBuffers( _buffer, 0, writeOffset, MAX_PHASE );

            // reset of properties at end of write
            if ( _cacheWriteIndex >= _sampleLength )
                calculateBuffers();
        }

        if ( loopStarted && bufferPos >= loopOffset )
        {
            bufferPos = minBufferPosition + loopOffset;

            if ( bufferPos >= _sampleStart && bufferPos <= _sampleEnd )
            {
                _cacheWriteIndex = 0; // render the snippet from the start
                render( _buffer );    // overwrites old buffer contents
                outputBuffer->mergeBuffers( _buffer, 0, loopOffset, MAX_PHASE );

                // reset of properties at end of write
                if ( _cacheWriteIndex >= _sampleLength )
                    calculateBuffers();
            }
        }
        unlock();
    }
}
Esempio n. 9
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 );
    }
}
Esempio n. 10
0
/**
 * the actual synthesizing of the audio
 *
 * @param aOutputBuffer {AudioBuffer*} the buffer to write into
 */
void SynthEvent::render( AudioBuffer* aOutputBuffer )
{
    int i;
    int bufferLength = aOutputBuffer->bufferSize;

    SAMPLE_TYPE amp = 0.0;
    SAMPLE_TYPE tmp, am, dpw, pmv;

    bool hasOSC2 = _osc2 != 0;

    int renderStartOffset = AudioEngineProps::EVENT_CACHING && isSequenced ? _cacheWriteIndex : 0;

    int maxSampleIndex  = _sampleLength - 1;                // max index possible for this events length
    int renderEndOffset = renderStartOffset + bufferLength; // max buffer index to be written to in this cycle

    // keep in bounds of event duration
    if ( renderEndOffset > maxSampleIndex )
    {
        renderEndOffset = maxSampleIndex;
        aOutputBuffer->silenceBuffers(); // as we tend to overwrite the incoming buffer
    }

    for ( i = renderStartOffset; i < renderEndOffset; ++i )
    {
        switch ( _type )
        {
            case WaveForms::SINE_WAVE:

                // ---- Sine wave

                if ( _phase < .5 )
                {
                    tmp = ( _phase * 4.0 - 1.0 );
                    amp = ( 1.0 - tmp * tmp );
                }
                else {
                    tmp = ( _phase * 4.0 - 3.0 );
                    amp = ( tmp * tmp - 1.0 );
                }
                amp *= .7; // sines tend to distort easily when overlapping multi timbral parts

                break;

            case WaveForms::SAWTOOTH:

                // ---- Sawtooth
                amp = ( _phase < 0 ) ? _phase - ( int )( _phase - 1 ) : _phase - ( int )( _phase );
                //amp *= ( !isSequenced ? .7  : 1.0; );

                break;

            case WaveForms::SQUARE_WAVE:

                // ---- Square wave
                if ( _phase < .5 )
                {
                    tmp = TWO_PI * ( _phase * 4.0 - 1.0 );
                    amp = ( 1.0 - tmp * tmp );
                }
                else {
                    tmp = TWO_PI * ( _phase * 4.0 - 3.0 );
                    amp = ( tmp * tmp - 1.0 );
                }
                amp *= .01; // these get loud ! 0.005
                break;

            case WaveForms::TRIANGLE:

                // ---- triangle
                if ( _phase < .5 )
                {
                    tmp = ( _phase * 4.0 - 1.0 );
                    amp = ( 1.0 - tmp * tmp ) * .75;
                }
                else {
                    tmp = ( _phase * 4.0 - 3.0 );
                    amp = ( tmp * tmp - 1.0 ) * .75;
                }
                // the actual triangulation function
                amp = amp < 0 ? -amp : amp;

                break;

            case WaveForms::PWM:

                // --- pulse width modulation
                pmv = i + ( ++_pwmValue ); // i + event position

                dpw = sin( pmv / 0x4800 ) * pwr; // LFO -> PW
                amp = _phase < PI - dpw ? pwAmp : -pwAmp;

                // PWM has its own phase update operation
                _phase = _phase + ( TWO_PI_OVER_SR * _frequency );
                _phase = _phase > TWO_PI ? _phase - TWO_PI : _phase;

                // we multiply the amplitude as PWM results in a "quieter" wave
                amp *= 4;

                /* // OLD: oscillation modulating the PW wave
                am   = sin( pmv / 0x1000 ); // LFO -> AM
                amp *= am;
                */
                break;

            case WaveForms::NOISE:

                // --- noise
                if ( _phase < .5 )
                {
                    tmp = ( _phase * 4.0 - 1.0 );
                    amp = ( 1.0 - tmp * tmp );
                }
                else {
                    tmp = ( _phase * 4.0 - 3.0 );
                    amp = ( tmp * tmp - 1.0 );
                }
                // above we calculated pitch, now we add some
                // randomization to the signal for the actual noise
                amp *= randomFloat();
                break;

            case WaveForms::KARPLUS_STRONG:

                // --- Karplus-Strong algorithm for plucked string-sound
                _ringBuffer->enqueue(( EnergyDecayFactor * (( _ringBuffer->dequeue() + _ringBuffer->peek()) / 2 )));
                amp = _ringBuffer->peek(); // * .7; gets the level down a bit, 'tis loud

                break;
        }

        // --- _phase update operations
        if ( _type != WaveForms::PWM )
        {
            _phase += _phaseIncr;

            // restore _phase, max range is 0 - 1 ( float )
            if ( _phase > MAX_PHASE )
                _phase -= MAX_PHASE;
        }

        if ( !isSequenced )
            amp *= .5; // anticipating multi-timbral fun

        // update modules
        if ( _arpeggiator != 0 )
        {
            // step the arpeggiator to the next position
            if ( _arpeggiator->peek())
                setFrequency( _arpeggiator->getPitchForStep( _arpeggiator->getStep(), _baseFrequency ), true, false );
        }

        // -- write the output into the buffers channels
        for ( int c = 0, ca = aOutputBuffer->amountOfChannels; c < ca; ++c )
            aOutputBuffer->getBufferForChannel( c )[ i ] = amp * _volume * VOLUME_CORRECTION;

        // stop caching/rendering loop when cancel was requested
        if ( _cancel )
            break;
    }

    // secondary oscillator ? render its contents into this (parent) buffer

    if ( hasOSC2 && !_cancel )
    {
        // create a temporary buffer (this prevents writing to deleted buffers
        // when the parent event changes its _buffer properties (f.i. tempo change)
        int tempLength = ( AudioEngineProps::EVENT_CACHING && isSequenced ) ? ( renderEndOffset - _cacheWriteIndex ) : bufferLength;
        AudioBuffer* tempBuffer = new AudioBuffer( aOutputBuffer->amountOfChannels, tempLength );
        _osc2->render( tempBuffer );
        aOutputBuffer->mergeBuffers( tempBuffer, 0, renderStartOffset, MAX_PHASE );

        delete tempBuffer; // free allocated memory
    }

    // apply envelopes and update cacheWriteIndex for next render cycle
    if ( !hasParent )
    {
        _adsr->apply( aOutputBuffer, _cacheWriteIndex );
        _cacheWriteIndex += i;
    }

    if ( AudioEngineProps::EVENT_CACHING )
    {
        if ( isSequenced )
        {
            _caching = false;

            // was a cancel requested ? re-cache to
            // match the new properties (cancel may only
            // be requested when changing properties!)
            if ( _cancel )
            {
                _cancel = false;
                calculateBuffers();
            }
            else
            {
                if ( i == maxSampleIndex )
                    _cachingCompleted = true;

                if ( _bulkCacheable )
                    _autoCache = true;
            }
        }
    }
}
Esempio n. 11
0
/**
 * actual updating of the properties, requested by invalidateProperties
 * this operation might potentially delete objects that could be in
 * use during a rendering operation, as such it is invoked from the render
 */
void BaseSynthEvent::updateProperties()
{
    calculateBuffers();
}