opcode

opcode — Commence un bloc d'opcode défini par l'utilisateur.

Définir des opcodes

Les instructions opcode et endop permettent de définir un nouvel opcode qui peut être utilisé de la même façon qu'un opcode original de Csound. Ces blocs d'opcode ressemblent beaucoup aux instruments (et sont, en fait, implémentés comme des instruments spéciaux), mais on ne peut pas les appeler comme des intruments normaux, par exemple avec des instructions i.

Un bloc d'opcode défini par l'utilisateur doit précéder l'instrument (ou l'opcode) depuis lequel on l'utilise. Mais un opcode peut aussi s'appeler lui-même. Cela permet une récursivité dont la profondeur n'est limitée que par la mémoire disponible. De plus, on peut, à titre expérimental, exécuter l'opcode défini à un taux de contrôle plus élevé que la valeur de kr spécifiée dans l'en-tête de l'orchestre.

Comme pour les intruments, les variables et les étiquettes d'un bloc d'opcode défini par l'utilisateur sont locales et ne sont pas visible depuis l'instrument appelant (de même que l'opcode n'a pas accès aux variables de l'instrument qui l'a appelé).

Cependant, certains paramètres sont copiés automatiquement à l'initialisation :

  • tous les p-champs jusqu'à celui de numéro le plus élevé inclus, référencés dans l'instrument appelant

  • le temps supplémentaire (voir aussi xtratim, linsegr, et les opcodes correspondants). Ceci peut affecter le fonctionnement de linsegr/expsegr/linenr/envlpxr dans le bloc d'opcode défini par l'utilisateur.

  • les paramètres MIDI, s'il y en a.

Le drapeau de release (voir l'opcode release) est également copié durant l'exécution.

La modification de la durée de la note dans la définition de l'opcode en assignant une valeur à p3, ou l'utilisation de ihold, turnoff, xtratim, linsegr, ou d'autres opcodes similaires affecteront aussi l'instrument appelant. Les changements sur des contrôleurs MIDI (par exemple avec ctrlinit) s'appliqueront aussi à l'instrument qui a appelé l'opcode.

Utilisez l'opcode setksmps pour fixer la valeur locale de ksmps.

Les opcodes xin et xout copient les variables vers et depuis la définition de l'opcode, permettant la communication avec l'instrument appelant.

Les types des variables d'entrée et de sortie sont définis par les paramètres intypes et outtypes.

[Astuce] Astuce

On peut créer des UDOs sans entrée ou sans sortie en remplaçant la chaîne de caractères correspondante par 0.

[Note] Notes

  • xin et xout ne doivent être appelés qu'une seule fois, et xin doit précéder xout, sinon une erreur d'initialisation et une désactivation de l'instrument courant peuvent se produire.

  • Ces deux opcodes n'agissent qu'à l'initialisation. La copie durant l'exécution est réalisée par l'appel de l'opcode de l'utilisateur. Cela signifie que sauter xin ou xout avec kgoto n'a aucun effet, alors que les sauter avec igoto affecte à la fois les opérations de l'initialisation et de l'exécution.

Syntaxe

opcode nom, outtypes, intypes

Initialisation

nom -- nom de l'opcode. Il est constitué de n'importe quelle combinaison de lettres, chiffres et traits de soulignement mais il ne doit pas commencer par un chiffre. Si un opcode du même nom existe déjà, il est redéfini (un avertissement est affiché dans ce cas). Certains mots réservés (comme instr et endin) ne peuvent pas être redéfinis.

intypes -- liste des types en entrée, toute combinaison des caractères a, f, k, O, P, V, K, i, o, p et j. Un caractère 0 unique peut être utilisé s'il n'y a pas d'argument en entrée. Il n'y a pas besoin d'apostrophes doubles et de délimiteurs (comme la virgule).

La signification des différent intypes est montrée dans le tableau suivant :

Type Description Types de Variable Autorisés Mise à jour
a variable de taux-a taux-a taux-a
f variable sig-f sig-f taux-k
i variable de taux-i taux-i initialisation
j facultatif de taux-i, -1 par défaut taux-i, constante initialisation
k variable de taux-k taux-k et -i, constante taux-k
O variable facultative de taux-k, valant 0 par défaut taux-k et -i, constante taux-k
P variable facultative de taux-k, valant 1 par défaut taux-k et -i, constante taux-k
V variable facultative de taux-k, valant 0.5 par défaut taux-k et -i, constante taux-k
J variable facultative de taux-k, valant -1 par défaut taux-k et -i, constante taux-k
K taux-k avec initialisation taux-k et -i, constante taux-i et taux-k
o facultatif à l'initialisation, 0 par défaut taux-i, constante initialisation
p facultatif à l'initialisation, 1 par défaut taux-i, constante initialisation
S variable chaîne de caractères chaîne de caractères de taux-k et -i, constante taux-i et taux-k

Le nombre maximum d'arguments en entrée autorisé est 256.

outtypes -- liste des types en sortie. Le format est le même que celui utilisé pour intypes.

Voici les outtypes disponibles :

Type Description Types de Variable Autorisés Mise à jour
a variable de taux-a taux-a taux-a
f variable sig-f sig-f taux-k
i variable de taux-i taux-i initialisation
k variable de taux-k taux-k taux-k
K taux-k avec initialisation taux-k taux-i et taux-k
S variable chaîne de caractères chaîne de caractères de taux-k et -i, constante taux-i et taux-k

Le nombre maximum d'arguments en sortie autorisé est 256.

iksmps (facultatif, 0 par défaut) -- fixe la valeur locale de ksmps. Doit être un nombre entier positif, et le ksmps de l'instrument appelant doit être un multiple entier de cette valeur. Par exemple, si ksmps vaut 10 dans l'instrument depuis lequel l'opcode a été appelé, les valeurs permises pour iksmps sont 1, 2, 5, et 10.

Si iksmps vaut zéro, le ksmps de l'instrument ou de l'opcode appelant est utilisé (c'est le comportement par défaut).

[Note] Note

Le ksmps local est implémenté en divisant une période de contrôle en sous-périodes-k plus petites et en modifiant temporairement les variables globales internes de Csound. Ceci nécessite aussi la conversion du taux des arguments d'entrée et de sortie de taux-k (les variables d'entrée reçoivent la même valeur dans tous les sous-périodes-k, tandis que les valeurs de sortie ne sont écrites que pendant la dernière).

[Avertissement] Avertissement au sujet du ksmps local

Lorsque le ksmps local est différent du ksmps de l'orchestre (celui spécifié dans l'en-tête de l'orchestre), il ne faut pas utiliser d'opération globale de taux-a dans le bloc d'opcode défini par l'utilisateur.

Ceci comprend :

  • tous les accès aux variables « ga »

  • les opcodes zak de taux-a (zar, zaw, etc.)

  • tablera et tablewa (ces deux opcodes peuvent fonctionner en fait, mais il faut prendre des précautions)

  • La famille d'ocpode in et out (ils lisent depuis et écrivent dans des tampons globaux de taux-a)

En général, il faut utiliser le ksmps local avec précaution car c'est une fonctionnalité expérimentale, bien qu'elle fonctionne correctement dans la plupart des cas.

L'instruction setksmps peut être utilisée pour fixer la valeur du ksmps local du bloc d'opcode défini par l'utilisateur. Elle a un paramètre de taux-i spécifiant la nouvelle valeur de ksmps (qui reste inchangée si l'on utilise zéro, voir aussi les notes au sujet de iksmps ci-dessus). setksmps doit être utilisé avant tout autre opcode (mais il est autorisé après xin), autrement des résultats imprévisibles peuvent se produire.

On peut lire les paramètres d'entrée avec l'opcode xin, et la sortie est écrite par l'opcode xout. On ne doit utiliser qu'une seule instance de ces unités, car xout écrase la sortie sans accumuler les valeurs. Le nombre et le type des arguments pour xin et xout doit être le même que dans la déclaration du bloc d'opcode défini par l'utilisateur (voir les tableaux ci-dessus).

Les arguments d'entrée et de sortie doivent se conformer à la définition à la fois en nombre (sauf si des entrées de taux-i facultatives sont utilisées) et en genre. Un paramètre d'entrée facultatif de taux-i (iksmps) est automatiquement ajouté à la liste des intypes et (comme pour setksmps) fixe la valeur du ksmps local.

Exécution

La syntaxe d'un bloc d'opcode défini par l'utilisateur est la suivante :

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

Le nouvel opcode peut ensuite être utilisé avec la syntaxe usuelle :

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

[Note] Note

L'opcode est toujours appelé à la fois durant l'initialisation et durant l'exécution, même s'il n'y a pas d'arguments de taux-k ou -a. Si l'on sait que plusieurs opcodes définis par l'utilisateur n'ont pas d'effet durant l'exécution (taux-k) dans un instrument, on peut épargner du temps CPU en sautant ces groupes d'opcodes avec kgoto.

Exemples

Voici un exemple d'opcode défini par l'utilisateur. Il utilise le fichier opcode.csd.

Exemple 678. Exemple d'opcode défini par l'utilisateur.

Voir les sections Audio en Temps Réel et Options de la Ligne de Commande pour plus d'information sur l'utilisation des options de la ligne de commande.

<CsoundSynthesizer>
<CsOptions>
; Select audio/midi flags here according to platform
-odac    ;;;realtime audio out
;-iadc    ;;;uncomment -iadc if realtime audio input is needed too
; For Non-realtime ouput leave only the line below:
; -o opcode_example.wav -W ;;; for file output any platform
</CsOptions>
<CsInstruments>

sr = 44100
ksmps = 32
nchnls = 2
0dbfs  = 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    =  .7                ; 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
        outs a1, a1

        endin


</CsInstruments>
<CsScore>

i 1 0 4
e5		;extra second before quitting

</CsScore>
</CsoundSynthesizer>


Voir aussi

endop, setksmps, xin, xout

Crédits

Auteur : Istvan Varga, 2002 ; basé sur du code de Matt J. Ingalls

Nouveau dans la version 4.22