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.

354 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)