18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/time.h> 78c2ecf20Sopenharmony_ci#include <linux/export.h> 88c2ecf20Sopenharmony_ci#include <sound/core.h> 98c2ecf20Sopenharmony_ci#include <sound/gus.h> 108c2ecf20Sopenharmony_ci#define __GUS_TABLES_ALLOC__ 118c2ecf20Sopenharmony_ci#include "gus_tables.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_gf1_atten_table); /* for snd-gus-synth module */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciunsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci unsigned short e, m, tmp; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci if (vol > 65535) 208c2ecf20Sopenharmony_ci vol = 65535; 218c2ecf20Sopenharmony_ci tmp = vol; 228c2ecf20Sopenharmony_ci e = 7; 238c2ecf20Sopenharmony_ci if (tmp < 128) { 248c2ecf20Sopenharmony_ci while (e > 0 && tmp < (1 << e)) 258c2ecf20Sopenharmony_ci e--; 268c2ecf20Sopenharmony_ci } else { 278c2ecf20Sopenharmony_ci while (tmp > 255) { 288c2ecf20Sopenharmony_ci tmp >>= 1; 298c2ecf20Sopenharmony_ci e++; 308c2ecf20Sopenharmony_ci } 318c2ecf20Sopenharmony_ci } 328c2ecf20Sopenharmony_ci m = vol - (1 << e); 338c2ecf20Sopenharmony_ci if (m > 0) { 348c2ecf20Sopenharmony_ci if (e > 8) 358c2ecf20Sopenharmony_ci m >>= e - 8; 368c2ecf20Sopenharmony_ci else if (e < 8) 378c2ecf20Sopenharmony_ci m <<= 8 - e; 388c2ecf20Sopenharmony_ci m &= 255; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci return (e << 8) | m; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#if 0 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciunsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci unsigned int rvol; 488c2ecf20Sopenharmony_ci unsigned short e, m; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (!gf1_vol) 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci e = gf1_vol >> 8; 538c2ecf20Sopenharmony_ci m = (unsigned char) gf1_vol; 548c2ecf20Sopenharmony_ci rvol = 1 << e; 558c2ecf20Sopenharmony_ci if (e > 8) 568c2ecf20Sopenharmony_ci return rvol | (m << (e - 8)); 578c2ecf20Sopenharmony_ci return rvol | (m >> (8 - e)); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciunsigned int snd_gf1_calc_ramp_rate(struct snd_gus_card * gus, 618c2ecf20Sopenharmony_ci unsigned short start, 628c2ecf20Sopenharmony_ci unsigned short end, 638c2ecf20Sopenharmony_ci unsigned int us) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci static const unsigned char vol_rates[19] = 668c2ecf20Sopenharmony_ci { 678c2ecf20Sopenharmony_ci 23, 24, 26, 28, 29, 31, 32, 34, 688c2ecf20Sopenharmony_ci 36, 37, 39, 40, 42, 44, 45, 47, 698c2ecf20Sopenharmony_ci 49, 50, 52 708c2ecf20Sopenharmony_ci }; 718c2ecf20Sopenharmony_ci unsigned short range, increment, value, i; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci start >>= 4; 748c2ecf20Sopenharmony_ci end >>= 4; 758c2ecf20Sopenharmony_ci if (start < end) 768c2ecf20Sopenharmony_ci us /= end - start; 778c2ecf20Sopenharmony_ci else 788c2ecf20Sopenharmony_ci us /= start - end; 798c2ecf20Sopenharmony_ci range = 4; 808c2ecf20Sopenharmony_ci value = gus->gf1.enh_mode ? 818c2ecf20Sopenharmony_ci vol_rates[0] : 828c2ecf20Sopenharmony_ci vol_rates[gus->gf1.active_voices - 14]; 838c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 848c2ecf20Sopenharmony_ci if (us < value) { 858c2ecf20Sopenharmony_ci range = i; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci } else 888c2ecf20Sopenharmony_ci value <<= 3; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci if (range == 4) { 918c2ecf20Sopenharmony_ci range = 3; 928c2ecf20Sopenharmony_ci increment = 1; 938c2ecf20Sopenharmony_ci } else 948c2ecf20Sopenharmony_ci increment = (value + (value >> 1)) / us; 958c2ecf20Sopenharmony_ci return (range << 6) | (increment & 0x3f); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#endif /* 0 */ 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ciunsigned short snd_gf1_translate_freq(struct snd_gus_card * gus, unsigned int freq16) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci freq16 >>= 3; 1038c2ecf20Sopenharmony_ci if (freq16 < 50) 1048c2ecf20Sopenharmony_ci freq16 = 50; 1058c2ecf20Sopenharmony_ci if (freq16 & 0xf8000000) { 1068c2ecf20Sopenharmony_ci freq16 = ~0xf8000000; 1078c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "snd_gf1_translate_freq: overflow - freq = 0x%x\n", freq16); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#if 0 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cishort snd_gf1_compute_vibrato(short cents, unsigned short fc_register) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci static const short vibrato_table[] = 1178c2ecf20Sopenharmony_ci { 1188c2ecf20Sopenharmony_ci 0, 0, 32, 592, 61, 1175, 93, 1808, 1198c2ecf20Sopenharmony_ci 124, 2433, 152, 3007, 182, 3632, 213, 4290, 1208c2ecf20Sopenharmony_ci 241, 4834, 255, 5200 1218c2ecf20Sopenharmony_ci }; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci long depth; 1248c2ecf20Sopenharmony_ci const short *vi1, *vi2; 1258c2ecf20Sopenharmony_ci short pcents, v1; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci pcents = cents < 0 ? -cents : cents; 1288c2ecf20Sopenharmony_ci for (vi1 = vibrato_table, vi2 = vi1 + 2; pcents > *vi2; vi1 = vi2, vi2 += 2); 1298c2ecf20Sopenharmony_ci v1 = *(vi1 + 1); 1308c2ecf20Sopenharmony_ci /* The FC table above is a list of pairs. The first number in the pair */ 1318c2ecf20Sopenharmony_ci /* is the cents index from 0-255 cents, and the second number in the */ 1328c2ecf20Sopenharmony_ci /* pair is the FC adjustment needed to change the pitch by the indexed */ 1338c2ecf20Sopenharmony_ci /* number of cents. The table was created for an FC of 32768. */ 1348c2ecf20Sopenharmony_ci /* The following expression does a linear interpolation against the */ 1358c2ecf20Sopenharmony_ci /* approximated log curve in the table above, and then scales the number */ 1368c2ecf20Sopenharmony_ci /* by the FC before the LFO. This calculation also adjusts the output */ 1378c2ecf20Sopenharmony_ci /* value to produce the appropriate depth for the hardware. The depth */ 1388c2ecf20Sopenharmony_ci /* is 2 * desired FC + 1. */ 1398c2ecf20Sopenharmony_ci depth = (((int) (*(vi2 + 1) - *vi1) * (pcents - *vi1) / (*vi2 - *vi1)) + v1) * fc_register >> 14; 1408c2ecf20Sopenharmony_ci if (depth) 1418c2ecf20Sopenharmony_ci depth++; 1428c2ecf20Sopenharmony_ci if (depth > 255) 1438c2ecf20Sopenharmony_ci depth = 255; 1448c2ecf20Sopenharmony_ci return cents < 0 ? -(short) depth : (short) depth; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ciunsigned short snd_gf1_compute_pitchbend(unsigned short pitchbend, unsigned short sens) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci static const long log_table[] = {1024, 1085, 1149, 1218, 1290, 1367, 1448, 1534, 1625, 1722, 1825, 1933}; 1508c2ecf20Sopenharmony_ci int wheel, sensitivity; 1518c2ecf20Sopenharmony_ci unsigned int mantissa, f1, f2; 1528c2ecf20Sopenharmony_ci unsigned short semitones, f1_index, f2_index, f1_power, f2_power; 1538c2ecf20Sopenharmony_ci char bend_down = 0; 1548c2ecf20Sopenharmony_ci int bend; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (!sens) 1578c2ecf20Sopenharmony_ci return 1024; 1588c2ecf20Sopenharmony_ci wheel = (int) pitchbend - 8192; 1598c2ecf20Sopenharmony_ci sensitivity = ((int) sens * wheel) / 128; 1608c2ecf20Sopenharmony_ci if (sensitivity < 0) { 1618c2ecf20Sopenharmony_ci bend_down = 1; 1628c2ecf20Sopenharmony_ci sensitivity = -sensitivity; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci semitones = (unsigned int) (sensitivity >> 13); 1658c2ecf20Sopenharmony_ci mantissa = sensitivity % 8192; 1668c2ecf20Sopenharmony_ci f1_index = semitones % 12; 1678c2ecf20Sopenharmony_ci f2_index = (semitones + 1) % 12; 1688c2ecf20Sopenharmony_ci f1_power = semitones / 12; 1698c2ecf20Sopenharmony_ci f2_power = (semitones + 1) / 12; 1708c2ecf20Sopenharmony_ci f1 = log_table[f1_index] << f1_power; 1718c2ecf20Sopenharmony_ci f2 = log_table[f2_index] << f2_power; 1728c2ecf20Sopenharmony_ci bend = (int) ((((f2 - f1) * mantissa) >> 13) + f1); 1738c2ecf20Sopenharmony_ci if (bend_down) 1748c2ecf20Sopenharmony_ci bend = 1048576L / bend; 1758c2ecf20Sopenharmony_ci return bend; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciunsigned short snd_gf1_compute_freq(unsigned int freq, 1798c2ecf20Sopenharmony_ci unsigned int rate, 1808c2ecf20Sopenharmony_ci unsigned short mix_rate) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci unsigned int fc; 1838c2ecf20Sopenharmony_ci int scale = 0; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci while (freq >= 4194304L) { 1868c2ecf20Sopenharmony_ci scale++; 1878c2ecf20Sopenharmony_ci freq >>= 1; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci fc = (freq << 10) / rate; 1908c2ecf20Sopenharmony_ci if (fc > 97391L) { 1918c2ecf20Sopenharmony_ci fc = 97391; 1928c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "patch: (1) fc frequency overflow - %u\n", fc); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci fc = (fc * 44100UL) / mix_rate; 1958c2ecf20Sopenharmony_ci while (scale--) 1968c2ecf20Sopenharmony_ci fc <<= 1; 1978c2ecf20Sopenharmony_ci if (fc > 65535L) { 1988c2ecf20Sopenharmony_ci fc = 65535; 1998c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "patch: (2) fc frequency overflow - %u\n", fc); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci return (unsigned short) fc; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#endif /* 0 */ 205