From 322c4454df0c16e3b2a522e82fdf2bf88cfc807e Mon Sep 17 00:00:00 2001 From: James Bradbury Date: Thu, 30 Jun 2022 15:30:42 +0100 Subject: [PATCH 1/2] [Release] 1.0.1 (#125) * 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 * 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 Co-authored-by: weefuzzy * 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` 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 arguments * change interp to interpolation in nmfmorph class (#115) * Feature/skmeans (#66) * add PCA whitening parameter * add FluidSKMeans * SKMeans correction * added RT query * transform -> encode * added to overview Co-authored-by: Gerard Co-authored-by: tremblap * [CI] Update Release Workflow (#118) * cleanup nightly.yaml * use new release style * refactor release * remove workflow dispatch variables * interface changes in 8c * knearest interface change in 10a * waveform help nmf interface change * capitalise beatRemember * two more changes of interface * typo * sign binaries * add -nightly affix * sign releases too * enforce concurrency of jobs * UMAP kr method should not allow user to pass numDimensions * slicers: change algo/metric select to symbols (#103) * slicers: change algo/metric selection to symbols * slicers: algo/metric accept UGen * FluidDataSetWr example code (#124) --- .github/workflows/nightly.yaml | 57 +++++++----- .github/workflows/release.yml | 47 ++++++---- .../Classes/FluidBufNoveltyFeature.sc | 14 +++ .../Classes/FluidBufNoveltySlice.sc | 24 ++++- .../Classes/FluidBufOnsetFeature.sc | 14 +++ .../Classes/FluidBufOnsetSlice.sc | 29 ++++-- .../Classes/FluidNoveltyFeature.sc | 16 +++- .../Classes/FluidNoveltySlice.sc | 31 +++++-- .../Classes/FluidOnsetFeature.sc | 8 ++ release-packaging/Classes/FluidOnsetSlice.sc | 42 +++++++-- release-packaging/Classes/FluidPlotter.sc | 2 +- release-packaging/Classes/FluidUMAP.sc | 5 +- .../Guides/Decomposition Examples.scd | 6 +- .../Examples/Guides/NMF Overview.scd | 2 +- .../8c-mlp-regressor-as-dim-redux.scd | 8 +- .../HelpSource/Classes/FluidBufNMF.schelp | 2 +- .../HelpSource/Classes/FluidDataSetWr.schelp | 92 ++++++++----------- .../HelpSource/Classes/FluidWaveform.schelp | 2 +- test/10a-weighted-MFCCs-comparison.scd | 8 +- test/12-windowed-clustered-segmentation.scd | 2 +- test/13-massive-parallelisation-example.scd | 2 +- test/8c-mlp-regressor-as-dim-redux.scd | 6 +- 22 files changed, 263 insertions(+), 156 deletions(-) diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index 2a3bd70e..a9a8d24e 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -1,37 +1,48 @@ -name: Nightly Releases +name: nightly on: - workflow_dispatch: push: branches: [ dev, ci/** ] +concurrency: + group: environment-${{ github.ref }} + cancel-in-progress: true + jobs: macbuild: - runs-on: macos-11 + runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: flucoma/actions/env@v5 - - uses: flucoma/actions/sc@v5 + - uses: actions/checkout@v3 + - uses: flucoma/actions/env@main + - uses: flucoma/actions/sc@main with: branch: origin/dev - - name: compress archive - run: zip -r FluCoMa-SC-Mac-nightly.zip FluidCorpusManipulation - working-directory: install - - - uses: actions/upload-artifact@v2 + - name: sign binaries + uses: flucoma/actions/distribution@main with: - name: macbuild - path: install/FluCoMa-SC-Mac-nightly.zip + glob: '-e scx' + package: 'install' + output_type: 'dmg' + output: FluCoMa-SC-Mac-nightly + cert: ${{ secrets.CERT }} + certpwd: ${{ secrets.CERTPWD }} + teamid: ${{ secrets.WWDRTEAMID }} + apppwd: ${{ secrets.APPSTORECONNECTPWD }} + appusr: ${{ secrets.APPSTORECONNECTUSERNAME }} + - uses: actions/upload-artifact@v3 + with: + name: macbuild + path: install/FluCoMa-SC-Mac-nightly.dmg winbuild: runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: flucoma/actions/env@v5 - - uses: flucoma/actions/sc@v5 + - uses: actions/checkout@v3 + - uses: flucoma/actions/env@main + - uses: flucoma/actions/sc@main with: branch: origin/dev @@ -42,25 +53,25 @@ jobs: run: 7z a FluCoMa-SC-Windows-nightly.zip FluidCorpusManipulation working-directory: install - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: winbuild path: install/FluCoMa-SC-Windows-nightly.zip linuxbuild: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: flucoma/actions/env@v5 - - uses: flucoma/actions/sc@v5 + - uses: actions/checkout@v3 + - uses: flucoma/actions/env@main + - uses: flucoma/actions/sc@main with: branch: origin/dev - 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@v3 with: name: linuxbuild path: install/FluCoMa-SC-Linux-nightly.tar.gz @@ -94,7 +105,7 @@ jobs: with: 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 }}" - files: FluCoMa-SC-* + files: FluCoMa* prerelease: true tag_name: nightly draft: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e336924..c54d4d4b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,33 +1,42 @@ -name: Release +name: release on: workflow_dispatch: jobs: macbuild: - runs-on: macos-11 + runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: flucoma/actions/env@v5 - - uses: flucoma/actions/sc@v5 + - uses: actions/checkout@v3 + - uses: flucoma/actions/env@main + - uses: flucoma/actions/sc@main with: branch: origin/main - - name: compress archive - run: zip -r FluCoMa-SC-Mac.zip FluidCorpusManipulation - working-directory: install + - name: sign binaries + uses: flucoma/actions/distribution@main + with: + glob: '-e scx' + package: 'install' + output_type: 'dmg' + output: FluCoMa-SC-Mac + cert: ${{ secrets.CERT }} + certpwd: ${{ secrets.CERTPWD }} + teamid: ${{ secrets.WWDRTEAMID }} + apppwd: ${{ secrets.APPSTORECONNECTPWD }} + appusr: ${{ secrets.APPSTORECONNECTUSERNAME }} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: macbuild - path: install/FluCoMa-SC-Mac.zip + path: install/FluCoMa-SC-Mac.dmg winbuild: runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: flucoma/actions/env@v5 - - uses: flucoma/actions/sc@v5 + - uses: actions/checkout@v3 + - uses: flucoma/actions/env@main + - uses: flucoma/actions/sc@main with: branch: origin/main @@ -38,19 +47,19 @@ jobs: run: 7z a FluCoMa-SC-Windows.zip FluidCorpusManipulation working-directory: install - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: winbuild path: install/FluCoMa-SC-Windows.zip linuxbuild: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest outputs: version: ${{ steps.get-version.outputs.version }} steps: - - uses: actions/checkout@v2 - - uses: flucoma/actions/env@v5 - - uses: flucoma/actions/sc@v5 + - uses: actions/checkout@v3 + - uses: flucoma/actions/env@main + - uses: flucoma/actions/sc@main with: branch: origin/main @@ -58,7 +67,7 @@ jobs: run: tar -zcvf FluCoMa-SC-Linux.tar.gz FluidCorpusManipulation working-directory: install - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: linuxbuild path: install/FluCoMa-SC-Linux.tar.gz diff --git a/release-packaging/Classes/FluidBufNoveltyFeature.sc b/release-packaging/Classes/FluidBufNoveltyFeature.sc index 868c37a2..1fca9ace 100644 --- a/release-packaging/Classes/FluidBufNoveltyFeature.sc +++ b/release-packaging/Classes/FluidBufNoveltyFeature.sc @@ -6,6 +6,10 @@ FluidBufNoveltyFeature : FluidBufProcessor { source = source.asUGenInput; features = features.asUGenInput; + algorithm = FluidNoveltySlice.prSelectAlgorithm(algorithm) ?? { + ("FluidBufNoveltySlice: % is not a recognised algorithm") + .format(algorithm).throw; + }; source.isNil.if {"FluidBufNoveltyFeature: Invalid source buffer".throw}; features.isNil.if {"FluidBufNoveltyFeature: Invalid features buffer".throw}; @@ -20,6 +24,11 @@ FluidBufNoveltyFeature : FluidBufProcessor { source = source.asUGenInput; features = features.asUGenInput; + algorithm = FluidNoveltySlice.prSelectAlgorithm(algorithm); + if (algorithm.isNil or: algorithm.isUGen) { + ("FluidBufNoveltySlice: % is not a recognised algorithm") + .format(algorithm).throw; + }; source.isNil.if {"FluidBufNoveltyFeature: Invalid source buffer".throw}; features.isNil.if {"FluidBufNoveltyFeature: Invalid features buffer".throw}; @@ -40,6 +49,11 @@ FluidBufNoveltyFeature : FluidBufProcessor { source.isNil.if {"FluidBufNoveltyFeature: Invalid source buffer".throw}; features.isNil.if {"FluidBufNoveltyFeature: Invalid features buffer".throw}; + algorithm = FluidNoveltySlice.prSelectAlgorithm(algorithm); + if (algorithm.isNil or: algorithm.isUGen) { + ("FluidBufNoveltySlice: % is not a recognised algorithm") + .format(algorithm).throw; + }; ^this.new( server, nil, [features] diff --git a/release-packaging/Classes/FluidBufNoveltySlice.sc b/release-packaging/Classes/FluidBufNoveltySlice.sc index b53820e5..82952fea 100644 --- a/release-packaging/Classes/FluidBufNoveltySlice.sc +++ b/release-packaging/Classes/FluidBufNoveltySlice.sc @@ -1,11 +1,15 @@ FluidBufNoveltySlice : FluidBufProcessor { - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, algorithm = 0, kernelSize = 3, threshold = 0.5, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1 , blocking = 0| + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, algorithm = 0, kernelSize = 3, threshold = 0.5, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1 , blocking = 0| var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; indices = indices.asUGenInput; + algorithm = FluidNoveltySlice.prSelectAlgorithm(algorithm) ?? { + ("FluidBufNoveltySlice: % is not a recognised algorithm") + .format(algorithm).throw; + }; source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw}; indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw}; @@ -15,15 +19,20 @@ FluidBufNoveltySlice : FluidBufProcessor { } *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, algorithm= 0, kernelSize = 3, threshold = 0.5, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action | - + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; indices = indices.asUGenInput; + algorithm = FluidNoveltySlice.prSelectAlgorithm(algorithm); + if (algorithm.isNil or: algorithm.isUGen) { + ("FluidBufNoveltySlice: % is not a recognised algorithm") + .format(algorithm).throw; + }; source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw}; indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw}; - + ^this.new( server, nil, [indices] ).processList( @@ -32,15 +41,20 @@ FluidBufNoveltySlice : FluidBufProcessor { } *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, algorithm= 0, kernelSize = 3, threshold = 0.5, filterSize = 1, minSliceLength = 2, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action | - + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; indices = indices.asUGenInput; + algorithm = FluidNoveltySlice.prSelectAlgorithm(algorithm); + if (algorithm.isNil or: algorithm.isUGen) { + ("FluidBufNoveltySlice: % is not a recognised algorithm") + .format(algorithm).throw; + }; source.isNil.if {"FluidBufNoveltySlice: Invalid source buffer".throw}; indices.isNil.if {"FluidBufNoveltySlice: Invalid features buffer".throw}; - + ^this.new( server, nil, [indices] ).processList( diff --git a/release-packaging/Classes/FluidBufOnsetFeature.sc b/release-packaging/Classes/FluidBufOnsetFeature.sc index 6ea08b01..1b3235c8 100644 --- a/release-packaging/Classes/FluidBufOnsetFeature.sc +++ b/release-packaging/Classes/FluidBufOnsetFeature.sc @@ -5,6 +5,10 @@ FluidBufOnsetFeature : FluidBufProcessor { source = source.asUGenInput; features = features.asUGenInput; + metric = FluidOnsetSlice.prSelectMetric(metric) ?? { + ("FluidBufOnsetSlice: % is not a recognised metric") + .format(metric).throw; + }; source.isNil.if {"FluidBufOnsetFeature: Invalid source buffer".throw}; features.isNil.if {"FluidBufOnsetFeature: Invalid features buffer".throw}; @@ -18,6 +22,11 @@ FluidBufOnsetFeature : FluidBufProcessor { source = source.asUGenInput; features = features.asUGenInput; + metric = FluidOnsetSlice.prSelectMetric(metric); + if (metric.isNil or: metric.isUGen) { + ("FluidBufOnsetSlice: % is not a recognised metric") + .format(metric).throw; + }; source.isNil.if {"FluidBufOnsetFeature: Invalid source buffer".throw}; features.isNil.if {"FluidBufOnsetFeature: Invalid features buffer".throw}; @@ -35,6 +44,11 @@ FluidBufOnsetFeature : FluidBufProcessor { source = source.asUGenInput; features = features.asUGenInput; + metric = FluidOnsetSlice.prSelectMetric(metric); + if (metric.isNil or: metric.isUGen) { + ("FluidBufOnsetSlice: % is not a recognised metric") + .format(metric).throw; + }; source.isNil.if {"FluidBufOnsetFeature: Invalid source buffer".throw}; features.isNil.if {"FluidBufOnsetFeature: Invalid features buffer".throw}; diff --git a/release-packaging/Classes/FluidBufOnsetSlice.sc b/release-packaging/Classes/FluidBufOnsetSlice.sc index 2f9a7548..0a3f6d78 100644 --- a/release-packaging/Classes/FluidBufOnsetSlice.sc +++ b/release-packaging/Classes/FluidBufOnsetSlice.sc @@ -1,27 +1,37 @@ FluidBufOnsetSlice : FluidBufProcessor { - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0| - + + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0| + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; indices = indices.asUGenInput; + metric = FluidOnsetSlice.prSelectMetric(metric) ?? { + ("FluidBufOnsetSlice: % is not a recognised metric") + .format(metric).throw; + }; source.isNil.if {"FluidBufOnsetSlice: Invalid source buffer".throw}; indices.isNil.if {"FluidBufOnsetSlice: Invalid features buffer".throw}; - + ^FluidProxyUgen.kr(\FluidBufOnsetSliceTrigger, -1, source, startFrame, numFrames, startChan, numChans, indices, metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking); } *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action| - + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; indices = indices.asUGenInput; + metric = FluidOnsetSlice.prSelectMetric(metric); + if (metric.isNil or: metric.isUGen) { + ("FluidBufOnsetSlice: % is not a recognised metric") + .format(metric).throw; + }; source.isNil.if {"FluidBufOnsetSlice: Invalid source buffer".throw}; indices.isNil.if {"FluidBufOnsetSlice: Invalid features buffer".throw}; - + ^this.new( server, nil, [indices] ).processList( @@ -30,15 +40,20 @@ FluidBufOnsetSlice : FluidBufProcessor { } *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action| - + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; indices = indices.asUGenInput; + metric = FluidOnsetSlice.prSelectMetric(metric); + if (metric.isNil or: metric.isUGen) { + ("FluidBufOnsetSlice: % is not a recognised metric") + .format(metric).throw; + }; source.isNil.if {"FluidBufOnsetSlice: Invalid source buffer".throw}; indices.isNil.if {"FluidBufOnsetSlice: Invalid features buffer".throw}; - + ^this.new( server, nil, [indices] ).processList( diff --git a/release-packaging/Classes/FluidNoveltyFeature.sc b/release-packaging/Classes/FluidNoveltyFeature.sc index ddb63139..a83df30f 100644 --- a/release-packaging/Classes/FluidNoveltyFeature.sc +++ b/release-packaging/Classes/FluidNoveltyFeature.sc @@ -1,13 +1,19 @@ FluidNoveltyFeature : FluidRTUGen { *kr { arg in = 0, algorithm = 0, kernelSize = 3, filterSize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1, maxKernelSize, maxFilterSize; - - maxKernelSize = maxKernelSize ? kernelSize; - maxFilterSize = maxFilterSize ? filterSize; - + + maxKernelSize = maxKernelSize ? kernelSize; + maxFilterSize = maxFilterSize ? filterSize; + algorithm = FluidNoveltySlice.prSelectAlgorithm(algorithm) ?? { + ("FluidNoveltySlice: % is not a recognised algorithm").format(algorithm); + }; + ^this.multiNew('control', in.asAudioRateInput(this), algorithm, kernelSize, maxKernelSize, filterSize, maxFilterSize, windowSize, hopSize, fftSize, maxFFTSize) } - + checkInputs { + if([\scalar, \control].includes(inputs.at(1).rate).not) { + ^(": invalid algorithm"); + }; if(inputs.at(9).rate != 'scalar') { ^(": maxFFTSize cannot be modulated."); }; diff --git a/release-packaging/Classes/FluidNoveltySlice.sc b/release-packaging/Classes/FluidNoveltySlice.sc index 9dd78dfa..da43d54f 100644 --- a/release-packaging/Classes/FluidNoveltySlice.sc +++ b/release-packaging/Classes/FluidNoveltySlice.sc @@ -1,20 +1,35 @@ FluidNoveltySlice : FluidRTUGen { - const = 0 && (sym < algorithms.size)) { + ^sym + } { + ^nil + } + }; + ^algorithms.indexOf(sym.asSymbol) + } *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; - + maxFilterSize = maxFilterSize ? filterSize; + + algorithm = this.prSelectAlgorithm(algorithm) ?? { + ("FluidNoveltySlice: % is not a recognised algorithm").format(algorithm); + }; + ^this.multiNew('audio', in.asAudioRateInput(this), algorithm, kernelSize, maxKernelSize, threshold, filterSize, maxFilterSize, minSliceLength, windowSize, hopSize, fftSize, maxFFTSize) } checkInputs { + if([\scalar, \control].includes(inputs.at(1).rate).not) { + ^(": invalid algorithm"); + }; if(inputs.at(11).rate != 'scalar') { ^(": maxFFTSize cannot be modulated."); }; diff --git a/release-packaging/Classes/FluidOnsetFeature.sc b/release-packaging/Classes/FluidOnsetFeature.sc index 894b3e90..d5b7786a 100644 --- a/release-packaging/Classes/FluidOnsetFeature.sc +++ b/release-packaging/Classes/FluidOnsetFeature.sc @@ -1,8 +1,16 @@ FluidOnsetFeature : FluidRTUGen { *kr { arg in = 0, metric = 0, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1; + + metric = FluidOnsetSlice.prSelectMetric(metric) ?? { + ("% is not a recognised metric").format(metric); + }; + ^this.multiNew('control', in.asAudioRateInput(this), metric, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize) } checkInputs { + if([\scalar, \control].includes(inputs.at(1).rate).not) { + ^(": invalid metric"); + }; if(inputs.at(7).rate != 'scalar') { ^(": maxFFTSize cannot be modulated."); }; diff --git a/release-packaging/Classes/FluidOnsetSlice.sc b/release-packaging/Classes/FluidOnsetSlice.sc index 91dd2c8d..507e1286 100644 --- a/release-packaging/Classes/FluidOnsetSlice.sc +++ b/release-packaging/Classes/FluidOnsetSlice.sc @@ -1,20 +1,42 @@ FluidOnsetSlice : FluidRTUGen { - const = 0 && (sym < metrics.size)) { + ^sym + } { + ^nil + } + }; + ^metrics.indexOf(sym.asSymbol) + } *ar { arg in = 0, metric = 0, threshold = 0.5, minSliceLength = 2, filterSize = 5, frameDelta = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = -1; + + metric = this.prSelectMetric(metric) ?? { + ("% is not a recognised metric").format(metric); + }; + ^this.multiNew('audio', in.asAudioRateInput(this), metric, threshold, minSliceLength, filterSize, frameDelta, windowSize, hopSize, fftSize, maxFFTSize) } checkInputs { + if([\scalar, \control].includes(inputs.at(1).rate).not) { + ^(": invalid metric"); + }; if(inputs.at(9).rate != 'scalar') { ^(": maxFFTSize cannot be modulated."); }; diff --git a/release-packaging/Classes/FluidPlotter.sc b/release-packaging/Classes/FluidPlotter.sc index d78a4745..579c538e 100644 --- a/release-packaging/Classes/FluidPlotter.sc +++ b/release-packaging/Classes/FluidPlotter.sc @@ -87,7 +87,7 @@ FluidPlotter : FluidViewer { if(dict_internal.at(identifier).notNil,{ "FluidPlotter::addPoint_ There already exists a point with identifier %. Point not added. Use setPoint_ to overwrite existing points.".format(identifier).warn; },{ - this.setPoint_(identifier,x,y,size,color); + this.setPoint_(identifier,x,y,color,size); }); } diff --git a/release-packaging/Classes/FluidUMAP.sc b/release-packaging/Classes/FluidUMAP.sc index 878ee999..24f632c3 100644 --- a/release-packaging/Classes/FluidUMAP.sc +++ b/release-packaging/Classes/FluidUMAP.sc @@ -63,10 +63,7 @@ FluidUMAP : FluidModelObject { this.prSendMsg(this.transformPointMsg(sourceBuffer,destBuffer)); } - kr{|trig, inputBuffer,outputBuffer,numDimensions| - - numDimensions = numDimensions ? this.numDimensions; - this.numDimensions_(numDimensions); + kr{|trig, inputBuffer,outputBuffer| ^FluidUMAPQuery.kr(trig, this, diff --git a/release-packaging/Examples/Guides/Decomposition Examples.scd b/release-packaging/Examples/Guides/Decomposition Examples.scd index 44c8cecc..84e06d19 100644 --- a/release-packaging/Examples/Guides/Decomposition Examples.scd +++ b/release-packaging/Examples/Guides/Decomposition Examples.scd @@ -17,7 +17,7 @@ y = { ) // isolate just sines or residual; -~song = Buffer.readChannel(s,FluidFilesPath("Tremblay-beatRemember.wav"),channels:[0]); +~song = Buffer.readChannel(s,FluidFilesPath("Tremblay-BeatRemember.wav"),channels:[0]); ( y = { @@ -37,7 +37,7 @@ y.set(\mix,0); y.set(\mix,1); // a stereo example -~song = Buffer.read(s,FluidFilesPath("Tremblay-beatRemember.wav")); +~song = Buffer.read(s,FluidFilesPath("Tremblay-BeatRemember.wav")); ( y = { @@ -85,7 +85,7 @@ FluidHPSS separates a sound into "harmonic" and "percussive" components. This ca */ //load a soundfile to play -~buf = Buffer.readChannel(s,FluidFilesPath("Tremblay-beatRemember.wav"),channels:[0]); +~buf = Buffer.readChannel(s,FluidFilesPath("Tremblay-BeatRemember.wav"),channels:[0]); // run with basic parameters (left is harmonic, right is percussive) {FluidHPSS.ar(PlayBuf.ar(1,~buf,loop:1))}.play diff --git a/release-packaging/Examples/Guides/NMF Overview.scd b/release-packaging/Examples/Guides/NMF Overview.scd index d75c22ea..8c82510b 100644 --- a/release-packaging/Examples/Guides/NMF Overview.scd +++ b/release-packaging/Examples/Guides/NMF Overview.scd @@ -59,7 +59,7 @@ Routine{ Routine{ var drums = Buffer.read(s,FluidFilesPath("Nicol-LoopE-M.wav")); var voice = Buffer.read(s,FluidFilesPath("Tremblay-AaS-VoiceQC-B2K-M.wav")); - var song = Buffer.read(s,FluidFilesPath("Tremblay-beatRemember.wav")); + var song = Buffer.read(s,FluidFilesPath("Tremblay-BeatRemember.wav")); s.sync; "drums through the drums bases as filters".postln; diff --git a/release-packaging/Examples/dataset/1-learning examples/8c-mlp-regressor-as-dim-redux.scd b/release-packaging/Examples/dataset/1-learning examples/8c-mlp-regressor-as-dim-redux.scd index 10e8ff3a..36636014 100644 --- a/release-packaging/Examples/dataset/1-learning examples/8c-mlp-regressor-as-dim-redux.scd +++ b/release-packaging/Examples/dataset/1-learning examples/8c-mlp-regressor-as-dim-redux.scd @@ -74,8 +74,6 @@ FluidBufMelBands.process(s,~audio, features: ~melfeatures,action: {\done.postln; //prepare the normalizers and the neural net for inverse query ( -~normalView.invert = 1; -~normalizer.invert = 1; ~mlp.tapIn = 2; ~mlp.tapOut = -1; ) @@ -114,9 +112,9 @@ v.mouseMoveAction = {|view, x, y| ~kdtree.kNearest(~queryPoint, action: {|nearest| //retrieve the nearest point ~norm.getPoint(nearest, ~dpN, action: { //get the normalised 40d ~raw.getPoint(nearest, ~datapoint, action: { // get the original 40d - ~normalView.transformPoint(~queryPoint, ~dQueryPoint, action: { //denormalise the 2d coordinate to get the right range of values for the MLP + ~normalView.inverseTransformPoint(~queryPoint, ~dQueryPoint, action: { //denormalise the 2d coordinate to get the right range of values for the MLP ~mlp.predictPoint(~dQueryPoint, ~dpMLPn, action: { //predict from the middle (2d) to the normalised output (40d) - ~normalizer.transformPoint(~dpMLPn, ~dpMLP, action: { //denormalised the 40d + ~normalizer.inverseTransformPoint(~dpMLPn, ~dpMLP, action: { //denormalised the 40d ~datapoint.getn(0,40,{|x|~arrayRawN = x; //retrieve the nearest ~dpN.getn(0,40,{|x|~arrayRawNn = x; // retrieve the normalised nearest ~dpMLPn.getn(0,40,{|x|~arrayMLPn = x; //retrieve the predicted normalised 40d @@ -158,4 +156,4 @@ w.drawFunc = { }; w.refresh; w.front; -) +) \ No newline at end of file diff --git a/release-packaging/HelpSource/Classes/FluidBufNMF.schelp b/release-packaging/HelpSource/Classes/FluidBufNMF.schelp index d5fae688..3497c2b3 100644 --- a/release-packaging/HelpSource/Classes/FluidBufNMF.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufNMF.schelp @@ -425,7 +425,7 @@ FluidWaveform(featureBuffer:~bases,bounds:Rect(0,0,1200,300)); // if we play a different source through FluidNMFFilter, it will try to decompose that real-time signal according to the bases // it is given (in our case the bases from the drum loop) -~song = Buffer.readChannel(s,FluidFilesPath("Tremblay-beatRemember.wav"),channels:[0]); +~song = Buffer.readChannel(s,FluidFilesPath("Tremblay-BeatRemember.wav"),channels:[0]); ( { diff --git a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp index ba674ab1..ef71b59c 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp @@ -1,7 +1,7 @@ TITLE:: FluidDataSetWr summary:: Write to FluidDataSet on the server categories:: Libraries>FluidCorpusManipulation -related:: Classes/FLuidDataSet +related:: Classes/FluidDataSet DESCRIPTION:: A UGen that adds data points with associated identifiers to a link::Classes/FluidDataSet:: Internally, this calls code::setPoint::, so IDs that already exist will be overwritten, and new IDs will be added. The actual work is done on the server's command queue, rather than the real-thread. @@ -21,10 +21,10 @@ CLASSMETHODS:: private:: *new1 METHOD:: kr -The equivalent of calling link::Classes/FluidDataSet#-addPoint::, but within a link::Classes/Synth:: +The equivalent of calling link::Classes/FluidDataSet#-setPoint::, but within a link::Classes/Synth:: ARGUMENT:: dataset -An instance of link::Classes/FluidDataSet:: or an instance's name. +An instance of link::Classes/FluidDataSet:: ARGUMENT:: idPrefix A string or symbol with a prefix for generated identifiers. @@ -67,58 +67,38 @@ s.reboot; ( ~ds.clear; OSCFunc({ - "FluidDataSetWr help: all points written".postln; - ~ds.print + "FluidDataSetWr help: all points written".postln; + ~ds.print },'/datasetwrdone').oneShot; -{ |n| - var b = LocalBuf.newFrom([0,1,2,3]); - var trig = Impulse.kr(ControlRate.ir / 8); - var idx = Stepper.kr(trig,min:-1, max:n); //we need to start at -1 to catch the first increment - 4.collect{|i| BufWr.kr([(4 * idx) + i],b,i)}; - FluidDataSetWr.kr(~ds,idNumber:idx,buf:b,trig:trig); - SendReply.kr(idx >= (n-1), '/datasetwrdone'); - FreeSelf.kr(idx >= (n-1)); -}.play(s,args:[n:100]); +{ + arg n; + var buf = LocalBuf(4); + var trig = Impulse.kr(ControlRate.ir / 8); // can't go any faster + var idx = Stepper.kr(trig,min:-1, max:n); //we need to start at -1 to catch the first increment + + FluidKrToBuf.kr((idx * 4) + [0,1,2,3],buf); + FluidDataSetWr.kr(~ds,"point-",idNumber:idx,buf:buf,trig:trig); + SendReply.kr(idx >= (n-1), '/datasetwrdone'); + FreeSelf.kr(idx >= (n-1)); +}.play(args:[\n,100]); ) +:: -//it printed with the return function - -//Again, but as fast as possible using a feedback of the trigger we are given when the writing is done -( -~ds.clear; -OSCFunc({ - "FluidDataSetWr help: all points written".postln; - ~ds.print -},'/datasetwrdone').oneShot; - -{ |n| - var b = LocalBuf.newFrom([0,1,2,3]); - var trig = LocalIn.kr(1,1); - var idx = Stepper.kr(trig,min:-1, max:n); - var wr = FluidDataSetWr.kr(~ds,idNumber:idx,buf:b,trig:trig); - 4.collect{|i| BufWr.kr([(4 * idx) + i],b,i)}; - LocalOut.kr(Done.kr(wr)); - SendReply.kr(idx >= (n-1), '/datasetwrdone'); - FreeSelf.kr(idx >= (n-1)); -}.play(s,args:[n:100]); -) +strong::incremental buffer writing - sky is the limit:: +code:: -// incremental buffer writing - sky is the limit -~ds.clear // start the entry maker, trigging twice a second ( +~ds.clear; { - var buf = LocalBuf.newFrom([0,1,2,3]); - var noise = 4.collect{WhiteNoise.kr()}; - var trig = Impulse.kr(2); - var count = PulseCount.kr(trig); - 4.do{|i| - BufWr.kr(noise[i], buf, DC.kr(i)); - }; - FluidDataSetWr.kr(~ds, idNumber: count, trig: trig, buf:buf); -}.play(s); + var buf = LocalBuf(4); + var trig = Impulse.kr(30); + var count = PulseCount.kr(trig) - 1; + FluidKrToBuf.kr(WhiteNoise.kr(1.dup(4)),buf); + FluidDataSetWr.kr(~ds,"point-",idNumber: count, trig: trig, buf:buf); +}.play; ) //print a few times @@ -132,18 +112,24 @@ OSCFunc({ ~ds.print; ~ds.clear -// circular writing +:: +strong::circular writing:: +Each time link::Classes/FluidDataSetWr:: is triggered it is like the link::Classes/FluidDataSet#-setPoint:: method so if the identifier does not exist it creates it. If the identifier does it exist then it updates it with the new values. + +By looping code::idNumber:: values, we can use a link::Classes/FluidDataSet:: similar to a "circle buffer", always have the most recent code::n:: points in it that we want. + +code:: + +// always have only the most recent 10 points in the buffer ( { var buf = LocalBuf.newFrom([0,1,2,3]); - var noise = 4.collect{WhiteNoise.kr()}; + var noise = WhiteNoise.kr(1.dup(4)) + Sweep.kr(1,1); var trig = Impulse.kr(2); var count = Stepper.kr(trig, min: 0, max: 9, resetval: -1); //0 to 9, starting at -1 to catch the first entry - 4.do{|i| - BufWr.kr(noise[i], buf, DC.kr(i)); - }; - FluidDataSetWr.kr(~ds, idNumber: count, trig: trig, buf:buf); -}.play(s); + FluidKrToBuf.kr(noise,buf); + FluidDataSetWr.kr(~ds, "point-",idNumber: count, trig: trig, buf:buf); +}.play; ) //print regularly to see a specific identifier being overwritten diff --git a/release-packaging/HelpSource/Classes/FluidWaveform.schelp b/release-packaging/HelpSource/Classes/FluidWaveform.schelp index 71466f54..7de7f4cb 100644 --- a/release-packaging/HelpSource/Classes/FluidWaveform.schelp +++ b/release-packaging/HelpSource/Classes/FluidWaveform.schelp @@ -293,7 +293,7 @@ s.waitForBoot{ ~resynths = {Buffer(s)} ! ~n_components; s.sync; - FluidBufNMF.processBlocking(s,~audio,resynth:~resynth,activations:~activations,components:~n_components); + FluidBufNMF.processBlocking(s,~audio,resynth:~resynth,resynthMode: 1,activations:~activations,components:~n_components); ~n_components.do{ arg i; diff --git a/test/10a-weighted-MFCCs-comparison.scd b/test/10a-weighted-MFCCs-comparison.scd index 38088b7f..db3f0a62 100644 --- a/test/10a-weighted-MFCCs-comparison.scd +++ b/test/10a-weighted-MFCCs-comparison.scd @@ -166,10 +166,10 @@ FluidBufCompose.process(s,~loader.buffer,a,(b-a),numChans: 1, destination: ~targ ~flatbuf[1].getn(0,182,{|x|~curatedWBuf = Buffer.loadCollection(s, x[[0,1,4,6,7,8,11,13].collect{|x|var y=x*13+1;(y..(y+11))}.flat].postln)}) //find its nearest neighbours -~tree.kNearest(~flatbuf[0],{|x| ~friends = x.postln;}) -~treeW.kNearest(~flatbuf[1],{|x| ~friendsW = x.postln;}) -~treeC.kNearest(~curatedBuf,{|x| ~friendsC = x.postln;}) -~treeCW.kNearest(~curatedWBuf,{|x| ~friendsCW = x.postln;}) +~tree.kNearest(~flatbuf[0],action:{|x| ~friends = x.postln;}) +~treeW.kNearest(~flatbuf[1],action:{|x| ~friendsW = x.postln;}) +~treeC.kNearest(~curatedBuf,action:{|x| ~friendsC = x.postln;}) +~treeCW.kNearest(~curatedWBuf,action:{|x| ~friendsCW = x.postln;}) // play them in a row diff --git a/test/12-windowed-clustered-segmentation.scd b/test/12-windowed-clustered-segmentation.scd index ac2b8baf..95dad07d 100644 --- a/test/12-windowed-clustered-segmentation.scd +++ b/test/12-windowed-clustered-segmentation.scd @@ -4,7 +4,7 @@ //slightly oversegment with novelty //segments should still make sense but might cut a few elements in 2 or 3 -~slicer = FluidSliceCorpus({ |src,start,num,dest| FluidBufNoveltySlice.kr(src,start,num,indices:dest, feature: 1, kernelSize: 29, threshold: 0.1, filterSize: 5, hopSize: 128, blocking: 1)}); +~slicer = FluidSliceCorpus({ |src,start,num,dest| FluidBufNoveltySlice.kr(src, start, num, indices:dest, algorithm:1, kernelSize:29, threshold:0.1, filterSize:5, hopSize:128, blocking:1)}); ~slicer.play(s, ~loader.buffer,~loader.index); //test the segmentation by looping them diff --git a/test/13-massive-parallelisation-example.scd b/test/13-massive-parallelisation-example.scd index 294a0413..e642eacf 100644 --- a/test/13-massive-parallelisation-example.scd +++ b/test/13-massive-parallelisation-example.scd @@ -297,7 +297,7 @@ FluidBufMelBands.process(s, ~inBuf, features: ~inBufMels, action: { FluidBufFlatten.process(s, ~inBufStats, destination:~inBufFlat, action: { FluidBufCompose.process(s, ~inBufFlat, numFrames: ~numMelBands, destination: ~inBufComp, action: { ~standardizer.transformPoint(~inBufComp, ~inBufStand, { - ~tree.kNearest(~inBufStand,{ |a|a.postln;~nearest = a;}) + ~tree.kNearest(~inBufStand,action:{ |a|a.postln;~nearest = a;}) }) }) }) diff --git a/test/8c-mlp-regressor-as-dim-redux.scd b/test/8c-mlp-regressor-as-dim-redux.scd index 4d9ee1ff..36636014 100644 --- a/test/8c-mlp-regressor-as-dim-redux.scd +++ b/test/8c-mlp-regressor-as-dim-redux.scd @@ -74,8 +74,6 @@ FluidBufMelBands.process(s,~audio, features: ~melfeatures,action: {\done.postln; //prepare the normalizers and the neural net for inverse query ( -~normalView.invert = 1; -~normalizer.invert = 1; ~mlp.tapIn = 2; ~mlp.tapOut = -1; ) @@ -114,9 +112,9 @@ v.mouseMoveAction = {|view, x, y| ~kdtree.kNearest(~queryPoint, action: {|nearest| //retrieve the nearest point ~norm.getPoint(nearest, ~dpN, action: { //get the normalised 40d ~raw.getPoint(nearest, ~datapoint, action: { // get the original 40d - ~normalView.transformPoint(~queryPoint, ~dQueryPoint, action: { //denormalise the 2d coordinate to get the right range of values for the MLP + ~normalView.inverseTransformPoint(~queryPoint, ~dQueryPoint, action: { //denormalise the 2d coordinate to get the right range of values for the MLP ~mlp.predictPoint(~dQueryPoint, ~dpMLPn, action: { //predict from the middle (2d) to the normalised output (40d) - ~normalizer.transformPoint(~dpMLPn, ~dpMLP, action: { //denormalised the 40d + ~normalizer.inverseTransformPoint(~dpMLPn, ~dpMLP, action: { //denormalised the 40d ~datapoint.getn(0,40,{|x|~arrayRawN = x; //retrieve the nearest ~dpN.getn(0,40,{|x|~arrayRawNn = x; // retrieve the normalised nearest ~dpMLPn.getn(0,40,{|x|~arrayMLPn = x; //retrieve the predicted normalised 40d From 9dd149ac2f0a2705a5018608e79e9c41a57ca4bd Mon Sep 17 00:00:00 2001 From: Ted Moore Date: Fri, 1 Jul 2022 11:56:04 +0100 Subject: [PATCH 2/2] modify fluid loudness by adding select in a test example --- test/8b-mlp-synth-control.scd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/8b-mlp-synth-control.scd b/test/8b-mlp-synth-control.scd index 49a3d387..51797ad4 100644 --- a/test/8b-mlp-synth-control.scd +++ b/test/8b-mlp-synth-control.scd @@ -69,8 +69,8 @@ b = { arg val = #[0,0,0,0,0,0,0,0,0,0]; var osc1, osc2, feed1, feed2, base1=69, base2=69, base3 = 130; #feed2,feed1 = LocalIn.ar(2); - osc1 = MoogFF.ar(SinOsc.ar((((feed1 * val[0]) + val[1]) * base1).midicps,mul: (val[2] * 50).dbamp).atan,(base3 - (val[3] * (FluidLoudness.kr(feed2, 1, 0, hopSize: 64)[0].clip(-120,0) + 120))).lag(128/44100).midicps, val[4] * 3.5); - osc2 = MoogFF.ar(SinOsc.ar((((feed2 * val[5]) + val[6]) * base2).midicps,mul: (val[7] * 50).dbamp).atan,(base3 - (val[8] * (FluidLoudness.kr(feed1, 1, 0, hopSize: 64)[0].clip(-120,0) + 120))).lag(128/44100).midicps, val[9] * 3.5); + osc1 = MoogFF.ar(SinOsc.ar((((feed1 * val[0]) + val[1]) * base1).midicps,mul: (val[2] * 50).dbamp).atan,(base3 - (val[3] * (FluidLoudness.kr(feed2,kWeighting:1,truePeak:0, hopSize: 64)[0].clip(-120,0) + 120))).lag(128/44100).midicps, val[4] * 3.5); + osc2 = MoogFF.ar(SinOsc.ar((((feed2 * val[5]) + val[6]) * base2).midicps,mul: (val[7] * 50).dbamp).atan,(base3 - (val[8] * (FluidLoudness.kr(feed1,kWeighting:1,truePeak:0, hopSize: 64)[0].clip(-120,0) + 120))).lag(128/44100).midicps, val[9] * 3.5); Out.ar(0,LeakDC.ar([osc1,osc2],mul: 0.1)); LocalOut.ar([osc1,osc2]); }.play;