From e05ce274fb8bcf5d23a75a6680cbb38ee52bf0d4 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Sat, 18 Aug 2007 21:14:56 +0000 Subject: [PATCH] rewrote code for monophonic behaviour (calculation of position at which to resume states etc.) git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@524 0778d3d1-df1d-0410-868b-ea421aaaa00d --- ChangeLog | 6 + plugins/lb302/lb302.cpp | 207 ++++++++++++++++++++------------ plugins/lb302/lb302.h | 6 +- src/tracks/instrument_track.cpp | 6 +- 4 files changed, 144 insertions(+), 81 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4298ed6c6..36b308dc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2007-08-18 Tobias Doerffel + * plugins/lb302/lb302.cpp: + * plugins/lb302/lb302.h: + - rewrote code for monophonic behaviour (calculation of position at + which to resume states etc.) + - added some debugging-stuff + * src/core/mixer.cpp: remove play-handles *after* we played all play-handles diff --git a/plugins/lb302/lb302.cpp b/plugins/lb302/lb302.cpp index 5938c6034..0671700a8 100644 --- a/plugins/lb302/lb302.cpp +++ b/plugins/lb302/lb302.cpp @@ -48,6 +48,7 @@ #include "knob.h" #include "note_play_handle.h" #include "templates.h" +#include "audio_port.h" #undef SINGLE_SOURCE_COMPILE #include "embed.cpp" @@ -68,6 +69,12 @@ #define LB_24_VOL_ADJUST 3.0 //#define LB_DECAY_NOTES +#define LB_DEBUG + +#ifdef LB_DEBUG +#include +#endif + // // Old config // @@ -76,7 +83,6 @@ #define LB_HZ 44100.0f -using namespace std; extern "C" { @@ -425,7 +431,7 @@ lb302Synth::lb302Synth( instrumentTrack * _channel_track ) : recalcFilter(); - lastFramesPlayed = 0; + lastFramesPlayed = 1; // because we subtract 1 later last_offset = 0; period_states = NULL; @@ -576,6 +582,9 @@ void lb302Synth::recalcFilter() vcf_envpos = ENVINC; // Trigger filter update in process() } +inline int MIN(int a, int b) { + return (a= ENVINC) { vcf->envRecalc(); @@ -610,20 +629,11 @@ int lb302Synth::process(sampleFrame *outbuf, const Uint32 size) vco_c += vco_inc; if(vco_c > 0.5) vco_c -= 1.0; - - if (catch_decay > 0) { - if (catch_decay < desiredReleaseFrames()) - catch_decay++; - else if (use_hold_note) { - printf("RETRIGGER\n"); - // We would retrigger the actual note we *should* be playing. - // I removed this for now, to help detect the true problem. - /*initNote(&hold_note); - catch_decay=0; - */ - use_hold_note = 0; - } - } +/* + if (catch_decay < desiredTransitionFrames()) { + catch_decay++; + continue; + }*/ switch(int(rint(wave_knob->value()))) { @@ -666,22 +676,24 @@ int lb302Synth::process(sampleFrame *outbuf, const Uint32 size) vco_k = (vco_c*2.0)+0.5; if (vco_k>1.0) vco_k = -0.5 ; else if (vco_k>0.5) { - w = 2*(vco_k-0.5)-1; - vco_k = 0.5 - sqrtf(1-(w*w)); - vco_k *= 2.0; // MOOG wave gets filtered away + w = 2.0*(vco_k-0.5)-1.0; + vco_k = 0.5 - sqrtf(1.0-(w*w)); } + vco_k *= 2.0; // MOOG wave gets filtered away break; } + vca_a = 0.5; // Write out samples. #ifdef LB_FILTERED samp = vcf->process(vco_k)*2.0*vca_a; #else samp = vco_k*vca_a; #endif + /* float releaseFrames = desiredReleaseFrames(); samp *= (releaseFrames - catch_decay)/releaseFrames; - + */ for(int c=0; cframesPerPeriod(); + fpp_t framesPerPeriod = engine::getMixer()->framesPerPeriod(); - // Malloc our period history buffer - if (period_states == NULL) - period_states = new lb302State[framesPerPeriod]; + ///=== WEIRD CODE FOR MONOPHONIC BEHAVIOUR - BEGIN === /// + + // number of frames to play - only modified below if we have to play + // the rest of an old note + fpp_t frames = _n->framesLeftForCurrentPeriod(); + + surroundSampleFrame * trkBuffer; + + // per default we resume at the last played frames - only in + // some special-cases (which we catch below) we have to resume + // somewhere else + f_cnt_t resume_pos = lastFramesPlayed-1; + + // find out which situation we're in + constNotePlayHandleVector v = + notePlayHandle::nphsOfInstrumentTrack( getInstrumentTrack(), TRUE ); + // more than one note running? + if( v.count() > 1 ) + { + const notePlayHandle * on = v.first(); // oldest note + const notePlayHandle * yn = v.last(); // youngest note + // are we playing a released note and the new (youngest) note + // has taken over successfully (i.e. played more than the + // difference of the two offsets)? + if ( _n->released() && + yn->totalFramesPlayed() >= yn->offset() - on->offset() ) + { + // then we do not need to play something anymore + return; + } + + // have to fill up the frames left to the new note so limit + // frames to play for not getting into trouble + if( _n != yn ) + { + frames = tMin( frames, yn->offset() - on->offset() ); +#ifdef LB_DEBUG + // should be always true - why? I don't know... ;-) + assert( frames > 0 ); +#endif + } + + // new note while other notes are running? + if( v.count() > 1 && yn == _n && + _n->totalFramesPlayed() == 0 ) + { + // if there had been a previous note whose + // offset > _n->offset() it played more frames than + // we actually need - therefore clear everything before + // the offset of the youngest note, otherwise we get + // frames with both waves overlapped + engine::getMixer()->clearAudioBuffer( + _n->getInstrumentTrack()->getAudioPort()-> + firstBuffer(), + framesPerPeriod - yn->offset(), yn->offset() ); + resume_pos = yn->offset() - on->offset() - 1; + // make sure we have positive value, otherwise we're + // accessing states out of borders + while( resume_pos < 0 ) + { + resume_pos += framesPerPeriod; + } + } + } + +#ifdef LB_DEBUG + if( _n->released() ) + { + printf( " RELEASED!!! %ld\n", _n ); + } + else + { + printf( "not released... %ld\n", _n ); + } + printf( "offset: %d frames:%d\n", _n->offset(), frames ); + + printf( "Resuming at %d\n", resume_pos ); +#endif + + ///=== WEIRD CODE FOR MONOPHONIC BEHAVIOUR - END === /// + + /// Malloc our period history buffer + if (period_states == NULL) + period_states = new lb302State[framesPerPeriod]; - // Print debug garbage - constNotePlayHandleVector v = - notePlayHandle::nphsOfInstrumentTrack( getInstrumentTrack() ); + // now resume at the proper position and process as usual + lb302State *state = &period_states[resume_pos]; - if ( _n->totalFramesPlayed() <= 0 ) - printf("New Note count: %d nphs: %d\n", note_count, v.size()); - - // OH HOLY FUCK!! These get interleaved between two different notes. - // is LMMS properly handling monophonic? I assumed that the youngest - // note would kill all earlier notes, even if they are released. - if (_n->released()) - printf(" RELEASED!!! %ld\n", _n); - else - printf("not released... %ld\n", _n); - // end debug garbage + /// Actually resume the state, now that we have the right state object. + vco_c = state->vco_c; + vca_a = state->vca_a; + sample_cnt = state->sample_cnt; + + /// Currently have release/decay disabled // Start the release decay if this is the first release period. - if (_n->released() && catch_decay == 0) - catch_decay = 1; + //if (_n->released() && catch_decay == 0) + // catch_decay = 1; - // I don't know if and when we will ever need this code again. - /* - if (_n->totalFramesPlayed() > 0) { - period_states_cnt = _n->framesLeftForCurrentPeriod(); - } - else { - // New note (not overlapping), restore - if (period_states_cnt > 0) { - lb302State *st = &period_states[period_states_cnt-1]; - - //printf("Restoring from: %d\n", period_states_cnt-1); - vco_c = st->vco_c; - } - //vca_a = st->vca_a; - //sample_cnt = st->sample_cnt; - } - */ - if ( _n->totalFramesPlayed() <= 0 ) { + /// This code is obsolete, hence the "if false" // Existing note. Allow it to decay. - if(note_count) { + if(/*note_count*/ false) { // BEGIN NOT SURE OF... //lb302State *st = &period_states[period_states_cnt-1]; //vca_a = st->vca_a; @@ -825,7 +895,7 @@ void lb302Synth::playNote( notePlayHandle * _n, bool ) hold_note.dead = deadToggle->value(); use_hold_note = true; } - // Start a new note + /// Start a new note. else { lb302Note note; note.vco_inc = _n->frequency()*vco_detune/LB_HZ; // TODO: Use actual sampling rate. @@ -837,25 +907,14 @@ void lb302Synth::playNote( notePlayHandle * _n, bool ) note_count=1; } - const fpp_t frames = _n->framesLeftForCurrentPeriod(); - sampleFrame *buf = new sampleFrame[frames]; - - bool dec_count; - if (_n->willFinishThisPeriod()) - dec_count = true; - else - dec_count = false; + sampleFrame *buf = new sampleFrame[frames]; process(buf, frames); getInstrumentTrack()->processAudioBuffer( buf, frames, _n ); delete[] buf; - if (dec_count) - note_count=0; - - - lastFramesPlayed = _n->totalFramesPlayed(); + lastFramesPlayed = frames;//_n->framesLeftForCurrentPeriod(); //_n->totalFramesPlayed(); } diff --git a/plugins/lb302/lb302.h b/plugins/lb302/lb302.h index 1f513bafc..bf0cc136d 100644 --- a/plugins/lb302/lb302.h +++ b/plugins/lb302/lb302.h @@ -36,7 +36,6 @@ #include "instrument.h" #include "led_checkbox.h" #include "mixer.h" -#include class knob; @@ -160,9 +159,8 @@ public: virtual f_cnt_t desiredReleaseFrames( void ) const { - return 2000; + return 512; } - private: @@ -218,7 +216,7 @@ private: lb302Note hold_note; bool use_hold_note; - float lastFramesPlayed; + int lastFramesPlayed; // More States diff --git a/src/tracks/instrument_track.cpp b/src/tracks/instrument_track.cpp index d43092c65..10c083439 100644 --- a/src/tracks/instrument_track.cpp +++ b/src/tracks/instrument_track.cpp @@ -597,7 +597,7 @@ void instrumentTrack::processAudioBuffer( sampleFrame * _buf, volumeVector v = m_surroundArea->getVolumeVector( v_scale ); engine::getMixer()->bufferToPort( _buf, - ( _n != NULL ) ? _n->framesLeftForCurrentPeriod() : _frames, + ( _n != NULL ) ? tMin( _n->framesLeftForCurrentPeriod(), _frames ) : _frames, ( _n != NULL ) ? _n->offset() : 0, v, m_audioPort ); } @@ -799,10 +799,10 @@ void instrumentTrack::playNote( notePlayHandle * _n, bool _try_parallelizing ) // in last period and have // to clear parts of it _n->noteOff(); -/* engine::getMixer()->clearAudioBuffer( m_audioPort->firstBuffer(), + engine::getMixer()->clearAudioBuffer( m_audioPort->firstBuffer(), engine::getMixer()->framesPerPeriod() - ( *youngest_note )->offset(), - ( *youngest_note )->offset() );*/ + ( *youngest_note )->offset() ); return; } }