Audacity and Python runner keep not responding

Hello, I’m developing an app in Python with a Tkinter GUI that communicates with Audacity via piping. Just wanted to see if anyone could help me get a sense of what it means when both Audacity and the Python runner stop responding, and how to debug these issues. It does not seem to be tied to any particular command. Sometimes I can run hundreds of commands with no problem, and other times things will just stop responding out of nowhere. The app now has over a thousand LOC, but I will attach the part of the code that interacts with Audacity and hopefully folks can help me add some try/except statements or debugging statements to my code, with the goal of preventing the dreaded spinning wheel and “application not responding” message.

The code below shows the utils.py file which contains the code that actually interacts with Audacity, and then the processor.py file which contains a class that runs the do_command function many times in succession.

# utils.py

import os
from sys import exit
from tkinter import messagebox

TONAME = '/tmp/audacity_script_pipe.to.' + str(os.getuid())
FROMNAME = '/tmp/audacity_script_pipe.from.' + str(os.getuid())

try:
  TOFILE = open(TONAME, 'w')
  FROMFILE = open(FROMNAME, 'rt')
except FileNotFoundError:
  messagebox.showerror("Pipe not found", 
    """The audacity pipe file was not found. 
    Please make sure Audacity is open before launching the application.""")
  exit()

def send_command(command):
  TOFILE.write(command + "\n")
  TOFILE.flush()

def get_response():
    """Return the command response."""
    result = ''
    line = ''
    while True:
        result += line
        line = FROMFILE.readline()
        if line == '\n' and len(result) > 0:
            break
    return result

def do_command(command):
  """Send one command, and return the response."""
  send_command(command)
  response = get_response()
  return response
  
  
  
# processor.py

import json
import os

from utils import do_command

class Processor:
    def __init__(self, master):
        self.master = master

    def process(self, params, processes):
        self.counter_start = int(params["counter_start"])
        self.num_iterations = int(params["num_iterations"])

        if self.num_iterations < 1:
            return

        if params["import"] == True:
            (do_command("ImportRaw:"))

        # Get audio info
        info = (do_command("GetInfo: Type=Tracks"))

        # Trim info
        info = info[1:-26]

        # Load track data
        track_data = json.loads(info)
        first_track_end = track_data[0]["end"]

        # Set start and end
        start = 0.2
        end = first_track_end

        # Create file path if does not already exist
        folder_name = params["folder_name"]
        filepath = f"/Users/jholland/Pictures/glitch/{folder_name}"
        if not os.path.exists(filepath):
            os.mkdir(filepath)
        
        for i in range(self.counter_start, 
            self.num_iterations + self.counter_start):

            if params["fill_gaps"] == True:
                if i not in params["gaps"]:
                    continue

            # Copy audio
            (do_command("SelectAll:"))
            (do_command("Copy:"))

            # Select portion to process
            (do_command(f"SelectTime: Start={start}  End={end}"))

            for effect in processes:
                command = effect["name"] + ": "

                for param in effect["params"]:
                    start_val = float(param["start_val"])
                    end_val = float(param["end_val"])
                    value = self.get_value(start_val, end_val, i)
                    command += param["name"] + "=" + str(value) + " "
                
                print(command)
                (do_command(command))

            # Select all for export
            (do_command("SelectAll:"))

            # Export
            filename = f"{filepath}/{i}.raw"
            command = f"Export2: Filename={filename}"
            (do_command(command))

            # Select all, delete, and paste original audio
            (do_command("SelectAll:"))
            (do_command("Delete:"))
            (do_command("Paste:"))

    def get_value(self, start_val, end_val, idx):
        if idx == 0:
            return start_val
        if idx == self.num_iterations:
            return end_val

        inc = (end_val - start_val) / self.num_iterations

        return start_val + (inc * (idx - self.counter_start))

I’d suggest that you use the pipeclient.py module. It communicates with Audacity using a separate thread so the main Python thread should still be running even if Audacity freezes.

Hmm that works for all of my commands except for “GetInfo.” But I can just use do_command for that one and pipe_client for all the rest. This may help, thank you so much for the tip!

GetInfo: works for me. What’s the exact command that you are sending and what do you see?

I appreciate it, but I’m not really interested in troubleshooting that at the moment. I’m much more interested in troubleshooting the freezing issue. Thanks to pipe_client, I now have the ability to exit the Python app when Audacity freezes, so then I only have to force quit Audacity rather than force quitting both the Python app and Audacity. That’s an improvement! But I’d still like to troubleshoot the freezing issue itself. Any thoughts on how to mitigate it?

Except for “GetInfo,” all of my commands function as expected.