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