Revision of handling of frameoffset for NPH, SPH

Change in handling of frameoffset for multistreamed instruments and sampletracks.
- Instead of holding the offset for the lifetime of the playhandle, negate the offset in the first period
- Multistream-instruments require some small changes: they have to now check for the offset and accordingly leave empty space in the start of the period (already done in this commit)
- There are possibly optimizations that can be done later
- This change is necessary so that we can have sample-exact models, and sample-exact vol/pan knobs for all instruments. Earlier multistream instruments were always rendering some frames ahead-of-time, so applying sample-exact data for them would have been impossible, since we don't have the future-values yet...
This commit is contained in:
Vesa
2014-06-29 23:13:00 +03:00
parent a7bb31159e
commit 270af579b8
23 changed files with 137 additions and 124 deletions

View File

@@ -119,6 +119,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer )
{
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
// Magic key - a frequency < 20 (say, the bottom piano note if using
// a A4 base tuning) restarts the start point. The note is not actually
@@ -165,14 +166,14 @@ void audioFileProcessor::playNote( NotePlayHandle * _n,
if( ! _n->isFinished() )
{
if( m_sampleBuffer.play( _working_buffer,
if( m_sampleBuffer.play( _working_buffer + offset,
(handleState *)_n->m_pluginData,
frames, _n->frequency(),
static_cast<SampleBuffer::LoopMode>( m_loopModel.value() ) ) )
{
applyRelease( _working_buffer, _n );
instrumentTrack()->processAudioBuffer( _working_buffer,
frames,_n );
frames + offset, _n );
emit isPlaying( ((handleState *)_n->m_pluginData)->frameIndex() );
}

View File

@@ -282,9 +282,10 @@ void bitInvader::playNote( NotePlayHandle * _n,
}
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
bSynth * ps = static_cast<bSynth *>( _n->m_pluginData );
for( fpp_t frame = 0; frame < frames; ++frame )
for( fpp_t frame = offset; frame < frames + offset; ++frame )
{
const sample_t cur = ps->nextStringSample();
for( ch_cnt_t chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl )
@@ -295,7 +296,7 @@ void bitInvader::playNote( NotePlayHandle * _n,
applyRelease( _working_buffer, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
}

View File

@@ -163,6 +163,8 @@ typedef KickerOsc<DspEffectLibrary::MonoToStereoAdaptor<DistFX> > SweepOsc;
void kickerInstrument::playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer )
{
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
const float decfr = m_decayModel.value() *
engine::mixer()->processingSampleRate() / 1000.0f;
const f_cnt_t tfp = _n->totalFramesPlayed();
@@ -187,10 +189,8 @@ void kickerInstrument::playNote( NotePlayHandle * _n,
_n->noteOff();
}
const fpp_t frames = _n->framesLeftForCurrentPeriod();
SweepOsc * so = static_cast<SweepOsc *>( _n->m_pluginData );
so->update( _working_buffer, frames, engine::mixer()->processingSampleRate() );
so->update( _working_buffer + offset, frames, engine::mixer()->processingSampleRate() );
if( _n->isReleased() )
{
@@ -199,12 +199,12 @@ void kickerInstrument::playNote( NotePlayHandle * _n,
for( fpp_t f = 0; f < frames; ++f )
{
const float fac = ( done+f < desired ) ? ( 1.0f - ( ( done+f ) / desired ) ) : 0;
_working_buffer[f][0] *= fac;
_working_buffer[f][1] *= fac;
_working_buffer[f+offset][0] *= fac;
_working_buffer[f+offset][1] *= fac;
}
}
instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
}

View File

@@ -1245,14 +1245,16 @@ MonstroInstrument::~MonstroInstrument()
void MonstroInstrument::playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer )
{
fpp_t frames = _n->framesLeftForCurrentPeriod();
if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == NULL )
{
_working_buffer += _n->offset();
frames -= _n->offset();
const sample_rate_t samplerate = m_samplerate;
_n->m_pluginData = new MonstroSynth( this, _n, samplerate, m_fpp );
}
const fpp_t frames = _n->framesLeftForCurrentPeriod();
MonstroSynth * ms = static_cast<MonstroSynth *>( _n->m_pluginData );
ms->renderOutput( frames, _working_buffer );

View File

@@ -556,21 +556,22 @@ NesInstrument::~NesInstrument()
void NesInstrument::playNote( NotePlayHandle * n, sampleFrame * workingBuffer )
{
const fpp_t frames = n->framesLeftForCurrentPeriod();
const f_cnt_t offset = n->noteOffset();
if ( n->totalFramesPlayed() == 0 || n->m_pluginData == NULL )
{
NesObject * nes = new NesObject( this, engine::mixer()->processingSampleRate(), n, engine::mixer()->framesPerPeriod() );
n->m_pluginData = nes;
}
const fpp_t frames = n->framesLeftForCurrentPeriod();
NesObject * nes = static_cast<NesObject *>( n->m_pluginData );
nes->renderOutput( workingBuffer, frames );
nes->renderOutput( workingBuffer + offset, frames );
applyRelease( workingBuffer, n );
instrumentTrack()->processAudioBuffer( workingBuffer, frames, n );
instrumentTrack()->processAudioBuffer( workingBuffer, frames + offset, n );
}

View File

@@ -227,6 +227,9 @@ QString organicInstrument::nodeName() const
void organicInstrument::playNote( NotePlayHandle * _n,
sampleFrame * _working_buffer )
{
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
if( _n->totalFramesPlayed() == 0 || _n->m_pluginData == NULL )
{
Oscillator * oscs_l[m_numOscillators];
@@ -296,10 +299,8 @@ void organicInstrument::playNote( NotePlayHandle * _n,
Oscillator * osc_l = static_cast<oscPtr *>( _n->m_pluginData )->oscLeft;
Oscillator * osc_r = static_cast<oscPtr *>( _n->m_pluginData)->oscRight;
const fpp_t frames = _n->framesLeftForCurrentPeriod();
osc_l->update( _working_buffer, frames, 0 );
osc_r->update( _working_buffer, frames, 1 );
osc_l->update( _working_buffer + offset, frames, 0 );
osc_r->update( _working_buffer + offset, frames, 1 );
// -- fx section --
@@ -317,7 +318,7 @@ void organicInstrument::playNote( NotePlayHandle * _n,
// -- --
instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
}

View File

@@ -238,6 +238,7 @@ void papuInstrument::playNote( NotePlayHandle * _n,
const f_cnt_t tfp = _n->totalFramesPlayed();
const int samplerate = engine::mixer()->processingSampleRate();
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
int data = 0;
int freq = _n->frequency();
@@ -400,12 +401,12 @@ void papuInstrument::playNote( NotePlayHandle * _n,
for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch )
{
sample_t s = float(buf[frame*2+ch])/32768.0;
_working_buffer[frames-framesleft+frame][ch] = s;
_working_buffer[frames-framesleft+frame+offset][ch] = s;
}
}
framesleft -= count;
}
instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
}

View File

@@ -138,6 +138,7 @@ void patmanInstrument::playNote( NotePlayHandle * _n,
}
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
if( !_n->m_pluginData )
{
@@ -148,12 +149,12 @@ void patmanInstrument::playNote( NotePlayHandle * _n,
float play_freq = hdata->tuned ? _n->frequency() :
hdata->sample->frequency();
if( hdata->sample->play( _working_buffer, hdata->state, frames,
if( hdata->sample->play( _working_buffer + offset, hdata->state, frames,
play_freq, m_loopedModel.value() ? SampleBuffer::LoopOn : SampleBuffer::LoopOff ) )
{
applyRelease( _working_buffer, _n );
instrumentTrack()->processAudioBuffer( _working_buffer,
frames, _n );
frames + offset, _n );
}
}

View File

@@ -454,6 +454,7 @@ void sfxrInstrument::playNote( NotePlayHandle * _n, sampleFrame * _working_buffe
float currentSampleRate = engine::mixer()->processingSampleRate();
fpp_t frameNum = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
if ( _n->totalFramesPlayed() == 0 || _n->m_pluginData == NULL )
{
_n->m_pluginData = new SfxrSynth( this );
@@ -477,7 +478,7 @@ void sfxrInstrument::playNote( NotePlayHandle * _n, sampleFrame * _working_buffe
{
for( ch_cnt_t j=0; j<DEFAULT_CHANNELS; j++ )
{
_working_buffer[i][j] = pitchedBuffer[i*pitchedFrameNum/frameNum][j];
_working_buffer[i+offset][j] = pitchedBuffer[i*pitchedFrameNum/frameNum][j];
}
}
@@ -485,7 +486,7 @@ void sfxrInstrument::playNote( NotePlayHandle * _n, sampleFrame * _working_buffe
applyRelease( _working_buffer, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frameNum, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frameNum + offset, _n );
}

View File

@@ -317,6 +317,7 @@ void sidInstrument::playNote( NotePlayHandle * _n,
_n->m_pluginData = sid;
}
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
cSID *sid = static_cast<cSID *>( _n->m_pluginData );
int delta_t = clockrate * frames / samplerate + 4;
@@ -430,11 +431,11 @@ void sidInstrument::playNote( NotePlayHandle * _n,
sample_t s = float(buf[frame])/32768.0;
for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch )
{
_working_buffer[frame][ch] = s;
_working_buffer[frame+offset][ch] = s;
}
}
instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
}

View File

@@ -265,6 +265,7 @@ void malletsInstrument::playNote( NotePlayHandle * _n,
}
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
malletsSynth * ps = static_cast<malletsSynth *>( _n->m_pluginData );
ps->setFrequency( freq );
@@ -274,7 +275,7 @@ void malletsInstrument::playNote( NotePlayHandle * _n,
{
add_scale = static_cast<sample_t>( m_strikeModel.value() ) * freq * 2.5f;
}
for( fpp_t frame = 0; frame < frames; ++frame )
for( fpp_t frame = offset; frame < frames + offset; ++frame )
{
_working_buffer[frame][0] = ps->nextSampleLeft() *
( m_scalers[m_presetsModel.value()] + add_scale );
@@ -282,7 +283,7 @@ void malletsInstrument::playNote( NotePlayHandle * _n,
( m_scalers[m_presetsModel.value()] + add_scale );
}
instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
}

View File

@@ -358,13 +358,14 @@ void TripleOscillator::playNote( NotePlayHandle * _n,
Oscillator * osc_r = static_cast<oscPtr *>( _n->m_pluginData )->oscRight;
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
osc_l->update( _working_buffer, frames, 0 );
osc_r->update( _working_buffer, frames, 1 );
osc_l->update( _working_buffer + offset, frames, 0 );
osc_r->update( _working_buffer + offset, frames, 1 );
applyRelease( _working_buffer, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
}

View File

@@ -302,10 +302,11 @@ void vibed::playNote( NotePlayHandle * _n, sampleFrame * _working_buffer )
}
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
stringContainer * ps = static_cast<stringContainer *>(
_n->m_pluginData );
for( fpp_t i = 0; i < frames; ++i )
for( fpp_t i = offset; i < frames + offset; ++i )
{
_working_buffer[i][0] = 0.0f;
_working_buffer[i][1] = 0.0f;
@@ -324,7 +325,7 @@ void vibed::playNote( NotePlayHandle * _n, sampleFrame * _working_buffer )
}
}
instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
}

View File

@@ -343,6 +343,8 @@ void WatsynInstrument::playNote( NotePlayHandle * _n,
}
const fpp_t frames = _n->framesLeftForCurrentPeriod();
const f_cnt_t offset = _n->noteOffset();
sampleFrame * buffer = _working_buffer + offset;
WatsynObject * w = static_cast<WatsynObject *>( _n->m_pluginData );
@@ -424,9 +426,9 @@ void WatsynInstrument::playNote( NotePlayHandle * _n,
const float amix = 1.0 - bmix;
// mix a/b streams according to mixing knob
_working_buffer[f][0] = ( abuf[f][0] * amix ) +
buffer[f][0] = ( abuf[f][0] * amix ) +
( bbuf[f][0] * bmix );
_working_buffer[f][1] = ( abuf[f][1] * amix ) +
buffer[f][1] = ( abuf[f][1] * amix ) +
( bbuf[f][1] * bmix );
}
}
@@ -440,16 +442,16 @@ void WatsynInstrument::playNote( NotePlayHandle * _n,
for( fpp_t f=0; f < frames; f++ )
{
// mix a/b streams according to mixing knob
_working_buffer[f][0] = ( abuf[f][0] * amix ) +
buffer[f][0] = ( abuf[f][0] * amix ) +
( bbuf[f][0] * bmix );
_working_buffer[f][1] = ( abuf[f][1] * amix ) +
buffer[f][1] = ( abuf[f][1] * amix ) +
( bbuf[f][1] * bmix );
}
}
applyRelease( _working_buffer, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames, _n );
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
}