• .
  • Willkommen im Forum!
  • Alles beim Alten...
  • Du hast kaum etwas verpasst ;-)
  • Jetzt noch sicherer mit HTTPS
Hallo, Gast! Anmelden Registrieren


PyAudio
#18
Jetzt kommt ein kleines Programm, das Sinusschwingungen ausgeben kann. Auf dem Netz habe ich nur solche gefunden, wo vorab eine Datei entsprechender Länge erzeugt wird, die dann abgespielt wird. Das ist aber nicht brauchbar als Tongenerator, wenn man erst etliche Minuten warten muss, bis die Datei für 30min Ton denn endlich erstellt ist.
Und ja, das geht auch anders, allerdings nicht so einfach. Das nun folgende Programm liefert Dauerton, sauber und ohne Unterbrechungen, nachdem ich in den letzten Tagen die unverzichtbare Phasensprungkorrektur mühsam debbugged habe.

Es wuerde mich freuen, wenn mal jemand das bei sich ausprobieren würde. Wink

Code:
#! /usr/bin/python2.7
"""
Tongenerator mit PC, Soundkarte und Python

Erzeugt Dauertoene aus einer Tabelle von der Groesse eines chunks (typ 1024 samples).
Die Soundkarte uebernimmt zyklisch diese chunks und haengt sie aneinander.

Nur in seltenen Ausnahmefaellen passt ein ganzzahliges Vielfaches einer Schwingungsperiode
genau in den chunk-Puffer, so dass an den Stossstellen zweier chunks immer ein Phasensprung statt findet.
Derartige Phasenspruenge sind stoerend, sie werden gehoermaessig sofort wahr genommen.
Die dynamische Phasenkorrektur verschiebt den Startpunkt im chunkbuffer immer passend,
so dass nahtlose Uebergaenge zustande kommen.

Der Kode ist ausgelegt fuer geringstmoegliche CPU-Last.
Massgeblich dafuer ist die Tonausgabe per callback-Funktion,
die Phasenkorrektur durch dynamische Indizierung des chunk-Puffers
und das mittels sleep-Anweisung ausgeduennte polling.
Am Lenovo X200 wurde 1% Zusatzlast bei 44,1kHz Abstastrate gemessen.

Waehrend die Soundkarte auf dem linken Ausgang Toene ausgibt,
kann audicity diese simultan ueber den Eingang aufzeichen
(kabelverbindung Ausgang-Eingang links).
Auf diese Weise wurden Tonschnipsel zur Dokumentation erstellt.

Zur Laufzeit koennen Frequenz und Amplitude modifiziert werden
durch Ueberschreiben des chunk-Puffers.

Bevor es losgeht
Div Python-Pakete installieren
Default Soundkarte einstellen ueber die PulsAudio-GUI.
Oder PulseAudio killen und direkt ueber Alsa gehen.
Dazu muss im home-Verzeichnis eine passende Datei ".asoundrc" abgelegt werden.

Getestet mit Lenovo X200, Behringer UCA 202 unter ubuntu 14.04, ohne PulseAudio
Stand 2014-10-27
"""
import pyaudio
import time
import numpy as np

#   Konfiguration

#   Audiosignal-Parameter
STREAM_CHANNELS = 1
STREAM_SAMPLE_RATE = 44100
STREAM_FORMAT = pyaudio.paInt16
#   Tongenerator
TONE_FQ = 1000.0
TONE_LEVEL = 0.5
CHUNK_LEN = 1024

#    callback Funktion

def callback_tonegen (out_data, frame_count, time_info, status):
    global NextChunk
    if NextChunk == True:
        print "!Fehler:output-chunk verloren!"
    # Handshake-Uebergabe an Hauptprogramm
    NextChunk = True
    # PhasenSprungKorrektur durch ArrayIndexOffset ("slicing")
    Data = DoubleChunkBuf[PhaseIdx::]
    return (Data, pyaudio.paContinue)

#   Befuelle Chunk-Puffer mit Sinus-Schwingungen
def DoubleChunkInit(fq, level, samplerate, chunklen):
    maxphase = 2 * np.pi * fq * chunklen / samplerate
    phaseofs = np.fmod(maxphase,(2 * np.pi))
    x = np.arange (2*chunklen)  
    doublechunkbuf = np.array(x)
    xcoeff = 2 * np.pi * fq / samplerate
    doublechunkbuf = level*2**15*np.sin(x * xcoeff)
    doublechunkbuf = doublechunkbuf.astype(np.int16)
    return(doublechunkbuf,phaseofs,maxphase)

#   Hauptprogramm Initialisierungen

Phase = 0.0
PhaseIdx = 0
NextChunk = False
DoubleChunkBuf, PhaseOfs, MaxPhase = DoubleChunkInit(TONE_FQ, TONE_LEVEL, STREAM_SAMPLE_RATE, CHUNK_LEN)

#   initialisiere die Soundkarte
p = pyaudio.PyAudio()

#   starte Audio-Stream
OutputStream = p.open(
    format=STREAM_FORMAT,
    channels=STREAM_CHANNELS,
    rate = STREAM_SAMPLE_RATE,
    input=False,
    output=True,
    stream_callback=callback_tonegen)
OutputStream.start_stream()

#   Hauptprogrammschleife

while OutputStream.is_active():
    if NextChunk == True:
        NextChunk = False
        # Versatz fuer PhasenSprungKorrektur
        Phase += PhaseOfs
        Phase = Phase % (2 * np.pi) #!!!
        PhaseIdx = int(Phase * CHUNK_LEN / (MaxPhase))
    time.sleep(0.001)

#   Programmende

OutputStream.stop_stream()
OutputStream.close()
p.terminate()
...mit der Lizenz zum Löten!
 
Reply
  


Nachrichten in diesem Thema
PyAudio - von alfsch - 04.10.2014, 12:57 AM
[Kein Betreff] - von voltwide - 04.10.2014, 12:59 AM
[Kein Betreff] - von voltwide - 04.10.2014, 01:07 AM
[Kein Betreff] - von voltwide - 04.10.2014, 01:21 AM
[Kein Betreff] - von voltwide - 04.10.2014, 10:44 AM
[Kein Betreff] - von voltwide - 04.10.2014, 09:39 PM
[Kein Betreff] - von voltwide - 04.10.2014, 10:05 PM
[Kein Betreff] - von voltwide - 05.10.2014, 08:06 PM
[Kein Betreff] - von voltwide - 07.10.2014, 03:06 PM
[Kein Betreff] - von kahlo - 07.10.2014, 03:18 PM
[Kein Betreff] - von Hoppenstett - 07.10.2014, 06:19 PM
[Kein Betreff] - von voltwide - 14.10.2014, 11:04 PM
[Kein Betreff] - von voltwide - 14.10.2014, 11:07 PM
[Kein Betreff] - von voltwide - 16.10.2014, 09:36 AM
[Kein Betreff] - von kahlo - 16.10.2014, 12:26 PM
[Kein Betreff] - von voltwide - 16.10.2014, 04:47 PM
[Kein Betreff] - von kahlo - 16.10.2014, 04:56 PM
[Kein Betreff] - von voltwide - 27.10.2014, 10:48 PM
[Kein Betreff] - von voltwide - 27.10.2014, 11:23 PM
[Kein Betreff] - von voltwide - 27.10.2014, 11:27 PM
[Kein Betreff] - von SEBOJ - 28.10.2014, 09:44 AM
RE: - von voltwide - 28.10.2014, 01:00 PM
[Kein Betreff] - von voltwide - 02.10.2015, 12:23 AM
RE: PyAudio - von alfsch - 26.12.2017, 08:08 PM
RE: PyAudio - von voltwide - 26.12.2017, 08:27 PM
RE: PyAudio - von scooot - 26.12.2017, 08:34 PM
RE: PyAudio - von alfsch - 26.12.2017, 09:43 PM