======2. Variante Oszilloskop======
Es gibt verschiedene graphische Benutzeroberflächen, die abhängig von Ereignissen andere Programme aufrufen können. Hier habe ich mich für **gtk** entschieden, es gibt noch Qt, tk und wx (komische Namen). Man kann matplotlib mitteilen, welche dieser Oberflächen er verwenden soll. Nur darin unterscheidet sich der Vorspann des Programms von der 1. Variante:
#!/usr/bin/python
# coding=utf8
from __future__ import division
### Audio-Modul
import pyaudio
##############
# Graphik und Berechnungen
import matplotlib
### Wir müssen uns hier für ein Graphik-System ('backend') entscheiden,
### wenn wir dieses die Ereigniskontroll übernehmen lassen wollen: 'gtk'
matplotlib.use('GTKAgg')
import gobject
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.
Der für die graphische Anzeige zuständige Teil unterscheidet sich nur wenig, aber in bedeutsamer Weise von der 1. Variante. Die Klasse `Anzeige` hat nun eine weitere Methode `zeichnen`. Die zeichnen-Methode des globalen Anzeige-Objekts wird mit dem so genannten `idle`-Event verknüpft, d.h. immer dann aufgerufen, wenn sonst nichts zu tun ist.
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)
def zeichnen(self,*args):
self.fig.canvas.draw()
return True
##################
### Anzeige setup, hier wird das 'idle'-Event (=nichts weiter
### zu tun) mit dem Zeichnen des momentanen Plots verbunden
anzeige=Anzeige(CHUNK,RATE)
gobject.idle_add(anzeige.zeichnen)
Der Audio-Teil unterscheidet sich nicht von der 1. Variante, siehe dort. Das Hauptprogramm tut nun nichts anderes mehr, als die beiden unabhängigen Prozesse (Mikrophon auslesen, Bild anzeigen) nebeneinander laufen zu lassen. Die Prozesse sind nicht synchron. Es kann sein, dass die Bilder sehr viel häufiger neu gezeichnet werden als neue Audio-Daten kommen. Das macht aber nichts. Da beide Prozesse schon gestartet wurden, muss nur dafür gesorgt werden, dass das Programm nicht beendet wird und die graphische Oberfläche aktiv bleibt:
plt.show()
Dieser Methodenaufruf wird erst beendet, wenn man das Graphikfenster schließt. Anschließend kann man wieder, wie in der 1. Variante, die beiden Prozesse sauber beenden.