/* make_ulaw_au.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 * */ #include #include #include #include #include #include #include #define AUDIO_PORT 8480 #define BUFFER_SIZE 1024 #define HEADER_SIZE 28 #define SAMPLE_RATE 8000 #define SAMPLE_CHANNELS 1 #define AU_FILE_MAGIC 0x2e736e64 #define AU_FILE_MULAW_8 1 #define MAX_WAIT 300 unsigned char LinearToMuLaw(short sample); main(argc, argv) int argc; char *argv[]; { register int i, j; int data_sock; struct sockaddr_in server; char buffer[BUFFER_SIZE]; char header[HEADER_SIZE]; long request; long l; 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_ulaw_au: 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_ulaw_au: connecting socket"); exit(1); } request = (argc > 1 ? atol(argv[1]) : 1) * 32000; /* Write ``.au'' file header */ l = htonl(AU_FILE_MAGIC); memcpy(&header[0], &l, sizeof (u_long)); l = htonl(HEADER_SIZE); memcpy(&header[4], &l, sizeof (u_long)); l = htonl(request / 4); memcpy(&header[8], &l, sizeof (u_long)); l = htonl(AU_FILE_MULAW_8); memcpy(&header[12], &l, sizeof (u_long)); l = htonl(SAMPLE_RATE); memcpy(&header[16], &l, sizeof (u_long)); l = htonl(SAMPLE_CHANNELS); memcpy(&header[20], &l, sizeof (u_long)); l = htonl(0L); memcpy(&header[24], &l, sizeof (u_long)); rc = write(1, header, HEADER_SIZE); if (rc < 0) { perror("make_ulaw_au: writing header"); exit(1); } /* Compress data from server to stdout */ while (request > 0) { i = request < BUFFER_SIZE ? request : BUFFER_SIZE; rc = read(data_sock, buffer, i); if (rc < 0) { perror("make_ulaw_au: reading data socket"); exit(1); } if (rc == 0) { exit(0); } request -= rc; /* Compress one channel to 8-bit mu-law */ j = 0; for (i = 0; i < rc; i += 4) { short in; in = buffer[i + 2] + (buffer[i + 3] << 8); buffer[j++] = LinearToMuLaw(in); } alarm(MAX_WAIT); rc = write(1, buffer, rc / 4); if (rc < 0) { if (errno != EPIPE) { perror("make_ulaw_au: writing data"); } exit(1); } } 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 }; unsigned char LinearToMuLaw(short sample) { int exponent; int mantissa; int compressedByte; int sign; sign = sample >> 8 & 0x80; if (sign) { sample = -sample; } if (sample > cClip) { sample = cClip; } sample = sample + cBias; exponent = MuLawCompressTable[(sample >> 7) & 0xFF]; mantissa = sample >> (exponent + 3) & 0x0F; compressedByte = ~ (sign | (exponent << 4) | mantissa); return compressedByte; }