summaryrefslogtreecommitdiff
path: root/dtmfencode.c
diff options
context:
space:
mode:
authorPaul Harrison <[email protected]>2026-06-07 17:49:16 -0700
committerPaul Harrison <[email protected]>2026-06-07 17:49:16 -0700
commit76a02622caf8f16979d8bc67890764768f7d06c0 (patch)
treed4578dd33e4b3a06623dbcdd158f099ec43fac09 /dtmfencode.c
DTMF Encoder
Diffstat (limited to 'dtmfencode.c')
-rw-r--r--dtmfencode.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/dtmfencode.c b/dtmfencode.c
new file mode 100644
index 0000000..be02660
--- /dev/null
+++ b/dtmfencode.c
@@ -0,0 +1,144 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "wav.h"
+
+void dtmf_freqs(char c, int *a, int *b) {
+ switch (c) {
+ case '1':
+ case '2':
+ case '3':
+ case 'A':
+ *a = 697;
+ break;
+ case '4':
+ case '5':
+ case '6':
+ case 'B':
+ *a = 770;
+ break;
+ case '7':
+ case '8':
+ case '9':
+ case 'C':
+ *a = 852;
+ break;
+ case '*':
+ case '0':
+ case '#':
+ case 'D':
+ *a = 941;
+ break;
+ default:
+ *a = 0;
+ }
+
+ switch (c) {
+ case '1':
+ case '4':
+ case '7':
+ case '*':
+ *b = 1209;
+ break;
+ case '2':
+ case '5':
+ case '8':
+ case '0':
+ *b = 1336;
+ break;
+ case '3':
+ case '6':
+ case '9':
+ case '#':
+ *b = 1477;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ *b = 1633;
+ break;
+ default:
+ *b = 0;
+ }
+}
+
+int16_t dtmf_gen(char c, int t, int rate) {
+ int a, b;
+ dtmf_freqs(c, &a, &b);
+ double v = 0.5 * sin(2.0 * M_PI * (double)a * ((double)t / (double)rate));
+ v += 0.5 * sin(2.0 * M_PI * (double)b * ((double)t / (double)rate));
+ return v * 32767.0;
+}
+
+int main(int argc, char *argv[]) {
+ /* usage */
+ if (argc != 5) {
+ fprintf(stderr, "usage: %s <wave file> <dtmf> <width> <spacing>\n", argv[0]);
+ return 2;
+ }
+
+ /* read arguments */
+ char *outfilename = argv[1];
+ char *dtmf = argv[2];
+ int width, spacing;
+ sscanf(argv[3], "%d", &width);
+ sscanf(argv[4], "%d", &spacing);
+
+ /* open output file */
+ FILE *fout = fopen(outfilename, "w");
+ if (fout == NULL) {
+ fprintf(stderr, "could not open '%s' for writing.\n", outfilename);
+ return 1;
+ }
+
+ /* create header */
+ struct wav_header wav_header;
+ memcpy(wav_header.riff_magic, "RIFF", 4);
+ memcpy(wav_header.wave_magic, "WAVE", 4);
+ memcpy(wav_header.format_magic, "fmt ", 4);
+ memcpy(wav_header.data_magic, "data", 4);
+ wav_header.format_size = 16;
+ wav_header.format_type = 1;
+ wav_header.channels = 1;
+ wav_header.sample_rate = 44100;
+ wav_header.bits_per_sample = 16;
+ wav_header.rate1 = (wav_header.sample_rate * wav_header.bits_per_sample * wav_header.channels) / 8;
+ wav_header.rate2 = (wav_header.bits_per_sample * wav_header.channels) / 8;
+
+ /* go past header */
+ fseek(fout, sizeof(wav_header), SEEK_SET);
+
+ /* generate sound */
+ int num_digits = strlen(dtmf);
+ uint32_t sample_count = wav_header.sample_rate * num_digits * (width + spacing);
+
+ for (int digit_index = 0; digit_index < num_digits; digit_index++) {
+ char digit = dtmf[digit_index];
+
+ /* emit dtmf tone */
+ for (int t = 0; t < (float)wav_header.sample_rate * (float)(width) / 1000.0f; t++) {
+ int16_t sample = dtmf_gen(digit, t, wav_header.sample_rate);
+ fwrite(&sample, sizeof(int16_t), 1, fout);
+ }
+
+ /* emit spacing */
+ fseek(fout, (float)wav_header.sample_rate * (float)(spacing) / 1000.0f, SEEK_CUR);
+ }
+
+ /* update header */
+ wav_header.size = ftell(fout) - 8;
+ wav_header.data_size = ftell(fout) - sizeof(wav_header);
+
+ /* write header */
+ fseek(fout, 0, SEEK_SET);
+ fwrite(&wav_header, sizeof(wav_header), 1, fout);
+
+ /* close file */
+ fclose(fout);
+
+ return 0;
+}