From b4dac45e19c026de9ddf16f04a97b95ee9f51b01 Mon Sep 17 00:00:00 2001 From: weefuzzy Date: Wed, 13 Mar 2019 00:04:18 +0000 Subject: [PATCH 01/18] CMakeList: Sandbag Mac specific things, and be strict with quoting --- CMakeLists.txt | 28 ++++++++++++++-------------- scripts/target_post.cmake | 16 ++++++++-------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index caab9fd..07f08b4 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,17 +4,17 @@ cmake_minimum_required(VERSION 3.3) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_EXTENSIONS OFF) +if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -mavx -msse -msse2 -msse3 -msse4") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libc++") SET(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.7" CACHE STRING "Minimum OS X deployment version") - - -project (fluid_decomposition_supercollider LANGUAGES CXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic") +endif() +project (fluid_decomposition_supercollider LANGUAGES CXX) option(SUPERNOVA "Build plugins for supernova" OFF) @@ -30,11 +30,11 @@ MACRO(SUBDIRLIST result curdir) ENDMACRO() set(FLUID_PATH ~/fluid_decomposition CACHE PATH "The top level of the fluid_decomposition repo") -set(LOCAL_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include) +set(LOCAL_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include") -get_filename_component(FLUID_ABS_PATH ${FLUID_PATH} ABSOLUTE) -message(${FLUID_ABS_PATH}) +get_filename_component(FLUID_ABS_PATH "${FLUID_PATH}" ABSOLUTE) +message("${FLUID_ABS_PATH}") # if (NOT DEFINED ${FLUID_DECOMP_PATH}) # message(FATAL_ERROR "Please set the path to the fluid_decomposition sources with -DFLUID_DECOMP_PATH=") # endif() @@ -43,11 +43,11 @@ if (NOT (EXISTS "${FLUID_ABS_PATH}/build/fluid_decomposition-exports.cmake")) message(FATAL_ERROR "Can't find the fluid_decomposition CMake targets file at ${FLUID_ABS_PATH}/build/fluid_decomposition-expors.cmake. Please go to ${FLUID_ABS_PATH}/build and run CMake") endif() -if (NOT (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/)) - file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/) +if (NOT (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/")) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/") endif() -file(COPY ${FLUID_ABS_PATH}/AudioFiles/ DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/) +file(COPY "${FLUID_ABS_PATH}/AudioFiles/" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/") include("${FLUID_ABS_PATH}/build/fluid_decomposition-exports.cmake") @@ -64,14 +64,14 @@ endif() add_library(FLUID_SC_WRAPPER INTERFACE) target_sources(FLUID_SC_WRAPPER INTERFACE -${CMAKE_CURRENT_SOURCE_DIR}/include/FluidSCWrapper.hpp -${CMAKE_CURRENT_SOURCE_DIR}/include/SCBufferAdaptor.hpp +"${CMAKE_CURRENT_SOURCE_DIR}/include/FluidSCWrapper.hpp" +"${CMAKE_CURRENT_SOURCE_DIR}/include/SCBufferAdaptor.hpp" ) -SUBDIRLIST(PROJECT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src) +SUBDIRLIST(PROJECT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src") foreach (project_dir ${PROJECT_DIRS}) if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/${project_dir}/CMakeLists.txt") message("Generating: ${project_dir}") - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/${project_dir}) + add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/src/${project_dir}") endif () endforeach () diff --git a/scripts/target_post.cmake b/scripts/target_post.cmake index 247c069..d59dae7 100644 --- a/scripts/target_post.cmake +++ b/scripts/target_post.cmake @@ -11,23 +11,23 @@ target_include_directories( PRIVATE ${LOCAL_INCLUDES} SYSTEM PRIVATE - ${SC_PATH}/include/plugin_interface - ${SC_PATH}/include/common - ${SC_PATH}/common - ${SC_PATH}/external_libraries/boost #we need boost::align for deallocating buffer memory :-( + "${SC_PATH}/include/plugin_interface" + "${SC_PATH}/include/common" + "${SC_PATH}/common" + "${SC_PATH}/external_libraries/boost" #we need boost::align for deallocating buffer memory :-( ) get_property(HEADERS TARGET FLUID_DECOMPOSITION PROPERTY INTERFACE_SOURCES) -source_group(TREE ${FLUID_PATH}/include FILES ${HEADERS}) +source_group(TREE "${FLUID_PATH}/include" FILES ${HEADERS}) if (SUPERNOVA) target_include_directories( ${PLUGIN} SYSTEM PRIVATE - ${SC_PATH}/external_libraries/nova-tt - ${SC_PATH}/external_libraries/boost_lockfree - ${SC_PATH}/external_libraries/boost-lockfree + "${SC_PATH}/external_libraries/nova-tt" + "${SC_PATH}/external_libraries/boost_lockfree" + "${SC_PATH}/external_libraries/boost-lockfree" ) endif() From e657c96e0b87da867d3a19ab5b50bc4beaba6d0b Mon Sep 17 00:00:00 2001 From: weefuzzy Date: Wed, 13 Mar 2019 00:05:20 +0000 Subject: [PATCH 02/18] target+post.cmake: Add avx and __use_maths_defines (for M_PI) on Windows --- scripts/target_post.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/target_post.cmake b/scripts/target_post.cmake index d59dae7..4089a56 100644 --- a/scripts/target_post.cmake +++ b/scripts/target_post.cmake @@ -81,6 +81,10 @@ if(MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mstackrealign") endif() +if(MSVC) + target_compile_options(${PLUGIN} PRIVATE /arch:AVX -D_USE_MATH_DEFINES) +endif() + ####### added the fluid_decomposition if(SUPERNOVA) From 2fd321b13f8b19d5eb1cf5b34c9f82eed67b1472 Mon Sep 17 00:00:00 2001 From: weefuzzy Date: Thu, 6 Jun 2019 20:28:05 +0100 Subject: [PATCH 03/18] ignore VS folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 960a6f8..59c8ca7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build release-packaging/Plugins release-packaging/AudioFiles *.scx +.vs/ From 58c1ea682a7bcdc232eee6e10c2c2d6b4f528582 Mon Sep 17 00:00:00 2001 From: weefuzzy Date: Thu, 6 Jun 2019 20:28:52 +0100 Subject: [PATCH 04/18] Uh, ok. Not sure why 'template' was there to start with. Fair cop MSVC --- include/FluidSCWrapper.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index f93aa09..ee631ac 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -129,7 +129,7 @@ public: { mControlsIterator.reset(mInBuf + 1); //mClient.audioChannelsIn()); Wrapper::setParams(mParams, mWorld->mVerbosity > 0, mWorld, mControlsIterator); // forward on inputs N + audio inputs as params - mParams.template constrainParameterValues(); + mParams.constrainParameterValues(); const Unit *unit = this; for (size_t i = 0; i < mClient.audioChannelsIn(); ++i) { @@ -218,7 +218,7 @@ private: static Result validateParameters(NonRealTime *w) { - auto results = w->mParams.template constrainParameterValues(); + auto results = w->mParams.constrainParameterValues(); for (auto &r : results) { if (!r.ok()) return r; @@ -397,7 +397,7 @@ public: if(inputs.size() == C::getParameterDescriptors().count()) { p.template setParameterValues(verbose, world, inputs); - if (constrain)p.template constrainParameterValues(); + if (constrain)p.constrainParameterValues(); } return p; } From 17ee67719711980ab9943314df08e78146c48db6 Mon Sep 17 00:00:00 2001 From: weefuzzy Date: Thu, 6 Jun 2019 20:30:01 +0100 Subject: [PATCH 05/18] Acheivable warning level, AVX in release --- CMakeLists.txt | 8 +++++++- scripts/target_post.cmake | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6c4b9d..7b8e648 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,9 +68,15 @@ add_library(FFTLIB STATIC ${FFT_SOURCES}) target_link_libraries( FFTLIB PRIVATE ${FFT_LINK} ) +if(WIN32) target_compile_options( - FFTLIB PRIVATE $<$>:-mavx -msse -msse2 -msse3 -msse4> + FFTLIB PRIVATE $<$>: /arch:AVX> ) +else(WIN32) +target_compile_options( + FFTLIB PRIVATE $<$>: -mavx -msse -msse2 -msse3 -msse4> +) +endif(WIN32) add_library(FLUID_SC_WRAPPER INTERFACE) target_sources(FLUID_SC_WRAPPER diff --git a/scripts/target_post.cmake b/scripts/target_post.cmake index c5cc0e2..36859c8 100644 --- a/scripts/target_post.cmake +++ b/scripts/target_post.cmake @@ -1,6 +1,8 @@ +target_compile_features(${PLUGIN} PUBLIC cxx_std_14) + if(MSVC) - target_compile_options(${PLUGIN} PRIVATE /W4 /WX) + target_compile_options(${PLUGIN} PRIVATE /W4) else() target_compile_options(${PLUGIN} PRIVATE -Wall -Wextra -Wpedantic -Wreturn-type -Wconversion) endif() @@ -74,7 +76,11 @@ endif() if(MSVC) target_compile_options(${PLUGIN} PRIVATE /arch:AVX -D_USE_MATH_DEFINES) -endif() +else(MSVC) +target_compile_options( + ${PLUGIN} PRIVATE $<$>: -mavx -msse -msse2 -msse3 -msse4> +) +endif(MSVC) ####### added the fluid_decomposition From 04d066ee3df73c55b9e00308ad36aa51f6222e06 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 11 Jun 2019 18:02:30 -0400 Subject: [PATCH 06/18] (Buf)Pitch new class definition with extra 3 params (minFreq maxFreq unit) and help --- release-packaging/Classes/FluidBufPitch.sc | 4 ++-- release-packaging/Classes/FluidPitch.sc | 4 ++-- .../HelpSource/Classes/FluidBufPitch.schelp | 13 +++++++++++-- .../HelpSource/Classes/FluidNMFFilter.schelp | 2 +- .../HelpSource/Classes/FluidPitch.schelp | 9 +++++++++ 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/release-packaging/Classes/FluidBufPitch.sc b/release-packaging/Classes/FluidBufPitch.sc index d0ad4ce..9bff1f8 100644 --- a/release-packaging/Classes/FluidBufPitch.sc +++ b/release-packaging/Classes/FluidBufPitch.sc @@ -1,5 +1,5 @@ FluidBufPitch{ - *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, windowSize = 1024, hopSize = -1, fftSize = -1, action; + *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -15,7 +15,7 @@ FluidBufPitch{ //whatever has been passed in language-side (e.g maxFFTSize still exists as a parameter for the server plugin, but makes less sense here: it just needs to be set to a legal value) forkIfNeeded{ - server.sendMsg(\cmd, \BufPitch, source, startFrame, numFrames, startChan, numChans, features, algorithm, windowSize, hopSize, fftSize, maxFFTSize); + server.sendMsg(\cmd, \BufPitch, source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize); server.sync; features = server.cachedBufferAt(features); features.updateInfo; server.sync; action.value(features); diff --git a/release-packaging/Classes/FluidPitch.sc b/release-packaging/Classes/FluidPitch.sc index 66bdfb9..b56eba7 100644 --- a/release-packaging/Classes/FluidPitch.sc +++ b/release-packaging/Classes/FluidPitch.sc @@ -1,7 +1,7 @@ FluidPitch : MultiOutUGen { - *kr { arg in = 0, algorithm = 2, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; - ^this.multiNew('control', in.asAudioRateInput(this), algorithm, windowSize, hopSize, fftSize, maxFFTSize); + *kr { arg in = 0, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; + ^this.multiNew('control', in.asAudioRateInput(this), algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize); } init {arg ...theInputs; diff --git a/release-packaging/HelpSource/Classes/FluidBufPitch.schelp b/release-packaging/HelpSource/Classes/FluidBufPitch.schelp index accd403..bf630c2 100644 --- a/release-packaging/HelpSource/Classes/FluidBufPitch.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufPitch.schelp @@ -43,6 +43,15 @@ ARGUMENT:: algorithm ## 2 || YinFFT: Implements the frequency domain version of the YIN algorithm, as described in FOOTNOTE::P. M. Brossier, "Automatic Annotation of Musical Audio for Interactive Applications.” QMUL, London, UK, 2007. :: See also https://essentia.upf.edu/documentation/reference/streaming_PitchYinFFT.html :: +ARGUMENT:: minFreq +The minimum frequency that the algorithm will search for an estimated fundamental. This sets the lowest value that will be generated. + +ARGUMENT:: maxFreq +The maximum frequency that the algorithm will search for an estimated fundamental. This sets the highest value that will be generated. + +ARGUMENT:: unit +The unit of the estimated value. The default of 0 is in Hz. A value of 1 will convert to MIDI note values. + ARGUMENT:: windowSize The window size. As sinusoidal estimation relies on spectral frames, we need to decide what precision we give it spectrally and temporally, in line with Gabor Uncertainty principles. http://www.subsurfwiki.org/wiki/Gabor_uncertainty @@ -105,11 +114,11 @@ b.play // create a buffer as destinations c = Buffer.new(s); -//run the process on them +//run the process on them, with limited bandwidth and units in MIDI notes ( Routine{ t = Main.elapsedTime; - FluidBufPitch.process(s, b, features: c); + FluidBufPitch.process(s, b, features: c, minFreq:200, maxFreq:2000, unit:1); (Main.elapsedTime - t).postln; }.play ) diff --git a/release-packaging/HelpSource/Classes/FluidNMFFilter.schelp b/release-packaging/HelpSource/Classes/FluidNMFFilter.schelp index 0493d38..36e181e 100644 --- a/release-packaging/HelpSource/Classes/FluidNMFFilter.schelp +++ b/release-packaging/HelpSource/Classes/FluidNMFFilter.schelp @@ -224,5 +224,5 @@ FluidBufNMF.process(s, d, bases:g, windowSize:2048, components:3); f.set(\bases, g.bufnum) //free -f.free; e.free; +f.free; e.free; b.free; c.free; d.free; g.free; :: diff --git a/release-packaging/HelpSource/Classes/FluidPitch.schelp b/release-packaging/HelpSource/Classes/FluidPitch.schelp index af6a0f1..f8cb7e6 100644 --- a/release-packaging/HelpSource/Classes/FluidPitch.schelp +++ b/release-packaging/HelpSource/Classes/FluidPitch.schelp @@ -24,6 +24,15 @@ ARGUMENT:: algorithm ## 2 || YinFFT: Implements the frequency domain version of the YIN algorithm, as described in FOOTNOTE::P. M. Brossier, "Automatic Annotation of Musical Audio for Interactive Applications.” QMUL, London, UK, 2007. :: See also https://essentia.upf.edu/documentation/reference/streaming_PitchYinFFT.html :: +ARGUMENT:: minFreq +The minimum frequency that the algorithm will search for an estimated fundamental. This sets the lowest value that will be generated. + +ARGUMENT:: maxFreq +The maximum frequency that the algorithm will search for an estimated fundamental. This sets the highest value that will be generated. + +ARGUMENT:: unit +The unit of the estimated value. The default of 0 is in Hz. A value of 1 will convert to MIDI note values. + ARGUMENT:: windowSize The window size. As sinusoidal estimation relies on spectral frames, we need to decide what precision we give it spectrally and temporally, in line with Gabor Uncertainty principles. http://www.subsurfwiki.org/wiki/Gabor_uncertainty From b7093de5b24e7e2830e3116cf1a39a4d776c5aa1 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Wed, 12 Jun 2019 10:54:21 +0100 Subject: [PATCH 07/18] SCWrapper: newline at end of console messages, ensures that they actually appear. --- include/FluidSCWrapper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index ee631ac..56b32f3 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -232,7 +232,7 @@ private: if (!r.ok()) { - std::cout << "ERROR: " << Wrapper::getName() << ": " << r.message().c_str(); + std::cout << "ERROR: " << Wrapper::getName() << ": " << r.message().c_str() << '\n'; return false; } From ab6103d984e547d11986d6f4d03f5e0e70504eca Mon Sep 17 00:00:00 2001 From: Owen Green Date: Wed, 12 Jun 2019 13:46:48 +0100 Subject: [PATCH 08/18] Don't run next(1) when we register calc function, clear outputs instead (otherwise we read into arbitary memory). Resolves #25 hopefully --- include/FluidSCWrapper.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 56b32f3..4bed7f7 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -117,8 +117,8 @@ public: for (int i = 0; i < static_cast(mClient.controlChannelsOut()); ++i) { mOutputs.emplace_back(nullptr, 0, 0); } - - set_calc_function(); + mCalcFunc = make_calc_function(); +// set_calc_function(); Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1); From 050c80286f8bf18949816f0904b95ba7a1fcf748 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 12 Jun 2019 15:28:09 -0400 Subject: [PATCH 09/18] examples: folder iteration and 2 passes now working fine --- .../buffer_compositing/fileiterator-2passes.sc | 10 +++++----- .../ignore/Examples/buffer_compositing/fileiterator.sc | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/release-packaging/ignore/Examples/buffer_compositing/fileiterator-2passes.sc b/release-packaging/ignore/Examples/buffer_compositing/fileiterator-2passes.sc index 79c2ecb..4eaa92c 100644 --- a/release-packaging/ignore/Examples/buffer_compositing/fileiterator-2passes.sc +++ b/release-packaging/ignore/Examples/buffer_compositing/fileiterator-2passes.sc @@ -2,7 +2,7 @@ ( var fileNames; -c = [0]; +c = []; FileDialog.new({|selection| var total, totaldur = 0, maxchans = 0; @@ -16,14 +16,11 @@ FileDialog.new({|selection| SoundFile.use(fp.asAbsolutePath , { arg file; var dur = file.numFrames; - c = c.add(dur); + c = c.add(totaldur); totaldur = totaldur + dur; maxchans = maxchans.max(file.numChannels); }); }); - c.postln; - totaldur.postln; - maxchans.postln; Routine{ b = Buffer.alloc(s,totaldur,maxchans); s.sync; @@ -42,4 +39,7 @@ b.plot c.postln b.play + +{PlayBuf.ar(1,b.bufnum,startPos:c[740])}.play + Buffer.freeAll \ No newline at end of file diff --git a/release-packaging/ignore/Examples/buffer_compositing/fileiterator.sc b/release-packaging/ignore/Examples/buffer_compositing/fileiterator.sc index e8ef47f..9808f72 100644 --- a/release-packaging/ignore/Examples/buffer_compositing/fileiterator.sc +++ b/release-packaging/ignore/Examples/buffer_compositing/fileiterator.sc @@ -36,3 +36,5 @@ FileDialog.new({|selection| b.plot c.postln b.play + +{PlayBuf.ar(1,b.bufnum,startPos:c[740])}.play From b1c56d03254ab013fa6a258a23305a8f8692216a Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 12 Jun 2019 16:10:42 -0400 Subject: [PATCH 10/18] new MFCC example (and corrected MelBands) thanks to Sam Pluta --- .../HelpSource/Classes/FluidMFCC.schelp | 174 ++++++++++++++++-- .../HelpSource/Classes/FluidMelBands.schelp | 26 +-- 2 files changed, 178 insertions(+), 22 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidMFCC.schelp b/release-packaging/HelpSource/Classes/FluidMFCC.schelp index 8bedc57..0f877ee 100644 --- a/release-packaging/HelpSource/Classes/FluidMFCC.schelp +++ b/release-packaging/HelpSource/Classes/FluidMFCC.schelp @@ -50,24 +50,27 @@ RETURNS:: EXAMPLES:: code:: -//create a monitoring bus for the descriptors -b = Bus.new(\control,0,13); - //create a monitoring window for the values ( +b = Bus.new(\control,0,13); w = Window("MFCCs Monitor", Rect(10, 10, 420, 320)).front; a = MultiSliderView(w,Rect(10, 10, 400, 300)).elasticMode_(1).isFilled_(1); +a.reference_(Array.fill(13,{0.5})); //make a center line to show 0 ) //run the window updating routine. ( + +~winRange = 500; + r = Routine { { b.get({ arg val; { if(w.isClosed.not) { - a.value = val; + //val.postln; + a.value = val.linlin(~winRange.neg,~winRange,0,1); } }.defer }); @@ -78,8 +81,8 @@ r = Routine { //play a simple sound to observe the values ( -x = {arg type = 0; - var source = Select.ar(type,[SinOsc.ar(220),Saw.ar(220),Pulse.ar(220)]) * LFTri.kr(0.1).exprange(0.01,0.1); +x = {arg type = 0; + var source = Select.ar(type,[SinOsc.ar(220),Saw.ar(220),Pulse.ar(220)]) * LFTri.kr(0.1).exprange(0.01,0.1); Out.kr(b,FluidMFCC.kr(source,maxNumCoeffs:13)); source.dup; }.play; @@ -87,19 +90,20 @@ x = {arg type = 0; // change the wave types, observe the amplitude invariance of the descriptors, apart from the leftmost coefficient x.set(\type, 1) +~winRange = 100; //adjust the range above and below 0 to zoom in or out on the MFCC x.set(\type, 2) x.set(\type, 0) // free this source x.free // load a more exciting one -c = Buffer.read(s,File.realpath(FluidMelBands.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav"); +c = Buffer.read(s,File.realpath(FluidMFCC.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav"); // analyse with parameters to be changed ( -x = {arg bands = 40, low = 20, high = 20000; +x = {arg bands = 40, low = 20, high = 20000; var source = PlayBuf.ar(1,c,loop:1); - Out.kr(b,FluidMelBands.kr(source, bands, low, high, 40) / 10); + Out.kr(b,FluidMFCC.kr(source, 13, bands, low, high, 13) / 10); source.dup; }.play; ) @@ -111,7 +115,7 @@ x.set(\bands,20) x.set(\bands,40) // focus all the bands on a mid range -x.set(\low,320, \high, 8000) +x.set(\low,320, \high, 800) // focusing on the low end shows the fft resolution issue. One could restart the analysis with a larger fft to show more precision x.set(\low,20, \high, 160) @@ -126,5 +130,153 @@ x.free;b.free;c.free;r.stop; STRONG::A musical example:: CODE:: -// todo: port the Max one +//program that freezes mfcc spectra, then looks for matches between two frozen spectra +( +SynthDef("MFCCJamz", {arg freq=220, source = 0, buffer, mfccBus, distBus, t_freeze0=0, t_freeze1=0, onsetsOn0=0, onsetsOn1=0; + var sound, mfcc, mfccFreeze0, mfccFreeze1, dist0, dist1, closest, slice; + + sound = SelectX.ar(source, [ + SinOsc.ar(freq, 0, 0.1), + LFTri.ar(freq, 0, 0.1), + LFSaw.ar(freq, 0, 0.1), + Pulse.ar(freq, 0.5, 0.1), + WhiteNoise.ar(0.1), + PinkNoise.ar(0.1), + PlayBuf.ar(1, buffer, 1, loop:1) + ]); + + slice = FluidOnsetSlice.ar(sound); //onset detection for mfcc freeze on onset + + mfcc = FluidMFCC.kr(sound,maxNumCoeffs:13); + mfccFreeze0 = Latch.kr(mfcc, t_freeze0+(slice*onsetsOn0)); + mfccFreeze1 = Latch.kr(mfcc, t_freeze1+(slice*onsetsOn1)); + + Out.kr(mfccBus,mfcc.addAll(mfccFreeze0).addAll(mfccFreeze1)); + + //distance calculations + + dist0 = Mix((mfcc.copyRange(1,12) - mfccFreeze0.copyRange(1,12)).squared).sqrt; + dist1 = Mix((mfcc.copyRange(1,12) - mfccFreeze1.copyRange(1,12)).squared).sqrt; + + Out.kr(distBus, [dist0, dist1]); + + //sends a trigger when the item with a closer euclidean distance changes + SendTrig.kr(Trig1.kr(dist1-dist0, 0.001)+Trig1.kr(dist0-dist1, 0.001), 0, dist1 Date: Thu, 13 Jun 2019 11:21:56 -0400 Subject: [PATCH 11/18] name change for Onset functions to metrics --- release-packaging/Classes/FluidBufOnsetSlice.sc | 4 ++-- release-packaging/Classes/FluidOnsetSlice.sc | 4 ++-- .../HelpSource/Classes/FluidBufOnsetSlice.schelp | 12 ++++++------ .../HelpSource/Classes/FluidOnsetSlice.schelp | 10 +++++----- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/release-packaging/Classes/FluidBufOnsetSlice.sc b/release-packaging/Classes/FluidBufOnsetSlice.sc index d7bbcac..4e3304c 100644 --- a/release-packaging/Classes/FluidBufOnsetSlice.sc +++ b/release-packaging/Classes/FluidBufOnsetSlice.sc @@ -1,5 +1,5 @@ FluidBufOnsetSlice{ - *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, function = 0, threshold = 0.1, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action; + *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, action; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -15,7 +15,7 @@ FluidBufOnsetSlice{ //whatever has been passed in language-side (e.g maxFFTSize still exists as a parameter for the server plugin, but makes less sense here: it just needs to be set to a legal value) forkIfNeeded{ - server.sendMsg(\cmd, \BufOnsetSlice, source, startFrame, numFrames, startChan, numChans, indices, function, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize); + server.sendMsg(\cmd, \BufOnsetSlice, source, startFrame, numFrames, startChan, numChans, indices, metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize); server.sync; indices = server.cachedBufferAt(indices); indices.updateInfo; server.sync; action.value(indices); diff --git a/release-packaging/Classes/FluidOnsetSlice.sc b/release-packaging/Classes/FluidOnsetSlice.sc index 2bedb64..2ecbb51 100644 --- a/release-packaging/Classes/FluidOnsetSlice.sc +++ b/release-packaging/Classes/FluidOnsetSlice.sc @@ -1,6 +1,6 @@ FluidOnsetSlice : UGen { - *ar { arg in = 0, function = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; - ^this.multiNew('audio', in.asAudioRateInput(this), function, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize) + *ar { arg in = 0, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; + ^this.multiNew('audio', in.asAudioRateInput(this), metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize) } checkInputs { if(inputs.at(9).rate != 'scalar') { diff --git a/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp index ecd692f..09389f7 100644 --- a/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition DESCRIPTION:: -This class implements many spectral-based onset detection functions, most of them taken from the literature. (http://www.dafx.ca/proceedings/papers/p_133.pdf) Some are already available in SuperCollider's LINK::Classes/Onsets:: object yet not as offline processes. It is part of the Fluid Decomposition Toolkit of the FluCoMa project.footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899).:: +This class implements many spectral-based onset detection metrics, most of them taken from the literature. (http://www.dafx.ca/proceedings/papers/p_133.pdf) Some are already available in SuperCollider's LINK::Classes/Onsets:: object yet not as offline processes. It is part of the Fluid Decomposition Toolkit of the FluCoMa project.footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899).:: The process will return a buffer which contains indices (in sample) of estimated starting points of different slices. @@ -34,8 +34,8 @@ ARGUMENT:: numChans ARGUMENT:: indices The index of the buffer where the indices (in sample) of the estimated starting points of slices will be written. The first and last points are always the boundary points of the analysis. -ARGUMENT:: function - The function used to derive a difference curve between spectral frames. It can be any of the following: +ARGUMENT:: metric + The metric used to derive a difference curve between spectral frames. It can be any of the following: TABLE:: ##0 || Energy || thresholds on (sum of squares of magnitudes / nBins) (like Onsets \power) ##1 || HFC || thresholds on (sum of (squared magnitudes * binNum) / nBins) @@ -50,7 +50,7 @@ ARGUMENT:: function :: ARGUMENT:: threshold -The thresholding of a new slice. Value ranges are different for each function, from 0 upwards. +The thresholding of a new slice. Value ranges are different for each metric, from 0 upwards. ARGUMENT:: minSliceLength The minimum duration of a slice in number of hopSize. @@ -59,7 +59,7 @@ ARGUMENT:: filterSize The size of a smoothing filter that is applied on the novelty curve. A larger filter filter size allows for cleaner cuts on very sharp changes. ARGUMENT:: frameDelta - For certain functions (HFC, SpectralFlux, MKL, Cosine), the distance does not have to be computed between consecutive frames. By default (0) it is, otherwise this sets the distane between the comparison window in samples. + For certain metrics (HFC, SpectralFlux, MKL, Cosine), the distance does not have to be computed between consecutive frames. By default (0) it is, otherwise this sets the distane between the comparison window in samples. ARGUMENT:: windowSize The window size. As spectral differencing relies on spectral frames, we need to decide what precision we give it spectrally and temporally, in line with Gabor Uncertainty principles. http://www.subsurfwiki.org/wiki/Gabor_uncertainty @@ -71,7 +71,7 @@ ARGUMENT:: fftSize The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will default to windowSize. ARGUMENT:: action - A Function to be evaluated once the offline process has finished and indices instance variables have been updated on the client side. The function will be passed indices as an argument. + A Function to be evaluated once the offline process has finished and indices instance variables have been updated on the client side. The metric will be passed indices as an argument. RETURNS:: Nothing, as the various destination buffers are declared in the function call. diff --git a/release-packaging/HelpSource/Classes/FluidOnsetSlice.schelp b/release-packaging/HelpSource/Classes/FluidOnsetSlice.schelp index 449c05f..1918be3 100644 --- a/release-packaging/HelpSource/Classes/FluidOnsetSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidOnsetSlice.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition DESCRIPTION:: -This class implements many spectral based onset detection functions, most of them taken from the literature. (http://www.dafx.ca/proceedings/papers/p_133.pdf) Some are already available in SuperCollider's LINK::Classes/Onsets:: object. It is part of the Fluid Decomposition Toolkit of the FluCoMa project.footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899).:: +This class implements many spectral based onset detection metrics, most of them taken from the literature. (http://www.dafx.ca/proceedings/papers/p_133.pdf) Some are already available in SuperCollider's LINK::Classes/Onsets:: object. It is part of the Fluid Decomposition Toolkit of the FluCoMa project.footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899).:: The process will return an audio steam with sample-long impulses at estimated starting points of the different slices. @@ -17,8 +17,8 @@ METHOD:: ar ARGUMENT:: in The audio to be processed. -ARGUMENT:: function - The function used to derive a difference curve between spectral frames. It can be any of the following: +ARGUMENT:: metric + The metric used to derive a difference curve between spectral frames. It can be any of the following: TABLE:: ##0 || Energy || thresholds on (sum of squares of magnitudes / nBins) (like Onsets \power) ##1 || HFC || thresholds on (sum of (squared magnitudes * binNum) / nBins) @@ -33,7 +33,7 @@ ARGUMENT:: function :: ARGUMENT:: threshold -The thresholding of a new slice. Value ranges are different for each function, from 0 upwards. +The thresholding of a new slice. Value ranges are different for each metric, from 0 upwards. ARGUMENT:: minSliceLength The minimum duration of a slice in number of hopSize. @@ -42,7 +42,7 @@ ARGUMENT:: filterSize The size of a smoothing filter that is applied on the novelty curve. A larger filter filter size allows for cleaner cuts on very sharp changes. ARGUMENT:: frameDelta - For certain functions (HFC, SpectralFlux, MKL, Cosine), the distance does not have to be computed between consecutive frames. By default (0) it is, otherwise this sets the distane between the comparison window in samples. + For certain metrics (HFC, SpectralFlux, MKL, Cosine), the distance does not have to be computed between consecutive frames. By default (0) it is, otherwise this sets the distane between the comparison window in samples. ARGUMENT:: windowSize The window size. As sinusoidal estimation relies on spectral frames, we need to decide what precision we give it spectrally and temporally, in line with Gabor Uncertainty principles. http://www.subsurfwiki.org/wiki/Gabor_uncertainty From f95cbe1b2c530612aae28fd228ae2482a1c2adfa Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Thu, 13 Jun 2019 12:12:28 -0400 Subject: [PATCH 12/18] (buf)sines: amended the description to make the fftSize capping behaviour clear. --- release-packaging/HelpSource/Classes/FluidBufSines.schelp | 4 ++-- release-packaging/HelpSource/Classes/FluidSines.schelp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidBufSines.schelp b/release-packaging/HelpSource/Classes/FluidBufSines.schelp index c283211..e0e767c 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSines.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSines.schelp @@ -43,7 +43,7 @@ ARGUMENT:: residual The index of the buffer where the residual of the sinusoidal component will be reconstructed. ARGUMENT:: bandwidth - The width in bins of the fragment of the fft window that is considered a normal deviation for a potential continuous sinusoidal track. It has an effect on CPU cost: the widest is more accurate but more computationally expensive. + The width in bins of the fragment of the fft window that is considered a normal deviation for a potential continuous sinusoidal track. It has an effect on CPU cost: the widest is more accurate but more computationally expensive. It is capped at (fftSize / 2) + 1. ARGUMENT:: threshold The normalised threshold, between 0 an 1, to consider a peak as a sinusoidal component from the normalized cross-correlation. @@ -64,7 +64,7 @@ ARGUMENT:: hopSize The window hop size. As sinusoidal estimation relies on spectral frames, we need to move the window forward. It can be any size but low overlap will create audible artefacts. ARGUMENT:: fftSize - The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. + The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will default to the highest of windowSize and (bandwidth - 1) * 2. ARGUMENT:: action A Function to be evaluated once the offline process has finished and all Buffer's instance variables have been updated on the client side. The function will be passed [sines, residual] as an argument. diff --git a/release-packaging/HelpSource/Classes/FluidSines.schelp b/release-packaging/HelpSource/Classes/FluidSines.schelp index fd6152f..f4b9a41 100644 --- a/release-packaging/HelpSource/Classes/FluidSines.schelp +++ b/release-packaging/HelpSource/Classes/FluidSines.schelp @@ -22,7 +22,7 @@ ARGUMENT:: in The input to be processed ARGUMENT:: bandwidth - The width in bins of the fragment of the fft window that is considered a normal deviation for a potential continuous sinusoidal track. It has an effect on CPU cost: the widest is more accurate but more computationally expensive. + The width in bins of the fragment of the fft window that is considered a normal deviation for a potential continuous sinusoidal track. It has an effect on CPU cost: the widest is more accurate but more computationally expensive. It is capped at (fftSize / 2) + 1. ARGUMENT:: threshold The normalised threshold, between 0 an 1, to consider a peak as a sinusoidal component from the normalized cross-correlation. @@ -43,7 +43,7 @@ ARGUMENT:: hopSize The window hop size. As sinusoidal estimation relies on spectral frames, we need to move the window forward. It can be any size but low overlap will create audible artefacts. The -1 default value will default to half of windowSize (overlap of 2). ARGUMENT:: fftSize - The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will default to windowSize. + The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will default to the highest of windowSize and (bandwidth - 1) * 2. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. From bf7ab1680ccab7a231a614fef98338a053272f99 Mon Sep 17 00:00:00 2001 From: Gerard Date: Thu, 13 Jun 2019 14:57:38 -0400 Subject: [PATCH 13/18] Rename RTNoveltySlice to NoveltySlice --- src/FluidBufNoveltySlice/CMakeLists.txt | 0 .../FluidBufNoveltySlice.cpp | 13 ++-- src/FluidBufNoveltySlice/tests.scd | 72 ------------------- .../FluidBufRTNoveltySlice.cpp | 14 ---- .../CMakeLists.txt | 0 .../FluidNoveltySlice.cpp} | 4 +- src/FluidRTNoveltySlice/CMakeLists.txt | 20 ------ 7 files changed, 8 insertions(+), 115 deletions(-) mode change 100755 => 100644 src/FluidBufNoveltySlice/CMakeLists.txt delete mode 100644 src/FluidBufNoveltySlice/tests.scd delete mode 100644 src/FluidBufRTNoveltySlice/FluidBufRTNoveltySlice.cpp rename src/{FluidBufRTNoveltySlice => FluidNoveltySlice}/CMakeLists.txt (100%) rename src/{FluidRTNoveltySlice/FluidRTNoveltySlice.cpp => FluidNoveltySlice/FluidNoveltySlice.cpp} (76%) delete mode 100644 src/FluidRTNoveltySlice/CMakeLists.txt diff --git a/src/FluidBufNoveltySlice/CMakeLists.txt b/src/FluidBufNoveltySlice/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp b/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp index 443f28b..52a4054 100644 --- a/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp +++ b/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp @@ -1,15 +1,14 @@ - // FD_BufNMF, an NRT buffer NMF Processor -// A tool from the FluCoMa project, funded by the European Research Council (ERC) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899) +// A tool from the FluCoMa project, funded by the European Research Council (ERC) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899) -#include +#include +#include #include -static InterfaceTable* ft; +static InterfaceTable *ft; -PluginLoad(OfflineFluidDecompositionUGens) -{ +PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("BufNoveltySlice", ft); + makeSCWrapper("BufNoveltySlice", ft); } diff --git a/src/FluidBufNoveltySlice/tests.scd b/src/FluidBufNoveltySlice/tests.scd deleted file mode 100644 index 28e7936..0000000 --- a/src/FluidBufNoveltySlice/tests.scd +++ /dev/null @@ -1,72 +0,0 @@ -s.reboot -//////////////////////////// -// test for efficiency - -( -b = Buffer.read(s,"../../release-packaging/AudioFiles/Tremblay-AaS-AcousticStrums-M.wav".resolveRelative); -c = Buffer.new(s); -) - -( -// with basic params -Routine{ - t = Main.elapsedTime; - FluidBufNoveltySlice.process(s,b.bufnum, transBufNum: c.bufnum, thresh:0.6); - s.sync; - (Main.elapsedTime - t).postln; -}.play -); - -//check the number of slices -c.query; -c.getn(0,34,{|x|x.postln}) - -//loops over a splice -( -{ - BufRd.ar( - 1, - b.bufnum, - Phasor.ar( - 0, - 1, - BufRd.kr( - 1, - c.bufnum, - MouseX.kr( - 0, - BufFrames.kr(c.bufnum) - 1), - 0, - 1), - BufRd.kr( - 1, - c.bufnum, - MouseX.kr( - 1, - BufFrames.kr(c.bufnum)), - 0, - 1), - BufRd.kr( - 1, - c.bufnum, - MouseX.kr( - 0, - BufFrames.kr(c.bufnum) - 1), - 0, - 1)), - 0, - 1) -}.play; -) - - -// with everything changed to make it much faster -( -Routine{ - t = Main.elapsedTime; - FluidBufNoveltySlice.process(s,b.bufnum, 44100, 44100, 0, 0, c.bufnum, d.bufnum, 100, 512,256,1,2,1,12,20);//needs something else - s.sync; - (Main.elapsedTime - t).postln; -}.play -); - diff --git a/src/FluidBufRTNoveltySlice/FluidBufRTNoveltySlice.cpp b/src/FluidBufRTNoveltySlice/FluidBufRTNoveltySlice.cpp deleted file mode 100644 index c637663..0000000 --- a/src/FluidBufRTNoveltySlice/FluidBufRTNoveltySlice.cpp +++ /dev/null @@ -1,14 +0,0 @@ - -// A tool from the FluCoMa project, funded by the European Research Council (ERC) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899) - -#include -#include -#include - -static InterfaceTable *ft; - -PluginLoad(OfflineFluidDecompositionUGens) { - ft = inTable; - using namespace fluid::client; - makeSCWrapper("BufRTNoveltySlice", ft); -} diff --git a/src/FluidBufRTNoveltySlice/CMakeLists.txt b/src/FluidNoveltySlice/CMakeLists.txt similarity index 100% rename from src/FluidBufRTNoveltySlice/CMakeLists.txt rename to src/FluidNoveltySlice/CMakeLists.txt diff --git a/src/FluidRTNoveltySlice/FluidRTNoveltySlice.cpp b/src/FluidNoveltySlice/FluidNoveltySlice.cpp similarity index 76% rename from src/FluidRTNoveltySlice/FluidRTNoveltySlice.cpp rename to src/FluidNoveltySlice/FluidNoveltySlice.cpp index 8e23423..b2f5103 100644 --- a/src/FluidRTNoveltySlice/FluidRTNoveltySlice.cpp +++ b/src/FluidNoveltySlice/FluidNoveltySlice.cpp @@ -1,7 +1,7 @@ // A tool from the FluCoMa project, funded by the European Research Council (ERC) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899) -#include +#include #include static InterfaceTable *ft; @@ -9,5 +9,5 @@ static InterfaceTable *ft; PluginLoad(FluidSTFTUGen) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidRTNoveltySlice", ft); + makeSCWrapper("FluidNoveltySlice", ft); } diff --git a/src/FluidRTNoveltySlice/CMakeLists.txt b/src/FluidRTNoveltySlice/CMakeLists.txt deleted file mode 100644 index 3693881..0000000 --- a/src/FluidRTNoveltySlice/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -cmake_minimum_required(VERSION 3.3) -get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) -message("Configuring ${PLUGIN}") -set(FILENAME ${PLUGIN}.cpp) - -add_library( - ${PLUGIN} - MODULE - ${FILENAME} -) - -target_include_directories( - ${PLUGIN} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../../include -) - -target_link_libraries( - ${PLUGIN} PRIVATE FLUID_DECOMPOSITION -) - -include(${CMAKE_CURRENT_LIST_DIR}/../../scripts/target_post.cmake) From 5af767a6e4773c7d080eb6ad795e928cfbd6368f Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Thu, 13 Jun 2019 15:38:19 -0400 Subject: [PATCH 14/18] (buf)noveltyslice: change to all interface merging --- .../Classes/FluidBufNoveltySlice.sc | 6 +- .../Classes/FluidBufRTNoveltySlice.sc | 21 --- ...RTNoveltySlice.sc => FluidNoveltySlice.sc} | 2 +- .../Classes/FluidBufNoveltySlice.schelp | 18 +- .../Classes/FluidBufRTNoveltySlice.schelp | 169 ------------------ ...ySlice.schelp => FluidNoveltySlice.schelp} | 2 +- 6 files changed, 18 insertions(+), 200 deletions(-) delete mode 100644 release-packaging/Classes/FluidBufRTNoveltySlice.sc rename release-packaging/Classes/{FluidRTNoveltySlice.sc => FluidNoveltySlice.sc} (95%) delete mode 100644 release-packaging/HelpSource/Classes/FluidBufRTNoveltySlice.schelp rename release-packaging/HelpSource/Classes/{FluidRTNoveltySlice.schelp => FluidNoveltySlice.schelp} (99%) diff --git a/release-packaging/Classes/FluidBufNoveltySlice.sc b/release-packaging/Classes/FluidBufNoveltySlice.sc index e55af95..2abf929 100644 --- a/release-packaging/Classes/FluidBufNoveltySlice.sc +++ b/release-packaging/Classes/FluidBufNoveltySlice.sc @@ -1,7 +1,7 @@ FluidBufNoveltySlice{ - *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, kernelSize = 3, threshold = 0.8, filterSize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, action; + *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, feature = 0, kernelSize = 3, threshold = 0.5, filterSize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, action; - //var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; //ready for when we need it from the RT wrapper + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; indices = indices.asUGenInput; @@ -12,7 +12,7 @@ FluidBufNoveltySlice{ server = server ? Server.default; forkIfNeeded{ - server.sendMsg(\cmd, \BufNoveltySlice, source, startFrame, numFrames, startChan, numChans, indices, kernelSize, threshold, filterSize, windowSize, hopSize, fftSize); + server.sendMsg(\cmd, \BufNoveltySlice, source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize); server.sync; indices = server.cachedBufferAt(indices); indices.updateInfo; server.sync; action.value(indices); diff --git a/release-packaging/Classes/FluidBufRTNoveltySlice.sc b/release-packaging/Classes/FluidBufRTNoveltySlice.sc deleted file mode 100644 index 5741f15..0000000 --- a/release-packaging/Classes/FluidBufRTNoveltySlice.sc +++ /dev/null @@ -1,21 +0,0 @@ -FluidBufRTNoveltySlice{ - *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, feature = 0, kernelSize = 3, threshold = 0.8, filterSize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, action; - - var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; - - source = source.asUGenInput; - indices = indices.asUGenInput; - - source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw}; - indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw}; - - server = server ? Server.default; - - forkIfNeeded{ - server.sendMsg(\cmd, \BufRTNoveltySlice, source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize); - server.sync; - indices = server.cachedBufferAt(indices); indices.updateInfo; server.sync; - action.value(indices); - }; - } -} diff --git a/release-packaging/Classes/FluidRTNoveltySlice.sc b/release-packaging/Classes/FluidNoveltySlice.sc similarity index 95% rename from release-packaging/Classes/FluidRTNoveltySlice.sc rename to release-packaging/Classes/FluidNoveltySlice.sc index 813d15a..80d57ca 100644 --- a/release-packaging/Classes/FluidRTNoveltySlice.sc +++ b/release-packaging/Classes/FluidNoveltySlice.sc @@ -1,4 +1,4 @@ -FluidRTNoveltySlice : UGen { +FluidNoveltySlice : UGen { *ar { arg in = 0, feature = 0, kernelSize = 3, threshold = 0.8, filterSize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384, maxKernelSize = 101, maxFilterSize = 100; ^this.multiNew('audio', in.asAudioRateInput(this), feature, kernelSize, threshold, filterSize, windowSize, hopSize, fftSize, maxFFTSize, maxKernelSize, maxFilterSize) } diff --git a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp index 92d3842..f649e13 100644 --- a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp @@ -36,6 +36,14 @@ ARGUMENT:: numChans ARGUMENT:: indices The index of the buffer where the indices (in sample) of the estimated starting points of slices will be written. The first and last points are always the boundary points of the analysis. +ARGUMENT:: feature + The feature on which novelty is computed. + table:: + ##0 || Spectrum || todo + ##1 || MFCC || todo + ##2 || Pitch || todo + ##3 || Loudness || todo +:: ARGUMENT:: kernelSize The granularity of the window in which the algorithm looks for change, in samples. A small number will be sensitive to short term changes, and a large number should look for long term changes. @@ -74,7 +82,7 @@ c = Buffer.new(s); // with basic params Routine{ t = Main.elapsedTime; - FluidBufNoveltySlice.process(s,b, indices: c, threshold:0.6); + FluidBufNoveltySlice.process(s,b, indices: c, threshold:0.45); (Main.elapsedTime - t).postln; }.play ) @@ -107,7 +115,7 @@ c = Buffer.new(s); ) // process with a given filterSize -FluidBufNoveltySlice.process(s,b, indices: c, kernelSize:31, threshold:0.3, filterSize:0) +FluidBufNoveltySlice.process(s,b, indices: c, kernelSize:31, threshold:0.1, filterSize:1) //check the number of slices: it is the number of frames in the transBuf minus the boundary index. c.query; @@ -124,13 +132,13 @@ c.query; }.play; ) -// change the filterSize in the code above to 4. Then to 8. Listen in between to the differences. +// change the filterSize in the code above to 4. Then to 12. Listen in between to the differences. // What's happening? In the first instance (filterSize = 1), the novelty line is jittery and therefore overtriggers on the arpegiated guitar. We also can hear attacks at the end of the segment. Setting the threshold higher (like in the 'Basic Example' pane) misses some more subtle variations. // So in the second settings (filterSize = 4), we smooth the novelty line a little, which allows us to catch small differences that are not jittery. It also corrects the ending cutting by the same trick: the averaging of the sharp pick is sliding up, crossing the threshold slightly earlier. -// If we smooth too much, like the third settings (filterSize = 8), we start to loose precision. Have fun with different values of theshold then will allow you to find the perfect segment for your signal. +// If we smooth too much, like the third settings (filterSize = 12), we start to loose precision and miss attacks. Have fun with different values of theshold then will allow you to find the perfect segment for your signal. :: STRONG::A stereo buffer example.:: @@ -151,7 +159,7 @@ c = Buffer.new(s); // with basic params Routine{ t = Main.elapsedTime; - FluidBufNoveltySlice.process(s,b, indices: c, threshold:0.6); + FluidBufNoveltySlice.process(s,b, indices: c, threshold:0.3); (Main.elapsedTime - t).postln; }.play ) diff --git a/release-packaging/HelpSource/Classes/FluidBufRTNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidBufRTNoveltySlice.schelp deleted file mode 100644 index e90651f..0000000 --- a/release-packaging/HelpSource/Classes/FluidBufRTNoveltySlice.schelp +++ /dev/null @@ -1,169 +0,0 @@ -TITLE:: FluidBufRTNoveltySlice -SUMMARY:: Buffer-Based Novelty-Based Slicer -CATEGORIES:: Libraries>FluidDecomposition, UGens>Buffer -RELATED:: Guides/FluCoMa, Guides/FluidDecomposition - - -DESCRIPTION:: -This class implements a non-real-time slicer using an algorithm assessing novelty in the signal to estimate the slicing points. A novelty curve is being derived from running a kernel across the diagonal of the similarity matrix, and looking for peak of changes. It implements the seminal results published in 'Automatic Audio Segmentation Using a Measure of Audio Novelty' by J Foote. It is part of the Fluid Decomposition Toolkit of the FluCoMa project. footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899).:: - - The process will return a buffer which contains indices (in sample) of estimated starting points of different slices. - - -CLASSMETHODS:: - -METHOD:: process -This is the method that calls for the slicing to be calculated on a given source buffer. - -ARGUMENT:: server - The server on which the buffers to be processed are allocated. - -ARGUMENT:: source - The index of the buffer to use as the source material to be sliced through novelty identification. The different channels of multichannel buffers will be summed. - -ARGUMENT:: startFrame - Where in the srcBuf should the slicing process start, in sample. - -ARGUMENT:: numFrames - How many frames should be processed. - -ARGUMENT:: startChan - For multichannel srcBuf, which channel should be processed. - -ARGUMENT:: numChans - For multichannel srcBuf, how many channel should be summed. - -ARGUMENT:: indices - The index of the buffer where the indices (in sample) of the estimated starting points of slices will be written. The first and last points are always the boundary points of the analysis. - -ARGUMENT:: feature - The feature on which novelty is computed. - table:: - ##0 || Spectrum || todo - ##1 || MFCC || todo - ##2 || Pitch || todo - ##3 || Loudness || todo -:: -ARGUMENT:: kernelSize - The granularity of the window in which the algorithm looks for change, in samples. A small number will be sensitive to short term changes, and a large number should look for long term changes. - -ARGUMENT:: threshold - The normalised threshold, between 0 an 1, on the novelty curve to consider it a segmentation point. - -ARGUMENT:: filterSize - The size of a smoothing filter that is applied on the novelty curve. A larger filter filter size allows for cleaner cuts on very sharp changes. - -ARGUMENT:: windowSize - The window size. As novelty estimation relies on spectral frames, we need to decide what precision we give it spectrally and temporally, in line with Gabor Uncertainty principles. http://www.subsurfwiki.org/wiki/Gabor_uncertainty - -ARGUMENT:: hopSize - The window hop size. As novelty estimation relies on spectral frames, we need to move the window forward. It can be any size but low overlap will create audible artefacts. - -ARGUMENT:: fftSize - The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. - -ARGUMENT:: action - A Function to be evaluated once the offline process has finished and indices instance variables have been updated on the client side. The function will be passed indices as an argument. - -RETURNS:: - Nothing, as the various destination buffers are declared in the function call. - - -EXAMPLES:: - -code:: -// load some buffers -( -b = Buffer.read(s,File.realpath(FluidBufRTNoveltySlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav"); -c = Buffer.new(s); -) - -( -// with basic params -Routine{ - t = Main.elapsedTime; - FluidBufRTNoveltySlice.process(s,b, indices: c, threshold:0.6); - (Main.elapsedTime - t).postln; -}.play -) - -//check the number of slices: it is the number of frames in the transBuf minus the boundary index. -c.query; - -//loops over a splice with the MouseX -( -{ - BufRd.ar(1, b, - Phasor.ar(0,1, - BufRd.kr(1, c, - MouseX.kr(0, BufFrames.kr(c) - 1), 0, 1), - BufRd.kr(1, c, - MouseX.kr(1, BufFrames.kr(c)), 0, 1), - BufRd.kr(1,c, - MouseX.kr(0, BufFrames.kr(c) - 1), 0, 1)), 0, 1); - }.play; -) - :: - -STRONG::Examples of the impact of the filterSize:: - - CODE:: -// load some buffers -( -b = Buffer.read(s,File.realpath(FluidBufRTNoveltySlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav"); -c = Buffer.new(s); -) - -// process with a given filterSize -FluidBufRTNoveltySlice.process(s,b, indices: c, kernSize:31, threshold:0.3, filterSize:0) - -//check the number of slices: it is the number of frames in the transBuf minus the boundary index. -c.query; - -//play slice number 2 -( -{ - BufRd.ar(1, b, - Line.ar( - BufRd.kr(1, c, DC.kr(2), 0, 1), - BufRd.kr(1, c, DC.kr(3), 0, 1), - (BufRd.kr(1, c, DC.kr(3)) - BufRd.kr(1, c, DC.kr(2), 0, 1) + 1) / s.sampleRate), - 0,1); -}.play; -) - -// change the filterSize in the code above to 4. Then to 8. Listen in between to the differences. - -// What's happening? In the first instance (filterSize = 1), the novelty line is jittery and therefore overtriggers on the arpegiated guitar. We also can hear attacks at the end of the segment. Setting the threshold higher (like in the 'Basic Example' pane) misses some more subtle variations. - -// So in the second settings (filterSize = 4), we smooth the novelty line a little, which allows us to catch small differences that are not jittery. It also corrects the ending cutting by the same trick: the averaging of the sharp pick is sliding up, crossing the threshold slightly earlier. - -// If we smooth too much, like the third settings (filterSize = 8), we start to loose precision. Have fun with different values of theshold then will allow you to find the perfect segment for your signal. -:: - -STRONG::A stereo buffer example.:: -CODE:: - -// make a stereo buffer -b = Buffer.alloc(s,88200,2); - -// add some stereo clicks and listen to them -((0..3)*22050+11025).do({|item,index| b.set(item+(index%2), 1.0)}); -b.play - -// create a new buffer as destinations -c = Buffer.new(s); - -//run the process on them -( -// with basic params -Routine{ - t = Main.elapsedTime; - FluidBufRTNoveltySlice.process(s,b, indices: c, threshold:0.6); - (Main.elapsedTime - t).postln; -}.play -) - -// list the indicies of detected attacks - the two input channels have been summed -c.getn(0,c.numFrames,{|item|item.postln;}) -:: diff --git a/release-packaging/HelpSource/Classes/FluidRTNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp similarity index 99% rename from release-packaging/HelpSource/Classes/FluidRTNoveltySlice.schelp rename to release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp index 166cf76..ee219bd 100644 --- a/release-packaging/HelpSource/Classes/FluidRTNoveltySlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp @@ -1,4 +1,4 @@ -TITLE:: FluidRTNoveltySlice +TITLE:: FluidNoveltySlice SUMMARY:: Spectral Difference-Based Real-Time Audio Slicer CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition From cb55015f8c05a094a095440f53e60259a62bf090 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Thu, 13 Jun 2019 17:25:54 -0400 Subject: [PATCH 15/18] (buf)noveltyslice updated helpfiles --- .../Classes/FluidBufNoveltySlice.schelp | 8 +++--- .../Classes/FluidNoveltySlice.schelp | 25 ++++++++++--------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp index f649e13..55470b2 100644 --- a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp @@ -39,10 +39,10 @@ ARGUMENT:: indices ARGUMENT:: feature The feature on which novelty is computed. table:: - ##0 || Spectrum || todo - ##1 || MFCC || todo - ##2 || Pitch || todo - ##3 || Loudness || todo + ##0 || Spectrum || The magnitude of the full spectrum. + ##1 || MFCC || 13 Mel-Frequency Cepstrum Coefficients. + ##2 || Pitch || The pitch and its confidence. + ##3 || Loudness || The TruePeak and Loudness. :: ARGUMENT:: kernelSize The granularity of the window in which the algorithm looks for change, in samples. A small number will be sensitive to short term changes, and a large number should look for long term changes. diff --git a/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp index ee219bd..4a90c54 100644 --- a/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp @@ -1,10 +1,10 @@ TITLE:: FluidNoveltySlice -SUMMARY:: Spectral Difference-Based Real-Time Audio Slicer +SUMMARY:: Real-Time Novelty-Based Slicer CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition DESCRIPTION:: -This class implements many spectral based onset detection functions, most of them taken from the literature. (http://www.dafx.ca/proceedings/papers/p_133.pdf) Some are already available in SuperCollider's LINK::Classes/Onsets:: object. It is part of the Fluid Decomposition Toolkit of the FluCoMa project.footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899).:: +This class implements a real-time slicer using an algorithm assessing novelty in the signal to estimate the slicing points. A novelty curve is being derived from running a kernel across the diagonal of the similarity matrix, and looking for peak of changes. It implements the seminal results published in 'Automatic Audio Segmentation Using a Measure of Audio Novelty' by J Foote. It is part of the Fluid Decomposition Toolkit of the FluCoMa project. footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899).:: The process will return an audio steam with sample-long impulses at estimated starting points of the different slices. @@ -20,10 +20,10 @@ ARGUMENT:: in ARGUMENT:: feature The feature on which novelty is computed. table:: - ##0 || Spectrum || todo - ##1 || MFCC || todo - ##2 || Pitch || todo - ##3 || Loudness || todo + ##0 || Spectrum || The magnitude of the full spectrum. + ##1 || MFCC || 13 Mel-Frequency Cepstrum Coefficients. + ##2 || Pitch || The pitch and its confidence. + ##3 || Loudness || The TruePeak and Loudness. :: ARGUMENT:: kernelSize The granularity of the window in which the algorithm looks for change, in samples. A small number will be sensitive to short term changes, and a large number should look for long term changes. @@ -53,27 +53,28 @@ ARGUMENT:: maxFilterSize This cannot be modulated. RETURNS:: - An audio stream with impulses at detected transients. The latency between the input and the output is windowSize at maximum. + An audio stream with impulses at detected transients. The latency between the input and the output is (windowSize + + ((((kernelSize - 1) / 2) + (filterSize - 1)) * hopSize) at maximum. EXAMPLES:: code:: //load some sounds -b = Buffer.read(s,File.realpath(FluidRTNoveltySlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); +b = Buffer.read(s,File.realpath(FluidNoveltySlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); // basic param (the process add a latency of windowSize samples -{var sig = PlayBuf.ar(1,b,loop:1); [FluidRTNoveltySlice.ar(sig,0,3,0.2) * 0.5, DelayN.ar(sig, 1, 1024/ s.sampleRate)]}.play +{var sig = PlayBuf.ar(1,b,loop:1); [FluidNoveltySlice.ar(sig,0,11,0.3) * 0.5, DelayN.ar(sig, 1, (1024 +((((11 - 1) / 2) + (1 - 1)) * 512)) / s.sampleRate)]}.play // other parameters -{var sig = PlayBuf.ar(1,b,loop:1); [FluidRTNoveltySlice.ar(sig, 0, 31, 0.05, 4, 128, 64) * 0.5, DelayN.ar(sig, 1, (128)/ s.sampleRate)]}.play +{var sig = PlayBuf.ar(1,b,loop:1); [FluidNoveltySlice.ar(sig, 1, 31, 0.004, 4, 128, 64) * 0.5, DelayN.ar(sig, 1, (128 +((((5 - 1) / 2) + (4 - 1)) * 64))/ s.sampleRate)]}.play // more musical trans-trigged autopan ( { var sig, trig, syncd, pan; sig = PlayBuf.ar(1,b,loop:1); - trig = FluidRTNoveltySlice.ar(sig, 0, 0.2, 100, 8, 0, 128); - syncd = DelayN.ar(sig, 1, ( 128 / s.sampleRate)); + trig = FluidNoveltySlice.ar(sig, 0, 11, 0.2, 4, 128); + syncd = DelayN.ar(sig, 1, ( (128 +((((11 - 1) / 2) + (4 - 1)) * 64)) / s.sampleRate)); pan = TRand.ar(-1,1,trig); Pan2.ar(syncd,pan); }.play From 6729665ce5f64cb9ecc8e048f58ef7b2965901f1 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Thu, 13 Jun 2019 19:20:38 -0400 Subject: [PATCH 16/18] (buf)amplslice basic helpfile and updated class def --- release-packaging/Classes/FluidAmpSlice.sc | 2 +- release-packaging/Classes/FluidBufAmpSlice.sc | 2 +- .../HelpSource/Classes/FluidAmpSlice.schelp | 15 +- .../Classes/FluidBufAmpSlice.schelp | 244 ++++++++++++++++++ .../Classes/FluidBufOnsetSlice.schelp | 2 +- 5 files changed, 258 insertions(+), 7 deletions(-) create mode 100644 release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp diff --git a/release-packaging/Classes/FluidAmpSlice.sc b/release-packaging/Classes/FluidAmpSlice.sc index 73d9e38..2d1a8b8 100644 --- a/release-packaging/Classes/FluidAmpSlice.sc +++ b/release-packaging/Classes/FluidAmpSlice.sc @@ -1,5 +1,5 @@ FluidAmpSlice : UGen { - *ar { arg in = 0, absRampUp = 10, absRampDown = 10, absThreshOn = -40, absThreshOff = -40, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = -144, relThreshOff = -144, highPassFreq = 250, maxSize = 88200, outputType = 0; + *ar { arg in = 0, absRampUp = 10, absRampDown = 10, absThreshOn = -40, absThreshOff = -40, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 250, maxSize = 88200, outputType = 0; ^this.multiNew('audio', in.asAudioRateInput(this), absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq, maxSize, outputType) } checkInputs { diff --git a/release-packaging/Classes/FluidBufAmpSlice.sc b/release-packaging/Classes/FluidBufAmpSlice.sc index 568c308..497caef 100644 --- a/release-packaging/Classes/FluidBufAmpSlice.sc +++ b/release-packaging/Classes/FluidBufAmpSlice.sc @@ -1,5 +1,5 @@ FluidBufAmpSlice{ - *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, absRampUp = 10, absRampDown = 10, absThreshOn = -40, absThreshOff = -40, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = -144, relThreshOff = -144, highPassFreq = 250, outputType = 0, action; + *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, absRampUp = 10, absRampDown = 10, absThreshOn = -40, absThreshOff = -40, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 250, outputType = 0, action; var maxSize = max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead)); diff --git a/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp index 8a45899..1aac99e 100644 --- a/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp @@ -172,22 +172,29 @@ code:: {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-1); [source, env] - }.plot(0.025); + }.plot(0.05); ) //a solution: minSliceLength ( {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-1, minSliceLength:441); [source, env] - }.plot(0.025); + }.plot(0.05); ) //drum slicing, many ways //load a buffer b = Buffer.read(s,File.realpath(FluidAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); ( {var env, source = PlayBuf.ar(1,b); - env = FluidAmpSlice.ar(source,absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:5, relRampDown:441, relThreshOn:5, relThreshOff:4, minSliceLength:441, outputType:0); + env = FluidAmpSlice.ar(source,absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:441, relThreshOn:14, relThreshOff:12, minSliceLength:4410, outputType:0); [source, env] - }.plot(1,maxval:[1,10],separately:true); + }.plot(2,maxval:[1,1],separately:true); +) + +( + {var env, source = PlayBuf.ar(1,b); + env = FluidAmpSlice.ar(source,highPassFreq:120, absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:2205, relThreshOn:12, relThreshOff:8, minSliceLength:441); + [source, env] + }.play); ) :: diff --git a/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp new file mode 100644 index 0000000..6f6938e --- /dev/null +++ b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp @@ -0,0 +1,244 @@ +TITLE:: FluidBufAmpSlice +SUMMARY:: Amplitude-based Slicer for Buffers +CATEGORIES:: Libraries>FluidDecomposition +RELATED:: Guides/FluCoMa, Guides/FluidDecomposition + +DESCRIPTION:: +This class implements an amplitude-based slicer, with various customisable options and conditions to detect absolute and relative amplitude changes as onsets and offsets. It is part of the Fluid Decomposition Toolkit of the FluCoMa project.footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899).:: + +FluidAmpSlice is based on two envelop followers on a highpassed version of the signal: one absolute, and one relative. Each have features that will interact, including independent Schmidt triggers and state-aware time contraints. The example code below is unfolding the various possibilites in order of complexity. + +The process will return a two-channel buffer with the addresses of the onset on the first channel, and the address of the offset on the second channel. + +CLASSMETHODS:: + +METHOD:: process + This is the method that calls for the slicing to be calculated on a given source buffer. + +ARGUMENT:: server + The server on which the buffers to be processed are allocated. + +ARGUMENT:: source + The index of the buffer to use as the source material to be sliced through novelty identification. The different channels of multichannel buffers will be summed. + +ARGUMENT:: startFrame + Where in the srcBuf should the slicing process start, in sample. + +ARGUMENT:: numFrames + How many frames should be processed. + +ARGUMENT:: startChan + For multichannel sources, which channel should be processed. + +ARGUMENT:: numChans + For multichannel sources, how many channel should be summed. + +ARGUMENT:: indices + The index of the buffer where the indices (in sample) of the estimated starting points of slices will be written. The first and last points are always the boundary points of the analysis. + +ARGUMENT:: absRampUp + The number of samples the absolute envelope follower will take to reach the next value when raising. + +ARGUMENT:: absRampDown + The number of samples the absolute envelope follower will take to reach the next value when falling. + +ARGUMENT:: absThreshOn + The threshold in dB of the absolute envelope follower to trigger an onset, aka to go ON when in OFF state. + +ARGUMENT:: absThreshOff + The threshold in dB of the absolute envelope follower to trigger an offset, , aka to go ON when in OFF state. + +ARGUMENT:: minSliceLength + The length in samples that the Slice will stay ON. Changes of states during that period will be ignored. + +ARGUMENT:: minSilenceLength + The length in samples that the Slice will stay OFF. Changes of states during that period will be ignored. + +ARGUMENT:: minLengthAbove + The length in samples that the absolute envelope have to be above the threshold to consider it a valid transition to ON. The Slice will start at the first sample when the condition is met. Therefore, this affects the latency. + +ARGUMENT:: minLengthBelow + The length in samples that the absolute envelope have to be below the threshold to consider it a valid transition to OFF. The Slice will end at the first sample when the condition is met. Therefore, this affects the latency. + +ARGUMENT:: lookBack + The length of the buffer kept before an onset to allow the algorithm, once a new Slice is detected, to go back in time (up to that many samples) to find the minimum amplitude as the Slice onset point. This affects the latency of the algorithm. + +ARGUMENT:: lookAhead + The length of the buffer kept after an offset to allow the algorithm, once the Slice is considered finished, to wait further in time (up to that many samples) to find a minimum amplitude as the Slice offset point. This affects the latency of the algorithm. + +ARGUMENT:: relRampUp + The number of samples the relative envelope follower will take to reach the next value when raising. Typically, this will be faster than absRampUp. + +ARGUMENT:: relRampDown + The number of samples the relative envelope follower will take to reach the next value when falling. Typically, this will be faster than absRampDown. + +ARGUMENT:: relThreshOn + The threshold in dB of the relative envelope follower to trigger an onset, aka to go ON when in OFF state. It is computed on the difference between the two envelope followers. + +ARGUMENT:: relThreshOff + The threshold in dB of the relative envelope follower to reset, aka to allow the differential envelop to trigger again. + +ARGUMENT:: highPassFreq + The frequency of the fourth-order Linkwitz–Riley high-pass filter (https://en.wikipedia.org/wiki/Linkwitz%E2%80%93Riley_filter). This is done first on the signal to minimise low frequency intermodulation with very fast ramp lengths. + +ARGUMENT:: outputType +(describe argument here) + +ARGUMENT:: action + A Function to be evaluated once the offline process has finished and indices instance variables have been updated on the client side. The metric will be passed indices as an argument. + +RETURNS:: + Nothing, as the destination buffer is declared in the function call. + +EXAMPLES:: + +code:: +//basic tests: highPass sanity +( +{var env, source = SinOsc.ar(320,0,0.5); + env = FluidAmpSlice.ar(source,highPassFreq:250, outputType:1); + [source, env] +}.plot(0.03); +) +//basic tests: absRampUp-Down sanity +( + {var env, source = SinOsc.ar(320,0,0.5); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:1000, outputType:2); + [source.abs, env] + }.plot(0.03); +) +///////////////////////////// +//basic tests: absThresh sanity +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12); + [source, env] + }.plot(0.1); +) +//basic tests: absThresh histeresis +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -16); + [source, env] + }.plot(0.1); +) +//basic tests: absThresh min slice +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minSliceLength:441); + [source, env] + }.plot(0.1); +) +//basic tests: absThresh min silence +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minSilenceLength:441); + [source, env] + }.plot(0.1); +) +//mid tests: absThresh time histeresis on +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthAbove:441, outputType:0); + [DelayN.ar(source,0.1,441/44100), env] + }.plot(0.1); +) +//mid tests: absThresh time histeresis off +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthBelow:441); + [DelayN.ar(source,0.1,441/44100), env] + }.plot(0.1); +) +//mid tests: absThresh with lookBack +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12,lookBack:441); + [DelayN.ar(source,0.1,441/44100), env] + }.plot(0.1); +) +//mid tests: absThresh with lookAhead +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12,lookAhead:441); + [DelayN.ar(source,0.1,441/44100), env] + }.plot(0.1); +) +//mid tests: absThresh with asymetrical lookBack and lookAhead +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12,lookBack:221, lookAhead:441); + [DelayN.ar(source,0.1,441/44100), env] + }.plot(0.1); +) +//advanced tests: absThresh histeresis, long tail +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16); + [source, env] + }.plot(0.1); +) +//solution: have to recut with relThresh +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-12); + [source, env] + }.plot(0.1); +) +//beware of double trig +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-1); + [source, env] + }.plot(0.05); +) +//a solution: minSliceLength +( + {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-1, minSliceLength:441); + [source, env] + }.plot(0.05); +) +//drum slicing, many ways +//load a buffer +b = Buffer.read(s,File.realpath(FluidAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); +( + {var env, source = PlayBuf.ar(1,b); + env = FluidAmpSlice.ar(source,absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:441, relThreshOn:14, relThreshOff:12, minSliceLength:4410, outputType:0); + [source, env] + }.plot(2,maxval:[1,1],separately:true); +) + +( + {var env, source = PlayBuf.ar(1,b); + env = FluidAmpSlice.ar(source,highPassFreq:120, absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:2205, relThreshOn:12, relThreshOff:8, minSliceLength:441); + [source, env] + }.play); +) +:: + +STRONG::A stereo buffer example.:: +CODE:: +// make a stereo buffer +b = Buffer.alloc(s,88200,2); + +// add some stereo clicks and listen to them +((0..3)*22050+11025).do({|item,index| b.set(item+(index%2), 1.0)}) +b.play + +// create a new buffer as destinations +c = Buffer.new(s); + +//run the process on them +( +// with basic params +Routine{ + t = Main.elapsedTime; + FluidBufAmpSlice.process(s,b, indices: c); + (Main.elapsedTime - t).postln; +}.play +) + +// list the indicies of detected attacks - the two input channels have been summed +c.getn(0,c.numFrames,{|item|item.postln;}) +:: diff --git a/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp index 09389f7..84a25b0 100644 --- a/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp @@ -74,7 +74,7 @@ ARGUMENT:: action A Function to be evaluated once the offline process has finished and indices instance variables have been updated on the client side. The metric will be passed indices as an argument. RETURNS:: - Nothing, as the various destination buffers are declared in the function call. + Nothing, as the destination buffer is declared in the function call. EXAMPLES:: From 982db962a4a0e96e5f38b6077cabf10466e914e9 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Fri, 14 Jun 2019 16:04:51 -0400 Subject: [PATCH 17/18] (buf)ampseg: more test code and commented examples of interface use --- release-packaging/Classes/FluidAmpSlice.sc | 2 +- release-packaging/Classes/FluidBufAmpSlice.sc | 2 +- .../HelpSource/Classes/FluidAmpSlice.schelp | 8 +- .../Classes/FluidBufAmpSlice.schelp | 182 +++++++----------- 4 files changed, 78 insertions(+), 116 deletions(-) diff --git a/release-packaging/Classes/FluidAmpSlice.sc b/release-packaging/Classes/FluidAmpSlice.sc index 2d1a8b8..8558d56 100644 --- a/release-packaging/Classes/FluidAmpSlice.sc +++ b/release-packaging/Classes/FluidAmpSlice.sc @@ -1,5 +1,5 @@ FluidAmpSlice : UGen { - *ar { arg in = 0, absRampUp = 10, absRampDown = 10, absThreshOn = -40, absThreshOff = -40, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 250, maxSize = 88200, outputType = 0; + *ar { arg in = 0, absRampUp = 10, absRampDown = 10, absThreshOn = -90, absThreshOff = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 85, maxSize = 88200, outputType = 0; ^this.multiNew('audio', in.asAudioRateInput(this), absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq, maxSize, outputType) } checkInputs { diff --git a/release-packaging/Classes/FluidBufAmpSlice.sc b/release-packaging/Classes/FluidBufAmpSlice.sc index 497caef..0c41b94 100644 --- a/release-packaging/Classes/FluidBufAmpSlice.sc +++ b/release-packaging/Classes/FluidBufAmpSlice.sc @@ -1,5 +1,5 @@ FluidBufAmpSlice{ - *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, absRampUp = 10, absRampDown = 10, absThreshOn = -40, absThreshOff = -40, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 250, outputType = 0, action; + *process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, absRampUp = 10, absRampDown = 10, absThreshOn = -90, absThreshOff = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 85, outputType = 0, action; var maxSize = max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead)); diff --git a/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp index 1aac99e..2fee617 100644 --- a/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp @@ -97,7 +97,7 @@ code:: [source, env] }.plot(0.1); ) -//basic tests: absThresh histeresis +//basic tests: absThresh hysteresis ( {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -16); @@ -118,14 +118,14 @@ code:: [source, env] }.plot(0.1); ) -//mid tests: absThresh time histeresis on +//mid tests: absThresh time hysteresis on ( {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthAbove:441, outputType:0); [DelayN.ar(source,0.1,441/44100), env] }.plot(0.1); ) -//mid tests: absThresh time histeresis off +//mid tests: absThresh time hysteresis off ( {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthBelow:441); @@ -153,7 +153,7 @@ code:: [DelayN.ar(source,0.1,441/44100), env] }.plot(0.1); ) -//advanced tests: absThresh histeresis, long tail +//advanced tests: absThresh hysteresis, long tail ( {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16); diff --git a/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp index 6f6938e..1bc5c06 100644 --- a/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp @@ -93,130 +93,92 @@ RETURNS:: EXAMPLES:: code:: -//basic tests: highPass sanity +// define a test signal and a destination buffer ( -{var env, source = SinOsc.ar(320,0,0.5); - env = FluidAmpSlice.ar(source,highPassFreq:250, outputType:1); - [source, env] -}.plot(0.03); + b = Buffer.sendCollection(s, Array.fill(44100,{|i| sin(i*pi/ (44100/640)) * (sin(i*pi/ 22050)).abs})); + c = Buffer.new(s); ) -//basic tests: absRampUp-Down sanity -( - {var env, source = SinOsc.ar(320,0,0.5); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:1000, outputType:2); - [source.abs, env] - }.plot(0.03); -) -///////////////////////////// +b.play +b.plot + //basic tests: absThresh sanity -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12); - [source, env] - }.plot(0.1); -) -//basic tests: absThresh histeresis -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -16); - [source, env] - }.plot(0.1); -) +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//basic tests: absThresh hysteresis +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -16) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + //basic tests: absThresh min slice -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minSliceLength:441); - [source, env] - }.plot(0.1); -) +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minSliceLength:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + //basic tests: absThresh min silence -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minSilenceLength:441); - [source, env] - }.plot(0.1); -) -//mid tests: absThresh time histeresis on -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthAbove:441, outputType:0); - [DelayN.ar(source,0.1,441/44100), env] - }.plot(0.1); -) -//mid tests: absThresh time histeresis off -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthBelow:441); - [DelayN.ar(source,0.1,441/44100), env] - }.plot(0.1); -) +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minSilenceLength:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + + +//mid tests: absThresh time hysteresis on +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthAbove:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//mid tests: absThresh time hysteresis off +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthBelow:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + //mid tests: absThresh with lookBack -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12,lookBack:441); - [DelayN.ar(source,0.1,441/44100), env] - }.plot(0.1); -) +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, lookBack:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + //mid tests: absThresh with lookAhead -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12,lookAhead:441); - [DelayN.ar(source,0.1,441/44100), env] - }.plot(0.1); -) +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, lookAhead:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + //mid tests: absThresh with asymetrical lookBack and lookAhead -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12,lookBack:221, lookAhead:441); - [DelayN.ar(source,0.1,441/44100), env] - }.plot(0.1); -) -//advanced tests: absThresh histeresis, long tail -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16); - [source, env] - }.plot(0.1); -) -//solution: have to recut with relThresh -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-12); - [source, env] - }.plot(0.1); -) -//beware of double trig -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-1); - [source, env] - }.plot(0.05); -) -//a solution: minSliceLength -( - {var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-1, minSliceLength:441); - [source, env] - }.plot(0.05); -) +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, lookBack:221, lookAhead:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//advanced tests: absThresh hysteresis, long tail //STRANGE OFFSET ADDRESS +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:22050, absThreshOn:-12, absThreshOff: -16, minSliceLength:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//solution: have to recut with relThresh //STRANGE OFFSET ADDRESS +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:22050, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-12) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//beware of double trig. a solution: minSliceLength //STRANGE OFFSET ADDRESS +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:22050, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-12, minSliceLength:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +///////////////////////// //drum slicing, many ways //load a buffer -b = Buffer.read(s,File.realpath(FluidAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); ( - {var env, source = PlayBuf.ar(1,b); - env = FluidAmpSlice.ar(source,absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:441, relThreshOn:14, relThreshOff:12, minSliceLength:4410, outputType:0); - [source, env] - }.plot(2,maxval:[1,1],separately:true); +b = Buffer.read(s,File.realpath(FluidBufAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); +c = Buffer.new(s); ) -( - {var env, source = PlayBuf.ar(1,b); - env = FluidAmpSlice.ar(source,highPassFreq:120, absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:2205, relThreshOn:12, relThreshOff:8, minSliceLength:441); - [source, env] - }.play); -) +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:441, relThreshOn:14, relThreshOff:12, minSliceLength:4410) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//AGAIN STRANGE OFFSET ADDRESSES + :: + /// //TO TROUBLESHOOT STRONG::A stereo buffer example.:: CODE:: // make a stereo buffer @@ -234,7 +196,7 @@ c = Buffer.new(s); // with basic params Routine{ t = Main.elapsedTime; - FluidBufAmpSlice.process(s,b, indices: c); + FluidBufAmpSlice.process(s,b, indices: c, absRampUp:1, absRampDown:1, absThreshOn:-90, absThreshOff:-95); (Main.elapsedTime - t).postln; }.play ) From b4ddab8cacd15472dbdd2ab4874f37e1066d8a8f Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Fri, 14 Jun 2019 19:31:05 -0400 Subject: [PATCH 18/18] last examples of bufampslice --- .../HelpSource/Classes/FluidBufAmpSlice.schelp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp index 1bc5c06..7c7375b 100644 --- a/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp @@ -121,7 +121,6 @@ FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThresh c.query c.getn(0,c.numFrames*2,{|item|item.postln;}) - //mid tests: absThresh time hysteresis on FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthAbove:441) c.query @@ -147,18 +146,18 @@ FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:100, absThresh c.query c.getn(0,c.numFrames*2,{|item|item.postln;}) -//advanced tests: absThresh hysteresis, long tail //STRANGE OFFSET ADDRESS -FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:22050, absThreshOn:-12, absThreshOff: -16, minSliceLength:441) +//advanced tests: absThresh hysteresis, long tail +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:2205, absRampDown:2205, absThreshOn:-60, absThreshOff: -60) c.query c.getn(0,c.numFrames*2,{|item|item.postln;}) -//solution: have to recut with relThresh //STRANGE OFFSET ADDRESS -FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:22050, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-12) +//solution: have to recut with relThresh +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:2205, absRampDown:2205, absThreshOn:-60, absThreshOff: -60, relRampUp:5, relRampDown:220, relThreshOn:2, relThreshOff:1) c.query c.getn(0,c.numFrames*2,{|item|item.postln;}) -//beware of double trig. a solution: minSliceLength //STRANGE OFFSET ADDRESS -FluidBufAmpSlice.process(s,b,indices:c, absRampUp:10, absRampDown:22050, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-12, minSliceLength:441) +//beware of double trig. a solution: minSliceLength +FluidBufAmpSlice.process(s,b,indices:c, absRampUp:2205, absRampDown:2205, absThreshOn:-60, absThreshOff: -60, relRampUp:5, relRampDown:220, relThreshOn:2, relThreshOff:1, minSliceLength:4410) c.query c.getn(0,c.numFrames*2,{|item|item.postln;}) @@ -196,7 +195,7 @@ c = Buffer.new(s); // with basic params Routine{ t = Main.elapsedTime; - FluidBufAmpSlice.process(s,b, indices: c, absRampUp:1, absRampDown:1, absThreshOn:-90, absThreshOff:-95); + FluidBufAmpSlice.process(s,b, indices: c, absRampUp:1, absRampDown:1, absThreshOn:-60, absThreshOff:-60); (Main.elapsedTime - t).postln; }.play )