[Release] 1.0.0-beta7 (#119)

* ignore more varieties of build folder

* deal with some warnings

* FluidWaveform 'lineWidth' argument now also affects feature lines

* add back the nmf-jit-classifier example

* novelty interface change in example

* resizable and layoutable guis (#83)

* resizable and layoutable guis

* FluidWaveform: rename 'win' to 'parent'

* FluidWaveform/FluidPlotter: update help

* FluidWaveform/Plotter: make views before forking

This way views are immediately available upon creation,
for example to be added to layouts.
Views are still correctly updated with data from within the fork,
whenever they are ready.

* Thanks @elgiano! + a few small edits

Co-authored-by: Ted Moore <ted@tedmooremusic.com>

* slicers: add enums for algorithms (#86)

* typo

* FluidBufNMF class: add resynthMode argument

* add PCA whitening parameter (#65)

* add PCA whitening parameter

* FluidPCA: Ensure whiten parameter is sent to kr query UGen

Co-authored-by: Gerard <gerard@bumblebee.lan>
Co-authored-by: weefuzzy <gungwho@gmail.com>

* Enhance/optional message args (#77)

* optional args: sc wrapper updates

* optional args: KDTree try out

* Enhance/choices param (#78)

* NRTWrapper: Add choices param (long <-> bitset)

* Update `FluidBufStats` with `select` control

* BufStats class: Fix bitfield for `select` and warn on duplicate items

* Update SpectralShape classes for new param

* `PCA.sc`: add batch `inverseTranform` method

* Wrapper: integer sign warnings

* Enhance/max params (#93)

* CMake: Centralise C++ version and set to 17

* Wrapper: handle new LongRuntimeMax param type

* POC for new LongRuntimeMax param with MFCC numCoeffs

* Wrapper: Make MSVC happy about constexpr lambda capture

* All scalers: replace 'invert' parameter with `inverseTransform` messages

* Wrapper: Work around 32 char limit for plugin commands

If too long, remove vowels. 
Sorry. 
Better ideas welcome

* fix #96

* typo

* Update SC classes for new style `max<X>` parameters

* SpectralShape SC class: maxFFT

* RealTime wrapper: play it safer with output channel count

This really relies on the SC class being correct, but then everything 
ultimately does...

* RT FFT Object SC Classes: Provide maxFFTSize default

* BufSTFT SC class: Add maxFFT (now needed due to core type change)

* Add select param to Loudness and Pitch SC clases (#101)

* Wrapper: workaround scsynth 32 char cmd length limit with extra dispatch layer 

also avoids need for formerly truncated plugin names in some cases

* removed invert from scalers class definitions (#102)

* Enhance/generate stubs (#104)

* CMake: generate .cpp stubs

* Remove old cpp stubs

* Ensure correct MSVC runtime by default

* CMake: invoke docs properly

* CMake: Tidy up

* CMake: Tidy up

* CMake: typo

* CI: Update nightly

* CI: remove lingering references to docs job

* CMake: belatedly add branch selection for flucoma deps upon which CI relies

* CMake: Actually commit important code for best collaborative results

* CMake: This file is now redundant, in fact

* cmake: missing slash in install

* bufnmf: added the maxFFTsize parameter in the server call

* FluidStats: Change where output Array reshape happens to keep SynthDescLib happy

* FluidBufNNDSVD: maxfftsize now needed in server call, or booooom

fixes #161

* BufNMFCross: Needs MaxFFTSize

* BufNNDSVD: Ensure activations buffer is queried at finish

* FluidBufToKr ensure that numFrames is an int (not a float)

* Added *(Buf)Feature objects to guide (and deleted old guide)

NNDSVD --> NMFSeed in Guide

fixed bad links in Guide

* change interface and file name (#113)

* hidden --> hiddenLayers in class definition (#114)

* reordered some max<X> arguments

* change interp to interpolation in nmfmorph class (#115)

* Feature/skmeans (#66)

* add PCA whitening parameter

* add FluidSKMeans

* SKMeans correction

* added RT query

* <fit>transform<point> -> <fit>encode<point>

* added to overview

Co-authored-by: Gerard <gerard@bumblebee.lan>
Co-authored-by: tremblap <info@pierrealexandretremblay.com>

* [CI] Update Release Workflow (#118)

* cleanup nightly.yaml

* use new release style

* refactor release

* remove workflow dispatch variables
nix
James Bradbury 4 years ago committed by GitHub
parent 229b46b11d
commit 8119849f91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,111 +7,80 @@ on:
branches: [ dev, ci/** ] branches: [ dev, ci/** ]
jobs: jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: flucoma/actions/env@v4
- uses: flucoma/actions/docs@v4
with:
target: MAKE_SC_REF
- uses: actions/upload-artifact@v2
with:
name: docs
path: build/sc_ref
macbuild: macbuild:
runs-on: macos-11 runs-on: macos-11
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: flucoma/actions/env@v4 - uses: flucoma/actions/env@v5
- uses: flucoma/actions/sc@v4 - uses: flucoma/actions/sc@v5
with:
branch: origin/dev
- name: compress archive
run: zip -r FluCoMa-SC-Mac-nightly.zip FluidCorpusManipulation
working-directory: install
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
with: with:
name: macbuild name: macbuild
path: install path: install/FluCoMa-SC-Mac-nightly.zip
winbuild: winbuild:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: flucoma/actions/env@v4 - uses: flucoma/actions/env@v5
- uses: flucoma/actions/sc@v4 - uses: flucoma/actions/sc@v5
with:
branch: origin/dev
- name: remove pdb files - name: remove pdb files
run: Remove-Item install -Recurse -Include *.pdb run: Remove-Item install -Recurse -Include *.pdb
- uses: actions/upload-artifact@v2 - name: compress archive
run: 7z a FluCoMa-SC-Windows-nightly.zip FluidCorpusManipulation
working-directory: install
- uses: actions/upload-artifact@v2
with: with:
name: winbuild name: winbuild
path: install path: install/FluCoMa-SC-Windows-nightly.zip
linuxbuild: linuxbuild:
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: flucoma/actions/env@v4 - uses: flucoma/actions/env@v5
- uses: flucoma/actions/sc@v4 - uses: flucoma/actions/sc@v5
with:
- uses: actions/upload-artifact@v2 branch: origin/dev
with:
name: linuxbuild - name: compress archive
path: install run: tar -zcvf FluCoMa-SC-Linux-nightly.tar.gz FluidCorpusManipulation
working-directory: install
- uses: actions/upload-artifact@v2
with:
name: linuxbuild
path: install/FluCoMa-SC-Linux-nightly.tar.gz
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [macbuild, winbuild, linuxbuild,docs] needs: [macbuild, winbuild, linuxbuild]
steps: steps:
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v2
with: with:
name: docs name: macbuild
path: docs
- uses: actions/download-artifact@v2
with:
name: macbuild
path: mac
- name: copy docs to mac
run: mkdir -p mac/FluidCorpusManipulation/HelpSource && cp -r docs/* mac/FluidCorpusManipulation/HelpSource
- name: compress win
run: zip -r ../FluCoMa-SC-Mac-nightly.zip .
working-directory: mac
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v2
with: with:
name: winbuild name: winbuild
path: win
- name: copy docs to win
run: mkdir -p win/FluidCorpusManipulation/HelpSource && cp -r docs/* win/FluidCorpusManipulation/HelpSource
- name: compress win
run: zip -r ../FluCoMa-SC-Windows-nightly.zip .
working-directory: win
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v2
with: with:
name: linuxbuild name: linuxbuild
path: linux
- name: copy docs to linux
run: mkdir -p linux/FluidCorpusManipulation/HelpSource && cp -r docs/* linux/FluidCorpusManipulation/HelpSource
- name: compress linux
run: zip -r ../FluCoMa-SC-Linux-nightly.zip .
working-directory: linux
- uses: dev-drprasad/delete-tag-and-release@v0.2.0 - uses: dev-drprasad/delete-tag-and-release@v0.2.0
with: with:
@ -125,7 +94,7 @@ jobs:
with: with:
name: FluCoMa SuperCollider Nightly Release name: FluCoMa SuperCollider Nightly Release
body: "This is a nightly build of the FluCoMa SuperCollider package. As such, be warned there may be bugs or other unexpected behaviour. The build hash is ${{ github.sha }}" body: "This is a nightly build of the FluCoMa SuperCollider package. As such, be warned there may be bugs or other unexpected behaviour. The build hash is ${{ github.sha }}"
files: FluCoMa-SC-*.zip files: FluCoMa-SC-*
prerelease: true prerelease: true
tag_name: nightly tag_name: nightly
draft: false draft: false

@ -2,60 +2,46 @@ name: Release
on: on:
workflow_dispatch: workflow_dispatch:
inputs:
base:
description: 'Base branch to deploy core from'
required: false
default: 'main'
jobs: jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: flucoma/actions/env@v4
with:
branch: ${{ github.event.inputs.base }}
- uses: flucoma/actions/docs@v4
with:
target: MAKE_SC_REF
branch: ${{ github.event.inputs.base }}
- uses: actions/upload-artifact@v2
with:
name: docs
path: build/sc_ref
macbuild: macbuild:
runs-on: macos-11 runs-on: macos-11
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: flucoma/actions/env@v4 - uses: flucoma/actions/env@v5
- uses: flucoma/actions/sc@v5
with: with:
branch: ${{ github.event.inputs.base }} branch: origin/main
- uses: flucoma/actions/sc@v4
- name: compress archive
run: zip -r FluCoMa-SC-Mac-nightly.zip FluidCorpusManipulation
working-directory: install
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
with: with:
name: macbuild name: macbuild
path: install path: install/FluCoMa-SC-Mac-nightly.zip
winbuild: winbuild:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: flucoma/actions/env@v4 - uses: flucoma/actions/env@v5
- uses: flucoma/actions/sc@v5
with: with:
branch: ${{ github.event.inputs.base }} branch: origin/main
- uses: flucoma/actions/sc@v4
- name: remove pdb files - name: remove pdb files
run: Remove-Item install -Recurse -Include *.pdb run: Remove-Item install -Recurse -Include *.pdb
- uses: actions/upload-artifact@v2 - name: compress archive
run: 7z a FluCoMa-SC-Windows-nightly.zip FluidCorpusManipulation
working-directory: install
- uses: actions/upload-artifact@v2
with: with:
name: winbuild name: winbuild
path: install path: install/FluCoMa-SC-Windows-nightly.zip
linuxbuild: linuxbuild:
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04
@ -63,15 +49,19 @@ jobs:
version: ${{ steps.get-version.outputs.version }} version: ${{ steps.get-version.outputs.version }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: flucoma/actions/env@v4 - uses: flucoma/actions/env@v5
- uses: flucoma/actions/sc@v5
with: with:
branch: ${{ github.event.inputs.base }} branch: origin/main
- uses: flucoma/actions/sc@v4
- name: compress archive
run: tar -zcvf FluCoMa-SC-Linux-nightly.tar.gz FluidCorpusManipulation
working-directory: install
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
with: with:
name: linuxbuild name: linuxbuild
path: install path: install/FluCoMa-SC-Linux-nightly.tar.gz
- id: get-version - id: get-version
run: echo "::set-output name=version::$(cat flucoma.version.rc)" run: echo "::set-output name=version::$(cat flucoma.version.rc)"
@ -79,51 +69,21 @@ jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [macbuild, winbuild, linuxbuild, docs] needs: [macbuild, winbuild, linuxbuild]
steps: steps:
- uses: actions/download-artifact@v2
with:
name: docs
path: docs
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v2
with: with:
name: macbuild name: macbuild
path: mac
- name: copy docs to mac
run: mkdir -p mac/FluidCorpusManipulation/HelpSource && cp -r docs/* mac/FluidCorpusManipulation/HelpSource
- name: compress win
run: zip -r ../FluCoMa-SC-Mac.zip .
working-directory: mac
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v2
with: with:
name: winbuild name: winbuild
path: win
- name: copy docs to win
run: mkdir -p win/FluidCorpusManipulation/HelpSource && cp -r docs/* win/FluidCorpusManipulation/HelpSource
- name: compress win
run: zip -r ../FluCoMa-SC-Windows.zip .
working-directory: win
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v2
with: with:
name: linuxbuild name: linuxbuild
path: linux
- name: copy docs to linux
run: mkdir -p linux/FluidCorpusManipulation/HelpSource && cp -r docs/* linux/FluidCorpusManipulation/HelpSource
- name: compress linux
run: zip -r ../FluCoMa-SC-Linux.zip .
working-directory: linux
- name: package and upload - name: package and upload
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:

2
.gitignore vendored

@ -1,4 +1,4 @@
build build*
**/build/* **/build/*
**/.DS_Store **/.DS_Store
release-packaging/Plugins release-packaging/Plugins

@ -7,10 +7,15 @@
cmake_minimum_required(VERSION 3.11) cmake_minimum_required(VERSION 3.11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
################################################################################ ################################################################################
# Paths # Paths
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/install" CACHE PATH "") set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/install" CACHE PATH "")
set(FLUID_BRANCH "origin/main" CACHE STRING "Branch to pull flucoma dependencies from")
set(SC_LIBRARY_OUTPUT_PREFIX "release-packaging" CACHE STRING "Where in the hierarchy to write sc plugins") set(SC_LIBRARY_OUTPUT_PREFIX "release-packaging" CACHE STRING "Where in the hierarchy to write sc plugins")
set(SC_PATH "" CACHE PATH "Path to the top of SuperCollider source tree") set(SC_PATH "" CACHE PATH "Path to the top of SuperCollider source tree")
@ -22,7 +27,6 @@ set(FLUID_PATH "" CACHE PATH "Optional path to the Fluid Decomposition repo")
if (APPLE) if (APPLE)
set(CMAKE_XCODE_GENERATE_SCHEME ON) set(CMAKE_XCODE_GENERATE_SCHEME ON)
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.8" CACHE STRING "") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.8" CACHE STRING "")
#A consequence of targetting 10.8. Needs to be set globally from 10.15 onwards in order for the test program to compile successfully during configure #A consequence of targetting 10.8. Needs to be set globally from 10.15 onwards in order for the test program to compile successfully during configure
string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++") string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++")
@ -30,6 +34,8 @@ endif()
option(SYSTEM_BOOST "Use boost libraries from system. If your SC was built with this enabled, so should FluCoMa-sc" OFF) option(SYSTEM_BOOST "Use boost libraries from system. If your SC was built with this enabled, so should FluCoMa-sc" OFF)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/scripts")
################################################################################ ################################################################################
# Main project # Main project
project (flucoma-sc LANGUAGES CXX) project (flucoma-sc LANGUAGES CXX)
@ -52,33 +58,20 @@ endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY ON) set(CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY ON)
MACRO(SUBDIRLIST result curdir)
FILE(GLOB children RELATIVE ${curdir} ${curdir}/*)
SET(dirlist "")
FOREACH(child ${children})
IF(IS_DIRECTORY ${curdir}/${child})
LIST(APPEND dirlist ${child})
ENDIF()
ENDFOREACH()
SET(${result} ${dirlist})
ENDMACRO()
include(FetchContent) include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
FetchContent_Declare( FetchContent_Declare(
flucoma-core flucoma-core
GIT_REPOSITORY https://github.com/flucoma/flucoma-core.git GIT_REPOSITORY https://github.com/flucoma/flucoma-core.git
GIT_PROGRESS TRUE GIT_PROGRESS TRUE
GIT_TAG origin/main GIT_TAG ${FLUID_BRANCH}
) )
FetchContent_Declare( FetchContent_Declare(
flucoma-docs flucoma-docs
GIT_REPOSITORY https://github.com/flucoma/flucoma-docs.git GIT_REPOSITORY https://github.com/flucoma/flucoma-docs.git
GIT_PROGRESS TRUE GIT_PROGRESS TRUE
GIT_TAG origin/main GIT_TAG ${FLUID_BRANCH}
) )
if(FLUID_PATH) if(FLUID_PATH)
@ -87,14 +80,14 @@ if(FLUID_PATH)
) )
endif() endif()
FetchContent_GetProperties(flucoma-core) FetchContent_MakeAvailable(flucoma-core)
if(NOT flucoma-core_POPULATED) # if(NOT flucoma-core_POPULATED)
FetchContent_Populate(flucoma-core) # FetchContent_Populate(flucoma-core)
add_subdirectory(${flucoma-core_SOURCE_DIR} ${flucoma-core_BINARY_DIR}) # add_subdirectory(${flucoma-core_SOURCE_DIR} ${flucoma-core_BINARY_DIR})
include(flucoma_version) include(flucoma_version)
include(flucoma-buildtools) include(flucoma-buildtools)
include(flucoma-buildtype) include(flucoma-buildtype)
endif() # endif()
option(DOCS "Generate scdocs" OFF) option(DOCS "Generate scdocs" OFF)
set(FLUID_DOCS_PATH "" CACHE PATH "Optional path to flucoma-docs (needed for docs); will download if absent") set(FLUID_DOCS_PATH "" CACHE PATH "Optional path to flucoma-docs (needed for docs); will download if absent")
@ -108,15 +101,17 @@ if(DOCS)
FETCHCONTENT_SOURCE_DIR_FLUCOMA-DOCS ${FLUID_DOCS_PATH} ABSOLUTE FETCHCONTENT_SOURCE_DIR_FLUCOMA-DOCS ${FLUID_DOCS_PATH} ABSOLUTE
) )
endif() endif()
FetchContent_MakeAvailable(flucoma-docs)
FetchContent_GetProperties(flucoma-docs) # FetchContent_GetProperties(flucoma-docs)
if(NOT flucoma-docs_POPULATED) # if(NOT flucoma-docs_POPULATED)
FetchContent_Populate(flucoma-docs) # FetchContent_Populate(flucoma-docs)
file(GLOB_RECURSE DOC_SOURCE RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${flucoma-docs_SOURCE_DIR}/**/*.cpp" ) # file(GLOB_RECURSE DOC_SOURCE RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${flucoma-docs_SOURCE_DIR}/**/*.cpp" )
source_group("\\SC Doc Gen" FILES ${DOC_SOURCE}) # source_group("\\SC Doc Gen" FILES ${DOC_SOURCE})
add_subdirectory(${flucoma-docs_SOURCE_DIR} ${flucoma-docs_BINARY_DIR}) # add_subdirectory(${flucoma-docs_SOURCE_DIR} ${flucoma-docs_BINARY_DIR})
endif() # endif()
include(FlucomaDocs)
set(SC_DOC_OUT "${CMAKE_BINARY_DIR}/sc_ref")
add_ref_target(sc "Making SC docs")
add_custom_target(SC_MAKE_DOCS ALL DEPENDS MAKE_SC_REF) add_custom_target(SC_MAKE_DOCS ALL DEPENDS MAKE_SC_REF)
endif() endif()
@ -130,6 +125,9 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_LIBRARY_OUTPUT_DIRECT
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_TEST "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_TEST "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
set(CMAKE_SHARED_MODULE_PREFIX "") set(CMAKE_SHARED_MODULE_PREFIX "")
set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/pdbtmp")
set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/pdbtmp")
if(APPLE OR WIN32) if(APPLE OR WIN32)
set(CMAKE_SHARED_MODULE_SUFFIX ".scx") set(CMAKE_SHARED_MODULE_SUFFIX ".scx")
endif() endif()
@ -189,8 +187,8 @@ if(APPLE)
target_compile_options(FLUID_SC_COPYREPLYADDR PRIVATE -stdlib=libc++) target_compile_options(FLUID_SC_COPYREPLYADDR PRIVATE -stdlib=libc++)
endif() endif()
target_compile_definitions(FLUID_SC_COPYREPLYADDR PRIVATE BOOST_ALL_NO_LIB BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE) target_compile_definitions(FLUID_SC_COPYREPLYADDR PRIVATE BOOST_ALL_NO_LIB PUBLIC BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE)
add_library(FLUID_SC_WRAPPER INTERFACE) add_library(FLUID_SC_WRAPPER INTERFACE)
target_include_directories(FLUID_SC_WRAPPER target_include_directories(FLUID_SC_WRAPPER
INTERFACE INTERFACE
@ -205,18 +203,39 @@ target_sources(FLUID_SC_WRAPPER
target_link_libraries(FLUID_SC_WRAPPER INTERFACE FLUID_SC_COPYREPLYADDR) target_link_libraries(FLUID_SC_WRAPPER INTERFACE FLUID_SC_COPYREPLYADDR)
SUBDIRLIST(PROJECT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src") include(MakePluginSources)
foreach (project_dir ${PROJECT_DIRS}) # generate targets for standalone clients
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/${project_dir}/CMakeLists.txt") get_client_group(NONE client_list)
message("Generating: ${project_dir}") foreach(client ${client_list})
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/src/${project_dir}") get_core_client_header(${client} header)
endif () get_core_client_class(${client} class)
endforeach () generate_sc_source(
CLIENTS ${client}
HEADERS ${header}
CLASSES ${class}
)
endforeach()
add_client(DataSetWr clients/rt/FluidDataSetWr.hpp CLASS NRTThreadedDataSetWriter GROUP MANIPULATION)
#generate target for MANIPULATION group
get_client_group(MANIPULATION client_list)
foreach(client ${client_list})
get_core_client_header(${client} header)
get_core_client_class(${client} class)
list(APPEND MANIPULATION_CLIENTS ${client})
list(APPEND MANIPULATION_HEADERS ${header})
list(APPEND MANIPULATION_CLASSES ${class})
endforeach()
generate_sc_source(
CLIENTS ${MANIPULATION_CLIENTS}
HEADERS ${MANIPULATION_HEADERS}
CLASSES ${MANIPULATION_CLASSES}
FILENAME FluidManipulation
)
#install bits. #install bits.
set(SC_INSTALL_PREFIX "." CACHE PATH "Prefix for assembling SC packages") set(SC_INSTALL_PREFIX "." CACHE PATH "Prefix for assembling SC packages")
set(FLUID_PACKAGE_NAME FluidCorpusManipulation CACHE STRING "Name for published package") set(FLUID_PACKAGE_NAME FluidCorpusManipulation CACHE STRING "Name for published package")
set(SC_PACKAGE_ROOT ${SC_INSTALL_PREFIX}/${FLUID_PACKAGE_NAME}) set(SC_PACKAGE_ROOT ${SC_INSTALL_PREFIX}/${FLUID_PACKAGE_NAME})
@ -242,6 +261,6 @@ install(FILES ${flucoma-core_SOURCE_DIR}/distribution.lic
RENAME LICENSE.md) RENAME LICENSE.md)
if(DOCS) if(DOCS)
install(DIRECTORY "${SC_DOC_OUT}" install(DIRECTORY "${SC_DOC_OUT}/"
DESTINATION "${SC_PACKAGE_ROOT}/HelpSource") DESTINATION "${SC_PACKAGE_ROOT}/HelpSource")
endif() endif()

@ -77,6 +77,11 @@ struct ParamReader<impl::FloatControlsIter>
return args.next(); return args.next();
} }
static auto fromArgs(Unit*, Controls& args, typename ChoicesT::type, int)
{
return typename ChoicesT::type(std::size_t(static_cast<index>(args.next())));
}
static SCBufferAdaptor* fetchBuffer(Unit* x, index bufnum) static SCBufferAdaptor* fetchBuffer(Unit* x, index bufnum)
{ {
if(bufnum >= x->mWorld->mNumSndBufs) if(bufnum >= x->mWorld->mNumSndBufs)
@ -114,6 +119,12 @@ struct ParamReader<impl::FloatControlsIter>
auto id = fromArgs(x, args, index{}, 0); auto id = fromArgs(x, args, index{}, 0);
return {id >= 0 ? std::to_string(id).c_str() : "" }; return {id >= 0 ? std::to_string(id).c_str() : "" };
} }
static auto fromArgs(Unit*,Controls& args,typename LongRuntimeMaxT::type&, int)
{
return typename LongRuntimeMaxT::type{static_cast<index>(args.next()), static_cast<index>(args.next())};
}
}; };
// NRT case: we're decoding data from sc_msg_iter*, there will be a World*, we can't have LocalBufs // NRT case: we're decoding data from sc_msg_iter*, there will be a World*, we can't have LocalBufs
@ -135,38 +146,45 @@ struct ParamReader<sc_msg_iter>
} }
} }
static const char* argTypeToString(std::string&)
template <typename T>
static const char* argTypeToString(Optional<T>&)
{
return argTypeToString(T{});
}
static const char* argTypeToString(const std::string&)
{ {
return "string"; return "string";
} }
template <typename T> template <typename T>
static std::enable_if_t<std::is_integral<T>::value, const char*> static std::enable_if_t<std::is_integral<T>::value, const char*>
argTypeToString(T&) argTypeToString(T)
{ {
return "integer"; return "integer";
} }
template <typename T> template <typename T>
static std::enable_if_t<std::is_floating_point<T>::value, const char*> static std::enable_if_t<std::is_floating_point<T>::value, const char*>
argTypeToString(T&) argTypeToString(T)
{ {
return "float"; return "float";
} }
static const char* argTypeToString(BufferT::type&) static const char* argTypeToString(const BufferT::type&)
{ {
return "buffer"; return "buffer";
} }
static const char* argTypeToString(InputBufferT::type&) static const char* argTypeToString(const InputBufferT::type&)
{ {
return "buffer"; return "buffer";
} }
template <typename P> template <typename P>
static std::enable_if_t<IsSharedClient<P>::value,const char*> static std::enable_if_t<IsSharedClient<P>::value,const char*>
argTypeToString(P&) argTypeToString(const P&)
{ {
return "shared_object"; //not ideal return "shared_object"; //not ideal
} }
@ -179,28 +197,34 @@ struct ParamReader<sc_msg_iter>
template <typename T> template <typename T>
static std::enable_if_t<std::is_integral<T>::value static std::enable_if_t<std::is_integral<T>::value
|| std::is_floating_point<T>::value, bool> || std::is_floating_point<T>::value, bool>
argTypeOK(T&, char tag) argTypeOK(T, char tag)
{ {
return tag == 'i' || tag == 'f' || tag == 'd'; return tag == 'i' || tag == 'f' || tag == 'd';
} }
static bool argTypeOK(BufferT::type&, char tag) static bool argTypeOK(const BufferT::type&, char tag)
{ {
return tag == 'i'; return tag == 'i';
} }
static bool argTypeOK(InputBufferT::type&, char tag) static bool argTypeOK(const InputBufferT::type&, char tag)
{ {
return tag == 'i'; return tag == 'i';
} }
template <typename P> template <typename P>
static std::enable_if_t<IsSharedClient<P>::value,bool> static std::enable_if_t<IsSharedClient<P>::value,bool>
argTypeOK(P&, char tag) argTypeOK(const P&, char tag)
{ {
return tag == 'i'; return tag == 'i';
} }
template<typename T>
static bool argTypeOK(const Optional<T>&, char tag)
{
return argTypeOK(T{},tag);
}
static auto fromArgs(World*, sc_msg_iter& args, std::string, int) static auto fromArgs(World*, sc_msg_iter& args, std::string, int)
{ {
const char* recv = args.gets(""); const char* recv = args.gets("");
@ -266,6 +290,23 @@ struct ParamReader<sc_msg_iter>
res[i] = static_cast<Value>(args.geti()); res[i] = static_cast<Value>(args.geti());
return res; return res;
} }
static auto fromArgs(World*,sc_msg_iter& args,typename LongRuntimeMaxT::type&, int)
{
return typename LongRuntimeMaxT::type{args.geti(), args.geti()};
}
static auto fromArgs(World*, sc_msg_iter& args, typename ChoicesT::type, int)
{
int x = args.geti();
return typename ChoicesT::type(asUnsigned(x));
}
template<typename T>
static auto fromArgs(World* w, sc_msg_iter& args, Optional<T>, int)
{
return Optional<T>{fromArgs(w,args,T{},int{})};
}
}; };

@ -35,23 +35,54 @@ struct FluidSCMessaging{
}; };
private:
static bool is_vowel(const char p_char)
{
constexpr char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U' };
return std::find(std::begin(vowels), std::end(vowels), p_char) != std::end(vowels);
}
static std::string remove_vowel(std::string st)
{
auto to_erase = std::remove_if(st.begin(), st.end(), is_vowel);
st.erase(to_erase, st.end());
return st;
}
public:
template <size_t N, typename T> template <size_t N, typename T>
struct SetupMessageCmd struct SetupMessageCmd
{ {
void operator()(const T& message) void operator()(const T& message)
{ {
static std::string messageName = std::string{getName()} + '/' + message.name; static std::string messageName = std::string{getName()} + '/' + message.name;
auto ft = getInterfaceTable(); FluidSCWrapper::registerMessage(messageName.c_str(),doMessage<N>);
ft->fDefinePlugInCmd(messageName.c_str(), doMessage<N>,(void*)messageName.c_str());
} }
}; };
template<typename T>
static auto constexpr filterOneOptional(const T&) { return std::make_tuple(T{}); }
template<typename T>
static auto constexpr filterOneOptional(const Optional<T>&) { return std::make_tuple(); }
template<typename...Ts>
static auto constexpr filterOptional(std::tuple<Ts...>)
{
return std::tuple_cat(filterOneOptional(Ts{})...);
}
template <typename Message> template <typename Message>
static bool validateMessageArgs(Message* msg, sc_msg_iter* inArgs) static Optional<size_t> validateMessageArgs(Message* msg, sc_msg_iter* inArgs)
{ {
//we can be sure that optional args always follow mandatory ones, as this is enforced at compile time in flucoma-core
using ArgTuple = decltype(msg->args); using ArgTuple = decltype(msg->args);
using MandatoryArgsTuple = decltype(filterOptional(msg->args));
std::string tags(inArgs->tags + inArgs->count);//evidently this needs commenting: construct string at pointer offset by tag count, to pick up args std::string tags(inArgs->tags + inArgs->count);//evidently this needs commenting: construct string at pointer offset by tag count, to pick up args
bool willContinue = true; bool willContinue = true;
@ -59,7 +90,7 @@ struct FluidSCMessaging{
auto& args = msg->args; auto& args = msg->args;
constexpr size_t expectedArgCount = std::tuple_size<ArgTuple>::value; static constexpr size_t expectedArgCount = std::tuple_size<MandatoryArgsTuple>::value;
/// TODO this squawks if we have a completion message, so maybe we can check if extra arg is a 'b' and squawk if not? /// TODO this squawks if we have a completion message, so maybe we can check if extra arg is a 'b' and squawk if not?
// if(tags.size() > expectedArgCount) // if(tags.size() > expectedArgCount)
@ -77,14 +108,16 @@ struct FluidSCMessaging{
auto tagsIter = tags.begin(); auto tagsIter = tags.begin();
auto tagsEnd = tags.end(); auto tagsEnd = tags.end();
ForEach(args,[&typesMatch,&tagsIter,&tagsEnd](auto& arg){ size_t argCount = 0;
ForEach(args,[&typesMatch,&tagsIter,&tagsEnd,firstTag=tags.begin(),&argCount](auto& arg){
if(tagsIter == tagsEnd) if(tagsIter == tagsEnd)
{ {
typesMatch = false; if(std::distance(firstTag,tagsIter) < asSigned(expectedArgCount)) typesMatch = false;
return; return;
} }
char t = *(tagsIter++); char t = *(tagsIter++);
typesMatch = typesMatch && ParamReader<sc_msg_iter>::argTypeOK(arg,t); typesMatch = typesMatch && ParamReader<sc_msg_iter>::argTypeOK(arg,t);
argCount++;
}); });
willContinue = willContinue && typesMatch; willContinue = willContinue && typesMatch;
@ -116,7 +149,7 @@ struct FluidSCMessaging{
report << ")\n"; report << ")\n";
} }
return willContinue; return willContinue ? Optional<size_t>(argCount) : Optional<size_t>();
} }
static void refreshParams(Params& p, MessageResult<ParamValues>& r) static void refreshParams(Params& p, MessageResult<ParamValues>& r)
@ -137,9 +170,9 @@ struct FluidSCMessaging{
msg->id = args->geti(); msg->id = args->geti();
msg->replyAddr = copyReplyAddress(replyAddr); msg->replyAddr = copyReplyAddress(replyAddr);
///TODO make this step contingent on verbosity or something, in the name of effieciency ///TODO make this step contingent on verbosity or something, in the name of effieciency
bool willContinue = validateMessageArgs(msg, args); auto tagCount = validateMessageArgs(msg, args);
if(!willContinue) if(!tagCount.has_value())
{ {
delete msg; delete msg;
return; return;
@ -148,9 +181,10 @@ struct FluidSCMessaging{
msg->name = std::string{'/'} + (const char*)(inUserData); msg->name = std::string{'/'} + (const char*)(inUserData);
ForEach(msg-> args,[inWorld,&args](auto& thisarg) ForEach(msg-> args,[inWorld,&args,tagCount,n=0](auto& thisarg)mutable
{ {
thisarg = ParamReader<sc_msg_iter>::fromArgs(inWorld, *args,thisarg,0); if(n++ < asSigned(tagCount.value()))
thisarg = ParamReader<sc_msg_iter>::fromArgs(inWorld, *args,thisarg,0);
}); });
size_t completionMsgSize{args ? args->getbsize() : 0}; size_t completionMsgSize{args ? args->getbsize() : 0};

@ -20,6 +20,12 @@ namespace impl {
/// Non Real Time Processor /// Non Real Time Processor
using ServerCommandFn = void(*)(World* world, void*, struct sc_msg_iter* args,
void* replyAddr);
using CommandMap = std::unordered_map<std::string_view, ServerCommandFn>;
template <typename Client, typename Wrapper> template <typename Client, typename Wrapper>
class NonRealTime : public SCUnit class NonRealTime : public SCUnit
{ {
@ -829,8 +835,8 @@ private:
completionMsgData); completionMsgData);
if (completionMsgSize) ft->fRTFree(world, completionMsgData); if (completionMsgSize) ft->fRTFree(world, completionMsgData);
}; };
ft->fDefinePlugInCmd(Command::name(), commandRunner, nullptr); mCommandDispatchTable[Command::name()] = commandRunner;
} }
@ -1106,6 +1112,12 @@ private:
static constexpr bool IsModel = Client::isModelObject::value; static constexpr bool IsModel = Client::isModelObject::value;
public: public:
static void registerMessage(const char* name, ServerCommandFn f)
{
mCommandDispatchTable[name] = f;
}
static void setup(InterfaceTable* ft, const char*) static void setup(InterfaceTable* ft, const char*)
{ {
defineNRTCommand<CommandNew>(); defineNRTCommand<CommandNew>();
@ -1125,6 +1137,21 @@ public:
static std::string flushCmd = std::string(Wrapper::getName()) + "/flush"; static std::string flushCmd = std::string(Wrapper::getName()) + "/flush";
ft->fDefinePlugInCmd(
Wrapper::getName(),
[](World* w, void* inUserData, struct sc_msg_iter* msg, void* replyAddr)
{
const char* name = msg->gets();
auto cmd = mCommandDispatchTable.find(name);
if (cmd != mCommandDispatchTable.end())
cmd->second(w, inUserData ? inUserData : (void*)name, msg, replyAddr);
else
std::cout << "ERROR: message " << name << " not registered.";
}, nullptr);
ft->fDefinePlugInCmd( ft->fDefinePlugInCmd(
flushCmd.c_str(), flushCmd.c_str(),
[](World*, void*, struct sc_msg_iter*, void*) { mCache.clear(); }, [](World*, void*, struct sc_msg_iter*, void*) { mCache.clear(); },
@ -1176,14 +1203,21 @@ private:
index mPreviousTrigger{0}; index mPreviousTrigger{0};
bool mSynchronous{true}; bool mSynchronous{true};
Result mResult; Result mResult;
static CommandMap mCommandDispatchTable;
}; };
template <typename Client, typename Wrapper> template <typename Client, typename Wrapper>
World* NonRealTime<Client, Wrapper>::mWorld{nullptr}; World* NonRealTime<Client, Wrapper>::mWorld{nullptr};
template <typename Client, typename Wrapper> template <typename Client, typename Wrapper>
typename NonRealTime<Client, Wrapper>::Cache typename NonRealTime<Client, Wrapper>::Cache
NonRealTime<Client, Wrapper>::mCache{}; NonRealTime<Client, Wrapper>::mCache{};
template <typename Client, typename Wrapper>
CommandMap NonRealTime<Client, Wrapper>::mCommandDispatchTable{};
} // namespace impl } // namespace impl
} // namespace client } // namespace client

@ -118,7 +118,7 @@ struct RealTimeBase
index outputSize = client.controlChannelsOut().size > 0 index outputSize = client.controlChannelsOut().size > 0
? std::max(client.audioChannelsOut(), ? std::max(client.audioChannelsOut(),
client.controlChannelsOut().size) client.maxControlChannelsOut())
: unit.mSpecialIndex + 1; : unit.mSpecialIndex + 1;
mOutputs.reserve(asUnsigned(outputSize)); mOutputs.reserve(asUnsigned(outputSize));
@ -174,18 +174,20 @@ struct RealTimeBase
} }
} }
void mapControlInputs(SCUnit& unit, Client& client) void mapControlInputs(SCUnit& unit, Client&)
{ {
for (index i = 0; i < unit.mSpecialIndex + 1; ++i) for (index i = 0; i < unit.mSpecialIndex + 1; ++i)
{ {
assert(i <= std::numeric_limits<int>::max()); assert(i <= std::numeric_limits<int>::max());
mControlInputBuffer[asUnsigned(i)] = unit.in0(static_cast<int>(i)); mControlInputBuffer[i] = unit.in0(static_cast<int>(i));
} }
} }
void mapControlOutputs(SCUnit& unit, Client& client) void mapControlOutputs(SCUnit& unit, Client&)
{ {
for (index i = 0; i < mControlOutputBuffer.size(); ++i) index numOuts = std::min<index>(mControlOutputBuffer.size(),unit.mNumOutputs);
for (index i = 0; i < numOuts; ++i)
{ {
assert(i <= std::numeric_limits<int>::max()); assert(i <= std::numeric_limits<int>::max());
unit.out0(static_cast<int>(i)) = mControlOutputBuffer(i); unit.out0(static_cast<int>(i)) = mControlOutputBuffer(i);

@ -7,7 +7,7 @@ FluidAudioTransport : FluidRTUGen {
// ^this.initOutputs(1,rate); // ^this.initOutputs(1,rate);
} }
*ar { arg in = 0, in2 = 0, interpolation = 0.0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; *ar { arg in = 0, in2 = 0, interpolation = 0.0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1;
^this.multiNew('audio', in.asAudioRateInput, in2, interpolation, windowSize, hopSize, fftSize, maxFFTSize) ^this.multiNew('audio', in.asAudioRateInput, in2, interpolation, windowSize, hopSize, fftSize, maxFFTSize)
} }
} }

@ -1,9 +1,5 @@
FluidBufAudioTransport : FluidBufProcessor { FluidBufAudioTransport : FluidBufProcessor {
*objectClassName{
^\FluidBufAudioTransp
}
*kr { |sourceA, startFrameA = 0, numFramesA = -1, startChanA = 0, numChansA = -1, sourceB, startFrameB = 0, numFramesB = -1, startChanB = 0, numChansB = -1, destination, interpolation = 0.0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0| *kr { |sourceA, startFrameA = 0, numFramesA = -1, startChanA = 0, numChansA = -1, sourceB, startFrameB = 0, numFramesB = -1, startChanB = 0, numChansB = -1, destination, interpolation = 0.0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};

@ -9,7 +9,7 @@ FluidBufChroma : FluidBufProcessor {
source.isNil.if {"FluidBufChroma: Invalid source buffer".throw}; source.isNil.if {"FluidBufChroma: Invalid source buffer".throw};
features.isNil.if {"FluidBufChroma: Invalid features buffer".throw}; features.isNil.if {"FluidBufChroma: Invalid features buffer".throw};
^FluidProxyUgen.kr(\FluidBufChromaTrigger,-1, source, startFrame, numFrames, startChan, numChans, features, padding, numChroma, ref, normalize, minFreq, maxFreq, numChroma, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking); ^FluidProxyUgen.kr(\FluidBufChromaTrigger,-1, source, startFrame, numFrames, startChan, numChans, features, padding, numChroma, numChroma, ref, normalize, minFreq, maxFreq, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
} }
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numChroma = 12, ref = 440, normalize = 0,minFreq = 0,maxFreq = -1, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numChroma = 12, ref = 440, normalize = 0,minFreq = 0,maxFreq = -1, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action|
@ -25,7 +25,7 @@ FluidBufChroma : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, numChroma, ref, normalize, minFreq, maxFreq, numChroma, windowSize, hopSize, fftSize, maxFFTSize, 0],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features, padding, numChroma, numChroma, ref, normalize, minFreq, maxFreq, windowSize, hopSize, fftSize, maxFFTSize, 0],freeWhenDone,action
); );
} }
@ -42,7 +42,7 @@ FluidBufChroma : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, numChroma, ref, normalize, minFreq, maxFreq, numChroma, windowSize, hopSize, fftSize, maxFFTSize, 1],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features, padding, numChroma, numChroma, ref, normalize, minFreq, maxFreq, windowSize, hopSize, fftSize, maxFFTSize, 1],freeWhenDone,action
); );
} }
} }

@ -9,7 +9,7 @@ FluidBufHPSS : FluidBufProcessor {
residual = residual ? -1; residual = residual ? -1;
source.isNil.if {"FluidBufHPSS: Invalid source buffer".throw}; source.isNil.if {"FluidBufHPSS: Invalid source buffer".throw};
^FluidProxyUgen.kr(\FluidBufHPSSTrigger, -1, source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize, harmFilterSize, percFilterSize, trig, blocking ^FluidProxyUgen.kr(\FluidBufHPSSTrigger, -1, source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, harmFilterSize, percFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking
); );
} }
@ -26,7 +26,7 @@ FluidBufHPSS : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [harmonic, percussive, residual].select{|x| x!= -1} server, nil, [harmonic, percussive, residual].select{|x| x!= -1}
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize, harmFilterSize, percFilterSize,0], freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, harmFilterSize, percFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone,action
); );
} }
@ -44,7 +44,7 @@ FluidBufHPSS : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [harmonic, percussive, residual].select{|x| x!= -1} server, nil, [harmonic, percussive, residual].select{|x| x!= -1}
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize,harmFilterSize, percFilterSize,1], freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, harmonic, percussive, residual, harmFilterSize, harmFilterSize, percFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone,action
); );
} }

@ -1,7 +1,30 @@
FluidBufLoudness : FluidBufProcessor{ FluidBufLoudness : FluidBufProcessor{
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, trig = 1, blocking = 0|
const <features=#[\loudness, \peak];
classvar featuresLookup;
*initClass {
featuresLookup = Dictionary.with(*this.features.collect{|x,i| x->(1<<i)});
}
*prWarnUnrecognised {|sym| ("WARNING: FluidLoudness -" + sym + "is not a recognised option").postln}
*prProcessSelect {|a|
var bits;
a.asBag.countsDo{|item,count,i|
if(count > 1) { ("Option '" ++ item ++ "' is repeated").warn};
};
bits = a.collect{ |sym|
(featuresLookup[sym.asSymbol] !? {|x| x} ?? {this.prWarnUnrecognised(sym); 0})
}.reduce{|x,y| x | y};
^bits
}
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, select, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, trig = 1, blocking = 0|
var maxwindowSize = windowSize.nextPowerOfTwo; var maxwindowSize = windowSize.nextPowerOfTwo;
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.features)};
source = source.asUGenInput; source = source.asUGenInput;
features = features.asUGenInput; features = features.asUGenInput;
@ -9,13 +32,15 @@ FluidBufLoudness : FluidBufProcessor{
source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; source.isNil.if {"FluidBufPitch: Invalid source buffer".throw};
features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw};
^FluidProxyUgen.kr(\FluidBufLoudnessTrigger, -1, source, startFrame, numFrames, startChan, numChans, features,padding, kWeighting, truePeak, windowSize, hopSize, maxwindowSize, trig, blocking); ^FluidProxyUgen.kr(\FluidBufLoudnessTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, selectbits, kWeighting, truePeak, windowSize, hopSize, maxwindowSize, trig, blocking);
} }
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, freeWhenDone = true, action| *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, select, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, freeWhenDone = true, action|
var maxwindowSize = windowSize.nextPowerOfTwo; var maxwindowSize = windowSize.nextPowerOfTwo;
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.features)};
source = source.asUGenInput; source = source.asUGenInput;
features = features.asUGenInput; features = features.asUGenInput;
@ -25,13 +50,15 @@ FluidBufLoudness : FluidBufProcessor{
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,0],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features, padding, selectbits, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,0],freeWhenDone,action
); );
} }
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, freeWhenDone = true, action| *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, select, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, freeWhenDone = true, action|
var maxwindowSize = windowSize.nextPowerOfTwo; var maxwindowSize = windowSize.nextPowerOfTwo;
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.features)};
source = source.asUGenInput; source = source.asUGenInput;
features = features.asUGenInput; features = features.asUGenInput;
@ -42,7 +69,7 @@ FluidBufLoudness : FluidBufProcessor{
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features,padding, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,1],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features,padding, selectbits, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,1],freeWhenDone,action
); );
} }
} }

@ -8,7 +8,7 @@ FluidBufMFCC : FluidBufProcessor{
source.isNil.if {"FluidBufMFCC: Invalid source buffer".throw}; source.isNil.if {"FluidBufMFCC: Invalid source buffer".throw};
features.isNil.if {"FluidBufMFCC: Invalid features buffer".throw}; features.isNil.if {"FluidBufMFCC: Invalid features buffer".throw};
^FluidProxyUgen.kr(\FluidBufMFCCTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, numCoeffs, numBands, startCoeff, minFreq, maxFreq, numCoeffs, windowSize, hopSize, fftSize, maxFFTSize,trig, blocking); ^FluidProxyUgen.kr(\FluidBufMFCCTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, numCoeffs, numCoeffs, numBands, startCoeff, minFreq, maxFreq, windowSize, hopSize, fftSize, maxFFTSize,trig, blocking);
} }
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, startCoeff = 0, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone=true, action | *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, startCoeff = 0, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone=true, action |
@ -23,7 +23,7 @@ FluidBufMFCC : FluidBufProcessor{
^this.new( ^this.new(
server, nil,[features] server, nil,[features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, numCoeffs, numBands, startCoeff, minFreq, maxFreq, numCoeffs, windowSize, hopSize, fftSize, maxFFTSize,0],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features, padding, numCoeffs, numCoeffs, numBands, startCoeff, minFreq, maxFreq, windowSize, hopSize, fftSize, maxFFTSize,0],freeWhenDone,action
); );
} }
@ -39,7 +39,7 @@ FluidBufMFCC : FluidBufProcessor{
^this.new( ^this.new(
server, nil,[features] server, nil,[features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, numCoeffs, numBands, startCoeff, minFreq, maxFreq, numCoeffs, windowSize, hopSize, fftSize, maxFFTSize,1],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features, padding, numCoeffs, numCoeffs, numBands, startCoeff, minFreq, maxFreq, windowSize, hopSize, fftSize, maxFFTSize,1],freeWhenDone,action
); );
} }
} }

@ -11,7 +11,7 @@ FluidBufMelBands : FluidBufProcessor {
features.isNil.if {"FluidBufMelBands: Invalid features buffer".throw}; features.isNil.if {"FluidBufMelBands: Invalid features buffer".throw};
^FluidProxyUgen.kr(\FluidBufMelBandsTrigger,-1, source, startFrame, numFrames, startChan, numChans, features, padding, numBands, minFreq, maxFreq, numBands, normalize, scale, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking); ^FluidProxyUgen.kr(\FluidBufMelBandsTrigger,-1, source, startFrame, numFrames, startChan, numChans, features, padding, numBands, numBands, minFreq, maxFreq, normalize, scale, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
} }
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, scale = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, scale = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action|
@ -27,7 +27,7 @@ FluidBufMelBands : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, numBands, minFreq, maxFreq, numBands, normalize, scale, windowSize, hopSize, fftSize, maxFFTSize, 0],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features, padding, numBands, numBands, minFreq, maxFreq, normalize, scale, windowSize, hopSize, fftSize, maxFFTSize, 0],freeWhenDone,action
); );
} }
@ -44,7 +44,7 @@ FluidBufMelBands : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, numBands, minFreq, maxFreq, numBands, normalize, scale, windowSize, hopSize, fftSize, maxFFTSize, 1],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features, padding, numBands, numBands, minFreq, maxFreq, normalize, scale, windowSize, hopSize, fftSize, maxFFTSize, 1],freeWhenDone,action
); );
} }
} }

@ -1,16 +1,16 @@
FluidBufNMF : FluidBufProcessor FluidBufNMF : FluidBufProcessor
{ {
*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, trig = 1, blocking = 0| *kr {|source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth, resynthMode = 0, bases, basesMode = 0, activations, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
source.isNil.if {"FluidBufNMF: Invalid source buffer".throw}; source.isNil.if {"FluidBufNMF: Invalid source buffer".throw};
resynth = resynth ? -1; resynth = resynth ? -1;
bases = bases ? -1; bases = bases ? -1;
activations = activations ? -1; activations = activations ? -1;
^FluidProxyUgen.kr(\FluidBufNMFTrigger,-1,source.asUGenInput, startFrame, numFrames, startChan, numChans, resynth.asUGenInput, bases.asUGenInput, basesMode, activations.asUGenInput, actMode, components, iterations, windowSize, hopSize, fftSize, trig, blocking); ^FluidProxyUgen.kr(\FluidBufNMFTrigger,-1,source.asUGenInput, startFrame, numFrames, startChan, numChans, resynth.asUGenInput, resynthMode, bases.asUGenInput, basesMode, activations.asUGenInput, actMode, components, iterations, windowSize, hopSize, fftSize, fftSize, trig, blocking);
} }
*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,freeWhenDone = true, action| *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth = -1, resynthMode = 0, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action|
source.isNil.if {"FluidBufNMF: Invalid source buffer".throw}; source.isNil.if {"FluidBufNMF: Invalid source buffer".throw};
resynth = resynth ? -1; resynth = resynth ? -1;
@ -19,10 +19,10 @@ FluidBufNMF : FluidBufProcessor
^this.new( ^this.new(
server,nil,[resynth, bases, activations].select{|x| x!= -1} server,nil,[resynth, bases, activations].select{|x| x!= -1}
).processList([source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize,0],freeWhenDone,action); ).processList([source, startFrame, numFrames, startChan, numChans, resynth, resynthMode, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, fftSize, 0],freeWhenDone,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,freeWhenDone = true, action| *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, resynth = -1, resynthMode = 0, bases = -1, basesMode = 0, activations = -1, actMode = 0, components = 1, iterations = 100, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action|
source.isNil.if {"FluidBufNMF: Invalid source buffer".throw}; source.isNil.if {"FluidBufNMF: Invalid source buffer".throw};
resynth = resynth ? -1; resynth = resynth ? -1;
@ -31,7 +31,7 @@ FluidBufNMF : FluidBufProcessor
^this.new( ^this.new(
server,nil,[resynth, bases, activations].select{|x| x!= -1} server,nil,[resynth, bases, activations].select{|x| x!= -1}
).processList([source, startFrame, numFrames, startChan, numChans, resynth, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, 1],freeWhenDone,action); ).processList([source, startFrame, numFrames, startChan, numChans, resynth, resynthMode, bases, basesMode, activations, actMode, components,iterations, windowSize, hopSize, fftSize, fftSize, 1],freeWhenDone,action);
} }
} }
FluidBufNMFTrigger : FluidProxyUgen {} FluidBufNMFTrigger : FluidProxyUgen {}

@ -9,7 +9,7 @@ FluidBufNMFCross : FluidBufProcessor {
target.isNil.if {"FluidBufNMFCross: Invalid target buffer".throw}; target.isNil.if {"FluidBufNMFCross: Invalid target buffer".throw};
output.isNil.if {"FluidBufNMFCross: Invalid output buffer".throw}; output.isNil.if {"FluidBufNMFCross: Invalid output buffer".throw};
^FluidProxyUgen.kr(\FluidBufNMFCrossTrigger, -1, source, target, output, timeSparsity, polyphony, continuity, iterations, windowSize, hopSize, fftSize, trig, blocking); ^FluidProxyUgen.kr(\FluidBufNMFCrossTrigger, -1, source, target, output, timeSparsity, polyphony, continuity, iterations, windowSize, hopSize, fftSize, fftSize, trig, blocking);
} }
*process { |server, source, target, output , timeSparsity = 7, polyphony = 10, continuity = 7, iterations = 50, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action| *process { |server, source, target, output , timeSparsity = 7, polyphony = 10, continuity = 7, iterations = 50, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
@ -25,7 +25,7 @@ FluidBufNMFCross : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [output] server, nil, [output]
).processList( ).processList(
[source, target, output, timeSparsity, polyphony, continuity, iterations, windowSize, hopSize, fftSize,0],freeWhenDone, action [source, target, output, timeSparsity, polyphony, continuity, iterations, windowSize, hopSize, fftSize, fftSize, 0],freeWhenDone, action
); );
} }
@ -42,7 +42,7 @@ FluidBufNMFCross : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [output] server, nil, [output]
).processList( ).processList(
[source, target, output, timeSparsity, polyphony, continuity, iterations, windowSize, hopSize, fftSize,1],freeWhenDone, action [source, target, output, timeSparsity, polyphony, continuity, iterations, windowSize, hopSize, fftSize, fftSize, 1],freeWhenDone, action
); );
} }
} }

@ -0,0 +1,48 @@
FluidBufNMFSeed : FluidBufProcessor{
*kr { |source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
source.isNil.if {"FluidBufNMFSeed: Invalid source buffer".throw};
bases.isNil.if {"FluidBufNMFSeed: Invalid bases buffer".throw};
activations.isNil.if {"FluidBufNMFSeed: Invalid bases buffer".throw};
source = source.asUGenInput;
bases = bases.asUGenInput;
activations = activations.asUGenInput;
^FluidProxyUgen.kr1(\FluidBufNMFSeedTrigger, -1, source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize, fftSize, trig, blocking);
}
*process { |server, source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
source.isNil.if {"FluidBufNMFSeed: Invalid source buffer".throw};
bases.isNil.if {"FluidBufNMFSeed: Invalid bases buffer".throw};
activations.isNil.if {"FluidBufNMFSeed: Invalid bases buffer".throw};
source = source.asUGenInput;
bases = bases.asUGenInput;
activations = activations.asUGenInput;
^this.new(
server, nil, [bases,activations]
).processList(
[source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize, fftSize, 0],freeWhenDone, action
)
}
*processBlocking { |server, source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
source.isNil.if {"FluidBufNMFSeed: Invalid source buffer".throw};
bases.isNil.if {"FluidBufNMFSeed: Invalid bases buffer".throw};
activations.isNil.if {"FluidBufNMFSeed: Invalid bases buffer".throw};
source = source.asUGenInput;
bases = bases.asUGenInput;
activations = activations.asUGenInput;
^this.new(
server, nil, [bases,activations]
).processList(
[source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize, fftSize, 1],freeWhenDone, action
)
}
}
FluidBufNMFSeedTrigger : FluidProxyUgen {}

@ -1,48 +0,0 @@
FluidBufNNDSVD : FluidBufProcessor{
*kr { |source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0|
source.isNil.if {"FluidBufNNDSVD: Invalid source buffer".throw};
bases.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
activations.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
source = source.asUGenInput;
bases = bases.asUGenInput;
activations = activations.asUGenInput;
^FluidProxyUgen.kr1(\FluidBufNNDSVDTrigger, -1, source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize, trig, blocking);
}
*process { |server, source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
source.isNil.if {"FluidBufNNDSVD: Invalid source buffer".throw};
bases.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
activations.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
source = source.asUGenInput;
bases = bases.asUGenInput;
activations = activations.asUGenInput;
^this.new(
server, nil, [bases]
).processList(
[source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize,0],freeWhenDone, action
)
}
*processBlocking { |server, source, bases, activations, minComponents = 1, maxComponents = 200, coverage = 0.5, method = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action|
source.isNil.if {"FluidBufNNDSVD: Invalid source buffer".throw};
bases.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
activations.isNil.if {"FluidBufNNDSVD: Invalid bases buffer".throw};
source = source.asUGenInput;
bases = bases.asUGenInput;
activations = activations.asUGenInput;
^this.new(
server, nil, [bases]
).processList(
[source, bases, activations, minComponents, maxComponents, coverage, method, windowSize, hopSize, fftSize,1],freeWhenDone, action
)
}
}
FluidBufNNDSVDTrigger : FluidProxyUgen {}

@ -1,9 +1,5 @@
FluidBufNoveltyFeature : FluidBufProcessor { FluidBufNoveltyFeature : FluidBufProcessor {
*objectClassName{
^\FluidBufNoveltyF
}
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 0, kernelSize = 3, filterSize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0| *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 0, kernelSize = 3, filterSize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0|
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
@ -14,7 +10,7 @@ FluidBufNoveltyFeature : FluidBufProcessor {
source.isNil.if {"FluidBufNoveltyFeature: Invalid source buffer".throw}; source.isNil.if {"FluidBufNoveltyFeature: Invalid source buffer".throw};
features.isNil.if {"FluidBufNoveltyFeature: Invalid features buffer".throw}; features.isNil.if {"FluidBufNoveltyFeature: Invalid features buffer".throw};
^FluidProxyUgen.kr(\FluidBufNoveltyFeatureTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, kernelSize, filterSize, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize, trig, blocking); ^FluidProxyUgen.kr(\FluidBufNoveltyFeatureTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, kernelSize, kernelSize, filterSize, filterSize, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
} }
@ -31,7 +27,7 @@ FluidBufNoveltyFeature : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, kernelSize, filterSize, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize,0],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, kernelSize, kernelSize, filterSize, filterSize, windowSize, hopSize, fftSize, maxFFTSize, 0],freeWhenDone,action
); );
} }
@ -48,7 +44,7 @@ FluidBufNoveltyFeature : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, kernelSize, filterSize, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize,1],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, kernelSize, kernelSize, filterSize, filterSize, windowSize, hopSize, fftSize, maxFFTSize, 1],freeWhenDone,action
); );
} }
} }

@ -10,7 +10,7 @@ FluidBufNoveltySlice : FluidBufProcessor {
source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw}; source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw};
indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw}; indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw};
^FluidProxyUgen.kr(\FluidBufNoveltySliceTrigger, -1, source, startFrame, numFrames, startChan, numChans, indices, algorithm, kernelSize, threshold, filterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize, trig, blocking); ^FluidProxyUgen.kr(\FluidBufNoveltySliceTrigger, -1, source, startFrame, numFrames, startChan, numChans, indices, algorithm, kernelSize, kernelSize, threshold, filterSize, filterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
} }
@ -27,7 +27,7 @@ FluidBufNoveltySlice : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [indices] server, nil, [indices]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, indices, algorithm, kernelSize, threshold, filterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize,0],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, indices, algorithm, kernelSize, kernelSize, threshold, filterSize, filterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize, 0],freeWhenDone,action
); );
} }
@ -44,7 +44,7 @@ FluidBufNoveltySlice : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [indices] server, nil, [indices]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, indices, algorithm, kernelSize, threshold, filterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize, kernelSize, filterSize,1],freeWhenDone,action [source, startFrame, numFrames, startChan, numChans, indices, algorithm, kernelSize, kernelSize, threshold, filterSize, filterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize, 1],freeWhenDone,action
); );
} }
} }

@ -1,8 +1,30 @@
FluidBufPitch : FluidBufProcessor{ FluidBufPitch : FluidBufProcessor{
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0| const <features=#[\pitch, \confidence];
classvar featuresLookup;
*initClass {
featuresLookup = Dictionary.with(*this.features.collect{|x,i| x->(1<<i)});
}
*prWarnUnrecognised {|sym| ("WARNING: FluidBufPitch -" + sym + "is not a recognised option").postln}
*prProcessSelect {|a|
var bits;
a.asBag.countsDo{|item,count,i|
if(count > 1) { ("Option '" ++ item ++ "' is repeated").warn};
};
bits = a.collect{ |sym|
(featuresLookup[sym.asSymbol] !? {|x| x} ?? {this.prWarnUnrecognised(sym); 0})
}.reduce{|x,y| x | y};
^bits
}
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, select, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0|
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.features)};
source = source.asUGenInput; source = source.asUGenInput;
features = features.asUGenInput; features = features.asUGenInput;
@ -10,14 +32,16 @@ FluidBufPitch : FluidBufProcessor{
source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; source.isNil.if {"FluidBufPitch: Invalid source buffer".throw};
features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw};
^FluidProxyUgen.kr(\FluidBufPitchTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking); ^FluidProxyUgen.kr(\FluidBufPitchTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, selectbits, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
} }
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, select, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action|
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.features)};
source = source.asUGenInput; source = source.asUGenInput;
features = features.asUGenInput; features = features.asUGenInput;
@ -27,13 +51,15 @@ FluidBufPitch : FluidBufProcessor{
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone, action [source, startFrame, numFrames, startChan, numChans, features, padding, selectbits, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone, action
); );
} }
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, select, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action|
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.features)};
source = source.asUGenInput; source = source.asUGenInput;
features = features.asUGenInput; features = features.asUGenInput;
@ -44,7 +70,7 @@ FluidBufPitch : FluidBufProcessor{
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone, action [source, startFrame, numFrames, startChan, numChans, features, padding, selectbits, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone, action
); );
} }
} }

@ -10,7 +10,7 @@ FluidBufSTFT : FluidBufProcessor {
phase = phase ? -1; phase = phase ? -1;
resynth = resynth ? - 1; resynth = resynth ? - 1;
^FluidProxyUgen.kr(\FluidBufSTFTTrigger, -1, source, startFrame, numFrames, startChan, magnitude, phase, resynth, inverse, padding, windowSize, hopSize, fftSize, trig, blocking); ^FluidProxyUgen.kr(\FluidBufSTFTTrigger, -1, source, startFrame, numFrames, startChan, magnitude, phase, resynth, inverse, padding, windowSize, hopSize, fftSize, -1, trig, blocking);
} }
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynth, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynth, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action|
@ -26,7 +26,7 @@ FluidBufSTFT : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [magnitude,phase,resynth].select{|b| b != -1} server, nil, [magnitude,phase,resynth].select{|b| b != -1}
).processList( ).processList(
[source, startFrame, numFrames, startChan, magnitude, phase, resynth, inverse, padding, windowSize, hopSize, fftSize, 0], freeWhenDone, action [source, startFrame, numFrames, startChan, magnitude, phase, resynth, inverse, padding, windowSize, hopSize, fftSize, -1, 0], freeWhenDone, action
); );
} }
@ -41,7 +41,7 @@ FluidBufSTFT : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [magnitude,phase,resynth].select{|b| b != -1} server, nil, [magnitude,phase,resynth].select{|b| b != -1}
).processList( ).processList(
[source, startFrame, numFrames, startChan, magnitude, phase, resynth, inverse, padding, windowSize, hopSize, fftSize, 1], freeWhenDone, action [source, startFrame, numFrames, startChan, magnitude, phase, resynth, inverse, padding, windowSize, hopSize, fftSize, -1, 1], freeWhenDone, action
); );
} }
} }

@ -1,12 +1,9 @@
FluidBufSpectralShape : FluidBufProcessor { FluidBufSpectralShape : FluidBufProcessor {
*objectClassName{ *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, select, minFreq = 0, maxFreq = -1, rolloffPercent = 95, unit = 0, power = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0|
^\FluidBufSpecShp
}
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, minFreq = 0, maxFreq = -1, rolloffPercent = 95, unit = 0, power = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0|
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
var selectbits = select !? {FluidSpectralShape.prProcessSelect(select)} ?? {FluidSpectralShape.prProcessSelect(FluidSpectralShape.features)};
source = source.asUGenInput; source = source.asUGenInput;
features = features.asUGenInput; features = features.asUGenInput;
@ -14,13 +11,15 @@ FluidBufSpectralShape : FluidBufProcessor {
source.isNil.if {"FluidBufSpectralShape: Invalid source buffer".throw}; source.isNil.if {"FluidBufSpectralShape: Invalid source buffer".throw};
features.isNil.if {"FluidBufSpectralShape: Invalid features buffer".throw}; features.isNil.if {"FluidBufSpectralShape: Invalid features buffer".throw};
^FluidProxyUgen.kr(this.objectClassName++\Trigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, minFreq, maxFreq, rolloffPercent, unit, power, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
^FluidProxyUgen.kr(this.objectClassName++\Trigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, selectbits, minFreq, maxFreq, rolloffPercent, unit, power, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking);
} }
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, minFreq = 0, maxFreq = -1, rolloffPercent = 95, unit = 0, power = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, select, minFreq = 0, maxFreq = -1, rolloffPercent = 95, unit = 0, power = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action|
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
var selectbits = select !? {FluidSpectralShape.prProcessSelect(select)} ?? {FluidSpectralShape.prProcessSelect(FluidSpectralShape.features)};
source = source.asUGenInput; source = source.asUGenInput;
features = features.asUGenInput; features = features.asUGenInput;
@ -31,13 +30,14 @@ FluidBufSpectralShape : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, minFreq, maxFreq, rolloffPercent, unit, power, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone, action [source, startFrame, numFrames, startChan, numChans, features, padding, selectbits, minFreq, maxFreq, rolloffPercent, unit, power, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone, action
); );
} }
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, minFreq = 0, maxFreq = -1, rolloffPercent = 95, unit = 0, power = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, select, minFreq = 0, maxFreq = -1, rolloffPercent = 95, unit = 0, power = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action|
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
var selectbits = select !? {FluidSpectralShape.prProcessSelect(select)} ?? {FluidSpectralShape.prProcessSelect(FluidSpectralShape.features)};
source = source.asUGenInput; source = source.asUGenInput;
features = features.asUGenInput; features = features.asUGenInput;
@ -48,7 +48,7 @@ FluidBufSpectralShape : FluidBufProcessor {
^this.new( ^this.new(
server, nil, [features] server, nil, [features]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, features, padding, minFreq, maxFreq, rolloffPercent, unit, power, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone, action [source, startFrame, numFrames, startChan, numChans, features, padding, selectbits, minFreq, maxFreq, rolloffPercent, unit, power, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone, action
); );
} }
} }

@ -1,7 +1,28 @@
FluidBufStats : FluidBufProcessor { FluidBufStats : FluidBufProcessor {
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, trig = 1, blocking = 0| const <stats=#[\mean,\std,\skewness,\kurtosis,\low,\mid,\high];
classvar statslookup;
*prWarnUnrecognised {|sym| ("WARNING: FluidBufStats -" + sym + "is not a recognised option").postln}
*prProcessSelect {|a|
var bits;
a.asBag.countsDo{|item,count,i|
if(count > 1) { ("Option '" ++ item ++ "' is repeated").warn};
};
bits = a.collect{ |sym|
(statslookup[sym.asSymbol] !? {|x| x} ?? {this.prWarnUnrecognised(sym); 0})
}.reduce{|x,y| x | y};
^bits
}
*initClass {
statslookup = Dictionary.with(*this.stats.collect{|x,i| x->(1<<i)});
}
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, select, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, trig = 1, blocking = 0|
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.stats)};
source = source.asUGenInput; source = source.asUGenInput;
stats = stats.asUGenInput; stats = stats.asUGenInput;
weights = weights.asUGenInput; weights = weights.asUGenInput;
@ -9,12 +30,13 @@ FluidBufStats : FluidBufProcessor {
source.isNil.if {"FluidBufStats: Invalid source buffer".throw}; source.isNil.if {"FluidBufStats: Invalid source buffer".throw};
stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw}; stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw};
weights = weights ? -1; weights = weights ? -1;
^FluidProxyUgen.kr(\FluidBufStatsTrigger, -1, source, startFrame, numFrames, startChan, numChans, stats, numDerivs, low, middle, high, outliersCutoff, weights, trig, blocking); ^FluidProxyUgen.kr(\FluidBufStatsTrigger, -1, source, startFrame, numFrames, startChan, numChans, stats, selectbits, numDerivs, low, middle, high, outliersCutoff, weights, trig, blocking);
} }
*process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, freeWhenDone = true, action| *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, select, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, freeWhenDone = true, action|
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.stats)};
source = source.asUGenInput; source = source.asUGenInput;
stats = stats.asUGenInput; stats = stats.asUGenInput;
weights = weights.asUGenInput; weights = weights.asUGenInput;
@ -22,28 +44,28 @@ FluidBufStats : FluidBufProcessor {
source.isNil.if {"FluidBufStats: Invalid source buffer".throw}; source.isNil.if {"FluidBufStats: Invalid source buffer".throw};
stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw}; stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw};
weights = weights ? -1; weights = weights ? -1;
^this.new( ^this.new(
server, nil, [stats] server, nil, [stats]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, stats,numDerivs, low, middle, high, outliersCutoff, weights, 0], freeWhenDone, action [source, startFrame, numFrames, startChan, numChans, stats, selectbits, numDerivs, low, middle, high, outliersCutoff, weights, 0], freeWhenDone, action
); );
} }
*processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, freeWhenDone = true, action| *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, stats, select numDerivs = 0, low = 0, middle = 50, high = 100, outliersCutoff = -1, weights, freeWhenDone = true, action|
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.stats)};
source = source.asUGenInput; source = source.asUGenInput;
stats = stats.asUGenInput; stats = stats.asUGenInput;
weights = weights.asUGenInput; weights = weights.asUGenInput;
source.isNil.if {"FluidBufStats: Invalid source buffer".throw}; source.isNil.if {"FluidBufStats: Invalid source buffer".throw};
stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw}; stats.isNil.if {"FluidBufStats: Invalid stats buffer".throw};
weights = weights ? -1; weights = weights ? -1;
^this.new( ^this.new(
server, nil, [stats] server, nil, [stats]
).processList( ).processList(
[source, startFrame, numFrames, startChan, numChans, stats,numDerivs, low, middle, high, outliersCutoff, weights, 1], freeWhenDone, action [source, startFrame, numFrames, startChan, numChans, stats, selectbits, numDerivs, low, middle, high, outliersCutoff, weights, 1], freeWhenDone, action
); );
} }

@ -61,7 +61,7 @@ FluidBufToKr {
}; };
if(numFrames > 1,{ if(numFrames > 1,{
^numFrames.collect{ ^numFrames.asInteger.collect{
arg i; arg i;
BufRd.kr(1,buffer,i+startFrame,0,0); BufRd.kr(1,buffer,i+startFrame,0,0);
} }

@ -1,7 +1,5 @@
FluidBufTransientSlice : FluidBufProcessor { FluidBufTransientSlice : FluidBufProcessor {
*objectClassName{^\FluidBufTrSlice}
*kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, minSliceLength = 1000, trig = 1, blocking = 0| *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, order = 20, blockSize = 256, padSize = 128, skew = 0, threshFwd = 2, threshBack = 1.1, windowSize = 14, clumpLength = 25, minSliceLength = 1000, trig = 1, blocking = 0|
source = source.asUGenInput; source = source.asUGenInput;

@ -1,20 +1,23 @@
FluidChroma : FluidRTMultiOutUGen { FluidChroma : FluidRTMultiOutUGen {
*kr { arg in = 0, numChroma = 12, ref = 440, normalize = 0, minFreq = 0, maxFreq = -1, windowSize = 1024, hopSize = -1, fftSize = -1, maxNumChroma = 120, maxFFTSize = 16384; *kr { arg in = 0, numChroma = 12, ref = 440, normalize = 0, minFreq = 0, maxFreq = -1, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1, maxNumChroma;
^this.multiNew('control', in.asAudioRateInput(this), numChroma, ref, normalize, minFreq, maxFreq, maxNumChroma, windowSize, hopSize, fftSize, maxFFTSize);
maxNumChroma = maxNumChroma ? numChroma;
^this.multiNew('control', in.asAudioRateInput(this), numChroma, maxNumChroma, ref, normalize, minFreq, maxFreq, windowSize, hopSize, fftSize, maxFFTSize);
} }
init {arg ...theInputs; init {arg ...theInputs;
inputs = theInputs; inputs = theInputs;
^this.initOutputs(inputs.at(6),rate); //this instantiate the number of output from the maxNumCoeffs in the multiNew order ^this.initOutputs(inputs.at(2),rate); //this instantiate the number of output from the maxNumCoeffs in the multiNew order
} }
checkInputs { checkInputs {
// the checks of rates here are in the order of the kr method definition // the checks of rates here are in the order of the kr method definition
if(inputs.at(10).rate != 'scalar') { if(inputs.at(2).rate != 'scalar') {
^(": maxNumChroma cannot be modulated."); ^(": maxNumChroma cannot be modulated.");
}; };
if(inputs.at(9).rate != 'scalar') { if(inputs.at(10).rate != 'scalar') {
^(": maxFFTSize cannot be modulated."); ^(": maxFFTSize cannot be modulated.");
};^this.checkValidInputs; };^this.checkValidInputs;
} }

@ -1,6 +1,10 @@
FluidHPSS : FluidRTMultiOutUGen { FluidHPSS : FluidRTMultiOutUGen {
*ar { arg in = 0, harmFilterSize=17, percFilterSize = 31, maskingMode=0, harmThreshFreq1 = 0.1, harmThreshAmp1 = 0, harmThreshFreq2 = 0.5, harmThreshAmp2 = 0, percThreshFreq1 = 0.1, percThreshAmp1 = 0, percThreshFreq2 = 0.5, percThreshAmp2 = 0, windowSize= 1024, hopSize= -1, fftSize= -1, maxFFTSize = 16384, maxHarmFilterSize = 101, maxPercFilterSize = 101; *ar { arg in = 0, harmFilterSize=17, percFilterSize = 31, maskingMode=0, harmThreshFreq1 = 0.1, harmThreshAmp1 = 0, harmThreshFreq2 = 0.5, harmThreshAmp2 = 0, percThreshFreq1 = 0.1, percThreshAmp1 = 0, percThreshFreq2 = 0.5, percThreshAmp2 = 0, windowSize= 1024, hopSize= -1, fftSize= -1, maxFFTSize = -1, maxHarmFilterSize, maxPercFilterSize;
^this.multiNew('audio', in.asAudioRateInput(this), harmFilterSize, percFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize, maxHarmFilterSize, maxPercFilterSize)
maxHarmFilterSize = maxHarmFilterSize ? harmFilterSize;
maxPercFilterSize = maxPercFilterSize ? percFilterSize;
^this.multiNew('audio', in.asAudioRateInput(this), harmFilterSize, maxHarmFilterSize, percFilterSize, maxPercFilterSize, maskingMode, harmThreshFreq1, harmThreshAmp1, harmThreshFreq2, harmThreshAmp2, percThreshFreq1, percThreshAmp1, percThreshFreq2, percThreshAmp2, windowSize, hopSize, fftSize, maxFFTSize)
} }
init { arg ... theInputs; init { arg ... theInputs;
inputs = theInputs; inputs = theInputs;
@ -12,13 +16,13 @@ FluidHPSS : FluidRTMultiOutUGen {
^channels ^channels
} }
checkInputs { checkInputs {
if(inputs.at(15).rate != 'scalar') { if(inputs.at(17).rate != 'scalar') {
^(": maxFFTSize cannot be modulated."); ^(": maxFFTSize cannot be modulated.");
}; };
if(inputs.at(16).rate != 'scalar') { if(inputs.at(2).rate != 'scalar') {
^(": maxHarmFilterSize cannot be modulated."); ^(": maxHarmFilterSize cannot be modulated.");
}; };
if(inputs.at(17).rate != 'scalar') { if(inputs.at(4).rate != 'scalar') {
^(": maxPercFilterSize cannot be modulated."); ^(": maxPercFilterSize cannot be modulated.");
}; };
^this.checkValidInputs; ^this.checkValidInputs;

@ -24,13 +24,16 @@ FluidKDTree : FluidModelObject
this.prSendMsg(this.fitMsg(dataSet)); this.prSendMsg(this.fitMsg(dataSet));
} }
kNearestMsg{|buffer| kNearestMsg{|buffer,k|
^this.prMakeMsg(\kNearest,id,this.prEncodeBuffer(buffer)); k !?
{^this.prMakeMsg(\kNearest,id,this.prEncodeBuffer(buffer),k);}
??
{^this.prMakeMsg(\kNearest,id,this.prEncodeBuffer(buffer));}
} }
kNearest{ |buffer, action| kNearest{ |buffer, k, action|
actions[\kNearest] = [strings(FluidMessageResponse,_,_),action]; actions[\kNearest] = [strings(FluidMessageResponse,_,_),action];
this.prSendMsg(this.kNearestMsg(buffer)); this.prSendMsg(this.kNearestMsg(buffer,k));
} }
kNearestDistMsg {|buffer| kNearestDistMsg {|buffer|

@ -1,15 +1,41 @@
FluidLoudness : FluidRTMultiOutUGen { FluidLoudness : FluidRTMultiOutUGen {
*kr { arg in = 0, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, maxWindowSize = 16384;
^this.multiNew('control', in.asAudioRateInput(this), kWeighting, truePeak, windowSize, hopSize, maxWindowSize); const <features=#[\loudness, \peak];
classvar featuresLookup;
*initClass {
featuresLookup = Dictionary.with(*this.features.collect{|x,i| x->(1<<i)});
}
*prWarnUnrecognised {|sym| ("WARNING: FluidLoudness -" + sym + "is not a recognised option").postln}
*prProcessSelect {|a|
var bits;
a.asBag.countsDo{|item,count,i|
if(count > 1) { ("Option '" ++ item ++ "' is repeated").warn};
};
bits = a.collect{ |sym|
(featuresLookup[sym.asSymbol] !? {|x| x} ?? {this.prWarnUnrecognised(sym); 0})
}.reduce{|x,y| x | y};
^bits
}
*kr { arg in = 0, select, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, maxWindowSize = 16384;
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.features)};
^this.multiNew('control', in.asAudioRateInput(this), selectbits, kWeighting, truePeak, windowSize, hopSize, maxWindowSize);
} }
init {arg ...theInputs; init {arg ...theInputs;
var numChannels;
inputs = theInputs; inputs = theInputs;
^this.initOutputs(2,rate); numChannels = inputs.at(1).asBinaryDigits.sum;
^this.initOutputs(numChannels,rate);
} }
checkInputs { checkInputs {
if(inputs.at(5).rate != 'scalar') { if(inputs.at(6).rate != 'scalar') {
^(": maxwindowSize cannot be modulated."); ^(": maxwindowSize cannot be modulated.");
}; };
^this.checkValidInputs; ^this.checkValidInputs;

@ -1,18 +1,21 @@
FluidMFCC : FluidRTMultiOutUGen { FluidMFCC : FluidRTMultiOutUGen {
*kr { arg in = 0, numCoeffs = 13, numBands = 40, startCoeff = 0, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, maxNumCoeffs = 13, maxFFTSize = 16384; *kr { arg in = 0, numCoeffs = 13, numBands = 40, startCoeff = 0, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1, maxNumCoeffs = nil;
^this.multiNew('control', in.asAudioRateInput(this), numCoeffs, numBands, startCoeff, minFreq, maxFreq, maxNumCoeffs, windowSize, hopSize, fftSize, maxFFTSize);
maxNumCoeffs = maxNumCoeffs ? numCoeffs;
^this.multiNew('control', in.asAudioRateInput(this), numCoeffs, maxNumCoeffs, numBands, startCoeff, minFreq, maxFreq, windowSize, hopSize, fftSize, maxFFTSize);
} }
init {arg ...theInputs; init {arg ...theInputs;
inputs = theInputs; inputs = theInputs;
^this.initOutputs(inputs.at(6),rate);//this instantiate the number of output from the maxNumCoeffs in the multiNew order ^this.initOutputs(inputs.at(2),rate);//this instantiate the number of output from the maxNumCoeffs in the multiNew order
} }
checkInputs { checkInputs {
// the checks of rates here are in the order of the kr method definition // the checks of rates here are in the order of the kr method definition
if(inputs.at(6).rate != 'scalar') { if(inputs.at(2).rate != 'scalar') {
^(": maxNumCoeffs cannot be modulated."); ^(": maxNumCoeffs cannot be modulated.");
}; };
if(inputs.at(10).rate != 'scalar') { if(inputs.at(10).rate != 'scalar') {

@ -5,12 +5,12 @@ FluidMLPRegressor : FluidModelObject {
const <relu = 2; const <relu = 2;
const <tanh = 3; const <tanh = 3;
var <>hidden, <>activation, <>outputActivation, <>tapIn, <>tapOut, <>maxIter, <>learnRate, <>momentum, <>batchSize, <>validation; var <>hiddenLayers, <>activation, <>outputActivation, <>tapIn, <>tapOut, <>maxIter, <>learnRate, <>momentum, <>batchSize, <>validation;
*new {|server, hidden = #[3,3] , activation = 2, outputActivation = 0, tapIn = 0, tapOut = -1,maxIter = 1000, learnRate = 0.0001, momentum = 0.9, batchSize = 50, validation = 0.2| *new {|server, hiddenLayers = #[3,3] , activation = 2, outputActivation = 0, tapIn = 0, tapOut = -1,maxIter = 1000, learnRate = 0.0001, momentum = 0.9, batchSize = 50, validation = 0.2|
^super.new(server, [hidden.size] ++ hidden ++ [activation, outputActivation, tapIn, tapOut, maxIter, learnRate, momentum, batchSize, validation]) ^super.new(server, [hiddenLayers.size] ++ hiddenLayers ++ [activation, outputActivation, tapIn, tapOut, maxIter, learnRate, momentum, batchSize, validation])
.hidden_(hidden) .hiddenLayers_(hiddenLayers)
.activation_(activation) .activation_(activation)
.outputActivation_(outputActivation) .outputActivation_(outputActivation)
.tapIn_(tapIn) .tapIn_(tapIn)
@ -23,7 +23,7 @@ FluidMLPRegressor : FluidModelObject {
} }
prGetParams{ prGetParams{
^[this.id, this.hidden.size] ++ this.hidden ++ [this.activation, this.outputActivation, this.tapIn, this.tapOut, this.maxIter, this.learnRate, this.momentum, this.batchSize, this.validation] ^[this.id, this.hiddenLayers.size] ++ this.hiddenLayers ++ [this.activation, this.outputActivation, this.tapIn, this.tapOut, this.maxIter, this.learnRate, this.momentum, this.batchSize, this.validation]
} }
clearMsg{ ^this.prMakeMsg(\clear, id) } clearMsg{ ^this.prMakeMsg(\clear, id) }
@ -89,7 +89,7 @@ FluidMLPRegressor : FluidModelObject {
prUpdateParams{|data| prUpdateParams{|data|
var rest = data.keep(-9); var rest = data.keep(-9);
this.hidden_(data.drop(1).drop(-9).copy); this.hiddenLayers_(data.drop(1).drop(-9).copy);
[\activation_, \outputActivation_, [\activation_, \outputActivation_,
\tapIn_, \tapOut_, \maxIter_, \tapIn_, \tapOut_, \maxIter_,
\learnRate_, \momentum_, \learnRate_, \momentum_,
@ -120,11 +120,11 @@ FluidMLPClassifier : FluidModelObject {
const <relu = 2; const <relu = 2;
const <tanh = 3; const <tanh = 3;
var <>hidden, <>activation, <> maxIter, <>learnRate, <> momentum, <>batchSize, <>validation; var <>hiddenLayers, <>activation, <> maxIter, <>learnRate, <> momentum, <>batchSize, <>validation;
*new {|server, hidden = #[3,3] , activation = 2, maxIter = 1000, learnRate = 0.0001, momentum = 0.9, batchSize = 50, validation = 0.2| *new {|server, hiddenLayers = #[3,3] , activation = 2, maxIter = 1000, learnRate = 0.0001, momentum = 0.9, batchSize = 50, validation = 0.2|
^super.new(server,[hidden.size] ++ hidden ++ [activation, maxIter, learnRate, momentum, batchSize, validation]) ^super.new(server,[hiddenLayers.size] ++ hiddenLayers ++ [activation, maxIter, learnRate, momentum, batchSize, validation])
.hidden_(hidden) .hiddenLayers_(hiddenLayers)
.activation_(activation) .activation_(activation)
.maxIter_(maxIter) .maxIter_(maxIter)
.learnRate_(learnRate) .learnRate_(learnRate)
@ -134,7 +134,7 @@ FluidMLPClassifier : FluidModelObject {
} }
prGetParams{ prGetParams{
^[this.id, this.hidden.size] ++ this.hidden ++ [this.activation, this.maxIter, this.learnRate, this.momentum, this.batchSize, this.validation]; ^[this.id, this.hiddenLayers.size] ++ this.hiddenLayers ++ [this.activation, this.maxIter, this.learnRate, this.momentum, this.batchSize, this.validation];
} }
clearMsg{ ^this.prMakeMsg(\clear,id) } clearMsg{ ^this.prMakeMsg(\clear,id) }
@ -183,7 +183,7 @@ FluidMLPClassifier : FluidModelObject {
prUpdateParams{|data| prUpdateParams{|data|
var rest = data.keep(-6); var rest = data.keep(-6);
this.hidden_(data.drop(1).drop(-6).copy); this.hiddenLayers_(data.drop(1).drop(-6).copy);
[\activation_, \maxIter_, [\activation_, \maxIter_,
\learnRate_, \momentum_, \learnRate_, \momentum_,
\batchSize_, \validation_] \batchSize_, \validation_]

@ -1,20 +1,23 @@
FluidMelBands : FluidRTMultiOutUGen { FluidMelBands : FluidRTMultiOutUGen {
*kr { arg in = 0, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, scale = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxNumBands = 120, maxFFTSize = 16384; *kr { arg in = 0, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, scale = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1, maxNumBands;
^this.multiNew('control', in.asAudioRateInput(this), numBands, minFreq, maxFreq, maxNumBands, normalize, scale, windowSize, hopSize, fftSize, maxFFTSize);
maxNumBands = maxNumBands ? numBands;
^this.multiNew('control', in.asAudioRateInput(this), numBands, maxNumBands, minFreq, maxFreq, normalize, scale, windowSize, hopSize, fftSize, maxFFTSize);
} }
init {arg ...theInputs; init {arg ...theInputs;
inputs = theInputs; inputs = theInputs;
^this.initOutputs(inputs.at(4),rate); //this instantiate the number of output from the maxNumCoeffs in the multiNew order ^this.initOutputs(inputs.at(2),rate); //this instantiate the number of output from the maxNumCoeffs in the multiNew order
} }
checkInputs { checkInputs {
// the checks of rates here are in the order of the kr method definition // the checks of rates here are in the order of the kr method definition
if(inputs.at(10).rate != 'scalar') { if(inputs.at(2).rate != 'scalar') {
^(": maxNumBands cannot be modulated."); ^(": maxNumBands cannot be modulated.");
}; };
if(inputs.at(9).rate != 'scalar') { if(inputs.at(10).rate != 'scalar') {
^(": maxFFTSize cannot be modulated."); ^(": maxFFTSize cannot be modulated.");
};^this.checkValidInputs; };^this.checkValidInputs;
} }

@ -1,7 +1,7 @@
FluidNMFFilter : FluidRTMultiOutUGen { FluidNMFFilter : FluidRTMultiOutUGen {
*ar { arg in = 0, bases, maxComponents = 1, iterations = 10, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; *ar { arg in = 0, bases, maxComponents = 1, iterations = 10, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1;
^this.multiNew('audio', in.asAudioRateInput(this), bases, maxComponents, iterations, windowSize, hopSize, fftSize, maxFFTSize); ^this.multiNew('audio', in.asAudioRateInput(this), bases, maxComponents, maxComponents, iterations, windowSize, hopSize, fftSize, maxFFTSize);
} }
init {arg ...theInputs; init {arg ...theInputs;
@ -10,10 +10,10 @@ FluidNMFFilter : FluidRTMultiOutUGen {
} }
checkInputs { checkInputs {
if(inputs.at(2).rate != 'scalar') { if(inputs.at(3).rate != 'scalar') {
^(": maxComponents cannot be modulated."); ^(": maxComponents cannot be modulated.");
}; };
if(inputs.at(7).rate != 'scalar') { if(inputs.at(8).rate != 'scalar') {
^(": maxFFTSize cannot be modulated."); ^(": maxFFTSize cannot be modulated.");
}; };
^this.checkValidInputs; ^this.checkValidInputs;

@ -1,7 +1,7 @@
FluidNMFMatch : FluidRTMultiOutUGen { FluidNMFMatch : FluidRTMultiOutUGen {
*kr { arg in = 0, bases, maxComponents = 1, iterations = 10, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; *kr { arg in = 0, bases, maxComponents = 1, iterations = 10, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1;
^this.multiNew('control', in.asAudioRateInput(this), bases, maxComponents, iterations, windowSize, hopSize, fftSize, maxFFTSize); ^this.multiNew('control', in.asAudioRateInput(this), bases, maxComponents, maxComponents, iterations, windowSize, hopSize, fftSize, maxFFTSize);
} }
init {arg ...theInputs; init {arg ...theInputs;
@ -10,10 +10,10 @@ FluidNMFMatch : FluidRTMultiOutUGen {
} }
checkInputs { checkInputs {
if(inputs.at(2).rate != 'scalar') { if(inputs.at(3).rate != 'scalar') {
^(": maxComponents cannot be modulated."); ^(": maxComponents cannot be modulated.");
}; };
if(inputs.at(7).rate != 'scalar') { if(inputs.at(8).rate != 'scalar') {
^(": maxFFTSize cannot be modulated."); ^(": maxFFTSize cannot be modulated.");
}; };
^this.checkValidInputs; ^this.checkValidInputs;

@ -1,12 +1,12 @@
FluidNMFMorph : FluidRTUGen { FluidNMFMorph : FluidRTUGen {
*ar { arg source = -1, target = -1, activations = -1, autoassign = 1, interp = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; *ar { arg source = -1, target = -1, activations = -1, autoassign = 1, interpolation = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1;
source = source ?? {-1}; source = source ?? {-1};
target = target ?? {-1}; target = target ?? {-1};
activations = activations ?? {-1}; activations = activations ?? {-1};
^this.new1('audio', source, target, activations, autoassign, interp, windowSize, hopSize, fftSize, maxFFTSize); ^this.new1('audio', source, target, activations, autoassign, interpolation, windowSize, hopSize, fftSize, maxFFTSize);
} }
init {arg ...theInputs; init {arg ...theInputs;

@ -1,14 +1,14 @@
FluidNormalize : FluidModelObject { FluidNormalize : FluidModelObject {
var <>min, <>max, <>invert; var <>min, <>max;
*new {|server, min = 0, max = 1, invert = 0| *new {|server, min = 0, max = 1|
^super.new(server,[min,max,invert]) ^super.new(server,[min,max])
.min_(min).max_(max).invert_(invert); .min_(min).max_(max);
} }
prGetParams{ prGetParams{
^[this.id, this.min,this.max,this.invert,-1,-1]; ^[this.id, this.min,this.max,-1,-1];
} }
@ -52,16 +52,37 @@ FluidNormalize : FluidModelObject {
this.prSendMsg(this.transformPointMsg(sourceBuffer, destBuffer)); this.prSendMsg(this.transformPointMsg(sourceBuffer, destBuffer));
} }
inverseTransformMsg{|sourceDataSet, destDataSet|
^this.prMakeMsg(\inverseTransform,id,sourceDataSet.id,destDataSet.id);
}
inverseTransform{|sourceDataSet, destDataSet, action|
actions[\inverseTransform] = [nil,action];
this.prSendMsg(this.inverseTransformMsg(sourceDataSet, destDataSet));
}
inverseTransformPointMsg{|sourceBuffer, destBuffer|
^this.prMakeMsg(\inverseTransformPoint,id,
this.prEncodeBuffer(sourceBuffer),
this.prEncodeBuffer(destBuffer),
["/b_query",destBuffer.asUGenInput]
);
}
inverseTransformPoint{|sourceBuffer, destBuffer, action|
actions[\inverseTransformPoint] = [nil,{action.value(destBuffer)}];
this.prSendMsg(this.inverseTransformPointMsg(sourceBuffer, destBuffer));
}
kr{|trig, inputBuffer,outputBuffer,min = 0 ,max = 1,invert = 0| kr{|trig, inputBuffer,outputBuffer,min = 0 ,max = 1,invert = 0|
min = min ? this.min; min = min ? this.min;
max = max ? this.max; max = max ? this.max;
invert = invert ? this.invert;
this.min_(min).max_(max).invert_(invert); this.min_(min).max_(max);
^FluidNormalizeQuery.kr(trig, ^FluidNormalizeQuery.kr(trig,
this, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer), this.min, this.max, this.invert); this, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer), this.min, this.max, invert);
} }

@ -1,15 +1,20 @@
FluidNoveltyFeature : FluidRTUGen { FluidNoveltyFeature : FluidRTUGen {
*kr { arg in = 0, algorithm = 0, kernelSize = 3, filterSize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384, maxKernelSize = 101, maxFilterSize = 100; *kr { arg in = 0, algorithm = 0, kernelSize = 3, filterSize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1, maxKernelSize, maxFilterSize;
^this.multiNew('control', in.asAudioRateInput(this), algorithm, kernelSize, filterSize, windowSize, hopSize, fftSize, maxFFTSize, maxKernelSize, maxFilterSize)
maxKernelSize = maxKernelSize ? kernelSize;
maxFilterSize = maxFilterSize ? filterSize;
^this.multiNew('control', in.asAudioRateInput(this), algorithm, kernelSize, maxKernelSize, filterSize, maxFilterSize, windowSize, hopSize, fftSize, maxFFTSize)
} }
checkInputs { checkInputs {
if(inputs.at(6).rate != 'scalar') { if(inputs.at(9).rate != 'scalar') {
^(": maxFFTSize cannot be modulated."); ^(": maxFFTSize cannot be modulated.");
}; };
if(inputs.at(7).rate != 'scalar') { if(inputs.at(3).rate != 'scalar') {
^(": maxKernelSize cannot be modulated."); ^(": maxKernelSize cannot be modulated.");
}; };
if(inputs.at(8).rate != 'scalar') { if(inputs.at(5).rate != 'scalar') {
^(": maxFilterSize cannot be modulated."); ^(": maxFilterSize cannot be modulated.");
}; };
^this.checkValidInputs; ^this.checkValidInputs;

@ -1,15 +1,27 @@
FluidNoveltySlice : FluidRTUGen { FluidNoveltySlice : FluidRTUGen {
*ar { arg in = 0, algorithm = 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), algorithm, kernelSize, threshold, filterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize, maxKernelSize, maxFilterSize) const <spectrum = 0;
const <mfcc = 1;
const <chroma = 2;
const <pitch = 3;
const <loudness = 4;
*ar { arg in = 0, algorithm = 0, kernelSize = 3, threshold = 0.8, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1, maxKernelSize, maxFilterSize;
maxKernelSize = maxKernelSize ? kernelSize;
maxFilterSize = maxFilterSize ? filterSize;
^this.multiNew('audio', in.asAudioRateInput(this), algorithm, kernelSize, maxKernelSize, threshold, filterSize, maxFilterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize)
} }
checkInputs { checkInputs {
if(inputs.at(8).rate != 'scalar') { if(inputs.at(11).rate != 'scalar') {
^(": maxFFTSize cannot be modulated."); ^(": maxFFTSize cannot be modulated.");
}; };
if(inputs.at(9).rate != 'scalar') { if(inputs.at(3).rate != 'scalar') {
^(": maxKernelSize cannot be modulated."); ^(": maxKernelSize cannot be modulated.");
}; };
if(inputs.at(10).rate != 'scalar') { if(inputs.at(6).rate != 'scalar') {
^(": maxFilterSize cannot be modulated."); ^(": maxFilterSize cannot be modulated.");
}; };
^this.checkValidInputs; ^this.checkValidInputs;

@ -1,5 +1,5 @@
FluidOnsetFeature : FluidRTUGen { FluidOnsetFeature : FluidRTUGen {
*kr { arg in = 0, metric = 0, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; *kr { arg in = 0, metric = 0, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1;
^this.multiNew('control', in.asAudioRateInput(this), metric, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize) ^this.multiNew('control', in.asAudioRateInput(this), metric, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize)
} }
checkInputs { checkInputs {

@ -1,5 +1,17 @@
FluidOnsetSlice : FluidRTUGen { FluidOnsetSlice : FluidRTUGen {
*ar { arg in = 0, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384;
const <power = 0;
const <hfc = 1;
const <flux = 2;
const <mkl = 3;
const <is = 4;
const <cosine = 5;
const <phase = 6;
const <wphase = 7;
const <complex = 8;
const <rcomplex = 9;
*ar { arg in = 0, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1;
^this.multiNew('audio', in.asAudioRateInput(this), metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize) ^this.multiNew('audio', in.asAudioRateInput(this), metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize)
} }
checkInputs { checkInputs {

@ -1,13 +1,13 @@
FluidPCA : FluidModelObject{ FluidPCA : FluidModelObject{
var <>numDimensions; var <>numDimensions, <>whiten;
*new {|server, numDimensions = 2| *new {|server, numDimensions = 2, whiten = 0|
^super.new(server,[numDimensions]).numDimensions_(numDimensions); ^super.new(server,[numDimensions, whiten]).numDimensions_(numDimensions).whiten_(whiten);
} }
prGetParams{ prGetParams{
^[this.id, numDimensions]; ^[this.id, numDimensions, whiten];
} }
fitMsg{|dataSet| fitMsg{|dataSet|
@ -55,7 +55,7 @@ FluidPCA : FluidModelObject{
numDimensions = numDimensions ? this.numDimensions; numDimensions = numDimensions ? this.numDimensions;
this.numDimensions_(numDimensions); this.numDimensions_(numDimensions);
^FluidPCAQuery.kr(trig ,this, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer), this.numDimensions); ^FluidPCAQuery.kr(trig ,this, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer), this.numDimensions, this.whiten);
} }
inverseTransformPointMsg{|sourceBuffer, destBuffer| inverseTransformPointMsg{|sourceBuffer, destBuffer|
@ -71,12 +71,22 @@ FluidPCA : FluidModelObject{
this.prSendMsg(this.inverseTransformPointMsg(sourceBuffer,destBuffer)); this.prSendMsg(this.inverseTransformPointMsg(sourceBuffer,destBuffer));
} }
inverseTransformMsg{|sourceDataSet, destDataSet|
^this.prMakeMsg(\inverseTransform,id,sourceDataSet.id, destDataSet.id);
}
inverseTransform{|sourceDataSet, destDataSet,action|
actions[\inverseTransform] = [nil,action];
this.prSendMsg(this.inverseTransformMsg(sourceDataSet, destDataSet));
}
} }
FluidPCAQuery : FluidRTMultiOutUGen { FluidPCAQuery : FluidRTMultiOutUGen {
*kr{ |trig, model, inputBuffer,outputBuffer,numDimensions| *kr{ |trig, model, inputBuffer,outputBuffer,numDimensions, whiten|
^this.multiNew('control',trig, model.asUGenInput, ^this.multiNew('control',trig, model.asUGenInput,
numDimensions, numDimensions, whiten,
inputBuffer.asUGenInput, outputBuffer.asUGenInput) inputBuffer.asUGenInput, outputBuffer.asUGenInput)
} }
@ -84,4 +94,4 @@ FluidPCAQuery : FluidRTMultiOutUGen {
inputs = theInputs; inputs = theInputs;
^this.initOutputs(1, rate); ^this.initOutputs(1, rate);
} }
} }

@ -1,16 +1,42 @@
FluidPitch : FluidRTMultiOutUGen { FluidPitch : FluidRTMultiOutUGen {
*kr { arg in = 0, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; const <features=#[\pitch, \confidence];
^this.multiNew('control', in.asAudioRateInput(this), algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize); classvar featuresLookup;
*initClass {
featuresLookup = Dictionary.with(*this.features.collect{|x,i| x->(1<<i)});
}
*prWarnUnrecognised {|sym| ("WARNING: FluidPitch -" + sym + "is not a recognised option").postln}
*prProcessSelect {|a|
var bits;
a.asBag.countsDo{|item,count,i|
if(count > 1) { ("Option '" ++ item ++ "' is repeated").warn};
};
bits = a.collect{ |sym|
(featuresLookup[sym.asSymbol] !? {|x| x} ?? {this.prWarnUnrecognised(sym); 0})
}.reduce{|x,y| x | y};
^bits
}
*kr { arg in = 0, select, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1;
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.features)};
^this.multiNew('control', in.asAudioRateInput(this), selectbits, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize);
} }
init {arg ...theInputs; init {arg ...theInputs;
var numChannels;
inputs = theInputs; inputs = theInputs;
^this.initOutputs(2,rate); numChannels = inputs.at(1).asBinaryDigits.sum;
^this.initOutputs(numChannels,rate);
} }
checkInputs { checkInputs {
if(inputs.at(5).rate != 'scalar') { if(inputs.at(9).rate != 'scalar') {
^(": maxFFTSize cannot be modulated."); ^(": maxFFTSize cannot be modulated.");
}; };
^this.checkValidInputs; ^this.checkValidInputs;

@ -2,36 +2,28 @@ FluidPlotterPoint {
var id, <x, <y, <>color, <>size = 1; var id, <x, <y, <>color, <>size = 1;
*new { *new {
arg id, x, y, color, size = 1; arg id, x, y, color(Color.black), size = 1;
^super.new.init(id,x,y,color,size); ^super.newCopyArgs(id,x,y,color,size);
}
init {
arg id_, x_, y_, color_, size_ = 1;
id = id_;
x = x_;
y = y_;
color = color_ ? Color.black;
size = size_;
} }
} }
FluidPlotter : FluidViewer { FluidPlotter : FluidViewer {
var <parent, <userView, <xmin, <xmax, <ymin, <ymax, <zoomxmin, <zoomxmax, <zoomymin, <zoomymax, <pointSize = 6, pointSizeScale = 1, dict_internal, <dict, shape = \circle, highlightIdentifiersArray, categoryColors; var <parent, <xmin, <xmax, <ymin, <ymax, standalone,
<zoomxmin, <zoomxmax, <zoomymin, <zoomymax,
<userView, <pointSize = 6, pointSizeScale = 1, dict_internal, <dict,
shape = \circle, highlightIdentifiersArray, categoryColors;
*new { *new {
arg parent, bounds, dict, mouseMoveAction,xmin = 0,xmax = 1,ymin = 0,ymax = 1; arg parent, bounds, dict, mouseMoveAction,
^super.new.init(parent, bounds, dict, mouseMoveAction,xmin,xmax,ymin,ymax); xmin = 0, xmax = 1, ymin = 0, ymax = 1, standalone = true;
if (parent.notNil) { standalone = false };
^super.newCopyArgs(parent, xmin, xmax, ymin, ymax, standalone)
.init(bounds, dict, mouseMoveAction);
} }
init { init {
arg parent_, bounds, dict_, mouseMoveAction, xmin_ = 0,xmax_ = 1,ymin_ = 0,ymax_ = 1; arg bounds, dict, mouseMoveAction;
parent = parent_;
xmin = xmin_;
xmax = xmax_;
ymin = ymin_;
ymax = ymax_;
zoomxmin = xmin; zoomxmin = xmin;
zoomxmax = xmax; zoomxmax = xmax;
@ -40,8 +32,8 @@ FluidPlotter : FluidViewer {
categoryColors = this.createCatColors; categoryColors = this.createCatColors;
dict_internal = Dictionary.new; dict_internal = Dictionary.new;
if(dict_.notNil,{this.dict_(dict_)}); if (dict.notNil) { this.dict = dict };
this.createPlotWindow(bounds,parent_,mouseMoveAction,dict_); this.createPlotWindow(bounds, mouseMoveAction);
} }
categories_ { categories_ {
@ -196,49 +188,61 @@ FluidPlotter : FluidViewer {
highlightIdentifiersArray = identifier.collect({arg item; item.asSymbol}); highlightIdentifiersArray = identifier.collect({arg item; item.asSymbol});
this.refresh; this.refresh;
} }
dictNotProperlyFormatted { dictNotProperlyFormatted {
"FluidPlotter: The dictionary passed in is not properly formatted.".error; "FluidPlotter: The dictionary passed in is not properly formatted.".error;
} }
createPlotWindow { createPlotWindow {
arg bounds,parent_, mouseMoveAction,dict_; arg bounds, mouseMoveAction;
var xpos, ypos;
var zoomRect = nil; var zoomRect = nil;
var zoomDragStart = Point(0,0); var zoomDragStart = Point(0,0);
if(parent_.isNil,{xpos = 0; ypos = 0},{xpos = bounds.left; ypos = bounds.top}); bounds = bounds ? Rect(0,0,800,800);
if (parent.isNil) {
if (standalone) {
parent = Window("FluidPlotter", bounds);
userView = UserView();
defer {
parent.view.layout = HLayout(userView).margins_(0).spacing_(0);
}
} {
parent = userView = UserView();
}
} {
userView = UserView(parent, bounds)
};
{ {
var reportMouseActivity; var reportMouseActivity;
parent = parent_ ? Window("FluidPlotter",bounds); userView.drawFunc = {
userView = UserView(parent,Rect(xpos,ypos,bounds.width,bounds.height)); arg viewport;
var w = viewport.bounds.width, h = viewport.bounds.height;
userView.drawFunc_({
if(dict_internal.notNil,{ if(dict_internal.notNil,{
dict_internal.keysValuesDo({ dict_internal.keysValuesDo({
arg key, pt; arg key, pt;
var pointSize_, scaledx, scaledy, color; var pointSize_, scaledx, scaledy, color;
if(highlightIdentifiersArray.notNil,{ pointSize_ = pointSize * pt.size;
if(highlightIdentifiersArray.includes(key),{ if (highlightIdentifiersArray.notNil) {
pointSize_ = pointSize * 2.3 * pt.size if (highlightIdentifiersArray.includes(key)) {
},{ pointSize_ = pointSize_ * 2.3;
pointSize_ = pointSize * pt.size };
}); };
},{
pointSize_ = pointSize * pt.size;
});
pointSize_ = pointSize_ * pointSizeScale; pointSize_ = pointSize_ * pointSizeScale;
scaledx = pt.x.linlin(zoomxmin,zoomxmax,0,userView.bounds.width,nil); scaledx = pt.x.linlin(zoomxmin,zoomxmax,0,w,nil) - (pointSize_/2);
scaledy = pt.y.linlin(zoomymax,zoomymin,0,userView.bounds.height,nil); scaledy = pt.y.linlin(zoomymax,zoomymin,0,h,nil) - (pointSize_/2);
shape.switch( shape.switch(
\square,{Pen.addRect(Rect(scaledx - (pointSize_ /2),scaledy - (pointSize_ /2),pointSize_,pointSize_))}, \square, {
\circle,{Pen.addOval(Rect(scaledx - (pointSize_ /2),scaledy - (pointSize_ /2),pointSize_,pointSize_))} Pen.addRect(Rect(scaledx,scaledy,pointSize_,pointSize_))
},
\circle, {
Pen.addOval(Rect(scaledx,scaledy,pointSize_,pointSize_))
}
); );
Pen.color_(pt.color); Pen.color_(pt.color);
@ -251,7 +255,7 @@ FluidPlotter : FluidViewer {
Pen.draw(2); Pen.draw(2);
}); });
}); });
}); };
reportMouseActivity = { reportMouseActivity = {
arg view, x, y, modifiers, buttonNumber, clickCount; arg view, x, y, modifiers, buttonNumber, clickCount;
@ -260,32 +264,32 @@ FluidPlotter : FluidViewer {
mouseMoveAction.(this,realx,realy,modifiers,buttonNumber, clickCount); mouseMoveAction.(this,realx,realy,modifiers,buttonNumber, clickCount);
}; };
userView.mouseDownAction_({ userView.mouseDownAction = {
arg view, x, y, modifiers, buttonNumber, clickCount; arg view, x, y, modifiers, buttonNumber, clickCount;
case{modifiers == 524288}{ case { modifiers.isAlt } {
zoomDragStart.x = x; zoomDragStart.x = x;
zoomDragStart.y = y; zoomDragStart.y = y;
zoomRect = Rect(zoomDragStart.x,zoomDragStart.y,0,0); zoomRect = Rect(zoomDragStart.x,zoomDragStart.y,0,0);
} }
{modifiers == 262144}{ { modifiers.isCtrl } {
this.resetZoom; this.resetZoom;
} }
{ {
reportMouseActivity.(this,x,y,modifiers,buttonNumber,clickCount); reportMouseActivity.(this,x,y,modifiers,buttonNumber,clickCount);
}; };
}); };
userView.mouseMoveAction_({ userView.mouseMoveAction = {
arg view, x, y, modifiers, buttonNumber, clickCount; arg view, x, y, modifiers, buttonNumber, clickCount;
if(modifiers == 524288,{ if (modifiers.isAlt) {
zoomRect = Rect(zoomDragStart.x,zoomDragStart.y,x - zoomDragStart.x,y - zoomDragStart.y); zoomRect = Rect(zoomDragStart.x,zoomDragStart.y,x - zoomDragStart.x,y - zoomDragStart.y);
this.refresh; this.refresh;
},{ } {
reportMouseActivity.(this,x,y,modifiers,buttonNumber,clickCount); reportMouseActivity.(this,x,y,modifiers,buttonNumber,clickCount);
}); };
}); };
userView.mouseUpAction_({ userView.mouseUpAction = {
arg view, x, y, modifiers, buttonNumber, clickCount; arg view, x, y, modifiers, buttonNumber, clickCount;
if(zoomRect.notNil,{ if(zoomRect.notNil,{
@ -312,14 +316,16 @@ FluidPlotter : FluidViewer {
}); });
reportMouseActivity.(this,x,y,modifiers,buttonNumber,clickCount); reportMouseActivity.(this,x,y,modifiers,buttonNumber,clickCount);
}); };
this.background_(Color.white); this.background_(Color.white);
if(parent_.isNil,{parent.front;}); if (standalone) { parent.front };
}.defer; }.defer;
} }
asView { ^userView }
resetZoom { resetZoom {
zoomxmin = xmin; zoomxmin = xmin;
zoomxmax = xmax; zoomxmax = xmax;

@ -1,14 +1,14 @@
FluidRobustScale : FluidModelObject { FluidRobustScale : FluidModelObject {
var <>low, <>high, <>invert; var <>low, <>high;
*new {|server, low = 25, high = 75, invert = 0| *new {|server, low = 25, high = 75|
^super.new(server,[low,high,invert]) ^super.new(server,[low,high])
.low_(low).high_(high).invert_(invert); .low_(low).high_(high);
} }
prGetParams{ prGetParams{
^[this.id,this.low,this.high,this.invert]; ^[this.id,this.low,this.high];
} }
@ -52,13 +52,31 @@ FluidRobustScale : FluidModelObject {
this.prSendMsg(this.transformPointMsg(sourceBuffer, destBuffer)); this.prSendMsg(this.transformPointMsg(sourceBuffer, destBuffer));
} }
kr{|trig, inputBuffer,outputBuffer,invert| inverseTransformMsg{|sourceDataSet, destDataSet|
^this.prMakeMsg(\inverseTransform,id,sourceDataSet.id,destDataSet.id);
}
inverseTransform{|sourceDataSet, destDataSet, action|
actions[\inverseTransform] = [nil,action];
this.prSendMsg(this.inverseTransformMsg(sourceDataSet, destDataSet));
}
inverseTransformPointMsg{|sourceBuffer, destBuffer|
^this.prMakeMsg(\inverseTransformPoint,id,
this.prEncodeBuffer(sourceBuffer),
this.prEncodeBuffer(destBuffer),
["/b_query",destBuffer.asUGenInput]
);
}
invert = invert ? this.invert; inverseTransformPoint{|sourceBuffer, destBuffer, action|
actions[\inverseRransformPoint] = [nil,{action.value(destBuffer)}];
this.prSendMsg(this.inverseTransformPointMsg(sourceBuffer, destBuffer));
}
// this.invert_(invert); kr{|trig, inputBuffer,outputBuffer,invert = 0|
^FluidRobustScaleQuery.kr(trig,this, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer), invert,); ^FluidRobustScaleQuery.kr(trig,this, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer), invert);
} }

@ -0,0 +1,136 @@
FluidSKMeans : FluidModelObject {
var clusters, threshold, maxiter;
*new {|server, numClusters = 4, encodingThreshold = 0.25, maxIter = 100|
^super.new(server,[numClusters,maxIter, encodingThreshold])
.numClusters_(numClusters)
.encodingThreshold_(encodingThreshold)
.maxIter_(maxIter);
}
numClusters_{|n| clusters = n.asInteger}
numClusters{ ^clusters }
encodingThreshold_{|t| threshold = t.asFloat}
encodingThreshold{ ^threshold }
maxIter_{|i| maxiter = i.asInteger}
maxIter{ ^maxiter }
prGetParams{^[this.id,this.numClusters, this.encodingThreshold, this.maxIter];}
fitMsg{ |dataSet| ^this.prMakeMsg(\fit,id,dataSet.id);}
fit{|dataSet, action|
actions[\fit] = [
numbers( FluidMessageResponse, _, this.numClusters ,_),
action
];
this.prSendMsg(this.fitMsg(dataSet));
}
fitPredictMsg{|dataSet, labelSet|
^this.prMakeMsg(\fitPredict, id, dataSet.id, labelSet.id)
}
fitPredict{|dataSet, labelSet,action|
actions[\fitPredict] = [
numbers(FluidMessageResponse, _, this.numClusters, _),
action
];
this.prSendMsg(this.fitPredictMsg(dataSet,labelSet));
}
predictMsg{|dataSet, labelSet|
^this.prMakeMsg(\predict, id, dataSet.id, labelSet.id)
}
predict{ |dataSet, labelSet, action|
actions[\predict] = [
numbers(FluidMessageResponse, _, this.numClusters, _),
action
];
this.prSendMsg(this.predictMsg(dataSet,labelSet));
}
predictPointMsg{|buffer|
^this.prMakeMsg(\predictPoint, id, this.prEncodeBuffer(buffer))
}
predictPoint { |buffer, action|
actions[\predictPoint] = [number(FluidMessageResponse,_,_),action];
this.prSendMsg(this.predictPointMsg(buffer))
}
fitEncodeMsg{|srcDataSet, dstDataSet|
^this.prMakeMsg(\fitEncode, id, srcDataSet.id, dstDataSet.id)
}
fitEncode{|srcDataSet, dstDataSet,action|
actions[\fitEncode] = [nil,action];
this.prSendMsg(this.fitEncodeMsg(srcDataSet,dstDataSet));
}
encodeMsg{|srcDataSet, dstDataSet|
^this.prMakeMsg(\encode, id, srcDataSet.id, dstDataSet.id)
}
encode{ |srcDataSet, dstDataSet, action|
actions[\encode] = [nil,action];
this.prSendMsg(this.encodeMsg(srcDataSet,dstDataSet));
}
encodePointMsg{ |sourceBuffer, targetBuffer|
^this.prMakeMsg(\encodePoint, id,
this.prEncodeBuffer(sourceBuffer),
this.prEncodeBuffer(targetBuffer),
["/b_query", targetBuffer.asUGenInput]);
}
encodePoint { |sourceBuffer, targetBuffer, action|
actions[\encodePoint] = [nil,{action.value(targetBuffer)}];
this.prSendMsg(this.encodePointMsg(sourceBuffer, targetBuffer));
}
getMeansMsg{|dataSet| ^this.prMakeMsg(\getMeans, id, dataSet.asUGenInput) }
getMeans{ |dataSet, action|
actions[\getMeans] = [nil, action];
this.prSendMsg(this.getMeansMsg(dataSet));
}
setMeansMsg{|dataSet| ^this.prMakeMsg(\setMeans, id, dataSet.asUGenInput) }
setMeans{ |dataSet, action|
actions[\setMeans] = [nil, action];
this.prSendMsg(this.setMeansMsg(dataSet));
}
clearMsg{ ^this.prMakeMsg(\clear, id) }
clear{ |action|
actions[\clear] = [nil, action];
this.prSendMsg(this.clearMsg);
}
kr{|trig, inputBuffer,outputBuffer|
^FluidSKMeansQuery.kr(trig,
this,
this.prEncodeBuffer(inputBuffer),
this.prEncodeBuffer(outputBuffer));
}
}
FluidSKMeansQuery : FluidRTMultiOutUGen {
*kr{ |trig, model,inputBuffer, outputBuffer |
^this.multiNew('control',trig, model.asUGenInput,inputBuffer.asUGenInput, outputBuffer.asUGenInput)
}
init { arg ... theInputs;
inputs = theInputs;
^this.initOutputs(1, rate);
}
}

@ -1,6 +1,6 @@
FluidSTFTPass : FluidRTUGen { FluidSTFTPass : FluidRTUGen {
*ar { arg in = 0, windowSize= 1024, hopSize= -1, fftSize= -1, maxFFTSize = 16384; *ar { arg in = 0, windowSize= 1024, hopSize= -1, fftSize= -1, maxFFTSize;
^this.multiNew('audio', in.asAudioRateInput(this), windowSize, hopSize, fftSize, maxFFTSize) ^this.multiNew('audio', in.asAudioRateInput(this), windowSize, hopSize = -1, fftSize = -1, maxFFTSize = -1)
} }
checkInputs { checkInputs {
if(inputs.at(4).rate != 'scalar') { if(inputs.at(4).rate != 'scalar') {

@ -30,8 +30,7 @@ FluidServerObject
*newMsg{|id, params| *newMsg{|id, params|
params = params !? {params.collect(_.asUGenInput)}; params = params !? {params.collect(_.asUGenInput)};
// ("Newms"++params).postln; ^this.prMakeMsg(\new,id,*params);
^['/cmd',this.objectClassName ++ '/new',id] ++ params
} }
*new{ |server, id, params, action, callNew = true| *new{ |server, id, params, action, callNew = true|
@ -55,10 +54,13 @@ FluidServerObject
serverCaches[this.class].remove(server,id); serverCaches[this.class].remove(server,id);
} }
prMakeMsg{|msg,id...args| *prMakeMsg{|msg,id...args|
^['/cmd',"%/%".format(this.class.objectClassName,msg),id].addAll(args); var commandName = "%/%".format(this.objectClassName,msg);
^['/cmd', this.objectClassName,commandName,id].addAll(args);
} }
prMakeMsg{|msg,id...args| ^this.class.prMakeMsg(msg,id,*args) }
freeMsg { freeMsg {
var msg; var msg;
id ?? {" % already freed".format(this.class.name).warn; ^nil}; id ?? {" % already freed".format(this.class.name).warn; ^nil};

@ -1,5 +1,5 @@
FluidSines : FluidRTMultiOutUGen { FluidSines : FluidRTMultiOutUGen {
*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; *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 = -1;
^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, detectionThreshold,birthLowThreshold, birthHighThreshold, minTrackLen, trackingMethod, trackMagRange, trackFreqRange, trackProb, windowSize, hopSize, fftSize, maxFFTSize) ^this.multiNew('audio', in.asAudioRateInput(this), bandwidth, detectionThreshold,birthLowThreshold, birthHighThreshold, minTrackLen, trackingMethod, trackMagRange, trackFreqRange, trackProb, windowSize, hopSize, fftSize, maxFFTSize)
} }
init { arg ... theInputs; init { arg ... theInputs;

@ -1,16 +1,42 @@
FluidSpectralShape : FluidRTMultiOutUGen { FluidSpectralShape : FluidRTMultiOutUGen {
*kr { arg in = 0, minFreq = 0, maxFreq = -1, rolloffPercent = 95, unit = 0, power = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384; const <features=#[\centroid,\spread,\skewness,\kurtosis,\rolloff,\flatness,\crest];
^this.multiNew('control', in.asAudioRateInput(this), minFreq, maxFreq, rolloffPercent, unit, power, windowSize, hopSize, fftSize, maxFFTSize); classvar featuresLookup;
*initClass {
featuresLookup = Dictionary.with(*this.features.collect{|x,i| x->(1<<i)});
}
*prWarnUnrecognised {|sym| ("WARNING: FluidSpectralShape -" + sym + "is not a recognised option").postln}
*prProcessSelect {|a|
var bits;
a.asBag.countsDo{|item,count,i|
if(count > 1) { ("Option '" ++ item ++ "' is repeated").warn};
};
bits = a.collect{ |sym|
(featuresLookup[sym.asSymbol] !? {|x| x} ?? {this.prWarnUnrecognised(sym); 0})
}.reduce{|x,y| x | y};
^bits
}
*kr { arg in = 0, select, minFreq = 0, maxFreq = -1, rolloffPercent = 95, unit = 0, power = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1;
var selectbits = select !? {this.prProcessSelect(select)} ?? {this.prProcessSelect(this.features)};
^this.multiNew('control', in.asAudioRateInput(this), selectbits, minFreq, maxFreq, rolloffPercent, unit, power, windowSize, hopSize, fftSize, maxFFTSize);
} }
init {arg ...theInputs; init {arg ...theInputs;
var numChannels;
inputs = theInputs; inputs = theInputs;
^this.initOutputs(7,rate); numChannels = inputs.at(1).asBinaryDigits.sum;
^this.initOutputs(numChannels,rate);
} }
checkInputs { checkInputs {
if(inputs.at(9).rate != 'scalar') { if(inputs.at(10).rate != 'scalar') {
^(": maxFFTSize cannot be modulated."); ^(": maxFFTSize cannot be modulated.");
}; };
^this.checkValidInputs; ^this.checkValidInputs;

@ -1,13 +1,11 @@
FluidStandardize : FluidModelObject { FluidStandardize : FluidModelObject {
var <>invert; *new {|server|
^super.new(server,[]);
*new {|server, invert = 0|
^super.new(server,[invert]).invert_(invert);
} }
prGetParams{ prGetParams{
^[this.id, this.invert]; ^[this.id];
} }
fitMsg{|dataSet| fitMsg{|dataSet|
@ -47,12 +45,31 @@ FluidStandardize : FluidModelObject {
this.prSendMsg(this.transformPointMsg(sourceBuffer,destBuffer)); this.prSendMsg(this.transformPointMsg(sourceBuffer,destBuffer));
} }
kr{|trig, inputBuffer,outputBuffer,invert| inverseTransformMsg{|sourceDataSet, destDataSet|
^this.prMakeMsg(\inverseTransform,id,sourceDataSet.id,destDataSet.id);
}
inverseTransform{|sourceDataSet, destDataSet, action|
actions[\inverseTransform] = [nil,action];
this.prSendMsg(this.inverseTransformMsg(sourceDataSet, destDataSet));
}
inverseTransformPointMsg{|sourceBuffer, destBuffer|
^this.prMakeMsg(\inverseTransformPoint,id,
this.prEncodeBuffer(sourceBuffer),
this.prEncodeBuffer(destBuffer),
["/b_query",destBuffer.asUGenInput]
);
}
inverseTransformPoint{|sourceBuffer, destBuffer, action|
actions[\inverseRransformPoint] = [nil,{action.value(destBuffer)}];
this.prSendMsg(this.inverseTransformPointMsg(sourceBuffer, destBuffer));
}
invert = invert ? this.invert; kr{|trig, inputBuffer,outputBuffer,invert = 0|
this.invert_(invert);
^FluidStandardizeQuery.kr(trig,this, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer), this.invert); ^FluidStandardizeQuery.kr(trig,this, this.prEncodeBuffer(inputBuffer), this.prEncodeBuffer(outputBuffer), invert);
} }
} }

@ -1,23 +1,16 @@
FluidStats : MultiOutUGen { FluidStats : MultiOutUGen {
var <channels; *kr { arg in, history;
^this.multiNew('control',*(in.asArray++history)).reshape(2,in.asArray.size);
*kr { arg in, size;
^this.multiNew('control',*(in.asArray++size));
} }
init {arg ...theInputs; init {arg ...theInputs;
inputs = theInputs; inputs = theInputs;
this.specialIndex = (inputs.size - 2).max(0); this.specialIndex = (inputs.size - 2).max(0);
// this.specialIndex.postln; ^this.initOutputs(inputs.size - 1,rate)
^this.initOutputs(inputs.size - 1,rate);
} }
checkInputs { checkInputs {
/* if(inputs.any.rate != 'control') {
^"input array input is not control rate";
};*/
^this.checkValidInputs; ^this.checkValidInputs;
} }
@ -30,7 +23,7 @@ FluidStats : MultiOutUGen {
channels = Array.fill(numChans * 2, { |i| channels = Array.fill(numChans * 2, { |i|
OutputProxy('control',this,i); OutputProxy('control',this,i);
}); });
^channels.reshape(2,numChans); ^channels
} }
numOutputs { ^(channels.size); } numOutputs { ^(channels.size); }

@ -24,38 +24,27 @@ FluidWaveformAudioLayer {
var audioBuffer, waveformColor; var audioBuffer, waveformColor;
*new { *new {
arg audioBuffer, waveformColor; arg audioBuffer, waveformColor(Color.gray);
^super.new.init(audioBuffer,waveformColor); ^super.newCopyArgs(audioBuffer, waveformColor);
}
init {
arg audioBuffer_, waveformColor_;
audioBuffer = audioBuffer_;
waveformColor = waveformColor_ ? Color.gray;
} }
draw { draw {
arg win, bounds; var path = "%%_%_FluidWaveform.wav".format(PathName.tmp,Date.localtime.stamp,UniqueID.next);
fork({ var sfv = SoundFileView();
var path = "%%_%_FluidWaveform.wav".format(PathName.tmp,Date.localtime.stamp,UniqueID.next); sfv.peakColor_(waveformColor);
var sfv; sfv.drawsBoundingLines_(false);
sfv.rmsColor_(Color.clear);
sfv.background_(Color.clear);
sfv.gridOn_(false);
forkIfNeeded({
audioBuffer.write(path,"wav"); audioBuffer.write(path,"wav");
audioBuffer.server.sync; audioBuffer.server.sync;
sfv = SoundFileView(win,bounds);
sfv.peakColor_(waveformColor);
sfv.drawsBoundingLines_(false);
sfv.rmsColor_(Color.clear);
sfv.background_(Color.clear);
sfv.readFile(SoundFile(path)); sfv.readFile(SoundFile(path));
sfv.gridOn_(false); File.delete(path)
}, AppClock);
File.delete(path); ^sfv
},AppClock);
^audioBuffer.server;
} }
} }
@ -63,100 +52,98 @@ FluidWaveformIndicesLayer : FluidViewer {
var indicesBuffer, audioBuffer, color, lineWidth; var indicesBuffer, audioBuffer, color, lineWidth;
*new { *new {
arg indicesBuffer, audioBuffer, color, lineWidth = 1; arg indicesBuffer, audioBuffer, color(Color.red), lineWidth = 1;
^super.new.init(indicesBuffer, audioBuffer, color, lineWidth); ^super.newCopyArgs(indicesBuffer, audioBuffer, color, lineWidth);
}
init {
arg indicesBuffer_, audioBuffer_, color_, lineWidth_;
indicesBuffer = indicesBuffer_;
audioBuffer = audioBuffer_;
color = color_ ? Color.red;
lineWidth = lineWidth_;
} }
draw { draw {
arg win, bounds; var userView;
var condition = CondVar();
if(audioBuffer.notNil,{ var slices_fa = nil;
fork({
indicesBuffer.numChannels.switch( var numChannels = indicesBuffer.numChannels;
1,{ if ([1, 2].includes(numChannels).not) {
indicesBuffer.loadToFloatArray(action:{ Error(
arg slices_fa; "% indicesBuffer must have either 1 or 2 channels."
UserView(win,bounds) .format(this.class)
.drawFunc_({ ).throw;
Pen.width_(lineWidth); };
slices_fa.do{ if (audioBuffer.isNil) {
arg start_samp; Error(
var x = start_samp.linlin(0,audioBuffer.numFrames,0,bounds.width); "% In order to display an indicesBuffer an audioBuffer must be included."
Pen.line(Point(x,0),Point(x,bounds.height)); .format(this.class)
Pen.color_(color); ).throw;
Pen.stroke; };
};
}); userView = UserView();
});
}, forkIfNeeded({
2,{ indicesBuffer.loadToFloatArray(action: {
indicesBuffer.loadToFloatArray(action:{ arg v;
arg slices_fa; slices_fa = v;
slices_fa = slices_fa.clump(2); condition.signalOne;
UserView(win,bounds) });
.drawFunc_({ condition.wait { slices_fa.notNil };
Pen.width_(lineWidth);
slices_fa.do{ userView.drawFunc = numChannels.switch(
arg arr; 1, {{
var start = arr[0].linlin(0,audioBuffer.numFrames,0,bounds.width); arg viewport;
var end = arr[1].linlin(0,audioBuffer.numFrames,0,bounds.width); var bounds = viewport.bounds;
Pen.addRect(Rect(start,0,end-start,bounds.height)); Pen.width_(lineWidth);
Pen.color_(color.alpha_(0.25)); slices_fa.do{
Pen.fill; arg start_samp;
}; var x = start_samp.linlin(0,audioBuffer.numFrames,0,bounds.width);
Pen.line(Point(x,0),Point(x,bounds.height));
}); Pen.color_(color);
}); Pen.stroke;
},{ }};
Error("% indicesBuffer must have either 1 nor 2 channels.".format(this.class)).throw; },
} 2, {{
); arg viewport;
},AppClock); var bounds = viewport.bounds;
^indicesBuffer.server; Pen.width_(lineWidth);
},{ slices_fa.clump(2).do{
Error("% In order to display an indicesBuffer an audioBuffer must be included.".format(this.class)).throw; arg arr;
}); var start = arr[0].linlin(0,audioBuffer.numFrames,0,bounds.width);
var end = arr[1].linlin(0,audioBuffer.numFrames,0,bounds.width);
Pen.addRect(Rect(start,0,end-start,bounds.height));
Pen.color_(color.alpha_(0.25));
Pen.fill;
}};
}
);
}, AppClock);
^userView;
} }
} }
FluidWaveformFeaturesLayer : FluidViewer { FluidWaveformFeaturesLayer : FluidViewer {
var featuresBuffer, colors, stackFeatures, normalizeFeaturesIndependently; var featuresBuffer, colors, stackFeatures, normalizeFeaturesIndependently, lineWidth;
*new { *new {
arg featuresBuffer, colors, stackFeatures = false, normalizeFeaturesIndependently = true; arg featuresBuffer, colors, stackFeatures = false, normalizeFeaturesIndependently = true, lineWidth = 1;
^super.new.init(featuresBuffer,colors,stackFeatures,normalizeFeaturesIndependently); colors = colors ?? { this.createCatColors };
}
init {
arg featuresBuffer_, colors_, stackFeatures_ = false, normalizeFeaturesIndependently_ = true;
featuresBuffer = featuresBuffer_;
normalizeFeaturesIndependently = normalizeFeaturesIndependently_;
stackFeatures = stackFeatures_;
colors = colors_ ?? {this.createCatColors};
// we'll index into it to draw, so just in case the user passed just one color, this will ensure it can be "indexed" into // we'll index into it to draw, so just in case the user passed just one color, this will ensure it can be "indexed" into
if(colors.isKindOf(SequenceableCollection).not,{colors = [colors]}); if (colors.isKindOf(SequenceableCollection).not) { colors = [colors] };
^super.newCopyArgs(
featuresBuffer,colors,stackFeatures,normalizeFeaturesIndependently, lineWidth
);
} }
draw { draw {
arg win, bounds; var userView = UserView();
var condition = CondVar();
var fa = nil;
featuresBuffer.loadToFloatArray(action:{ forkIfNeeded({
arg fa;
var minVal = 0, maxVal = 0; var minVal = 0, maxVal = 0;
var stacked_height;
if(stackFeatures,{ featuresBuffer.loadToFloatArray(action:{
stacked_height = bounds.height / featuresBuffer.numChannels; arg v;
fa = v;
condition.signalOne
}); });
condition.wait { fa.notNil };
if(normalizeFeaturesIndependently.not,{ if(normalizeFeaturesIndependently.not,{
minVal = fa.minItem; minVal = fa.minItem;
@ -165,7 +152,14 @@ FluidWaveformFeaturesLayer : FluidViewer {
fa = fa.clump(featuresBuffer.numChannels).flop; fa = fa.clump(featuresBuffer.numChannels).flop;
fork({ userView.drawFunc_({
arg viewport;
var bounds = viewport.bounds;
var stacked_height;
if (stackFeatures) {
stacked_height = bounds.height / featuresBuffer.numChannels;
};
fa.do({ fa.do({
arg channel, channel_i; arg channel, channel_i;
var maxy;// a lower value; var maxy;// a lower value;
@ -184,22 +178,22 @@ FluidWaveformFeaturesLayer : FluidViewer {
maxVal = channel.maxItem; maxVal = channel.maxItem;
}); });
channel = channel.resamp1(bounds.width).linlin(minVal,maxVal,miny,maxy); channel = channel.resamp1(bounds.width)
.linlin(minVal,maxVal,miny,maxy);
UserView(win,bounds)
.drawFunc_({ Pen.width = lineWidth;
Pen.moveTo(Point(0,channel[0])); Pen.moveTo(Point(0,channel[0]));
channel[1..].do{ channel[1..].do{
arg val, i; arg val, i;
Pen.lineTo(Point(i+1,val)); Pen.lineTo(Point(i+1,val));
}; };
Pen.color_(colors[channel_i % colors.size]); Pen.color_(colors[channel_i % colors.size]);
Pen.stroke; Pen.stroke;
});
}); });
},AppClock); });
}); }, AppClock);
^featuresBuffer.server;
^userView;
} }
} }
@ -208,27 +202,73 @@ FluidWaveformImageLayer {
*new { *new {
arg imageBuffer, imageColorScheme = 0, imageColorScaling = 0, imageAlpha = 1; arg imageBuffer, imageColorScheme = 0, imageColorScaling = 0, imageAlpha = 1;
^super.new.init(imageBuffer,imageColorScheme,imageColorScaling,imageAlpha); ^super.newCopyArgs(
imageBuffer, imageColorScheme, imageColorScaling, imageAlpha
);
} }
init { draw {
arg imageBuffer_, imageColorScheme_ = 0, imageColorScaling_ = 0, imageAlpha_ = 1; var colors = this.prGetColorsFromScheme(imageColorScheme);
var condition = CondVar();
var vals = nil;
var userView = UserView();
forkIfNeeded({
var img = Image(imageBuffer.numFrames, imageBuffer.numChannels);
imageBuffer.loadToFloatArray(action: {
arg v;
vals = v;
condition.signalOne;
});
condition.wait { vals.notNil };
imageBuffer = imageBuffer_; imageColorScaling.switch(
imageColorScheme = imageColorScheme_; FluidWaveform.lin,{
imageColorScaling = imageColorScaling_; var minItem = vals.minItem;
imageAlpha = imageAlpha_; vals = (vals - minItem) / (vals.maxItem - minItem);
vals = (vals * 255).asInteger;
},
FluidWaveform.log,{
vals = (vals + 1e-6).log;
vals = vals.linlin(vals.minItem,vals.maxItem,0.0,255.0).asInteger;
},
{
"% colorScaling argument % is invalid.".format(thisMethod,imageColorScaling).warn;
}
);
vals.do{
arg val, index;
img.setColor(colors[val], index.div(imageBuffer.numChannels), imageBuffer.numChannels - 1 - index.mod(imageBuffer.numChannels));
};
userView.drawFunc = {
arg viewport;
var bounds = viewport.bounds;
img.drawInRect(
Rect(0, 0, bounds.width, bounds.height),
fraction: imageAlpha
);
};
}, AppClock);
^userView;
} }
draw { loadColorFile {
arg win, bounds; arg filename;
var colors; ^CSVFileReader.readInterpret(FluidFilesPath("../color-schemes/%.csv".format(filename))).collect{
arg row;
Color.fromArray(row);
}
}
prGetColorsFromScheme {
arg imageColorScheme;
var colors;
if(imageColorScheme.isKindOf(Color),{ if(imageColorScheme.isKindOf(Color),{
// "imageColorScheme is a kind of Color".postln;
colors = 256.collect{ colors = 256.collect{
arg i; arg i;
Color(imageColorScheme.red,imageColorScheme.green,imageColorScheme.blue,i.linlin(0,255,0.0,1.0)); imageColorScheme.copy.alpha_(i.linlin(0,255,0.0,1.0));
}; };
},{ },{
imageColorScheme.switch( imageColorScheme.switch(
@ -253,156 +293,90 @@ FluidWaveformImageLayer {
); );
}); });
imageBuffer.loadToFloatArray(action:{ ^colors;
arg vals;
fork({
var img = Image(imageBuffer.numFrames,imageBuffer.numChannels);
imageColorScaling.switch(
FluidWaveform.lin,{
var minItem = vals.minItem;
vals = (vals - minItem) / (vals.maxItem - minItem);
vals = (vals * 255).asInteger;
},
FluidWaveform.log,{
vals = (vals + 1e-6).log;
vals = vals.linlin(vals.minItem,vals.maxItem,0.0,255.0).asInteger;
// vals.postln;
},
{
"% colorScaling argument % is invalid.".format(thisMethod,imageColorScaling).warn;
}
);
// colors.postln;
vals.do{
arg val, index;
img.setColor(colors[val], index.div(imageBuffer.numChannels), imageBuffer.numChannels - 1 - index.mod(imageBuffer.numChannels));
};
UserView(win,bounds)
.drawFunc_{
img.drawInRect(Rect(0,0,bounds.width,bounds.height),fraction:imageAlpha);
};
},AppClock);
});
^imageBuffer.server;
}
loadColorFile {
arg filename;
^CSVFileReader.readInterpret(FluidFilesPath("../color-schemes/%.csv".format(filename))).collect{
arg row;
Color.fromArray(row);
}
} }
} }
FluidWaveform : FluidViewer { FluidWaveform : FluidViewer {
classvar <lin = 0, <log = 1; classvar <lin = 0, <log = 1;
var <win, bounds, display_bounds, <layers; var <parent, bounds, standalone, view, <layers;
*new { *new {
arg audioBuffer, indicesBuffer, featuresBuffer, parent, bounds, lineWidth = 1, waveformColor, stackFeatures = false, imageBuffer, imageColorScheme = 0, imageAlpha = 1, normalizeFeaturesIndependently = true, imageColorScaling = 0; arg audioBuffer, indicesBuffer, featuresBuffer,
^super.new.init(audioBuffer,indicesBuffer, featuresBuffer, parent, bounds, lineWidth, waveformColor,stackFeatures,imageBuffer,imageColorScheme,imageAlpha,normalizeFeaturesIndependently,imageColorScaling); parent, bounds,
lineWidth = 1, waveformColor, stackFeatures = false,
imageBuffer, imageColorScheme = 0, imageAlpha = 1,
normalizeFeaturesIndependently = true, imageColorScaling = 0,
standalone = true;
if (parent.notNil) { standalone = false };
^super.newCopyArgs(parent, bounds, standalone)
.init(audioBuffer, indicesBuffer, featuresBuffer,
lineWidth, waveformColor, stackFeatures,
imageBuffer, imageColorScheme, imageAlpha,
normalizeFeaturesIndependently, imageColorScaling
);
} }
init { init {
arg audio_buf, slices_buf, feature_buf, parent_, bounds_, lineWidth = 1, waveformColor,stackFeatures = false, imageBuffer, imageColorScheme = 0, imageAlpha = 1, normalizeFeaturesIndependently = true, imageColorScaling = 0; arg audio_buf, slices_buf, feature_buf,
layers = List.new; lineWidth = 1, waveformColor, stackFeatures = false,
imageBuffer, imageColorScheme = 0, imageAlpha = 1,
fork({ normalizeFeaturesIndependently = true, imageColorScaling = 0;
var plotImmediately = false; var plotImmediately = false;
bounds = bounds_;
waveformColor = waveformColor ? Color(*0.6.dup(3)); layers = List.new;
waveformColor = waveformColor ? Color(*0.6.dup(3));
if(bounds.isNil && imageBuffer.notNil,{ if (imageBuffer.notNil) {
this.addImageLayer(imageBuffer, imageColorScheme, imageColorScaling, imageAlpha);
if(standalone && bounds.isNil) {
bounds = Rect(0,0,imageBuffer.numFrames,imageBuffer.numChannels); bounds = Rect(0,0,imageBuffer.numFrames,imageBuffer.numChannels);
}); };
plotImmediately = true;
bounds = bounds ? Rect(0,0,800,200); };
if(parent_.isNil,{
win = Window("FluidWaveform",bounds);
win.background_(Color.white);
display_bounds = Rect(0,0,bounds.width,bounds.height);
},{
win = parent_;
display_bounds = bounds;
});
if(imageBuffer.notNil,{
this.addImageLayer(imageBuffer,imageColorScheme,imageColorScaling,imageAlpha);
imageBuffer.server.sync;
plotImmediately = true;
});
if(audio_buf.notNil,{ if (audio_buf.notNil) {
this.addAudioLayer(audio_buf,waveformColor); this.addAudioLayer(audio_buf, waveformColor);
audio_buf.server.sync; plotImmediately = true;
plotImmediately = true; };
});
if(feature_buf.notNil,{ if (feature_buf.notNil) {
this.addFeaturesLayer(feature_buf,this.createCatColors,stackFeatures,normalizeFeaturesIndependently); this.addFeaturesLayer(feature_buf, this.createCatColors, stackFeatures, normalizeFeaturesIndependently, lineWidth);
feature_buf.server.sync; plotImmediately = true;
plotImmediately = true; };
});
if(slices_buf.notNil,{ if (slices_buf.notNil) {
this.addIndicesLayer(slices_buf,audio_buf,Color.red,lineWidth); this.addIndicesLayer(slices_buf, audio_buf, Color.red, lineWidth);
slices_buf.server.sync; plotImmediately = true;
plotImmediately = true; };
});
if(plotImmediately,{this.front;}); if (plotImmediately) { this.front };
},AppClock);
} }
addImageLayer { addImageLayer {
arg imageBuffer, imageColorScheme = 0, imageColorScaling = 0, imageAlpha = 1; arg imageBuffer, imageColorScheme = 0, imageColorScaling = 0, imageAlpha = 1;
var l = FluidWaveformImageLayer(imageBuffer,imageColorScheme,imageColorScaling,imageAlpha); var l = FluidWaveformImageLayer(imageBuffer, imageColorScheme, imageColorScaling, imageAlpha);
// l.postln;
layers.add(l); layers.add(l);
// layers.postln;
// l.draw(win,display_bounds);
} }
addAudioLayer { addAudioLayer {
arg audioBuffer, waveformColor; arg audioBuffer, waveformColor;
var l = FluidWaveformAudioLayer(audioBuffer,waveformColor); var l = FluidWaveformAudioLayer(audioBuffer, waveformColor);
// l.postln;
layers.add(l); layers.add(l);
// layers.postln;
// l.draw(win,display_bounds);
} }
addIndicesLayer { addIndicesLayer {
arg indicesBuffer, audioBuffer, color, lineWidth = 1; arg indicesBuffer, audioBuffer, color, lineWidth = 1;
var l = FluidWaveformIndicesLayer(indicesBuffer,audioBuffer,color,lineWidth); var l = FluidWaveformIndicesLayer(indicesBuffer,audioBuffer,color,lineWidth);
// l.postln;
layers.add(l); layers.add(l);
// layers.postln;
// l.draw(win,display_bounds);
} }
addFeaturesLayer { addFeaturesLayer {
arg featuresBuffer, colors, stackFeatures = false, normalizeFeaturesIndependently = true; arg featuresBuffer, colors, stackFeatures = false, normalizeFeaturesIndependently = true, lineWidth = 1;
var l = FluidWaveformFeaturesLayer(featuresBuffer,colors,stackFeatures,normalizeFeaturesIndependently); var l = FluidWaveformFeaturesLayer(featuresBuffer,colors,stackFeatures,normalizeFeaturesIndependently, lineWidth);
// l.postln;
layers.add(l); layers.add(l);
// layers.postln;
// l.draw(win,display_bounds);
} }
addLayer { addLayer {
@ -411,26 +385,50 @@ FluidWaveform : FluidViewer {
} }
front { front {
this.prMakeView;
fork({ fork({
this.refresh;
if (standalone) { parent.front };
}, AppClock);
}
UserView(win,display_bounds) // defer({}, nil) forks if not already running on the AppClock
.drawFunc_{ refresh {
Pen.fillColor_(Color.white); forkIfNeeded({
Pen.addRect(Rect(0,0,bounds.width,bounds.height)); var noView = if (view.isNil) { true } { view.isClosed };
Pen.fill; if (noView) { this.prMakeView };
}; view.removeAll;
view.layout = StackLayout().mode_(\stackAll);
layers.do{ layers.do {
arg layer; arg layer, n;
// layer.postln; var layerView;
layer.draw(win,display_bounds).sync; layerView = layer.draw;
view.layout.add(layerView);
view.layout.index = view.layout.index + 1;
}; };
win.front; view.refresh;
},AppClock); }, AppClock);
} }
close { close {
win.close; parent.close;
} }
}
prMakeView {
if (parent.isNil) {
if (standalone) {
parent = Window("FluidWaveform", bounds: bounds ? Rect(0,0,800,200));
parent.background_(Color.white);
view = parent.view;
} {
parent = view = View();
view.background_(Color.white);
}
} {
view = View(parent, bounds);
view.background_(Color.white);
};
}
asView { ^view }
}

@ -43,7 +43,7 @@ do the whole process in one go!
var indices = Buffer(s); // a buffer for saving the discovered indices into var indices = Buffer(s); // a buffer for saving the discovered indices into
// play around the the threshold anad feature (see help file) to get differet slicing results // play around the the threshold anad feature (see help file) to get differet slicing results
FluidBufNoveltySlice.processBlocking(s,buffer,indices:indices,feauture:0,threshold:0.5,action:{ FluidBufNoveltySlice.processBlocking(s,buffer,indices:indices,algorithm:0,threshold:0.5,action:{
"% slices found".format(indices.numFrames).postln; "% slices found".format(indices.numFrames).postln;
"average duration in seconds: %".format(buffer.duration/indices.numFrames).postln; "average duration in seconds: %".format(buffer.duration/indices.numFrames).postln;
action.(buffer,indices); action.(buffer,indices);

@ -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 improvements!

@ -1,4 +1,4 @@
TITLE:: FluidBufNNDSVD TITLE:: FluidBufNMFSeed
summary:: Non-Negative Double Singular Value Decomposition on a Buffer summary:: Non-Negative Double Singular Value Decomposition on a Buffer
categories:: Libraries>FluidCorpusManipulation categories:: Libraries>FluidCorpusManipulation
related:: Classes/FluidBufNMF related:: Classes/FluidBufNMF
@ -79,7 +79,7 @@ b = Buffer.read(s,FluidFilesPath("Nicol-LoopE-M.wav"));
//how many bases do I need to decompose the buffer with 90% accuracy //how many bases do I need to decompose the buffer with 90% accuracy
( (
Routine{ Routine{
FluidBufNNDSVD.process(s, b, ~bases, ~activations, coverage: 0.9, method: 1).wait; FluidBufNMFSeed.process(s, b, ~bases, ~activations, coverage: 0.9, method: 1).wait;
"% bases".format(~bases.numChannels).postln; "% bases".format(~bases.numChannels).postln;
}.play; }.play;
) )
@ -89,7 +89,7 @@ Routine{
//try the same process with less accuracy //try the same process with less accuracy
( (
Routine{ Routine{
FluidBufNNDSVD.process(s, b, ~bases, ~activations, coverage: 0.5).wait; FluidBufNMFSeed.process(s, b, ~bases, ~activations, coverage: 0.5).wait;
"% bases".format(~bases.numChannels).postln; "% bases".format(~bases.numChannels).postln;
}.play }.play
) )

@ -53,7 +53,7 @@ code::
~mlp = FluidMLPClassifier(s); ~mlp = FluidMLPClassifier(s);
// load a model that has been pre-trained to classify between a tone and noise, simple, i know, but... // load a model that has been pre-trained to classify between a tone and noise, simple, i know, but...
~mlp.read(FluidFilesPath("../Resources/bufToKrExample.json")); ~mlp.read(FluidFilesPath("../../Resources/bufToKrExample.json"));
// can be used to demonstrate that... // can be used to demonstrate that...
( (

@ -14,7 +14,7 @@ METHOD:: new
Creates a new instance of FluidPlotter Creates a new instance of FluidPlotter
ARGUMENT:: parent ARGUMENT:: parent
A parent view to embed the FluidPlotter in. If no parent is passed, FluidPlotter will create a window for itself at the given bounds. A parent view to embed the FluidPlotter in. If no parent is passed, FluidPlotter will create a window for itself at the given bounds. To create a view without STRONG::parent:: and STRONG::bounds:: (e.g. for GUIs with link::Guides/GUI-Layout-Management::), see the STRONG::standalone:: argument below.
ARGUMENT:: bounds ARGUMENT:: bounds
Where to show the FluidPlotter, either within the parent or on the screen (if no parent is passed). Where to show the FluidPlotter, either within the parent or on the screen (if no parent is passed).
@ -37,6 +37,9 @@ Minimum of the Y range to display. Default is 0.
ARGUMENT:: ymax ARGUMENT:: ymax
Maximum of the Y range to display. Default is 1. Maximum of the Y range to display. Default is 1.
ARGUMENT:: standalone
If strong::false::, creates a link::Classes/View:: without parent or bounds, so that it can be used as part of a larger GUI, e.g. with link::Guides/GUI-Layout-Management::.
returns:: returns::
An instance of FluidPlotter An instance of FluidPlotter
@ -308,6 +311,36 @@ w = Window("test",Rect(50,50,800,600)).front;
},xmin:20,xmax:20000,ymin:-130,ymax:0); },xmin:20,xmax:20000,ymin:-130,ymax:0);
) )
// two FluidPlotter side by side with standalone=false
(
Window.closeAll;
// make two different data dictionaries
d = 2.collect { Dictionary.newFrom([
"cols",2,
"data",Dictionary.newFrom(Array.fill(200,{
arg i;
var return;
if((i%2) == 0,{
return = "example-%".format((i/2).asInteger);
},{
return = [exprand(20,20000),rrand(-130,0)];
});
return;
}))
])};
w = Window("test",Rect(50,50,1200,600)).front;
// make two plotters, one for each data dictionary
~fluidPlotters = d.collect { |data|
FluidPlotter(dict: data, standalone: false, mouseMoveAction:{
arg view, x, y, modifiers;
[view, x, y, modifiers].postln;
"".postln;
},xmin:20,xmax:20000,ymin:-130,ymax:0)
};
// assign plotters to window's layout
w.layout = HLayout(~fluidPlotters[0], ~fluidPlotters[1]);
)
// you can make an empty one and then set the dict later // you can make an empty one and then set the dict later
( (
Window.closeAll; Window.closeAll;

@ -21,7 +21,7 @@ ARGUMENT:: featuresBuffer
A link::Classes/Buffer:: containing features to plot over the waveform. If this link::Classes/Buffer:: is multiple channels, it will plot each channel as a separate feature. A link::Classes/Buffer:: containing features to plot over the waveform. If this link::Classes/Buffer:: is multiple channels, it will plot each channel as a separate feature.
ARGUMENT:: parent ARGUMENT:: parent
A link::Classes/Window:: to place this FluidWaveform in. If STRONG::nil::, FluidWaveform will make its own window using the STRONG::bounds:: argument. A link::Classes/Window:: to place this FluidWaveform in. If STRONG::nil::, FluidWaveform will make its own window using the STRONG::bounds:: argument. To create a view without parent and bounds (e.g. for GUIs with link::Guides/GUI-Layout-Management::), see the STRONG::standalone:: argument below.
ARGUMENT:: bounds ARGUMENT:: bounds
A link::Classes/Rect:: of where to place the FluidWaveform. If parent is STRONG::nil::, these bounds will be used to create a new link::Classes/Window::. If parent is not STRONG::nil::, these bounds will be used to place this FluidWaveform in the parent. A link::Classes/Rect:: of where to place the FluidWaveform. If parent is STRONG::nil::, these bounds will be used to create a new link::Classes/Window::. If parent is not STRONG::nil::, these bounds will be used to place this FluidWaveform in the parent.
@ -57,6 +57,9 @@ Boolean. All the features in STRONG::featureBuf:: need to be normalized for plot
ARGUMENT:: imageColorScaling ARGUMENT:: imageColorScaling
An integer indicating how to scale the values in strong::imageBuffer:: before applying the strong::imageColorScheme::. 0 indicates linear scaling, 1 indicates logarithmic scaling. The default is 1. These integers can also be accessed via FluidWaveform.lin and FluidWaveform.log. An integer indicating how to scale the values in strong::imageBuffer:: before applying the strong::imageColorScheme::. 0 indicates linear scaling, 1 indicates logarithmic scaling. The default is 1. These integers can also be accessed via FluidWaveform.lin and FluidWaveform.log.
ARGUMENT:: standalone
If strong::false::, creates a link::Classes/View:: without parent or bounds, so that it can be used as part of a larger GUI, e.g. with link::Guides/GUI-Layout-Management::.
returns:: A new instance of FluidWaveform. returns:: A new instance of FluidWaveform.
METHOD:: lin METHOD:: lin
@ -109,6 +112,9 @@ See this argument in the class method 'new' above.
ARGUMENT:: normalizeFeaturesIndependently ARGUMENT:: normalizeFeaturesIndependently
See this argument in the class method 'new' above. See this argument in the class method 'new' above.
ARGUMENT:: lineWidth
See this argument in the class method 'new' above.
METHOD:: addImageLayer METHOD:: addImageLayer
Add a grapic layer that shows an image derived from a buffer. Add a grapic layer that shows an image derived from a buffer.
@ -127,11 +133,14 @@ See this argument in the class method 'new' above.
METHOD:: front METHOD:: front
Similar to link::Classes/Window::'s strong::front:: method. Shows the FluidWaveform. This must be called after layers have been added in order to see the layers. Similar to link::Classes/Window::'s strong::front:: method. Shows the FluidWaveform. This must be called after layers have been added in order to see the layers.
METHOD:: refresh
Similar to link::Classes/Window::'s strong::refresh:: method. Redraws all FluidWaveform layers. Has to be called after link::Classes/FluidWaveform#-addLayer:: in order to see the new layer.
METHOD:: close METHOD:: close
Close the FluidWaveform window. If parent is not STRONG::nil::, this method will close the parent window. Close the FluidWaveform window. If parent is not STRONG::nil::, this method will close the parent window.
METHOD:: win METHOD:: parent
returns:: The FluidWaveform window. If parent is not STRONG::nil::, this method will return the parent window. returns:: The FluidWaveform window. If parent is not STRONG::nil::, this method will return the parent window.
@ -154,6 +163,14 @@ FluidWaveform(~drums,parent:w,bounds:Rect(100,100,800,300));
w.front; w.front;
) )
// put two of them in another window's layout
(
w = Window("FluidWaveform Test",Rect(0,0,1000,500));
f = 2.collect{FluidWaveform(~drums, standalone: false)};
w.view.layout = VLayout(f[0], f[1]);
w.front;
)
// show spectrogram // show spectrogram
~mags = Buffer(s); ~mags = Buffer(s);
FluidBufSTFT.processBlocking(s,~drums,magnitude:~mags,action:{"stft done".postln;}); FluidBufSTFT.processBlocking(s,~drums,magnitude:~mags,action:{"stft done".postln;});
@ -249,7 +266,7 @@ FluidBufPitch.processBlocking(s,~audio,features:~pitch_analysis,action:{"done".p
~fw.addAudioLayer(~audio,Color(1,1,1,0.5)); ~fw.addAudioLayer(~audio,Color(1,1,1,0.5));
~fw.addIndicesLayer(~indices,~audio,Color.black); ~fw.addIndicesLayer(~indices,~audio,Color.black);
~fw.addFeaturesLayer(~pitch_analysis,[Color.cyan,Color.magenta]); ~fw.addFeaturesLayer(~pitch_analysis,[Color.cyan,Color.magenta]);
~fw.front; // // if no buffers of any kind are passed, then you'll need to call `.front` after adding layers ~fw.front;
) )
( (
@ -262,7 +279,7 @@ FluidBufPitch.processBlocking(s,~audio,features:~pitch_analysis,action:{"done".p
) )
// add one more // add one more
~fw.addFeaturesLayer(~pitch_analysis,[Color.cyan,Color.yellow]).front; // <<<----- notice the `.front` here to update display after adding this layer ~fw.addFeaturesLayer(~pitch_analysis,[Color.cyan,Color.yellow]).refresh; // <<<----- notice the `.refresh` here to update display after adding this layer
// check how many layers // check how many layers
~fw.layers.size ~fw.layers.size
@ -301,4 +318,4 @@ s.waitForBoot{
~fw.front; ~fw.front;
} }
) )
:: ::

@ -23,7 +23,7 @@ table::
## strong::on signals:: || strong:: on buffers:: || strong::digest:: ## strong::on signals:: || strong:: on buffers:: || strong::digest::
## Link::Classes/FluidAmpGate:: || LINK:: Classes/FluidBufAmpGate:: || Events from amplitude enevelope ## Link::Classes/FluidAmpGate:: || LINK:: Classes/FluidBufAmpGate:: || Events from amplitude enevelope
## LINK:: Classes/FluidAmpSlice:: || Link::Classes/FluidBufAmpSlice:: || Onsets from amplitude envelope ## LINK:: Classes/FluidAmpSlice:: || Link::Classes/FluidBufAmpSlice:: || Onsets from amplitude envelope
## link::Classes/FluidOnsetSlice::||link::Classes/FluidBufOnsetSlice::||Spectral onset detecor ## link::Classes/FluidOnsetSlice::||link::Classes/FluidBufOnsetSlice::||Spectral onset detector
## link::Classes/FluidTransientSlice::||link::Classes/FluidBufTransientSlice::||Transient model onset detector ## link::Classes/FluidTransientSlice::||link::Classes/FluidBufTransientSlice::||Transient model onset detector
## LINK:: Classes/FluidNoveltySlice::||LINK:: Classes/FluidBufNoveltySlice::|| Novelty based onset detection on a choice of descriptors ## LINK:: Classes/FluidNoveltySlice::||LINK:: Classes/FluidBufNoveltySlice::|| Novelty based onset detection on a choice of descriptors
:: ::
@ -39,8 +39,11 @@ table::
##link::Classes/FluidSpectralShape:: || link::Classes/FluidBufSpectralShape:: || Seven Spectral Shape Descriptors ##link::Classes/FluidSpectralShape:: || link::Classes/FluidBufSpectralShape:: || Seven Spectral Shape Descriptors
##link::Classes/FluidChroma:: || link::Classes/FluidBufChroma:: || Pitch Classes Descriptor ##link::Classes/FluidChroma:: || link::Classes/FluidBufChroma:: || Pitch Classes Descriptor
##link::Classes/FluidNMFMatch:: || || Real-time activation of link::Classes/FluidBufNMF##NMF:: bases ##link::Classes/FluidNMFMatch:: || || Real-time activation of link::Classes/FluidBufNMF##NMF:: bases
## || link::Classes/FluidBufNNDSVD::|| Quick starting estimates for link::Classes/FluidBufNMF##NMF:: components using Singular Value Decomposition ## || link::Classes/FluidBufNMFSeed::|| Quick starting estimates for link::Classes/FluidBufNMF##NMF:: components using Singular Value Decomposition
## || link::Classes/FluidBufSTFT:: || Perform STFT / ISTFT on link::Classes/Buffer::s ## || link::Classes/FluidBufSTFT:: || Perform STFT / ISTFT on link::Classes/Buffer::s
##link::Classes/FluidAmpFeature:: || link::Classes/FluidBufAmpFeature:: || Detrending Amplitude Envelope Descriptor
##link::Classes/FluidNoveltyFeature:: || link::Classes/FluidBufNoveltyFeature:: || Novelty descriptor based on a choice of analysis descriptors
##link::Classes/FluidOnsetFeature:: || link::Classes/FluidBufOnsetFeature:: || Descriptor comparing spectral frames using a choice of comparisons
:: ::
section:: Decompose Audio section:: Decompose Audio
@ -96,6 +99,7 @@ table::
##link::Classes/FluidPCA:: || Principal Component Analysis for preprocessing and dimension reduction ##link::Classes/FluidPCA:: || Principal Component Analysis for preprocessing and dimension reduction
##link::Classes/FluidMDS:: || Multidimensional Scaling for dimension reduction ##link::Classes/FluidMDS:: || Multidimensional Scaling for dimension reduction
##link::Classes/FluidKMeans:: || K-Means clustering ##link::Classes/FluidKMeans:: || K-Means clustering
##link::Classes/FluidSKMeans:: || Spherical K-Means clustering
##link::Classes/FluidUMAP:: || Dimension reduction with UMAP algorithm ##link::Classes/FluidUMAP:: || Dimension reduction with UMAP algorithm
##link::Classes/FluidGrid:: || Transform a data set of two dimensional points into a two dimensional grid using the Munkres Algorithm. ##link::Classes/FluidGrid:: || Transform a data set of two dimensional points into a two dimensional grid using the Munkres Algorithm.
:: ::

@ -1,66 +0,0 @@
TITLE:: Fluid Decomposition Toolbox
SUMMARY:: An overview of the FluCoMa toolbox for signal decomposition
CATEGORIES:: Libraries>FluidCorpusManipulation
The Fluid Decomposition toolbox provides an open-ended, loosely coupled set of objects to break up and analyse sound in terms of slices (segments in time), layers (superpositions in time and frequency) and objects (configurable or discoverable patterns in sound). Almost all objects have audio-rate and buffer-based versions.
This toolbox was made possible thanks to the FluCoMa project ( LINK::http://www.flucoma.org/:: ) funded by the European Research Council ( LINK::https://erc.europa.eu/:: ) under the European Unions Horizon 2020 research and innovation programme (grant agreement No 725899).
SECTION::Slices
Slice by amplitude envelope:
LINK::Classes/FluidAmpSlice:: LINK::Classes/FluidBufAmpSlice::
Slice by onsets in the spectral domain:
LINK::Classes/FluidOnsetSlice:: LINK::Classes/FluidBufOnsetSlice::
Slice by estimated novelty on a choice of features:
LINK::Classes/FluidNoveltySlice:: LINK::Classes/FluidBufNoveltySlice::
Slice by transient modelling:
LINK::Classes/FluidTransientSlice:: LINK::Classes/FluidBufTransientSlice::
SECTION::Layers
Decompose into sines + residual
LINK::Classes/FluidSines:: LINK::Classes/FluidBufSines::
Decompose into transients + residual
LINK::Classes/FluidTransients:: LINK::Classes/FluidBufTransients::
Decompose into 'harmonic' and 'percussive' layers
LINK::Classes/FluidHPSS:: LINK::Classes/FluidBufHPSS::
SECTION::Objects
Use Nonnegative Matrix Factorisation to explore and decompose sounds
LINK::Classes/FluidBufNMF:: LINK::Classes/FluidNMFFilter:: LINK::Classes/FluidNMFMatch::
SECTION::Descriptors
Report amplitude and peak, or r128 loudness and true peak
LINK::Classes/FluidLoudness:: LINK::Classes/FluidBufLoudness::
A suite of pitch estimators
LINK::Classes/FluidPitch:: LINK::Classes/FluidBufPitch::
Energy across Mel bands
LINK::Classes/FluidMelBands:: LINK::Classes/FluidBufMelBands::
Mel Frequency Ceptstral Coefficients
LINK::Classes/FluidMFCC:: LINK::Classes/FluidBufMFCC::
Summary measures of spectral shape
LINK::Classes/FluidSpectralShape:: LINK::Classes/FluidBufSpectralShape::
Statistics of buffers
LINK::Classes/FluidBufStats::
SECTION::Utility
Copy, slice, stack, mix concatenate. All the things you've wanted to do with buffers...
LINK::Classes/FluidBufCompose::
A tutorial object to experiment with multithreading in FluidBuf* objects
LINK::Classes/FluidBufThreadDemo::

@ -0,0 +1,28 @@
# 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 Unions Horizon 2020 research and innovation programme
# (grant agreement No 725899).
cmake_minimum_required(VERSION 3.18)
file(GLOB helpfiles "${ROOT}/help/*")
file(GLOB abstractions "${ROOT}/abstractions/*")
file(GLOB externals "${ROOT}/pd_objects/*")
set(devfolder "${ROOT}/dev")
file(REMOVE_RECURSE ${devfolder})
file(MAKE_DIRECTORY ${devfolder})
foreach(item IN LISTS helpfiles abstractions externals)
get_filename_component(item_name "${item}" NAME)
file(CREATE_LINK "${item}" "${devfolder}/${item_name}" SYMBOLIC)
endforeach()
file(CREATE_LINK "${CORE_SRC}/Resources/" "${devfolder}/Resources" SYMBOLIC)
file(CREATE_LINK "${BINARIES}/Resources/" "${devfolder}/Resources" SYMBOLIC)
file(CREATE_LINK "${CORE_SRC}/Resources/" "${devfolder}/Resources" SYMBOLIC)
file(CREATE_LINK "${CORE_SRC}/Resources/" "${devfolder}/Resources" SYMBOLIC)
file(CREATE_LINK "${CORE_SRC}/Resources/" "${devfolder}/Resources" SYMBOLIC)

@ -0,0 +1,129 @@
# 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 Unions Horizon 2020 research and innovation programme
# (grant agreement No 725899).
include(FluidClientStub)
function(make_external_name client header var)
set(${var} Fluid${client} PARENT_SCOPE)
endfunction()
function(add_sc_extension PLUGIN FILENAME)
add_library(${PLUGIN} MODULE ${FILENAME})
if(MSVC)
target_compile_options(${PLUGIN} PRIVATE /external:W0 /W3 /bigobj)
else()
target_compile_options(${PLUGIN} PRIVATE
-Wall -Wextra -Wpedantic -Wreturn-type -Wconversion
)
#GCC doesn't have Wno-c++11-narrowing
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(${PLUGIN} PRIVATE -Wno-c++11-narrowing)
endif()
endif()
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}
PRIVATE
FLUID_DECOMPOSITION
FLUID_SC_WRAPPER
HISSTools_FFT
)
target_include_directories(
${PLUGIN}
PRIVATE
"${LOCAL_INCLUDES}"
"${FLUID_VERSION_PATH}"
)
file(GLOB_RECURSE FLUID_SC_HEADERS CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/include/wrapper/*.hpp")
target_sources(
${PLUGIN} PUBLIC ${FLUID_SC_HEADERS}
)
target_include_directories(
${PLUGIN}
SYSTEM PRIVATE
"${SC_PATH}/include/plugin_interface"
"${SC_PATH}/include/common"
"${SC_PATH}/common"
"${SC_PATH}/external_libraries/boost" #we need boost::align for deallocating buffer memory :-(
)
get_property(HEADERS TARGET FLUID_DECOMPOSITION PROPERTY INTERFACE_SOURCES)
source_group(TREE "${flucoma-core_SOURCE_DIR}/include" FILES ${HEADERS})
source_group(TREE "${CMAKE_SOURCE_DIR}/include/wrapper" PREFIX wrapper FILES ${FLUID_SC_HEADERS})
if(MINGW)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mstackrealign")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mstackrealign")
endif()
if(DEFINED FLUID_ARCH)
target_compile_options(${PLUGIN} PRIVATE ${FLUID_ARCH})
endif()
if(MSVC)
target_compile_options(${PLUGIN} PRIVATE -D_USE_MATH_DEFINES)
else()
target_compile_options(${PLUGIN} PRIVATE -fvisibility=hidden)
endif()
#optional extra build settings (e.g for /bigobj with MSVC)
include(
"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/settings/${PLUGIN}.cmake"
OPTIONAL
)
endfunction()
function(generate_sc_source)
# # Define the supported set of keywords
set(noValues "")
set(singleValues FILENAME EXTERNALS_OUT FILE_OUT)
set(multiValues CLIENTS HEADERS CLASSES)
# # Process the arguments passed in
include(CMakeParseArguments)
cmake_parse_arguments(ARG
"${noValues}"
"${singleValues}"
"${multiValues}"
${ARGN})
set(CCE_WRAPPER "#include <FluidSCWrapper.hpp>")
set(ENTRY_POINT "PluginLoad(FlucomaPlugin)")
set(WRAPPER_TEMPLATE [=[makeSCWrapper<${class}>("${external}", inTable);]=])
set(EXTRA_SOURCE_FILE "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/settings/${ARG_FILENAME}.cpp.in")
if(EXISTS ${EXTRA_SOURCE_FILE})
generate_source(${ARGN} EXTRA_SOURCE ${EXTRA_SOURCE_FILE} EXTERNALS_OUT external FILE_OUT outfile)
else()
generate_source(${ARGN} EXTERNALS_OUT external FILE_OUT outfile)
endif()
if(ARG_FILENAME)
set(external_filename ${ARG_FILENAME})
else()
list(GET external 0 external_filename)
endif()
message(STATUS "Generating: ${external_filename}")
add_sc_extension(${external_filename} ${outfile})
endfunction()

@ -0,0 +1,12 @@
makeSCWrapper<RTKDTreeQueryClient>("FluidKDTreeQuery",inTable);
makeSCWrapper<RTKMeansQueryClient>("FluidKMeansQuery",inTable);
makeSCWrapper<RTSKMeansQueryClient>("FluidSKMeansQuery",inTable);
makeSCWrapper<RTKNNClassifierQueryClient>("FluidKNNClassifierQuery",inTable);
makeSCWrapper<RTKNNRegressorQueryClient>("FluidKNNRegressorQuery",inTable);
makeSCWrapper<RTNormalizeQueryClient>("FluidNormalizeQuery",inTable);
makeSCWrapper<RTRobustScaleQueryClient>("FluidRobustScaleQuery",inTable);
makeSCWrapper<RTStandardizeQueryClient>("FluidStandardizeQuery",inTable);
makeSCWrapper<RTPCAQueryClient>("FluidPCAQuery",inTable);
makeSCWrapper<RTUMAPQueryClient>("FluidUMAPQuery",inTable);
makeSCWrapper<RTMLPRegressorQueryClient>("FluidMLPRegressorQuery",inTable);
makeSCWrapper<RTMLPClassifierQueryClient>("FluidMLPClassifierQuery",inTable);

@ -1,95 +0,0 @@
# 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 Unions Horizon 2020 research and innovation programme
# (grant agreement No 725899).
target_compile_features(${PLUGIN} PRIVATE cxx_std_14)
if(MSVC)
target_compile_options(${PLUGIN} PRIVATE /W3)
else()
target_compile_options(${PLUGIN} PRIVATE
-Wall -Wextra -Wpedantic -Wreturn-type -Wconversion
)
#GCC doesn't have Wno-c++11-narrowing
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(${PLUGIN} PRIVATE -Wno-c++11-narrowing)
endif()
endif()
set_target_properties(${PLUGIN} PROPERTIES
CXX_STANDARD 14
CXX_STANDARD_REQUIRED YES
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}
PRIVATE
FLUID_DECOMPOSITION
FLUID_SC_WRAPPER
HISSTools_FFT
)
target_include_directories(
${PLUGIN}
PRIVATE
"${LOCAL_INCLUDES}"
"${FLUID_VERSION_PATH}"
)
file(GLOB_RECURSE FLUID_SC_HEADERS CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/include/wrapper/*.hpp")
target_sources(
${PLUGIN} PUBLIC ${FLUID_SC_HEADERS}
)
target_include_directories(
${PLUGIN}
SYSTEM PRIVATE
"${SC_PATH}/include/plugin_interface"
"${SC_PATH}/include/common"
"${SC_PATH}/common"
"${SC_PATH}/external_libraries/boost" #we need boost::align for deallocating buffer memory :-(
)
get_property(HEADERS TARGET FLUID_DECOMPOSITION PROPERTY INTERFACE_SOURCES)
source_group(TREE "${flucoma-core_SOURCE_DIR}/include" FILES ${HEADERS})
source_group(TREE "${CMAKE_SOURCE_DIR}/include/wrapper" PREFIX wrapper FILES ${FLUID_SC_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(DEFINED FLUID_ARCH)
target_compile_options(${PLUGIN} PRIVATE ${FLUID_ARCH})
endif()
if(MSVC)
target_compile_options(${PLUGIN} PRIVATE -D_USE_MATH_DEFINES)
else()
target_compile_options(${PLUGIN} PRIVATE -fvisibility=hidden)
endif()

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,22 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/AmpFeatureClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<RTAmpFeatureClient>("FluidAmpFeature", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,22 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/AmpGateClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<RTAmpGateClient>("FluidAmpGate", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,22 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/AmpSliceClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<RTAmpSliceClient>("FluidAmpSlice", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,21 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/AudioTransportClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<RTAudioTransportClient>("FluidAudioTransport",ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,22 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/AmpFeatureClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedAmpFeatureClient>("FluidBufAmpFeature", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,22 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/AmpGateClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(OfflineFluidDecompositionUGens)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedAmpGateClient>("FluidBufAmpGate", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,22 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/AmpSliceClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(OfflineFluidDecompositionUGens)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedAmpSliceClient>("FluidBufAmpSlice", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,21 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/AudioTransportClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedAudioTransportClient>("FluidBufAudioTransp",ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,21 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/ChromaClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen) {
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedChromaClient>("FluidBufChroma", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,22 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/nrt/BufComposeClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(OfflineFluidDecompositionUGens)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedBufComposeClient>("FluidBufCompose", ft);
}

@ -1,67 +0,0 @@
s.reboot
////////////////////////////
// test for efficiency
(
b = Buffer.read(s,"../../release-packaging/AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav".resolveRelative);
c = Buffer.read(s,"../../release-packaging/AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav".resolveRelative);
d = Buffer.new(s);
)
(
// with basic params (basic summing of each full buffer in all dimensions)
Routine{
t = Main.elapsedTime;
FluidBufCompose.process(s, srcBufNumA: b.bufnum, srcBufNumB: c.bufnum, dstBufNum: d.bufnum);
s.sync;
(Main.elapsedTime - t).postln;
}.play;
)
d.query;
d.play;
d.plot
//constructing a mono buffer, with a quiet punch from the synth, with a choked piano resonance from the left channel
(
Routine{
t = Main.elapsedTime;
FluidBufCompose.process(s, srcBufNumA: b.bufnum, nFramesA: 9000, srcGainA: 0.5, srcBufNumB: c.bufnum, startAtB:30000, nFramesB:44100, nChansB:1, srcGainB:0.9, dstBufNum: d.bufnum);
s.sync;
(Main.elapsedTime - t).postln;
}.play;
)
//constructing a stereo buffer, with the end of the mono synth in both channels, with a piano resonance in swapped stereo
(
Routine{
t = Main.elapsedTime;
FluidBufCompose.process(s, srcBufNumA: b.bufnum, startAtA: 441000, nChansA: 2, srcGainA: 0.6, srcBufNumB: c.bufnum, nFramesB: 80000, startChanB: 1, nChansB: 2, srcGainB: 0.5, dstStartAtB: 22050, dstStartChanB: 0, dstBufNum: d.bufnum);
s.sync;
(Main.elapsedTime - t).postln;
}.play;
)
//constructing a one second buffer: the first second of each buffer, the mono synth on the right, the piano on the left
(
Routine{
t = Main.elapsedTime;
FluidBufCompose.process(s, srcBufNumA: b.bufnum, nFramesA: 44100, nChansA: 1, dstStartChanA: 1, srcBufNumB: c.bufnum, nFramesB:44100, nChansB:1, dstBufNum: d.bufnum);
s.sync;
(Main.elapsedTime - t).postln;
}.play;
)
// trying to grow a buffer on itself
e = Buffer.alloc(s,1,1);
(
Routine {
FluidBufCompose.process(s,srcBufNumA: b.bufnum, srcBufNumB: e.bufnum, dstBufNum: e.bufnum);
s.sync;
FluidBufCompose.process(s,srcBufNumA: c.bufnum, nChansA: 1, srcBufNumB: e.bufnum, dstBufNum: e.bufnum);
s.sync;
}.play;
)
e.plot
e.play

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,22 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/nrt/BufFlattenClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(OfflineFluidDecompositionUGens)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedBufFlattenClient>("FluidBufFlatten", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,23 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/HPSSClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(OfflineFluidDecompositionUGens)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedHPSSClient>("FluidBufHPSS", ft);
}

@ -1,51 +0,0 @@
s.reboot
////////////////////////////
// test for efficiency
(
b = Buffer.read(s,"../../release-packaging/AudioFiles/Tremblay-AaS-SynthTwoVoices-M.wav".resolveRelative);
c = Buffer.new(s);
d = Buffer.new(s);
e = Buffer.new(s);
)
(
// with basic params
Routine{
t = Main.elapsedTime;
FluidBufHPSS.process(s, b.bufnum, harmBufNum: c.bufnum, percBufNum: d.bufnum);
s.sync;
(Main.elapsedTime - t).postln;
}.play
);
c.query;
c.play;
d.query;
d.play;
e.query;
e.play;
//nullsumming tests
{(PlayBuf.ar(1,c.bufnum))+(PlayBuf.ar(1,d.bufnum))+(-1*PlayBuf.ar(1,b.bufnum,doneAction:2))}.play
// with everything changed to make it much faster
(
Routine{
t = Main.elapsedTime;
FluidBufHPSS.process(s,b.bufnum, 44100, 44100, 0, 0, c.bufnum, d.bufnum, e.bufnum, 51, 31, 2); // need to change these for something sensible
s.sync;
(Main.elapsedTime - t).postln;
}.play
);
// owen's sexy example (The world's most expensive stereoizer)
(
{
var hpss = FluidHPSS.ar(PlayBuf.ar(1,b.bufnum,loop:1),modeFlag:2,hta1:SinOsc.kr(1.5,mul:20,add:20),hta2:SinOsc.kr(3,mul:25,add:25), pta1:SinOsc.kr(1.6,0,mul:30,add:30),pta2:SinOsc.kr(1.7,0,mul:17,add:24));
[hpss[2] + 0.5 * hpss[0], hpss[1] + 0.5 * hpss[0]];
}.play;
)

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,21 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/LoudnessClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(OfflineFluidDecompositionUGens) {
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedLoudnessClient>("FluidBufLoudness", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,21 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/MFCCClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen) {
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedMFCCClient>("FluidBufMFCC", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,21 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/rt/MelBandsClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(FluidSTFTUGen) {
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedMelBandsClient>("FluidBufMelBands", ft);
}

@ -1,21 +0,0 @@
# 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 Unions 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)

@ -1,22 +0,0 @@
/*
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 Unions Horizon 2020 research and innovation programme
(grant agreement No 725899).
*/
#include <clients/nrt/NMFClient.hpp>
#include <FluidSCWrapper.hpp>
static InterfaceTable *ft;
PluginLoad(OfflineFluidDecompositionUGens)
{
ft = inTable;
using namespace fluid::client;
makeSCWrapper<NRTThreadedNMFClient>("FluidBufNMF", ft);
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save