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