From df975e2c8f0d4b246b01dc0614bebfa12fedc786 Mon Sep 17 00:00:00 2001 From: car Date: Sat, 7 Mar 2026 22:46:09 -0500 Subject: [PATCH] DTMF --- .gitignore | 3 + Makefile | 9 +++ README.md | 0 dtmfencode.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++ scratch.c | 4 ++ 5 files changed, 175 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 dtmfencode.c create mode 100644 scratch.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2dd1182 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.wav +*~ +dtmfencode diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..316eca8 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +.PHONY: test + +all: dtmfencode test + +dtmfencode: dtmfencode.c + cc $^ -o $@ + +test: dtmfencode + ./dtmfencode test.wav "1234567890*#ABCD" 40000 100 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/dtmfencode.c b/dtmfencode.c new file mode 100644 index 0000000..3799f09 --- /dev/null +++ b/dtmfencode.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include +#include + +struct wav_header { + char riff_magic[4]; + uint32_t size; + char wave_magic[4]; + char format_magic[4]; + uint32_t format_size; + uint16_t format_type; + uint16_t channels; + uint32_t sample_rate; + uint32_t rate1; + uint16_t rate2; + uint16_t bits_per_sample; + char data_magic[4]; + uint32_t data_size; +}; + +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 \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; +} diff --git a/scratch.c b/scratch.c new file mode 100644 index 0000000..411dc21 --- /dev/null +++ b/scratch.c @@ -0,0 +1,4 @@ + for (int i = 0; i < sample_count; i++) { + int16_t sample = (int16_t)(sinf(500.0 * 2.0 * M_PI * ((float)i / (float)(wav_header.sample_rate))) * 32768.0); + fwrite(&sample, sizeof(int16_t), 1, fout); + }