Skip to content
This repository has been archived by the owner on Aug 17, 2024. It is now read-only.

Commit

Permalink
added variable order dc blocking, update README
Browse files Browse the repository at this point in the history
  • Loading branch information
thezhe committed Dec 22, 2021
1 parent f5bd872 commit 56182d6
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 22 deletions.
18 changes: 7 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
![SOUL-VA_logo](https://user-images.githubusercontent.com/42720670/143501884-f9a4daac-9460-4312-bacf-4984ef002dc4.png)
# The SOUL Virtual Analog Library
[SOUL-VA](https://github.com/thezhe/SOUL-VA) is a collection of analog-inspired audio effects. Unlike other libraries, this project achieves [analytical](https://math.stackexchange.com/questions/935405/what-s-the-difference-between-analytical-and-numerical-approaches-to-problems) solutions and [a strict -60dB peak amplitude limit for aliasing artifacts](https://github.com/thezhe/SOUL-VA#example-3-onepolec_lan-nonlinearity--500). Each effect can run at full quality at 44.1kHz without any additional antialiasing measures. In addition, most parameters are stable and artifact-free under modulation up through 20Hz.
[SOUL-VA](https://github.com/thezhe/SOUL-VA) is a collection of analog-inspired audio effects. Unlike other libraries, this project achieves [analytical](https://math.stackexchange.com/questions/935405/what-s-the-difference-between-analytical-and-numerical-approaches-to-problems) solutions and [a strict -60dB peak amplitude limit for aliasing artifacts](https://github.com/thezhe/SOUL-VA#example-3-onepolec_lan-nonlinearity--500). Each effect can run at full quality at 44.1kHz without any additional antialiasing measures. In addition, unless marked otherwise, parameters are artifact-free under modulation up through 20Hz.

## Background Knowledge
This library considers background knowledge trivial; *SOUL-VA does not re-explain any of the following concepts*:
Expand All @@ -15,11 +15,7 @@ This library considers background knowledge trivial; *SOUL-VA does not re-explai
The current effect endpoints in `VA::HighLevel` will not be removed (excluding major bugs and design revisions), but new endpoints may appear in updates. In other words, effects are backward compatible, but internal code is subject to changes.

## Contents
- `include/VA.soul` - single-file library
- `examples/main.soul` - example `[[main]]` instance for instantiating `Processors` from `VA::HighLevel`
- `examples/main.soulpatch` - 'includes' and 'links' VA.soul with main.soul
- `tests/testMain.m` - script that runs test cases on main.soulpatch
- `tools/soul.json` - [VSCode snippets](https://code.visualstudio.com/docs/editor/userdefinedsnippets)
Files within each top-level directory start with a short summary of their function. Users can utilize VA::HighLevel using only the `include/` and `examples/` directories.

## Official Ways to Use SOUL-VA
1. [SOUL Playground](https://soul.dev/lab/)
Expand All @@ -32,17 +28,17 @@ Include soul.exe in the 'Path' environment variable. Set `SOUL-VA/tests/` as the
## Contributing
Please post bugs in issues and feature requests in discussions. Bug fixes take priority. Pull requests are not accepted at the moment.

## Octave Examples
The following sections explain the output after running `testMain (44100)` on different `VA::HighLevel` effects (instantiated in `Processor [[main]]`). The script is useful for catching common errors in development without needing to listen to processed samples.
### Example 1: `Dummy`
## Octave Examples (`tests/testEffect.m`)
The following sections explain the output after running `testEffect (44100)` on different `VA::HighLevel` effects (instantiated in `effects.soul`). The script is useful for catching common errors in development without needing to listen to processed samples.
### Example Effect 1: `Dummy`
The system is trivial (and linear) and simply passes signals through unmodified. Notice how the step response input is actually a pulse signal with values 0.5 and 0.25 so that the test can measure overshoot (up towards 1) and undershoot (down towards -1). The DC IO plot is the same as the decibel mapping of a dynamic range compressor with a ratio of 1 and SinRamp IO plot shows what the system would look like as a waveshaper (may not always be a function).
![Dummy2](https://user-images.githubusercontent.com/42720670/143499549-a8484fe7-bb55-4c24-8242-aa6dd5be6b1c.png)
![Dummy1](https://user-images.githubusercontent.com/42720670/143499553-e699e725-ad35-413c-9378-3121313d5d49.png)
### Example 2: `OnepoleC_Lan` (nonlinearity = 200)
### Example Effect 2: `OnepoleC_Lan` (nonlinearity = 200)
The system is significantly nonlinear and all outputs show some sort of nontrivial filtering. While the magnitude response applies only to linear systems, its plot accurately predicts that `OnepoleC_Lan` tends to boost bass frequencies.
![OnepoleC_Lan(200)2](https://user-images.githubusercontent.com/42720670/143499888-6d6bb662-d376-4e94-90f3-c417c346b851.png)
![OnepoleC_Lan(200)1](https://user-images.githubusercontent.com/42720670/143499897-f637bf2f-9c7f-469a-954f-06ace715cf5c.png)
### Example 3: `OnepoleC_Lan` (nonlinearity = 500)
### Example Effect 3: `OnepoleC_Lan` (nonlinearity = 500)
The system is nontrivial, but does not meet the standards of this library. Not all aliasing components are less than -60dB as shown by the partials (black dots) in the bottom right-hand corner of 'SinSweep (BW)'. These partials are not desired since they are not parallel to any harmonics/inharmonics, nor are their frequencies low enough to be residual DC noise.
![OnepoleC_Lan(500)2](https://user-images.githubusercontent.com/42720670/143499912-0e513b21-b668-488e-ae87-a767db9aadab.png)
![OnepoleC_Lan(500)1](https://user-images.githubusercontent.com/42720670/143499917-0621c055-8e9d-4c08-891e-cf0de483885d.png)
Expand Down
65 changes: 60 additions & 5 deletions include/VA.soul
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@
/** Task List
Test:
- min buffer size
- fix approximation for ADAA2 and snippet
- smooth nl, increase slew rate

Future Tasks:
- add updateSample to snippets
- all ADAA in one processor
- Add more static_assert checks
- convert Omega endpoints to cutoff endpoints for consistency
Expand Down Expand Up @@ -147,8 +146,8 @@ VA::HighLevel Processors 12/22/21
let
{
dcBlockerIn = filt::dc_blocker::Processor (5.f);
dcBlockerOut = filt::dc_blocker::Processor (5.f);
dcBlockerOutN = DC_BlockerN::Processor (5.f, 8);

stereoLink = StereoLink::Processor (initialStereoLinkPercent);

internal = Internal::Processor (initialNonlinearity) * 2;
Expand All @@ -170,7 +169,7 @@ VA::HighLevel Processors 12/22/21
internal.lowpassOut -> onepoleMixer.lowpassIn;

onepoleMixer.out -> autoSmoothedVolume.in;
autoSmoothedVolume.out -> dcBlockerOut -> out;
autoSmoothedVolume.out -> dcBlockerOutN -> out;
}
}

Expand Down Expand Up @@ -602,6 +601,62 @@ Filter Processors 12/21/21
}
}

/** Variable order DC blocker using soul::filters::dc_blocker */
namespace DC_BlockerN
{
namespace M (int order)
{
struct Coeffs
{
filt::dc_blocker::Coeffs[order] coeffs;
}

void update (Coeffs& c, float64 SampleRate, float64 freqHz)
{
for (int i = 0; i < order; ++i)
filt::dc_blocker::update (c.coeffs.at(i), SampleRate, freqHz);
}

struct State
{
filt::dc_blocker::State[order] state;
}

SampleType process (State& s, SampleType x, Coeffs& c)
{
var y = filt::dc_blocker::process (s.state.at(0), x, c.coeffs.at(0));

for (int i = 1; i < order; ++i)
y = filt::dc_blocker::process (s.state.at(i), y, c.coeffs.at(i));

return y;
}
}

processor Processor (float64 frequency = 5, int order = 1)
{
input stream SampleType in;
output stream SampleType out;

void run()
{
M(order)::State s;
M(order)::Coeffs c;

M(order)::update (c, processor.frequency, frequency);

loop
{
out << M(order)::process (s, in, c);

advance();
}
}
}
}



/** Modified version of https://soul.dev/lab/?id=Delay

For feedback make a loop with a unit delay (i.e. DelayLine.out -> [1] -> add your effects here -> DelayLine.in)
Expand Down
4 changes: 2 additions & 2 deletions tests/effect.soul
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** Duplicate of '../examples/main.soul' for testEffect.m */
/** Duplicate of '../examples/main.soul' boilerplate for testEffect.m */

namespace main
{
Expand Down Expand Up @@ -66,7 +66,7 @@ namespace main
let
{
//define effect as a 'Processor' from 'VA::HighLevel'
effect = VA::HighLevel::OnepoleC_Lan::Processor;
effect = VA::HighLevel::OnepoleC_Lan::Processor (200);

//comment out for stereo
up = FloatToSampleType::Processor;
Expand Down
8 changes: 4 additions & 4 deletions tests/effect.soulpatch
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"soulPatchV1": {
"ID": "com.TheZhe.SOULVA.main",
"ID": "com.TheZhe.SOULVA.effect",
"version": "1.0",
"name": "main",
"description": "link VA.soul with main.soul",
"name": "effect",
"description": "link VA.soul with effect.soul",
"category": "effect",
"manufacturer": "TheZhe",
"website": "https://github.com/thezhe/SOUL-VA",
"isInstrument": false,
"source": [
"main.soul",
"effect.soul",
"../include/VA.soul"
]
}
Expand Down
1 change: 1 addition & 0 deletions tools/soul.json → tools/soul.jsonc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** VSCode snippets (https://code.visualstudio.com/docs/editor/userdefinedsnippets) */
{
"VA::graph": {
"prefix": "VA::graph",
Expand Down

0 comments on commit 56182d6

Please sign in to comment.