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/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ef2ebe..71c94fb 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,21 +4,18 @@ cmake_minimum_required(VERSION 3.3) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 14) - -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx -msse -msse2 -msse3 -msse4") set(CMAKE_CXX_EXTENSIONS OFF) + if(APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") - 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") +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") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic") endif() project (fluid_decomposition_supercollider LANGUAGES CXX) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic") - - option(SUPERNOVA "Build plugins for supernova" OFF) MACRO(SUBDIRLIST result curdir) @@ -33,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() @@ -46,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-exports.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") @@ -71,26 +68,32 @@ add_library(FFTLIB STATIC ${FFT_SOURCES}) target_link_libraries( FFTLIB PRIVATE ${FFT_LINK} ) +if(WIN32) + target_compile_options( + FFTLIB PRIVATE $<$>: /arch:AVX> + ) +else(WIN32) target_compile_options( - FFTLIB PRIVATE $<$>:-mavx -msse -msse2 -msse3 -msse4> + FFTLIB PRIVATE $<$>: -mavx -msse -msse2 -msse3 -msse4> ) +endif(WIN32) + #needed for complaint-free static linking with GCC if(CMAKE_COMPILER_IS_GNUCXX) - target_compile_options( FFTLIB PUBLIC -fPIC ) +target_compile_options( FFTLIB PUBLIC -fPIC ) ENDIF(CMAKE_COMPILER_IS_GNUCXX) - 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/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index f93aa09..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); @@ -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; @@ -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; } @@ -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; } diff --git a/release-packaging/Classes/FluidAmpSlice.sc b/release-packaging/Classes/FluidAmpSlice.sc index 73d9e38..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 568c308..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/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/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/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/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/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/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/FluidAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp index 8a45899..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); @@ -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..7c7375b --- /dev/null +++ b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp @@ -0,0 +1,205 @@ +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:: +// define a test signal and a destination buffer +( + b = Buffer.sendCollection(s, Array.fill(44100,{|i| sin(i*pi/ (44100/640)) * (sin(i*pi/ 22050)).abs})); + c = Buffer.new(s); +) +b.play +b.plot + +//basic tests: absThresh sanity +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 +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 +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 +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 +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 +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 +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 +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 +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;}) + +///////////////////////// +//drum slicing, many ways +//load a buffer +( +b = Buffer.read(s,File.realpath(FluidBufAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); +c = Buffer.new(s); +) + +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 +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, absRampUp:1, absRampDown:1, absThreshOn:-60, absThreshOff:-60); + (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/FluidBufNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp index 92d3842..55470b2 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 || 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. @@ -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/FluidBufOnsetSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp index ecd692f..84a25b0 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,10 +71,10 @@ 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. + Nothing, as the destination buffer is declared in the function call. EXAMPLES:: 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/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/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/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, dist1FluidDecomposition 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 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 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 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. 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 diff --git a/scripts/target_post.cmake b/scripts/target_post.cmake index fde11a3..2ce587f 100644 --- a/scripts/target_post.cmake +++ b/scripts/target_post.cmake @@ -1,9 +1,11 @@ -# if(MSVC) -# target_compile_options(${PLUGIN} PRIVATE /W4 /WX) -# else() -# target_compile_options(${PLUGIN} PRIVATE -Wall -Wextra -Wpedantic -Wreturn-type -Wconversion) -# endif() +target_compile_features(${PLUGIN} PUBLIC cxx_std_14) + +if(MSVC) + target_compile_options(${PLUGIN} PRIVATE /W4) +else() + target_compile_options(${PLUGIN} PRIVATE -Wall -Wextra -Wpedantic -Wreturn-type -Wconversion) +endif() set_target_properties(${PLUGIN} PROPERTIES CXX_STANDARD 14 @@ -30,23 +32,23 @@ target_include_directories( target_include_directories( ${PLUGIN} 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() @@ -75,6 +77,14 @@ if(MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mstackrealign") endif() +if(MSVC) + target_compile_options(${PLUGIN} PRIVATE /arch:AVX -D_USE_MATH_DEFINES) +else(MSVC) +target_compile_options( + ${PLUGIN} PRIVATE $<$>: -mavx -msse -msse2 -msse3 -msse4> +) +endif(MSVC) + ####### added the fluid_decomposition if(SUPERNOVA) 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)