diff --git a/.gitignore b/.gitignore index 59c8ca7..e612641 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ release-packaging/Plugins release-packaging/AudioFiles *.scx .vs/ +Darwin/* +Linux/* +Windows/* +install/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 0513eda..340c0a8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,37 @@ -####### original SC Cmake file starts here -cmake_minimum_required(VERSION 3.3) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). +cmake_minimum_required(VERSION 3.11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_EXTENSIONS OFF) +################################################################################ +# Paths +set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/install" CACHE PATH "") -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") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic") +set(SC_LIBRARY_OUTPUT_PREFIX "release-packaging" CACHE STRING "Where in the hierarchy to write sc plugins (different for superbuild)") + +set(SC_PATH "" CACHE PATH "Path to the top of SuperCollider source tree") +if(NOT SC_PATH) + message(FATAL_ERROR "SuperCollider source path is not set") endif() -project (fluid_decomposition_supercollider LANGUAGES CXX) +set(FLUID_PATH "" CACHE PATH "Optional path to the Fluid Decomposition repo") +set(FLUID_M_PATH "" CACHE PATH "Optional path to the Fluid fluid_manipulation repo") -option(SUPERNOVA "Build plugins for supernova" OFF) +if (APPLE) + set(CMAKE_OSX_ARCHITECTURES x86_64) + set(CMAKE_XCODE_GENERATE_SCHEME ON) + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7) +endif() + +################################################################################ +# Main project +project (fluid_decomposition_supercollider LANGUAGES CXX) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY ON) MACRO(SUBDIRLIST result curdir) FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) @@ -29,66 +44,57 @@ MACRO(SUBDIRLIST result curdir) SET(${result} ${dirlist}) 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(FLUID_M_PATH ~/dev/fluid_manipulation/fluid_manipulation CACHE PATH "The top level of the fluid_manipulation repo") +include(FetchContent) +set(FETCHCONTENT_QUIET FALSE) -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() +FetchContent_Declare( + fluid_decomposition + GIT_REPOSITORY https://bitbucket.org/flucoma/fluid_decomposition.git + GIT_PROGRESS TRUE +) -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") +if(FLUID_PATH) + get_filename_component( + FETCHCONTENT_SOURCE_DIR_FLUID_DECOMPOSITION ${FLUID_PATH} ABSOLUTE + ) endif() -if (NOT (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/")) - file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/") +FetchContent_GetProperties(fluid_decomposition) +if(NOT fluid_decomposition_POPULATED) + FetchContent_Populate(fluid_decomposition) + add_subdirectory(${fluid_decomposition_SOURCE_DIR} ${fluid_decomposition_BINARY_DIR}) + include(flucoma_version) + include(flucoma-buildtools) endif() -file(COPY "${FLUID_ABS_PATH}/AudioFiles/" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/AudioFiles/") - - -include("${FLUID_ABS_PATH}/build/fluid_decomposition-exports.cmake") +set_if_toplevel(VAR CMAKE_LIBRARY_OUTPUT_DIRECTORY + TOPLEVEL "${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/plugins" + SUPERBUILD "${CMAKE_SOURCE_DIR}/sc_plugins/${CMAKE_HOST_SYSTEM_NAME}/${CMAKE_HOST_SYSTEM_PROCESSOR}") -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/release-packaging/plugins") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") - set(CMAKE_SHARED_MODULE_PREFIX "") + if(APPLE OR WIN32) -set(CMAKE_SHARED_MODULE_SUFFIX ".scx") + set(CMAKE_SHARED_MODULE_SUFFIX ".scx") endif() -get_property(FFT_SOURCES TARGET HISSTools_FFT PROPERTY INTERFACE_SOURCES) -get_property(FFT_LINK TARGET HISSTools_FFT PROPERTY INTERFACE_LINK_LIBRARIES) - -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> -) -endif(WIN32) - #needed for complaint-free static linking with GCC if(CMAKE_COMPILER_IS_GNUCXX) -target_compile_options( FFTLIB PUBLIC -fPIC ) -ENDIF(CMAKE_COMPILER_IS_GNUCXX) + target_compile_options( HISSTools_FFT PUBLIC -fPIC ) +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" +target_include_directories(FLUID_SC_WRAPPER + INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include/" +) + +target_sources(FLUID_SC_WRAPPER + INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include/FluidSCWrapper.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/include/SCBufferAdaptor.hpp" ) SUBDIRLIST(PROJECT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src") @@ -98,3 +104,18 @@ foreach (project_dir ${PROJECT_DIRS}) add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/src/${project_dir}") endif () endforeach () + +#install bits. + +set(SC_INSTALL_PREFIX "." CACHE PATH "Prefix for assembling SC packages") +set(FLUID_PACKAGE_NAME FluidCorpusManipulation CACHE STRING "Name for published package") +set(SC_PACKAGE_ROOT ${SC_INSTALL_PREFIX}/${FLUID_PACKAGE_NAME}) + +foreach(PACKAGE_DIRECTORY Classes;HelpSource;Examples) + install(DIRECTORY "release-packaging/${PACKAGE_DIRECTORY}" DESTINATION ${SC_PACKAGE_ROOT}) +endforeach() + +install(DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/ DESTINATION ${SC_PACKAGE_ROOT}/plugins PATTERN "*.ilk" EXCLUDE PATTERN "*.PDB" EXCLUDE) +install(DIRECTORY "${fluid_decomposition_SOURCE_DIR}/AudioFiles" DESTINATION ${SC_PACKAGE_ROOT}) +install(FILES QuickStart.md DESTINATION ${SC_PACKAGE_ROOT}) +install(FILES ${fluid_decomposition_SOURCE_DIR}/license-executableform.md DESTINATION ${SC_PACKAGE_ROOT} RENAME license.md) diff --git a/QuickStart.md b/QuickStart.md index 79a749f..6895b17 100644 --- a/QuickStart.md +++ b/QuickStart.md @@ -1,9 +1,11 @@ -# Instructions for the SupperCollider version of the fluid.decomposition toolbox +# Instructions for the SuperCollider version of the Fluid Corpus Manipulation toolbox ## How to start: -1) move the full fluid_decomposition folder in your Extensions folder (see the 'Using Extensions' Guide in the documentation), and restart SuperCollider. +1) move the full FluidCorpusManipulation folder in your Extensions folder (see the 'Using Extensions' Guide in the documentation), and restart SuperCollider. -There is a Guide giving the overview of the toolbox. Full documentation, and examples, are also available. +There is a Guide giving the overview of the toolbox. Full documentation is also available, as well as an Examples folder in the package. #### Enjoy! + +> This project has received funding from the European Research Council (ERC) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899). diff --git a/README.md b/README.md new file mode 100644 index 0000000..11d0c54 --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +# Fluid Corpus Manipulation: SuperCollider Objects Library + +This repository hosts code for generating the SC objects and documentation resources for the Fluid Corpus Manipulation Project. Much of the actual code that does the exciting stuff lives in this repository's principal dependency, the [Fluid Corpus Manipulation Library](). What lives here are: + +* A wrapper from our code to the SC API, that allows us to generate SC objects from a generic class. +* Stubs for producing SC objects for each 'client' in the Fluid Corpus Manipulation Library. +* CMake code for managing dependencies, building and packaging. + + +## I'm in a Hurry... + +...and you already have a development environment set up, understand CMake, and have the SC source available? + +Cool: + +``` +cmake -DSC_PATH= .. +make +``` +You can either symbolically link the `release-packaging` directory into your SC extensions folder, or use CMake to generate a 'clean package' with `make install`. + +## Pre-requisites + +* [CMake](http://cmake.org) >= 3.11 +* A C++ 14 compliant compiler for Mac or Windows (via XCode tools on Mac, and Visual Studio 17 >= 15.9 on Windows) + +## Dependencies + +* [SC Source Code](https://github.com/supercollider/supercollider): this is the only dependency we don't (optionally) manage for you, so there must be a version available to point to when you run, using the CMake Variable `SC_PATH` (see below). It can live anywhere on your file system. + +These will be downloaded and configured automatically, unless you pass CMake a source code location on disk for each (see below): +* [Fluid Corpus Manipulation Library]() +* [Eigen](https://gitlab.com/libeigen/eigen) (3.3.5) +* [HISSTools Library](https://github.com/AlexHarker/HISSTools_Library) + +Unless you are simultaneously committing changes to these dependencies (or are *seriously* worried about disk space), there is nothing to be gained by pointing to external copies, and the easiest thing to is let CMake handle it all. + +## Building + +Simplest possible build: +1. Download the SuperCollider source (>= 3.10.0) if you haven't already +2. Clone this repo +``` +git clone +``` +3. Change to the directory for this repo, make a build directory, and run CMake, passing in the location for the Max SDK +``` +mkdir -p build && cd build +cmake -DSC_PATH= .. +``` +At this point, CMake will set up your tool chain (i.e. look for compilers), and download all the dependencies. + +An alternative to setting up / running CMake directly on the command line is to install the CMake GUI, or use to use the curses gui `ccmake`. + +With CMake you have a choice of which build system you use. +* The default on Mac is `Unix Makefiles`, but you can use Xcode by passing `-GXcode` to CMake when you first run it. +* The default on Windows is the latest version of Visual Studio installed. However, Visual Studio can open CMake files directly as projects, which has some upsides. When used this way, CMake variables have to be set via a JSON file that MSVC will use to configure CMake. + +When using `make`, then +``` +make +``` +will compile all objects ('targets', in CMake-ish). Alternatively, in Xcode or Visual Studio, running 'build' will (by default) build all objects. Note that these IDEs allow you to build both for debugging and for release, whereas with Makefiles, you need to re-run CMake and pass a `CMAKE_CONFIG` variable for different build types. + + +``` +make install +``` +Will assemble a clean package in `release-packaging/FluidCorpusManipulation`. + + +## Structure: + +The top-level folders mostly correspond to those you would find in a typical Max package. Some more will appear when you compile (such as `externals` and possibly `docs`). + +The main action is in `source`: +``` +source +├── include +├── src +└── scripts +``` +* `include` contains the header files for the FluCoMa-SC wrapper +* `src` contains a subfolder for each object to be generated; each of these subfolders has a `.cpp` stub and a `CMakeLists.txt`. The `.cpp` file name needs to match its parent folder. +* `scripts` contains CMake scripts (most significantly, `target_post.cmake`, which sets behaviours for all the objects). + +## Development: Manual Dependencies + +If you're making changes to the Fluid Corpus Manipulation Library and testing against Max (and, hopefully, our other deployment environments), then it makes sense to have the source for this cloned somewhere else on your disk, so that you can commit and push changes, and ensure that they work in all environments. This would be the case, e.g., if you're developing a new client. + +To bypass the automatic cloning of the Fluid Corpus Manipulation Library, we pass in the cache variable `FLUID_PATH` + +``` +cmake -DSC_PATH= -DFLUID_PATH= .. +``` +Note +1. You don't need to run CMake on the Fluid Corpus Manipulation Library first (well, you can, but it doesn't make any difference!). CMake's FetchContent facility will grab the targets from there, but won't look in its CMakeCache, so there should never be a conflict between the state of a build tree at `FLUID_PATH` and your build-tree here. +2. It is **up to you** to make sure the commits you have checked out in each repository make sense together. We use tags against release versions on the `master` branch, so – at the very least – these should line up (unless you're tracking down some regression bug or similar). In general, there is no guarantee, or likelihood, that mismatched tags will build or run, as architectural changes can, do, will happen... + +### Dependencies of dependencies! +The same steps and considerations apply to manually managing the dependencies of the Fluid Corpus Manipulation Library itself. If these aren't explicitly passed whilst running CMake against this build tree, then CMake will download them itself against the tags / commits we develop against. Nevertheless, if you are in the process of making changes to these libraries and running against this (which is much less likely than above), then the CMake variables of interest are: +* `EIGEN_PATH` pointing to the location of Eigen on disk +* `HISS_PATH` pointing to the location of the HISSTools Library + +To find out which branches / tags / commits of these we use, look in the top level `CMakeLists.txt` of the Fluid Corpus Manipulation Library for the `FetchContent_Declare` statements for each dependency. + +# Vector instructions and CPU architecture. +Most types of CPU in common use support a range of specialised instructions for processing vectors of numbers at once, which can offer substantial speed gains. For instance, on Intel / AMD chips there have been a succession of such instruction sets (MMX, SSE, AVX and so on). + +If you find objects causing 'illegal instruction' segmentation faults, it is likely that our default vector instruction flag isn't supported by your CPU. + +### I'm in a hurry... + +And *only building for your own machine*? You want to enable the maximal set of CPU features for your machine without worrying? Using Clang / GCC? + +Pass `-DFLUID_ARCH=-mnative` when you run CMake. This tells the compiler to figure out what instruction sets your personal CPU supports, and enable them. This implies a possible performance gain in return for a portability loss. + +### More Detail +By default, on Intel / AMD, we enable AVX instructions (`-mavx` on clang/GCC; `/ARCH:AVX` on MSVC). These should work on all relatively recent CPUs (from, say, 2012 onwards). On Arm (with the Bela in mind), we use the following architecture flags: + +``` +-march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon +``` + +If your needs are different, then these defaults can be overridden by passing the desired compiler flags to CMake via the `FLUID_ARCH` cache variable. Note that this variable expects you to pass arguments in a form suitable for your compiler, and currently performs no checking or validation. + +* Clang and GCC options are generally the same, see https://clang.llvm.org/docs/ClangCommandLineReference.html +* See MSVC options here https://docs.microsoft.com/en-us/cpp/build/reference/arch-minimum-cpu-architecture?view=vs-2019 + +If your Intel / AMD chip is too old to support AVX, it probably still supports SSE. On Mac OS and Linux, `sysctl -a | grep cpu.feat` can be used to produce a list of the various features your CPU supports. + +> This project has received funding from the European Research Council (ERC) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899). diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index f5ce737..b9c6ad7 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -1,3 +1,13 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ + #pragma once #include "SCBufferAdaptor.hpp" @@ -5,9 +15,8 @@ #include #include #include - +#include #include - #include #include #include @@ -47,17 +56,14 @@ namespace impl { // Iterate over kr/ir inputs via callbacks from params object struct FloatControlsIter { - FloatControlsIter(float **vals, size_t N) - : mValues(vals) - , mSize(N) - {} - + FloatControlsIter(float** vals, index N) : mValues(vals), mSize(N) {} + float next() { return mCount >= mSize ? 0 : *mValues[mCount++]; } - - void reset(float **vals) + + void reset(float** vals) { mValues = vals; - mCount = 0; + mCount = 0; } size_t size() const noexcept { return mSize; } @@ -66,13 +72,13 @@ struct FloatControlsIter return mSize - mCount; } private: - float **mValues; - size_t mSize; - size_t mCount{0}; + float** mValues; + index mSize; + index mCount{0}; }; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + // Real Time Processor template @@ -80,78 +86,107 @@ class RealTime : public SCUnit { using HostVector = FluidTensorView; using ParamSetType = typename Client::ParamSetType; - - // using Client = typename Wrapper::ClientType; public: - static void setup(InterfaceTable *ft, const char *name) + static void setup(InterfaceTable* ft, const char* name) { registerUnit(ft, name); ft->fDefineUnitCmd(name, "latency", doLatency); } - static void doLatency(Unit *unit, sc_msg_iter*) + static void doLatency(Unit* unit, sc_msg_iter*) { - float l[]{static_cast(static_cast(unit)->mClient.latency())}; - auto ft = Wrapper::getInterfaceTable(); + float l[]{ + static_cast(static_cast(unit)->mClient.latency())}; + auto ft = Wrapper::getInterfaceTable(); std::stringstream ss; ss << '/' << Wrapper::getName() << "_latency"; - std::cout << ss.str() << '\n'; + std::cout << ss.str() << std::endl; ft->fSendNodeReply(&unit->mParent->mNode, -1, ss.str().c_str(), 1, l); } - + RealTime() - : mControlsIterator{mInBuf + mSpecialIndex + 1,static_cast(static_cast(mNumInputs) - mSpecialIndex - 1)} - , mParams{Wrapper::Client::getParameterDescriptors()} - , mClient{Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld, mControlsIterator,true)} + : mControlsIterator{mInBuf + mSpecialIndex + 1, + static_cast(mNumInputs) - mSpecialIndex - 1}, + mParams{Wrapper::Client::getParameterDescriptors()}, + mClient{Wrapper::setParams(mParams, mWorld->mVerbosity > 0, mWorld, + mControlsIterator, true)} {} void init() { - assert(!(mClient.audioChannelsOut() > 0 && mClient.controlChannelsOut() > 0) && - "Client can't have both audio and control outputs"); + assert( + !(mClient.audioChannelsOut() > 0 && mClient.controlChannelsOut() > 0) && + "Client can't have both audio and control outputs"); + + // If we don't the number of arguments we expect, the language side code is + // probably the wrong version set plugin to no-op, squawk, and bail; + if (mControlsIterator.size() != Client::getParameterDescriptors().count()) + { + mCalcFunc = Wrapper::getInterfaceTable()->fClearUnitOutputs; + std::cout + << "ERROR: " << Wrapper::getName() + << " wrong number of arguments. Expected " + << Client::getParameterDescriptors().count() << ", got " + << mControlsIterator.size() + << ". Your .sc file and binary plugin might be different versions." + << std::endl; + return; + } mClient.sampleRate(fullSampleRate()); - mInputConnections.reserve(mClient.audioChannelsIn()); - mOutputConnections.reserve(mClient.audioChannelsOut()); - mAudioInputs.reserve(mClient.audioChannelsIn()); - mOutputs.reserve(std::max(mClient.audioChannelsOut(), mClient.controlChannelsOut())); + mInputConnections.reserve(asUnsigned(mClient.audioChannelsIn())); + mOutputConnections.reserve(asUnsigned(mClient.audioChannelsOut())); + mAudioInputs.reserve(asUnsigned(mClient.audioChannelsIn())); + mOutputs.reserve(asUnsigned( + std::max(mClient.audioChannelsOut(), mClient.controlChannelsOut()))); - for (int i = 0; i < static_cast(mClient.audioChannelsIn()); ++i) + for (index i = 0; i < mClient.audioChannelsIn(); ++i) { - mInputConnections.emplace_back(isAudioRateIn(i)); + mInputConnections.emplace_back(isAudioRateIn(static_cast(i))); mAudioInputs.emplace_back(nullptr, 0, 0); } - for (int i = 0; i < static_cast(mClient.audioChannelsOut()); ++i) + for (index i = 0; i < mClient.audioChannelsOut(); ++i) { mOutputConnections.emplace_back(true); mOutputs.emplace_back(nullptr, 0, 0); } - - for (int i = 0; i < static_cast(mClient.controlChannelsOut()); ++i) { mOutputs.emplace_back(nullptr, 0, 0); } - + + for (index i = 0; i < mClient.controlChannelsOut(); ++i) + { mOutputs.emplace_back(nullptr, 0, 0); } + mCalcFunc = make_calc_function(); Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1); } void next(int) { - mControlsIterator.reset(mInBuf + mSpecialIndex + 1); //mClient.audioChannelsIn()); - Wrapper::setParams(mParams, mWorld->mVerbosity > 0, mWorld, mControlsIterator); // forward on inputs N + audio inputs as params - mParams.constrainParameterValues(); - const Unit *unit = this; - for (size_t i = 0; i < mClient.audioChannelsIn(); ++i) + mControlsIterator.reset(mInBuf + mSpecialIndex + 1); // mClient.audioChannelsIn()); + Wrapper::setParams( + mParams, mWorld->mVerbosity > 0, mWorld, + mControlsIterator); // forward on inputs N + audio inputs as params + mParams.constrainParameterValues(); + const Unit* unit = this; + for (index i = 0; i < mClient.audioChannelsIn(); ++i) + { + if (mInputConnections[asUnsigned(i)]) + { mAudioInputs[asUnsigned(i)].reset(IN(i), 0, fullBufferSize()); } + } + for (index i = 0; i < mClient.audioChannelsOut(); ++i) { - if (mInputConnections[i]) mAudioInputs[i].reset(IN(i), 0, fullBufferSize()); + assert(i <= std::numeric_limits::max()); + if (mOutputConnections[asUnsigned(i)]) + mOutputs[asUnsigned(i)].reset(out(static_cast(i)), 0, + fullBufferSize()); } - for (size_t i = 0; i < mClient.audioChannelsOut(); ++i) + for (index i = 0; i < mClient.controlChannelsOut(); ++i) { - if (mOutputConnections[i]) mOutputs[i].reset(out(static_cast(i)), 0, fullBufferSize()); + assert(i <= std::numeric_limits::max()); + mOutputs[asUnsigned(i)].reset(out(static_cast(i)), 0, 1); } - for (size_t i = 0; i < mClient.controlChannelsOut(); ++i) { mOutputs[i].reset(out(static_cast(i)), 0, 1); } - mClient.process(mAudioInputs, mOutputs,mContext); + mClient.process(mAudioInputs, mOutputs, mContext); } private: @@ -163,97 +198,107 @@ private: FluidContext mContext; protected: - ParamSetType mParams; - Client mClient; + ParamSetType mParams; + Client mClient; }; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// /// Non Real Time Processor -/// This is also a UGen, but the main action is delegated off to a worker thread, via the NRT thread. -/// The RT bit is there to allow us (a) to poll our thread and (b) emit a kr progress update +/// This is also a UGen, but the main action is delegated off to a worker +/// thread, via the NRT thread. The RT bit is there to allow us (a) to poll our +/// thread and (b) emit a kr progress update template -class NonRealTime: public SCUnit +class NonRealTime : public SCUnit { using ParamSetType = typename Client::ParamSetType; - -public: - static void setup(InterfaceTable *ft, const char *name) +public: + static void setup(InterfaceTable* ft, const char* name) { registerUnit(ft, name); ft->fDefineUnitCmd(name, "cancel", doCancel); - ft->fDefineUnitCmd(name, "queue_enabled", [](struct Unit* unit, struct sc_msg_iter* args) - { - auto w = static_cast(unit); - w->mQueueEnabled = args->geti(0); - w->mFifoMsg.Set(w->mWorld,[](FifoMsg* f) - { - auto w = static_cast(f->mData); - w->mClient.setQueueEnabled(w->mQueueEnabled); - },nullptr,w); - Wrapper::getInterfaceTable()->fSendMsgFromRT(w->mWorld, w->mFifoMsg); - }); - ft->fDefineUnitCmd(name, "synchronous", [](struct Unit* unit, struct sc_msg_iter* args) - { - auto w = static_cast(unit); - w->mSynchronous = args->geti(0); - w->mFifoMsg.Set(w->mWorld,[](FifoMsg* f) - { - auto w = static_cast(f->mData); - w->mClient.setSynchronous(w->mSynchronous); - },nullptr,w); - Wrapper::getInterfaceTable()->fSendMsgFromRT(w->mWorld, w->mFifoMsg); - }); + ft->fDefineUnitCmd( + name, "queue_enabled", [](struct Unit* unit, struct sc_msg_iter* args) { + auto w = static_cast(unit); + w->mQueueEnabled = args->geti(0); + w->mFifoMsg.Set( + w->mWorld, + [](FifoMsg* f) { + auto w = static_cast(f->mData); + w->mClient.setQueueEnabled(w->mQueueEnabled); + }, + nullptr, w); + Wrapper::getInterfaceTable()->fSendMsgFromRT(w->mWorld, w->mFifoMsg); + }); + ft->fDefineUnitCmd( + name, "synchronous", [](struct Unit* unit, struct sc_msg_iter* args) { + auto w = static_cast(unit); + w->mSynchronous = args->geti(0); + w->mFifoMsg.Set( + w->mWorld, + [](FifoMsg* f) { + auto w = static_cast(f->mData); + w->mClient.setSynchronous(w->mSynchronous); + }, + nullptr, w); + Wrapper::getInterfaceTable()->fSendMsgFromRT(w->mWorld, w->mFifoMsg); + }); } - - /// Penultimate input is the doneAction, final is blocking mode. Neither are params, so we skip them in the controlsIterator - NonRealTime() : - mControlsIterator{mInBuf,static_cast(static_cast(mNumInputs) - mSpecialIndex - 2)} - , mParams{Wrapper::Client::getParameterDescriptors()} - , mClient{Wrapper::setParams(mParams,mWorld->mVerbosity > 0, mWorld, mControlsIterator,true)} - , mSynchronous{mNumInputs > 2 ? (in0(static_cast(mNumInputs - 1)) > 0) : false} + + /// Penultimate input is the doneAction, final is blocking mode. Neither are + /// params, so we skip them in the controlsIterator + NonRealTime() + : mControlsIterator{mInBuf, index(mNumInputs) - mSpecialIndex - 2}, + mParams{Wrapper::Client::getParameterDescriptors()}, + mClient{Wrapper::setParams(mParams, mWorld->mVerbosity > 0, mWorld, + mControlsIterator, true)}, + mSynchronous{mNumInputs > 2 ? (in0(int(mNumInputs) - 1) > 0) : false} {} - + ~NonRealTime() { - if(mClient.state() == ProcessState::kProcessing) + if (mClient.state() == ProcessState::kProcessing) { - std::cout << Wrapper::getName() << ": Processing cancelled \n"; - Wrapper::getInterfaceTable()->fSendNodeReply(&mParent->mNode,1,"/done",0,nullptr); + std::cout << Wrapper::getName() << ": Processing cancelled" << std::endl; + Wrapper::getInterfaceTable()->fSendNodeReply(&mParent->mNode, 1, "/done", + 0, nullptr); } - //processing will be cancelled in ~NRTThreadAdaptor() + // processing will be cancelled in ~NRTThreadAdaptor() } - + /// No option of not using a worker thread for now - /// init() sets up the NRT process via the SC NRT thread, and then sets our UGen calc function going + /// init() sets up the NRT process via the SC NRT thread, and then sets our + /// UGen calc function going void init() { mFifoMsg.Set(mWorld, initNRTJob, nullptr, this); - mWorld->ft->fSendMsgFromRT(mWorld,mFifoMsg); - //we want to poll thread roughly every 20ms - checkThreadInterval = static_cast(0.02 / controlDur()); + mWorld->ft->fSendMsgFromRT(mWorld, mFifoMsg); + // we want to poll thread roughly every 20ms + checkThreadInterval = static_cast(0.02 / controlDur()); set_calc_function(); }; - - /// The calc function. Checks to see if we've cancelled, spits out progress, launches tidy up when complete + + /// The calc function. Checks to see if we've cancelled, spits out progress, + /// launches tidy up when complete void poll(int) { - out0(0) = mDone ? 1.0 : static_cast(mClient.progress()); + out0(0) = mDone ? 1.0f : static_cast(mClient.progress()); - if(0 == pollCounter++ && !mCheckingForDone) + if (0 == pollCounter++ && !mCheckingForDone) { mCheckingForDone = true; - mWorld->ft->fDoAsynchronousCommand(mWorld, nullptr, Wrapper::getName(), this, - postProcess, exchangeBuffers, tidyUp, destroy, - 0, nullptr); + mWorld->ft->fDoAsynchronousCommand(mWorld, nullptr, Wrapper::getName(), + this, postProcess, exchangeBuffers, + tidyUp, destroy, 0, nullptr); } pollCounter %= checkThreadInterval; } - - /// To be called on NRT thread. Validate parameters and commence processing in new thread + + /// To be called on NRT thread. Validate parameters and commence processing in + /// new thread static void initNRTJob(FifoMsg* f) { auto w = static_cast(f->mData); @@ -261,42 +306,51 @@ public: w->mCancelled = false; Result result = validateParameters(w); - + if (!result.ok()) { - std::cout << "ERROR: " << Wrapper::getName() << ": " << result.message().c_str() << std::endl; - return; + std::cout << "ERROR: " << Wrapper::getName() << ": " + << result.message().c_str() << std::endl; + return; } - w->mClient.setSynchronous(w->mSynchronous); + w->mClient.setSynchronous(w->mSynchronous); w->mClient.enqueue(w->mParams); w->mClient.process(); } /// Check result and report if bad - static bool postProcess(World*, void *data) + static bool postProcess(World*, void* data) { - auto w = static_cast(data); - Result r; + auto w = static_cast(data); + Result r; ProcessState s = w->mClient.checkProgress(r); - - if((s==ProcessState::kDone || s==ProcessState::kDoneStillProcessing) - || (w->mSynchronous && s==ProcessState::kNoProcess) ) //I think this hinges on the fact that when mSynchrous = true, this call will always be behind process() on the command FIFO, so we can assume that if the state is kNoProcess, it has run (vs never having run) + + if ((s == ProcessState::kDone || s == ProcessState::kDoneStillProcessing) || + (w->mSynchronous && + s == ProcessState::kNoProcess)) // I think this hinges on the fact that + // when mSynchrous = true, this call + // will always be behind process() on + // the command FIFO, so we can assume + // that if the state is kNoProcess, it + // has run (vs never having run) { - //Given that cancellation from the language now always happens by freeing the - //synth, this block isn't reached normally. HOwever, if someone cancels using u_cmd, this is what will fire - if(r.status() == Result::Status::kCancelled) + // Given that cancellation from the language now always happens by freeing + // the synth, this block isn't reached normally. HOwever, if someone + // cancels using u_cmd, this is what will fire + if (r.status() == Result::Status::kCancelled) { - std::cout << Wrapper::getName() << ": Processing cancelled \n"; + std::cout << Wrapper::getName() << ": Processing cancelled" << std::endl; w->mCancelled = true; return false; } - - if(!r.ok()) + + if (!r.ok()) { - std::cout << "ERROR: " << Wrapper::getName() << ": " << r.message().c_str() << '\n'; + std::cout << "ERROR: " << Wrapper::getName() << ": " + << r.message().c_str() << std::endl; return false; } - + w->mDone = true; return true; } @@ -304,88 +358,121 @@ public: } /// swap NRT buffers back to RT-land - static bool exchangeBuffers(World *world, void *data) { return static_cast(data)->exchangeBuffers(world); } + static bool exchangeBuffers(World* world, void* data) + { + return static_cast(data)->exchangeBuffers(world); + } /// Tidy up any temporary buffers - static bool tidyUp(World *world, void *data) { return static_cast(data)->tidyUp(world); } - - /// Now we're actually properly done, call the UGen's done action (possibly destroying this instance) + static bool tidyUp(World* world, void* data) + { + return static_cast(data)->tidyUp(world); + } + + /// Now we're actually properly done, call the UGen's done action (possibly + /// destroying this instance) static void destroy(World* world, void* data) { auto w = static_cast(data); - if(w->mDone && w->mNumInputs > 2) //don't check for doneAction if UGen has no ins (there should be 3 minimum -> sig, doneAction, blocking mode) + if (w->mDone && + w->mNumInputs > + 2) // don't check for doneAction if UGen has no ins (there should be + // 3 minimum -> sig, doneAction, blocking mode) { - int doneAction = static_cast(w->in0(static_cast(w->mNumInputs - 2))); //doneAction is penultimate input; THIS IS THE LAW - world->ft->fDoneAction(doneAction,w); + int doneAction = static_cast( + w->in0(int(w->mNumInputs) - + 2)); // doneAction is penultimate input; THIS IS THE LAW + world->ft->fDoneAction(doneAction, w); return; } w->mCheckingForDone = false; } - - static void doCancel(Unit *unit, sc_msg_iter*) + + static void doCancel(Unit* unit, sc_msg_iter*) { - static_cast(unit)->mClient.cancel(); + static_cast(unit)->mClient.cancel(); } + private: - - static Result validateParameters(NonRealTime *w) + static Result validateParameters(NonRealTime* w) { auto results = w->mParams.constrainParameterValues(); - for (auto &r : results) + for (auto& r : results) { if (!r.ok()) return r; } return {}; } - bool exchangeBuffers(World *world) //RT thread + bool exchangeBuffers(World* world) // RT thread { - mParams.template forEachParamType(world); - //At this point, we can see if we're finished and let the language know (or it can wait for the doneAction, but that takes extra time) - //use replyID to convey status (0 = normal completion, 1 = cancelled) - if(mDone) world->ft->fSendNodeReply(&mParent->mNode,0,"/done",0,nullptr); - if(mCancelled) world->ft->fSendNodeReply(&mParent->mNode,1,"/done",0,nullptr); + mParams.template forEachParamType(world); + // At this point, we can see if we're finished and let the language know (or + // it can wait for the doneAction, but that takes extra time) use replyID to + // convey status (0 = normal completion, 1 = cancelled) + if (mDone) + world->ft->fSendNodeReply(&mParent->mNode, 0, "/done", 0, nullptr); + if (mCancelled) + world->ft->fSendNodeReply(&mParent->mNode, 1, "/done", 0, nullptr); return true; } - bool tidyUp(World *) //NRT thread + bool tidyUp(World*) // NRT thread { mParams.template forEachParamType(); return true; } + template + struct AssignBuffer + { + void operator()(const typename BufferT::type& p, World* w) + { + if (auto b = static_cast(p.get())) b->assignToRT(w); + } + }; + + template + struct CleanUpBuffer + { + void operator()(const typename BufferT::type& p) + { + if (auto b = static_cast(p.get())) b->cleanUp(); + } + }; + + FloatControlsIter mControlsIterator; + FifoMsg mFifoMsg; + char* mCompletionMessage = nullptr; + void* mReplyAddr = nullptr; + const char* mName = nullptr; + index checkThreadInterval; + index pollCounter{0}; - - FloatControlsIter mControlsIterator; - FifoMsg mFifoMsg; - char* mCompletionMessage = nullptr; - void* mReplyAddr = nullptr; - const char *mName = nullptr; - size_t checkThreadInterval; - size_t pollCounter{0}; protected: - ParamSetType mParams; - Client mClient; - bool mSynchronous{true}; - bool mQueueEnabled{false}; - bool mCheckingForDone{false}; //only write to this from RT thread kthx - bool mCancelled{false}; + ParamSetType mParams; + Client mClient; + bool mSynchronous{true}; + bool mQueueEnabled{false}; + bool mCheckingForDone{false}; // only write to this from RT thread kthx + bool mCancelled{false}; }; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + /// An impossible monstrosty template -class NonRealTimeAndRealTime : public RealTime, public NonRealTime +class NonRealTimeAndRealTime : public RealTime, + public NonRealTime { - static void setup(InterfaceTable *ft, const char *name) + static void setup(InterfaceTable* ft, const char* name) { - RealTime::setup(ft, name); - NonRealTime::setup(ft, name); + RealTime::setup(ft, name); + NonRealTime::setup(ft, name); } }; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + // Template Specialisations for NRT/RT template @@ -394,26 +481,26 @@ class FluidSCWrapperImpl; template class FluidSCWrapperImpl : public NonRealTime -{ -//public: -// FluidSCWrapperImpl(World* w, sc_msg_iter *args): NonRealTime(w,args){}; -}; +{}; template -class FluidSCWrapperImpl : public RealTime +class FluidSCWrapperImpl + : public RealTime {}; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +//////////////////////////////////////////////////////////////////////////////// + // Make base class(es), full of CRTP mixin goodness template -using FluidSCWrapperBase = FluidSCWrapperImpl, typename Client::isNonRealTime, typename Client::isRealTime>; +using FluidSCWrapperBase = + FluidSCWrapperImpl, isNonRealTime, + isRealTime>; } // namespace impl -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// -///The main wrapper +/// The main wrapper template class FluidSCWrapper : public impl::FluidSCWrapperBase { @@ -434,7 +521,7 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase static auto fromArgs(World *w, FloatControlsIter& args, std::string, int) { //first is string size, then chars - int size = static_cast(args.next()); + index size = args.next(); char* chunk = static_cast(FluidSCWrapper::getInterfaceTable()->fRTAlloc(w,size + 1)); if (!chunk) { @@ -442,7 +529,7 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase return std::string{""}; } - for(int i = 0; i < size; ++i) + for(index i = 0; i < size; ++i) chunk[i] = static_cast(args.next()); chunk[size] = 0; //terminate string @@ -475,8 +562,10 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase static auto fromArgs(World *w, ArgType args, InputBufferT::type&, int) { - typename LongT::type bufnum = static_cast(fromArgs(w, args, LongT::type(), -1)); - return InputBufferT::type(bufnum >= 0 ? new SCBufferAdaptor(bufnum, w) : nullptr); + typename LongT::type bufnum = + static_cast(fromArgs(w, args, LongT::type(), -1)); + return InputBufferT::type(bufnum >= 0 ? new SCBufferAdaptor(bufnum, w) + : nullptr); } template @@ -494,7 +583,7 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase template struct Setter { - static constexpr size_t argSize = C::getParameterDescriptors().template get().fixedSize; + static constexpr index argSize = C::getParameterDescriptors().template get().fixedSize; typename T::type operator()(World *w, ArgType args) { @@ -506,9 +595,10 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase } ParamLiteralConvertor a; - using LiteralType = typename ParamLiteralConvertor::LiteralType; + using LiteralType = + typename ParamLiteralConvertor::LiteralType; - for (size_t i = 0; i < argSize; i++) + for (index i = 0; i < argSize; i++) a[i] = static_cast(ParamReader::fromArgs(w, args, a[0], 0)); return a.value(); @@ -713,42 +803,59 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase ft->fSendNodeReply(&x->mParent->mNode, -1, s.c_str(), static_cast(numArgs), values); } - - + + + static void doVersion(Unit*, sc_msg_iter*) + { + std::cout << "Fluid Corpus Manipualtion Toolkit version " << fluidVersion() + << std::endl; + } + + public: using Client = C; using ParameterSetType = typename C::ParamSetType; - FluidSCWrapper() - { - impl::FluidSCWrapperBase::init(); - } + FluidSCWrapper() { impl::FluidSCWrapperBase::init(); } - static const char *getName(const char *setName = nullptr) + static const char* getName(const char* setName = nullptr) { - static const char *name = nullptr; + static const char* name = nullptr; return (name = setName ? setName : name); } - static InterfaceTable *getInterfaceTable(InterfaceTable *setTable = nullptr) + static InterfaceTable* getInterfaceTable(InterfaceTable* setTable = nullptr) { - static InterfaceTable *ft = nullptr; + static InterfaceTable* ft = nullptr; return (ft = setTable ? setTable : ft); } - static void setup(InterfaceTable *ft, const char *name) + static void setup(InterfaceTable* ft, const char* name) { getName(name); getInterfaceTable(ft); impl::FluidSCWrapperBase::setup(ft, name); Client::getMessageDescriptors().template iterate(); + ft->fDefineUnitCmd(name, "version", doVersion); } - static auto& setParams(ParameterSetType& p, bool verbose, World* world, FloatControlsIter& inputs, bool constrain = false) + static auto& setParams(ParameterSetType& p, bool verbose, World* world, + FloatControlsIter& inputs, bool constrain = false) { - p.template setParameterValues(verbose, world, inputs); - if(inputs.remain() > 0) std::cout << "WARNING: "<< getName() << " received " << inputs.remain() << " more parameters than expected. Perhaps your binary plugins and SC sources are different versions\n"; - if (constrain) p.constrainParameterValues(); + // We won't even try and set params if the arguments don't match + if (inputs.size() == C::getParameterDescriptors().count()) + { + p.template setParameterValues(verbose, world, inputs); + if (constrain) p.constrainParameterValues(); + } + else + { + std::cout << "ERROR: " << getName() + << ": parameter count mismatch. Perhaps your binary plugins " + "and SC sources are different versions" + << std::endl; + } + return p; } diff --git a/include/SCBufferAdaptor.hpp b/include/SCBufferAdaptor.hpp index e1ae6e1..5b31b3b 100644 --- a/include/SCBufferAdaptor.hpp +++ b/include/SCBufferAdaptor.hpp @@ -1,11 +1,21 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ + #pragma once -#include -#include #include -#include -#include #include +#include +#include +#include +#include #include #include #include @@ -13,29 +23,25 @@ #include -namespace fluid -{ -namespace client -{ +namespace fluid { +namespace client { /** A descendent of SndBuf that will populate itself from the NRT mirror buffers given a world and a bufnum **/ -struct NRTBuf { - NRTBuf(SndBuf *b) - : mBuffer(b) - { - } - NRTBuf(World *world, uint32 bufnum, bool rt = false) - : NRTBuf(rt ? World_GetBuf(world, bufnum) - : World_GetNRTBuf(world, bufnum)) +struct NRTBuf +{ + NRTBuf(SndBuf* b) : mBuffer(b) {} + NRTBuf(World* world, index bufnum, bool rt = false) + : NRTBuf(rt ? World_GetBuf(world, static_cast(bufnum)) + : World_GetNRTBuf(world, static_cast(bufnum))) { if (mBuffer && !static_cast(mBuffer->samplerate)) mBuffer->samplerate = world->mFullRate.mSampleRate; } protected: - SndBuf *mBuffer; + SndBuf* mBuffer; }; /** @@ -57,30 +63,24 @@ protected: class SCBufferAdaptor : public NRTBuf, public client::BufferAdaptor { public: -// SCBufferAdaptor() = delete; - SCBufferAdaptor(const SCBufferAdaptor &) = delete; - SCBufferAdaptor& operator=(const SCBufferAdaptor &) = delete; + // SCBufferAdaptor() = delete; + SCBufferAdaptor(const SCBufferAdaptor&) = delete; + SCBufferAdaptor& operator=(const SCBufferAdaptor&) = delete; SCBufferAdaptor(SCBufferAdaptor&&) = default; SCBufferAdaptor& operator=(SCBufferAdaptor&&) = default; - SCBufferAdaptor(intptr_t bufnum,World *world, bool rt = false) - : NRTBuf(world, static_cast(bufnum), rt) - , mBufnum(bufnum) - , mWorld(world) - { - } - + SCBufferAdaptor(index bufnum, World* world, bool rt = false) + : NRTBuf(world, bufnum, rt), mBufnum(bufnum), mWorld(world) + {} - SCBufferAdaptor() = default; + ~SCBufferAdaptor() { cleanUp(); } - ~SCBufferAdaptor(){ cleanUp(); } - - void assignToRT(World *rtWorld) + void assignToRT(World* rtWorld) { - SndBuf *rtBuf = World_GetBuf(rtWorld, static_cast(mBufnum)); - *rtBuf = *mBuffer; + SndBuf* rtBuf = World_GetBuf(rtWorld, static_cast(mBufnum)); + *rtBuf = *mBuffer; rtWorld->mSndBufUpdates[mBufnum].writes++; } @@ -90,7 +90,7 @@ public: { boost::alignment::aligned_free(mOldData); mOldData = nullptr; - } + } } // No locks in (vanilla) SC, so no-ops for these @@ -101,99 +101,95 @@ public: // knows about bool valid() const override { - return (mBuffer && mBufnum >= 0 && mBufnum < mWorld->mNumSndBufs); - } - - bool exists() const override - { - return true; + return (mBuffer && mBufnum >= 0 && mBufnum < asSigned(mWorld->mNumSndBufs)); } - FluidTensorView samps(size_t channel) override + bool exists() const override { return true; } + + FluidTensorView samps(index channel) override { - FluidTensorView v{mBuffer->data, 0, - static_cast(mBuffer->frames), - static_cast(mBuffer->channels)}; + FluidTensorView v{mBuffer->data, 0, mBuffer->frames, + mBuffer->channels}; return v.col(channel); } - FluidTensorView samps(size_t offset, size_t nframes, - size_t chanoffset) override + FluidTensorView samps(index offset, index nframes, + index chanoffset) override { - FluidTensorView v{mBuffer->data, 0, - static_cast(mBuffer->frames), - static_cast(mBuffer->channels)}; + FluidTensorView v{mBuffer->data, 0, mBuffer->frames, + mBuffer->channels}; return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1)).col(0); } - FluidTensorView samps(size_t channel) const override + FluidTensorView samps(index channel) const override { - FluidTensorView v{mBuffer->data, 0, - static_cast(mBuffer->frames), - static_cast(mBuffer->channels)}; + FluidTensorView v{mBuffer->data, 0, mBuffer->frames, + mBuffer->channels}; return v.col(channel); } - FluidTensorView samps(size_t offset, size_t nframes, - size_t chanoffset) const override + FluidTensorView samps(index offset, index nframes, + index chanoffset) const override { - FluidTensorView v{mBuffer->data, 0, - static_cast(mBuffer->frames), - static_cast(mBuffer->channels)}; + FluidTensorView v{mBuffer->data, 0, mBuffer->frames, + mBuffer->channels}; return v(fluid::Slice(offset, nframes), fluid::Slice(chanoffset, 1)).col(0); } - size_t numFrames() const override + index numFrames() const override { - return valid() ? static_cast(this->mBuffer->frames) : 0u; + return valid() ? this->mBuffer->frames : 0; } - size_t numChans() const override + index numChans() const override { - return valid() ? static_cast(this->mBuffer->channels) : 0u; + return valid() ? this->mBuffer->channels : 0; } - double sampleRate() const override { return valid() ? mBuffer->samplerate : 0; } + double sampleRate() const override + { + return valid() ? mBuffer->samplerate : 0; + } - std::string asString() const override { return std::to_string(bufnum()); } + std::string asString() const override { return std::to_string(bufnum()); } - const Result resize(size_t frames, size_t channels, double sampleRate) override + const Result resize(index frames, index channels, double sampleRate) override { - SndBuf *thisThing = mBuffer; - mOldData = thisThing->data; - int allocResult = mWorld->ft->fBufAlloc(mBuffer, static_cast(channels), static_cast(frames), sampleRate); - + SndBuf* thisThing = mBuffer; + mOldData = thisThing->data; + int allocResult = + mWorld->ft->fBufAlloc(mBuffer, static_cast(channels), + static_cast(frames), sampleRate); + Result r; - - if(allocResult != kSCErr_None) + + if (allocResult != kSCErr_None) { r.set(Result::Status::kError); r.addMessage("Resize on buffer ", bufnum(), " failed."); } - return r; + return r; } - intptr_t bufnum() const { return mBufnum; } - void realTime(bool rt) { mRealTime = rt; } + index bufnum() const { return mBufnum; } + void realTime(bool rt) { mRealTime = rt; } protected: - - bool mRealTime{false}; - float *mOldData{0}; - intptr_t mBufnum; - World *mWorld; + bool mRealTime{false}; + float* mOldData{0}; + index mBufnum; + World* mWorld; }; -std::ostream& operator <<(std::ostream& os, SCBufferAdaptor& b) +std::ostream& operator<<(std::ostream& os, SCBufferAdaptor& b) { - return os << b.bufnum(); + return os << b.bufnum(); } } // namespace client } // namespace fluid - diff --git a/license.md b/license.md new file mode 100644 index 0000000..a17c640 --- /dev/null +++ b/license.md @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017-2019 University of Huddersfield +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/release-packaging/Classes/FluidAmpGate.sc b/release-packaging/Classes/FluidAmpGate.sc new file mode 100644 index 0000000..1fe4a29 --- /dev/null +++ b/release-packaging/Classes/FluidAmpGate.sc @@ -0,0 +1,11 @@ +FluidAmpGate : UGen { + *ar { arg in = 0, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, maxSize = 88200; + ^this.multiNew('audio', in.asAudioRateInput(this), rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq, maxSize) + } + checkInputs { + if(inputs.at(12).rate != 'scalar') { + ^(": maxSize cannot be modulated."); + }; + ^this.checkValidInputs; + } +} diff --git a/release-packaging/Classes/FluidAmpSlice.sc b/release-packaging/Classes/FluidAmpSlice.sc index 27640a9..d39e1af 100644 --- a/release-packaging/Classes/FluidAmpSlice.sc +++ b/release-packaging/Classes/FluidAmpSlice.sc @@ -1,11 +1,9 @@ FluidAmpSlice : UGen { - *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; - ^this.multiNew('audio', in.asAudioRateInput(this), absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq, maxSize, 0) + *ar { arg in = 0, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85; + + ^this.multiNew('audio', in.asAudioRateInput(this), fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq) } checkInputs { - if(inputs.at(16).rate != 'scalar') { - ^(": maxSize cannot be modulated."); - }; ^this.checkValidInputs; } } diff --git a/release-packaging/Classes/FluidBufAmpGate.sc b/release-packaging/Classes/FluidBufAmpGate.sc new file mode 100644 index 0000000..cd32d7b --- /dev/null +++ b/release-packaging/Classes/FluidBufAmpGate.sc @@ -0,0 +1,37 @@ +FluidBufAmpGate : UGen { + + *new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, doneAction = 0, blocking| + var maxSize = max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead)); + + source = source.asUGenInput; + indices = indices.asUGenInput; + + source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw}; + indices.isNil.if {"FluidBufAmpSlice: Invalid features buffer".throw}; + + ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq, maxSize, doneAction, blocking); + } + + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, doneAction = 0| + + ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq, doneAction,blocking:0); + } + + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, action | + + ^FluidNRTProcess.new( + server, this, action, [indices] + ).process( + source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq + ); + } + + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, rampUp = 10, rampDown = 10, onThreshold = -90, offThreshold = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, highPassFreq = 85, action| + + ^FluidNRTProcess.new( + server, this, action, [indices], blocking: 1 + ).process( + source, startFrame, numFrames, startChan, numChans, indices, rampUp, rampDown, onThreshold, offThreshold, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, highPassFreq + ); + } +} diff --git a/release-packaging/Classes/FluidBufAmpSlice.sc b/release-packaging/Classes/FluidBufAmpSlice.sc index 8205564..d2ceae4 100644 --- a/release-packaging/Classes/FluidBufAmpSlice.sc +++ b/release-packaging/Classes/FluidBufAmpSlice.sc @@ -1,7 +1,6 @@ FluidBufAmpSlice : UGen { - *new1 { |rate, 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, doneAction = 0, blocking| - var maxSize = max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead)); + *new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, doneAction = 0, blocking| source = source.asUGenInput; indices = indices.asUGenInput; @@ -9,29 +8,29 @@ FluidBufAmpSlice : UGen { source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw}; indices.isNil.if {"FluidBufAmpSlice: Invalid features buffer".throw}; - ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq, maxSize, 0, doneAction, blocking); + ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq, doneAction, blocking); } - *kr { |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, doneAction = 0| + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, doneAction = 0| - ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq, 0, doneAction,blocking:0); + ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq, doneAction,blocking:0); } - *process { |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, action | + *process { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, action | ^FluidNRTProcess.new( server, this, action, [indices] ).process( - source, startFrame, numFrames, startChan, numChans, indices, absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq + source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq ); } - *processBlocking { |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, action| + *processBlocking { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, action| ^FluidNRTProcess.new( server, this, action, [indices], blocking: 1 ).process( - source, startFrame, numFrames, startChan, numChans, indices, absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq + source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq ); } } diff --git a/release-packaging/Classes/FluidBufMelBands.sc b/release-packaging/Classes/FluidBufMelBands.sc index c9fa718..6ec3f8f 100644 --- a/release-packaging/Classes/FluidBufMelBands.sc +++ b/release-packaging/Classes/FluidBufMelBands.sc @@ -1,5 +1,5 @@ FluidBufMelBands : UGen { - *new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0, blocking = 0| + *new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0, blocking = 0| var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -13,26 +13,26 @@ FluidBufMelBands : UGen { //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) // same for maxNumBands which is passed numBands - ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, windowSize, hopSize, fftSize, maxFFTSize, doneAction, blocking); + ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize, maxFFTSize, doneAction, blocking); } - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0| - ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, windowSize, hopSize, fftSize, doneAction); + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0| + ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize, doneAction); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, action| + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, action| ^FluidNRTProcess.new( server, this, action, [features] ).process( - source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, windowSize, hopSize, fftSize + source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, normalize, windowSize, hopSize, fftSize ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, action| + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, action| ^FluidNRTProcess.new( server, this, action, [features], blocking:1 ).process( - source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, windowSize, hopSize, fftSize + source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, normalize, windowSize, hopSize, fftSize ); } } \ No newline at end of file diff --git a/release-packaging/Classes/FluidBufNMF.sc b/release-packaging/Classes/FluidBufNMF.sc index 87fac60..1d41eed 100644 --- a/release-packaging/Classes/FluidBufNMF.sc +++ b/release-packaging/Classes/FluidBufNMF.sc @@ -1,47 +1,47 @@ FluidBufNMF : UGen { - *new1 {|rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, bases, basesMode = 0, activations, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, doneAction = 0, blocking = 0| + *new1 {|rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth, bases, basesMode = 0, activations, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, doneAction = 0, blocking = 0| source = source.asUGenInput; - destination = destination.asUGenInput; + resynth = resynth.asUGenInput; bases = bases.asUGenInput; activations = activations.asUGenInput; source.isNil.if {"FluidBufNMF: Invalid source buffer".throw}; - destination = destination ? -1; + resynth = resynth ? -1; bases = bases ? -1; activations = activations ? -1; - ^super.new1(rate,source, startFrame, numFrames, startChan, numChans, destination, bases, basesMode, activations, actMode, components, iterations, windowSize, hopSize, fftSize, doneAction, blocking); + ^super.new1(rate,source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components, iterations, windowSize, hopSize, fftSize, doneAction, blocking); } - *kr {|source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination, bases, basesMode = 0, activations, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, doneAction = 0| - ^this.multiNew(\control,source, startFrame, numFrames, startChan, numChans, destination, bases, basesMode, activations, actMode, components, iterations, windowSize, hopSize, fftSize, doneAction); + *kr {|source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth, bases, basesMode = 0, activations, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, doneAction = 0| + ^this.multiNew(\control,source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components, iterations, windowSize, hopSize, fftSize, doneAction); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination = -1, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, action| + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth = -1, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, action| source.isNil.if {"FluidBufNMF: Invalid source buffer".throw}; ^FluidNRTProcess.new( - server, this, action, [destination, bases, activations].select{|x| x!= -1} + server, this, action, [resynth, bases, activations].select{|x| x!= -1} ).process( - source, startFrame, numFrames, startChan, numChans, destination, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, windowType, randomSeed + source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, windowType, randomSeed ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, destination = -1, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, action| + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth = -1, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, windowType = 0, randomSeed = -1, action| source.isNil.if {"FluidBufNMF: Invalid source buffer".throw}; ^FluidNRTProcess.new( - server, this, action, [destination, bases, activations].select{|x| x!= -1},blocking: 1 + server, this, action, [resynth, bases, activations].select{|x| x!= -1},blocking: 1 ).process( - source, startFrame, numFrames, startChan, numChans, destination, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, windowType, randomSeed + source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, windowType, randomSeed ); } } diff --git a/release-packaging/Classes/FluidBufNoveltySlice.sc b/release-packaging/Classes/FluidBufNoveltySlice.sc index a2bf80d..7467349 100644 --- a/release-packaging/Classes/FluidBufNoveltySlice.sc +++ b/release-packaging/Classes/FluidBufNoveltySlice.sc @@ -1,5 +1,5 @@ FluidBufNoveltySlice : UGen { - *new1 { |rate, 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, doneAction = 0, blocking = 0 | + *new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, feature = 0, kernelSize = 3, threshold = 0.5, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0, blocking = 0 | var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -9,29 +9,29 @@ FluidBufNoveltySlice : UGen { source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw}; indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw}; - ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize, doneAction, blocking); + ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize, doneAction, blocking); } - *kr { |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, doneAction = 0 | + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, feature = 0, kernelSize = 3, threshold = 0.5, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0 | - ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, windowSize, hopSize, fftSize, doneAction); + ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, minSliceLength, windowSize, hopSize, fftSize, doneAction); } - *process { |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 | + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, feature = 0, kernelSize = 3, threshold = 0.5, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, action | ^FluidNRTProcess.new( server, this, action, [indices] ).process( - source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, windowSize, hopSize, fftSize + source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, minSliceLength, windowSize, hopSize, fftSize ); } - *processBlocking { |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 | + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, feature = 0, kernelSize = 3, threshold = 0.5, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, action | ^FluidNRTProcess.new( server, this, action, [indices], blocking:1 ).process( - source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, windowSize, hopSize, fftSize + source, startFrame, numFrames, startChan, numChans, indices, feature, kernelSize, threshold, filterSize, minSliceLength, windowSize, hopSize, fftSize ); } } diff --git a/release-packaging/Classes/FluidBufSines.sc b/release-packaging/Classes/FluidBufSines.sc index ad65c64..dce7f43 100644 --- a/release-packaging/Classes/FluidBufSines.sc +++ b/release-packaging/Classes/FluidBufSines.sc @@ -1,6 +1,6 @@ FluidBufSines : UGen{ - *new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, sines = -1, residual = -1, bandwidth = 76, threshold = 0.7, minTrackLen = 15, magWeight = 0.1, freqWeight = 1, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0, blocking = 0| + *new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, sines = -1, residual = -1, bandwidth = 76, detectionThreshold = -96, birthLowThreshold = -24, birthHighThreshold = -60, minTrackLen = 15, trackingMethod = 0, trackMagRange = 15, trackFreqRange = 50, trackProb = 0.5, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0, blocking = 0| var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -13,26 +13,26 @@ FluidBufSines : UGen{ //NB For wrapped versions of NRT classes, we set the params for maxima to //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) - ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, sines, residual, bandwidth, threshold, minTrackLen, magWeight, freqWeight, windowSize, hopSize, fftSize, maxFFTSize, doneAction, blocking); + ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, sines, residual, bandwidth, detectionThreshold,birthLowThreshold, birthHighThreshold, minTrackLen, trackingMethod, trackMagRange, trackFreqRange, trackProb, windowSize, hopSize, fftSize, maxFFTSize, doneAction, blocking); } - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, sines = -1, residual = -1, bandwidth = 76, threshold = 0.7, minTrackLen = 15, magWeight = 0.1, freqWeight = 1, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0| - ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, sines, residual, bandwidth, threshold, minTrackLen, magWeight, freqWeight, windowSize, hopSize, fftSize, doneAction); + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, sines = -1, residual = -1, bandwidth = 76, detectionThreshold = -96, birthLowThreshold = -24, birthHighThreshold = -60, minTrackLen = 15, trackingMethod = 0, trackMagRange = 15, trackFreqRange = 50, trackProb = 0.5, windowSize = 1024, hopSize = -1, fftSize = -1, doneAction = 0| + ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, sines, residual, bandwidth, detectionThreshold,birthLowThreshold, birthHighThreshold, minTrackLen, trackingMethod, trackMagRange, trackFreqRange, trackProb, windowSize, hopSize, fftSize, doneAction); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, sines = -1, residual = -1, bandwidth = 76, threshold = 0.7, minTrackLen = 15, magWeight = 0.1, freqWeight = 1, windowSize = 1024, hopSize = -1, fftSize = -1, action| + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, sines = -1, residual = -1, bandwidth = 76, detectionThreshold = -96, birthLowThreshold = -24, birthHighThreshold = -60, minTrackLen = 15, trackingMethod = 0, trackMagRange = 15, trackFreqRange = 50, trackProb = 0.5, windowSize = 1024, hopSize = -1, fftSize = -1, action| ^FluidNRTProcess.new( server, this, action, [sines, residual].select{|x| x!= -1} ).process( - source, startFrame, numFrames, startChan, numChans, sines, residual, bandwidth, threshold, minTrackLen, magWeight, freqWeight, windowSize, hopSize, fftSize + source, startFrame, numFrames, startChan, numChans, sines, residual, bandwidth, detectionThreshold,birthLowThreshold, birthHighThreshold, minTrackLen, trackingMethod, trackMagRange, trackFreqRange, trackProb, windowSize, hopSize, fftSize ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, sines = -1, residual = -1, bandwidth = 76, threshold = 0.7, minTrackLen = 15, magWeight = 0.1, freqWeight = 1, windowSize = 1024, hopSize = -1, fftSize = -1, action| + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, sines = -1, residual = -1, bandwidth = 76, detectionThreshold = -96, birthLowThreshold = -24, birthHighThreshold = -60, minTrackLen = 15, trackingMethod = 0, trackMagRange = 15, trackFreqRange = 50, trackProb = 0.5, windowSize = 1024, hopSize = -1, fftSize = -1, action| ^FluidNRTProcess.new( server, this, action, [sines, residual].select{|x| x!= -1}, blocking: 1 ).process( - source, startFrame, numFrames, startChan, numChans, sines, residual, bandwidth, threshold, minTrackLen, magWeight, freqWeight, windowSize, hopSize, fftSize + source, startFrame, numFrames, startChan, numChans, sines, residual, bandwidth, detectionThreshold,birthLowThreshold, birthHighThreshold, minTrackLen, trackingMethod, trackMagRange, trackFreqRange, trackProb, windowSize, hopSize, fftSize ); } diff --git a/release-packaging/Classes/FluidMelBands.sc b/release-packaging/Classes/FluidMelBands.sc index 3021006..db0aa35 100644 --- a/release-packaging/Classes/FluidMelBands.sc +++ b/release-packaging/Classes/FluidMelBands.sc @@ -1,7 +1,7 @@ FluidMelBands : MultiOutUGen { - *kr { arg in = 0, numBands = 40, minFreq = 20, maxFreq = 20000, maxNumBands = 120, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; - ^this.multiNew('control', in.asAudioRateInput(this), numBands, minFreq, maxFreq, maxNumBands, windowSize, hopSize, fftSize, maxFFTSize); + *kr { arg in = 0, numBands = 40, minFreq = 20, maxFreq = 20000, maxNumBands = 120, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; + ^this.multiNew('control', in.asAudioRateInput(this), numBands, minFreq, maxFreq, maxNumBands, normalize, windowSize, hopSize, fftSize, maxFFTSize); } init {arg ...theInputs; diff --git a/release-packaging/Classes/FluidNoveltySlice.sc b/release-packaging/Classes/FluidNoveltySlice.sc index 80d57ca..a0ecbe1 100644 --- a/release-packaging/Classes/FluidNoveltySlice.sc +++ b/release-packaging/Classes/FluidNoveltySlice.sc @@ -1,6 +1,6 @@ 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) + *ar { arg in = 0, feature = 0, kernelSize = 3, threshold = 0.8, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384, maxKernelSize = 101, maxFilterSize = 100; + ^this.multiNew('audio', in.asAudioRateInput(this), feature, kernelSize, threshold, filterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize, maxKernelSize, maxFilterSize) } checkInputs { if(inputs.at(8).rate != 'scalar') { diff --git a/release-packaging/Classes/FluidSines.sc b/release-packaging/Classes/FluidSines.sc old mode 100644 new mode 100755 index 5edf880..8676004 --- a/release-packaging/Classes/FluidSines.sc +++ b/release-packaging/Classes/FluidSines.sc @@ -1,6 +1,6 @@ FluidSines : MultiOutUGen { - *ar { arg in = 0, bandwidth = 76, threshold = 0.7, minTrackLen = 15, magWeight = 0.1, freqWeight = 1.0, windowSize= 1024, hopSize= -1, fftSize= -1, maxFFTSize=16384; - ^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, threshold, minTrackLen, magWeight, freqWeight ,windowSize, hopSize, fftSize, maxFFTSize) + *ar { arg in = 0, bandwidth = 76, detectionThreshold = -96, birthLowThreshold = -24, birthHighThreshold = -60, minTrackLen = 15, trackingMethod = 0, trackMagRange = 15, trackFreqRange = 50, trackProb = 0.5, windowSize= 1024, hopSize= -1, fftSize= -1, maxFFTSize=16384; + ^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, detectionThreshold,birthLowThreshold, birthHighThreshold, minTrackLen, trackingMethod, trackMagRange, trackFreqRange, trackProb, windowSize, hopSize, fftSize, maxFFTSize) } init { arg ... theInputs; inputs = theInputs; @@ -11,7 +11,7 @@ FluidSines : MultiOutUGen { ^channels } checkInputs { - if(inputs.at(9).rate != 'scalar') { + if(inputs.at(13).rate != 'scalar') { ^(": maxFFTSize cannot be modulated."); }; ^this.checkNInputs(1) diff --git a/release-packaging/Examples/GUI_examples/HPSS.scd b/release-packaging/Examples/GUI_examples/HPSS.scd new file mode 100755 index 0000000..f426b04 --- /dev/null +++ b/release-packaging/Examples/GUI_examples/HPSS.scd @@ -0,0 +1,100 @@ +( +var win, soundFileView, freqSscope,loadButton, loopButton; +var harmSlider, percSlider, mixSlider; +var soundFile, buffer; +var synthDef, synth; +var makeSynthDef; + +Font.default = Font("Monaco", 16); +buffer = Buffer.new; +win = Window.new("HPSS", Rect(200,200,800,450)).background_(Color.gray); + +soundFileView = SoundFileView.new(win) + .gridOn_(false) + .waveColors_([Color.white]); + +loadButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_([["Load", Color.grey, Color.grey(0.8)]]); + +loopButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_( + [["Play", Color.grey, Color.grey(0.8)], + ["Stop", Color.grey, Color.grey(0.2)]] + ); + +harmSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +percSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +mixSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +freqSscope = FreqScopeView(win, server:Server.default); +freqSscope.active_(true); + +loadButton.action_{ + FileDialog({ |path| + soundFile = SoundFile.new; + soundFile.openRead(path[0]); + buffer = Buffer.read(Server.default, path[0]); + soundFileView.soundfile = soundFile; + soundFileView.read(0, soundFile.numFrames); + }); +}; + +loopButton.action_{|but| + if(but.value == 1, { + synth = Synth(\hpssExtractionDemo, [\buffer, buffer.bufnum]); + mixSlider.action.value(mixSlider); + },{ + synth.free; + }); +}; + + +mixSlider.action_{|slider| + synth.set(\bal, ControlSpec(0, 1).map(slider.value)); +}; + + + +makeSynthDef = { + +synthDef = SynthDef(\hpssExtractionDemo, + {|buffer, bal = 0.5| + var player, fhpss, mix; + var harmSize = (2 * ControlSpec(1, 100, step:1).map(harmSlider.value)) - 1; + var percSize = (2 * ControlSpec(1,100, step:1).map(percSlider.value)) - 1; + player = PlayBuf.ar(1, buffer, loop:1); + fhpss = FluidHPSS.ar(in: player, harmFilterSize: harmSize, percFilterSize: percSize, maskingMode: 1, harmThreshFreq1: 0.1, harmThreshAmp1: 0, harmThreshFreq2: 0.5, harmThreshAmp2: 0, percThreshFreq1: 0.1, percThreshAmp1: 0, percThreshFreq2: 0.5, percThreshAmp2: 0, windowSize: 1024, hopSize: 256, fftSize: -1); + + mix =(bal * fhpss[0]) + ((1 - bal) * fhpss[1]); + Out.ar(0,Pan2.ar(mix)); + } +).add; + +}; + +win.layout_( + VLayout( + [ + HLayout( + [loadButton, stretch:1], + [soundFileView, stretch:5] + ), stretch:2 + ], + [ + HLayout( + [loopButton, stretch:1], + [VLayout( + HLayout(StaticText(win).string_("H Size ").minWidth_(100), harmSlider), + HLayout(StaticText(win).string_("P Size").minWidth_(100), percSlider), + HLayout(StaticText(win).string_("Mix").minWidth_(100), mixSlider) + ), stretch:5] + ), stretch:2 + ], + [freqSscope, stretch:2] + ) +); + +makeSynthDef.value; +win.front; +) \ No newline at end of file diff --git a/release-packaging/Examples/GUI_examples/NMF4.scd b/release-packaging/Examples/GUI_examples/NMF4.scd new file mode 100755 index 0000000..cdd7833 --- /dev/null +++ b/release-packaging/Examples/GUI_examples/NMF4.scd @@ -0,0 +1,111 @@ +( +var server; +var win, soundFileView, loadButton, loopButton; +var sliders; +var soundFile, audioBuffer, destBuffer; +var synthDef, synth; +var sl1, sl2, sl3, sl4; + +server = Server.default; +Font.default = Font("Monaco", 16); + +audioBuffer = Buffer.new; +destBuffer = Buffer.new; + + +synthDef = SynthDef(\nmfDemo,{|bufnum, a1, a2, a3, a4| + var p = PlayBuf.ar(4, bufnum, loop:1); + var mix = (a1*p[0]) + (a2 * p[1]) + (a3*p[2]) + (a4*p[3]); + Out.ar(0, Pan2.ar(mix)); +}).add; + + + +win = Window.new("NMF4", + Rect(200,200,800,450)).background_(Color.gray); + +soundFileView = SoundFileView.new(win) + .gridOn_(false) + .waveColors_([Color.white]); + +loadButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_([["Load", Color.grey, Color.grey(0.8)], + ["Wait", Color.grey, Color.grey(0.2)]] + ); + +loopButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_( + [["Play", Color.grey, Color.grey(0.8)], + ["Stop", Color.grey, Color.grey(0.2)]] + ); + +sliders = Array.fill(4, {|i| + var s = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); + s.action_{ + var sym = ("a"++(i+1)).asSymbol; + synth.set(sym, ControlSpec(0, 1).map(s.value)); + } +}); + + +loadButton.action_{ + FileDialog({ |path| + soundFile = SoundFile.new; + soundFile.openRead(path[0]); + soundFileView.soundfile = soundFile; + soundFileView.read(0, soundFile.numFrames); + Routine{ + audioBuffer = Buffer.read(server, path[0]); + server.sync; + FluidBufNMF.process(server, + audioBuffer.bufnum,resynth:destBuffer.bufnum, components:4 + ); + server.sync; + destBuffer.query; + server.sync; + {loadButton.value_(0)}.defer; + }.play; + }); +}; + +loopButton.action_{|but| + var a1 = ControlSpec(0, 1).map(sliders[0].value); + var a2 = ControlSpec(0, 1).map(sliders[1].value); + var a3 = ControlSpec(0, 1).map(sliders[2].value); + var a4 = ControlSpec(0, 1).map(sliders[3].value); + + if(but.value == 1, { + synth = Synth(\nmfDemo, + [\bufnum, destBuffer.bufnum, \a1, a1, \a2, a2, \a3, a3, \a4, a4]); + },{ + synth.free; + }); +}; + + +win.layout_( + VLayout( + [ + HLayout( + [loadButton, stretch:1], + [soundFileView, stretch:5] + ), stretch:2 + ], + [ + HLayout( + [loopButton, stretch:1], + [VLayout( + HLayout(StaticText(win).string_("source 1 ").minWidth_(100), sliders[0]), + HLayout(StaticText(win).string_("source 2 ").minWidth_(100), sliders[1]), + HLayout(StaticText(win).string_("source 3 ").minWidth_(100), sliders[2]), + HLayout(StaticText(win).string_("source 4 ").minWidth_(100), sliders[3]) + ), stretch:5] + ), stretch:2 + ] + ) +); + +win.front; +) diff --git a/release-packaging/Examples/GUI_examples/NoveltySegmentation.scd b/release-packaging/Examples/GUI_examples/NoveltySegmentation.scd new file mode 100755 index 0000000..f8469e8 --- /dev/null +++ b/release-packaging/Examples/GUI_examples/NoveltySegmentation.scd @@ -0,0 +1,150 @@ +( +var server; +var win, soundFileView,loadButton, processButton; +var ksSlider, thSlider; +var soundFile, audioBuffer, slicesBuffer, slicesArray; +var addSelections, playFunc, stopFunc; +var synthDef, synth; +var synths; + +var playing, currentSelection, colors, prevColor; +var qwerty = "1234567890qwertyuiopasdfghjklzxcvbnm"; +playing = Array.fill(qwerty.size, {false}); +server = Server.default; +Font.default = Font("Monaco", 16); + +audioBuffer = Buffer.new; +slicesBuffer = Buffer.new; + +colors = Array.fill(qwerty.size, {Color.rand}); +synths = Array.fill(qwerty.size, {nil}); + +synthDef = SynthDef(\noveltySegDemo,{|buf, start, end| + Out.ar(0, BufRd.ar(1, buf, Phasor.ar(1, 1, start, end))); +}).add; + +playFunc = {|index| + var dur; + currentSelection = index; + if(playing[index].not){ + synths[index] = Synth(\noveltySegDemo, + [\buf, audioBuffer.bufnum, + \start, slicesArray[index], + \end, slicesArray[index+1] + ]); + playing[index] = true; + }; + soundFileView.setSelectionColor(currentSelection, Color.white); +}; + +stopFunc = {|index| synths[index].free; playing[index] = false; + soundFileView.setSelectionColor( + index, colors[index] + ); +}; + + +win = Window.new("NoveltySegmentation", + Rect(200,200,800,450)).background_(Color.gray); + +win.view.keyDownAction_{|view, char, modifiers, unicode, keycode, key| + var num = qwerty.indexOf(char); + if (num.notNil&& slicesArray.notNil){ + playFunc.value(num); + } +}; + +win.view.keyUpAction_{|view, char| + var num = qwerty.indexOf(char); + if(num.notNil){ + stopFunc.value(num); + } +}; + +soundFileView = SoundFileView.new(win) + .gridOn_(false) + .waveColors_([Color.white]); + +loadButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_([["Load", Color.grey, Color.grey(0.8)]]); + +processButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_( + [["Process", Color.grey, Color.grey(0.8)], + ["Wait", Color.grey, Color.grey(0.2)]] + ); + +ksSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +thSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); + + +loadButton.action_{ + FileDialog({ |path| + soundFile = SoundFile.new; + soundFile.openRead(path[0]); + audioBuffer = Buffer.read(server, path[0]); + soundFileView.soundfile = soundFile; + soundFileView.read(0, soundFile.numFrames); + }); +}; + +processButton.action_{|but| + var ks = 2*(ControlSpec(2, 100, step:1).map(ksSlider.value)) - 1; + var th = ControlSpec(0, 1).map(thSlider.value); + if(but.value == 1, { + Routine{ + FluidBufNoveltySlice.process( + server, + source:audioBuffer.bufnum, + indices:slicesBuffer.bufnum, + kernelSize:ks, + threshold: th + ); + server.sync; + slicesBuffer.loadToFloatArray(action:{|arr| + slicesArray = arr; + { processButton.value_(0); + addSelections.value(slicesArray) + }.defer; + + }); + }.play; + }); +}; + + + +addSelections = {|array| + var nSegments = min(array.size, soundFileView.selections.size) - 1; + soundFileView.selections.do({|sel, i| soundFileView.selectNone(i)}); + nSegments.do({|i| + soundFileView.setSelectionStart(i, array[i]); + soundFileView.setSelectionSize(i, array[i+1] - array[i]); + soundFileView.setSelectionColor(i, colors[i]); + }); +}; + +win.layout_( + VLayout( + [ + HLayout( + [loadButton, stretch:1], + [soundFileView, stretch:5] + ), stretch:2 + ], + [ + HLayout( + [processButton, stretch:1], + [VLayout( + HLayout(StaticText(win).string_("Kernel ").minWidth_(100), ksSlider), + HLayout(StaticText(win).string_(" Threshold").minWidth_(100), thSlider) + ), stretch:5] + ), stretch:2 + ] + ) +); + +win.front; +) diff --git a/release-packaging/Examples/GUI_examples/SineExtraction.scd b/release-packaging/Examples/GUI_examples/SineExtraction.scd new file mode 100755 index 0000000..9903797 --- /dev/null +++ b/release-packaging/Examples/GUI_examples/SineExtraction.scd @@ -0,0 +1,107 @@ +( +var win, soundFileView, freqSscope,loadButton, loopButton; +var thresholdSlider, lenSlider, mixSlider; +var soundFile, buffer; +var synthDef, synth; + +Font.default = Font("Monaco", 16); +buffer = Buffer.new; +win = Window.new("SineExtraction", + Rect(200,200,800,450)).background_(Color.gray); + +soundFileView = SoundFileView.new(win) + .gridOn_(false) + .waveColors_([Color.white]); + +loadButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_([["Load", Color.grey, Color.grey(0.8)]]); + +loopButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_( + [["Play", Color.grey, Color.grey(0.8)], + ["Stop", Color.grey, Color.grey(0.2)]] + ); + +thresholdSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +lenSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +mixSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +freqSscope = FreqScopeView(win, server:Server.default); +freqSscope.active_(true); + +loadButton.action_{ + FileDialog({ |path| + soundFile = SoundFile.new; + soundFile.openRead(path[0]); + buffer = Buffer.read(Server.default, path[0]); + soundFileView.soundfile = soundFile; + soundFileView.read(0, soundFile.numFrames); + }); +}; + +loopButton.action_{|but| + if(but.value == 1, { + synth = Synth(\sineExtractionDemo, [\buffer, buffer.bufnum]); + mixSlider.action.value(mixSlider); + thresholdSlider.action.value(thresholdSlider); + lenSlider.action.value(lenSlider); + },{ + synth.free; + }); +}; + + +mixSlider.action_{|slider| + synth.set(\bal, ControlSpec(0, 1).map(slider.value)); +}; + + +thresholdSlider.action_{|slider| + synth.set(\threshold, ControlSpec(-144, 0).map(slider.value)); +}; + + +lenSlider.action_{|slider| + synth.set(\minLength, ControlSpec(0, 30).map(slider.value)); +}; + + +synthDef = SynthDef(\sineExtractionDemo, + {|buffer, threshold = 0.9, minLength = 15, bal = 0.5| + var player, fse, mix; + player = PlayBuf.ar(1, buffer, loop:1); + fse = FluidSines.ar(in: player, bandwidth: 76, + detectionThreshold: threshold, minTrackLen: minLength, + windowSize: 2048, + hopSize: 512, fftSize: 8192 + ); + mix =(bal * fse[0]) + ((1 - bal) * fse[1]); + Out.ar(0,Pan2.ar(mix)); + } +).add; + +win.layout_( + VLayout( + [ + HLayout( + [loadButton, stretch:1], + [soundFileView, stretch:5] + ), stretch:2 + ], + [ + HLayout( + [loopButton, stretch:1], + [VLayout( + HLayout(StaticText(win).string_("Threshold ").minWidth_(100), thresholdSlider), + HLayout(StaticText(win).string_("Min Length").minWidth_(100), lenSlider), + HLayout(StaticText(win).string_("Mix").minWidth_(100), mixSlider) + ), stretch:5] + ), stretch:2 + ], + [freqSscope, stretch:2] + ) +); + +win.front; +) diff --git a/release-packaging/Examples/GUI_examples/TransientExtraction.scd b/release-packaging/Examples/GUI_examples/TransientExtraction.scd new file mode 100755 index 0000000..35b882d --- /dev/null +++ b/release-packaging/Examples/GUI_examples/TransientExtraction.scd @@ -0,0 +1,103 @@ +( +var win, soundFileView, freqSscope,loadButton, loopButton; +var fwSlider, bwSlider, mixSlider; +var soundFile, buffer; +var synthDef, synth; + +Font.default = Font("Monaco", 16); +buffer = Buffer.new; +win = Window.new("TransientExtraction", + Rect(200,200,800,450)).background_(Color.gray); + +soundFileView = SoundFileView.new(win) + .gridOn_(false) + .waveColors_([Color.white]); + +loadButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_([["Load", Color.grey, Color.grey(0.8)]]); + +loopButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_( + [["Play", Color.grey, Color.grey(0.8)], + ["Stop", Color.grey, Color.grey(0.2)]] + ); + +fwSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +bwSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +mixSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +freqSscope = FreqScopeView(win, server:Server.default); +freqSscope.active_(true); + +loadButton.action_{ + FileDialog({ |path| + soundFile = SoundFile.new; + soundFile.openRead(path[0]); + buffer = Buffer.read(Server.default, path[0]); + soundFileView.soundfile = soundFile; + soundFileView.read(0, soundFile.numFrames); + }); +}; + +loopButton.action_{|but| + if(but.value == 1, { + synth = Synth(\transientExtractionDemo, [\buffer, buffer.bufnum]); + mixSlider.action.value(mixSlider); + fwSlider.action.value(fwSlider); + bwSlider.action.value(bwSlider); + },{ + synth.free; + }); +}; + + +mixSlider.action_{|slider| + synth.set(\bal, ControlSpec(0, 1).map(slider.value)); +}; + + +fwSlider.action_{|slider| + synth.set(\fw, ControlSpec(0.0001, 3, \exp).map(slider.value)); +}; + + +bwSlider.action_{|slider| + synth.set(\bw, ControlSpec(0.0001, 3, \exp).map(slider.value)); +}; + + +synthDef = SynthDef(\transientExtractionDemo, + {|buffer, fw = 3, bw = 1, bal = 0.5| + var player, fte, mix; + player = PlayBuf.ar(1, buffer, loop:1); + fte = FluidTransients.ar(in: player, threshFwd:fw, threshBack:bw, clumpLength:256); + mix =(bal * fte[0]) + ((1 - bal) * fte[1]); + Out.ar(0,Pan2.ar(mix)); + } +).add; + +win.layout_( + VLayout( + [ + HLayout( + [loadButton, stretch:1], + [soundFileView, stretch:5] + ), stretch:2 + ], + [ + HLayout( + [loopButton, stretch:1], + [VLayout( + HLayout(StaticText(win).string_("Forward Th ").minWidth_(100), fwSlider), + HLayout(StaticText(win).string_("Backward Th").minWidth_(100), bwSlider), + HLayout(StaticText(win).string_("Mix").minWidth_(100), mixSlider) + ), stretch:5] + ), stretch:2 + ], + [freqSscope, stretch:2] + ) +); + +win.front; +) diff --git a/release-packaging/Examples/GUI_examples/TransientSegmentation.scd b/release-packaging/Examples/GUI_examples/TransientSegmentation.scd new file mode 100755 index 0000000..b7b69f5 --- /dev/null +++ b/release-packaging/Examples/GUI_examples/TransientSegmentation.scd @@ -0,0 +1,148 @@ +( +var server; +var win, soundFileView,loadButton, processButton; +var fwSlider, bwSlider, debounceSlider; +var soundFile, audioBuffer, slicesBuffer, slicesArray; +var addSelections, playFunc, stopFunc; +var synthDef, synth; + +var playing, currentSelection, colors, prevColor; +var qwerty = "1234567890qwertyuiopasdfghjklzxcvbnm"; + +playing = false; +server = Server.default; +Font.default = Font("Monaco", 16); + +audioBuffer = Buffer.new; +slicesBuffer = Buffer.new; + +colors = Array.fill(64, {Color.rand}); + +synthDef = SynthDef(\transientSegDemo,{|buf, start, end| + Out.ar(0, BufRd.ar(1, buf, Phasor.ar(1, 1, start, end))); +}).add; + +playFunc = {|index| + var dur; + currentSelection = index; + if(playing.not){ + synth = Synth(\transientSegDemo, + [\buf, audioBuffer.bufnum, + \start, slicesArray[index], + \end, slicesArray[index+1] + ]); + playing = true; + }; + soundFileView.setSelectionColor(currentSelection, Color.white); +}; + +stopFunc = {synth.free; playing = false; + soundFileView.setSelectionColor(currentSelection, colors[currentSelection]); + +}; + + +win = Window.new("TransientSegmentation", + Rect(200,200,800,450)).background_(Color.gray); + +win.view.keyDownAction_{|view, char, modifiers, unicode, keycode, key| + var num = qwerty.indexOf(char); + if(num.notNil && slicesArray.notNil){ + playFunc.value(num); + } +}; + +win.view.keyUpAction_{stopFunc.value;}; + + + +soundFileView = SoundFileView.new(win) + .gridOn_(false) + .waveColors_([Color.white]); + +loadButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_([["Load", Color.grey, Color.grey(0.8)]]); + +processButton = Button(win, Rect(0, 0, 100, 100)) + .minHeight_(150) + .states_( + [["Process", Color.grey, Color.grey(0.8)], + ["Wait", Color.grey, Color.grey(0.2)]] + ); + +fwSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +bwSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); +debounceSlider = Slider(win, Rect(0, 0, 100, 10)).value_(0.5); + +loadButton.action_{ + FileDialog({ |path| + soundFile = SoundFile.new; + soundFile.openRead(path[0]); + audioBuffer = Buffer.read(server, path[0]); + soundFileView.soundfile = soundFile; + soundFileView.read(0, soundFile.numFrames); + }); +}; + +processButton.action_{|but| + var fw = ControlSpec(0.0001, 3, \exp).map(fwSlider.value); + var bw = ControlSpec(0.0001, 3, \exp).map(bwSlider.value); + var db = ControlSpec(1, 4410).map(debounceSlider.value); + if(but.value == 1, { + Routine{ + FluidBufTransientSlice.process( + server, + source:audioBuffer.bufnum, + indices:slicesBuffer.bufnum, + threshFwd: fw, + threshBack: bw, + clumpLength:db + ); + server.sync; + slicesBuffer.loadToFloatArray(action:{|arr| + slicesArray = arr; + { processButton.value_(0); + addSelections.value(slicesArray) + }.defer; + + }); + }.play; + }); +}; + + + +addSelections = {|array| + var nSegments = min(array.size, soundFileView.selections.size) - 1; + soundFileView.selections.do({|sel, i| soundFileView.selectNone(i)}); + nSegments.do({|i| + soundFileView.setSelectionStart(i, array[i]); + soundFileView.setSelectionSize(i, array[i+1] - array[i]); + soundFileView.setSelectionColor(i, colors[i]); + }); +}; + +win.layout_( + VLayout( + [ + HLayout( + [loadButton, stretch:1], + [soundFileView, stretch:5] + ), stretch:2 + ], + [ + HLayout( + [processButton, stretch:1], + [VLayout( + HLayout(StaticText(win).string_("Forward Th ").minWidth_(100), fwSlider), + HLayout(StaticText(win).string_("Backward Th").minWidth_(100), bwSlider), + HLayout(StaticText(win).string_("Debounce").minWidth_(100), debounceSlider) + ), stretch:5] + ), stretch:2 + ] + ) +); + +win.front; +) diff --git a/release-packaging/Examples/buffer_compositing/bufcompose-MS-FIR.scd b/release-packaging/Examples/buffer_compositing/bufcompose-MS-FIR.scd new file mode 100644 index 0000000..b13b37a --- /dev/null +++ b/release-packaging/Examples/buffer_compositing/bufcompose-MS-FIR.scd @@ -0,0 +1,67 @@ +// A complex example of using composition as an Mid-Side FIR filtering process + +// load a stereo buffer and initialise the many destinations +( +b = Buffer.read(s,File.realpath(FluidBufCompose.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav"); +c = Buffer.new(s); +d = Buffer.new(s); +e = Buffer.new(s); +f = Buffer.new(s); +) + +// encode the mid (in c) and the side (in d) +( +FluidBufCompose.process(s,b, numChans: 1, gain: -3.0.dbamp, destination: c); +FluidBufCompose.process(s,b, numChans: 1, gain: -3.0.dbamp, destination: d); +FluidBufCompose.process(s,b, numChans: 1, gain: -3.0.dbamp, startChan: 1, destination: c, destGain: 1.0); +FluidBufCompose.process(s,b, numChans: 1, gain: -3.0.dbamp * -1.0, startChan: 1, destination: d, destGain: 1.0); +) + +// (optional) compare auraly the stereo with the MS +b.play; +{PlayBuf.ar(1,[c,d])}.play; + +// The geeky bit: copy the side (buffer d) on itself with specific amplitudes and delays, in effect applying a FIR filter through expensive convolution + +// Important: do either of the 3 options below + +// option 1: apply a high pass on the side, with a cutoff of nyquist / 4 +e.free; e = Buffer.new(s); +( +[1.0, -1.0].do({ arg x,y; + FluidBufCompose.process(s, d, gain: x, destStartFrame: y, destination: e, destGain: 1.0); +}); +) + +// option 2: apply a high pass on the side, with a cutoff of nyquist / 10 +e.free; e = Buffer.new(s); +( +[0.8, -0.32, -0.24, -0.16, -0.08].do({ arg x,y; + FluidBufCompose.process(s, d, gain: x, destStartFrame: y, destination: e, destGain: 1.0); +}); +) + +// option 3: apply a high pass on the side, with a cutoff of nyquist / 100 +e.free; e = Buffer.new(s); +( +[0.982494, -0.066859, -0.064358, -0.061897, -0.059477, -0.057098, -0.054761, -0.052466, -0.050215, -0.048007, -0.045843, -0.043724, -0.041649, -0.03962, -0.037636, -0.035697, -0.033805, -0.031959, -0.030159, -0.028406, -0.026699, -0.025038, -0.023425, -0.021857, -0.020337].do({ arg x,y; + FluidBufCompose.process(s, d, gain: x, destStartFrame: y, destination: e, destGain: 1.0); +}); +) + +// play the high-passed side buffer +e.play; +// if you want to try the other filters, do not forget to clear the destination buffer since it will add programmatically onto itself and would not create the expected frequency response + +// decode the MS back to stereo +( +FluidBufCompose.process(s,c, numChans: 2, gain: -3.0.dbamp, destination: f); +FluidBufCompose.process(s,e, gain: -3.0.dbamp, destination: f, destGain: 1.0); +FluidBufCompose.process(s,e, gain: -3.0.dbamp * -1.0, destination: f, destStartChan: 1, destGain: 1.0); +) + +// play the MS processed version +f.play; + +// compare with the original +b.play; \ No newline at end of file diff --git a/release-packaging/Examples/buffer_compositing/bufcomposemacros.scd b/release-packaging/Examples/buffer_compositing/bufcomposemacros.scd new file mode 100644 index 0000000..061349f --- /dev/null +++ b/release-packaging/Examples/buffer_compositing/bufcomposemacros.scd @@ -0,0 +1,100 @@ +// (re)set the source buffers +( +~low = Buffer.sendCollection(s, (Signal.sineFill(4410, Array.fill(3,0) ++ 1))); +~mid = Buffer.sendCollection(s, (Signal.sineFill(4410, Array.fill(12,0) ++ 1))); +~high = Buffer.sendCollection(s, (Signal.sineFill(4410, Array.fill(48,0) ++ 1))); +~piano = Buffer.read(s,File.realpath(FluidBufCompose.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav",0,8820); +) + +// draw the buffers to see what happened +( +~low.plot; +~mid.plot; +~high.plot; +~piano.plot; +) + +// define the concatenation macro +( +~concat = { + arg x; + if(x.class != Array, + { + "Error - Needs an array as argument".postln; + }, { + Routine{ + for (1,x.size - 1, { + arg i; + FluidBufCompose.process(s,x[i],destination:x[0], destStartFrame:x[0].numFrames); + }); + "Done!".postln; + }.play; + } + ); +} +) +// test various combinations of concatenation +~concat.value([~low,~mid]) +~concat.value([~mid,~low,~high]) +~concat.value([~mid,~piano,~low]) +~concat.value([~mid,~piano]) + +// check the buffers for the results + +//////////////////////////////// + +// define the merging macro +( +~merge = { + arg x; + if(x.class != Array, + { + "Error - Needs an array as argument".postln; + }, { + Routine{ + for (1,x.size - 1, { + arg i; + FluidBufCompose.process(s,x[i],destination:x[0],destGain:1); + }); + "Done!".postln; + }.play; + } + ); +} +) +// test various combinations of merging +~merge.value([~low,~mid]) +~merge.value([~mid,~low,~high]) +~merge.value([~mid,~piano,~low]) +~merge.value([~mid,~piano]) + +// check the buffers for the results + +//////////////////////////////// + +// define the stacking macro +( +~stack = { + arg x; + if(x.class != Array, + { + "Error - Needs an array as argument".postln; + }, { + Routine{ + for (1,x.size - 1, { + arg i; + FluidBufCompose.process(s,x[i],destination:x[0], destStartChan:x[0].numChannels); + }); + "Done!".postln; + }.play; + } + ); +} +) +// test various combinations of stacking +~stack.value([~low,~mid]) +~stack.value([~mid,~low,~high]) +~stack.value([~mid,~piano,~low]) +~stack.value([~mid,~piano]) + +// check the buffers for the results diff --git a/release-packaging/Examples/nmf/JiT-NMF-classifier.scd b/release-packaging/Examples/nmf/JiT-NMF-classifier.scd new file mode 100644 index 0000000..b76c08d --- /dev/null +++ b/release-packaging/Examples/nmf/JiT-NMF-classifier.scd @@ -0,0 +1,202 @@ +// using nmf in 'real-time' as a classifier +// how it works: a circular buffer is recording and attacks trigger the process +// if in learning mode, it does a one component nmf which makes an approximation of the base. 3 of those will be copied in 3 different positions of our final 3-component base +// in in guessing mode, it does a thres component nmf from the trained bases and yields the 3 activation peaks, on which it thresholds resynth + +//how to use: +// 1. start the server +// 2. select between parenthesis below and execute. You should get a window with 3 pads (bd sn hh) and various menus +// 3. train the 3 classes: +// 3.1 select the learn option +// 3.2 select which class you want to train +// 3.3 play the sound you want to associate with that class a few times (the left audio channel is the source) +// 3.4 click the transfer button +// 3.5 repeat (3.2-3.4) for the other 2 classes. +// 3.x you can observe the 3 bases here: +~classify_bases.plot(numChannels:3) + +// 4. classify +// 4.1 select the classify option +// 4.2 press a pad and look at the activation +// 4.3 tweak the thresholds and enjoy the resynthesis. (the right audio channel is the detected class where classA is a bd sound) +// 4.x you can observe the 3 activations here: +~activations.plot(numChannels:3) + +/// code to execute first +( +var circle_buf = Buffer.alloc(s,s.sampleRate * 2); // b +var input_bus = Bus.audio(s,1); // g +var classifying = 0; // c +var cur_training_class = 0; // d +var train_base = Buffer.alloc(s, 65); // e +var activation_vals = [0.0,0.0,0.0]; // j +var thresholds = [0.5,0.5,0.5]; // k +var activations_disps; +var analysis_synth; +var osc_func; +var update_rout; + +~classify_bases = Buffer.alloc(s, 65, 3); // f +~activations = Buffer.new(s); + +// the circular buffer with triggered actions sending the location of the head at the attack +Routine { + SynthDef(\JITcircular,{arg bufnum = 0, input = 0, env = 0; + var head, head2, duration, audioin, halfdur, trig; + duration = BufFrames.kr(bufnum) / 2; + halfdur = duration / 2; + head = Phasor.ar(0,1,0,duration); + head2 = (head + halfdur) % duration; + + // circular buffer writer + audioin = In.ar(input,1); + BufWr.ar(audioin,bufnum,head,0); + BufWr.ar(audioin,bufnum,head+duration,0); + trig = FluidAmpSlice.ar(audioin, 10, 1666, 2205, 2205, 12, 9, -47,4410, 85); + + // cue the calculations via the language + SendReply.ar(trig, '/attack',head); + + Out.ar(0,audioin); + }).add; + + // drum sounds taken from original code by snappizz + // https://sccode.org/1-523 + // produced further and humanised by PA + SynthDef(\fluidbd, { + |out = 0| + var body, bodyFreq, bodyAmp; + var pop, popFreq, popAmp; + var click, clickAmp; + var snd; + + // body starts midrange, quickly drops down to low freqs, and trails off + bodyFreq = EnvGen.ar(Env([Rand(200,300), 120, Rand(45,49)], [0.035, Rand(0.07,0.1)], curve: \exp)); + bodyAmp = EnvGen.ar(Env([0,Rand(0.8,1.3),1,0],[0.005,Rand(0.08,0.085),Rand(0.25,0.35)]), doneAction: 2); + body = SinOsc.ar(bodyFreq) * bodyAmp; + // pop sweeps over the midrange + popFreq = XLine.kr(Rand(700,800), Rand(250,270), Rand(0.018,0.02)); + popAmp = EnvGen.ar(Env([0,Rand(0.8,1.3),1,0],[0.001,Rand(0.018,0.02),Rand(0.0008,0.0013)])); + pop = SinOsc.ar(popFreq) * popAmp; + // click is spectrally rich, covering the high-freq range + // you can use Formant, FM, noise, whatever + clickAmp = EnvGen.ar(Env.perc(0.001,Rand(0.008,0.012),Rand(0.07,0.12),-5)); + click = RLPF.ar(VarSaw.ar(Rand(900,920),0,0.1), 4760, 0.50150150150) * clickAmp; + + snd = body + pop + click; + snd = snd.tanh; + + Out.ar(out, snd); + }).add; + + SynthDef(\fluidsn, { + |out = 0| + var pop, popAmp, popFreq; + var noise, noiseAmp; + var click; + var snd; + + // pop makes a click coming from very high frequencies + // slowing down a little and stopping in mid-to-low + popFreq = EnvGen.ar(Env([Rand(3210,3310), 410, Rand(150,170)], [0.005, Rand(0.008,0.012)], curve: \exp)); + popAmp = EnvGen.ar(Env.perc(0.001, Rand(0.1,0.12), Rand(0.7,0.9),-5)); + pop = SinOsc.ar(popFreq) * popAmp; + // bandpass-filtered white noise + noiseAmp = EnvGen.ar(Env.perc(0.001, Rand(0.13,0.15), Rand(1.2,1.5),-5), doneAction: 2); + noise = BPF.ar(WhiteNoise.ar, 810, 1.6) * noiseAmp; + + click = Impulse.ar(0); + snd = (pop + click + noise) * 1.4; + + Out.ar(out, snd); + }).add; + + SynthDef(\fluidhh, { + |out = 0| + var click, clickAmp; + var noise, noiseAmp, noiseFreq; + + // noise -> resonance -> expodec envelope + noiseAmp = EnvGen.ar(Env.perc(0.001, Rand(0.28,0.3), Rand(0.4,0.6), [-20,-15]), doneAction: 2); + noiseFreq = Rand(3900,4100); + noise = Mix(BPF.ar(ClipNoise.ar, [noiseFreq, noiseFreq+141], [0.12, 0.31], [2.0, 1.2])) * noiseAmp; + + Out.ar(out, noise); + }).add; + + // makes sure all the synthdefs are on the server + s.sync; + + // instantiate the JIT-circular-buffer + analysis_synth = Synth(\JITcircular,[\bufnum, circle_buf, \input, input_bus]); + train_base.fill(0,65,0.1); + + // instantiate the listener to cue the processing from the language side + osc_func = OSCFunc({ arg msg; + var head_pos = msg[3]; + // when an attack happens + if (classifying == 0, { + // if in training mode, makes a single component nmf + FluidBufNMF.process(s, circle_buf, head_pos, 128, bases:train_base, basesMode: 1, windowSize: 128); + }, { + // if in classifying mode, makes a 3 component nmf from the pretrained bases and compares the activations with the set thresholds + FluidBufNMF.process(s, circle_buf, head_pos, 128, components:3, bases:~classify_bases, basesMode: 2, activations:~activations, windowSize: 128, action:{ + // we are retrieving and comparing against the 2nd activation, because FFT processes are zero-padded on each sides, therefore the complete 128 samples are in the middle of the analysis. + ~activations.getn(3,3,{|x| + activation_vals = x; + if (activation_vals[0] >= thresholds[0], {Synth(\fluidbd,[\out,1])}); + if (activation_vals[1] >= thresholds[1], {Synth(\fluidsn,[\out,1])}); + if (activation_vals[2] >= thresholds[2], {Synth(\fluidhh,[\out,1])}); + defer{ + activations_disps[0].string_("A:" ++ activation_vals[0].round(0.01)); + activations_disps[1].string_("B:" ++ activation_vals[1].round(0.01)); + activations_disps[2].string_("C:" ++ activation_vals[2].round(0.01)); + }; + }); + }; + ); + }); + }, '/attack', s.addr); + + // make sure all the synths are instantiated + s.sync; + + // GUI for control + { + var win = Window("Control", Rect(100,100,610,100)).front; + + Button(win, Rect(10,10,80, 80)).states_([["bd",Color.black,Color.white]]).mouseDownAction_({Synth(\fluidbd, [\out, input_bus], analysis_synth, \addBefore)}); + Button(win, Rect(100,10,80, 80)).states_([["sn",Color.black,Color.white]]).mouseDownAction_({Synth(\fluidsn, [\out, input_bus], analysis_synth, \addBefore)}); + Button(win, Rect(190,10,80, 80)).states_([["hh",Color.black,Color.white]]).mouseDownAction_({Synth(\fluidhh, [\out, input_bus], analysis_synth,\addBefore)}); + StaticText(win, Rect(280,7,85,25)).string_("Select").align_(\center); + PopUpMenu(win, Rect(280,32,85,25)).items_(["learn","classify"]).action_({|value| + classifying = value.value; + if(classifying == 0, { + train_base.fill(0,65,0.1) + }); + }); + PopUpMenu(win, Rect(280,65,85,25)).items_(["classA","classB","classC"]).action_({|value| + cur_training_class = value.value; + train_base.fill(0,65,0.1); + }); + Button(win, Rect(375,65,85,25)).states_([["transfer",Color.black,Color.white]]).mouseDownAction_({ + if(classifying == 0, { + // if training + FluidBufCompose.process(s, train_base, numChans:1, destination:~classify_bases, destStartChan:cur_training_class); + }); + }); + StaticText(win, Rect(470,7,75,25)).string_("Acts"); + activations_disps = Array.fill(3, {arg i; + StaticText(win, Rect(470,((i+1) * 20 )+ 7,80,25)); + }); + StaticText(win, Rect(540,7,55,25)).string_("Thresh").align_(\center); + 3.do {arg i; + TextField(win, Rect(540,((i+1) * 20 )+ 7,55,25)).string_("0.5").action_({|x| thresholds[i] = x.value.asFloat;}); + }; + + win.onClose_({circle_buf.free;input_bus.free;osc_func.clear;analysis_synth.free;}); + }.defer; +}.play; +) + +// thanks to Ted Moore for the SC code cleaning and improvments! diff --git a/release-packaging/Examples/nmf/JiT-NMF.scd b/release-packaging/Examples/nmf/JiT-NMF.scd index 7ec4394..f10195c 100644 --- a/release-packaging/Examples/nmf/JiT-NMF.scd +++ b/release-packaging/Examples/nmf/JiT-NMF.scd @@ -40,16 +40,16 @@ SynthDef(\playa, { arg output = 0, bufnum = 0; // instantiate the player x = Synth(\playa,[\output, g.index, \bufnum, e.bufnum]); -// instantiate the processor +// instantiate the processor, please ignore the Buffer UGen warnings y = Synth(\becauseIcan,[\bufnum, b.bufnum, \nmfa, c.bufnum, \nmfb, d.bufnum, \input, g.index, \env, h.bufnum], x, 'addAfter'); // instantiate the listener to cue the processing from the language side ( w = OSCFunc({ arg msg; if(msg[3]== 1, { - FluidBufNMF.process(s, b, numFrames: 22500, destination: c.bufnum, iterations: 3, fftSize: 1024, windowSize: 512, hopSize: 256); + FluidBufNMF.process(s, b, numFrames: 22500, resynth: c.bufnum, components: 3, fftSize: 1024, windowSize: 512, hopSize: 256); }, { - FluidBufNMF.process(s, b, 22050, 22500, destination: d.bufnum, iterations: 3, fftSize: 1024, windowSize: 512, hopSize: 256); + FluidBufNMF.process(s, b, 22050, 22500, resynth: d.bufnum, components: 3, fftSize: 1024, windowSize: 512, hopSize: 256); });}, '/processplease', s.addr); ) diff --git a/release-packaging/Examples/nmf/nmfmatch-object-finding.scd b/release-packaging/Examples/nmf/nmfmatch-object-finding.scd new file mode 100644 index 0000000..7ab2c3d --- /dev/null +++ b/release-packaging/Examples/nmf/nmfmatch-object-finding.scd @@ -0,0 +1,74 @@ +// using NMF, splitting a small portion, then associating components to targets, then thresholding on these target's activations to find objects. + +//set some buffers +( +b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-BaB-SoundscapeGolcarWithDog.wav"); +c = Buffer.new(s); +x = Buffer.new(s); +e = Buffer.new(s); +) + +// train where all objects are present +( +Routine { + FluidBufNMF.process(s,b,130000,150000,0,1, c, x, components:10); + c.query; +}.play; +) + +// wait for the query to print +// then find a component for each item you want to find. You could also sum them. Try to find a component with a good object-to-rest ratio +( + ~dog =1; + {PlayBuf.ar(10,c)[~dog]}.play +) + +( + ~bird = 3; + {PlayBuf.ar(10,c)[~bird]}.play +) + + +// copy at least one other component to a third filter, a sort of left-over channel +( +Routine{ + FluidBufCompose.process(s, x, startChan:~dog, numChans: 1, destination: e); + FluidBufCompose.process(s, x, startChan:~bird, numChans: 1, destStartChan: 1, destination: e, destGain:1); + (0..9).removeAll([~dog,~bird]).do({|chan|FluidBufCompose.process(s,x, startChan:chan, numChans: 1, destStartChan: 2, destination: e, destGain:1)}); + e.query; +}.play; +) +e.plot; + +//using this trained basis we can then see the activation... (wait for 5 seconds before it prints!) +( +{ + var source, blips; + //read the source + source = PlayBuf.ar(2, b); + blips = FluidNMFMatch.kr(source.sum,e,3); + }.plot(5); +) + +// ...and use some threshold to 'find' objects... +( +{ + var source, blips; + //read the source + source = PlayBuf.ar(2, b); + blips = Schmidt.kr(FluidNMFMatch.kr(source.sum,e,3),0.5,[10,1,1000]); + }.plot(5); +) + +// ...and use these to sonify them +( +{ + var source, blips, dogs, birds; + //read the source + source = PlayBuf.ar(2, b); + blips = Schmidt.kr(FluidNMFMatch.kr(source.sum,e,3),0.5,[10,1,1000]); + dogs = SinOsc.ar(100,0,Lag.kr(blips[0],0.05,0.15)); + birds = SinOsc.ar(1000,0,Lag.kr(blips[1],0.05,0.05)); + [dogs, birds] + source; + }.play; +) \ No newline at end of file diff --git a/release-packaging/Examples/nmf/nmfmatch-pretrained-piano.scd b/release-packaging/Examples/nmf/nmfmatch-pretrained-piano.scd new file mode 100644 index 0000000..d630387 --- /dev/null +++ b/release-packaging/Examples/nmf/nmfmatch-pretrained-piano.scd @@ -0,0 +1,51 @@ +// Using an 88-components piano base to do polyphonic pitch tracking + +//load in the sound in and a pretrained basis +( + b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav"); + c = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/filters/piano-dicts.wav"); +) +b.play +c.query + +//use the pretrained bases to compute activations of each notes to drive the amplitude of a resynth +( +{ + var source, resynth; + source = PlayBuf.ar(2, b,loop:1).sum; + resynth = SinOsc.ar((21..108).midicps, 0, FluidNMFMatch.kr(source,c,88,10,4096).madd(0.002)).sum; + [source, resynth] +}.play +) + + +//now sample and hold the same stream to get notes identified, played and sent back via osc +( +{ + var source, resynth, chain, trig, acts; + source = PlayBuf.ar(2,b,loop:1).sum; + + // built in attack detection, delayed until the stable part of the sound + chain = FFT(LocalBuf(256), source); + trig = TDelay.kr(Onsets.kr(chain, 0.5),0.1); + + // samples and holds activation values that are scaled and capped, in effect thresholding them + acts = Latch.kr(FluidNMFMatch.kr(source,c,88,10,4096).linlin(15,20,0,0.1),trig); + + // resynths as in the previous example, with the values sent back to the language + resynth = SinOsc.ar((21..108).midicps, 0, acts).sum; + SendReply.kr(trig, '/activations', acts); + [source, resynth] + // [source, T2A.ar(trig)] + // resynth +}.play +) + +// define a receiver for the activations +( + OSCdef(\listener, {|msg| + var data = msg[3..]; + // removes the silent and spits out the indicies as midinote number + data.collect({arg item, i; if (item > 0.01, {i + 21})}).reject({arg item; item.isNil}).postln; + }, '/activations'); +) \ No newline at end of file diff --git a/release-packaging/Examples/segmenting/nb_of_slices.scd b/release-packaging/Examples/segmenting/nb_of_slices.scd new file mode 100644 index 0000000..c30174e --- /dev/null +++ b/release-packaging/Examples/segmenting/nb_of_slices.scd @@ -0,0 +1,59 @@ +( +b = Buffer.read(s,File.realpath(FluidBufNoveltySlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); +c = Buffer.new(s); +) + +( +// with basic params +Routine{ + var startTime, target, tolerance, startThresh, prevThresh, curThresh, curVal, prevVal, iters, maxIters, dVal, dThresh; + startTime = Main.elapsedTime; + prevThresh = 0.1; //initial threshold (between 0.00001 and 0.99999 + target = 10; //number of slices desired + tolerance = 0; // the acceptable error in the number of slices yield + maxIters = 100; //max number of iterations acceptable + + //makes a first iteration + FluidBufNoveltySlice.process(s,b, indices: c, threshold:prevThresh,action:{|x|prevVal = x.numFrames}); + //makes a second iteration + if ( (prevVal < target), { + curThresh = (prevThresh * 0.5).max(0.000001); + }, { + curThresh = (prevThresh * 2).min(0.999999); + }); + FluidBufNoveltySlice.process(s,b, indices: c, threshold:curThresh,action:{|x|curVal = x.numFrames}); + + //makes further iterations until the result is achieved, or the maximum of acceptable iterations is reached + iters = 2; + while ( { + (iters < maxIters) && ((curVal - target).abs > tolerance) + }, { + iters = iters + 1; + dVal = curVal - prevVal; + dThresh = curThresh - prevThresh; + + prevThresh = curThresh; + prevVal = curVal; + + if ( (dVal == 0), { + //if we have not change results between the last 2 passes, make the variation of threshold bigger + curThresh = (dThresh + curThresh).min(0.999999).max(0.000001); + },{ + //if we have + curThresh = (((dThresh / dVal) * (target - curVal)) + curThresh).min(0.999999).max(0.000001); + }); + FluidBufNoveltySlice.process(s,b, indices: c, threshold:curThresh,action:{|x|curVal = x.numFrames}); + } + ); + //depending on the outcome, gives the right info back + + if ( iters >= maxIters, { + // failed + "Failed to find a suitable threshold in % seconds.\n".postf((Main.elapsedTime - startTime).round(0.01)); + }, { + // succeeded + "Found % as a suitable threshold for % slices in % seconds and % iterations.\n".postf(curThresh, curVal, (Main.elapsedTime - startTime).round(0.01), iters); + } + ); +}.play +) \ No newline at end of file diff --git a/release-packaging/HelpSource/Classes/FluidAmpGate.schelp b/release-packaging/HelpSource/Classes/FluidAmpGate.schelp new file mode 100644 index 0000000..880a960 --- /dev/null +++ b/release-packaging/HelpSource/Classes/FluidAmpGate.schelp @@ -0,0 +1,136 @@ +TITLE:: FluidAmpGate +SUMMARY:: Amplitude-based Gating Slicer +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 amplitude changes as onsets and offsets. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ + +FluidAmpSlice is based on an envelop follower on a highpassed version of the signal, which is then going through a Schmidt trigger and state-aware time contraints. The example code below is unfolding the various possibilites in order of complexity. + +The process will return an audio steam with square envelopes around detected slices the different slices, where 1s means in slice and 0s mean in silence. + +CLASSMETHODS:: + +METHOD:: ar + The audio rate version of the object. + +ARGUMENT:: in + The audio to be processed. + +ARGUMENT:: rampUp + The number of samples the absolute envelope follower will take to reach the next value when raising. + +ARGUMENT:: rampDown + The number of samples the absolute envelope follower will take to reach the next value when falling. + +ARGUMENT:: onThreshold + The threshold in dB of the absolute envelope follower to trigger an onset, aka to go ON when in OFF state. + +ARGUMENT:: offThreshold + 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:: 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:: maxSize + How large can the buffer be for time-critical conditions, by allocating memory at instantiation time. This cannot be modulated. + +RETURNS:: + An audio stream with square envelopes around the slices. The latency between the input and the output is STRONG::max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead))::. + +EXAMPLES:: + +code:: +//basic tests: absThresh sanity +( +{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpGate.ar(source, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12); + [source, env] +}.plot(0.1); +) +//basic tests: absThresh hysteresis +( +{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpGate.ar(source, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -16); + [source, env] +}.plot(0.1); +) +//basic tests: absThresh min slice +( +{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpGate.ar(source, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -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 = FluidAmpGate.ar(source, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, minSilenceLength:441); + [source, env] +}.plot(0.1); +) +//mid tests: absThresh time hysteresis on +( +{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpGate.ar(source, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, minLengthAbove:441); + [DelayN.ar(source,0.1,441/44100), env] +}.plot(0.1); +) +//mid tests: absThresh time hysteresis off +( +{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); + env = FluidAmpGate.ar(source, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -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 = FluidAmpGate.ar(source, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -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 = FluidAmpGate.ar(source, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -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 = FluidAmpGate.ar(source, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, lookBack:221, lookAhead:441); + [DelayN.ar(source,0.1,441/44100), env] +}.plot(0.1); +) +//drum slicing, many ways +//load a buffer +b = Buffer.read(s,File.realpath(FluidAmpGate.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); +//have fun with a gate (explore lookahead and lookback, but correct for latency, which will be the greatest of the lookahead and lookback) +( +{var env, source = PlayBuf.ar(1,b); + env = FluidAmpGate.ar(source, rampUp:441, rampDown:2205, onThreshold:-27, offThreshold: -31, minSilenceLength:1100, lookBack:441, highPassFreq:20); + [DelayN.ar(source,delaytime:441/44100), env] +}.plot(2, separately:true); +) +:: diff --git a/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp index d1789b7..72d87e8 100644 --- a/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp @@ -1,14 +1,14 @@ TITLE:: FluidAmpSlice -SUMMARY:: Amplitude-based Slicer +SUMMARY:: Amplitude-based Detrending Slicer 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).:: +This class implements an amplitude-based slicer, with various customisable options and conditions to detect relative amplitude changes as onsets. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ -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. +FluidAmpSlice is based on two envelop followers on a highpassed version of the signal: one slow that gives the trend, and one fast. Each have features that will interact. The example code below is unfolding the various possibilites in order of complexity. -The process will return an audio steam with square envelopes around detected slices the different slices, where 1s means in slice and 0s mean in silence. +The process will return an audio steam with sample-long impulses at estimated starting points of the different slices. CLASSMETHODS:: @@ -18,166 +18,68 @@ METHOD:: ar ARGUMENT:: in The audio to be processed. -ARGUMENT:: absRampUp +ARGUMENT:: fastRampUp + The number of samples the fast envelope follower will take to reach the next value when raising. Typically, this will be faster than slowRampUp. + +ARGUMENT:: fastRampDown + The number of samples the fast envelope follower will take to reach the next value when falling. Typically, this will be faster than slowRampDown. + +ARGUMENT:: slowRampUp The number of samples the absolute envelope follower will take to reach the next value when raising. -ARGUMENT:: absRampDown +ARGUMENT:: slowRampDown 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:: onThreshold + 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:: offThreshold + The threshold in dB of the relative envelope follower to reset, aka to allow the differential envelop to trigger again. -ARGUMENT:: absThreshOff - The threshold in dB of the absolute envelope follower to trigger an offset, , aka to go ON when in OFF state. +ARGUMENT:: floor + The level in dB the slowRamp needs to be above to consider a detected difference valid, allowing to ignore the slices in the noise floor. 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:: maxSize - How large can the buffer be for time-critical conditions, by allocating memory at instantiation time. This cannot be modulated. - RETURNS:: - An audio stream with square envelopes around the slices. The latency between the input and the output is STRONG::max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead))::. + An audio stream with square envelopes around the slices. The latency between the input and the output is dependant on the relation between the two envelope followers. EXAMPLES:: code:: -//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 hysteresis +// detrending explained +// Our source here is a sinewave that does not go to silence and has sharp-ish amplitude bumps as onsets we try to track ( -{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs); - env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -16); +{var env, source = SinOsc.ar(320,0,LFSaw.ar(20, 0, -0.4, 0.6)); + env = FluidAmpSlice.ar(source,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 10,floor: -60); [source, env] -}.plot(0.1); +}.plot(0.08); ) -//basic tests: absThresh min slice +//beware of double trigger at the begining of the 2nd cycle above). A solution: Schmidth triggers ( -{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); +{var env, source = SinOsc.ar(320,0,LFSaw.ar(20, 0, -0.4, 0.6)); + env = FluidAmpSlice.ar(source,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 7,floor: -60); [source, env] -}.plot(0.1); +}.plot(0.08); ) -//basic tests: absThresh min silence +// another solution: minslicelength ( -{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); +{var env, source = SinOsc.ar(320,0,LFSaw.ar(20, 0, -0.4, 0.6)); + env = FluidAmpSlice.ar(source,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 7,floor: -60, minSliceLength: 220); [source, env] -}.plot(0.1); -) -//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); - [DelayN.ar(source,0.1,441/44100), env] -}.plot(0.1); -) -//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); - [DelayN.ar(source,0.1,441/44100), env] -}.plot(0.1); +}.plot(0.08); ) -//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 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); - [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 +//quick drum onsets //load a buffer b = Buffer.read(s,File.realpath(FluidAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); -//have fun with a gate (explore lookahead and lookback, but correct for latency) ( {var env, source = PlayBuf.ar(1,b); - env = FluidAmpSlice.ar(source,absRampUp:44, absRampDown:2205, absThreshOn:-20, absThreshOff: -23, minSilenceLength:1100, lookBack:441); - [DelayN.ar(source,delaytime:441/44100), env] -}.plot(2,separately:true); -) - -( -{var env, source = PlayBuf.ar(1,b); - env = FluidAmpSlice.ar(source,highPassFreq:120, absRampUp:4410, absRampDown:4410, absThreshOn:-60, absThreshOff: -60, relRampUp:10, relRampDown:2205, relThreshOn:13, relThreshOff:10, minSilenceLength:4410, highPassFreq:20); - [source, Trig.ar(env,0)] + env = FluidAmpSlice.ar(source,fastRampUp: 10,fastRampDown: 2205,slowRampUp: 4410,slowRampDown: 4410,onThreshold: 10,offThreshold: 5,floor: -40,minSliceLength: 4410,highPassFreq: 20); + [source, env] }.play; ) :: diff --git a/release-packaging/HelpSource/Classes/FluidBufAmpGate.schelp b/release-packaging/HelpSource/Classes/FluidBufAmpGate.schelp new file mode 100644 index 0000000..438208a --- /dev/null +++ b/release-packaging/HelpSource/Classes/FluidBufAmpGate.schelp @@ -0,0 +1,196 @@ +TITLE:: FluidBufAmpGate +SUMMARY:: Amplitude-based Gating Slicer for Buffers +CATEGORIES:: Libraries>FluidDecomposition +RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading + +DESCRIPTION:: +This class implements an amplitude-based slicer, with various customisable options and conditions to detect absolute amplitude changes as onsets and offsets. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ + +FluidBufAmpGate is based on an envelop follower on a highpassed version of the signal, which is then going through a Schmidt trigger 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. + +STRONG::Threading:: + +By default, this UGen spawns a new thread to avoid blocking the server command queue, so it is free to go about with its business. For a more detailed discussion of the available threading and monitoring options, including the two undocumented Class Methods below (.processBlocking and .kr) please read the guide LINK::Guides/FluidBufMultiThreading::. + +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:: rampUp + The number of samples the absolute envelope follower will take to reach the next value when raising. + +ARGUMENT:: rampDown + The number of samples the absolute envelope follower will take to reach the next value when falling. + +ARGUMENT:: onThreshold + The threshold in dB of the absolute envelope follower to trigger an onset, aka to go ON when in OFF state. + +ARGUMENT:: offThreshold + 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:: 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:: 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 +FluidBufAmpGate.process(s, b, indices:c, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//basic tests: absThresh hysteresis +FluidBufAmpGate.process(s, b, indices:c, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -16) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//basic tests: absThresh min slice +FluidBufAmpGate.process(s, b, indices:c, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, minSliceLength:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//basic tests: absThresh min silence +FluidBufAmpGate.process(s, b, indices:c, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, minSilenceLength:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//mid tests: absThresh time hysteresis on +FluidBufAmpGate.process(s, b, indices:c, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, minLengthAbove:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//mid tests: absThresh time hysteresis off +FluidBufAmpGate.process(s, b, indices:c, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, minLengthBelow:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//mid tests: absThresh with lookBack +FluidBufAmpGate.process(s, b, indices:c, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, lookBack:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//mid tests: absThresh with lookAhead +FluidBufAmpGate.process(s, b, indices:c, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, lookAhead:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) + +//mid tests: absThresh with asymetrical lookBack and lookAhead +FluidBufAmpGate.process(s, b, indices:c, rampUp:5, rampDown:25, onThreshold:-12, offThreshold: -12, lookBack:221, lookAhead:441) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) +:: + +STRONG::A musical example.:: +CODE:: +//load a buffer +( +b = Buffer.read(s,File.realpath(FluidBufAmpGate.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); +c = Buffer.new(s); +) + +// slice the samples +FluidBufAmpGate.process(s, b, indices:c, rampUp:110, rampDown:2205, onThreshold:-27, offThreshold: -31, minSilenceLength:1100, lookBack:441, highPassFreq:40) +c.query +c.getn(0,c.numFrames*2,{|item|item.postln;}) +//reformatting to read the onsets and offsets as pairs +c.getn(0,c.numFrames*2,{|items|items.reshape(c.numFrames,2).do({|x| x.postln});}) + +//loops over a splice with the MouseX, taking the respective onset and offset of a given slice +( +{ + BufRd.ar(1, b, + Phasor.ar(0,1, + BufRd.kr(2, c, + MouseX.kr(0, BufFrames.kr(c)), 0, 1)[0], + BufRd.kr(2, c, + MouseX.kr(1, BufFrames.kr(c)), 0, 1)[1], + BufRd.kr(2,c, + MouseX.kr(0, BufFrames.kr(c)), 0, 1)[0] + ), 0, 1); +}.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; + FluidBufAmpGate.process(s, b, indices: c, rampUp:1, rampDown:10, onThreshold: -30); + (Main.elapsedTime - t).postln; +}.play +) + +// list the indicies of detected attacks - the two input channels have been summed. The two channels of the output, respectively onset and offset indices, are interleaved as this is the SuperCollider buffer data formatting +c.getn(0,c.numFrames*2,{|item|(item*2).postln;}) +// a more readable version: deinterleave onsetand offset +c.getn(0,c.numFrames*2,{|items|items.reshape(c.numFrames,2).do({|x| (x*2).postln});}) +:: diff --git a/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp index 7cd73ba..1cdf44b 100644 --- a/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp @@ -1,14 +1,14 @@ TITLE:: FluidBufAmpSlice -SUMMARY:: Amplitude-based Slicer for Buffers +SUMMARY:: Amplitude-based Detrending Slicer for Buffers CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading 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).:: +This class implements an amplitude-based slicer,with various customisable options and conditions to detect relative amplitude changes as onsets. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ -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. +FluidBufAmpSlice is based on two envelop followers on a highpassed version of the signal: one slow that gives the trend, and one fast. Each have features that will interact. 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. +The process will return a buffer which contains indices (in sample) of estimated starting points of different slices. STRONG::Threading:: @@ -40,48 +40,30 @@ 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:: absRampUp +ARGUMENT:: fastRampUp + The number of samples the fast envelope follower will take to reach the next value when raising. Typically, this will be faster than slowRampUp. + +ARGUMENT:: fastRampDown + The number of samples the fast envelope follower will take to reach the next value when falling. Typically, this will be faster than slowRampDown. + +ARGUMENT:: slowRampUp The number of samples the absolute envelope follower will take to reach the next value when raising. -ARGUMENT:: absRampDown +ARGUMENT:: slowRampDown 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:: onThreshold + 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:: offThreshold + The threshold in dB of the relative envelope follower to reset, aka to allow the differential envelop to trigger again. -ARGUMENT:: absThreshOff - The threshold in dB of the absolute envelope follower to trigger an offset, , aka to go ON when in OFF state. +ARGUMENT:: floor + The level in dB the slowRamp needs to be above to consider a detected difference valid, allowing to ignore the slices in the noise floor. 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. @@ -94,73 +76,30 @@ RETURNS:: EXAMPLES:: code:: +// detrending explained // 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})); +b = Buffer.sendCollection(s, Array.fill(44100,{|i| sin(i*pi/ (44100/640)) * ((((79000-i) % 22050).abs / 28000.0) + 0.2)})); c = Buffer.new(s); ) +// the source is a sinewave that does not go to silence and has sharp-ish amplitude bumps as onsets we try to track 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) +// +FluidBufAmpSlice.process(s, b,indices: c,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 10,floor: -60); c.query -c.getn(0,c.numFrames*2,{|item|item.postln;}) +c.getn(0,c.numFrames,{|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) +//beware of multiple triggers at the begining of the 2nd cycle above). A solution: Schmidth triggers +FluidBufAmpSlice.process(s, b,indices: c,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 7,floor: -60); c.query -c.getn(0,c.numFrames*2,{|item|item.postln;}) +c.getn(0,c.numFrames,{|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) +// we got most of them sorted, but there is another solution: minslicelength +FluidBufAmpSlice.process(s, b,indices: c,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 7,floor: -60, minSliceLength: 500); c.query -c.getn(0,c.numFrames*2,{|item|item.postln;}) +c.getn(0,c.numFrames,{|item|item.postln;}) :: STRONG::A musical example.:: @@ -172,25 +111,22 @@ c = Buffer.new(s); ) // slice the samples -FluidBufAmpSlice.process(s,b,indices:c, absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:441, relThreshOn:14, relThreshOff:12, minSliceLength:4410) +FluidBufAmpSlice.process(s,b,indices:c,fastRampUp: 10,fastRampDown: 2205,slowRampUp: 4410,slowRampDown: 4410,onThreshold: 10,offThreshold: 5,floor: -40,minSliceLength: 4410,highPassFreq: 20); c.query -c.getn(0,c.numFrames*2,{|item|item.postln;}) -//reformatting to read the onsets and offsets as pairs -c.getn(0,c.numFrames*2,{|items|items.reshape(c.numFrames,2).do({|x| x.postln});}) +c.getn(0,c.numFrames,{|item|item.postln;}) //loops over a splice with the MouseX, taking the respective onset and offset of a given slice ( { - BufRd.ar(1, b, - Phasor.ar(0,1, - BufRd.kr(2, c, - MouseX.kr(0, BufFrames.kr(c)), 0, 1)[0], - BufRd.kr(2, c, - MouseX.kr(1, BufFrames.kr(c)), 0, 1)[1], - BufRd.kr(2,c, - MouseX.kr(0, BufFrames.kr(c)), 0, 1)[0] - ), 0, 1); -}.play; + 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; ) :: @@ -211,11 +147,11 @@ c = Buffer.new(s); // with basic params Routine{ t = Main.elapsedTime; - FluidBufAmpSlice.process(s,b, indices: c, absRampUp:1, absRampDown:1, absThreshOn:-60, absThreshOff:-60); + FluidBufAmpSlice.process(s,b, indices: c, fastRampUp: 10,fastRampDown: 2205,slowRampUp: 4410,slowRampDown: 4410, onThreshold: 10,offThreshold: 5); (Main.elapsedTime - t).postln; }.play ) -// list the indicies of detected attacks - the two input channels have been summed. The two channels of the output, respectively onset and offset indices, are interleaved as this is the SuperCollider buffer data formatting -c.getn(0,c.numFrames*2,{|item|item.postln;}) +// list the indicies of detected attacks - the two input channels have been summed. +c.getn(0,c.numFrames,{|item|(item * 2).postln;}) :: diff --git a/release-packaging/HelpSource/Classes/FluidBufCompose.schelp b/release-packaging/HelpSource/Classes/FluidBufCompose.schelp index 7f188f8..5c2b323 100644 --- a/release-packaging/HelpSource/Classes/FluidBufCompose.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufCompose.schelp @@ -4,8 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition, UGens>Buffer RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading, Classes/Buffer DESCRIPTION:: -A FluidBufCompose object provides a flexible utility for combining the contents of buffers on the server. It can be used for thing like mixing down multichannel buffers, or converting from left-right stereo to mid-side. It is used extensively in all the example code of LINK::Guides/FluidDecomposition:: as part 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).:: +A FluidBufCompose object provides a flexible utility for combining the contents of buffers on the server. It can be used for thing like mixing down multichannel buffers, or converting from left-right stereo to mid-side. It is used extensively in all the example code of LINK::Guides/FluidDecomposition:: as part of the FluCoMa project. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ At its most simple, the object copies the content of a source buffer into a destination buffer. The flexibility comes from the various flags controlling which portions and channels of the source to use, and by applying gains (which can be positive or negative) to the source data and the portion of the destination that would be overwritten. @@ -94,74 +93,4 @@ FluidBufCompose.process(s, source: b, numFrames: 44100, numChans: 1, destStartCh FluidBufCompose.process(s, source: c, numFrames:44100, numChans:1, destination: d, destGain: 1.0); d.query; d.play; -:: - - STRONG::A more complex example: using composition as an Mid-Side filtering process:: - - CODE:: -// load a stereo buffer and initialise the many destinations -( -b = Buffer.read(s,File.realpath(FluidBufCompose.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav"); -c = Buffer.new(s); -d = Buffer.new(s); -e = Buffer.new(s); -f = Buffer.new(s); -) - -// encode the mid (in c) and the side (in d) -( -FluidBufCompose.process(s,b, numChans: 1, gain: -3.0.dbamp, destination: c); -FluidBufCompose.process(s,b, numChans: 1, gain: -3.0.dbamp, destination: d); -FluidBufCompose.process(s,b, numChans: 1, gain: -3.0.dbamp, startChan: 1, destination: c, destGain: 1.0); -FluidBufCompose.process(s,b, numChans: 1, gain: -3.0.dbamp * -1.0, startChan: 1, destination: d, destGain: 1.0); -) - -// (optional) compare auraly the stereo with the MS -b.play; -{PlayBuf.ar(1,[c,d])}.play; - -// The geeky bit: copy the side (buffer d) on itself with specific amplitudes and delays, in effect applying a FIR filter through expensive convolution - -// Important: do either of the 3 options below - -// option 1: apply a high pass on the side, with a cutoff of nyquist / 4 -e.free; e = Buffer.new(s); -( -[1.0, -1.0].do({ arg x,y; - FluidBufCompose.process(s, d, gain: x, destStartFrame: y, destination: e, destGain: 1.0); -}); -) - -// option 2: apply a high pass on the side, with a cutoff of nyquist / 10 -e.free; e = Buffer.new(s); -( -[0.8, -0.32, -0.24, -0.16, -0.08].do({ arg x,y; - FluidBufCompose.process(s, d, gain: x, destStartFrame: y, destination: e, destGain: 1.0); -}); -) - -// option 3: apply a high pass on the side, with a cutoff of nyquist / 100 -e.free; e = Buffer.new(s); -( -[0.982494, -0.066859, -0.064358, -0.061897, -0.059477, -0.057098, -0.054761, -0.052466, -0.050215, -0.048007, -0.045843, -0.043724, -0.041649, -0.03962, -0.037636, -0.035697, -0.033805, -0.031959, -0.030159, -0.028406, -0.026699, -0.025038, -0.023425, -0.021857, -0.020337].do({ arg x,y; - FluidBufCompose.process(s, d, gain: x, destStartFrame: y, destination: e, destGain: 1.0); -}); -) - -// play the high-passed side buffer -e.play; -// if you want to try the other filters, do not forget to clear the destination buffer since it will add programmatically onto itself and would not create the expected frequency response - -// decode the MS back to stereo -( -FluidBufCompose.process(s,c, numChans: 2, gain: -3.0.dbamp, destination: f); -FluidBufCompose.process(s,e, gain: -3.0.dbamp, destination: f, destGain: 1.0); -FluidBufCompose.process(s,e, gain: -3.0.dbamp * -1.0, destination: f, destStartChan: 1, destGain: 1.0); -) - -// play the MS processed version -f.play; - -// compare with the original -b.play; :: diff --git a/release-packaging/HelpSource/Classes/FluidBufHPSS.schelp b/release-packaging/HelpSource/Classes/FluidBufHPSS.schelp index 7a55417..711bf5b 100644 --- a/release-packaging/HelpSource/Classes/FluidBufHPSS.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufHPSS.schelp @@ -16,11 +16,7 @@ The algorithm takes a buffer in, and divides it into two or three outputs, depen ## a percussive component; ## a residual of the previous two if the flag is set to inter-dependant thresholds. See the maskingMode below.:: -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). -:: - -More information on median filtering, and on HPSS for musicianly usage, are availabe in LINK::Guides/FluCoMa:: overview file. +It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ STRONG::Threading:: @@ -101,10 +97,10 @@ ARGUMENT:: windowSize The window size in samples. As HPSS 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 in samples. As HPSS relies on spectral frames, we need to move the window forward. It can be any size but low overlap may create audible artefacts. + The window hop size in samples. As HPSS relies on spectral frames, we need to move the window forward. It can be any size but low overlap may 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 than the window size provides interpolation in frequency. + 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 than the window size provides interpolation in frequency. The -1 default value will use the next power of 2 equal or above the windowSize. 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 [harmonic, percussive, residual] as an argument. diff --git a/release-packaging/HelpSource/Classes/FluidBufLoudness.schelp b/release-packaging/HelpSource/Classes/FluidBufLoudness.schelp index 006b9f6..be696d5 100644 --- a/release-packaging/HelpSource/Classes/FluidBufLoudness.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufLoudness.schelp @@ -5,7 +5,7 @@ RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreadi DESCRIPTION:: -This class implements two loudness descriptors, computing the true peak of the signal as well as applying the filters proposed by broadcasting standards to emulate the perception of amplitude. 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 two loudness descriptors, computing the true peak of the signal as well as applying the filters proposed by broadcasting standards to emulate the perception of amplitude. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a multichannel buffer with two channels per input channel, one for loudness and one for the true peak value of the frame, both in dBfs. More information on broadcasting standardisation of loudness measurement is available at the reference page FOOTNOTE::https://tech.ebu.ch/docs/tech/tech3341.pdf:: and in more musician-friendly explantions here FOOTNOTE::http://designingsound.org/2013/02/06/loudness-and-metering-part-1/::. Each sample represents a value, which is every hopSize. Its sampling rate is STRONG::sourceSR / hopSize::. diff --git a/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp b/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp index d2e4b88..ec1f1bd 100644 --- a/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading, Classes/FluidBufMelBands DESCRIPTION:: -This class implements a classic spectral descriptor, the Mel-Frequency Cepstral Coefficients (https://en.wikipedia.org/wiki/Mel-frequency_cepstrum). The input is first filtered in to STRONG::numBands:: perceptually-spaced bands, as in LINK::Classes/FluidMelBands::. It is then analysed into STRONG::numCoeffs:: number of cepstral coefficients. It has the avantage of being amplitude invarient, except for the first coefficient. 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 classic spectral descriptor, the Mel-Frequency Cepstral Coefficients (https://en.wikipedia.org/wiki/Mel-frequency_cepstrum). The input is first filtered in to STRONG::numBands:: perceptually-spaced bands, as in LINK::Classes/FluidMelBands::. It is then analysed into STRONG::numCoeffs:: number of cepstral coefficients. It has the advantage of being amplitude invariant, except for the first coefficient. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a single multichannel buffer of STRONG::numCoeffs:: per input channel. Each frame represents a value, which is every hopSize. @@ -54,10 +54,10 @@ ARGUMENT:: windowSize The window size. As MFCC computation 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 MFCC computation relies on spectral frames, we need to move the window forward. It can be any size but low overlap will create audible artefacts. + The window hop size. As MFCC computation 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 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 use the next power of 2 equal or above the windowSize. 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 [features] as an argument. diff --git a/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp b/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp index a345c43..da18154 100644 --- a/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp @@ -5,7 +5,7 @@ RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreadi DESCRIPTION:: -This class implements a spectral shape descriptor where the amplitude is given for a number of equally spread perceptual bands. The spread is based on the Mel scale (https://en.wikipedia.org/wiki/Mel_scale) which is one of the first attempt to mimic pitch perception scientifically. This implementation allows to select the range and number of bands dynamically. 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 spectral shape descriptor where the amplitude is given for a number of equally spread perceptual bands. The spread is based on the Mel scale (https://en.wikipedia.org/wiki/Mel_scale) which is one of the first attempt to mimic pitch perception scientifically. This implementation allows to select the range and number of bands dynamically. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a single multichannel buffer of STRONG::numBands:: per input channel. Each frame represents a value, which is every hopSize. @@ -48,14 +48,17 @@ ARGUMENT:: minFreq ARGUMENT:: maxFreq The highest boundary of the highest band of the model, in Hz. +ARGUMENT:: normalize + This flag enables the scaling of the output to preserve the energy of the window. It is on (1) by default. + ARGUMENT:: windowSize The window size. As spectral description 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 spectral description relies on spectral frames, we need to move the window forward. It can be any size but low overlap will create audible artefacts. + The window hop size. As spectral description 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 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 use the next power of 2 equal or above the windowSize. 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 [features] as an argument. diff --git a/release-packaging/HelpSource/Classes/FluidBufNMF.schelp b/release-packaging/HelpSource/Classes/FluidBufNMF.schelp index e0a2d32..ba97ecb 100644 --- a/release-packaging/HelpSource/Classes/FluidBufNMF.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufNMF.schelp @@ -27,10 +27,7 @@ In this implementation, the components are reconstructed by masking the original The whole process can be related to a channel vocoder where, instead of fixed bandpass filters, we get more complex filter shapes that are learned from the data, and the activations correspond to channel envelopes. -More information on possible musicianly uses of NMF are availabe in LINK::Guides/FluCoMa:: overview file. - -FluidBufNMF 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). :: +FluidBufNMF is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ STRONG::Threading:: @@ -59,7 +56,7 @@ ARGUMENT:: startChan ARGUMENT:: numChans For multichannel srcBuf, how many channel should be processed. -ARGUMENT:: destination +ARGUMENT:: resynth The index of the buffer where the different reconstructed components will be reconstructed. The buffer will be resized to STRONG::components * numChannelsProcessed:: channels and STRONG::sourceDuration:: lenght. If STRONG::nil:: is provided, the reconstruction will not happen. ARGUMENT:: bases @@ -94,10 +91,10 @@ ARGUMENT:: windowSize The window size. As NMF 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 NMF relies on spectral frames, we need to move the window forward. It can be any size but low overlap will create audible artefacts. + The window hop size. As NMF 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 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 use the next power of 2 equal or above the windowSize. ARGUMENT:: windowType The inner FFT/IFFT windowing type (not implemented yet) @@ -106,7 +103,7 @@ ARGUMENT:: randomSeed The NMF process needs to seed its starting point. If specified, the same values will be used. The default of -1 will randomly assign them. (not implemented yet) 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 [destination, bases, activations] as an argument. + 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 [resynth, bases, activations] as an argument. RETURNS:: Nothing, as the various destination buffers are declared in the function call. @@ -145,7 +142,7 @@ d.play //////(beware !!!! loud!!!) ( // separate them in 2 components Routine { - FluidBufNMF.process(s, d, destination:e, bases: f, activations:g, components:2); + FluidBufNMF.process(s, d, resynth:e, bases: f, activations:g, components:2); e.query; f.query; g.query; @@ -299,7 +296,7 @@ z.do({|chan| FluidBufCompose.process(s, ~bases, startChan:chan, numChans: 1, des //process the whole file, splitting it with the 2 trained bases ( Routine{ - FluidBufNMF.process(s, b, destination: ~sortedNMF, bases: ~trainedBases, basesMode: 2, components:2); + FluidBufNMF.process(s, b, resynth: ~sortedNMF, bases: ~trainedBases, basesMode: 2, components:2); ~originalNMF.query; }.play; ) @@ -357,7 +354,7 @@ e.query ( // use the seeding basis, without updating Routine { - FluidBufNMF.process(s, d, destination:f, bases: e, basesMode: 2, activations:g, components:3); + FluidBufNMF.process(s, d, resynth:f, bases: e, basesMode: 2, activations:g, components:3); e.query; f.query; g.query; @@ -376,7 +373,7 @@ g.plot; ( // use the seeding bases, with updating this time Routine { - FluidBufNMF.process(s, d, destination:f, bases: e, basesMode: 1, activations:g, components:3); + FluidBufNMF.process(s, d, resynth:f, bases: e, basesMode: 1, activations:g, components:3); e.query; f.query; g.query; diff --git a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp index 98be3fd..0dba199 100644 --- a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition, UGens>Buffer RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading 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).:: +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 LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a buffer which contains indices (in sample) of estimated starting points of different slices. @@ -55,14 +55,17 @@ ARGUMENT:: threshold 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:: minSliceLength + The minimum duration of a slice in number of hopSize. + 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. + 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. 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 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 use the next power of 2 equal or above the 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. @@ -81,10 +84,10 @@ c = Buffer.new(s); ) ( -// with basic params +// with basic params, with a minimum slight length to avoid over Routine{ t = Main.elapsedTime; - FluidBufNoveltySlice.process(s,b, indices: c, threshold:0.45); + FluidBufNoveltySlice.process(s,b, indices: c, threshold:0.4,filterSize: 4, minSliceLength: 8); (Main.elapsedTime - t).postln; }.play ) @@ -122,15 +125,15 @@ FluidBufNoveltySlice.process(s,b, indices: c, kernelSize:31, threshold:0.1, filt //check the number of slices: it is the number of frames in the transBuf minus the boundary index. c.query; -//play slice number 2 +//play slice number 3 ( { - 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); + BufRd.ar(1, b, + Line.ar( + BufRd.kr(1, c, DC.kr(3), 0, 1), + BufRd.kr(1, c, DC.kr(4), 0, 1), + (BufRd.kr(1, c, DC.kr(4)) - BufRd.kr(1, c, DC.kr(3), 0, 1) + 1) / s.sampleRate), + 0,1); }.play; ) @@ -167,5 +170,5 @@ Routine{ ) // list the indicies of detected attacks - the two input channels have been summed -c.getn(0,c.numFrames,{|item|item.postln;}) +c.getn(0,c.numFrames,{|item|(item * 2).postln;}) :: diff --git a/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufOnsetSlice.schelp index 2e6563a..4942473 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, Guides/FluidBufMultiThreading DESCRIPTION:: -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).:: +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 LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a buffer which contains indices (in sample) of estimated starting points of different slices. @@ -72,7 +72,7 @@ ARGUMENT:: hopSize The window hop size. As spectral differencing 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 use the next power of 2 equal or above the 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. @@ -134,11 +134,11 @@ c = Buffer.new(s); // with basic params Routine{ t = Main.elapsedTime; - FluidBufOnsetSlice.process(s,b, indices: c, threshold:0.1); + FluidBufOnsetSlice.process(s,b, indices: c, threshold:0.00001); (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;}) +c.getn(0,c.numFrames,{|item|(item * 2).postln;}) :: diff --git a/release-packaging/HelpSource/Classes/FluidBufPitch.schelp b/release-packaging/HelpSource/Classes/FluidBufPitch.schelp index ed40dfe..3b8f530 100644 --- a/release-packaging/HelpSource/Classes/FluidBufPitch.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufPitch.schelp @@ -5,7 +5,7 @@ RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreadi DESCRIPTION:: -This class implements three popular pitch descriptors, computed as frequency and the confidence in its value. 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 three popular pitch descriptors, computed as frequency and the confidence in its value. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a multichannel buffer with two channels per input channel, one for pitch and one for the pitch tracking confidence. Each sample represents a value, which is every hopSize. Its sampling rate is sourceSR / hopSize. @@ -60,10 +60,10 @@ 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 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 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 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 use the next power of 2 equal or above the windowSize. 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 [features] as an argument. diff --git a/release-packaging/HelpSource/Classes/FluidBufSines.schelp b/release-packaging/HelpSource/Classes/FluidBufSines.schelp index 7b42a75..152d651 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSines.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSines.schelp @@ -5,13 +5,13 @@ RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreadi DESCRIPTION:: -This class triggers a Sinusoidal Modelling process on buffers on the non-real-time thread of the server. It implements a mix and match algorithms taken from classic papers. 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 triggers a Sinusoidal Modelling process on buffers on the non-real-time thread of the server. It implements a mix of algorithms taken from classic papers. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The algorithm will take a buffer in, and will divide it in two parts: LIST:: ## a reconstruction of what it detects as sinusoidal; ## a residual derived from the previous buffer to allow null-summing:: - The whole process is based on the assumption that signal is made of pitched steady components that have a long-enough duration and are periodic enough to be perceived as such, that can be tracked, resynthesised and removed from the original, leaving behind what is considered as non-pitched, noisy, and/or transient. It first tracks the peaks, then checks if they are the continuation of a peak in previous spectral frames, by assigning them a track. More information on this model, and on how it links to musicianly thinking, are availabe in LINK::Guides/FluCoMa:: overview file. + The whole process is based on the assumption that signal is made of pitched steady components that have a long-enough duration and are periodic enough to be perceived as such, that can be tracked, resynthesised and removed from the original, leaving behind what is considered as non-pitched, noisy, and/or transient. It first tracks the peaks, then checks if they are the continuation of a peak in previous spectral frames, by assigning them a track. STRONG::Threading:: @@ -47,28 +47,40 @@ 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. It is capped at (fftSize / 2) + 1. + The number of bins used to resynthesises a peak. 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. +ARGUMENT:: detectionThreshold + The threshold in dB above which a magnitude peak is considered to be a sinusoidal component. + +ARGUMENT:: birthLowThreshold + The threshold in dB above which to consider a peak to start a sinusoidal component tracking, for the low end of the spectrum. It is interpolated across the spectrum until birthHighThreshold at half-Nyquist. + +ARGUMENT:: birthHighThreshold + The threshold in dB above which to consider a peak to start a sinusoidal component tracking, for the high end of the spectrum. It is interpolated across the spectrum until birthLowThreshold at DC. ARGUMENT:: minTrackLen - The minimum duration, in spectral frames, for a sinusoidal track to be accepted as a partial. It allows to remove space-monkeys, but is more CPU intensive and might reject quick pitch material. + The minimum duration, in spectral frames, for a sinusoidal track to be accepted as a partial. It allows to remove bubbly pitchy artefacts, but is more CPU intensive and might reject quick pitch material. + +ARGUMENT:: trackingMethod + The algorithm used to track the sinusoidal continuity between spectral frames. 0 is the default, "Greedy", and 1 is a more expensive "Hungarian" one. footnote::Neri, J., and Depalle, P., "Fast Partial Tracking of Audio with Real-Time Capability through Linear Programming". Proceedings of DAFx-2018.:: + +ARGUMENT:: trackMagRange + The amplitude difference allowed for a track to diverge between frames, in dB. -ARGUMENT:: magWeight - The weight of the magnitude proximity of a peak when trying to associate it to an existing track (relative to freqWeight - suggested between 0 to 1) +ARGUMENT:: trackFreqRange + The frequency difference allowed for a track to diverge between frames, in Hertz. -ARGUMENT:: freqWeight - The weight of the frequency proximity of a peak when trying to associate it to an existing track (relative to magWeight - suggested between 0 to 1) +ARGUMENT:: trackProb + The probability of the tracking algorithm to find a track. 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 + 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 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 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 the highest of windowSize and (bandwidth - 1) * 2. + 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 use the next power of 2 equal or above 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. @@ -123,7 +135,7 @@ d = Buffer.new(s); e = Buffer.new(s); ( Routine{ t = Main.elapsedTime; - FluidBufSines.process(s, b, sines: d, residual:e, threshold:0.3); + FluidBufSines.process(s, b, sines: d, residual:e, windowSize: 2048, hopSize: 256, fftSize: 16384); (Main.elapsedTime - t).postln; }.play ) diff --git a/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp b/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp index a45b139..e85d93f 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp @@ -5,7 +5,7 @@ RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreadi DESCRIPTION:: -This class implements seven of the most popular spectral shape descriptors, computed on a linear scale for both amplitude and frequency. 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 seven of the most popular spectral shape descriptors, computed on a linear scale for both amplitude and frequency. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The descriptors are: LIST:: @@ -59,10 +59,10 @@ ARGUMENT:: windowSize The window size. As spectral shape 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 spectral shape 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 window hop size. As spectral shape 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 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 use the next power of 2 equal or above the windowSize. 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 [features] as an argument. diff --git a/release-packaging/HelpSource/Classes/FluidBufStats.schelp b/release-packaging/HelpSource/Classes/FluidBufStats.schelp index dbae2f0..ce83e04 100644 --- a/release-packaging/HelpSource/Classes/FluidBufStats.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufStats.schelp @@ -5,7 +5,7 @@ RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreadi DESCRIPTION:: -This class implements non-real-time statistical analysis on buffer channels. Typically, a buffer would hold various time series (i.e. descriptors over time), and link::Classes/FluidBufStats:: allows this series to be described statistically. 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 non-real-time statistical analysis on buffer channels. Typically, a buffer would hold various time series (i.e. descriptors over time), and link::Classes/FluidBufStats:: allows this series to be described statistically. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process returns a buffer where each channel of the STRONG::source:: buffer has been reduced to 7 statistics: mean, standard deviation, skewness, kurtosis, followed by 3 percentiles, by default the minimum value, the median, and the maximum value. Moreover, it is possible to request the same 7 stats to be applied to derivative of the input. These are useful to describe statistically the rate of change of the time series. The STRONG::stats:: buffer will grow accordingly, yielding the seven same statistical description of the n requested derivatives. Therefore, the STRONG::stats:: buffer will have as many channel as the input buffer, and as many frames as 7 times the requested STRONG::numDerivs::. diff --git a/release-packaging/HelpSource/Classes/FluidBufThreadDemo.schelp b/release-packaging/HelpSource/Classes/FluidBufThreadDemo.schelp index 2a78bc0..99427b3 100644 --- a/release-packaging/HelpSource/Classes/FluidBufThreadDemo.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufThreadDemo.schelp @@ -4,7 +4,9 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading DESCRIPTION:: -This class implements a simple tutorial object to illustrate and experiment with the behaviour of the FluidBuf* objects. 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).:: It simply starts a process that will, upon completion of its task, write a single value to the destination buffer. This is the general behaviour of much of the CPU consuming FluidBuf* objects. In this case, as a toy example, the task is simply just wait and do nothing, to simulate a task that would actually take that long in the background. +This class implements a simple tutorial object to illustrate and experiment with the behaviour of the FluidBuf* objects. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ + +It simply starts a process that will, upon completion of its task, write a single value to the destination buffer. This is the general behaviour of much of the CPU consuming FluidBuf* objects. In this case, as a toy example, the task is simply just wait and do nothing, to simulate a task that would actually take that long in the background. The process will, after waiting for STRONG::time:: millisecond, return its delay lenght as a Float writen at index [0] of the specified destination buffer. diff --git a/release-packaging/HelpSource/Classes/FluidBufTransientSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufTransientSlice.schelp index 21f5c5e..709a058 100644 --- a/release-packaging/HelpSource/Classes/FluidBufTransientSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufTransientSlice.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition, UGens>Buffer RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading, Classes/FluidBufTransients DESCRIPTION:: -This class implements a non-real-time transient-based slice extractor relying on the same algorithm than Classes/FluidBufTransients using clicks/transients/derivation/anomaly in the signal to estimate the slicing points. 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 non-real-time transient-based slice extractor relying on the same algorithm than Classes/FluidBufTransients using clicks/transients/derivation/anomaly in the signal to estimate the slicing points. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a buffer which contains indices (in sample) of estimated starting points of the different slices. @@ -144,5 +144,5 @@ Routine{ ) // list the indicies of detected attacks - the two input channels have been summed -c.getn(0,c.numFrames,{|item|item.postln;}) +c.getn(0,c.numFrames,{|item|(item*2).postln;}) :: diff --git a/release-packaging/HelpSource/Classes/FluidBufTransients.schelp b/release-packaging/HelpSource/Classes/FluidBufTransients.schelp index 237d7d2..4f71858 100644 --- a/release-packaging/HelpSource/Classes/FluidBufTransients.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufTransients.schelp @@ -4,14 +4,13 @@ CATEGORIES:: Libraries>FluidDecomposition, UGens>Buffer RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading DESCRIPTION:: -This class triggers a transient extractor on buffers on the non-real-time thread of the server. It implements declicking algorithm from chapter 5 of the classic Digital Audio Restoration by Godsill, Simon J., Rayner, Peter J.W. with some bespoke improvements on the detection function tracking. 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 triggers a transient extractor on buffers on the non-real-time thread of the server. It implements declicking algorithm from chapter 5 of the classic Digital Audio Restoration by Godsill, Simon J., Rayner, Peter J.W. with some bespoke improvements on the detection function tracking. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The algorithm will take a buffer in, and will divide it in two outputs: LIST:: ## the transients, estimated from the signal and extracted from it; ## the remainder of the material, as estimated by the algorithm.:: - The whole process is based on the assumption that a transient is an element that is deviating from the surrounding material, as sort of click or anomaly. The algorithm then estimates what should have happened if the signal had followed its normal path, and resynthesises this estimate, removing the anomaly which is considered as the transient. More information on signal estimation, and on its musicianly usage, are availabe in LINK::Guides/FluCoMa:: overview file. + The whole process is based on the assumption that a transient is an element that is deviating from the surrounding material, as sort of click or anomaly. The algorithm then estimates what should have happened if the signal had followed its normal path, and resynthesises this estimate, removing the anomaly which is considered as the transient. STRONG::Threading:: diff --git a/release-packaging/HelpSource/Classes/FluidGain.schelp b/release-packaging/HelpSource/Classes/FluidGain.schelp index 18f4d61..2783e26 100644 --- a/release-packaging/HelpSource/Classes/FluidGain.schelp +++ b/release-packaging/HelpSource/Classes/FluidGain.schelp @@ -5,7 +5,7 @@ RELATED:: Guides/FluCoMa, Guides/FluidDecomposition,Classes/UnaryOpFunction DESCRIPTION:: -This class implements a sanity test for the FluCoMa Real-Time Client Wrapper. 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 sanity test for the FluCoMa Real-Time Client Wrapper. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ CLASSMETHODS:: diff --git a/release-packaging/HelpSource/Classes/FluidHPSS.schelp b/release-packaging/HelpSource/Classes/FluidHPSS.schelp index 084519f..96f2570 100644 --- a/release-packaging/HelpSource/Classes/FluidHPSS.schelp +++ b/release-packaging/HelpSource/Classes/FluidHPSS.schelp @@ -14,11 +14,8 @@ The algorithm takes an audio in, and divides it into two or three outputs, depen ## a percussive component; ## a residual of the previous two if the flag is set to inter-dependant thresholds. See the maskingMode below.:: -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). -:: +It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ -More information on median filtering, and on HPSS for musicianly usage, are availabe in LINK::Guides/FluCoMa:: overview file. CLASSMETHODS:: METHOD:: ar @@ -73,7 +70,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 use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. diff --git a/release-packaging/HelpSource/Classes/FluidLoudness.schelp b/release-packaging/HelpSource/Classes/FluidLoudness.schelp index 449beb2..9a6ffdc 100644 --- a/release-packaging/HelpSource/Classes/FluidLoudness.schelp +++ b/release-packaging/HelpSource/Classes/FluidLoudness.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition DESCRIPTION:: -This class implements two loudness descriptors, computing the true peak of the signal as well as applying the filters proposed by broadcasting standards to emulate the perception of amplitude. 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 two loudness descriptors, computing the true peak of the signal as well as applying the filters proposed by broadcasting standards to emulate the perception of amplitude. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a multichannel control steam with [loudness, truepeak] values, both in dBfs, which will be repeated if no change happens within the algorithm, i.e. when the hopSize is larger than the server's kr period. More information on broadcasting standardisation of loudness measurement is available at the reference page FOOTNOTE::https://tech.ebu.ch/docs/tech/tech3341.pdf:: and in more musician-friendly explantions here FOOTNOTE::http://designingsound.org/2013/02/06/loudness-and-metering-part-1/::. diff --git a/release-packaging/HelpSource/Classes/FluidMFCC.schelp b/release-packaging/HelpSource/Classes/FluidMFCC.schelp index d685eb2..4fb62cf 100644 --- a/release-packaging/HelpSource/Classes/FluidMFCC.schelp +++ b/release-packaging/HelpSource/Classes/FluidMFCC.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Classes/FluidMelBands DESCRIPTION:: -This class implements a classic spectral descriptor, the Mel-Frequency Cepstral Coefficients (https://en.wikipedia.org/wiki/Mel-frequency_cepstrum). The input is first filtered in to STRONG::numBands:: perceptually-spaced bands, as in LINK::Classes/FluidMelBands::. It is then analysed into STRONG::numCoeffs:: number of cepstral coefficients. It has the avantage of being amplitude invarient, except for the first coefficient. 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 classic spectral descriptor, the Mel-Frequency Cepstral Coefficients (https://en.wikipedia.org/wiki/Mel-frequency_cepstrum). The input is first filtered in to STRONG::numBands:: perceptually-spaced bands, as in LINK::Classes/FluidMelBands::. It is then analysed into STRONG::numCoeffs:: number of cepstral coefficients. It has the avantage of being amplitude invarient, except for the first coefficient. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a multichannel control steam of STRONG::maxNumCoeffs::, which will be repeated if no change happens within the algorythm, i.e. when the hopSize is larger than the server's kr period. @@ -38,7 +38,7 @@ ARGUMENT:: hopSize The window hop size. As MFCC computation 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 use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. diff --git a/release-packaging/HelpSource/Classes/FluidMelBands.schelp b/release-packaging/HelpSource/Classes/FluidMelBands.schelp index 473bd4d..3eca271 100644 --- a/release-packaging/HelpSource/Classes/FluidMelBands.schelp +++ b/release-packaging/HelpSource/Classes/FluidMelBands.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Classes/FluidMFCC DESCRIPTION:: -This class implements a spectral shape descriptor where the amplitude is given for a number of equally spread perceptual bands. The spread is based on the Mel scale (https://en.wikipedia.org/wiki/Mel_scale) which is one of the first attempt to mimic pitch perception scientifically. This implementation allows to select the range and number of bands dynamically. 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 spectral shape descriptor where the amplitude is given for a number of equally spread perceptual bands. The spread is based on the Mel scale (https://en.wikipedia.org/wiki/Mel_scale) which is one of the first attempt to mimic pitch perception scientifically. This implementation allows to select the range and number of bands dynamically. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return a multichannel control steam of size STRONG::maxNumBands::, which will be repeated if no change happens within the algorythm, i.e. when the hopSize is larger than the server's kr period. @@ -28,6 +28,9 @@ ARGUMENT:: maxFreq ARGUMENT:: maxNumBands The maximum number of Mel bands that can be modelled. This sets the number of channels of the output, and therefore cannot be modulated. +ARGUMENT:: normalize + This flag enables the scaling of the output to preserve the energy of the window. It is on (1) by default. + 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 @@ -35,7 +38,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 use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. @@ -59,7 +62,7 @@ a = MultiSliderView(w,Rect(10, 10, 600, 300)).elasticMode_(1).isFilled_(1); //run the window updating routine. ( -~winRange = 100; +~winRange = 0.1; r = Routine { { b.get({ arg val; @@ -78,7 +81,7 @@ r = Routine { ( x = { var source = SinOsc.ar(LFTri.kr(0.1).exprange(80,800),0,0.1); - Out.kr(b,FluidMelBands.kr(source,maxNumBands:40) / 50); + Out.kr(b,FluidMelBands.kr(source,maxNumBands:40)); source.dup; }.play; ) @@ -99,7 +102,7 @@ x = {arg bands = 40, low = 20, high = 20000; ) //set the winRange to a more informative value -~winRange = 400; +~winRange = 0.05; // observe the number of bands. The unused ones at the top are not updated x.set(\bands,20) @@ -107,7 +110,7 @@ x.set(\bands,20) // back to the full range x.set(\bands,40) -// focus all the bands on a mid range +// focus all the bands on a mid range: nothing to see! 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 @@ -125,12 +128,12 @@ STRONG::A musical example: a perceptually spread vocoder:: CODE:: //load a source and define control bus for the resynthesis cluster ( -b = Bus.new(\control,0,40); +b = Bus.control(s,40); c = Buffer.read(s,File.realpath(FluidMelBands.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); d = Group.new; ) -//play the source and s +//play the source and send the analysis on the ( x = { arg dry = 0.2; @@ -154,7 +157,7 @@ var stepMel = rangeMel / 41; arg i; var freqMel = (stepMel * (i +1)) + lowMel; var freq = ((freqMel/ 1127.01048).exp - 1 ) * 700; - {SinOsc.ar(freq,mul:Lag.kr(In.kr(b,40)[i],512*SampleDur.ir,0.0001))}.play(d,1,addAction:\addToTail); + {SinOsc.ar(freq,mul:Lag.kr(In.kr(b,40)[i],512*SampleDur.ir,0.5))}.play(d,1,addAction:\addToTail); }); ) @@ -167,7 +170,7 @@ d.free; x.free; b.free; c.free; // the bus, source and group ( -b = Bus.new(\control,0,40); +b = Bus.control(s,40); c = Buffer.read(s,File.realpath(FluidMelBands.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); d = Group.new; ) @@ -193,11 +196,10 @@ x = { var stepMel = rangeMel / 41; var freqMel = (stepMel * (i +1)) + lowMel; var freq = ((freqMel/ 1127.01048).exp - 1 ) * 700; - SinOsc.ar(freq,mul:Lag.kr(In.kr(b,40)[i],512*SampleDur.ir,0.0001))}.play(d,1,addAction:\addToTail); + SinOsc.ar(freq,mul:Lag.kr(In.kr(b,40)[i],512*SampleDur.ir,0.5))}.play(d,1,addAction:\addToTail); }); ) // free all d.free; x.free; b.free; c.free; - :: diff --git a/release-packaging/HelpSource/Classes/FluidNMFFilter.schelp b/release-packaging/HelpSource/Classes/FluidNMFFilter.schelp index 664ff8d..a5efa31 100644 --- a/release-packaging/HelpSource/Classes/FluidNMFFilter.schelp +++ b/release-packaging/HelpSource/Classes/FluidNMFFilter.schelp @@ -12,9 +12,7 @@ NMF has been a popular technique in signal processing research for things like s The whole process can be related to a channel vocoder where, instead of fixed bandpass filters, we get more complex filter shapes and the activations correspond to channel envelopes. -More information on possible musicianly uses of NMF are availabe in LINK::Guides/FluCoMa:: overview file. - -FluidBufNMF 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). :: +FluidBufNMF is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ CLASSMETHODS:: @@ -41,7 +39,7 @@ ARGUMENT:: hopSize The window hop size. As NMF 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 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 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 use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. diff --git a/release-packaging/HelpSource/Classes/FluidNMFMatch.schelp b/release-packaging/HelpSource/Classes/FluidNMFMatch.schelp index 3aeecc2..d4202e2 100644 --- a/release-packaging/HelpSource/Classes/FluidNMFMatch.schelp +++ b/release-packaging/HelpSource/Classes/FluidNMFMatch.schelp @@ -12,9 +12,7 @@ NMF has been a popular technique in signal processing research for things like s The whole process can be related to a channel vocoder where, instead of fixed bandpass filters, we get more complex filter shapes and the activations correspond to channel envelopes. -More information on possible musicianly uses of NMF are availabe in LINK::Guides/FluCoMa:: overview file. - -FluidBufNMF 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). :: +FluidBufNMF is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ CLASSMETHODS:: @@ -41,7 +39,7 @@ ARGUMENT:: hopSize The window hop size. As NMF 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 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 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 use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. @@ -182,134 +180,8 @@ z.do({|chan| FluidBufCompose.process(s, ~bases, startChan:chan, numChans: 1, des ) :: -STRONG::Object finder:: - CODE:: -//set some buffers -( -b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-BaB-SoundscapeGolcarWithDog.wav"); -c = Buffer.new(s); -x = Buffer.new(s); -e = Buffer.new(s); -) -// train where all objects are present -( -Routine { - FluidBufNMF.process(s,b,130000,150000,0,1, c, x, components:10); - c.query; -}.play; -) - -// wait for the query to print -// then find a component for each item you want to find. You could also sum them. Try to find a component with a good object-to-rest ratio -( - ~dog =4; - {PlayBuf.ar(10,c)[~dog]}.play -) -( - ~bird = 3; - {PlayBuf.ar(10,c)[~bird]}.play -) - - -// copy at least one other component to a third filter, a sort of left-over channel -( -Routine{ - FluidBufCompose.process(s, x, startChan:~dog, numChans: 1, destination: e); - FluidBufCompose.process(s, x, startChan:~bird, numChans: 1, destStartChan: 1, destination: e, destGain:1); - (0..9).removeAll([~dog,~bird]).do({|chan|FluidBufCompose.process(s,x, startChan:chan, numChans: 1, destStartChan: 2, destination: e, destGain:1)}); - e.query; -}.play; -) -e.plot; - -//using this trained basis we can then see the activation... (wait for 5 seconds before it prints!) -( -{ - var source, blips; - //read the source - source = PlayBuf.ar(2, b); - blips = FluidNMFMatch.kr(source.sum,e,3); - }.plot(5); -) - -// ...and use some threshold to 'find' objects... -( -{ - var source, blips; - //read the source - source = PlayBuf.ar(2, b); - blips = Schmidt.kr(FluidNMFMatch.kr(source.sum,e,3),0.5,[10,1,1000]); - }.plot(5); -) - -// ...and use these to sonify them -( -{ - var source, blips, dogs, birds; - //read the source - source = PlayBuf.ar(2, b); - blips = Schmidt.kr(FluidNMFMatch.kr(source.sum,e,3),0.5,[10,1,1000]); - dogs = SinOsc.ar(100,0,Lag.kr(blips[0],0.05,0.15)); - birds = SinOsc.ar(1000,0,Lag.kr(blips[1],0.05,0.05)); - [dogs, birds] + source; - }.play; -) -:: - STRONG::Pretrained piano:: - CODE:: -//load in the sound in and a pretrained basis -( - b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav"); - c = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/filters/piano-dicts.wav"); -) -b.play -c.query - -//use the pretrained bases to compute activations of each notes to drive the amplitude of a resynth -( -{ - var source, resynth; - source = PlayBuf.ar(2, b,loop:1).sum; - resynth = SinOsc.ar((21..108).midicps, 0, FluidNMFMatch.kr(source,c,88,10,4096).madd(0.002)).sum; - [source, resynth] -}.play -) - - -//now sample and hold the same stream to get notes identified, played and sent back via osc -( -{ - var source, resynth, chain, trig, acts; - source = PlayBuf.ar(2,b,loop:1).sum; - - // built in attack detection, delayed until the stable part of the sound - chain = FFT(LocalBuf(256), source); - trig = TDelay.kr(Onsets.kr(chain, 0.5),0.1); - - // samples and holds activation values that are scaled and capped, in effect thresholding them - acts = Latch.kr(FluidNMFMatch.kr(source,c,88,10,4096).linlin(15,20,0,0.1),trig); - - // resynths as in the previous example, with the values sent back to the language - resynth = SinOsc.ar((21..108).midicps, 0, acts).sum; - SendReply.kr(trig, '/activations', acts); - [source, resynth] - // [source, T2A.ar(trig)] - // resynth -}.play -) - -// define a receiver for the activations -( - OSCdef(\listener, {|msg| - var data = msg[3..]; - // removes the silent and spits out the indicies as midinote number - data.collect({arg item, i; if (item > 0.01, {i + 21})}).reject({arg item; item.isNil}).postln; - }, '/activations'); -) - -:: STRONG::Strange Resonators:: CODE:: //load the source and declare buffers/arrays diff --git a/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp index 4a90c54..e5f8ec3 100644 --- a/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidNoveltySlice.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition DESCRIPTION:: -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).:: +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 LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return an audio steam with sample-long impulses at estimated starting points of the different slices. @@ -34,6 +34,9 @@ ARGUMENT:: threshold 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:: minSliceLength + The minimum duration of a slice in number of hopSize. + 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 @@ -41,7 +44,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 use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. @@ -53,8 +56,7 @@ 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 + - ((((kernelSize - 1) / 2) + (filterSize - 1)) * hopSize) at maximum. + An audio stream with impulses at detected transients. The latency between the input and the output is STRONG::windowSize + (hopSize * (((kernelSize+1)/2) + (filterSize / 2))):: samples at minimum. EXAMPLES:: @@ -63,20 +65,20 @@ code:: 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); [FluidNoveltySlice.ar(sig,0,11,0.3) * 0.5, DelayN.ar(sig, 1, (1024 +((((11 - 1) / 2) + (1 - 1)) * 512)) / s.sampleRate)]}.play +{var sig = PlayBuf.ar(1,b,loop:1); [FluidNoveltySlice.ar(sig,0,11,0.33) * 0.5, DelayN.ar(sig, 1, (1024 + (512 * (((11+1)/2) + (1 / 2))))/ s.sampleRate, 0.2)]}.play // other parameters -{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 +{var sig = PlayBuf.ar(1,b,loop:1); [FluidNoveltySlice.ar(sig, 1, 31, 0.0035, 4, 100, 128, 32) * 0.5, DelayN.ar(sig, 1, (128 + (32 * (((31+1)/2) + (4 / 2))))/ s.sampleRate,0.2)]}.play -// more musical trans-trigged autopan +// More musical, novelty-trigged autopan ( { var sig, trig, syncd, pan; sig = PlayBuf.ar(1,b,loop:1); - trig = FluidNoveltySlice.ar(sig, 0, 11, 0.2, 4, 128); - syncd = DelayN.ar(sig, 1, ( (128 +((((11 - 1) / 2) + (4 - 1)) * 64)) / s.sampleRate)); + trig = FluidNoveltySlice.ar(sig, 0, 11, 0.25, 5, 1, 128, 32); + syncd = DelayN.ar(sig, 1, (128 + (32 * (((11+1)/2) + (5 / 2))))/ s.sampleRate); pan = TRand.ar(-1,1,trig); Pan2.ar(syncd,pan); }.play ) -:: \ No newline at end of file +:: diff --git a/release-packaging/HelpSource/Classes/FluidOnsetSlice.schelp b/release-packaging/HelpSource/Classes/FluidOnsetSlice.schelp index 1918be3..dcc14ce 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 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).:: +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 LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The process will return an audio steam with sample-long impulses at estimated starting points of the different slices. @@ -51,7 +51,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 use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. @@ -71,7 +71,7 @@ b = Buffer.read(s,File.realpath(FluidOnsetSlice.class.filenameSymbol).dirname.wi // other parameters {var sig = PlayBuf.ar(1,b,loop:1); [FluidOnsetSlice.ar(sig, 2, 0.06, 55, 7, 0, 128, 64) * 0.5, DelayN.ar(sig, 1, (128)/ s.sampleRate)]}.play -// more musical trans-trigged autopan +// More musical, onset-trigged autopan ( { var sig, trig, syncd, pan; diff --git a/release-packaging/HelpSource/Classes/FluidPitch.schelp b/release-packaging/HelpSource/Classes/FluidPitch.schelp index f8cb7e6..d442f0f 100644 --- a/release-packaging/HelpSource/Classes/FluidPitch.schelp +++ b/release-packaging/HelpSource/Classes/FluidPitch.schelp @@ -4,9 +4,9 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Classes/Pitch DESCRIPTION:: -This class implements three popular pitch descriptors, computed as frequency and the confidence in its value. 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 three popular pitch descriptors, computed as frequency and the confidence in its value. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ - The process will return a multichannel control steam with [pitch, confidence] values, which will be repeated if no change happens within the algorithm, i.e. when the hopSize is larger than the server's kr period. +The process will return a multichannel control steam with [pitch, confidence] values, which will be repeated if no change happens within the algorithm, i.e. when the hopSize is larger than the server's kr period. CLASSMETHODS:: @@ -40,7 +40,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 use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. diff --git a/release-packaging/HelpSource/Classes/FluidSTFTPass.schelp b/release-packaging/HelpSource/Classes/FluidSTFTPass.schelp index 2f73b18..90f2c59 100644 --- a/release-packaging/HelpSource/Classes/FluidSTFTPass.schelp +++ b/release-packaging/HelpSource/Classes/FluidSTFTPass.schelp @@ -5,7 +5,7 @@ RELATED:: Guides/FluCoMa, Guides/FluidDecomposition,Classes/UnaryOpFunction DESCRIPTION:: -This class implements a sanity test for the FluCoMa Real-Time Client FFT/IFFT Wrapper. 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 sanity test for the FluCoMa Real-Time Client FFT/IFFT Wrapper. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ CLASSMETHODS:: @@ -23,7 +23,7 @@ ARGUMENT:: hopSize How much the buffered window moves forward, in samples. The -1 default value will default to half of windowSize (overlap of 2). ARGUMENT:: fftSize - How large will the FFT be, zero-padding the buffer to the right size, which should be bigger than the windowSize argument, bigger than 4 samples, and should be a power of 2. This is a way to oversample the FFT for extra precision. The -1 default value will default to windowSize. + How large will the FFT be, zero-padding the buffer to the right size, which should be bigger than the windowSize argument, bigger than 4 samples, and should be a power of 2. This is a way to oversample the FFT for extra precision. The -1 default value will use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. diff --git a/release-packaging/HelpSource/Classes/FluidSines.schelp b/release-packaging/HelpSource/Classes/FluidSines.schelp index f4b9a41..f419a7c 100644 --- a/release-packaging/HelpSource/Classes/FluidSines.schelp +++ b/release-packaging/HelpSource/Classes/FluidSines.schelp @@ -4,13 +4,13 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition DESCRIPTION:: -This class applies a Sinusoidal Modelling process on its audio input. It implements a mix and match algorithms taken from classic papers. 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 applies a Sinusoidal Modelling process on its audio input. It implements a mix of algorithms taken from classic papers. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The algorithm will take an audio in, and will divide it in two parts: LIST:: ## a reconstruction of what it detects as sinusoidal; ## a residual derived from the previous signal to allow null-summing:: - The whole process is based on the assumption that signal is made of pitched steady components that have a long-enough duration and are periodic enough to be perceived as such, that can be tracked, resynthesised and removed from the original, leaving behind what is considered as non-pitched, noisy, and/or transient. It first tracks the peaks, then checks if they are the continuation of a peak in previous spectral frames, by assigning them a track. More information on this model, and on how it links to musicianly thinking, are availabe in LINK::Guides/FluCoMa:: overview file. + The whole process is based on the assumption that signal is made of pitched steady components that have a long-enough duration and are periodic enough to be perceived as such, that can be tracked, resynthesised and removed from the original, leaving behind what is considered as non-pitched, noisy, and/or transient. It first tracks the peaks, then checks if they are the continuation of a peak in previous spectral frames, by assigning them a track. CLASSMETHODS:: @@ -22,19 +22,31 @@ 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. It is capped at (fftSize / 2) + 1. + The number of bins used to resynthesises a peak. 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. +ARGUMENT:: detectionThreshold + The threshold in dB above which a magnitude peak is considered to be a sinusoidal component. + +ARGUMENT:: birthLowThreshold + The threshold in dB above which to consider a peak to start a sinusoidal component tracking, for the low end of the spectrum. It is interpolated across the spectrum until birthHighThreshold at half-Nyquist. + +ARGUMENT:: birthHighThreshold + The threshold in dB above which to consider a peak to start a sinusoidal component tracking, for the high end of the spectrum. It is interpolated across the spectrum until birthLowThreshold at DC. ARGUMENT:: minTrackLen - The minimum duration, in spectral frames, for a sinusoidal track to be accepted as a partial. It allows to remove space-monkeys, but is more CPU intensive and might reject quick pitch material. + The minimum duration, in spectral frames, for a sinusoidal track to be accepted as a partial. It allows to remove bubbly pitchy artefacts, but is more CPU intensive and might reject quick pitch material. + +ARGUMENT:: trackingMethod + The algorithm used to track the sinusoidal continuity between spectral frames. 0 is the default, "Greedy", and 1 is a more expensive "Hungarian" one. footnote::Neri, J., and Depalle, P., "Fast Partial Tracking of Audio with Real-Time Capability through Linear Programming". Proceedings of DAFx-2018.:: -ARGUMENT:: magWeight - The weight of the magnitude proximity of a peak when trying to associate it to an existing track (relative to freqWeight - suggested between 0 to 1) +ARGUMENT:: trackMagRange + The amplitude difference allowed for a track to diverge between frames, in dB. -ARGUMENT:: freqWeight - The weight of the frequency proximity of a peak when trying to associate it to an existing track (relative to magWeight - suggested between 0 to 1) +ARGUMENT:: trackFreqRange + The frequency difference allowed for a track to diverge between frames, in Hertz. + +ARGUMENT:: trackProb + The propensity of peaks to become enrolled into tracks. 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 @@ -43,7 +55,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 the highest of windowSize and (bandwidth - 1) * 2. + 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 next power of 2 equal or above the highest of the windowSize and (bandwidth - 1) * 2. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. @@ -59,11 +71,17 @@ CODE:: b = Buffer.read(s,File.realpath(FluidSines.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav"); // run with large parameters - left is sinusoidal model, right is residual -{FluidSines.ar(PlayBuf.ar(1,b,loop:1),threshold: 0.2, minTrackLen: 2, windowSize: 2048, fftSize: 8192)}.play +{FluidSines.ar(PlayBuf.ar(1,b,loop:1),detectionThreshold: -40, minTrackLen: 2, windowSize: 2048, fftSize: 8192)}.play // interactive parameters with a narrower bandwidth -{FluidSines.ar(PlayBuf.ar(1,b,loop:1),30,MouseX.kr(), 5, windowSize: 1000, hopSize: 200, fftSize: 4096)}.play +{FluidSines.ar(PlayBuf.ar(1,b,loop:1), 30, MouseX.kr(-140,-10),MouseY.kr(-110,-10),MouseY.kr(-140,-40), 10 , windowSize: 1000, hopSize: 200, fftSize: 4096)}.play // null test (the process add a latency of (( hopSize * minTrackLen) + windowSize) samples {var sig = PlayBuf.ar(1,b,loop:1); [FluidSines.ar(sig).sum - DelayN.ar(sig, 1, ((( 512 * 15) + 1024)/ s.sampleRate))]}.play + +// as the algorithm resynthesize the sinusoidal peaks, we would expect to get it to work almost perfectly on a sine wave, with these settings that tell the process to tolerate everything as a sinusoid, even short and quiet peaks +{FluidSines.ar(SinOsc.ar(mul: 0.1),detectionThreshold: -144,birthLowThreshold: -144,birthHighThreshold: -144,minTrackLen: 1,trackMagRange: 200,trackFreqRange: 1000,trackProb: 0)}.play; + +// as this is a windowed process, the frequency of the peak is good for that full window, and therefore interesting artefacts appear when the pitch is changing. +{FluidSines.ar(SinOsc.ar(LFTri.kr(0.1).exprange(220,880),mul: 0.1),detectionThreshold: -144,birthLowThreshold: -144,birthHighThreshold: -144,minTrackLen: 1,trackMagRange: 300,trackFreqRange: 1000,trackProb: 0)}.play; :: diff --git a/release-packaging/HelpSource/Classes/FluidSpectralShape.schelp b/release-packaging/HelpSource/Classes/FluidSpectralShape.schelp index 6376579..8a918f7 100644 --- a/release-packaging/HelpSource/Classes/FluidSpectralShape.schelp +++ b/release-packaging/HelpSource/Classes/FluidSpectralShape.schelp @@ -4,7 +4,7 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Classes/SpecCentroid, Classes/SpecFlatness, Classes/SpecCentroid, Classes/SpecPcile DESCRIPTION:: -This class implements seven of the most popular spectral shape descriptors, computed on a linear scale for both amplitude and frequency. 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 seven of the most popular spectral shape descriptors, computed on a linear scale for both amplitude and frequency. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The descriptors are: LIST:: @@ -39,7 +39,7 @@ ARGUMENT:: hopSize The window hop size. As spectral shape 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 use the next power of 2 equal or above the windowSize. ARGUMENT:: maxFFTSize How large can the FFT be, by allocating memory at instantiation time. This cannot be modulated. diff --git a/release-packaging/HelpSource/Classes/FluidTransientSlice.schelp b/release-packaging/HelpSource/Classes/FluidTransientSlice.schelp index 1df863d..55dc5dd 100644 --- a/release-packaging/HelpSource/Classes/FluidTransientSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidTransientSlice.schelp @@ -4,9 +4,9 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition DESCRIPTION:: -This class implements a real-time transient-based slice extractor relying on the same algorithm than Classes/FluidBufTransients using clicks/transients/derivation/anomaly in the signal to estimate the slicing points. 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 transient-based slice extractor relying on the same algorithm than Classes/FluidBufTransients using clicks/transients/derivation/anomaly in the signal to estimate the slicing points. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ - The process will return an audio steam with sample-long impulses at estimated starting points of the different slices. +The process will return an audio steam with sample-long impulses at estimated starting points of the different slices. CLASSMETHODS:: @@ -59,7 +59,7 @@ b = Buffer.read(s,File.realpath(FluidTransientSlice.class.filenameSymbol).dirnam // other parameters {var sig = PlayBuf.ar(1,b,loop:1); [FluidTransientSlice.ar(sig,order:80,minSliceLength:2205) * 0.5, DelayN.ar(sig, 1, ((256 + 128 - 80)/ s.sampleRate))]}.play -// more musical trans-trigged autopan +// More musical, transient-trigged autopan ( { var sig, trig, syncd, pan; diff --git a/release-packaging/HelpSource/Classes/FluidTransients.schelp b/release-packaging/HelpSource/Classes/FluidTransients.schelp index 8724858..475f080 100644 --- a/release-packaging/HelpSource/Classes/FluidTransients.schelp +++ b/release-packaging/HelpSource/Classes/FluidTransients.schelp @@ -4,14 +4,13 @@ CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition DESCRIPTION:: -This class applies a real-time transient extractor on its input. It implements declicking algorithm from chapter 5 of the classic Digital Audio Restoration by Godsill, Simon J., Rayner, Peter J.W. with some bespoke improvements on the detection function tracking. 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 applies a real-time transient extractor on its input. It implements declicking algorithm from chapter 5 of the classic Digital Audio Restoration by Godsill, Simon J., Rayner, Peter J.W. with some bespoke improvements on the detection function tracking. It is part of the LINK:: Guides/FluidDecomposition:: of LINK:: Guides/FluCoMa::. For more explanations, learning material, and discussions on its musicianly uses, visit http://www.flucoma.org/ The algorithm will take an audio in, and will divide it in two outputs: LIST:: ## the transients, estimated from the signal and extracted from it; ## the remainder of the material, as estimated by the algorithm. :: - The whole process is based on the assumption that a transient is an element that is deviating from the surrounding material, as sort of click or anomaly. The algorithm then estimates what should have happened if the signal had followed its normal path, and resynthesises this estimate, removing the anomaly which is considered as the transient. More information on signal estimation, and on its musicianly usage, are availabe in LINK::Guides/FluCoMa:: overview file. + The whole process is based on the assumption that a transient is an element that is deviating from the surrounding material, as sort of click or anomaly. The algorithm then estimates what should have happened if the signal had followed its normal path, and resynthesises this estimate, removing the anomaly which is considered as the transient. CLASSMETHODS:: diff --git a/release-packaging/HelpSource/Guides/FluCoMa.schelp b/release-packaging/HelpSource/Guides/FluCoMa.schelp index fe14906..0f16dc3 100644 --- a/release-packaging/HelpSource/Guides/FluCoMa.schelp +++ b/release-packaging/HelpSource/Guides/FluCoMa.schelp @@ -4,8 +4,8 @@ categories:: Libraries>FluidDecomposition related:: Classes/FluidBufNMF description:: -This is my description 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 Fluid Corpus Manipulation project (FluCoMA) instigates new musical ways of exploiting ever-growing banks of sound and gestures within the digital composition process, by bringing breakthroughs of signal decomposition DSP and machine learning to the toolset of techno-fluent computer composers, creative coders and digital artists. The first set of tools released is the LINK:: Guides/FluidDecomposition:: -subsection:: stuff -This is my subsection +This was made possible thanks to a grant by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899). + +For more information, including a forum and learning material, please visit the FluCoMa project website at http://www.flucoma.org/ \ No newline at end of file diff --git a/release-packaging/HelpSource/Guides/FluidBufMultiThreading.schelp b/release-packaging/HelpSource/Guides/FluidBufMultiThreading.schelp index 43c0c73..f1f1e49 100644 --- a/release-packaging/HelpSource/Guides/FluidBufMultiThreading.schelp +++ b/release-packaging/HelpSource/Guides/FluidBufMultiThreading.schelp @@ -81,7 +81,7 @@ d = Bus.control(s,1); ) // start a very long job -e = {Out.kr(d,FluidBufNMF.kr(b, destination:c, components:50, iterations:1000, windowSize:8192, hopSize:256))}.play +e = {Out.kr(d,FluidBufNMF.kr(b, resynth:c, components:50, iterations:1000, windowSize:8192, hopSize:256))}.play // make a dummy synth to look at the progress f = {In.kr(d).poll}.play @@ -160,5 +160,3 @@ Routine{ }.play; ) :: - - diff --git a/release-packaging/HelpSource/Guides/FluidDecomposition.schelp b/release-packaging/HelpSource/Guides/FluidDecomposition.schelp index fa4d288..bfe55a0 100644 --- a/release-packaging/HelpSource/Guides/FluidDecomposition.schelp +++ b/release-packaging/HelpSource/Guides/FluidDecomposition.schelp @@ -10,6 +10,9 @@ subsection:: Slices LINK:: Classes/FluidAmpSlice:: & LINK:: Classes/FluidBufAmpSlice:: +LINK:: Classes/FluidAmpGate:: & +LINK:: Classes/FluidBufAmpGate:: + Slice by amplitude envelope LINK:: Classes/FluidOnsetSlice:: & diff --git a/scripts/target_post.cmake b/scripts/target_post.cmake index a211e05..0a6a727 100644 --- a/scripts/target_post.cmake +++ b/scripts/target_post.cmake @@ -1,10 +1,28 @@ +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). -target_compile_features(${PLUGIN} PUBLIC cxx_std_14) +target_compile_features(${PLUGIN} PRIVATE cxx_std_14) if(MSVC) - target_compile_options(${PLUGIN} PRIVATE /W4) + foreach(flag_var + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${flag_var} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endif() + endforeach() +endif() + +if(MSVC) + target_compile_options(${PLUGIN} PRIVATE /W3) else() - target_compile_options(${PLUGIN} PRIVATE -Wall -Wextra -Wpedantic -Wreturn-type -Wconversion) + target_compile_options(${PLUGIN} PRIVATE + -Wall -Wextra -Wpedantic -Wreturn-type -Wconversion -Wno-c++11-narrowing + ) endif() set_target_properties(${PLUGIN} PROPERTIES @@ -13,16 +31,23 @@ set_target_properties(${PLUGIN} PROPERTIES CXX_EXTENSIONS NO ) +if(APPLE) + set_target_properties(${PLUGIN} PROPERTIES + XCODE_GENERATE_SCHEME ON + ) + #If we target 10.7 (actually < 10.9), we have to manually include this: + target_compile_options(${PLUGIN} PRIVATE -stdlib=libc++) +endif() + target_link_libraries( ${PLUGIN} - PUBLIC - FLUID_DECOMPOSITION - FLUID_SC_WRAPPER PRIVATE - FFTLIB + FLUID_DECOMPOSITION + # FLUID_MANIP + FLUID_SC_WRAPPER + HISSTools_FFT ) - target_include_directories( ${PLUGIN} PRIVATE @@ -47,56 +72,32 @@ target_include_directories( ) get_property(HEADERS TARGET FLUID_DECOMPOSITION PROPERTY INTERFACE_SOURCES) -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" - ) -endif() - -if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - target_compile_options(${PLUGIN} PRIVATE -fvisibility=hidden) - - include (CheckCXXCompilerFlag) - - # CHECK_CXX_COMPILER_FLAG(-msse HAS_CXX_SSE) - # CHECK_CXX_COMPILER_FLAG(-msse2 HAS_CXX_SSE2) - # CHECK_CXX_COMPILER_FLAG(-mfpmath=sse HAS_CXX_FPMATH_SSE) - # CHECK_CXX_COMPILER_FLAG(-mavx HAS_AVX) - # CHECK_CXX_COMPILER_FLAG(-mavx2 HAS_AVX2) - - target_compile_options( - ${PLUGIN} - PRIVATE - $<$>: -mavx -msse -msse2 -msse3 -msse4> - ) -endif() - - +source_group(TREE "${fluid_decomposition_SOURCE_DIR}/include" FILES ${HEADERS}) + +# get_property(HEADERS TARGET FLUID_MANIP PROPERTY INTERFACE_SOURCES) +# source_group(TREE "${fluid_manipulation_SOURCE_DIR}/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" +# ) +# endif() if(MINGW) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mstackrealign") 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(DEFINED FLUID_ARCH) + target_compile_options(${PLUGIN} PRIVATE ${FLUID_ARCH}) +endif() -if(SUPERNOVA) - add_library(${PLUGIN}_supernova MODULE ${FILENAME}) - set_property(TARGET ${PROJECT}_supernova - PROPERTY COMPILE_DEFINITIONS SUPERNOVA) +if(MSVC) + target_compile_options(${PLUGIN} PRIVATE -D_USE_MATH_DEFINES) +else() + target_compile_options(${PLUGIN} PRIVATE -fvisibility=hidden) endif() diff --git a/src/FluidAmpGate/CMakeLists.txt b/src/FluidAmpGate/CMakeLists.txt new file mode 100644 index 0000000..9646a4e --- /dev/null +++ b/src/FluidAmpGate/CMakeLists.txt @@ -0,0 +1,21 @@ +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + +get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) +message("Configuring ${PLUGIN}") +set(FILENAME ${PLUGIN}.cpp) + +add_library( + ${PLUGIN} + MODULE + ${FILENAME} +) + +include(${CMAKE_CURRENT_LIST_DIR}/../../scripts/target_post.cmake) diff --git a/src/FluidAmpGate/FluidAmpGate.cpp b/src/FluidAmpGate/FluidAmpGate.cpp new file mode 100644 index 0000000..3b696e2 --- /dev/null +++ b/src/FluidAmpGate/FluidAmpGate.cpp @@ -0,0 +1,22 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ + +#include + +#include + +static InterfaceTable *ft; + +PluginLoad(FluidSTFTUGen) +{ + ft = inTable; + using namespace fluid::client; + makeSCWrapper("FluidAmpGate", ft); +} diff --git a/src/FluidAmpSlice/CMakeLists.txt b/src/FluidAmpSlice/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidAmpSlice/CMakeLists.txt +++ b/src/FluidAmpSlice/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidAmpSlice/FluidAmpSlice.cpp b/src/FluidAmpSlice/FluidAmpSlice.cpp index 64738d2..3ac71fd 100644 --- a/src/FluidAmpSlice/FluidAmpSlice.cpp +++ b/src/FluidAmpSlice/FluidAmpSlice.cpp @@ -1,7 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; diff --git a/src/FluidBufAmpGate/CMakeLists.txt b/src/FluidBufAmpGate/CMakeLists.txt new file mode 100644 index 0000000..9646a4e --- /dev/null +++ b/src/FluidBufAmpGate/CMakeLists.txt @@ -0,0 +1,21 @@ +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + +get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) +message("Configuring ${PLUGIN}") +set(FILENAME ${PLUGIN}.cpp) + +add_library( + ${PLUGIN} + MODULE + ${FILENAME} +) + +include(${CMAKE_CURRENT_LIST_DIR}/../../scripts/target_post.cmake) diff --git a/src/FluidBufAmpGate/FluidBufAmpGate.cpp b/src/FluidBufAmpGate/FluidBufAmpGate.cpp new file mode 100644 index 0000000..9e25548 --- /dev/null +++ b/src/FluidBufAmpGate/FluidBufAmpGate.cpp @@ -0,0 +1,22 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ + +#include + +#include + +static InterfaceTable *ft; + +PluginLoad(OfflineFluidDecompositionUGens) +{ + ft = inTable; + using namespace fluid::client; + makeSCWrapper("FluidBufAmpGate", ft); +} diff --git a/src/FluidBufAmpSlice/CMakeLists.txt b/src/FluidBufAmpSlice/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidBufAmpSlice/CMakeLists.txt +++ b/src/FluidBufAmpSlice/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufAmpSlice/FluidBufAmpSlice.cpp b/src/FluidBufAmpSlice/FluidBufAmpSlice.cpp index ce9116d..78a5100 100644 --- a/src/FluidBufAmpSlice/FluidBufAmpSlice.cpp +++ b/src/FluidBufAmpSlice/FluidBufAmpSlice.cpp @@ -1,8 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ -// FD_BufHPSS, an NRT buffer HPSS 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) +#include -#include #include static InterfaceTable *ft; @@ -11,5 +18,5 @@ PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufAmpSlice", ft); + makeSCWrapper("FluidBufAmpSlice", ft); } diff --git a/src/FluidBufCompose/CMakeLists.txt b/src/FluidBufCompose/CMakeLists.txt index 3693881..9646a4e 100755 --- a/src/FluidBufCompose/CMakeLists.txt +++ b/src/FluidBufCompose/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufCompose/FluidBufCompose.cpp b/src/FluidBufCompose/FluidBufCompose.cpp index ea5f763..8ba836d 100644 --- a/src/FluidBufCompose/FluidBufCompose.cpp +++ b/src/FluidBufCompose/FluidBufCompose.cpp @@ -1,7 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; @@ -10,5 +18,5 @@ PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufCompose", ft); + makeSCWrapper("FluidBufCompose", ft); } diff --git a/src/FluidBufHPSS/CMakeLists.txt b/src/FluidBufHPSS/CMakeLists.txt index 3693881..9646a4e 100755 --- a/src/FluidBufHPSS/CMakeLists.txt +++ b/src/FluidBufHPSS/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufHPSS/FluidBufHPSS.cpp b/src/FluidBufHPSS/FluidBufHPSS.cpp index e87633e..36e609a 100644 --- a/src/FluidBufHPSS/FluidBufHPSS.cpp +++ b/src/FluidBufHPSS/FluidBufHPSS.cpp @@ -1,8 +1,16 @@ -// FD_BufHPSS, an NRT buffer HPSS 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; @@ -11,5 +19,5 @@ PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufHPSS", ft); + makeSCWrapper("FluidBufHPSS", ft); } diff --git a/src/FluidBufLoudness/CMakeLists.txt b/src/FluidBufLoudness/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidBufLoudness/CMakeLists.txt +++ b/src/FluidBufLoudness/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufLoudness/FluidBufLoudness.cpp b/src/FluidBufLoudness/FluidBufLoudness.cpp index 3a47459..44abbd4 100644 --- a/src/FluidBufLoudness/FluidBufLoudness.cpp +++ b/src/FluidBufLoudness/FluidBufLoudness.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidBufMFCC/CMakeLists.txt b/src/FluidBufMFCC/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidBufMFCC/CMakeLists.txt +++ b/src/FluidBufMFCC/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufMFCC/FluidBufMFCC.cpp b/src/FluidBufMFCC/FluidBufMFCC.cpp index 64a78c3..f985016 100644 --- a/src/FluidBufMFCC/FluidBufMFCC.cpp +++ b/src/FluidBufMFCC/FluidBufMFCC.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidBufMelBands/CMakeLists.txt b/src/FluidBufMelBands/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidBufMelBands/CMakeLists.txt +++ b/src/FluidBufMelBands/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufMelBands/FluidBufMelBands.cpp b/src/FluidBufMelBands/FluidBufMelBands.cpp index e91ead2..dcb39fc 100644 --- a/src/FluidBufMelBands/FluidBufMelBands.cpp +++ b/src/FluidBufMelBands/FluidBufMelBands.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidBufNMF/CMakeLists.txt b/src/FluidBufNMF/CMakeLists.txt index 3693881..9646a4e 100755 --- a/src/FluidBufNMF/CMakeLists.txt +++ b/src/FluidBufNMF/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufNMF/FluidBufNMF.cpp b/src/FluidBufNMF/FluidBufNMF.cpp index 854370e..e74cd2a 100644 --- a/src/FluidBufNMF/FluidBufNMF.cpp +++ b/src/FluidBufNMF/FluidBufNMF.cpp @@ -1,5 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; @@ -8,5 +18,5 @@ PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufNMF", ft); + makeSCWrapper("FluidBufNMF", ft); } diff --git a/src/FluidBufNoveltySlice/CMakeLists.txt b/src/FluidBufNoveltySlice/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidBufNoveltySlice/CMakeLists.txt +++ b/src/FluidBufNoveltySlice/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp b/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp index 8880e1c..039db41 100644 --- a/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp +++ b/src/FluidBufNoveltySlice/FluidBufNoveltySlice.cpp @@ -1,8 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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; @@ -10,5 +17,5 @@ static InterfaceTable *ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufNoveltySlice", ft); + makeSCWrapper("FluidBufNoveltySlice", ft); } diff --git a/src/FluidBufOnsetSlice/CMakeLists.txt b/src/FluidBufOnsetSlice/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidBufOnsetSlice/CMakeLists.txt +++ b/src/FluidBufOnsetSlice/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufOnsetSlice/FluidBufOnsetSlice.cpp b/src/FluidBufOnsetSlice/FluidBufOnsetSlice.cpp index bbcb4fb..7ff5eef 100644 --- a/src/FluidBufOnsetSlice/FluidBufOnsetSlice.cpp +++ b/src/FluidBufOnsetSlice/FluidBufOnsetSlice.cpp @@ -1,8 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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; @@ -10,5 +17,5 @@ static InterfaceTable *ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufOnsetSlice", ft); + makeSCWrapper("FluidBufOnsetSlice", ft); } diff --git a/src/FluidBufPitch/CMakeLists.txt b/src/FluidBufPitch/CMakeLists.txt index 3693881..711f3d3 100644 --- a/src/FluidBufPitch/CMakeLists.txt +++ b/src/FluidBufPitch/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,5 @@ add_library( ${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) diff --git a/src/FluidBufPitch/FluidBufPitch.cpp b/src/FluidBufPitch/FluidBufPitch.cpp index c988b8c..41bd762 100644 --- a/src/FluidBufPitch/FluidBufPitch.cpp +++ b/src/FluidBufPitch/FluidBufPitch.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidBufSines/CMakeLists.txt b/src/FluidBufSines/CMakeLists.txt index 3693881..9646a4e 100755 --- a/src/FluidBufSines/CMakeLists.txt +++ b/src/FluidBufSines/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufSines/FluidBufSines.cpp b/src/FluidBufSines/FluidBufSines.cpp index 2fbf8e9..f230694 100644 --- a/src/FluidBufSines/FluidBufSines.cpp +++ b/src/FluidBufSines/FluidBufSines.cpp @@ -1,8 +1,15 @@ - // FD_BufSines, an NRT buffer Sinusoidal Modelling 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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; @@ -11,5 +18,5 @@ PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufSines", ft); + makeSCWrapper("FluidBufSines", ft); } diff --git a/src/FluidBufSpectralShape/CMakeLists.txt b/src/FluidBufSpectralShape/CMakeLists.txt index 3693881..9646a4e 100755 --- a/src/FluidBufSpectralShape/CMakeLists.txt +++ b/src/FluidBufSpectralShape/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufSpectralShape/FluidBufSpectralShape.cpp b/src/FluidBufSpectralShape/FluidBufSpectralShape.cpp index fba5c3e..adda5b1 100644 --- a/src/FluidBufSpectralShape/FluidBufSpectralShape.cpp +++ b/src/FluidBufSpectralShape/FluidBufSpectralShape.cpp @@ -1,8 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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; diff --git a/src/FluidBufStats/CMakeLists.txt b/src/FluidBufStats/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidBufStats/CMakeLists.txt +++ b/src/FluidBufStats/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufStats/FluidBufStats.cpp b/src/FluidBufStats/FluidBufStats.cpp index 8d33ad2..c81c117 100644 --- a/src/FluidBufStats/FluidBufStats.cpp +++ b/src/FluidBufStats/FluidBufStats.cpp @@ -1,7 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; @@ -10,5 +18,5 @@ PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufStats", ft); + makeSCWrapper("FluidBufStats", ft); } diff --git a/src/FluidBufThreadDemo/CMakeLists.txt b/src/FluidBufThreadDemo/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidBufThreadDemo/CMakeLists.txt +++ b/src/FluidBufThreadDemo/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufThreadDemo/FluidBufThreadDemo.cpp b/src/FluidBufThreadDemo/FluidBufThreadDemo.cpp index ae810f3..a702bc5 100644 --- a/src/FluidBufThreadDemo/FluidBufThreadDemo.cpp +++ b/src/FluidBufThreadDemo/FluidBufThreadDemo.cpp @@ -1,7 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; @@ -9,5 +17,5 @@ static InterfaceTable *ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufThreadDemo", ft); + makeSCWrapper("FluidBufThreadDemo", ft); } diff --git a/src/FluidBufTransientSlice/CMakeLists.txt b/src/FluidBufTransientSlice/CMakeLists.txt index 3693881..9646a4e 100755 --- a/src/FluidBufTransientSlice/CMakeLists.txt +++ b/src/FluidBufTransientSlice/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp b/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp index ec539dd..520b066 100644 --- a/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp +++ b/src/FluidBufTransientSlice/FluidBufTransientSlice.cpp @@ -1,8 +1,15 @@ - // 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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; @@ -10,5 +17,5 @@ static InterfaceTable* ft; PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufTransientSlice", ft); + makeSCWrapper("FluidBufTransientSlice", ft); } diff --git a/src/FluidBufTransients/CMakeLists.txt b/src/FluidBufTransients/CMakeLists.txt index 3693881..711f3d3 100755 --- a/src/FluidBufTransients/CMakeLists.txt +++ b/src/FluidBufTransients/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,5 @@ add_library( ${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) diff --git a/src/FluidBufTransients/FluidBufTransients.cpp b/src/FluidBufTransients/FluidBufTransients.cpp index 55c2da9..6cd9f6d 100644 --- a/src/FluidBufTransients/FluidBufTransients.cpp +++ b/src/FluidBufTransients/FluidBufTransients.cpp @@ -1,6 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 +18,5 @@ PluginLoad(OfflineFluidDecompositionUGens) { ft = inTable; using namespace fluid::client; - makeSCWrapper("FluidBufTransients", ft); + makeSCWrapper("FluidBufTransients", ft); } diff --git a/src/FluidGain/CMakeLists.txt b/src/FluidGain/CMakeLists.txt index 4f27137..9646a4e 100755 --- a/src/FluidGain/CMakeLists.txt +++ b/src/FluidGain/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${FILENAME} ) -target_include_directories( - ${PLUGIN} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../../include -) - -target_link_libraries( - ${PLUGIN} PRIVATE FLUID_DECOMPOSITION FLUID_SC_WRAPPER -) - include(${CMAKE_CURRENT_LIST_DIR}/../../scripts/target_post.cmake) diff --git a/src/FluidGain/FluidGain.cpp b/src/FluidGain/FluidGain.cpp index 54e192f..0dcb164 100644 --- a/src/FluidGain/FluidGain.cpp +++ b/src/FluidGain/FluidGain.cpp @@ -1,8 +1,16 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; diff --git a/src/FluidHPSS/CMakeLists.txt b/src/FluidHPSS/CMakeLists.txt index 3693881..9646a4e 100755 --- a/src/FluidHPSS/CMakeLists.txt +++ b/src/FluidHPSS/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidHPSS/FluidHPSS.cpp b/src/FluidHPSS/FluidHPSS.cpp index 387e9a3..d8db092 100644 --- a/src/FluidHPSS/FluidHPSS.cpp +++ b/src/FluidHPSS/FluidHPSS.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidLoudness/CMakeLists.txt b/src/FluidLoudness/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidLoudness/CMakeLists.txt +++ b/src/FluidLoudness/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidLoudness/FluidLoudness.cpp b/src/FluidLoudness/FluidLoudness.cpp index 690be0c..ccf0300 100644 --- a/src/FluidLoudness/FluidLoudness.cpp +++ b/src/FluidLoudness/FluidLoudness.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidMFCC/CMakeLists.txt b/src/FluidMFCC/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidMFCC/CMakeLists.txt +++ b/src/FluidMFCC/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidMFCC/FluidMFCC.cpp b/src/FluidMFCC/FluidMFCC.cpp index 2ce26a5..79cc90f 100644 --- a/src/FluidMFCC/FluidMFCC.cpp +++ b/src/FluidMFCC/FluidMFCC.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidMelBands/CMakeLists.txt b/src/FluidMelBands/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidMelBands/CMakeLists.txt +++ b/src/FluidMelBands/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidMelBands/FluidMelBands.cpp b/src/FluidMelBands/FluidMelBands.cpp index 228c820..01aeff1 100644 --- a/src/FluidMelBands/FluidMelBands.cpp +++ b/src/FluidMelBands/FluidMelBands.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidNMFFilter/CMakeLists.txt b/src/FluidNMFFilter/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidNMFFilter/CMakeLists.txt +++ b/src/FluidNMFFilter/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidNMFFilter/FluidNMFFilter.cpp b/src/FluidNMFFilter/FluidNMFFilter.cpp index 90e40f0..9324f20 100644 --- a/src/FluidNMFFilter/FluidNMFFilter.cpp +++ b/src/FluidNMFFilter/FluidNMFFilter.cpp @@ -1,7 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; diff --git a/src/FluidNMFMatch/CMakeLists.txt b/src/FluidNMFMatch/CMakeLists.txt index 3693881..9646a4e 100755 --- a/src/FluidNMFMatch/CMakeLists.txt +++ b/src/FluidNMFMatch/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidNMFMatch/FluidNMFMatch.cpp b/src/FluidNMFMatch/FluidNMFMatch.cpp index 1b93838..e84b0e8 100644 --- a/src/FluidNMFMatch/FluidNMFMatch.cpp +++ b/src/FluidNMFMatch/FluidNMFMatch.cpp @@ -1,7 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; diff --git a/src/FluidNoveltySlice/CMakeLists.txt b/src/FluidNoveltySlice/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidNoveltySlice/CMakeLists.txt +++ b/src/FluidNoveltySlice/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidNoveltySlice/FluidNoveltySlice.cpp b/src/FluidNoveltySlice/FluidNoveltySlice.cpp index 22c78cf..4044310 100644 --- a/src/FluidNoveltySlice/FluidNoveltySlice.cpp +++ b/src/FluidNoveltySlice/FluidNoveltySlice.cpp @@ -1,7 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; diff --git a/src/FluidOnsetSlice/CMakeLists.txt b/src/FluidOnsetSlice/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidOnsetSlice/CMakeLists.txt +++ b/src/FluidOnsetSlice/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidOnsetSlice/FluidOnsetSlice.cpp b/src/FluidOnsetSlice/FluidOnsetSlice.cpp index dd47e9f..aec600f 100644 --- a/src/FluidOnsetSlice/FluidOnsetSlice.cpp +++ b/src/FluidOnsetSlice/FluidOnsetSlice.cpp @@ -1,7 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; diff --git a/src/FluidPitch/CMakeLists.txt b/src/FluidPitch/CMakeLists.txt index 3693881..711f3d3 100644 --- a/src/FluidPitch/CMakeLists.txt +++ b/src/FluidPitch/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,5 @@ add_library( ${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) diff --git a/src/FluidPitch/FluidPitch.cpp b/src/FluidPitch/FluidPitch.cpp index 81e74c4..b1d8a87 100644 --- a/src/FluidPitch/FluidPitch.cpp +++ b/src/FluidPitch/FluidPitch.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidSTFTPass/CMakeLists.txt b/src/FluidSTFTPass/CMakeLists.txt index 3693881..711f3d3 100755 --- a/src/FluidSTFTPass/CMakeLists.txt +++ b/src/FluidSTFTPass/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,5 @@ add_library( ${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) diff --git a/src/FluidSTFTPass/FluidSTFTPass.cpp b/src/FluidSTFTPass/FluidSTFTPass.cpp index f2188aa..9fff5e4 100644 --- a/src/FluidSTFTPass/FluidSTFTPass.cpp +++ b/src/FluidSTFTPass/FluidSTFTPass.cpp @@ -1,8 +1,16 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; diff --git a/src/FluidSines/CMakeLists.txt b/src/FluidSines/CMakeLists.txt index 3693881..711f3d3 100755 --- a/src/FluidSines/CMakeLists.txt +++ b/src/FluidSines/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,5 @@ add_library( ${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) diff --git a/src/FluidSines/FluidSines.cpp b/src/FluidSines/FluidSines.cpp index bb4c7fb..93ac2a7 100644 --- a/src/FluidSines/FluidSines.cpp +++ b/src/FluidSines/FluidSines.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidSpectralShape/CMakeLists.txt b/src/FluidSpectralShape/CMakeLists.txt index 3693881..9646a4e 100644 --- a/src/FluidSpectralShape/CMakeLists.txt +++ b/src/FluidSpectralShape/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidSpectralShape/FluidSpectralShape.cpp b/src/FluidSpectralShape/FluidSpectralShape.cpp index fa6efc7..7c6b19b 100644 --- a/src/FluidSpectralShape/FluidSpectralShape.cpp +++ b/src/FluidSpectralShape/FluidSpectralShape.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft; diff --git a/src/FluidTransientSlice/CMakeLists.txt b/src/FluidTransientSlice/CMakeLists.txt index 3693881..9646a4e 100755 --- a/src/FluidTransientSlice/CMakeLists.txt +++ b/src/FluidTransientSlice/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) @@ -9,12 +18,4 @@ add_library( ${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) diff --git a/src/FluidTransientSlice/FluidTransientSlice.cpp b/src/FluidTransientSlice/FluidTransientSlice.cpp index 1a60332..987097d 100644 --- a/src/FluidTransientSlice/FluidTransientSlice.cpp +++ b/src/FluidTransientSlice/FluidTransientSlice.cpp @@ -1,7 +1,15 @@ +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from 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 static InterfaceTable *ft; diff --git a/src/FluidTransients/CMakeLists.txt b/src/FluidTransients/CMakeLists.txt index d1e5005..9646a4e 100755 --- a/src/FluidTransients/CMakeLists.txt +++ b/src/FluidTransients/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.3) +# Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +# Copyright 2017-2019 University of Huddersfield. +# Licensed under the BSD-3 License. +# See license.md file in the project root for full license information. +# This project has received funding from the European Research Council (ERC) +# under the European Union’s Horizon 2020 research and innovation programme +# (grant agreement No 725899). + +cmake_minimum_required(VERSION 3.11) + get_filename_component(PLUGIN ${CMAKE_CURRENT_LIST_DIR} NAME_WE) message("Configuring ${PLUGIN}") set(FILENAME ${PLUGIN}.cpp) diff --git a/src/FluidTransients/FluidTransients.cpp b/src/FluidTransients/FluidTransients.cpp index 0b7c22f..be7816f 100644 --- a/src/FluidTransients/FluidTransients.cpp +++ b/src/FluidTransients/FluidTransients.cpp @@ -1,7 +1,15 @@ - -// 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) +/* +Part of the Fluid Corpus Manipulation Project (http://www.flucoma.org/) +Copyright 2017-2019 University of Huddersfield. +Licensed under the BSD-3 License. +See license.md file in the project root for full license information. +This project has received funding from the European Research Council (ERC) +under the European Union’s Horizon 2020 research and innovation programme +(grant agreement No 725899). +*/ #include + #include static InterfaceTable *ft;