I am fairly new to Python, would appreciate any help with the following issue I have, I am trying to make a GUI to test out potentially faulty headsets, I have been looking all over the internet trying to find a graphic design for real-time-audio-input, I have eventually found on and I am currently struggling a little with the following:
I have one script (main.py & a 2nd script Plot_input.py).
I have a few buttons for numerous things, I have a button to start/stop the audio to test if any sound is coming through the headset and that works fine, I also have another button that when clicked is meant to open up the other script (Plot_input.py), the issue I have is that when I run my (Main.py) it auto runs the (Plot_input.py) without the button being clicked, it works as such that when you close down (Plot_input.py) the button then works and it will open up once clicked, my issue is that I do not want the (Plot_input.py) to run until specifically told to (clicking the button), as at the moment it auto opens on running (Main.py), any help would be much appreciated and I will add my code below.
MAIN.PY
import pygame
from tkinter import ttk
from plot_input import *
import subprocess
window = Tk()
window.title("Audio Testing")
window.geometry('750x650')
window.iconbitmap('C:\\MY FILE PATH IS HERE.ico')
window.resizable(False, False)
Img = PhotoImage(file='C:\\MY FILE PATH IS HERE.png')
'''Img_label = Label(window, image=Img)
Img_label.place(x=0, y=0, relwidth=1, relheight=1)'''
my_canvas = Canvas(window, width=750, height=650)
my_canvas.pack(fill='both', expand=True)
my_canvas.create_image(0, 0, image=Img, anchor="nw")
my_canvas.create_text(375, 100, text="Audio Testing App",
font=("Helvetica", 20), fill="white")
my_canvas.create_text(75, 200, text="Headphone",
font=("Helvetica", 14), fill="white")
my_canvas.create_text(75, 250, text="Microphone",
font=("Helvetica", 14), fill="white")
my_canvas.create_text(200, 300, text="Bluetooth (Connection/dongle)",
font=("Helvetica", 14), fill="white")
pygame.mixer.init()
def play():
pygame.mixer.music.load(
'C:\\MY FILE PATH IS HERE.mp3')
pygame.mixer.music.play(loops=0)
def stop():
pygame.mixer.music.stop()
def run_program():
subprocess.call(["python", "plot_input.py"])
button1 = ttk.Button(window, text="Play Song", command=play)
button2 = ttk.Button(window, text="Stop Song", command=stop)
button3 = ttk.Button(window, text="CLICK TO START MIC TEST", command=run_program)
button1_window = my_canvas.create_window(350, 190, anchor="nw", window=button1)
button2_window = my_canvas.create_window(450, 190, anchor="nw", window=button2)
button3_window = my_canvas.create_window(355, 240, anchor="nw", window=button3)
window.mainloop()
PLOT_INPUT.PY
import argparse
import queue
import sys
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
import sounddevice as sd
def int_or_str(text):
"""Helper function for argument parsing."""
try:
return int(text)
except ValueError:
return text
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument(
'-l', '--list-devices', action='store_true',
help='show list of audio devices and exit')
args, remaining = parser.parse_known_args()
if args.list_devices:
print(sd.query_devices())
parser.exit(0)
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parser])
parser.add_argument(
'channels', type=int, default=[1], nargs='*', metavar='CHANNEL',
help='input channels to plot (default: the first)')
parser.add_argument(
'-d', '--device', type=int_or_str,
help='input device (numeric ID or substring)')
parser.add_argument(
'-w', '--window', type=float, default=200, metavar='DURATION',
help='visible time slot (default: %(default)s ms)')
parser.add_argument(
'-i', '--interval', type=float, default=30,
help='minimum time between plot updates (default: %(default)s ms)')
parser.add_argument(
'-b', '--blocksize', type=int, help='block size (in samples)')
parser.add_argument(
'-r', '--samplerate', type=float, help='sampling rate of audio device')
parser.add_argument(
'-n', '--downsample', type=int, default=10, metavar='N',
help='display every Nth sample (default: %(default)s)')
args = parser.parse_args(remaining)
if any(c < 1 for c in args.channels):
parser.error('argument CHANNEL: must be >= 1')
mapping = [c - 1 for c in args.channels] # Channel numbers start with 1
q = queue.Queue()
def audio_callback(indata, frames, time, status):
"""This is called (from a separate thread) for each audio block."""
if status:
print(status, file=sys.stderr)
# Fancy indexing with mapping creates a (necessary!) copy:
q.put(indata[::args.downsample, mapping])
def update_plot(frame):
"""This is called by matplotlib for each plot update.
Typically, audio callbacks happen more frequently than plot updates,
therefore the queue tends to contain multiple blocks of audio data.
"""
global plotdata
while True:
try:
data = q.get_nowait()
except queue.Empty:
break
shift = len(data)
plotdata = np.roll(plotdata, -shift, axis=0)
plotdata[-shift:, :] = data
for column, line in enumerate(lines):
line.set_ydata(plotdata[:, column])
return lines
try:
if args.samplerate is None:
device_info = sd.query_devices(args.device, 'input')
args.samplerate = device_info['default_samplerate']
length = int(args.window * args.samplerate / (1000 * args.downsample))
plotdata = np.zeros((length, len(args.channels)))
fig, ax = plt.subplots()
lines = ax.plot(plotdata)
if len(args.channels) > 1:
ax.legend([f'channel {c}' for c in args.channels],
loc='lower left', ncol=len(args.channels))
ax.axis((0, len(plotdata), -1, 1))
ax.set_yticks([0])
ax.yaxis.grid(True)
ax.tick_params(bottom=False, top=False, labelbottom=False,
right=False, left=False, labelleft=False)
fig.tight_layout(pad=0)
stream = sd.InputStream(
device=args.device, channels=max(args.channels),
samplerate=args.samplerate, callback=audio_callback)
ani = FuncAnimation(fig, update_plot, interval=args.interval, blit=True)
with stream:
plt.show()
except Exception as e:
parser.exit(type(e).__name__ ': ' str(e))
CodePudding user response:
Ok your main problem is happening in this line of code in main.py
(It's a mistake not a coding error):
from plot_input import *
You DO NOT need this line!! Because you anyway run it using subprocess.call
, then why do you need to import that when you do subprocess.call
then it is going to search for plot_input.py
in that directory.
Why is that a problem?
Because when you import everything from plot_input.py
it automatically runs the code that is the plot_input.py which results 2 windows. You can simply remove that line because you don't use anything from plot_input.py
. You are simply executing it when the user presses your button right?
CodePudding user response:
Not quite sure, but maybe try putting the last try/except block in a separate function.