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