Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global RAM for Formula #3

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 3 additions & 25 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,31 +1,9 @@
# If RACK_DIR is not defined when calling the Makefile, default to two directories above
RACK_DIR ?= ../..

# Must follow the format in the Naming section of
# https://vcvrack.com/manual/PluginDevelopmentTutorial.html
SLUG = BOKONTEPByteBeatMachine

# Must follow the format in the Versioning section of
# https://vcvrack.com/manual/PluginDevelopmentTutorial.html
SLUG = FrankBussFormula
VERSION = 0.6.1

# FLAGS will be passed to both the C and C++ compiler
FLAGS +=
CFLAGS +=
CXXFLAGS +=

# Careful about linking to shared libraries, since you can't assume much about the user's environment and library search path.
# Static libraries are fine.
LDFLAGS +=
SOURCES += $(wildcard src/*.cpp src/formula/*.cpp)

# Add .cpp and .c files to the build
SOURCES += $(wildcard src/*.cpp)
SOURCES += $(wildcard src/*.c)


# Add files to the ZIP package when running `make dist`
# The compiled plugin is automatically added.
DISTRIBUTABLES += $(wildcard LICENSE*) res

# Include the VCV Rack plugin Makefile framework
RACK_DIR ?= ../..
include $(RACK_DIR)/plugin.mk
165 changes: 120 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,141 @@
# Formula

# BokontepByteBeatMachine
A formula module for VCV Rack, by Frank Buss, based on BokontepByteBeatMachine.

javascript bytebeat on VCVRack
Now you can burn countless cpu cycles by creating 8 bit oscillators with javascript! Built with duktape and caffeine drinks!
This plugin provides 3 inputs: x, y and z. In the text field you can write a
formula for the output. For example `x+y` would be a simple adder.

Demo video here:
[![BokontepByteBeatMachine demo](http://img.youtube.com/vi/AQctoH3ucmQ/0.jpg)](http://www.youtube.com/watch?v=AQctoH3ucmQ)
Some functions take 2 arguments. For example you could use the max function, to
get either the input x or the input y, depending on which voltage is higher:
`max(x, y)`.

Some kind of manual
===================
The red LED is blinking if there is a parsing error. If it is on, the formula
is running.

![alt text](bytebeatmachine.png "BokontepByteBeatMachine on VCVRack")
BokontepByteBeatMachine is an 8bit, 8000 Hz javascript oscillator. You can enter a javascript expression in the textbox
(better write it in a text editor if is more than one line and paste it there), right click on the context menu and select initialize (or just press CTRL+I)
to compile the expression. If the expression is compiled successfully the red led over the textarea with the javascript turns to red.
If there is an error in compiling the statement the red led flashes. If the expression is successfully compiled, when a trigger is received on the trigger input, or if you
press the button above the trigger input the expression is evaluated and eventually outputted as an 8bit unsigned integer (0-255),
which in turn is converted to the -5.0 .. 5.0 values that VCVRack works with.
The javascript expression can contain javascript functions, bit and arithmetic operations and 3 variables. t, X and Y (look out for case sensitivity t is lower case, X and Y upper case).
t is the current time. X and Y are 8 bit unsigned ints coming from the X and Y inputs. Each value from the inputs with a value between -5.0 and 5.0 is mapped to an integer between 0 and 255.
This works at a glorious 8000 samples per second so there you have it, a bytebeat oscillator in javascript!
You can also use the trigger led button over the trigger input to test the oscillator.
A few things to try.
![alt text](add.png "Add example")

The simplest thing to try is just putting t as the expression. This produces a kind of stepped saw.
Or you can try my personal favorite (([1.122,1.259,1.498,1.681,1.887][((t >> 12) ^ ((t >> 10)+ 3561)) %5]) * t & 128 | (([1.122,1.259,1.498,1.681,1.887][((t >> 11) ^ ((t >> 9) +2137)) %5]) * t) & ((t>>14)%120+8) | (t>>4) )
I call the above snippet ΚΙΝΕΖΙΚΑ ΠΑΡΑΘΥΡΑ (chinese windows if this is greek to you)
If you want to learn more about bytebeat you can start here:
https://www.reddit.com/r/bytebeat/
http://countercomplex.blogspot.gr/2011/10/algorithmic-symphonies-from-one-line-of.html
http://countercomplex.blogspot.gr/2011/10/some-deep-analysis-of-one-line-music.html
It works with CV and audio signals. The output is clamped to -5V/+5V. Some more
examples for what you can use it:

# Waveform Generator

Some more technical mumbo jumbo
===============================
BokontepByteBeatMachine is built using the opensource duktape javascript engine. The expression you enter on the textbox is actually turned into a javascript function before
compilation so if you enter just the t, internally a function is constructed like this:
You can also use functions, see later for a list of all available functions,
and you can use the variable `pi`. In combination with a sawtooth, this can be
used as a mathematically wave generator. The sawtooth has to be a simple
generator, with no anti-aliasing algorithms, because the falling edge of the
ramp needs to be with no smoothing in one sample. Otherwise there would be
samples from the rising part created, which results in distortions.

s-ol's Circle VCO is such an oscillator. It outputs a ramp from 0V to 5V at a
frequency of 187.5 Hz, if the pitch knob is at 0. So a sine wave with the usual
10Vpp can be generated with `sin(2*pi*x/5)*5`.

More complex formulas are possible as well, you can enter multiple lines. For
example this approximates the square wave function with additive synthesis with
the base frequency and the first 3 harmonics of the square wave:

```
function f(t,X,Y)
{
return (t);
}
4*(
sin(2*pi*x/5)+
sin(6*pi*x/5)/3+
sin(10*pi*x/5)/5+
sin(14*pi*x/5)/7
)
```

The function is compiled and then repeatedly executed. That's it. Each time a trigger is received t is reset to 0. For more insights on how this works just look at the source code.
![alt text](formula.png "Additive synthesis example")


# Level Converter

Another wider range of applications is parameter adjustment. For example the
VCO-1 in Fundamental has a V/OCT input. This means when you create a new
instance with the initial frequency for C4 (261.626 Hz) and apply 1 V, the
frequency will be increased by one octave to C5 (523.252 Hz).

A small disclaimerish note on audio quality
===========================================
This plugin produces sound with a lot of unpleasant frequencies due to low bit rate and aliasing. This is by design in this case.
But what if you have a linear V/Hz CV signal and want to convert it in a way
that it can be used with a V/OCT input? Then you need to calculate the log to
base 2 of the input level. There is only the log function to base e and base 10
available in Formula, but with `log(x)/log(2)` you can calculate the signal. So
for `x=1.5` it would be exactly `1.5 * 261.626 Hz = 392.439 Hz`.

![alt text](oct-hz.png "Level converter")

Legal stuff aka license
=======================
This code is left on the public domain. Do as you please with it.
# Relational operators

The relational operators (<, >, <= and >=) allow other interesting
applications. For example if you want to select one of two signals, based on
the CV level of another signal (a multiplexer). Then you could use the formula
`(z<=5)*x+(z>5)*y`. This would output x, if the level at the z input is 5V or
less, otherwise it outputs y. It works because if `z<=5` is valid, the term
evaluates to 1, otherwise to 0.

Peace,
![alt text](mux.png "Multiplexer")

# Boolean operators

Finally there are the boolean operators `&` for logical-and, `|` for logical-or
and `!`for not. This can be useful, if you want to test two signals with the
relational operators, like if x and y has some minimum value at the same time,
only then output the value of z. Or you could even use it to implement a 10
step sequencer with chromatic scale:

```
((x>=0 & x<1) * 1 + (x>=1 & x<2) * 5 +
(x>=2 & x<3) * 8 + (x>=3 & x<4) * 9 +
(x>=4 & x<5) * 10 + (x>=5 & x<6) * 12 +
(x>=6 & x<7) * 10 + (x>=7 & x<8) * 9 +
(x>=8 & x<9) * 8 + (x>=9 & x<10) * 5)
/ 12
```

ВОКОИТЕР 2018
Try it and listen to it, then change the factors interactively. Unlike a normal
step sequencer, you can adjust the length of the indivual steps as well by
changing the x time windows, lots of fun :-)

Oh, and if you like this don't forget to check out my music and my ramblings on
http://bokontep.blogspot.gr
![alt text](sequencer.png "Sequencer")

# Quantizer

You can use the `floor` function to implement a simple quantizer. This function
rounds the value down to the next integer value. For example `floor(1.8)=1`.
For a chromatic quantizer, only the voltages 0, 1/12, 2/12 etc. are allowed.
This can be enforced with this formula: `floor(x*12)/12`.

![alt text](quantizer.png "Quantizer")

# The geeky details

The following functions are implemented:

acos, asin, atan, atan2, cos, cosh, exp, fabs, fmod, log, log10, pow, sin,
sinh, tan, tanh, sqrt, ceil, floor, max, and min. See here for a detailed
description of each function: http://www.cplusplus.com/reference/cmath/

The full BNF grammar for the parser looks like this:

```
expression = and-expression [or-operator and-expression]
and-expression = equal-expression [and-operator equal-expression]
equal-expression = relational-expression [equal-operator relational-expression]
relational-expression = sum [relational-operator sum]
sum = [sign] term {additive-operator term}
term = factor {multiplicative-operator factor}
factor = power {power-operator power}
power = power_operand {power-operator power_operand}
power_operand = unsigned-real | variable | (expression) | function-call
or-operator = |
and-operator = &
equal-operator = == | !=
relational-operator = < | > | <= | >=
additive-operator = + | -
multiplicative-operator = * | / | %
power-operator = ^
not-operator = !
variable = [a-z, A-Z, _]+ [a-z, A-Z, 0-9, _]*
unsigned-real = [0-9]* [.] [0-9]* [real-exponent]
real-exponent = [e|E] [+|-] [0-9]+
```

I wrote the formula library in 2001, here is the original page with a function
plotter as another example: http://www.frank-buss.de/formula/index.html
Binary file added add.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed bytebeatmachine.png
Binary file not shown.
Binary file added formula.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added mux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added oct-hz.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added quantizer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
187 changes: 0 additions & 187 deletions res/MyModule - Αντιγραφή.svg

This file was deleted.

Loading