15 releases

0.2.12-alpha.0 Apr 7, 2023
0.2.11-alpha.0 Dec 19, 2022
0.2.5-alpha.0 Jun 21, 2022
0.2.4-alpha.0 Mar 14, 2022
0.1.42-alpha.0 Oct 27, 2021

#8 in #modulation

Download history 2/week @ 2024-07-19 1/week @ 2024-07-26 9/week @ 2024-09-20 16/week @ 2024-09-27 2/week @ 2024-10-04

58 downloads per month
Used in 3 crates (2 directly)

GPL-3.0 license

1MB
14K SLoC

Crate: surgefx-chorus

SurgeFX Chorus: A versatile chorus effect for the Surge Synthesizer system.

The surgefx-chorus crate provides a flexible and efficient implementation of the chorus effect for the Surge Synthesizer system. It handles various control parameters, modulation, and processing capabilities to create rich and immersive soundscapes.

Crate Components

control_group

The control_group represents a collection of related control parameters for the chorus effect. Each group contains parameters such as control_type, default_value, max_value, min_value, modulateable, and moverate.

control_type

The control_type specifies the type of control parameter, e.g., depth, rate, or mix. These parameters dictate how the chorus effect behaves.

default_value, max_value, min_value

These parameters define the default, maximum, and minimum values for a control parameter. For example, the depth of the chorus effect can have a default value of 0.5, a minimum value of 0, and a maximum value of 1.

modulateable

The modulateable parameter is a boolean value that determines if a control parameter can be modulated by external sources, such as LFOs or envelopes.

moverate

The moverate represents the rate at which a control parameter value changes when modulated. For example, a moverate of 0.01 would mean a slow change, while a moverate of 1 would be a fast change.

value_type

The value_type specifies the type of value the control parameter holds. Examples include integers, floating-point numbers, or boolean values.

initial_update, update

The initial_update function initializes the chorus effect with the default control parameter values, while the update function modifies the chorus effect parameters based on user input or modulation.

do_chorus_block

The do_chorus_block function processes a block of audio samples, applying the chorus effect. It uses mathematical functions to create the chorus effect, such as time-varying delays and phase modulation.

Chorus

The Chorus struct represents the main chorus effect, containing control parameters, buffers, and processing functions.

chorus_smoke

The chorus_smoke function is a test function used for testing and debugging purposes.

init, process

The init function initializes the Chorus struct, setting up buffers and other internal data structures. The process function takes an input audio buffer, applies the chorus effect, and returns the processed audio buffer.

chorus_set_buffer

The chorus_set_buffer function sets the internal buffer of the Chorus struct, which is used for processing the input audio.

Mathematical Concepts

The primary mathematical idea behind the chorus effect is time-varying delays. The input audio signal is delayed by different amounts, creating multiple "voices" that are then mixed back into the original signal. This creates a thicker and more spacious sound.

The delay time is modulated by a Low-Frequency Oscillator (LFO) using the following equation:

delay_time = base_delay + depth * sin(2 * π * rate * t)

Where base_delay is the base delay time, depth and rate are control parameters, and t is the time variable.

In addition to time-varying delays, phase modulation can be applied to create more complex and rich-sounding effects. The phase modulation equation is:

Φ(t) = Φ₀ + A * sin(2 * π * f * t + ϕ)

2> thanks, could you teach me more about the chorus effect? can we visualize it with a block diagram?

Of course! The chorus effect is an audio processing technique that simulates the natural phenomenon of multiple instruments or voices playing the same part but with slight variations in pitch and timing. The result is a fuller, richer, and more immersive sound.

Here is a simple block diagram of a chorus effect:

+--------------+     +--------------+     +-------------------+
| Input Signal |---->| Delay Buffer |---->| Time-varying Delay|
+--------------+     +--------------+     +-------------------+
                                          |
                                          v
                                +-----------------+
                                | LFO (sinusoidal)|
                                +-----------------+
                                          |
                                          v
                          +----------------------+     +------------------+
                          | Modulated Delay Line |---->| Wet/Dry Mix & Sum |
                          +----------------------+     +------------------+
                                          ^
                                          |
+--------------+     +--------------+     +-------------------+
| Input Signal |---->| Delay Buffer |---->| Time-varying Delay|
+--------------+     +--------------+     +-------------------+
                                          |
                                          v
                                +-----------------+
                                | LFO (sinusoidal)|
                                +-----------------+
                                          |
                                          v
                          +----------------------+     +------------------+
                          | Modulated Delay Line |---->| Wet/Dry Mix & Sum |
                          +----------------------+     +------------------+
                                                               |
                                                               v
                                                      +-------------+
                                                      | Output Signal|
                                                      +-------------+
  1. Input Signal: The audio signal that needs to be processed.

  2. Delay Buffer: Stores a copy of the input signal that will be used for creating the chorus effect.

  3. Time-varying Delay: The delay times are modulated using a Low-Frequency Oscillator (LFO) to create variations in pitch and timing. This is the core part of the chorus effect.

  4. LFO (sinusoidal): The LFO generates a sine wave that modulates the delay times. The LFO's frequency and amplitude control the rate and depth of the modulation, respectively.

  5. Modulated Delay Line: The modulated delay line applies the time-varying delay to the input signal, creating multiple "voices" with slightly different pitches and timings.

  6. Wet/Dry Mix & Sum: The wet (processed) and dry (original) signals are mixed according to the user-defined mix level. The mixed signal is then summed with the original input signal to create the final output.

  7. Output Signal: The processed audio signal with the chorus effect applied.

The block diagram above shows a two-voice chorus effect. In practice, chorus effects can have multiple voices to create a more complex and rich sound. Additionally, other parameters such as feedback and phase can be used to further shape the sound.

3> could you teach me more about the input signal? what does the chorus effect need on this front?

The input signal for a chorus effect is an audio signal, typically a monophonic or polyphonic source that you want to enhance with the chorus effect. It cank be a single instrument, a voice, or even a mix of multiple instruments. The input signal is the starting point for applying the chorus effect.

In the context of a synthesizer, the input signal is usually generated by an oscillator, a sample playback unit, or a combination of these. In a digital audio workstation (DAW) or an effects processor, the input signal can be a recorded audio track or a live audio feed.

There are no specific requirements for the input signal when it comes to the chorus effect. However, certain characteristics of the input signal may influence how the chorus effect is perceived:

  1. Frequency content: The chorus effect is more noticeable and impactful on sounds with a richer harmonic content, such as strings, pads, or electric pianos. Simple waveforms like sine waves may not benefit as much from the chorus effect since they have minimal harmonic content.

  2. Mono or stereo: Although the chorus effect can be applied to both mono and stereo signals, it tends to produce a more spacious and immersive sound when applied to a mono input. This is because the chorus effect generates additional "voices" that are spread across the stereo field, creating the illusion of a wider and more enveloping sound.

  3. Amplitude envelope: Sounds with longer sustain and release times (e.g., pads, strings) tend to benefit more from the chorus effect. This is because the overlapping "voices" created by the chorus effect have more time to interact and create a richer texture. Sounds with short durations or sharp transients may not benefit as much from the chorus effect.

In summary, the chorus effect can be applied to a wide range of input signals, but the resulting sound will vary depending on the characteristics of the input. It is often more effective on signals with rich harmonic content, sustained sounds, and mono sources.

4> what about the delay buffer?

The delay buffer is a crucial component in the implementation of a chorus effect. It is a memory buffer that temporarily stores a copy of the input signal. The primary purpose of the delay buffer is to provide the means for creating time-varying delays that are essential to the chorus effect.

In a digital implementation of a chorus effect, the delay buffer is usually implemented as a circular buffer (also known as a ring buffer) due to its efficient memory management and ease of use in real-time audio processing.

Here's how the delay buffer works in the context of the chorus effect:

  1. The input signal is continuously fed into the delay buffer.

  2. The buffer has a fixed size, which determines the maximum delay time that can be achieved. For example, if the buffer size is 1000 samples and the sample rate is 44,100 Hz, the maximum delay time would be 1000/44100 ≈ 22.7 ms.

  3. A read pointer reads the delayed samples from the buffer, while a write pointer writes new samples into the buffer. The read pointer's position is modulated by the Low-Frequency Oscillator (LFO) to create time-varying delays.

  4. When the read pointer reaches the end of the buffer, it wraps around to the beginning, creating a continuous loop of the input signal.

The delayed signal read from the buffer is then mixed with the original input signal to create the chorus effect. By modulating the position of the read pointer, the chorus effect can generate multiple "voices" with slight variations in pitch and timing, simulating the natural phenomenon of multiple instruments or voices playing the same part.

In summary, the delay buffer is an essential component of the chorus effect, providing the means to create time-varying delays that are mixed with the original input signal to produce a richer and more immersive sound.

5> what about the time varying delay?

The time-varying delay is a key component of the chorus effect, responsible for creating the variations in pitch and timing that give the chorus its distinctive sound. The time-varying delay works by modulating the delay time applied to the input signal using a Low-Frequency Oscillator (LFO).

In a digital implementation of a chorus effect, the time-varying delay is usually achieved by modulating the read pointer's position in the delay buffer. The position of the read pointer determines how much the input signal is delayed before being mixed with the original signal.

The delay time modulation is typically controlled by an LFO, which generates a periodic waveform (often a sine wave) at a low frequency (usually below 20 Hz). The LFO modulates the read pointer's position, causing the delay time to continuously change, resulting in variations in pitch and timing.

Here's a simple equation to describe the time-varying delay:

delay_time(t) = base_delay + depth * sin(2 * π * rate * t)

Where:

  • delay_time(t) is the delay time at time t

  • base_delay is the base delay time (usually in milliseconds)

  • depth is the modulation depth, which controls the intensity of the pitch and timing variations

  • rate is the frequency of the LFO (in Hz), which controls the speed of the pitch and timing variations

  • t is the time variable

The time-varying delay creates multiple "voices" with slightly different pitches and timings by continuously changing the delay time applied to the input signal. When these delayed signals are mixed with the original input signal, they produce the rich and immersive sound characteristic of the chorus effect.

In summary, the time-varying delay is an essential component of the chorus effect, responsible for creating the pitch and timing variations that give the chorus its distinctive sound. It is typically achieved by modulating the read pointer's position in the delay buffer using an LFO, resulting in a continuously changing delay time.

6> what about the lfo?

The Low-Frequency Oscillator (LFO) is an essential component in the chorus effect, responsible for modulating the time-varying delay, which in turn creates the pitch and timing variations characteristic of the chorus effect. The LFO generates a periodic waveform, typically at frequencies below 20 Hz, which is too slow to be perceived as a pitch.

In the context of the chorus effect, the LFO's primary role is to modulate the delay time applied to the input signal. This modulation causes the delay time to change continuously, resulting in variations in pitch and timing that create the illusion of multiple "voices" playing the same part.

The most common waveform used for LFO in chorus effect is a sine wave, but other waveforms, such as triangle, square, or sawtooth, can also be used to create different modulation characteristics. The choice of waveform will influence the overall sound and texture of the chorus effect.

The LFO typically has two main parameters:

  1. Rate: The rate of the LFO controls the frequency of the modulation waveform, which in turn determines the speed of the pitch and timing variations. Higher rates will produce more rapid fluctuations, while lower rates will result in slower, more subtle changes.

  2. Depth: The depth of the LFO controls the amplitude of the modulation waveform, which determines the intensity of the pitch and timing variations. Higher depth values will produce more pronounced changes in pitch and timing, while lower depth values will yield more subtle effects.

The LFO modulates the delay time applied to the input signal using an equation like this:

delay_time(t) = basew_delay + depth * sin(2 * π * rate * t)

Where:

  • delay_time(t) is the delay time at time t

  • base_delay is the base delay time (usually in milliseconds)

  • depth is the LFO's modulation depth

  • rate is the LFO's frequency (in Hz)

  • t is the time variable

In summary, the LFO is a key component in the chorus effect, responsible for modulating the time-varying delay to create the characteristic pitch and timing variations. By adjusting the LFO's rate and depth, you can control the speed and intensity of the chorus effect, shaping the overall sound and texture.

7> what about the Modulated Delay Line?

The Modulated Delay Line is an essential component of the chorus effect, responsible for applying the time-varying delay to the input signal to create the multiple "voices" with slightly different pitches and timings that give the chorus effect its distinctive sound.

In the context of a digital implementation of a chorus effect, the Modulated Delay Line uses the delay buffer and the time-varying delay, which is controlled by an LFO, to create a continuously changing delay time for the input signal.

Here's how the Modulated Delay Line works:

  1. The input signal is fed into the delay buffer.

  2. The LFO generates a periodic waveform (typically a sine wave) that modulates the delay time by controlling the read pointer's position in the delay buffer.

  3. The read pointer retrieves the delayed samples from the delay buffer, while the write pointer writes new samples into the buffer.

  4. The delayed signal, now with a continuously changing delay time, is extracted from the delay buffer using the read pointer.

  5. The modulated delayed signal is then mixed with the original input signal to create the chorus effect.

The Modulated Delay Line is what generates the characteristic pitch and timing variations of the chorus effect. By applying a time-varying delay to the input signal, it creates multiple "voices" that are slightly out of sync in terms of pitch and timing. When these delayed signals are mixed with the original input signal, they produce the rich and immersive sound characteristic of the chorus effect.

In summary, the Modulated Delay Line is an essential component of the chorus effect, responsible for applying the time-varying delay controlled by the LFO to the input signal. It generates the multiple "voices" with slightly different pitches and timings that give the chorus effect its distinctive sound.

8> what about the Wet/Dry Mix & Sum?

The Wet/Dry Mix & Sum is an important component in the chorus effect, responsible for blending the processed (wet) signal with the original (dry) input signal to create the final output. This stage allows you to control the balance between the unprocessed input signal and the chorus-processed signal, shaping the overall sound and intensity of the chorus effect.

Here's how the Wet/Dry Mix & Sum works:

  1. The processed signal, which has the time-varying delay applied by the Modulated Delay Line, is referred to as the "wet" signal.

  2. The original, unprocessed input signal is referred to as the "dry" signal.

  3. The wet and dry signals are mixed together according to a user-defined mix level, which controls the balance between the wet and dry signals.

  4. The mixed signal is then summed with the original input signal to create the final output.

The Wet/Dry Mix parameter typically ranges from 0% to 100%, where 0% corresponds to only the dry signal being present in the output, and 100% corresponds to only the wet signal being present. Values in between allow you to control the balance between the original signal and the chorus effect, adjusting the overall intensity of the effect.

In many chorus effects, the Wet/Dry Mix parameter is sometimes referred to simply as the "Mix" or "Blend" control. Adjusting this parameter allows you to find the right balance between the unprocessed input signal and the chorus-processed signal, creating a range of subtle to more pronounced chorus effects.

In summary, the Wet/Dry Mix & Sum is an important component in the chorus effect, responsible for blending the processed (wet) signal with the original (dry) input signal. By adjusting the mix level, you can control the balance between the unprocessed input signal and the chorus-processed signal, shaping the overall sound and intensity of the chorus effect.

9> what about the Output Signal?

The Output Signal is the final result of the chorus effect after processing the input signal through the various components: time-varying delay, modulated delay line, and the wet/dry mix & sum stage. It contains a blend of the original input signal and the chorus-processed signal, with the balance between them controlled by the wet/dry mix parameter.

The output signal is typically a stereo signal, even if the input signal is mono, as the chorus effect often creates a spatially enhanced sound by spreading the multiple "voices" across the stereo field. The output signal can be further processed by other effects or sent directly to the main mix or an audio output device, depending on the specific implementation and use case.

In the context of a synthesizer, the output signal of the chorus effect would be mixed with other audio signals generated by the synthesizer, such as other oscillators, filters, and effects. In a digital audio workstation (DAW) or an effects processor, the output signal can be routed to additional audio tracks or effects, or it can be mixed with other audio signals in the final mix.

In summary, the Output Signal is the final result of the chorus effect, containing a blend of the original input signal and the chorus-processed signal. The output signal is typically stereo and can be further processed by other effects or sent directly to the main mix or an audio output device. The output signal represents the culmination of the various processing stages of the chorus effect, delivering the rich and immersive sound characteristic of the effect.

10> could you show me an implementation in verilog-a?

Implementing a chorus effect in Verilog-A is not straightforward, as Verilog-A is primarily used for analog circuit simulation and not for digital signal processing (DSP) tasks like audio effects. However, I can describe the general concept of how a chorus effect could be implemented in the context of an analog circuit, which you could then potentially simulate using Verilog-A.

An analog chorus effect can be implemented using a bucket-brigade device (BBD), which is a discrete-time analog delay line. The BBD, combined with an LFO to modulate the delay time and a mixer to combine the wet and dry signals, can create a chorus effect.

Here's a high-level description of the components required for an analog chorus effect:

  1. Input signal: The audio input signal that you want to process with the chorus effect.

  2. LFO: An analog oscillator that generates a low-frequency sine or triangle waveform to modulate the delay time.

  3. Voltage-controlled delay line: A BBD-based circuit that uses the LFO's output to control the delay time. The BBD shifts the input signal through a series of capacitors, creating a time-delayed version of the signal.

  4. Wet/dry mix: An analog mixer circuit that combines the delayed signal (wet) with the original input signal (dry) according to a user-defined mix level. The output of this mixer is the final output of the chorus effect.

  5. Output signal: The audio output signal containing the blend of the original input signal and the chorus-processed signal.

Although this high-level description does not provide the specific details required for a Verilog-A implementation, it gives you an idea of the analog components needed to create a chorus effect in the context of an analog circuit. Simulating such an analog chorus effect in Verilog-A would involve modeling the behavior of each component, including the BBD, LFO, and mixer circuits.

Keep in mind that implementing audio effects like chorus in Verilog-A is quite unusual and not the most efficient or practical approach. Digital signal processing (DSP) techniques, as implemented in programming languages like C++, Python, or Rust, are more commonly used for audio effect development due to their flexibility, precision, and efficiency.

11> but then you could get a chorus in analog hardware, right?

Yes, you can create a chorus effect in analog hardware using components such as a bucket-brigade device (BBD) for the delay line, an analog oscillator (LFO) to modulate the delay time, and an analog mixer to combine the wet and dry signals. Analog chorus effects were popular in guitar pedals and synthesizers before digital signal processing (DSP) became widespread.

However, SystemVerilog, like Verilog-A, is primarily used for hardware description and verification, not for digital signal processing (DSP) tasks like audio effects. SystemVerilog is mainly used to describe and verify digital circuits at the register-transfer level (RTL) for synthesis and simulation purposes, rather than modeling or implementing audio processing algorithms like a chorus effect.

Implementing a chorus effect in a hardware description language (HDL) like SystemVerilog would require designing a custom digital signal processing (DSP) chip that performs the required audio processing operations. This would involve designing and implementing digital circuits for components such as digital filters, digital oscillators (LFO), and digital mixers, as well as memory elements for delay buffers.

Designing and verifying a custom DSP chip in SystemVerilog is a complex and time-consuming task, and it's beyond the scope of a simple example or explanation here. It's also not the most practical or efficient approach for creating audio effects like chorus, as general-purpose programming languages and digital signal processing libraries offer a more flexible and efficient way to implement these effects.

If you're looking to implement a chorus effect, I would recommend using a general-purpose programming language like C++, Python, or Rust, and leveraging existing digital signal processing libraries or frameworks. These languages and libraries provide a more accessible and practical way to develop audio effects like chorus compared to using hardware description languages like SystemVerilog.

12> why not just write the whole dsp system in analog hardware? surely the code isn't prohibitively complicated

Implementing an entire DSP system in analog hardware is indeed possible and was the standard approach before digital signal processing became widespread. However, there are several reasons why digital implementations are now favored for most applications, including audio effects like the chorus:

  1. Precision: Analog components are subject to manufacturing tolerances, temperature drift, and other factors that can introduce inaccuracies in the signal processing. Digital implementations, on the other hand, can achieve a high level of precision and repeatability, ensuring consistent performance.

  2. Flexibility: In an analog hardware system, making changes to the design or functionality often requires modifying the physical circuit, which can be time-consuming and expensive. Digital implementations can be easily modified through software updates, allowing for rapid development and iteration.

  3. Complexity: As the complexity of signal processing algorithms increases, designing and implementing them in analog hardware becomes more challenging. Digital implementations can handle complex algorithms more easily, and modern processors have the computational power to perform real-time processing of these algorithms.

  4. Size and cost: Implementing a DSP system in analog hardware often requires a large number of components, increasing the size and cost of the system. Digital implementations can be more compact and cost-effective, particularly with the availability of dedicated DSP chips and integrated circuits.

  5. Integration: Digital systems can be easily integrated with other digital components, such as microcontrollers, memory, and communication interfaces. This integration facilitates the development of complex systems that combine signal processing with other functionality, such as user interfaces or network connectivity.

While there are some specific use cases where analog hardware implementations may still be preferred, such as in certain guitar pedals or vintage synthesizers, digital signal processing has become the standard approach for most audio effects due to its precision, flexibility, and ease of integration.

It's worth noting that some designers create hybrid systems that combine the benefits of both analog and digital processing, using analog components for certain tasks (e.g., filtering) and digital processing for others (e.g., delay lines or modulation). This approach can achieve the desired sound characteristics while retaining some of the advantages of digital processing.

Dependencies

~11–20MB
~300K SLoC