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 [2024/06/08 15:55] larsgetting_started_vividshaper [2025/01/09 21:41] (current) – [Using more oscillators] lars
Line 52: Line 52:
 Here is an explanation of all the menu alternatives: Here is an explanation of all the menu alternatives:
  
- * Load factory patches: This is where you load one of factory patches that come with VividShaper. As you can see, these are in turn divided into a number of categories, for instance bass and drone. You will be able to organise your patches in categories too. More about that under **"Our first patch: Triangle"**. +  * 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 of categories, for instance bass and drone. You will be able to organise your patches in categories too. More about that under **The patch organiser**. 
- * 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 how that works in detail below. +  * 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 how that works in detail below. 
- * Delete user patches: This is where you delete your own patches. +  * Delete user patches: This is where you delete your own patches. 
- * Save to iCloud: This saves your patch to iCloud. +  * Save to iCloud: This saves your patch to iCloud. 
- * Save to Local: This saves your patch to the local filesystem. +  * 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 ("Patch Friday"), hopefully weekly or at least a few times per month. +  * 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 ("Patch Friday"), hopefully weekly or at least a few times per month. 
- * Debug: This is only available in the developer version, so you won't see it.+  * Debug: This is only available in the developer version, so you won't see it.
  
 Next to the Patches menu button, you will find a few other buttons: Next to the Patches menu button, you will find a few other buttons:
  
-**New:** +**New:** The New button will remove anything you have written and start from the simple patch you see in the image.
- +
-The New button will remove anything you have written and start from the simple patch you see in the image.+
  
 <code Lua> <code Lua>
Line 74: Line 72:
 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. 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.
  
-**Parse** +**Parse**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 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).  +
- +
-**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. +
  
 +**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, all patches were stored in alphabetic order in one huge list. The patch organiser, introduced in v1.2, allows you to tag each patch by adding #tags to your patch name. For instance, the patch **Super Moving Saw #pad #supersaw** that you find among the factory patches is located both under the **#pad** category and the **supersaw** category. You can organise your patches in the same way. The patches you store in iCloud will have their own category system separate from locally stored patches. If you don't add a tag, they will be found under the **Unlabelled** menu item.
  
 +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 99: Line 92:
 wave[1] = VSTriangle(1,0) wave[1] = VSTriangle(1,0)
 vol[1] = velocity*VSADSRE(1,1,0.8,3,0,gatetimeon,gatetimeoff) vol[1] = velocity*VSADSRE(1,1,0.8,3,0,gatetimeon,gatetimeoff)
 +active = vol[1] > 0.000001
 </code> </code>
  
-On the first row, you see a comment saying "-- Patch: Triangle #retro". You don't need to add this row, but it will always be added as the first row in the code when you save the patch anyway. The first row always tell the name of the patch (which is equal to the filename). In our example, the name of the patch is "Triangle #retro".+On the first row, you see a comment saying **-- Patch: Triangle #retro**. You don't need to add this row, but it will always be added as the first row in the code when you save the patch anyway. The first row always tell the name of the patch (which is equal to the filename). In our example, the name of the patch is **Triangle #retro**. By giving it the hashtag **#retro**, we will save it under a new category that we call retro.
  
-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.+In VividShaper, 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. In this example, we will only use one oscillator.
  
 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.  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: 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.    * A frequency of 1 Hz means that the wave will be filled with exactly one complete cycle of the triangle wave.
Line 137: Line 129:
 The variables gatetimeon and gatetimeoff tells how long time it has been since the key was pressed down (gatetimeon) and released (gatetimeoff). When the key is released, the gatetimeon time freezes at that time point. This means we can sum together gatetimeon+gatetimeoff to get the total time from when the key was pressed down. The variables gatetimeon and gatetimeoff tells how long time it has been since the key was pressed down (gatetimeon) and released (gatetimeoff). When the key is released, the gatetimeon time freezes at that time point. This means we can sum together gatetimeon+gatetimeoff to get the total time from when the key was pressed down.
  
-The volume output of VSADSRE is then stored to vol[1], which is the volume for the first oscillator. Since we have eight oscillators, we can store eight different volumes as well.+The output from VSADSRE is stored to vol[1], which is the volume for the first oscillator. Each of the eight oscillators has its own volume, ranging from vol[1] to vol[8]. 
 + 
 +The final row will tell if the generator should be active or not: 
 + 
 +<code Lua> 
 +active = vol[1] > 0.000001 
 +</code> 
 + 
 +The variable **active** is a boolean variable that is either true or false. Your generator gets activated when a note has been pressed. The variable **active** turns true at the very moment when the generator starts. The generator continues to run as long as **active == true**, but you can turn it off by setting **active = false**. It is a good idea to always turn off a generator when you know it won't play anything anymore. 
 + 
 +In this example, we continue to let the generator be active as long as the volume for the oscillator is above 0.000001. Once the volume goes below, then **active == false** and the generator will turn itself off (until you press a note again). 
 + 
 +From version 1.3, you can instead call **VSDeactivate()**. It will run exactly the same code: 
 + 
 +<code Lua> 
 +VSDeactivate() 
 +-- This runs exactly the same thing as
 +--   active = vol[1] > 0.000001 
 +</code>
  
-When you now play this simple patch, you will see the wave on the right side view:+When you play this simple patch, you will see the wave on the right side view:
  
 {{:VSTriangle.png?600|}} {{:VSTriangle.png?600|}}
Line 161: Line 171:
 panning[2] = 0.75 panning[2] = 0.75
 gvol = 0.5 gvol = 0.5
 +
 +active = VSMax(vol) > 0.00001
 +
 +pitchbend = pitchbend * 2
 </code> </code>
  
Line 167: Line 181:
 note[x] is an array corresponding to the notes being played for the eight oscillators (x is between 1-8). If we don't set note[x] explicitly, each oscillator will keep the default notein value. Hence, you don't have to set the note[] array if you don't want to change the note. note[x] is an array corresponding to the notes being played for the eight oscillators (x is between 1-8). If we don't set note[x] explicitly, each oscillator will keep the default notein value. Hence, you don't have to set the note[] array if you don't want to change the note.
  
-Given that notein=48, note[1] will be 47.99 and note[2] will be 48.01. Setting these two oscillators slightly detuned will create a beat effect, which you can read more about here:+The pitchbend variable is representing the current pitch bend data from your keyboard, and ranges by default between -2 to +2 (two semi-tones in each direction). This value is added to each note[x] value in the sound engine (after the Lua code has finished running). Say that note[1] == 48 and pitchbend == 0.3. The note that will be played by the oscillator will then be 48.3. In the code above, we manipulate the pitchbend variable so that it ranges from -4 to +4 instead. If you wish to turn it off (or use the pitchbend data to modulate something else), you can do so by setting pitchbend = 0 somewhere in the code. 
 + 
 +In the above code, we are adding and subtracting 0.01 for note[1] and note[2]. Given that notein == 48, note[1] will then be 47.99 and note[2] will be 48.01. Setting these two oscillators slightly detuned will create a beat effect, which you can read more about here:
  
 https://en.wikipedia.org/wiki/Beat_(acoustics) https://en.wikipedia.org/wiki/Beat_(acoustics)
Line 175: Line 191:
 We can also set the panning of each oscillator, telling them if the sound should be played on the left speaker, the right speaker, or anything in between. This is done by setting the panning[x] array, which again is an array of eight values, one value for each oscillator. A panning value of 0 means left, a panning value of 1 means right, and consequently a panning value of 0.5 means in the middle. We can also set the panning of each oscillator, telling them if the sound should be played on the left speaker, the right speaker, or anything in between. This is done by setting the panning[x] array, which again is an array of eight values, one value for each oscillator. A panning value of 0 means left, a panning value of 1 means right, and consequently a panning value of 0.5 means in the middle.
  
-Finally, we set the gvol variable to 0.5. This is the global volume that VividShaper sends to the DAW and the default value is 1. If we add more than one oscillator, it can be a good idea to lower the global volume. Otherwise, the total volume will be saturated.+Since we are using two oscillators, it is a good idea to change the global volume **gvol** variable to 0.5. This is the global volume that VividShaper sends to the DAW and the default value is 1. If we add more than one oscillator, it can be a good idea to lower the global volume. Otherwise, the total volume will be saturated. 
 + 
 +Finally, we turn off the generator if both oscillators drop below 0.00001 in volume. The **vol** variable is an array of 8 elements and VSMax(vol) returns the highest value of the array. This way, we don't turn off the generator until all oscillators are below the chosen threshold. 
 + 
 +You may want to play a bit with the threshold value. Setting it very low may seem to be a good idea, but if you use the exponential VSADSRE() envelope, the volume will mathematically speaking never reach zero and it may take a very long time for it to reach your threshold. Similarly, setting it too high (e.g. 0.1) will certainly give you an audible disruption in the sound. You want to turn it off when you really cannot hear it any longer. 
 + 
 +This image does not do justice of what is going on, because the waves are changing shape over time. Still, you can tell from the image that the superposition of the two waves makes it look somewhat different from a triangle wave: 
 + 
 +{{:twooscillators.png?600|}}
  
 ===== Waves view ===== ===== Waves view =====
  
-By default, the waves view always show the first wave (wave[1]). You can change this by setting the wavesview variable. For instance, by setting wavesview = 3, you will tell VividShaper to show wave[3] instead. You can also change the y-axis scale of the waves view, by setting the scaleview variable. The default value is set to 1, but if you set scaleview to e.g. scaleview=2, you will magnify the wave being plotted without changing the volume.+By default, the waves view always show the oscilloscope view. In the version prior to v1.2, it was always showing the first wave (wave[1]). You can change this by setting the wavesview variable. For instance, by setting **wavesview = 1**, you will tell VividShaper to show wave[1] instead of the oscilloscope view. If you set it to **wavesview = 3**, you will show wave[3]. 
 + 
 +If you set **wavesview = 0**, you will get back the oscilloscope view. 
 + 
 +You can also change the y-axis scale of the waves view, by setting the scaleview variable. The default value is set to 1, but if you set scaleview to e.g. scaleview=2, you will magnify the wave being plotted without changing the volume.
  
 Finally, there's a text variable that will display anything that you set it to at the bottom of the view. This is great for debugging. In this example, text=gatetimeoff, telling how many seconds it has been since the key was released. Finally, there's a text variable that will display anything that you set it to at the bottom of the view. This is great for debugging. In this example, text=gatetimeoff, telling how many seconds it has been since the key was released.
  
 +The screenshot is from v1.1 where wave[1] was the default view:
 {{:textgatetimeoff.png?600|}} {{:textgatetimeoff.png?600|}}
  
Line 200: Line 229:
 VSSin and VSSaw takes the same arguments as VSTriangle. VSSquare has one extra argument to set the width of the square wave (between 0 to 1). VSNoise generates a random wave given the seed variable, where seed is an integer, e.g. VSNoise(32). If you want the VSNoise to generate new waves every time you call it, you can write VSNoise(tick). The variable tick counts the number of times the Lua code has been called from when it was initiated. Since it is incrementing every time, you will make sure to generate a new random wave. VSSin and VSSaw takes the same arguments as VSTriangle. VSSquare has one extra argument to set the width of the square wave (between 0 to 1). VSNoise generates a random wave given the seed variable, where seed is an integer, e.g. VSNoise(32). If you want the VSNoise to generate new waves every time you call it, you can write VSNoise(tick). The variable tick counts the number of times the Lua code has been called from when it was initiated. Since it is incrementing every time, you will make sure to generate a new random wave.
  
 +===== Low Frequency Oscillators (LFOs) =====
 +
 +Version 1.2 introduced LFO functions:
 +
 +<code Lua>
 +lfo = VSLFOSin(frequency,phase,time)          -- phase is in degrees
 +lfo = VSLFOTriangle(frequency,phase,time) 
 +lfo = VSLFOSaw(frequency,phase,time)
 +lfo = VSLFOSquare(frequency,phase,width,time) -- width is between 0 to 1
 +</code>
 +
 +All these LFO functions will oscillate between -1 to 1, so if you want the range 0 to 1 you need to add the LFO by 1 and divide it by 2.
 +
 +In contrast to the wave functions, the LFO functions outputs a single value (scalar value). The first function, VSLFOSin, is really just the same as writing **math.sin(2*math.pi*frequency*time+2*math.pi*phase/360)** in Lua, but VSLFOSin is more compact and aligned with the rest of the LFO functions.
 +
 +If you want a pulsating sound that modulates the volume, you could do something like this
 +
 +<code Lua>
 +-- Patch: New
 +wave[1] = VSTriangle(1,0)
 +v = VSADSRE(0.3,0.2,0.8,1,0,gatetimeon,gatetimeoff)
 +lfo = VSLFOSquare(tempo/60,0,0.5,gatetimeon+gatetimeoff)
 +
 +vol[1] = v*(lfo+1)/2
 +
 +active = v > 0.000001
 +</code>
 +
 +Notice that in this patch, we need to calculate the envelope volume separately first, then we calculate the lfo and multiply it with the volume (after fixing the range between 0 and 1). Finally, we test if the generator should be active based on the envelope volume *v*, not the final volume **vol[1]**.
  
 ===== Variational Autoencoder ===== ===== Variational Autoencoder =====
Line 224: Line 282:
 </code> </code>
  
 +The screenshot is from v1.1 where wave[1] was the default view:
 {{:autoencoder.png?600|}} {{:autoencoder.png?600|}}
  
Line 319: Line 378:
 wave[1] = VSAdd(wave1,wave2) wave[1] = VSAdd(wave1,wave2)
 </code> </code>
 +
 +===== Ring and sync modulation =====
 +
 +Introduced in v1.2, you can now let one oscillator either ring or sync modulate another oscillator:
 +
 +<code Lua>
 +ring[x]=y      -- Oscillator x should be ring moduled by oscillator y
 +sync[x]=y      -- Oscillator x should be synced by oscillator y
 +</code>
 +
 +Ring modulation means one oscillator is multiplied by another oscillator (the modulator) and the output from this oscillator is the multiplication of the two. Sync modulation means that one oscillator is restarting from zero whenever another oscillator (the modulator) restarts from zero.
 +
 +An important rule here is that **y<x** for both. This means that oscillator 1 can ring or sync module oscillator 2, but not the other way around. The reason for this is because the generator calculates oscillator 1 first, then oscillator 2. Here is an example from the factory patches:
 +
 +<code Lua>
 +-- Patch: Ringing #drone #new
 +wave[1] = VSSaw(1,0)
 +wave[2] = VSTriangle(1,0)
 +vol[2] = VSADSRE(1.0,0.5,0.8,2,0,gatetimeon,gatetimeoff)
 +vol[1] = VSADSRE(0.2,0.5,0.3,1,0,gatetimeon,gatetimeoff)
 +
 +ring[2] = 1
 +note[2] = notein-24
 +note[1] = note[2]-1
 +gvol = 0.7
 +panning[1] = 0.3
 +panning[2] = 0.7
 +oscnote = note[1]
 +
 +active = VSMax(vol) > 0.00001
 +</code>
 +
 +In this example, oscillator 2 is ring modulated by oscillator 1. Sometimes, you want to mute the modulating oscillator, but in this example we keep both oscillators playing: notice also that we change the frequency of the note for one of the oscillators. This is quite important, because otherwise it won't give you much of a time dependent modulation (then you could just multiply the two waves using VSMul()).
  
 ===== Optimisation ===== ===== Optimisation =====
Line 338: Line 430:
 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.  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 =====+===== MIDI CC input, AUv3 input parameters, 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.+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 playedBy multiplying the volume output with velocity, you can make your patch velocity sensitive.+Version 1.2 introduces eight AUv3 parametersthat you read from the **par[x]** array where x is from 1 to 8. In your DAW, these parameters will be called P1 to P8 and have the range from 0 to 1 (just like **ncc[x]**).
  
-The variable tempo tells you the current tempo from the DAW, e.g. 120. A corresponding variable is beatpos for beat position.+The variable velocity tells the current velocity of the note being played (from 0 to 1). 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: 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:
Line 360: Line 454:
 </code> </code>
  
 +===== Delay effect =====
 +
 +Version 1.3 of VividShaper comes with a delay effect. 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.
 +
 +{{ :delayeffect.png?800 |}}
 +
 +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:
 +
 +<code>
 +d1vol[1] = 1
 +d2vol[2] = 1
 +</code>
 +
 +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 ovol[x] = 0, for oscillator x.
 +
 +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:
 +
 +<code>
 +delay1[1] -- Feedback from itself
 +delay1[2] -- Feedback from delay2
 +delay1[3] -- How much of the input that should be sent through the delay (0 = dry, 1 = wet)
 +delay1[4] -- How much the volume should be amplified (1 = normal)
 +delay1[5] -- Panning (0 = left, 1 = right)
 +delay1[6] -- Time in seconds, e.g. 0.5
 +
 +delay2[1] -- Feedback from itself
 +delay2[2] -- Feedback from delay1
 +delay2[3] -- How much of the input that should be sent through the delay (0 = dry, 1 = wet)
 +delay2[4] -- How much the volume should be amplified (1 = normal)
 +delay2[5] -- Panning (0 = left, 1 = right)
 +delay2[6] -- Time in seconds, e.g. 0.5
 +</code>
 +
 +There are three functions that you can use to set these parameters more easily:
 +
 +<code>
 +VSPingPong(feedback,time)    -- Gives you a ping pong delay
 +VSStereoDelay(feedback,time) -- Gives you a stereo delay, using panning[] info for each oscillator
 +VSMonoDelay(feedback,time)   -- Gives you a mono delay
 +</code>
 +
 +Simply adding VSPingPoing(0.9,0.2) as the last line in your code will give you a nice ping pong effect. You can then change parts of the delay parameters if you like after calling this function.
 +
 +===== MIDI output (experimental) =====
 +
 +MIDI output is a new experimental feature in v1.2. If you add an instance of VividShaper as MIDI effect plugin, only one generator will run (for now at least - this may change) and you will not be able to play any sound but you can instead send MIDI.
 +
 +<code Lua>
 +VSMIDI(command,data1,data2) -- Send MIDI data. (Next version)
 +VSMIDINote(channel,note,velocity,length) -- Play a given note on the given channel. length=1/4 means a quarter note, (Next version)
 +VSTick(prevbeatpos,beatpos,length) -- Returns true for every new time interval with the given length. (Next version)
 +</code>
 +
 +The first function **VSMIDI()** is allowing you to send any kind of MIDI data, notes or CC messages. If you use it to play notes, you need to take of also turning them off. How MIDI messages are constructed is not covered here, but there are plenty of MIDI documentation that describe this.
 +
 +If you prefer to let VividShaper handle this, you can use **VSMIDINote()** instead. Here, you will only need to tell that you want to play a certain note on a specific channel with a given velocity and length.
 +
 +For instance, **VSMIDINote(0,36,127,1/4)** will play C-3 (note=36 corresponds to C-3) at maximum velocity (127) as a quarter note. Note that 1/4 is the gate time. Sometimes, you may want the gate time to be somewhat shorter, in which case you could write: **VSMIDINote(0,36,127,1/4-1/4*0.1)**. This would give you 90% gate time of a quarter note (we subtracted 10%).
 +
 +The final function is a pretty useful function not only for MIDI but for other things as well. It will return a true/false value for every time interval. You can think of it as a metronome returning "ticks". For instance:
 +
 +<code Lua>
 +tick = VSTick(prevbeatpos,beatpos,1/4)
 +</code>
 +
 +would give **tick==true** four times per bar (one time per quarter note).
 +
 +These functions together makes it possible to make simple sequencers, where one VividShaper instance can control any AUv3 plugin or even real hardware.
 +
 +Here is a longer example that you can try in Logic. Load a drum kit as instrument and VividShaper as MIDI effect.
 +
 +<code Lua>
 +-- Patch: MIDItest #midi
 +tick = VSTick(prevbeatpos,beatpos,1/16)
 +step = math.floor(beatpos*4)
 +
 +bd = {1,0,0,0,0,0,1,0}
 +sn = {0,0,0,0,1,0,0,0}
 +hh = {1}
 +
 +bdindex = step % #bd
 +snindex = step % #sn
 +hhindex = step % #hh
 +
 +if tick == true then
 +  if bd[bdindex+1] == 1 then
 +    VSMIDINote(0,36,127,1/16)
 +  end
 +  if sn[bdindex+1] == 1 then
 +    VSMIDINote(0,36+4,127,1/16)
 +  end
 +  if hh[hhindex+1] == 1 then
 +    VSMIDINote(0,36+6,127,1/16)
 +  end
 +end
 +</code>
  
 +Here is a short explanation:
  
 +   * **tick** gives us a metronome with 1/16 notes
 +   * We have three arrays telling when different percussions should be played. These arrays are our step sequencer data:
 +     * **bd** is the bass drum.
 +     * **sn** is the snare drum.
 +     * **hh** is the hihat.
 +   * The index variables **bdindex**, ***snindex**, **hhindex**, each tell the position of each step sequencer. Yes, they are in fact independent, allowing for polymeter sequences if you decide to shorten one of them.
 +   * If **tick == true**, we have jumped to another step in the step sequencer and we need to check if we should play something.
  
  
getting_started_vividshaper.1717854931.txt.gz · Last modified: 2024/06/08 15:55 by lars