Building chords from scales

Hi! Is there a way to get chords built on a particular scale by specifying the degree? I'm thinking something like the chord_degree function in Sonic Pi that takes degree, root note, scale and number of notes and returns a list of midi notes:

(chord_degree :i, :c4, :major, 3)
> 60, 64, 67

(chord_degree :ii, :c4, :major, 3)
> 62, 65, 69

(chord_degree :vii, :c4, :major, 3)
> 71, 74, 77

Can I achieve something similar in Tidal? Maybe composing "scale" with some other function?

Hi, yes you can do it in the mini-notation, e.g.
n "c4'maj'3i"

the first bit is the note and octave, then chord, then number of notes and the degree. I just noticed that degree only accepts a succession of is, I'll make a note to fix that..

There: https://github.com/tidalcycles/Tidal/issues/699

Thank you, that's exactly what I was looking for.

After further inspection I realized that adding degrees in the mini-notation does something different from what I expected. The Sonic Pi chord_degree I was referring to actually returns the chord built on the specific scale degree, picking notes from the original scale but respecting the intervals, thus giving you the classic chord progressions. For the C major scale that would be:

I    ii   iii  IV   V    vi   vii(diminished)
Cmaj Dmin Emin Fmaj Gmaj Amin Bdim

For example:

(chord_degree :ii, :c4, :major, 3)
# 62, 65, 69 -> D minor (degree ii of the C major scale)

(chord_degree :vii, :c4, :major, 3)
# 71, 74, 77 -> B diminished (degree vii(dim) of the C major scale)

Both these chords (Dmin and Bdim) fit in the C tonality and are built on the C scale.
What Tidal does instead I think is looking at the degree specified, picking the notes that compose the original chord, applying an offset and adding the same notes on top from an octave above. For example:

d1 $ arpg $ n "c'maj'4ii" # sound "superpiano"
-- same as:
d1 $ arpg $ n "[g5,c6,e6,g6]" # sound "superpiano"

d1 $ arpg $ n "c'maj'4iiiiiii" # sound "superpiano"
-- same as:
d1 $ arpg $ n "[e7,g7,c8,e8]" # sound "superpiano"

If I'm not mistaken these are all C chord inversions, but my knowledge of musical theory is not so good, I might be wrong :slightly_smiling_face:

You're correct, that notation is for inversions, not referencing scale degrees

This is an interesting problem, you could build triads using mini notation, then describe the interval change:

d1 $ n (scale "ionian" "[0,2,4]") |+ n "<0 1 2 3 4 5 6>" # s "superpiano" 

That should play the triads (built in the scale section), with the degree of the scale described as n - 1 after the |+

Not intuitive relative to normal music notation, but at the very least trying to describe the intended outcome to @yaxu

1 Like

@cleary I came to a similar solution, maybe a bit more "intuitive":

-- degree IV of the D major scale:
d1 $ n (scale "major" ("[-1,1,3]" + "4") + "d5") # s "superpiano"

-- simple progression (I IV V ii) in D major:
d1 $ slow 2 $ n (scale "major" ("[-1,1,3]" + "1 4 5 2") + "d5") # s "superpiano"

-- same as:
d1 $ slow 2 $ n "d5'maj'3 g5'maj'3 a5'maj'3 e5'min'3" # s "superpiano"

-- simple progression (I III v VII) in E minor:
d1 $ slow 2 $ n (scale "minor" ("[-1,1,3]" + "1 3 5 7") + "e5") # s "superpiano"

-- same as:
d1 $ slow 2 $ n "e5'min'3 g5'maj'3 b5'min'3 d6'maj'3" # s "superpiano"

It would be nice to have a dedicated function that could take also roman numbers for the degrees and a chord type (e.g. "maj" instead of "[-1,1,3]") but I'm really a beginner at Haskell :roll_eyes:

11 Likes

Cross linking:

1 Like

Cross linking

This is one of the topics I've been working on a lot lately.

My motivation was to make some rules accessible via TidalCycles using the system of western music theory that I am familiar with. However, I attach great importance to defining and transforming chord progressions and notes with patterns, in order to be able to use the strengths of TidalCycles flexibly here.

There are now a lot of ideas flowed in here and I have collected everything here once. To give you an idea, the usage in TidalCycles looks like this:

do
-- Define chord progressions with roman numerals
s1 = sheet {key = "c", mode "major", numerals = "<1 1 4 5>"}
-- The chord will be created on their elements like 
-- root (1), major/minor third (3) and perfect fifth (5).
-- And the chord progressions is based on the sheet. 
-- This will play <Cmaj Cmaj Fmaj Gmaj>  
d1 $ s "superpiano" <| prog s1 "[1,3,5]" |- note 12
-- Create a melody with the chord changes but use 
-- diatonic notes outside of the chord
d2 $ s "superpiano" <| prog s1 "1 5 7@2 3 6 8@2" 

I addressed a lot of western harmony concepts like secondary dominants, tritone substitution, borrowed chords and inversions. And you can play a harmony in one scale (like major) and the melody in another scale (like minPent).

Personally, I'm able to code melodic sets much more specifically live with it. I also use it to write flexible backing tracks/loops for the guitar.

If you are interested in such stuff, here is the complete post:

5 Likes

hey @mrreason i am getting hung up on this portion of your code.tidal...it won't evaluate for me. do i not have a certain extension/package installed? any other ideas?

-- Used for using parts and segments
stacker = Map.fromList
(!) = (Map.!)
transformStacker parts = stacker $ map (\x -> (fst $ head x, transform x)) (transpose $ filledWithSilence parts)
    where allowedAndNeededKeys = ["lead", "bass", "key", "drums", "pad", "clock", "pod", "arp"]
          filledWithSilence parts = map (\x -> addSilence x) parts
          addSilence pt = map (\x -> if (Map.member x (pt)) then (x, pt ! x) else (x, silence)) allowedAndNeededKeys
          transform x = transformBy 1 x
          transformBy _ [] = []
          transformBy y [x] = [(show y, snd x)]
          transformBy y (x:xs) = (show y, snd x) : (transformBy (y + 1) xs)

Hey @kit-christopher, glad to hear that you give these concepts a chance!

any other ideas?

Hard to tell since I don't recognize the indentations. It it possible for you to add the TC code here in the code block? Do you get an error message? What does it look like? When I evaluate the code from code.tidal, everything works like I expect.

1 Like

sorry! i put the code into a block above...i just copied and pasted your stuff into an existing tidal session i had open and evaluated every line on its own. here's the error i get when trying to eval the Map portion

Not in scope: `Map.fromList'
    No module named `Map' is imported.


    Not in scope: `Map.!'
    No module named `Map' is imported.


    Not in scope: `Map.member'
    No module named `Map' is imported

Oh, I didn't realized that I forgot that. You need to evaluate import qualified Data.Map.Strict as Map. I have this added to my BootTidal.hs and will add it this line to the code.tidal file.
This should fix the problem.

1 Like

wonderful, adding now! thanks @mrreason!

1 Like