Skip to content

Commit

Permalink
NotePlayHandle, InstrumentFunctions: reworked stacking and arpeggio h…
Browse files Browse the repository at this point in the history
…andling

Instead of having various flags for realizing the arpeggion functionality
use a more generic approach here using the recently introduced "origin"
property.
  • Loading branch information
tobydox committed Mar 26, 2014
1 parent 89dc820 commit 6650dd3
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 139 deletions.
31 changes: 13 additions & 18 deletions include/NotePlayHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class EXPORT NotePlayHandle : public PlayHandle, public note
{
OriginPattern, /*! playback of a note from a pattern */
OriginMidiInput, /*! playback of a MIDI note input event */
OriginNoteStacking, /*! created by note stacking instrument function */
OriginArpeggio, /*! created by arpeggio instrument function */
OriginCount
};
typedef Origins Origin;
Expand All @@ -60,7 +62,6 @@ class EXPORT NotePlayHandle : public PlayHandle, public note
const f_cnt_t frames,
const note& noteToPlay,
NotePlayHandle* parent = NULL,
const bool isPartOfArp = false,
int midiEventChannel = -1,
Origin origin = OriginPattern );
virtual ~NotePlayHandle();
Expand Down Expand Up @@ -160,27 +161,24 @@ class EXPORT NotePlayHandle : public PlayHandle, public note
return m_instrumentTrack;
}

/*! Returns whether note is a top note, e.g. is not part of an arpeggio or a chord */
bool isTopNote() const
/*! Returns whether note has a parent, e.g. is not part of an arpeggio or a chord */
bool hasParent() const
{
return m_topNote;
return m_hasParent;
}

/*! Returns whether note is part of an arpeggio playback */
bool isPartOfArpeggio() const
/*! Returns origin of note */
Origin origin() const
{
return m_partOfArpeggio;
return m_origin;
}

/*! Sets whether note is part of an arpeggio playback */
void setPartOfArpeggio( const bool _on )
/*! Returns whether note has children */
bool isMasterNote() const
{
m_partOfArpeggio = _on;
return m_subNotes.size() > 0 || m_hadChildren;
}

/*! Returns whether note is base note for arpeggio */
bool isArpeggioBaseNote() const;

/*! Returns whether note is muted */
bool isMuted() const
{
Expand Down Expand Up @@ -268,11 +266,8 @@ class EXPORT NotePlayHandle : public PlayHandle, public note
// release of note
NotePlayHandleList m_subNotes; // used for chords and arpeggios
volatile bool m_released; // indicates whether note is released
bool m_topNote; // indicates whether note is a
// base-note (i.e. no sub-note)
bool m_partOfArpeggio; // indicates whether note is part of
// an arpeggio (either base-note or
// sub-note)
bool m_hasParent;
bool m_hadChildren;
bool m_muted; // indicates whether note is muted
track* m_bbTrack; // related BB track

Expand Down
2 changes: 1 addition & 1 deletion plugins/lb302/lb302.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ void lb302Synth::playNote( NotePlayHandle * _n, sampleFrame * _working_buffer )
{
//fpp_t framesPerPeriod = engine::mixer()->framesPerPeriod();

if( _n->isArpeggioBaseNote() )
if( _n->isMasterNote() )
{
return;
}
Expand Down
115 changes: 39 additions & 76 deletions src/core/InstrumentFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,47 +231,37 @@ void InstrumentFunctionNoteStacking::processNote( NotePlayHandle * _n )
// at the same time we only add sub-notes if nothing of the note was
// played yet, because otherwise we would add chord-subnotes every
// time an audio-buffer is rendered...
if( ( ( _n->isTopNote() && _n->instrumentTrack()->isArpeggioEnabled() == false ) || _n->isPartOfArpeggio() ) &&
_n->totalFramesPlayed() == 0 &&
m_chordsEnabledModel.value() == true )
if( ( _n->origin() == NotePlayHandle::OriginArpeggio || ( _n->hasParent() == false && _n->instrumentTrack()->isArpeggioEnabled() == false ) ) &&
_n->totalFramesPlayed() == 0 &&
m_chordsEnabledModel.value() == true )
{
// then insert sub-notes for chord
const int selected_chord = m_chordsModel.value();

for( int octave_cnt = 0;
octave_cnt < m_chordRangeModel.value(); ++octave_cnt )
for( int octave_cnt = 0; octave_cnt < m_chordRangeModel.value(); ++octave_cnt )
{
const int sub_note_key_base = base_note_key +
octave_cnt * KeysPerOctave;
const int sub_note_key_base = base_note_key + octave_cnt * KeysPerOctave;
// if octave_cnt == 1 we're in the first octave and
// the base-note is already done, so we don't have to
// create it in the following loop, then we loop until
// there's a -1 in the interval-array
for( int i = ( octave_cnt == 0 ) ? 1 : 0;
i < chord_table[selected_chord].size();
++i )
for( int i = ( octave_cnt == 0 ) ? 1 : 0; i < chord_table[selected_chord].size(); ++i )
{
// add interval to sub-note-key
const int sub_note_key = sub_note_key_base +
(int) chord_table[
selected_chord][i];
const int sub_note_key = sub_note_key_base + (int) chord_table[selected_chord][i];
// maybe we're out of range -> let's get outta
// here!
if( sub_note_key > NumKeys )
{
break;
}
// create copy of base-note
note note_copy( _n->length(), 0, sub_note_key,
_n->getVolume(),
_n->getPanning(),
_n->detuning() );
note note_copy( _n->length(), 0, sub_note_key, _n->getVolume(), _n->getPanning(), _n->detuning() );

// create sub-note-play-handle, only note is
// different
new NotePlayHandle( _n->instrumentTrack(),
_n->offset(),
_n->frames(), note_copy,
_n );
new NotePlayHandle( _n->instrumentTrack(), _n->offset(), _n->frames(), note_copy,
_n, -1, NotePlayHandle::OriginNoteStacking );
}
}
}
Expand Down Expand Up @@ -310,10 +300,8 @@ InstrumentFunctionArpeggio::InstrumentFunctionArpeggio( Model * _parent ) :
m_arpEnabledModel( false ),
m_arpModel( this, tr( "Arpeggio type" ) ),
m_arpRangeModel( 1.0f, 1.0f, 9.0f, 1.0f, this, tr( "Arpeggio range" ) ),
m_arpTimeModel( 100.0f, 25.0f, 2000.0f, 1.0f, 2000, this,
tr( "Arpeggio time" ) ),
m_arpGateModel( 100.0f, 1.0f, 200.0f, 1.0f, this,
tr( "Arpeggio gate" ) ),
m_arpTimeModel( 100.0f, 25.0f, 2000.0f, 1.0f, 2000, this, tr( "Arpeggio time" ) ),
m_arpGateModel( 100.0f, 1.0f, 200.0f, 1.0f, this, tr( "Arpeggio gate" ) ),
m_arpDirectionModel( this, tr( "Arpeggio direction" ) ),
m_arpModeModel( this, tr( "Arpeggio mode" ) )
{
Expand All @@ -325,10 +313,8 @@ InstrumentFunctionArpeggio::InstrumentFunctionArpeggio( Model * _parent ) :

m_arpDirectionModel.addItem( tr( "Up" ), new PixmapLoader( "arp_up" ) );
m_arpDirectionModel.addItem( tr( "Down" ), new PixmapLoader( "arp_down" ) );
m_arpDirectionModel.addItem( tr( "Up and down" ),
new PixmapLoader( "arp_up_and_down" ) );
m_arpDirectionModel.addItem( tr( "Random" ),
new PixmapLoader( "arp_random" ) );
m_arpDirectionModel.addItem( tr( "Up and down" ), new PixmapLoader( "arp_up_and_down" ) );
m_arpDirectionModel.addItem( tr( "Random" ), new PixmapLoader( "arp_random" ) );
m_arpDirectionModel.setInitValue( ArpDirUp );

m_arpModeModel.addItem( tr( "Free" ), new PixmapLoader( "arp_free" ) );
Expand All @@ -349,18 +335,19 @@ InstrumentFunctionArpeggio::~InstrumentFunctionArpeggio()
void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
{
const int base_note_key = _n->key();
if( _n->isTopNote() == false ||
!m_arpEnabledModel.value() ||
( _n->isReleased() && _n->releaseFramesDone() >= _n->actualReleaseFramesToDo() ) )
if( _n->origin() == NotePlayHandle::OriginArpeggio ||
_n->origin() == NotePlayHandle::OriginNoteStacking ||
!m_arpEnabledModel.value() ||
( _n->isReleased() && _n->releaseFramesDone() >= _n->actualReleaseFramesToDo() ) )
{
return;
}


const int selected_arp = m_arpModel.value();

ConstNotePlayHandleList cnphv = NotePlayHandle::nphsOfInstrumentTrack(
_n->instrumentTrack() );
ConstNotePlayHandleList cnphv = NotePlayHandle::nphsOfInstrumentTrack( _n->instrumentTrack() );

if( m_arpModeModel.value() != FreeMode && cnphv.size() == 0 )
{
// maybe we're playing only a preset-preview-note?
Expand All @@ -379,27 +366,23 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
const int total_range = range * cnphv.size();

// number of frames that every note should be played
const f_cnt_t arp_frames = (f_cnt_t)( m_arpTimeModel.value() / 1000.0f *
engine::mixer()->processingSampleRate() );
const f_cnt_t gated_frames = (f_cnt_t)( m_arpGateModel.value() *
arp_frames / 100.0f );
const f_cnt_t arp_frames = (f_cnt_t)( m_arpTimeModel.value() / 1000.0f * engine::mixer()->processingSampleRate() );
const f_cnt_t gated_frames = (f_cnt_t)( m_arpGateModel.value() * arp_frames / 100.0f );

// used for calculating remaining frames for arp-note, we have to add
// arp_frames-1, otherwise the first arp-note will not be setup
// correctly... -> arp_frames frames silence at the start of every note!
int cur_frame = ( ( m_arpModeModel.value() != FreeMode ) ?
cnphv.first()->totalFramesPlayed() :
_n->totalFramesPlayed() ) + arp_frames - 1;
cnphv.first()->totalFramesPlayed() :
_n->totalFramesPlayed() ) + arp_frames - 1;
// used for loop
f_cnt_t frames_processed = 0;

while( frames_processed < engine::mixer()->framesPerPeriod() )
{
const f_cnt_t remaining_frames_for_cur_arp = arp_frames -
( cur_frame % arp_frames );
const f_cnt_t remaining_frames_for_cur_arp = arp_frames - ( cur_frame % arp_frames );
// does current arp-note fill whole audio-buffer?
if( remaining_frames_for_cur_arp >
engine::mixer()->framesPerPeriod() )
if( remaining_frames_for_cur_arp > engine::mixer()->framesPerPeriod() )
{
// then we don't have to do something!
break;
Expand All @@ -413,8 +396,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
// in sorted mode: is it our turn or do we have to be quiet for
// now?
if( m_arpModeModel.value() == SortMode &&
( ( cur_frame / arp_frames ) % total_range ) /
range != (f_cnt_t) _n->index() )
( ( cur_frame / arp_frames ) % total_range ) / range != (f_cnt_t) _n->index() )
{
// update counters
frames_processed += arp_frames;
Expand All @@ -439,33 +421,28 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
// once down -> makes 2 * range possible notes...
// because we don't play the lower and upper notes
// twice, we have to subtract 2
cur_arp_idx = ( cur_frame / arp_frames ) %
( range * 2 - 2 );
cur_arp_idx = ( cur_frame / arp_frames ) % ( range * 2 - 2 );
// if greater than range, we have to play down...
// looks like the code for arp_dir==DOWN... :)
if( cur_arp_idx >= range )
{
cur_arp_idx = range - cur_arp_idx %
( range - 1 ) - 1;
cur_arp_idx = range - cur_arp_idx % ( range - 1 ) - 1;
}
}
else if( dir == ArpDirRandom )
{
// just pick a random chord-index
cur_arp_idx = (int)( range * ( (float) rand() /
(float) RAND_MAX ) );
cur_arp_idx = (int)( range * ( (float) rand() / (float) RAND_MAX ) );
}

// now calculate final key for our arp-note
const int sub_note_key = base_note_key + (cur_arp_idx /
cur_chord_size ) *
KeysPerOctave +
chord_table[selected_arp][cur_arp_idx % cur_chord_size];
const int sub_note_key = base_note_key + (cur_arp_idx / cur_chord_size ) *
KeysPerOctave + chord_table[selected_arp][cur_arp_idx % cur_chord_size];

// range-checking
if( sub_note_key >= NumKeys ||
sub_note_key < 0 ||
engine::mixer()->criticalXRuns() )
engine::mixer()->criticalXRuns() )
{
continue;
}
Expand All @@ -477,34 +454,20 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
}

// create new arp-note
note new_note( MidiTime( 0 ), MidiTime( 0 ),
sub_note_key,
(volume_t)
qRound( _n->getVolume() * vol_level ),
_n->getPanning(), _n->detuning() );

// create sub-note-play-handle, only ptr to note is different
// and is_arp_note=true
new NotePlayHandle( _n->instrumentTrack(),
( ( m_arpModeModel.value() != FreeMode ) ?
cnphv.first()->offset() :
_n->offset() ) +
frames_processed,
gated_frames,
new_note,
_n, true );
( ( m_arpModeModel.value() != FreeMode ) ? cnphv.first()->offset() : _n->offset() ) + frames_processed,
gated_frames,
note( MidiTime( 0 ), MidiTime( 0 ), sub_note_key, (volume_t) qRound( _n->getVolume() * vol_level ),
_n->getPanning(), _n->detuning() ),
_n, -1, NotePlayHandle::OriginArpeggio );

// update counters
frames_processed += arp_frames;
cur_frame += arp_frames;
}

// make sure, note is handled as arp-base-note, even if we didn't add a
// sub-note so far
if( m_arpModeModel.value() != FreeMode )
{
_n->setPartOfArpeggio( true );
}
}


Expand Down
Loading

0 comments on commit 6650dd3

Please sign in to comment.