Cabbage Logo
Back to Cabbage Site

Audio dropouts with ftload/ftloadk

I am triggering ftloadk to load tables from txt files (with unlatched button). The loading is done within an always on instrument separate from the audio generating instrument(s).

I am getting audio dropouts when I load a table and when sound is playing.

This is happening also if I use a dummy table (csd below), which is not used in the actual sound generating instrument. Noticeable with VST3 inside DAWs at lower buffer sizes (Live, Reaper) but not in Cabbage IDE (at buffer size the same as in DAW). I have also tried a version with ftload and reinit with the same results. The dropout threshold depends on table size and how much is happening in the plugin. In the example below I need quite large tables to notice the problem.

An obvious solution seems to be to load all tables at the init stage or pack all the values inside a single txt file / table and then virtually switch tables by appropriate indexing.

I am curious if anyone had similar experiences or has any suggestions how to avoid dropouts when loading txt files to tables while sound is playing. Why is this happening? I was assuming the audio thread would be independent from reading tables? I am probably missing something and there is likely a better way of handling tables than in my example below?

<Cabbage>
form caption("test instrument") size(370, 280) colour(58, 110, 182) pluginId("tins") guiMode("queue")
button bounds(84, 78, 40, 30) channel("Set") text("SET", "SET") latched(0) corners(2) colour:0(100, 80, 0, 255) colour:1(255, 255, 0, 255) fontColour:1(0, 0, 0, 255) _toSL(1) _MAP(1)

</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-d -n -+rtmidi=null -M0 -m0d
</CsOptions>
<CsInstruments>

ksmps = 16
nchnls = 2
0dbfs = 1

giTable ftgen 0, 0, 2^16, -2, 0

instr 1

Spath = sprintf("%s/%s", chnget:S("CSD_PATH"), "table.txt")
ftsave Spath, 1, giTable ;  save a dummy table

kSet, kSetChanged cabbageGetValue "Set"
ftloadk Spath, kSet*kSetChanged, 1, giTable ; press SET to load

endin


instr 888
a1 poscil .02, 440
gaL += a1
gaR += a1
endin


instr 999
outs gaL, gaR	
clear gaL, gaR
endin

</CsInstruments>
<CsScore>
i1 0 z 
i 888 0 -1 
i 999 0 -1 

</CsScore>
</CsoundSynthesizer>

Not sure if it helps, but I had similar audio issues when clearing large tables. My assessment was that it was taking a lot of resources and the playback glitched as a result. I ended up trying another approach.

How big are these text files? I was dealing with about a minute of audio at 24 bit, 48 kHz.

Try adding --realtime to your CsOptions. Csound will then attempt to load all resources in a separate thread. From the manual:

--realtime

realtime priority mode is switched on which the following effects:

1. all opcode audio file reading/writing is handled asynchronously by a separate thread.
2. all init-pass operations are also performed asynchronously.

Thank you for suggestions!
The --realtime option doesn’t seem to affect my csd example. Good to be aware of the option though :slight_smile:

However, I noticed another thing: the dropouts are audiable but they don’t get recorded, so since I don’t hear them in Cabbage IDE and they are not recorded this seems more like a DAW issue :thinking:
Maybe something could be done in e.g. Reaper?

Just to reiterate my previous post: the dropouts in DAW start when the table size is large enough relative to how busy the plugin is and what the buffer size is. With the almost still example above, this happens at 128 buffer size for tables of e.g. 2^16 length. On M1 mac (MacOS 12.6.1).

How about instead of saving and loading the tables as text files, you write when as audio files instead?

What would be the advantage of audio files? Maybe they take less time to load?

I am still puzzled why loading tables interrupts audio in DAW, but the recorded waveform has no glitches.

I make a varying number of tables containing scale frequencies outside (with Python) and use the file names to display info about the loaded file (scale). I have now adapted my code, so I first read and copy all the files one by one into a large function table (at init) via a temporary function table and construct an array of strings from file names. Then I can index the large table and the strings as if I had separate tables. The large table and string array size is determined on the fly depending on the number of files. This seems to work without glitches. One disadvantage is a bit of extra memory for one temporary function table, but that seems irrelevant. I could externally make one single table and manually construct the string array, but the way I did it suites my workflow better for now. However, I am curious if audio files would be better for this?

Is there a reason you want Python to synthesize the sounds? You might consider having Python generate the Csound score (what instrument plays what notes and when) and let Csound do the synthesis.

I’m just making tables with Python (or Octave/Matlab) for microtonal Csound instruments that are played in real-time (not scored).

BTW. This issues could be relevant for completely different cases, for example if a large enough function table is used to handle presets of complex instruments. I use my custom preset handling methods relaying on function tables, which I find more flexible for some extreme cases :wink:

I was confused because you mentioned “scale” when talking about Python. That sounded like a set of pitches.

I am not sure if audio files will work better, but I think with realtime mode set they might. Also, in my libsndfile is extremely efficient at reading files from disk.

I finally got around to trying this … instant crash from Cabbage on my big project. I’ll need to spend some time trying to figure out what trips it up.

I see. I shall try this.

I’m not familiar with libsndfile, but I shall read more on Github. It seems interesting and useful! Maybe for some future multidimensional looper projects :slightly_smiling_face:
Could you refer to some examples? Thanks!

This seems like an unrelated issue? Maybe is crashing due to weird strings (too long, special characters…), maybe check paths and permissions…

It’s the library that Csound uses for all its audio file stuff. you don’t need to access it separately. It’s built in :+1:

1 Like

i prefer ftload over ftloadk. just make separate instrument and trigger it to load with ftload. What i rearn about csound is always use i when its possible, k only when necessary .

This is a good thing to try too. The --realtime flag only works when loading audio files, or during init passes. Switching to loading at i-time might make things smoother.