Skip to content

Instantly share code, notes, and snippets.

@ricardo-valerio
Last active March 8, 2018 03:53
Show Gist options
  • Save ricardo-valerio/1d8f28ede8a26aad68087a0a2e9cc294 to your computer and use it in GitHub Desktop.
Save ricardo-valerio/1d8f28ede8a26aad68087a0a2e9cc294 to your computer and use it in GitHub Desktop.
script that generates random chords for you to practice... An efficient alternative for dice rolling...
#!/usr/bin/python3
from random import choice
from termcolor import colored
from time import sleep as wait_a_few_seconds_between_chords
########################################################
# Feel free to comment/uncomment any key and quality
# that you want (or not) to practice...
########################################################
keys = [
'C ' ,
'Db' ,
'D ' ,
'Eb' ,
'E ' ,
'F ' ,
'Gb' ,
'G ' ,
'Ab' ,
'A ' ,
'Bb' ,
'B '
]
qualities = [
####################
#? Triads
####################
"Major ",
"minor ",
"diminished",
"Augmented ",
####################
#? Sus2/Sus4
####################
# "Sus2 ",
# "Sus4 ",
# "Dom 7 Sus4",
####################
#? 6ths
####################
# "Major 6 ",
# "minor 6 ",
####################
#? 7ths (Total of 8)
####################
# "Major 7 ",
# "minor 7 ",
# "Dom 7 ",
# "min 7 b5 ",
# "dimini 7 ",
# "minMaj 7 ",
# "AugMaj 7 ",
# "Augmen 7 ",
####################
#? 9ths
####################
# "Major 9 ",
# "minor 9 ",
# "Dom 9 ",
####################
#? 11ths
####################
# "Dom 11 ",
####################
#? 13ths
####################
# "Dom 13 ",
##########################
#? Other Altered Chords
##########################
# "Major b5 ", # Ex: C(-5)
# "Dom 7 #5 ", # Ex: C7(+5)
# "Dom 7 b5 ", # Ex: C7(-5)
# "Major 7 b3b5 ", # Ex: CM7(b3b5)
# "Major 7 b3#5 ", # Ex: CM7(b3#5)
# "Dom 9 #5 ", # Ex: C9(+5)
# "Dom 9 b5 ", # Ex: C9(-5)
# "minor 9 #5 ", # Ex: Cm9(+5)
# "minor 9 b5 ", # Ex: Cm9(-5)
# "Dom 7 b9 ", # Ex: C7(b9)
# "Dom 11 b9 ", # Ex: C11(b9)
# "Dom 11 #5 ", # Ex: C11(#5)
# "Dom 13 b9 ", # Ex: C13(b9)
# "Dom 7 Add 6 ", # Ex: C7(6)
# "Major 6 Add 9", # Ex: C6(9)
]
positions = [
"Root Position",
"1st Inversion",
"2nd Inversion",
"3rd Inversion"
]
# this variable will hold the generated quality to compare
# with the next one...at the beginning is "None" obviously!
previous_generated_chord_quality = None
# this list will hold all randomly generated chords
CHORDS_THAT_WERE_GENERATED_AND_PRACTICED = []
########################################################
# Functions (total of 6)
########################################################
def _chord_position_highlight(generated_position: str) -> str:
if generated_position == "in 1st Inversion":
return "on_blue"
elif generated_position == "in 2nd Inversion":
return "on_red"
elif generated_position == "in 3rd Inversion":
return "on_green"
def _is_not_a_triad(generated_quality: str) -> bool:
check_4_note_chord = ["6", "7", "9", "11", "13"]
return any(degree in check_4_note_chord for degree in generated_quality)
def generate_and_print_random_chord() -> None:
key = choice(keys)
quality = choice(qualities)
########################################################
# don't let qualities repeat one after the other
########################################################
global previous_generated_chord_quality
while previous_generated_chord_quality == quality:
quality = choice(qualities)
previous_generated_chord_quality = quality
########################################################
# Check if it's a 4 note chord or a triad and give
# the respective valide inversions for it.
########################################################
if _is_not_a_triad(quality):
position = "in " + choice(positions)
# add chord for frequency analysis
CHORDS_THAT_WERE_GENERATED_AND_PRACTICED.append(
key + " " + quality + " " + position)
print(colored(key, "magenta"),
colored(quality, "magenta"),
colored(text=position,
color="white",
on_color=_chord_position_highlight(position),
attrs=["bold"]))
else:
# Since it's a Triad exclude 3rd Inversion with slice [:-1]
# And for now just practice Root Position for Augmented chords
# but don't specify any position
position = "in " + choice(positions[:-1]) \
if quality != "Augmented " \
else ""
# add chord for frequency analysis
CHORDS_THAT_WERE_GENERATED_AND_PRACTICED.append(
key + " " + quality + " " + (position if quality != "Augmented " else "in Root Position"))
print(colored(key, "yellow"),
colored(quality, "yellow"),
colored(text=position,
color="white",
on_color=_chord_position_highlight(position),
attrs=["bold"]))
def _chord_frequency_counter() -> None:
remove_duplicate_chords = list(set(CHORDS_THAT_WERE_GENERATED_AND_PRACTICED))
remove_duplicate_chords.sort()
for each in remove_duplicate_chords:
print( colored(each[:14], "magenta") if _is_not_a_triad(each) else each[:14], _nicely_highlited(each[14:]) , ":", colored(CHORDS_THAT_WERE_GENERATED_AND_PRACTICED.count(each), "cyan"))
wait_a_few_seconds_between_chords(1)
def _nicely_highlited(each_chord_position: str) -> None:
return colored(text=each_chord_position,
color="white",
on_color=_chord_position_highlight(each_chord_position),
attrs=["bold"])
def final_stats_practice_session_report() -> None:
#################################################################
# friendly message
#################################################################
print(colored("-" * 45, "cyan"))
print(colored("Nice...Time to rest!", "green"))
#################################################################
# overview stats
#################################################################
print(colored("-" * 45, "cyan"))
print(colored("Here is some stats of your practice session:", "red"))
print("You practiced", colored(round_counter, "red"),
"round!" if round_counter == 1 else "rounds!")
print("That equates to", colored(20 * round_counter, "red"),
"random chords practiced...")
print("And without redundant frequency:",
colored(len(set(CHORDS_THAT_WERE_GENERATED_AND_PRACTICED)), "red"))
print(colored("-" * 45, "cyan"))
wait_a_few_seconds_between_chords(9)
#################################################################
# chord frequency stats
#################################################################
print(colored("And here is the frequency of each chord:", "green"))
_chord_frequency_counter()
print() # just a final separator
########################################################
print() # initial separator
########################################################
round_counter = 1
while "Practicing Chords":
# ROUND START ###########################################################
print(colored("*" * 10, "red"), "ROUND:", round_counter, colored("*" * 10, "red"))
#########################################################################
for _ in range(4):
print(colored("-" * 30, "cyan"))
for _ in range(5):
generate_and_print_random_chord()
wait_a_few_seconds_between_chords(7)
# ROUND END ############################################################
print(colored("+" * 30, color="red", attrs=["blink"]))
########################################################################
wait_between_rounds = str(input()) # click <return> to continue
# ctrl-D to kill the program
# or write some specific input in order to see the stats report
allowed_input_text_from_user_to_break_loop = ["q" , "quit",
"s" , "stop", "enough",
"tired" , "tired as fuck" ]
if allowed_input_text_from_user_to_break_loop.__contains__(wait_between_rounds.lower()):
break
round_counter+=1
final_stats_practice_session_report()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment