Cabbage Logo
Back to Cabbage Site

Transient clicks when changing effects

In my effect plugin, I have one instrument perpetually running that continually receives an external audio stream and applies however many effects I wish. However, toggling effects makes clicks and I would like to get rid of that. I initially looked into setting up an ADSR envelope, but since the instrument is always running, it only applies the envelope once at the beginning of the runtime.

I’m not sure how to change the instrument from a perpetual to a triggerable one to have the option of using envelopes. I would like to have the option of either having clean audio, one effect, or multiple chained effects. The way I have the instrument working is below:

instr effect
    a1 inch 1
    a2 inch 2

    if kEffect1 == 1 then
        ; a1 & a2 are manipulated
    if kEffect2 == 1 then
        ; a1 & a2 are manipulated
    if kEffect3 == 1 then
        ; a1 & a2 are manipulated
    if kEffect4 == 1 then
        ; a1 & a2 are manipulated

    outs a1, a2

how do I fix this to keep my effect chaining and remove the clicking? If I need to make a triggerable instrument for each effect, how do I chain the effects to the same a-rate?

I think the best solution here would be to start and stop instruments rather than attempting to do it in a single instrument. That way it’s much easier to control the fade IO times. Here’s a simple example that turns on or off an effect with a checkbox, like this:

if kEffTrig1 == 1 then
    if kEffect1 == 1 then
        event "i", 2, 0, 9999
        turnoff2 2, 0, 1

effectToggle.csd (2.6 KB)

What I don’t like in this instrument is I keep repeating myself with those if statements. So I think I would rather do something like this :slight_smile:

effectToggle2.csd (1.9 KB)

1 Like

This is great, thank you. I made one instrument that sets the signal channel and outputs the audio to have clean output with no effects. However, the more instruments there are modifying the signal, the louder the signal gets because of duplication. How do I regulate the loudness? Do I need to chain chnset a2, "signal" in each instrument and have one final instrument receiving the signal and outputting it, or do I divide the signal value by the number of instruments playing?

I’m trying the “chaining” of chnset and chnget and this is what I have so far for the only instrument outputting sound. I plan to have smaller versions of these conditional blocks in the effect instruments to combine effects.

instr output
    ; determine where to get signal
    if gkFX1Trigger == 1 then
        a1 chnget "signal1FX1"
        a2 chnget "signal2FX1"
    elseif gkFX2Trigger == 1 then
        a1 chnget "signal1FX2"
        a2 chnget "signal2FX2"
    elseif gkFX3Trigger == 1 then
        a1 chnget "signal1FX3"
        a2 chnget "signal2FX3"
    elseif gkFX4Trigger == 1 then
        a1 chnget "signal1FX4"
        a2 chnget "signal2FX4"
        a1 chnget "signal1Clean"
        a2 chnget "signal2Clean"

    ; output signal
    outs a1, a2

This is the only way I found chnget to work properly, because it only takes the channel name string once at i-time I think. Going to continue finishing this chain, but is there a better way of doing this? :sweat_smile:

Hmmm, separating out the effects and triggering them actually made the clicking worse. It was fun to develop but this is disappointing. The main issue is that I am switching through effects very quickly in a sequence and there is bound to be clicking because I have to keep the attack very short to maintain volume. The hope was that this could mitigate it as much as possible. This is what I did:

  1. Made all of the effect instruments trigger on an event. There is clicking every time an effect is enabled.
  2. Instead kept the effects in separate instruments but constantly running, triggering the switch in signal channels instead. Same results as having all effects in one instrument, understandably. There is only clicking on 2 effects out of 4, as I started out with.
  3. Instead made the main output instrument have an envelope and trigger on an event at each step of the sequence. There is clicking every time the step of the sequence changes, understandably because its the same process of triggering an instrument in short succession as the first attempt. There is a gated effect because of the envelope, which is cool and I don’t mind, but it doesn’t fix the clicking.

I guess I have to just deal with it and roll back my changes. I can share my code of before and after making the changes to show the problem.

They shouldn’t be any clicking if you use envelopes for each instrument like in my example? But if you dynamically route audio to those effects you’ll need to also apply some kind of fade. You can do something like this…

routing.csd (1.6 KB)

1 Like

The code examples work very well, but for my purposes, I’m not just not able to provide that many milliseconds :joy:. I am using attack envelopes of 0.05 seconds, and would need to apply the fade within the same time amount. It otherwise heavily mutes the 32nd notes I am using to trigger the effect changes.

But thank you for being with me in this entire process! Hopefully this might help someone else who is looking to find smooth transitions between different streams of audio.

I should’ve prefaced this question with how my plugin works, but my test code is here below for archiving sake. (40.1 KB)

I just tested this with fade IO times of 0.01 and it still works fine without any clicks?

1 Like

Then it may be an entirely different issue I haven’t identified :confused:
Using the plugin in the DAW has less transient clicks, so maybe it’s my setup in Cabbage…

Strange. What is your ksmps set to?

I don’t have it hardcoded, but it gets calculated to 32. I have my FocusRite Scarlett 4i4 audio interface connected using the FocusRite USB ASIO at 44,100 Hz with a buffer rate of 512 samples (11.6 ms delay). I use the same settings for my DAW with no issues.

Csound output when running the plugin:

UnifiedCSD:  C:\Users\Me\Projects\BadHumors\BadHumors.csd
rtaudio: PortAudio module enabled ...
using callback interface
rtmidi: PortMIDI module enabled
instr startup uses instrument number 1
instr main uses instrument number 2
instr sequencer uses instrument number 3
instr effects uses instrument number 4
Elapsed time at end of orchestra compile: real: 0.010s, CPU: 0.011s
sorting score ...
	... done
Elapsed time at end of score sort: real: 0.010s, CPU: 0.011s
--Csound version 6.18 (double samples) Nov 23 2022
[commit: a1580f9cdf331c35dceb486f4231871ce0b00266]
displays suppressed
sr = 44100.0, kr = 1378.125, ksmps = 32
0dBFS level = 1.0, A4 tuning = 440.0
orch now loaded
audio buffered in 4096 sample-frame blocks
Cabbage version:2.9.0
new alloc for instr startup:
new alloc for instr main:
new alloc for instr effects:
ftable 101:
ftable 102:
ftgenonce: created new func: 102
ftgenonce: re-using existing func: 102.000000

That’s strange, I’m getting no clicks here :thinking: