arpeggiator sorted mode fixed (#7025)
Fixes an issue where sorted arpeggios over multiple notes used a largely unusable algorithm. piano-octave-arp instead of octave-arp-piano. Fixes #6499 Fixes #4491
This commit is contained in:
@@ -31,6 +31,9 @@
|
||||
#include "InstrumentTrack.h"
|
||||
#include "PresetPreviewPlayHandle.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
|
||||
@@ -348,10 +351,11 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
_n->setMasterNote();
|
||||
|
||||
const int selected_arp = m_arpModel.value();
|
||||
const auto arpMode = static_cast<ArpMode>(m_arpModeModel.value());
|
||||
|
||||
ConstNotePlayHandleList cnphv = NotePlayHandle::nphsOfInstrumentTrack( _n->instrumentTrack() );
|
||||
ConstNotePlayHandleList cnphv = NotePlayHandle::nphsOfInstrumentTrack(_n->instrumentTrack());
|
||||
|
||||
if( static_cast<ArpMode>(m_arpModeModel.value()) != ArpMode::Free && cnphv.size() == 0 )
|
||||
if(arpMode != ArpMode::Free && cnphv.size() == 0 )
|
||||
{
|
||||
// maybe we're playing only a preset-preview-note?
|
||||
cnphv = PresetPreviewPlayHandle::nphsOfInstrumentTrack( _n->instrumentTrack() );
|
||||
@@ -363,10 +367,25 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
}
|
||||
}
|
||||
|
||||
// avoid playing same key for all
|
||||
// currently playing notes if sort mode is enabled
|
||||
if (arpMode == ArpMode::Sort && _n != cnphv.first()) { return; }
|
||||
|
||||
const InstrumentFunctionNoteStacking::ChordTable & chord_table = InstrumentFunctionNoteStacking::ChordTable::getInstance();
|
||||
const int cur_chord_size = chord_table.chords()[selected_arp].size();
|
||||
const int range = static_cast<int>(cur_chord_size * m_arpRangeModel.value() * m_arpRepeatsModel.value());
|
||||
const int total_range = range * cnphv.size();
|
||||
const int total_chord_size = cur_chord_size * cnphv.size();
|
||||
// how many notes are in a single chord (multiplied by range)
|
||||
const int singleNoteRange = static_cast<int>(cur_chord_size * m_arpRangeModel.value() * m_arpRepeatsModel.value());
|
||||
// how many notes are in the final chord
|
||||
const int range = arpMode == ArpMode::Sort ? singleNoteRange * cnphv.size() : singleNoteRange;
|
||||
|
||||
if (arpMode == ArpMode::Sort)
|
||||
{
|
||||
std::sort(cnphv.begin(), cnphv.end(), [](const NotePlayHandle* a, const NotePlayHandle* b)
|
||||
{
|
||||
return a->key() < b->key();
|
||||
});
|
||||
}
|
||||
|
||||
// number of frames that every note should be played
|
||||
const auto arp_frames = (f_cnt_t)(m_arpTimeModel.value() / 1000.0f * Engine::audioEngine()->outputSampleRate());
|
||||
@@ -375,11 +394,11 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
// 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 = ( ( static_cast<ArpMode>(m_arpModeModel.value()) != ArpMode::Free ) ?
|
||||
int cur_frame = (arpMode != ArpMode::Free ?
|
||||
cnphv.first()->totalFramesPlayed() :
|
||||
_n->totalFramesPlayed() ) + arp_frames - 1;
|
||||
_n->totalFramesPlayed()) + arp_frames - 1;
|
||||
// used for loop
|
||||
f_cnt_t frames_processed = ( static_cast<ArpMode>(m_arpModeModel.value()) != ArpMode::Free ) ? cnphv.first()->noteOffset() : _n->noteOffset();
|
||||
f_cnt_t frames_processed = arpMode != ArpMode::Free ? cnphv.first()->noteOffset() : _n->noteOffset();
|
||||
|
||||
while( frames_processed < Engine::audioEngine()->framesPerPeriod() )
|
||||
{
|
||||
@@ -395,17 +414,6 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
|
||||
frames_processed += remaining_frames_for_cur_arp;
|
||||
|
||||
// in sorted mode: is it our turn or do we have to be quiet for
|
||||
// now?
|
||||
if( static_cast<ArpMode>(m_arpModeModel.value()) == ArpMode::Sort &&
|
||||
( ( cur_frame / arp_frames ) % total_range ) / range != (f_cnt_t) _n->index() )
|
||||
{
|
||||
// update counters
|
||||
frames_processed += arp_frames;
|
||||
cur_frame += arp_frames;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip notes randomly
|
||||
if( m_arpSkipModel.value() )
|
||||
{
|
||||
@@ -435,7 +443,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
// process according to arpeggio-direction...
|
||||
if (dir == ArpDirection::Up || dir == ArpDirection::Down)
|
||||
{
|
||||
cur_arp_idx = ( cur_frame / arp_frames ) % range;
|
||||
cur_arp_idx = (cur_frame / arp_frames) % range;
|
||||
}
|
||||
else if ((dir == ArpDirection::UpAndDown || dir == ArpDirection::DownAndUp) && range > 1)
|
||||
{
|
||||
@@ -454,7 +462,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
else if( dir == ArpDirection::Random )
|
||||
{
|
||||
// just pick a random chord-index
|
||||
cur_arp_idx = (int)( range * ( (float) rand() / (float) RAND_MAX ) );
|
||||
cur_arp_idx = static_cast<int>(range * static_cast<float>(rand()) / static_cast<float>(RAND_MAX));
|
||||
}
|
||||
|
||||
// Divide cur_arp_idx with wanted repeats. The repeat feature will not affect random notes.
|
||||
@@ -464,7 +472,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
if( m_arpCycleModel.value() && dir != ArpDirection::Random )
|
||||
{
|
||||
cur_arp_idx *= m_arpCycleModel.value() + 1;
|
||||
cur_arp_idx %= static_cast<int>( range / m_arpRepeatsModel.value() );
|
||||
cur_arp_idx %= static_cast<int>(range / m_arpRepeatsModel.value());
|
||||
}
|
||||
|
||||
// If ArpDirection::Down or ArpDirection::DownAndUp, invert the final range.
|
||||
@@ -474,8 +482,23 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
}
|
||||
|
||||
// now calculate final key for our arp-note
|
||||
const int sub_note_key = base_note_key + (cur_arp_idx / cur_chord_size ) *
|
||||
int sub_note_key = 0;
|
||||
if (arpMode != ArpMode::Sort)
|
||||
{
|
||||
sub_note_key = base_note_key + (cur_arp_idx / cur_chord_size) *
|
||||
KeysPerOctave + chord_table.chords()[selected_arp][cur_arp_idx % cur_chord_size];
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto octaveDiv = std::div(cur_arp_idx, total_chord_size);
|
||||
const int octave = octaveDiv.quot;
|
||||
const auto arpDiv = std::div(octaveDiv.rem, cnphv.size());
|
||||
const int arpIndex = arpDiv.rem;
|
||||
const int chordIndex = arpDiv.quot;
|
||||
sub_note_key = cnphv[arpIndex]->key()
|
||||
+ chord_table.chords()[selected_arp][chordIndex]
|
||||
+ octave * KeysPerOctave;
|
||||
}
|
||||
|
||||
// range-checking
|
||||
if( sub_note_key >= NumKeys ||
|
||||
|
||||
Reference in New Issue
Block a user