Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
Jaroslav Kysela | c1017a4 | 2007-10-15 09:50:19 +0200 | [diff] [blame] | 2 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3 | * |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by |
| 7 | * the Free Software Foundation; either version 2 of the License, or |
| 8 | * (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 18 | * |
| 19 | */ |
| 20 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 | #include <linux/time.h> |
| 22 | #include <sound/core.h> |
| 23 | #include <sound/gus.h> |
| 24 | #define __GUS_TABLES_ALLOC__ |
| 25 | #include "gus_tables.h" |
| 26 | |
| 27 | EXPORT_SYMBOL(snd_gf1_atten_table); /* for snd-gus-synth module */ |
| 28 | |
| 29 | unsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol) |
| 30 | { |
| 31 | unsigned short e, m, tmp; |
| 32 | |
| 33 | if (vol > 65535) |
| 34 | vol = 65535; |
| 35 | tmp = vol; |
| 36 | e = 7; |
| 37 | if (tmp < 128) { |
| 38 | while (e > 0 && tmp < (1 << e)) |
| 39 | e--; |
| 40 | } else { |
| 41 | while (tmp > 255) { |
| 42 | tmp >>= 1; |
| 43 | e++; |
| 44 | } |
| 45 | } |
| 46 | m = vol - (1 << e); |
| 47 | if (m > 0) { |
| 48 | if (e > 8) |
| 49 | m >>= e - 8; |
| 50 | else if (e < 8) |
| 51 | m <<= 8 - e; |
| 52 | m &= 255; |
| 53 | } |
| 54 | return (e << 8) | m; |
| 55 | } |
| 56 | |
Adrian Bunk | 209ac85 | 2005-05-23 10:29:53 +0200 | [diff] [blame] | 57 | #if 0 |
| 58 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 | unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol) |
| 60 | { |
| 61 | unsigned int rvol; |
| 62 | unsigned short e, m; |
| 63 | |
| 64 | if (!gf1_vol) |
| 65 | return 0; |
| 66 | e = gf1_vol >> 8; |
| 67 | m = (unsigned char) gf1_vol; |
| 68 | rvol = 1 << e; |
| 69 | if (e > 8) |
| 70 | return rvol | (m << (e - 8)); |
| 71 | return rvol | (m >> (8 - e)); |
| 72 | } |
| 73 | |
Takashi Iwai | 5e2da20 | 2005-11-17 14:36:44 +0100 | [diff] [blame] | 74 | unsigned int snd_gf1_calc_ramp_rate(struct snd_gus_card * gus, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 75 | unsigned short start, |
| 76 | unsigned short end, |
| 77 | unsigned int us) |
| 78 | { |
| 79 | static unsigned char vol_rates[19] = |
| 80 | { |
| 81 | 23, 24, 26, 28, 29, 31, 32, 34, |
| 82 | 36, 37, 39, 40, 42, 44, 45, 47, |
| 83 | 49, 50, 52 |
| 84 | }; |
| 85 | unsigned short range, increment, value, i; |
| 86 | |
| 87 | start >>= 4; |
| 88 | end >>= 4; |
| 89 | if (start < end) |
| 90 | us /= end - start; |
| 91 | else |
| 92 | us /= start - end; |
| 93 | range = 4; |
| 94 | value = gus->gf1.enh_mode ? |
| 95 | vol_rates[0] : |
| 96 | vol_rates[gus->gf1.active_voices - 14]; |
| 97 | for (i = 0; i < 3; i++) { |
| 98 | if (us < value) { |
| 99 | range = i; |
| 100 | break; |
| 101 | } else |
| 102 | value <<= 3; |
| 103 | } |
| 104 | if (range == 4) { |
| 105 | range = 3; |
| 106 | increment = 1; |
| 107 | } else |
| 108 | increment = (value + (value >> 1)) / us; |
| 109 | return (range << 6) | (increment & 0x3f); |
| 110 | } |
| 111 | |
Adrian Bunk | 209ac85 | 2005-05-23 10:29:53 +0200 | [diff] [blame] | 112 | #endif /* 0 */ |
| 113 | |
Takashi Iwai | 5e2da20 | 2005-11-17 14:36:44 +0100 | [diff] [blame] | 114 | unsigned short snd_gf1_translate_freq(struct snd_gus_card * gus, unsigned int freq16) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 | { |
| 116 | freq16 >>= 3; |
| 117 | if (freq16 < 50) |
| 118 | freq16 = 50; |
| 119 | if (freq16 & 0xf8000000) { |
| 120 | freq16 = ~0xf8000000; |
Takashi Iwai | 99b359b | 2005-10-20 18:26:44 +0200 | [diff] [blame] | 121 | snd_printk(KERN_ERR "snd_gf1_translate_freq: overflow - freq = 0x%x\n", freq16); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | } |
| 123 | return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq; |
| 124 | } |
| 125 | |
Adrian Bunk | 209ac85 | 2005-05-23 10:29:53 +0200 | [diff] [blame] | 126 | #if 0 |
| 127 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | short snd_gf1_compute_vibrato(short cents, unsigned short fc_register) |
| 129 | { |
| 130 | static short vibrato_table[] = |
| 131 | { |
| 132 | 0, 0, 32, 592, 61, 1175, 93, 1808, |
| 133 | 124, 2433, 152, 3007, 182, 3632, 213, 4290, |
| 134 | 241, 4834, 255, 5200 |
| 135 | }; |
| 136 | |
| 137 | long depth; |
| 138 | short *vi1, *vi2, pcents, v1; |
| 139 | |
| 140 | pcents = cents < 0 ? -cents : cents; |
| 141 | for (vi1 = vibrato_table, vi2 = vi1 + 2; pcents > *vi2; vi1 = vi2, vi2 += 2); |
| 142 | v1 = *(vi1 + 1); |
| 143 | /* The FC table above is a list of pairs. The first number in the pair */ |
| 144 | /* is the cents index from 0-255 cents, and the second number in the */ |
| 145 | /* pair is the FC adjustment needed to change the pitch by the indexed */ |
| 146 | /* number of cents. The table was created for an FC of 32768. */ |
| 147 | /* The following expression does a linear interpolation against the */ |
| 148 | /* approximated log curve in the table above, and then scales the number */ |
| 149 | /* by the FC before the LFO. This calculation also adjusts the output */ |
| 150 | /* value to produce the appropriate depth for the hardware. The depth */ |
| 151 | /* is 2 * desired FC + 1. */ |
| 152 | depth = (((int) (*(vi2 + 1) - *vi1) * (pcents - *vi1) / (*vi2 - *vi1)) + v1) * fc_register >> 14; |
| 153 | if (depth) |
| 154 | depth++; |
| 155 | if (depth > 255) |
| 156 | depth = 255; |
| 157 | return cents < 0 ? -(short) depth : (short) depth; |
| 158 | } |
| 159 | |
| 160 | unsigned short snd_gf1_compute_pitchbend(unsigned short pitchbend, unsigned short sens) |
| 161 | { |
| 162 | static long log_table[] = {1024, 1085, 1149, 1218, 1290, 1367, 1448, 1534, 1625, 1722, 1825, 1933}; |
| 163 | int wheel, sensitivity; |
| 164 | unsigned int mantissa, f1, f2; |
| 165 | unsigned short semitones, f1_index, f2_index, f1_power, f2_power; |
| 166 | char bend_down = 0; |
| 167 | int bend; |
| 168 | |
| 169 | if (!sens) |
| 170 | return 1024; |
| 171 | wheel = (int) pitchbend - 8192; |
| 172 | sensitivity = ((int) sens * wheel) / 128; |
| 173 | if (sensitivity < 0) { |
| 174 | bend_down = 1; |
| 175 | sensitivity = -sensitivity; |
| 176 | } |
| 177 | semitones = (unsigned int) (sensitivity >> 13); |
| 178 | mantissa = sensitivity % 8192; |
| 179 | f1_index = semitones % 12; |
| 180 | f2_index = (semitones + 1) % 12; |
| 181 | f1_power = semitones / 12; |
| 182 | f2_power = (semitones + 1) / 12; |
| 183 | f1 = log_table[f1_index] << f1_power; |
| 184 | f2 = log_table[f2_index] << f2_power; |
| 185 | bend = (int) ((((f2 - f1) * mantissa) >> 13) + f1); |
| 186 | if (bend_down) |
| 187 | bend = 1048576L / bend; |
| 188 | return bend; |
| 189 | } |
| 190 | |
| 191 | unsigned short snd_gf1_compute_freq(unsigned int freq, |
| 192 | unsigned int rate, |
| 193 | unsigned short mix_rate) |
| 194 | { |
| 195 | unsigned int fc; |
| 196 | int scale = 0; |
| 197 | |
| 198 | while (freq >= 4194304L) { |
| 199 | scale++; |
| 200 | freq >>= 1; |
| 201 | } |
| 202 | fc = (freq << 10) / rate; |
| 203 | if (fc > 97391L) { |
| 204 | fc = 97391; |
Takashi Iwai | 99b359b | 2005-10-20 18:26:44 +0200 | [diff] [blame] | 205 | snd_printk(KERN_ERR "patch: (1) fc frequency overflow - %u\n", fc); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | } |
| 207 | fc = (fc * 44100UL) / mix_rate; |
| 208 | while (scale--) |
| 209 | fc <<= 1; |
| 210 | if (fc > 65535L) { |
| 211 | fc = 65535; |
Takashi Iwai | 99b359b | 2005-10-20 18:26:44 +0200 | [diff] [blame] | 212 | snd_printk(KERN_ERR "patch: (2) fc frequency overflow - %u\n", fc); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 213 | } |
| 214 | return (unsigned short) fc; |
| 215 | } |
Adrian Bunk | 209ac85 | 2005-05-23 10:29:53 +0200 | [diff] [blame] | 216 | |
| 217 | #endif /* 0 */ |