1 /* $NetBSD: dtmf.c,v 1.5 2026/04/03 08:37:46 mlelstv Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Jared D. McNeill <jmcneill (at) invisible.ca> 5 * Copyright (c) 2026 Michael van ELst <mlelstv (at) netbsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/endian.h> 31 32 #include <err.h> 33 #include <fcntl.h> 34 #include <math.h> 35 #include <stdio.h> 36 #include <stdint.h> 37 #include <string.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 41 #include "dtmf.h" 42 43 /* dialtone frequency pair */ 44 struct dialtone { 45 float a; 46 float b; 47 }; 48 49 #define PI2 (3.14159265358979323846f * 2) 50 51 static void 52 dtmf_create(int16_t *buf, unsigned int sample_rate, 53 unsigned short sample_length, unsigned short channels, 54 unsigned int chanmask, float freq1, float freq2, 55 unsigned attack, unsigned decay) 56 { 57 int c; 58 unsigned i; 59 size_t sample_count = sample_rate * sample_length / 1000; 60 float gain; 61 int16_t v; 62 63 for (i = 0; i < sample_count; i++) { 64 if (i < attack) 65 gain = 1.0 * i / attack; 66 else if (sample_count - i < decay) 67 gain = 1.0 * (sample_count - i) / decay; 68 else 69 gain = 1.0; 70 for (c = 0; c < channels; c++) { 71 if ((chanmask & (1 << c)) == 0) 72 continue; 73 v = ( 74 sin(i * PI2 * (freq1 / sample_rate)) + 75 sin(i * PI2 * (freq2 / sample_rate)) 76 ) * gain * 16383; 77 buf[c] = htole16(v); 78 } 79 buf += channels; 80 } 81 } 82 83 static void 84 dtmf_new(int16_t **buf, size_t *buflen, unsigned int sample_rate, 85 unsigned short sample_length, unsigned short channels, 86 unsigned int chanmask, struct dialtone dt) 87 { 88 size_t oldlen, more; 89 90 oldlen = *buflen; 91 more = sample_rate * sample_length / 1000 * sizeof(**buf) * channels; 92 93 *buflen = oldlen + more; 94 *buf = realloc(*buf, *buflen); 95 if (*buf == NULL) { 96 warn("realloc"); 97 return; 98 } 99 memset((*buf) + oldlen/sizeof(**buf), 0, more); 100 101 if (dt.a > 0 || dt.b > 0) 102 dtmf_create((*buf) + oldlen/sizeof(**buf), 103 sample_rate, sample_length, channels, chanmask, 104 dt.a, dt.b, 500, 800); 105 } 106 107 static struct dialtone tones[] = { 108 { 697, 1209 }, /* 1 */ 109 { 697, 1336 }, /* 2 */ 110 { 697, 1477 }, /* 3 */ 111 { 697, 1633 }, /* 4 */ 112 { 770, 1209 }, /* 5 */ 113 { 770, 1336 }, /* 6 */ 114 { 770, 1477 }, /* 7 */ 115 { 770, 1633 }, /* 8 */ 116 { 852, 1209 }, /* 9 */ 117 { 852, 1336 }, /* . */ 118 { 852, 1477 }, /* 0 */ 119 { 852, 1633 }, /* # */ 120 { 941, 1209 }, /* A */ 121 { 941, 1336 }, /* B */ 122 { 941, 1477 }, /* C */ 123 { 941, 1633 } /* D */ 124 }; 125 #define TONES "123456789.0#ABCD" 126 127 static struct dialtone dialtone = { 350.0, 440.0 }; 128 static struct dialtone reordertone = { 480.0, 620.0 }; 129 static struct dialtone ringingtone = { 440.0, 480.0 }; 130 static struct dialtone silence = { 0.0, 0.0 }; 131 132 int 133 dtmf_dial(const char *number, unsigned int sample_rate, 134 unsigned int channels, unsigned int chanmask, 135 int16_t **bufp, size_t *buflenp) 136 { 137 size_t buflen; 138 int i; 139 char ch, *p; 140 141 *bufp = NULL; 142 buflen = 0; 143 144 /* dial tone */ 145 dtmf_new(bufp, &buflen, sample_rate, 2000, 146 channels, chanmask, dialtone); 147 dtmf_new(bufp, &buflen, sample_rate, 65, 148 channels, chanmask, silence); 149 150 if (*number == '\0') 151 goto no_number; 152 153 /* number */ 154 while ((ch = *number++) != '\0') { 155 p = strchr(TONES, ch); 156 if (p == NULL) { 157 dtmf_new(bufp, &buflen, sample_rate, 130, 158 channels, chanmask, silence); 159 } else { 160 i = p - TONES; 161 dtmf_new(bufp, &buflen, sample_rate, 65, 162 channels, chanmask, tones[i]); 163 dtmf_new(bufp, &buflen, sample_rate, 65, 164 channels, chanmask, silence); 165 } 166 } 167 168 /* pause */ 169 dtmf_new(bufp, &buflen, sample_rate, 325, 170 channels, chanmask, silence); 171 172 if (chanmask & 0x55555555) { 173 /* even channel */ 174 175 /* reorder tone */ 176 for (i=0; i<12; ++i) { 177 dtmf_new(bufp, &buflen, sample_rate, 250, 178 channels, chanmask, reordertone); 179 dtmf_new(bufp, &buflen, sample_rate, 250, 180 channels, chanmask, silence); 181 } 182 183 /* pause */ 184 dtmf_new(bufp, &buflen, sample_rate, 2000, 185 channels, chanmask, silence); 186 } else { 187 /* odd channel */ 188 189 /* ringing tone */ 190 dtmf_new(bufp, &buflen, sample_rate, 2000, 191 channels, chanmask, ringingtone); 192 dtmf_new(bufp, &buflen, sample_rate, 4000, 193 channels, chanmask, silence); 194 dtmf_new(bufp, &buflen, sample_rate, 2000, 195 channels, chanmask, ringingtone); 196 197 /* pause */ 198 dtmf_new(bufp, &buflen, sample_rate, 250, 199 channels, chanmask, silence); 200 } 201 202 no_number: 203 *buflenp = buflen; 204 return *bufp == NULL; 205 } 206