source: buchla-68k/orig/GEMDOS/MIDIVIEW.TXT@ f40a309

Last change on this file since f40a309 was 3ae31e9, checked in by Thomas Lopatic <thomas@…>, 7 years ago

Imported original source code.

  • Property mode set to 100755
File size: 6.6 KB
Line 
1HOW IT WORKS
2
3MIDIVIEW is written in Megamax C, the language of choice among ST
4developers, though it can be easily modified to work with any C that
5has hooks to GEM and the XBIOS functions. The program was my first
6attempt at programming in C, as well as my first serious ST MIDI
7program (can any ST BASIC program be considered serious?), a double
8challenge that was made much simpler by the convenience of the ST's
9built in MIDI ports, and much tougher by the lack of good
10documentation on using GEM and accessing the MIDI ports. The two
11toughest parts of the program were modifying the ST's MIDI buffer and
12figuring out which GEM calls to use to start and end the program, but
13once these chores were done, the program practically wrote itself,
14according to the rules set down in the MIDI Detailed Specification.
15
16The function main() calls a series of preparatory functions before
17calling view_midi(), which is the heart of the program. init_gem()
18does the minimal amount of work needed to get a simple program like
19this started from the desktop, and is not much different than what's
20used it other programs of this sort. midi_buffer(), which establishes
21a new and larger buffer for the ST's MIDI input is a much more
22interesting function, and is explained in detail below. The calls to
23form_alert(), v_hide_c(), and v_clrwk() are standard GEM syntax, and
24are explained fully in the Megamax documentation. The two Cconout()
25calls send an "Esc H" sequence to the ST's keyboard processor, which
26positions the text cursor in the upper left corner of the screen, and
27flush_buffer() clears out the contents of the MIDI buffer before
28view_midi() is called. When you're done examining MIDI data, the
29program restores the original MIDI buffer, and ends with the usual GEM
30calls.
31
32Since the program displays data much more slowly than it can be
33received via MIDI, a relatively large input buffer is needed to avoid
34an overflow situation. The ST's default MIDI buffer is a paltry 128
35bytes, hardly up to the task, but it is possible to modify the size
36and location of this buffer using the XBIOS function Iorec().
37midi_buffer() handles the task of allocating memory for the new
38buffer, saving the location and size of the old buffer, and telling
39the op system to use the new buffer. Similarly, old_buffer() undoes
40the work of midi_buffer(). MIDIVIEW uses the ST's maximum 32K MIDI
41buffer size, though you can probably get by with less in most cases.
42
43view_midi(), which comprises the program's main loop, is made up of
44two nested while() loops, one of which watches for the Control key to
45be pressed, while the other looks for the Alternate key. The GEM
46function graf_mkstate() modifies the external variable gr_mkkstate,
47which holds the status of the Control, Alternate, and Shift keys, as
48well as the left and right mouse buttons. As long as the Control key
49is not pressed, the outer loop is executed, and if the Alternate key
50is pressed, the program goes into a very tight loop and waits for the
51key to be released. Next the status of the Shift keys are checked,
52and if one was pressed, the flag for the Active Sense/Clock filter is
53toggled. This part of the function also checks to make sure that the
54current keyboard state is not the same as it was the last time through
55the loop, which would result in the filter flag being toggled
56repeatedly and unpredictably.
57
58With the keyboard thoroughly scanned, the program checks the ST's MIDI
59input for unprocessed data. If a byte has been received, from_midi()
60is called, which gets a word from the input buffer and masks the upper
61byte, thereby converting the number to the standard eight bit format
62used by MIDI. If filtering is turned off, or if the byte is not a
63Clock or Active Sense message, the program calls print_midi(), which
64processes the data with a call to interpret(), and then prints the
65data byte, its index, and its interpretation.
66
67interpret(), in its turn, simply determines whether the byte is a
68status byte or a data byte, before calling a function to interpret the
69byte. The job of actually translating each byte to an appropriate
70English description is handled by the functions num_to_status(),
71num_to_note(), num_to_cc(), num_to_pb(), num_to_spp(), and
72type_to_text(), each of which operates on a different type of data.
73Unfortunately, the arrangement of status bytes, message lengths, and
74meanings doesn't really exhibit any helpful patterns in MIDI, so there
75is no simple way to index the various interpretations according the
76the current status byte.
77
78Rather than construct some elegant scheme to allow the use of
79indexing, I used a brute force method based around the switch()
80statement and arbitrarily assigned a type number to groups of
81otherwise unrelated messages that have similar interpretations. For
82instance, the data bytes of a Program Change, Song Select, Channel
83Pressure, or System Exclusive message are best represented as a number
84between 0 and 127, so these messages are grouped together as type 4.
85When a type 4 data byte is received, the function type_to_text is
86called, which prints a generic label for data bytes of a number of
87types that don't require much in the way of processing. Many data
88types are handled by a single function this way, simply to keep the
89number of functions to a manageable level.
90
91The program also maintains one other external variable that modifies
92the interpretation of a data byte, called byte_num, which simply
93counts the number of bytes in the current message, based on the
94requirements of the most recent status byte. byte_num is reset to 1
95whenever a status byte is received, unless the status byte is a System
96Real Time message. The MIDI spec allows timing-related messages as
97Start, Stop, and Clock to be inserted in the middle of a running
98status message, without the need to send a new status byte, though few
99instruments actually use this "loophole", and some machines seem to
100have occasional problems with it.
101
102Of the interpretation functions themselves, only num_to_pb() and
103num_to_spp(), which handle Pitch Bend and Song Pointer messages, hold
104any surprises. The two data bytes for these message types are
105combined by the program to produce a single interpretation. Pitch
106Bend data bytes are simply converted to a 14 bit signed integer, but
107Song Pointer messages are translated to a measure:beat:step format.
108The function assumes the standard MIDI clock resolution of 24 PPQN
109(pulses per quarter note) is in use, and that a measure consists of
110four quarter notes -- both of which are valid assumptions for 95% of
111all music being made today, but which could lead to mild confusion in
112other cases.
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
Note: See TracBrowser for help on using the repository browser.