!7 import static x30_pkg.x30_util.VF1; sclass AudioOutput > DynPrintLog { int bufSize = 40960; float gain = 1; transient playAudioFromSampleMakingFunction_AudioLoop loop; transient L> sources = synchroList(); JComponent visualize() { ret centerAndSouth(super.visualize(), withLabel("Volume (0-200%):", liveSliderZeroToOne(gain/2, voidfunc(float f) { setField(gain := f*2) }))); } void start { ownTimer(loop = playAudioFromSampleMakingFunction(bufSize, voidfunc(double[] pair) { makeSample(pair) })); } void makeSample(double[] pair) { double l = 0, r = 0; for i over sources: { // synchro-safe, garbage-free iteration VF1 source = syncGet(sources, i); continue if source == null; callF(source, pair); l += pair[0]; r += pair[1]; } pair[0] = l*gain; pair[1] = r*gain; } void addSource(VF1 source) { sources.add(source); } void removeSource(VF1 source) { sources.remove(source); } }