1 /*----------------------------------------------------------------------------
2 * emu8k.c - low-level functions for AWE32 driver
3 *----------------------------------------------------------------------------
5 * (c) George Foot April-September 1997
7 * Information taken primarily from "AWE32/EMU8000 Programmer's Guide" (AEPG)
8 * by Dave Rossum. The AEPG is part of the AWE32 Developers' Information Pack
9 * (ADIP) from Creative Labs.
11 * I/O port verification technique taken from "The Un-official Sound
12 * Blaster AWE32 Programming Guide" by Vince Vu a.k.a. Judge Dredd
14 * Miscellaneous guidance taken from Takashi Iwai's Linux AWE32 driver
21 #error This file should only be used by the djgpp version of Allegro
24 #include <math.h> /* for `pow' in the conversion routines */
25 #include <pc.h> /* for I/O port access */
26 #include <stdlib.h> /* for getenv("BLASTER") during detection */
27 #include <string.h> /* for strtol to parse the address in BLASTER */
28 #include <stdio.h> /* for error messaging */
30 #include "internal.h" /* for `rest' in emu8k_init */
31 #include "emu8k.h" /* structs and prototypes */
35 /****************************************************************************\
37 * EMU8000.H : EMU8000 init arrays ( for hardware level programming only ) *
39 * (C) Copyright Creative Technology Ltd. 1992-96. All rights reserved *
42 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY *
43 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE *
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR *
47 \****************************************************************************/
49 static unsigned short init1_1[32] = { 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330, 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730, 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30, 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30 };
50 static unsigned short init1_2[32] = { 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330, 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730, 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30, 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30 };
51 static unsigned short init1_3[32] = { 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330, 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730, 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30, 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30 };
52 static unsigned short init1_4[32] = { 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330, 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730, 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30, 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30 };
54 static unsigned short init2_1[32] = { 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330, 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730, 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30, 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30 };
55 static unsigned short init2_2[32] = { 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330, 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730, 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30, 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30 };
56 static unsigned short init2_3[32] = { 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330, 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730, 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30, 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30 };
57 static unsigned short init2_4[32] = { 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330, 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730, 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30, 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30 };
59 static unsigned short init3_1[32] = { 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254, 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234, 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224 };
60 static unsigned short init3_2[32] = { 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254, 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264, 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294, 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3 };
61 static unsigned short init3_3[32] = { 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287, 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7, 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386, 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55 };
62 static unsigned short init3_4[32] = { 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308, 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F, 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319, 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570 };
64 static unsigned short init4_1[32] = { 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254, 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234, 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224 };
65 static unsigned short init4_2[32] = { 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254, 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264, 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294, 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3 };
66 static unsigned short init4_3[32] = { 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287, 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7, 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386, 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55 };
67 static unsigned short init4_4[32] = { 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308, 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F, 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319, 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570 };
69 /*** (end of init arrays) ***/
73 #define MIN_LOOP_LEN 2
75 int _emu8k_baseport=0;
76 int _emu8k_numchannels=32;
80 /* Functions to deal with the AWE32's I/O ports
82 static inline void write_word(int reg,int channel,int port,int data) {
83 int out_port=_emu8k_baseport;
85 case 0: out_port+=0x0000; break;
86 case 1: out_port+=0x0400; break;
87 case 2: out_port+=0x0402; break;
88 case 3: out_port+=0x0800; break;
91 outportw(_emu8k_baseport+0x802,(reg<<5)+(channel&0x1f));
92 outportw(out_port,data);
95 static inline unsigned int read_word(int reg,int channel,int port) {
96 int in_port=_emu8k_baseport;
98 case 0: in_port+=0x0000; break;
99 case 1: in_port+=0x0400; break;
100 case 2: in_port+=0x0402; break;
101 case 3: in_port+=0x0800; break;
104 outportw(_emu8k_baseport+0x802,(reg<<5)+(channel&0x1f));
105 return inportw(in_port);
108 static inline void write_dword(int reg,int channel,int port,unsigned int data) {
109 int out_port=_emu8k_baseport;
111 case 0: out_port+=0x0000; break;
112 case 1: out_port+=0x0400; break;
113 case 2: out_port+=0x0402; break;
114 case 3: out_port+=0x0800; break;
117 outportw(_emu8k_baseport+0x802,(reg<<5)+(channel&0x1f));
118 outportw(out_port,data&0xffff);
119 outportw(out_port+2,(data>>16)&0xffff);
122 static inline unsigned int read_dword(int reg,int channel,int port) {
124 in_port=_emu8k_baseport;
126 case 0: in_port+=0x0000; break;
127 case 1: in_port+=0x0400; break;
128 case 2: in_port+=0x0402; break;
129 case 3: in_port+=0x0800; break;
132 outportw(_emu8k_baseport+0x802,(reg<<5)+(channel&0x1f));
134 b=inportw(in_port+2);
141 * Functions to write information to the AWE32's registers
142 * (abbreviated as in the EPG).
144 static inline void write_CPF(int channel,int i) { write_dword(0,channel,0,i); }
145 static inline void write_PTRX(int channel,int i) { write_dword(1,channel,0,i); }
146 static inline void write_CVCF(int channel,int i) { write_dword(2,channel,0,i); }
147 static inline void write_VTFT(int channel,int i) { write_dword(3,channel,0,i); }
148 static inline void write_PSST(int channel,int i) { write_dword(6,channel,0,i); }
149 static inline void write_CSL(int channel,int i) { write_dword(7,channel,0,i); }
150 static inline void write_CCCA(int channel,int i) { write_dword(0,channel,1,i); }
151 static inline void write_HWCF4(int i) { write_dword(1, 9,1,i); }
152 static inline void write_HWCF5(int i) { write_dword(1, 10,1,i); }
153 static inline void write_HWCF6(int i) { write_dword(1, 13,1,i); }
154 static inline void write_SMALR(int i) { write_dword(1, 20,1,i); }
155 static inline void write_SMARR(int i) { write_dword(1, 21,1,i); }
156 static inline void write_SMALW(int i) { write_dword(1, 22,1,i); }
157 static inline void write_SMARW(int i) { write_dword(1, 23,1,i); }
158 static inline void write_SMLD(int i) { write_word (1, 26,1,i); }
159 static inline void write_SMRD(int i) { write_word (1, 26,2,i); }
160 static inline void write_WC(int i) { write_word (1, 27,2,i); }
161 static inline void write_HWCF1(int i) { write_word (1, 29,1,i); }
162 static inline void write_HWCF2(int i) { write_word (1, 30,1,i); }
163 static inline void write_HWCF3(int i) { write_word (1, 31,1,i); }
164 static inline void write_INIT1(int channel,int i) { write_word (2,channel,1,i); } /* `channel' is really `element' here */
165 static inline void write_INIT2(int channel,int i) { write_word (2,channel,2,i); }
166 static inline void write_INIT3(int channel,int i) { write_word (3,channel,1,i); }
167 static inline void write_INIT4(int channel,int i) { write_word (3,channel,2,i); }
168 static inline void write_ENVVOL(int channel,int i) { write_word (4,channel,1,i); }
169 static inline void write_DCYSUSV(int channel,int i) { write_word (5,channel,1,i); }
170 static inline void write_ENVVAL(int channel,int i) { write_word (6,channel,1,i); }
171 static inline void write_DCYSUS(int channel,int i) { write_word (7,channel,1,i); }
172 static inline void write_ATKHLDV(int channel,int i) { write_word (4,channel,2,i); }
173 static inline void write_LFO1VAL(int channel,int i) { write_word (5,channel,2,i); }
174 static inline void write_ATKHLD(int channel,int i) { write_word (6,channel,2,i); }
175 static inline void write_LFO2VAL(int channel,int i) { write_word (7,channel,2,i); }
176 static inline void write_IP(int channel,int i) { write_word (0,channel,3,i); }
177 static inline void write_IFATN(int channel,int i) { write_word (1,channel,3,i); }
178 static inline void write_PEFE(int channel,int i) { write_word (2,channel,3,i); }
179 static inline void write_FMMOD(int channel,int i) { write_word (3,channel,3,i); }
180 static inline void write_TREMFRQ(int channel,int i) { write_word (4,channel,3,i); }
181 static inline void write_FM2FRQ2(int channel,int i) { write_word (5,channel,3,i); }
186 * Functions to read information from the AWE32's registers
187 * (abbreviated as in the AEPG).
189 static inline int read_CPF(int channel) { return read_dword(0,channel,0); }
190 static inline int read_PTRX(int channel) { return read_dword(1,channel,0); }
191 static inline int read_CVCF(int channel) { return read_dword(2,channel,0); }
192 static inline int read_VTFT(int channel) { return read_dword(3,channel,0); }
193 static inline int read_PSST(int channel) { return read_dword(6,channel,0); }
194 static inline int read_CSL(int channel) { return read_dword(7,channel,0); }
195 static inline int read_CCCA(int channel) { return read_dword(0,channel,1); }
196 static inline int read_HWCF4() { return read_dword(1, 9,1); }
197 static inline int read_HWCF5() { return read_dword(1, 10,1); }
198 static inline int read_HWCF6() { return read_dword(1, 13,1); }
199 static inline int read_SMALR() { return read_dword(1, 20,1); }
200 static inline int read_SMARR() { return read_dword(1, 21,1); }
201 static inline int read_SMALW() { return read_dword(1, 22,1); }
202 static inline int read_SMARW() { return read_dword(1, 23,1); }
203 static inline int read_SMLD() { return read_word (1, 26,1); }
204 static inline int read_SMRD() { return read_word (1, 26,2); }
205 static inline int read_WC() { return read_word (1, 27,2); }
206 static inline int read_HWCF1() { return read_word (1, 29,1); }
207 static inline int read_HWCF2() { return read_word (1, 30,1); }
208 static inline int read_HWCF3() { return read_word (1, 31,1); }
209 static inline int read_INIT1() { return read_word (2, 0,1); }
210 static inline int read_INIT2() { return read_word (2, 0,2); }
211 static inline int read_INIT3() { return read_word (3, 0,1); }
212 static inline int read_INIT4() { return read_word (3, 0,2); }
213 static inline int read_ENVVOL(int channel) { return read_word (4,channel,1); }
214 static inline int read_DCYSUSV(int channel) { return read_word (5,channel,1); }
215 static inline int read_ENVVAL(int channel) { return read_word (6,channel,1); }
216 static inline int read_DCYSUS(int channel) { return read_word (7,channel,1); }
217 static inline int read_ATKHLDV(int channel) { return read_word (4,channel,2); }
218 static inline int read_LFO1VAL(int channel) { return read_word (5,channel,2); }
219 static inline int read_ATKHLD(int channel) { return read_word (6,channel,2); }
220 static inline int read_LFO2VAL(int channel) { return read_word (7,channel,2); }
221 static inline int read_IP(int channel) { return read_word (0,channel,3); }
222 static inline int read_IFATN(int channel) { return read_word (1,channel,3); }
223 static inline int read_PEFE(int channel) { return read_word (2,channel,3); }
224 static inline int read_FMMOD(int channel) { return read_word (3,channel,3); }
225 static inline int read_TREMFRQ(int channel) { return read_word (4,channel,3); }
226 static inline int read_FM2FRQ2(int channel) { return read_word (5,channel,3); }
231 * Functions to wait for DMA streams to be ready.
233 static inline void wait_LR() { while (read_SMALR()&0x80000000); }
234 static inline void wait_LW() { while (read_SMALW()&0x80000000); }
235 static inline void wait_RR() { while (read_SMARR()&0x80000000); }
236 static inline void wait_RW() { while (read_SMARW()&0x80000000); }
238 /* write_init_arrays:
239 * Writes the given set of initialisation arrays to the card.
241 static void write_init_arrays(short int *init1,short int *init2,short int *init3,short int *init4) {
243 for (i=0;i<32;i++) write_INIT1(i,init1[i]);
244 for (i=0;i<32;i++) write_INIT2(i,init2[i]);
245 for (i=0;i<32;i++) write_INIT3(i,init3[i]);
246 for (i=0;i<32;i++) write_INIT4(i,init4[i]);
252 * Initialise the synthesiser. See AEPG chapter 4.
258 for (channel=0;channel<_emu8k_numchannels;channel++) write_DCYSUSV(channel,0x0080);
259 for (channel=0;channel<_emu8k_numchannels;channel++) {
260 write_ENVVOL(channel,0);
261 write_ENVVAL(channel,0);
262 write_DCYSUS(channel,0);
263 write_ATKHLDV(channel,0);
264 write_LFO1VAL(channel,0);
265 write_ATKHLD(channel,0);
266 write_LFO2VAL(channel,0);
268 write_IFATN(channel,0);
269 write_PEFE(channel,0);
270 write_FMMOD(channel,0);
271 write_TREMFRQ(channel,0);
272 write_FM2FRQ2(channel,0);
273 write_PTRX(channel,0);
274 write_VTFT(channel,0);
275 write_PSST(channel,0);
276 write_CSL(channel,0);
277 write_CCCA(channel,0);
279 for (channel=0;channel<_emu8k_numchannels;channel++) {
280 write_CPF(channel,0);
281 write_CVCF(channel,0);
287 write_init_arrays(init1_1,init1_2,init1_3,init1_4);
288 rest(25); /* wait 24 msec + 1 for luck */
289 write_init_arrays(init2_1,init2_2,init2_3,init2_4);
290 write_init_arrays(init3_1,init3_2,init3_3,init3_4);
292 write_HWCF5(0x00000083);
293 write_HWCF6(0x00008000);
294 write_init_arrays(init4_1,init4_2,init4_3,init4_4);
301 * Start a sound on a channel.
303 void emu8k_startsound(int channel,struct envparms_t *envparms) {
304 write_DCYSUSV(channel,0x0080);
305 write_VTFT(channel,0);
306 write_CVCF(channel,0);
307 write_PTRX(channel,0);
308 write_CPF(channel,0);
310 write_ENVVOL(channel,envparms->envvol);
311 write_ENVVAL(channel,envparms->envval);
312 write_DCYSUS(channel,envparms->dcysus);
313 write_ATKHLDV(channel,envparms->atkhldv);
314 write_LFO1VAL(channel,envparms->lfo1val);
315 write_ATKHLD(channel,envparms->atkhld);
316 write_LFO2VAL(channel,envparms->lfo2val);
317 write_IP(channel,envparms->ip);
318 write_IFATN(channel,envparms->ifatn);
319 write_PEFE(channel,envparms->pefe);
320 write_FMMOD(channel,envparms->fmmod);
321 write_TREMFRQ(channel,envparms->tremfrq);
322 write_FM2FRQ2(channel,envparms->fm2frq2);
326 switch (envparms->smpmode&3) {
327 case 0: /* no looping */
328 case 2: /* invalid; should be read as `no looping' */
329 psst = (envparms->psst&0xff000000) /* copy pan verbatim; mask out loop start */
330 + (envparms->sampend) /* set loop start to near sample end */
332 csl = (envparms->csl &0xff000000) /* copy chorus verbatim; mask out loop end */
333 + (envparms->sampend) /* set loop end to sample end */
336 case 1: /* loop indefinitely */
337 case 3: /* loop until key released, then continue */
338 psst = envparms->psst; /* leave the loop as it stands */
342 write_PSST(channel,psst);
343 write_CSL (channel,csl);
345 write_CCCA(channel,envparms->ccca);
347 write_VTFT(channel,0x0000FFFF);
348 write_CVCF(channel,0x0000FFFF);
349 write_DCYSUSV(channel,envparms->dcysusv);
350 write_PTRX(channel,envparms->ptrx);
351 write_CPF(channel,0x40000000);
353 static END_OF_FUNCTION(emu8k_startsound);
357 /* emu8k_releasesound:
358 * End a sound on a channel by starting its release phase.
360 void emu8k_releasesound(int channel,struct envparms_t *envparms) {
361 if (envparms->smpmode==3) { /* If sound should stop looping and continue, do so */
362 write_CSL(channel,(envparms->chorus<<24)+envparms->sampend + MIN_LOOP_LEN);
363 write_PSST(channel,(envparms->pan<<24)+envparms->sampend - MIN_LOOP_LEN);
365 write_DCYSUSV(channel,0x8000+envparms->volrel); /* Start volume envelope release phase */
366 write_DCYSUS (channel,0x8000+envparms->modrel); /* Start modulation envelope release phase */
368 static END_OF_FUNCTION(emu8k_releasesound);
372 * Modulation functions - changing a channel's sound in various ways.
374 void emu8k_modulate_atten (int channel, int atten) {
376 ifatn = read_IFATN (channel);
377 write_IFATN (channel,(ifatn&0xff00)+(atten&0xff));
379 static END_OF_FUNCTION(emu8k_modulate_atten);
382 void emu8k_modulate_ip (int channel, int ip) {
383 write_IP(channel,ip);
385 static END_OF_FUNCTION(emu8k_modulate_ip);
388 void emu8k_modulate_pan (int channel, int pan) {
390 psst = read_PSST(channel);
391 write_PSST(channel,(pan<<24)+(psst&0x00ffffff));
393 static END_OF_FUNCTION(emu8k_modulate_pan);
397 /* emu8k_terminatesound:
398 * End a sound on a channel immediately (may produce an audible click).
400 void emu8k_terminatesound(int channel) {
401 write_DCYSUSV(channel,0x0080);
402 write_VTFT(channel,0x0000FFFF);
403 write_CVCF(channel,0x0000FFFF);
405 static END_OF_FUNCTION(emu8k_terminatesound);
410 * Locate the EMU8000. This tries to extract the base port from the E section
411 * of the BLASTER environment variable, and then does some test reads to check
412 * that there is an EMU8000 there.
416 if (!(envvar=getenv("BLASTER"))) {
417 sprintf(allegro_error,"BLASTER environment variable not set");
423 if (*envvar=='E') _emu8k_baseport=strtol(envvar+1,NULL,16);
424 while ((*envvar!=' ')&&(*envvar!=0)) envvar++;
425 if (*envvar) envvar++;
427 if (!_emu8k_baseport) {
428 sprintf(allegro_error,"BLASTER environment variable has no E section");
432 sprintf(allegro_error,"AWE32 detection failed on port 0x%04x",_emu8k_baseport);
434 if ((read_word(7, 0,3)&0x000f)!=0x000c) return 0;
435 if ((read_word(1,29,1)&0x007e)!=0x0058) return 0;
436 if ((read_word(1,30,1)&0x0003)!=0x0003) return 0;
445 * Functions to convert SoundFont information to EMU8000 parameters.
447 static inline unsigned short emu_delay(int x) {
448 int a=0x8000-pow(2,x/1200.0)/0.000725;
449 return (a<0)?0:((a>0x8000)?0x8000:a);
452 static inline unsigned char emu_attack(int x) {
454 * AEPG doesn't specify exact conversion here; I'm using what Takashi Iwai used for
458 msec=pow(2,x/1200.0)*1000;
459 if (msec==0) return 0x7f;
463 // a=32+53.426*log10(360.0/msec);
465 return (a<1)?1:((a>0x7f)?0x7f:a);
468 static inline unsigned char emu_hold(int x) {
469 int a=0x7f-(int)(pow(2,x/1200.0)*0x7f/11.68);
470 return (a<0)?0:((a>0x7f)?0x7f:a);
473 static inline unsigned char emu_decay(int x) {
475 * AEPG doesn't specify exact conversion here; I'm using an adaptation of
476 * what Takashi Iwai used for his Linux driver
479 msec=pow(2,x/1200.0)*1000;
480 if (msec==0) return 0x7f;
481 a=0x7f-54.8*log10(msec/23.04); /* Takashi's */
482 // a = 47349/(msec+349); /* mine */
483 return (a<1)?1:((a>0x7f)?0x7f:a);
486 static inline unsigned char emu_sustain(int x) {
487 /* This is not the same as in Takashi Iwai's Linux driver, but I think I'm right */
489 return (a<0)?0:((a>0x7f)?0x7f:a);
492 static inline unsigned char emu_release(int x) {
496 static inline unsigned char emu_mod(int x,int peak_deviation) {
497 int a=x*0x80/peak_deviation;
498 return (a<-0x80)?0x80:((a>0x7f)?0x7f:a);
501 static inline unsigned char emu_freq(int x) {
502 int a=(8.176*pow(2,x/1200.0)+0.032)/0.042;
503 return (a<0)?0:((a>0xff)?0xff:a);
506 static inline unsigned char emu_reverb(int x) {
508 return (a<0)?0:((a>0xff)?0xff:a);
511 static inline unsigned char emu_chorus(int x) {
513 return (a<0)?0:((a>0xff)?0xff:a);
516 static inline unsigned char emu_pan(int x) {
517 int a=0x7f-(x*0xff)/1000;
518 return (a<8)?8:((a>0xf8)?0xf8:a);
521 static inline unsigned char emu_filterQ(int x) {
523 return (a<0)?0:((a>15)?15:a);
526 static inline unsigned int emu_address(int base,int offset,int coarse_offset) {
527 return base+offset+coarse_offset*32*1024;
530 static inline unsigned short emu_pitch(int key,int rootkey,int scale,int coarse,int fine,int initial) {
531 int a=(((key-rootkey)*scale+coarse*100+fine-initial)*0x1000)/1200+0xE000;
532 return (a<0)?0:((a>0xFFFF)?0xFFFF:a);
535 static inline unsigned char emu_filter(int x) {
537 return (a<0)?0:((a>0xff)?0xff:a);
540 static inline unsigned char emu_atten(int x) {
542 return (a<0)?0:((a>0xff)?0xff:a);
547 /* emu8k_createenvelope:
548 * Converts a set of SoundFont generators to equivalent EMU8000 register
549 * settings, for passing to the sound playing functions above.
551 envparms_t *emu8k_createenvelope(generators_t sfgen) {
552 envparms_t *envelope=(envparms_t *)_lock_malloc(sizeof(envparms_t));
554 envelope->envvol = emu_delay(sfgen[sfgen_delayModEnv]);
555 envelope->envval = emu_delay(sfgen[sfgen_delayVolEnv]);
556 envelope->modsust = (emu_sustain(sfgen[sfgen_sustainModEnv])<<8);
557 envelope->modrel = (emu_release(sfgen[sfgen_releaseModEnv])<<0);
558 envelope->dcysus = (0<<15) // we're programming the decay, not the release
561 + (emu_decay(sfgen[sfgen_decayModEnv])<<0);
562 envelope->atkhldv = (0<<15) // 0 otherwise it won't attack
563 + (emu_hold(sfgen[sfgen_holdVolEnv])<<8)
565 + (emu_attack(sfgen[sfgen_attackVolEnv])<<0);
566 envelope->lfo1val = emu_delay(sfgen[sfgen_delayModLFO]);
567 envelope->atkhld = (0<<15) // 0 otherwise it won't attack
568 + (emu_hold(sfgen[sfgen_holdModEnv])<<8)
570 + (emu_attack(sfgen[sfgen_attackModEnv])<<0);
571 envelope->lfo2val = emu_delay(sfgen[sfgen_delayVibLFO]);
572 envelope->pitch = 0xe000;
573 envelope->ip = envelope->pitch;
574 envelope->filter = (emu_filter(sfgen[sfgen_initialFilterFc])<<8);
575 envelope->atten = (emu_atten(sfgen[sfgen_initialAttenuation])<<0);
576 envelope->ifatn = envelope->filter+envelope->atten;
577 envelope->pefe = (emu_mod(sfgen[sfgen_modEnvToPitch],1200)<<8)
578 + (emu_mod(sfgen[sfgen_modEnvToFilterFc],7200)<<0);
579 envelope->fmmod = (emu_mod(sfgen[sfgen_modLfoToPitch],1200)<<8)
580 + (emu_mod(sfgen[sfgen_modLfoToFilterFc],3600)<<0);
581 envelope->tremfrq = (emu_mod(sfgen[sfgen_modLfoToVolume],120)<<8)
582 + (emu_freq(sfgen[sfgen_freqModLFO])<<0);
583 envelope->fm2frq2 = (emu_mod(sfgen[sfgen_vibLfoToPitch],1200)<<8)
584 + (emu_freq(sfgen[sfgen_freqVibLFO])<<0);
585 envelope->volsust = (emu_sustain(sfgen[sfgen_sustainVolEnv])<<8);
586 envelope->volrel = (emu_release(sfgen[sfgen_releaseVolEnv])<<0);
587 envelope->dcysusv = (0<<15) // we're programming decay not release
589 + (0<<7) // turn on envelope engine
590 + (emu_decay(sfgen[sfgen_decayVolEnv])<<0);
591 envelope->ptrx = (0x4000<<16) // ??? I thought the top word wasn't for me to use
592 + (emu_reverb(sfgen[sfgen_reverbEffectsSend])<<8)
594 envelope->pan = emu_pan(sfgen[sfgen_pan]);
595 envelope->loopst = emu_address(sfgen[gfgen_startloopAddrs],sfgen[sfgen_startloopAddrsOffset],sfgen[sfgen_startloopAddrsCoarseOffset]);
596 envelope->sampend = emu_address(sfgen[gfgen_endAddrs],sfgen[sfgen_endAddrsOffset],sfgen[sfgen_endAddrsCoarseOffset]);
597 envelope->psst = (envelope->pan<<24)
598 + (envelope->loopst);
599 envelope->chorus = emu_chorus(sfgen[sfgen_chorusEffectsSend]);
600 envelope->csl = (envelope->chorus<<24)
601 + (emu_address(sfgen[gfgen_endloopAddrs],sfgen[sfgen_endloopAddrsOffset],sfgen[sfgen_endloopAddrsCoarseOffset])<<0);
602 envelope->ccca = (emu_filterQ(sfgen[sfgen_initialFilterQ])<<28)
603 + (0<<24) // DMA control bits
604 + (emu_address(sfgen[gfgen_startAddrs],sfgen[sfgen_startAddrsOffset],sfgen[sfgen_startAddrsCoarseOffset])<<0);
606 envelope->rootkey = (sfgen[sfgen_overridingRootKey]!=-1)?sfgen[sfgen_overridingRootKey]:69;
607 envelope->ipbase = ((sfgen[sfgen_coarseTune]*100+sfgen[sfgen_fineTune]-envelope->rootkey*sfgen[sfgen_scaleTuning])*0x1000)/1200+0xE000;
608 envelope->ipscale = sfgen[sfgen_scaleTuning];
610 envelope->minkey = sfgen[sfgen_keyRange]&0xff;
611 envelope->maxkey = (sfgen[sfgen_keyRange]>>8)&0xff;
612 envelope->minvel = sfgen[sfgen_velRange]&0xff;
613 envelope->maxvel = (sfgen[sfgen_velRange]>>8)&0xff;
616 envelope->exc = sfgen[sfgen_exclusiveClass];
617 envelope->keyMEH = 0;
618 envelope->keyMED = 0;
619 envelope->keyVEH = 0;
620 envelope->keyVED = 0;
621 envelope->smpmode = sfgen[sfgen_sampleModes];
628 /* emu8k_destroyenvelope:
629 * Destroys an envelope created by emu8k_createenvelope.
631 void emu8k_destroyenvelope(envparms_t *env) {
638 * Locks all data and functions which might be called in an interrupt context.
641 LOCK_VARIABLE(_emu8k_baseport);
642 LOCK_VARIABLE(_emu8k_numchannels);
644 LOCK_FUNCTION(emu8k_startsound);
645 LOCK_FUNCTION(emu8k_releasesound);
646 LOCK_FUNCTION(emu8k_modulate_atten);
647 LOCK_FUNCTION(emu8k_modulate_ip);
648 LOCK_FUNCTION(emu8k_modulate_pan);
649 LOCK_FUNCTION(emu8k_terminatesound);