]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/allg_snd/sound/drv/emu8k.c
Import of d2x-0.0.8
[btb/d2x.git] / arch / dos / allg_snd / sound / drv / emu8k.c
1 /*----------------------------------------------------------------------------
2  *  emu8k.c - low-level functions for AWE32 driver
3  *----------------------------------------------------------------------------
4  *
5  * (c) George Foot April-September 1997
6  *
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.
10  *
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
13  *
14  * Miscellaneous guidance taken from Takashi Iwai's Linux AWE32 driver
15  *
16  */
17
18
19
20 #ifndef DJGPP
21 #error This file should only be used by the djgpp version of Allegro
22 #endif
23
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 */
29
30 #include "internal.h"   /* for `rest' in emu8k_init */
31 #include "emu8k.h"      /* structs and prototypes */
32
33
34
35 /****************************************************************************\
36 *                                                                            *
37 * EMU8000.H : EMU8000 init arrays ( for hardware level programming only )    *
38 *                                                                            *
39 * (C) Copyright Creative Technology Ltd. 1992-96. All rights reserved        *
40 * worldwide.                                                                 *
41 *                                                                            *
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      *
45 * PURPOSE.                                                                   *
46 *                                                                            *
47 \****************************************************************************/
48
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 };
53
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 };
58
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 };
63
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 };
68
69 /*** (end of init arrays) ***/
70
71
72
73 #define MIN_LOOP_LEN 2
74
75 int _emu8k_baseport=0;
76 int _emu8k_numchannels=32;
77
78
79
80 /*  Functions to deal with the AWE32's I/O ports
81  */
82 static inline void write_word(int reg,int channel,int port,int data) {
83  int out_port=_emu8k_baseport;
84  switch(port) {
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;
89  default: return;
90  }
91  outportw(_emu8k_baseport+0x802,(reg<<5)+(channel&0x1f));
92  outportw(out_port,data);
93 }
94
95 static inline unsigned int read_word(int reg,int channel,int port) {
96  int in_port=_emu8k_baseport;
97  switch(port) {
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;
102  default: return 0;
103  }
104  outportw(_emu8k_baseport+0x802,(reg<<5)+(channel&0x1f));
105  return inportw(in_port);
106 }
107
108 static inline void write_dword(int reg,int channel,int port,unsigned int data) {
109  int out_port=_emu8k_baseport;
110  switch(port) {
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;
115  default: return;
116  }
117  outportw(_emu8k_baseport+0x802,(reg<<5)+(channel&0x1f));
118  outportw(out_port,data&0xffff);
119  outportw(out_port+2,(data>>16)&0xffff);
120 }
121
122 static inline unsigned int read_dword(int reg,int channel,int port) {
123  int in_port,a,b;
124  in_port=_emu8k_baseport;
125  switch(port) {
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;
130  default: return 0;
131  }
132  outportw(_emu8k_baseport+0x802,(reg<<5)+(channel&0x1f));
133  a=inportw(in_port);
134  b=inportw(in_port+2);
135  return ((b<<16)+a);
136 }
137
138
139
140 /* write_*:
141  *  Functions to write information to the AWE32's registers
142  *  (abbreviated as in the EPG).
143  */
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); }
182
183
184
185 /* read_*:
186  *  Functions to read information from the AWE32's registers
187  *  (abbreviated as in the AEPG).
188  */
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); }
227
228
229
230 /* wait_*:
231  *  Functions to wait for DMA streams to be ready.
232  */
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); }
237
238 /* write_init_arrays:
239  *  Writes the given set of initialisation arrays to the card.
240  */
241 static void write_init_arrays(short int *init1,short int *init2,short int *init3,short int *init4) {
242  int i;
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]);
247 }
248
249
250
251 /* emu8k_init:
252  *  Initialise the synthesiser. See AEPG chapter 4.
253  */
254 void emu8k_init() {
255  int channel;
256  write_HWCF1(0x0059);
257  write_HWCF2(0x0020);
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);
267   write_IP(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);
278  }
279  for (channel=0;channel<_emu8k_numchannels;channel++) {
280   write_CPF(channel,0);
281   write_CVCF(channel,0);
282  }
283  write_SMALR(0);
284  write_SMARR(0);
285  write_SMALW(0);
286  write_SMARW(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);
291  write_HWCF4(0);
292  write_HWCF5(0x00000083);
293  write_HWCF6(0x00008000);
294  write_init_arrays(init4_1,init4_2,init4_3,init4_4);
295  write_HWCF3(0x0004);
296 }
297
298
299
300 /* emu8k_startsound:
301  *  Start a sound on a channel.
302  */
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);
309
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);
323
324  {
325   int psst=0,csl=0;
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 */
331          - MIN_LOOP_LEN;
332     csl  = (envparms->csl &0xff000000)  /* copy chorus verbatim; mask out loop end */
333          + (envparms->sampend)          /* set loop end to sample end */
334          + MIN_LOOP_LEN;
335     break;
336    case 1:      /* loop indefinitely */
337    case 3:      /* loop until key released, then continue */
338     psst = envparms->psst;              /* leave the loop as it stands */
339     csl  = envparms->csl;
340     break;
341   }
342   write_PSST(channel,psst);
343   write_CSL (channel,csl);
344  }
345  write_CCCA(channel,envparms->ccca);
346
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);
352 }
353 static END_OF_FUNCTION(emu8k_startsound);
354
355
356
357 /* emu8k_releasesound:
358  *  End a sound on a channel by starting its release phase.
359  */
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);
364  }
365  write_DCYSUSV(channel,0x8000+envparms->volrel);        /* Start volume envelope release phase */
366  write_DCYSUS (channel,0x8000+envparms->modrel);        /* Start modulation envelope release phase */
367 }
368 static END_OF_FUNCTION(emu8k_releasesound);
369
370
371 /* emu8k_modulate_*:
372  *  Modulation functions - changing a channel's sound in various ways.
373  */
374 void emu8k_modulate_atten (int channel, int atten) {
375  int ifatn;
376  ifatn = read_IFATN (channel);
377  write_IFATN (channel,(ifatn&0xff00)+(atten&0xff));
378 }
379 static END_OF_FUNCTION(emu8k_modulate_atten);
380
381
382 void emu8k_modulate_ip (int channel, int ip) {
383  write_IP(channel,ip);
384 }
385 static END_OF_FUNCTION(emu8k_modulate_ip);
386
387
388 void emu8k_modulate_pan (int channel, int pan) {
389  int psst;
390  psst = read_PSST(channel);
391  write_PSST(channel,(pan<<24)+(psst&0x00ffffff));
392 }
393 static END_OF_FUNCTION(emu8k_modulate_pan);
394
395
396
397 /* emu8k_terminatesound:
398  *  End a sound on a channel immediately (may produce an audible click).
399  */
400 void emu8k_terminatesound(int channel) {
401  write_DCYSUSV(channel,0x0080);
402  write_VTFT(channel,0x0000FFFF);
403  write_CVCF(channel,0x0000FFFF);
404 }
405 static END_OF_FUNCTION(emu8k_terminatesound);
406
407
408
409 /* emu8k_detect:
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.
413  */
414 int emu8k_detect() {
415  char *envvar;
416  if (!(envvar=getenv("BLASTER"))) {
417   sprintf(allegro_error,"BLASTER environment variable not set");
418   return 0;
419  }
420
421  _emu8k_baseport=0;
422  while (*envvar) {
423   if (*envvar=='E') _emu8k_baseport=strtol(envvar+1,NULL,16);
424   while ((*envvar!=' ')&&(*envvar!=0)) envvar++;
425   if (*envvar) envvar++;
426  }
427  if (!_emu8k_baseport) {
428   sprintf(allegro_error,"BLASTER environment variable has no E section");
429   return 0;
430  }
431
432  sprintf(allegro_error,"AWE32 detection failed on port 0x%04x",_emu8k_baseport);
433
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;
437
438  *allegro_error=0;
439  return 1;
440 }
441
442
443
444 /* emu_*:
445  *  Functions to convert SoundFont information to EMU8000 parameters.
446  */
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);
450 }
451
452 static inline unsigned char emu_attack(int x) {
453 /*
454  * AEPG doesn't specify exact conversion here; I'm using what Takashi Iwai used for
455  * his Linux driver
456  */
457  int a,msec;
458  msec=pow(2,x/1200.0)*1000;
459  if (msec==0) return 0x7f;
460 // if (msec>=360)
461   a=11878/msec;
462 // else
463 //  a=32+53.426*log10(360.0/msec);
464
465  return (a<1)?1:((a>0x7f)?0x7f:a);
466 }
467
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);
471 }
472
473 static inline unsigned char emu_decay(int x) {
474 /*
475  * AEPG doesn't specify exact conversion here; I'm using an adaptation of
476  * what Takashi Iwai used for his Linux driver
477  */
478  int a,msec;
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);
484 }
485
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 */
488  int a=0x7f-x/7.5;
489  return (a<0)?0:((a>0x7f)?0x7f:a);
490 }
491
492 static inline unsigned char emu_release(int x) {
493  return emu_decay(x);
494 }
495
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);
499 }
500
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);
504 }
505
506 static inline unsigned char emu_reverb(int x) {
507  int a=(x*0xff)/1000;
508  return (a<0)?0:((a>0xff)?0xff:a);
509 }
510
511 static inline unsigned char emu_chorus(int x) {
512  int a=(x*0xff)/1000;
513  return (a<0)?0:((a>0xff)?0xff:a);
514 }
515
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);
519 }
520
521 static inline unsigned char emu_filterQ(int x) {
522  int a=(x/15);
523  return (a<0)?0:((a>15)?15:a);
524 }
525
526 static inline unsigned int emu_address(int base,int offset,int coarse_offset) {
527  return base+offset+coarse_offset*32*1024;
528 }
529
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);
533 }
534
535 static inline unsigned char emu_filter(int x) {
536  int a = (x-4721)/25;
537  return (a<0)?0:((a>0xff)?0xff:a);
538 }
539
540 static inline unsigned char emu_atten(int x) {
541  int a = x/3.75;
542  return (a<0)?0:((a>0xff)?0xff:a);
543 }
544
545
546
547 /* emu8k_createenvelope:
548  *  Converts a set of SoundFont generators to equivalent EMU8000 register
549  *  settings, for passing to the sound playing functions above.
550  */
551 envparms_t *emu8k_createenvelope(generators_t sfgen) {
552  envparms_t *envelope=(envparms_t *)_lock_malloc(sizeof(envparms_t));
553  if (envelope) {
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
559                     + envelope->modsust
560                     + (0<<7)  // unused
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)
564                     + (0<<7)  // unused
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)
569                     + (0<<7)  // unused
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
588                     + envelope->volsust
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)
593                     + (0<<0);      // unused
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);
605
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];
609
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;
614   envelope->key     = -1;
615   envelope->vel     = -1;
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];
622  }
623  return envelope;
624 }
625
626
627
628 /* emu8k_destroyenvelope:
629  *  Destroys an envelope created by emu8k_createenvelope.
630  */
631 void emu8k_destroyenvelope(envparms_t *env) {
632  free(env);
633 }
634
635
636
637 /* emu8k_lock:
638  *  Locks all data and functions which might be called in an interrupt context.
639  */
640 void emu8k_lock() {
641  LOCK_VARIABLE(_emu8k_baseport);
642  LOCK_VARIABLE(_emu8k_numchannels);
643
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);
650 }
651