Cabbage Logo
Back to Cabbage Site

Changing audio buffer size in ftgen?

I will try it :+1:

If I do something like this:

opcode Reverse, a, aiiki

    setksmps 1
    
    aIn, iFn, iEnvTable, kLength, iOffset  xin
    kTableLength = int(ftlen(iFn)*kLength)
    
    kWritePointer init 0
    kReadPointer init 0
    kOffset init 0
    aEnvPhs init 0
    
    
    if changed(kTableLength) == 1 then
            reinit Reset
    endif
    
    Reset:
    kWritePointer init 0
    kReadPointer init 0
    kOffset init 0
    aEnvPhs init 0

    if kOffset != iOffset then
        kOffset vdelayk kOffset + iOffset, (iOffset*(kTableLength/sr)), 10
    endif

    if kOffset == iOffset then      
        tablew aIn, a(kReadPointer), iFn  
        aSignal table  kTableLength-a(kReadPointer), iFn
    
        kWritePointer = kWritePointer < kTableLength ? kWritePointer + 1 : 0
        kReadPointer = kReadPointer < kTableLength ? kReadPointer + 1 : 0
        
        aEnvPhs phasor (sr/(kTableLength))
        aEnv table aEnvPhs*2, iEnvTable, 1, 0, 1
    endif
    aout vdelay aSignal*aEnv, ((iOffset*(kTableLength/sr))*1000), 10000 
    xout aout
endop

It just ends up looping the same buffer of audio twice in a row with a offset of 0.5 :thinking:

I also tried delaying the envelope to half a cycle like this:

        aEnvPhs phasor (sr/(kTableLength))
        aEnv table aEnvPhs, iEnvTable, 1, 0, 1 
        aEnv vdelay aEnv, ((kTableLength/sr)/2)*1000, 10000

but no dice…

Here’s offsetting by samples instead of a float between 0 and 1…

<Cabbage> bounds(0, 0, 0, 0)
form caption("Reverse") size(400, 300), guiMode("queue"), colour(58, 110, 182), pluginId("def1")
rslider bounds(26, 28, 60, 60) channel("length") range(0, 1, 1, 1, 0.1), text("Length")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d --midi-key=4 --midi-velocity-amp=5
</CsOptions>
<CsInstruments>
ksmps = 32
nchnls = 2
0dbfs = 1

giTableLen = 2^16

giTableL1 ftgen  0, 0, giTableLen, 7, 0, giTableLen, 0
giTableL2 ftgen  0, 0, giTableLen, 7, 0, giTableLen, 0
giTableR1 ftgen  0, 0, giTableLen, 7, 0, giTableLen, 0
giTableR2 ftgen  0, 0, giTableLen, 7, 0, giTableLen, 0
giEnvTable ftgen  0, 0, giTableLen, 9, 0.5, 1, 0

opcode Reverse, a, aiiki

    setksmps 1
    
    aIn, iFn, iEnvTable, kLength, iOffset  xin
    kTableLength = int(ftlen(iFn)*kLength)
    
    kWritePointer init 0
    kReadPointer init 0
    kOffset init 0
    aEnvPhs init 0
    
    
    if changed(kTableLength) == 1 then
            reinit Reset
    endif
    
    Reset:
    kWritePointer init 0
    kReadPointer init 0
    kOffset init 0
    aEnvPhs init 0
    
    kOffset_Sec = (iOffset/sr)/2
    
    if kOffset != kOffset_Sec then
        kOffset vdelayk kOffset + kOffset_Sec, kOffset_Sec, 10
    endif

    if kOffset == kOffset_Sec then      
        tablew aIn, a(kReadPointer), iFn  
        aSignal table  kTableLength-a(kReadPointer), iFn
    
        kWritePointer = kWritePointer < kTableLength ? kWritePointer + 1 : 0
        kReadPointer = kReadPointer < kTableLength ? kReadPointer + 1 : 0
        
        aEnvPhs phasor (sr/(kTableLength))
        aEnv table aEnvPhs*2, iEnvTable, 1, 0, 1 
    endif
    
    xout aSignal*aEnv
endop

instr 1
kLength cabbageGetValue "length"

a1 inch 1
a2 inch 2

aRevL1 Reverse a1, giTableL1, giEnvTable, kLength, 0
aRevL2 Reverse a1, giTableL2, giEnvTable, kLength, giTableLen/2

aRevR1 Reverse a2, giTableR1, giEnvTable, kLength, 0
aRevR2 Reverse a2, giTableR2, giEnvTable, kLength, giTableLen/2

outs aRevL1 + aRevL2, aRevR1 + aRevR2

endin

</CsInstruments>
<CsScore>
i1 0 z
</CsScore>
</CsoundSynthesizer>

Is this correct?

Let’s split things up as the envelope is doing: Table1[1] & [2] and Table2[1] & [2].

It sounds to me like the second half of Table1[1] and first half of Table2[1] is identical? Same with second half of Table2[1] and first half of Table1[1].

But I am not completely sure, my mind is seriously tangled from this stuff…

Yes, that’s what I was suggesting. It will result in a slight echo sound, but I thought it might be interesting. What about offloading the second delay to a new instrument that starts half a table’s worth of samples behind instrument one? You can still read the same slider channel, but you will need to delay updating it for the second instance, otherwise the two delays will sync up again.

That’s what I’m trying to do with this

 if kOffset != iOffset then
        kOffset vdelayk kOffset + iOffset, (iOffset*(kTableLength/sr)), 10
 endif

Trying to offset the time before the second table starts writing, so that a window with offset is not only a delayed version of the first window, but they have different contents. But the issue with the last one (2 replys up), is that it works quite nicely, but :

It sounds to me like the second half of Table1[1] and first half of Table2[1] is identical? Same with second half of Table2[1] and first half of Table1[1].

Anyway, I landed on this being the final solution:

<Cabbage> bounds(0, 0, 0, 0)
form caption("Reverse") size(400, 300), guiMode("queue"), colour(58, 110, 182), pluginId("def1")
rslider bounds(26, 28, 60, 60) channel("length") range(0, 1, 1, 1, 0.1), text("Length")
gentable bounds(154, 118, 189, 138), , outlineThickness(3), tableNumber(90.0), tableGridColour(155, 155, 155, 255) tableBackgroundColour(0, 0, 0, 0) tableColour:0(147, 210, 0, 255)
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d --midi-key=4 --midi-velocity-amp=5
</CsOptions>
<CsInstruments>
ksmps = 32
nchnls = 2
0dbfs = 1

giTableLen = 2^16

giTableL1 ftgen  0, 0, giTableLen, 7, 0, giTableLen, 0
giTableL2 ftgen  0, 0, giTableLen, 7, 0, giTableLen, 0
giTableR1 ftgen  0, 0, giTableLen, 7, 0, giTableLen, 0
giTableR2 ftgen  0, 0, giTableLen, 7, 0, giTableLen, 0
giEnvTable  ftgen 90, 0, 8192, 20, 1, 1

opcode Reverse, a, aiiki

    setksmps 1
    
    aIn, iFn, iEnvTable, kLength, iOffset  xin
    kTableLength = int(ftlen(iFn)*kLength)
    
    kWritePointer init 0
    kReadPointer init 0
    kOffset init 0
    aEnvPhs init 0

    if changed(kTableLength) == 1 then
            reinit Reset
    endif
    
    Reset:
    kWritePointer init 0
    kReadPointer init 0
    kOffset init 0
    aEnvPhs init 0
    kOffset_Sec init 0

    kOffset_Sec = (iOffset/sr) * kLength
     
    if kOffset != kOffset_Sec then
        kOffset vdelayk kOffset + kOffset_Sec, kOffset_Sec, 10
    endif

    if kOffset == kOffset_Sec then      
        tablew aIn, a(kReadPointer), iFn  
        aSignal table  kTableLength-a(kReadPointer), iFn
    
        kWritePointer = kWritePointer < kTableLength ? kWritePointer + 1 : 0
        kReadPointer = kReadPointer < kTableLength ? kReadPointer + 1 : 0
        
        aEnvPhs phasor (sr/(kTableLength))
        aEnv table aEnvPhs*2, iEnvTable, 1, 0, 1 

    endif

    xout aSignal*aEnv
      
endop

instr 1
kLength cabbageGetValue "length"

a1 inch 1
a2 inch 2

aRevL1 Reverse a1, giTableL1, giEnvTable, kLength, 0
aRevL2 Reverse a1, giTableL2, giEnvTable, kLength, giTableLen/4

aRevR1 Reverse a2, giTableR1, giEnvTable, kLength, 0
aRevR2 Reverse a2, giTableR2, giEnvTable, kLength, giTableLen/4

outs aRevL1 + aRevL2, aRevR1 + aRevR2

endin

</CsInstruments>
<CsScore>
i1 0 z
</CsScore>
</CsoundSynthesizer>

Still I wish I would be able to offset the envelope Table and remove the click by offset instead of doubling the phasor speed, but I guess this is satisfactory.

Hopefully someone else also get’s some use out of it :+1:

1 Like