Introduction au son avec Python et une raspberry PI

Bonjour tout le monde,

Voici mon premier article depuis le confinement.
Quelle période ! Peut être je ferai un billet sur « mon confinement ».

Vu que l’on va parler de son, je vous propose d’écouter ce son pendant la lecture de ce billet.

Une Vague,

Non il n’est pas temps de partir sur le bord de l’océan pour profiter des vagues.
D’un point de vue physique,
le son est émis sous forme d’ondes.
Ces ondes ont des paramètres prédéfinis tels que la fréquence d’onde, et l’amplitude.
C’est très important, car on considère que ce qui n’est pas periodique n’est autre que du bruit.
Le son peut être disponible sous plusieurs formes. Par exemple en dent de scie, en triangle, etc. Dans ce billet je vais retenir une sinusoïdale.

D’un point de vue numérique maintenant,il faut prendre en compte une autre variable.
l’Échantillonnage.
Bien sur, c’est normalisé. Le standard le plus connu pour un novice comme moi, est le 44,1Khz de Sony.
Il ne faut pas confondre cette fréquence avec la fréquence du son émis ou entendu.
Avec un échantillon (Sample in English) de 44,1Khz cela signifie que l’on possède 44100 échantillons de « son » par seconde.
C’est dans cette échantillon que l’on retrouve « la tension » d’alimentation des enceintes en allant au bout des choses. Dans ce billet j’utilise la librairie python « sounddevice ».

Si l’on décortique pour jouer point par point cette échantillon, on obtiendra que des « bips » ou « scratchs ».
Et pour le Sample, si l’on a un son stocké en 44,1Khz et qu’on l’enregistre sur un standard disons de 22Khz, en sortie ça va « speeder ».

Bon je m’arrête la pour l’intro, mais on pourrait aller plus loin (Qualité 16b ou 32b ? :)).

Générons du son,

Pour générer du son, il faut donc produire un ensemble de données, simulant un signal périodique.
Je vais faire cela avec une sinusoïde.
Pour faire une sinusoïde on va utiliser la formule très connue :
y(t)=Asin(2*PI*f*t)
« A » sera l’amplitude de notre signal, « f » la fréquence et « t » la durée.

Mais pour générer les données avec python, il faut tenir compte de l’échantillonnage sinon on obtiendra rien de probant.
Pour ce faire, on va sortir « t » de la formule et ce sera lui qui contiendra notre lot de données.
Si on prend un signal qui dure une seconde, il faut posséder un tableau ayant 44100 lignes et dont la valeur finale vaudra 1 (bon la c’est 0.9 mais c’est python !).
Enfin notre jeux de données doit être linéaire forcément.

Une droite contenant 44100 points
Une sinusoïde avec 10 points
Une sinusoïde avec 44100 points

Pour choisir la fréquence du son que je vais créer, je n’ai pas la science infuse, merci Wikipedia

Et ce qui nous donne le script python suivant :

import numpy as np
import sounddevice as sd
from scipy.io.wavfile import write
sample=44_100
time=10
Volume=3
frequencyList={
'tt':300,
'minPiano':32.703125,
'cello-min':65.40625,
'viola-mandola-min':130.8125,
'Middle-C':261.625,
'Treble-Clef':523.25,
'Highest-Female-Voice':1046.5,
'Highest-Flute':2093,
'High-piano':4186,
'UnkNow':8372,
'CRT-TV-Noise':16744,
}

data=np.arange(sample*time)/sample
Frame=[]
def constructionPalette():
  for x in frequencyList:
    Frame=Volume*np.sin(2*np.pi*frequencyList[x]*data)
    write(x+'.wav',sample,Frame)
constructionPalette()

Vu que ça marche bien, j’ai poussé un peu le truc et j’ai consulté cette page wiki, donnant la formule pour générer les 106 touches d’un piano.
Ce qui me donne maintenant le code suivant :

import numpy as np
from scipy.io.wavfile import write
import sounddevice as sd
number_key=np.arange(0,106)
sound_keyfre=[]
sample=44100
volume=4
def keyConstr(n):\
  return(2**((n-49)/12)*440)

for x in number_key:
  sound_keyfre.append(keyConstr(number_key[x]))

data=np.arange(sample)/sample
for x in number_key:
  Frame=volume*np.sin(2*np.pi*sound_keyfre[x]*data)
  title=str(x)
  write(title+'.wav',sample, Frame)

Arrivé à ce stade, j’ai appelé un ami car moi je n’y connais rien en musique, et ma palette de 106 sons pour moi cela ne se résume qu’à du bruit.
Je lui ai demandé :
Si tu dois retenir que 5 fréquences pour faire un mini piano « potable » (en gros 5 notes mais j’y connais rien donc je parle en fréquence) lesquelles serait-ce ?
Après avoir regardé un peu pour faire la conversion de note en fréquence, il me dit de retenir : 440, 391, 349, 293 et 261.

Merci à lui car sinon j’en serai resté la je pense,

J’ai donc repris « viteuf » mon premier script, et j’ai mis mes 5 fréquences en place. J’ai ressorti la breadboard, leds et boutons pour le raspberry.
Voici le résultat final (A l’instant T).

Voici le code (A adapter selon votre GPIO et cablage, of course)

#!/usr/bin/env python3
import sounddevice as sd
import scipy.io.wavfile as wave
from gpiozero import LED
from gpiozero import Button

from signal import pause

one = wave.read('40.wav')
two = wave.read('42.wav')
three = wave.read('45.wav')
four = wave.read('47.wav')
five = wave.read('49.wav')

def touch_one():
return sd.play(one[1], 44100)
def touch_two():
return sd.play(two[1], 44100)
def touch_three():
return sd.play(three[1], 44100)
def touch_four():
return sd.play(four[1], 44100)
def touch_five():
return sd.play(five[1], 44100)

led1=LED(5)
button1=Button(2)
led2=LED(6)
button2=Button(3)
led3=LED(19)
button3=Button(4)
led4=LED(13)
button4=Button(27)
led5=LED(26)
button5=Button(17)

led1.source=button1
led2.source=button2
led3.source=button3
led4.source=button4
led5.source=button5
button1.when_pressed=touch_one
button2.when_pressed=touch_two
button3.when_pressed=touch_three
button4.when_pressed=touch_four
button5.when_pressed=touch_five

pause()

Bon c’est pas le truc de « ouf »  mais c’est rigolo et c’est bien l’essentiel.
C’est pas demain que je vais jouer Bohemian Rhapsody, on est d’accord !

N’hésitez pas à réagir, partager, critiquer.

@+


Quelques liens :

https://www.teachmeaudio.com/mixing/techniques/audio-spectrum
https://gpiozero.readthedocs.io/en/stable/
https://docs.scipy.org/doc/numpy/index.html
https://scipy.org/


		

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

1 × deux =