!7 import static x30_pkg.x30_util.VF1; sclass AudioInputOutput > DynPrintLog { int bufSize = 40960; transient recordToAudioListeners_AudioLoop loop; transient SimpleLiveValue lvVolume = floatLiveValue(); // in percent L> audioListeners = synchroList(); float gain = 1; transient playAudioFromSampleMakingFunction_AudioLoop outputLoop; transient L> sources = synchroList(); visualize { ret centerAndSouthWithMargins(super.visualize(), vstackWithSpacing( withLabel("Volume (0-200%):", liveSliderZeroToOne(gain/2, voidfunc(float f) { setField(gain := f*2) })), jCenteredLine(jLiveValueLabel(mapLiveValue(func(float volume) -> S { "Input Volume: " + iround(volume) + " %" }, S, lvVolume))))); } start { ownTimer(loop = recordToAudioListeners(audioListeners, bufSize, lvVolume)); ownTimer(outputLoop = playAudioFromSampleMakingFunction_dontStart(bufSize, voidfunc(double[] pair) { audio_makeSampleFromSources(sources, pair, gain) })); Mixer mixer = AudioSystem.getMixer(null); print("Mixer: " + mixer); Line[] lines = { loop.line, outputLoop.out }; bool fullSync = true; bool canSync = mixer.isSynchronizationSupported(lines, true); print("Can sync: " + canSync); if (!canSync) { fullSync = false; canSync = mixer.isSynchronizationSupported(lines, false); print("Can sync: " + canSync); } if (canSync) mixer.synchronize(lines, fullSync); loop.start(); outputLoop.start(); } void addAudioListener(VF1 l) { audioListeners.add(l); } void removeAudioListener(VF1 l) { audioListeners.remove(l); } void addSource(VF1 source) { sources.add(source); } void removeSource(VF1 source) { sources.remove(source); } }