ref
Abstract
Get a reference to a variable
Description
ref
and deref
implement a mechanism to pass a reference to an array,
allowing to share it across instruments, opcodes, etc. Refs are reference counted and
deallocate themselves when out of scope and not being used by any
object. It makes it possible to pass arrays by reference to user defined
opcodes, allowing to modify an array in place, skip copying memory, etc.
iX[] fillarray 0, 1, 2, 3, 4
iref ref iX
iY[] deref iref
In the case above, iY
shares the same memory as iX
and any modification in
one array will be visible in the other.
Syntax
iref ref xArray, [iextrarefs=0]
Arguments
- xArray: the array to be referenced
- iextrarefs: use this for the niche case where a reference is passed to an
event scheduled at a point in time later that the end of the current event.
Without this, the ref would go out of scope before the
deref
takes place. Any extra ref must be matched with an extra deref (kArr[] deref iref, 1
)
Output
- iref: an integer identifying the reference handle.
Execution Time
- Init
Examples
<CsoundSynthesizer>
<CsOptions>
--nosound
</CsOptions>
<CsInstruments>
;; Example file for ref - deref
sr = 44100
ksmps = 64
nchnls = 2
0dbfs = 1
giA[] fillarray 0, 1000, 2000, 3000
; Example 1: take a ref from an array, deref it to create a second view of it
instr 1
; a source array
iX[] fillarray 0, 10, 20, 30, 40
; create a ref of iXs, return the index
iref ref iX
; now iYs points to iXs
iY[] deref iref
printarray iY, "", "instrument 1, iY"
iZ[] fillarray 0, 1, 3, 5, 7
; create a ref, pass it to instr. 2
schedule 2, 0, 1, ref(iZ)
; create another ref of iZ. In this case the event is scheduled
; in the future, so the source will not exist anymore when instr. 2
; is scheduled. This should fail.
schedule 2, 1, 1, ref(iZ)
turnoff
endin
instr 2
iref = p4
if refvalid(iref) == 1 then
iZs[] deref iref
printarray iZs, "", "p1=2, iZs"
else
prints "\n The reference has become invalid\n"
endif
turnoff
endin
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Example 2: extra references to keep array alive
instr 3
; create a source array
kXs[] fillarray 1, 1, 2, 3, 5, 8, 13
; In order to bridge the time gap between the end of life of the source
; of a ref and the scheduled event where a deref is taken, it is possible
; to create a forward reference, a "promise" that one deref has been scheduled
; in the future.
; short lived event, ends before this event
schedule 4, 0, 0.1, ref(kXs), 0
; starts before we end, but survives us
schedule 4, p3-0.1, 0.2, ref(kXs), 0
; starts after we end, we need an extra reference
schedule 4, p3+1, 0.1, ref(kXs, 1), 1
defer "prints", " --- instr. 3 finished --- \n"
endin
instr 4
prints "instr. 4\n "
kView[] deref p4, p5
printarray kView
defer "prints", " --- instr. 4 finished --- \n"
; At deinition time the memory of the `iView` array is marked as deallocated.
; The handle (a global structure created by the `ref` opcode) which owns the memory,
; is signaled that no other clients of this data are alive. It deallocates the
; original memory and frees itself
endin
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; test: multiple derefs
instr 5
iXs[] fillarray 0, 1, 4, 9
iref ref iXs
iYs[] deref iref
iZs[] deref iref
printarray iYs
printarray iZs
iXs[0] = 100
printarray iZs
turnoff
endin
; test performance of pass-by-value vs pass-by-reference
opcode arrayadd, i[], i[]i
; pass by value in and out
iIn[], ix xin
iOut[] = iIn + ix
xout iOut
endop
opcode arrayaddref, i[], ii
; pass by ref in, by value out
iref, ix xin
iIn[] deref iref
iOut[] = iIn + ix
xout iOut
endop
opcode arrayadd_inplace, 0, ii
; in place
iref, ix xin
iIn[] deref iref
iIn += ix
endop
opcode arrayadd_byref_inout, 0, iii
; pass by ref in and out
irefin, irefout, ix xin
iIn[] deref irefin
iOut[] deref irefout
if lenarray(iOut) >= lenarray(iIn) then
iOut = iIn + ix
endif
endop
instr testUdoPerformance1
; Here we test the performance gain of passing arrays by reference.
; Passing the input array by reference seems to produce a speedup of ~25%,
inum = 10000
iXs[] genarray 0, inum
ii = 0
it0 rtclock
while ii < 20 do
iYs[] arrayadd iXs, 2.0
ii += 1
od
it1 rtclock
prints "Dur UDO pass by value = %.8f \n", it1 - it0
iref = ref(iXs)
it0 rtclock
iY0[] arrayaddref iref, 0.1
iY0 arrayaddref iref, 0.2
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
iY0 arrayaddref iref, 0.3
it1 rtclock
prints "Dur UDO pass by ref input = %.8f \n", it1 - it0
iZs[] genarray 0, inum
iOut[] init lenarray(iZs)
it0 rtclock
irefZ = ref(iZs)
irefOut = ref(iOut)
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
arrayadd_byref_inout irefZ, irefOut, 0.5
it1 rtclock
prints "Dur UDO pass by ref in and out=%.8f \n", it1 - it0
; printarray iOut
endin
instr 7
iIn[] genarray 0, 1000
iOut[] init lenarray(iIn)
arrayadd_byref_inout ref(iIn), ref(iOut), 0.5
turnoff
endin
instr 8
; test k arrays
; 1. A way to convert a i-array to a k-array by taking a reference
iXs[] genarray 0, 99
kXs[] deref ref(iXs)
kXs[0] = timeinsts()
printarray kXs, metro(8)
endin
instr 9
; we need genarray_i because otherwise kXs is not initialized at i-time
kXs[] genarray 0, 9
iXs[] deref ref(kXs)
iXs += 10
printarray iXs
printarray kXs
turnoff
endin
; schedule 1, 0, 1
; schedule 3, 0, 1
; schedule 5, 0, 0.1
schedule "testUdoPerformance1", 0, 0.1
; schedule 8, 0, 4
</CsInstruments>
<CsScore>
e 10
</CsScore>
</CsoundSynthesizer>
See also
Credits
Eduardo Moguillansky, 2019