Closed jsl303 closed 3 years ago
Ouch... A file to decompressed (m4a) into a numpy array, then copied into a pyo table, while the audio is running, will surely get you into trouble. You can't guarantee that all this work will be done fast enough so that every audio buffer (asked by the audio driver) will be filled with valid samples.
Few advises:
1) It's always better to preload all your sounds into different buffers at the beginning of the program. Switching which buffer to read is very cheap.
2) It's better to use uncompressed soundfiles (wav or aiff), instead of any compressed format, because they are faster to read.
3) Try to avoid multiple copies at runtime. If you absolutely need to use numpy array, take a look at the buffer protocol, implemented in the PyoTableObject.
In the documentation, this line:
t = SndTable(SNDS_PATH+”/transparent.aif”) arr = numpy.asarray(t.getBuffer())
should be read:
t = SndTable(SNDS_PATH+”/transparent.aif”)
arr = numpy.asarray(t.getBuffer())
Thanks! I modified the snippet from the multiprocessing example, and separated Loader and Player with Queue mechanism. It now runs without stutter even with m4a.
from pyo import *
import multiprocessing as mp
import random
from glob import glob
import librosa
import time
import warnings
class Player(mp.Process):
def __init__(self, q):
super(Player, self).__init__()
self.daemon = True
self._terminated = False
self.q = q
def run(self):
self.server = Server(duplex=0)
self.server.boot()
self.server.start()
while not self._terminated:
d = self.q.get()
print(d['path'])
shape = d['shape']
if len(shape) > 1: length = shape[1]
else: length = shape[0]
dur = length/44100
table = DataTable(length, chnls=2, init=d['y'])
osc = Looper(table, mode=0, dur=dur, xfade=1).out()
time.sleep(dur)
self.server.stop()
def stop(self):
self._terminated = True
class Loader(mp.Process):
def __init__(self, q):
super(Loader, self).__init__()
self.daemon = True
self._terminated = False
self.q = q
def run(self):
files = glob('sounds/**/*.m4a', recursive=True)
while not self._terminated:
while self.q.qsize()>20: time.sleep(0.1)
try:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
d = {}
path = files[random.randint(0,len(files))]
d['path'] = path
length = librosa.get_duration(filename=path)
dur = random.uniform(3,5)
d['dur'] = dur
start = random.uniform(0, length-dur)
y, sr = librosa.load(path, sr=44100, offset=start, duration=dur, mono=False)
d['shape'] = y.shape
d['y'] = y.tolist()
self.q.put(d)
except Exception as e: print(e)
def stop(self):
self._terminated = True
if __name__ == '__main__':
q = mp.Queue()
loader = Loader(q)
loader.start()
player = Player(q)
player.start()
input("Running")
player.stop()
loader.stop()
exit()
I have the following simple code that extract random parts of soundfiles from a folder. However, each load, the sound stutters with the last few milliseconds before playing the next. I use librosa to load m4a files into numpy, and then load into DataTable. I'd appreciate any suggestion.