ARRAYS
Since Csound 5.14 (see the release note) there is a possibility to use an experimental way of handling arrays, called t-variables (t as table) which are basically vectors of k-variables. In Csound6, the implementation of arrays has been extended considerably and is continuously developing. Please keep an eye on the changes and documentation.
As for now, we will give some examples for t-variables in Csound 5, and sort of preview on arrays in Csound 6.
Csound 5
Initialisation and allocation:
t1 init 10
allocates t1[0] through t1[9], initialised to zero.
t2 init 20, 1
allocates t2[0] through t2[19], initialised to 1
Individual elements can be assigned via
t1[kvar] = ...expression...
and all expressions can contain t1[kexpr]
It is possible to copy a table witht1 = t2
At present there are no global t variables (use ftables).
Interaction with tables
tans copy2ftab tab, kftbl
The copy2ftab opcode takes a t-var and copies the contents to an f-table.
tans copy2ttab tab, kftbl
The copy2ttab opcode takes an f-table and copies the contents to a t-var.
For example if you want to transfer data from one instrument to another, you need to use global f-tables (and there is plenty of other cases where it is necessary to write data from f-table to t-array or vice versa).
EXAMPLE 03E01_Array_to_table.csd
<CsoundSynthesizer> <CsOptions> -odac -d ;Example by Tarmo Johannes </CsOptions> <CsInstruments> sr = 44100 ksmps = 32 nchnls = 1 0dbfs = 1 giTab1 ftgen 0, 0, -6, -2, 10,11,12,13,14,15 giTab2 ftgen 0, 0, -6, -2, 0 instr 1 tvar init ftlen(giTab1) ; declare and initialize array tvar copy2ttab tvar,giTab1 ; copy giTab1 to tvar printk2 tvar[4] tvar[4]=tvar[4]+tvar[3] ; change a value copy2ftab tvar, giTab2 ; write the whole array to the other table turnoff ; stop after 1st k-cycle endin instr 2 index = 0 loophere: ival tab_i index,giTab2 print index,ival loop_lt index, 1, ftlen(giTab2), loophere endin </CsInstruments> <CsScore> i 1 0 0.1 ; must have some duration, since tvar is handled in k-time (percormance pass) i 2 0.2 0 ; here only i-values, no duration needed </CsScore> </CsoundSynthesizer>
Other opcodes with t-variables
plustab - Performs an element by element addition of two vectors.
tans plustab tleft, tright
multtab - Performs an element by element multiplication of two vectors.
tans multtab tleft, tright
maxtab - returns the maximum value in a vector.
kmax maxtab tab
mintab - returns the minimum value in a vector.
kmin mintab tab
sumtab - returns the sum of the elements in a vector.
ksum sumtab tab
scalet - scales the values in a range of a vector.
scalet tab, kmin, kmax[, kleft, kright]
(tab -- table for operation, kmin, kmax -- target minimum and maximum values, kleft, kright -- range of table to use, defaulting to 0 and size of the vector)
pvs2tab - copies spectral data to t-variables.
kframe pvs2tab tvar, fsig
tab2pvs - copies spectral data from t-variables
fsig tab2pvs tvar[,ihopsize, iwinsize, iwintype]
Examples
Example 1: normalize two tables tables to the maximum value of the tables (using maxtab and scalet ) - can be useful for leveling also tables with audio data.
EXAMPLE 03E02_norm_to_max.csd
<CsoundSynthesizer> <CsOptions> -odac ; no -d -allow displays ;Example by Tarmo Johannes </CsOptions> <CsInstruments> sr = 44100 ksmps = 32 nchnls = 1 0dbfs = 1 #define ELEMENTS #5# seed 0 giTab1 ftgen 0,0,-$ELEMENTS,-21,1,100 ; table of random numbers, 5 elements, maximum 100 giTab2 ftgen 0,0,-$ELEMENTS,-21,1,100 instr 1 t1 init $ELEMENTS t2 init $ELEMENTS copy2ttab t1, giTab1 ; f-tables to vectors copy2ttab t2, giTab2 ; find out maxima kmax1 maxtab t1 kmax2 maxtab t2 if (kmax1>kmax2) then scalet t2, 0,kmax1 ; scale to the maximum of the higer table printks "Vector 1 has higer maximum: %f\n",0, kmax1 copy2ftab t2, giTab2 ; and write it back to f-table else scalet t1, 0,kmax2 ; scale to the maximum of the higer table printks "Vector 2 has higer maximum %f\n",0, kmax2 copy2ftab t1, giTab1 endif ; output the new values of the vectors kindex=0 loop2: event "i", 2, 0, 0, 1,kindex,t1[kindex] event "i", 2, 0, 0, 2,kindex,t2[kindex] loop_lt kindex,1,$ELEMENTS, loop2 turnoff ; finish after 1 performance pass endin instr 2 ; output values prints "Vector: %d index: %d value: %f\n", p4,p5,p6 endin </CsInstruments> <CsScore> i 1 0 0.1 </CsScore> </CsoundSynthesizer>
Example 2: detect peaks in the signal - save data from FFT analyze to array (pvs2tab), scan the array for peaks and play back sound on the frequencies and amplitudes of the peaks as arpeggio.
EXAMPLE 03E03_FFT_peaks_arpegg.csd
<CsoundSynthesizer> <CsOptions> -odac -d -m128 ; Example by Tarmo Johannes </CsOptions> <CsInstruments> sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 4096, 10, 1 instr getPeaks ; generate signal to analyze kfrcoef jspline 60,0.1,1 ; change the signal in time a bit for better testing kharmcoef jspline 4,0.1,1 kmodcoef jspline 1,0.1,1 kenv linen 0.5,0.05,p3,0.05 asig foscil kenv, 300+kfrcoef,1,1+kmodcoef, 10,giSine outs asig*0.05,asig*0.05 ; original sound in backround ; FFT analyze ifftsize = 1024 ioverlap = ifftsize / 4 iwinsize = ifftsize iwinshape = 1 fsig pvsanal asig, ifftsize, ioverlap, iwinsize, iwinshape ithresh= 0.001 ; detect only peaks over this value tFrames init iwinsize+2 ; declare array kframe pvs2tab tFrames, fsig ; FFT values to array - every even member - amp of one bin, odd - frequency ; detect peaks kindex = 2 ; start checking from second bin, to be able to compare it to previous one kcounter = 0 iMaxPeaks = 13 ; track up to iMaxPeaks peaks ktrigger metro 1/2 ; check after every 2 seconds if (kframe>0 && ktrigger==1 ) then label1: if (tFrames[kindex-2]<=tFrames[kindex] && tFrames[kindex]>tFrames[kindex+2] && tFrames[kindex]>ithresh && kcounter<iMaxPeaks) then ; check with neigbouring amps - if higher or equal than previous amp and more than the coming one, must be peak. kamp = tFrames[kindex] kfreq = tFrames[kindex+1] event "i", "sound", kcounter*0.1, 1, kamp, kfreq ; play sounds with the amplitude and frequency of the peak as in arpeggio kcounter=kcounter+1 endif loop_lt kindex,2,ifftsize,label1; endif endin instr sound iamp= p4 ifreq=p5 kenv adsr 0.1,0.1,0.5,p3/2 kndx line 5,p3,1 asig foscil iamp*kenv, ifreq,1,0.75,kndx,giSine outs asig, asig endin </CsInstruments> <CsScore> i "getPeaks" 0 60 </CsScore> </CsoundSynthesizer>
Arrays in Csound 6
During the time of writing on this release, Csound 6 is still in alpha development. But it may nevertheless be useful to put some examples for arrays in Csound 6 here which are working already now in march 2013.
i-Arrays Local
<CsoundSynthesizer> <CsOptions> -dnm0 </CsOptions> <CsInstruments> ;test local iArrays ;jh march 2013 instr 1 prints "iArr in instr %d:\n", p1 iArr[] init 4 icounter = 0 until (icounter >= 4) do iArr[icounter] = icounter ^ 2 prints " iArr[%d] = %f\n", icounter, iArr[icounter] icounter += 1 od endin instr 2 prints "iArr in instr %d:\n", p1 iArr[] init 4 icounter = 0 until (icounter >= 4) do iArr[icounter] = icounter ^ 2 + 1 prints " iArr[%d] = %f\n", icounter, iArr[icounter] icounter += 1 od endin </CsInstruments> <CsScore> i 1 0 0 i 2 0 0 </CsScore> </CsoundSynthesizer>
Prints:
iArr in instr 1:
iArr[0] = 0.000000
iArr[1] = 1.000000
iArr[2] = 4.000000
iArr[3] = 9.000000
iArr in instr 2:
iArr[0] = 1.000000
iArr[1] = 2.000000
iArr[2] = 5.000000
iArr[3] = 10.000000
i-Arrays Global
<CsoundSynthesizer> <CsOptions> -dnm0 </CsOptions> <CsInstruments> ;test global iArrays ;jh march 2013 giArr[] init 4 instr 1 prints "Printing giArr[] in instr %d:\n [", p1 icounter = 0 until (icounter == 3) do prints "%f ", giArr[icounter] icounter += 1 od prints "%f]\n", giArr[3] endin instr 2 prints "Changing giArr[] in instr %d.\n", p1 icounter = 0 until (icounter == 4) do giArr[icounter] = rnd(10) printf_i " giArr[%d] = %f\n", icounter+1, icounter, giArr[icounter] icounter += 1 od endin instr 3 prints "Printing giArr[] in instr %d:\n [", p1 icounter = 0 until (icounter == 3) do prints "%f ", giArr[icounter] icounter += 1 od prints "%f]\n", giArr[3] endin </CsInstruments> <CsScore> i 1 0 0 i 2 0 0 i 3 0 0 </CsScore> </CsoundSynthesizer>
Prints:
Printing giArr[] in instr 1:
[0.000000 0.000000 0.000000 0.000000]
Changing giArr[] in instr 2.
giArr[0] = 9.735000
giArr[1] = 1.394045
giArr[2] = 7.694886
giArr[3] = 5.250046
Printing giArr[] in instr 3:
[9.735000 1.394045 7.694886 5.250046]
k-Arrays Local
<CsoundSynthesizer> <CsOptions> -dnm0 </CsOptions> <CsInstruments> ;test local kArrays ;jh march 2013 instr 1 printks "kArr in instr %d:\n", 0, p1 kArr[] init 4 kcounter = 0 until (kcounter == 4) do kArr[kcounter] = kcounter ^ 2 printf " kArr[%d] = %f\n", kcounter+1, kcounter, kArr[kcounter] kcounter += 1 od turnoff endin instr 2 printks "kArr in instr %d:\n", 0, p1 kArr[] init 4 kcounter = 0 until (kcounter == 4) do kArr[kcounter] = kcounter ^ 2 + 1 printf " kArr[%d] = %f\n", kcounter+1, kcounter, kArr[kcounter] kcounter += 1 od turnoff endin </CsInstruments> <CsScore> i 1 0 1 i 2 0 1 </CsScore> </CsoundSynthesizer>Prints:
kArr in instr 1:
kArr[0] = 0.000000
kArr[1] = 1.000000
kArr[2] = 4.000000
kArr[3] = 9.000000
kArr in instr 2:
kArr[0] = 1.000000
kArr[1] = 2.000000
kArr[2] = 5.000000
kArr[3] = 10.000000
k-Arrays Global
<CsoundSynthesizer> <CsOptions> -dnm0 </CsOptions> <CsInstruments> ;test global iArrays ;jh march 2013 giArrLen = 5 gkArr[] init giArrLen instr 1 printks "Printing gkArr[] in instr %d:\n [", 0, p1 kcounter = 0 until (kcounter == giArrLen-1) do printf "%f ", kcounter+1, gkArr[kcounter] kcounter += 1 od printf "%f]\n", kcounter+1, gkArr[kcounter] turnoff endin instr 2 printks "Changing gkArr[] in instr %d.\n", 0, p1 kcounter = 0 kLim init 10 until kcounter == giArrLen do gkArr[kcounter] = rnd(kLim) printf " gkArr[%d] = %f\n", kcounter+1, kcounter, gkArr[kcounter] kcounter += 1 od turnoff endin instr 3 printks "Printing gkArr[] in instr %d:\n [", 0, p1 kcounter = 0 until (kcounter == giArrLen-1) do printf "%f ", kcounter+1, gkArr[kcounter] kcounter += 1 od printf "%f]\n", kcounter+1, gkArr[kcounter] turnoff endin </CsInstruments> <CsScore> i 1 0 1 i 2 0 1 i 3 0 1 </CsScore> </CsoundSynthesizer>Prints:
Printing gkArr[] in instr 1:
[0.000000 0.000000 0.000000 0.000000 0.000000]
Changing gkArr[] in instr 2.
gkArr[0] = 9.735000
gkArr[1] = 1.394045
gkArr[2] = 7.694886
gkArr[3] = 5.250046
gkArr[4] = 6.226652
Printing gkArr[] in instr 3:
[9.735000 1.394045 7.694886 5.250046 6.226652]
a-Arrays Local
<CsoundSynthesizer> <CsOptions> -odac -d </CsOptions> <CsInstruments> ;test local aArrays ;jh march 2013 sr = 44100 ksmps = 32 nchnls = 2 instr 1 aArr[] init 2 a1 oscils .2, 400, 0 a2 oscils .2, 500, 0 kEnv transeg 1, p3, -3, 0 aArr[0] = a1 * kEnv * 20000 aArr[1] = a2 * kEnv * 20000 outch 1, aArr[0], 2, aArr[1] endin instr 2 ;to test identical names aArr[] init 2 a1 oscils .2, 600, 0 a2 oscils .2, 700, 0 kEnv transeg 0, p3-p3/10, 3, 1, p3/10, -6, 0 aArr[0] = a1 * kEnv * 20000 aArr[1] = a2 * kEnv * 20000 outch 1, aArr[0], 2, aArr[1] endin </CsInstruments> <CsScore> i 1 0 3 i 2 0 3 </CsScore> </CsoundSynthesizer>
a-Arrays Global
<CsoundSynthesizer> <CsOptions> -odac -d </CsOptions> <CsInstruments> ;test global aArrays ;jh march 2013 (using code from iain mccurdy) sr = 44100 ksmps = 32 nchnls = 2 gaArr[] init 2 instr 1 ; left channel kEnv loopseg 0.5, 0, 0, 1,0.003, 1,0.0001, 0,0.9969 aSig pinkish kEnv gaArr[0] = aSig * 20000 endin instr 2 ; right channel kEnv loopseg 0.5, 0, 0.5, 1,0.003, 1,0.0001, 0,0.9969 aSig pinkish kEnv gaArr[1] = aSig * 20000 endin instr 3 ; reverb aInSigL = gaArr[0] / 3 aInSigR = gaArr[1] / 2 aRvbL,aRvbR reverbsc aInSigL, aInSigR, 0.88, 8000 gaArr[0] = gaArr[0] + aRvbL gaArr[1] = gaArr[1] + aRvbR outs gaArr[0], gaArr[1] gaArr[0] = 0 gaArr[1] = 0 endin </CsInstruments> <CsScore> i 1 0 10 i 2 0 10 i 3 0 12 </CsScore> </CsoundSynthesizer>
S-Arrays Local
<CsoundSynthesizer> <CsOptions> -dnm0 </CsOptions> <CsInstruments> ;test local SArrays ;(same code in instr 1 and 2, different values) ;create and fill string array at i-time, modify at k-time ;jh march 2013 opcode StrAgrm, S, Sj ;changes the elements in Sin randomly, like in an anagram Sin, iLen xin if iLen == -1 then iLen strlen Sin endif Sout = "" ;for all elements in Sin iCnt = 0 iRange = iLen loop: ;get one randomly iRnd rnd31 iRange-.0001, 0 iRnd = int(abs(iRnd)) Sel strsub Sin, iRnd, iRnd+1 Sout strcat Sout, Sel ;take it out from Sin Ssub1 strsub Sin, 0, iRnd Ssub2 strsub Sin, iRnd+1 Sin strcat Ssub1, Ssub2 ;adapt range (new length) iRange = iRange-1 loop_lt iCnt, 1, iLen, loop xout Sout endop instr 1 prints "SArr[] in instr %d at init-time:\n [", p1 ;create S_Arr[] init 4 ;fill iCounter = 0 until (iCounter == 4) do S_new StrAgrm "csound" S_Arr[iCounter] = S_new iCounter += 1 od ;print iCounter = 0 until (iCounter == 4) do printf_i "%s ", iCounter+1, S_Arr[iCounter] iCounter += 1 od prints "]\n" kCycle timeinstk printks "SArr[] in instr %d at k-cycle %d:\n [", 0, p1, kCycle ;fill kCounter = 0 until (kCounter == 4) do kChar random 33, 127 S_new sprintfk "%c ", int(kChar) S_Arr[kCounter] strcpyk S_new ;'=' should work but does not kCounter += 1 od ;print kCounter = 0 until (kCounter == 4) do printf "%s ", kCounter+1, S_Arr[kCounter] kCounter += 1 od printks "]\n", 0 if kCycle == 3 then turnoff endif endin instr 2 prints "SArr[] in instr %d at init-time:\n [", p1 ;create S_Arr[] init 4 ;fill iCounter = 0 until (iCounter == 4) do S_new StrAgrm "csound" S_Arr[iCounter] = S_new iCounter += 1 od ;print iCounter = 0 until (iCounter == 4) do printf_i "%s ", iCounter+1, S_Arr[iCounter] iCounter += 1 od prints "]\n" kCycle timeinstk printks "SArr[] in instr %d at k-cycle %d:\n [", 0, p1, kCycle ;fill kCounter = 0 until (kCounter == 4) do kChar random 33, 127 S_new sprintfk "%c ", int(kChar) S_Arr[kCounter] strcpyk S_new ;'=' should work but does not kCounter += 1 od ;print kCounter = 0 until (kCounter == 4) do printf "%s ", kCounter+1, S_Arr[kCounter] kCounter += 1 od printks "]\n", 0 if kCycle == 3 then turnoff endif endin </CsInstruments> <CsScore> i 1 0 1 i 2 1 1 </CsScore> </CsoundSynthesizer>
Prints:
SArr[] in instr 1 at init-time:
[consdu uncdos oduscn scodun ]
SArr[] in instr 1 at k-cycle 1:
[s < x + ]
SArr[] in instr 1 at k-cycle 2:
[! P Z r ]
SArr[] in instr 1 at k-cycle 3:
[u U b K ]
SArr[] in instr 2 at init-time:
[uocdsn odscnu uscdon sncduo ]
SArr[] in instr 2 at k-cycle 1:
[c " h h ]
SArr[] in instr 2 at k-cycle 2:
[9 = # U ]
SArr[] in instr 2 at k-cycle 3:
[x F Z l ]
S-Arrays Global
<CsoundSynthesizer> <CsOptions> -dnm0 </CsOptions> <CsInstruments> ;test global SArrays ;jh march 2013 giArrLen = 5 gSArr[] init giArrLen opcode StrAgrm, S, Sj ;changes the elements in Sin randomly, like in an anagram Sin, iLen xin if iLen == -1 then iLen strlen Sin endif Sout = "" ;for all elements in Sin iCnt = 0 iRange = iLen loop: ;get one randomly iRnd rnd31 iRange-.0001, 0 iRnd = int(abs(iRnd)) Sel strsub Sin, iRnd, iRnd+1 Sout strcat Sout, Sel ;take it out from Sin Ssub1 strsub Sin, 0, iRnd Ssub2 strsub Sin, iRnd+1 Sin strcat Ssub1, Ssub2 ;adapt range (new length) iRange = iRange-1 loop_lt iCnt, 1, iLen, loop xout Sout endop instr 1 prints "Filling gSArr[] in instr %d at init-time!\n", p1 iCounter = 0 until (iCounter == giArrLen) do S_new StrAgrm "csound" gSArr[iCounter] = S_new iCounter += 1 od endin instr 2 prints "Printing gSArr[] in instr %d at init-time:\n [", p1 iCounter = 0 until (iCounter == giArrLen) do printf_i "%s ", iCounter+1, gSArr[iCounter] iCounter += 1 od prints "]\n" endin instr 3 printks "Printing gSArr[] in instr %d at perf-time:\n [", 0, p1 kcounter = 0 until (kcounter == giArrLen) do printf "%s ", kcounter+1, gSArr[kcounter] kcounter += 1 od printks "]\n", 0 turnoff endin instr 4 prints "Modifying gSArr[] in instr %d at init-time!\n", p1 iCounter = 0 until (iCounter == giArrLen) do S_new StrAgrm "csound" gSArr[iCounter] = S_new iCounter += 1 od endin instr 5 prints "Printing gSArr[] in instr %d at init-time:\n [", p1 iCounter = 0 until (iCounter == giArrLen) do printf_i "%s ", iCounter+1, gSArr[iCounter] iCounter += 1 od prints "]\n" endin instr 6 kCycle timeinstk printks "Modifying gSArr[] in instr %d at k-cycle %d!\n", 0, p1, kCycle kCounter = 0 until (kCounter == giArrLen) do kChar random 33, 127 S_new sprintfk "%c ", int(kChar) gSArr[kCounter] strcpyk S_new ;'=' should work but does not kCounter += 1 od if kCycle == 3 then turnoff endif endin instr 7 kCycle timeinstk printks "Printing gSArr[] in instr %d at k-cycle %d:\n [", 0, p1, kCycle kCounter = 0 until (kCounter == giArrLen) do printf "%s ", kCounter+1, gSArr[kCounter] kCounter += 1 od printks "]\n", 0 if kCycle == 3 then turnoff endif endin </CsInstruments> <CsScore> i 1 0 1 i 2 0 1 i 3 0 1 i 4 1 1 i 5 1 1 i 6 1 1 i 7 1 1 </CsScore> </CsoundSynthesizer>
Prints:
Filling gSArr[] in instr 1 at init-time!
Printing gSArr[] in instr 2 at init-time:
[nudosc coudns dsocun ocsund osncdu ]
Printing gSArr[] in instr 3 at perf-time:
[nudosc coudns dsocun ocsund osncdu ]
Modifying gSArr[] in instr 4 at init-time!
Printing gSArr[] in instr 5 at init-time:
[ousndc uocdns sudocn usnocd ouncds ]
Modifying gSArr[] in instr 6 at k-cycle 1!
Printing gSArr[] in instr 7 at k-cycle 1:
[s < x + ! ]
Modifying gSArr[] in instr 6 at k-cycle 2!
Printing gSArr[] in instr 7 at k-cycle 2:
[P Z r u U ]
Modifying gSArr[] in instr 6 at k-cycle 3!
Printing gSArr[] in instr 7 at k-cycle 3:
[b K c " h ]