160 lines
3.4 KiB
C
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;
|
|
}
|