Generating random songwriting assignments (rudimentary code included)

Disclaimer: I am not a good programmer. In fact, I am not a programmer :smiley:

I wrote a (very rudimentary!) Phython code to generate random songwriting assignments. It needs python as well as the yaml and numpy packages.

I would be very happy to get input / feedback / advice from the community. And of course if anyone manages to use this for inspiration, Iā€™d love to hear what music you wrote with it :slight_smile:

Just dump the 2 files in the same folder and run it.

When you run the code, you just have to input a song structure like ā€œA B A Bā€. Then the code will extract various characteristics for each section (key, mode, energy level etc).

Here is an example output for a simple ā€œABAā€ structure.

Section A mode: G Phrygian
Section B mode: G Aeolian
----------
*** Section A (1) ***
Energy : high
Pace : fast
Arrangement : sparse
Heaviness : low
----------
*** Section B (2) ***
Energy : high
Pace : medium
Arrangement : sparse
Heaviness : low
----------
*** Section A (3) ***
Energy : low
Pace : medium
Arrangement : sparse
Heaviness : low
----------

The data that gets randomized is in a yaml file which you can fully customize to your liking. I added comments to both code and yaml file which I hope will be helpful to anyone who wants to take this further.

Edit: I canā€™t upload the files directly. I will just post the relevant code in the next comment.

So here is the code. Save it as a ā€œ.pyā€ file such as ā€œRandomSong.pyā€

# This "code" needs yaml and numpy modules for Python. 

import yaml
import numpy as np

# Open the (customizable) yaml file with the various song properties to randomize. Yaml file should be kept in the same folder as this code (unless you want to change appropriate details in the code below.)

with open('Songdata.yaml') as f:
    data = yaml.load(f, Loader=yaml.FullLoader)

#Ask user to provide song structure, e.g. use ABCB for "verse-chorus-bridge-chorus"

struct = input("input song structure, for example 'ABAB' or 'ABCBA' -> ")  

# pick unique sections from the structure.  e.g. if struct = ABAB, then the unique sections are 'A' and 'B'.

sez = set(struct)

#print the structure  

print("----------")
print("*** Song Structure: " + struct + " ***")
print()

# pick keys and modes at random for each section, print them
for j in sez:
    print("Section "  + j + " mode: " + np.random.choice(data["keys"])+ " " + np.random.choice(data["modes"]) )

print("----------")

# pick random additional characteristics for each song section (including repeated sections), print them. You can freely edit these characteristics in the yaml file.
num=1
for j in struct:
    print("*** Section "  + j + " ("+ str(num) +")" + " ***")
    num=num+1
    for k in data["options"]:

        print(k["cat"] + " : " + str(np.random.choice(k["values"])))
    print("----------")

And here is the yaml file which should be saved as ā€œSongdata.yamlā€ and put in the same folder as the python file above:

# list of 12 possible keys. Feel free to delete some if you prefer to reduce the options

keys: [A, Bb, B, C, Db, D Eb, E, F, 'F#',G,'G#']

# modes you want to consider (I put all the major scale modes, but you can delete or add as needed e.g. you can add "mixolydian flat 6", "dorian #4" and whatnot)

modes:
- Ionian
- Dorian
- Phrygian
- Lydian
- Mixolydian
- Aeolian
- Locrian

# here is a list of options that you can randomize for each section. Copy the syntax as shown below if you want to add more:
# - cat: name of the category (single word is probably best). Make sure it's preceeded by two spaces and "-"
# values: here you can put a list of the possible values for the category. do it like so: ['value1', 'value2'] etc. There should be no "-" but the word "values" should be aligned with "cat" (see below) by using 4 spaces. 

options:
  - cat: Energy
    values: ['low','medium','high']
  - cat: Pace
    values: ['slow', 'medium', 'fast']
  - cat: Arrangement
    values: ['sparse', 'busy']
  - cat: Heaviness
    values: ['low', 'medium', 'high']
1 Like

This is a great idea! Very ā€œMozart rolling dice,ā€ which Iā€™m always in favor of.

I have two suggestions:

  1. Iā€™m not sure thereā€™s much utility to suggesting ā€œmodes to play inā€ unless itā€™s tied to suggesting chords. What about having a list of common chord progressions to suggest for each section instead, and tying that to a key? ā€œThis section is i-bVI-iv-V7 tonal center of D, i bVI bVII i tonal center of A, I - vi - IV - V tonal center of G#,ā€ etc.

  2. What about making the structure an output instead of an input? ABAB, AABA, AABB, etc. are common. AABA in particular covers most pop song structures if you have a final verse after the bridge.

Wrote this during second cup of coffee, so apologies if it sounds overly critical ā€“ Iā€™m absolutely going to steal this idea and tinker with it for my own purposes!

2 Likes

Thanks Eric! I I didnā€™t know Mozart did this kind of thing for inspiration, cool!

In general I totally agree that the current set of options is probably far from ideal. One of the reasons why Iā€™m looking for feedback :slight_smile: Ideally, we can collectively come up with a version that can lead to ā€œinspirationā€ in the most straightforward way.

I think these changes should be easy to do by just changing a couple lines here and there :+1:

Iā€™d love to see your version of this if you want to share it!

PS: other things I thought about (but some of them require more technical skills):

  • give some guidance on the type of riff / melody for each section (ā€œuse pedal tonesā€ / ā€œsyncopatedā€ etc.)
  • generate some kind of random drum groove for each section (maybe by combining typical betas for various genres) and export it as midi (much harder to do, I know!)
1 Like

Wall of text/brain-vomit incoming:

To clarify, the reason I think ā€œsuggesting a modeā€ is possibly a suboptimal way to do it is because I personally donā€™t find it useful to think of music in terms of scales. Even modal jazz doesnā€™t really say ā€œweā€™re writing in this modeā€ as far as I know, but rather plays various scales over a single chord, right? Iā€™m not a jazz expert, so someone please correct me if Iā€™m totally off :smiley:

For less ā€œstraightforward rock and roll,ā€ it could be interesting to randomly generate progressions chord-by-chord rather than picking from a list of common ones. A lot of my cooler ideas have come from saying ā€œI want to get there from here, how do I do it and make it sound good?ā€

Yes!

Other textural ideas:

  • Arpeggiated chords
  • Strummed chords
  • Trem picked lines/double stops (a la Anataā€™s Slain Upon His Altar, etc.)
  • Big Chugga Chuggas (If you donā€™t know what I mean, go listen to Defeated Sanityā€™s Naraka)
  • Predefined types of chord voicings (very open/shell chords/ could even pick specific combinations of strings to voice the chords on)

To inspire cool riffs, it would probably be necessary to write a script that says ā€œcombine these two textural ideas in a single one-guitar riff.ā€

Also, Iā€™ve found it very inspiring to pick a time signature I donā€™t normally use for a section. This is probably the first change Iā€™d make.

Hm. According to Wikipedia, itā€™s not verified that Mozart actually did this, but at least some composers definitely did.

Iā€™m going to play with this later today if I can get Python running on the ( :nauseated_face: ) Windows machine I do music on, will post results if I can get anything working.

1 Like

Hereā€™s a quick edit. Iā€™ve been meaning to improve my Python skills a bit, so maybe this will help :laughing:


import yaml
import numpy as np

# Open the (customizable) yaml file with the various song properties to randomize. Yaml file should be kept in the same folder as this code (unless you want to change appropriate details in the code below.)

with open('Songdata.yaml') as f:
    data = yaml.load(f, Loader=yaml.FullLoader)

# Ask user to provide song structure, e.g. use ABCB for "verse-chorus-bridge-chorus"

struct = 'AABA'  # input("input song structure, for example 'ABAB' or 'ABCBA' -> ")

# pick unique sections from the structure.  e.g. if struct = ABAB, then the unique sections are 'A' and 'B'.

sez = set(struct)

# print the structure

print("----------")
print("*** Song Structure: " + struct + " ***")
print()

# pick keys and modes at random for each section, print them
for j in sez:
    print("Section " + j + " tonal center: " + np.random.choice(data["tonal_centers"]) + " with chord progression " + np.random.choice(
        data["progs"]) + " and time signature " + np.random.choice(data["time_sigs"]))

print("----------")

# pick random additional characteristics for each song section (including repeated sections), print them. You can freely edit these characteristics in the yaml file.
num = 1
for j in struct:
    print("*** Section " + j + " (" + str(num) + ")" + " ***")
    num = num + 1
    for k in data["options"]:
        print(k["cat"] + " : " + str(np.random.choice(k["values"])) + ' and ' + str(np.random.choice(k["values"])))
    print("----------")

and the yaml file:


tonal_centers: [A, Bb, B, C, Db, D Eb, E, F, 'F#',G,'G#']

# common chord progressions:

progs:
  - I-vi-IV-V
  - I-IV-V-I
  - i-iv-V
  - i-bVI-bVII
  - i-bVI-III-V
  - i-bVI-iv-bVII

#time signatures:

time_sigs:
  - '3/4'
  - '4/4'
  - '5/4'
  - '6/8'
  - '7/8'
  - '11/16'

# here is a list of options that you can randomize for each section. Copy the syntax as shown below if you want to add more:
# - cat: name of the category (single word is probably best). Make sure it's preceeded by two spaces and "-"
# values: here you can put a list of the possible values for the category. do it like so: ['value1', 'value2'] etc. There should be no "-" but the word "values" should be aligned with "cat" (see below) by using 4 spaces. 

options:
  - cat: Texture
    values: ['Arpeggiated chords', 'Strummed chords', 'Tremolo picked single note lines', 'Tremolo picked double/triple stops', 'Chugga Chugga']
  - cat: Voicings
    values: ['Shell chords', 'Cowboy chords', 'Root-5/root-6 chords', 'Power chords']

And finally, sample output:

----------
*** Song Structure: AABA ***

Section A tonal center: F# with chord progression I-vi-IV-V and time signature 4/4
Section B tonal center: Db with chord progression i-iv-V and time signature 3/4
----------
*** Section A (1) ***
Texture : Tremolo picked double/triple stops and Chugga Chugga
Voicings : Root-5/root-6 chords and Cowboy chords
----------
*** Section A (2) ***
Texture : Tremolo picked double/triple stops and Tremolo picked single note lines
Voicings : Cowboy chords and Power chords
----------
*** Section B (3) ***
Texture : Strummed chords and Strummed chords
Voicings : Root-5/root-6 chords and Cowboy chords
----------
*** Section A (4) ***
Texture : Tremolo picked single note lines and Strummed chords
Voicings : Root-5/root-6 chords and Shell chords
----------

This is really not optimal, but I might use something like this. Some of the combinations of texture and voicing are kind of wonky: trem picking cowboy chords is pretty lol.

1 Like

i dont know if this would be of any help but i was using this site to practice ear training back when i was going crazy over trying to develop perfect relative pitch in monophonic land

might could get some ideas with how its structured or use it somehow in your script

Random Music Generators

1 Like

Ha, I think this is amazing! Thank you itā€™s really great to have someone elseā€™s perspective on this kind of thing. I will try to use this too :slight_smile:

1 Like

Iā€™m glad you like it! I might try to do a more ā€œprocedural pitch-class set generationā€ version too, for my, uh, more br00tal stuff :laughing:

And a side note: since many pop and rock melodies follow an AABA structure as well, you can use the texture generator again to decide which parts of the texture for the section should have which of the two textures given.

1 Like

Then of course ChatGPT arrives and makes all of this obsolete :smiley:

Asking for more details:

perhaps it can teach us more about ā€œharmialsā€

1 Like