Files
dtmf/dtmfencode.c
2026-03-07 22:46:09 -05:00

160 lines
3.4 KiB
C

#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
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 <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;
}