├── .gitattributes ├── .github └── workflows │ └── cmake-multi-platform.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── code ├── grainflow.grainRecord.gendsp ├── grainflow.rateSizePhasor.gendsp ├── grainflow.record.gendsp ├── grainflow.sahPhasor.gendsp ├── grainflow.vbap3dnode.gendsp └── grainflow.voice.gendsp ├── create_release.py ├── data └── grainflow.speakersetups.json ├── docs ├── grainflow.biquad~.maxref.xml ├── grainflow.chorus~.maxref.xml ├── grainflow.freeze~.maxref.xml ├── grainflow.function2D.maxref.xml ├── grainflow.harmonize~.maxref.xml ├── grainflow.live~.maxref.xml ├── grainflow.scrubSynth~.maxref.xml ├── grainflow.spatview~.maxref.xml ├── grainflow.streams~.maxref.xml ├── grainflow.sustain~.maxref.xml ├── grainflow.synth~.maxref.xml ├── grainflow.util.3dspread.maxref.xml ├── grainflow.util.bphasor~.maxref.xml ├── grainflow.util.grainRecord~.maxref.xml ├── grainflow.util.listChange.maxref.xml ├── grainflow.util.list~.maxref.xml ├── grainflow.util.multiPan~.maxref.xml ├── grainflow.util.phasor~.maxref.xml ├── grainflow.util.randomRangeList.maxref.xml ├── grainflow.util.rateSizePhasor~.maxref.xml ├── grainflow.util.record~.maxref.xml ├── grainflow.util.sahRandom~.maxref.xml ├── grainflow.util.stereoPan~.maxref.xml ├── grainflow.util.vbap3d.maxref.xml ├── grainflow.waveform~.maxref.xml ├── grainflow~.maxref.xml └── spat │ ├── grainflow.spat.3dspread.maxref.xml │ ├── grainflow.spat.format.maxref.xml │ ├── grainflow.spat.pan~.maxref.xml │ ├── grainflow.spat.phys.add.maxref.xml │ ├── grainflow.spat.phys.drag.maxref.xml │ ├── grainflow.spat.phys.magnets.maxref.xml │ ├── grainflow.spat.phys.maxref.xml │ ├── grainflow.spat.phys.transform.maxref.xml │ ├── grainflow.spat.speakers.maxref.xml │ ├── grainflow.spat.spirograph.maxref.xml │ ├── grainflow.spat.split.maxref.xml │ ├── grainflow.spat.transform.maxref.xml │ ├── grainflow.spat.transformOverLife.maxref.xml │ └── grainflow.spat.volume.maxref.xml ├── extras └── grainflow │ ├── advanced features │ ├── GlissonBuffers.maxpat │ ├── MultichannelSoundfileShuffle.maxpat │ ├── RealtimeTimestretch.maxpat │ ├── Streams │ │ ├── multiharmonizer.maxpat │ │ ├── multiloops.maxpat │ │ └── vmultitap.maxpat │ └── Synthesis │ │ ├── Aviary.maxpat │ │ ├── filterbank.maxpat │ │ ├── granularFMSoundscape.maxpat │ │ └── ksGuitar.maxpat │ ├── examples │ ├── apps │ │ ├── grainFlowApp.maxpat │ │ ├── grainflow.gfapp.defaultbank.json │ │ └── looperApp.maxpat │ └── readymades │ │ ├── chorus.maxpat │ │ ├── harmonizer.maxpat │ │ ├── scrubber.maxpat │ │ └── shuffle.maxpat │ ├── grainflowOverview.maxpat │ └── tutorials │ ├── 01_Grainflow_Basics.maxpat │ ├── 02_Live_Input.maxpat │ ├── 03_Grain_Spatialization.maxpat │ ├── 04_Granular_Synthesis.maxpat │ ├── 05_Parameter_Buffers.maxpat │ ├── 06_Dynamic_Bussing.maxpat │ ├── 07_Grainflow_With_Snowphasor.maxpat │ └── Recipes │ ├── GrainflowRecipe1-Stutter.maxpat │ ├── GrainflowRecipe2-Harmonizer.maxpat │ ├── GrainflowRecipe3-Sustain.maxpat │ └── GrainflowRecipe4-Bubbler.maxpat ├── grainflowimage.psd ├── help ├── fx │ └── grainflow.fx.filter~.maxhelp ├── grainflow.chorus~.maxhelp ├── grainflow.freeze~.maxhelp ├── grainflow.function2D.maxhelp ├── grainflow.harmonize~.maxhelp ├── grainflow.live~.maxhelp ├── grainflow.moddial.maxhelp ├── grainflow.scrubSynth~.maxhelp ├── grainflow.streams~.maxhelp ├── grainflow.sustain~.maxhelp ├── grainflow.synth~.maxhelp ├── grainflow.util.3dspread.maxhelp ├── grainflow.util.bphasor~.maxhelp ├── grainflow.util.genEnv2D.maxhelp ├── grainflow.util.grainRecord~.maxhelp ├── grainflow.util.listChange.maxhelp ├── grainflow.util.list~.maxhelp ├── grainflow.util.multiPan~.maxhelp ├── grainflow.util.phasor~.maxhelp ├── grainflow.util.randomRangeList.maxhelp ├── grainflow.util.rateSizePhasorClassic~.maxhelp ├── grainflow.util.rateSizePhasor~.maxhelp ├── grainflow.util.record~.maxhelp ├── grainflow.util.sahRandom~.maxhelp ├── grainflow.util.stereoPan~.maxhelp ├── grainflow.util.vbap3d.maxhelp ├── grainflow.vbap3d.maxhelp ├── grainflow.waveform~.maxhelp ├── grainflow~.maxhelp └── spat │ ├── grainflow.spat.3dspread.maxhelp │ ├── grainflow.spat.doppler~.maxhelp │ ├── grainflow.spat.format.maxhelp │ ├── grainflow.spat.pan~.maxhelp │ ├── grainflow.spat.phys.add.maxhelp │ ├── grainflow.spat.phys.drag.maxhelp │ ├── grainflow.spat.phys.magnets.maxhelp │ ├── grainflow.spat.phys.maxhelp │ ├── grainflow.spat.phys.transform.maxhelp │ ├── grainflow.spat.speakers.maxhelp │ ├── grainflow.spat.spirograph.maxhelp │ ├── grainflow.spat.split.maxhelp │ ├── grainflow.spat.transform.maxhelp │ ├── grainflow.spat.transformOverLife.maxhelp │ ├── grainflow.spat.volume.maxhelp │ └── grainflow.spatview~.maxhelp ├── icon.png ├── javascript ├── _grainflow.spat.js └── _grainflowutil.js ├── jsui ├── grainFlow.waveform~.js ├── grainflow.function2D.js ├── grainflow.moddial.js └── grainflow.spatview~.js ├── license.txt ├── media ├── CP_Bubbling_Pasta_Sauce.wav ├── CP_Pinball.wav ├── grainflow.2DEnvelope.aif ├── grainflow.Blackman.aif ├── grainflow.FatPluck.aif ├── grainflow.Hamming.aif ├── grainflow.Hanning.aif ├── grainflow.Kaiser.aif ├── grainflow.Pluck.aif ├── grainflow.ReverseFatPluck.aif ├── grainflow.ReversePluck.aif ├── grainflow.Triangle.aif ├── grainflow.icon.click.svg ├── grainflow.icon.freeze.svg ├── grainflow.icon.info.svg ├── grainflow.icon.pingpong.svg ├── grainflow.icon.playBackward.svg ├── grainflow.icon.playForward.svg ├── grainflow.icon.repeat.svg └── grainflow.icon.stop.svg ├── misc ├── grainflow.speakerExample.json ├── grainflow.speakerExample.txt └── grainflow.speakersetups.json ├── package-info.json ├── package-info.json.in ├── patchers ├── _private │ ├── _grainFlow.streamR~.maxpat │ ├── _grainflow.aed2xyz.maxpat │ ├── _grainflow.harmVoice.maxpat │ ├── _grainflow.keyin.maxpat │ ├── _grainflow.poly.freezer.maxpat │ ├── _grainflow.poly.freezer2.maxpat │ ├── _grainflow.poly.maxpat │ ├── _grainflow.poly.multilerp.maxpat │ ├── _grainflow.poly.streams.maxpat │ ├── _grainflow.random~.maxpat │ ├── _grainflow.snapshot~.maxpat │ ├── _grainflow.spat.pointparse.maxpat │ ├── _grainflow.spreadlist.maxpat │ ├── _grainflow.streamReceive~.maxpat │ ├── _grainflow.synth_voice.maxpat │ ├── _grainflow.vbap3dnode.maxpat │ ├── _grainflow.xfade~.maxpat │ ├── _grainflow.xyz2aed.maxpat │ └── _grainflow_mc~.maxpat ├── fx │ ├── grainflow.fx.chorus~.maxpat │ ├── grainflow.fx.filter~.maxpat │ └── grainflow.fx.karplus~.maxpat ├── grainflow.chorus~.maxpat ├── grainflow.freeze~.maxpat ├── grainflow.harmonize~.maxpat ├── grainflow.scrubSynth~.maxpat ├── grainflow.streams~.maxpat ├── grainflow.sustain~.maxpat ├── grainflow.synth~.maxpat ├── grainflow.util.bufferPopulate.maxpat ├── readymades │ ├── grainflow.bp.livegrain.maxpat │ ├── grainflow.readymade.chorus~.maxpat │ ├── grainflow.readymade.cloudhopper.maxpat │ ├── grainflow.readymade.grainDelay~.maxpat │ ├── grainflow.readymade.harmonize~.maxpat │ ├── grainflow.readymade.looper~.maxpat │ ├── grainflow.readymade.scrubber~.maxpat │ ├── grainflow.readymade.shuffle~.maxpat │ └── grainflow.readymade.sustain.maxpat ├── shortcut │ ├── grainflow.function2D.maxpat │ └── grainflow.moddial.maxpat ├── spat │ ├── grainflow.spat.3dspread.maxpat │ ├── grainflow.spat.doppler~.maxpat │ ├── grainflow.spat.format.maxpat │ ├── grainflow.spat.meshphasor~.maxpat │ ├── grainflow.spat.pan~.maxpat │ ├── grainflow.spat.speakers.maxpat │ ├── grainflow.spat.spirograph.maxpat │ ├── grainflow.spat.split.maxpat │ ├── grainflow.spat.transform.maxpat │ ├── grainflow.spat.transformOverLife.maxpat │ ├── grainflow.spat.volume.maxpat │ └── phys │ │ ├── grainflow.spat.phys.add.maxpat │ │ ├── grainflow.spat.phys.drag.maxpat │ │ ├── grainflow.spat.phys.magnets.maxpat │ │ ├── grainflow.spat.phys.maxpat │ │ └── grainflow.spat.phys.transform.maxpat └── util │ ├── grainflow.util.3dspread.maxpat │ ├── grainflow.util.bphasor.maxpat │ ├── grainflow.util.bphasor~.maxpat │ ├── grainflow.util.genEnv2D.maxpat │ ├── grainflow.util.grainRecord~.maxpat │ ├── grainflow.util.grainlerp.maxpat │ ├── grainflow.util.listChange.maxpat │ ├── grainflow.util.list~.maxpat │ ├── grainflow.util.multilerp.maxpat │ ├── grainflow.util.phasor~.maxpat │ ├── grainflow.util.randomRangeList.maxpat │ ├── grainflow.util.random~.maxpat │ ├── grainflow.util.rateSizePhasorClassic~.maxpat │ ├── grainflow.util.rateSizePhasor~.maxpat │ ├── grainflow.util.sahRandom~.maxpat │ └── grainflow.util.vbap3d.maxpat ├── scripts └── removeStyles.py └── source ├── experimental_projects └── grainflow.fx.morphFilter_tilde │ ├── CMakeLists.txt │ └── grainflow.fx.morphFilter_tilde.cpp ├── projects ├── common │ ├── grainflowBase.h │ └── maxBufferReader.h ├── grainflow.live_tilde │ ├── CMakeLists.txt │ ├── grainflow.live_tilde.cpp │ └── grainflow.live_tilde.h ├── grainflow.spatview_tilde │ ├── CMakeLists.txt │ └── grainflow.spatview_tilde.cpp ├── grainflow.util.multipan_tilde │ ├── CMakeLists.txt │ ├── grainflow.util.multipan_tilde.cpp │ └── grainflow.util.multipan_tilde.h ├── grainflow.util.record_tilde │ ├── CMakeLists.txt │ ├── grainflow.util.record_tilde.cpp │ └── grainflow.util.record_tilde.h ├── grainflow.util.stereopan_tilde │ ├── CMakeLists.txt │ ├── grainflow.util.stereopan_tilde.cpp │ └── grainflow.util.stereopan_tilde.h ├── grainflow.waveform_tilde │ ├── CMakeLists.txt │ └── grainflow.waveform_tilde.cpp └── grainflow_tilde │ ├── CMakeLists.txt │ ├── grainflow_tilde.cpp │ └── grainflow_tilde.h └── test_projects └── gftest.biquad_tilde ├── CMakeLists.txt └── gftest.biquad_tilde.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/workflows/cmake-multi-platform.yml: -------------------------------------------------------------------------------- 1 | # This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. 2 | # See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml 3 | name: CMake on multiple platforms 4 | 5 | on: 6 | push: 7 | branches: [ "master", "f/ci_builds" ] 8 | pull_request: 9 | branches: [ "master" ] 10 | 11 | jobs: 12 | build: 13 | runs-on: ${{ matrix.os }} 14 | 15 | strategy: 16 | # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. 17 | fail-fast: true 18 | 19 | 20 | matrix: 21 | os: [macos-latest, windows-latest] 22 | build_type: [Release] 23 | include: 24 | - os: windows-latest 25 | c_compiler: cl 26 | cpp_compiler: cl 27 | - os: macos-latest 28 | c_compiler: clang 29 | cpp_compiler: clang++ 30 | 31 | steps: 32 | - uses: actions/checkout@v4 33 | - name: Checkout submodules 34 | run: git submodule update --init --recursive 35 | - name: Set reusable strings 36 | # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. 37 | id: strings 38 | shell: bash 39 | run: | 40 | echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" 41 | 42 | - name: Configure CMake 43 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 44 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 45 | run: | 46 | cmake -B Build -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} 47 | 48 | - name: Build 49 | # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). 50 | run: | 51 | cmake --build Build --config ${{ matrix.build_type }} 52 | 53 | #- name: Test 54 | # working-directory: ${{ steps.strings.outputs.build-output-dir }} 55 | # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). 56 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 57 | # run: ctest --build-config ${{ matrix.build_type }} 58 | - name: Upload a Build Artifact 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: Grainflow-${{ matrix.os }} 62 | path: ./externals/* 63 | retention-days: 0 64 | compression-level: 6 65 | overwrite: true 66 | include-hidden-files: false 67 | 68 | merge: 69 | runs-on: macos-latest 70 | needs: [build] 71 | steps: 72 | - name: Checkout 73 | uses: actions/checkout@v2.3.4 74 | - name: download-win-externals 75 | uses: actions/download-artifact@v4 76 | with: 77 | name: Grainflow-windows-latest 78 | path: ./externals 79 | - name: download-mac-externals 80 | uses: actions/download-artifact@v4 81 | with: 82 | name: Grainflow-macos-latest 83 | path: ./externals 84 | - name: Make-MaxPack 85 | run: | 86 | python3 create_release.py pack 87 | - name: Upload-MaxPack 88 | uses: actions/upload-artifact@v4 89 | with: 90 | name: GrainflowPackage 91 | path: ./grainflow.maxpack 92 | 93 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __* 2 | sysbuild 3 | *.sdf 4 | *.suo 5 | *.sln 6 | *.opensdf 7 | log.txt 8 | extensions 9 | support 10 | build/ 11 | build-*/ 12 | tests 13 | *.o 14 | *.dylib 15 | tmp 16 | .DS_Store 17 | .vs 18 | package-info.json 19 | 20 | externals/codesign.sh 21 | externals/grainflowExternals.zip 22 | .vscode 23 | grainflow.zip 24 | .secrets 25 | grainflow.maxpack 26 | externals 27 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "source/min-api"] 2 | path = source/min-api 3 | url = https://github.com/composingcap/min-api.git 4 | [submodule "source/min-lib"] 5 | path = source/min-lib 6 | url = https://github.com/Cycling74/min-lib.git 7 | [submodule "source/GrainflowLib"] 8 | path = source/GrainflowLib 9 | url = https://github.com/composingcap/GrainflowLib.git 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(Grainflow) 3 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 4 | 5 | set(BUILD_TEST OFF) 6 | set(BUILD_EXPERIMENTAL OFF) 7 | string(REGEX REPLACE "(.*)/" "" THIS_PACKAGE_NAME "${CMAKE_CURRENT_SOURCE_DIR}") 8 | 9 | if (APPLE) 10 | if (${CMAKE_GENERATOR} MATCHES "Xcode") 11 | if (${XCODE_VERSION} VERSION_LESS 10) 12 | message(STATUS "Xcode 10 or higher is required. Please install from the Mac App Store.") 13 | return () 14 | elseif(${XCODE_VERSION} VERSION_GREATER_EQUAL 12) 15 | set(C74_BUILD_FAT YES) 16 | endif () 17 | endif () 18 | 19 | if (NOT CMAKE_OSX_ARCHITECTURES) 20 | if(C74_BUILD_FAT) 21 | set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "macOS architecture" FORCE) 22 | else() 23 | set(CMAKE_OSX_ARCHITECTURES ${CMAKE_SYSTEM_PROCESSOR} CACHE STRING "macOS architecture" FORCE) 24 | endif() 25 | message("CMAKE_OSX_ARCHITECTURES set to ${CMAKE_OSX_ARCHITECTURES}") 26 | endif() 27 | endif() 28 | 29 | 30 | # Misc setup and subroutines 31 | include(${CMAKE_CURRENT_SOURCE_DIR}/source/min-api/script/min-package.cmake) 32 | 33 | 34 | # Add the Lib, if it exists 35 | if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/source/min-lib/CMakeLists.txt") 36 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/source/min-lib) 37 | endif () 38 | 39 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/source/GrainflowLib) 40 | 41 | 42 | # Generate a project for every folder in the "source/projects" folder 43 | SUBDIRLIST(PROJECT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/source/projects) 44 | foreach (project_dir ${PROJECT_DIRS}) 45 | if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/source/projects/${project_dir}/CMakeLists.txt") 46 | message("Generating: ${project_dir}") 47 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/source/projects/${project_dir}) 48 | endif () 49 | endforeach () 50 | 51 | 52 | if (BUILD_TEST) 53 | message("Test externals enabled.") 54 | SUBDIRLIST(PROJECT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/source/test_projects) 55 | foreach (project_dir ${PROJECT_DIRS}) 56 | if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/source/test_projects/${project_dir}/CMakeLists.txt") 57 | message("Generating: ${project_dir}") 58 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/source/test_projects/${project_dir}) 59 | endif () 60 | endforeach () 61 | endif () 62 | 63 | if (BUILD_EXPERIMENTAL) 64 | message("Experimental externals enabled.") 65 | SUBDIRLIST(PROJECT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/source/experimental_projects) 66 | foreach (project_dir ${PROJECT_DIRS}) 67 | if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/source/experimental_projects/${project_dir}/CMakeLists.txt") 68 | message("Generating: ${project_dir}") 69 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/source/experimental_projects/${project_dir}) 70 | endif () 71 | endforeach () 72 | endif () 73 | # Comment the line below if you want automatic cmake regneration enabled 74 | set(CMAKE_SUPPRESS_REGENERATION true) 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Grainflow is a powerful granulation tool build for Max designed to be as flexible as possible to allow for rapid experimentation with granulation. Grainflow is a synchronous and sample accurate granulator that is scheduled entirely on Max's audio thread while offering a toolkit of vast customization. 2 | 3 | 4 | ## Key Features 5 | - Multichannel soundfile and live granulation 6 | - Control of grains using mc signals 7 | - Use custom envelopes including 2D buffers 8 | - Per grain spatialization in both circular and 3D panning 9 | - Graphical tools to help visualize grains on a waveform and in 3D spatialization 10 | - A suite of prebuilt granular effects that can be dropped in to patches or used as a reference 11 | - Per grain attribute control that acts similar to the MC system 12 | 13 | 14 | ## Installation via Precompiled Package 15 | *Major releases will always be avalible through the Max Package Manager, but if you like living on the edge, you can download prereleases and ci builds or build from source.* 16 | 1. Download the latest signed [release](https://github.com/composingcap/grainflow/releases) or **unsigned** [ci-build](https://nightly.link/composingcap/grainflow/workflows/cmake-multi-platform/master/GrainflowPackage.zip) 17 | 2. Unzip the package and drag **grainflow.maxpack** into any Max window or open it with Max 18 | 19 | ## Advanced Features 20 | - Set delay, window placement, and pitch as banks using buffers 21 | - Support for grouping grains into streams 22 | - Set grain level loop points 23 | - Set glisson curves using Max buffers 24 | - Provides detailed grain information 25 | 26 | ## How to contribute 27 | Grainflow is open to contributions both in terms of Max examples, abstractions, and help file improvements as well as help with the C++ codebase in `./source` and the [GrainflowLib](https://github.com/composingcap/GrainflowLib) repository. \ 28 | Additionally, please post any feature requests to [Issues](https://github.com/composingcap/grainflow/issues) or the Grainflow Discord. \ 29 | We are also happy to assist in implementation of GrainflowLib outside of Max and am planning to target other platforms as I have time. 30 | ## Building from source 31 | Building from source is the best way to ensure you get the most up-to-date changes 32 | 33 | Currently grainflow has only ben tested on Windows 11 and Mac OS 14 34 | You must have [cmake](https://cmake.org/) and Visual Studio (Windows) or Xcode (Mac) 35 | ### Downloading the repo 36 | Open a terminal window in the directory you would like to place grainflow. 37 | If you would like to place grainflow in you Max Packages directory, make sure to remove any other grainflow folder. 38 | ``` 39 | git clone https://github.com/composingcap/grainflow.git --recursive 40 | ``` 41 | ### Building grainflow externals 42 | 43 | #### Windows: 44 | *Windows builds should use the MSVC compiler* 45 | ``` 46 | cd ./grainflow 47 | mkdir ./build 48 | cd build 49 | cmake ../ 50 | cmake --build . --config Release 51 | ``` 52 | #### Mac: 53 | *Mac builds should use the Xcode compiler (not clang)* 54 | ``` 55 | cd ./grainflow 56 | mkdir ./build 57 | cd build 58 | cmake ../ -G Xcode 59 | cmake --build 60 | ``` 61 | 62 | ### With python: 63 | This build script should work on most platforms. You may also sign externals with an apple developer ID and create a MaxPack. 64 | #### build 65 | ``` 66 | python3 ./create_release.py build 67 | ``` 68 | #### code sign and notarize 69 | *this requires an apple developer ID* 70 | 1. create a json keystore `./.secrets/keystore.json` 71 | 2. add your developer key as `developer_team_code` 72 | 3. run: 73 | ``` 74 | python3 ./create_release.py sign 75 | ``` 76 | 4. copy the submission ID when prompted 77 | 78 | #### pack 79 | ``` 80 | python3 ./create_release.py pack 81 | ``` 82 | 83 | -------------------------------------------------------------------------------- /code/grainflow.grainRecord.gendsp: -------------------------------------------------------------------------------- 1 | { 2 | "patcher" : { 3 | "fileversion" : 1, 4 | "appversion" : { 5 | "major" : 8, 6 | "minor" : 3, 7 | "revision" : 1, 8 | "architecture" : "x64", 9 | "modernui" : 1 10 | } 11 | , 12 | "classnamespace" : "dsp.gen", 13 | "rect" : [ 740.0, 739.0, 1294.0, 480.0 ], 14 | "bglocked" : 0, 15 | "openinpresentation" : 0, 16 | "default_fontsize" : 10.0, 17 | "default_fontface" : 0, 18 | "default_fontname" : "Futura Medium", 19 | "gridonopen" : 1, 20 | "gridsize" : [ 15.0, 15.0 ], 21 | "gridsnaponopen" : 1, 22 | "objectsnaponopen" : 1, 23 | "statusbarvisible" : 2, 24 | "toolbarvisible" : 1, 25 | "lefttoolbarpinned" : 0, 26 | "toptoolbarpinned" : 0, 27 | "righttoolbarpinned" : 0, 28 | "bottomtoolbarpinned" : 0, 29 | "toolbars_unpinned_last_save" : 0, 30 | "tallnewobj" : 0, 31 | "boxanimatetime" : 200, 32 | "enablehscroll" : 1, 33 | "enablevscroll" : 1, 34 | "devicewidth" : 0.0, 35 | "description" : "", 36 | "digest" : "", 37 | "tags" : "", 38 | "style" : "Minimal", 39 | "subpatcher_template" : "minimal", 40 | "assistshowspatchername" : 0, 41 | "boxes" : [ { 42 | "box" : { 43 | "id" : "obj-3", 44 | "maxclass" : "newobj", 45 | "numinlets" : 0, 46 | "numoutlets" : 1, 47 | "outlettype" : [ "" ], 48 | "patching_rect" : [ 776.0, 55.0, 27.0, 21.0 ], 49 | "text" : "in 3" 50 | } 51 | 52 | } 53 | , { 54 | "box" : { 55 | "id" : "obj-9", 56 | "maxclass" : "newobj", 57 | "numinlets" : 1, 58 | "numoutlets" : 0, 59 | "patching_rect" : [ 683.0, 500.0, 35.0, 21.0 ], 60 | "text" : "out 2" 61 | } 62 | 63 | } 64 | , { 65 | "box" : { 66 | "id" : "obj-2", 67 | "maxclass" : "newobj", 68 | "numinlets" : 0, 69 | "numoutlets" : 1, 70 | "outlettype" : [ "" ], 71 | "patching_rect" : [ 675.0, 30.0, 27.0, 21.0 ], 72 | "text" : "in 2" 73 | } 74 | 75 | } 76 | , { 77 | "box" : { 78 | "code" : "Param trav(1);\r\nParam ngrains(4);\r\nParam rec(0);\r\nParam travRandom(0);\r\nParam overdub(0);\r\nBuffer buf();\r\nBuffer env();\r\n\r\nData travPos(1000);\r\nData lastWindowPosition(1000);\r\nData grainInitFlag(1000);\r\n\r\nHistory baseTravPos(0);\r\n\r\ninput = in1;\r\n\r\ngrainclock = in2;\r\n\r\ndelaySampled = mstosamps(in3);\r\n\r\nif (rec==1){\r\n\t\r\n\tbaseTravPos = wrap(baseTravPos+(1/trav)/(dim(buf)),0,1);\r\n\tbaseTravSamp = floor(dim(buf)*baseTravPos);\r\n\r\n\tpoke(buf, 0, (baseTravSamp-vectorsize*3), (mc_channel-1), overdub, boundmode=\"wrap\" );\r\n\t\r\n\r\n\t\r\n\tfor (g = 0 ; g < ngrains; g+=1){\r\n\t\tmyLastWindowPosition = peek(lastWindowPosition,g);\r\n\t\tmyWindowPosition = wrap(grainclock+g/ngrains,0,1);\r\n\t\t\r\n\t\tif (myWindowPosition - myLastWindowPosition < 0){\r\n\t\t\tpoke(grainInitFlag,1,g);\r\n\t\t\tmyTravPos = baseTravSamp+(mstosamps(((noise()+1)*0.5)*travRandom)) + delaySampled;\r\n\t\t\tpoke(travPos, myTravPos ,g);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\tmyGrainInitFlag = peek(grainInitFlag,g);\r\n\t\tif (myGrainInitFlag == 1){\r\n\t\t\tgrainEnv = peek(env, myWindowPosition, 0, index=\"phase\");\r\n\t\t\tgrainRec = input*grainEnv; \r\n\t\t\tmyTravPos = peek(travPos,g);\r\n\t\t\tpoke(buf, grainRec, myTravPos,(mc_channel-1)%dim(buf), 1, boundmode=\"wrap\", overdubmode=\"accum\");\r\n\t\t\tpoke(travPos,myTravPos+1,g);\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t}\r\n\t\t\tpoke(lastWindowPosition, myWindowPosition, g);\r\n\t\t\r\n\t\t}\r\n\t\r\n\r\n}\r\n\r\n\r\nout1 =wrap(baseTravPos-vectorsize/dim(buf),0,1);\r\nout2 =wrap(baseTravPos-((vectorsize+mstosamps(travRandom))/dim(buf)),0,1);\r\n", 79 | "fontface" : 0, 80 | "fontname" : "", 81 | "fontsize" : 10.0, 82 | "id" : "obj-5", 83 | "maxclass" : "codebox", 84 | "numinlets" : 3, 85 | "numoutlets" : 2, 86 | "outlettype" : [ "", "" ], 87 | "patching_rect" : [ 24.0, 79.0, 678.0, 388.0 ] 88 | } 89 | 90 | } 91 | , { 92 | "box" : { 93 | "id" : "obj-1", 94 | "maxclass" : "newobj", 95 | "numinlets" : 0, 96 | "numoutlets" : 1, 97 | "outlettype" : [ "" ], 98 | "patching_rect" : [ 24.0, 34.0, 27.0, 21.0 ], 99 | "text" : "in 1" 100 | } 101 | 102 | } 103 | , { 104 | "box" : { 105 | "id" : "obj-4", 106 | "maxclass" : "newobj", 107 | "numinlets" : 1, 108 | "numoutlets" : 0, 109 | "patching_rect" : [ 24.0, 488.0, 35.0, 21.0 ], 110 | "text" : "out 1" 111 | } 112 | 113 | } 114 | ], 115 | "lines" : [ { 116 | "patchline" : { 117 | "destination" : [ "obj-5", 0 ], 118 | "source" : [ "obj-1", 0 ] 119 | } 120 | 121 | } 122 | , { 123 | "patchline" : { 124 | "destination" : [ "obj-5", 1 ], 125 | "source" : [ "obj-2", 0 ] 126 | } 127 | 128 | } 129 | , { 130 | "patchline" : { 131 | "destination" : [ "obj-5", 2 ], 132 | "source" : [ "obj-3", 0 ] 133 | } 134 | 135 | } 136 | , { 137 | "patchline" : { 138 | "destination" : [ "obj-4", 0 ], 139 | "source" : [ "obj-5", 0 ] 140 | } 141 | 142 | } 143 | , { 144 | "patchline" : { 145 | "destination" : [ "obj-9", 0 ], 146 | "source" : [ "obj-5", 1 ] 147 | } 148 | 149 | } 150 | ], 151 | "styles" : [ { 152 | "name" : "Minimal", 153 | "default" : { 154 | "accentcolor" : [ 0.0, 0.0, 0.0, 1.0 ], 155 | "bgcolor" : [ 0.999999, 0.999974, 0.999991, 1.0 ], 156 | "bgfillcolor" : { 157 | "angle" : 270.0, 158 | "autogradient" : 0.0, 159 | "color" : [ 0.65098, 0.666667, 0.662745, 1.0 ], 160 | "color1" : [ 0.65098, 0.666667, 0.662745, 1.0 ], 161 | "color2" : [ 0.290196, 0.309804, 0.301961, 1.0 ], 162 | "proportion" : 0.39, 163 | "type" : "color" 164 | } 165 | , 166 | "color" : [ 0.0, 0.0, 0.0, 1.0 ], 167 | "elementcolor" : [ 0.999999, 0.999974, 0.999991, 1.0 ], 168 | "fontface" : [ 0 ], 169 | "fontname" : [ "Futura Medium" ], 170 | "fontsize" : [ 10.0 ], 171 | "selectioncolor" : [ 0.0, 0.0, 0.0, 1.0 ], 172 | "textcolor_inverse" : [ 0.0, 0.0, 0.0, 1.0 ] 173 | } 174 | , 175 | "parentstyle" : "", 176 | "multi" : 0 177 | } 178 | ], 179 | "editing_bgcolor" : [ 0.956862745098039, 0.956862745098039, 0.956862745098039, 1.0 ] 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /code/grainflow.rateSizePhasor.gendsp: -------------------------------------------------------------------------------- 1 | { 2 | "patcher" : { 3 | "fileversion" : 1, 4 | "appversion" : { 5 | "major" : 9, 6 | "minor" : 0, 7 | "revision" : 0, 8 | "architecture" : "x64", 9 | "modernui" : 1 10 | } 11 | , 12 | "classnamespace" : "dsp.gen", 13 | "rect" : [ 201.0, 225.0, 1083.0, 597.0 ], 14 | "gridsize" : [ 15.0, 15.0 ], 15 | "style" : "Grainflow", 16 | "subpatcher_template" : "minimal", 17 | "boxes" : [ { 18 | "box" : { 19 | "id" : "obj-3", 20 | "maxclass" : "newobj", 21 | "numinlets" : 0, 22 | "numoutlets" : 1, 23 | "outlettype" : [ "" ], 24 | "patching_rect" : [ 393.0, 432.0, 71.0, 23.0 ], 25 | "text" : "mc_channel" 26 | } 27 | 28 | } 29 | , { 30 | "box" : { 31 | "id" : "obj-2", 32 | "maxclass" : "newobj", 33 | "numinlets" : 1, 34 | "numoutlets" : 0, 35 | "patching_rect" : [ 901.0, 487.0, 36.0, 23.0 ], 36 | "text" : "out 2" 37 | } 38 | 39 | } 40 | , { 41 | "box" : { 42 | "code" : "\r\nParam size(100);\r\nParam ngrains(0);\r\nParam jitter(0);\r\n\r\nHistory enabled(0);\r\nHistory p(0);\r\nHistory increment (0);\r\nHistory lastClock(0);\r\n\r\nclock = in1;\r\noffset = (mc_channel-1)/ngrains;\r\n\r\n\r\n\r\nif (!enabled){\r\n\tp = 0;\t\r\n\tif (mc_channel <= ngrains){\r\n\tif ((wrap(clock+offset+noise()*jitter,0,1))< 0.001) {\r\n\t\tif (clock != lastClock){\r\n\t\tenabled = 1;\r\n\t\t\r\n\t\t}\r\n\t\t}\r\n\t}\r\n\t}\r\n\t\r\nif(enabled){\r\n\tincrement = 1/mstosamps(size);\r\n\tp += increment;\r\n\t\r\n\tif (p>=1){\r\n\t\tenabled = 0;\r\n\t\t}\r\n\t\r\n\t}\r\n\t\r\nlastClock = clock;\r\nout1 = p;\r\nout2 = offset;", 43 | "fontface" : 0, 44 | "fontname" : "", 45 | "fontsize" : 12.0, 46 | "id" : "obj-7", 47 | "maxclass" : "codebox", 48 | "numinlets" : 1, 49 | "numoutlets" : 2, 50 | "outlettype" : [ "", "" ], 51 | "patching_rect" : [ 169.0, 58.0, 768.0, 370.0 ] 52 | } 53 | 54 | } 55 | , { 56 | "box" : { 57 | "id" : "obj-1", 58 | "maxclass" : "newobj", 59 | "numinlets" : 0, 60 | "numoutlets" : 1, 61 | "outlettype" : [ "" ], 62 | "patching_rect" : [ 169.0, 25.0, 28.0, 23.0 ], 63 | "text" : "in 1" 64 | } 65 | 66 | } 67 | , { 68 | "box" : { 69 | "id" : "obj-4", 70 | "maxclass" : "newobj", 71 | "numinlets" : 1, 72 | "numoutlets" : 0, 73 | "patching_rect" : [ 165.0, 437.0, 36.0, 23.0 ], 74 | "text" : "out 1" 75 | } 76 | 77 | } 78 | ], 79 | "lines" : [ { 80 | "patchline" : { 81 | "destination" : [ "obj-7", 0 ], 82 | "source" : [ "obj-1", 0 ] 83 | } 84 | 85 | } 86 | , { 87 | "patchline" : { 88 | "destination" : [ "obj-2", 0 ], 89 | "source" : [ "obj-7", 1 ] 90 | } 91 | 92 | } 93 | , { 94 | "patchline" : { 95 | "destination" : [ "obj-4", 0 ], 96 | "source" : [ "obj-7", 0 ] 97 | } 98 | 99 | } 100 | ], 101 | "originid" : "pat-280", 102 | "styles" : [ { 103 | "name" : "Grainflow", 104 | "default" : { 105 | "bgcolor" : [ 0.0, 0.0, 0.0, 1.0 ], 106 | "color" : [ 0.470588235294118, 1.0, 0.403921568627451, 1.0 ], 107 | "editing_bgcolor" : [ 0.333333333333333, 0.333333333333333, 0.333333333333333, 1.0 ], 108 | "fontname" : [ "Lato Medium" ], 109 | "fontsize" : [ 12.0 ], 110 | "locked_bgcolor" : [ 0.313725490196078, 0.313725490196078, 0.313725490196078, 1.0 ], 111 | "syntax_attrargcolor" : [ 1.0, 1.0, 1.0, 1.0 ], 112 | "syntax_attributecolor" : [ 0.807843137254902, 1.0, 0.784313725490196, 1.0 ], 113 | "syntax_objectcolor" : [ 0.470588235294118, 1.0, 0.403921568627451, 1.0 ] 114 | } 115 | , 116 | "parentstyle" : "", 117 | "multi" : 0 118 | } 119 | ] 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /code/grainflow.vbap3dnode.gendsp: -------------------------------------------------------------------------------- 1 | { 2 | "patcher" : { 3 | "fileversion" : 1, 4 | "appversion" : { 5 | "major" : 8, 6 | "minor" : 1, 7 | "revision" : 11, 8 | "architecture" : "x64", 9 | "modernui" : 1 10 | } 11 | , 12 | "classnamespace" : "dsp.gen", 13 | "rect" : [ 1373.0, 622.0, 1059.0, 450.0 ], 14 | "bglocked" : 0, 15 | "openinpresentation" : 0, 16 | "default_fontsize" : 12.0, 17 | "default_fontface" : 0, 18 | "default_fontname" : "Arial", 19 | "gridonopen" : 1, 20 | "gridsize" : [ 15.0, 15.0 ], 21 | "gridsnaponopen" : 1, 22 | "objectsnaponopen" : 1, 23 | "statusbarvisible" : 2, 24 | "toolbarvisible" : 1, 25 | "lefttoolbarpinned" : 0, 26 | "toptoolbarpinned" : 0, 27 | "righttoolbarpinned" : 0, 28 | "bottomtoolbarpinned" : 0, 29 | "toolbars_unpinned_last_save" : 0, 30 | "tallnewobj" : 0, 31 | "boxanimatetime" : 200, 32 | "enablehscroll" : 1, 33 | "enablevscroll" : 1, 34 | "devicewidth" : 0.0, 35 | "description" : "", 36 | "digest" : "", 37 | "tags" : "", 38 | "style" : "", 39 | "subpatcher_template" : "", 40 | "assistshowspatchername" : 0, 41 | "boxes" : [ { 42 | "box" : { 43 | "id" : "obj-5", 44 | "maxclass" : "newobj", 45 | "numinlets" : 0, 46 | "numoutlets" : 1, 47 | "outlettype" : [ "" ], 48 | "patching_rect" : [ 552.333333333333371, 22.0, 28.0, 22.0 ], 49 | "text" : "in 4" 50 | } 51 | 52 | } 53 | , { 54 | "box" : { 55 | "id" : "obj-1", 56 | "maxclass" : "newobj", 57 | "numinlets" : 0, 58 | "numoutlets" : 1, 59 | "outlettype" : [ "" ], 60 | "patching_rect" : [ 394.333333333333371, 27.0, 28.0, 22.0 ], 61 | "text" : "in 3" 62 | } 63 | 64 | } 65 | , { 66 | "box" : { 67 | "code" : "Param x;\r\nParam y;\r\nParam z;\r\n\r\nParam soundingDistance(1);\r\n\r\nx1 = in2;\r\ny1 = in3;\r\nz1 = in4;\r\n\r\n\r\n\r\ndx = x1-x;\r\ndy = y1-y;\r\ndz = z1-z;\r\n\r\ndistance = sqrt(dx*dx+dy*dy+dz*dz);\r\n\r\nout1 = in1*pow(clip(1-distance,0,soundingDistance)/soundingDistance,2);", 68 | "fontface" : 0, 69 | "fontname" : "", 70 | "fontsize" : 12.0, 71 | "id" : "obj-10", 72 | "maxclass" : "codebox", 73 | "numinlets" : 4, 74 | "numoutlets" : 1, 75 | "outlettype" : [ "" ], 76 | "patching_rect" : [ 50.0, 103.0, 506.0, 207.0 ] 77 | } 78 | 79 | } 80 | , { 81 | "box" : { 82 | "id" : "obj-3", 83 | "maxclass" : "newobj", 84 | "numinlets" : 0, 85 | "numoutlets" : 1, 86 | "outlettype" : [ "" ], 87 | "patching_rect" : [ 207.333333333333371, 27.0, 28.0, 22.0 ], 88 | "text" : "in 2" 89 | } 90 | 91 | } 92 | , { 93 | "box" : { 94 | "id" : "obj-2", 95 | "maxclass" : "newobj", 96 | "numinlets" : 0, 97 | "numoutlets" : 1, 98 | "outlettype" : [ "" ], 99 | "patching_rect" : [ 50.0, 27.0, 28.0, 22.0 ], 100 | "text" : "in 1" 101 | } 102 | 103 | } 104 | , { 105 | "box" : { 106 | "id" : "obj-4", 107 | "maxclass" : "newobj", 108 | "numinlets" : 1, 109 | "numoutlets" : 0, 110 | "patching_rect" : [ 54.0, 389.0, 35.0, 22.0 ], 111 | "text" : "out 1" 112 | } 113 | 114 | } 115 | ], 116 | "lines" : [ { 117 | "patchline" : { 118 | "destination" : [ "obj-10", 2 ], 119 | "source" : [ "obj-1", 0 ] 120 | } 121 | 122 | } 123 | , { 124 | "patchline" : { 125 | "destination" : [ "obj-4", 0 ], 126 | "source" : [ "obj-10", 0 ] 127 | } 128 | 129 | } 130 | , { 131 | "patchline" : { 132 | "destination" : [ "obj-10", 0 ], 133 | "source" : [ "obj-2", 0 ] 134 | } 135 | 136 | } 137 | , { 138 | "patchline" : { 139 | "destination" : [ "obj-10", 1 ], 140 | "source" : [ "obj-3", 0 ] 141 | } 142 | 143 | } 144 | , { 145 | "patchline" : { 146 | "destination" : [ "obj-10", 3 ], 147 | "source" : [ "obj-5", 0 ] 148 | } 149 | 150 | } 151 | ] 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /create_release.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import subprocess 4 | import json 5 | from getpass import getpass 6 | import platform 7 | import sys 8 | import re 9 | 10 | 11 | keystorePath = "./.secrets/keystore.json" 12 | paths_to_remove = ["/build", "/source", "/CMakeLists.txt", "/create_release.py", "/.git", "/.gitmodules", "/.gitignore", "/.vscode", "/.gitattributes"] 13 | paths_to_include = ["/code", "/data", "/docs", "/help", "/javascript", "/jsui", "/externals", "/media", "/misc", "/patchers", "/extras", "/icon.png", "/license.txt", "/README.md", "/package-info.json"] 14 | externals = [] 15 | mac_externals = [] 16 | 17 | generator = "-G Xcode" if (platform.system() == "Darwin") else "" 18 | 19 | def cmake_build(): 20 | print("configuring with cmake...") 21 | if (os.path.isdir("./build")): 22 | shutil.rmtree("./build") 23 | os.mkdir("./build") 24 | p = subprocess.Popen(["cmake", "-B./build", "-S.", f'{generator}']) 25 | p.wait() 26 | print("building with cmake...") 27 | p = subprocess.Popen(["cmake", "--build", "build", "--config", "Release"]) 28 | p.wait() 29 | print("Build Complete!") 30 | 31 | def macos_codesign(): 32 | if (platform.system() != "Darwin"): 33 | print("not on mac os and connot sign") 34 | return 35 | macoskey = "" 36 | with open(keystorePath) as keystore: 37 | keys = json.load(keystore) 38 | macoskey = keys["developer_team_code"] 39 | 40 | if len(macoskey) <= 0: 41 | print("err: not valid key found") 42 | return 43 | 44 | dest = "./externals/grainflowExternals_temp" 45 | archive = "./externals/grainflowExternals" 46 | if os.path.isdir(dest): 47 | shutil.rmtree(dest) 48 | os.mkdir(dest) 49 | 50 | externals = os.listdir("./externals") 51 | mac_externals = [ s for s in externals if re.search(r"\.mxo$", s) ] 52 | 53 | 54 | print(mac_externals) 55 | if (len(mac_externals) <= 0): return 56 | for external in mac_externals: 57 | ex_path = f'./externals/{external}' 58 | cmd = f'sudo codesign -s {macoskey} --options runtime --timestamp --force --deep -f {ex_path}' 59 | p = subprocess.Popen(cmd, shell=True) 60 | p.wait() 61 | shutil.copytree(ex_path, dest + f'/{external}') 62 | 63 | 64 | 65 | print("zipping into archive for submission...") 66 | if os.path.isfile(archive+".zip"): 67 | os.remove(archive+".zip") 68 | shutil.make_archive(archive, "zip", dest) 69 | 70 | print("Uploading for approval...") 71 | 72 | cmd = f'xcrun notarytool submit {archive}.zip --keychain-profile grainflow' 73 | p = subprocess.Popen(cmd, shell=True) 74 | p.wait() 75 | output, error = p.communicate() 76 | submissionid = input("ID: ") 77 | cmd = f'xcrun notarytool wait --keychain-profile grainflow {submissionid}' 78 | p = subprocess.Popen(cmd, shell=True) 79 | p.wait() 80 | for external in mac_externals: 81 | shutil.rmtree(f'./externals/{external}') 82 | shutil.unpack_archive(archive+".zip", "./externals") 83 | mac_staple() 84 | shutil.rmtree(dest) 85 | os.remove(archive+".zip") 86 | 87 | def package_release(): 88 | src = "./" 89 | dest = "./release" 90 | archive = "./grainflow" 91 | externals = os.listdir("./externals") 92 | 93 | if os.path.isdir(dest): 94 | shutil.rmtree(dest) 95 | if os.path.isfile(archive+".maxpack"): 96 | os.remove(archive+".maxpack") 97 | 98 | print("copying all files into release folder") 99 | 100 | for p in paths_to_include: 101 | src_path = src+p 102 | dest_path = dest+p 103 | print(f'copying {p}') 104 | if os.path.isdir(src_path): 105 | shutil.copytree(src_path, dest_path) 106 | if os.path.isfile(src_path): 107 | shutil.copy2(src_path, dest_path) 108 | 109 | reposition_max_patches(dest, 20,20) 110 | print("zipping...") 111 | shutil.make_archive(archive, 'zip', dest) 112 | os.rename(f"{archive}.zip", f"{archive}.maxpack") 113 | print(f"Created {archive}.maxpack") 114 | print("cleaning up") 115 | shutil.rmtree(dest) 116 | 117 | def reposition_max_patches(dir, x, y): 118 | #Reposition all windows 119 | print(f"Repositioning all patcher windows to {x},{y}") 120 | for root, dirs, files in os.walk(dir): 121 | for file in files: 122 | if file.endswith(".maxpat") or file.endswith(".maxhelp"): 123 | path = os.path.join(root, file) 124 | maxfile = open(path) 125 | maxtxt = maxfile.read() 126 | maxfile.close() 127 | maxjson = json.loads(maxtxt) 128 | bounds = maxjson['patcher']['rect'] 129 | bounds[0] = x 130 | bounds[1] = y 131 | maxjson['patcher']['rect'] = bounds 132 | maxtxt = json.dumps(maxjson, indent= 4) 133 | os.remove(path) 134 | maxfile = open(path, 'w') 135 | maxfile.write(maxtxt) 136 | maxfile.close() 137 | 138 | def mac_staple(): 139 | if (platform.system() != "Darwin"): return 140 | externals = os.listdir("./externals") 141 | mac_externals = [ s for s in externals if re.search(r"\.mxo$", s) ] 142 | for external in mac_externals: 143 | cmd = f'xcrun stapler staple ./externals/{external}' 144 | p = subprocess.Popen(cmd, shell=True) 145 | p.wait() 146 | 147 | def mac_validate(): 148 | if (platform.system() != "Darwin"): return 149 | externals = os.listdir("./externals") 150 | mac_externals = [ s for s in externals if re.search(r"\.mxo$", s) ] 151 | for external in mac_externals: 152 | print(f"===== {external} ======") 153 | cmd = f'codesign -dv --verbose=4 ./externals/{external}' 154 | p = subprocess.Popen(cmd, shell=True) 155 | p.wait() 156 | print("\n") 157 | 158 | def main(): 159 | args = sys.argv 160 | modes = [] 161 | 162 | 163 | if len(args) > 1: 164 | modes = args[1:] 165 | if ('all' in modes): 166 | cmake_build() 167 | macos_codesign() 168 | package_release() 169 | if ('build' in modes): cmake_build() 170 | if ('sign' in modes): macos_codesign() 171 | if ('staple' in modes): mac_staple() 172 | if('validate' in modes): mac_validate() 173 | if ('pack' in modes): package_release() 174 | 175 | 176 | if len(args) <= 1: 177 | res = input("Would you like to build for your current platform? (Y/N)" ) 178 | if res.lower() == 'y': 179 | cmake_build() 180 | if (platform.system() == "Darwin"): 181 | res = input("Would you like to codesign? (Y/N)" ) 182 | if res.lower() == 'y': 183 | macos_codesign() 184 | res = input("Would you like to zip a release package? (Y/N)" ) 185 | if res.lower() == 'y': 186 | package_release() 187 | 188 | if __name__=="__main__": 189 | main() -------------------------------------------------------------------------------- /data/grainflow.speakersetups.json: -------------------------------------------------------------------------------- 1 | { 2 | "8ch stereo pairs" : { 3 | "speakers" : { 4 | "1" : [ -0.4, 1, 0 ], 5 | "2" : [ 0.4, 1, 0 ], 6 | "3" : [ -1, 0.4, 0 ], 7 | "4" : [ 1, 0.4, 0 ], 8 | "5" : [ -1, -0.4, 0 ], 9 | "6" : [ 1, -0.4, 0 ], 10 | "7" : [ -0.4, -1, 0 ], 11 | "8" : [ 0.4, -1, 0 ] 12 | } 13 | , 14 | "falloffDistance" : 1.5, 15 | "falloffCurve" : -1, 16 | "dimmask" : [ 1, 1, 0 ] 17 | } 18 | , 19 | "8ch double diamond" : { 20 | "speakers" : { 21 | "1" : [ 0, 1, 0 ], 22 | "2" : [ 0.5, 0.5, 0 ], 23 | "3" : [ 1, 0, 0 ], 24 | "4" : [ 0.5, -0.5, 0 ], 25 | "5" : [ 0, -1, 0 ], 26 | "6" : [ -0.5, -0.5, 0 ], 27 | "7" : [ -1, 0, 0 ], 28 | "8" : [ -0.5, 0.5, 0 ] 29 | } 30 | , 31 | "falloffDistance" : 1, 32 | "falloffCurve" : -1, 33 | "dimmask" : [ 1, 1, 0 ] 34 | } 35 | , 36 | "stereo" : { 37 | "speakers" : { 38 | "1" : [ -1, 0, 0 ], 39 | "2" : [ 1, 0, 0 ] 40 | } 41 | , 42 | "falloffDistance" : 1.5, 43 | "falloffCurve" : -1, 44 | "dimmask" : [ 1, 0, 0 ] 45 | } 46 | , 47 | "quad" : { 48 | "speakers" : { 49 | "1" : [ -1, 1, 0 ], 50 | "2" : [ 1, 1, 0 ], 51 | "3" : [ -1, -1, 0 ], 52 | "4" : [ 1, -1, 0 ] 53 | } 54 | , 55 | "falloffDistance" : 1.5, 56 | "falloffCurve" : -1, 57 | "dimmask" : [ 1, 1, 0 ] 58 | } 59 | , 60 | "5ch surround" : { 61 | "speakers" : { 62 | "1" : [ -1, 1, 0 ], 63 | "2" : [ 1, 1, 0 ], 64 | "3" : [ 0, 1, 0 ], 65 | "4" : [ -1, -1, 0 ], 66 | "5" : [ 1, -1, 0 ] 67 | } 68 | , 69 | "falloffDistance" : 1.5, 70 | "falloffCurve" : -1, 71 | "dimmask" : [ 1, 1, 0 ] 72 | } 73 | , 74 | "7ch surround" : { 75 | "speakers" : { 76 | "1" : [ -1, 1, 0 ], 77 | "2" : [ 1, 1, 0 ], 78 | "3" : [ 0, 1, 0 ], 79 | "4" : [ -1, -1, 0 ], 80 | "5" : [ 1, -1, 0 ], 81 | "6" : [ -1, 0, 0 ], 82 | "7" : [ 1, 0, 0 ] 83 | } 84 | , 85 | "falloffDistance" : 1.5, 86 | "falloffCurve" : -1, 87 | "dimmask" : [ 1, 1, 0 ] 88 | } 89 | , 90 | "16ch Stacked Stereo Pairs" : { 91 | "speakers" : { 92 | "1" : [ -0.4, 1, 0 ], 93 | "2" : [ 0.4, 1, 0 ], 94 | "3" : [ -1, 0.4, 0 ], 95 | "4" : [ 1, 0.4, 0 ], 96 | "5" : [ -1, -0.4, 0 ], 97 | "6" : [ 1, -0.4, 0 ], 98 | "7" : [ -0.4, -1, 0 ], 99 | "8" : [ 0.4, -1, 0 ], 100 | "9" : [ -0.4, 1, 1 ], 101 | "10" : [ 0.4, 1, 1 ], 102 | "11" : [ -1, 0.4, 1 ], 103 | "12" : [ 1, 0.4, 1 ], 104 | "13" : [ -1, -0.4, 1 ], 105 | "14" : [ 1, -0.4, 1 ], 106 | "15" : [ -0.4, -1, 1 ], 107 | "16" : [ 0.4, -1, 1 ] 108 | } 109 | , 110 | "falloffDistance" : 0.75, 111 | "falloffCurve" : -1, 112 | "dimmask" : [ 1, 1, 1 ] 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /docs/grainflow.biquad~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Biquad Test 10 | Biquad Test 11 | 12 | 13 | 14 | 15 | 16 | Christopher Poovey 17 | granulation 18 | msp 19 | grainflow 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/grainflow.spatview~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Visualize Grainflow spatialization 10 | Visualize Grainflow spatialization 11 | 12 | 13 | 14 | 15 | 16 | Christopher Poovey 17 | ui 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Sets speakers using a dictionary 34 | Sets speakers using a dictionary 35 | 36 | 37 | 38 | grain positions for an individual grain in the format of (index x y z) 39 | grain positions for an individual grain in the format of (index x y z) 40 | 41 | 42 | 43 | Dictionary of grain visualization information generated by grainflow 44 | Dictionary of grain visualization information generated by grainflow.spat.pan~ 45 | 46 | 47 | 48 | grain positions for an individual grain in the format of (index x y z) 49 | grain positions for an individual grain in the format of (index x y z) 50 | 51 | 52 | 53 | set grain amplitudes in the format of grain value 54 | set grain amplitudes in the format of grain value 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | set speaker amplitudes for display in the format speaker value 64 | set speaker amplitudes for display in the format speaker value 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Used in grainflow 76 | Used in grainflow.span.pan~ to control the the distance a sound will be put into a speaker for distance based panning 77 | 78 | 79 | 80 | Speaker positions in a list of XYZ coordinates 81 | Speaker positions in a list of XYZ coordinates 82 | 83 | 84 | 85 | A mask for what dimentions are used in spatialization 86 | A mask for what dimentions are used in spatialization 87 | 88 | 89 | 90 | Used in grainflow 91 | Used in grainflow.span.pan~ to control the falloff curve for the distance panning 92 | 93 | 94 | 95 | the color of the speaker zone 96 | the color of the speaker zone 97 | 98 | 99 | 100 | Enables/Disables the center handle 101 | Enables/Disables the center handle 102 | 103 | 104 | 105 | the color of the background 106 | the color of the background 107 | 108 | 109 | 110 | The secondary grain color 111 | The secondary grain color 112 | 113 | 114 | 115 | The primary grain color 116 | The primary grain color 117 | 118 | 119 | 120 | Color of the center handle 121 | Color of the center handle 122 | 123 | 124 | 125 | speaker on color when sounding 126 | speaker on color when sounding 127 | 128 | 129 | 130 | Size of the grains 131 | Size of the grains 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /docs/grainflow.util.3dspread.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | An easy way to pan grains generated with grainflow. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | Grains as independent channels. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | x y z positions of a channel 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | The maximum random distance from the center. Can be set as a single number or in XYZ format 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | The center of the stereo image in x y z format 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/grainflow.util.bphasor~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | An easy to adust phasor for granulation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | Rate of playback 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Phase offset 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Phasor signal. 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Buffer the phasor will be based upon 60 | 61 | 62 | Inital playback rate of the phasor. 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Resets the phasor to the phase offset 74 | 75 | 76 | sets the buffer 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /docs/grainflow.util.grainRecord~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Record grains of an incoming signal to a buffer. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | Signal to record 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | grain clock 35 | 36 | 37 | 38 | Grains will be scheduled based on this clock in accordance to the windowOffset and space parameters. windowOffset tells the granulator how much each voice should offset as a percentage of the phasor size. If there are two grains and the windowOffset is 0.5 then one grain will start when the phasor is 0 and the other will start when the phasor reaches 0.5. Space determined the size of the grain in relation to the phasor. If space is 0 the grain will take up the entire length of the phasor. If it is 0.5 it will take up half of the length. 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | record head 49 | 50 | 51 | 52 | 53 | 54 | 55 | record head 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | The name of the buffer the granulate. 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | state of the the recording. 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | travRandom will allow grainRecord to record non-linearly. In ms. 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | The number of grains to be recorded. 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | the amount the previous values in the buffer are mixed into the newly recorded value. 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /docs/grainflow.util.listChange.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | detects changes in lists 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | List to check for changes from the last list. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | list of changes. 0 is no change 1 is a change in a positive direction, -1 is a change in a negitive dirrection. 40 | 41 | 42 | 43 | 44 | 45 | 46 | indices of changed members. Signs are applied to signifiy the dirrection of the change. 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | List to check for changes from the last list. 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/grainflow.util.list~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Selects from a list based on an audio value from 0-1. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | Sampling value from 0-1 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | list to sample from 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | Values sampled from list 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Values to be sampled from 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /docs/grainflow.util.multiPan~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | An easy way to pan grains generated with grainflow 10 | An easy way to pan grains generated with grainflow. 11 | 12 | 13 | 14 | 15 | 16 | Christopher Poovey 17 | granulation 18 | msp 19 | grainflow 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | The number of output channels 29 | The number of output channels 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | The center to where grain pan 48 | The center to where grain pan 49 | 50 | 51 | 52 | The distance grains can pan from the center 53 | The distance grains can pan from the center 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /docs/grainflow.util.phasor~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | An easy to adust phasor for granulation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | Rate of the phasor in hz. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | low boundary 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | High boundary 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Phasor signal. 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Inital frequency of the phasor. 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | Phasor wraping mode- mode are fold and wrap. 78 | 79 | 80 | Resets the phasor to 0. 81 | 82 | 83 | Sets the phasor to a certain value. 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /docs/grainflow.util.randomRangeList.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Generates a random list of n elements between two numbers. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | Triggers a list. 26 | 27 | 28 | 29 | 30 | 31 | Members in the list. 32 | 33 | 34 | 35 | 36 | 37 | Min value. 38 | 39 | 40 | 41 | 42 | 43 | Max value. 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Random list. 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Length of the random list. 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /docs/grainflow.util.rateSizePhasor~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | A utility that translates grain rate and grain size to the phasor overlap model used in grain flow for grain scheduling. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | Grain Rate. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Grain size ms. 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | Grain clock and messages for grainflow. 47 | 48 | 49 | 50 | 51 | 52 | 53 | overlap 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | The maximum number of grains. 65 | 66 | 67 | in hz 68 | 69 | 70 | in ms 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /docs/grainflow.util.record~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A simple buffer recorder intended to be used with grainflow 10 | A simple buffer recorder intended to be used with grainflow 11 | 12 | 13 | 14 | 15 | 16 | Christopher Poovey 17 | granulation 18 | msp 19 | grainflow 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | the buffer to record to 29 | the buffer to record to 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Choose a named buffer~ from which to read 51 | Choose a named buffer~ from which to read. 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | target buffer 63 | target buffer 64 | 65 | 66 | 67 | should the output buffer position be frozen? 68 | should the output buffer position be frozen? 69 | 70 | 71 | 72 | The amount of the old samples that will be mixed in with the new samples 73 | The amount of the old samples that will be mixed in with the new samples 74 | 75 | 76 | 77 | Determines to write loop 78 | Determines to write loop 79 | 80 | 81 | 82 | state of the recorder 83 | state of the recorder 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /docs/grainflow.util.sahRandom~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Generates random numbers in a range whenver a grain turns off. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | Grain state (0 triggers output) 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Min 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Max 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Random numbers as signals per grain 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/grainflow.util.stereoPan~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | An easy way to pan grains generated with grainflow 10 | An easy way to pan grains generated with grainflow. 11 | 12 | 13 | 14 | 15 | 16 | Christopher Poovey 17 | granulation 18 | msp 19 | grainflow 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | The center to where grain pan 43 | The center to where grain pan 44 | 45 | 46 | 47 | The distance grains can pan from the center 48 | The distance grains can pan from the center 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /docs/grainflow.util.vbap3d.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | An easy way to pan grains generated with grainflow. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | 20 | 21 | 22 | 23 | 24 | 25 | Grains as independent channels. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | A list containing the grain number folled by the xyz position of that grain. 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | Can be set as a dictionary with the key as the speaker index and the data as a 3 member array that indicate the xyz position of the speaker. 67 | Can also be set as a list containing the speaker number followed by the position of that speaker. 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /docs/grainflow.waveform~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Visualize Grainflow granulation on a waveform display 10 | Visualize Grainflow granulation on a waveform display 11 | 12 | 13 | 14 | 15 | 16 | Christopher Poovey 17 | ui 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | redraws the buffer display 34 | redraws the buffer display 35 | 36 | 37 | 38 | Choose a named buffer~ from which to read 39 | Choose a named buffer~ from which to read. 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | sets the size of the grain dots 49 | sets the size of the grain dots 50 | 51 | 52 | 53 | sets the tracker position 54 | sets the tracker position 55 | 56 | 57 | 58 | sets the positions of the grain dots 59 | sets the positions of the grain dots 60 | 61 | 62 | 63 | sets if the grain dots should draw at all 64 | sets if the grain dots should draw at all 65 | 66 | 67 | 68 | sets the vertical position of the grain dots 69 | sets the vertical position of the grain dots 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | Changed the backgroun color 86 | Changed the backgroun color 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | The channel that the waveform will draw 96 | The channel that the waveform will draw. Grains are also filtered by channel. 0 will draw the first channel and all grains 97 | 98 | 99 | 100 | changes the primary grain display color 101 | changes the primary grain display color 102 | 103 | 104 | 105 | changes the secondary grain display color 106 | changes the secondary grain display color 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | The interaction mode for the waveform 131 | The interaction mode for the waveform. Scrub -> click and drag to change selected position. Selection -> click and drag to select a range. Loop -> click and drag to move a selection, hold option/alt to change the selection size 132 | 133 | 134 | 135 | changes color of the selection range 136 | changes color of the selection range 137 | 138 | 139 | 140 | The selected range of the waveform display 141 | The selected range of the waveform display 142 | 143 | 144 | 145 | shows triangles pointing at the selection position 146 | shows triangles pointing at the selection position 147 | 148 | 149 | 150 | changes color of the position tracker 151 | changes color of the position tracker 152 | 153 | 154 | 155 | How thick the position tracker is 156 | How thick the position tracker is 157 | 158 | 159 | 160 | changes the selection triangles 161 | changes the selection triangles 162 | 163 | 164 | 165 | Increases the Y scale of the waveform 166 | Increases the Y scale of the waveform 167 | 168 | 169 | 170 | Changes the color of the waveform 171 | Changes the color of the waveform 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.3dspread.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Spreads grains from a center point 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | Grain state as mc 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | xyz positions 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | The amount grains may deviate from the center 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | The amount grains may deviate from the center as a single value or a list of XYZ values 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | The center point defined in XYZ coordinates 72 | 73 | 74 | 75 | 76 | 77 | 78 | The center point defined in AED coordinates 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.format.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Formats grain position messages for other systems such as Spat Gris or the IEM Suite 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | converted message 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | XYZ grain position message to be converted into aother format. AED is unsupported at this time. 60 | 61 | 62 | 63 | 64 | Sets the translation mode based on an integer. 0: spatGrisCube, 1: spatGrisDome, 2: IEM/SPARTA, 3: ICSTXYZ, 4: ICSTAED, 5: SpatXYZ, 6: SpatAED 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.pan~.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | A 3D Panner for grainflow 7 | 8 | Pan grains based on position to speakers. Currently suports basic distance based panning and vector based panning. 9 | 10 | 11 | 12 | 13 | 14 | 15 | Christopher Poovey 16 | Grainflow 17 | Granulation 18 | MSP 19 | Spatialization 20 | 21 | 22 | 23 | 24 | 25 | 26 | Grains as MC, pan positions and speaker posions as messages. 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Panned Grains 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | Information for grainflow.spatview~ 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | A list containing the grain number folled by the xyz position of that grain. 69 | 70 | 71 | 72 | 73 | 74 | 75 | Can be set as a dictionary with the key as the speaker index and the data as a 3 member array that indicate the xyz position of the speaker. 76 | Can also be set as a list containing the speaker number followed by the position of that speaker. 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | see speakers 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | How far the range of a speaker is. 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | The curve of the falloff. 0 is linear, 1 is exponentail, -1 is logarithmic (equal power) 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | A mask in X Y Z that determines how much each dimmention contributes to speaker volumes 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | The method used for determining speaker volumes. 1: distance based amplitude panning; 2: vector based amplitude panning 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | The maximum number of speakers selected in the vector based panner. 2 is good for 2D and 3 is good for 3D. 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.phys.add.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Adds values to physics fields using the lambda outlet for custom updates. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | grainflow.phys matrix 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | Lamda outlet for custom physics proccessing 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Position tranform for the position of each grain in XYZ coordinates 56 | 57 | 58 | 59 | 60 | 61 | 62 | A random deviation from position tranform for the position of each grain in XYZ coordinates 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Velocity tranform for the position of each grain in XYZ coordinates 72 | 73 | 74 | 75 | 76 | 77 | 78 | A random deviation from velocity tranform for the position of each grain in XYZ coordinates 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | Acceleration tranform for the position of each grain in XYZ coordinates 87 | 88 | 89 | 90 | 91 | 92 | 93 | A random deviation from acceleration determined at the start of each grain. 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.phys.drag.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Applies drag to a grainflow physics matrix 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | grainflow.phys matrix 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | drag 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | Lamda outlet for custom physics proccessing 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.phys.magnets.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Calculates distanced between grains and magnets then applies physics 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | grainflow.phys matrix 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | Lamda outlet for custom physics proccessing 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Magents can be set as a list of quintupplets formated as position(x,y,z) followed by a distance and strength value. These values can also be loaded in via a dictionary which is often more convenient- this is formated as a dictionary of nested dictionaries representing each magnet with a keys for position, strength, and distance. 56 | 57 | 58 | 59 | 60 | 61 | 62 | The dimention the magnets operate on. 0 = position; 1= velocity; 2= acceleration. The distance caluclation is always based on position. 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.phys.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | A simple physics engine that allows for manipulation of position, velocity, and acceleration manipulations. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | Grain State as MC 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Jitter matrix created using the lambda outlet. The matrix will insert itself before each physics update. 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | xyz positions 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Lamda outlet for custom physics proccessing 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | The intial position of each grain in XYZ coordinates 74 | 75 | 76 | 77 | 78 | 79 | 80 | A random deviation from position determined at the start of each grain 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | The initial velocity of each grain in XYZ 89 | 90 | 91 | 92 | 93 | 94 | 95 | A random deviation from velocity determined at the start of each grain. 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | Initial acceleration of each grain in XYZ 104 | 105 | 106 | 107 | 108 | 109 | 110 | A random deviation from acceleration determined at the start of each grain. 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | The update rate of the physics system in ms. Default is 10ms. 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.phys.transform.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Applies transformations to a selected physics field 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | grainflow.phys matrix 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | Lamda outlet for custom physics proccessing 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Adds and XYZ vector to the physics field 56 | 57 | 58 | 59 | 60 | 61 | 62 | Multiplies curve value to the physics field. 100 doubles the size, -100 halves the size. 63 | 64 | 65 | 66 | 67 | 68 | 69 | Rotates a physics field using normalized euler rotation 70 | 71 | 72 | 73 | 74 | 75 | 76 | The dimention the magnets operate on. 0 = position; 1= velocity; 2= acceleration. The distance caluclation is always based on position. 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.speakers.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Allows for easy access to speaker presets and loading of speaker files 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | name of a speaker setup as a symbol 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | speaker json 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Name of a preset speaker setup 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Updates a umenu with avalible options for speaker setups 66 | 67 | 68 | 69 | 70 | 71 | 72 | Reads a properly formated text file 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | Reads a properly formated json file 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.spirograph.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Samples signals to spatialize grains with grainflow.spat.pan~ 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | Grain State as MC 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | X position 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Y position 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Z position 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | xyz message for grainflow.spat.pan~ 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.split.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Splits grain posiiton messages based on their IDs 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | speaker position messages or grain state messages (will generate positions at 0 0 0) 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | grain positions within the range 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | grain positions outside of the range 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | grain ID that starts the range 60 | 61 | 62 | 63 | 64 | grain ID that ends the range 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.transform.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Samples 3D volumes for grainflow.spat.pan~ 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | xyz positions to transform 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | xyz positions 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Information for grainflow.spatview~ 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | Updates the transform for all grains 67 | 68 | 69 | 70 | 71 | 72 | 73 | Translates each sampled point by a 3d vector. 74 | 75 | 76 | 77 | 78 | 79 | 80 | Randomly translates each sampled point by a 3d vector. 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Translates each sampled point by a 3d vector. 89 | 90 | 91 | 92 | 93 | 94 | 95 | Randomly translates each sampled point by a 3d vector. 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | Scale each sampled point by a 3d vector around 0,0,0. 104 | 105 | 106 | 107 | 108 | 109 | 110 | Randomly scales each sampled point by a 3d vector around 0,0,0 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | Rotates each sampled point by a 3d vector around 0,0,0. Maximum phase is represented by 1. 119 | 120 | 121 | 122 | 123 | 124 | 125 | Randomly roatates each sampled point by a 3d vector around 0,0,0. Maximum phase is represented by 1. 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.transformOverLife.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Samples 3D volumes for grainflow.spat.pan~ 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | xyz positions to transform 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | xyz positions 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Information for grainflow.spatview~ 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Translates each sampled point by a 3d vector. 68 | 69 | 70 | 71 | 72 | 73 | 74 | Randomly translates each sampled point by a 3d vector. 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | Translates each sampled point by a 3d vector. 83 | 84 | 85 | 86 | 87 | 88 | 89 | Randomly translates each sampled point by a 3d vector. 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | Scale each sampled point by a 3d vector around 0,0,0. 98 | 99 | 100 | 101 | 102 | 103 | 104 | Randomly scales each sampled point by a 3d vector around 0,0,0 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | Rotates each sampled point by a 3d vector around 0,0,0. Maximum phase is represented by 1. 113 | 114 | 115 | 116 | 117 | 118 | 119 | Randomly roatates each sampled point by a 3d vector around 0,0,0. Maximum phase is represented by 1. 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /docs/spat/grainflow.spat.volume.maxref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Samples 3D volumes for grainflow.spat.pan~ 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Christopher Poovey 15 | Grainflow 16 | Granulation 17 | MSP 18 | Spatialization 19 | 20 | 21 | 22 | 23 | 24 | 25 | Grain states 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | xyz positions 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Information for grainflow.spatview~ 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | A symbol representing the shape you wish to sample: circle, sphere, square, cube, or torus 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | The depth at which the volume is sampled on the x/y plane 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | The depth at which the volume is sampled on the z plane 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | The amount of space left empty in the center of the volume. 0 samples all posible points. 1 samples the parimeter. 92 | 93 | 94 | 95 | 96 | 97 | 98 | Translates each sampled point by a 3d vector. 99 | 100 | 101 | 102 | 103 | 104 | 105 | Randomly translates each sampled point by a 3d vector. 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Translates each sampled point by a 3d vector. 114 | 115 | 116 | 117 | 118 | 119 | 120 | Randomly translates each sampled point by a 3d vector. 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Scale each sampled point by a 3d vector around 0,0,0. 129 | 130 | 131 | 132 | 133 | 134 | 135 | Randomly scales each sampled point by a 3d vector around 0,0,0 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | Rotates each sampled point by a 3d vector around 0,0,0. Maximum phase is represented by 1. 144 | 145 | 146 | 147 | 148 | 149 | 150 | Randomly roatates each sampled point by a 3d vector around 0,0,0. Maximum phase is represented by 1. 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | Begins sampleing the vertices of the input matrix in trigrid format 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /grainflowimage.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/grainflowimage.psd -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/icon.png -------------------------------------------------------------------------------- /javascript/_grainflow.spat.js: -------------------------------------------------------------------------------- 1 | var centerpos = { 2 | x: 0, y:0, z:0 3 | } 4 | 5 | var rotation = { 6 | x: 0, y:0, z:0 7 | } 8 | 9 | var scale = { 10 | x:1, y:1, z:1 11 | 12 | } 13 | 14 | function cartopol(x,y){ 15 | var r = Math.sqrt(x*x + y*y) 16 | var t = Math.atan2(y,x) //This takes y first 17 | var position = {'r':r, 't':t} 18 | return position; 19 | } 20 | 21 | function poltocar(r ,t){ 22 | var x = r * Math.cos(t); 23 | var y = r * Math.sin(t); 24 | var position = {'x':x,'y':y,'z':0}; 25 | return position; 26 | } 27 | 28 | function outputPos(grain, pos){ 29 | pos.x += centerpos.x; 30 | pos.y += centerpos.y; 31 | pos.z += centerpos.z; 32 | 33 | pos = _rotate(pos,rotation); 34 | 35 | outlet(0,["pos", grain, pos.x, pos.y, pos.z]); 36 | } 37 | 38 | function arcVolume2d(grain, rad, phase, innerRad){ 39 | if (rad == null) rad = 1; 40 | if (phase == null) phase = 1; 41 | if (innerRad== null) innerRad = 0; 42 | 43 | var pos = poltocar(((rad*(1-innerRad))*Math.random())+rad*innerRad, (Math.random()*phase)*Math.PI*2); 44 | 45 | pos.z = pos.y; 46 | pos.y = 0 47 | 48 | outputPos(grain, pos); 49 | } 50 | 51 | function boxVolume2d(grain, w, h, inner){ 52 | if (!h) h=1; 53 | if (!w) w=1; 54 | if (!inner) inner = 0; 55 | 56 | var pos = { 57 | 'x' : (((Math.random()*(1-inner))+inner)*0.5)*(1-((Math.random()>0.5)*2))*w, 58 | 'y' : 0, 59 | 'z': ((Math.random())*0.5)*(1-((Math.random()>0.5)*2))*h 60 | }; 61 | 62 | 63 | if(Math.random() > 0.5){ 64 | var x = pos.x; 65 | var y = pos.z; 66 | pos.x = y; 67 | pos.z = x; 68 | 69 | } 70 | 71 | 72 | outputPos(grain,pos); 73 | 74 | } 75 | 76 | function moveto(x,y,z){ 77 | centerpos.x = x; 78 | centerpos.y = y; 79 | centerpos.z = z 80 | 81 | } 82 | 83 | function move(x,y,z){ 84 | centerpos.x += x; 85 | centerpos.y += y; 86 | centerpos.z += z 87 | 88 | } 89 | 90 | function rotateto(pitch, roll, yaw){ 91 | rotation.x = pitch * (Math.PI)*2; 92 | rotation.y = roll * (Math.PI)*2; 93 | rotation.z = yaw * (Math.PI)*2; 94 | 95 | } 96 | 97 | function rotate(pitch, roll, yaw){ 98 | rotation.x += pitch* (Math.PI)*2; 99 | rotation.y += roll*(Math.PI)*2; 100 | rotation.z += yaw* (Math.PI)*2; 101 | 102 | } 103 | 104 | 105 | function _rotate(point, rot){ 106 | var cosa = Math.cos(rot.x); 107 | var sina = Math.sin(rot.x); 108 | 109 | var cosb = Math.cos(rot.y); 110 | var sinb = Math.sin(rot.y); 111 | 112 | var cosc = Math.cos(rot.z); 113 | var sinc = Math.sin(rot.z); 114 | 115 | var Axx = cosa*cosb; 116 | var Axy = cosa*sinb*sinc - sina*cosc; 117 | var Axz = cosa*sinb*cosc + sina*sinc; 118 | 119 | var Ayx = sina*cosb; 120 | var Ayy = sina*sinb*sinc + cosa*cosc; 121 | var Ayz = sina*sinb*cosc - cosa*sinc; 122 | 123 | var Azx = -sinb; 124 | var Azy = cosb*sinc; 125 | var Azz = cosb*cosc; 126 | 127 | var px = point.x; 128 | var py = point.y; 129 | var pz = point.z; 130 | 131 | point.x = Axx*px + Axy*py + Axz*pz; 132 | point.y = Ayx*px + Ayy*py + Ayz*pz; 133 | point.z = Azx*px + Azy*py + Azz*pz; 134 | 135 | return point; 136 | 137 | } 138 | 139 | function center(x,y,z){ 140 | moveto(x,y,z); 141 | 142 | } 143 | 144 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Christopher Poovey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /media/CP_Bubbling_Pasta_Sauce.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/CP_Bubbling_Pasta_Sauce.wav -------------------------------------------------------------------------------- /media/CP_Pinball.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/CP_Pinball.wav -------------------------------------------------------------------------------- /media/grainflow.2DEnvelope.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.2DEnvelope.aif -------------------------------------------------------------------------------- /media/grainflow.Blackman.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.Blackman.aif -------------------------------------------------------------------------------- /media/grainflow.FatPluck.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.FatPluck.aif -------------------------------------------------------------------------------- /media/grainflow.Hamming.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.Hamming.aif -------------------------------------------------------------------------------- /media/grainflow.Hanning.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.Hanning.aif -------------------------------------------------------------------------------- /media/grainflow.Kaiser.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.Kaiser.aif -------------------------------------------------------------------------------- /media/grainflow.Pluck.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.Pluck.aif -------------------------------------------------------------------------------- /media/grainflow.ReverseFatPluck.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.ReverseFatPluck.aif -------------------------------------------------------------------------------- /media/grainflow.ReversePluck.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.ReversePluck.aif -------------------------------------------------------------------------------- /media/grainflow.Triangle.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/composingcap/grainflow/3a014c772d3c4fd87ba95bc82db7e0ac43e10791/media/grainflow.Triangle.aif -------------------------------------------------------------------------------- /media/grainflow.icon.click.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /media/grainflow.icon.freeze.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /media/grainflow.icon.info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /media/grainflow.icon.pingpong.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /media/grainflow.icon.playBackward.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /media/grainflow.icon.playForward.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /media/grainflow.icon.repeat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /media/grainflow.icon.stop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /misc/grainflow.speakerExample.json: -------------------------------------------------------------------------------- 1 | { 2 | "speakers" : { 3 | "1" : [ -1, 1, 0 ], 4 | "2" : [ 1, 1, 0 ], 5 | "3" : [ -1, -1, 0 ], 6 | "4" : [ 1, -1, 0 ] 7 | } 8 | , 9 | "falloffDistance" : 1.5, 10 | "falloffCurve" : -1, 11 | "dimmask" : [ 1, 1, 0 ] 12 | } 13 | -------------------------------------------------------------------------------- /misc/grainflow.speakerExample.txt: -------------------------------------------------------------------------------- 1 | 1 -0.4 1 0 2 | 2 0.4 1 0 3 | 3 -1 0.4 0 4 | 4 1 0.4 0 5 | 5 -1 -0.4 0 6 | 6 1 -0.4 0 7 | 7 -0.4 -1 0 8 | 8 0.4 -1 0 9 | falloffDistance 1.5 10 | falloffCurve -1 11 | dimmask 1 1 0 -------------------------------------------------------------------------------- /misc/grainflow.speakersetups.json: -------------------------------------------------------------------------------- 1 | { 2 | "8ch stereo pairs" : { 3 | "speakers" : { 4 | "1" : [ -0.4, 1, 0 ], 5 | "2" : [ 0.4, 1, 0 ], 6 | "3" : [ -1, 0.4, 0 ], 7 | "4" : [ 1, 0.4, 0 ], 8 | "5" : [ -1, -0.4, 0 ], 9 | "6" : [ 1, -0.4, 0 ], 10 | "7" : [ -0.4, -1, 0 ], 11 | "8" : [ 0.4, -1, 0 ] 12 | } 13 | , 14 | "falloffDistance" : 1.5, 15 | "falloffCurve" : -1, 16 | "dimmask" : [ 1, 1, 0 ] 17 | } 18 | , 19 | "8ch double diamond" : { 20 | "speakers" : { 21 | "1" : [ 0, 1, 0 ], 22 | "2" : [ 0.5, 0.5, 0 ], 23 | "3" : [ 1, 0, 0 ], 24 | "4" : [ 0.5, -0.5, 0 ], 25 | "5" : [ 0, -1, 0 ], 26 | "6" : [ -0.5, -0.5, 0 ], 27 | "7" : [ -1, 0, 0 ], 28 | "8" : [ -0.5, 0.5, 0 ] 29 | } 30 | , 31 | "falloffDistance" : 1, 32 | "falloffCurve" : -1, 33 | "dimmask" : [ 1, 1, 0 ] 34 | } 35 | , 36 | "stereo" : { 37 | "speakers" : { 38 | "1" : [ -1, 0, 0 ], 39 | "2" : [ 1, 0, 0 ] 40 | } 41 | , 42 | "falloffDistance" : 1.5, 43 | "falloffCurve" : -1, 44 | "dimmask" : [ 1, 0, 0 ] 45 | } 46 | , 47 | "quad" : { 48 | "speakers" : { 49 | "1" : [ -1, 1, 0 ], 50 | "2" : [ 1, 1, 0 ], 51 | "3" : [ -1, -1, 0 ], 52 | "4" : [ 1, -1, 0 ] 53 | } 54 | , 55 | "falloffDistance" : 1.5, 56 | "falloffCurve" : -1, 57 | "dimmask" : [ 1, 1, 0 ] 58 | } 59 | , 60 | "5ch surround" : { 61 | "speakers" : { 62 | "1" : [ -1, 1, 0 ], 63 | "2" : [ 1, 1, 0 ], 64 | "3" : [ 0, 1, 0 ], 65 | "4" : [ -1, -1, 0 ], 66 | "5" : [ 1, -1, 0 ] 67 | } 68 | , 69 | "falloffDistance" : 1.5, 70 | "falloffCurve" : -1, 71 | "dimmask" : [ 1, 1, 0 ] 72 | } 73 | , 74 | "7ch surround" : { 75 | "speakers" : { 76 | "1" : [ -1, 1, 0 ], 77 | "2" : [ 1, 1, 0 ], 78 | "3" : [ 0, 1, 0 ], 79 | "4" : [ -1, -1, 0 ], 80 | "5" : [ 1, -1, 0 ], 81 | "6" : [ -1, 0, 0 ], 82 | "7" : [ 1, 0, 0 ] 83 | } 84 | , 85 | "falloffDistance" : 1.5, 86 | "falloffCurve" : -1, 87 | "dimmask" : [ 1, 1, 0 ] 88 | } 89 | , 90 | "16ch Stacked Stereo Pairs" : { 91 | "speakers" : { 92 | "1" : [ -0.4, 1, 0 ], 93 | "2" : [ 0.4, 1, 0 ], 94 | "3" : [ -1, 0.4, 0 ], 95 | "4" : [ 1, 0.4, 0 ], 96 | "5" : [ -1, -0.4, 0 ], 97 | "6" : [ 1, -0.4, 0 ], 98 | "7" : [ -0.4, -1, 0 ], 99 | "8" : [ 0.4, -1, 0 ], 100 | "9" : [ -0.4, 1, 1 ], 101 | "10" : [ 0.4, 1, 1 ], 102 | "11" : [ -1, 0.4, 1 ], 103 | "12" : [ 1, 0.4, 1 ], 104 | "13" : [ -1, -0.4, 1 ], 105 | "14" : [ 1, -0.4, 1 ], 106 | "15" : [ -0.4, -1, 1 ], 107 | "16" : [ 0.4, -1, 1 ] 108 | } 109 | , 110 | "falloffDistance" : 0.75, 111 | "falloffCurve" : -1, 112 | "dimmask" : [ 1, 1, 1 ] 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /package-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "author" : "Christopher Poovey", 3 | "authors" : [ ], 4 | "description" : "A suite of granulation tools that leverage the multichannel system in Max to allow for the rapid creation of creative granular tool. Grainflow 2.0 introduces new externals for grainflow~, grainflow.waveform~, and grainflow.spatview~. Please report any issues to https://github.com/composingcap/grainflow/issues or to the grainflow discord channel- every bug report helps!", 5 | "displayname" : "Grainflow", 6 | "extends" : "", 7 | "extensible" : 0, 8 | "homepatcher" : "grainflowOverview.maxpat", 9 | "max_version_max" : "none", 10 | "max_version_min" : "8.5", 11 | "LegalCopyright": "Copyright (c) Christopher Poovey 2024", 12 | "name" : "Grainflow", 13 | "os" : { 14 | "macintosh" : { 15 | "platform" : [ "ia32", "x64" ], 16 | "min_version" : "none" 17 | } 18 | , 19 | "windows" : { 20 | "platform" : [ "x64" ], 21 | "min_version" : "none" 22 | } 23 | 24 | } 25 | , 26 | "package_extra" : { 27 | 28 | } 29 | , 30 | "tags" : [ "granulation", "mc" ], 31 | "version" : "2.1.2", 32 | "website" : "https://github.com/composingcap/grainflow", 33 | "filelist" : { 34 | "externals" : [], 35 | "patchers" : [], 36 | "help" : [ ], 37 | "misc" : [ ], 38 | "extras" : [] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /package-info.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "author" : "Christopher Poovey", 3 | "authors" : [ ], 4 | "description" : "A suite of granulation tools that leverage the multichannel system in Max to allow for the rapid creation of creative granular tool. Grainflow 2.0 introduces new externals for grainflow~, grainflow.waveform~, and grainflow.spatview~. Please report any issues to https://github.com/composingcap/grainflow/issues or to the grainflow discord channel- every bug report helps!", 5 | "displayname" : "Grainflow", 6 | "extends" : "", 7 | "extensible" : 0, 8 | "homepatcher" : "grainflowOverview.maxpat", 9 | "max_version_max" : "none", 10 | "max_version_min" : "8.5", 11 | "LegalCopyright": "Copyright (c) Christopher Poovey 2024", 12 | "name" : "Grainflow", 13 | "os" : { 14 | "macintosh" : { 15 | "platform" : [ "ia32", "x64" ], 16 | "min_version" : "none" 17 | } 18 | , 19 | "windows" : { 20 | "platform" : [ "x64" ], 21 | "min_version" : "none" 22 | } 23 | 24 | } 25 | , 26 | "package_extra" : { 27 | 28 | } 29 | , 30 | "tags" : [ "granulation", "mc" ], 31 | "version" : "2.1.2", 32 | "website" : "https://github.com/composingcap/grainflow", 33 | "filelist" : { 34 | "externals" : [], 35 | "patchers" : [], 36 | "help" : [ ], 37 | "misc" : [ ], 38 | "extras" : [] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /patchers/_private/_grainFlow.streamR~.maxpat: -------------------------------------------------------------------------------- 1 | { 2 | "patcher": { 3 | "fileversion": 1, 4 | "appversion": { 5 | "major": 8, 6 | "minor": 1, 7 | "revision": 8, 8 | "architecture": "x64", 9 | "modernui": 1 10 | }, 11 | "classnamespace": "box", 12 | "rect": [ 13 | 198.0, 14 | 270.0, 15 | 230.0, 16 | 342.0 17 | ], 18 | "bglocked": 0, 19 | "openinpresentation": 0, 20 | "default_fontsize": 11.0, 21 | "default_fontface": 0, 22 | "default_fontname": "Lato", 23 | "gridonopen": 1, 24 | "gridsize": [ 25 | 15.0, 26 | 15.0 27 | ], 28 | "gridsnaponopen": 1, 29 | "objectsnaponopen": 1, 30 | "statusbarvisible": 2, 31 | "toolbarvisible": 1, 32 | "lefttoolbarpinned": 0, 33 | "toptoolbarpinned": 0, 34 | "righttoolbarpinned": 0, 35 | "bottomtoolbarpinned": 0, 36 | "toolbars_unpinned_last_save": 0, 37 | "tallnewobj": 0, 38 | "boxanimatetime": 200, 39 | "enablehscroll": 1, 40 | "enablevscroll": 1, 41 | "devicewidth": 0.0, 42 | "description": "", 43 | "digest": "", 44 | "tags": "", 45 | "assistshowspatchername": 0, 46 | "boxes": [ 47 | { 48 | "box": { 49 | "id": "obj-1", 50 | "maxclass": "newobj", 51 | "numinlets": 1, 52 | "numoutlets": 1, 53 | "outlettype": [ 54 | "" 55 | ], 56 | "patching_rect": [ 57 | 50.0, 58 | 134.0, 59 | 68.0, 60 | 22.0 61 | ], 62 | "text": "prepend set" 63 | } 64 | }, 65 | { 66 | "box": { 67 | "id": "obj-16", 68 | "maxclass": "newobj", 69 | "numinlets": 2, 70 | "numoutlets": 2, 71 | "outlettype": [ 72 | "", 73 | "" 74 | ], 75 | "patching_rect": [ 76 | 50.0, 77 | 100.0, 78 | 53.0, 79 | 22.0 80 | ], 81 | "text": "route #2" 82 | } 83 | }, 84 | { 85 | "box": { 86 | "id": "obj-13", 87 | "maxclass": "newobj", 88 | "numinlets": 1, 89 | "numoutlets": 1, 90 | "outlettype": [ 91 | "multichannelsignal" 92 | ], 93 | "patching_rect": [ 94 | 50.0, 95 | 166.0, 96 | 121.0, 97 | 22.0 98 | ], 99 | "text": "mc.receive~ #0_r #1" 100 | } 101 | }, 102 | { 103 | "box": { 104 | "comment": "", 105 | "id": "obj-18", 106 | "index": 0, 107 | "maxclass": "inlet", 108 | "numinlets": 0, 109 | "numoutlets": 1, 110 | "outlettype": [ 111 | "" 112 | ], 113 | "patching_rect": [ 114 | 50.0, 115 | 40.0, 116 | 30.0, 117 | 30.0 118 | ] 119 | } 120 | }, 121 | { 122 | "box": { 123 | "comment": "", 124 | "id": "obj-19", 125 | "index": 0, 126 | "maxclass": "outlet", 127 | "numinlets": 1, 128 | "numoutlets": 0, 129 | "patching_rect": [ 130 | 50.0, 131 | 214.0, 132 | 30.0, 133 | 30.0 134 | ] 135 | } 136 | } 137 | ], 138 | "lines": [ 139 | { 140 | "patchline": { 141 | "destination": [ 142 | "obj-13", 143 | 0 144 | ], 145 | "source": [ 146 | "obj-1", 147 | 0 148 | ] 149 | } 150 | }, 151 | { 152 | "patchline": { 153 | "destination": [ 154 | "obj-19", 155 | 0 156 | ], 157 | "source": [ 158 | "obj-13", 159 | 0 160 | ] 161 | } 162 | }, 163 | { 164 | "patchline": { 165 | "destination": [ 166 | "obj-1", 167 | 0 168 | ], 169 | "source": [ 170 | "obj-16", 171 | 0 172 | ] 173 | } 174 | }, 175 | { 176 | "patchline": { 177 | "destination": [ 178 | "obj-16", 179 | 0 180 | ], 181 | "source": [ 182 | "obj-18", 183 | 0 184 | ] 185 | } 186 | } 187 | ], 188 | "dependency_cache": [], 189 | "autosave": 0 190 | } 191 | } -------------------------------------------------------------------------------- /patchers/_private/_grainflow.keyin.maxpat: -------------------------------------------------------------------------------- 1 | { 2 | "patcher": { 3 | "fileversion": 1, 4 | "appversion": { 5 | "major": 8, 6 | "minor": 2, 7 | "revision": 0, 8 | "architecture": "x64", 9 | "modernui": 1 10 | }, 11 | "classnamespace": "box", 12 | "rect": [ 13 | 985.0, 14 | 586.0, 15 | 1082.0, 16 | 597.0 17 | ], 18 | "bglocked": 0, 19 | "openinpresentation": 0, 20 | "default_fontsize": 12.0, 21 | "default_fontface": 0, 22 | "default_fontname": "Lato", 23 | "gridonopen": 1, 24 | "gridsize": [ 25 | 15.0, 26 | 15.0 27 | ], 28 | "gridsnaponopen": 1, 29 | "objectsnaponopen": 1, 30 | "statusbarvisible": 2, 31 | "toolbarvisible": 1, 32 | "lefttoolbarpinned": 0, 33 | "toptoolbarpinned": 0, 34 | "righttoolbarpinned": 0, 35 | "bottomtoolbarpinned": 0, 36 | "toolbars_unpinned_last_save": 0, 37 | "tallnewobj": 0, 38 | "boxanimatetime": 200, 39 | "enablehscroll": 1, 40 | "enablevscroll": 1, 41 | "devicewidth": 0.0, 42 | "description": "", 43 | "digest": "", 44 | "tags": "", 45 | "assistshowspatchername": 0, 46 | "boxes": [ 47 | { 48 | "box": { 49 | "id": "obj-26", 50 | "maxclass": "newobj", 51 | "numinlets": 1, 52 | "numoutlets": 1, 53 | "outlettype": [ 54 | "" 55 | ], 56 | "patching_rect": [ 57 | 15.0, 58 | 66.0, 59 | 84.0, 60 | 23.0 61 | ], 62 | "text": "prepend keyin" 63 | } 64 | }, 65 | { 66 | "box": { 67 | "id": "obj-23", 68 | "maxclass": "newobj", 69 | "numinlets": 3, 70 | "numoutlets": 1, 71 | "outlettype": [ 72 | "" 73 | ], 74 | "patching_rect": [ 75 | 15.0, 76 | 41.0, 77 | 40.0, 78 | 23.0 79 | ], 80 | "text": "join 3" 81 | } 82 | }, 83 | { 84 | "box": { 85 | "id": "obj-20", 86 | "maxclass": "newobj", 87 | "numinlets": 0, 88 | "numoutlets": 4, 89 | "outlettype": [ 90 | "int", 91 | "int", 92 | "int", 93 | "int" 94 | ], 95 | "patching_rect": [ 96 | 15.0, 97 | 16.0, 98 | 50.5, 99 | 23.0 100 | ], 101 | "text": "key" 102 | } 103 | }, 104 | { 105 | "box": { 106 | "comment": "", 107 | "id": "obj-33", 108 | "index": 1, 109 | "maxclass": "outlet", 110 | "numinlets": 1, 111 | "numoutlets": 0, 112 | "patching_rect": [ 113 | 15.0, 114 | 149.0, 115 | 30.0, 116 | 30.0 117 | ] 118 | } 119 | } 120 | ], 121 | "lines": [ 122 | { 123 | "patchline": { 124 | "destination": [ 125 | "obj-23", 126 | 2 127 | ], 128 | "source": [ 129 | "obj-20", 130 | 3 131 | ] 132 | } 133 | }, 134 | { 135 | "patchline": { 136 | "destination": [ 137 | "obj-23", 138 | 1 139 | ], 140 | "source": [ 141 | "obj-20", 142 | 2 143 | ] 144 | } 145 | }, 146 | { 147 | "patchline": { 148 | "destination": [ 149 | "obj-23", 150 | 0 151 | ], 152 | "source": [ 153 | "obj-20", 154 | 0 155 | ] 156 | } 157 | }, 158 | { 159 | "patchline": { 160 | "destination": [ 161 | "obj-26", 162 | 0 163 | ], 164 | "source": [ 165 | "obj-23", 166 | 0 167 | ] 168 | } 169 | }, 170 | { 171 | "patchline": { 172 | "destination": [ 173 | "obj-33", 174 | 0 175 | ], 176 | "source": [ 177 | "obj-26", 178 | 0 179 | ] 180 | } 181 | } 182 | ] 183 | } 184 | } -------------------------------------------------------------------------------- /patchers/_private/_grainflow.random~.maxpat: -------------------------------------------------------------------------------- 1 | { 2 | "patcher": { 3 | "fileversion": 1, 4 | "appversion": { 5 | "major": 8, 6 | "minor": 5, 7 | "revision": 4, 8 | "architecture": "x64", 9 | "modernui": 1 10 | }, 11 | "classnamespace": "box", 12 | "rect": [ 13 | 535.0, 14 | 217.0, 15 | 1343.0, 16 | 480.0 17 | ], 18 | "bglocked": 0, 19 | "openinpresentation": 0, 20 | "default_fontsize": 11.0, 21 | "default_fontface": 0, 22 | "default_fontname": "Lato", 23 | "gridonopen": 1, 24 | "gridsize": [ 25 | 15.0, 26 | 15.0 27 | ], 28 | "gridsnaponopen": 1, 29 | "objectsnaponopen": 1, 30 | "statusbarvisible": 2, 31 | "toolbarvisible": 1, 32 | "lefttoolbarpinned": 0, 33 | "toptoolbarpinned": 0, 34 | "righttoolbarpinned": 0, 35 | "bottomtoolbarpinned": 0, 36 | "toolbars_unpinned_last_save": 0, 37 | "tallnewobj": 0, 38 | "boxanimatetime": 200, 39 | "enablehscroll": 1, 40 | "enablevscroll": 1, 41 | "devicewidth": 0.0, 42 | "description": "", 43 | "digest": "", 44 | "tags": "", 45 | "assistshowspatchername": 0, 46 | "boxes": [ 47 | { 48 | "box": { 49 | "comment": "", 50 | "id": "obj-3", 51 | "index": 2, 52 | "maxclass": "inlet", 53 | "numinlets": 0, 54 | "numoutlets": 1, 55 | "outlettype": [ 56 | "" 57 | ], 58 | "patching_rect": [ 59 | 336.0, 60 | 116.0, 61 | 30.0, 62 | 30.0 63 | ] 64 | } 65 | }, 66 | { 67 | "box": { 68 | "comment": "", 69 | "id": "obj-2", 70 | "index": 1, 71 | "maxclass": "outlet", 72 | "numinlets": 1, 73 | "numoutlets": 0, 74 | "patching_rect": [ 75 | 133.0, 76 | 312.0, 77 | 30.0, 78 | 30.0 79 | ] 80 | } 81 | }, 82 | { 83 | "box": { 84 | "comment": "", 85 | "id": "obj-1", 86 | "index": 1, 87 | "maxclass": "inlet", 88 | "numinlets": 0, 89 | "numoutlets": 1, 90 | "outlettype": [ 91 | "" 92 | ], 93 | "patching_rect": [ 94 | 133.0, 95 | 116.0, 96 | 30.0, 97 | 30.0 98 | ] 99 | } 100 | } 101 | ], 102 | "lines": [] 103 | } 104 | } -------------------------------------------------------------------------------- /patchers/_private/_grainflow.streamReceive~.maxpat: -------------------------------------------------------------------------------- 1 | { 2 | "patcher": { 3 | "fileversion": 1, 4 | "appversion": { 5 | "major": 8, 6 | "minor": 1, 7 | "revision": 8, 8 | "architecture": "x64", 9 | "modernui": 1 10 | }, 11 | "classnamespace": "box", 12 | "rect": [ 13 | 172.0, 14 | 194.0, 15 | 215.0, 16 | 292.0 17 | ], 18 | "bglocked": 0, 19 | "openinpresentation": 0, 20 | "default_fontsize": 11.0, 21 | "default_fontface": 0, 22 | "default_fontname": "Lato", 23 | "gridonopen": 1, 24 | "gridsize": [ 25 | 15.0, 26 | 15.0 27 | ], 28 | "gridsnaponopen": 1, 29 | "objectsnaponopen": 1, 30 | "statusbarvisible": 2, 31 | "toolbarvisible": 1, 32 | "lefttoolbarpinned": 0, 33 | "toptoolbarpinned": 0, 34 | "righttoolbarpinned": 0, 35 | "bottomtoolbarpinned": 0, 36 | "toolbars_unpinned_last_save": 0, 37 | "tallnewobj": 0, 38 | "boxanimatetime": 200, 39 | "enablehscroll": 1, 40 | "enablevscroll": 1, 41 | "devicewidth": 0.0, 42 | "description": "", 43 | "digest": "", 44 | "tags": "", 45 | "assistshowspatchername": 0, 46 | "boxes": [ 47 | { 48 | "box": { 49 | "id": "obj-1", 50 | "maxclass": "newobj", 51 | "numinlets": 1, 52 | "numoutlets": 1, 53 | "outlettype": [ 54 | "" 55 | ], 56 | "patching_rect": [ 57 | 50.0, 58 | 134.0, 59 | 68.0, 60 | 22.0 61 | ], 62 | "text": "prepend set" 63 | } 64 | }, 65 | { 66 | "box": { 67 | "id": "obj-16", 68 | "maxclass": "newobj", 69 | "numinlets": 2, 70 | "numoutlets": 2, 71 | "outlettype": [ 72 | "", 73 | "" 74 | ], 75 | "patching_rect": [ 76 | 50.0, 77 | 100.0, 78 | 53.0, 79 | 22.0 80 | ], 81 | "text": "route #2" 82 | } 83 | }, 84 | { 85 | "box": { 86 | "id": "obj-13", 87 | "maxclass": "newobj", 88 | "numinlets": 1, 89 | "numoutlets": 1, 90 | "outlettype": [ 91 | "multichannelsignal" 92 | ], 93 | "patching_rect": [ 94 | 50.0, 95 | 166.0, 96 | 118.0, 97 | 22.0 98 | ], 99 | "text": "mc.receive~ #0_r #1" 100 | } 101 | }, 102 | { 103 | "box": { 104 | "comment": "", 105 | "id": "obj-18", 106 | "index": 0, 107 | "maxclass": "inlet", 108 | "numinlets": 0, 109 | "numoutlets": 1, 110 | "outlettype": [ 111 | "" 112 | ], 113 | "patching_rect": [ 114 | 50.0, 115 | 40.0, 116 | 30.0, 117 | 30.0 118 | ] 119 | } 120 | }, 121 | { 122 | "box": { 123 | "comment": "", 124 | "id": "obj-19", 125 | "index": 0, 126 | "maxclass": "outlet", 127 | "numinlets": 1, 128 | "numoutlets": 0, 129 | "patching_rect": [ 130 | 50.0, 131 | 214.0, 132 | 30.0, 133 | 30.0 134 | ] 135 | } 136 | } 137 | ], 138 | "lines": [ 139 | { 140 | "patchline": { 141 | "destination": [ 142 | "obj-13", 143 | 0 144 | ], 145 | "source": [ 146 | "obj-1", 147 | 0 148 | ] 149 | } 150 | }, 151 | { 152 | "patchline": { 153 | "destination": [ 154 | "obj-19", 155 | 0 156 | ], 157 | "source": [ 158 | "obj-13", 159 | 0 160 | ] 161 | } 162 | }, 163 | { 164 | "patchline": { 165 | "destination": [ 166 | "obj-1", 167 | 0 168 | ], 169 | "source": [ 170 | "obj-16", 171 | 0 172 | ] 173 | } 174 | }, 175 | { 176 | "patchline": { 177 | "destination": [ 178 | "obj-16", 179 | 0 180 | ], 181 | "source": [ 182 | "obj-18", 183 | 0 184 | ] 185 | } 186 | } 187 | ], 188 | "dependency_cache": [], 189 | "autosave": 0 190 | } 191 | } -------------------------------------------------------------------------------- /patchers/util/grainflow.util.genEnv2D.maxpat: -------------------------------------------------------------------------------- 1 | { 2 | "patcher": { 3 | "fileversion": 1, 4 | "appversion": { 5 | "major": 8, 6 | "minor": 1, 7 | "revision": 11, 8 | "architecture": "x64", 9 | "modernui": 1 10 | }, 11 | "classnamespace": "box", 12 | "rect": [ 13 | 59.0, 14 | 107.0, 15 | 640.0, 16 | 480.0 17 | ], 18 | "bglocked": 0, 19 | "openinpresentation": 0, 20 | "default_fontsize": 12.0, 21 | "default_fontface": 0, 22 | "default_fontname": "Arial", 23 | "gridonopen": 1, 24 | "gridsize": [ 25 | 15.0, 26 | 15.0 27 | ], 28 | "gridsnaponopen": 1, 29 | "objectsnaponopen": 1, 30 | "statusbarvisible": 2, 31 | "toolbarvisible": 1, 32 | "lefttoolbarpinned": 0, 33 | "toptoolbarpinned": 0, 34 | "righttoolbarpinned": 0, 35 | "bottomtoolbarpinned": 0, 36 | "toolbars_unpinned_last_save": 0, 37 | "tallnewobj": 0, 38 | "boxanimatetime": 200, 39 | "enablehscroll": 1, 40 | "enablevscroll": 1, 41 | "devicewidth": 0.0, 42 | "description": "", 43 | "digest": "", 44 | "tags": "", 45 | "assistshowspatchername": 0, 46 | "boxes": [ 47 | { 48 | "box": { 49 | "comment": "", 50 | "id": "obj-3", 51 | "index": 1, 52 | "maxclass": "outlet", 53 | "numinlets": 1, 54 | "numoutlets": 0, 55 | "patching_rect": [ 56 | 53.0, 57 | 216.0, 58 | 30.0, 59 | 30.0 60 | ] 61 | } 62 | }, 63 | { 64 | "box": { 65 | "id": "obj-1", 66 | "maxclass": "newobj", 67 | "numinlets": 1, 68 | "numoutlets": 1, 69 | "outlettype": [ 70 | "" 71 | ], 72 | "patching_rect": [ 73 | 53.0, 74 | 106.0, 75 | 112.0, 76 | 22.0 77 | ], 78 | "text": "prepend genEnv2D" 79 | } 80 | }, 81 | { 82 | "box": { 83 | "id": "obj-2", 84 | "maxclass": "newobj", 85 | "numinlets": 1, 86 | "numoutlets": 1, 87 | "outlettype": [ 88 | "" 89 | ], 90 | "patching_rect": [ 91 | 53.0, 92 | 141.0, 93 | 91.0, 94 | 22.0 95 | ], 96 | "saved_object_attributes": { 97 | "filename": "_grainflowutil.js", 98 | "parameter_enable": 0 99 | }, 100 | "text": "js _grainflowutil" 101 | } 102 | }, 103 | { 104 | "box": { 105 | "comment": "", 106 | "id": "obj-21", 107 | "index": 1, 108 | "maxclass": "inlet", 109 | "numinlets": 0, 110 | "numoutlets": 1, 111 | "outlettype": [ 112 | "" 113 | ], 114 | "patching_rect": [ 115 | 53.0, 116 | 49.0, 117 | 30.0, 118 | 30.0 119 | ] 120 | } 121 | } 122 | ], 123 | "lines": [ 124 | { 125 | "patchline": { 126 | "destination": [ 127 | "obj-2", 128 | 0 129 | ], 130 | "source": [ 131 | "obj-1", 132 | 0 133 | ] 134 | } 135 | }, 136 | { 137 | "patchline": { 138 | "destination": [ 139 | "obj-3", 140 | 0 141 | ], 142 | "source": [ 143 | "obj-2", 144 | 0 145 | ] 146 | } 147 | }, 148 | { 149 | "patchline": { 150 | "destination": [ 151 | "obj-1", 152 | 0 153 | ], 154 | "source": [ 155 | "obj-21", 156 | 0 157 | ] 158 | } 159 | } 160 | ] 161 | } 162 | } -------------------------------------------------------------------------------- /scripts/removeStyles.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import subprocess 4 | import json 5 | import platform 6 | import sys 7 | import re 8 | 9 | root_path = "../" 10 | patcher_roots = ["patchers", "help", "extras"] 11 | 12 | def main(): 13 | for dir_path in patcher_roots: 14 | path = root_path + dir_path 15 | for root, dirs, files in os.walk(path): 16 | for file in files: 17 | purge_styles(root, file) 18 | 19 | 20 | def purge_styles(root, file): 21 | if not file.endswith(".maxpat") and not file.endswith(".maxhelp"): 22 | return 23 | path = os.path.join(root, file) 24 | print(path) 25 | 26 | maxfile = open(path) 27 | maxtxt = maxfile.read() 28 | maxfile.close() 29 | maxjson = json.loads(maxtxt) 30 | 31 | 32 | maxjson= remove_fields_recursively(maxjson,["style","parentstyle","styles","subpatcher_template"]) 33 | maxtxt = json.dumps(maxjson, indent= 4) 34 | maxfile = open(path, 'w') 35 | maxfile.write(maxtxt) 36 | maxfile.close() 37 | 38 | def remove_fields_recursively(data, fields_to_remove): 39 | if isinstance(data, dict): 40 | data = { 41 | key: remove_fields_recursively(value, fields_to_remove) 42 | for key, value in data.items() 43 | if key not in fields_to_remove 44 | } 45 | elif isinstance(data, list): 46 | data = [remove_fields_recursively(item, fields_to_remove) for item in data] 47 | return data 48 | if __name__=="__main__": 49 | main() -------------------------------------------------------------------------------- /source/experimental_projects/grainflow.fx.morphFilter_tilde/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Min-DevKit Authors. All rights reserved. 2 | # Use of this source code is governed by the MIT License found in the License.md file. 3 | 4 | set(C74_MIN_API_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../min-api) 5 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 6 | include(${C74_MIN_API_DIR}/script/min-pretarget.cmake) 7 | 8 | 9 | ############################################################# 10 | # MAX EXTERNAL 11 | ############################################################# 12 | 13 | 14 | include_directories( 15 | "${C74_INCLUDES}" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/../../GrainflowLib/include" 17 | ) 18 | 19 | 20 | set(SOURCE_FILES 21 | ${PROJECT_NAME}.cpp 22 | ) 23 | 24 | 25 | add_library( 26 | ${PROJECT_NAME} 27 | MODULE 28 | ${SOURCE_FILES} 29 | ) 30 | set(RELFLAGS ) 31 | if (MSVC) 32 | set(RELFLAGS /Oi /O2 /Ot /Ob2 /GL /GT) 33 | endif() 34 | if(APPLE) 35 | set(RELFLAGS -Ofast) 36 | endif() 37 | target_compile_options(${PROJECT_NAME} PRIVATE 38 | "$<$:${RELFLAGS}>" 39 | ) 40 | 41 | include(${C74_MIN_API_DIR}/script/min-posttarget.cmake) 42 | 43 | 44 | ############################################################# 45 | # UNIT TEST 46 | ############################################################# 47 | 48 | 49 | -------------------------------------------------------------------------------- /source/projects/grainflow.live_tilde/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Min-DevKit Authors. All rights reserved. 2 | # Use of this source code is governed by the MIT License found in the License.md file. 3 | 4 | cmake_minimum_required(VERSION 3.11) 5 | 6 | set(C74_MIN_API_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../min-api) 7 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 8 | include(${C74_MIN_API_DIR}/script/min-pretarget.cmake) 9 | 10 | 11 | ############################################################# 12 | # MAX EXTERNAL 13 | ############################################################# 14 | 15 | 16 | include_directories( 17 | "${C74_INCLUDES}" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/../../GrainflowLib/include" 19 | "${CMAKE_CURRENT_SOURCE_DIR}/../common" 20 | ) 21 | 22 | 23 | set(SOURCE_FILES 24 | ${PROJECT_NAME}.cpp 25 | ${PROJECT_NAME}.h 26 | ${CMAKE_CURRENT_SOURCE_DIR}/../common/grainflowBase.h 27 | ) 28 | 29 | 30 | add_library( 31 | ${PROJECT_NAME} 32 | MODULE 33 | ${SOURCE_FILES} 34 | ) 35 | set(RELFLAGS ) 36 | if (MSVC) 37 | set(RELFLAGS /Oi /O2 /Ot /Ob2 /GL /GT) 38 | endif() 39 | if(APPLE) 40 | set(RELFLAGS -Ofast) 41 | endif() 42 | target_compile_options(${PROJECT_NAME} PRIVATE 43 | "$<$:${RELFLAGS}>" 44 | ) 45 | 46 | include(${C74_MIN_API_DIR}/script/min-posttarget.cmake) 47 | 48 | 49 | ############################################################# 50 | # UNIT TEST 51 | ############################################################# 52 | 53 | 54 | -------------------------------------------------------------------------------- /source/projects/grainflow.spatview_tilde/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Min-DevKit Authors. All rights reserved. 2 | # Use of this source code is governed by the MIT License found in the License.md file. 3 | 4 | cmake_minimum_required(VERSION 3.11) 5 | 6 | set(C74_MIN_API_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../min-api) 7 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 8 | include(${C74_MIN_API_DIR}/script/min-pretarget.cmake) 9 | 10 | 11 | ############################################################# 12 | # MAX EXTERNAL 13 | ############################################################# 14 | 15 | 16 | include_directories( 17 | "${C74_INCLUDES}" 18 | ) 19 | 20 | 21 | set( SOURCE_FILES 22 | ${PROJECT_NAME}.cpp 23 | 24 | ) 25 | 26 | 27 | add_library( 28 | ${PROJECT_NAME} 29 | MODULE 30 | ${SOURCE_FILES} 31 | ) 32 | 33 | 34 | include(${C74_MIN_API_DIR}/script/min-posttarget.cmake) 35 | 36 | 37 | ############################################################# 38 | # UNIT TEST 39 | ############################################################# 40 | 41 | 42 | -------------------------------------------------------------------------------- /source/projects/grainflow.util.multipan_tilde/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Min-DevKit Authors. All rights reserved. 2 | # Use of this source code is governed by the MIT License found in the License.md file. 3 | 4 | cmake_minimum_required(VERSION 3.11) 5 | 6 | set(C74_MIN_API_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../min-api) 7 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 8 | include(${C74_MIN_API_DIR}/script/min-pretarget.cmake) 9 | 10 | 11 | ############################################################# 12 | # MAX EXTERNAL 13 | ############################################################# 14 | 15 | 16 | include_directories( 17 | "${C74_INCLUDES}" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/../../GrainflowLib/include" 19 | ) 20 | 21 | 22 | 23 | 24 | set( SOURCE_FILES 25 | ${PROJECT_NAME}.cpp 26 | ${PROJECT_NAME}.h 27 | ) 28 | 29 | 30 | 31 | add_library( 32 | ${PROJECT_NAME} 33 | MODULE 34 | ${SOURCE_FILES} 35 | ) 36 | set(RELFLAGS ) 37 | if (MSVC) 38 | set(RELFLAGS /Oi /O2 /Ot /Ob2 /GL /GT) 39 | endif() 40 | if(APPLE) 41 | set(RELFLAGS -Ofast) 42 | endif() 43 | target_compile_options(${PROJECT_NAME} PRIVATE 44 | "$<$:${RELFLAGS}>" 45 | ) 46 | 47 | include(${C74_MIN_API_DIR}/script/min-posttarget.cmake) 48 | 49 | 50 | ############################################################# 51 | # UNIT TEST 52 | ############################################################# 53 | 54 | 55 | -------------------------------------------------------------------------------- /source/projects/grainflow.util.multipan_tilde/grainflow.util.multipan_tilde.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @ingroup grainflow 3 | /// @copyright Copyright 2024 Christopher Poovey 4 | /// @license Use of this source code is governed by the MIT License found in the License.md file. 5 | /// 6 | /// 7 | /// 8 | #include "grainflow.util.multipan_tilde.h" 9 | 10 | using namespace c74::min; 11 | using namespace Grainflow; 12 | 13 | grainflow_util_multipan_tilde::grainflow_util_multipan_tilde() 14 | { 15 | panner_ = std::make_unique>(input_chans, 2); 16 | internal_update.delay(33); 17 | } 18 | 19 | grainflow_util_multipan_tilde::~grainflow_util_multipan_tilde() 20 | { 21 | panner_.release(); 22 | } 23 | #pragma region DSP 24 | 25 | void grainflow_util_multipan_tilde::operator()(audio_bundle input, audio_bundle output) 26 | { 27 | output.clear(); 28 | if (input.channel_count() < input_chans * 2) return; 29 | panner_->process(input.samples(), &input.samples()[input_chans], output.samples(), input.frame_count()); 30 | } 31 | 32 | #pragma endregion 33 | 34 | 35 | void grainflow_util_multipan_tilde::setup_panner(const int inputs) const 36 | { 37 | panner_->set_channels(inputs, output_channels_value); 38 | } 39 | 40 | #pragma region MAX_API_EX 41 | 42 | /// 43 | /// Allows for the use of mc inputs. Must be added as an event at the objects startup. Also requires an input channels register 44 | /// 45 | /// 46 | /// 47 | /// 48 | /// 49 | long grainflow_util_multipan_tilde::simplemc_inputchanged(c74::max::t_object* x, long ch, long count) 50 | { 51 | if (ch != 0) return 1; 52 | minwrap* ob = reinterpret_cast*>(x); 53 | 54 | int chans = count > 0 ? count : 1; 55 | ob->m_min_object.input_chans = chans; // Tells us how many channels are in each inlet 56 | ob->m_min_object.setup_panner(chans); 57 | return chans; 58 | } 59 | 60 | long grainflow_util_multipan_tilde::simplemc_output(c74::max::t_object* x, long ch, long count) 61 | { 62 | minwrap* ob = reinterpret_cast*>(x); 63 | return ob->m_min_object.output_channels_value; 64 | } 65 | #pragma endregion 66 | 67 | MIN_EXTERNAL(grainflow_util_multipan_tilde); 68 | -------------------------------------------------------------------------------- /source/projects/grainflow.util.multipan_tilde/grainflow.util.multipan_tilde.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gfUtils.h" 4 | #include "gfPanner.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | constexpr size_t INTERNALBLOCK = 16; 11 | 12 | using namespace c74::min; 13 | using namespace Grainflow; 14 | 15 | class grainflow_util_multipan_tilde : public object, public mc_operator<> 16 | { 17 | public: 18 | MIN_DESCRIPTION{"An easy way to pan grains generated with grainflow."}; 19 | MIN_TAGS{"granulation, msp, grainflow"}; 20 | MIN_AUTHOR{"Christopher Poovey"}; 21 | MIN_RELATED{"grainflow.util.multipan~,""grainflow.spatpan~"}; 22 | 23 | private: 24 | double oneOverSamplerate = 1; 25 | unique_ptr> panner_; 26 | 27 | public: 28 | int input_chans = 1; 29 | int output_channels_value = 2; 30 | #pragma region MAX_IO 31 | inlet<> grains{this, "(multichannelsignal) grains", "multichannelsignal"}; 32 | inlet<> grain_states{this, "(multichannelsignal) grain_states", "multichannelsignal"}; 33 | 34 | outlet<> output{this, "(multichannel) panned grains", "multichannelsignal"}; 35 | outlet<> positions{this, "list of pan positions", "list"}; 36 | 37 | 38 | #pragma endregion 39 | #pragma region DSP 40 | #pragma region DSP 41 | 42 | grainflow_util_multipan_tilde(); 43 | ~grainflow_util_multipan_tilde(); 44 | void operator()(audio_bundle input, audio_bundle output); 45 | static long simplemc_inputchanged(c74::max::t_object* x, long g, long count); 46 | static long simplemc_output(c74::max::t_object* x, long g, long count); 47 | void setup_panner(int inputs) const; 48 | 49 | #pragma endregion 50 | 51 | #pragma region MAX_ARGS 52 | argument output_channels{ 53 | this, 54 | "output channels", 55 | "The number of output channels", 56 | [this](const c74::min::atom& arg) 57 | { 58 | output_channels_value = static_cast(arg); 59 | } 60 | }; 61 | #pragma endregion 62 | 63 | 64 | #pragma region MAX_MESSAGES 65 | // Setup functions 66 | 67 | message<> setup{ 68 | this, 69 | "setup", 70 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 71 | { 72 | return {}; 73 | } 74 | }; 75 | 76 | message<> maxclass_setup{ 77 | this, 78 | "maxclass_setup", 79 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 80 | { 81 | c74::max::t_class* c = args[0]; 82 | c74::max::class_addmethod(c, reinterpret_cast(simplemc_inputchanged), "inputchanged", 83 | c74::max::A_CANT, 0); 84 | c74::max::class_addmethod(c, reinterpret_cast(simplemc_output), 85 | "multichanneloutputs", 86 | c74::max::A_CANT, 0); 87 | return {}; 88 | } 89 | }; 90 | 91 | message<> dspsetup{ 92 | this, 93 | "dspsetup", 94 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 95 | { 96 | oneOverSamplerate = 1 / samplerate(); 97 | return {}; 98 | } 99 | }; 100 | 101 | attribute pan_center{ 102 | this, 103 | "panCenter", 104 | 0.5, 105 | setter{ 106 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 107 | { 108 | if (args.empty()) return args; 109 | if (panner_ == nullptr) return args; 110 | panner_->pan_position = static_cast(args[0]); 111 | return args; 112 | } 113 | }, 114 | description{"The center to where grain pan"}, 115 | }; 116 | 117 | attribute pan_spread{ 118 | this, 119 | "panSpread", 120 | 0.25, 121 | setter{ 122 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 123 | { 124 | if (args.empty()) return args; 125 | if (panner_ == nullptr) return args; 126 | panner_->pan_spread = static_cast(args[0]); 127 | return args; 128 | } 129 | }, 130 | description{"The distance grains can pan from the center"}, 131 | }; 132 | 133 | attribute quantize{ 134 | this, 135 | "quantize", 136 | 0.0, 137 | setter{ 138 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 139 | { 140 | if (args.empty()) return args; 141 | if (panner_ == nullptr) return args; 142 | panner_->pan_quantization = static_cast(args[0]); 143 | return args; 144 | } 145 | }, 146 | description{"A speaker division grains will lock to"}, 147 | }; 148 | 149 | timer internal_update{ 150 | this, 151 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 152 | { 153 | if (panner_ != nullptr) 154 | { 155 | auto pos = panner_->get_positions(); 156 | atoms output; 157 | output.assign(pos.begin(), pos.end()); 158 | positions.send(output); 159 | } 160 | 161 | internal_update.delay(33); 162 | return {}; 163 | } 164 | }; 165 | #pragma endregion 166 | }; 167 | -------------------------------------------------------------------------------- /source/projects/grainflow.util.record_tilde/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Min-DevKit Authors. All rights reserved. 2 | # Use of this source code is governed by the MIT License found in the License.md file. 3 | 4 | cmake_minimum_required(VERSION 3.11) 5 | 6 | set(C74_MIN_API_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../min-api) 7 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 8 | include(${C74_MIN_API_DIR}/script/min-pretarget.cmake) 9 | 10 | 11 | ############################################################# 12 | # MAX EXTERNAL 13 | ############################################################# 14 | 15 | 16 | include_directories( 17 | "${C74_INCLUDES}" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/../../GrainflowLib/include" 19 | "${CMAKE_CURRENT_SOURCE_DIR}/../common" 20 | 21 | ) 22 | 23 | 24 | 25 | 26 | set( SOURCE_FILES 27 | ${PROJECT_NAME}.cpp 28 | ${PROJECT_NAME}.h 29 | ) 30 | 31 | 32 | 33 | add_library( 34 | ${PROJECT_NAME} 35 | MODULE 36 | ${SOURCE_FILES} 37 | ) 38 | set(RELFLAGS ) 39 | if (MSVC) 40 | set(RELFLAGS /Oi /O2 /Ot /Ob2 /GL /GT) 41 | endif() 42 | if(APPLE) 43 | set(RELFLAGS -Ofast) 44 | endif() 45 | target_compile_options(${PROJECT_NAME} PRIVATE 46 | "$<$:${RELFLAGS}>" 47 | ) 48 | 49 | include(${C74_MIN_API_DIR}/script/min-posttarget.cmake) 50 | 51 | 52 | ############################################################# 53 | # UNIT TEST 54 | ############################################################# 55 | 56 | 57 | -------------------------------------------------------------------------------- /source/projects/grainflow.util.record_tilde/grainflow.util.record_tilde.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @ingroup grainflow 3 | /// @copyright Copyright 2024 Christopher Poovey 4 | /// @license Use of this source code is governed by the MIT License found in the License.md file. 5 | /// 6 | /// 7 | /// 8 | #include "grainflow.util.record_tilde.h" 9 | 10 | using namespace c74::min; 11 | using namespace Grainflow; 12 | 13 | grainflow_util_record_tilde::grainflow_util_record_tilde() 14 | { 15 | target_buffer_ = new buffer_reference(this); 16 | recorder_ = std::make_unique>( 17 | max_buffer_reader::get_max_buffer_reader()); 18 | internal_update.delay(33); 19 | } 20 | 21 | grainflow_util_record_tilde::~grainflow_util_record_tilde() 22 | { 23 | recorder_.release(); 24 | delete target_buffer_; 25 | } 26 | #pragma region DSP 27 | 28 | void grainflow_util_record_tilde::operator()(audio_bundle input, audio_bundle output) 29 | { 30 | auto channels = input_chans[0]; 31 | auto frames = input.frame_count(); 32 | 33 | auto input_samples = input.samples(); 34 | auto output_samples = output.samples()[0]; 35 | 36 | 37 | if (target_buffer_ == nullptr) return; 38 | auto buffer = target_buffer_; 39 | buffer_lock<> samples(*buffer); 40 | if (!samples.valid()) 41 | { 42 | auto bname = buffer->name(); 43 | buffer->set(" "); 44 | buffer->set(bname); 45 | return; 46 | } 47 | 48 | bool sync = sync_signal.has_signal_connection(); 49 | double time_override = 0; 50 | if (sync) 51 | { 52 | time_override = input_samples[channels][0]; 53 | } 54 | recorder_->sync = sync; 55 | recorder_->freeze = freeze; 56 | recorder_->overdub = overdub; 57 | recorder_->samplerate = samplerate(); 58 | recorder_->state = state; 59 | 60 | recorder_->process(input_samples, time_override, buffer, frames, channels, output_samples); 61 | samples.dirty(); 62 | } 63 | 64 | #pragma endregion 65 | 66 | 67 | #pragma region MAX_API_EX 68 | 69 | /// 70 | /// Allows for the use of mc inputs. Must be added as an event at the objects startup. Also requires an input channels register 71 | /// 72 | /// 73 | /// 74 | /// 75 | /// 76 | long grainflow_util_record_tilde::simplemc_inputchanged(c74::max::t_object* x, long ch, long count) 77 | { 78 | if (ch != 0) return 1; 79 | minwrap* ob = reinterpret_cast*>(x); 80 | 81 | if (ch >= ob->m_min_object.input_chans.size()) return 1; 82 | int chans = count > 0 ? count : 1; 83 | ob->m_min_object.input_chans[ch] = chans; // Tells us how many channels are in each inlet 84 | ob->m_min_object.recorder_->set_n_filter_channels(chans); 85 | return chans; 86 | } 87 | 88 | long grainflow_util_record_tilde::simplemc_output(c74::max::t_object* x, long ch, long count) 89 | { 90 | return 1; 91 | } 92 | #pragma endregion 93 | 94 | MIN_EXTERNAL(grainflow_util_record_tilde); 95 | -------------------------------------------------------------------------------- /source/projects/grainflow.util.record_tilde/grainflow.util.record_tilde.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gfUtils.h" 4 | #include "gfPanner.h" 5 | #include "maxBufferReader.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | constexpr size_t INTERNALBLOCK = 16; 13 | 14 | using namespace c74::min; 15 | using namespace Grainflow; 16 | 17 | class grainflow_util_record_tilde : public object, public mc_operator<> 18 | { 19 | public: 20 | MIN_DESCRIPTION{"A simple buffer recorder intended to be used with grainflow"}; 21 | MIN_TAGS{"granulation, msp, grainflow"}; 22 | MIN_AUTHOR{"Christopher Poovey"}; 23 | MIN_RELATED{"grainflow~,""grainflow.live~"}; 24 | 25 | private: 26 | double oneOverSamplerate = 1; 27 | buffer_reference* target_buffer_; 28 | gf_i_buffer_reader buffer_reader_; 29 | std::unique_ptr> recorder_; 30 | 31 | public: 32 | std::array input_chans = {1, 0}; 33 | 34 | #pragma region MAX_IO 35 | inlet<> input_signal{this, "(multichannelsignal) input signal", "multichannelsignal"}; 36 | inlet<> sync_signal{this, "(signal) sync signal", "signal"}; 37 | outlet<> traversal{this, "(signal) normalized position in buffer", "signal"}; 38 | outlet<> dump{this, "dump", "list"}; 39 | 40 | 41 | #pragma endregion 42 | #pragma region DSP 43 | #pragma region DSP 44 | 45 | grainflow_util_record_tilde(); 46 | ~grainflow_util_record_tilde(); 47 | void operator()(audio_bundle input, audio_bundle output); 48 | static long simplemc_inputchanged(c74::max::t_object* x, long g, long count); 49 | static long simplemc_output(c74::max::t_object* x, long g, long count); 50 | 51 | #pragma endregion 52 | 53 | #pragma region MAX_ARGS 54 | argument buffer_name_arg{ 55 | this, 56 | "buffer-name", 57 | "the buffer to record to", 58 | [this](const c74::min::atom& arg) 59 | { 60 | buffer.set({arg}); 61 | } 62 | }; 63 | 64 | #pragma endregion 65 | 66 | 67 | #pragma region MAX_MESSAGES 68 | // Setup functions 69 | 70 | message<> setup{ 71 | this, 72 | "setup", 73 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 74 | { 75 | return {}; 76 | } 77 | }; 78 | 79 | message<> maxclass_setup{ 80 | this, 81 | "maxclass_setup", 82 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 83 | { 84 | c74::max::t_class* c = args[0]; 85 | c74::max::class_addmethod(c, reinterpret_cast(simplemc_inputchanged), "inputchanged", 86 | c74::max::A_CANT, 0); 87 | c74::max::class_addmethod(c, reinterpret_cast(simplemc_output), 88 | "multichanneloutputs", 89 | c74::max::A_CANT, 0); 90 | return {}; 91 | } 92 | }; 93 | 94 | message<> dspsetup{ 95 | this, 96 | "dspsetup", 97 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 98 | { 99 | oneOverSamplerate = 1 / samplerate(); 100 | return {}; 101 | } 102 | }; 103 | 104 | message<> int_mess{ 105 | this, 106 | "int", 107 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 108 | { 109 | state.set({(static_cast(args[0]) > 0)}); 110 | return {}; 111 | } 112 | }; 113 | 114 | message<> buf_mess{ 115 | this, 116 | "buf", 117 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 118 | { 119 | buffer.set(args); 120 | return {}; 121 | } 122 | }; 123 | 124 | attribute buffer{ 125 | this, 126 | "buffer", 127 | "", 128 | setter{ 129 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 130 | { 131 | if (args.size() < 1) return {}; 132 | auto name = static_cast(args[0]); 133 | if (name.empty() || name == "") return {""}; 134 | target_buffer_->set(name); 135 | return args; 136 | } 137 | }, 138 | description{"target buffer"}, 139 | }; 140 | 141 | attribute> od_filters{ 142 | this, 143 | "overdubFilters", 144 | {0.0}, 145 | setter{ 146 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 147 | { 148 | if (dummy()) 149 | { 150 | return {0.0}; 151 | } 152 | int n_filters = args.size() / 3; 153 | if (n_filters < 1) 154 | { 155 | return {0.0}; 156 | } 157 | atoms output_args; 158 | output_args.reserve(n_filters * 3); 159 | recorder_->set_n_filters(n_filters); 160 | for (int i = 0; i < n_filters; ++i) 161 | { 162 | const float freq = std::clamp(args[0 + i * 3], 0.0f, samplerate() * 0.5f); 163 | const float q = std::clamp(args[1 + i * 3], 0.001f, 10000); 164 | const float dub = std::clamp(args[2 + i * 3], 0.0f, 1.0); 165 | recorder_->set_filter_params(i, freq, q, dub); 166 | output_args.emplace_back(freq); 167 | output_args.emplace_back(q); 168 | output_args.emplace_back(dub); 169 | } 170 | return output_args; 171 | } 172 | }, 173 | description{"filter bands in freq q overdub"}, 174 | }; 175 | 176 | attribute overdub{ 177 | this, 178 | "overdub", 179 | 0.0, 180 | description{"The amount of the old samples that will be mixed in with the new samples"}, 181 | }; 182 | 183 | attribute state{ 184 | this, 185 | "state", 186 | 0, 187 | description{"state of the recorder"}, 188 | }; 189 | 190 | 191 | attribute freeze{ 192 | this, 193 | "freeze", 194 | 0, 195 | description{"should the output buffer position be frozen?"}, 196 | }; 197 | #ifdef Experimental 198 | attribute> recordRange{ 199 | this, "recRange", {0.0f,1.0f}, 200 | description{"Determines to write loop"}, 201 | setter{ 202 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms{ 203 | atoms fixedArgs = { 204 | args.empty() ? 0.0f : std::clamp(static_cast(args[0]), 0.0f, 1.0f), 205 | args.size() < 2 ? 1.0f : std::clamp(static_cast(args[1]), 0.0f, 1.0f), 206 | }; 207 | if(recorder_ != nullptr){ 208 | recorder_->recRange[0].store(static_cast(fixedArgs[0])); 209 | recorder_->recRange[1].store(static_cast(fixedArgs[1])); 210 | } 211 | return fixedArgs; 212 | } 213 | } 214 | }; 215 | #endif 216 | 217 | timer internal_update{ 218 | this, 219 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 220 | { 221 | internal_update.delay(12.5); 222 | double pos_norm; 223 | double pos_samps; 224 | double pos_ms; 225 | recorder_->get_position(pos_samps, pos_norm, pos_ms); 226 | dump.send({"recordHead", pos_norm}); 227 | dump.send({"recordHeadMs", pos_ms}); 228 | return {}; 229 | } 230 | }; 231 | #pragma endregion 232 | }; 233 | -------------------------------------------------------------------------------- /source/projects/grainflow.util.stereopan_tilde/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Min-DevKit Authors. All rights reserved. 2 | # Use of this source code is governed by the MIT License found in the License.md file. 3 | 4 | cmake_minimum_required(VERSION 3.11) 5 | 6 | set(C74_MIN_API_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../min-api) 7 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 8 | include(${C74_MIN_API_DIR}/script/min-pretarget.cmake) 9 | 10 | 11 | ############################################################# 12 | # MAX EXTERNAL 13 | ############################################################# 14 | 15 | 16 | include_directories( 17 | "${C74_INCLUDES}" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/../../GrainflowLib/include" 19 | ) 20 | 21 | 22 | 23 | 24 | set( SOURCE_FILES 25 | ${PROJECT_NAME}.cpp 26 | ${PROJECT_NAME}.h 27 | ) 28 | 29 | 30 | 31 | add_library( 32 | ${PROJECT_NAME} 33 | MODULE 34 | ${SOURCE_FILES} 35 | ) 36 | set(RELFLAGS ) 37 | if (MSVC) 38 | set(RELFLAGS /Oi /O2 /Ot /Ob2 /GL /GT) 39 | endif() 40 | if(APPLE) 41 | set(RELFLAGS -Ofast) 42 | endif() 43 | target_compile_options(${PROJECT_NAME} PRIVATE 44 | "$<$:${RELFLAGS}>" 45 | ) 46 | 47 | include(${C74_MIN_API_DIR}/script/min-posttarget.cmake) 48 | 49 | 50 | ############################################################# 51 | # UNIT TEST 52 | ############################################################# 53 | 54 | 55 | -------------------------------------------------------------------------------- /source/projects/grainflow.util.stereopan_tilde/grainflow.util.stereopan_tilde.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @ingroup grainflow 3 | /// @copyright Copyright 2024 Christopher Poovey 4 | /// @license Use of this source code is governed by the MIT License found in the License.md file. 5 | /// 6 | /// 7 | /// 8 | #include "grainflow.util.stereopan_tilde.h" 9 | 10 | using namespace c74::min; 11 | using namespace Grainflow; 12 | 13 | grainflow_util_stereopan_tilde::grainflow_util_stereopan_tilde() 14 | { 15 | panner_ = std::make_unique>(input_chans, 2); 16 | internal_update.delay(33); 17 | } 18 | 19 | grainflow_util_stereopan_tilde::~grainflow_util_stereopan_tilde() 20 | { 21 | panner_.release(); 22 | } 23 | #pragma region DSP 24 | 25 | void grainflow_util_stereopan_tilde::operator()(audio_bundle input, audio_bundle output) 26 | { 27 | output.clear(); 28 | if (input.channel_count() < input_chans * 2) return; 29 | panner_->process(input.samples(), &input.samples()[input_chans], output.samples(), input.frame_count()); 30 | } 31 | 32 | #pragma endregion 33 | 34 | 35 | void grainflow_util_stereopan_tilde::setup_panner(const int inputs) const 36 | { 37 | panner_->set_channels(inputs, 2); 38 | } 39 | 40 | #pragma region MAX_API_EX 41 | 42 | /// 43 | /// Allows for the use of mc inputs. Must be added as an event at the objects startup. Also requires an input channels register 44 | /// 45 | /// 46 | /// 47 | /// 48 | /// 49 | long grainflow_util_stereopan_tilde::simplemc_inputchanged(c74::max::t_object* x, long ch, long count) 50 | { 51 | if (ch != 0) return 1; 52 | minwrap* ob = reinterpret_cast*>(x); 53 | 54 | int chans = count > 0 ? count : 1; 55 | ob->m_min_object.input_chans = chans; // Tells us how many channels are in each inlet 56 | ob->m_min_object.setup_panner(chans); 57 | return chans; 58 | } 59 | 60 | long grainflow_util_stereopan_tilde::simplemc_output(c74::max::t_object* x, long ch, long count) 61 | { 62 | return 2; 63 | } 64 | #pragma endregion 65 | 66 | MIN_EXTERNAL(grainflow_util_stereopan_tilde); 67 | -------------------------------------------------------------------------------- /source/projects/grainflow.util.stereopan_tilde/grainflow.util.stereopan_tilde.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gfUtils.h" 4 | #include "gfPanner.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | constexpr size_t INTERNALBLOCK = 16; 11 | 12 | using namespace c74::min; 13 | using namespace Grainflow; 14 | 15 | class grainflow_util_stereopan_tilde : public object, public mc_operator<> 16 | { 17 | public: 18 | MIN_DESCRIPTION{"An easy way to pan grains generated with grainflow."}; 19 | MIN_TAGS{"granulation, msp, grainflow"}; 20 | MIN_AUTHOR{"Christopher Poovey"}; 21 | MIN_RELATED{"grainflow.util.multipan~,""grainflow.spatpan~"}; 22 | 23 | private: 24 | double oneOverSamplerate = 1; 25 | unique_ptr> panner_; 26 | 27 | public: 28 | int input_chans = 1; 29 | 30 | #pragma region MAX_IO 31 | inlet<> grains{this, "(multichannelsignal) grains", "multichannelsignal"}; 32 | inlet<> grain_states{this, "(multichannelsignal) grain_states", "multichannelsignal"}; 33 | 34 | outlet<> output{this, "(multichannel) panned grains", "multichannelsignal"}; 35 | outlet<> positions{this, "list of pan positions", "list"}; 36 | 37 | 38 | #pragma endregion 39 | #pragma region DSP 40 | #pragma region DSP 41 | 42 | grainflow_util_stereopan_tilde(); 43 | ~grainflow_util_stereopan_tilde(); 44 | void operator()(audio_bundle input, audio_bundle output); 45 | static long simplemc_inputchanged(c74::max::t_object* x, long g, long count); 46 | static long simplemc_output(c74::max::t_object* x, long g, long count); 47 | void setup_panner(int inputs) const; 48 | 49 | #pragma endregion 50 | 51 | #pragma region MAX_ARGS 52 | 53 | 54 | #pragma endregion 55 | 56 | 57 | #pragma region MAX_MESSAGES 58 | // Setup functions 59 | 60 | message<> setup{ 61 | this, 62 | "setup", 63 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 64 | { 65 | return {}; 66 | } 67 | }; 68 | 69 | message<> maxclass_setup{ 70 | this, 71 | "maxclass_setup", 72 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 73 | { 74 | c74::max::t_class* c = args[0]; 75 | c74::max::class_addmethod(c, reinterpret_cast(simplemc_inputchanged), "inputchanged", 76 | c74::max::A_CANT, 0); 77 | c74::max::class_addmethod(c, reinterpret_cast(simplemc_output), 78 | "multichanneloutputs", 79 | c74::max::A_CANT, 0); 80 | return {}; 81 | } 82 | }; 83 | 84 | message<> dspsetup{ 85 | this, 86 | "dspsetup", 87 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 88 | { 89 | oneOverSamplerate = 1 / samplerate(); 90 | return {}; 91 | } 92 | }; 93 | 94 | attribute pan_center{ 95 | this, 96 | "panCenter", 97 | 0.5, 98 | setter{ 99 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 100 | { 101 | if (args.empty()) return args; 102 | if (panner_ == nullptr) return args; 103 | panner_->pan_position = static_cast(args[0]); 104 | return args; 105 | } 106 | }, 107 | description{"The center to where grain pan"}, 108 | }; 109 | 110 | attribute pan_spread{ 111 | this, 112 | "panSpread", 113 | 0.25, 114 | setter{ 115 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 116 | { 117 | if (args.empty()) return args; 118 | if (panner_ == nullptr) return args; 119 | panner_->pan_spread = static_cast(args[0]); 120 | return args; 121 | } 122 | }, 123 | description{"The distance grains can pan from the center"}, 124 | }; 125 | 126 | timer internal_update{ 127 | this, 128 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 129 | { 130 | if (panner_ != nullptr) 131 | { 132 | auto pos = panner_->get_positions(); 133 | atoms output; 134 | output.resize(pos.size()); 135 | for (auto i = 0; i < pos.size(); ++i) 136 | { 137 | output[i] = pos[i] * 2.0f - 1.0f; 138 | } 139 | positions.send(output); 140 | } 141 | 142 | internal_update.delay(33); 143 | return {}; 144 | } 145 | }; 146 | #pragma endregion 147 | }; 148 | -------------------------------------------------------------------------------- /source/projects/grainflow.waveform_tilde/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Min-DevKit Authors. All rights reserved. 2 | # Use of this source code is governed by the MIT License found in the License.md file. 3 | 4 | cmake_minimum_required(VERSION 3.11) 5 | 6 | set(C74_MIN_API_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../min-api) 7 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 8 | include(${C74_MIN_API_DIR}/script/min-pretarget.cmake) 9 | 10 | 11 | ############################################################# 12 | # MAX EXTERNAL 13 | ############################################################# 14 | 15 | 16 | include_directories( 17 | "${C74_INCLUDES}" 18 | ) 19 | 20 | 21 | set( SOURCE_FILES 22 | ${PROJECT_NAME}.cpp 23 | 24 | ) 25 | 26 | 27 | add_library( 28 | ${PROJECT_NAME} 29 | MODULE 30 | ${SOURCE_FILES} 31 | ) 32 | 33 | 34 | include(${C74_MIN_API_DIR}/script/min-posttarget.cmake) 35 | 36 | 37 | ############################################################# 38 | # UNIT TEST 39 | ############################################################# 40 | 41 | 42 | -------------------------------------------------------------------------------- /source/projects/grainflow_tilde/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Min-DevKit Authors. All rights reserved. 2 | # Use of this source code is governed by the MIT License found in the License.md file. 3 | 4 | set(C74_MIN_API_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../min-api) 5 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 6 | include(${C74_MIN_API_DIR}/script/min-pretarget.cmake) 7 | 8 | 9 | ############################################################# 10 | # MAX EXTERNAL 11 | ############################################################# 12 | 13 | 14 | include_directories( 15 | "${C74_INCLUDES}" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/../../GrainflowLib/include" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/../common" 18 | ) 19 | 20 | 21 | set(SOURCE_FILES 22 | ${PROJECT_NAME}.cpp 23 | ${PROJECT_NAME}.h 24 | ${CMAKE_CURRENT_SOURCE_DIR}/../common/grainflowBase.h 25 | ) 26 | 27 | 28 | add_library( 29 | ${PROJECT_NAME} 30 | MODULE 31 | ${SOURCE_FILES} 32 | ) 33 | set(RELFLAGS ) 34 | if (MSVC) 35 | set(RELFLAGS /Oi /O2 /Ot /Ob2 /GL /GT) 36 | endif() 37 | if(APPLE) 38 | set(RELFLAGS -Ofast) 39 | endif() 40 | target_compile_options(${PROJECT_NAME} PRIVATE 41 | "$<$:${RELFLAGS}>" 42 | ) 43 | 44 | include(${C74_MIN_API_DIR}/script/min-posttarget.cmake) 45 | 46 | 47 | ############################################################# 48 | # UNIT TEST 49 | ############################################################# 50 | 51 | 52 | -------------------------------------------------------------------------------- /source/projects/grainflow_tilde/grainflow_tilde.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @ingroup grainflow 3 | /// @copyright Copyright 2024 Christopher Poovey 4 | /// @license Use of this source code is governed by the MIT License found in the License.md file. 5 | /// 6 | /// 7 | /// 8 | 9 | #include "grainflow_tilde.h" 10 | 11 | #include 12 | 13 | using namespace c74::min; 14 | using namespace Grainflow; 15 | 16 | 17 | void grainflow_tilde::init() 18 | { 19 | data_outlet = &o_grain_info; 20 | grainflow_base::init(); 21 | } 22 | 23 | void grainflow_tilde::operator()(audio_bundle input, audio_bundle output) 24 | { 25 | //This is a hack to get around some wierd ordering issues when playing the first frame when the number of voices has changed 26 | max_grains_this_frame = std::min(static_cast(output.channel_count() / 8), grain_collection_->grains()); 27 | io_config_.livemode = live_mode; 28 | setup_inputs(io_config_, input_chans, input.samples()); 29 | setup_outputs(io_config_, output.samples()); 30 | 31 | // Clear unused channels or we will get garbage 32 | io_config_.block_size = output.frame_count(); 33 | io_config_.samplerate = samplerate_; 34 | for (int g = 0; g < output.channel_count(); g++) 35 | { 36 | memset(output.samples()[g], static_cast(0), sizeof(double) * io_config_.block_size); 37 | } 38 | 39 | if (!state) 40 | { 41 | return; 42 | } 43 | 44 | grain_collection_->process(io_config_); 45 | update_grain_data(io_config_, max_grains_this_frame); 46 | } 47 | 48 | 49 | void grainflow_tilde::setup_outputs(gf_io_config<>& io_config, double** outputs) const 50 | { 51 | // Outputs are constant because they are based on the max grain count 52 | io_config.grain_output = &outputs[0 * max_grains_this_frame]; 53 | io_config.grain_state = &outputs[1 * max_grains_this_frame]; 54 | io_config.grain_progress = &outputs[2 * max_grains_this_frame]; 55 | io_config.grain_playhead = &outputs[3 * max_grains_this_frame]; 56 | io_config.grain_amp = &outputs[4 * max_grains_this_frame]; 57 | io_config.grain_envelope = &outputs[5 * max_grains_this_frame]; 58 | io_config.grain_buffer_channel = &outputs[6 * max_grains_this_frame]; 59 | io_config.grain_stream_channel = &outputs[7 * max_grains_this_frame]; 60 | } 61 | 62 | void grainflow_tilde::setup_inputs(gf_io_config<>& io_config, const int* input_channels, double** inputs) 63 | { 64 | io_config.grain_clock_chans = input_channels[0]; 65 | io_config.traversal_phasor_chans = input_channels[1]; 66 | io_config.fm_chans = input_channels[2]; 67 | io_config.am_chans = input_channels[3]; 68 | 69 | // These variable indicate the starting indices of each mc parameter 70 | constexpr auto grain_clock_ch = 0; 71 | auto traversal_phasor_ch = io_config.grain_clock_chans; 72 | const auto fm_ch = traversal_phasor_ch + io_config.traversal_phasor_chans; 73 | const auto am_ch = fm_ch + io_config.fm_chans; 74 | 75 | io_config.grain_clock = &inputs[grain_clock_ch]; 76 | io_config.traversal_phasor = &inputs[traversal_phasor_ch]; 77 | io_config.fm = &inputs[fm_ch]; 78 | io_config.am = &inputs[am_ch]; 79 | } 80 | 81 | 82 | void grainflow_tilde::max_class_setup(const atoms& args) 83 | { 84 | c74::max::t_class* c = args[0]; 85 | c74::max::class_addmethod(c, reinterpret_cast(simplemc_multichanneloutputs), 86 | "multichanneloutputs", c74::max::A_CANT, 0); 87 | c74::max::class_addmethod(c, reinterpret_cast(simplemc_inputchanged), "inputchanged", 88 | c74::max::A_CANT, 0); 89 | } 90 | 91 | 92 | #pragma region MAX_API_EX 93 | /// 94 | /// Allows for the use of mc outlets. Must be added as an event at the objects startup 95 | /// 96 | /// 97 | /// 98 | /// 99 | /// 100 | long grainflow_tilde::simplemc_multichanneloutputs(c74::max::t_object* x, long g, long count) 101 | { 102 | minwrap* ob = (minwrap*)(x); 103 | return ob->m_min_object.get_max_grains(); 104 | } 105 | 106 | /// 107 | /// Allows for the use of mc inputs. Must be added as an event at the objects startup. Also requires an input channels regester 108 | /// 109 | /// 110 | /// 111 | /// 112 | /// 113 | long grainflow_tilde::simplemc_inputchanged(c74::max::t_object* x, long g, long count) 114 | { 115 | minwrap* ob = (minwrap*)(x); 116 | // auto chan_number = ob->m_min_object.GetMaxGrains(); //We should check for bonus channels and handle it 117 | ob->m_min_object.input_chans[g] = count > 0 ? count : 1; // Tells us how many channels are in each inlet 118 | return false; 119 | } 120 | #pragma endregion 121 | 122 | 123 | MIN_EXTERNAL(grainflow_tilde); 124 | -------------------------------------------------------------------------------- /source/projects/grainflow_tilde/grainflow_tilde.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "grainflowBase.h" 7 | 8 | 9 | using namespace c74::min; 10 | using namespace Grainflow; 11 | 12 | 13 | class grainflow_tilde final : public grainflow_base 14 | // NOLINT(cppcoreguidelines-special-member-functions) 15 | { 16 | public: 17 | MIN_DESCRIPTION{"the base object for grainflow"}; 18 | MIN_TAGS{"granulation, msp, grainflow"}; 19 | MIN_AUTHOR{"Christopher Poovey"}; 20 | MIN_RELATED{""}; 21 | 22 | private: 23 | static long simplemc_multichanneloutputs(c74::max::t_object* x, long g, long count); 24 | static long simplemc_inputchanged(c74::max::t_object* x, long g, long count); 25 | 26 | void max_class_setup(const atoms& args) override; 27 | 28 | public: 29 | int input_chans[4] = {0, 0, 0, 0}; 30 | int max_grains_this_frame = 0; 31 | 32 | #pragma region MAX_IO 33 | inlet<> grain_clock{this, "(multichannelsignal) phasor input", "multichannelsignal"}; 34 | inlet<> traversal_phasor{ 35 | this, "(multichannelsignal) where the grain should be sampled from the buffer", "multichannelsignal" 36 | }; 37 | inlet<> fm{this, "(multichannelsignal) grain playback rate", "multichannelsignal"}; 38 | inlet<> am{this, "(multichannelsignal) amplitude modulation", "multichannelsignal"}; 39 | 40 | outlet<> output{this, "(multichannel) grain output", "multichannelsignal"}; 41 | 42 | outlet<> o_grain_info{this, "(list) grain info", "list"}; 43 | 44 | outlet<> grain_state{this, "(multichannel) grainState", "multichannelsignal"}; 45 | outlet<> grain_progress{this, "(multichannel) grainProgress", "multichannelsignal"}; 46 | outlet<> grain_playhead{this, "(multichannel) grainPlayhead", "multichannelsignal"}; 47 | outlet<> grain_amp{this, "(multichannel) grainAmp (abs)", "multichannelsignal"}; 48 | outlet<> envelope{this, "(multichannel) grainEnvelope", "multichannelsignal"}; 49 | outlet<> channel{this, "(multichannel) channel", "multichannelsignal"}; 50 | outlet<> stream{this, "(multichannel) stream", "multichannelsignal"}; 51 | #pragma endregion 52 | #pragma region DSP 53 | 54 | void operator()(audio_bundle input, audio_bundle output); 55 | void init() override; 56 | void setup_outputs(gf_io_config<>& io_config, double** outputs) const; 57 | static void setup_inputs(gf_io_config<>& io_config, const int* input_channels, double** inputs); 58 | 59 | 60 | #pragma endregion 61 | 62 | #pragma region MAX_ARGS 63 | argument buffer_arg{ 64 | this, 65 | "buf", 66 | "Buffer~ from which to read.", 67 | [this](const c74::min::atom& arg) 68 | { 69 | buffer_arg_ = (string)arg; 70 | } 71 | }; 72 | 73 | argument grains_arg{ 74 | this, 75 | "number-of-grains", 76 | "max number of grains", 77 | [this](const c74::min::atom& arg) 78 | { 79 | max_grains_ = static_cast(arg); 80 | if (max_grains_ < 1) max_grains_ = 2; 81 | } 82 | }; 83 | 84 | argument envelope_arg{ 85 | this, 86 | "envelope-buffer", 87 | "(optional) the initial envelope buffer for all grains", 88 | [this](const c74::min::atom& arg) 89 | { 90 | env_arg_ = static_cast(arg); 91 | return arg; 92 | } 93 | }; 94 | 95 | #pragma endregion 96 | }; 97 | -------------------------------------------------------------------------------- /source/test_projects/gftest.biquad_tilde/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Min-DevKit Authors. All rights reserved. 2 | # Use of this source code is governed by the MIT License found in the License.md file. 3 | 4 | set(C74_MIN_API_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../min-api) 5 | set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) 6 | include(${C74_MIN_API_DIR}/script/min-pretarget.cmake) 7 | 8 | 9 | ############################################################# 10 | # MAX EXTERNAL 11 | ############################################################# 12 | 13 | 14 | include_directories( 15 | "${C74_INCLUDES}" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/../../GrainflowLib/include" 17 | ) 18 | 19 | 20 | set(SOURCE_FILES 21 | ${PROJECT_NAME}.cpp 22 | ) 23 | 24 | 25 | add_library( 26 | ${PROJECT_NAME} 27 | MODULE 28 | ${SOURCE_FILES} 29 | ) 30 | set(RELFLAGS ) 31 | if (MSVC) 32 | set(RELFLAGS /Oi /O2 /Ot /Ob2 /GL /GT) 33 | endif() 34 | if(APPLE) 35 | set(RELFLAGS -Ofast) 36 | endif() 37 | target_compile_options(${PROJECT_NAME} PRIVATE 38 | "$<$:${RELFLAGS}>" 39 | ) 40 | 41 | include(${C74_MIN_API_DIR}/script/min-posttarget.cmake) 42 | 43 | 44 | -------------------------------------------------------------------------------- /source/test_projects/gftest.biquad_tilde/gftest.biquad_tilde.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gfFilters.h" 3 | #include 4 | #include 5 | #include 6 | 7 | constexpr size_t INTERNALBLOCK = 16; 8 | 9 | using namespace c74::min; 10 | using namespace Grainflow; 11 | 12 | class gfTest_biquad_tilde : public object, public vector_operator<> 13 | { 14 | public: 15 | MIN_DESCRIPTION{"biquad test"}; 16 | MIN_TAGS{"tests"}; 17 | MIN_AUTHOR{"Christopher Poovey"}; 18 | MIN_RELATED{""}; 19 | 20 | private: 21 | double oneOverSamplerate = 1; 22 | biquad biquad_; 23 | std::atomic> params_atom; 24 | biquad_params params; 25 | biquad_params params_dsp; 26 | int blocks_per_vector_ = 1; 27 | public: 28 | std::array inlet_chans{1, 1, 1, 1, 1, 1}; 29 | std::vector last_grain_state{0}; 30 | int output_chans = 1; 31 | 32 | inlet<> i_input{this, "(signal) input", "signal"}; 33 | 34 | outlet<> o_output{this, "(signal) output", "signal"}; 35 | 36 | 37 | void operator()(audio_bundle input, audio_bundle output) 38 | { 39 | if (!i_input.has_signal_connection()) 40 | { 41 | output.clear(); 42 | return; 43 | } 44 | 45 | params_dsp = params_atom.load(); 46 | blocks_per_vector_ = input.frame_count() / INTERNALBLOCK; 47 | auto** input_samples = input.samples(); 48 | auto** output_samples = output.samples(); 49 | for (int i = 0; i < blocks_per_vector_; ++i){ 50 | auto* input_pin = input_samples[0]+i*INTERNALBLOCK; 51 | auto* output_pin = output_samples[0]+i*INTERNALBLOCK; 52 | biquad_.perform(input_pin, INTERNALBLOCK, params_dsp, output_pin); 53 | } 54 | } 55 | 56 | message<> setup{ 57 | this, 58 | "setup", 59 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 60 | { 61 | return {}; 62 | } 63 | }; 64 | 65 | message<> maxclass_setup{ 66 | this, 67 | "maxclass_setup", 68 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 69 | { 70 | c74::max::t_class* c = args[0]; 71 | return {}; 72 | } 73 | }; 74 | 75 | message<> dspsetup{ 76 | this, 77 | "dspsetup", 78 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 79 | { 80 | oneOverSamplerate = 1 / samplerate(); 81 | biquad_.clear(); 82 | return {}; 83 | } 84 | }; 85 | 86 | message<> m_clear{ 87 | this, 88 | "clear", 89 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 90 | { 91 | biquad_.clear(); 92 | return {}; 93 | } 94 | }; 95 | 96 | message<> m_biquad{ 97 | this, 98 | "biquad", 99 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 100 | { 101 | if (args.size() < 5){ 102 | return {}; 103 | } 104 | params.b0 = args[0]; 105 | params.b1 = args[1]; 106 | params.b2 = args[2]; 107 | params.a1 = args[3]; 108 | params.a2 = args[4]; 109 | params_atom.store(params); 110 | return {}; 111 | } 112 | }; 113 | 114 | message<> m_morph{ 115 | this, 116 | "morph", 117 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 118 | { 119 | if (args.size() < 3){ 120 | return {}; 121 | } 122 | biquad_params::morph(params, args[0], args[1], args[2], samplerate()); 123 | params_atom.store(params); 124 | return {}; 125 | } 126 | }; 127 | 128 | message<> m_bandpass{ 129 | this, 130 | "band", 131 | [this](const c74::min::atoms& args, const int inlet)-> c74::min::atoms 132 | { 133 | if (args.size() < 2){ 134 | return {}; 135 | } 136 | biquad_params::bandpass(params, args[0], args[1], samplerate()); 137 | params_atom.store(params); 138 | return {}; 139 | } 140 | }; 141 | 142 | 143 | 144 | 145 | }; 146 | 147 | MIN_EXTERNAL(gfTest_biquad_tilde); 148 | --------------------------------------------------------------------------------