Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

M-OSC/Waveforms Chords, Color parameter .... #121

Closed
eh2k opened this issue Dec 30, 2024 · 7 comments
Closed

M-OSC/Waveforms Chords, Color parameter .... #121

eh2k opened this issue Dec 30, 2024 · 7 comments

Comments

@eh2k
Copy link
Owner

eh2k commented Dec 30, 2024

I have removed the quantizer numbers - to avoid unnecessary confusion.

Cmon please 😅 bring them back!
Only ppl with the perfect pitch can hear such complex and multi note chords (not me) so it was very useful...

Originally posted by @koswir in #117 (comment)

Braids Renaissance Chords:

const uint8_t diatonic_chords[16][4] = {
{1, 7, 0, 0}, // octave
{2, 5, 7, 0}, // octave add6
{1, 6, 0, 0}, // 7th
{2, 5, 6, 0}, // 7th add6
{2, 6, 8, 0}, // 9th
{3, 6, 8, 10}, // 11th
{3, 5, 7, 10}, // 11th add6
{1, 8, 0, 0}, // add9
{2, 6, 10, 0}, // 7th add11
{2, 6, 12, 0}, // 7th add13
{1, 7, 0, 0}, // oct sus4
{1, 6, 0, 0}, // 7th sus4
{2, 6, 8, 0}, // 9th sus4
{2, 6, 8, 0}, // 9th sus2
{3, 8, 10, 6}, // 11th sus4
};
void DigitalOscillator::RenderDiatonicChord(
const uint8_t* sync,
int16_t* buffer,
size_t size) {
uint8_t extensionIndex = (parameter_[1] >> 12) & 0xf;
// uint8_t inversion = (parameter_[1] >> 13) & 0x7;
uint8_t offsets[6];
uint8_t len = 0;
if (quantizer.enabled()) {
offsets[1] = 4;
if (extensionIndex < 11) {
offsets[0] = 2;
} else if (extensionIndex < 15) {
offsets[0] = 3;
} else {
offsets[0] = 1;
}
len = diatonic_chords[extensionIndex][0];
for (size_t i = 0; i < len; i++) {
offsets[i+2] = diatonic_chords[extensionIndex][i+1];
}
len += 3;
} else {
// send len=0 as indication to use the phase offsets from the paraphonic chord array.
}
renderChord(sync, buffer, size, offsets, len);
}

Actually quite similar to the Plaits Chords

const char* const chord_names[kChordNumChords] = {
"OCT",
"Fifth",
"m",
"m7",
"m9",
"m11",
"M",
"M7",
"M9",
"Sus4",
"69",
"6th",
"10th",
"D7",
"D7(b9)",
"HD",
"FD",
};
// Alternative chord table by Jon Butler [email protected]
/* static */
const float ChordBank::chords_[kChordNumChords][kChordNumNotes] = {
// Fixed Intervals
{ 0.00f, 0.01f, 11.99f, 12.00f }, // Octave
{ 0.00f, 7.00f, 7.01f, 12.00f }, // Fifth
// Minor
{ 0.00f, 3.00f, 7.00f, 12.00f }, // Minor
{ 0.00f, 3.00f, 7.00f, 10.00f }, // Minor 7th
{ 0.00f, 3.00f, 10.00f, 14.00f }, // Minor 9th
{ 0.00f, 3.00f, 10.00f, 17.00f }, // Minor 11th
// Major
{ 0.00f, 4.00f, 7.00f, 12.00f }, // Major
{ 0.00f, 4.00f, 7.00f, 11.00f }, // Major 7th
{ 0.00f, 4.00f, 11.00f, 14.00f }, // Major 9th
// Colour Chords
{ 0.00f, 5.00f, 7.00f, 12.00f }, // Sus4
{ 0.00f, 2.00f, 9.00f, 16.00f }, // 69
{ 0.00f, 4.00f, 7.00f, 9.00f }, // 6th
{ 0.00f, 7.00f, 16.00f, 23.00f }, // 10th (Spread maj7)
{ 0.00f, 4.00f, 7.00f, 10.00f }, // Dominant 7th
{ 0.00f, 7.00f, 10.00f, 13.00f }, // Dominant 7th (b9)
{ 0.00f, 3.00f, 6.00f, 10.00f }, // Half Diminished
{ 0.00f, 3.00f, 6.00f, 9.00f }, // Fully Diminished
};
#else

In the current version, the colour parameter incrementation does not match the chords table.
It may be possible to simply name the chords instead of ‘Colour’ as with the Plaits Chords.

@koswir
Copy link

koswir commented Jan 1, 2025

I have removed the quantizer numbers - to avoid unnecessary confusion.

Cmon please 😅 bring them back!
Only ppl with the perfect pitch can hear such complex and multi note chords (not me) so it was very useful...

Originally posted by @koswir in #117 (comment)

Braids Renaissance Chords:

const uint8_t diatonic_chords[16][4] = {
{1, 7, 0, 0}, // octave
{2, 5, 7, 0}, // octave add6
{1, 6, 0, 0}, // 7th
{2, 5, 6, 0}, // 7th add6
{2, 6, 8, 0}, // 9th
{3, 6, 8, 10}, // 11th
{3, 5, 7, 10}, // 11th add6
{1, 8, 0, 0}, // add9
{2, 6, 10, 0}, // 7th add11
{2, 6, 12, 0}, // 7th add13
{1, 7, 0, 0}, // oct sus4
{1, 6, 0, 0}, // 7th sus4
{2, 6, 8, 0}, // 9th sus4
{2, 6, 8, 0}, // 9th sus2
{3, 8, 10, 6}, // 11th sus4
};
void DigitalOscillator::RenderDiatonicChord(
const uint8_t* sync,
int16_t* buffer,
size_t size) {
uint8_t extensionIndex = (parameter_[1] >> 12) & 0xf;
// uint8_t inversion = (parameter_[1] >> 13) & 0x7;
uint8_t offsets[6];
uint8_t len = 0;
if (quantizer.enabled()) {
offsets[1] = 4;
if (extensionIndex < 11) {
offsets[0] = 2;
} else if (extensionIndex < 15) {
offsets[0] = 3;
} else {
offsets[0] = 1;
}
len = diatonic_chords[extensionIndex][0];
for (size_t i = 0; i < len; i++) {
offsets[i+2] = diatonic_chords[extensionIndex][i+1];
}
len += 3;
} else {
// send len=0 as indication to use the phase offsets from the paraphonic chord array.
}
renderChord(sync, buffer, size, offsets, len);
}

Actually quite similar to the Plaits Chords

const char* const chord_names[kChordNumChords] = {
"OCT",
"Fifth",
"m",
"m7",
"m9",
"m11",
"M",
"M7",
"M9",
"Sus4",
"69",
"6th",
"10th",
"D7",
"D7(b9)",
"HD",
"FD",
};
// Alternative chord table by Jon Butler [email protected]
/* static */
const float ChordBank::chords_[kChordNumChords][kChordNumNotes] = {
// Fixed Intervals
{ 0.00f, 0.01f, 11.99f, 12.00f }, // Octave
{ 0.00f, 7.00f, 7.01f, 12.00f }, // Fifth
// Minor
{ 0.00f, 3.00f, 7.00f, 12.00f }, // Minor
{ 0.00f, 3.00f, 7.00f, 10.00f }, // Minor 7th
{ 0.00f, 3.00f, 10.00f, 14.00f }, // Minor 9th
{ 0.00f, 3.00f, 10.00f, 17.00f }, // Minor 11th
// Major
{ 0.00f, 4.00f, 7.00f, 12.00f }, // Major
{ 0.00f, 4.00f, 7.00f, 11.00f }, // Major 7th
{ 0.00f, 4.00f, 11.00f, 14.00f }, // Major 9th
// Colour Chords
{ 0.00f, 5.00f, 7.00f, 12.00f }, // Sus4
{ 0.00f, 2.00f, 9.00f, 16.00f }, // 69
{ 0.00f, 4.00f, 7.00f, 9.00f }, // 6th
{ 0.00f, 7.00f, 16.00f, 23.00f }, // 10th (Spread maj7)
{ 0.00f, 4.00f, 7.00f, 10.00f }, // Dominant 7th
{ 0.00f, 7.00f, 10.00f, 13.00f }, // Dominant 7th (b9)
{ 0.00f, 3.00f, 6.00f, 10.00f }, // Half Diminished
{ 0.00f, 3.00f, 6.00f, 9.00f }, // Fully Diminished
};
#else

In the current version, the colour parameter incrementation does not match the chords table. It may be possible to simply name the chords instead of ‘Colour’ as with the Plaits Chords.

@eh2k I do not get the first table.
How this is a 7th chord: {1, 6, 0, 0}, // 7th?
7th chord should contain first, third, fifth and seventh note in a scale.
If its + something (like the display you have removed) it should be +0, 2, 4, 6 scale degrees to a first note

@eh2k
Copy link
Owner Author

eh2k commented Jan 2, 2025

@koswir

Initially, I more or less simply copied the code from Renaissance-Repo without understanding the chord oscillators in detail. I had to make a few adjustments because there is an internal and an ‘engine-specific’ quantizer in S&C. The internal one is generally built into SC and affects all engines.

I have taken a closer look at the ‘Renaissance Chords’ code and must honestly say that the following points do not seem entirely logical to me:

  1. Only the first 8 chords from the table are used (only the top 3 bits from colour parameter are used for the chord table index)
    • The entries with index > 7 are actually unused code.
  2. Independent of the Color parameter value, two notes offsets 2 and 4 are added to the root note in all cases ( index << 11 ). Further note offsets are taken from the table lib/braids/chords_stack.cc#L534
    • As you also write, the values do not match the chords in the comments...
    • I wouldn't know how to name the chords either, as they still correspond to the quantizer steps.
  3. The logic of using the offsets to determine the frequencies from the quantiezer table and generating chords from them is also not clear to me (I think it's logical to use the mechanism with the turing machine, but I have no idea whether this makes any sense at all in terms of music theory).

I would prefer to use the same chords as in plaits chords (M-OSC/Chords), and extend it to 6 voices (Plaits only has a maximum of 4 voices). Then I would create the individual notes form the default semitone scale.

  • Doesn't it make more sense to quantize each voice at the end than if there were 6x CV outputs individually for external oscillators?

@eh2k
Copy link
Owner Author

eh2k commented Jan 4, 2025

@koswir

In the latest update 4b23f97 there are the following changes to the chord oscillators:

  • If no quantiser is set, everything behaves as with WTx4. This means that the original Braids Chords table is used and the colour parameter interpolates between the values.
    image

  • If the SEMI Quantiser is set, the Plaits Chord table is used, where the default chords such as m7, m9, etc. are used (The value paramter becomes the selection as with M-OSC/Chords).
    image

  • For all other quantizer, the algorithm from Braids Renaissance is used, and the voice offsets are displayed as follows (by offsets I mean the index in the quantiser table):
    image

@koswir
Copy link

koswir commented Jan 5, 2025

@eh2k Great!
Thank you.
I am going to test it about monday.
👋

@rootapprox
Copy link

@koswir

In the latest update 4b23f97 there are the following changes to the chord oscillators:

  • If no quantiser is set, everything behaves as with WTx4. This means that the original Braids Chords table is used and the colour parameter interpolates between the values.
    image
  • If the SEMI Quantiser is set, the Plaits Chord table is used, where the default chords such as m7, m9, etc. are used (The value paramter becomes the selection as with M-OSC/Chords).
    image
  • For all other quantizer, the algorithm from Braids Renaissance is used, and the voice offsets are displayed as follows (by offsets I mean the index in the quantiser table):
    image

Looks and sounds dope @eh2k Thanks a lot for this update!

@koswir
Copy link

koswir commented Jan 8, 2025

@koswir

In the latest update 4b23f97 there are the following changes to the chord oscillators:

  • If no quantiser is set, everything behaves as with WTx4. This means that the original Braids Chords table is used and the colour parameter interpolates between the values.
    image
  • If the SEMI Quantiser is set, the Plaits Chord table is used, where the default chords such as m7, m9, etc. are used (The value paramter becomes the selection as with M-OSC/Chords).
    image
  • For all other quantizer, the algorithm from Braids Renaissance is used, and the voice offsets are displayed as follows (by offsets I mean the index in the quantiser table):
    image

@eh2k I love all the changes you've made - great work! I do have one suggestion, though:

Would it be possible to adjust the numbering of chord notes so they start from 1 instead of 0?
In music theory, there's no such thing as a 'note zero.' For example, in a fifth, the notes are numbered 1 and 5, while a seventh chord consists of 1 (root), 3 (third), 5 (fifth), and 7 (seventh) - which is why it's called a 7th chord.

Currently, the numeration for a seventh chord goes like 0+2+4+6, but in my opinion it would be better to follow the correct sequence of 1+3+5+7. Similarly, the octave should be labeled as 8 (from 'octave'), not 7.

This change would make the numbering more intuitive and clear for a new user and aligned with standard musical theory.


There is still an issue with chord quantization when the transpose value is set to anything other than octaves in both transpose settings - the one in the I/O settings and the one on the main machine's panel.
When transpose is set to multiples of 12 (octaves), the chords quantize correctly. However, if the value is different, the chords behave unpredictably.

I'm not ready for digging into this behavior right now, though. 😅

@eh2k
Copy link
Owner Author

eh2k commented Jan 11, 2025

@koswir @rootapprox

thanks for your feedback.

@koswir - your suggestion (chord numeration) is now in the latest version aa5c787.

I'm closing this issue, if there is still something with the ‘general’ quantization, let's discuss it here. #117

@eh2k eh2k closed this as completed Jan 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants