====== 1. Variante Oszilloskop ====== Der Anfang besteht nur aus einigen Imports und Definitionen: #!/usr/bin/python # coding=utf8 from __future__ import division ### Audio-Modul import pyaudio ############## # Graphik und Berechnungen import matplotlib.pyplot as plt import numpy as np ### Zeit import time ########################### ### GLOBALE VARIABLEN CHANNELS=1 RATE=44100 DAUER=1 ANZAHL=DAUER*RATE # ANZAHL der Frames, CHUNK=2**11 # globale Variablen, schlechter Programmierstil, hier aber ganz # praktisch: Nach Aufnahme oder Lesen werden diese Variablen # entsprechend gesetzt. Dann kommt der Code-Teil, der die für die Anzeige relevanten Strukturen erzeugt. Ein Anzeige-Objekt erzeugt einen Plot, der sich mit einer 'update'-Methode an veränderte Daten anpassen lässt. class Anzeige(object): '''Anzeige-Objekt, zeigt 'chunk' frames an, x-Achse beschriftet mit den korrekten Zeiten. Das zweite Argument ist die Sample-Rate''' def __init__(self,chunk,rate): self.fig,self.ax=plt.subplots(1,1) self.ax = plt.axes(ylim=(-1,1),xlim=(0,chunk/RATE)) self.xwerte=np.arange(chunk)/RATE self.kurve, = self.ax.plot(self.xwerte,np.zeros(chunk), lw=2) self.fig.canvas.draw() plt.pause(0.001) self.chunk=chunk def update(self,data): '''Plottet 'data' ''' self.kurve.set_data(self.xwerte,data/2**16) anzeige=Anzeige(CHUNK,RATE) Nun der für die Audioverarbeitung zuständige Teil. Dabei wird ein so genannter **stream** erzeugt, der mit einer **callback**-Funktion ausgestattet ist. Der stream ist ein unabhängig vom weiteren Programm laufender Prozess, der die Audiodaten liest (man könnte ihn ebenso zum Schreiben verwenden). Immer wenn eine gewisse Menge von Daten zusammengekommen ist (genauer: CHUNK Samples), ruft dieser Prozess die callback-Funktion, die bei seiner Erzeugung angegeben wurde. Diese callback-Funktion aktualisiert hier nur die beim Plotten verwendeten Daten, ohne selbst zu plotten. (Sie könnte ebenso gut eine komplizierte Transformation der Daten durchführen und sie an ein anderes Programm durchreichen.) ### Audio setup ########################################### ### Hier wird ein 'Audio-Stream' gestartet, der immer, wenn ### CHUNK Frames aus dem Mikrophon gelesen wurden, die Funktion ### micro_callback aufruft, die diese Daten dann in den Plot ### 'anzeige' schreibt. Stattdessen könnte man die Daten auch ### erste bearbeiten und irgendwoanders hin schreiben. ### Dieser Audiostream läuft unabhängig vom weiteren Programm. ### Die Daten in anzeige.kurve sind also stets aktuell. ### Ums Anzeigen kümmert sich dann die 'Hauptschleife unten. ############################################################## def micro_callback(in_data, frame_count, time_info, status): '''callback Funktion: wird vom PyAudio-Objekt aufgerufen, wenn CHUNK Frames von der Soundkarte (Mikrophon) gelesen wurden''' y=np.fromstring(in_data,dtype=np.short) if CHANNELS==2: y=y.reshape((y.shape[0]//2,2)) else: y=y.reshape((y.shape[0],1)) anzeige.update(y[:,0]) return (in_data, pyaudio.paContinue) p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16 , channels=CHANNELS, rate=RATE, input=True, output=False, stream_callback=micro_callback, frames_per_buffer=CHUNK) stream.start_stream() time.sleep(0.5) Das Hauptprogramm kümmert sich nur darum, den Plot mit den aktuellen Daten neu zu zeichnen: ### 'Hauptschleife' while stream.is_active(): anzeige.fig.canvas.draw() time.sleep(0.05) #### Alles wieder schließen, was geöffnet wurde stream.stop_stream() stream.close() p.terminate() Diese Hauptschleife ist keine sehr elegante Lösung. Besser wäre es, der Plot kümmert sich 'selbst' darum, wann er gezeichnet wird, ebenso wie sich der Audio-Stream selbst um die Aktualisierung der Daten kümmert. Das ist aber gerade die 2. Variante.