Skip to content

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:

Explicit Variable Types
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

instr 1
 obj:Opcode = create(oscili)
 sig:a = run(obj, p4, p5)
   out(sig)
endin

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.