#include "dtmflib.h"
#include <math.h>
#include "compat.h"
#include "log.h"

struct dtmf_freq {
	unsigned int prim,
		     sec;
};

static const struct dtmf_freq dtmf_freqs[] = {
	{ 941, 1336 }, /* 0 */
	{ 697, 1209 }, /* 1 */
	{ 697, 1336 }, /* 2 */
	{ 697, 1477 }, /* 3 */
	{ 770, 1209 }, /* 4 */
	{ 770, 1336 }, /* 5 */
	{ 770, 1477 }, /* 6 */
	{ 852, 1209 }, /* 7 */
	{ 852, 1336 }, /* 8 */
	{ 852, 1477 }, /* 9 */
	{ 941, 1209 }, /* 10 = * */
	{ 941, 1477 }, /* 11 = # */
	{ 697, 1633 }, /* 12 = A */
	{ 770, 1633 }, /* 13 = B */
	{ 852, 1633 }, /* 14 = C */
	{ 941, 1633 }, /* 15 = D */
};


INLINE double freq2iter(unsigned int hz, unsigned int sample_rate) {
	double ret = hz;
	ret *= 2 * M_PI;
	ret /= sample_rate;
	return ret;
}

// pow(1.122018, x)
static const double vol_table[] = {
	1.0,
	1.122018,
	1.2589243923239999,
	1.4125358288265897,
	1.5848906255883524,
	1.778275809941392,
	1.9952574677188206,
	2.238714793414936,
	2.5118782950778393,
	2.818372660886647,
	3.1622648562227136,
	3.5481180894492965,
	3.9810523624877208,
	4.466812409653747,
	5.011843926254878,
	5.623379098448646,
	6.309532569283152,
	7.079409114321943,
	7.9432244556332785,
	8.91244081726074,
	9.99991902090126,
	11.22008913999359,
	12.589141976677327,
	14.12524390238754,
	15.848777912869062,
	17.78261409624152,
	19.952413103036715,
	22.38696664504305,
	25.118579541137912,
	28.183498379588475,
	31.6223924848691,
	35.480893571087854,
	39.810201242844855,
	44.667762378094295,
	50.1180334079446,
	56.23333560831519,
	63.094814752570585,
	70.79351785904974,
	79.43160132117526,
	89.12368645118244,
	99.9983804245828,
	112.19998280722955,
	125.89040030940208,
	141.25129517435468,
	158.4864957089391,
	177.82470094235242,
	199.52251530193638,
	223.86785357404804,
	251.18376133144622,
	281.8327015215866,
	316.22136409584755,
	354.8060625000947,
	398.0987886342312,
	446.6740066258028,
	501.17627556627,
	562.3288023583151,
	630.943038164472,
	707.9294457952245,
	794.3095809122663,
	891.2296473560191,
	999.9757064671057,
	1121.9907422188091,
	1258.8938086028636,
	1412.501513340968,
	1584.852122995806,
	1778.2326093395081,
	1995.2089958658962,
	2238.660407123461,
	2511.8172726798516,
	2818.3041926577016,
	3162.188033637409,
	3548.031893125778,
	3980.955648661199,
	4466.703894999541,
	5011.722170859594,
	5623.242486703541,
	6309.379288446133,
	7079.237130463753,
	7943.031486648679,
	8912.224302586577,
	9999.676087539585,
	11219.81656438899,
	12588.836141942606,
	14124.900750310158,
	15848.392890061503,
	17782.182093721025,
	19951.928388432676,
	22386.422786532454,
	25117.969322099572,
	28182.813702843516,
	31621.624265237075,
	35480.03161483277,
	39809.23411241143,
	44666.67724033965,
	50116.815863851414,
	56231.96950192683,
	63093.28195661294,
	70791.79803439493,
	79429.67164695573,
	89121.52132197398,
	99995.95111063859,
	112197.2570732565,
	125887.34198682109,
	141247.86368136902,
	158482.6455120423,
	177820.38095213068,
	199517.66819514774,
	223862.4150329833,
	251177.65919047783,
	281825.85480958153,
	316213.68196173705,
	354797.44300734426,
	398089.11740821437,
	446663.1553361299,
	501164.10022393375,
	562315.1414050576,
	630927.7103290199,
	707912.2476879463,
	794290.2843263341,
	891207.9962392647,
	999951.4135243873,
	1121963.485099806,
	1258863.225624714,
	1412467.1986889902,
	1584813.6213386236,
	1778189.4097871196,
	1995160.5251905243,
	2238606.0221532215,
};

// only packed audio supported

#define freq_samples_x(type, mult) \
INLINE void freq_samples_ ## type(type *samples, unsigned long offset, unsigned long num, unsigned int prim_freq, \
		unsigned int sec_freq, unsigned int volume, unsigned int sample_rate, unsigned int channels) \
{ \
	if (!channels) \
		channels = 1; \
\
	double vol; \
	if (volume < G_N_ELEMENTS(vol_table)) \
		vol = vol_table[volume]; \
	else \
		vol = pow(1.122018, volume); \
\
	if (sec_freq) /* halve volume of we have two tones */ \
		vol *= 2.0; \
\
	double prim_iter = freq2iter(prim_freq, sample_rate); \
	double sec_iter = sec_freq ? freq2iter(sec_freq, sample_rate) : 0; \
\
	num += offset; /* end here */ \
	while (offset < num) { \
		double prim = sin(prim_iter * offset) / vol; \
		type sample; \
		if (!sec_freq) \
			sample = prim * mult; \
		else { \
			double sec = sin(sec_iter * offset) / vol; \
			sample = prim * mult + sec * mult; \
		} \
		for (unsigned int ch = 0; ch < channels; ch++) \
			*samples++ = sample; \
		offset++; \
	} \
}

freq_samples_x(int16_t, 32767.0)
freq_samples_x(int32_t, 2147483647.0)
freq_samples_x(double, 1.0)
freq_samples_x(float, 1.0)

#define tone_samples_x(type) \
void tone_samples_ ## type(type *samples, unsigned long offset, unsigned long num, unsigned int freq, \
		unsigned int volume, unsigned int sample_rate, unsigned int channels) \
{ \
	freq_samples_ ## type(samples, offset, num, freq, 0, volume, sample_rate, channels); \
}

tone_samples_x(int16_t)
tone_samples_x(int32_t)
tone_samples_x(double)
tone_samples_x(float)

#define dtmf_samples_x(type) \
void dtmf_samples_ ## type(type *samples, unsigned long offset, unsigned long num, unsigned int event, \
		unsigned int volume, unsigned int sample_rate, unsigned int channels) \
{ \
	const struct dtmf_freq *df; \
\
	if (event == 0xff) { \
		/* pause - silence samples */ \
		memset(samples, 0, num * sizeof(type)); \
		return; \
	} \
\
	if (event >= G_N_ELEMENTS(dtmf_freqs)) { \
		ilog(LOG_WARN | LOG_FLAG_LIMIT, "Unsupported DTMF event %u", event); \
		memset(samples, 0, num * sizeof(type)); \
		return; \
	} \
	df = &dtmf_freqs[event]; \
\
	freq_samples_ ## type(samples, offset, num, df->prim, df->sec, volume, sample_rate, channels); \
} \

dtmf_samples_x(int16_t)
dtmf_samples_x(int32_t)
dtmf_samples_x(double)
dtmf_samples_x(float)

void dtmf_samples_int16_t_mono(void *buf, unsigned long offset, unsigned long num, unsigned int event,
		unsigned int volume, unsigned int sample_rate)
{
	dtmf_samples_int16_t(buf, offset, num, event, volume, sample_rate, 1);
}