Cabbage Logo
Back to Cabbage Site

Cpsmidi input for a-rate custom opcode

I want to write a custom opcode that takes in frequency input via the cpsmidi opcode. Assuming I’m just producing a sine wave for example how would I set up the opcode to retrieve real-time midi input via cpsmidi?

If we were to strip it down to just the lines to retrieve and use the frequency info from cpsmidi (disregarding all the other things youd need to set up such as sample rate, period, etc etc) would those lines look as simple as:

// declare output var, input var for frequency, internal frequency var in data //structure
typedef struct _newopc {
OPDS h;
MYFLT *out;
MYFLT *in1;
MYFLT freq;
}newopc;

//initialize time set internal frequency var to value of input var
int new_opc_init(CSOUND *csound, newopc *p){
p->freq = *p->in1;
return OK;
}

//at performance time use frequency input to calculate and output //sinewave
int new_opc_process_audio(CSOUND *csound, newopc *p){
MYFLT freq = *p->freq;
//Now use freq in calculating sinewave output
return OK;
}

//register opcode
static OENTRY localops[] = {
{“newopc”, sizeof(newopc), 0, 7, “a”, “i”,
(SUBR) new_opc_init, (SUBR) new_opc_process_audio,}
};

LINKAGE

I ask because it seems like you would need to be continuously taking in input at performance time but I’m confused because to call cpsmidi you use an i-time variable. I want the implementation in csound to look like:

instr1
icps cpsmidi
asig myopc icps
outs asig, asig
endin

At it’s most basic level…

This looks fine, what exactly is the issue? You assign newopc.freq the input frequeny in your init function, and then access it in your perform function. This seems like a reasonable approach.

My quesion is lets say my opcode is generating a simple sine wave and takes in frequency as input, would this implementation work for taking in frequency input via the cpsmidi opcode. So the csound instrument using the custom opcode would look like:

instr1
icps cpsmidi
asig newopc icps
outs asig, asig
endin

When I run my opcode using cpsmidi for frequency input it doesnt seem to be changing frequency when I press a different note on the virtual midi keyboard.

If it’s not my frequency implementation in the opcode source that’s the issue I’m not sure what is at this point. I think I’ll have to try and pin down the issue. It makes a waveform but won’t change pitch. Every midi key press generates the same note.

Run it through the debugger and you’ll get more information about what’s going on. You can also use logging functions to print info to the Csound output, I think it’s called csound->Message(..). If icps is changing on each note, then your opcode’s internal freq member should be updating too.

Okay, I set it to print the internal frequency variable value it was recieiving from input like this:
csound->Message(csound, “frequency: %f Hz\n”, freq);

and it was changing frequncy as I changed midi notes on the virtual keyboard.
It turns out I needed to remove the freq variable from the initialization function since that was sort of setting the frequency in stone. Instead I added the frequency variable to the processing function so it would update in real time as the frequency changed.

so I declared my structure:

typedef struct _newopc {
OPDS h;
MYFLT *out;
MYFLT *in1, *in2;
MYFLT freq;
MYFLT amp;
} newopc;

I ignore freq and amp in the initialization function, and then in my processing function I add the freq variable:

int new_opc_process_audio(CSOUND *csound, newopc *p){

MYFLT *aout = p->out;  /* output signal */
MYFLT freq = *p->in1;
MYFLT amp= *p->in2;

retrun OK;
}

That’s ignoring all the other stuff going on in the opcode but yeah, it changes pitch now when I change midi notes!
Sick :call_me_hand:

I’m glad you got it sorted. I still can’t see why it didn’t work. Your opcode is only running for the duration of the note. When the note ends, it’s cleared and its memory is freed. Therefore the freq value should update fine on each new note. However, accessing the freq in the perf function means your opcode can now handle k-rate parameters which makes it more versatile :+1: