Cabbage Logo
Back to Cabbage Site

Continuous display of audio data

Hi!
I’d like to display the amplitude of my input signal in real-time as shown in this video at 00:16: https://youtu.be/aLdyFhaCbKA

As you can see the display is scrolling towards a direction and the input is written immediately, moving the index in which is saved sample-per-sample. That graph in the video have been made with Max Jitter/OpenGL object jit.gl.graph.

This topic have previously privately discussed with Rory.

Thank you very much!

Rory provided this code:

<Cabbage>
form caption("Untitled") size(400, 300), colour(58, 110, 182), pluginid("def1")

gentable bounds(2, 6, 393, 199), tablenumber(1), fill(0), identchannel("table1")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d 
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 64
nchnls = 2
0dbfs = 1

instr 1
    a1 inch 1
    aRand randi 1, 200
    kSig downsamp aRand

    kIndex linseg 256, 10, 0, 0, 0
    tabw kSig, kIndex, 1

    kCnt = 256
    if metro(10) == 1 then
        if kIndex == 0 then
            while kCnt>0 do
                kSample tab kCnt-1, 1
                tabw kSample, kCnt, 1 
                kCnt-=1
            od
        endif
        chnset "tablenumber(1)", "table1"
    endif
endin

</CsInstruments>
<CsScore>
f1 0 256 7 0 256 0
;causes Csound to run for about 7000 years...
f0 z
;starts instrument 1 and runs it for a week
i1 0 [60*60*24*7] 
</CsScore>
</CsoundSynthesizer>

which works very close to the result I’d like to obtain.
It’s a little slow in drawing, so I’ve raised the metro to (50) and set the ksmps = 16.

The other problem is that the downsample opcode seems to cause the signal to not be written correctly. I tried to substitute the random function with my input “inch 1” but there are strange glitches: the correct peak is shown for an instant and erased a moment after.
For instance, tapping on my computer’s mic I should see a very high peak on the graph, but I don’t.
Also when tapping at my highest continuously to see when and what it is drawing it seems to pick the peaks very randomly, again for the downsample opcode probably.

Thank you again!

1 Like

Ok, I can try to make some changes here. For now I was just curious to see if this was heading in the right direction! I would probably write a UDO so I can run ksmps as 1. I will try that for you later.

Awesome, very nice from you, thank you so much!

How about this one. I tested with live mic input and it seems to work ok better now, but perhaps still not quite good enough…

<Cabbage>
form caption("Scrolling waveform") size(400, 300), colour(58, 110, 182), guiresfresh(32), pluginid("def1")

gentable bounds(2, 6, 393, 199), tablenumber(1), fill(0), identchannel("table1")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d 
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 64
nchnls = 2
0dbfs = 1


opcode ScrollTable, 0, aikiS
    setksmps 1
    aSig, iTable, kRate, iScrollPoint, SChannel xin
    kSig = aSig
    kIndex linseg ftlen(iTable), 5, iScrollPoint, 0, iScrollPoint
    tabw kSig, kIndex, 1
    STableString sprintf "tablenumber(%d)", iTable

    kCnt = ftlen(iTable)
    if metro(kRate) == 1 then
        if kIndex == iScrollPoint then
            while kCnt>iScrollPoint do
                kSample tab kCnt-1, 1
                tabw kSample, kCnt, 1 
                kCnt-=1
            od
        endif
        chnset STableString, SChannel
    endif
endop


instr 1
    a1 inch 1
                ;sig    table   update rate     scroll point    table channel
    ScrollTable a1,     1,      32,             64,             "table1"
endin

</CsInstruments>
<CsScore>
f1 0 256 7 0 256 0
;causes Csound to run for about 7000 years...
f0 z
;starts instrument 1 and runs it for a week
i1 0 [60*60*24*7] 
</CsScore>
</CsoundSynthesizer>

It seems better but still imprecise and the glitch is always there. It should work since you set the ksmps to 1…
Don’t know :confused:

What about this one. When I play it I don’t see any issues with peaks be misrepresented? Sorry, I don’t have a mic right now because I moved location! But I have a feeling that the update rates really aren’t high-res enough for what you want. Note that the peaks are those which Csound records directly into a table. If Cabbage misses some of these it’s due to the screen res or size of the widget. Can you try changeing the dimensions of the widgets to see if anything improves?

<Cabbage>
form caption("Scrolling waveform") size(400, 300), colour(58, 110, 182), guiresfresh(32), pluginid("def1")

gentable bounds(2, 6, 393, 199), tablenumber(1), fill(0), identchannel("table1")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d 
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 64
nchnls = 2
0dbfs = 1


opcode ScrollTable, 0, aikiS
    setksmps 1
    aSig, iTable, kRate, iScrollPoint, SChannel xin
    kSig = aSig
    kIndex linseg ftlen(iTable), 5, iScrollPoint, 0, iScrollPoint
    tabw kSig, kIndex, 1
    STableString sprintf "tablenumber(%d)", iTable

    kCnt = ftlen(iTable)
    if metro(kRate) == 1 then
        if kIndex == iScrollPoint then
            while kCnt>iScrollPoint do
                kSample tab kCnt-1, 1
                tabw kSample, kCnt, 1 
                kCnt-=1
            od
        endif
        chnset STableString, SChannel
    endif
endop


instr 1
    a1 inch 1
    a1 = oscili(1, 200)*tab(phasor:a(1), 2, 1)
                ;sig    table   update rate     scroll point    table channel
    ScrollTable a1,     1,      32,             64,             "table1"
endin

</CsInstruments>
<CsScore>
f2 0 1024 7 0 256 1 [256*3] 0 
f1 0 256 7 0 256 0
;causes Csound to run for about 7000 years...
f0 z
;starts instrument 1 and runs it for a week
i1 0 [60*60*24*7] 
</CsScore>
</CsoundSynthesizer>

Hi,

Here is the code Rory provided with little tweaks to update the syntax and scroll from left to right with no margin. I’m sure it can be improved, please let me know if you see how it could be improved, but it’s already working well!

<Cabbage>
form caption("Scrolling waveform") size(400, 300), colour(58, 110, 182), guiMode("queue"), pluginid("def1") 

gentable bounds(2, 6, 393, 199), tableNumber(1), fill(0), channel("table1")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d 
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 64
nchnls = 2
0dbfs = 1


opcode ScrollTable, 0, aikiS
    setksmps 1
    aSig, iTable, kRate, iScrollPoint, SChannel xin
    kSig = aSig
    kCnt = 0
    kIndex linseg 0, 8, ftlen(iTable), 0, ftlen(iTable)
 
    if metro(kRate) == 1 then
        tabw kSig, kIndex, 1
        if kIndex == ftlen(iTable) then
            while kCnt<ftlen(iTable) do
                kSample tab kCnt+1, 1
                tabw kSample, kCnt, 1 
                kCnt+=1
            od
        endif
    endif
    
endop

instr drawGentable
    cabbageSet      "table1", "tableNumber", 1
endin
instr 1
    a1 inch 1
    
    a1 = oscili(1, 200)*tab(phasor:a(1), 2, 1)
    ;a1 follow2 a1, 0.01, 0.01
    ScrollTable a1,     1,      32,             0,             "table1"
                ;sig    table   update rate     scroll point    table channel
    event "i", "drawGentable" , 0, 0.0008
    
    outs a1, a1
endin

</CsInstruments>
<CsScore>
f2 0 1024 7 0 256 1 [256*3] 0 
f1 0 256 7 0 256 0
;causes Csound to run for about 7000 years...
f0 z
;starts instrument 1 and runs it for a week
i1 0 [60*60*24*7] 
</CsScore>
</CsoundSynthesizer>

Ha, I’m looking forward to testing this. The last post was 5 years ago :joy:

Hi @rorywalsh,

For some reasons, the minimal example above crashes with the latest version of Cabbage (from Aug 9)
I tried a few versions but couldn’t find any version not crashing… I also tries with v 2.9.227 and 2.9.224. It’s weird that it’s suddenly not working… I can’t understand what’s happening.

I wasn’t able to output any log so I don’t have much context regarding the crash. It runs for like 20ms and then stops working and Cabbage crashes. Same issue when I export in VST and load the VST in Live.

I confirm the code works when I comment the gentable line.

Thanks,

Julien

So you’re trying to redraw the table almost 700 times a second. Not only is a waste of resources, most of those updates won’t actually get displayed. You’ll remove the crash if you wrap the update code like this:

if metro(20) == 1 then
    event "i", "drawGentable" , 0, 0.0008
endif

This is the second time something like this has popped up in the past month or so. I may well have done something to break the old behaviour, but regardless, you should try to be careful about how often you trigger a UI update.

1 Like

Thank you! It’s working perfectly!
I guess the old behavior was hiding my mistake…

Thanks :slight_smile:

It’s one of the main reasons I added an update trigger argument to the cabbageSet opcodes. It makes it a little less likely that people will update the UI on every k cycle, :+1:

1 Like

Hi Rory,

FYI I added a label that is updated everytime the values of a hrange change.
Here is how I do it (I only left the code to update the label, I removed the gentables and the dsp stuff):

<Cabbage>
;----------
; container     
;----------  
 
form caption("Bug") pluginId("AS14") size(840, 500), guiMode("queue"), colour(200,200,200) 

label bounds(35, 288, 178, 22) channel("leftEqValue")  text("[eq mode deactivated]") ,fontSize(24), fontColour(0, 0, 0, 255)

hrange bounds(34, 268, 176, 27), channel("FreqMinAttack", "FreqMaxAttack"), _info("Frequency range of the attack transient shaping (uses a bell curve)"), range(1, 25000, 1:400, 0.3, 1) valueTextBox(0) trackerBackgroundColour(0,0,0,0)  trackerBackgroundColour(0,0,0,0) colour(20,20,20,0)  outlineColour(100,100,100) trackerThickness(2)  outlineColour(100,100,100) trackerThickness(2)  

</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d --displays 
</CsOptions> 
<CsInstruments> 
ksmps  =  64
nchnls =  2
0dbfs  =  1

instr 1

    ; --- values
    kFreqMinAttack, kMinEqAttackTrigger cabbageGetValue "FreqMinAttack"
    kFreqMaxAttack, kMaxEqAttackTrigger cabbageGetValue "FreqMaxAttack"

    StxtEqAttack sprintfk "[%d Hz - %d Hz]", kFreqMinAttack, kFreqMaxAttack
    ; test 1
    cabbageSet max(kFreqMinAttack, kFreqMaxAttack), "leftEqValue", "text", StxtEqAttack

endin 

</CsInstruments>

<CsScore>
i 1 0 [60 * 60 * 24 * 7] 
f1 0 256 7 0 256 0
</CsScore>

</CsoundSynthesizer> 

This code works well, but not in the context of my plugin. When I comment the gentable declaration in my plugin code, it works well, but when I add the gentable back, it crashes after a few seconds when I play with the hrange. I suspect it’s a performance issue… Even when I update the hrange with metro(20) or metro(10), it crashes, but a bit later.

Do you know what could happen? My plugin probable requires too much CPU, and that might cause the issue, but let’s add a gentable to the example above and see what it does:

;---------- ; container ;----------

form caption(“Bug”) pluginId(“AS14”) size(840, 500), guiMode(“queue”), colour(200,200,200)

label bounds(35, 288, 178, 22) channel(“leftEqValue”) text("[eq mode deactivated]") ,fontSize(24), fontColour(0, 0, 0, 255)

hrange bounds(34, 268, 176, 27), channel(“FreqMinAttack”, “FreqMaxAttack”), _info(“Frequency range of the attack transient shaping (uses a bell curve)”), range(1, 25000, 1:400, 0.3, 1) valueTextBox(0) trackerBackgroundColour(0,0,0,0) trackerBackgroundColour(0,0,0,0) colour(20,20,20,0) outlineColour(100,100,100) trackerThickness(2) outlineColour(100,100,100) trackerThickness(2)

gentable bounds(266, 160, 300, 71), tableNumber(1), fill(0), channel(“table1”), tableGridColour(152, 0, 0, 0) tableBackgroundColour(15, 15, 15, 0) tableColour:0(255, 255, 255, 255)

</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d --displays 
</CsOptions> 
<CsInstruments> 
ksmps  =  64
nchnls =  2
0dbfs  =  1

opcode ScrollTable, 0, aikiS
    setksmps 1
    aSig, iTable, kRate, iScrollPoint, SChannel xin
    kSig = aSig
    kCnt = 0
    kIndex linseg 0, 3.7, ftlen(iTable), 0, ftlen(iTable)
 
    if metro(kRate) == 1 then
        tabw kSig, kIndex, 1
        if kIndex == ftlen(iTable) then
            while kCnt<ftlen(iTable) do
                kSample tab kCnt+1, 1
                tabw kSample, kCnt, 1 
                kCnt+=1
            od
        endif
    endif
    
endop

instr drawGentable
    cabbageSet      "table1", "tableNumber", 1
endin

instr 1

    ; --- values
    kFreqMinAttack, kMinEqAttackTrigger cabbageGetValue "FreqMinAttack"
    kFreqMaxAttack, kMaxEqAttackTrigger cabbageGetValue "FreqMaxAttack"

    StxtEqAttack sprintfk "[%d Hz - %d Hz]", kFreqMinAttack, kFreqMaxAttack
    ; test 1
    cabbageSet max(kFreqMinAttack, kFreqMaxAttack), "leftEqValue", "text", StxtEqAttack
    
    if metro(1) == 1 then
        event "i", "drawGentable" , 0, 0.0008
    endif

endin 

</CsInstruments>

<CsScore>
i 1 0 [60 * 60 * 24 * 7] 
f1 0 256 7 0 256 0

</CsScore>

</CsoundSynthesizer> 

Of course it doesn’t display anything but the goal is to test this empty skeleton. I played with it 20 secs and can reproduce this bug (in my plugin is takes like 3 seconds though…)

See the video below, crash occuring at 8 sec, the mouse pointer should be the wheel spinning but the screen recorder didnt capture that:

Do you know what could be the cause and how I could investigate? There are no logs so it’s hard to spot the issue.

Thank you :slight_smile:

I’ve just being playing with this for the last 2 minutes and I can’t get it to crash :thinking:

[edit] I made myself a cup of coffee, and when I returned it had crashed :woman_facepalming:

I tried it again, and I confirm I was able to reproduce the bug two times. It takes around 15-20 sec but is faster in the context of my plugin (more cpu usage?).

I wonder if I’m hitting an edge case that could cause the bug … But the values causing the bug are random so I don’t think that’s the case.

EDIT: I saw your edit. Actually I had the issue in Live (without the hrange / label updates, but I was doing something else and then I realized the VST crashed). I suspect the gentable causes the issue but I need to do more tests to confirm that. I’ll export a build without the gentable and test it to see if it helps.

In my tests it appears to have something to do with the call to cabbageSet. If I take that out I no longer get the crash…

I confirm I don’t get the crash when I comment the “cabbageSet” line in the drawTable instr

It’s odd. The crash looks to be coming from a threading issue. On the audio thread we update the internal data struct. This happens when cabbageSet is called. It is then accessed on the message thread when the UI is being updated. The data structure is protected with locks, so there should be any race conditions. Maybe I’ve overestimated the juce::Array/CtricialSection class…

The simple solution is to choke the updates. Can you try something like this:

kUpdate  = changed:k(samphold:k(max(kFreqMinAttack, kFreqMaxAttack), metro(20)))
cabbageSet kUpdate, "leftEqValue", "text", StxtEqAttack

this will choke the update to 20 per second.

The more robust solution, and one I’ve already implemented in Cabbage 3 is to use a lock free fifo when passing data between the audio and message thread. I’m not sure I want to go to the trouble doing this in Cabbage 2. It would be quite a lot of work.