facet
facet copied to clipboard
Live coding and synthesis with NodeJS and a browser
Overview
Facet is an open-source live coding system for algorithmic music. With a code editor in the browser and a NodeJS server running locally on your machine, Facet can generate and sequence audio and MIDI data in real-time.
Getting started
- Download and install Node.js and npm: https://www.npmjs.com/get-npm
- Download and install SoX: http://sox.sourceforge.net/
- Download the Facet repo.
- In a terminal, navigate to the root of the Facet repository, and run
npm install
. - After the previous command completes, run
npm run facet
. The server should start running, and it should open up a new browser window with the code editor. - Copy this command into the code editor in the browser:
_.sine(100,200).play();
Move your cursor so it's on the line. Hit[ctrl + enter]
to run the command. The code editor application will always briefly highlights to illustrate what command(s) ran. You should hear a sine wave playing out of your computer's default sound card.
For more information on getting started, check out this mini-tutorial on YouTube: https://www.youtube.com/watch?v=ceJbWjh8VOs
Facet commands
Syntax
Facet commands are based entirely around JavaScript, using a custom class called a FacetPattern
. In order to produce audio or MIDI output, simply create an instance of a FacetPattern, and run some methods:
new FacetPattern().sine(100,200).play();
There are two shorthands for creating a new instance of a FacetPattern
:
new $('my_sine').sine(100,200).play(); // named my_sine
_.sine(100,200).play(); // no name
Next, translate that data:
_.sine(100,200).gain(random()).play();
// each time you run ^, the same sine wave at a different volume
Certain operations (e.g. sometimes()
, iter()
, slices()
) allow you to supply functions as arguments:
_.iter(16,1,()=>{this.append(_.randsamp().speed(0.1))}).play();
// stitches together 16 random samples, each playing at 10x normal speed, and play back the result one time
UI controls in the browser
Below the text editor, there are several UI elements which control the Facet server running in the background. Moving from left to right:
- Server connection status indicator (green = online; red = offline)
- CPU% indicator
- Slider for setting the BPM of the global transport
- Slider for setting the number of steps in a whole note
- MIDI output selector / refresh button
- ▶ = start global transport
- ■ = stop global transport
- ↵ = rerun the block of code wherever the cursor is
- ⊖ = clear all event hooks. More information on event hooks is in the
.on()
function documentation below.
Keyboard shortcuts
- Run command(s):
[ctrl + enter]
. All commands not separated by multiple newlines will run together. - Stop the transport and clear all hooks (effectively a global mute):
[ctrl + m]
- Clear all hooks, but continue the transport:
[ctrl + c]
- Mute/unmute hooks:
[ctrl + f]
Variables
mousex / mousey
Both mousex
and mousey
, as floating-point number representations of your cursor's position in the browser window, are available for use in commands, e.g.:
_.sine(100,200).gain(mousey); // cursor y position controls volume every time the code runs
notevalues
There are 128 notevalues variables, corresponding to note divisions of 1 whole note. A whole note is n1, a half note is n2, etc... up to n128.
Command reference
Rerunning commands
-
on ( FacetPattern = 0, every_n_times = 1 )
- Reruns the command at however many positions are specified in FacetPattern, as the global transport steps through a whole note.
- FacetPattern should contain floating-point numbers between 0 and 1, corresponding to the relative point in the transport between 0 and 1 when the code should rerun, given the number of steps.
- With no first argument, the command will regenerate at point 0, i.e. at the beginning of each whole note. You can supply a number, array, or FacetPattern as the first argument.
- With no second argument, the command will regenerate at the beginning of each whole note. When a second argument is present, the command will only regenerate every
n
whole notes. - Hit
[ctrl + c]
to delete all hooks. You should see a message indicate successful deletion in the browser. - Hit
[ctrl + f]
to toggle between muting and un-muting all hooks. You should see a message indicating the current status in the browser. - example:
-
_.randsamp().play().on() // play new sample at the beginning of every whole note
-
_.randsamp().play().on(_.noise(4)) // play new sample at 4 random times throughrought every whole note
-
_.randsamp().play().on(_.choose(0,0.125,0.25,0.375,0.5,0.625,0.75,0.875)) // play new sample at 8 geometrically related times throughout every note
-
Audio output
-
channel ( channels )
- Facet ultimately creates .wav files that can have any number of channels. The
.channel()
function (and equivalentchannels()
function) allow you to route the output of a FacetPattern onto any channel(s) you specify in thechannels
input array. NOTE: CPU will also increase as the total number of channels increases. - example:
-
_.randsamp().channel(1).play(); // first channel only
-
_.randsamp().channels([1,3]).play(); // second channel only
-
_.randsamp().channel(_.from([9,10,11,12,13,14,15,16]).shuffle().reduce(random(1,8,1))).play(); // play on a random number of channels from 9-16
-
- Facet ultimately creates .wav files that can have any number of channels. The
-
play ( FacetPattern )
- plays the FacetPattern as audio to your computer's default sound card, at however many positions are specified in FacetPattern, as the global transport steps through a whole note.
- FacetPattern should contain floating-point numbers between 0 and 1, corresponding to the relative point in the transport between 0 and 1 when the generated audio should play, given the number of steps.
- With no arguments, the command will regenerate at point 0, i.e. at the beginning of each whole note. You can supply a number, array, or FacetPattern as the argument.
- Whereas
repeat()
will continually loop playback,play()
only runs a single time. - example:
-
_.randsamp().play(); // plays once at beginning of loop
-
_.randsamp().play(0.5); // plays once at middle point
-
_.randsamp().play(_.noise(4)); // plays once at 4 random steps
-
-
repeat ( FacetPattern )
- continually plays the sequence at whatever positions were specified, each time the transport moves through a whole note.
- FacetPattern should contain floating-point numbers between 0 and 1, corresponding to the relative point in the transport between 0 and 1 when the generated audio should play, given the number of steps.
- With no arguments, the command will regenerate at point 0, i.e. at the beginning of each whole note. You can supply a number, array, or FacetPattern as the argument.
-
Note: if you want to use
on()
withrepeat()
, you will need to give your FacetPattern a name, e.g.new $('name_goes here')
. - example:
-
_.randsamp().repeat(); // repeats, starting at beginning of loop
-
_.randsamp().repeat(0.5); // repeats, starting at middle point
-
new $('name_goes_here').randsamp().repeat(_.noise(4)).on(); // note how the FacetPattern is named
-
-
size ( new_size )
- upscales or downscales the FacetPattern prior to playback, so its length is
new_size
samples. The upscaling and downscaling happens in SoX after all other calculations are complete, when the .wav file is generating. This means you can place the.size()
anywhere in a command, since it runs at the end of the chain of function calls, no matter what. This also means you can only use one.size()
per command, and if you use more than one, it will default to the last one in the command. - example:
-
_.drunk(256,0.1).size(44100); // upscaling a 256-sample drunk walk to be 1 second
-
- upscales or downscales the FacetPattern prior to playback, so its length is
MIDI output
You might need to activate a MIDI driver on your machine in order to send MIDI from Facet to a DAW. If Facet finds no MIDI drivers, the dropdown select UI in the browser will be empty, and if you try the below commands they will produce no output. Google "install midi driver {your OS goes here}" for more information.
-
note ( VelocityPattern = 100, DurationPattern = 125, channel = 1 )
- sends a MIDI note on/off pair for every value in the FacetPattern's data.
- The VelocityPattern and DurationPatterns will automatically scale to match the note pattern. This allows you to modulate MIDI velocity and duration over the course of the whole note.
- The
channel
argument by default sends the MIDI out all channels (channel 0). It can be set to any channel between 1-16. - example:
-
_.sine(1,32).scale(36,90).round().note();
-
_.sine(1,random(32,100,1)).scale(36,random(52,100,1)).prob(random()).nonzero().round().note().on();
-
-
cc ( controller_number = 70, channel = 1 )
- sends a MIDI cc event bound to controller #
controller_number
for every value in the FacetPattern's data. - Note: This function is automatically scaled into cc data, so you can supply it a FacetPattern between 0 and 1.
- The
channel
argument by default sends the MIDI out all channels (channel 0). It can be set to any channel between 1-16. - example:
-
_.drunk(64,mousey).cc().on();
-
- sends a MIDI cc event bound to controller #
-
pitchbend ( channel = 1 )
- sends a MIDI pitch bend event for every value in the FacetPattern's data.
- The
channel
argument by default sends the MIDI out all channels (channel 0). It can be set to any channel between 1-16. - Note: This function is automatically scaled into pitch bend data, so you can supply it a FacetPattern between 0 and 1.
- example:
-
_.pitchbend(64,random()).scale(0,127).cc();
-
Single number generators
-
choose ( pattern )
- returns a randomly selected value from a supplied array.
- example:
-
_.sine(choose([2,3,4]),40); // sine wave with either 2, 3, or 4 cycles
-
-
random ( min = 0, max = 1, int_mode = 0 )
- returns a random number between
min
andmax
. Ifint_mode
= 1, returns an integer. Otherwise, returns a float by default. - example:
-
_.sine(random(1,100,1),40) // a sine wave with 1 - 100 cycles
-
- returns a random number between
FacetPattern generators
-
binary ( integer, length)
- Computes the binary representation of
integer
. Iflength
is not present, the output FacetPattern will be the actual length of the binary representation ofinteger
. - example:
-
_.binary(8); // 1000
-
_.binary(490321,13); // 1110111101101: truncated at 13 values
-
_.binary(8,12); // 000000001000: padded with 0s
-
- Computes the binary representation of
-
cosine ( periods, length )
- generates a cosine for
periods
periods, each period havinglength
values. - example:
-
_.cosine(2,30); // 2 cycles, 30 values each
-
- generates a cosine for
-
drunk ( length, intensity )
- generates a random walk of values between 0 and 1 for
length
values.intensity
controls how much to add. - example:
-
_.drunk(16,0.1); // slight random movement
-
- generates a random walk of values between 0 and 1 for
-
from ( pattern )
- allows the user to specify their own pattern. Note the array syntax!
- example:
-
_.from([1,2,3,4]);
-
-
noise ( length )
- generates a random series of values between9 0 and 1 for
length
. - example:
-
_.noise(1024); // lots of randomness
-
- generates a random series of values between9 0 and 1 for
-
phasor ( periods, length )
- ramps from 0 to 1 for
periods
periods, each period having lengthlength
. - example:
-
_.phasor(10,100); // 10 ramps
-
- ramps from 0 to 1 for
-
ramp ( from, to, size )
- moves from
from
toto
oversize
values. - example:
-
_.ramp(250,100,1000); // go from 250 to 100 over 1000 values
-
- moves from
-
sine ( periods, length )
- generates a cosine for
periods
periods, each period havinglength
values. - example:
-
_.cosine(2,30); // 2 cycles, 30 values each
-
- generates a cosine for
-
spiral ( length, degrees = 137.5 )
- generates a spiral of length
length
of continually ascending values in a circular loop between 0 and 1, where each value isdegrees
away from the previous value.degrees
can be any number between 0 and 360. By defaultdegrees
is set to 137.5 which produces an output pattern similar to branching leaves, where each value is as far away as possible from the previous value. - example:
-
_.sine(1,1000).times(_.spiral(1000,random(1,360))); // an interesting, modulated sine wave
-
_.spiral(100); // defaults to a Fibonacci leaf spiral
-
- generates a spiral of length
-
square ( periods, length )
- generates a square wave (all 0 and 1 values) for
periods
periods, each period havinglength
values. - example:
-
_.square(5,6); // 5 cycles, 6 values each
-
- generates a square wave (all 0 and 1 values) for
-
turing ( length )
- generates a pattern of length
length
with random 1s and 0s. - example:
-
_.turing(64); // instant rhythmic triggers
-
- generates a pattern of length
-
tri ( periods, length )
- generates a triangle wave for
periods
periods, each period havinglength
values. - example:
-
_.triangle(30,33); // 30 cycles, 33 values each
-
- generates a triangle wave for
FacetPattern modulators
-
abs ( )
- returns the absolute value of all numbers in the FacetPattern.
- example:
-
_.sine(1,100).offset(-0.3).abs(); // a wonky sine
-
-
at ( position, value )
- replaces the value of a FacetPattern at the relative position
position
withvalue
. - example:
-
_.turing(16).at(0,1); // the 1st value of the 16-step Turing sequence (i.e. 0% position) is always 1
-
_.turing(16).at(0.5,2); // the 9th value of the 16-step Turing sequence (i.e. 50% position) is always 2
-
- replaces the value of a FacetPattern at the relative position
-
changed ( )
- returns a 1 or 0 for each value in the FacetPattern. If the value is different than the previous value, returns a 1. Otherwise returns a 0. (The first value is compared against the last value in the FacetPattern.)
- example:
-
_.from([1,1,3,4]).changed(); // 1 0 1 1
-
-
clip ( min, max )
- clips any numbers in the FacetPattern to a
min
andmax
range. - example:
-
_.from([1,2,3,4]).clip(2,3); // 2 2 3 3
-
- clips any numbers in the FacetPattern to a
-
curve ( tension = 0.5, segments = 25 )
- returns a curved version of the FacetPattern. Tension and number of segments in the curve can be included but default to 0.5 and 25, respectively.
- example:
-
_.noise(16).curve(); // not so noisy
-
_.noise(16).curve(0.5, 10); // fewer segments per curve
-
_.noise(16).curve(0.9); // different curve type
-
-
distavg ( )
- computes the distance from the average of the FacetPattern, for each element in the FacetPattern.
- example:
-
_.from([0.1,4,3.14]).distavg(); // -2.3133 1.5867 0.7267
-
-
dup ( num )
- duplicates the FacetPattern
num
times. - example:
-
_.sine(1,100).dup(random(2,4,1)); // sine has 2, 3, or 4 cycles
-
- duplicates the FacetPattern
-
echo ( num, feedback = 0.666 )
- repeats the FacetPattern
num
times, with amplitude multiplied byfeedback
each repeat. - example:
-
_.from([1]).echo(5); // 1 0.666 0.4435 0.29540 0.19674 0.13103
-
_.phasor(5,20).echo(8); // phasor decreases after each 5 cycles
-
- repeats the FacetPattern
-
fade ( )
- applies a crossfade window to the FacetPattern, so the beginning and end are faded out.
- example:
-
_.noise(1024).fade();
-
-
fft ( )
- computes the FFT of the FacetPattern, translating the FacetPattern data into "phase data" that could theoretically reconstruct it using sine waves.
- example:
-
_.from([1,0,1,1]).fft(); // 3 0 0 1 1 0 0 -1
-
-
flipAbove ( maximum )
- for all values above
maximum
, it returnsmaximum
minus how far above the value was. - example:
-
_.sine(1,1000).flipAbove(0.2); // wonky sine
-
- for all values above
-
flipBelow ( min )
- for all values below
minimum
, it returnsminimum
plus how far below the value was. - example:
-
_.sine(1,1000).flipBelow(0.2); // inverse wonky sine
-
- for all values below
-
flattop ( )
- applies a flat top window to the FacetPattern, which a different flavor of fade.
- example:
-
_.noise(1024).flattop();
-
-
fracture ( pieces )
- divides and scrambles the FacetPattern into
pieces
pieces. - example:
-
_.phasor(1,1000).fracture(100); // the phasor has shattered into 100 pieces!
-
- divides and scrambles the FacetPattern into
-
gain ( amt )
- multiplies every value in the FacetPattern by a number.
- example:
-
_.from([0,1,2]).gain(100); // 0 100 200
-
_.from([0,1,2]).gain(0.5); // 0 0.5 1
-
-
get ( name )
- retrieves a FacetPattern previously stored in memory by a
.set()
command. NOTE: You cannot run.get()
in the same block of commands where the pattern was initially stored via.set()
.- example:
-
_.randsamp().set('my_pattern'); // first, set a random sample, in a separate command
-
_.get('my_pattern').dup(1).play() // then in a new command, run these two together
-
_.get('my_pattern').dup(3).play() // to play the same sample 2 and 4 times simultaneously
- retrieves a FacetPattern previously stored in memory by a
-
gt ( amt )
- returns
1
for every value in the FacetPattern greater thanamt
and0
for all other values. - example:
-
_.from([0.1,0.3,0.5,0.7]).gt(0.6); // 0 0 0 1
-
- returns
-
gte ( amt )
- returns
1
for every value in the FacetPattern greater than or equal toamt
and0
for all other values. - example:
-
_.from([0.1,0.3,0.5,0.7]).gte(0.5); // 0 0 1 1
-
- returns
-
ifft ( )
- computes the IFFT of the FacetPattern. Typically it would be used to reconstruct a FacetPattern after it had been translated into "phase data". But you can run an IFFT on any data.
- example:
-
_.randsamp().set('p');_.iter(6,()=>{this.get('p').fft().shift(0.4).ifft().normalize().set('p')}); // iterative bin shifting
-
-
interp ( weight = 0.5, name )
- interpolates the FacetPattern with a FacetPattern previously stored in memory by a
.set()
command. A weight of 0.5 gives equal weight to both patterns. NOTE: You cannot run.interp()
in the same block of commands where the pattern was initially stored via.set()
.- example:
-
_.randsamp().set('mypattern'); // first in one command, set a random sample
-
_.sine(100,350).interp(0.5,_.get('mypattern')).play(); // then in a second command, 50% interpolate with a sine wave
- interpolates the FacetPattern with a FacetPattern previously stored in memory by a
-
invert ( )
- computes the
minimum
andmaximum
values in the FacetPattern, then scales every number to the opposite position, relative tominimum
andmaximum
. - example:
-
_.from([0,0.1,0.5,0.667,1]).invert(); // 1 0.9 0.5 0.333 0
-
- computes the
-
iter ( num_times, commands = function(), prob = 1 )
- A shorthand for rerunning a certain command over and over, with prob as a float between 0 and 1 controlling the likelihood that the code actually runs. You can refer to the current iteration of the algorithm via the reserved word:
this
(see example). - example:
-
_.randsamp().iter(3,1,()=>{this.echo(random(1,30,1),1.2)}).scale(-1,1).lpf(2400); // dubby feedback
-
- A shorthand for rerunning a certain command over and over, with prob as a float between 0 and 1 controlling the likelihood that the code actually runs. You can refer to the current iteration of the algorithm via the reserved word:
-
jam ( prob, amt )
- changes values in the FacetPattern.
prob
(float 0-1) sets the likelihood of each value changing.amt
is how much bigger or smaller the changed values can be. Ifamt
is set to 2, andprob
is set to 0.5 half the values could have any number between 2 and -2 added to them. - example:
-
_.drunk(128,0.05).jam(0.1,0.7); // small 128 step random walk with larger deviations from the jam
-
- changes values in the FacetPattern.
-
lt ( amt )
- returns
1
for every value in the FacetPattern less thanamt
and0
for all other values. - example:
-
_.from([0.1,0.3,0.5,0.7]).lt(0.6); // 1 1 0 0
-
- returns
-
lte ( amt )
- returns
1
for every value in the FacetPattern less than or equal toamt
and0
for all other values. - example:
-
_.from(0.1,0.3,0.5,0.7]).lte(0.5); // 1 1 1 0
-
- returns
-
log ( base, direction )
- stretches a FacetPattern according to a logarithmic curve
base
, where the values at the end can be stretched for a significant portion of the FacetPattern, and the values at the beginning can be squished together. Ifdirection
is negative, returns the FacetPattern in reverse. - example:
-
_.ramp(1,0,1000).log(100); // a logarithmic curve from 1 to 0
-
- stretches a FacetPattern according to a logarithmic curve
-
lpf ( cutoff )
- applies a simple low pass filter to the FacetPattern.
- example:
-
_.noise(44100).lpf(random(1,1000)); // low-passed noise
-
-
modulo ( amt )
- returns the modulo i.e.
% amt
calculation for each value in the FacetPattern. - example:
-
_.from([1,2,3,4]).modulo(3); // 1 2 0 1
-
- returns the modulo i.e.
-
normalize ( )
- scales the FacetPattern to the 0 - 1 range.
- example:
-
_.sine(1,100).gain(4000).normalize(); // the gain is undone!
-
_sine(1,100).scale(-1, 1).normalize(); // works with negative values
-
-
nonzero ( )
- replaces all instances of 0 with the previous nonzero value. Useful after with probability controls, which by default will set some values to 0. Chaining a nonzero() after that would replace the 0s with the other values the pattern. Particularly in a MIDI context with .prob(), you probably don't want to send MIDI note values of 0, so this will effectively sample and hold each nonzero value, keeping the MIDI note values in the expected range.
- example:
-
_.from([1,2,3,4]).prob(0.5).nonzero(); // if 2 and 4 are set to 0 by prob(0.5), the output of .nonzero() would be 1 1 3 3
-
-
offset ( amt )
- adds
amt
to each value in the FacetPattern. - example:
-
_.sine(4,40).offset(-0.2); // sine's dipping into negative territory
-
- adds
-
palindrome ( )
- returns the original FacetPattern plus the reversed FacetPattern.
- example:
-
_.from([0,1,2,3]).palindrome(); // 0 1 2 3 3 2 1 0
-
-
pong ( min, max )
- folds FacetPattern values greater than
max
so their output continues atmin
. If the values are twice greater thanmax
, their output continues atmin
again. Similar for values less thanmin
, such that they wrap around the min/max thresholds. - if no value is entered for
max
, then the first argument will be used to create themin
andmax
, centered around 0. For instance,pong(0.3) == pong(-0.3,0.3)
- example:
-
_.sine(1,1000).offset(-0.1).pong(0.2,0.5); // EZ cool waveform ready to normalize
-
- folds FacetPattern values greater than
-
pow ( expo, direction = 1 )
- stretches a FacetPattern according to an exponential power
expo
, where the values at the beginning can be stretched for a significant portion of the FacetPattern, and the values at the end can be squished together. Ifdirection
is negative, returns the FacetPattern in reverse. - example:
-
_.sine(5,200).pow(6.5); // squished into the end
-
_.sine(5,200).pow(6.5,-1) // squished at the beginning
-
- stretches a FacetPattern according to an exponential power
-
prob ( amt )
- sets some values in the FacetPattern to 0.
prob
(float 0-1) sets the likelihood of each value changing. - example:
-
_.from([1,2,3,4]).prob(0.5); // 1 0 3 0 first time it runs
-
_.from([1,2,3,4]).prob(0.5); // 0 0 3 4 second time it runs
-
_.from([1,2,3,4]).prob(0.5); // 0 2 3 4 third time it runs
-
- sets some values in the FacetPattern to 0.
-
quantize ( resolution )
- returns
0
for every step in the FacetPattern whose position is not a multiple ofresolution
. - example:
-
_.drunk(16,0.5).quantize(4); // 0.5241 0 0 0 0.7420 0 0 0 1.0 0 0 0 0.4268 0 0 0
-
- returns
-
range ( new_min, new_max )
- returns the subset of the FacetPattern from the relative positions of
new_min
(float 0-1) andnew_max
(float 0-1). - example:
-
_.from([0.1,0.2,0.3,0.4]).range(0.5,1); // 0.3 0.4
-
- returns the subset of the FacetPattern from the relative positions of
-
recurse ( prob )
- randomly copies portions of the FacetPattern onto itself, creating nested, self-similar structures.
prob
(float 0-1) sets the likelihood of each value running a recursive copying process. - example:
-
_.noise(128).recurse(0.7); // remove the recurse to hear the difference
-
- randomly copies portions of the FacetPattern onto itself, creating nested, self-similar structures.
-
reduce ( new_size )
- reduces the FacetPattern length to
new_size
. Ifnew_size
is larger than the FacetPattern length, no change. - example:
-
_.from([1,2,3,4]).reduce(2); // 1 3
-
- reduces the FacetPattern length to
-
reverse ( )
- returns the reversed FacetPattern.
- example:
-
_.phasor(1,1000).reverse(); // go from 1 to 0 over 1000 values
-
-
round ( )
- rounds all values in the FacetPattern to an integer.
- example:
-
_.from([0.1,0.5,0.9,1.1]).round(); // 0 1 1 1
-
-
saheach ( n )
- samples and holds every
nth
value in the FacetPattern. - example:
-
_.phasor(1,20).saheach(2); // 0 0 0.1 0.1 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.6 0.7 0.7 0.8 0.8 0.9 0.9
-
- samples and holds every
-
saturate ( gain )
- runs nonlinear waveshaping (distortion) on the FacetPattern, always returning values between -1 and 1.
- example:
-
_.phasor(1,20).gain(10).saturate(6); // 0 0.995 0.9999 0.99999996 0.9999999999 0.999999999999 0.9999999999999996 1 1 1 1 1 1 1 1 1 1 1 1 1
-
-
saveAs ( filename )
- creates a new wav file in the
samples/
directory or a sub-directory containing the FacetPattern. NOTE: the directory must already exist. - example:
-
_.iter(6,1,()=>{this.append(_.sine(random(1,40,1),100)).saveAs('/myNoiseStuff/' + Date.now()
)}); // creates 6 wav files in the myNoiseStuff directory. Each filename is the UNIX timestamp to preserve order.`
-
- creates a new wav file in the
-
scale ( new_min, new_max )
- moves the FacetPattern to a new range, from
new_min
tonew_max
. NOTE: this function will return the average of new_min and new_max if the FacetPattern is only 1 value long. since you cannot interpolate where the value would fall in the new range, without a larger FacetPattern to provide initial context of the value's relative position. This operation works better with sequences larger than 3 or 4. - if no value is entered for
new_max
, then the first argument will be used to create thenew_min
andnew_max
, centered around 0. For instance,scale(1) == scale(-1,1)
- example:
-
_.sine(10,100).scale(-1,1); // bipolar signal
-
- moves the FacetPattern to a new range, from
-
set ( name )
- stores a FacetPattern in memory for temporary reference in future operations. NOTE: You cannot run
.get()
in the same block of commands where the pattern was initially stored via.set()
. Any FacetPatterns stored via.set()
will only be stored until the server is closed.- example:
-
_.noise(32).set('my_pattern');
- stores a FacetPattern in memory for temporary reference in future operations. NOTE: You cannot run
-
shift ( amt )
- moves the FacetPattern to the left or the right.
amt
gets wrapped to values between -1 and 1, since you can't shift more than 100% left or 100% right. - example:
-
_.from([1,2,3,4]).shift(-0.5); // 3 4 2 1
-
- moves the FacetPattern to the left or the right.
-
shuffle ( )
- randomizes the FacetPattern.
- example:
-
_.from([1,2,3,4]).shuffle(); // first time: 3 2 1 4
-
_.from([1,2,3,4]).shuffle(); // second time: 1 3 4 2
-
-
skip ( prob )
- Sometimes, skip executing the command, as if it had never been attempted. Useful if you only want to update the wavetable in Max some of the time, but otherwise want to preserve the previous data.
- example:
-
_.spiral(16,random(1,360)).skip(0.95); // only load data into the "new samples" wavetable 5% of the time when this command runs
- Sometimes, skip executing the command, as if it had never been attempted. Useful if you only want to update the wavetable in Max some of the time, but otherwise want to preserve the previous data.
-
slew ( depth = 25, up_speed = 1, down_speed = 1 )
- adds upwards and/or downwards slew to the FacetPattern.
depth
controls how many slew values exist between each value.up_speed
anddown_speed
control how long the slew lasts: at 0, the slew has no effect, whereas at 1, the slew occurs over the entiredepth
between each FacetPattern value. - example:
-
_.from([0,0.5,0.9,0.1]).slew(25,0,1) // the first three numbers will jump immediately because upwards slew is 0. then it will slew from 0.9 to 0.1 over the course of the entire depth range
-
- adds upwards and/or downwards slew to the FacetPattern.
-
slices ( num_slices, commands = function, prob = 1 )
- slices the FacetPattern into
num_slices
slices, and forprob
percent of those slices, runscommands
, appending all slices back together. You can refer to the current slice of the algorithm via the reserved word:this
(see example). - example:
-
_.randsamp().slices(32,1,()=>{this.fft().shift(random()).ifft()});
-
- slices the FacetPattern into
-
smooth ( )
- interpolates each value so it falls exactly between the values that precede and follow it.
- example:
-
_.noise(64).smooth(); // less noisy
-
-
sometimes (prob, operations)
- runs a chain of operations only some of the time, at a probability set by
prob
.
- runs a chain of operations only some of the time, at a probability set by
_.phasor(1,100).sticky(0.5).scale(40,80).sometimes(0.5,()=>this.reverse());
// half the time, pattern goes up; half the time, it goes down
-
sort ( )
- returns the FacetPattern ordered lowest to highest.
- example:
-
_.sine(1,100).sort(); // a nice smoothing envelope from 0 to 1
-
-
speed ( amt )
- increases or decreases the playback speed of the FacetPattern, similar to transposing audio samples up or down. amt values less than 1 speed up; amt values greater than 1 slow down. amt is clamped between 0.02083 and 8.
- example
-
_.randsamp().speed(0.2); // fast sample
-
_.randsamp().speed(1.5); // slow sample
-
-
sticky ( amt )
- samples and holds values in the FacetPattern based on probability.
amt
(float 0-1) sets the likelihood of each value being sampled and held. - example
-
_.sine(1,1000).sticky(0.98); // glitchy sine
-
- samples and holds values in the FacetPattern based on probability.
-
subset ( percentage )
- returns a subset of the FacetPattern with
percentage
% values in it. - example:
-
_.phasor(1,50).subset(0.3); // originally 50 values long, now 0.02 0.08 0.50 0.58 0.62 0.700 0.76 0.78 0.92
-
- returns a subset of the FacetPattern with
-
truncate ( length )
- truncates the FacetPattern so it's now
length
values long. Iflength
is longer than the FacetPattern, return the whole FacetPattern. - example:
-
_.from([0,1,2,3]).truncate(2); // now 2 values long
-
_.from([0,1,2,3]).truncate(6); // still 4 values long
-
- truncates the FacetPattern so it's now
-
unique ( )
- returns the set of unique values in the FacetPattern.
- example:
-
_.from([1,2,3,0,0.4,2]).unique(); // 1 2 3 0 0.4
-
-
walk ( prob, amt )
- changes positions in the FacetPattern.
prob
(float 0-1) sets the likelihood of each position changing.amt
controls how many steps the values can move. Ifamt
is set to 10, andprob
is set to 0.5 half the values could move 10 positions to the left or the right. - example:
-
_.from([0,1,2,0,1,0.5,2,0]).walk(0.25, 3); // a sequence for jamming
-
- changes positions in the FacetPattern.
Pattern modulators with a second pattern as argument
-
add ( FacetPattern, match_sizes = false )
- adds the first FacetPattern and the second FacetPattern. If
match_sizes
is false, the output FacetPattern will be the longer pattern's length, and the "missing" values from the shorter pattern will be set to 0. Ifmatch_sizes
is true, both FacetPatterns will be made the same size before the calculations occur. - example:
-
_.sine(1,100).add(_.from([0.5, 0.25, 0.1, 1]));
-
- adds the first FacetPattern and the second FacetPattern. If
-
and ( FacetPattern, match_sizes = false )
- computes the logical AND of both FacetPattern, returning a 0 if one of the values is 0 and returning a 1 if both of the values are nonzero. If
match_sizes
is false, the output FacetPattern will be the longer pattern's length, and the "missing" values from the shorter pattern will be set to 0. Ifmatch_sizes
is true, both FacetPatterns will be made the same size before the calculations occur. - example:
-
_.from([1,0,1,0]).and(_.from([0,1])); // 0 0 1 0
-
- computes the logical AND of both FacetPattern, returning a 0 if one of the values is 0 and returning a 1 if both of the values are nonzero. If
-
append ( FacetPattern )
- appends the second FacetPattern onto the first.
- example:
-
_.sine(1,100).append(_.phasor(1,100)).append(_.from([1,2,3,4]));
-
-
divide ( FacetPattern, match_sizes = false )
- divides the first FacetPattern by the second. If
match_sizes
is false, the output FacetPattern will be the longer pattern's length, and the "missing" values from the shorter pattern will be set to 0. Ifmatch_sizes
is true, both FacetPatterns will be made the same size before the calculations occur. - example:
-
_.sine(1,100).divide(_.from([0.5,0.25,0.1,1]));
-
- divides the first FacetPattern by the second. If
-
equals ( FacetPattern, match_sizes = false )
- computes the logical EQUALS of both FacetPattern, returning a 0 if the values don't equal each other and returning a 1 if they do. If
match_sizes
is false, the output FacetPattern will be the longer pattern's length, and the "missing" values from the shorter pattern will be set to 0. Ifmatch_sizes
is true, both FacetPatterns will be made the same size before the calculations occur. - example:
-
_.sine(1,100).equals(_.sine(2,100)); // two sine waves phasing
-
- computes the logical EQUALS of both FacetPattern, returning a 0 if the values don't equal each other and returning a 1 if they do. If
-
interlace ( FacetPattern )
- interlaces two FacetPatterns. If one FacetPattern is smaller, it will be interspersed evenly throughout the other FacetPattern.
- example:
-
_.sine(1,100).interlace(_.phasor(1,20));
-
-
map ( FacetPattern )
- forces all values of the input FacetPattern to be mapped onto a new set of values from a second FacetPattern.**
- example:
-
_.from([1,2,3,4]).map([11,12,13,14]); // 11 11 11 11
-
_.from([1,2,3,4]).scale(30,34).map(_.from([31,31.5,32,32.5])); // 31 31.5 32.5 32.5
-
-
or ( FacetPattern, match_sizes = false )
- computes the logical OR of both FacetPattern, returning a 0 if both of the values are 0 and returning a 1 if either of the values are nonzero. If
match_sizes
is false, the output FacetPattern will be the longer pattern's length, and the "missing" values from the shorter pattern will be set to 0. Ifmatch_sizes
is true, both FacetPatterns will be made the same size before the calculations occur. - example:
-
_.from([1,0,1,0]).or(_.from([0,1])); // 1 0 1 1
-
- computes the logical OR of both FacetPattern, returning a 0 if both of the values are 0 and returning a 1 if either of the values are nonzero. If
-
sieve ( FacetPattern )
- uses the second FacetPattern as a lookup table, with each value's relative value determining which value from the input sequence to select.
- example:
-
_.noise(1024).sieve(_.sine(10,1024)); // sieving noise with a sine wave into the audio rate :D
-
-
subtract ( FacetPattern, match_sizes = false )
- subtracts the second FacetPattern from the first. If
match_sizes
is false, the output FacetPattern will be the longer pattern's length, and the "missing" values from the shorter pattern will be set to 0. Ifmatch_sizes
is true, both FacetPatterns will be made the same size before the calculations occur. - example:
-
_.sine(1,100).subtract(_.from([0.5,0.25,0.1,1]));
-
- subtracts the second FacetPattern from the first. If
-
times ( FacetPattern, match_sizes = false)
- multiplies the first FacetPattern by the second. If
match_sizes
is false, the output FacetPattern will be the longer pattern's length, and the "missing" values from the shorter pattern will be set to 0. Ifmatch_sizes
is true, both FacetPatterns will be made the same size before the calculations occur. - example:
-
_.sine(1,100).times(_.from([0.5,0.25,0.1,1]));
-
- multiplies the first FacetPattern by the second. If
Audio-rate operations
Facet can load audio samples (.wav files) as FacetPatterns and run arbitrary operations on them.
To prevent humongous computations, there are some guardrails, but even so, audio processing can increase your computer's CPU load quite a bit, and it is possible that you accidentally run a command that requires more computing power than your computer can handle in real(ish) time. Of course, if you're just running the command for sound design or testing purposes, you can just wait for it to complete and hear what it comes up with. But if the CPU% indicator goes way up, or the server seems to not be responding, just stop and restart the node server in your terminal, and try tailoring the audio commands so they are within the limitations of your machine.
-
allpass ( )
- runs the audio through an allpass filter.
- example:
-
_.randsamp().iter(12,1,()=>{this.allpass().delay(random(1,6000))}).scale(-1,1).play(); // reverb :)
-
-
audio ( )
- removes any DC offset via a high-pass biquadratic filter at ~0Hz.
- example:
-
_.randsamp().times(_.noise(4)).audio().play();
-
-
chaos ( FacetPattern, iterations = 100, cx = 0, cy = 0)
- each piece of data in the FacetPattern is paired with the corresponding value in the second FacetPattern. The resulting complex number x,y coordinate is run through a function: f(x) = x2 + c, over
iterations
iterations. The output is a value between 0 and 1, which corresponds to how stable or unstable that particular point is in the complex number plane. - By default, both cx and cy are set to 0 (Mandelbrot set). But you can set them to other values from -1 to 1, which can produce all sorts of Julia set variations.
- example:
_.sine(44,1000).chaos(_.drunk(44100,0.01)).play()
- each piece of data in the FacetPattern is paired with the corresponding value in the second FacetPattern. The resulting complex number x,y coordinate is run through a function: f(x) = x2 + c, over
-
convolve ( FacetPattern )
- computes the convolution between the two FacetPatterns.
- example:
-
_.randsamp().convolve(_.randsamp()).play(); // convolving random samples
-
-
delay ( samples, wet = 0.5 )
- delays the input FacetPattern by
samples
samples. You can crossfade between the original and delayed copies withwet
. - example:
-
_.randsamp().delay(random(1700,10000)).play();
-
- delays the input FacetPattern by
-
harmonics ( FacetPattern, amplitude=0.9 )
- superimposes
FacetPattern.length
copies of the input FacetPattern onto the output. Each number inFacetPattern
corresponds to the frequency of the harmonic, which is a copy of the input signal playing at a different speed. Each harmonic n in the output sequence is slightly lower in level, by 0.9^n. Allows for all sorts of crazy sample-accurate polyphony. - example:
-
_.randsamp().harmonics(_.noise(16).gain(3)).times(ramp(1,0,12000)).play(); // add 16 inharmonic frequencies, all between 0 and 3x the input speed
-
_.randsamp().harmonics(_.map([0,0.5,0.666,0.75,1,1.25,1.3333,1.5,1.6667,2,2.5,3],module.exports.noise(3)).play(); // add 3 harmonics at geometric ratios
-
- superimposes
-
ichunk ( FacetPattern )
- slices the input into
FacetPattern.length
windowed chunks (to avoid audible clicks). Loops through every value ofFacetPattern
as a lookup table, determining which ordered chunk of audio from the input sequence it corresponds to, and appends that window to the output buffer. - example:
-
_.randsamp().ichunk(_.ramp(0,0.5,256)).play(); // play 256 slices between point 0 and 0.5 of randsamp()... timestretching :)
-
_.noise(4096).sort().ichunk(_.noise(256).sort()).play(); // structuring noise with noise
-
- slices the input into
-
mix ( wet, command, match_sizes = false )
- Mixes the input FacetPattern with a second FacetPattern generated by
command
. Ifmatch_sizes
is false, the output FacetPattern will be the longer pattern's length, and the "missing" values from the shorter pattern will be set to 0. Ifmatch_sizes
is true, both FacetPatterns will be made the same size before the calculations occur. - example:
-
_.randsamp().ichunk(_.ramp(0,0.5,256)).play(); // play 256 slices between point 0 and 0.5 of randsamp()... timestretching :)
-
_.noise(4096).sort().ichunk(_.noise(256).sort()).play(); // structuring noise with noise
-
- Mixes the input FacetPattern with a second FacetPattern generated by
-
mutechunks ( chunks, prob )
- slices the input FacetPattern into
chunks
chunks and mutesprob
percent of them. - example:
-
_.randsamp().mutechunks(16,0.33).play(); // 33% of 16 audio slices muted
-
- slices the input FacetPattern into
-
randsamp ( dir =
../samples/
)- loads a random wav file from the
dir
directory into memory. The default directory is../samples/
, but you can supply any directory as an argument. - example:
-
_.randsamp().reverse().play(); // random backwards sample
-
- loads a random wav file from the
-
sample ( filename )
- loads a wav file from the
samples/
directory into memory. You can specify other subdirectories inside the Facet repo as well. - example:
-
_.sample('1234.wav').play(); // if 1234.wav is in the samples directory, you're good to go
-
_.sample('myfolder/myfile.wav'); // or point to the file with a relative path
-
- loads a wav file from the
-
suspend ( start_pos, end_pos )
- surrounds the FacetPattern with silence, so that the entire input FacetPattern still occurs, but only for a fraction of the overall resulting FacetPattern. The smallest possible fraction is 1/8 of the input FacetPattern, to safeguard against generating humongous and almost entirely empty wav files.
- example:
-
_.randsamp().suspend(0.25,0.75).play(); // the input pattern is now squished into the middle 50% of the buffer
-