I'm having a very strange problem, which I managed to reduce as much as possible like this:
import sounddevice
import time
class SamplerBox:
def __init__(self):
self.samples = {}
def audio_callback(self, outdata, frame_count, time_info, status):
print('ac')
def init(self):
self.connect_audio_output()
self.load_samples()
time.sleep(20)
def connect_audio_output(self):
try:
sd = sounddevice.OutputStream(callback=self.audio_callback)
sd.start()
print('Opened audio device')
except:
print('Invalid audio device')
exit(1)
def load_samples(self):
for midinote in range(128):
for velocity in range(128):
self.samples[midinote, velocity] = Sound()
class Sound:
def __init__(self):
pass
sb = SamplerBox()
sb.init()
As soon as I create that big self.samples
dict, and only create a new audio stream with an empty callback, I get "Bus Error 10" with Python 3.11.
With Python 3.9 I get "Illegal instruction 4"
In my original script (reduced here) I got "Segmentation Fault 11"
I'm running Homebrew Python 3.11 on MacOS 10.15.7.
Worst than that, written in a procedural way, it runs perfectly :
import sounddevice
import time
samples = {}
class Sound:
def __init__(self):
pass
def audio_callback(self, outdata, frame_count, time_info, status):
print('ac')
try:
sd = sounddevice.OutputStream(callback=audio_callback)
sd.start()
print('Opened audio device')
except:
print('Invalid audio device')
exit(1)
for midinote in range(128):
for velocity in range(128):
samples[midinote, velocity] = Sound()
time.sleep(20)
Any idea?
You do not keep a reference to the output stream object created in connect_audio_output
, so when the method finishes the sounddevice.OutputStream
object associated to the local variable sd
loses all its references and will be eventually collected by the GC.
Keep the object alive, e.g. by assigning it to an instance attribute:
def connect_audio_output(self):
try:
self.sd = sounddevice.OutputStream(callback=self.audio_callback)
self.sd.start()
print('Opened audio device')
except:
print('Invalid audio device')
exit(1)
In your procedural approach sd
is a global variable, so the object will persist as long as the process exists.