Csound plugin opcode with array of audio signals

Dear Csounders!

How can I implement a Csound plugin opcode with array of audio signals (using Csound Plugin Opcode Framework (CPOF))?

I’ve tried this and it’s not working :confused:

// Declaration of input and output variables
static constexpr char const *otypes = "a[]";
static constexpr char const *itypes = "a[]";

// Plugin declaration
csnd::plugin<MyPlug>(csound, "myplug", "a[]", "a[]", csnd::thread::a);

// only working on a-rate
int aperf() {
    csnd::Vector<csnd::AudioSig> &in = inargs.vector_data<csnd::AudioSig>(0);
    csnd::Vector<csnd::AudioSig> &out = outargs.vector_data<csnd::AudioSig>(0);

    // simply copy input to output -> doesn’t work
    for (int ch_index = 0; ch_index < csound->nchnls_i(); ch_index++)
        for (int sample_index = 0; sample_index < in[ch_index].GetNsmps(); sample_index++)
           out[ch_index][sample_index] = in[ch_index][sample_index];
    return OK;
}

When I’m doing this I get access violation error. I think that this isn’t the right way to do this because i.e. in[0] doesn’t point me to audio signal from mic 1.

Any ideas?

Hi @Lovre. You need to iterate over the input arguments, and you also need to initialise the size of the output array as it is not known. I would do something like this (keep in mind I’ve never used audio variables with this framework!):


    csnd::Vector<csnd::AudioSig> &in = inargs.vector_data<csnd::AudioSig>(0);
    csnd::Vector<csnd::AudioSig> &out = outargs.vector_data<csnd::AudioSig>(0);

    //set the size of the output array
    out.init(csound, (int)in.len());

    //iterate over input signals
    for ( int i = 0 ; i < in.len() ; i++)
    {
        //do you assignment here, I'm not sure, but maybe you can do:
       out[i] = in[i];
       
       //if that doesn't work you probably need to assign the size and data member individually:
       //out[i].size = in[i].size;
       //out[i].data = in[i].data;
    }

It’s rare that would ever query nchnls in a plugin opcode. Opcodes are nchnls agnostic for the most part. Assuming that the input and output arrays somehow match nchnls could lead to all sorts of access violations.

Thanks @rory for your answer!

Unfortunately it is still not working.

In.len() → gives back 2, which is good but
out[i] = in[i]; → this doesn’t give an error but also doesn’t fill the output buffer.

When I iterate over in or out vector I don’t have size or data arguments. I have csnd::AudioSig class arguments.

Reason why I want an array of audio signals as input is because I’m planning to make one Csound plugin for microphone array processing.

Do you have maybe any other idea what I could try?

And also i.e. in[i].GetNsmps() gives some random junk values.

This also gives access violation error:
std::copy(in[0].begin(), in[0].end(), out[0].begin());

Ok, let me take a look and see if I can find the solution before annoying Victor about it :slight_smile:

So you will access the microphone channels using one of the in-family of opcodes, and then do some further processing? Or are you looking to access the raw mic data, directly from the audio drivers? If it’s the latter than I am not sure you will be able to do it with this framework…

Thank you @rory.

“So you will access the microphone channels using one of the in-family of opcodes, and then do some further processing?” → yes.

I know that csound isn’t typical choice for this kind of stuff but I’m working on one application implemented (at least for now) in python and then, for real-time audio, python binding for csound is pretty cool and powerful.

When I run the code above I get audio but it’s noisy. I’ve checked nsmps and it seems to report the wrong size, I guess this might be what’s causing the noise. Anyhow, I reached out to Victor to see what’s the most CPOF esque way of doing this.

Ok. Thanks @rory. Looking forward to Victor’s response :slight_smile:

Looks like were barking up the wrong tree with AudioSig. Here’s an example Victor pointed me to

1 Like

Yep! Seams to work :partying_face: Thanks @rory and Victor

Just for the sake of better overview here is the interesting code snippet from the file above (part of the SimpleArrayA strucut)

int aperf() {
    csnd::Vector<MYFLT> &out = outargs.vector_data<MYFLT>(0);
    csnd::Vector<MYFLT> &in = inargs.vector_data<MYFLT>(0);
    // copy each a-var ksmps vector in turn
    // NB: copying the whole memory block
    // from in.begin() to in.end() also works
    for (int i = 0; i < in.len(); i++)
      std::copy(in.begin() + i * in.elem_offset(),
                in.begin() + (i + 1) * in.elem_offset(),
                out.begin() + i * in.elem_offset());
    return OK;
  }

Nice. I guess csnd::AudioSig could still be used in this context to wrap the contents of the audio array. But I need to read more about its use.

If you find a way how to use AudioSig in this context, post it here :wink: I would be also very interested to see how it’s done

Maybe unnecessary but here is a code with the same functionality as above but in sample per sample way of processing:

for(int chanel_index = 0; chanel_index < in.len(); chanel_index++)
    for(int frame_index = 0; frame_index < in.elem_offset(); frame_index++){
        int sample_index = frame_index + chanel_index * in.elem_offset();
        MYFLT sample_value = in[sample_index];
        out[sample_index] = sample_value;
     }
1 Like