Corrigé Projet Musique

1. Introduction

1.0.1. Fréquence d’une touche de piano

coeff valeurs <= 0 valeurs >= 89 autres
1 2 2 5
def freq_touche(n) :
    if 0 < n and n < 89 :
        return 2 ** ( ( n - 49 ) / 12 ) * 440
    return 0

2. Mélodie MIDI depuis une liste

2.1. Outils numériques

2.1.1. Valeur absolue

coeff valeurs < 0 valeurs > 0 en 0
1 4 4 1
def vabs(x) :
    if x < 0 :
        return -x
    return x

2.1.2. Approximation de pi

coeff en 0 rang correct calcul correct structure correcte
2 1 2 4 3
def approx_pi(n) :
    somme = 1
    for i in range(1,n+1) :
        somme += (-3.0) ** (-i) / (2.0 * i + 1.0)
    return 12.0 ** 0.5 * somme

2.1.3. Modulo deux pi

coeff valeur < -pi valeur entre -pi et pi valeur > pi
2 3 3 3

On note que dans la correction si dessous, \(\pi\) est envoyé sur \(-\pi\), ce qui ne répond pas à la consigne. Cela n’a toutefois que très peu de sens de parler de ce qui se passe exactement en \(\pi\), ce nombre n’étant pas représentable dans la mémoire d’un ordinateur. Ce n’est donc pas important de traiter le cas où x = pi qui n’est de toute façon pas réellement le cas \(x = \pi\) \ldots.

def modulo_2pi(x) :
    x_modulo = abs(x)
    while x_modulo > pi :
        x_modulo = x_modulo - 2 * pi
    if x < 0 :
        x_modulo = -x_modulo
    return x_modulo

2.1.4. Approximation du sinus

coeff au rang 0 rang correct calcul correct grandes valeurs structure correcte
2 1 2 4 2 1
def approx_sin(x,n) :
    x_modulo = modulo_2pi(x)
    u = x_modulo
    somme = u
    for i in range(1, n+1) :
        u = - u * x_modulo * x_modulo / ( 2 * i * (2 * i + 1) )
        somme += u
    return somme

2.2. Échantillonnage

2.2.1. Discrétisation d’un intervalle

coeff commence par a contient n valeurs intervalles réguliers
3 1 4 4
def discretisation(a,b,n) :
    ecart = (b-a) / (n-1)
    dis = [a]
    for i in range(1,n-1) :
        dis.append(a + i * ecart)
    dis.append(b)
    return dis

2.2.2. Échantillonnage d’une note

coeff nombre de valeurs discretisation correcte echantillonnage correct
3 2 2 4
def echantillonnage_note(frequence,duree,freq_ech,amplitude) :
    t = discretisation(0,duree,int(freq_ech*duree))
    e = []
    for x in t :
        e.append(amplitude * approx_sin(2 * pi * frequence * x, 100))
    return e

2.2.3. Échantillonnage d’une partition

coeff parcours partition appel concaténation
3 3 2 4
def echantillonnage_partition(partition, freq_ech, amplitude) :
    e = []
    for (note,duree) in partition :
        freq = freq_touche(note)
        e += echantillonnage_note(freq,duree/8,freq_ech,amplitude)
    return e

2.2.4. Échantillonnage d’un accord

coeff parcours accord calcul résultat
3 3 2 4
def echantillonnage_accord(frequences,duree,freq_ech,amplitude) :
    pi = approx_pi(40)
    t = discretisation(0,duree,int(freq_ech*duree))
    e = []
    for x in t :
        valeur = 0
        for f in frequences :
            valeur = valeur + amplitude * approx_sin(2 * pi * f * x, 100)
        e.append(valeur)
    return e

2.2.5. Échantillonnage d’une partition d’accord

coeff parcours partition calcul fréquences résultat
3 3 3 3
def echantillonnage_partition_accords(partition, freq_ech, amplitude) :
    e = []
    for (accord,duree) in partition :
        freqs_accord = []
        for note in accord :
            freqs_accord.append(freq_touche(note))
        e += echantillonnage_accord(freqs_accord,duree/8,freq_ech,amplitude)
    return e

3. Mélodie MIDI depuis une partition écrite

3.0.1. Touche correspondant à une note dans l’octave

coeff touche valide touche invalide
2 6 3
def touche_octave(s) :
    notes = "CcDdEFfGgAaB"
    for i in range(len(notes)) :
        if notes[i] == s :
            return i
    return -1

3.0.2. Touche correspondant à une note sur le piano

coeff touche valide touche invalide
2 6 3
def touche_piano(s,n) :
    t = touche_octave(s)
    if t != - 1 :
        t = t - 8 + n * 12
    return t

3.0.3. Lecture d’une partition

coeff parcours création de la liste de couple Partition vide
3 4 4 1
def partition(s) :
    notes = []
    for i in range(0,len(s),3) :
        notes.append((touche_piano(s[i],int(s[i+1])), int(s[i+2])))
    return notes

3.0.4. Conversion fichier vers WAV

coeff ouverture de fichier lecture appels écriture
2 3 2 2 2
def generer_partition(fichier, wave, freq_ech, amplitude) :
    ofichier = open(fichier,'r')
    s = ofichier.read()
    p = partition(s)
    e = echantillonnage_partition(p,freq_ech,amplitude)
    wavfile.write(wave, rate=freq_ech, data=np.array(e).astype(np.int16) )