diff --git a/tnc/main.py b/tnc/main.py index 46c5fc11..1dd2f304 100755 --- a/tnc/main.py +++ b/tnc/main.py @@ -220,6 +220,30 @@ if __name__ == "__main__": action="store_true", help="Enable publishing stats to https://freedata.app", ) + + PARSER.add_argument( + "--tci", + dest="audio_enable_tci", + action="store_true", + help="Enable TCI as audio source", + ) + + PARSER.add_argument( + "--tci-ip", + dest="tci_ip", + default='127.0.0.1', + type=str, + help="Set tci destination ip", + ) + + PARSER.add_argument( + "--tci-port", + dest="tci_port", + default=9000, + type=int, + help="Set tci destination port", + ) + ARGS = PARSER.parse_args() # set save to folder state for allowing downloading files to local file system @@ -270,6 +294,9 @@ if __name__ == "__main__": static.ENABLE_EXPLORER = ARGS.enable_explorer static.AUDIO_AUTO_TUNE = ARGS.enable_audio_auto_tune static.ENABLE_STATS = ARGS.enable_stats + static.AUDIO_ENABLE_TCI = ARGS.audio_enable_tci + static.TCI_IP = ARGS.tci_ip + static.TCI_PORT = ARGS.tci_port except Exception as e: log.error("[DMN] Error reading config file", exception=e) @@ -317,6 +344,9 @@ if __name__ == "__main__": static.ENABLE_EXPLORER = config['TNC']['explorer'] in ["True", "true", True] static.AUDIO_AUTO_TUNE = config['AUDIO']['auto_tune'] in ["True", "true", True] static.ENABLE_STATS = config['TNC']['stats'] in ["True", "true", True] + static.AUDIO_ENABLE_TCI = config['AUDIO']['enable_tci'] in ["True", "true", True] + static.TCI_IP = str(config['AUDIO']['tci_ip']) + static.TCI_PORT = int(config['AUDIO']['tci_port']) except KeyError as e: log.warning("[CFG] Error reading config file near", key=str(e)) diff --git a/tnc/modem.py b/tnc/modem.py index 78abd7fe..5e9a3e19 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -153,7 +153,7 @@ class RF: self.freedv_datac1_tx = open_codec2_instance(10) self.freedv_datac3_tx = open_codec2_instance(12) # --------------------------------------------CREATE PYAUDIO INSTANCE - if not TESTMODE: + if not TESTMODE and not static.AUDIO_ENABLE_TCI: try: self.stream = sd.RawStream( channels=1, @@ -175,11 +175,40 @@ class RF: self.stream.start() except Exception as err: self.log.error("[MDM] init: starting pyaudio callback failed", e=err) + + elif not TESTMODE and static.AUDIO_ENABLE_TCI: + # placeholder area for processing audio via TCI + # https://github.com/maksimus1210/TCI + self.log.debug("[MDM] [TCI] Not yet implemented", ip=static.TCI_IP, port=static.TCI_PORT) + # we are trying this by simulating an audio stream Object like with mkfifo + class Object: + """An object for simulating audio stream""" + active = True + + self.stream = Object() + + # let's start the audio rx callback + self.log.debug("[MDM] Starting tci rx callback thread") + tci_rx_callback_thread = threading.Thread( + target=self.tci_rx_callback, + name="TCI RX CALLBACK THREAD", + daemon=True, + ) + tci_rx_callback_thread.start() + + # let's start the audio tx callback + self.log.debug("[MDM] Starting tci tx callback thread") + tci_tx_callback_thread = threading.Thread( + target=self.tci_tx_callback, + name="TCI TX CALLBACK THREAD", + daemon=True, + ) + tci_tx_callback_thread.start() + else: class Object: """An object for simulating audio stream""" - active = True self.stream = Object() @@ -286,6 +315,52 @@ class RF: worker_transmit.start() # -------------------------------------------------------------------------------------------------------- + def tci_tx_callback(self) -> None: + """ + Callback for TCI TX + """ + while True: + threading.Event().wait(0.01) + + # -----write + if len(self.modoutqueue) > 0 and not self.mod_out_locked: + data_out48k = self.modoutqueue.popleft() + + + def tci_rx_callback(self) -> None: + """ + Callback for TCI RX + + data_in48k must be filled with 48000Hz audio raw data + + """ + + while True: + threading.Event().wait(0.01) + + # generate random audio data + data_in48k = np.random.uniform(-1, 1, 48000) + + x = np.frombuffer(data_in48k, dtype=np.int16) + x = self.resampler.resample48_to_8(x) + + self.fft_data = x + + length_x = len(x) + for data_buffer, receive in [ + (self.sig0_datac0_buffer, RECEIVE_SIG0), + (self.sig1_datac0_buffer, RECEIVE_SIG1), + (self.dat0_datac1_buffer, RECEIVE_DATAC1), + (self.dat0_datac3_buffer, RECEIVE_DATAC3), + ]: + if ( + not (data_buffer.nbuffer + length_x) > data_buffer.size + and receive + ): + data_buffer.push(x) + + + def mkfifo_read_callback(self) -> None: """ Support testing by reading the audio data from a pipe and diff --git a/tnc/static.py b/tnc/static.py index 950403af..4693f394 100644 --- a/tnc/static.py +++ b/tnc/static.py @@ -81,6 +81,12 @@ AUDIO_RECORD: bool = False AUDIO_RECORD_FILE = '' BUFFER_OVERFLOW_COUNTER: list = [0, 0, 0, 0, 0] AUDIO_AUTO_TUNE: bool = False +# Audio TCI Support +AUDIO_ENABLE_TCI: bool = False +TCI_IP: str = '127.0.0.1' +TCI_PORT: int = '9000' + + AUDIO_DBFS: int = 0 FFT: list = [0]