Digital Music Programming II: duration
This lab demonstrates how to measure the time difference between
note-ons and note-offs so that the duration of notes can be determined.
The duration object given below has two inputs and two outputs:
Inputs | Outputs |
1. MIDI Note Number | 1. MIDI Note Number |
2. MIDI Attack Velocity | 2. duration in milliseconds |
The duration object keeps track of all 128 MIDI notes and
determines whether they are on or off. If an incoming note message
is a note-on message, then the duration object will store
the time that the note-on message came in. When a note-off message
comes into the object, the time when the note was played will be
subtracted from the current time which will then be sent out of the
object as the note's duration in milliseconds.
To remember the note-on times, the duration object
has an array of 128 longs called ontimes. When a note-on
is received by the object, the time will be stored in the ontimes
array based on the key number which ranges from 0 to 127. When a note-off
message comes for the same key, then the object will check to see when the
last note-on message came for that key in the ontimes array.
duration.c
#include "ext.h"
typedef struct {
t_object max_data;
long ontimes[127];
long velin;
void* outputKeyNumber;
void* outputDuration;
} MyObject;
void* object_data = NULL;
void* create_object (void);
void InputKeyNumber (MyObject* mo, long value);
void InputVelocity (MyObject* mo, long value);
void MessageClear (MyObject* mo);
long midilimit (long value);
void main(void) {
setup((t_messlist**)&object_data, (method)create_object,
NULL, sizeof(MyObject), NULL, A_NOTHING);
addint ((method)InputKeyNumber);
addinx ((method)InputVelocity, 1);
addmess((method)MessageClear, "clear", A_NOTHING);
}
void* create_object(void) {
MyObject* mo = (MyObject*)newobject(object_data);
MessageClear(mo);
mo->velin = 0;
mo->outputDuration = intout(mo);
mo->outputKeyNumber = intout(mo);
intin(mo, 1);
return mo;
}
void InputKeyNumber(MyObject* mo, long value) {
long curtime = gettime();
value = midilimit(value);
if (mo->velin == 0 && mo->ontimes[value] >= 0) {
outlet_int(mo->outputDuration, curtime - mo->ontimes[value]);
outlet_int(mo->outputKeyNumber, value);
mo->ontimes[value] = -1;
} else if (mo->velin > 0 && mo->ontimes[value] >= 0) {
outlet_int(mo->outputDuration, curtime - mo->ontimes[value]);
outlet_int(mo->outputKeyNumber, value);
mo->ontimes[value] = curtime;
} else if (mo->velin > 0) {
mo->ontimes[value] = curtime;
}
}
void InputVelocity(MyObject* mo, long value) {
mo->velin = value;
}
void MessageClear(MyObject* mo) {
int i;
for (i=0; i<128; i++) {
mo->ontimes[i] = -1;
}
}
long midilimit(long value) {
if (value < 0) return 0;
if (value > 127) return 127;
return value;
}
|
Exercises
- Create the following patch to test the duration object.
Play somes notes and see if the notes have about the right
durations. You might need to select the option Overdrive to
get accurate results on a slow computer.
- Use the duration information from the duration object
in a musical manner. For example, use the durations to control tempo, or
the notes to be divided into functions depending on their durations --
such as short notes would cause staccato textures, and longer durations
would cause legato textures.
- Take the duration output from the duration object and
quantize it to a set of rhythms, such as quarter note, sixteenth note, eighth
note, etc.
|