3 minute read

Siccome sono abbastanza handicappato nell’utilizzo del k-rate in csound e mi perdo sempre qualcosa, ho bisogno di una fase di test solida quando scrivo gli strumenti e l’unico modo (che conosco) su Csound è costruire un sistema di debug solido che non lascia spazio a dubbi sul funzionamento del motore.

Ho preparato un csd per ricordarmi ogni qual volta ho dei dubbi come funzionano i-rate e k-rate. Però è sempre il caso ricordarsi la differenza tra i due:

  • Init‑pass (i‑time): qui vengono eseguiti tutti gli opcodes e le assegnazioni consentite solo a i‑rate; succede una sola volta quando lo strumento viene instanziato.
  • Perf‑pass (k‑rate): qui avviene la generazione audio e il controllo a k‑rate, con cadenza determinata da kr e ksmps. Ogni k‑ciclo Csound aggiorna le k‑variabili e percorre il corpo dello strumento.

Oki grazie Tars per la semplicità di queste parole. Abbiamo bisogno adesso di una leggiadra spiegazione rattoppata delle istruzioni di stampa che ci fornisce il carissimo Csound:

i-rate input particolarità Colonna 4
print uno o piu iarg non è preciso, meglio printf Dati 1,4
prints la stringa e gli iargs richiamati nella stringa   Dati 2,4
k-rate input particolarità
printk itime, kargs stampa valore preceduto da numero dello strumento
printks formato printf() a intervalli definiti non può essere chiamato piu volte nello stesso k-rate. non funziona con i loop, while etc
printsk formato printf() funziona che è una bomba
println formato printf() è printsk ma con \n automatico

poi ci sono printk2 e printks2, le versioni di printk e printks che hanno la peculiarità di stampare solo quando ricevono un bang. molto comodino.

Oki ho preparato questo test.csd molti simpatico. Il log è molto ordinato e comprensibile. Da notare le istruzioni di stampa a init-pass e quelli a perf-pass. Notare printks che stampa solamente al primo giro del loop.

<CsoundSynthesizer>
<CsOptions>
-n
</CsOptions>
<CsInstruments>
;----------------------------------------
; Impostazioni globali
;----------------------------------------
sr     = 96000
ksmps  = 1
nchnls = 2
0dbfs  = 1

;----------------------------------------
; Creazione “tabelle sporche” con GEN02
;----------------------------------------
; GEN02: trasferisce dati dai p-fields in una function table 
gi_active_octaves            ftgen 0, 0, 8,  -2, 60,62,64,65,67,69,71,72
gi_active_registers          ftgen 0, 0, 4,  -2,  1,  2,  3,  4
gi_octave_register_matrix    ftgen 0, 0, 32, -2,  1,2,3,4, 1,2,3,4, 1,2,3,4, 1,2,3,4, 1,2,3,4, 1,2,3,4, 1,2,3,4, 1,2,3,4

;----------------------------------------
; Strumento: pulisce le tabelle a k-rate
;----------------------------------------
; dichiariamo un UDO con 6 parametri k‑rate:
;   kfn, ktrig, kstart, kend, kstep, knumcols

instr AnalizzatoreArmonico
  ; bang a k-rate 10 Hz
  kTrig metro p3*2                         ; metro genera un bang (0→1→0) a k-rate 
  kCurrentTime times                     ; tempo assoluto in secondi a k-rate 
  kcountHowManyIfkTrig init 0 
  ; array di numeri di tabella, k-rate
  iArr[] = fillarray(gi_active_octaves, gi_active_registers, gi_octave_register_matrix)  
  iarrIdx = 0         

  prints "\n===========================================\n"
  prints "\tlet's observe the tables at init-pass\n\n"
  prints "gi_active_octaves\n"
  ftprint gi_active_octaves
  prints "\n"
  prints "gi_active_registers\n"
  ftprint gi_active_registers
  prints "\n"
  prints "gi_octave_register_matrix\n"
  ftprint gi_octave_register_matrix
  prints "\n===========================================\n"
  prints "\tnow let's going on with the if k-rate!\n\n"
  kLenArr = lenarray(iArr)               ; conta quanti elementi (tabelle) 
  kcountHowManyIfkTrig += kTrig
  if kTrig == 1 then                     ; al primo campione di ciascun bang
    println "inside if n° %d\n",kcountHowManyIfkTrig
    kBigIdx = 0                          ; reset contatore esterno
  LoopBig:
    kfn      = iArr[kBigIdx]             ; numero di tabella corrente
    println "\tPRINTSK bigLoop at k-cycle: %d and a-cycle: %d at abs time: %f", kCurrentTime*kr, kCurrentTime*sr, kCurrentTime
    printks "\t\t*PRINTKS bigLoop at k-cycle: %d and a-cycle: %d at abs time: %f)\n\n",0, kCurrentTime*kr, kCurrentTime*sr, kCurrentTime
    kLenTab  = tableng(kfn)              ; lunghezza di quella tabella a k-rate 
    kIdx     = 0                         ; reset contatore interno
  LoopClear:
    println "\t\t%d. PRINTSK LoopClear at k-cycle: %d and a-cycle: %d at abs time: %f", kIdx,kCurrentTime*kr, kCurrentTime*sr, kCurrentTime
    printks "\t\t\t*PRINTKS LoopClear at k-cycle: %d and a-cycle: %d at abs time: %f\n \t\t\t*[[questo print si ripete un sola volta ogni if k-rate]]\n", 0,kCurrentTime*kr, kCurrentTime*sr, kCurrentTime
    println "\n\t\t\t- before cleaning\n\t\t\t\tkIdx: %d, value: %d, kfn: %d\n", kIdx, tablekt(kIdx,kfn), kfn
    tablewkt 0, kIdx, kfn                ; scrive zero nella tabella kfn 
    println "\t\t\t- after cleaning\n\t\t\t\tkIdx: %d, value: %d, kfn: %d\n", kIdx, tablekt(kIdx,kfn), kfn

    loop_lt  kIdx, 1, kLenTab, LoopClear ; ripeti finché kIdx<kLenTab

    loop_lt  kBigIdx, 1, kLenArr, LoopBig ; passa alla prossima tabella
    println "finish if\n\n"  
  endif
endin

</CsInstruments>

<CsScore>
; esegui lo strumento per 3 secondi
i "AnalizzatoreArmonico" 0 1
e
</CsScore>
</CsoundSynthesizer>