Douglas Lyon
Fall 1995
© IEEE Computer Society Press.


1.1.1. Note On

The Note On message indicates a key event. The Note On status word is a number which ranges from 144-159. The MIDI specification uses base two to describe the status words. This has led many programmers (including this author) to write cryptic bit-masking code. While this is very machine efficient, it makes the code less clear. Suffice it to say, therefore, that the least significant 4 bits are used to signify the channel number. Decimal status words and channel numbers for the Note On message are shown in Figure 1.1.1-1.

Figure 1.1.1-1 MIDI Channel Voice Message Note On Status Word

The least significant four bits of a status word are used to signify the channel number. Channel_number = Status_word -143.

The Note On status must be followed by two bytes. These are called the Key Number and the attack velocity. The Key Number ranges from 0-127, with the number 60 indicating middle C. The Key Number DIV 12 is the octave. For example, Key Number 91 is 91 DIV 12 or octave number 7. There are 127 DIV 12 or 10 octaves in all. Key Number MOD 12 is the note class. The relationship between note class and note name is given in Figure 1.1.1-2 [Valenti 1988].

Figure 1.1.1-2 Note Class and Note Name

Channel_number = status_word - 143.

Figure 1.1.1-3 Note Numbers and Note Names

Key_number mod 12 can be used to index a string array which contains the note names. Octave = Note_number DIV 12.

The attack velocity ranges from 0-127. Non-dynamic keyboards (i.e., those which do not sense velocity) typically send a velocity of 64. If the velocity is set to 0, the effect is to turn the note off.

Example 1: 148, 60, 64,148, 60, 0; note on channel 5, note # 60 (middle C), velocity 64, note on channel 5, note number 60, velocity 0 (i.e., turn off the note).

Example 2: 144, 96, 72, 144, 48, 104; note on channel 1, note #96, velocity 72, note on channel 1, note #48, velocity 104.

Example 3: 144, 48, 104; note on channel 1, note #48, velocity 104.

It is possible to merge two MIDI streams. Suppose Example 2 and Example 3 come from two such MIDI streams. They may be merged with or without the use of the running status;

Example 4 Merge Example 3 and 2 without running status: 144, 48, 104, 144, 96, 72, 144, 48, 104; note on channel 1, note #48, velocity 104, note on channel 1, note #96, velocity 72, note on channel 1, note #48, velocity 104.

Example 5 Merge Example 3 and 2 with running status: 144, 96 72 48 104, note on, note #96, velocity 72, note #48, velocity 104.

Example 5 illustrates the running status property that a new status byte does not have to be sent until the status changes [Clark 1990]. The running status is permitted by BNF rule 5 in section 1. Rule 12 of the BNF permits insertion of real-time messages.

See section 2. MIDI and ZIPI for more discussion on merging.

There is an exception to the note number names which have been mentioned so far. The General MIDI Specification 1.0 indicates that channel 10 is to be used for drum sounds. On this channel a General MIDI Percussion Key Map may apply (depending on the abilities of the MIDI instruments). This is shown in Figure 1.1.1-4.

Figure 1.1.1-4. General MIDI Percussion Key Map.

This applies only to channel 10, which is reserved for percussion by the General MIDI Specification.

An introduction to MIDI must make some assumptions about the expertise of the reader. In the following example, the reader should have a good working knowledge of C and have access to an ANSI C library and compiler. The code is written to be portable to any platform as it does no direct MIDI output. Any program which does do direct MIDI output cannot be ported without change. The computer science community would be well served if there were a MIDI standard library of calls, but that is beyond the scope of this primer.

The following code ignores the General MIDI Specification regarding percussive instrument assignment on channel 10. The most general approach is probably to place a MIDI implementation chart into a machine readable form so that a program can automatically update these special parameters. This is a parsing problem which is beyond the scope of this primer.

/* A zeroth order stochastic MIDI program using structures */
/*

Note# Status Note Name  Channel   #: Instrument
   70   150     A#      Channel   7:Flute
   53   149     F       Channel   6:Brass Ensemble
   97   145     C#      Channel   2:Harpsichord
   71   151     B       Channel   8:Chorus
   35   147     B       Channel   4:Jazz Organ
   39   151     D#      Channel   8:Chorus
   36   148     C       Channel   5:Pipe Organ
   14   158     D       Channel  15:Accordion
   24   152     C       Channel   9:Bells
   23   151     B       Channel   8:Chorus
   83   147     B       Channel   4:Jazz Organ
   */
#include
#include
#include
#define number_of_events 127
struct event_struct {
char *note_name;
int note_number;
char *channel_name;
int channel_number;
}; /* end event_struct */
typedef struct event_struct event_type;
void initialize_event_array(event_type *event_pointer, char *[], char *[]);
void randomize_event_array(event_type *);
void print_event_array(event_type *);
int main(void)
{
event_type event_array[number_of_events+1];
char *note_name_array[] =
{"C", "C#", "D", "D#", "E",
"F", "F#", "G", "G#", "A",
"A#", "B"
}; /* end note_name_array */
char *channel_name_array[] =
{
"Piano ",
"Harpsichord ",
"Vibes ",
"Jazz Organ ",
"Pipe Organ ",
"Brass Ensemble ",
"Flute ",
"Chorus ",
"Bells ",
"Drums ",
"Electric Piano ",
"Funky Clavi ",
"Jazz Guitar ",
"Organ ",
"Accordion ",
"Strings "
}; /* end channel_name_array */
/* initialize the random function */
srand(time(NULL));
initialize_event_array(event_array, note_name_array, channel_name_array);
randomize_event_array(event_array);
print_event_array(event_array);
return 0;
} /* end main */
void initialize_event_array(
event_type *array_of_event_type,
char *note_name_array[],
char *channel_name_array[])
{
int i;
for (i = 0; i <= number_of_events; i++)
{
array_of_event_type[i].note_name = note_name_array[i % 12];
array_of_event_type[i].note_number = i;
array_of_event_type[i].channel_name = channel_name_array[i % 16];
array_of_event_type[i].channel_number = (i % 16) + 1;
} /* end for */
} /* end initialize_note_array */
void randomize_event_array(event_type *array_of_event_type)
{
int i, j;
event_type temp_event;
for (i = 0; i <= number_of_events; i++)
{
j = rand() % number_of_events;
temp_event = array_of_event_type[i];
array_of_event_type[i] = array_of_event_type[j];
array_of_event_type[j] = temp_event;
} /* end for */
} /* end randomize_note_array */
void print_event_array(event_type *array_of_event_type)
{
int i;
printf("Note# Status Note Name Channel #: Instrument\n");
for (i = 0; i <= 10; i++) /* reduced to 10 for printing */
printf("%5d%6d\t%s\tChannel%4d:%s\t\n",
array_of_event_type[i].note_number,
array_of_event_type[i].channel_number + 143,
array_of_event_type[i].note_name,
array_of_event_type[i].channel_number,
array_of_event_type[i].channel_name
);
} /* end print_note_array */


[ Index | Main Paragraph | Next Paragraph ]