source: cmedia/trunk/Drv16/fmassign.cpp@ 354

Last change on this file since 354 was 354, checked in by stevenhl, 17 years ago

Import untested baseline cmedia sources, work products and binaries
Binaries and work products should be deleted from repository.
once new builds are verified to work.

File size: 11.0 KB
Line 
1/* SCCSID = src/dev/mme/tropez/fmassign.cpp, tropez, c.basedd 97/07/17 */
2/****************************************************************************
3 * *
4 * Copyright (c) IBM Corporation 1994 - 1997. *
5 * Copyright (c) Voyetra Technologies 1990-1993. All rights reserved *
6 * *
7 * The following IBM OS/2 source code is provided to you solely for the *
8 * the purpose of assisting you in your development of OS/2 device drivers. *
9 * You may use this code in accordance with the IBM License Agreement *
10 * provided in the IBM Device Driver Source Kit for OS/2. *
11 * *
12 ****************************************************************************/
13/**@internal src/dev/mme/tropez/fmassign.cpp, tropez, c.basedd
14 * Allocation of FM synth resources to note generation.
15 * @version 1.2
16 * @context
17 * Unless otherwise noted, all interfaces are Ring-0, 16-bit, kernel stack.
18 * @notes
19 * @history
20 */
21
22extern "C" {
23#include <os2.h>
24#include <os2medef.h>
25#include <ssm.h>
26#include <audio.h>
27#include <meerror.h>
28#include "fmadlib.h"
29#include "fmglobal.h"
30}
31#include "fmsynth.hpp"
32
33#define MAX_NUMBER_OF_DRUM_OPERATORS 3
34
35/////#pragma message("this allocation wastes space..")
36/* MAX_NUMBER_OF_OPERATORS is the total possible number of voices */
37/* MAX_NUMBER_OF_DRUM_OPERATORS is a subset of all the voices */
38/* and are treated different here but not in other array with */
39/* MAX_NUMBER_OF_OPERATORS entries in them */
40
41static OFF_ENTRY near note_q_data[MAX_NUMBER_OF_OPERATORS] = {0};
42static OFF_ENTRY near drum_q_data[MAX_NUMBER_OF_DRUM_OPERATORS] = {0};
43
44static VOICE_STATUS_ENTRY note_op_stats[MAX_NUMBER_OF_OPERATORS] = {0};
45static VOICE_STATUS_ENTRY drum_op_stats[MAX_NUMBER_OF_DRUM_OPERATORS] = {0};
46
47ALLOC_Q note_q = {0, 0, 0, 0, note_q_data, note_op_stats};
48ALLOC_Q drum_q = {0, 0, 0, 0, drum_q_data, drum_op_stats};
49
50
51
52static char is_sused[MAX_NUMBER_OF_OPERATORS];
53
54/* do_sus_off(op)
55 * Shut off operator op if sustaining. the little guy
56 */
57void FMSYNTH::do_sus_off(int op)
58{
59 if (is_sused[op])
60 {
61 shut_off_chan_voice(op);
62 is_sused[op] = 0;
63 }
64}
65
66
67/* for_all_ops_on_chan(function)
68 * Calls named function for each operator which is currently
69 * playing and is on given channel
70 * called only for note_q!
71 *
72 */
73void FMSYNTH::for_all_ops_on_chan(BYTE mchan, int functionID)
74{
75 int curptr;
76
77 curptr = note_q.usedlist;
78 while (curptr >= 0)
79 {
80 register int tptr = curptr;
81 curptr = note_q_data[curptr].next;
82 if (note_op_stats[tptr].cur_chan == mchan)
83 switch( functionID ) {
84 case ID_do_handle_pitch_bend:
85 do_handle_pitch_bend(tptr);
86 break;
87 case ID_shut_off_chan_voice:
88 shut_off_chan_voice(tptr);
89 break;
90 case ID_do_sus_off:
91 do_sus_off(tptr);
92 break;
93 }
94 }
95}
96
97/* init_q()
98 * Initialize the note off queue structure.
99 */
100void FMSYNTH::init_q(void)
101{
102 init_q_sub(&note_q, sizeof(note_q_data), max_melo_voice);
103 init_q_sub(&drum_q, sizeof(drum_q_data), MAX_NUMBER_OF_DRUM_OPERATORS -1);
104}
105
106void FMSYNTH::init_q_sub(NPALLOC_Q q, int size, int limit)
107{
108 int i;
109
110 for (i = 0; i < size; i++) //go thru the list
111 {
112 q->data[i].next = (char) (i + 1); // link all the entries
113 }
114 q->data[limit].next = -1; // terminate at desired limit
115 q->freelist = 0;
116 q->usedlist = -1;
117 q->usedcount = 0;
118 q->lastused = -1;
119 return;
120}
121
122
123/* remove_target(p, chan, op)
124 * Search for and remove a particular note from the queue.
125 * Return the operator it was assigned to at *op.
126 * Return 0 if not found in queue, 1 if found.
127 */
128
129int FMSYNTH::remove_target(int p, int chan, int * op)
130{
131 return remove_target_sub(p, chan, op, &note_q);
132}
133
134int FMSYNTH::remove_target2(int p, int chan, int * op)
135{
136 return remove_target_sub(p, chan, op, &drum_q);
137}
138
139int FMSYNTH::remove_target_sub(int p, int chan, int * op, NPALLOC_Q q)
140{
141int found;
142int curptr;
143int prevptr;
144int search;
145int nexts;
146
147 found = 0; /* found flag */
148 curptr = q->usedlist; /* search through the used list */
149 prevptr = -1; /* remember previous enttry */
150 while (curptr >= 0 && !found) /* until target found, or no more entries */
151 {
152 if (p == (int) q->op_stats[curptr].cur_pitch && chan == (int) q->op_stats[curptr].cur_chan)
153 {
154 found++;
155 }
156 else
157 {
158 look_more:
159 prevptr = curptr;
160 curptr = q->data[curptr].next;
161 }
162 }
163
164 if (found)
165 {
166 if (channel_stats[chan].sus_pedal) // implement Sustain here
167 {
168 if (is_sused[curptr])
169 {
170 found = 0;
171 goto look_more;
172 }
173 is_sused[curptr] = 1; // LMH 5-22-92
174 *op = curptr;
175 return 0; // so NoteOff not called
176 }
177 if (curptr == q->lastused) /* if this is last entry in used list */
178 q->lastused = prevptr; /* then keep this variable current */
179
180 if (prevptr >= 0) /* if not first entry in list */
181 q->data[prevptr].next = q->data[curptr].next; /* link around this one, as we're deleting it */
182 else /* found in first entry so */
183 q->usedlist = q->data[curptr].next; /* just bump up list head */
184
185
186 for (nexts=search=q->freelist; nexts>= 0; ) // find end of Q
187 {
188 search = nexts;
189 nexts = q->data[search].next;
190 }
191 q->data[curptr].next = -1; // mark as end of q
192 if (search >= 0)
193 q->data[search].next = (signed char) curptr; // if sonething in q
194 else
195 q->freelist = curptr; // if this will be only entry
196
197 *op = curptr;
198 q->usedcount--;
199 }
200 else
201 {
202 *op = -1;
203 }
204
205return(found);
206}
207
208/* static int near search_list(int chan, int pitch)
209 *
210 * Will look for a free voice that matches chan AND pitch
211 * if pitch < 0, will only try to match chan
212 * if found, will remove from free list and return index
213 * if !found, returns < 0
214 */
215static int near search_list(int chan, int pitch, NPALLOC_Q q)
216{
217 int found;
218 int curptr;
219 int prevptr;
220
221 found = 0; /* found flag */
222 curptr = q->freelist; /* search through the used list */
223 prevptr = -1; /* remember previous enttry */
224 while (curptr >= 0 && !found) /* until target found, or no more entries */
225 {
226 if (( chan == (int) q->op_stats[curptr].cur_chan) &&
227 (pitch < 0 || (pitch == (int)q->op_stats[curptr].cur_pitch)))
228 {
229 found++;
230 }
231 else
232 {
233 prevptr = curptr;
234 curptr = q->data[curptr].next;
235 }
236 }
237
238 if (found)
239 {
240 if (prevptr >= 0) /* if not first entry in list */
241 q->data[prevptr].next = q->data[curptr].next; /* link around this one, as we're deleting it */
242 else /* found in first entry so */
243 q->freelist = q->data[curptr].next; /* just bump up list head */
244 }
245
246 return found ? curptr : -1;
247}
248
249/* add_q(p, chan, op)
250 * Add the specified pitch and channel to the queue. If necessary,
251 * shut off the oldest operator to free one up. Assign an operator
252 * and return that choice at *op.
253 */
254
255void FMSYNTH::add_q(int p, int chan, int * op)
256{
257 add_q_sub(p, chan, op, &note_q, max_melo_voice);;
258}
259
260void FMSYNTH::add_q2(int p, int chan, int * op)
261{
262 add_q_sub(p, chan, op, &drum_q, MAX_NUMBER_OF_DRUM_OPERATORS -1);
263}
264
265void FMSYNTH::add_q_sub(int p, int chan, int * op, NPALLOC_Q q, int limit)
266{
267 int curptr;
268
269 if (q->usedcount > limit)
270 {
271 shut_off_oldest(q);
272 }
273
274 curptr = search_list(chan, p, q);
275 if (curptr < 0) curptr = search_list(chan, -1, q);
276 if (curptr < 0)
277 {
278 curptr = q->freelist; /* save and */
279 q->freelist = q->data[q->freelist].next; /* advance free list ptr */
280 }
281
282 if (q->lastused >= 0) q->data[q->lastused].next = (char) curptr; /* insert new guy at */
283 q->data[curptr].next = -1; /* end of used list */
284
285 q->op_stats[curptr].cur_chan = (char) chan;
286 q->op_stats[curptr].cur_pitch = (char) p;
287
288 if (q->usedlist < 0) q->usedlist = curptr;
289 q->lastused = curptr;
290 is_sused[curptr] = 0;
291 *op = curptr;
292 q->usedcount++;
293}
294
295/* shut_off_chan_voice(op)
296 * Shut off an operator and remove its note from queue.
297 * only from note_q
298 */
299void FMSYNTH::shut_off_chan_voice(int op)
300{
301 remove_target(note_op_stats[op].cur_pitch, note_op_stats[op].cur_chan, &gop); /* we know gop will = op */
302 _NoteOff(gop);
303}
304
305/* shut_off_oldest()
306 * Shuts off the oldest note playing.
307 * Assumes there are notes playing!!
308 */
309
310void FMSYNTH::shut_off_oldest(NPALLOC_Q q)
311{
312 remove_next_q( &gop, q );
313 _NoteOff(gop);
314}
315
316/* shut_off_all()
317 * Shuts off all the melodic and percussive operators.
318 */
319void FMSYNTH::shut_off_all(void)
320{
321 shut_off_all_sub(&note_q);
322 shut_off_all_sub(&drum_q);
323}
324
325void FMSYNTH::shut_off_all_sub( NPALLOC_Q q)
326{
327 while (q->usedcount)
328 shut_off_oldest(q);
329}
330
331/* remove_next_q(op)
332 * Remove the oldest note from the queue. Return the operator
333 * it was assigned to at *op.
334 * note: operator == voice
335 */
336
337void FMSYNTH::remove_next_q(int * op, NPALLOC_Q q)
338{
339 int temp;
340
341 temp = q->usedlist; /* save and */
342 q->usedlist = q->data[q->usedlist].next; /* advance used list ptr */
343 if (temp == q->lastused) q->lastused = -1;
344
345 q->data[temp].next = (char) q->freelist; /* insert at front */
346 q->freelist = temp; /* of free list */
347
348 *op = temp;
349 q->usedcount--;
350 return;
351}
352
Note: See TracBrowser for help on using the repository browser.