This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| getting_started_vividshaper [2025/01/09 20:41] – [Using more oscillators] lars | getting_started_vividshaper [2026/09/09 21:00] (current) – [Filter functions] lars | ||
|---|---|---|---|
| Line 46: | Line 46: | ||
| ===== The user interface ===== | ===== The user interface ===== | ||
| - | In VividShaper, most of the things you do to control the synthesizer will be done through coding, so VividShaper does not have any knobs. However, it does have a few buttons. On the left side, there' | + | VividShaper |
| + | |||
| + | * The old editor was replaced by a new editor with syntax highlighting | ||
| + | * The old dropdown menu for selecting patches was replaced by a patch browser | ||
| + | |||
| + | Some of the images seen here may be prior to v2.0, but you can tell if it is the new version if the code editor has syntax highlighting | ||
| {{: | {{: | ||
| - | Here is an explanation of all the menu alternatives: | + | ===== The patch browser ===== |
| - | * Load factory patches: This is where you load one of factory patches that come with VividShaper. As you can see, these are divided into a number | + | In VividShaper, |
| - | * Load user patches: Here you will find all your patches and load them, either locally or from iCloud. It has the same category system as for factory patches and we will go through | + | |
| - | * Delete user patches: This is where you delete your own patches. | + | |
| - | * Save to iCloud: This saves your patch to iCloud. | + | |
| - | * Save to Local: This saves your patch to the local filesystem. | + | |
| - | * Update factory patches: This is a new feature in v1.2. You can now update the factory patches with new patches from the Internet. The plan is to release new patches regularly on Fridays (" | + | |
| - | * Debug: This is only available in the developer version, so you won't see it. | + | |
| - | Next to the Patches | + | {{: |
| + | |||
| + | The browser is divided into Factory patches, Local patches, and iCloud patches. Factory contains all the patches that comes with VividShaper. These are updated once in a while and you can check for new updates by pressing the " | ||
| + | |||
| + | {{: | ||
| + | |||
| + | When you select a patch, you will notice that the Patches button | ||
| + | |||
| + | Each patch can belong to one or more categories. This is done by tagging the each patch by adding | ||
| + | |||
| + | {{: | ||
| + | |||
| + | If you select Local or iCloud, you will be able to save your patches either locally on your device or in iCloud. Storing them in iCloud allows you to share patches between your devices and patches that are only in the cloud will have a cloud symbol next to them. You can of course organise your patches in categories too. Patches that you store in iCloud will have their own category system separate from locally stored patches and factory patches. If you don't add a tag, they will be found under the **Unlabelled** category. | ||
| + | |||
| + | The creation or deletion of categories is done automatically. As soon as you save a patch with a new hashtag, e.g. **Blip #8bit**, the organiser will create the category **#8bit** for you. Once you delete all patches with a given hashtag, the category will be removed. | ||
| + | |||
| + | ===== The code editor and waves view ===== | ||
| + | |||
| + | {{: | ||
| + | |||
| + | |||
| + | In the code editor view, you will also find three other buttons | ||
| **New:** The New button will remove anything you have written and start from the simple patch you see in the image. | **New:** The New button will remove anything you have written and start from the simple patch you see in the image. | ||
| Line 76: | Line 96: | ||
| **View**: 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). | **View**: 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). | ||
| - | **Help**: 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. If you press help again, it will switch back to your original code that you worked on. | ||
| - | |||
| - | ===== The patch organiser ===== | ||
| - | |||
| - | In the first version of VividShaper, | ||
| - | |||
| - | You don't have to create or delete the categories. This is done automatically. As soon as you save a patch with a new hashtag, e.g. **Blip #8bit**, the organiser will create the category **#8bit** for you. Once you delete all patches with a given hashtag, the category will be removed. | ||
| ===== Our first patch: Triangle ===== | ===== Our first patch: Triangle ===== | ||
| Line 299: | Line 312: | ||
| ===== Filter functions ===== | ===== Filter functions ===== | ||
| + | There are three different filters available in VividShaper: | ||
| - | The lowpass/ | + | These can either be applied on the actual waveform |
| <code Lua> | <code Lua> | ||
| - | wave[x] | + | filter1 |
| + | filter2 = VSBandpass(cutoffFreq, | ||
| + | filter3 = VSHighpass(cutoffFreq, | ||
| </ | </ | ||
| - | It can be quite difficult | + | If you want to apply the lowpass filter on the actual waveform, you will do this with the VSBiquad function: |
| <code Lua> | <code Lua> | ||
| - | biquadcoeff | + | wave[1] |
| - | biquadcoeff = VSBandpass(cutoffFreq, | + | |
| - | biquadcoeff = VSHighpass(cutoffFreq, | + | |
| </ | </ | ||
| - | 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). | + | Since this filter |
| - | A full example comes here: | + | The other method is to use the filter as an insert effect, processing the oscillator output continuously. In this case, the filter retains its state from one waveform cycle to the next. This is particularly important for resonance: instead of being baked into a single repeating waveform, the resonant response can build up and ring across successive cycles, producing a more dynamic filter response over time. |
| + | |||
| + | Say we want to apply the highpass-filter above as an insert on oscillator 1. Then we will write it like this: | ||
| + | |||
| + | <code Lua> | ||
| + | afilter[1] = filter3 | ||
| + | </ | ||
| + | |||
| + | You can even combine the two methods. Say you first filter the wave with a lowpass filter, then you apply the bandpass filter as an insert: | ||
| + | |||
| + | <code Lua> | ||
| + | filter1 = VSLowpass(cutoffFreq, | ||
| + | filter2 = VSBandpass(cutoffFreq, | ||
| + | wave[1] = VSBiquad(wave[1], | ||
| + | afilter[1] = filter2 | ||
| + | </ | ||
| + | |||
| + | You can even apply the same filter twice: | ||
| + | |||
| + | <code Lua> | ||
| + | filter1 = VSLowpass(cutoffFreq, | ||
| + | wave[1] = VSBiquad(wave[1], | ||
| + | afilter[1] = filter1 | ||
| + | </ | ||
| + | |||
| + | Both the waveform and the insert filters VividSynths are biquad filters. 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. The different filter functions return an array with 11 values. The first five values are used by the waveform filter (i.e. VSBiquad()) and the second five values are used by the insert filter. The final value is just a value to turn on or off the insert filter (0 or 1). You don't really need to understand how this works since the filter functions calculate the biquad parameters for us. | ||
| + | |||
| + | In previous versions, you also needed to provide the current note to the filter, like this: | ||
| + | |||
| + | <code Lua> | ||
| + | filter1 = VSLowpass(cutoffFreq, | ||
| + | </ | ||
| + | |||
| + | From v2.0, you don't have to do that any longer, as notein is default. However, you can still provide a note value to obtain the effect of a filter that follows the note in terms of the cutoff-frequency: | ||
| + | |||
| + | |||
| + | <code Lua> | ||
| + | filter1 = VSLowpass(cutoffFreq, | ||
| + | </ | ||
| + | |||
| + | A full example comes here for how to apply the waveform filter: | ||
| <code Lua> | <code Lua> | ||
| -- Patch: Filter example | -- Patch: Filter example | ||
| wave[1] = VSSaw(1,0) | wave[1] = VSSaw(1,0) | ||
| - | vol[1] = VSADSRE(1, | + | vol[1] = VSADSRE(1, |
| - | biquadcoeff = VSLowpass(300, | + | biquadcoeff = VSLowpass(300, |
| wave[1] = VSBiquad(wave[1], | wave[1] = VSBiquad(wave[1], | ||
| </ | </ | ||
| Line 358: | Line 412: | ||
| ===== Math functions ===== | ===== Math functions ===== | ||
| - | Besides | + | VividShaper allows you do apply all maths operators on the different waves: |
| + | |||
| + | **+ - * / %** | ||
| + | |||
| + | For instance, say you want to build an additive synth with sine waves, Then you can write: | ||
| + | |||
| + | < | ||
| + | wave[1] = 0.3*VSSin(1,0)+0.6*VSSin(2, | ||
| + | </ | ||
| + | |||
| + | You can also multiply two wave forms with each other, element-wise: | ||
| + | |||
| + | <code Lua> | ||
| + | wave[1] = VSSin(1, | ||
| + | </ | ||
| + | |||
| + | The modulus operator works with floats as well as integers: | ||
| + | |||
| + | <code Lua> | ||
| + | wave[1] = 2*(VSSin(1, | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | If you divide one waveform with another waveform, you may get a division with zero. Although not mathematically correct, such divisions will always return zero for convenience. | ||
| + | |||
| + | Previous versions before v2.0 did have functions | ||
| <code Lua> | <code Lua> | ||
| Line 369: | Line 449: | ||
| </ | </ | ||
| - | 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 | + | An additive synth with the older functions |
| <code Lua> | <code Lua> | ||
| Line 454: | Line 534: | ||
| </ | </ | ||
| - | ===== Delay effect | + | ===== Delay and reverb effects |
| - | Version 1.3 of VividShaper comes with a delay effect. There are two delays (delay1 | + | VividShaper comes with both reverb |
| - | There is not a separate delay for each generator. Instead, the generators share the same delays. This means the parameters for the actual delays (feedback, time, amplify) are set globally for all generators. However, | + | {{ : |
| - | you can control how much audio from each oscillator in each generator that should be routed to each delay. For instance, it is possible to let only one oscillator be sent to the delay. | + | |
| - | {{ : | + | There are two delays (delay1 and delay2), which can either be used separately or as a ping-pong delay. There are a number of ways to route the audio through these delays. |
| + | |||
| + | There is not a separate delay for each generator. Instead, the generators share the same delays. This means the parameters for the actual delays (feedback, time, amplify) are set globally for all generators. However,you can control how much audio from each oscillator in each generator that should be routed to each delay. For instance, it is possible to let only one oscillator be sent to the delay. | ||
| The above picture shows how the different parameters affect the delays. The arrays d1vol[x] and d2vol[x] tell for each oscillator how much of the output that should be sent to each delay. For instance, if you wish to send the output of oscillator 1 to delay1 and the output from oscillator 2 to delay 2, you would set it as: | The above picture shows how the different parameters affect the delays. The arrays d1vol[x] and d2vol[x] tell for each oscillator how much of the output that should be sent to each delay. For instance, if you wish to send the output of oscillator 1 to delay1 and the output from oscillator 2 to delay 2, you would set it as: | ||
| Line 472: | Line 553: | ||
| The output to the delay lines are also affected by vol[x], so if you have set vol[1] = 0, then you won't send any sound to the delay lines. It is thus the output after applying any volume envelopes that are sent to the delays. | The output to the delay lines are also affected by vol[x], so if you have set vol[1] = 0, then you won't send any sound to the delay lines. It is thus the output after applying any volume envelopes that are sent to the delays. | ||
| - | Separately, you can now also turn off the main output of an oscillator and just let it go through the delays. This is done by setting | + | Separately, you can also turn off the main output of an oscillator and just let it go through the delays. This is done by setting |
| + | |||
| + | **Note that in previous versions before v1.4, mvol[x] was called ovol[x] and mrvol was called mvol.** | ||
| d1vol, d2vol, and ovol are local variables for each generator. You can for instance let oscillator 1 be routed through the delay lines in generator 1, but not generator 2, depending e.g. on the note value (allowing you to only let higher notes be sent to the delays). | d1vol, d2vol, and ovol are local variables for each generator. You can for instance let oscillator 1 be routed through the delay lines in generator 1, but not generator 2, depending e.g. on the note value (allowing you to only let higher notes be sent to the delays). | ||
| - | There is a new global variable called mvol, which default value is always 1. It tells how much of the main output that should be sent to the output lines (before being amplify modulated by gvol). This allows you to decrease or increase the main volume without changing the delay effect volume. | ||
| Delay1 and delay2 are controlled using two global arrays delay1[x] and delay2[x], with the following parameters: | Delay1 and delay2 are controlled using two global arrays delay1[x] and delay2[x], with the following parameters: | ||
| Line 506: | Line 588: | ||
| Simply adding VSPingPoing(0.9, | Simply adding VSPingPoing(0.9, | ||
| + | After the delay lines and the main route are mixed together, they go through the main reverb called reverb1. If you want an oscillator to bypass this reverb, you can send it through the alternative route instead and turn off the main route. Say that you want to send oscillator 5 through the alternative route. Then you would do as follows: | ||
| + | |||
| + | < | ||
| + | mvol[5] = 0 -- Turn off oscillator 5 from the main route | ||
| + | avol[5] = 1 -- Turn on oscillator 5 on the alternative route | ||
| + | apanning[5] = 0.5 -- Set the panning of the alternative route for oscillator 5 | ||
| + | </ | ||
| + | |||
| + | The parameters for the reverb are: | ||
| + | |||
| + | < | ||
| + | reverb1[1] -- Dry or wet (0 to 1). Default is 0, which means no reverb | ||
| + | reverb1[2] -- Space (0 to 1). How large space you want. A value of 1 is quite big | ||
| + | reverb1[3] -- Damp (0 to 1). A value close to 0 gives almost no damping. | ||
| + | reverb1[4] -- Reverb level, how much how the reverb signal that should be mixed in (default = 1) | ||
| + | reverb1[5] -- mixMode, where 0=insert and 1=send. | ||
| + | reverb1[6] -- tailLatch, where 0=off and 1=on. | ||
| + | reverb1[7] -- keep (0 - 1). How much of the stereo signal that should be kept in the reverb. | ||
| + | reverb1[8] -- cross (0 - 1). How much of the stereo signal that should be leaked | ||
| + | reverb1[9] -- Stereo (0 - 1). If you want the final output from the reverb to be mono or stereo. | ||
| + | </ | ||
| + | |||
| + | Turn tail latch on if you want the reverb signal to always play even if you set wet=0. For instance, say you have a synth sound that you are playing with tailLatch=1. When you increase the wet variable, the sound of your synth will be sent through the reverb, but when you drop it back to 0 (totally dry) then the signal won't enter the reverb. However, whatever you already have in the reverb will continue to play if tailLatch is on. Keep and cross are different ways to retain the stereo signal. | ||
| + | |||
| + | You cannot control how much of each oscillator are the delays that should be sent into reverb1, but there is also another reverb (reverb2) where you can do exactly that. It is on its own reverb route and you control how much of each oscillator that should be passed through it by setting the rvol[x] value for each oscillator and then also rpanning[x] to tell the panning. The delays can also be sent up to reverb2. | ||
| + | |||
| + | To summarise, there are a number of alternative routes your sound can go through: | ||
| + | |||
| + | |||
| + | |||
| + | * Main route: On by default | ||
| + | * Alternative route: Off by default | ||
| + | * Reverb route: Off by default. All sounds here go through reverb2 | ||
| + | * Delay 1 route. Off by default | ||
| + | * Delay 2 route: Off by default | ||
| + | |||
| + | All routes except the alternative routes also go through reverb1. Both reverbs are off by default. | ||
| ===== MIDI output (experimental) ===== | ===== MIDI output (experimental) ===== | ||