Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / sound / isa / i386 / gus / gus_vol.c
1 /*
2  * gus_vol.c - Compute volume for GUS.
3  * 
4  * Greg Lee 1993.
5  */
6 #include <i386/isa/sound/sound_config.h>
7
8 #ifdef CONFIG_GUS
9 #include <i386/isa/sound/gus_linearvol.h>
10
11 #define GUS_VOLUME      gus_wave_volume
12
13
14 extern int      gus_wave_volume;
15 unsigned short  gus_adagio_vol(int vel, int mainv, int xpn, int voicev);
16 unsigned short  gus_linear_vol(int vol, int mainvol);
17
18 /*
19  * Calculate gus volume from note velocity, main volume, expression, and
20  * intrinsic patch volume given in patch library.  Expression is multiplied
21  * in, so it emphasizes differences in note velocity, while main volume is
22  * added in -- I don't know whether this is right, but it seems reasonable to
23  * me.  (In the previous stage, main volume controller messages were changed
24  * to expression controller messages, if they were found to be used for
25  * dynamic volume adjustments, so here, main volume can be assumed to be
26  * constant throughout a song.)
27  * 
28  * Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
29  * we can give a big boost to very weak voices like nylon guitar and the
30  * basses.  The normal value is 64.  Strings are assigned lower values.
31  */
32 unsigned short
33 gus_adagio_vol(int vel, int mainv, int xpn, int voicev)
34 {
35     int             i, m, n, x;
36
37     /*
38      * A voice volume of 64 is considered neutral, so adjust the main
39      * volume if something other than this neutral value was assigned in
40      * the patch library.
41      */
42     x = 256 + 6 * (voicev - 64);
43
44     /*
45      * Boost expression by voice volume above neutral.
46      */
47     if (voicev > 65)
48         xpn += voicev - 64;
49     xpn += (voicev - 64) / 2;
50
51     /*
52      * Combine multiplicative and level components.
53      */
54     x = vel * xpn * 6 + (voicev / 4) * x;
55
56 #ifdef GUS_VOLUME
57     /*
58      * Further adjustment by installation-specific master volume control
59      * (default 60).
60      */
61     x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
62 #endif
63
64 #ifdef GUS_USE_CHN_MAIN_VOLUME
65     /*
66      * Experimental support for the channel main volume
67      */
68
69     mainv = (mainv / 2) + 64;   /* Scale to 64 to 127 */
70     x = (x * mainv * mainv) / 16384;
71 #endif
72
73     if (x < 2)
74         return (0);
75     else if (x >= 65535)
76         return ((15 << 8) | 255);
77
78     /*
79      * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
80      * mantissa m.
81      */
82     n = x;
83     i = 7;
84     if (n < 128) {
85         while (i > 0 && n < (1 << i))
86             i--;
87     } else
88         while (n > 255) {
89             n >>= 1;
90             i++;
91         }
92     /*
93      * Mantissa is part of linear volume not expressed in exponent.
94      * (This is not quite like real logs -- I wonder if it's right.)
95      */
96     m = x - (1 << i);
97
98     /*
99      * Adjust mantissa to 8 bits.
100      */
101     if (m > 0) {
102         if (i > 8)
103             m >>= i - 8;
104         else if (i < 8)
105             m <<= 8 - i;
106     }
107     return ((i << 8) + m);
108 }
109
110 /*
111  * Volume-values are interpreted as linear values. Volume is based on the
112  * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
113  * and the volume set by the mixer-device (default 60%).
114  */
115
116 unsigned short
117 gus_linear_vol(int vol, int mainvol)
118 {
119     int             mixer_mainvol;
120
121     RANGE (vol, 0, 127) ;
122
123 #ifdef GUS_VOLUME
124     mixer_mainvol = GUS_VOLUME;
125 #else
126     mixer_mainvol = 100;
127 #endif
128
129 #ifdef GUS_USE_CHN_MAIN_VOLUME
130     RANGE (mainvol, 0, 127);
131 #else
132     mainvol = 127;
133 #endif
134
135     return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100];
136 }
137
138 #endif