| I discovered a malfunction of the trigseq opcode, when the ktime_unit
argument is changed at k-rate. Also I updated the behavior of trigseq,
in that it now outputs zeroes and the scaled time values of the table,
instead of simply zeroes and ones as trigger signal. In this way, it is
possible to use the time values for eventual durations of triggered events.
I also added trigseq2, an opcode very similar to trigseq, except it can
be reinitialized by a trigger signal input.
/////// MANUAL ///////////
Sequence-timing-related opcodes
-------------------------------
ktrig seqtime ktime_unit, kstart, kloop, initndx, kfn_times
ktrig seqtime2 ktrig_in, ktime_unit, kstart, kloop, kinitndx, kfn_times
DESCRIPTION
Handle timed-sequences of groups of values stored into tables.
INITIALIZATION
initndx - initial index
PERFORMANCE
kinitndx - reinit starting index
ktrig - output trigger signal (alterates zeros and current time element
values)
ktime_unit - unit of measure of time, related to seconds.
kstart - start index of looped section
kloop - end index of looped section
kfn_times - number of table containing a sequence of times
kfn_values - numer of a table containing a sequence of groups of values
ktrig_in - input tirgger signal
These opcodes handle timed-sequences of groups of values stored into tables.
seqtime generates a trigger signal (a sequence of impulses, see also
trigger opcode), according to the values stored in kfn_times table. This
table should contain a series of delta-times (i.e. times beetween to
adiacent events). The time units stored into table are expressed in
seconds, but can be rescaled by means of ktime_unit argument. The table
can be filled with GEN02 or by means of an external text-file containing
numbers, with GEN23. It is possible to start the sequence from a value
different than the first, by assigning to initndx an index different
than zero (which corresponds to the first value of the table). Normally
the sequence is looped, and the start and end of loop can be adjusted by
modifying kstart and kloop arguments. User must be sure that values of
these arguments (as well as initndx) correspond to valid table numbers,
otherwise Csound will crash (because no range-checking is
implementeted). It is possible to disable loop (one-shot mode) by
assigning the same value both to kstart and kloop arguments. In this
case, the last read element will be the one corresponding to the value
of such arguments. Table can be read backward by assigning a negative
kloop value. It is possible to trigger two events almost at the same
time (actually separated by a k-cycle) by giving a zero value to the
corresponding delta-time. First element contained in the table should be
zero, if the user intend to send a trigger impulse it immediately after
the orchestra instrument containing seqtime opcode. seqtime outputs a
stream of zeroes except when a new time value stored in the table is
reached. In this case the ktrig argument is filled with the time value,
scaled according to current ktime_unit value.
seqtime2 is similar to seqtime, the difference is that when ktrig_in
contains a non-zero value, current index is reset to kinitndx value.
kinitndx can be varied at performance time.
////////// entry.c ///////////////////
{ "seqtime", S(SEQTIM), 3, "k", "kkkkk", seqtim_set, seqtim,
NULL },
{ "seqtime2", S(SEQTIM2), 3, "k", "kkkkkk", seqtim2_set,
seqtim2, NULL},
////////// seqtime.h /////////////
typedef struct {
OPDS h;
MYFLT *ktrig, *unit_time, *kstart, *kloop, *initndx, *kfn;
long ndx;
int done, first_flag;
double start, newtime;
long pfn;
MYFLT *table, curr_unit_time;
} SEQTIM;
typedef struct {
OPDS h;
MYFLT *ktrig, *ktrigin, *unit_time, *kstart, *kloop, *kinitndx, *kfn;
long ndx;
int done, first_flag;
double start, newtime;
long pfn;
MYFLT *table, curr_unit_time;
} SEQTIM2;
/////////////// seqtime.c ///////////////
void seqtim_set(SEQTIM *p) /* by G.Maldonado */
{
FUNC *ftp;
long start, loop;
long *ndx = &p->ndx;
p->pfn = (long) *p->kfn;
if ((ftp = ftfind(p->kfn)) == NULL) {
initerror(Str(X_1536,"seqtime: incorrect table number"));
return;
}
*ndx = (long) *p->initndx;
p->done = 0;
p->table = ftp->ftable;
if (p->ndx > 0)
p->newtime = p->table[p->ndx-1];
else
p->newtime = 0;
p->start = kcounter * onedkr ;
start = (long) *p->kstart;
loop = (long) *p->kloop;
if (loop > 0) {
*ndx %= loop;
if (*ndx == 0) {
*ndx += start;
}
}
else if (loop < 0) {
(*ndx)--;
while (*ndx < start) {
*ndx -= loop + start;
}
}
p->curr_unit_time = *p->unit_time;
p->first_flag= 1;
}
void seqtim(SEQTIM *p)
{
if (p->done)
*p->ktrig=FL(0.0);
else {
long start = (long) *p->kstart, loop = (long) *p->kloop;
long *ndx = &p->ndx;
if (p->pfn != (long)*p->kfn) {
FUNC *ftp;
if ((ftp = ftfindp(p->kfn)) == NULL) {
perferror(Str(X_1536,"seqtime: incorrect table number"));
return;
}
p->pfn = (long)*p->kfn;
p->table = ftp->ftable;
}
if (p->curr_unit_time != *p->unit_time) {
double constant = p->start - kcounter * onedkr;
double difference_new = p->newtime * p->curr_unit_time +
constant;
double difference_old = p->newtime * *p->unit_time +
constant;
double difference = difference_new - difference_old;
p->start = p->start + difference;
p->curr_unit_time = *p->unit_time;
}
if (kcounter * onedkr > p->newtime * *p->unit_time + p->start) {
float curr_val = p->table[p->ndx];
p->first_flag = 0;
p->newtime += curr_val;
if (loop > 0) {
(*ndx)++;
*ndx %= loop;
if (*ndx == 0){
if (start == loop) {
p->done = 1;
return;
}
*ndx += start;
}
}
else if (loop < 0 ){
(*ndx)--;
while (p->ndx < 0) {
if (start == loop) {
p->done = 1;
return;
}
*ndx -= loop + start;
}
}
*p->ktrig = curr_val * p->curr_unit_time;
}
else {
if(p->first_flag) {
*p->ktrig = p->table[p->ndx];
p->first_flag=0;
}
else {
*p->ktrig=FL(0.0);
}
}
}
}
/**---------------------------------------**/
void seqtim2_set(SEQTIM2 *p)
{
FUNC *ftp;
long start, loop;
long *ndx = &p->ndx;
p->pfn = (long) *p->kfn;
if ((ftp = ftfind(p->kfn)) == NULL) {
initerror("seqtim: incorrect table number");
return;
}
*ndx = (long) *p->kinitndx;
p->done=0;
p->table = ftp->ftable;
p->newtime = p->table[p->ndx];
p->start = kcounter * onedkr ;
start = (long) *p->kstart;
loop = (long) *p->kloop;
if (loop > 0 ) {
(*ndx)++;
*ndx %= loop;
if (*ndx == 0) {
*ndx += start;
}
}
else if (loop < 0 ){
(*ndx)--;
while (*ndx < start) {
*ndx -= loop + start;
}
}
p->curr_unit_time = *p->unit_time;
p->first_flag=1;
}
void seqtim2(SEQTIM2 *p)
{
if (*p->ktrigin ){
p->ndx = (long) *p->kinitndx;
}
if (p->done)
goto end;
else {
long start = (long) *p->kstart, loop = (long) *p->kloop;
long *ndx = &p->ndx;
if (p->pfn != (long)*p->kfn) {
FUNC *ftp;
if ( (ftp = ftfindp(p->kfn) ) == NULL) {
perferror("seqtim: incorrect table number");
return;
}
p->pfn = (long)*p->kfn;
p->table = ftp->ftable;
}
if (p->curr_unit_time != *p->unit_time) {
double constant = p->start - kcounter * onedkr;
double difference_new = p->newtime * p->curr_unit_time +
constant;
double difference_old = p->newtime * *p->unit_time +
constant;
double difference = difference_new - difference_old;
p->start = p->start + difference;
p->curr_unit_time = *p->unit_time;
}
if (kcounter * onedkr > p->newtime * *p->unit_time + p->start) {
float curr_val = p->table[p->ndx];
p->newtime += p->table[p->ndx];
if (loop > 0 ) {
(*ndx)++;
*ndx %= loop;
if (*ndx == 0){
if (start == loop) {
p->done =1;
return;
}
*ndx += start;
}
}
else if (loop < 0 ){
(*ndx)--;
while (p->ndx < 0) {
if (start == loop) {
p->done =1;
return;
}
*ndx -= loop + start;
}
}
*p->ktrig = curr_val * p->curr_unit_time;
}
else {
if(p->first_flag) {
*p->ktrig = p->table[p->ndx];
p->first_flag=0;
}
else {
end:
*p->ktrig=FL(0.0);
}
}
}
}
--
Gabriel Maldonado
http://csounds.com/maldonado
--
|