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; }
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 ); } }
/** * @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 ); }
/** * @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(); } } }
/** * @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 ); } }