""" Lit un fichier audio .wav via un port série en utilisant des données formatées pour générer un signal PWM rudimentaire. """ import wave import argparse import serial # Taille du buffer pour l'envoi via le port série (permet l'arrêt du script via CTRL-C) STREAM_BUFFER_SIZE = 1024 def chunks(l, n): """ Découpe le buffer l en morceau de n octets. """ for i in range(0, len(l), n): yield l[i : i + n] def resample(x): """ Converti l'échantillon audio x sur 8 bits en un signal PWM sur 3 bits (avec inversion). """ if x >= 224: return 0b00000000 if x >= 195: return 0b10000000 if x >= 168: return 0b11000000 if x >= 140: return 0b11100000 if x >= 112: return 0b11110000 if x >= 84: return 0b11111000 if x >= 56: return 0b11111100 if x >= 28: return 0b11111110 return 0b11111111 def stream_audio_file(filename, serial_port): """ Lit le fichier audio spécifié via le port série spécifié en utilisant des données formatées pour générer un signal PWM rudimentaire. """ # Ouvre le fichier audio with wave.open(filename, 'rb') as fi: # Vérifie la compatibilité du format de fichier assert fi.getnchannels() == 1, "Only mono wave files are supported" assert fi.getsampwidth() == 1, "Only 8bits PCM wave files are supported" # Converti les données audio en données série PWM print("Converting audio file to PWM serial data ...") nb_frames = fi.getnframes() framerate = fi.getframerate() print('Source file "{}" is {} frames long, sampled at {} Hertz'.format(filename, nb_frames, framerate)) data = bytes(map(resample, fi.readframes(nb_frames))) # Ouvre le port série et envoi les données serial_baudrate = framerate * 10 # 8N1: 1 Start, 8 Data, 1 Stop print('Setting serial port "{}" in mode 8N1, at {} bps ...'.format(serial_port, serial_baudrate)) with serial.Serial(port=serial_port, baudrate=serial_baudrate, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE) as serial_com: print("Streaming data ... Use CTRL+C to stop.") for chunk in chunks(data, STREAM_BUFFER_SIZE): serial_com.write(chunk) serial_com.flush() # Interface en ligne de commande if __name__ == "__main__": parser = argparse.ArgumentParser(description='Stream an audio wave file over a serial port using PWM-like serial data.') parser.add_argument('filename', metavar='', help='The input audio wave file (must be a mono 8 bits PCM file).') parser.add_argument('serialport', metavar='', help='The output serial port.') args = parser.parse_args() stream_audio_file(args.f