User-written C procedures should go into a file called userprocs.c. This file is linked in to the aprlwish program by the Makefile provided with APRL. If you add user functions in other files, you will need to modify the Makefile.
Sections:
The inputs i1,i2,... must be in a comma-separated list with no spaces.
If sample rate is not specified, it defaults to the fastest sample rate among the input sources.
If buffer time is not specified, it defaults to the longest among the inputs.
The global variables num_cfuncs and cnames are used to register new C procedures with APRL. cnames is an array of type name_table, which is struct { char *name; UserFunc *func; } -- a string containing the name of the function and a pointer to the function itself.
The cnames[].name field is the name by which the new procedure is referred to in the APRL code. It is not necessary that the name provided in this field be identical to the name given the function in C, but it makes the code cleaner if there is an obvious relationship.
num_cfuncs should specify the number of new commands being registered in the cnames structure. An example cnames declaration might look like this:
UserFunc my_first_function,my_second_function; name_table cnames[] = { {"func1",&my_first_function}, {"func2",&my_second_function} } ;
The UC_parm type is as follows:
typedef struct { char *name; int length; DATA *s; double samplerate; } UC_parm;The name field contains a string with the name of the source or pipe object whose output is connected to the input of this object.
The length field tells how many samples of data are available at this time from this source. This number will vary from iteration to iteration; it is dependant on the sampling rate of the source, but also the various buffer sizes of "upstream" sources, and the current processing load on the machine.
The s field contains an array of samples, where s[0] is the earliest sample in time.
The samplerate field contains the sampling rate of the source.
void gate(UC_parm *parms,UC_parm *retval,int ct) { /* parms[0] is an audio signal, parms[1] is a control signal. pass the audio signal through to the output whenever the control signal is above THRESH this is a multirate process; the audio signal is assumed to be at a higher sampling rate than the control signal. */ int i,j,pos; double dsfactor; /* allocate space for the returned data */ retval->s = (DATA *)calloc(retval->length,sizeof(DATA)); /* calculate the rate ratio of the two inputs */ dsfactor = parms[0].length / parms[1].length; pos = 0; for (i=0;i!=parms[1].length;i++) { /* for each sample in the control signal */ for (j=0;jThere are a few important points to highlight. This function is running at the sampling rate of the faster (audio) input. The default sampling rate for a user command is that of the fastest of its inputs; if another sampling rate is desired, the length should be set appropriately in the *retval structure, and the other sampling rate specified on the APRL command line (see Calling User Commands from APRL ).THRESH) /* and do the gating */ retval->s[pos] = parms[0].s[pos]; else retval->s[pos] = 0; pos++; } } }
Also, notice that the retval->s array is not pre-allocated. We use calloc() to create space for it. free() is called on the retval->s pointer upon return if non-NULL, so it is important that the value be set to NULL if the return value isn't being used.
The samples of data are of type DATA; they can be added, multiplied, compared, etc using the normal operators.
It is not necessary to set the name and samplerate value for the retval structure. It IS necessary to set the length value, though, as it is used upon return.