-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathArpeggiator.cpp
148 lines (137 loc) · 3.71 KB
/
Arpeggiator.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* Arpeggiator.cpp
*
* Created on: Apr 11, 2015
* Author: Martin Baar
*/
#include "Arpeggiator.h"
#include "random.h"
Arpeggiator::Arpeggiator() : algorithm_(Arpeggiator::UP), windowSize_(1), count_(0), started_(false),
currentIndex_(0), upDownGoingUp_(true), removeNoteAfterGettingNext_(false)
{
}
bool Arpeggiator::addNote(unsigned char note) {
if (count_ != ARPEGGIATOR_MAX_VALUES) {
unsigned char valueIndex;
if (!findValue(note, notes_, valueIndex)) {
notes_[count_] = note;
count_++;
fillSorted();
return true;
}
}
return false;
}
bool Arpeggiator::removeNote(unsigned char note) {
//When note is just playing we shall remove it later when we want to do another step
if (note == notes_[currentIndex_]) {
removeNoteAfterGettingNext_ = true;
return true;
} else {
unsigned char valueIndex;
if (findValue(note, notes_, valueIndex)) {
if (valueIndex < currentIndex_) {
currentIndex_--;
}
for (unsigned char i = valueIndex; i < (count_ - 1); i++) {
notes_[i] = notes_[i + 1];
}
count_--;
fillSorted();
return true;
}
}
return false;
}
bool Arpeggiator::getNextNote(unsigned char& note) {
if (count_ != 0) {
unsigned char oldIndex = currentIndex_;
do {
currentIndex_ = getNextIndex();
} while (currentIndex_ < (count_ - windowSize_));
note = notes_[currentIndex_];
if (removeNoteAfterGettingNext_) {
removeNote(notes_[oldIndex]);
removeNoteAfterGettingNext_ = false;
if (count_ == 0) {
return false;
}
}
return true;
}
return false;
}
bool Arpeggiator::findValue(unsigned char value, unsigned char* array, unsigned char& index) {
for (unsigned char i = 0; i < count_; i++) {
if (array[i] == value) {
index = i;
return true;
}
}
return false;
}
unsigned char Arpeggiator::getNextIndex() {
if (started_) {
switch (algorithm_) {
case Arpeggiator::UP :
return (currentIndex_ + 1) % count_;
case Arpeggiator::DOWN:
return (currentIndex_ == 0) ? (count_ - 1) : (currentIndex_ - 1);
case Arpeggiator::UP_DOWN:
unsigned char newIndex;
if (upDownGoingUp_) {
if ((currentIndex_ + 1) == count_) {
upDownGoingUp_ = false;
return currentIndex_ - 1;
} else {
return (currentIndex_ + 1) % count_;
}
} else {
if (currentIndex_ == 0 || (currentIndex_ == count_ - windowSize_)) {
upDownGoingUp_ = true;
return (currentIndex_ + 1) % count_;
} else {
return currentIndex_ - 1;
}
}
if (newIndex == (count_ - 1) || newIndex == (count_ - windowSize_) || newIndex == 0) {
upDownGoingUp_ = ! upDownGoingUp_;
}
return newIndex;
case Arpeggiator::SORTED:
unsigned char indexInSorted;
findValue(currentIndex_, sortedNotes_, indexInSorted);
return sortedNotes_[(indexInSorted + 1) % count_];
case Arpeggiator::RANDOM:
return bastlRandom::range(count_- windowSize_, count_ - 1);
default:
return currentIndex_;
}
} else {
//Sequence just started so based on used algorithm we have to return
//correct first note to play
started_ = true;
//For Down initial index is last item not the first one!
if (algorithm_ == Arpeggiator::DOWN) {
currentIndex_ = (count_ - 1);
} else if (algorithm_ == Arpeggiator::SORTED) {
currentIndex_ = sortedNotes_[0];
} else {
currentIndex_ = 0;
upDownGoingUp_ = true;
}
}
return currentIndex_;
}
void Arpeggiator::fillSorted() {
for (unsigned char sourceIndex = 0; sourceIndex < count_; sourceIndex++) {
unsigned char value = notes_[sourceIndex];
unsigned char targetIndex = 0;
for (unsigned char checkedIndex = 0; checkedIndex < count_; checkedIndex++) {
if (value > notes_[checkedIndex]) {
targetIndex++;
}
}
sortedNotes_[targetIndex] = sourceIndex;
}
}