opcode

opcode --  Defines the start of user-defined opcode block.

Description

This feature is based on Matt J. Ingalls' subinstruments. However, there are some differences. (Sub-instruments can be used independently with the original syntax.) User defined opcodes have these differences as compared to subinstruments:

The opcode and endop statements allow defining a new opcode that can be used the same way as any of the built-in Csound opcodes. These opcode blocks are very similar to instruments (and are, in fact, implemented as special instruments). However, in most cases, they cannot be used from the score with i statements.

A user-defined opcode block must precede the instrument (or other opcode) from which it is used. But it is possible to call the opcode from itself. This allows recursion of any depth that is limited only by available memory. Additionally, there is an experimental feature that allows running the opcode definition at a higher control rate than the kr value specified in the orchestra header.

Similarly to instruments, the variables and labels of a user-defined opcode block are local and cannot be accessed from the caller instrument (and the opcode cannot access variables of the caller, either).

Some parameters are automatically copied at initialization, however:

Also, the release flag (see the release opcode) is copied at performance time.

It must be noted that none of the above (with the exception of MIDI channel parameters that can be modified by opcodes like ctrlinit) are copied back to the calling instrument. This is particularly important in the case of p3 and xtratim - note duration cannot be changed from the opcode. However, this may change in future releases. So orchestras should not rely on what happens when an user-defined opcode block modifies p3 or the extra time.

WarningWarning
 

The turnoff opcode must not be used from user-defined opcodes, as it can have unpredictable results.

Use the setksmps opcode to set the local ksmps value.

The xin and xout opcodes copy variables to and from the opcode definition, allowing communication with the calling instrument.

The types of input and output variables are defined by the parameters intypes and outtypes.

NoteNotes
 

  • xin and xout should be called only once, and xin should precede xout, otherwise an init error and deactivation of the current instrument may occur.

  • These opcodes actually run only at i-time. Performance time copying is done by the user opcode call. This means that skipping xin or xout with kgoto has no effect, while skipping with igoto affects both init and performance time operation.

Syntax

opcode name, outtypes, intypes

Initialization

name -- name of the opcode. It may consist of any combination of letters, digits, and underscore but should not begin with a digit. If an opcode with the specified name already exists, it is redefined (a warning is printed in such cases). Some reserved words (like instr and endin) cannot be redefined.

outtypes -- list of output types. The format is the same as in the case of intypes.

Here are the available outtypes:

TypeDescriptionVariable Types AllowedUpdated At
aa-rate variablea-ratea-rate
ii-time variablei-timei-time
kk-rate variablek-ratek-rate
Kk-rate with initializationk-ratei-time and k-rate

The maximum allowed number of output arguments is 24. However, only the first 15 may be audio rate ("a").

intypes -- list of input types, any combination of the characters: a, k, K, i, o, p, and j. A single 0 character can be used if there are no input arguments. Double quotes and delimiter characters (e.g. comma) are not needed.

The meaning of the various intypes is shown in the following table:

TypeDescriptionVariable Types AllowedUpdated At
aa-rate variablea-ratea-rate
ii-time variablei-timei-time
joptional i-time, defaults to -1i-time, constanti-time
kk-rate variablek-ratek-rate
Kk-rate with initializationk-ratei-time and k-rate
ooptional i-time, defaults to 0i-time, constanti-time
poptional i-time, defaults to 1i-time, constanti-time

The maximum allowed number of input arguments is 24. However, only the first 15 may be audio rate ("a").

iksmps (optional, default=0) -- sets the local ksmps value.

If iksmps is set to zero, the ksmps of the caller instrument or opcode is used (this is the default behavior).

NoteNote
 

The local ksmps is implemented by splitting up a control period into smaller sub-kperiods and temporarily modifying internal Csound global variables. This also requires converting the rate of k-rate input and output arguments (input variables receive the same value in all sub-kperiods, while outputs are written only in the last one).

WarningWarning about local ksmps
 

When the local ksmps is not the same as the orchestra level ksmps value (as specified in the orchestra header). Global a-rate operations must not be used in the user-defined opcode block.

These include:

  • any access to "ga" variables

  • a-rate zak opcodes (zar, zaw, etc.)

  • tablera and tablewa (these two opcodes may in fact work, but caution is needed)

  • The in and out opcode family (these read from, and write to global a-rate buffers)

In general, the local ksmps should be used with care as it is an experimental feature. Though it works correctly in most cases.

The setksmps statement can be used to set the local ksmps value of the user-defined opcode block. It has one i-time parameter specifying the new ksmps value (which is left unchanged if zero is used). setksmps should be used before any other opcodes (but allowed after xin), otherwise unpredictable results may occur.

The input parameters can be read with xin, and the output is written by xout opcode. Only one instance of these units should be used, as xout overwrites and does not accumulate the output. The number and type of arguments for xin and xout must be the same as the declaration of the user-defined opcode block.

The input and output arguments must agree with the definition both in number (except if the optional i-time input is used) and type. An optional i-time input parameter (iksmps) is automatically added to the intypes list, and (similarly to setksmps) sets the local ksmps value.

Performance

The syntax of a user-defined opcode block is as follows:

opcode  name, outtypes, intypes
xinarg1 [, xinarg2] [, xinarg3] ... [xinargN]  xin
[setksmps  iksmps]
... the rest of the instrument's code.
xout  xoutarg1 [, xoutarg2] [, xoutarg3] ... [xoutargN]
endop
      

The new opcode can then be used with the usual syntax:

[xinarg1] [, xinarg2] ... [xinargN]  name  [xoutarg1] [, xoutarg2] ... [xoutargN] [, iksmps]
      

Examples

Here is an example of a user-defined opcode. It uses the files opcode_example.orc and opcode_example.sco.

Example 1. Example of a user-defined opcode.

/* ---- opcode_example.orc ---- */
sr      =  44100
ksmps   =  50
nchnls  =  1

/* example opcode 1: simple oscillator */

        opcode Oscillator, a, kk

kamp, kcps      xin             ; read input parameters
a1      vco2 kamp, kcps         ; sawtooth oscillator
        xout a1                 ; write output

        endop

/* example opcode 2: lowpass filter with local ksmps */

        opcode Lowpass, a, akk

        setksmps 1              ; need sr=kr
ain, ka1, ka2   xin             ; read input parameters
aout    init 0                  ; initialize output
aout    =  ain*ka1 + aout*ka2   ; simple tone-like filter
        xout aout               ; write output

        endop

/* example opcode 3: recursive call */

        opcode RecursiveLowpass, a, akkpp

ain, ka1, ka2, idep, icnt       xin     ; read input parameters
        if (icnt >= idep) goto skip1    ; check if max depth reached
ain     RecursiveLowpass ain, ka1, ka2, idep, icnt + 1
skip1:
aout    Lowpass ain, ka1, ka2           ; call filter
        xout aout                       ; write output

        endop

/* example opcode 4: de-click envelope */

        opcode DeClick, a, a

ain     xin
aenv    linseg 0, 0.02, 1, p3 - 0.05, 1, 0.02, 0, 0.01, 0
        xout ain * aenv         ; apply envelope and write output

        endop

/* instr 1 uses the example opcodes */

        instr 1

kamp    =  20000                ; amplitude
kcps    expon 50, p3, 500       ; pitch
a1      Oscillator kamp, kcps                   ; call oscillator
kflt    linseg 0.4, 1.5, 0.4, 1, 0.8, 1.5, 0.8  ; filter envelope
a1      RecursiveLowpass a1, kflt, 1 - kflt, 10 ; 10th order lowpass
a1      DeClick a1
        out a1

        endin
/* ---- opcode_example.orc ---- */
        
/* ---- opcode_example.sco ---- */
i 1 0 4
e
/* ---- opcode_example.sco ---- */
        

See Also

endop, setksmps, xin, xout

Credits

Author: Istvan Varga, 2002; based on code by Matt J. Ingalls

New in version 4.07