Skip to content
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
36ec16a
merged with upstream
szeli1 Apr 13, 2024
94d9003
arp_style_changes
szeli1 Dec 22, 2023
dc0c0f1
added merge changes back
szeli1 Apr 13, 2024
30b28db
changes applyed to merge
szeli1 Apr 13, 2024
7a7214b
InstrumentFunctions_sorting_replaced_with_stdless
szeli1 Apr 23, 2024
b28b4cc
InstrumentFunctions_range_combined_with_sortOffset
szeli1 Apr 23, 2024
10c33b5
InstrumentFunctions_std_div_instead_of_operators
szeli1 Apr 24, 2024
6f51813
InstrumentFunctions_reworked_sorting
szeli1 May 9, 2024
3bf63c4
InstrumentFunctions_finished_sort_changes
szeli1 May 10, 2024
fba9e31
InstrumentSoundShaping_envelope_now_uses_parent_note
szeli1 May 10, 2024
44df07e
EnvelopeAndLFOParameters_added_checkbox
szeli1 May 11, 2024
164f165
InstrumentFunctions_fixed_sort_order
szeli1 May 12, 2024
f6f2654
Revert "EnvelopeAndLFOParameters_added_checkbox"
szeli1 May 15, 2024
f8622f8
Revert "InstrumentSoundShaping_envelope_now_uses_parent_note"
szeli1 May 15, 2024
a86651a
InstrumentFunctions_arp_order_octave_arp_piano
szeli1 Jun 8, 2024
7b09570
InstrumentFunctions_style_changes
szeli1 Jun 8, 2024
975352c
InstrumentFunctions_introduced_arpMode_variable
szeli1 Jun 15, 2024
1dc8a81
InstrumentFunctions_replaced_offsetRange_by_range
szeli1 Jun 15, 2024
a7f49bc
InstrumentFunctions_added_return_instead_of_break
szeli1 Jun 15, 2024
6e9e626
InstrumentFunctions_removed_old_code
szeli1 Jun 15, 2024
a534b31
InstrumentFunctions_implemented_cnphv_sorting
szeli1 Jun 15, 2024
0c0b19f
InstrumentFunctions_removed_include_QMutex
szeli1 Jun 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 45 additions & 22 deletions src/core/InstrumentFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
#include "InstrumentTrack.h"
#include "PresetPreviewPlayHandle.h"

#include <vector>
#include <algorithm>

namespace lmms
{

Expand Down Expand Up @@ -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() );
Expand All @@ -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()->processingSampleRate());
Expand All @@ -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() )
{
Expand All @@ -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() )
{
Expand Down Expand Up @@ -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)
{
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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 ||
Expand Down