Le son:
au format audio wave

L'écriture et la lecture du contenu d'un fichier audio au format WAV est simplifiée par l'utilisation du module wave.

Ecriture

Voici un exemple de création d'un fichier audio (PCM 8 bits stéréo 44100 Hz) avec une forme d'onde sinusoïdale :


import wave
import math
import binascii

print("Création d'un fichier audio au format WAV (PCM 8 bits stéréo 44100 Hz)")
print("Son de forme sinusoïdale sur chaque canal\n")

NomFichier = 'son.wav'			
Monson = wave.open(NomFichier,'w')  	#création et ouverture du fichier en mode write 'w' (écriture)
					 # initialisation de l'objet Monson 

nbCanal = 2    		# stéreo
nbOctet = 1    		# taille d'un échantillon : 1 octet = 8 bits
fech = 44100   		# fréquence d'échantillonnage

frequenceG = float(input('Fréquence du son du canal de gauche (Hz) ? '))
frequenceD = float(input('Fréquence du son du canal de droite (Hz) ? '))
niveauG = float(input('Niveau du son du canal de gauche (0 à 1) ? '))
niveauD = float(input('Niveau du son du canal de droite (0 à 1) ? '))
duree = float(input('Durée (en secondes) ? '))

nbEchantillon = int(duree*fech)
print("Nombre d'échantillons :",nbEchantillon)

parametres = (nbCanal,nbOctet,fech,nbEchantillon,'NONE','not compressed')	# tuple
Monson.setparams(parametres)   				 # création de l'en-tête (44 octets)

# niveau max dans l'onde positive : +1 -> 255 (0xFF)
# niveau max dans l'onde négative : -1 ->   0 (0x00)
# niveau sonore nul :                0 -> 127.5 (0x80 en valeur arrondi)

amplitudeG = 127.5*niveauG
amplitudeD = 127.5*niveauD

print('Veuillez patienter...')
for i in range(0,nbEchantillon):       # canal gauche
    # 127.5 + 0.5 pour arrondir à l'entier le plus proche
    valG = wave.struct.pack('B',int(128.0 + amplitudeG*math.sin(2.0*math.pi*frequenceG*i/fech)))
    # canal droit
    valD = wave.struct.pack('B',int(128.0 + amplitudeD*math.sin(2.0*math.pi*frequenceD*i/fech)))
    Monson.writeframes(valG + valD)  # écriture frame 

Monson.close()

Fichier = open(NomFichier,'rb')
data = Fichier.read()
tailleFichier = len(data)
print('\nTaille du fichier',NomFichier, ':', tailleFichier,'octets')
print("Lecture du contenu de l'en-tête (44 octets) :")
print(binascii.hexlify(data[0:44]))
print("Nombre d'octets de données :",tailleFichier - 44)
Fichier.close()			# fermeture du fichier 

>>>
Création d'un fichier audio au format WAV (PCM 8 bits stéréo 44100 Hz)
Son de forme sinusoïdale sur chaque canal

Fréquence du son du canal de gauche (Hz) ? 440.0
Fréquence du son du canal de droite (Hz) ?  880.0
Niveau du son du canal de gauche (0 à 1) ?  1.0
Niveau du son du canal de droite (0 à 1) ?  0.5
Durée (en secondes) ? 2.5
Nombre d'échantillons : 110250
Veuillez patienter...

Taille du fichier son.wav : 220544 octets
Lecture du contenu de l'en-tête (44 octets) :
b'52494646785d030057415645666d7420100000000100020044ac0000885801000200080064617461545d0300'
Nombre d'octets de données : 220500
>>>  

On peut aussi choisir un emplacement quelconque en spécifiant le chemin absolu, par exemple NomFichier = 'C:/Mon dossier/son.wav').

Ecouter le son

Il est possible lire le fichier son.wav avec un lecteur multimédia quelconque (VLC par exemple). Mais on peut aussi faire directement une lecture audio avec le module adéquat (module externe pygame.mixer, module ossaudiodev sous Linux, module winsound sous Windows, etc...) :


# lecture audio (sortie vers la carte son)
import winsound
winsound.PlaySound('son.wav',winsound.SND_FILENAME)

Le module pygame est un module externe de création de jeux vidéo en 2D. pygame contient un sous module pygame.mixer qui permet de charger et de lire des musiques ou des sons dans plusieurs formats (mp3, ogg, wav...). Pour télécharger ce module de pygame cliquer ici


import pygame
pygame.mixer.init()
pygame.mixer.Sound("son.wav").play()
while pygame.mixer.get_busy():
    # lecture en cours
    pass

Lecture du fichier

On peut compléter l'étude du fichier en l'ouvrant son.wav avec un éditeur de sons tel que Audacity :

Il est aussi possible de lire le fichier son avec un éditeur hexadécimal tel que Hex Editor Néo.

GHex

Voici un script qui permet d'obtenir les caractéristiques d'un ficher son au format Wave.



import wave
import binascii

NomFichier = input('Entrer le nom du fichier : ')
Monson = wave.open(NomFichier,'r')	# instanciation de l'objet Monson

print("\nNombre de canaux :",Monson.getnchannels())
print("Taille d'un échantillon (en octets):",Monson.getsampwidth())
print("Fréquence d'échantillonnage (en Hz):",Monson.getframerate())
print("Nombre d'échantillons :",Monson.getnframes())
print("Type de compression :",Monson.getcompname())

TailleData = Monson.getnchannels()*Monson.getsampwidth()*Monson.getnframes()

print("Taille du fichier (en octets) :",TailleData + 44)
print("Nombre d'octets de données :",TailleData)

print("\nAffichage d'une plage de données (dans l'intervalle 0 -",Monson.getnframes()-1,")")

echDebut = int(input('N° échantillon (début) : '))
echFin = int(input('N° échantillon (fin) : '))

print("\nN° échantillon	Contenu")

Monson.setpos(echDebut)
plage = echFin - echDebut + 1
for i in range(0,plage):
    print(Monson.tell(),'\t\t',binascii.hexlify(Monson.readframes(1)))

Monson.close()

Voici les données que ce script produit :


>>>
Entrer le nom du fichier : son.wav

Nombre de canaux : 2
Taille d'un échantillon (en octets): 1
Fréquence d'échantillonnage (en Hz): 4410044100
Nombre d'échantillons : 110250110250
Type de compression : not compressed
Taille du fichier (en octets) : 220544
Nombre d'octets de données : 220500

Affichage d'une plage de données (dans l'intervalle 0 - 110249 )
N° échantillon (début) : 0
N° échantillon (fin) : 5

N° échantillon 	Contenu
0 		 b'8080'
1 		 b'8787'
2 		 b'8f8f'
3 		 b'9797'
4 		 b'9f9e'
5 		 b'a7a5'
>>>

Un échantillon est ici constitué de deux octets : le premier correspond à l'échantillon du canal de gauche, le second à celui du canal de droite.
Si le fichier est placé dans un répertoire spécifique, à l'appel du nom du fichier, il faut entrer le chemin absolu, par exemple :
NomFichier = 'C:/Mon dossier/son.wav'

Exercice: La tonalité du téléphone.

La tonalité du téléphone provient de codes DTMF (dual-tone multi-frequency) qui sont des combinaisons de fréquences. Ces codes sont émis lors de la pression sur une touche du clavier téléphonique, et sont utilisés pour la composition des numéros de téléphones.
Ecrire un programme qui génère la tonalité d'un numéro.
Par exemple :0887825361

>>> Numéro de téléphone ? 0887825361
Veuillez patienter...
Le fichier dtmf.wav a été créé >>>

Aide :

Code DTMF