Csound opcode with arbitrary number of input arguments

Hello dear Csounders!

Is it possible to register a csound opcode with an arbitrary number of input arguments?

So that an opcode can be called with one, two or more e.g. a-values:

  • my_cool_opcode(av1)
  • my_cool_opcode(av1, av2)
  • my_cool_opcode(av1, av2 …. av10)

I guess one way would be something like

void csnd::on_load(Csound *csound) {
  csnd::plugin<MyCoolOpcode>(csound, "my_cool_opcode.a", , "a", csnd::thread::a);
  csnd::plugin<MyCoolOpcode>(csound, "my_cool_opcode.aa", , "aa", csnd::thread::a);
  csnd::plugin<MyCoolOpcode>(csound, "my_cool_opcode.aaa", , "aaa", csnd::thread::a);
  ...  
  csnd::plugin<MyCoolOpcode>(csound, "my_cool_opcode.aaaaaaaaaa", , "aaaaaaaaaa", csnd::thread::a);
}

but this would then mean that I also need to make x-different constructors, something like:

struct MyCoolOpcode : csnd::Plugin<0, 1> {}
struct MyCoolOpcode : csnd::Plugin<0, 2> {}
struct MyCoolOpcode : csnd::Plugin<0, 3> {}
...
struct MyCoolOpcode : csnd::Plugin<0, 10> {}

Is there a more elegant way to do this?

I can’t really help you. But maybe check the code of the linseg opcode out, which can take an arbitrary number of input arguments.

Yes you can use m I think:

You can check the num of args using in_count().

Hi @Philipp and @rory! That is exactly what I was looking for! I think that N is the best type for me since I’m interested in any count/rate i,k,a,S.

But check this out…

If I make following plugin:

struct MyCoolOpcode : csnd::Plugin<1, 'N'> {

    int kperf() {
        int numInputs = in_count();
        for(int i = 0; i < numInputs; i++) {
            std::string input_value ="kperf: input:" + std::to_string(inargs[i]);
            csound->message(input_value);
        }
        return OK;
    }

};

#include <modload.h>

void csnd::on_load(Csound *csound) {
    csnd::plugin<MyCoolOpcode>(csound, "cooling.N", "k", "N", csnd::thread::k);
}

I can use it as expected in an instrument:

instr 1
    k1 = 1
    k2 = 2
    k3 = cooling(k1, k2)
endin

but when I make plugin without outputs:

struct MyCoolOpcode : csnd::Plugin<0, 'N'> {

    int kperf() {
        int numInputs = in_count();
        for(int i = 0; i < numInputs; i++) {
            std::string input_value ="kperf: input:" + std::to_string(inargs[i]);
            csound->message(input_value);
        }
        return OK;
    }

};

#include <modload.h>

void csnd::on_load(Csound *csound) {
    csnd::plugin<MyCoolOpcode>(csound, "cooling.N", "", "N", csnd::thread::k);
}

And use it in similar way:

instr 1
    k1 = 1
    k2 = 2
    cooling(k1, k2)
endin

I get → csound command: Segmentation violation when accessing second input argument.

Any ideas what is wrong here? I am using Csound 6.18 on Windows 11.

No, in this case you must define the max number of inputs you need, even if you have no intention of ever using that many. Something like:

struct MyCoolOpcode : csnd::Plugin<0,64> {

Also, if you are building an opcode with no outputs there is a special csnd::InPlug struct you should use.

struct MyCoolOpcode : csnd::InPlug<64> {

And in this case inargs becomes args. :+1:

1 Like

Cool! many thanks @rory ! I will give it a try :crossed_fingers: