I'm creating a midi program to alter incoming midi and putting out the altered midi, I do a bunch of stuff with it (one note chords etc) and everything is working fine. Next function I want to build in is a pretty standard function in music programs but i can't wrap my head around it. > Scales.
When a user select a scale from a list and plays a midi note the scale function should return the nearest (down) note to that played note.
// return greates number in list that is smaller than or equal input
// assuming that list is ordered (ascending)
int clamp(constint input, const std::vector<int> &list)
{
int result = 0;
for (std::vector<int>::const_iterator iter = list.cbegin(); iter != list.cend(); iter++)
{
if (*iter <= input)
{
result = *iter;
}
else
{
break;
}
}
return result;
}
int main()
{
std::vector<int> scale = { 0,2,3,5,7,8,11 };
std::cout << clamp(6, scale) << std::endl;
}
If it has to work with unordered lists too:
1 2 3 4 5 6 7 8 9 10 11 12 13
// return greates number in list that is smaller than or equal input
int clamp2(constint input, const std::vector<int> &list)
{
int result = 0;
for (std::vector<int>::const_iterator iter = list.cbegin(); iter != list.cend(); iter++)
{
if ((*iter <= input) && (*iter > result))
{
result = *iter;
}
}
return result;
}
And what do you think that error means? Do you know what a template argument is? Template arguments are the parts inside the < > on a template instantiation.
So it's saying that it's trying to use a template without specifying the < > part, in this case <int>. Look at lines 2 and 3 of the post. You'd fix that by doing vector<int> instead of just vector.
Edit: And also change std::vector::const_iter (or change it to just 'auto'). Or just use a for-each loop.
yes, i was reading up on it, already changed the template to int but didn't change the auto. The code is running now!
So, when i run it and i input midi notes, let's say note 24, 68, etc the result will be always 11 off course as this is the highest number in the vector.
So i'm thinking I prob need to have a "root note" that has a value from 0 to 11 (or 1 to 12).
Then do some math that when i play a midi note it will start calculating from that root note and give me back the nearest number according to the scale vector, so if i input for example 45 it could give back 43, 44, 46 etc according to that scale.
@Ganado no, for example 24 is note C1, 36 is note C2, 48 is note C3, every time between these notes is C,C#,D,D#,E,F,F# so every octave has 12 notes and just repeats. So every incoming midi note responds to a musical note. Now what I'm trying to accomplisch is to transpose every incoming number to the nearest number in one of those scale vectors
If I'm understanding, the goal here is to to be able to take any midi sequence, and convert it from one mode to another? (e.g. major (Ionian) to natural minor scale (Aeolian)). Don't you need to know what mode the untransposed notes are a part of, in order to do this? Or am I misunderstanding the goal?
If I am misunderstanding, it's fine -- I'd say try out the method you're planning, and then explain it more if your idea doesn't work after you try it.
So, i'm processing incoming midi from a keyboard. So the incoming midi is not in a mode. It's just notes being played. I now want to "lock in" these notes to a certain scale. This is a very common practice in synthesizers and sequencers so the player can't play any wrong notes or the sequencer can't play wrong notes if other parts of a song or in the same scale key.
The note value I get needs to be divided by x times 12, then the rest value of that needs to be inputted in the function above and x times 12 needs to be added again.
Anyone now how to do this in c++?
So if the incoming number would be 77 then we need to subtract 6 times 12 (to get close to zero and get the remainder) = 72. Then 77 - 12 = 5 needs to be put in the scale function above, we get back another number (the one closest too) and to that number we add 72 again :)
The note value I get needs to be divided by x times 12, then the rest value of that needs to be inputted in the function above and x times 12 needs to be added again.
The modulus operator (rest of integer division) is denoted as % in C/C++: int rest = input % (x * 12);
This can be more efficient, because on most CPU architectures the "divide" instructions returns quotient and remainder at once; and there is no separate "modulus" instruction. So the div() function can be implemented with just a single hardware instruction, whereas your above code would effectively require two divisions...
(unless the compiler is smart enough to optimize to code to a single division, of course)
Ok guys, I'm back :D Everything is working fine but now i have to implement a "root note function" I'm way too tired to explain it right but maybe someone will get it :)
So, the user can select a scale and with the above function everything is returned as it should.
Now the user can also select a root note: (C,C#,D,D#,E,F,F#,G,G#,A,A#,B) so from 1 to 12.
This needs to be inserted in the function somehow, so the lookup needs to be transposed.
I've been staring at it for hours but i can't find the solution. So if I just add the root note it's not good because it will only shift the notes higher, so the transpose should set the 0 in the for example: { 0,2,3,5,7,8,11 } to the root note integer (1 to 12)
Sorry for my bad explanation, hopefully someone will understand :)
*EDIT: Found it:
auto note = currentMessage.getNoteNumber() - rootNote;
int quotient = note / 12;
int remainder = note % 12;
notejaja = changeNoteToScale(remainder,scaleSelected) + rootNote;
So know I reversed the code, to get the nearest number up:
It works but if I put in 11, off course it will break, it should return then the nearest (being 11 in this case) I'm also not sure if my logic is correct...
Initialize result to std::vector::back() before the loop. Or what else, if not the last (greatest) value in the vector, you want to get, if the given input is greater than any value in the vector?