├── randomTutorial.prlgunit ├── randomTutorial.mnlgxdunit ├── manifest.json ├── project.mk ├── LICENSE.txt ├── Makefile ├── prologuemakefile ├── README.md ├── randomtable.h └── randomTutorial.c /randomTutorial.prlgunit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammondeggs/logue_RandomLFOTutorial/HEAD/randomTutorial.prlgunit -------------------------------------------------------------------------------- /randomTutorial.mnlgxdunit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammondeggs/logue_RandomLFOTutorial/HEAD/randomTutorial.mnlgxdunit -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "header" : 3 | { 4 | "platform" : "prologue", 5 | "module" : "modfx", 6 | "api" : "1.0-0", 7 | "dev_id" : 0, 8 | "prg_id" : 0, 9 | "version" : "1.01-1", 10 | "name" : "RandomDemo", 11 | "num_param" : 0 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /project.mk: -------------------------------------------------------------------------------- 1 | # ############################################################################# 2 | # Project Customization 3 | # ############################################################################# 4 | 5 | PROJECT = randomTutorial 6 | 7 | UCSRC = randomTutorial.c 8 | 9 | UCXXSRC = 10 | 11 | UINCDIR = 12 | 13 | UDEFS = 14 | 15 | ULIB = 16 | 17 | ULIBDIR = 18 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 hammondeggs , All rights reserved. 2 | 3 | 1. USE 4 | 5 | The acquisition of this software by a user grants one license for the software. A 6 | license grants use on all operating systems on all applicable hardware owned by the 7 | user, provided the primary user is the license holder. 8 | 9 | You must not remove or alter any copyright notices on any copy of this 10 | software. 11 | 12 | You may not distribute resources from this software package. 13 | 14 | 15 | 2. DISTRIBUTION 16 | 17 | You may not distribute or sell licenses or this software to third parties. 18 | Licenses are revoked if distributed or sold to third parties. 19 | 20 | 21 | 3. WARRANTIES 22 | 23 | This software is provided by the copyright holders and contributors "as is" 24 | and any express or implied warranties, including, but not limited to, the 25 | implied warranties of merchantability and fitness for a particular purpose are 26 | disclaimed. In no event shall the copyright holder be liable for any direct, 27 | indirect, incidental, special, exemplary, or consequential damages (including, 28 | but not limited to, procurement of substitute goods or services; loss of use, 29 | data, or profits; or business interruption) however caused and on any theory 30 | of liability, whether in contract, strict liability, or tort (including 31 | negligence or otherwise) arising in any way out of the use of this software, 32 | even if advised of the possibility of such damage. 33 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ############################################################################# 2 | # Prologue Mod. FX Makefile 3 | # ############################################################################# 4 | 5 | ifeq ($(OS),Windows_NT) 6 | ifeq ($(MSYSTEM), MSYS) 7 | detected_OS := $(shell uname -s) 8 | else 9 | detected_OS := Windows 10 | endif 11 | else 12 | detected_OS := $(shell uname -s) 13 | endif 14 | 15 | 16 | PLATFORMDIR = ../../.. 17 | PROJECTDIR = ../.. 18 | TOOLSDIR = $(PLATFORMDIR)/../../tools 19 | EXTDIR = $(PLATFORMDIR)/../ext 20 | 21 | CMSISDIR = $(EXTDIR)/CMSIS/CMSIS 22 | 23 | # ############################################################################# 24 | # configure archive utility 25 | # ############################################################################# 26 | 27 | ZIP = /usr/bin/zip 28 | ZIP_ARGS = -r -m -q 29 | 30 | ifeq ($(OS),Windows_NT) 31 | ifneq ($(MSYSTEM), MSYS) 32 | ZIP = $(TOOLSDIR)/zip/bin/zip 33 | endif 34 | endif 35 | 36 | # ############################################################################# 37 | # Include project specific definition 38 | # ############################################################################# 39 | 40 | include ./project.mk 41 | 42 | # ############################################################################# 43 | # configure cross compilation 44 | # ############################################################################# 45 | 46 | MCU = cortex-m4 47 | 48 | GCC_TARGET = arm-none-eabi- 49 | GCC_BIN_PATH = $(TOOLSDIR)/gcc/gcc-arm-none-eabi-5_4-2016q3/bin 50 | 51 | CC = $(GCC_BIN_PATH)/$(GCC_TARGET)gcc 52 | CXXC = $(GCC_BIN_PATH)/$(GCC_TARGET)g++ 53 | LD = $(GCC_BIN_PATH)/$(GCC_TARGET)gcc 54 | #LD = $(GCC_BIN_PATH)/$(GCC_TARGET)g++ 55 | CP = $(GCC_BIN_PATH)/$(GCC_TARGET)objcopy 56 | AS = $(GCC_BIN_PATH)/$(GCC_TARGET)gcc -x assembler-with-cpp 57 | AR = $(GCC_BIN_PATH)/$(GCC_TARGET)ar 58 | OD = $(GCC_BIN_PATH)/$(GCC_TARGET)objdump 59 | SZ = $(GCC_BIN_PATH)/$(GCC_TARGET)size 60 | 61 | HEX = $(CP) -O ihex 62 | BIN = $(CP) -O binary 63 | 64 | LDDIR = $(PROJECTDIR)/ld 65 | RULESPATH = $(LDDIR) 66 | LDSCRIPT = $(LDDIR)/usermodfx.ld 67 | DLIBS = -lm 68 | 69 | DADEFS = -DSTM32F446xE -DCORTEX_USE_FPU=TRUE -DARM_MATH_CM4 70 | DDEFS = -DSTM32F446xE -DCORTEX_USE_FPU=TRUE -DARM_MATH_CM4 -D__FPU_PRESENT 71 | 72 | COPT = -std=c11 -mstructure-size-boundary=8 73 | CXXOPT = -std=c++11 -fno-rtti -fno-exceptions -fno-non-call-exceptions 74 | 75 | LDOPT = -Xlinker --just-symbols=$(LDDIR)/main_api.syms 76 | 77 | CWARN = 78 | CXXWARN = 79 | 80 | FPU_OPTS = -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -fcheck-new 81 | 82 | OPT = -g -Os -mlittle-endian 83 | OPT += $(FPU_OPTS) 84 | #OPT += -flto 85 | 86 | TOPT = -mthumb -mno-thumb-interwork -DTHUMB_NO_INTERWORKING -DTHUMB_PRESENT 87 | 88 | 89 | # ############################################################################# 90 | # set targets and directories 91 | # ############################################################################# 92 | 93 | PKGDIR = $(PROJECT) 94 | PKGARCH = $(PROJECT).mnlgxdunit 95 | MANIFEST = manifest.json 96 | PAYLOAD = payload.bin 97 | BUILDDIR = $(PROJECTDIR)/build 98 | OBJDIR = $(BUILDDIR)/obj 99 | LSTDIR = $(BUILDDIR)/lst 100 | 101 | ASMSRC = $(UASMSRC) 102 | 103 | ASMXSRC = $(UASMXSRC) 104 | 105 | CSRC = $(PROJECTDIR)/tpl/_unit.c $(UCSRC) 106 | 107 | CXXSRC = $(UCXXSRC) 108 | 109 | vpath %.s $(sort $(dir $(ASMSRC))) 110 | vpath %.S $(sort $(dir $(ASMXSRC))) 111 | vpath %.c $(sort $(dir $(CSRC))) 112 | vpath %.cpp $(sort $(dir $(CXXSRC))) 113 | 114 | ASMOBJS := $(addprefix $(OBJDIR)/, $(notdir $(ASMSRC:.s=.o))) 115 | ASMXOBJS := $(addprefix $(OBJDIR)/, $(notdir $(ASMXSRC:.S=.o))) 116 | COBJS := $(addprefix $(OBJDIR)/, $(notdir $(CSRC:.c=.o))) 117 | CXXOBJS := $(addprefix $(OBJDIR)/, $(notdir $(CXXSRC:.cpp=.o))) 118 | 119 | OBJS := $(ASMXOBJS) $(ASMOBJS) $(COBJS) $(CXXOBJS) 120 | 121 | DINCDIR = $(PROJECTDIR)/inc \ 122 | $(PROJECTDIR)/inc/api \ 123 | $(PLATFORMDIR)/inc \ 124 | $(PLATFORMDIR)/inc/dsp \ 125 | $(PLATFORMDIR)/inc/utils \ 126 | $(CMSISDIR)/Include 127 | 128 | INCDIR := $(patsubst %,-I%,$(DINCDIR) $(UINCDIR)) 129 | 130 | DEFS := $(DDEFS) $(UDEFS) 131 | ADEFS := $(DADEFS) $(UADEFS) 132 | 133 | LIBS := $(DLIBS) $(ULIBS) 134 | 135 | LIBDIR := $(patsubst %,-I%,$(DLIBDIR) $(ULIBDIR)) 136 | 137 | 138 | # ############################################################################# 139 | # compiler flags 140 | # ############################################################################# 141 | 142 | MCFLAGS := -mcpu=$(MCU) 143 | ODFLAGS = -x --syms 144 | ASFLAGS = $(MCFLAGS) -g $(TOPT) -Wa,-alms=$(LSTDIR)/$(notdir $(<:.s=.lst)) $(ADEFS) 145 | ASXFLAGS = $(MCFLAGS) -g $(TOPT) -Wa,-alms=$(LSTDIR)/$(notdir $(<:.S=.lst)) $(ADEFS) 146 | CFLAGS = $(MCFLAGS) $(TOPT) $(OPT) $(COPT) $(CWARN) -Wa,-alms=$(LSTDIR)/$(notdir $(<:.c=.lst)) $(DEFS) 147 | CXXFLAGS = $(MCFLAGS) $(TOPT) $(OPT) $(CXXOPT) $(CXXWARN) -Wa,-alms=$(LSTDIR)/$(notdir $(<:.cpp=.lst)) $(DEFS) 148 | LDFLAGS = $(MCFLAGS) $(TOPT) $(OPT) -nostartfiles $(LIBDIR) -Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch,--library-path=$(RULESPATH),--script=$(LDSCRIPT) $(LDOPT) 149 | 150 | OUTFILES := $(BUILDDIR)/$(PROJECT).elf \ 151 | $(BUILDDIR)/$(PROJECT).hex \ 152 | $(BUILDDIR)/$(PROJECT).bin \ 153 | $(BUILDDIR)/$(PROJECT).dmp \ 154 | $(BUILDDIR)/$(PROJECT).list 155 | 156 | ############################################################################### 157 | # targets 158 | ############################################################################### 159 | 160 | all: PRE_ALL $(OBJS) $(OUTFILES) POST_ALL 161 | 162 | PRE_ALL: 163 | 164 | POST_ALL: package 165 | 166 | $(OBJS): | $(BUILDDIR) $(OBJDIR) $(LSTDIR) 167 | 168 | $(BUILDDIR): 169 | @echo Compiler Options 170 | @echo $(CC) -c $(CFLAGS) -I. $(INCDIR) 171 | @echo 172 | @mkdir -p $(BUILDDIR) 173 | 174 | $(OBJDIR): 175 | @mkdir -p $(OBJDIR) 176 | 177 | $(LSTDIR): 178 | @mkdir -p $(LSTDIR) 179 | 180 | $(ASMOBJS) : $(OBJDIR)/%.o : %.s Makefile 181 | @echo Assembling $( $@ 211 | @echo 212 | @$(SZ) $< 213 | @echo 214 | 215 | %.list: %.elf 216 | @echo Creating $@ 217 | @$(OD) -S $< > $@ 218 | 219 | clean: 220 | @echo Cleaning 221 | -rm -fR .dep $(BUILDDIR) $(PKGARCH) 222 | @echo 223 | @echo Done 224 | 225 | package: 226 | @echo Packaging to ./$(PKGARCH) 227 | @mkdir -p $(PKGDIR) 228 | @cp -a $(MANIFEST) $(PKGDIR)/ 229 | @cp -a $(BUILDDIR)/$(PROJECT).bin $(PKGDIR)/$(PAYLOAD) 230 | @$(ZIP) $(ZIP_ARGS) $(PROJECT).zip $(PKGDIR) 231 | @mv $(PROJECT).zip $(PKGARCH) 232 | @echo 233 | @echo Done 234 | -------------------------------------------------------------------------------- /prologuemakefile: -------------------------------------------------------------------------------- 1 | # ############################################################################# 2 | # Prologue Mod. FX Makefile 3 | # ############################################################################# 4 | 5 | ifeq ($(OS),Windows_NT) 6 | ifeq ($(MSYSTEM), MSYS) 7 | detected_OS := $(shell uname -s) 8 | else 9 | detected_OS := Windows 10 | endif 11 | else 12 | detected_OS := $(shell uname -s) 13 | endif 14 | 15 | 16 | PLATFORMDIR = ../../.. 17 | PROJECTDIR = ../.. 18 | TOOLSDIR = $(PLATFORMDIR)/../../tools 19 | EXTDIR = $(PLATFORMDIR)/../ext 20 | 21 | CMSISDIR = $(EXTDIR)/CMSIS/CMSIS 22 | 23 | # ############################################################################# 24 | # configure archive utility 25 | # ############################################################################# 26 | 27 | ZIP = /usr/bin/zip 28 | ZIP_ARGS = -r -m -q 29 | 30 | ifeq ($(OS),Windows_NT) 31 | ifneq ($(MSYSTEM), MSYS) 32 | ZIP = $(TOOLSDIR)/zip/bin/zip 33 | endif 34 | endif 35 | 36 | # ############################################################################# 37 | # Include project specific definition 38 | # ############################################################################# 39 | 40 | include ./project.mk 41 | 42 | # ############################################################################# 43 | # configure cross compilation 44 | # ############################################################################# 45 | 46 | MCU = cortex-m4 47 | 48 | GCC_TARGET = arm-none-eabi- 49 | GCC_BIN_PATH = $(TOOLSDIR)/gcc/gcc-arm-none-eabi-5_4-2016q3/bin 50 | 51 | CC = $(GCC_BIN_PATH)/$(GCC_TARGET)gcc 52 | CXXC = $(GCC_BIN_PATH)/$(GCC_TARGET)g++ 53 | LD = $(GCC_BIN_PATH)/$(GCC_TARGET)gcc 54 | #LD = $(GCC_BIN_PATH)/$(GCC_TARGET)g++ 55 | CP = $(GCC_BIN_PATH)/$(GCC_TARGET)objcopy 56 | AS = $(GCC_BIN_PATH)/$(GCC_TARGET)gcc -x assembler-with-cpp 57 | AR = $(GCC_BIN_PATH)/$(GCC_TARGET)ar 58 | OD = $(GCC_BIN_PATH)/$(GCC_TARGET)objdump 59 | SZ = $(GCC_BIN_PATH)/$(GCC_TARGET)size 60 | 61 | HEX = $(CP) -O ihex 62 | BIN = $(CP) -O binary 63 | 64 | LDDIR = $(PROJECTDIR)/ld 65 | RULESPATH = $(LDDIR) 66 | LDSCRIPT = $(LDDIR)/usermodfx.ld 67 | DLIBS = -lm 68 | 69 | DADEFS = -DSTM32F446xE -DCORTEX_USE_FPU=TRUE -DARM_MATH_CM4 70 | DDEFS = -DSTM32F446xE -DCORTEX_USE_FPU=TRUE -DARM_MATH_CM4 -D__FPU_PRESENT 71 | 72 | COPT = -std=c11 -mstructure-size-boundary=8 73 | CXXOPT = -std=c++11 -fno-rtti -fno-exceptions -fno-non-call-exceptions 74 | 75 | LDOPT = -Xlinker --just-symbols=$(LDDIR)/main_api.syms 76 | 77 | CWARN = 78 | CXXWARN = 79 | 80 | FPU_OPTS = -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -fcheck-new 81 | 82 | OPT = -g -Os -mlittle-endian 83 | OPT += $(FPU_OPTS) 84 | #OPT += -flto 85 | 86 | TOPT = -mthumb -mno-thumb-interwork -DTHUMB_NO_INTERWORKING -DTHUMB_PRESENT 87 | 88 | 89 | # ############################################################################# 90 | # set targets and directories 91 | # ############################################################################# 92 | 93 | PKGDIR = $(PROJECT) 94 | PKGARCH = $(PROJECT).prlgunit 95 | MANIFEST = manifest.json 96 | PAYLOAD = payload.bin 97 | BUILDDIR = $(PROJECTDIR)/build 98 | OBJDIR = $(BUILDDIR)/obj 99 | LSTDIR = $(BUILDDIR)/lst 100 | 101 | ASMSRC = $(UASMSRC) 102 | 103 | ASMXSRC = $(UASMXSRC) 104 | 105 | CSRC = $(PROJECTDIR)/tpl/_unit.c $(UCSRC) 106 | 107 | CXXSRC = $(UCXXSRC) 108 | 109 | vpath %.s $(sort $(dir $(ASMSRC))) 110 | vpath %.S $(sort $(dir $(ASMXSRC))) 111 | vpath %.c $(sort $(dir $(CSRC))) 112 | vpath %.cpp $(sort $(dir $(CXXSRC))) 113 | 114 | ASMOBJS := $(addprefix $(OBJDIR)/, $(notdir $(ASMSRC:.s=.o))) 115 | ASMXOBJS := $(addprefix $(OBJDIR)/, $(notdir $(ASMXSRC:.S=.o))) 116 | COBJS := $(addprefix $(OBJDIR)/, $(notdir $(CSRC:.c=.o))) 117 | CXXOBJS := $(addprefix $(OBJDIR)/, $(notdir $(CXXSRC:.cpp=.o))) 118 | 119 | OBJS := $(ASMXOBJS) $(ASMOBJS) $(COBJS) $(CXXOBJS) 120 | 121 | DINCDIR = $(PROJECTDIR)/inc \ 122 | $(PROJECTDIR)/inc/api \ 123 | $(PLATFORMDIR)/inc \ 124 | $(PLATFORMDIR)/inc/dsp \ 125 | $(PLATFORMDIR)/inc/utils \ 126 | $(CMSISDIR)/Include 127 | 128 | INCDIR := $(patsubst %,-I%,$(DINCDIR) $(UINCDIR)) 129 | 130 | DEFS := $(DDEFS) $(UDEFS) 131 | ADEFS := $(DADEFS) $(UADEFS) 132 | 133 | LIBS := $(DLIBS) $(ULIBS) 134 | 135 | LIBDIR := $(patsubst %,-I%,$(DLIBDIR) $(ULIBDIR)) 136 | 137 | 138 | # ############################################################################# 139 | # compiler flags 140 | # ############################################################################# 141 | 142 | MCFLAGS := -mcpu=$(MCU) 143 | ODFLAGS = -x --syms 144 | ASFLAGS = $(MCFLAGS) -g $(TOPT) -Wa,-alms=$(LSTDIR)/$(notdir $(<:.s=.lst)) $(ADEFS) 145 | ASXFLAGS = $(MCFLAGS) -g $(TOPT) -Wa,-alms=$(LSTDIR)/$(notdir $(<:.S=.lst)) $(ADEFS) 146 | CFLAGS = $(MCFLAGS) $(TOPT) $(OPT) $(COPT) $(CWARN) -Wa,-alms=$(LSTDIR)/$(notdir $(<:.c=.lst)) $(DEFS) 147 | CXXFLAGS = $(MCFLAGS) $(TOPT) $(OPT) $(CXXOPT) $(CXXWARN) -Wa,-alms=$(LSTDIR)/$(notdir $(<:.cpp=.lst)) $(DEFS) 148 | LDFLAGS = $(MCFLAGS) $(TOPT) $(OPT) -nostartfiles $(LIBDIR) -Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch,--library-path=$(RULESPATH),--script=$(LDSCRIPT) $(LDOPT) 149 | 150 | OUTFILES := $(BUILDDIR)/$(PROJECT).elf \ 151 | $(BUILDDIR)/$(PROJECT).hex \ 152 | $(BUILDDIR)/$(PROJECT).bin \ 153 | $(BUILDDIR)/$(PROJECT).dmp \ 154 | $(BUILDDIR)/$(PROJECT).list 155 | 156 | ############################################################################### 157 | # targets 158 | ############################################################################### 159 | 160 | all: PRE_ALL $(OBJS) $(OUTFILES) POST_ALL 161 | 162 | PRE_ALL: 163 | 164 | POST_ALL: package 165 | 166 | $(OBJS): | $(BUILDDIR) $(OBJDIR) $(LSTDIR) 167 | 168 | $(BUILDDIR): 169 | @echo Compiler Options 170 | @echo $(CC) -c $(CFLAGS) -I. $(INCDIR) 171 | @echo 172 | @mkdir -p $(BUILDDIR) 173 | 174 | $(OBJDIR): 175 | @mkdir -p $(OBJDIR) 176 | 177 | $(LSTDIR): 178 | @mkdir -p $(LSTDIR) 179 | 180 | $(ASMOBJS) : $(OBJDIR)/%.o : %.s Makefile 181 | @echo Assembling $( $@ 211 | @echo 212 | @$(SZ) $< 213 | @echo 214 | 215 | %.list: %.elf 216 | @echo Creating $@ 217 | @$(OD) -S $< > $@ 218 | 219 | clean: 220 | @echo Cleaning 221 | -rm -fR .dep $(BUILDDIR) $(PKGARCH) 222 | @echo 223 | @echo Done 224 | 225 | package: 226 | @echo Packaging to ./$(PKGARCH) 227 | @mkdir -p $(PKGDIR) 228 | @cp -a $(MANIFEST) $(PKGDIR)/ 229 | @cp -a $(BUILDDIR)/$(PROJECT).bin $(PKGDIR)/$(PAYLOAD) 230 | @$(ZIP) $(ZIP_ARGS) $(PROJECT).zip $(PKGDIR) 231 | @mv $(PROJECT).zip $(PKGARCH) 232 | @echo 233 | @echo Done 234 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # logue_RandomLFOTutorial 2 | 3 | A "Random" filter LFO MOD effect for your logue sdk compatible synthesizers, with commented code and a brief explanation on how this all works... 4 | 5 | **This is provided for informational and entertainment purposes only, any use of the following information is done solely at your own risk! No guarantee is made on the suitibility or accuracy of any information provided.** 6 | 7 | ### A quick word... 8 | I've been having a ton of fun creating these plugins, and if you like stuff like this and my other work, by all means feel free to contribute whatever you can! 9 | 10 | This can be done here : [Donate!](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MSTCVLXMG7Z5J&source=url) 11 | 12 | 13 | Note, you will also find a writeup (and possibly more information) at [my main website](http://hammondeggsmusic.ca/blognotes/note2.html) 14 | 15 | 16 | 17 | **So glad you could attend....** 18 | 19 | So, you just bought your 'logue synthesizer, and realized it only has one LFO. And not only that, the single LFO only has saw, triangle and square modulation options! No sample-and-hold to be found here. 20 | 21 | Fortunately, the logue SDK provides a means to extend the capabilities of your synthesizer! While you currently cannot generate custom LFO waveforms, you can of course create your own modulator effects (choruses and the like, typically), reverb and delay effects. But, they don't "have" to fall in that category. You can do as you please, within the CPU time alloted. For this demo, we are going to create a mod effect that emulates a filter that is modulated by a "random" LFO. The randomness is provided by a 1024 entry floating-point table generated at random.org. 22 | 23 | Why a 'fixed' pre-calculated table? Well for the same reason this demo is all "straight C" (no C++ is actually required to make oscillators and effects) - for simplicities sake for beginners to start to be able to create their own effects. And for practical purposes, this works well enough. 24 | 25 | This demo uses a 'chamberlin' style filter as described in the book "Musical Applications For Microprocessors", by Hal Chamberlin. A definite must read once you've got the handle of getting the SDK to make some noise! Personally I find these filters not only extremely efficient (the math is fairly simple - compare with the actual biquad implementation!). A very good writeup of this filter is currently available [here]( https://www.earlevel.com/main/2003/03/02/the-digital-state-variable-filter/) 26 | 27 | I should probably note here, that as there currently is no actual "documentation" provided by KORG, most if not all of this is me "figuring this out". It is entirely possible, if not likely, that some of this is actually wrong, or interpreted incorrectly. Proceed at your own peril! 28 | Getting Started 29 | 30 | First, you must be able to build the demos provided by KORG, and be familiar with how to install them. There are some videos on YouTube etc. to help you get to this point. And, I'm not about to copy the entire SDK over at this time, but if you have installed the SDK on your system and can build the "waves" oscillator, or the 'biquad' modfx test, then you should be good to go. 31 | 32 | Please note, this was built on a minilogue-centric system, as I do not own a prologue. So my plugins are generally built in the platform/minilouge-xd/..... folders. 33 | 34 | First, create a new directory in the SDK modfx\tests (e.g. logue-sdk\platform\minilogue-xd\modfx\tests\) folder called "RandomDemo". Into this folder copy the source contents (the files : makefile, makefilePrologue, project.mk, manifest.json, randomDemo.c and the randomtable.h files). The demos provided by KORG place the source in the \src folder, however I myself like to have the source files in the project folders themselves, this ultimately can be entirely up to you. The demos provided by KORG place the source in the \src folder, however I myself like to have the source files in the project folders themselves, this ultimately can be entirely up to you. 35 | 36 | Next, enter the folder of the effect via your console (same means you used to build the demos), and type "make clean". This is generally a good idea before running make, as it cleans up any previous object files, and ensures you are building from scratch. 37 | Building the source 38 | 39 | To build the source, type "make" for the minilgoue xd, and if you wish to build this for the prologue, you could either copy this into the prologue platform directory, or, I've included a makefile that will allow you to do this. Just enter "make -f prologuemakefile" and it should generate the prlgunit. 40 | The code 41 | 42 | I believe the code itself is well commented to explain what is going on, but the fundamentally, there are 3 areas of concern: 43 | 44 | `void MODFX_INIT(uint32_t platform, uint32_t api)` 45 | 46 | - This is called whenever the effect is actually loaded. It is not called when the effect is simply turned off and on. Here, you will initialize any variables, classes etc that you wish to use. Personally, any module variables I use I try to initialize here, I do not rely solely on the compiler initializing these with the variable initializers for me despite writing it that way as well. 47 | 48 | `void MODFX_PROCESS(const float *main_xn, float *main_yn,const float *sub_xn, float *sub_yn,uint32_t frames)` 49 | 50 | This is the actual DSP function. It is here, where you will process the samples. With MOD FX , there are four separate buffers - two buffers for inputs ("main" and "sub" - applicable to prologue only when in dual / split modes), and for outputs: "main" and "sub"- again applicable to the prologue only. If you are properly implementing the prologue, you must have a separate, independent (duplicate) processor for the "sub" channel. For our demo we will merely pass the signal straight through for this channel. For the minilogue-xd, it is pointless to implement the sub channel as you will be wasting CPU cycles for something that is not supported. 51 | 52 | The samples are stereo in, stereo out, and the buffers appear to store these as LRLRLR - alternating left right samples. This is also true for the resultant output. Our effect is MONO, so we load in the LEFT channel (and ignore the right channel input - note we still have to "skip" that sample), and store the resultant value twice in the output buffer for both channels. 53 | 54 | `void MODFX_PARAM(uint8_t index, int32_t value)` 55 | 56 | This is called whenever one of the time/depth knobs are turned. Any math you can 'pre-calculate' e.g. a frequency that is based off of the knob position, is wisely calculated here, as there is no need to waste any CPU cycles calculating anything you do not need to in the DSP loop! 57 | 58 | The value provided by the API is a Q31 type, however the line 'const float valf = q31_to_f32(value);' converts this to a much more convenient float type, which ranges from 0 (knob left) to 1(knob right). We use this 0-1 value to calculate the LFO rate (by multiplying this with the MAX lfo rate we get a value from 0 to the max LFO rate, and we also use this to calculate the max frequency deviation similarly. 59 | 60 | 61 | When version 2 is released for the minilogue xd (or when the minilogue xd supports the API that enables shift-time and shift-depth), we will add the ability to change the centre frequency and the resonance via these parameters 62 | 63 | *Improvements for next time: Add a slew to the filter frequency to prevent sudden sharp frequency changes. Oversampling - oversampling would definitely be recommended, and is super easy to implement. This would also greatly increase the upper frequency range of the filter as well, as this filter type does not do well when you get close to 1/6 the sample rate. As well, as it is, it's not immune from "blowing up" - some simple safety checks / restrictions would help prevent this. Code optimizations. You can eliminate the D1/D2 variables in the filter easily to save some CPU time.* 64 | 65 | *Currently, the software available on this site is all offered for free, with an optional donation link for each if you like. All software is provided as-is, with no guarantees whatsoever - and is to be used entirely at your own risk.* 66 | 67 | *© All rights reserved. Any trademarks used are property of their respective owners* 68 | 69 | *Be sure to read the included license with each software download!* 70 | -------------------------------------------------------------------------------- /randomtable.h: -------------------------------------------------------------------------------- 1 | #ifndef RANDTABLE_H 2 | #define RANDTABLE_H 3 | 4 | // We don't have access to osc_white() as an effect (that I know of), so a simple 5 | // random table will suffice as this is for an LFO anyway. 6 | // This data was supplied by random.org, and modified to range from -1 to +1 7 | 8 | const float randTable[] = { 9 | -0.2314043,0.54651998,-0.63066714,-0.56493826,-0.48839572,-0.21916766,0.36462972,-0.2314043, 10 | -0.99293382,0.02225008,-0.0590655,-0.21065798,0.06464326,-0.7347001,-0.91283052,-0.99293382, 11 | 0.3101707,-0.86855938,0.44824784,0.9036195,-0.28517914,0.8671554,-0.06817168,0.3101707, 12 | -0.8786993,-0.99871646,-0.15906958,-0.64955412,-0.37710026,-0.94079724,0.4753889,-0.8786993, 13 | -0.77826232,-0.14901172,0.33947494,0.03480126,0.09901146,-0.15244496,0.85045282,-0.77826232, 14 | 0.14016282,-0.60031686,-0.7368612,0.11132936,0.52192004,-0.41913956,0.88288848,0.14016282, 15 | -0.82591624,-0.1756249,0.8422039,0.16095136,0.57135906,0.16372388,0.40648962,-0.82591624, 16 | -0.2247487,-0.90857676,-0.5081932,-0.08806882,0.81553532,0.30983194,-0.2376289,-0.2247487, 17 | 0.4132079,-0.21331628,0.57936184,0.42806572,0.18708752,0.96893894,-0.24882998,0.4132079, 18 | -0.77042766,-0.34924854,-0.94949042,0.8972434,0.91106102,-0.60743606,0.19371502,-0.77042766, 19 | -0.20218988,0.55676338,-0.79940764,0.0350633,-0.87155422,-0.22175292,-0.3637481,-0.20218988, 20 | 0.80896964,-0.42424776,-0.1810431,-0.14813198,-0.86818626,-0.49408196,-0.37851346,0.80896964, 21 | -0.99097862,0.62281918,-0.29857836,0.02390016,-0.03124716,-0.64804244,-0.43743098,-0.99097862, 22 | 0.58934736,-0.74861602,-0.76835268,-0.43021606,0.60707464,0.7244966,-0.7383832,0.58934736, 23 | 0.71779614,-0.95523746,-0.07665894,0.44470714,0.52566676,-0.86983378,0.92545644,0.71779614, 24 | 0.38263472,-0.96802444,-0.79689302,0.71366932,-0.39558382,-0.65158116,-0.44408322,0.38263472, 25 | 0.935562,0.5750502,0.6562886,0.71282426,0.67813702,-0.4311562,0.6084606,0.935562, 26 | -0.26947288,-0.7139464,-0.04079366,-0.49264042,0.41609684,-0.06236994,-0.4971883,-0.26947288, 27 | -0.07856028,0.3929187,-0.32627672,-0.29705398,0.7890507,0.67830528,0.43366444,-0.07856028, 28 | 0.36294672,-0.31054328,-0.60386346,-0.02516008,-0.23534518,-0.6276771,0.31781314,0.36294672, 29 | -0.21189904,-0.75042106,0.26553776,0.7815531,0.9266826,-0.06401378,-0.70242802,-0.21189904, 30 | -0.00936448,-0.91823652,0.48105932,0.00951496,0.3392277,-0.45449716,-0.52413002,-0.00936448, 31 | -0.50997314,0.16993856,-0.08575838,0.4424623,-0.94508054,-0.34301426,-0.04919728,-0.50997314, 32 | 0.30901268,0.54388654,-0.33703698,-0.45763798,0.24929596,-0.15978512,-0.37281858,0.30901268, 33 | -0.10214188,-0.23829564,0.12783704,0.46121502,0.2292569,-0.09900852,-0.63343892,-0.10214188, 34 | -0.67469454,0.41727694,-0.81324414,0.43579636,0.73391266,0.6970582,-0.73210638,-0.67469454, 35 | 0.40319666,0.09532302,-0.22735666,-0.53536714,-0.160397,-0.81317548,-0.20088504,0.40319666, 36 | -0.28883144,0.65829508,-0.59187258,0.5097592,-0.41594004,0.44822682,0.7629366,-0.28883144, 37 | 0.06847554,0.60397858,0.6186918,0.84819908,0.26638464,-0.71567522,-0.8988414,0.06847554, 38 | 0.86504872,0.48504544,0.36794678,0.74209346,0.30406672,0.87543584,0.9796863,0.86504872, 39 | -0.70568536,0.8672872,0.44382892,0.93275502,-0.95336612,0.84455776,-0.16467936,-0.70568536, 40 | -0.29009186,-0.66740094,0.13505892,-0.43017214,-0.8631255,-0.03546404,-0.4399171,-0.29009186, 41 | -0.8593023,-0.81491286,-0.40073122,-0.58075978,0.27444308,0.1904516,-0.96401404,-0.8593023, 42 | 0.34587482,0.23805126,-0.91135086,-0.89460414,0.27017916,-0.91989172,-0.85167016,0.34587482, 43 | 0.73536208,-0.09942514,-0.41704324,0.79051778,0.90658084,0.99153646,0.837739,0.73536208, 44 | 0.86572852,0.27813708,0.43269964,0.90900152,-0.67233946,-0.97474204,0.48845818,0.86572852, 45 | -0.21380142,0.39929994,-0.80022058,-0.56837196,-0.50921048,-0.3124034,-0.95404658,-0.21380142, 46 | -0.40691598,0.318588,0.62351066,-0.12148224,-0.69638694,-0.65496068,0.6022502,-0.40691598, 47 | 0.48854354,0.0636686,-0.57160988,0.06542284,-0.2267567,0.03774302,0.11637682,0.48854354, 48 | 0.3825501,0.34476354,-0.0351772,0.98224094,0.86545646,0.50505714,0.88864984,0.3825501, 49 | 0.12601476,-0.1363979,0.81608432,0.98896292,-0.69395204,0.8427457,-0.54178978,0.12601476, 50 | 0.09100582,-0.9007689,0.28847144,0.3337846,0.36541946,-0.88785694,-0.8370231,0.09100582, 51 | 0.37488482,0.34915012,0.7443386,0.39204604,0.55510766,0.96835834,0.14980906,0.37488482, 52 | 0.20555192,-0.26560552,0.9518228,-0.13262536,-0.19100506,-0.52570092,-0.18064476,0.20555192, 53 | 0.44051352,0.14131978,0.22155736,0.41442382,-0.18391942,0.70283572,0.12699806,0.44051352, 54 | -0.3781742,0.11146934,0.63289098,-0.2925214,0.1646008,-0.43433538,0.79793442,-0.3781742, 55 | 0.77492172,-0.69407076,0.88648988,-0.70925196,0.6115666,0.84393016,0.80714512,0.77492172, 56 | 0.11579974,-0.04395392,-0.43886524,0.1824845,-0.02778724,-0.75786064,-0.75553636,0.11579974, 57 | 0.7082662,0.13112518,-0.27631096,-0.79033644,-0.76531656,0.61693112,0.39563396,0.7082662, 58 | -0.477837,-0.10082598,0.79172574,-0.7774507,0.7316623,0.47095156,-0.2043716,-0.477837, 59 | -0.03313346,-0.70989702,-0.95510214,0.90332946,0.55298562,-0.13992812,0.09431898,-0.03313346, 60 | 0.50456728,0.1131065,-0.34402842,-0.2611352,0.79526646,-0.22803676,-0.85018172,0.50456728, 61 | -0.01294152,-0.58154144,0.00154482,-0.72775036,0.27340302,0.39507792,-0.1670534,-0.01294152, 62 | 0.49344392,-0.41576682,0.86465826,0.90609496,0.2680744,-0.55431324,-0.22611028,0.49344392, 63 | -0.63166678,0.03681282,0.93732292,0.79421054,0.75680826,0.39488566,-0.32658604,-0.63166678, 64 | 0.68596476,-0.5706574,0.4860868,0.94466168,-0.71115912,-0.22444316,0.37643138,0.68596476, 65 | -0.89011724,0.02987618,-0.27796526,-0.8050375,0.18051244,0.64654424,0.62688122,-0.89011724, 66 | 0.11059842,0.8483728,0.8744601,0.75997206,0.1736532,0.82692448,-0.55796142,0.11059842, 67 | 0.36995662,-0.84295624,0.8016379,-0.57090636,0.74974554,0.54700102,0.65746982,0.36995662, 68 | 0.18232336,0.02867258,-0.23261566,0.0935524,0.8179281,-0.88214384,-0.5697386,0.18232336, 69 | -0.71342984,0.0694111,-0.70011866,0.64776678,-0.84788004,-0.3425736,-0.9646738,-0.71342984, 70 | 0.31538774,0.07037428,0.88726658,-0.4807112,-0.32982548,0.1126246,0.60388196,0.31538774, 71 | -0.53313652,0.08372012,0.61973796,0.394952,0.8246582,0.88481538,-0.24087682,-0.53313652, 72 | 0.3757394,-0.413241,-0.0945069,-0.9761171,-0.00620484,-0.20354766,0.08883772,0.3757394, 73 | 0.3822473,0.64147354,0.83369564,0.64492258,0.81652656,-0.27513836,-0.02186548,0.3822473, 74 | -0.23742436,-0.56438892,-0.50334852,0.76430476,-0.46838836,-0.09395952,0.7842414,-0.23742436, 75 | -0.81575202,-0.95378786,-0.3807743,-0.06967186,-0.45942342,0.5827417,-0.56857122,-0.81575202, 76 | 0.46063568,-0.42610522,-0.45516278,-0.10268336,-0.23541684,0.4688219,0.64099866,0.46063568, 77 | 0.05802952,0.8001778,0.40879144,-0.27307604,-0.1332455,0.33208252,-0.07461506,0.05802952, 78 | 0.34954332,0.09076,-0.88862838,-0.00414206,-0.75859052,0.29397976,-0.6346285,0.34954332, 79 | 0.05661016,-0.82731236,0.69710546,0.03473258,0.55473872,0.67017612,-0.83585294,0.05661016, 80 | -0.97620244,0.50511004,-0.20961808,0.5006253,0.63531356,-0.83025904,-0.48152776,-0.97620244, 81 | 0.21433048,0.63335392,-0.1608967,0.30105834,-0.63062486,0.84330696,0.46969242,0.21433048, 82 | -0.7705885,0.32313618,0.31046994,-0.2540674,0.72786842,0.4826595,-0.62235638,-0.7705885, 83 | -0.0355434,0.98520864,-0.87815162,0.6134161,-0.5571174,0.31718424,-0.75338136,-0.0355434, 84 | -0.40396276,0.08816002,-0.81646766,-0.07225528,-0.75480328,0.33934536,0.18545084,-0.40396276, 85 | -0.48748834,0.13756104,0.6310622,0.3034468,0.14029578,-0.9440509,-0.4640537,-0.48748834, 86 | -0.47710832,0.82863812,-0.1383758,0.23267684,-0.61737126,-0.11208714,-0.07084092,-0.47710832, 87 | 0.94755754,0.78811298,0.45811822,-0.33411394,-0.15942362,-0.61453288,0.71096872,0.94755754, 88 | -0.07839638,-0.08976006,0.12007358,-0.96183704,-0.31404778,-0.96943192,-0.41512276,-0.07839638, 89 | -0.54852896,0.8740867,0.3379375,0.81187394,-0.00210008,0.73306086,0.4609503,-0.54852896, 90 | 0.49422332,0.17922812,-0.1386416,-0.1393405,-0.91146206,0.49270092,0.2462627,0.49422332, 91 | -0.8197245,-0.48312942,-0.80193424,0.4479154,0.52112698,0.34536922,0.54820328,-0.8197245, 92 | -0.2262592,-0.23449196,-0.7786537,-0.92515908,-0.36395126,-0.84451746,0.21900604,-0.2262592, 93 | 0.73757986,-0.65245366,-0.30550586,0.95831574,0.06069778,-0.88631858,-0.4106099,0.73757986, 94 | -0.60824484,0.2038373,0.86603704,0.73372154,-0.46523922,-0.49777182,0.69381506,-0.60824484, 95 | -0.54085014,0.84711214,-0.91277862,-0.60943694,-0.441752,-0.84145232,0.86151768,-0.54085014, 96 | 0.09213472,0.3800744,0.6929552,-0.7063468,-0.71690908,0.62472782,-0.3959323,0.09213472, 97 | 0.46058696,-0.877636,0.70621148,0.47732396,0.05142446,-0.49096676,0.91644368,0.46058696, 98 | -0.00800808,-0.52304498,-0.97128446,0.03976988,-0.50942394,-0.32669776,-0.922751,-0.00800808, 99 | -0.63294416,-0.56306758,0.32199748,0.32300178,0.59354418,0.7756601,-0.8233271,-0.63294416, 100 | 0.25103728,0.87239092,-0.56712866,0.90606774,-0.6677721,0.39281932,0.84309108,0.25103728, 101 | 0.37337992,0.94187978,0.07638866,-0.32099372,-0.58138784,-0.97862178,0.71326742,0.37337992, 102 | -0.76686512,-0.53764692,0.7847194,0.29846142,-0.88972228,0.87018062,-0.23668248,-0.76686512, 103 | 0.1493731,0.43799574,0.05076102,-0.62367112,0.79723884,-0.17013764,-0.7539358,0.1493731, 104 | 0.21666458,0.66255286,-0.16891254,0.27636212,-0.32907146,0.9597485,-0.08596422,0.21666458, 105 | 0.6752897,-0.91632782,0.1766806,0.68083844,0.78558016,-0.69103544,-0.53728112,0.6752897, 106 | 0.03214486,0.32830092,0.25647,0.23625178,-0.5937636,-0.81135356,-0.61167908,0.03214486, 107 | 0.46395552,0.63193942,0.2744395,-0.73164268,-0.94913722,0.90574892,0.10697688,0.46395552, 108 | -0.20396274,-0.0234194,-0.0575235,0.01722004,0.64399618,0.61442178,0.99113932,-0.20396274, 109 | -0.76422526,-0.6194951,0.72925818,0.36197314,0.23534978,0.75465732,0.79619018,-0.76422526, 110 | -0.55393706,-0.6084027,-0.35747332,0.39381542,-0.59639696,0.83248228,0.46917922,-0.55393706, 111 | 0.12264462,-0.3503252,-0.98878778,-0.7684302,-0.36647644,-0.84689388,-0.0645377,0.12264462, 112 | -0.71479686,-0.88359914,0.28704114,0.3028856,-0.65854258,-0.6530489,0.1083362,-0.71479686, 113 | 0.922393,-0.6527999,0.36411138,-0.90696742,-0.99082768,-0.10158124,0.07324462,0.922393, 114 | -0.04140592,0.40771058,-0.07072772,-0.2538809,0.58221524,0.61175048,-0.09769316,-0.04140592, 115 | -0.8814879,-0.77124736,0.27771956,-0.48963556,0.66815244,-0.1080161,-0.21262796,-0.8814879, 116 | -0.61492572,-0.42203502,0.7195284,-0.25434106,0.64691226,-0.44513018,-0.02941122,-0.61492572, 117 | 0.50274572,0.2756404,0.02407392,0.37121628,0.04699242,0.9128808,-0.18845168,0.50274572, 118 | -0.77884166,-0.46262852,-0.39944948,0.55292146,-0.72219574,0.60688358,-0.19910118,-0.77884166, 119 | 0.42477142,0.89974092,-0.65722284,-0.43353628,-0.17143786,-0.52309142,-0.46600464,0.42477142, 120 | 0.97069046,-0.49841484,-0.94977502,0.1913803,-0.91883316,0.37074546,-0.88487906,0.97069046, 121 | 0.94334796,0.56821762,-0.58964888,-0.64170976,0.01179128,0.70265266,-0.11852944,0.94334796, 122 | 0.54163886,0.1586083,-0.04181242,-0.32787398,0.57439822,-0.3969753,0.72897126,0.54163886, 123 | 0.13941208,0.40877528,0.13773482,0.46797796,-0.93322648,-0.56495112,0.61498848,0.13941208, 124 | 0.018925,-0.7066864,-0.31434506,0.53509898,-0.55762274,0.95048358,0.64756374,0.018925, 125 | 0.0650226,-0.4017769,0.65596522,0.09263014,0.93796024,0.3377664,-0.42533138,0.0650226, 126 | -0.79292012,0.04997824,0.1495786,-0.84438184,0.6027439,-0.69079686,-0.75112544,-0.79292012, 127 | -0.83698166,0.14413686,-0.40629302,0.60902136,-0.98837546,0.87648698,0.00596088,-0.83698166, 128 | 0.09025938,-0.94727352,0.0734586,-0.44196806,-0.44749486,-0.9185154,-0.13636142,0.09025938, 129 | 0.22891506,-0.14429294,-0.38508474,0.95292222,-0.31463094,0.6672517,0.9800606,0.22891506, 130 | 0.45206848,0.9604608,-0.1762746,-0.6321978,-0.24293544,-0.79310718,0.90345182,0.45206848, 131 | 0.23725112,0.14157852,0.17782366,-0.09028856,0.19427224,-0.92004778,0.32713364,0.23725112, 132 | 0.82832232,0.43888252,-0.89298774,-0.81558362,-0.0721609,0.72197366,-0.7685944,0.82832232, 133 | 0.16965144,0.52118662,-0.18801678,0.6772434,0.67489392,-0.94508016,0.85821014,0.16965144, 134 | 0.40983294,-0.50604126,0.42803208,0.5227238,-0.04413686,-0.04499508,0.80413176,0.40983294, 135 | -0.68272964,-0.03683318,0.43897514,0.04808062,-0.21115644,-0.66316636,0.785461,-0.68272964, 136 | -0.72476526,0.3522723,0.52550746,-0.76996668,0.93492206,0.90414748,-0.21409846,-0.72476526, 137 | }; 138 | 139 | #endif //RANDTABLE_H -------------------------------------------------------------------------------- /randomTutorial.c: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////// 2 | // 3 | // "random" lfo demo tutorial 4 | // 5 | // (c) 2019 hammondeggsmusic 6 | // 7 | // A simple 'random' LFO modfx (using a fixed table set) demo 8 | // in straightforward C for simplicity and efficiency. 9 | // 10 | // this is provided for informational purposes only and is to be 11 | // used at your own risk. 12 | // 13 | //////////////////////////////////////////////////////////////////////// 14 | //Includes 15 | #include "usermodfx.h" 16 | #include "randomtable.h" 17 | 18 | // Defines 19 | #define FIXED_Q 0.17 // Do not reach zero nor do not exceed 2. Lower values = more resonance. 20 | #define TWOPI 6.283185307 // 2*pi constant used by the filter 21 | 22 | #define RANDOM_TABLE_MASK 0x3FF // The table has 1024 (0x400) values, we simply mask the increment register with this value vs "checking if value >= max then set to 0". 23 | #define SAMPLE_RATE 48000 24 | #define CENTRE_FREQUENCY 1200 // This is the centre frequency of the filter. When the depth is set to 0, the filter will be at this frequency. 25 | // * When version 2.00 of the minilogue xd is released, you could use shift+depth to set this... 26 | #define INITIAL_FREQUENCY 800 // On effect load this is the frequency to assign to the filter initially 27 | #define INITIAL_FREQUENCY_DEVIATION 800 // On effect load this is the 'depth' amout to assign initially 28 | #define INITIAL_LFO_FREQUENCY 6 // On effect load this is the starting LFO rate 29 | 30 | #define MAX_FREQUENCY_DEVIATION 1100 // This should not exceed the centre frequency! This sets how much the frequency will deviate when the depth knob is at 'full'. 31 | #define MAX_LFO_RATE 20 // This is the maximum rate the LFO for the "sample and hold/randomizer" will run 32 | 33 | float phaseAccumLFO1 = 0; // LFO phase accumulator - this will count from 0 to (just under)1 , cycling at the LFO rate. 34 | float LFORate1 = INITIAL_LFO_FREQUENCY;// LFO frequency 35 | float valTime = 0; // Float value of the "Time" knob from 0 to 1 36 | float valDepth = 0; // Float value of the "Depth" knob from 0 to 1 37 | float effectDepth = 0; // Pre-calculated effect deviation (calculated at the knob turn event) 38 | uint16_t randomIndex = 0; // Current index into the random table. 39 | float currentFrequency = INITIAL_FREQUENCY; 40 | 41 | //Chamberlin filter variables. Ideally, these would all be in a filter class or at least a struct, 42 | // but for the this demo we will just declare these here, as they must persist. 43 | // I find these much easier to use than biquads, and are described in the book "Musical Applications For Microprocessors", by Hal Chamberlin. 44 | 45 | float D1 = 0; // Used internally by the filter (1-sample delay for bandpass filter) 46 | float D2 = 0; // Used internally by the filter (1-sample delay for low pass filter) 47 | float Q = FIXED_Q; // Filter resonance. This is defined as 1/Q, so a value of 2 = no resonance, and lower values = more resonance. A value of 0 may silence the filter however. 48 | float F1 = 0; // Used internally by the filter (frequency) 49 | float F = 0; // Filter cutoff frequency, although not quite expressed as 1:1 for frequency 50 | float H = 0; // High pass filter output value 51 | float B = 0; // Band pass filter output value 52 | float L = 0; // Low pass filter output value 53 | float N = 0; // Notch filter output value 54 | 55 | 56 | 57 | //////////////////////////////////////////////////////////////////////// 58 | // Effect Load event 59 | //////////////////////////////////////////////////////////////////////// 60 | void MODFX_INIT(uint32_t platform, uint32_t api) 61 | { 62 | // This occurs once when the mod fx is selected. This is not executed when the effect is enabled / disabled 63 | 64 | // Reset the phase accumulator 65 | phaseAccumLFO1 = 0; 66 | 67 | // Set a default filter LFO rate 68 | LFORate1 = INITIAL_LFO_FREQUENCY; 69 | 70 | // Initialize the random table index 71 | randomIndex = 0; //index in the random table 72 | 73 | // Initialize the filter. Again, you could put the filter in a class and call the constructor here etc, but 74 | // for simplicity's sake we'll keep this straightforward C. 75 | F = INITIAL_FREQUENCY; 76 | Q = FIXED_Q; 77 | B = 0; 78 | L = 0; 79 | N = 0; 80 | D1 = 0; 81 | D2 = 0; 82 | effectDepth = INITIAL_FREQUENCY_DEVIATION; //Initialize the initial effect depth 83 | 84 | } 85 | 86 | 87 | 88 | //////////////////////////////////////////////////////////////////////// 89 | // Effect process event 90 | //////////////////////////////////////////////////////////////////////// 91 | void MODFX_PROCESS(const float *main_xn, float *main_yn, 92 | const float *sub_xn, float *sub_yn, 93 | uint32_t frames) 94 | { 95 | // This is called each time the synthesizer feeds your effect some data 96 | // Variables passed to the effect: 97 | 98 | // *main_xn : Pointer to floating point INPUT data for the "main" channel (used by the minilogue xd and by the prologue in non-split/layer mode) 99 | // *sub_xn : Pointer to floating point INPUT data for the "sub" channel (currently used by the prologue in split/layer mode for the other channel) 100 | // *main_yn : Pointer to floating point OUTPUT data for the "main" channel 101 | // *sub_yn : Pointer to floating point OUTPUT data for the "sub" channel. 102 | // frames : Number of samples to process 103 | 104 | // Note, since the effects are stereo, there are two channels in each buffer. They appear to be stored as LEFT/RIGHT thus the end pointer is calculated as + 2*frames 105 | 106 | // It's important to note, that the "sub" channel, should effectively be treated as a separate effect. That is, any variables etc should be unique 107 | // to run this effect. This doubles the CPU time spent, and is not necessary on the minilogue xd (and likely the nts1) as it currently does not have a 'sub' channel. 108 | // That said, the prologue currently cannot run both delay and reverb at the same time (unlike the minilogue), so you can likely safely "double up" for the prologue and 109 | // restrict to a single channel for the minilogue. 110 | 111 | // As defined by the supplied demo code, the pointers are copied here: 112 | const float * mx = main_xn; 113 | float * __restrict my = main_yn; 114 | const float * my_e = my + 2*frames; 115 | 116 | const float *sx = sub_xn; 117 | float * __restrict sy = sub_yn; 118 | 119 | float sigOut; // Signal output value 120 | float sigIn; // Signal input value 121 | 122 | float randomValueF; // Floating point random value to get from table 123 | 124 | // Loop through the samples 125 | for (; my != my_e; ) 126 | { 127 | // Pass sub through for prologue for now (L,R), you will need a separate filter at least if you want to process this properly 128 | *(sy++) = *(sx++); // Copy *sy to *sx (Left channel) 129 | *(sy++) = *(sx++); // Copy *sy to *sx again (right channel) 130 | 131 | // Run the LFO oscillator 132 | // *Usually for an oscillator, I will run the LFO 'outside' of the DSP loop, as the oscillators currently run at 16 samples per loop, resulting 133 | // in 48000/16 = 3000hz update rate. The effects however currently use 64 samples, which equals a 750hz update rate. Especially as this effect 134 | // doesn't do a whole lot, we will keep the LFO in the DSP loop 135 | 136 | // *As always, the LFO itself could even be in a separate class etc however for this demo it is of courser kept simple. It is also entirely possible 137 | // that doing so also may result in using less CPU time, which is imperative as this is realtime DSP code! 138 | 139 | phaseAccumLFO1 += (LFORate1 / 48000); //48000 is the sample rate 140 | 141 | // Since we want a new random sample each time it loops, we'll check to see if it's overflowed here: 142 | if (phaseAccumLFO1 >= 1) 143 | { 144 | // Restrict the lfo phase accumulator to 0-1 145 | phaseAccumLFO1 -= (uint32_t) phaseAccumLFO1; 146 | 147 | // Calculate the new filter frequency: 148 | 149 | // Get the value from the table. *Note, the random table provided by random.org is a value from 0-1. Again, to save time, I've converted this table 150 | // to -1 to +1 ((val*2)-1) to save potentially wasted CPU time. 151 | 152 | randomValueF = randTable[randomIndex]; // Get a 'random' value from -1 to 1 153 | 154 | // Set the filter frequency here 155 | F = CENTRE_FREQUENCY + (randomValueF*effectDepth); 156 | 157 | // Increment and roll over the random table index 158 | randomIndex++; 159 | 160 | randomIndex &= RANDOM_TABLE_MASK; // This is the same as "if value >= # of entries then value = 0" but by using a table size that can be bitmasked 161 | // (e.g.1,2,4,8,16,32,64,128 etc, ours is 1024), we merely mask off the exceeding bits to again save time. We don't 162 | // *need* a table with say 1000 or 950 entries, a table of 1024 is perfectly fine. 163 | } 164 | 165 | // Get the input signal from the left channel (note effects are processed chorus->delay->reverb, and the synthesizer is currently mono up until the effects, 166 | // so we'll just use the left channel input for now) 167 | 168 | sigIn = (*mx++); 169 | mx++; // Advance the input pointer once more to skip the right channel input - we only use the left channel as an input. 170 | 171 | //Run the chamberlin filter: 172 | 173 | F1 = TWOPI * F / SAMPLE_RATE; // Calculate the F1 value(2pi * filter frequency / samplerate) 174 | L = D2 + F1 * D1; // Calculate the low pass portion 175 | H = sigIn - L - Q * D1; // Calculate the high pass portion 176 | B = F1 * H + D1; // Calculate the bandpass portion 177 | N = H + L; // Calculate the notch portion 178 | D1 = B; // Store the bandpass result into the bandpass delay value 179 | D2 = L; // Store the low pass result into the low pass delay value 180 | 181 | //*you can actually optimize this filter by removing the delays (D1 and D2) and simply using the 'last' bandpass and lowpass value, but 182 | // for simplicities sake this is again kept as straightforward as possible. 183 | 184 | // We'll use the L - lowpass output. Change this to H for highpass, N for notch, and B for bandpass if you wish.. 185 | sigOut = L; 186 | 187 | // Send this out to the left channel 188 | *(my++) = sigOut; 189 | // Send the same out to the right channel too, this is a mono effect. 190 | *(my++) = sigOut; 191 | } 192 | } 193 | 194 | //////////////////////////////////////////////////////////////////////// 195 | // Parameter change event 196 | //////////////////////////////////////////////////////////////////////// 197 | void MODFX_PARAM(uint8_t index, int32_t value) 198 | { 199 | // This occurs any time a parameter (in the case of effects, currently the "time" and "depth" knob (on minilogue)) 200 | const float valf = q31_to_f32(value); //Get the incoming value as a float from 0-1 201 | 202 | switch (index) 203 | { 204 | case 0: 205 | // Time knob - this will set the LFO rate(s) 206 | 207 | // valf, is the knob value as a float, from 0 to 1. 208 | valTime = valf; //Store this if we wish to use it later 209 | 210 | // Set the LFO rate here, no need to calculate it every time the sample loop runs! 211 | LFORate1 = MAX_LFO_RATE * valf; 212 | return; 213 | 214 | case 1: 215 | // Depth knob. 216 | valDepth = valf; //Store this if we wish to use it later. 217 | 218 | // Pre-calculate the deviation here, no need to do costly multiplications in the dsp loop for values that only change when the knob is turned! 219 | effectDepth = valf * MAX_FREQUENCY_DEVIATION; 220 | return; 221 | 222 | default: 223 | break; 224 | } 225 | } 226 | 227 | --------------------------------------------------------------------------------