/* make_gsm_wav.c - Audio client that writes a .au file to stdout */ /* * Copyright (C) 1995-2005 Jeffrey Chilton * * Permission is granted to anyone to make or distribute copies of * this program, in any medium, provided that the copyright notice * and permission notice are preserved, and that the distributor * grants the recipient permission for further redistribution as * permitted by this notice. * * Author's E-mail address: jwc@chilton.com * */ /* * This program uses the GSM compression library developed by Jutta * Degener at the Technical University of Berlin. See his web page * at: * * http://kbs.cs.tu-berlin.de/~jutta/toast.html * * (link confirmed September 1997) * */ #include #include #include #include #include #include #include #include "gsm.h" #define BLOCK_SIZE 160 #define AUDIO_PORT 8480 #define MAX_WAIT 300 int F_wav_fmt = 1; int write_header(long, FILE *); main(argc, argv) int argc; char *argv[]; { register int i, j; struct sockaddr_in server; int data_sock; FILE *sfp; gsm handle; long samples; long data_size; long total_out; gsm_signal linear[4 * BLOCK_SIZE]; gsm_frame frame; int out_size; int rc; /* Go away if can't write for MAX_WAIT seconds */ signal(SIGALRM, SIG_DFL); /* Create socket */ data_sock = socket(AF_INET, SOCK_STREAM, 0); if (data_sock < 0) { perror("make_gsm_wav: opening socket"); exit(1); } /* Connect socket to local audio service */ server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); server.sin_port = htons(AUDIO_PORT); rc = connect(data_sock, (struct sockaddr *)&server, sizeof(server)); if (rc < 0) { perror("make_gsm_wav: connecting socket"); exit(1); } sfp = fdopen(data_sock, "r"); if (sfp == 0) { perror("make_gsm_wav: creating file pointer"); exit(1); } /* Read .au file header info and calulate output size */ samples = (argc > 1 ? atol(argv[1]) : 1) * 8000L; data_size = ((samples + (2 * BLOCK_SIZE - 1)) / (2 * BLOCK_SIZE)); data_size *= 2 * sizeof (frame) - 1; /* fprintf(stderr, "samples requested: %d\n", samples); fprintf(stderr, "calculated data size: %d\n", data_size); */ /* Create the GSM codec object and option it for wave framing */ handle = gsm_create(); if (!handle) { perror("cannot create gsm codec"); exit(1); } (void )gsm_option(handle, GSM_OPT_WAV_FMT, &F_wav_fmt); /* Write the .wav file header */ rc = write_header(data_size, stdout); if (rc) { perror("error writing header"); exit(1); } /* Compress data from server to stdout */ total_out = 0; while (samples > 0) { alarm(MAX_WAIT); /* Read two frames worth of samples */ rc = fread(linear, sizeof(linear), 1, sfp); if (rc == 0) { perror("make_gsm_wav: reading data socket"); exit(1); } samples -= sizeof(linear) / 4; /* Discard one channel */ j = 0; for (i = 0; i < 4 * BLOCK_SIZE; i += 2) { linear[j++] = linear[i]; } /* Encode the even half and write short (32-byte) frame */ gsm_encode(handle, &linear[0], frame); out_size = sizeof (frame) - 1; rc = fwrite(frame, (size_t )1, out_size, stdout); if (rc != out_size) { if (errno != EPIPE) { perror("make_gsm_wav: error writing output"); } exit(1); } total_out += rc; /* Encode the odd half and write long (33-byte) frame */ gsm_encode(handle, &linear[160], frame); out_size = sizeof (frame); rc = fwrite(frame, (size_t )1, out_size, stdout); if (rc != out_size) { if (errno != EPIPE) { perror("make_gsm_wav: error writing output"); } exit(1); } total_out += rc; fflush(stdout); } /* Pad output to even number of bytes */ if (total_out & 0x1) { frame[0] = 0x00; rc = fwrite(frame, (size_t )1, 1, stdout); if (rc != 1) { if (errno != EPIPE) { perror("make_gsm_wav: error writing output"); } exit(1); } total_out += rc; fflush(stdout); } /* fprintf(stderr, "total bytes written: %ld\n", total_out); */ /* Clean up */ gsm_destroy(handle); exit(0); } /* from http://hazelware.luggle.com/tutorials/mulawcompression.html */ const int cBias = 0x84; const int cClip = 32635; static char MuLawCompressTable[256] = { 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; /* write_header - write (approximation of) MS wave file header */ static int fputlong(x, fp) long x; FILE *fp; { return fputc(x & 0xFF, fp) == EOF || fputc((x >> 8) & 0xFF, fp) == EOF || fputc((x >> 16) & 0xFF, fp) == EOF || fputc((x >> 24) & 0xFF, fp) == EOF; } static int fputshort(x, fp) short x; FILE *fp; { return fputc(x & 0xFF, fp) == EOF || fputc((x >> 8) & 0xFF, fp) == EOF; } #define WAVE_HS 20 #define FACT_HS 4 #define GSM_FMT 49 /* Format code number */ #define N_CHAN 1 /* Number of channels (mono) */ #define SAMP_FREQ 8000 /* Uncompressed samples/second */ #define BYTE_FREQ 1625 /* Compressed bytes/second */ #define X_1 65 /* Unknown format-specific */ #define X_2 2 /* Unknown format-specific */ #define X_3 320 /* Unknown format-specific */ #define Y_1 20160 /* Unknown "fact" value */ int write_header(data_size, fp) long data_size; FILE *fp; { unsigned short s; int rc; rc = 0; rc |= fputs("RIFF", fp) == EOF; rc |= fputlong(52 + ((data_size + 1) & ~0x1), fp); rc |= fputs("WAVEfmt ", fp) == EOF; rc |= fputlong(WAVE_HS, fp); rc |= fputshort(GSM_FMT, fp); rc |= fputshort(N_CHAN, fp); rc |= fputlong(SAMP_FREQ, fp); rc |= fputlong(BYTE_FREQ, fp); rc |= fputlong(X_1, fp); rc |= fputshort(X_2, fp); rc |= fputshort(X_3, fp); rc |= fputs("fact", fp) == EOF; rc |= fputlong(FACT_HS, fp); rc |= fputlong(Y_1, fp); rc |= fputs("data", fp) == EOF; rc |= fputlong(data_size, fp); return rc; }