Hi James, I ran into more less this problem a while back. I found two different solutions. One is to use multithreaded(see program below) and the other is to use networking. The advantage of networking (pyoscreceive and send) is that you can run two separate programs whereas with multithreading you are not truly working in parallel. But here is a multithreaded example:
from pyo import Server
from pyo import Sine
from pyo import LinTable
from pyo import Osc
from threading import Thread
import tkinter as tk
from tkinter import ttk
import tkinter.font as tkFont
class pyoClass(Thread):
def __init__(self):
Thread.__init__(self)
self.runProgram = True
self.pyoServer = Server(buffersize=1024)
self.pyoServer.setInOutDevice(14) # The device index returned by portaudio go here
self.pyoServer.boot()
#a = Input(chnl=0, mul=.7)# 0 is the first channel of the device (give [0,1] to get stereo input)
#spec = Spectrum(a, size=4096)
self.frequency =1.0
self.change = True
sine = Sine(freq = self.frequency).out(chnl = 0)
self.pyoServer.start()
def run(self):
self.theShape = LinTable([(0,-0.8), (4000, 0.8), (8191,-0.8)]) #, size = 16
while self.runProgram == True:
if self.change:
myOscil = Osc(self.theShape, freq=self.frequency, mul=0.8)
myOscil.out(chnl=0)
self.change = False
self.pyoServer.stop()
def setFreq(self, freqIn):
self.frequency = freqIn
self.change = True
def setShape(self, pos, amplitude):
self.theShape = LinTable([(0,-0.8), (pos,amplitude), (8191, -0.8)])
self.change = True
def stopPyo(self):
self.runProgram = False
class App(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.grid()
self.create_widgets()
self.update()
self.myPyo= pyoClass()
self.myPyo.start()
def create_widgets(self):
self.freqVar = tk.StringVar()
self.posVar = tk.StringVar()
self.ampVar = tk.StringVar()
self.btn_font = tkFont.Font(family="Helvetica", size=12, weight='bold')
self.ShowData_text = ttk.Entry(self, textvariable = self.freqVar)
self.ShowData_text.grid(column = 3, row = 1)
self.sendFreqButton = tk.Button(self, font = self.btn_font,text="Send Freq", command=self.sendFreq)
self.sendFreqButton.grid(column = 3, row = 50, pady = 5, sticky = 'we')
self.ShowPos_text = ttk.Entry(self, textvariable = self.posVar)
self.ShowPos_text.grid(column = 4, row = 1)
self.ShowAmp_text = ttk.Entry(self, textvariable = self.ampVar)
self.ShowAmp_text.grid(column = 5, row = 1)
self.sendShapeButton = tk.Button(self, font = self.btn_font,text="Send Shape", command=self.sendShape)
self.sendShapeButton.grid(column = 4, row = 50, pady = 5, sticky = 'we')
self.stopButton = tk.Button(self, font = self.btn_font,text="Stop It", command=self.stopIt)
self.stopButton.grid(column = 4, row = 60, pady = 5, sticky = 'we')
def mainloop(self):
super().mainloop()
self.update()
self.destroy()
def sendFreq(self):
freq = float(self.ShowData_text.get())
self.myPyo.setFreq(freq)
def sendShape(self):
pos = int(self.ShowPos_text.get())
ampl = float(self.ShowAmp_text.get())
self.myPyo.setShape(pos, ampl)
def stopIt(self):
self.myPyo.stopPyo()
tk.Frame.quit(self)
self.destroy()
def main():
app = App()
app.master.title('Spectrum Analyzer')
app.master.geometry('900x980')
app.mainloop()
if __name__ == '__main__':
main()
I prefer networking because you can develop the programs separately and even run them on two different computers.
In stead of multithreading you might consider asyncio.
I hope this helps
Erwin