User Tools

Site Tools


getting_started_vividshaper

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
getting_started_vividshaper [2023/07/06 20:05] larsgetting_started_vividshaper [2023/11/12 19:46] (current) lars
Line 18: Line 18:
 Later, in 2002, Dave Smith released his first instrument after selling Sequential to Yamaha. It was called the Evolver and it was a real wavetable synthesizer. It had the same waves as the Prophet VS, plus 32 user waves that could be uploaded via MIDI. That allowed users to create their own waves and play them back. Later, in 2002, Dave Smith released his first instrument after selling Sequential to Yamaha. It was called the Evolver and it was a real wavetable synthesizer. It had the same waves as the Prophet VS, plus 32 user waves that could be uploaded via MIDI. That allowed users to create their own waves and play them back.
  
-It should be noted that there is some misconception around the term "wavetable". Sometimes, it is referred to a set of waves that you can loop through, and sometimes it is just referred to a single wave. Sometimes, this is then referred to as a "single-cycle" wavetable. Today, a wavetable synthesizer is just the overall technique of using very short samples that either changes dynamically or +It should be noted that there is some misconception around the term "wavetable". Sometimes, it is referred to a set of waves that you can loop through, and sometimes it is just referred to a single wave. Sometimes, this is then referred to as a "single-cycle" wavetable. Today, a wavetable synthesizer is just the overall technique of using very short samples that either changes dynamically or are played statically where other effects are added like a subtractive synthesizer. 
  
 ===== VividShaper introduction ===== ===== VividShaper introduction =====
Line 24: Line 25:
 Today, there are many software synthesizers that have adapted the concept of wavetable synthesis, including Native Instrument's Massive, Reason Studios Europa, and Serum from xfer records. However, they are all built around the idea of predefined wavetables that you can manipulate using various effects. Today, there are many software synthesizers that have adapted the concept of wavetable synthesis, including Native Instrument's Massive, Reason Studios Europa, and Serum from xfer records. However, they are all built around the idea of predefined wavetables that you can manipulate using various effects.
  
-VividShaper is quite different. It is a wavetable AUv3 plugin synthesizer for macOS and iOS that borrows the idea from the early wavetable synthesizers to have only 128 samples per wave, but instead of having a fixed number of waves to choose from, VividShaper lets you program and modify your waves over time using the built in Lua programming language.+VividShaper is quite different. It is a wavetable AUv3 plugin synthesizer for macOS and iOS that borrows the idea from the early wavetable synthesizers that had only 128 samples per wave and with a number of waves to cycle through. However, instead of having only a fixed number of waves to choose from, VividShaper lets you program and modify your waves over time using the built in Lua programming language.
  
 When you start the plugin for the first time, you will see a window with the Lua coding editor on the left side and a waves view on the right side. When you start the plugin for the first time, you will see a window with the Lua coding editor on the left side and a waves view on the right side.
Line 30: Line 31:
 {{:VividShaperstart.png?600|}} {{:VividShaperstart.png?600|}}
  
-There are only a few buttons that you can select. On the left side, there's a patch menu button that will allow you to load and save patches (either locally or to iCloud). The New button will remove anything you have written and start from the simple patch you see in the image. The Parse button is pressed when you have coded something and you want to use the new code. You can also reset the synth using the parse button. The View button will change the view of the editor and the graph (only editor, only graph view, editor left to graph, editor below graph). Finally, there is also a Help button. This button loads some text into the editor, telling which version you have and gives you a simple example.+There are only a few buttons that you can select. On the left side, there's a patch menu button that will allow you to load and save patches (either locally or to iCloud). The New button will remove anything you have written and start from the simple patch you see in the image. 
 + 
 +<code Lua> 
 +-- Patch: New 
 +wave[1] = VSSin(1,0) 
 +vol[1] = gate 
 +</code> 
 + 
 +This patch creates a sinewave and sets the volume to 1 if gate is on. The variable gate is either 1 if the key is pressed or 0 if the key is released, so in this very simple example the volume is either on or off. 
 + 
 +The Parse button is pressed when you have coded something new and want to use the new code. You can also reset the synth using the parse button (even if it is the same code). The View button will change the view of the editor and the graph (only editor, only graph view, editor left to graph, editor below graph). Finally, there is also a Help button. This button loads some text into the editor, telling which version you have and gives you a simple example.
  
  
-simple Lua program may look like this:+Another simple Lua program may look like this:
  
 <code Lua> <code Lua>
 -- Patch: A simple example -- Patch: A simple example
 wave[1] = VSTriangle(1,0) wave[1] = VSTriangle(1,0)
-vol[1] = VSADSRE(1,1,0.8,3,0,gatetimeon,gatetimeoff)+vol[1] = velocity*VSADSRE(1,1,0.8,3,0,gatetimeon,gatetimeoff)
 </code> </code>
  
Line 45: Line 56:
 Each generator has eight oscillators, where each oscillator plays one wave. A wave consists of 128 samples and the wave[] array consists of eight such wave arrays, one for each oscillator. In other words, wave[1] corresponds to the wave of the first oscillator, wave[2] corresponds to the wave of the second oscillator, and so on. Each generator has eight oscillators, where each oscillator plays one wave. A wave consists of 128 samples and the wave[] array consists of eight such wave arrays, one for each oscillator. In other words, wave[1] corresponds to the wave of the first oscillator, wave[2] corresponds to the wave of the second oscillator, and so on.
  
-On the second row, we will call the built in function VSTriangle(frequency,phase). This function will create a new wave of 128 samples (array) and store it to the first oscillator. The frequency is set to 1 Hz, meaning it will fill the 128 samples with one cycle of the triangle wave. If we change this to e.g. 2 Hz, we will fill the wave with 2 repeating triangle waves. The phase is given in degrees (0-360) and is here set to zero.+On the second row, we will call the built in function VSTriangle(frequency,phase). This function will create a new wave of 128 samples (array) and store it to the first oscillator. The frequency is set to 1 Hz, meaning it will fill the 128 samples with one cycle of the triangle wave. If we change this to e.g. 2 Hz, we will fill the wave with 2 repeating triangle waves.  
 + 
 +The term 'frequency' in this context refers to the number of cycles of the wave that fit into the 128-sample, not the pitch of the note that will be played. For example: 
 + 
 + 
 + 
 +   * A frequency of 1 Hz means that the wave will be filled with exactly one complete cycle of the triangle wave. 
 +   * Increasing the frequency to 2 Hz results in two complete cycles within the sample 128-sample space. 
 +   * Higher frequencies will pack more cycles of the wave into the sample. 
 +   * A frequency of 1.5 does not mean it will create 1.5 higher frequency at playback, but rather that the waveform will not complete two cycles, ending at a point which may give interesting timbre. 
 + 
 +The phase is given in degrees (0-360) and is here set to zero. The 'phase' of 0 means the wave starts at its beginning, while adjusting the phase shifts the start point of the waveform cycle, which can create subtle changes int he sound when combined with other waves. 
 + 
 +It is important to grasp these concepts. VSSin, VSSaw, VSTriangle all works the same, with one argument for frequency and one for phase. VSSquare has an additional argument for the width. Here is some additional examples: 
 + 
 +   * wave[1] = VSTriangle(2,0) -- This creates a wave form with two triangle waves within the 128 sample space 
 +   * wave[1] = VSSaw(1,45) -- This create a saw wave form with one saw wave, phase shifted 45 degrees
  
-On the third row, we set the output volume using the Attack, Decay, Sustain, Release (ADSR) envelope (VSADSRE). The E stands for Exponential release. If you don't want exponential release but a linear release, you can use VSADSR instead. They take the same arguments. The arguments are as follows:+On the third row, we set the output volume using the Attack, Decay, Sustain, Release (ADSR) envelope (VSADSRE). This is then multiplied by the velocity of the note. The E stands for Exponential release. If you don't want exponential release but a linear release, you can use VSADSR instead. They take the same arguments. The arguments are as follows:
  
 <code Lua> <code Lua>
Line 113: Line 140:
 We have so far used the VSTriangle waveform, but VividShaper also comes with a few other waveforms: We have so far used the VSTriangle waveform, but VividShaper also comes with a few other waveforms:
  
-<code>+<code Lua>
 -- Wave generators -- Wave generators
 wave[x] = VSSin(frequency,phase)           -- Sine-wave. frequency=1 is base, phase is in degrees. wave[x] = VSSin(frequency,phase)           -- Sine-wave. frequency=1 is base, phase is in degrees.
Line 135: Line 162:
 There are two functions that you can use. First, you can use the VSAutoencoder2() function to obtain the latent space variables. The output of these two variables are between -1 to 1, so you can see the output as a 2D map. There are two functions that you can use. First, you can use the VSAutoencoder2() function to obtain the latent space variables. The output of these two variables are between -1 to 1, so you can see the output as a 2D map.
  
-<code>+<code Lua>
 saw = VSSaw(1,0) saw = VSSaw(1,0)
 latent = VSAutoencoder2(saw) latent = VSAutoencoder2(saw)
Line 142: Line 169:
 Then you can feed in the latent variables to VSAutodecoder2() and generate a new wave given the coordinates in this 2D map. Then you can feed in the latent variables to VSAutodecoder2() and generate a new wave given the coordinates in this 2D map.
  
-<code>+In this example, we can see how the decoded sawtooth wave looks like and we also obtain the latent space coordinates by printing them. The volume has been set to vol=1 just to allow it to play constantly even when the note has been released. You may want to replace this vol with an ADSR-envelope instead, but it made it easier to make a screenshot to keep the volume on. 
 + 
 +<code Lua>
 wave[1] = VSAutodecoder2(latent) wave[1] = VSAutodecoder2(latent)
 </code> </code>
  
 {{:autoencoder.png?600|}} {{:autoencoder.png?600|}}
 +
 +Using gatetimeon and gatetimeoff variables makes it possible to dynamically change the position of the latent space over time. For instance, you can let it spin around (like a record):
 +
 +<code Lua>
 +-- Circular movement in latent space
 +local t = gatetimeon + gatetimeoff
 +local radius = 1 -- Radius of circular motion
 +local x = radius * math.cos(t/5) -- Divide time by a factor for slower movement
 +local y = radius * math.sin(t/5)
 +wave[1] = VSAutodecoder2({x,y}) -- Generate waveform from latent space
 +</code>
 +
 +The functions are called VSAutoencoder2 and VSAutodecoder2 since the latent space is two variables. There may be other auto encoder networks with a latent space having more dimensions in a future update.
 +
 +===== Filter functions =====
 +
 +The lowpass/bandpass/highpass filters work a little bit different from other apps. Instead of filtering the output from the oscillators, you can filter the wave itself. The wave filter function in VividSynths is a biquad filter. A biquad filter consists of five different coefficients and depending on how you set them you can create either a lowpass, bandpass, or a highpass filter.
 +
 +<code Lua>
 +wave[x] = VSBiquad(wave[x],biquadcoeff) 
 +</code>
 +
 +It can be quite difficult to calculate how these coefficients should be set, so VividShaper comes with three functions for this purpose:
 +
 +<code Lua>
 +biquadcoeff = VSLowpass(cutoffFreq,resonance,notein)
 +biquadcoeff = VSBandpass(cutoffFreq,resonance,notein)
 +biquadcoeff = VSHighpass(cutoffFreq,resonance,notein)
 +</code>
 +
 +A very important thing is that you need to provide each of these helper functions with the current note. If you play a note at a low frequency, you may actually play under the cutoffFreq so that no filter should be applied at all for a lowpass filter. That means the filter effect on the wave depends not only on the cutoff frequency and the resonance, but also on the playback frequency (i.e. the note).
 +
 +A full example comes here:
 +
 +<code Lua>
 +-- Patch: Filter example
 +wave[1] = VSSaw(1,0)
 +vol[1] = VSADSRE(1,1,0.8,3,0,gatetimeon,gatetimeoff)
 +biquadcoeff = VSLowpass(300,1,notein)
 +wave[1] = VSBiquad(wave[1],biquadcoeff)
 +</code>
 +
 +Setting the frequency as a function of time since gate on may give you some interesting sweeping filter effects.
 +
 +===== Waveform manipulators =====
 +
 +VividShaper comes with two different sorts of waveform manipulators. The first one is a wavefold effect. If the amplitude is e.g. 1.2, it is going over the limit with 0.2. The wavefold effect will then fold the waveform down again with the amount it was exceeding the limit: 1.0-0.2 = 0.8. This can result in some interesting harmonics.
 +
 +This is how the wavefold function is called:
 +
 +<code Lua>
 +wave[1] = VSWavefold(wave[1],1.5)
 +</code>
 +
 +The 1.5 coefficient means the wave should be multiplied with 1.5 first, then folded.
 +
 +Another important function is a wave normalisation function. If the wave reaches above a given threshold (that we define), we can normalise the wave to a new value:
 +
 +<code Lua>
 +threshold = 1.0
 +normvalue = 1.0
 +wave[1] = VSNorm(wave[1],threshold,normvalue)
 +</code>
 +
 +If the max amplitude of the wave is 1.5, this will divide the wave with 1.5 so that the new max amplitude is 1.0. However, if the max amplitude is below 1.0, it won't do anything. If we always want the wave to normalise to 1.0, even if the amplitude is lower, we can set the threshold to 0:
 +
 +<code Lua>
 +threshold = 0.0
 +normvalue = 1.0
 +wave[1] = VSNorm(wave[1],threshold,normvalue)
 +</code>
 +
 +===== Math functions =====
 +
 +Besides all the built in math functions that come with Lua, VividShaper also comes with some wave manipulating wave functions that you may find useful. These are:
 +
 +<code Lua>
 +-- Wave math operators - arguments can be either arrays or scalar factors
 +wave[x] = VSMul(wave1,wave2) -- Multiply element wise wave1 with wave2
 +wave[x] = VSMul(wave1,1.5)   -- Multiply element wise wave1 with 1.5
 +wave[x] = VSDiv(1,5,wave2)   -- Divide element wise 1.5 with wave2
 +wave[x] = VSAdd(wave1,wave2) -- Add element wise wave1 with wave2
 +wave[x] = VSSub(wave1,wave2) -- Subtract element wise wave1 with wave2
 +</code>
 +
 +With these functions, you can either e.g. multiply a wave with a scalar value or a wave with another wave. These are very useful functions if you want to create an additive synth:
 +
 +<code Lua>
 +wave1 = VSSin(1,0)
 +wave1 = VSMul(wave1,0.7)
 +wave2 = VSSin(2,0)
 +wave2 = VSMul(wave2,0.3)
 +wave[1] = VSAdd(wave1,wave2)
 +</code>
 +
 +===== Optimisation =====
 +
 +Running all the eight generators may be CPU intensive but there are ways to optimise it. You can either choose to decrease the number of generators in use, by setting the variable generators to a value between 1 and 8.
 +
 +<code Lua>
 +generators = 1 -- This sets VividShaper to become a mono synth
 +</code>
 +
 +You can also tell VividSynths how often it should run the Lua code. The default value is that the synth engine runs the Lua code after 512 samples have been played back. If the playback frequency is 48000 Hz, the Lua code will be executed 48000/512=93.75 times per second. That is a lot and sometimes not necessary. You can decrease this to e.g. running the Lua code after 1024 samples instead, changing the number of times it is executed to 46.875 times per second. This is done by setting the updatefreq variable:
 +
 +<code Lua>
 +updatefreq = 1024
 +</code>
 +
 +You can also increase the speed. This variable can be set to the following values: 128, 256, 512, 1024, 2048, and 4096.
 +
 +However, setting it to 128 means the Lua code is called 48000/128=375 times per second. That will put some demands on your CPU so test this carefully. 
 +
 +===== MIDI CC and other messages =====
 +
 +Sometimes, it is very useful to obtain CC-messages so that you can manipulate the sound in realtime using an external MIDI controller. The array cc[x] gives you at each update the current values of all CC messages except CC message 0 which is not used. Hence, cc[1] gives you the message for CC 1, cc[20] gives you the message for CC 20, etc. The values you get are between 0 and 127. If you prefer to get them normalised between 0 and 1, you can use the array ncc[x] instead.
 +
 +The variable velocity tells the current velocity of the note being played. By multiplying the volume output with velocity, you can make your patch velocity sensitive.
 +
 +The variable tempo tells you the current tempo from the DAW, e.g. 120. A corresponding variable is beatpos for beat position.
 +
 +Finally, the array prevvol[x] tells you the volumes of each oscillator when the gate flipped from off to on again. This can be useful information if you are making a monophonic synthesizer (generators=1) and want to start the ADSR envelopes initial volumes to the volume when the gate was turned on:
 +
 +<code Lua>
 +generators = 1
 +wave[1] = VSTriangle(1,0)
 +
 +attack = 1
 +decay = 1
 +sustain = 0.8
 +release = 3
 +initlevel = prevvol[1]
 +vol[1] = VSADSR(attack, decay, sustain, release, initlevel, gatetimeon, gatetimeoff)
 +</code>
 +
  
  
  
  
getting_started_vividshaper.1688666754.txt.gz · Last modified: 2023/07/06 20:05 by lars