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
This commit is contained in:
Tobias Doerffel
2007-08-18 21:14:56 +00:00
parent 30bdca17c0
commit e05ce274fb
4 changed files with 144 additions and 81 deletions

View File

@@ -1,5 +1,11 @@
2007-08-18 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* 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

View File

@@ -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 <assert.h>
#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<b)?a:b;
}
int lb302Synth::process(sampleFrame *outbuf, const Uint32 size)
{
@@ -583,9 +592,19 @@ int lb302Synth::process(sampleFrame *outbuf, const Uint32 size)
unsigned int i;
float w;
float samp;
for(i=0;i<size;i++) {
/* TODO: ONLY DO THIS IF WE ARE EDGE-TO-EDGE NON-DEAD */
/*if (sample_cnt < desiredTransitionFrames()) {
for(int c=0; c<DEFAULT_CHANNELS; c++)
outbuf[i][c]=0;
sample_cnt++;
continue;
}
*/
// update vcf
if(vcf_envpos >= 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; c<DEFAULT_CHANNELS; c++) {
outbuf[i][c]=samp;
@@ -763,57 +775,115 @@ void lb302Synth::initNote( lb302Note *n)
void lb302Synth::playNote( notePlayHandle * _n, bool )
{
int framesPerPeriod = engine::getMixer()->framesPerPeriod();
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<fpp_t>( 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();
}

View File

@@ -36,7 +36,6 @@
#include "instrument.h"
#include "led_checkbox.h"
#include "mixer.h"
#include <iostream>
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

View File

@@ -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<f_cnt_t>( _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;
}
}