source: sbliveos2/trunk/drv16/midimsg.cpp@ 660

Last change on this file since 660 was 142, checked in by ktk, 25 years ago

Import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.0 KB
Line 
1/* $Id: midimsg.cpp 142 2000-04-23 14:55:46Z ktk $ */
2
3/* SCCSID = %W% %E% */
4/****************************************************************************
5 * *
6 * Copyright (c) IBM Corporation 1994 - 1997. *
7 * *
8 * The following IBM OS/2 source code is provided to you solely for the *
9 * the purpose of assisting you in your development of OS/2 device drivers. *
10 * You may use this code in accordance with the IBM License Agreement *
11 * provided in the IBM Device Driver Source Kit for OS/2. *
12 * *
13 ****************************************************************************/
14/**@internal %W%
15 * MIDIMSG object implementation.
16 * @version %I%
17 * @context
18 * Unless otherwise noted, all interfaces are Ring-0, 16-bit, kernel stack.
19 * @notes
20 * For reference, this is the format of the IBM Sysex command. Many more
21 * commands are defined by the IBM MMPM/2 command reference, but the subset
22 * noted here is all that is implemented. Most of the other commands are
23 * historical for an IBM proprietary sound card, now withdrawn from market.
24 *
25 * Sysex command format: F0 00 00 3A cmd [ subCmd | data ] data *
26 *
27 * cmd subCmd (cmdName) Data
28 * ------------- ----------- ---------------------------------
29 * 1 tc long lsb msb (discard *)
30 * 3 1 ppqn ctl (discard 1) PPQN_byte (discard *)
31 * 3 2 tempo lsb msb
32 * 7-127 tc short (none)
33 *
34 * 'tc' = time compression
35 *
36 * @history
37 */
38
39#ifndef OS2_INCLUDED // Doesn't like being included twice.
40extern "C" { // 16-bit header files are not C++ aware
41 #define INCL_NOPMAPI
42 #include <os2.h>
43}
44#endif // end OS2_INCLUDED
45
46#include <string.h> // _fmemcpy()
47#include "maudio.hpp" // Object definition MIDIAUDIO
48#include "midimsg.hpp" // Object definition
49
50
51/**@external eMidiByteType
52 * Determine the type of the Midi status byte.
53 * @param MIDIBYTE b
54 * @return MIDIBYTETYPE, as enumerated in midimsg.hpp.
55 * @notes Ref. .hpp file for definition of the enumerated values.
56 */
57MIDIBYTETYPE eMidiByteType( MIDIBYTE b )
58{
59 if (b < 0x80)
60 return MBT_Data;
61 else if (b < 0xF0)
62 return MBT_ChannelStatus;
63 else if (b == 0xF0)
64 return MBT_Sysex;
65 else if (b < 0xF8)
66 return MBT_SystemCommon;
67 else
68 return MBT_SystemRT;
69}
70
71
72// Do we have a complete message?
73BOOL MIDIMSG::isComplete( void )
74{
75 int expectedLength = _queryExpectedLength();
76 return (expectedLength > 0) && (_length >= expectedLength) ;
77}
78
79
80// Is the message unsupported?
81BOOL MIDIMSG::isUnsupported( void )
82{
83 return _queryExpectedLength() < 0;
84}
85
86
87// Concatenate 1 byte to end of message.
88VOID MIDIMSG::addByte( MIDIBYTE b )
89{
90 if (_length < MAX_MidiMsgLen) {
91 _msg[ _length ] = b;
92 ++ _length;
93 }
94}
95
96
97// Flush message to a MIDI hardware object using writeByte() method.
98VOID MIDIMSG::flush( MIDIAUDIO* pmhw )
99{
100 for ( int i=0; i<_length; ++i) pmhw->writeByte( _msg[i] );
101}
102
103
104/**@external MIDIMSG::discardSignature
105 * Delete the IBM signature prefix from the front of an IBM Sysex msg,
106 * shift the remaining bytes to the front of the string.
107 * @notes We assume that the IBM signature is there; we don't check for it.
108 */
109VOID MIDIMSG::discardSignature( void )
110{
111 for (int i=0; i < _length; ++i) {
112 _msg[i] = _msg[i + IBMSysexSigLen];
113 }
114 _length -= IBMSysexSigLen;
115}
116
117
118/**@internal MIDIMSG::_queryExpectedLength()
119 * Given a status byte, returns expected length of a message,
120 * (including the status byte).
121 * @param None. Examines _msg[].
122 * @return int >0 - Expected length of complete message.
123 * @return int 0 - Don't have enough bytes to determine length
124 * of complete message.
125 * @return negative int MIDIMSG_Err_NotStatus when 1st byte in
126 * message isn't a status byte.
127 * @return negative int MIDIMSG_Err_BadSysex when buffered message
128 * is recognized as an unsupported IBM sysex.
129 * @notes A nonzero value for _expectedLength indicates we've already
130 * computed this. We'll use it if we've got it, otherwise we'll compute
131 * it and save the value.
132 */
133int MIDIMSG::_queryExpectedLength( void )
134{
135 MIDIBYTE b;
136 int iResult;
137
138 // Check if already figured out the expected length. Once the expected
139 // message length is computed for a given message, it doesn't change.
140 // This function is called for every byte received, can optimize here.
141 if (_expectedLength) {
142 return _expectedLength;
143 }
144
145 b = _msg[0];
146 switch( eMidiByteType( b )) {
147 case MBT_ChannelStatus:
148 {
149 int cmdIndex = (b >> 4) - 8; // Transform 0x80..0xE0 to 0..6
150 static UCHAR channelMsgLen[] = { 3, 3, 3, 3, 2, 2, 3 };
151 iResult = channelMsgLen[ cmdIndex ];
152 }
153 break;
154
155 case MBT_Sysex:
156 iResult = _queryExpectedSysexLength();
157 break;
158
159 case MBT_SystemCommon:
160 {
161 int cmdIndex = (b & 7) - 1; // Transform 0xF1..0xF7 to 0..6
162 static UCHAR sysMsgLen[] = { 2, 3, 2, 1, 1, 1, 1 };
163 iResult = sysMsgLen[ cmdIndex ];
164 }
165 break;
166
167 case MBT_SystemRT:
168 iResult = 1; // All 0xF8 - 0xFF are 1 byte.
169 break;
170
171 case MBT_Data:
172 default:
173 iResult = MIDIMSG_Err_NotStatus;
174 break;
175 }
176
177 _expectedLength = iResult;
178 return iResult;
179}
180
181
182/**@internal MIDIMSG::_queryExpectedSysexLength
183 * Returns expected length of an IBM sysex command (incl. signature prefix).
184 * @param None. Examines _msg[].
185 * @return int Expected length of IBM sysex command.
186 * @return 0 If command cannot be determined (some commands
187 * require several command bytes).
188 * @return negative int MIDIMSG_Err_BadSysex If this is a Sysex command that
189 * we don't handle.
190 * @notes The expected return length includes the length of the IBM Sysex
191 * signature prefix, but not the 0xF7 "EOX" byte. The length returned
192 * counts only up to the number of bytes we need to interpret the command,
193 * which might not be all the bytes in the message definition.
194 */
195int MIDIMSG::_queryExpectedSysexLength( void )
196{
197 MIDIBYTE b1 = _msg[ IBMSysexSigLen ]; // First Sysex cmd byte.
198 MIDIBYTE b2 = _msg[ IBMSysexSigLen+1 ]; // Second Sysex cmd byte.
199
200 if (_length <= IBMSysexSigLen)
201 return 0;
202
203 switch( b1 ) {
204 case 1: // Timing compression Long: 2 data bytes follow.
205 return IBMSysexSigLen + 3;
206 case 7: // Timing compression short: No data bytes.
207 return IBMSysexSigLen + 1;
208 case 3: // Device driver control.
209 if (_length <= IBMSysexSigLen+1) // Have 2nd cmd byte? Return 0 if not.
210 return 0;
211 else if (b2 == 1)
212 return IBMSysexSigLen + 4;
213 else if (b2 == 2)
214 return IBMSysexSigLen + 4;
215 else
216 return MIDIMSG_Err_BadSysex;
217 default:
218 return MIDIMSG_Err_BadSysex;
219 }
220}
221
Note: See TracBrowser for help on using the repository browser.