horus-gui/horusgui/audio.py

121 wiersze
3.6 KiB
Python

# Audio Interfacing
import logging
import pyaudio
# Global PyAudio object
pyAudio = None
audioStream = None
audioDevices = {}
def init_audio(widgets):
""" Initialise pyaudio object, and populate list of sound card in GUI """
global pyAudio, audioDevices
# Init PyAudio
pyAudio = pyaudio.PyAudio()
audioDevices = {}
# Clear list
widgets["audioDeviceSelector"].clear()
# Add in the 'dummy' GQRX UDP interface
widgets["audioDeviceSelector"].addItem('GQRX UDP')
# Iterate through PyAudio devices
for x in range(0, pyAudio.get_device_count()):
_dev = pyAudio.get_device_info_by_index(x)
# Does the device have inputs?
if _dev["maxInputChannels"] > 0:
# Get the name
_name = _dev["name"]
# Add to local store of device info
audioDevices[_name] = _dev
# Add to audio device selection list.
widgets["audioDeviceSelector"].addItem(_name)
# Select first item.
if len(list(audioDevices.keys())) > 0:
widgets["audioDeviceSelector"].setCurrentIndex(0)
# Initial population of sample rates.
populate_sample_rates(widgets)
return audioDevices
def populate_sample_rates(widgets):
""" Populate the sample rate ComboBox with the sample rates of the currently selected audio device """
global audioDevices
# Clear list of sample rates.
widgets["audioSampleRateSelector"].clear()
# Get information on current audio device
_dev_name = widgets["audioDeviceSelector"].currentText()
# Add in fixed sample rate for GQRX input.
if _dev_name == 'GQRX UDP':
widgets["audioSampleRateSelector"].addItem(str(48000))
widgets["audioSampleRateSelector"].setCurrentIndex(0)
if _dev_name in audioDevices:
# TODO: Determine valid samples rates. For now, just use the default.
# TODO: Add support for resampling.
_samp_rate = 48000 # int(audioDevices[_dev_name]["defaultSampleRate"])
widgets["audioSampleRateSelector"].addItem(str(_samp_rate))
widgets["audioSampleRateSelector"].setCurrentIndex(0)
else:
logging.error("Audio - Unknown Audio Device")
class AudioStream(object):
""" Start up a pyAudio input stream, and pass data around to different callbacks """
def __init__(self, audio_device, fs, block_size=8192, fft_input=None, modem=None, stats_callback = None):
self.audio_device = audio_device
self.fs = fs
self.block_size = block_size
self.fft_input = fft_input
self.modem = modem
self.stats_callback = stats_callback
# Start audio stream
self.audio = pyaudio.PyAudio()
self.stream = self.audio.open(
format=pyaudio.paInt16,
channels=1,
rate=self.fs,
frames_per_buffer=self.block_size,
input=True,
input_device_index=self.audio_device,
output=False,
stream_callback=self.handle_samples,
)
def handle_samples(self, data, frame_count, time_info="", status_flags=""):
""" Handle incoming samples from pyaudio """
# Pass samples directly into fft.
if self.fft_input:
self.fft_input(data)
if self.modem:
# Add samples to modem
_stats = self.modem.add_samples(data)
# Send any stats data back to the stats callback
if _stats:
if self.stats_callback:
self.stats_callback(_stats)
return (None, pyaudio.paContinue)
def stop(self):
""" Halt stream """
self.stream.close()