What's new in Csound 7
Csound 7 brings major changes which offer new possibilities for users and modernize coding. Nevertheless Csound 7 keeps backwards compatibility: Despite new syntax features any valid Csound code from the past can be run without any code change.
Explicit Variable Types
Variable names no longer have to start with i
, k
, a
etc. to declare their data type implicitely. Instead any name (except existing opcodes or keywords) can be used, and the type declared explicitely:
maxamp@global:i = 0dbfs / 5
instr 1
freq:i = 444
ramp:k = linseg(maxamp,p3,0)
sound:a = poscil(ramp,freq)
outall(sound)
endin
schedule(1,0,2)
In addition, a number of new variable types have been introduced.
New UDO Syntax and Pass-by-reference
User Defined Opcodes now follow the syntax opcode name(inargs):(outargs)
.
opcode myop(inval:i):(i)
xout(inval+1)
endop
opcode empty():void
puts("empty!", 1)
endop
instr 1
print(myop(17))
empty()
endin
schedule(1, 0, 0)
When the new opcode syntax is used, the default call semantics is by reference, instead of copy. The exceptions are when local sampling rate or local ksmps are used, when pass-by-copy is used. In pass-by-reference semantics all arguments data are shared between the caller and the UDO.
The classic opcode syntax always implies pass-by-copy.
Local Sampling Rate for UDOs
UDOs can now be set to a local sampling rate, which may be higher
or lower than the calling environment. The opcodes oversample
and
undersample
are used to set the local sampling rate. The limitations
are that the sampling rate always needs to be an integer multiple or
divisor of the caller sampling rate and local ksmps are not allowed
together with local sampling rates.
Functional Style Enhancements
Multiple output arguments can now be used in functional style, e.g.
nchnls = 2
instr 1
sig:a = rand(0dbfs/10)
aL,aR = pan2(sig, 3/4)
out(aL, aR)
endin
schedule(1, 0, 1)
Additionally, the new parser makes functional expressions behave exactly as the classic syntax, with no penalties.
User-Defined Types
The type system in Csound 7 is very sophisticated and it allows new types to be added using Csound code (similarly to user-defined opcodes). Once created, these types are available to define new variables, arguments etc.
struct MyType val0:i, val1:i
instr 1
testVal:MyType init 8, 88
print(testVal.val0)
print(testVal.val1)
endin
schedule(1, 0, 0)
Instrument Definition Type
Csound 7 introduces a new type InstrDef
to hold instrument
definitions. The name of an instrument becomes a global constant of
that type, which may be referred directly in the code,
instr Ping
out(oscili(expon(p4,p3,0.001), p5))
schedule(Ping,0.1,0.2,rnd(0.5),500+rnd(100))
endin
schedule(Ping,0,0.2,0.5,500)
Furthermore, instrument definitions can be created directly from
Csound code. If the InstrDef
var is not yet available, we
can use the self-reference this_instr
. The following
code demonstrates this,
Ping:InstrDef = create({{
out(oscili(expon(p4,p3,0.001),p5))
schedule(this_instr,0.1,0.2,rnd(0.5),500+rnd(100))
}})
schedule(Ping,0,0.2,0.5,500)
Notice that with this code pattern, we do not need to enclose the
instrument inside instr
and endin
, and the instrument
number is assigned dynamically.
Instrument Instance Type
Csound 7 introduces a new type for instrument instances, Instr
.
Instrument instances can be assigned to variables and manipulated
by various opcodes. For example,
instr Container
myInstr:InstrDef = create({{ out Osci(p4,p5) }})
myInstance:Instr = create(myInstr)
err1:i = init(myInstance,0.5,440)
err2:k = perf(myInstance)
delete(myInstance)
delete(myInstr)
endin
In addition to these, several other opcodes can be used to manipulate instances in Csound code.
Opcode Reference and Opcode Types
References to opcodes can be assigned to variables and instantiated as Opcode-type objects, for example
Opcode objects may be invoked in loops, passed as parameters, have their init and perf functions executed, exist in arrays, etc. For example, we can run an array of opcodes in parallel,
freq:i[] = fillarray(p5*0.75, p5, p5*1.333, p5*1.666)
obj:Opcode[] = create(reson, lenarray(freq))
src:a = rand(linenr(p4,0.1,0.1,0.01))
sig:a[] = run(obj, src, freq, freq/p6, 2)
or in series
obj:Opcode[] = create(reson, 4)
sig:a = rand(linenr(p4,0.1,0.1,0.01))
sig = run(obj, sig, p5, p5/p6, 1)
Complex Type
Complex numbers are supported natively in the language now. All
basic complex arithmetic operations and functions are supported
for both scalars and arrays. For example, the following code
implements single-sideband modulation using Complex
arrays
instr 1
sig:Complex[] = hilbert(oscili(p4,p5))
mod:Complex[] = oscili(0.5,100,-1,0.25), oscili(0.5,100)
ssb:Complex[] = mod * sig
out real(ssb)
endin
UDP Server OSC message support
The UDP server now has builtin support for OSC messages. It also
includes message addresses for channels and events. To
access these messages a new overload of OSClisten
is provided,
taking the message address and type only and returning the message
data,
instr 1
freq:k = chnget("freq")
amp:k = chnget("amp")
out oscili(0dbfs*amp, p4*freq)
status:k, f:k, mess:S, n:k = OSClisten("/in", "fsi")
puts mess, status
printk2 n
printk2 f
status, nums:k[] = OSClisten("/ina", "fi")
printk2 nums[0]
printk2 nums[1]
endin
which can be controlled by the following messages,
instr 2
OSCsend 0, "localhost", 7000, "/csound/event/instr", "ffff", 1, 0, 1, 300
OSCsend 1, "localhost", 7000, "/csound/channel/freq/amp", "ff", p4, p5
OSCsend 2, "localhost", 7000, "/in", "fsi", p5, "hello", p4
OSCsend 3, "localhost", 7000, "/ina", "fi", p5, p4
OSCsend 4, "localhost", 7000, "/csound/event", "s", "i3 4 1"
OSCsend 5, "localhost", 7000, "/csound/compile", "s", "schedule 1,2,2,500"
endin
MIDI File Input Opcodes
Support for multiple MIDI input files with port mapping has been added. Opcodes for opening files and transport control are available.
Limitations Removed
The previous power-of-two limitation for table sizes has been removed, so that any size tables can be used everywhere.
The limitation of event parameter numbers has been lifted, any number of parameters are possible everywhere.