Posts
-
RE: Instrument Design problem.......posted in General Questions
@dannytaurus
That much is true.
Technically.
Not legally, by the way.
At least not where I am, in the UK.You can decompile software partially and only in the case that you're making a piece of software that needs to be compatible with the thing you are decompiling. Not so that you can learn it's inner workings for any other reason.
My loophole was to go and talk to a large number of developers about their works.
It cost a lot of money and time to do the interviews, but that's one way to gain a lot of knowledge on a subject, learning personally from the best in each discipline. No decompiling needed.(sorry Lindon! I've messed up your thread a little)
-
RE: Instrument Design problem.......posted in General Questions
@dannytaurus
You're probably right, that it's more than good enough for a wide variety of tasks!The knowledge gaps become an issue in fields where information is less free. And noticeable in fields where small imperfections = failure.
However, I've also had to trundle through quite a lot of entirely vibecoded codebases lately from various clients and there have been some horrible dumpster fires
lol.
So my perspective is probably a bit tainted by these experiences!
-
RE: Instrument Design problem.......posted in General Questions
@dannytaurus
That's interesting!
Maybe we are working on different kinds of projects?I've been using GPT Astra Max, for DSP science. And I've found it to not be "clever enough" with it's coding. Part of the problem is likely that a lot of DSP solutions are proprietary and so there is a gap in it's knowledge, but even when I supply the solutions, the code (or advice) produced, is short sighted, and blocks off many quite important optimizations down the line if I were to take it's advice seriously.
And without a very good measurement harness (super-resolution frequency response, phase, sidebands, etc), it wasn't able to QA audio properly either to realize that its solution was nonsense.
It's the kind of thing where I think many people would take it's word for it as well.
-
RE: Instrument Design problem.......posted in General Questions
@dannytaurus
For this reason I only ever use AI to advise with code, if it's something with an instantly falsifiable result (eg. that math was supposed to result in a flat frequency response, but we measured ripples, therefore it failed). Making it reason about abstract problems and solutions still performs very badly in the absence of good measurement tools to determine sucess.Actually, even if an Agent is in a good feedback loop where it can run the code in question, and check the result of its idea, I've found that it still ends up cheating the problem and writing the code in a way that will come back to bite you later, even if the immediate answer is correct.
Perhaps it will continue to improve, the advancements in this field have been speedy indeedy.
-
RE: HELP! I modeled a Roland D-50 in HISE/Faust, but...posted in General Questions
@Morphoice
Ah, no but that is a reason to reset everything!
Under many conditions, changing parameter values all at once can produce monstruous audio. Like, if the DSP effect has feedback, if you don't clear all the buffers, the audio from before the switch, could blow up under the new parameters. There are scenarios that can sound really horrible or blow out your speakers. I mean, let's say the new preset has different reverb parameters, you'll get all the reverb knobs yanked while it's still playing, and get all that washy doppler... Of course that's not a horrible situation, but you can imagine that certain DSP would produce really loud nightmares. Which is why it's quite sane for Hise to send reset() on a preset change, to clear out all the buffers and start from silence. It's the safest thing to do.But I agree that creatively, there are situations where this is not what you want. But you can understand why Hise went with the blanket solution.
-
RE: HELP! I modeled a Roland D-50 in HISE/Faust, but...posted in General Questions
Hise calls reset() during those changes, so i'm afraid it's Hise actually telling the dsp to clear the buffers! Reverb can't be continuous unless you do some really hacky stuff, like leaving the reset() function empty and using prepare() to cut off tails instead (lots of Daws call prepare() before audio rendering and so that can be used as the reset function) but it just dawned on me that Hise might also might be calling prepare() too when you change presets... not sure.
But If I were you, I wouldn't use any hacky methods like that, because not all Daws will work the same. This seems like a tricky situation! I'm not sure if there is a Hise feature that makes sense, that could be proposed? The fix would have to be in the Hise engine, but it's a bit of an odd feature. So I'm not sure if Christoph would be enthusiastic about it. Maybe worth asking him about this scenario.
I'd probably investigate @ustk 's suggestion first, to make a custom preset system.
-
RE: [DEVLOG] Pro EQposted in C++ Development
@Morphoice
Sounds like an interesting project!
I'm looking forward to seeing the results, this is exactly the kind of thing this project was for. -
RE: Measuring plugin delay times....posted in General Questions
I was under the impression that Hise has a Hisescript way to probe latency?
And so you could measure it whenever you make a change to the FX stack. But maybe I was mistaken.If I'm honest with you, in this situation, this is the kind of task I would be lazy and let an AI agent handle.
Although I know already that you might not have something like that set up.
But if it were me solving it, I would be tempted to be lazy and brute force it, use the REST API and Codex, and have it send timed impulses through the empty chain, and then through each FX once loaded individually. That then becomes the lookup table of all the latencies. Do it for different sample rates to find the ones that scale with sample rate. Since its a serial chain, you can basically just add together the latency that each processor give you. I would also entirely discard any latency that is non-linear / different for different frequencies, for individual effects.
I would discard the entire value for that effect, because those are likely nonlinear-phase / group delay latencies and it will actually have a worse sounding phasing if you compensate for those.That's the lazy route. It's pretty wasteful.
And I suppose you could actually do this by hand too, using the Hise latency finding tool, and write the LUT yourself.But personally I always keep track of the latency of my own DSP while I'm developing it, so it's never a mystery. But I can only do that because I only use my own C++ DSP in Hise.
An alternative is that you could read through the source code of whatever DSP pieces you are using and find all the delays though (it will mostly be explicit delay lines for lookahead, feedback stabilization, and things like Linear phase oversampling (dont try to compensate nonlinear phase oversampling), and FIR filters, FFT) those all give measurable latency.
But yeah, if there is a Hisescript API for measuring latency, I would assume that is the thing to use! You could even build a LUT using Hisescript and no C++, if that feature exists.
-
RE: [DEVLOG] Pro EQposted in C++ Development
@ustk
@lalalandsynth
@Chazrox
@dannytaurusThanks for your kind comments!
I've done some optimization today and the EQ now uses 1.5x the CPU of ProQ4.
Happy progress.-You'll have to wait for the Hise Asset store, for me to release this for free, but consider this my gift to all of you fantastic people in the Hise Community. My humble beginnings took place on this platform and forum, and now I code DSP fulltime as my living.
-
[DEVLOG] Pro EQposted in C++ Development
Over the last year, I've been doing heavy R&D to design the perfect minimum-phase EQ.
My initial goal was to "beat" Fabfilter's ProQ4 product.I was successful,
and I'd like to share some of my findings!
First of all, what's this all about? Why do I want to make a better EQ than ProQ? What's wrong with ProQ?
a few things.
- ProQ's frequency response gets warped near nyquist (high frequencies)
- ProQ cannot be modulated for synthesis (the modulation is full of artefacts)
But before correcting these issues,
I wanted to first create an EQ that at least matches with ProQ.
After I've achieved that, then I can create the technology to improve upon it. Right?Well, I was not expecting this first step to be so difficult!
The first thing I did was analyze the ProQ shapes (minimum phase mode) and I discovered instantly that none of them are "standard" EQ shapes. They are all custom shapes, even the normal bell shapes are not what we call "cookbook" shapes. They are all unique shapes that Fabfilter invented. So right off the bat, we can cross off using normal EQ filter shapes that can be found on the internet.
It makes sense that ProQ would be using custom shapes though.
If you look at ProQ, the shapes can get super wild. No normal EQ is capable of such high Q!freaking steep!

And so the first thing I tried was stacking multiple minimum phase filters in series, to try and get the same shapes. Basically I created a cascade of bells, slopes, etc.
And this paid off, I managed to create a decent "sloped bell" shape and other steep shapes, by combining filters in series.However - as soon as I moved the cutoff of all these filters together, we got artefacts. Little inconsistencies would appear, and it turned out that cascading minimum phase filters is actually a little bit delicate. The shape gets warped subtly at different cutoffs, and so the overall filter ended up having weird spikes and nasty shape issues at different cutoffs...!
ProQ actually does have this issue too - but to a smaller degree compared to my filter cascade.
The solution was a little devious. This is how I believe ProQ works:
The EQ is essentially an "analog-prototype digitizer".
When a Bell is created, the DSP constructs what is called an "Analog Prototype".
This is an "ideal frequency response" target. In other words it imagines the shape it
wants to create.It then digitizes each part of the shape separately so that we get a cascade of filters
that match the target when ran in series (same as my initial idea).
But the important part is that it gives extra weight to "perceptually important points"
on the filter frequency response target. The solver that creates the matching filters, makes sure
that the filters will pass through the most important points. This prevents wobble and weird spikes.
Basically, every time you move the cutoff, the DSP recalculates the entire shape, it creates the
Analog Prototype frequency response target, and creates the fitted filters that match that shape as close as possible.Basically it's adjusting the cascade of filters every time you touch a parameter. Self-correcting itself every time to try and match the "target" frequency response.
An amazing advantage of this technique is that you can then reduce the amount that you fit to "impossible" parts of the target frequency response. For example doing filtering near nyquist (the top end of the sample rate) you can reduce the amount that you weight towards those parts (trying to fit a filter to ultrasonic frequencies will cause the rest of the filter response to warp and bend) meaning we fit only to the important audible parts and keep the filter response stable.
The side effect of this, is that you can't really do true modulation. Because you're recalculating the filters every time. So ProQ does crossfades instead, when it recalculates the filters it crossfades from the old ones to the new ones.
After doing the above, my own EQ filter could match with ProQ4:

That was much more complex than I'd imagined!
They are definitely worthy of the name "Fabfilter" with this kind of effort.But...
I want to be the very best, like noone ever was 
So I set out on my year long journey to invent a better EQ.
The final solution involved creating a solver that can be modulated at audio rate, doesn't ever use crossfades, and matches the analog response target as closely as possible. Making the realtime solver smooth so that changing frequency didn't create inconsistencies was the hardest challenge. I present the end result of my research:
GriffinFilter matches Fabfilter for all the "easy" shapes:

Where Fabfilter warps, GriffinFilter does not:

--
100Q anyone?
That's twice as steep Q as Fabfilter can manage.
--
And we can modulate cleanly, at audio rate
Here's the printed specs:
CPU usage is currently higher for GriffinEQ.
But the good news is that the GriffinEQ project is still under development!
This is the next obstacle for me to tackle. The aim is to get GriffinEQ performance matched with ProQ4.
And now, for the all important question:
Q: Do these EQ improvements really matter?
A: In some ways, no, not really!Musicians already use multiple EQ bands. They stack whatever number of bands they want, to get the sound that they want.
You mix with your ears, not with your eyes.
And for ordinary EQ situations ProQ4 matches the ideal shape really closely. It only gets warped at the highest frequencies, which are practically inaudible.So why go through this enormous effort to improve it?
The answer is synthesis.
I love using EQ to create new sounds. And I commonly stack lots of EQ bands ontop of each other and modulate them around like crazy to make wild phasing effects!
And so the limits of ProQ started to matter to me. I wanted something that was as precise as ProQ, capable of those really steep filter shapes, but I also needed it to modulate smooth and consistent, so that I can do big modulated sweeps that reach right up into the high frequencies! Without unintentional weird spikes or warping. Which is an issue that ProQ still suffers from.In scientific terms it's better, and in musical terms it's different.
Maybe it doesn't hurt to have just one more EQ to choose from? : )
I plan to make this DSP available in the upcoming Hise Asset Store for free.

-
[BLOG] How does DSP work? [Part 3]posted in C++ Development
How does DSP work? [Part 3]
This time, we're going to look at distortion.
In Part 1, I briefly described distortion as "bending the waveform" by changing the sample values.
Now let's unpack what that actually means.Distorting a waveform
To "distort" something means to change its shape.
A distortion effect does exactly that to a waveform:

We talked previously about how in a gain/volume effect, every sample is multiplied by the same amount.
The waveform becomes taller or shorter, but it keeps the same shape.A distortion effect changes sample heights by different amounts.
That is what allows the waveform to bend shape.Clipping
The simplest example of distortion is clipping.
For example, a clipper that only allows sample values between
-1.0and+1.0.(fact: Most audio file formats will clip at this value)
Values inside that range are left alone.
Anything above+1.0or below-1.0is clamped.Watch what happens as the waveform gets louder:

At first, the waveform simply gets taller.
Once the peaks reach the limits, they cannot get any taller.
That's how a clipper works. This is a distortion.Let's zoom in and look at a few of the sample values:

Only the sample values that exceed the limits are changed.
The extra height is cut off, leaving the waveform with flat edges.In pseudocode, the whole effect could be written like this:
for each sample in the buffer: sample = clamp(sample, -1.0, 1.0)In other words:
if the sample value is less than-1.0, it gets set to-1.0.
if the sample value is greater than1.0, it gets set to1.0.Waveshaping
This kind of distortion is called a Waveshaper.
Hardclippingis just the straightforward clamp.
But we can use other rules/functions to create different waveshapers.
You can create waveshapers by defining a function that maps input values to output values.

In other words:
If the original sample value is equal to-0.75we set it to-0.88.
If the original sample value is equal to-0.50we set it to-0.67,
and so on.This is called mapping.
One value is mapped to another value.And the table is called a lookup table.
Drawing the table
The input and output mapping can also be drawn as points on a graph.
You've probably seen this kind of thing before:
It's an easy way to visualize the waveshaper.
Input values run along the bottom.
Output values run up the right side.To look up an input of
0.50, start at0.50along the bottom, move up until the line is reached, then move right to read the output:
The result is
0.67.This plot is called a transfer curve or waveshaper curve.

Bending the line means we are mapping the samples to different output values.
A waveshaper
Here is a waveshaper processing a waveform:

For each sample of the original wave, we look up the input value on the transfer curve,
and replace it with the corresponding output value.The same process on a more dense smooth waveform looks like this:

The Math
The input and output mappings do not have to be stored in a lookup table.
Some waveshaper distortions use a table, but some use a formula instead.Here is the most common "soft-clipping" formula:
output = tanh(input * drive)inputis the current sample value.
tanhis a math function that returns the new sample value.The function is simply another way of providing an input-to-output map.
(You could also use
sin,cos, or any other function that takes an input value and gives you an output value!)The
drivemultiplication in my code makes the original sample value larger (increases gain) beforetanhwaveshapes the output.
Tanhhas more of a shape at the extreme edges, so increasing the volume of our waveform means we get mapped with all those strong parts of the curve.
And get a more warped (distorted) waveform.
Basically we get more distortion when we go into the waveshaper with a louder signal.
The algorithm is still very simple:
for each sample in the buffer: sample = tanh(sample * drive)In HISE-style C++:

HISE's
math.exprnode does exactly this kind of thing, and it lets you type in your own waveshaping formula!
What distortion sounds like
Different shaped waveforms sound different (well duh).
A sine wave sounds smooth and pure.
A square wave sounds harsh and loud.When we apply waveshaping, we are bending the waveform to make new waveforms.

More bending changes the shape more (and creates all kinds of harmonics)!
You can use a lot of different kinds of formulas to bend waveforms in weird ways.
Different transfer curves create different effects!
To Recap
A distortion effect changes the shape of a waveform by altering the sample values.
A clipper does this by limiting/clamping sample values.
Waveshapers use a function to map each input sample value to a new output value.
You can visualise this mapping nicely as a transfer curve.Apply the mapping to every sample in the buffer, and the new sample heights you get, form a distorted waveform.
That is how a waveshaper works.
-
RE: Made a thing: Roland JX-8P/JC-10/MKS-70 emulation in HISEposted in General Questions
Great work, it's amazing to see how far you've come in what feels like such a short span of time!
So cool -
[BLOG] How does DSP work? [Part 2]posted in C++ Development
How does DSP work? [Part 2]
Welcome back!
In the previous part, we saw that audio effects work by changing sample values.
And we saw that a volume effect is just multiplication.Next you might be wondering: how does something like a filter work?
That's the question we are going to answer today.We're going to start with the simplest example of a filter: a smoother.
A smoother is a low pass filter in its simplest form.
The reason will become clear as we build one.Low pass filter
You probably already know that a low-pass filter removes high frequencies.
But inside a DSP effect, the audio waveform is just a block of sample values:
[0.14, 0.21, 0.08, 0.29, -0.04, -0.18, -0.11, -0.32, ...]Those numbers are the waveform.
So how are we supposed to alter these sample values to remove high frequencies?
let me explain:
You probably already know that frequency is how fast a waveform is.

And of course, a waveform can contain many frequencies at once.
For example, if we add two waves together:
We get a wave that contains high and low frequencies.
So how do we remove the high frequencies from this kind of wave?
Let's demonstrate with a complex wave.
Here is a waveform with plenty of high-frequency content:
The broad sine-like shape is low frequency.
The fine, noisy-looking details are higher frequencies.Now watch what happens when we low-pass the sound:

The noisy detail is removed, while the broad low-frequency shape remains.
The waveform looks smoothed! A smoothing algorithm can remove the high frequencies!
A Smoother
So let's look at how a smoother works.
[My explanation may be a little hard to follow - bear with me please! I will try and explain it in a few different ways]
There are many ways to write a smoother.
The version we're going to use generates a new, smoothed waveform in place of the original one.The algorithm works like this:
Every sample, look at the original waveform sample, and move our new waveform sample (the smoothed waveform) towards it.
But only move it a small amount each sample.Here is an animation that shows the algorithm in action:

Green is the original waveform sample value.
Blue is our smoothed waveform we are creating.We use the green as a "target", and our smoothed value will move towards it over time.
Notice how the original (Green) instantly moves to the new sample value, while our smoothed (Blue) value takes a while to catch up.
Basically, it's incapable of moving fast!
In other words... it can't be high frequency. Only low frequency!Here is the same process running from sample to sample, on a (very zoomed in) waveform:

At the right edge, green is the current sample of the original waveform, and blue is our smoothed value.
The smoothing algorithm works by starting from the previous blue value, and then moving towards the green target sample value.
The resulting smoothed waveform is basically a slow, tired version of the original wave.
It can follow the broad movements, but it can't keep up with quick detailsThe algorithm looks like this:
var green; for each sample in the chunk: move the green value partway towards the current sample output the green valueThe Math
Now let's write the smoothing algorithm as pseudocode:
amount = 0.1 smoothedValue = 0.0 for each sample in the chunk: smoothedValue = lerp(smoothedValue, sample, amount) sample = smoothedValuesmoothedValueis the current height of the blue waveform.
It starts at0.0, and it is kept after each sample so that the next calculation can continue from the same height.For each sample,
lerpmovessmoothedValuetowards the height of the original waveform.
Theamountcontrols how far it is allowed to move.An
amountof1.0reaches the original sample value immediately.
Anamountof0.1only moves one tenth of the distance.lerpis short for a linear interpolation function.
In this case, it calculates a new sample value (height) between the currentsmoothedValueand the originalsample.The calculation inside
lerpis:smoothedValue += (sample - smoothedValue) * amountsample - smoothedValuemeasures the distance between the blue value and the green target.
Multiplying that distance byamountchooses how much of the distance to travel.
Adding the result tosmoothedValuemoves the blue value towards the green one.Finally, we output the
smoothedValue.Because every calculation continues from the value calculated for the previous sample, repeating this process across the waveform for every sample in the buffer, produces exponential smoothing.
In HISE-Style C++
The same calculation in C++ looks like this:

Some trivia:
That stored value is called the filter's state.
Because each result depends on the result from the sample before it, this is a recursive filter, also called an IIR filter.
With one stored value per channel, this particular algorithm is called a one-pole low-pass filter.Cutoff Frequency
Our example code uses a fixed
amountof0.1.If we set
amountto1.0, the smoothed value reaches every sample immediately.
Nothing is smoothed.With a smaller amount, the smoothed value takes longer to reach each sample:
The smoothed value changes more slowly, so more high-frequency detail is flattened.When this calculation is used in an audio filter effect, the control is normally presented as a cutoff frequency in Hz.
This is done using some extra conversion math.
The cutoff frequency and Daw sample rate are then converted into theamountused by the code.
^ The smoother with changing
amount(cutoff):At a low cutoff, the blue waveform loses most of its fine detail.
As the cutoff rises, the blue waveform follows more of the detail.Other Audio Filters
The smoother I showed you is a real one-pole low-pass filter.
Its slope is a gentle 6 dB per octave!But audio filters can also have steeper slopes, resonance, and completely different shapes:

Different filter calculations produce different frequency responses:

More advanced filters store more values, and combine them in different ways.
Two useful names to look for are state-variable filters and biquad filters.
You can find the algorithms for these online, and they are also implemented in HISE'sFilternode.HISE provides a state-variable filter node.
MusicDSP's Chamberlin state-variable filter provides a compact explanation and working algorithms for SVF filters.
The Audio EQ Cookbook contains the standard equations for many familiar EQ filter shapes.To Recap
Inside a DSP effect, the audio waveform is made up of chunks of sample values.
For a one-pole smoother, each sample we calculate a new value partway between its previous result and the incoming sample.
This adds resistance to fast changes, and suppresses the fine detail in the waveform.
That "fast detail" contains high-frequency content, so the high frequencies become quieter when we do this.
-
RE: [BLOG] How does DSP work? [Part 1]posted in C++ Development
@David-Healey
Thank you!
Maybe with some refinement :)It's far from perfect.
This explanation is just my own attempt to boil down the theory into a simple form.
...and it still ended up a bit of a ramble!I think it's quite a tricky subject to teach, because in real life there are so many implications and exceptions to every rule.
Even simple DSP can look a bit monstrous when you layer ontop all of the common optimizations and C++ tricks. -
[BLOG] How does DSP work? [Part 1]posted in C++ Development
Welcome to the first part of my new blog series!
To be clear, this is not a series about how to write DSP code in HISE (That tutorial series is coming later).
Rather, this is a beginner focused, theory-heavy guide on "How does DSP work".Understanding this theory, will make it much easier to write your own DSP later.
So without further ado, let's begin the first part!How does DSP work? [Part 1]
Audio programming does not look like audio.

It looks like values and numbers.
And that's exactly what makes DSP possible.
Once sound is represented by numbers, code can manipulate it!Without further ado, let me explain how audio gets represented as data, and how changing that data changes what you hear.
Audio as Data
A speaker makes sound by moving.

The line at the top is a waveform.
For now, think of it as the shape the speaker is following.
When the waveform moves up, the cone moves one way.
When the waveform moves down, the cone moves the other way.That movement pushes air, and we hear it as sound.
Real audio is generally faster and messier, but the idea does not change:
a speaker is following a changing value over time.So, if we want to create a sound,
we need to create a waveform.The waveform as numbers
In digital audio, a waveform is stored as numbers.
A tiny piece of a waveform might look like this:[0.00, 0.70, 0.82, 0.27, -0.51, -0.86, -0.51, 0.27]So, what is this?
Well, digital audio does not store a "picture" of a waveform.
It stores the height over time.Plot those heights from left to right, and the waveform appears.

These height numbers are called samples.
Because each number is one tiny "sample" of the waveform height at one moment in time.The order matters because the order is time:

The array of data is the digital waveform. The drawing is the same data made easier to see.
Lots of samples
The example I showed you above, is tiny on purpose.
Real audio has far more samples than this.I'm sure you've heard of "Sample rate".
44.1k, 48k. 96k, etc.
With 48k being a common DAW sample rate.Well, running a program at 48 kHz means that one second of mono audio contains 48,000 sample values.
That's the kind of high resolution that produces smooth waves.
The simple drawings in this article are just a readable version.
But real audio is the same thing packed more tightly in time.
(^ That's just something to be aware of. You don't have to worry about it for now, since I'll be continuing to use small pieces of audio for the sake of this article).
So far we have looked at audio as one long strip of sample values.
But we have not talked about how a plugin generates this big stream of audio.So let's talk about chunks / buffers.
Chunks (Buffers)
Real time DSP does not work on a big, long, sound in one go.
- It processes chunks of audio.
A DSP effect takes a short chunk of audio, processes it, then moves on to the next chunk.
An effect is like this:
A chunk comes in.
The effect changes the numbers inside it.
The chunk goes out.
Then the next chunk comes in.This is the basic shape of a normal audio effect.

(The reason we process in small chunks of sound is efficiency related. But it's also practical:
It's quite useful to have access to a whole portion of audio at a time)A simple example: volume
Let's look at a real-life example.
Volume is a good example because it's easy to see.
You probably already know:
Volume is the height of the waveform.Making a waveform less tall means the speaker isn't moving as much.
In other words, height affects volume.
...And earlier we saw that we store waveforms as height values.
(you can see where I'm going with this).
If we want to make the waveform quieter,
all we need to do is make the sample values smaller.For example if we multiply every sample by 0.5 (half):
The shape is the same.
The height is half as large.
We've made the waveform half as loud.
The algorithm for a volume effect then boils down to:

In pseudocode form:
receive buffer for each sample in the buffer { sample = sample * gain; } ^ do the above for every buffer we receiveSo:
If gain is 1.0, the sample values stay the same.
If gain is 0.5, the waveform is half as tall.
If gain is 2.0, the waveform is twice as loud/tall.
If gain is 0.0, every sample becomes zero, which is silence.In actual C++ DSP:

(^ I bet you understand this now!)
The main part of the effect is a function that receives a buffer of samples (a chunk) and processes them using math.
That's what DSP code looks like!The real HISE gain node has some extra controls and parameter smoothing, but the core audio operation is still this simple multiplication.
The Lesson
Honestly that's pretty much it.
DSP is not very complicated.Most Audio effects work by:
Take a buffer of sample values,
change those values,
and pass the buffer onwardA Gain effect multiplies the samples.A Distortion bends the waveform shape by changing the samples.A Delay stores samples and plays them back later.Oscillators are a slightly different case. They create new sample values rather than affecting incoming ones.

^ And I'm if being 100% honest, this isn't quite the whole picture.
If we zoom out a little, you'll see that there is actually a bigger loop going on.
Where something is sending us a buffer, and asking our DSP to process or fill it.
Then it takes that buffer back and sends it to the next place.(in our case, that "something" is HISE / JUCE).

For an effect, something is going to send us a chunk and say "please process this" and we do that.
For an oscillator, we might be given an empty chunk and we just need to write a waveform into the chunk and send that back.
To Recap
1. The table, the waveform, the buffer.
They are different visualizations of the same thing:
sample values over time.
2. Audio plugins work by processing chunks of samples. These chunks are passed around between different oscillators and effects.

3. Down the line, part of the program will mix the chunks and send them to the speaker and we will hear the waveform (we don't usually have to worry about that part, Hise or Juce will take care of those parts for us).

Next: filters and other effects
I know what you're thinking:
Gain makes sense, but how do we create filters and other kinds of effects? What kind of maths causes those?Look forward to [Part 2].
-
RE: Which modulation routing method would you recommend for my project?posted in General Questions
@David-Healey Really? He's talking about block and frame sizes though? DSP usually reads parameter values at the start of each block. Using larger blocks means you might not be reading the parameters / LFO modulation as frequently. (assuming the modulation / parameter callbacks are also being called fast enough by the modulator)
