source: cmedia/trunk/Sblive/voicemgr.c@ 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: 12.3 KB
Line 
1/* $Id: voicemgr.c,v 1.1 2000/04/23 14:55:46 ktk Exp $ */
2
3
4/*
5 **********************************************************************
6 * voicemgr.c - Voice manager for emu10k1 driver
7 * Copyright 1999, 2000 Creative Labs, Inc.
8 *
9 **********************************************************************
10 *
11 * Date Author Summary of changes
12 * ---- ------ ------------------
13 * October 20, 1999 Bertrand Lee base code release
14 *
15 **********************************************************************
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, write to the Free
29 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
30 * USA.
31 *
32 **********************************************************************
33 */
34
35#include "hwaccess.h"
36
37struct emu_voice *emu10k1_voice_alloc(struct voice_manager *voicemgr, struct voice_allocdesc *voiceallocdesc)
38{
39 struct emu10k1_card *card = voicemgr->card;
40 struct emu_voice *voice_tmp = voicemgr->voice;
41 struct emu_voice *voice = NULL;
42 int i;
43 unsigned long flags;
44
45 DPF(2, "emu10k1_voice_alloc()\n");
46
47 spin_lock_irqsave(&voicemgr->lock, flags);
48
49 if (voiceallocdesc->flags & VOICEMGR_FLAGS_MONO) {
50 for (i = 0; i < NUM_G; i++)
51 if (voice_tmp[i].usage == VOICEMGR_USAGE_FREE) {
52 voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags;
53 voice_tmp[i].usage = voiceallocdesc->usage;
54 voice = &voice_tmp[i];
55#ifdef PRIVATE_PCM_VOLUME
56 {
57 int j;
58 for(j = 0; j < MAX_PCM_CHANNELS; j++) {
59 if (sblive_pcm_volume[j].files == current->files) {
60 sblive_pcm_volume[j].channel_l = voice_tmp[i].num;
61 sblive_pcm_volume[j].channel_r = NUM_G;
62 }
63 }
64 }
65#endif
66 break;
67 }
68 } else {
69 for (i = 0; i < NUM_G; i += 2)
70 if ((voice_tmp[i].usage == VOICEMGR_USAGE_FREE)
71 && (voice_tmp[i + 1].usage == VOICEMGR_USAGE_FREE)) {
72 voice_tmp[i].linked_voice = &voice_tmp[i + 1];
73 voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags;
74 voice_tmp[i].usage = voiceallocdesc->usage;
75 voice_tmp[i + 1].flags = VOICEMGR_FLAGS_STEREOSLAVE | voiceallocdesc->flags;
76 voice_tmp[i + 1].usage = voiceallocdesc->usage;
77 voice = &voice_tmp[i];
78#ifdef PRIVATE_PCM_VOLUME
79 {
80 int j;
81 for(j = 0; j < MAX_PCM_CHANNELS; j++) {
82 if (sblive_pcm_volume[j].files == current->files) {
83 sblive_pcm_volume[j].channel_l = voice_tmp[i].num;
84 sblive_pcm_volume[j].channel_r = voice_tmp[i+1].num;
85 }
86 }
87 }
88#endif
89 break;
90 }
91 }
92
93 spin_unlock_irqrestore(&voicemgr->lock, flags);
94
95 voice_tmp = voice;
96
97 while (voice_tmp != NULL) {
98
99 DPD(2, " voice allocated -> %d\n", voice_tmp->num);
100
101 sblive_writeptr(card, IFATN, voice_tmp->num, 0xffff);
102 sblive_writeptr(card, DCYSUSV, voice_tmp->num, ENV_OFF);
103 sblive_writeptr(card, VTFT, voice_tmp->num, 0xffff);
104 sblive_writeptr(card, PTRX, voice_tmp->num, 0);
105
106 voice_tmp = voice_tmp->linked_voice;
107 }
108
109 return voice;
110}
111
112void emu10k1_voice_free(struct voice_manager *voicemgr, struct emu_voice *voice)
113{
114 struct emu10k1_card *card = voice->card;
115 struct emu_voice *voice_tmp;
116 unsigned dcysusv;
117 u32 cra, sample;
118 int i;
119 unsigned long flags;
120
121 DPF(2, "emu10k1_voice_free()\n");
122
123 voice_tmp = voice;
124
125 while (voice_tmp != NULL) {
126
127 DPD(2, " voice freed -> %d\n", voice_tmp->num);
128
129 sblive_writeptr(card, IFATN, voice_tmp->num, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK);
130 sblive_writeptr(card, IP, voice_tmp->num, 0);
131
132 dcysusv = sblive_readptr(card, DCYSUSV, voice_tmp->num) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK);
133 sblive_writeptr(card, DCYSUSV, voice_tmp->num, dcysusv | ENV_OFF);
134
135 sblive_writeptr(card, VTFT, voice_tmp->num, VTFT_FILTERTARGET_MASK);
136 sblive_writeptr(card, PTRX_PITCHTARGET, voice_tmp->num, 0);
137 sblive_writeptr(card, CVCF, voice_tmp->num, CVCF_CURRENTFILTER_MASK);
138 sblive_writeptr(card, CPF, voice_tmp->num, 0);
139
140 sample = (voice_tmp->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080;
141 cra = sblive_readptr(card, CCR, voice_tmp->num) & CCR_READADDRESS_MASK;
142 sblive_writeptr(card, CCR, voice_tmp->num, cra);
143 cra = (cra >> 18) & 0xf;
144 sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample);
145 cra = (cra + 0x1) & 0xf;
146 sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample);
147
148 for (i = 0; i < NUM_FXSENDS; i++)
149 voice_tmp->sendhandle[i] = 0;
150
151 voice_tmp->flags = 0;
152
153 spin_lock_irqsave(&voicemgr->lock, flags);
154 voice_tmp->usage = VOICEMGR_USAGE_FREE;
155
156 voice_tmp = voice_tmp->linked_voice;
157 voice->linked_voice = NULL;
158 spin_unlock_irqrestore(&voicemgr->lock, flags);
159 }
160
161 return;
162}
163
164/* Sets up a voices for Wave Playback */
165
166void emu10k1_voice_playback_setup(struct emu_voice *voice)
167{
168 struct emu10k1_card *card = voice->card;
169 u32 sample, cra = 0, start = 0;
170
171 DPF(2, "emu10k1_voice_playback_setup()\n");
172
173 while (voice != NULL) {
174 sblive_writeptr(card, DCYSUSV, voice->num, ENV_OFF);
175 sblive_writeptr(card, VTFT, voice->num, VTFT_FILTERTARGET_MASK);
176 sblive_writeptr(card, CVCF, voice->num, CVCF_CURRENTFILTER_MASK);
177 sblive_writeptr(card, FXRT, voice->num, (voice->flags & VOICEMGR_FLAGS_FXRT2) ? 0xd23c0000 : 0xd01c0000);
178
179 /* Stop CA */
180 /* Assumption that PT is alreadt 0 so no harm overwriting */
181 sblive_writeptr(card, PTRX, voice->num, (voice->params.send_a << 8) | voice->params.send_b);
182
183 if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) {
184 if (voice->linked_voice != NULL) {
185 /* Set stereo bit */
186 cra = 64;
187 sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
188 sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
189 } else {
190 cra = 32;
191 sblive_writeptr(card, CPF, voice->num, 0);
192 }
193
194 if (voice->flags & VOICEMGR_FLAGS_16BIT)
195 sample = 0;
196 else {
197 cra = cra * 2;
198 sample = 0x80808080;
199 }
200 cra -= 4;
201
202 if (voice->linked_voice != NULL) {
203 /* CCR_READADDRESS_MASK */
204 sblive_writeptr(card, CCR, voice->num, 0x3c << 16);
205 sblive_writeptr(card, CCR, voice->num + 1, cra << 16);
206 sblive_writeptr(card, CDE, voice->num + 1, sample);
207 sblive_writeptr(card, CDF, voice->num + 1, sample);
208 start = voice->params.start + cra / 2;
209 } else {
210 sblive_writeptr(card, CCR, voice->num, 0x1c << 16); /* FIXME: Is 0x1c correct? */
211 sblive_writeptr(card, CDE, voice->num, sample);
212 sblive_writeptr(card, CDF, voice->num, sample);
213 start = voice->params.start + cra;
214 }
215
216 if (start > voice->params.endloop) {
217 start -= voice->params.endloop;
218
219 if (voice->linked_voice != NULL)
220 cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9);
221 else
222 cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9);
223
224 start += voice->params.startloop;
225
226 if (start >= voice->params.endloop)
227 start = voice->params.endloop - 1;
228 } else if (voice->linked_voice != NULL)
229 cra = (cra << 25) | (0x3c << 16);
230 else
231 cra = (cra << 25) | (0x1c << 16);
232
233 start |= CCCA_INTERPROM_0;
234 }
235
236 /* CSL, ST, CA */
237 sblive_writeptr(card, DSL, voice->num, voice->params.endloop | (voice->params.send_d << 24));
238 sblive_writeptr(card, PSST, voice->num, voice->params.startloop | (voice->params.send_c << 24));
239
240 if (voice->flags & VOICEMGR_FLAGS_16BIT)
241 sblive_writeptr(card, CCCA, voice->num, start);
242 else
243 sblive_writeptr(card, CCCA, voice->num, start | CCCA_8BITSELECT);
244
245 /* Clear filter delay memory */
246 sblive_writeptr(card, Z1, voice->num, 0);
247 sblive_writeptr(card, Z2, voice->num, 0);
248
249 /* Invalidate maps */
250 sblive_writeptr(card, MAPA, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
251 sblive_writeptr(card, MAPB, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
252
253 /* Fill cache */
254 if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER)
255 sblive_writeptr(card, CCR, voice->num, cra);
256
257 sblive_writeptr(card, ATKHLDV, voice->num, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK);
258 sblive_writeptr(card, LFOVAL1, voice->num, 0x8000);
259 sblive_writeptr(card, ATKHLDM, voice->num, 0);
260 sblive_writeptr(card, DCYSUSM, voice->num, DCYSUSM_DECAYTIME_MASK);
261 sblive_writeptr(card, LFOVAL2, voice->num, 0x8000);
262 sblive_writeptr(card, IP, voice->num, voice->params.initial_pitch);
263 sblive_writeptr(card, PEFE, voice->num, 0x7f);
264 sblive_writeptr(card, FMMOD, voice->num, 0);
265 sblive_writeptr(card, TREMFRQ, voice->num, 0);
266 sblive_writeptr(card, FM2FRQ2, voice->num, 0);
267 sblive_writeptr(card, ENVVAL, voice->num, 0xbfff);
268 sblive_writeptr(card, ENVVOL, voice->num, 0xbfff);
269
270#ifdef PRIVATE_PCM_VOLUME
271 {
272 int i;
273
274 for (i = 0; i < MAX_PCM_CHANNELS; i++) {
275 if (sblive_pcm_volume[i].channel_l == voice->num) {
276 voice->params.initial_attn = (sblive_pcm_volume[i].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l :
277 // test for mono channel (reverse logic is correct here!)
278 (sblive_pcm_volume[i].attn_r >
279 sblive_pcm_volume[i].attn_l) ? sblive_pcm_volume[i].attn_l : sblive_pcm_volume[i].attn_r;
280 DPD(2, "set left volume %d\n", voice->params.initial_attn);
281 break;
282 } else if (sblive_pcm_volume[i].channel_r == voice->num) {
283 voice->params.initial_attn = sblive_pcm_volume[i].attn_r;
284 DPD(2, "set right volume %d\n", voice->params.initial_attn);
285 break;
286 }
287 }
288 }
289#endif
290 sblive_writeptr(card, IFATN, voice->num, IFATN_FILTERCUTOFF_MASK | voice->params.initial_attn);
291
292 voice->params.FC_target = 0xffff;
293 voice->params.pitch_target = (u16) (IP_TO_CP(voice->params.initial_pitch) >> 16);
294
295 voice = voice->linked_voice;
296 }
297
298 return;
299}
300
301void emu10k1_voice_start(struct emu_voice *voice)
302{
303 struct emu10k1_card *card = voice->card;
304
305 DPF(2, "emu10k1_voice_start()\n");
306
307 while (voice != NULL) {
308 sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, voice->params.pitch_target);
309
310 if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER)
311 sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->params.pitch_target);
312
313 sblive_writeptr(card, VTFT, voice->num, ((u32) voice->params.volume_target << 16)
314 | voice->params.FC_target);
315 sblive_writeptr(card, CVCF, voice->num, ((u32) voice->params.volume_target << 16)
316 | voice->params.FC_target);
317 sblive_writeptr(card, DCYSUSV, voice->num, (voice->params.byampl_env_sustain << 8)
318 | ENV_ON | voice->params.byampl_env_decay);
319
320 /* Using StopOnLoop for MIDI stops the playback
321 too early, which may cause a DC level to be played
322 until the note is released. */
323
324 if (voice->usage == VOICEMGR_USAGE_MIDI)
325 emu10k1_clear_stop_on_loop(card, voice->num);
326 else {
327 if (voice->params.startloop > voice->params.end)
328 emu10k1_set_stop_on_loop(card, voice->num);
329 else
330 emu10k1_clear_stop_on_loop(card, voice->num);
331 }
332 voice = voice->linked_voice;
333 }
334
335 return;
336}
337
338void emu10k1_voice_stop(struct emu_voice *voice)
339{
340 struct emu10k1_card *card = voice->card;
341
342 DPF(2, "emu10k1_voice_stop()\n");
343
344 while (voice != NULL) {
345 sblive_writeptr(card, IFATN, voice->num, 0xffff);
346 sblive_writeptr(card, IP, voice->num, 0);
347 sblive_writeptr(card, VTFT, voice->num, 0xffff);
348 sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, 0);
349 voice = voice->linked_voice;
350 }
351
352 return;
353}
354
355void emu10k1_voice_setcontrol(struct emu_voice *voice, struct voice_cntlset *setting, u32 numparam)
356{
357 struct emu10k1_card *card = voice->card;
358 int count;
359
360 for (count = 0; count < numparam; count++)
361 sblive_writeptr(card, setting[count].paramID, voice->num, setting[count].value);
362
363 return;
364}
365
366void emu10k1_voice_getcontrol(struct emu_voice *voice, u32 controlid, u32 * value)
367{
368 struct emu10k1_card *card = voice->card;
369
370 *value = sblive_readptr(card, controlid, voice->num);
371
372 return;
373}
Note: See TracBrowser for help on using the repository browser.