Cabbage Logo
Back to Cabbage Site

What's wrong with my glitchy sampler?

I am trying to implement Casio SK-1 style sampler in Cabbage. I thought most hard part will be getting that oldschool lofi sound but it turns out I cannot get clean sound without glitching.

What’s wrong with my code?

<Cabbage>
form caption("KASIA SK1") size(400, 300), colour(51, 51, 51), guiMode("queue"), pluginId("ksk1")
keyboard bounds(8, 158, 381, 95)
checkbox bounds(278, 12, 100, 30) channel("rec") text("RECORD") colour:1(255, 0, 0, 255) colour:0(118, 0, 0, 255) 
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 --midi-key-cps=4 --midi-velocity-amp=5
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 32
nchnls = 2
0dbfs = 1

; RAM filled with zeros
giRAM  ftgen 0, 0, 2*sr, 2, 0

;instrument will be triggered by keyboard widget
instr 1
    kbnd pchbend 0, 100
    kcps = p4 + kbnd
    kvel = p5

    kEnv madsr .1, .2, .6, .4
    ;aOut vco2 p5, p4
    aOut poscil3 0.5, kcps, giRAM
    outs aOut*kEnv, aOut*kEnv
endin

gkRecDur    init    0
giTableLen init 0

instr GUI ; checks controls panel
    prints "SR = %d\n", sr
    giTableLen ftlen giRAM
    
    kRec, kRecTrig cabbageGetValue "rec"
    if kRecTrig==1 && kRec==1 then
        printks "REC!\n", 1
        event "i", "Record", 0, 3
        event "i", "beep", 3, 0.5
    endif
    
endin



instr beep ; played out when sampling stops
    aOut vco2 0.3, 440, 12
    outs aOut, aOut
    prints "gkRecDur = %d\n", gkRecDur
endin


; this does sampling itself
instr    Record 
    ;if    gkPause=1    goto SKIP_RECORD        ;IF PAUSE BUTTON IS ACTIVATED TEMPORARILY SKIP RECORDING PROCESS

        ainL,ainR    ins                    ;READ AUDIO FROM LIVE INPUT CHANNEL 1
        aRecNdx    line        0,giTableLen/sr,1    ;CREATE A POINTER FOR WRITING TO TABLE - FREQUENCY OF POINTER IS DEPENDENT UPON TABLE LENGTH AND SAMPLE RATE
        aRecNdx    =        aRecNdx*giTableLen    ;RESCALE POINTER ACCORDING TO LENGTH OF FUNCTION TABLE 
        gkRecDur    downsamp    aRecNdx            ;CREATE A K-RATE GLOBAL VARIABLE THAT WILL BE USED BY THE 'PLAYBACK' INSTRUMENT TO DETERMINE THE LENGTH OF RECORDED DATA            
              tablew        ainL,  aRecNdx, giRAM;WRITE AUDIO TO AUDIO STORAGE TABLE
        ;      tablew        ainR*gkInGain,  aRecNdx, gistorageR;WRITE AUDIO TO AUDIO STORAGE TABLE
        if    gkRecDur>=giTableLen    then            ;IF MAXIMUM RECORD TIME IS REACHED...
            kRecord=0
            printks "REC END\n", 1
            printks "gkRecDur = %d", 1, gkRecDur
        endif                        ;END OF CONDITIONAL BRANCH
        
        if changed(release())==1 && release()==1 then
            printks "OUT\n", 1
        endif
    ;SKIP_RECORD:
endin



</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z

i "GUI"  0 z 

</CsScore>
</CsoundSynthesizer>

It records from input but recorded sound sounds very metalic and to me it sounds like there is some issue with sample rates.

I think that the glitches are on account of instr 1 playing back a sample of 2-seconds duration at very high frequencies. Something like this in instr 1, in exchange for the poscil, will produce a more conventional sampler in which C3 on the keyboard plays the recording back untransposed.

giTableLen ftlen giRAM
aPhs line        0,(giTableLen/sr) * (cpsmidinn(60)/p4),1
aOut tablei      aPhs, giRAM, 1
1 Like

Works great! Thanks!

However I am wondering why poscil does work with table created in this style giPiano ftgen 0, 0, 0, 1, "akwf/AKWF_piano_0001.wav", 0, 0, 0 but not one recorded with tablew.

(I am able to work around with ifs but I want to understand what is going on here.)

poscil can still work with the recorded table, you just need to scale kcps down, as if I play middle C, it is going to repeat your 2-seconds of audio 261 times a second. Something like this will work:

aOut poscil3 0.5, kcps/cpsmidinn(60), giRAM

By the way, something like this for the pitch bend might be more satisfactory:

kbnd pchbend 0, 2
kcps = p4 * semitone(kbnd)

It will bend the pitch up and down by 2 semitones. Using cycles-per-second directly will mean that the interval up will be smaller than the interval down.

1 Like

Now I understand what was wrong:

I used single cycle samples before which is what (probably) poscil expects but now I am using full recording with multiple samples. kcps parameter of poscil is literally how many times a second I want to play it!

Great! I suspected your piano sample was a single cycle.

One thing I missed: the frequency of the poscil should also be scaled by the duration of the buffer in seconds, so in the case of your 2-second buffer:

aOut poscil3 0.5, kcps/(cpsmidinn(60)*2), giRAM