Open Reaper, go to Options > Preferences⦠> MIDI Devices and check that your device is recognized at MIDI inputs and MIDI outputs.
Control your Neural DSP plug-ins by using your MIDI devices!
Need an electronic drum set that can be routed into your DAW through a MIDI connection? Check out our guide on the best electronic drum sets right here. Oh and if you are running Reaper as your main DAW to run your VSTs through, this is, in my opinion, the best VST for Reaper that you are likely to find for the low, low cost of free. Well, I finally managed to get a midi controller and a midi interface, but when I use my virtual instrument (Crystal VST, a synthesiser) there's a problem: no sound comes out regardless on which keyboard (virtual or midi controller) I used. Other virtual instruments don't work either. Record monitoring is on and the tracks are record armed. Does anybody know what's wrong?
A collection of 25+ MIDI data filters in LV2 plugin format. The filters follow the basic rules: One MIDI input, one MIDI output (no generators, no synths) No custom GUI, control inputs only.
After this, you just need to map your presets/parameters using the MIDI learn function or the MIDI mappings window. You can also use this method to automate preset changes through notes/PC messages. Keep in mind that there may be an offset of notes/MIDI messages between the DAW and the Plugin (example: C2 on the Plugin = C0 on the DAW, PC0 on the Plugin = PC1 on the DAW).
Today Iâm going to show you how to write a MIDI plugin in Reaper using JSFX.
BUT WAIT! Iâm going to assume that you are a total newb. I am going to walk you through every aspect of the process includinghow to find information.
The following topics will be covered:
The only thing that you need for this is a computer with Reaper installed and a working internet connection. If you have any questions then please comment, I will happily answer to the best of my ability.
Big shoutout to Jon at The Reaper Blog. He brought up this question about a plugin that translated MIDI notes to CC on behalf of another user. Thatâs why I wrote this entire thing.
This tutorial really isnât for you, but maybe you can skip to results to see what happened.
You may still enjoy reading this anyway, I hope!
A long time ago on a planet. uh, well. right here, there was some monstrosity called Jesusonic. Go ahead and click that link. Bask in its glory.
Keep baskingâ¦
Ok. Done? From the lineage of Jesusonic came JSFX which is an integated programming language in Reaper. This language allows you to create realtime audio, MIDI
A JSFX plugin works like any other VST/DX/AU plugin. You insert it on a track, the JSFX plugin accepts data and outputs data. The fun part is that we can output any data that we want!
Now we want to write a plugin. First Iâm going to cover some concepts, then in part 2 weâll dive in.
If you wish to just jump in you can simply skip to part 2. I will reference this pre-requisite information, and you can always jump back if you get lost.
If any of part 1 doesnât sink in, or if you feel confused then just skip to part 2. Iâll be walking you through the application of these concepts and you may find it easier to understand these concepts in a context.
Come up with an idea
Generally the first thing that you need to do is come up with an idea. I already have an idea, so lets discuss that.
I want a plugin that takes incoming MIDI notes and converts them to MIDI CC (controller change). This would allow someone to use their keyboard keys to change the values of something. For instance I could press the keys on my keyboard to adjust the value of a knob in another plugin.
Iâd like a few extra features as well:
Weâll cover adding these features one by one along with the logic for each one.
Write it!
Iâm just kidding. You canât write anything yet. First we need to cover some JSFX basics, and some programming basics.
Most of these things wonât make immediate sense if youâve never programmed before. You will have to reference back and forth as you go. Donât be ashamed! Thatâs how we learn. Let the puzzle be built in your brain piece by piece. Each new piece put in place will help build a more recognizable picture, but only after much time spent digging through the unrecognizable pile of puzzle pieces!
JSFX programming has a few basic things we need to cover. This section will allow you to read the code thatâs presented in future sections. Iâm going to explain each of these as if you have never programmed before.
If you have programmed before then you can hop right over to the JSFX page and learn how things work.
Programming conceptsVariables
A variable is just a word that references some data. There are various words in JSFX that do something special. The rest of the english language is ours to use.
The first time that we use a word thatâs not used by JSFX, then a new storage space is create for us. We can reference the data in that storage space using the name we give it. Like this:
Now anytime I use the word ârobertâ, itâs exactly as if I used the number 1. I can mutate (change) the value of ârobertâ later too. If I do
robert = 36 , then any time after that ârobertâ will be exactly like using the number 36.
Variables give us an easy way to hold on to data, and to refer to that data later.
Weâll be creating variables a lot.
Statements
A statement is a thing that does something. Assigning a variable is a statement for instance.
When we have a statement, we need to separate it from other statements. This is done with a
; . After a statement we just put a ; to say that weâre done with that.
If you have any errors, the most likely situation is that you forgot a
; . That goes even for the most experienced programmers.
Conditionals
When programming weâre often stood at a crossroads. Weâll need to act based on something that has happened before. If X happened then we do Y, but if T happened then we do R.
JSFX gives us a way of branching our program based on some value. It looks like this:
First we need something to test. âvalueâ in the example above is something to test. A result of 0 is considered âFalseâ. Anything other than 0 is considered true.
We can test just a variable, or we can test a comparison. We can compare 2 variables using operators like > (greater than) and < (less than). If we want to see if two things are equal then we use double equals signs like . If the comparison is correct then it is true, if the comparison is wrong then the value is false. So letâs try one:
What do you think âjohnâs value is?
Looping
Another thing that we often need to do in programming is to repeat an action. JSFX has 2 methods of doing this, but weâll only need one of them. You can discover the second one here
The construct we will use simply says, âWhile this variable/comparison is true, repeat this block of code. Check the variable/comparison each time we repeat to know if we should stopâ It looks like this:
Yeah, itâs that simple. The âwhileâ statement takes something to check, and then we have a bunch of code we put between () thatâs executed. After the execution we check if our situation is still to our satisfaction. If it is then we repeat the code again.
Math
Math is simple. Just things like
1 + 1 or 4 - 3 work.
If you need more complex facilities, then we use functions. A list of math functions is here.
These functions take some information, and they return a result for us. We usually need to do something with that value, such as assign it to a variable or use it in a comparison. Letâs give it a shot.
We assign ârobertâ a value of 1. Then we assign âjohnâ the result of
min(robert, 0) . min() takes 2 values and it returns the smallest of the two values.
What do you think the value of john is now?
I canât help you with your math, but luckily we wonât need anything fancier than basic addition and subtraction today.
Functions
Sometimes we need to call another piece of code somewhere. We send it some data, and it gives us some data back. This is done with the syntax:
function(data, data2, data3); . âdataâ, âdata2â, âdata3â are any information that you want to send. They can be numbers, variables or even other functions that return a value!
From there we would assign that to a variable so we can use that value later. Like this
result = function(data, data2, data3); Whatever âfunctionâ returns is now stored inside of result .
Order of operations
Often you may see things like this:
result = sqr(20 - ceil(9.8)); How do we interpret this?
The rule is that we work from the most interior parenthesis outwards. Photoshop cs6 cho macbook pro.
The variable âresultâ now contains the data â100â.
If you need to break it down visually, then open a text editor or a notebook and do it! Even the best programmers sometimes have to break down things in to their component pieces so they can understand it.
Create the plugin
Now that we have some basic programming knowledge, in the context of JSFX, under our belt we can create the plugin.
Letâs start!
File
The first thing we need to know is where to put this file that contains our code, and how to access it.
![]()
This is where JSFX files are stored. These are plaintext files, nothing special about them.
.jsfx is fine. Most JSFX plugins donât have an extension. Itâs up to you!).
To create a JSFX plugin:
Now we need to give it a Description after we learn to edit JSFX.
Editing JSFX
Editing JSFX
Now open Reaper. Add a track then click the FX button. Find the JS plugin that you just created. I can search for âRobertâ and find it since itâs in the âEffects/Robertsâ folder.
You will see the window on the left in the image above. Click that button that says âEditâ and a text editor will open up in Reaper with our file.
This is where weâll do all of our work from now on. You can edit the plugin inside of Reaper, and on the right side of the editor we have a realtime list of everything thatâs happening inside of our plugin. Donât worry if this seems intimidating, weâre going to work through it!
Description
In order for Reaper to know that we have a JSFX and what itâs called, we need to give it a description. JSFX has a format for this.
Yeah, thatâs it.
So Iâm going to add a description and some extra information to my plugin:
You see that line with
//author ? Those first 2 slashes indicate that the line is a comment. Comments are not read by Reaper when running the effect. Itâs just a way of communicating to the person reading the code.
Save your file. Control-s (Windows) or Command-S (macOS).
Controls - Part 1
Controls!
The first thing we need to do is lay out some controls. The users needs a way to interact with our plugin. Since we already thought out our idea beforehand, we can layout a set of controls based on that idea.
So letâs explore how JSFX allows us to create controls. The format looks like this:
Letâs work through that line:
So letâs try to make our first slider. We need to know what MIDI CC value to send. There are 128 possible options from 0 to 127. We can only use whole numbers (increments of 1). The default value can be anything, but Iâll use 0. We want it to be called âCC to sendâ. Try this on your own first before you see the solution!
Thereâs our first slider. It has a default value of 0, limits from 0 to 127 in increments of 1 with the label âCC to sendâ. Excellent!
Now add controls for MIDI note (0-127) cutoffs for low and high note. Values from 0-127 in increments of 1. Remember these are new sliders, so we canât reuse âslider1â.
Controls - Part 2
More Controls!
For some controls we donât want a slider. We want the user to select from pre-defined values. Sliders can be turned in to checkboxes by adding {} after the increment value. It looks like this:
The number 1 (after the 15) is our increment, but instead we create a list of values inside of curly braces {}. Each of these values inside of the curly braces is shown in a dropdown box.
The preselected values can be text too. To let the user choose to turn on Scaling or Inversion as we decided before, we can just use the words âYesâ and âNoâ like this:
That gives us a box with just the values of No and Yes. The default value is 0, which means the first value we offer is the default. â1â would mean that the second value is selected, etcâ¦
See if you can duplicate the controls Iâve laid out above. It shouldnât be too difficult.
Init
Init section
When our plugin is loaded, thereâs a few things that we may want to do first. Right now we have nothing, but weâll add that block anyway.
Simply add
@init below your sliders. Later weâll add some stuff here.
Slider
When we want to know the value of a slider in our program we can simply refer to it as âslider1â. With the default setup if we did something like
slider1 + 2 then the result would be 2. The default slider1 value is 0. We add 2 to that, and we get 2.
Itâs really bothersome to have to remember that âslider1â is âCC to Sendâ though. So JSFX gives us a place that we can create a new variable that references a sliderâs value. It looks like this:
Things inside the
@slider section happen when a slider changes. When the user moves a slider, then all of that code between @slider and the upcoming @block is called. It can be any code, but weâre only going to do variable assignments. So we create a new variable called âccValueâ that is assigned the value of slider1.
Iâve created a number of easy to remember variables that I can refer to the sliders by. Look at the screenshot above to see my setup.
EDIT Another option is to declare the slider with the variable that we want updated.
It looks like this:
slider1:ccValue=0<0,127,1>CC to send . We simply add ccValue= in front of the default value, and now our âccValueâ variable is updated when the slider moves.
Block
Block - where the work happens
Eventually stuff needs to happen when our plugin receives data.
@block is where that happens. The code in the @block section is called when our plugin needs to process some data.
Why is it called âblockâ though? Audio is processed in blocks. MIDI is processed in blocks too. They are actually processed in the same blocks, but weâre only working with MIDI today. The plugin receives a block of data, acts on it, outputs it, then waits for more data.
If youâre paying attention you may realize that when we get a block of data, weâll need to loop over that data to act on each piece of data in the block. That is correct, and weâll cover that soon.
So just add a
@block and weâre off to the races!
MIDI Concepts
In order to process MIDI we need to know what MIDI is.
I somewhat assume that you know what MIDI is if youâre reading this, but letâs go over some basics.
MIDI is a standard that covers a plethora of specifications related to a communication protocol. This communications protocol is generally used in musical and A/V applications to communicate simple data between devices.
This tutorial is only concerned with MIDI as a way of communicating data between devices. MIDI doesnât actually do anything. It doesnât make noises. It doesnât make lights. Itâs just the data that something else interprets, and that something else can do things based on that MIDI data.
MIDI data consists of 8bit âwordsâ, and the full message may be multiple words. A simple MIDI message may look like this
10010000 1000000 1000000 . That message says âNote E3 (64) on channel 1 with a velocity of 64â. By the end of this tutorial youâll be able to figure that out on your own without any trouble.
In this tutorial we are going to deal with 3 âwordâ messages. Most MIDI messages are 3 âwordsâ. The exception to the 3 âwordâ scenario is a type of message called System, which we donât care about today and you probably wonât encounter very often. These words will be called bytes from now on, as 8 bits = 1 byte. Here is a typical 3 byte message:
A typical musical scenario is the pressing of a piano key. The first byte communicates the channel and that âthis is a key pressâ. The second byte communicates the note. The third byte communicates how hard the key was pressed.
DONâT BE SCARED! Iâm going to teach you how to make sense of these bits, bytes and bagels.
How did I find this information?
![]()
I just googled for âMIDI specificationâ and I got this page, which wasnât helpful really.
Then I found this one, which is a step up. Wireless game controller for macbook pro.
So I thought maybe searching for âMIDI message programmingâ, and then I found this one. Much better!
Just continually searching and adjusting search teams until you find something that gives you more clues. This is a process of finding bits of information, then refining your search based on that information. Eventually you build up a pile of info in your brain that is what you need.
Itâs a process of refinement. If you donât get it the first time, use the little knowledge that you have to get a little bit more knowledge. Now repeat!
Binary
Computers âspeakâ in binary. MIDI messages come in binary. So we need to understand binary. Luckily itâs not that hard!
Binary is a different way of counting. In the form of counting that you are familiar with, each âplaceâ represents a multiple of 10. We have the 1âs place, 10âs place, 100âs place etcâ¦
With binary, each place is a â2âs exponent placeâ. Each place can either be there or not. The âon-nessâ of a place is indicated by a 1 for âonâ and a 0 for âoffâ.
Each place in binary is equivalent to 2^position. Our first position is 0, and we count up from there. So the first position is âtwo to the zero powerâ, either 1 or 0. The second position is âtwo to the first powerâ, either 2 or 0. The second position is âtwo to the second powerâ, either 4 or 0 etcâ¦
To determine the decimal value of a binary number, we take the value of each place and add them together.
Letâs work through the image above.
Our binary number is
01001011 . We work from right to left to figure this out (^implies that the next number is an exponent):
So now we take all the values of the bits that are turned on and add them. 64 + 8 + 2 + 1. That equals 75.
01001011 = 75 in decimal.
So what have we learned? Next time you need to convert binary to decimal, all you have to do is google for âBinary to decimal converterâ. Iâm serious. Almost nobody does this in their head!
Even more importantly, binary values are not always used to represent numeric values. Imagine this, I have 8 light switches. I want to communicate in the shortest possible way that I want light switches one, two, four and seven turned on downstairs. I can call downstairs and say â75â. That corresponds to 01001011 in binary⦠Which tells us exactly which light switches we want on and off!
Often in software, numbers are used like this. They are called âflagsâ or âbit fieldsâ. We use numbers to communicate data other than numbers, we can communicate âstateâ of simple on/off switches this way.
There are special math operators for binary that allow us to operate on binary, these are called âbitwise operatorsâ. We will be using one of these in our plugin, and I will explain it later. Itâs the â&â operator, which I suggest you research on your own for fun.
We will also be using plain normal math to operate on our binary values. I will explain these as well. The only thing that you need to know is how to convert binary to decimal, and have a grasp of the idea that binary is often used to communicate data that doesnât correspond to its numerical value.
Hex
Binary is a pain to be typing out all the time. Hexidecimal is much easier. Weâll be using hexidecimal in our plugin.
Binary is a âbase 2â system. Every place represents an exponential value of 2. Hexidecimal is a âbase 16â system. Every place represents an exponential value of 16.
âBut we only have 10 numbers!â, you exclaim! Youâre right. So we use letters. Counting in hexidecimal goes like this: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F. The letter âAâ corresponds to â10. âFâ is 15â.
Just like binary, each place is an exponent. So 10 in hexidecimal is 1*16^1 + 0*16^0 16.
33 in hexidecimal is 3*16^1 + 3*16^0 3*15 + 3*1 51.
So letâs practice that again⦠Convert 7FB3E9AA to decimal.
Howâd you do? I sure hope you googled, âHexidecimal to decimal calculatorâ, copy&pasted and came up with â2,142,497,194â. If not, youâre crazy. USE TOOLS. Donât do any more work than you need to!
In JSFX we denote that weâre using a hex value by prefixing our value with
$x . That means that $x0F is a hexidecimal value of 0F , which we know is â15â in decimal. EDIT - As of Reaper 5.00+ you can simply use 0x0F for hex values. The â$â is not needed. I will be using the $x0F format for the rest of this post.
Binary to Hex
Weâll need to convert from binary to hex. The MIDI spec is often listed in binary, but weâll be programming using hex. So letâs try this.
Our value is
01001011 just like before. Before you try to convert this, even using google (or WolframAlpha), letâs cover a trick.
You donât actually need to convert the whole thing at once. Because 16 is the result of 2^4, we can cheat. We only need to work in chunks of 4 bits. Letâs split it up from right to left.
Thatâs it! Just combine those 2 values.
01001011 = 4B in hex. No matter how big the binary number is, we can convert it in chunks of 4 bits.
You may also recall from before that the MIDI messages are 3 bytes. Thatâs 3 sets of 8 bits. We can think of each byte as 2 hexidecimal places. So a MIDI message in hex may look like
90 40 40 (which is 10010000 1000000 1000000 in binary). This is a much easier way to type the data and think of things.
Donât worry if this doesnât make total sense yet. Just try to grasp the general idea. Once we start using this information, it should make more sense!
We are now fully armed with the general idea of the information we need to write this plugin. Donât worry if everything doesnât make sense yet!. This is an iterative process. You may need to try something, read about it, try it again, read about it some more⦠a dozen times.
Every programmer does this. All of us. Itâs a process of trial and error. Even the super ultra smart geniuses went through this at some point.
The loop
The start of the main loop
We already discussed how JSFX sends us a block of data, and we need to process each piece of the block. To do that we write a loop.
How do we write the loop? We donât! We use one that we found. Google âJSFX MIDI programmingâ and this is the first result. Excellent. Letâs dig.
We know that we need to receive MIDI data and process it. So letâs grab the first thing that looks like it receives and processes data which is
midirecv(offset,msg1,msg2,msg3) -- REAPER 4.60+ .
The code is:
Thatâs exactly what we need. We want to process only notes, and thatâs what this does.
The line
msg1$x90 && msg3!=0 says âIf the first msg1 is a note and the velocity isnât zeroâ then⦠we do stuff.
How do we know that? Letâs head over to that page about MIDI for programmers.
In the âNOTE messagesâ section it tells us that we have 3 bytes. A status byte, which is msg1. A data byte 1, which is msg2. A data byte 2, which is msg3. Letâs go over each thing listed on that web page.
So this is how we figure out what the MIDI information is. We browse the spec (or google for more information), then we compare that information to the âmsg1â, âmsg2â and âmsg3â that JSFX gives us.
But what about that offset value? Well weâve been given a block of data, and the time position of each event is stored as an offset. If we want events to have the same âtimingâ on output as input, then we just pass the offset to
midisend() without changing it. You can create other effects like delays by messing with that value.
First Init value
Our first INIT value
That
$x90 value is ugly. We donât always want to remember that. So letâs create a variable that corresponds to that always.
In our
@init section, create a new variable like this noteOn = $x90; .
From now on when we want to reference the concept of a MIDI note event, we can use the word ânoteOnâ instead of having to remember that silly value.
Finding the MIDI channel
We know that
90 in hex refers to a note on channel 1. But what if we receive a value of 91 ?
We donât want to have to check for â90â, â91â, â92â, â93â etc⦠to know if we have a note value! We need a way to split up the first 4 bits of the âstatus byteâ and the second 4 bits.
This is where bitwise operators come in to play. We are going to use the âandâ operator. This specific operation is part of bit masking. These things may sound scary, but I assure you they are not that difficult!
Letâs assume that we have a note message on channel 8. That value looks like
98 . Itâs a combination of 90 and 08 . We want to âuncombineâ the 98 .
Letâs first unpack that
98 to binary. Fire up google and youâll convert your 98 hexidecimal to 1001 1000 . Having this in binary helps us think about the problem better because we are using bitwise operations, so itâs nicer to think in bits.
The âandâ bitwise operator takes 2 values. It compares the bits in each place. If both places have a 1, then the result is 1. If either places has a 0, then the result is 0. Thatâs where the trick lies. We can âturn offâ values by using a bitwise âandâ that has 0s in the place we want to cut off.
So if we just want the first 4 bits, then we leave those and turn off the other 4. So look in the image above.
We do the following operation:
1001 1000 & 1111 0000 . From top to bottom the numbers are âandedâ. If both numbers are 1 then the result is 1. If either number is 0 then the result is 0.
Look at the result! It zeroâd out the rightmost 4 bits. The result is only our leftmost bits. Now we have a value that only contains information about âwhat type of eventâ weâre dealing with.
We need to do this in hexidecimal though. Easily enough, we know that each hex place is 4 bits. âFâ is âall bitsâ, and â0â is âno bitsâ. So to extract the event type and channel we do this:
Weâve taken the first message, zerod out the left most bits, and assigned that to
noteStatus . Now we can use noteStatus to find out if our message is a note, and not worry about the channel.
Then we took the first message and zerod out the left most bits. This contains the 4 bits that is our MIDI channel number.
Transfer imac to macbook pro. Now letâs add those variables in to our loop (since we need to extract these values for each piece of data in the block) and change our code to use the
noteStatus variable to check if we are processing a note:
New code with bitmasks
Filtering the MIDI Channel
Now we need to make sure that we only respond to messages on the MIDI channel that the user selected. This is as simple as using our
inChannel variable in our conditional.
Iâm going to replace the
msg3!=0 with a check for the correct MIDI input channel. See the screenshot.
Reacting to the correct notes
Note Filtering
In our specification we said that we wanted to only react to a range of notes. After weâre sure that we have a note message on the correct channel, we want to make sure that the note is in the range that we determined.
In english we would say âIf the input is greater than the lowNote AND the input is less than the highNoteâ.
First thing Iâll do is assign
msg2 to something more readable. Inside the âwhileâ loop where we determined the noteStatus and channel , letâs assign currentNote = msg2 . Now we can refer to currentNote when we want to know the note number.
Vsti For Reaper
Then since we learned conditionals already, so we can translate that to code to this:
Thereâs no
: ( ) because we donât care what happens if the note is out of range. We only act if the scenario is correct.
Remember to indent your code as you go!
Made the plugin do something
Our first working plugin
Right now our plugin does nothing. Letâs make it work, but ignore the scaling and inversion.
Letâs just make the plugin output the current MIDI note value as a CC message. First though, what is a CC message? Weâll visit the reference that Iâve been using most of this tutorial, but you can find this information directly in the specification.
MIDI CC messages are exactly like note messages. The first status byte is
B0 to signify a CC event plus the MIDI channel. The second byte selects which MIDI CC message, from 0-127. The third byte is the value of that CC from 0-127.
First thing we need to do is create a variable that references that
B0 . In the @init section weâll add cc = $xB0; .
Next we want to use the
midisend function to output our data, and weâll do this in the section where we act if our note is in the correct range. It looks like this:
We keep our offset the same. Then we combine the
B0 CC message with our channel. Simple addition works here, no bit math necessary. Next we send the ccValue , which is selected by the user in the GUI, as the CC number. Now we send the ccMsg value as the value of the midi CC. (The astute reader will notice that I created this variable and snuck it in⦠Look at the screenshot to see where it was created. Pay attention closely!)
Your code should look just like in the screenshot so far.
Invert
Optionally invert the output
Now we need to implement the invert functions.
The idea is that we want an input of 127 to come out as 0, and an input of 0 to come out as 127. We donât want to create a massive map of values. That would be silly. Letâs abuse some math.
Using Midi In Reaper
Whatâs an easy way to turn 127 to 0? Just subtract 127! What if we subtract 127 when the value is already 0 though? We end up with -127. Thatâs very close to what we want. We want 0 to be 127, not to be -127. What we want is the absolute value. Letâs check the JSFX reference and find the absolute value function. Itâs
abs() . Now letâs implement a new variable that contains our inverted value;
We only want to do this calculation when the inversion slider is active, so letâs surround that in a conditional
Weâll insert that code before we use
midisend() when the note is in range. See the screenshot.
Scaling
Scaling parameters
Next we need to scale the values optionally. This is more complex. What we need to do is figure out the distance between lowNote and highNote, then figure out how to map that range to a range of 0-127.
First thing is figure out the distance between the high and low note.
ccMsg = highNote - lowNote; . Easy.
Now we need to figure out how much âone valueâ equals between our high/low notes. Thatâs defined as such
128 / (highNote - lowNote); . So if our high note is 80, and our lowNote is 90 we have a distance of 10. That means each increase in note value will correspond to a 128 / 10 (12.8) increase in ccMsg. Each note increase changes the CC value by 12.8. Weâll call this our âscalarâ and define it like this scalar = (128 / (highNote - lowNote));
So now we know how much the distance between notes scales to CC values. We need to create real values out of this. We need to know how far we are from the low note. Our current distance from the low note is
currentNote - lowNote . So if our currentNote is 55, and our lowNote is 50, then we know weâre a distance of 5 from our low note. Weâll call that our âdistanceâ and define it like this: distance = (currentNote - lowNote);
To get the CC value, we multiply the distance by the scaling value:
ccMsg = scalar * distance; . The first part determines the scaling, then we multiply it by the distance.
We have a problem here though! Our example before gave us a value of â12.8â. CC values are whole numbers. We need to make sure that the value we send is a whole number. We only want an integer. Check the JSFX reference again to find something that makes sure we only have an integer.
floor() is an option. ceil() is an option too. I want to use floor, so letâs wrap our entire thing in a floor: ccMsg = floor(scalar * distance); .
Once again, we also only want to do this if our
scaleVal slider says âYesâ (or is true). So weâll wrap that in a conditional, and our final code gets inserted after the inversion code:
Itâs important here to know that this is how a lot of programming is done. You slowly solve the problem, piece by piece. We figured out the easiest part. Then we kept breaking it down until we assembled a fully working piece of code.
Protection
Protection
Weâre limited to values of 0 to 127 for our
ccMsg , and itâs possible that after scaling we may end up with a value thatâs greater than 127!
We need to add some protection code. Thereâs a few ways to do this, so Iâm going to let you solve it yourself. You can of course see how I solved it in the screenshot.
Finish it off
Thereâs a few last things here. The first issue is that for this plugin, I never want to send MIDI that isnât part of the conversion. So I will remove the âelseâ line from our biggest conditional. I took away this bit:
Next is to COMMENT YOUR CODE. This should be done the whole time! I intentionally left comments out of this code so there was less visual clutter. I actually had to retake a number of screenshots because I instinctively commented something.
Anytime you write something that isnât entirely obvious, add a comment in plain english explaining it. Even if nobody ever looks at your code, it will help you while youâre working on the code. I canât tell you how much time Iâve spent trying to understand my own code! Itâs probably the biggest time sink in the industry. Do it for yourself, COMMENT YOUR CODE.
Here is my resulting code:
This code actually took me about a total of 25 minutes to write, including looking up the MIDI spec and testing things. For a total beginner, it may take you days!
Programming takes practice like anything else.
Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |