From a922b8db3f36eb867edfee5cc6ac2a6f8fafad8f Mon Sep 17 00:00:00 2001 From: LuKe Tidd Date: Mon, 12 Feb 2024 19:05:17 -0500 Subject: [PATCH] created a static radio player --- ex 1.grc | 641 ++++++++++++++++++++++++++++++++++ static_radio_ttf_and_audio.py | 219 ++++++++++++ 2 files changed, 860 insertions(+) create mode 100644 ex 1.grc create mode 100755 static_radio_ttf_and_audio.py diff --git a/ex 1.grc b/ex 1.grc new file mode 100644 index 0000000..24080b8 --- /dev/null +++ b/ex 1.grc @@ -0,0 +1,641 @@ +options: + parameters: + author: '' + catch_exceptions: 'True' + category: '[GRC Hier Blocks]' + cmake_opt: '' + comment: '' + copyright: '' + description: '' + gen_cmake: 'On' + gen_linking: dynamic + generate_options: qt_gui + hier_block_src_path: '.:' + id: ex1 + max_nouts: '0' + output_language: python + placement: (0,0) + qt_qss_theme: '' + realtime_scheduling: '' + run: 'True' + run_command: '{python} -u {filename}' + run_options: prompt + sizing_mode: fixed + thread_safe_setters: '' + title: fm radio example + window_size: (1000,1000) + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [8, 8] + rotation: 0 + state: enabled + +blocks: +- name: center_freq + id: variable + parameters: + comment: '' + value: 97.9e6 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [168, 784.0] + rotation: 0 + state: enabled +- name: channel_freq + id: variable + parameters: + comment: '' + value: '96100000.0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [48, 864.0] + rotation: 0 + state: enabled +- name: channel_width + id: variable + parameters: + comment: '' + value: 200e3 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [168, 864.0] + rotation: 0 + state: enabled +- name: samp_rate + id: variable + parameters: + comment: '' + value: 20e6 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [64, 784.0] + rotation: 0 + state: enabled +- name: volume_adjust + id: variable_qtgui_range + parameters: + comment: '' + gui_hint: '' + label: '' + min_len: '200' + orient: QtCore.Qt.Horizontal + rangeType: float + start: '0' + step: '.01' + stop: '5' + value: '1' + widget: counter_slider + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [984, 872.0] + rotation: 0 + state: enabled +- name: analog_sig_source_x_0 + id: analog_sig_source_x + parameters: + affinity: '' + alias: '' + amp: '1' + comment: '' + freq: center_freq - channel_freq + maxoutbuf: '0' + minoutbuf: '0' + offset: '0' + phase: '0' + samp_rate: samp_rate + showports: 'False' + type: complex + waveform: analog.GR_COS_WAVE + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [128, 616.0] + rotation: 0 + state: enabled +- name: analog_wfm_rcv_0 + id: analog_wfm_rcv + parameters: + affinity: '' + alias: '' + audio_decimation: '10' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + quad_rate: '48000' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [816, 608.0] + rotation: 0 + state: enabled +- name: audio_sink_0 + id: audio_sink + parameters: + affinity: '' + alias: '' + comment: '' + device_name: '' + num_inputs: '1' + ok_to_block: 'True' + samp_rate: '48000' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1080, 504.0] + rotation: 0 + state: enabled +- name: blocks_multiply_const_vxx_0 + id: blocks_multiply_const_vxx + parameters: + affinity: '' + alias: '' + comment: '' + const: volume_adjust + maxoutbuf: '0' + minoutbuf: '0' + type: float + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1048, 672.0] + rotation: 0 + state: enabled +- name: blocks_multiply_xx_0 + id: blocks_multiply_xx + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + num_inputs: '2' + type: complex + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [440, 552.0] + rotation: 0 + state: enabled +- name: low_pass_filter_0 + id: low_pass_filter + parameters: + affinity: '' + alias: '' + beta: '6.76' + comment: '' + cutoff_freq: 75e3 + decim: int(samp_rate/channel_width) + gain: '1' + interp: '1' + maxoutbuf: '0' + minoutbuf: '0' + samp_rate: samp_rate + type: fir_filter_ccf + width: 25e3 + win: window.WIN_HAMMING + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [488, 748.0] + rotation: 0 + state: enabled +- name: osmosdr_source_0 + id: osmosdr_source + parameters: + affinity: '' + alias: '' + ant0: '' + ant1: '' + ant10: '' + ant11: '' + ant12: '' + ant13: '' + ant14: '' + ant15: '' + ant16: '' + ant17: '' + ant18: '' + ant19: '' + ant2: '' + ant20: '' + ant21: '' + ant22: '' + ant23: '' + ant24: '' + ant25: '' + ant26: '' + ant27: '' + ant28: '' + ant29: '' + ant3: '' + ant30: '' + ant31: '' + ant4: '' + ant5: '' + ant6: '' + ant7: '' + ant8: '' + ant9: '' + args: '""' + bb_gain0: '20' + bb_gain1: '20' + bb_gain10: '20' + bb_gain11: '20' + bb_gain12: '20' + bb_gain13: '20' + bb_gain14: '20' + bb_gain15: '20' + bb_gain16: '20' + bb_gain17: '20' + bb_gain18: '20' + bb_gain19: '20' + bb_gain2: '20' + bb_gain20: '20' + bb_gain21: '20' + bb_gain22: '20' + bb_gain23: '20' + bb_gain24: '20' + bb_gain25: '20' + bb_gain26: '20' + bb_gain27: '20' + bb_gain28: '20' + bb_gain29: '20' + bb_gain3: '20' + bb_gain30: '20' + bb_gain31: '20' + bb_gain4: '20' + bb_gain5: '20' + bb_gain6: '20' + bb_gain7: '20' + bb_gain8: '20' + bb_gain9: '20' + bw0: '0' + bw1: '0' + bw10: '0' + bw11: '0' + bw12: '0' + bw13: '0' + bw14: '0' + bw15: '0' + bw16: '0' + bw17: '0' + bw18: '0' + bw19: '0' + bw2: '0' + bw20: '0' + bw21: '0' + bw22: '0' + bw23: '0' + bw24: '0' + bw25: '0' + bw26: '0' + bw27: '0' + bw28: '0' + bw29: '0' + bw3: '0' + bw30: '0' + bw31: '0' + bw4: '0' + bw5: '0' + bw6: '0' + bw7: '0' + bw8: '0' + bw9: '0' + clock_source0: '' + clock_source1: '' + clock_source2: '' + clock_source3: '' + clock_source4: '' + clock_source5: '' + clock_source6: '' + clock_source7: '' + comment: '' + corr0: '0' + corr1: '0' + corr10: '0' + corr11: '0' + corr12: '0' + corr13: '0' + corr14: '0' + corr15: '0' + corr16: '0' + corr17: '0' + corr18: '0' + corr19: '0' + corr2: '0' + corr20: '0' + corr21: '0' + corr22: '0' + corr23: '0' + corr24: '0' + corr25: '0' + corr26: '0' + corr27: '0' + corr28: '0' + corr29: '0' + corr3: '0' + corr30: '0' + corr31: '0' + corr4: '0' + corr5: '0' + corr6: '0' + corr7: '0' + corr8: '0' + corr9: '0' + dc_offset_mode0: '0' + dc_offset_mode1: '0' + dc_offset_mode10: '0' + dc_offset_mode11: '0' + dc_offset_mode12: '0' + dc_offset_mode13: '0' + dc_offset_mode14: '0' + dc_offset_mode15: '0' + dc_offset_mode16: '0' + dc_offset_mode17: '0' + dc_offset_mode18: '0' + dc_offset_mode19: '0' + dc_offset_mode2: '0' + dc_offset_mode20: '0' + dc_offset_mode21: '0' + dc_offset_mode22: '0' + dc_offset_mode23: '0' + dc_offset_mode24: '0' + dc_offset_mode25: '0' + dc_offset_mode26: '0' + dc_offset_mode27: '0' + dc_offset_mode28: '0' + dc_offset_mode29: '0' + dc_offset_mode3: '0' + dc_offset_mode30: '0' + dc_offset_mode31: '0' + dc_offset_mode4: '0' + dc_offset_mode5: '0' + dc_offset_mode6: '0' + dc_offset_mode7: '0' + dc_offset_mode8: '0' + dc_offset_mode9: '0' + freq0: center_freq + freq1: 100e6 + freq10: 100e6 + freq11: 100e6 + freq12: 100e6 + freq13: 100e6 + freq14: 100e6 + freq15: 100e6 + freq16: 100e6 + freq17: 100e6 + freq18: 100e6 + freq19: 100e6 + freq2: 100e6 + freq20: 100e6 + freq21: 100e6 + freq22: 100e6 + freq23: 100e6 + freq24: 100e6 + freq25: 100e6 + freq26: 100e6 + freq27: 100e6 + freq28: 100e6 + freq29: 100e6 + freq3: 100e6 + freq30: 100e6 + freq31: 100e6 + freq4: 100e6 + freq5: 100e6 + freq6: 100e6 + freq7: 100e6 + freq8: 100e6 + freq9: 100e6 + gain0: '0' + gain1: '10' + gain10: '10' + gain11: '10' + gain12: '10' + gain13: '10' + gain14: '10' + gain15: '10' + gain16: '10' + gain17: '10' + gain18: '10' + gain19: '10' + gain2: '10' + gain20: '10' + gain21: '10' + gain22: '10' + gain23: '10' + gain24: '10' + gain25: '10' + gain26: '10' + gain27: '10' + gain28: '10' + gain29: '10' + gain3: '10' + gain30: '10' + gain31: '10' + gain4: '10' + gain5: '10' + gain6: '10' + gain7: '10' + gain8: '10' + gain9: '10' + gain_mode0: 'False' + gain_mode1: 'False' + gain_mode10: 'False' + gain_mode11: 'False' + gain_mode12: 'False' + gain_mode13: 'False' + gain_mode14: 'False' + gain_mode15: 'False' + gain_mode16: 'False' + gain_mode17: 'False' + gain_mode18: 'False' + gain_mode19: 'False' + gain_mode2: 'False' + gain_mode20: 'False' + gain_mode21: 'False' + gain_mode22: 'False' + gain_mode23: 'False' + gain_mode24: 'False' + gain_mode25: 'False' + gain_mode26: 'False' + gain_mode27: 'False' + gain_mode28: 'False' + gain_mode29: 'False' + gain_mode3: 'False' + gain_mode30: 'False' + gain_mode31: 'False' + gain_mode4: 'False' + gain_mode5: 'False' + gain_mode6: 'False' + gain_mode7: 'False' + gain_mode8: 'False' + gain_mode9: 'False' + if_gain0: '20' + if_gain1: '20' + if_gain10: '20' + if_gain11: '20' + if_gain12: '20' + if_gain13: '20' + if_gain14: '20' + if_gain15: '20' + if_gain16: '20' + if_gain17: '20' + if_gain18: '20' + if_gain19: '20' + if_gain2: '20' + if_gain20: '20' + if_gain21: '20' + if_gain22: '20' + if_gain23: '20' + if_gain24: '20' + if_gain25: '20' + if_gain26: '20' + if_gain27: '20' + if_gain28: '20' + if_gain29: '20' + if_gain3: '20' + if_gain30: '20' + if_gain31: '20' + if_gain4: '20' + if_gain5: '20' + if_gain6: '20' + if_gain7: '20' + if_gain8: '20' + if_gain9: '20' + iq_balance_mode0: '0' + iq_balance_mode1: '0' + iq_balance_mode10: '0' + iq_balance_mode11: '0' + iq_balance_mode12: '0' + iq_balance_mode13: '0' + iq_balance_mode14: '0' + iq_balance_mode15: '0' + iq_balance_mode16: '0' + iq_balance_mode17: '0' + iq_balance_mode18: '0' + iq_balance_mode19: '0' + iq_balance_mode2: '0' + iq_balance_mode20: '0' + iq_balance_mode21: '0' + iq_balance_mode22: '0' + iq_balance_mode23: '0' + iq_balance_mode24: '0' + iq_balance_mode25: '0' + iq_balance_mode26: '0' + iq_balance_mode27: '0' + iq_balance_mode28: '0' + iq_balance_mode29: '0' + iq_balance_mode3: '0' + iq_balance_mode30: '0' + iq_balance_mode31: '0' + iq_balance_mode4: '0' + iq_balance_mode5: '0' + iq_balance_mode6: '0' + iq_balance_mode7: '0' + iq_balance_mode8: '0' + iq_balance_mode9: '0' + maxoutbuf: '0' + minoutbuf: '0' + nchan: '1' + num_mboards: '1' + sample_rate: samp_rate + sync: sync + time_source0: '' + time_source1: '' + time_source2: '' + time_source3: '' + time_source4: '' + time_source5: '' + time_source6: '' + time_source7: '' + type: fc32 + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [96, 380.0] + rotation: 0 + state: enabled +- name: qtgui_sink_x_0_0 + id: qtgui_sink_x + parameters: + affinity: '' + alias: '' + bw: samp_rate + comment: '' + fc: channel_freq + fftsize: '32768' + gui_hint: '' + maxoutbuf: '0' + minoutbuf: '0' + name: '""' + plotconst: 'True' + plotfreq: 'True' + plottime: 'True' + plotwaterfall: 'True' + rate: '10' + showports: 'False' + showrf: 'True' + type: complex + wintype: window.WIN_BLACKMAN_hARRIS + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [800, 280.0] + rotation: 0 + state: enabled +- name: rational_resampler_xxx_0 + id: rational_resampler_xxx + parameters: + affinity: '' + alias: '' + comment: '' + decim: '5' + fbw: '0' + interp: '12' + maxoutbuf: '0' + minoutbuf: '0' + taps: '[]' + type: ccc + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [608, 560.0] + rotation: 0 + state: enabled + +connections: +- [analog_sig_source_x_0, '0', blocks_multiply_xx_0, '1'] +- [analog_wfm_rcv_0, '0', blocks_multiply_const_vxx_0, '0'] +- [blocks_multiply_const_vxx_0, '0', audio_sink_0, '0'] +- [blocks_multiply_xx_0, '0', low_pass_filter_0, '0'] +- [blocks_multiply_xx_0, '0', qtgui_sink_x_0_0, '0'] +- [low_pass_filter_0, '0', rational_resampler_xxx_0, '0'] +- [osmosdr_source_0, '0', blocks_multiply_xx_0, '0'] +- [rational_resampler_xxx_0, '0', analog_wfm_rcv_0, '0'] + +metadata: + file_format: 1 + grc_version: 3.10.9.2 diff --git a/static_radio_ttf_and_audio.py b/static_radio_ttf_and_audio.py new file mode 100755 index 0000000..3f47a75 --- /dev/null +++ b/static_radio_ttf_and_audio.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 + +from PyQt5 import Qt +from gnuradio import qtgui +from PyQt5 import QtCore +from gnuradio import analog +from gnuradio import audio +from gnuradio import blocks +from gnuradio import filter +from gnuradio.filter import firdes +from gnuradio import gr +from gnuradio.fft import window +import sys +import signal +from PyQt5 import Qt +from argparse import ArgumentParser +from gnuradio.eng_arg import eng_float, intx +from gnuradio import eng_notation +import osmosdr +import time +import sip + + + +class ex1(gr.top_block, Qt.QWidget): + + def __init__(self): + gr.top_block.__init__(self, "fm radio example", catch_exceptions=True) + Qt.QWidget.__init__(self) + self.setWindowTitle("fm radio example") + qtgui.util.check_set_qss() + try: + self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) + except BaseException as exc: + print(f"Qt GUI: Could not set Icon: {str(exc)}", file=sys.stderr) + self.top_scroll_layout = Qt.QVBoxLayout() + self.setLayout(self.top_scroll_layout) + self.top_scroll = Qt.QScrollArea() + self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) + self.top_scroll_layout.addWidget(self.top_scroll) + self.top_scroll.setWidgetResizable(True) + self.top_widget = Qt.QWidget() + self.top_scroll.setWidget(self.top_widget) + self.top_layout = Qt.QVBoxLayout(self.top_widget) + self.top_grid_layout = Qt.QGridLayout() + self.top_layout.addLayout(self.top_grid_layout) + + self.settings = Qt.QSettings("GNU Radio", "ex1") + + try: + geometry = self.settings.value("geometry") + if geometry: + self.restoreGeometry(geometry) + except BaseException as exc: + print(f"Qt GUI: Could not restore geometry: {str(exc)}", file=sys.stderr) + + ################################################## + # Variables + ################################################## + self.volume_adjust = volume_adjust = 1 + self.samp_rate = samp_rate = 20e6 + self.channel_width = channel_width = 200e3 + self.channel_freq = channel_freq = 96100000.0 + self.center_freq = center_freq = 97.9e6 + + ################################################## + # Blocks + ################################################## + + self._volume_adjust_range = qtgui.Range(0, 5, .01, 1, 200) + self._volume_adjust_win = qtgui.RangeWidget(self._volume_adjust_range, self.set_volume_adjust, "'volume_adjust'", "counter_slider", float, QtCore.Qt.Horizontal) + self.top_layout.addWidget(self._volume_adjust_win) + self.rational_resampler_xxx_0 = filter.rational_resampler_ccc( + interpolation=12, + decimation=5, + taps=[], + fractional_bw=0) + self.qtgui_sink_x_0_0 = qtgui.sink_c( + 32768, #fftsize + window.WIN_BLACKMAN_hARRIS, #wintype + channel_freq, #fc + samp_rate, #bw + "", #name + True, #plotfreq + True, #plotwaterfall + True, #plottime + True, #plotconst + None # parent + ) + self.qtgui_sink_x_0_0.set_update_time(1.0/10) + self._qtgui_sink_x_0_0_win = sip.wrapinstance(self.qtgui_sink_x_0_0.qwidget(), Qt.QWidget) + + self.qtgui_sink_x_0_0.enable_rf_freq(True) + + self.top_layout.addWidget(self._qtgui_sink_x_0_0_win) + self.osmosdr_source_0 = osmosdr.source( + args="numchan=" + str(1) + " " + "" + ) + self.osmosdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t()) + self.osmosdr_source_0.set_sample_rate(samp_rate) + self.osmosdr_source_0.set_center_freq(center_freq, 0) + self.osmosdr_source_0.set_freq_corr(0, 0) + self.osmosdr_source_0.set_dc_offset_mode(0, 0) + self.osmosdr_source_0.set_iq_balance_mode(0, 0) + self.osmosdr_source_0.set_gain_mode(False, 0) + self.osmosdr_source_0.set_gain(0, 0) + self.osmosdr_source_0.set_if_gain(20, 0) + self.osmosdr_source_0.set_bb_gain(20, 0) + self.osmosdr_source_0.set_antenna('', 0) + self.osmosdr_source_0.set_bandwidth(0, 0) + self.low_pass_filter_0 = filter.fir_filter_ccf( + (int(samp_rate/channel_width)), + firdes.low_pass( + 1, + samp_rate, + 75e3, + 25e3, + window.WIN_HAMMING, + 6.76)) + self.blocks_multiply_xx_0 = blocks.multiply_vcc(1) + self.blocks_multiply_const_vxx_0 = blocks.multiply_const_ff(volume_adjust) + self.audio_sink_0 = audio.sink(48000, '', True) + self.analog_wfm_rcv_0 = analog.wfm_rcv( + quad_rate=48000, + audio_decimation=10, + ) + self.analog_sig_source_x_0 = analog.sig_source_c(samp_rate, analog.GR_COS_WAVE, (center_freq - channel_freq), 1, 0, 0) + + + ################################################## + # Connections + ################################################## + self.connect((self.analog_sig_source_x_0, 0), (self.blocks_multiply_xx_0, 1)) + self.connect((self.analog_wfm_rcv_0, 0), (self.blocks_multiply_const_vxx_0, 0)) + self.connect((self.blocks_multiply_const_vxx_0, 0), (self.audio_sink_0, 0)) + self.connect((self.blocks_multiply_xx_0, 0), (self.low_pass_filter_0, 0)) + self.connect((self.blocks_multiply_xx_0, 0), (self.qtgui_sink_x_0_0, 0)) + self.connect((self.low_pass_filter_0, 0), (self.rational_resampler_xxx_0, 0)) + self.connect((self.osmosdr_source_0, 0), (self.blocks_multiply_xx_0, 0)) + self.connect((self.rational_resampler_xxx_0, 0), (self.analog_wfm_rcv_0, 0)) + + + def closeEvent(self, event): + self.settings = Qt.QSettings("GNU Radio", "ex1") + self.settings.setValue("geometry", self.saveGeometry()) + self.stop() + self.wait() + + event.accept() + + def get_volume_adjust(self): + return self.volume_adjust + + def set_volume_adjust(self, volume_adjust): + self.volume_adjust = volume_adjust + self.blocks_multiply_const_vxx_0.set_k(self.volume_adjust) + + def get_samp_rate(self): + return self.samp_rate + + def set_samp_rate(self, samp_rate): + self.samp_rate = samp_rate + self.analog_sig_source_x_0.set_sampling_freq(self.samp_rate) + self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.samp_rate, 75e3, 25e3, window.WIN_HAMMING, 6.76)) + self.osmosdr_source_0.set_sample_rate(self.samp_rate) + self.qtgui_sink_x_0_0.set_frequency_range(self.channel_freq, self.samp_rate) + + def get_channel_width(self): + return self.channel_width + + def set_channel_width(self, channel_width): + self.channel_width = channel_width + + def get_channel_freq(self): + return self.channel_freq + + def set_channel_freq(self, channel_freq): + self.channel_freq = channel_freq + self.analog_sig_source_x_0.set_frequency((self.center_freq - self.channel_freq)) + self.qtgui_sink_x_0_0.set_frequency_range(self.channel_freq, self.samp_rate) + + def get_center_freq(self): + return self.center_freq + + def set_center_freq(self, center_freq): + self.center_freq = center_freq + self.analog_sig_source_x_0.set_frequency((self.center_freq - self.channel_freq)) + self.osmosdr_source_0.set_center_freq(self.center_freq, 0) + + + + +def main(top_block_cls=ex1, options=None): + + qapp = Qt.QApplication(sys.argv) + + tb = top_block_cls() + + tb.start() + + tb.show() + + def sig_handler(sig=None, frame=None): + tb.stop() + tb.wait() + + Qt.QApplication.quit() + + signal.signal(signal.SIGINT, sig_handler) + signal.signal(signal.SIGTERM, sig_handler) + + timer = Qt.QTimer() + timer.start(500) + timer.timeout.connect(lambda: None) + + qapp.exec_() + +if __name__ == '__main__': + main()