//dtmf.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2012 * * This file is part of libroardsp a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * libroardsp is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "libroardsp.h" ssize_t roar_dtmf_mus2samples(const int_least32_t t, const uint32_t rate) { int64_t ret = t; if ( t < 0 || rate == 0 ) { roar_err_set(ROAR_ERROR_INVAL); return -1; } ret *= (int64_t)rate; ret /= (int64_t)1000000; return ret; } int roar_dtmf_break(int16_t * samples, const size_t len, const uint32_t rate, const int options) { (void)rate, (void)options; ROAR_DBG("roar_dtmf_break(samples=%p, len=%llu, rate=%lu, options=%i) = ?", samples, (long long unsigned int)len, (long unsigned int)rate, options); if ( samples == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } memset(samples, 0, len*sizeof(int16_t)); return 0; } #define _FQL0 697 #define _FQL1 770 #define _FQL2 852 #define _FQL3 941 #define _FQH0 1209 #define _FQH1 1336 #define _FQH2 1477 #define _FQH3 1633 #define _FRL0 571 #define _FRL1 631 #define _FRL2 _FQL0 #define _FRL3 _FQL1 #define _FRL4 _FQL2 #define _FRL5 _FQL3 #define _FRL6 1040 #define _FRH0 _FQH0 #define _FRH1 _FQH1 #define _FRH2 _FQH2 #define _FRH3 _FQH3 #define _FRH4 1805 #define _FRH5 1995 #define _FRH6 2205 static const struct tone { const uint16_t c; const float f0; const float f1; } _roardsp_tones[] = { {ROAR_DTMF_CHAR_DTMF('1'), _FQL0, _FQH0}, {ROAR_DTMF_CHAR_DTMF('2'), _FQL0, _FQH1}, {ROAR_DTMF_CHAR_DTMF('3'), _FQL0, _FQH2}, {ROAR_DTMF_CHAR_DTMF('A'), _FQL0, _FQH3}, {ROAR_DTMF_CHAR_DTMF('4'), _FQL1, _FQH0}, {ROAR_DTMF_CHAR_DTMF('5'), _FQL1, _FQH1}, {ROAR_DTMF_CHAR_DTMF('6'), _FQL1, _FQH2}, {ROAR_DTMF_CHAR_DTMF('B'), _FQL1, _FQH3}, {ROAR_DTMF_CHAR_DTMF('7'), _FQL2, _FQH0}, {ROAR_DTMF_CHAR_DTMF('8'), _FQL2, _FQH1}, {ROAR_DTMF_CHAR_DTMF('9'), _FQL2, _FQH2}, {ROAR_DTMF_CHAR_DTMF('C'), _FQL2, _FQH3}, {ROAR_DTMF_CHAR_DTMF('*'), _FQL3, _FQH0}, {ROAR_DTMF_CHAR_DTMF('0'), _FQL3, _FQH1}, {ROAR_DTMF_CHAR_DTMF('#'), _FQL3, _FQH2}, {ROAR_DTMF_CHAR_DTMF('D'), _FQL3, _FQH3}, {ROAR_DTMF_CHAR_NOOP, _FRL0, _FRH0}, {ROAR_DTMF_CHAR_ESCAPE, _FRL0, _FRH1}, {ROAR_DTMF_CHAR_ROAR('"'), _FRL0, _FRH2}, {ROAR_DTMF_CHAR_ROAR(' '), _FRL0, _FRH3}, {ROAR_DTMF_CHAR_ROAR('F'), _FRL0, _FRH4}, {ROAR_DTMF_CHAR_ROAR('M'), _FRL0, _FRH5}, {ROAR_DTMF_CHAR_ROAR('T'), _FRL0, _FRH6}, {ROAR_DTMF_CHAR_ROAR('.'), _FRL1, _FRH0}, {ROAR_DTMF_CHAR_ROAR('?'), _FRL1, _FRH1}, {ROAR_DTMF_CHAR_ROAR('!'), _FRL1, _FRH2}, {ROAR_DTMF_CHAR_ROAR(','), _FRL1, _FRH3}, {ROAR_DTMF_CHAR_ROAR('G'), _FRL1, _FRH4}, {ROAR_DTMF_CHAR_ROAR('N'), _FRL1, _FRH5}, {ROAR_DTMF_CHAR_ROAR('U'), _FRL1, _FRH6}, {ROAR_DTMF_CHAR_ROAR('1'), _FRL2, _FRH0}, {ROAR_DTMF_CHAR_ROAR('2'), _FRL2, _FRH1}, {ROAR_DTMF_CHAR_ROAR('3'), _FRL2, _FRH2}, {ROAR_DTMF_CHAR_ROAR('A'), _FRL2, _FRH3}, {ROAR_DTMF_CHAR_ROAR('H'), _FRL2, _FRH4}, {ROAR_DTMF_CHAR_ROAR('O'), _FRL2, _FRH5}, {ROAR_DTMF_CHAR_ROAR('V'), _FRL2, _FRH6}, {ROAR_DTMF_CHAR_ROAR('4'), _FRL3, _FRH0}, {ROAR_DTMF_CHAR_ROAR('5'), _FRL3, _FRH1}, {ROAR_DTMF_CHAR_ROAR('6'), _FRL3, _FRH2}, {ROAR_DTMF_CHAR_ROAR('B'), _FRL3, _FRH3}, {ROAR_DTMF_CHAR_ROAR('I'), _FRL3, _FRH4}, {ROAR_DTMF_CHAR_ROAR('P'), _FRL3, _FRH5}, {ROAR_DTMF_CHAR_ROAR('W'), _FRL3, _FRH6}, {ROAR_DTMF_CHAR_ROAR('7'), _FRL4, _FRH0}, {ROAR_DTMF_CHAR_ROAR('8'), _FRL4, _FRH1}, {ROAR_DTMF_CHAR_ROAR('9'), _FRL4, _FRH2}, {ROAR_DTMF_CHAR_ROAR('C'), _FRL4, _FRH3}, {ROAR_DTMF_CHAR_ROAR('J'), _FRL4, _FRH4}, {ROAR_DTMF_CHAR_ROAR('Q'), _FRL4, _FRH5}, {ROAR_DTMF_CHAR_ROAR('X'), _FRL4, _FRH6}, {ROAR_DTMF_CHAR_ROAR('*'), _FRL5, _FRH0}, {ROAR_DTMF_CHAR_ROAR('0'), _FRL5, _FRH1}, {ROAR_DTMF_CHAR_ROAR('#'), _FRL5, _FRH2}, {ROAR_DTMF_CHAR_ROAR('D'), _FRL5, _FRH3}, {ROAR_DTMF_CHAR_ROAR('K'), _FRL5, _FRH4}, {ROAR_DTMF_CHAR_ROAR('R'), _FRL5, _FRH5}, {ROAR_DTMF_CHAR_ROAR('Y'), _FRL5, _FRH6}, {ROAR_DTMF_CHAR_ROAR('@'), _FRL6, _FRH0}, {ROAR_DTMF_CHAR_ROAR('+'), _FRL6, _FRH1}, {ROAR_DTMF_CHAR_ROAR('-'), _FRL6, _FRH2}, {ROAR_DTMF_CHAR_ROAR('E'), _FRL6, _FRH3}, {ROAR_DTMF_CHAR_ROAR('L'), _FRL6, _FRH4}, {ROAR_DTMF_CHAR_ROAR('S'), _FRL6, _FRH5}, {ROAR_DTMF_CHAR_ROAR('Z'), _FRL6, _FRH6}, {0, -1, -1} }; static const struct tone * __lookup_tone_by_char(const int options, uint16_t c) { size_t i; (void)options; if ( (c >= ROAR_DTMF_CHAR_DTMF('a') && c <= ROAR_DTMF_CHAR_DTMF('z')) || (c >= ROAR_DTMF_CHAR_ROAR('a') && c <= ROAR_DTMF_CHAR_ROAR('z')) ) c -= 'a' - 'A'; for (i = 0; _roardsp_tones[i].c != 0; i++) { if ( _roardsp_tones[i].c == c ) { return &(_roardsp_tones[i]); } } roar_err_set(ROAR_ERROR_NOENT); return NULL; } static const struct tone * __lookup_tone_by_freq(const int options, float f0, float f1) { const struct tone * ct; size_t i; float tmp; (void)options; if ( f0 > f1 ) { tmp = f0; f0 = f1; f1 = tmp; } for (i = 0; _roardsp_tones[i].c != 0; i++) { ct = &(_roardsp_tones[i]); // allow 3.5% freq error as defined in ITU-T Q.23 and Q.24. if ( ct->f0 < f0*.965 || ct->f0 > f0*1.035 ) continue; if ( ct->f1 < f1*.965 || ct->f1 > f1*1.035 ) continue; return ct; } roar_err_set(ROAR_ERROR_NOENT); return NULL; } int roar_dtmf_tone (int16_t * samples, const size_t len, const uint32_t rate, const int options, const uint16_t c) { const struct tone * ct = NULL; size_t i; float t; float t_inc = 1./rate; float fc0, fc1; ROAR_DBG("roar_dtmf_tone(samples=%p, len=%llu, rate=%lu, options=%i, c=%i) = ?", samples, (long long unsigned int)len, (long unsigned int)rate, options, (int)c); if ( samples == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( c == ROAR_DTMF_CHAR_BREAK ) return roar_dtmf_break(samples, len, rate, options); ct = __lookup_tone_by_char(options, c); if ( ct == NULL ) { roar_err_set(ROAR_ERROR_NOENT); return -1; } fc0 = 2. * M_PI * ct->f0; fc1 = 2. * M_PI * ct->f1; // memset(samples, 0, len); for (i = 0, t = 0.; i < len; t += t_inc, i++) { samples[i] = (sinf(fc0*t) + sinf(fc1*t))*8192.0; } return 0; } uint16_t roar_dtmf_freqs2char(const int options, float f0, float f1) { const struct tone * ct = __lookup_tone_by_freq(options, f0, f1); if ( ct == NULL ) return ROAR_DTMF_CHAR_BREAK; return ct->c; } //ll