!7 cmodule LiveFFT > DynImageSurface { volatile bool enabled = true; switchable bool normalize = true; switchable double windowSize = 1; // seconds transient Q q; transient L buffer = synchroList(); transient volatile int bufferSize; transient int neededSamples; transient Clip clip; visualize { if (!hasImage()) setImage( whiteImage(audio_estimatedFrequencyImageWidth(windowSize), audio_frequencyImageHeight())); ret centerAndSouthWithMargins(super.visualizeWithDoubleBuffering(), jrightalignedline(dm_fieldCheckBox('enabled))); } void onNewWindowSize { neededSamples = iround(windowSize*44100); buffer.clear(); bufferSize = 0; } start { dm_watchFieldAndNow windowSize(r onNewWindowSize); q = dm_startQ(); dm_addAudioListener(voidfunc(short[] data) { if (!enabled) ret; data = dm_audioInputIsStereo() ? mixStereoShortArrayToMono(data) : cloneShortArray(data); if (normalize) { //int vol = absShortMax(data); //short[] oldData = data; data = normalizeShortArray(data); /*print("vol: " + vol + ". " + sfu(takeFirstOfShortArray(4, oldData)) + " " + sfu(takeFirstOfShortArray(4, data)));*/ } buffer.add(data); bufferSize += l(data); if (bufferSize >= neededSamples) { bufferSize -= neededSamples; final L salvaged = cloneList(buffer); buffer.clear(); if (bufferSize > 0) { buffer.add(lastNShorts(bufferSize, last(salvaged))); replaceLastElement(salvaged, dropLastNShorts(bufferSize, last(salvaged))); } q.add(r { MultiShortArrayInputStream_resettable stream = new(salvaged); stream.bigEndian = true; clip = spectro_clipFromMonoInputStream(stream); vmBus_send newAudioFrequencyClip(clip); BWImage img = clipToFrequencyImage(clip); vmBus_send newAudioFrequencyImage(img); setImage(img); }); } }); } }