Skip to content
Merged
Changes from 5 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
84 changes: 67 additions & 17 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 <algorithm>
#include <vector>

namespace lmms
{

Expand Down Expand Up @@ -365,6 +368,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )

const InstrumentFunctionNoteStacking::ChordTable & chord_table = InstrumentFunctionNoteStacking::ChordTable::getInstance();
const int cur_chord_size = chord_table.chords()[selected_arp].size();
const int total_chord_size = cur_chord_size * cnphv.size();
const int range = static_cast<int>(cur_chord_size * m_arpRangeModel.value() * m_arpRepeatsModel.value());
const int total_range = range * cnphv.size();

Expand Down Expand Up @@ -395,15 +399,45 @@ 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() )
// for sort mode, we combine all of the chord's keys for every
// currently playing note in an arrray, sort it and play it
// sortOffset offsets range to account for
// the arp getting bigger if arpmode = sort
int sortOffset = 0;
// this array will contain the combined, sorted keys
std::vector<int> noteKeysArray(total_chord_size);
if (static_cast<ArpMode>(m_arpModeModel.value()) == ArpMode::Sort)
{
// update counters
frames_processed += arp_frames;
cur_frame += arp_frames;
continue;
int minIndex = _n->index();

// combining all of the chord keys
for (int i = 0; i < cnphv.size(); i++)
{
for (int j = 0; j < cur_chord_size; j++)
{
// get the value of the chord's selected note (j)
// + the base note's value
noteKeysArray[i * cur_chord_size + j] = cnphv[i]->key() + chord_table.chords()[selected_arp][j];
}
if (cnphv[i]->index() < minIndex)
{
minIndex = cnphv[i]->index();
}
}

// avoid playing same key for all
// currently playing notes
if (minIndex != _n->index())
{
break;
}

// sorting:
std::sort(noteKeysArray.begin(), noteKeysArray.end(), std::less{});

// we need to account for a bigger arp
// sortOffset will make range greater
sortOffset = total_range - range;
}

// Skip notes randomly
Expand Down Expand Up @@ -435,26 +469,27 @@ 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 + sortOffset);
}
else if ((dir == ArpDirection::UpAndDown || dir == ArpDirection::DownAndUp) && range > 1)
else if ((dir == ArpDirection::UpAndDown || dir == ArpDirection::DownAndUp) &&
(range + sortOffset) > 1)
{
// imagine, we had to play the arp once up and then
// 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 * static_cast<int>(m_arpRepeatsModel.value())));
cur_arp_idx = (cur_frame / arp_frames) % ((range + sortOffset) * 2 - (2 * static_cast<int>(m_arpRepeatsModel.value())));
// if greater than range, we have to play down...
// looks like the code for arp_dir==DOWN... :)
if (cur_arp_idx >= range)
if (cur_arp_idx >= (range + sortOffset))
{
cur_arp_idx = range - cur_arp_idx % (range - 1) - static_cast<int>(m_arpRepeatsModel.value());
cur_arp_idx = (range + sortOffset) - cur_arp_idx % (range + sortOffset - 1) - static_cast<int>(m_arpRepeatsModel.value());
}
}
else if( dir == ArpDirection::Random )
{
// just pick a random chord-index
cur_arp_idx = (int)( range * ( (float) rand() / (float) RAND_MAX ) );
cur_arp_idx = (int)((range + sortOffset) * ((float) rand() / (float) RAND_MAX));
}

// Divide cur_arp_idx with wanted repeats. The repeat feature will not affect random notes.
Expand All @@ -464,18 +499,33 @@ 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 + sortOffset) / m_arpRepeatsModel.value());
}

// If ArpDirection::Down or ArpDirection::DownAndUp, invert the final range.
if (dir == ArpDirection::Down || dir == ArpDirection::DownAndUp)
{
cur_arp_idx = static_cast<int>(range / m_arpRepeatsModel.value()) - cur_arp_idx - 1;
cur_arp_idx = static_cast<int>((range + sortOffset) / m_arpRepeatsModel.value()) - cur_arp_idx - 1;
}

// 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 (static_cast<ArpMode>(m_arpModeModel.value()) != 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
{
// if we are sorting, we already have the base note key and the chord key
sub_note_key = noteKeysArray[cur_arp_idx % total_chord_size] + (cur_arp_idx / total_chord_size) *
KeysPerOctave;
// limiting the played key so it does not get out of NumKeys range
if (sub_note_key >= NumKeys)
{
sub_note_key = NumKeys - 1;
}
}

// range-checking
if( sub_note_key >= NumKeys ||
Expand Down