You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
15 KiB
355 lines
15 KiB
#! /usr/bin/python3
|
|
|
|
import json
|
|
import random
|
|
import time
|
|
import re
|
|
import sys
|
|
import select
|
|
import tty
|
|
import termios
|
|
from playsound import playsound
|
|
from threading import Thread
|
|
|
|
old_settings = None
|
|
|
|
class color:
|
|
SUCCESS = '\033[92m'
|
|
FAIL = '\033[91m'
|
|
INFO = '\033[93m'
|
|
ENDC = '\033[0m'
|
|
BOLD = '\033[1m'
|
|
|
|
guitare_fretboard = """
|
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
|
Mi ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
|
|
La ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤
|
|
Ré ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤
|
|
Sol ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤
|
|
Si ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤
|
|
Mi └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
|
|
"""
|
|
bass_fretboard = """
|
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
|
Mi ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
|
|
La ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤
|
|
Ré ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤
|
|
Sol └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
|
|
"""
|
|
|
|
# Get notes list from json file
|
|
with open('notes.json', 'r') as notes_file:
|
|
notes = json.loads(notes_file.read())
|
|
|
|
def choose_random_note(instrument, user_octave, scale):
|
|
while True:
|
|
note = random.choice(notes)
|
|
if scale == "diatonic" and note["scale"] != scale:
|
|
continue
|
|
if instrument == "guitar":
|
|
if set(user_octave) & set(note["guitar_positions"].keys()):
|
|
return note
|
|
else:
|
|
if set(user_octave) & set(note["bass_positions"].keys()):
|
|
return note
|
|
|
|
def choose_random_octave(note, instrument, user_octave):
|
|
if instrument == "guitar":
|
|
return random.choice(list(set(user_octave) & set(note["guitar_positions"].keys())))
|
|
else:
|
|
return random.choice(list(set(user_octave) & set(note["bass_positions"].keys())))
|
|
|
|
def choose_random_position(note, instrument, octave):
|
|
if instrument == "guitar":
|
|
return random.randint(0, len(note["guitar_positions"][octave]) - 1)
|
|
else:
|
|
return random.randint(0, len(note["bass_positions"][octave]) - 1)
|
|
|
|
def choose_random_string(note, instrument, octave, position):
|
|
if instrument == "guitar":
|
|
return " corde " + str(note["guitar_positions"][octave][position][1])
|
|
else:
|
|
return " corde " + str(note["bass_positions"][octave][position][1])
|
|
|
|
# Wait 'delay' ms or more if paused and handle keyboard
|
|
def wait_handle_pause(delay, mode):
|
|
is_paused = False
|
|
start = time.time()
|
|
while (time.time() < start + (delay / 1000) or is_paused):
|
|
time.sleep(0.1)
|
|
if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
|
|
c = sys.stdin.read(1)
|
|
if c == ' ':
|
|
is_paused = not is_paused
|
|
elif c == '\x1b':
|
|
if "a" in mode:
|
|
print(color.BOLD + color.INFO + "En attente de la fin du son ... (appuyer sur 'CTRL-C' pour forcer)." + color.ENDC)
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
|
|
sys.exit()
|
|
|
|
# Play the audio note until delay is over or once
|
|
def play_note(path, delay, play_note_once):
|
|
if play_note_once:
|
|
playsound(path)
|
|
else:
|
|
start = time.time()
|
|
while time.time() < start + (delay / 1000):
|
|
playsound(path)
|
|
|
|
# Ask user for scale
|
|
while True:
|
|
scale = input("Sélectionner une gamme (C = Chromatique ou d = Diatonique): ")
|
|
if scale == "" or scale == "c" or scale == "C":
|
|
scale = "chromatic"
|
|
print(color.SUCCESS + "Gamme chromatique sélectionnée" + color.ENDC)
|
|
break
|
|
elif scale == "d" or scale == "D":
|
|
scale = "diatonic"
|
|
print(color.SUCCESS + "Gamme diatonique sélectionnée" + color.ENDC)
|
|
break
|
|
else:
|
|
print(color.FAIL + "Erreur : Gamme inconnu" + color.ENDC)
|
|
|
|
# Ask user for instrument
|
|
while True:
|
|
instrument = input("Sélectionner un instrument (G = Guitare ou b = Basse): ")
|
|
if instrument == "" or instrument == "g" or instrument == "G":
|
|
instrument = "guitar"
|
|
print(color.SUCCESS + "Guitar sélectionnée" + color.ENDC)
|
|
break
|
|
elif instrument == "b" or instrument == "B":
|
|
instrument = "bass"
|
|
print(color.SUCCESS + "Basse sélectionnée" + color.ENDC)
|
|
break
|
|
else:
|
|
print(color.FAIL + "Erreur : instrument inconnu" + color.ENDC)
|
|
|
|
# Ask user for octave
|
|
if instrument == "guitar":
|
|
while True:
|
|
user_octave = input("Sélectionner les octaves à utiliser (2,3,4,5,6 ou 0 pour tous): ")
|
|
if user_octave == "" or user_octave == "0":
|
|
user_octave = "23456"
|
|
print(color.SUCCESS + "Tous les octaves sélectionnées" + color.ENDC)
|
|
break
|
|
elif re.match('^[23456]+$', user_octave):
|
|
print(color.SUCCESS + "Octaves ", end = "")
|
|
for i, c in enumerate(user_octave):
|
|
if i == len(user_octave) - 2:
|
|
print(c + " et ", end = "")
|
|
elif i == len(user_octave) - 1:
|
|
print(c, end = "")
|
|
else:
|
|
print(c + ", ", end = "")
|
|
print(" sélectionnées" + color.ENDC)
|
|
break
|
|
else:
|
|
print(color.FAIL + "Erreur : octave(s) non disponible pour cet instrument" + color.ENDC)
|
|
else:
|
|
while True:
|
|
user_octave = input("Sélectionner les octaves à utiliser (1,2,3,4 ou 0 pour tous): ")
|
|
if user_octave == "" or user_octave == "0":
|
|
user_octave = "1234"
|
|
print(color.SUCCESS + "Tous les octaves sélectionnées" + color.ENDC)
|
|
break
|
|
elif re.match('^[1234]+$', user_octave):
|
|
for i, c in enumerate(user_octave):
|
|
if i == len(user_octave) - 2:
|
|
print(c + " et ", end = "")
|
|
elif i == len(user_octave) - 1:
|
|
print(c, end = "")
|
|
else:
|
|
print(c + ", ", end = "")
|
|
print(" sélectionnées" + color.ENDC)
|
|
break
|
|
else:
|
|
print(color.FAIL + "Erreur : octave(s) non disponible pour cet instrument" + color.ENDC)
|
|
|
|
# Ask user to choose a mode
|
|
# In the 'mode' string there will be some letters which meaning is :
|
|
# n -> note
|
|
# o -> octave
|
|
# s -> string
|
|
# a -> audio
|
|
while True:
|
|
mode = input("""Choix du mode :
|
|
1 : Le programme donne une note
|
|
2 : Le programme donne une note et une octave
|
|
3 : Le programme donne une note, un octave et une corde
|
|
4 : Le programme donne un son uniquement
|
|
5 : Le programme donne un son, une note et une octave
|
|
6 : Le programme donne un son, une note et une octave et une corde\n""")
|
|
if mode == "" or mode == "1":
|
|
mode = "n"
|
|
print(color.SUCCESS + "Mode note uniquement sélectionné" + color.ENDC)
|
|
break
|
|
elif mode == "2":
|
|
mode = "no"
|
|
print(color.SUCCESS + "Mode note et octave sélectionné" + color.ENDC)
|
|
break
|
|
elif mode == "3":
|
|
mode = "nos"
|
|
print(color.SUCCESS + "Mode note, octave et corde sélectionné" + color.ENDC)
|
|
break
|
|
elif mode == "4":
|
|
mode = "a"
|
|
print(color.SUCCESS + "Mode son uniquement sélectionné" + color.ENDC)
|
|
break
|
|
elif mode == "5":
|
|
mode = "ano"
|
|
print(color.SUCCESS + "Mode son, note et octave sélectionné" + color.ENDC)
|
|
break
|
|
elif mode == "6":
|
|
mode = "anos"
|
|
print(color.SUCCESS + "Mode son, note, octave et corde sélectionné" + color.ENDC)
|
|
break
|
|
else:
|
|
print(color.FAIL + "Erreur : mode inconnu" + color.ENDC)
|
|
|
|
# Ask user if he prefer the note to be played once or until correction
|
|
if "a" in mode:
|
|
while True:
|
|
strin = input("""Sélectionner la répétition des notes :
|
|
1 : La note est jouée une seule fois
|
|
2 : La note est jouée jusqu'à la correction\n""")
|
|
if strin == "1" or strin == "":
|
|
play_note_once = True
|
|
print(color.SUCCESS + "La note sera jouée une seule fois" + color.ENDC)
|
|
break
|
|
elif strin == "2":
|
|
play_note_once = False
|
|
print(color.SUCCESS + "La note sera jouée jusqu'à la correction" + color.ENDC)
|
|
break
|
|
else:
|
|
print(color.FAIL + "Erreur : code incorrect" + color.ENDC)
|
|
|
|
# Ask user for notes locale
|
|
while True:
|
|
locale = input("Sélectionner une notation (FR, en, de): ")
|
|
if locale == "" or locale == "fr" or locale == "FR":
|
|
locale = "FR"
|
|
print(color.SUCCESS + "'FR' sélectionné" + color.ENDC)
|
|
break
|
|
elif locale == "en" or locale == "EN":
|
|
locale = "EN"
|
|
print(color.SUCCESS + "'EN' sélectionné" + color.ENDC)
|
|
break
|
|
elif locale == "de" or locale == "DE":
|
|
locale = "DE"
|
|
print(color.SUCCESS + "'DE' sélectionné" + color.ENDC)
|
|
break
|
|
else:
|
|
print(color.FAIL + "Erreur : notation inconnu" + color.ENDC)
|
|
|
|
# Ask user for delay between note and correction
|
|
while True:
|
|
strin = input("Sélectionner le temps entre la note et la correction (ms): ")
|
|
if strin == "":
|
|
delay_note_correc = 1000
|
|
else:
|
|
try:
|
|
delay_note_correc = int(strin)
|
|
except ValueError:
|
|
print(color.FAIL + "Erreur, Entrer un nombre (en millisecondes)" + color.ENDC)
|
|
continue
|
|
print(color.SUCCESS + str(delay_note_correc) + " millisecondes entre la note et sa correction" + color.ENDC)
|
|
break
|
|
|
|
# Ask user for delay between correction and next note
|
|
while True:
|
|
strin = input("Sélectionner le temps entre la correction et la note suivante(ms): ")
|
|
if strin == "":
|
|
delay_correc_note = 1000
|
|
else:
|
|
try:
|
|
delay_correc_note = int(strin)
|
|
except ValueError:
|
|
print(color.FAIL + "Erreur, Entrer un nombre (en millisecondes)" + color.ENDC)
|
|
continue
|
|
print(color.SUCCESS + str(delay_correc_note) + " millisecondes entre la correction et la note suivante" + color.ENDC)
|
|
break
|
|
|
|
# Change the terminal mode to get key without 'enter' being pressed
|
|
old_settings = termios.tcgetattr(sys.stdin)
|
|
tty.setcbreak(sys.stdin.fileno())
|
|
|
|
print(color.BOLD + color.INFO + "\n*appuyer sur 'espace' pour mettre en pause ou 'échap' pour quitter*\n" + color.ENDC)
|
|
|
|
# Print randomly selected notes
|
|
while True:
|
|
note = choose_random_note(instrument, user_octave, scale)
|
|
if "o" in mode or "a" in mode:
|
|
octave = choose_random_octave(note, instrument, user_octave)
|
|
else:
|
|
octave = ""
|
|
if "s" in mode:
|
|
position = choose_random_position(note, instrument, octave)
|
|
string = choose_random_string(note, instrument, octave, position)
|
|
else:
|
|
string = ""
|
|
if "a" in mode:
|
|
path = "./sounds/beep/" + note["note_EN"] + octave + ".wav"
|
|
Thread(target = play_note, args = (path, delay_note_correc, play_note_once, )).start()
|
|
|
|
if instrument == "guitar":
|
|
if mode != "a":
|
|
if locale == "FR":
|
|
print(note["note_FR"] + octave + string)
|
|
elif locale == "EN":
|
|
print(note["note_EN"] + octave + string)
|
|
elif locale == "DE":
|
|
print(note["note_DE"] + octave + string)
|
|
wait_handle_pause(delay_note_correc, mode)
|
|
|
|
note_fretboard = list(guitare_fretboard)
|
|
if mode == "n":
|
|
for octave in set(user_octave) & set(note["guitar_positions"]):
|
|
for position in range(len(note["guitar_positions"][octave])):
|
|
real_x = note["guitar_positions"][octave][position][0] * 3 + 5
|
|
real_y = note["guitar_positions"][octave][position][1] + 1
|
|
note_fretboard[69 * (real_y - 1) + real_x] = "x"
|
|
note_fretboard[69 * (real_y - 1) + real_x + 1] = "x"
|
|
elif mode == "no" or mode == "ano" or mode == "a":
|
|
for position in range(len(note["guitar_positions"][octave])):
|
|
real_x = note["guitar_positions"][octave][position][0] * 3 + 5
|
|
real_y = note["guitar_positions"][octave][position][1] + 1
|
|
note_fretboard[69 * (real_y - 1) + real_x] = "x"
|
|
note_fretboard[69 * (real_y - 1) + real_x + 1] = "x"
|
|
else:
|
|
real_x = note["guitar_positions"][octave][position][0] * 3 + 5
|
|
real_y = note["guitar_positions"][octave][position][1] + 1
|
|
note_fretboard[69 * (real_y - 1) + real_x] = "x"
|
|
note_fretboard[69 * (real_y - 1) + real_x + 1] = "x"
|
|
# If not guitare
|
|
else:
|
|
if mode != "a":
|
|
if locale == "FR":
|
|
print(note["note_FR"] + octave + string)
|
|
elif locale == "EN":
|
|
print(note["note_EN"] + octave + string)
|
|
elif locale == "DE":
|
|
print(note["note_DE"] + octave + string)
|
|
wait_handle_pause(delay_note_correc, mode)
|
|
|
|
note_fretboard = list(bass_fretboard)
|
|
if mode == "n":
|
|
for octave in user_octave:
|
|
for position in range(len(note["bass_positions"][octave])):
|
|
real_x = note["bass_positions"][octave][position][0] * 3 + 5
|
|
real_y = note["bass_positions"][octave][position][1] + 1
|
|
note_fretboard[69 * (real_y - 1) + real_x] = "x"
|
|
note_fretboard[69 * (real_y - 1) + real_x + 1] = "x"
|
|
elif mode == "no" or mode == "ano" or mode == "a":
|
|
for position in range(len(note["bass_positions"][octave])):
|
|
real_x = note["bass_positions"][octave][position][0] * 3 + 5
|
|
real_y = note["bass_positions"][octave][position][1] + 1
|
|
note_fretboard[69 * (real_y - 1) + real_x] = "x"
|
|
note_fretboard[69 * (real_y - 1) + real_x + 1] = "x"
|
|
else:
|
|
real_x = note["bass_positions"][octave][position][0] * 3 + 5
|
|
real_y = note["bass_positions"][octave][position][1] + 1
|
|
note_fretboard[69 * (real_y - 1) + real_x] = "x"
|
|
note_fretboard[69 * (real_y - 1) + real_x + 1] = "x"
|
|
print(''.join(note_fretboard))
|
|
wait_handle_pause(delay_correc_note, mode)
|