Hey all, how are you?
So, I’m doing some testing with Rubberband to see if it suits my needs, and the idea is to use it to create harmonies for vocals.
The issue is that I need a way to adjust the pitch live depending on the interval of the scale so that the pitched notes are actually part of the scale.
(Example: In C major doing a harmony in thirds would mean that from C to E there are 4 semitones, but if then the bottom note moves up to E, the third would have to be G, so 3 semitones up).
My idea for now is the following:
- Pitch shift the harmony 3 semitones up.
- Take the incoming, original pitch (not shifted) and use it to detect what note of the key it is.
- Then, depending on what interval that note is, return a 1 or a 0 and add that to the pitch shift, so that instead of shifting up 3 semitones, it can vary between 3 and 4.
However, for now I have not been too successful lol!
This is what I got so far (with some help from AI)
int isFullStepOrHalfStep(float freq, int keyThatBeginsScale, int majorOrMinor)
{
// Get the closest frequency in the scale
float closestFreq = getClosestKeyFreqInScale(freq, keyThatBeginsScale, majorOrMinor);
int currentKeyNum = 0;
// Find the key number for our frequency
for (int i = 1; i <= NUM_PIANO_KEYS; i++) {
if (std::fabs(keyFreq[i] - closestFreq) < 0.01) {
currentKeyNum = i;
break;
}
}
// If we couldn't find the key number, return -1 for error
if (currentKeyNum == 0) return -1;
// Find position in scale (0-6, representing steps between notes)
int scalePosition = 0;
int tempKey = keyThatBeginsScale;
const int* scaleSteps = (majorOrMinor == 1) ? majorStep : minorStep;
while (tempKey < currentKeyNum) {
tempKey += scaleSteps[scalePosition];
scalePosition = (scalePosition + 1) % (NUM_OF_KEYS_IN_SCALE - 1);
}
// Now scalePosition points to the next step in the scale
// If we're at position 2 or 6 in major scale (E->F or B->C), it's a half step
// If we're at position 1 or 4 in minor scale (B->C or E->F), it's a half step
if (majorOrMinor == 1) { // Major scale
return (scalePosition != 2 && scalePosition != 6);
} else { // Minor scale
return (scalePosition != 1 && scalePosition != 4);
}
}
I sort of feel like this might not be the best approach, although shifting up a semitone or not depending on the interval seems pretty doable.
Any ideas? Or do you know of a more typical way this is usually done?
Thanks!
