Skip to content
Snippets Groups Projects
Commit f309558d authored by Jean-Marie Favreau's avatar Jean-Marie Favreau
Browse files

Début d'implémentation de la génération des spectrogrammes

parent 3592a499
No related branches found
No related tags found
No related merge requests found
......@@ -24,6 +24,8 @@ $(EXERCICESDIR)/ex-spec-%.tex: %.py
$(SONS)/%.wav: %.py
python $<
cleantex:
rm -f $(EXESPECTEX)
clean:
rm -f $(EXESPECTEX) $(EXESPECPDF)
clean: cleantex
rm -f $(EXESPECPDF) $(WAVES)
......@@ -15,8 +15,37 @@ class GenerateurExercice(GammeTemperee):
def __init__(self, bpm = 120, dureeSon = 0.1):
GammeTemperee.__init__(self, bpm)
self.dureeSon = dureeSon
self.dureeFrappe = 0.2 * self. dureeSon # la durée de la frappe
self.margeDocument = 1.0
self.bandeLegendeSpectrogramme = 1.0
self.margeDuree = 0.1
self.margeFrequence = 10
# calcule la durée de la partition donnée en paramètre, dans le
# cas où elle est jouée au battement par minute courant
def calculeDureePartition(self, partition):
durees = [p[1] for p in partition]
durees[-1] = max(durees[-1], self.dureeSon)
return sum(durees)
# calcule la durée maximale des partitions données en paramètre, dans le
# cas où elles sont jouées au battement par minute courant
def calculeDureePartitions(self, partitions):
return max([self.calculeDureePartition(p) for p in partitions])
# calcule les fréquences minimales et maximales des partitions
def calculeIntervalleFrequencesPartition(self, partition):
minf = min([ min([ f for f in note[0]]) if not isinstance(note[0], float) else note[0] for note in partition])
maxf = max([ max([ f for f in note[0]]) if not isinstance(note[0], float) else note[0] for note in partition])
return (minf, maxf)
# calcule les fréquences minimales et maximales des partitions
def calculeIntervalleFrequencesPartitions(self, partitions):
intervalles = [ self.calculeIntervalleFrequencesPartition(p) for p in partitions]
return ( min([i[0] for i in intervalles]), max([i[1] for i in intervalles]))
# cette fonction calcule l'échelle qui sera utilisée pour le spectrogramme:
# - combien de cm de large pour 1 seconde de la partition
......@@ -25,10 +54,12 @@ class GenerateurExercice(GammeTemperee):
# * partitions: la liste des notes qui seront dessinées
# * largeur: la largeur de la figure en cm
# * hauteur: la hauteur de la figure en cm
# * marge: la marge en cm utilisée au dessus et à droite des derniers dessins
def initialisationEchelleSpectrogramme(self, partitions, largeur, hauteur, marge):
# TODO
pass
def initialisationEchelleSpectrogramme(self, partitions, largeur, hauteur):
self.duree = self.calculeDureePartitions(partitions)
(self.fmin, self.fmax) = self.calculeIntervalleFrequencesPartitions(partitions)
self.echelleX = largeur / (self.duree + self.margeDuree * 2)
self.echelleY = hauteur / (self.fmax - self.fmin + self.margeFrequence * 2)
# cette fonction retourne l'entête d'un document LaTeX
......@@ -59,24 +90,77 @@ class GenerateurExercice(GammeTemperee):
# cette fonction écrit le début de l'exercice spectrogramme
def debutExerciceSpectrogramme(self):
result = "\\section{Les fréquences de la gamme tempérée}"
result = "\n"
result += "\\section{Les fréquences de la gamme tempérée}\n"
result += "\\begin{center}\n"
result += "{\\scriptsize \\begin{tabular}{r|ccccccccccccc}\n"
result += "note & \\textbf{do} & do$\\sharp$ & ré & mi$\\flat$ & mi & fa & fa$\\sharp$ &sol & sol$\\sharp$ & la & si$\\flat$ & si & \\textbf{do} \\\\\n"
result += "\\hline\n"
result += " Fréquence & 264,00 & 279,70& 296,33 & 313,95& 332,62& 352,40& 373,35& 395,55& 419,07& 443,99& 470,39& 498,37& 528,00 \\\\\n"
result += "\\end{tabular}}\n"
result += "\\end{center}\n"
result += "\n"
result += "\n"
result += "\n"
result += "\n"
result += "\\section{Analyse de spectrogramme}\n"
# TODO
return result
# cette fonction écrit la fin de l'exercice spectrogramme
def finExerciceSpectrogramme(self, partitions):
result = ""
# TODO
result = "\n"
return result
def frequenceEnCm(self, frequence):
return self.bandeLegendeSpectrogramme + self.margeFrequence + frequence * self.echelleY
def horodatageEnCm(self, horodatage):
return self.bandeLegendeSpectrogramme + self.margeDuree + horodatage * self.echelleX
# dessine sur le spectrogramme l'accord donné en paramètre,
# à l'horodatage donné
def noteSpectrogrammePartition(self, frequence, duree, horodatage, couleur):
y = self.frequenceEnCm(frequence)
xmin = self.horodatageEnCm(horodatage)
xmilieu = self.horodatageEnCm(horodatage + self.dureeFrappe)
xmax = self.horodatageEnCm(horodatage + duree)
result = "\draw[" + couleur +", very thick] (" + str(xmin) + "," + str(y) + ") -- (" + str(xmilieu) + "," + str(y) + ");\n"
result += "\draw[" + couleur +", very thin] (" + str(xmilieu) + "," + str(y) + ") -- (" + str(xmax) + "," + str(y) + ");\n"
return result
# dessine sur le spectrogramme l'accord donné en paramètre,
# à l'horodatage donné
def accordSpectrogrammePartition(self, accord, horodatage, couleur):
if isinstance(accord[0], float):
return self.noteSpectrogrammePartition(accord[0], self.dureeSon, horodatage, couleur)
else:
return ''.join([self.noteSpectrogrammePartition(note, self.dureeSon, horodatage, couleur) for note in accord[0]])
# dessine sur le spectrogramme les notes données en paramètre
def notesSpectrogrammePartition(self, partition, couleur):
resultat = ""
horodatage = 0.
for note in partition:
resultat += self.accordSpectrogrammePartition(note, horodatage, couleur)
horodatage += note[1]
return resultat
# cette fonction écrit le spectrogramme simplifié correspondant à la
# partition donnée en paramètre
def spectrogramme(self, partitions):
# on commence par initialiser l'échelle
self.initialisationEchelleSpectrogramme(partitions, 21 - 2 * self.margeDocument, 10, 0.5)
self.initialisationEchelleSpectrogramme(partitions, 21 - 2 * self.margeDocument, 10)
result = ""
# TODO
result += "\\begin{tikzpicture}[]"
# TODO: ajouter les axes
couleur = { 0: "black", 1: "darkgray", 2: "gray"}
for i,p in enumerate(partitions):
result += self.notesSpectrogrammePartition(p, couleur.get(i, "lightgray"))
result += "\\end{tikzpicture}"
return result
# Genère une feuille d'exercice au format LaTeX à partir des notes donnees
......
......@@ -72,7 +72,7 @@ class GammeTemperee:
return [ self.silence(), self.doublecroche ]
# Etant donne un nombre de battements par minute, cette fonction fixe la duree
# de chacune des notes
# de chacune des notes, exprimée en secondes
# Paramètre:
# * bpm: nombre de battements par minute (= nombre de noires par minute)
def setBPM(self, bpm):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment