Newsgroups: comp.sources.unix From: guido.van.rossum@cwi.nl (Guido van Rossum) Subject: v26i162: radio - UDP broadcast/receive utilities for audio data, V2.0.2, Part01/02 Sender: unix-sources-moderator@vix.com Approved: paul@vix.com Submitted-By: guido.van.rossum@cwi.nl (Guido van Rossum) Posting-Number: Volume 26, Issue 162 Archive-Name: radio2.0.2/part01 This is Radio version 2.0, patchlevel 2 (a.k.a. 2.0.2). If you have a local area network full of workstations with audio capabilities and at least one FM/AM radio or other audio source, you can broadcast the audio over the network, and let other users listen to it. This software works for Sun Sparcs running SunOS 4.0 or 4.1, for SGI Indigo or Personal IRIS 4D/30 or 4D/35 workstations running SGI IRIX 4.0 or 3.3.2, and for NeXT workstations (running version 2.1). At CWI, versions of it have been in continuous use on a mix of Sun and SGI system types for almost two years; version 1.0 (patchlevel 4) was last tested on a NeXT. (I've heard that the program doesn't work on NeXT 3.1; if you fix it please send me the changes!) Man pages for "radio" and "broadcast" are provided. The implementation continuously transmits UDP broadcast packets of 1400 bytes each (i.e. less than six per second), which contain the data in U-LAW format (8000 samples/second, 1 byte/sample, logarithmically encoded). On a typical ethernet, this uses about 1 percent of the net available bandwith. Some loss of UDP packets is tolerated by the receiving program (this is heard as short interruptions of the sound). Every now and then, a short "station call" packet is transmitted as well, for the benefit of advanced listening programs. It is possible to use multiple transmission stations (each identified by a different UDP port), and to transmit to multiple connected subnets simultaneously (as long as the gateways let UDP broadcast packets through). For reasons you don't want to know, you can only have one broadcasting and one radio process per host, except on the SGI there may be multiple radio processes. If you have Motif, you may be interested in the "tuner" program X(version 1.3) by Jack Jansen. This is a window-based interface that shows the different broadcasting stations at your site and lets you tune your radio process to the station of your choice. It will be posted to comp.sources.x around the same time as radio 2.0; you can also ftp it from site ftp.cwi.nl [192.16.184.180], file /pub/tuner1.3.tar.Z. If you missed a part of the posting of radio, you can ftp the whole source from ftp.cwi.nl [192.16.184.180], file /pub/radio2.0.tar.Z. Guido van Rossum CWI, dept. CST Kruislaan 413 X1098 SJ Amsterdam The Netherlands E-mail (Internet) : Guido.van.Rossum@cwi.nl (guido@cwi.nl) The "libst" U-LAW conversion library is written and copyrighted by Jef Poskanzer. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'MANIFEST' <<'END_OF_FILE' X File Name Archive # Description X----------------------------------------------------------- X MANIFEST 1 X Makefile 1 X README 1 X adpcm.c 1 X adpcm.h 1 X broadcast.c 2 X broadcast.man 1 X checkradio.py 2 X libst.c 1 X libst.h 1 X nielsen.py 1 X patchlevel.h 1 X playulaw.c 1 X radio.c 2 X radio.h 1 X radio.man 1 X recordlinear.c 1 X recordulaw.c 1 X sndulaw.c 1 X socklib.c 1 X stations.pl 1 X stations.py 1 X ttytuner.py 1 X ulawadpcm.c 1 END_OF_FILE if test 840 -ne `wc -c <'MANIFEST'`; then echo shar: \"'MANIFEST'\" unpacked with wrong size! fi # end of 'MANIFEST' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(2817 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# /*********************************************************** X# Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The X# Netherlands. X# X# All Rights Reserved X# X# Permission to use, copy, modify, and distribute this software and its X# documentation for any purpose and without fee is hereby granted, X# provided that the above copyright notice appear in all copies and that X# both that copyright notice and this permission notice appear in X# supporting documentation, and that the names of Stichting Mathematisch X# Centrum or CWI not be used in advertising or publicity pertaining to X# distribution of the software without specific, written prior permission. X# X# STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO X# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND X# FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE X# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES X# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN X# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT X# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X# X# ******************************************************************/ X X default: X @echo 'You must use "make sun4.0", "make sun4.1",' X @echo '"make next" or "make sgi"' X exit 1 X all: radio broadcast X X# Platform-specific entries X sun4.0: # For SunOS 4.x X make all LIBS=-lX11 X sun4.1: # For SunOS 4.1 with audio library (/usr/demo/SOUND) X make all LIBS='-lX11 /usr/demo/SOUND/libaudio.a' \ X CFLAGS='-DREMHDR -I/usr/demo/SOUND' X sun4.1.2: # For SunOS 4.1 with multicast & audio library (/usr/demo/SOUND) X make all LIBS='-lX11 /usr/demo/SOUND/libaudio.a' \ X CFLAGS='-DHAVE_MCAST -DREMHDR -I/usr/demo/SOUND -DDEFMCAST=\"radio.multicast\"' X sgi: # For SGI IRIX 4.0 X make all recordulaw recordlinear playulaw LIBS='-lX11 -laudio' X next: # NeXT 2.1 X make all sndulaw X X# Common programs: X ROBJ= radio.o socklib.o ulawadpcm.o adpcm.o libst.o BOBJ= broadcast.o socklib.o adpcm.o ulawadpcm.o libst.o X radio: $(ROBJ) X $(CC) $(ROBJ) $(LIBS) -o radio X broadcast: $(BOBJ) X $(CC) $(BOBJ) $(LIBS) -o broadcast X X# NeXT-only programs: X sndulaw: sndulaw.o X $(CC) sndulaw.o -o sndulaw X X# SGI-only programs: X recordulaw: recordulaw.o libst.o X $(CC) recordulaw.o -laudio -o recordulaw X recordlinear: recordlinear.o X $(CC) recordlinear.o -laudio -o recordlinear X playulaw: playulaw.o X $(CC) playulaw.o -laudio -o playulaw X X# Service entries: X clean: X -rm -f core *.o *~ @* '#'* ,* *.pyc *.BAK Part?? X clobber: clean X -rm -f radio broadcast recordulaw recordlinear playulaw sndulaw X X# Dependencies: X broadcast.o: radio.h adpcm.h radio.o: radio.h adpcm.h libst.h ulawadpcm.o: adpcm.h libst.h playulaw.o: libst.h END_OF_FILE if test 2817 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(15880 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' Welcome to the wonderful world of Local Area Network radio! X=========================================================== X This is Radio version 2.0, patchlevel 2 (a.k.a. 2.0.2). X If you have a local area network full of workstations with audio capabilities and at least one FM/AM radio or other audio source, you can broadcast the audio over the network, and let other users listen to it. X This software works for Sun Sparcs running SunOS 4.0 or 4.1, for SGI Indigo or Personal IRIS 4D/30 or 4D/35 workstations running SGI IRIX X4.0 or 3.3.2, and for NeXT workstations (running version 2.1). At CWI, versions of it have been in continuous use on a mix of Sun and SGI system types for almost two years; version 1.0 (patchlevel 4) was last tested on a NeXT. (I've heard that the program doesn't work on NeXT 3.1; if you fix it please send me the changes!) X Man pages for "radio" and "broadcast" are provided. X The implementation continuously transmits UDP broadcast packets of X1400 bytes each (i.e. less than six per second), which contain the data in U-LAW format (8000 samples/second, 1 byte/sample, logarithmically encoded). On a typical ethernet, this uses about 1 percent of the net available bandwith. Some loss of UDP packets is tolerated by the receiving program (this is heard as short interruptions of the sound). Every now and then, a short "station call" packet is transmitted as well, for the benefit of advanced listening programs. X It is possible to use multiple transmission stations (each identified by a different UDP port), and to transmit to multiple connected subnets simultaneously (as long as the gateways let UDP broadcast packets through). For reasons you don't want to know, you can only have one broadcasting and one radio process per host, except on the SGI there may be multiple radio processes. X If you have Motif, you may be interested in the "tuner" program X(version 1.3) by Jack Jansen. This is a window-based interface that shows the different broadcasting stations at your site and lets you tune your radio process to the station of your choice. It will be posted to comp.sources.x around the same time as radio 2.0; you can also ftp it from site ftp.cwi.nl [192.16.184.180], file X/pub/tuner1.3.tar.Z. X If you missed a part of the posting of radio, you can ftp the whole source from ftp.cwi.nl [192.16.184.180], file /pub/radio2.0.tar.Z. X This software is copyrighted. See the notice at the end of this file. X X Changes in 2.0 patchlevel 2 X--------------------------- X Broadcast can now also read 16-bit linear samples from standard input, as this is more appropriate for ADPCM encoding (see below). Use the X-l option. There is a program, recordlinear, which outputs such samples, for the SGI only. X On the SGI, radio's cleanup handler (invoked when it receives a TERM or INTR signal) resets the output volume only if it was set with the X-v option. It resets nothing at all if the program was currently paused by a tuner. X There is now a default multicast address, from the unofficial range. X(This only has meaning for SGI users and for users of a hacked SunOS version which supports multicast.) X Data packets now have a 2-byte header, which is compatible with IVS, INRIA's video and audio conferencing system, and allows us to support different encoding schemes. (The control packet format is unchanged, compatibility with IVS is not a point here.) Currently supported encodings are: X X- PCM_64 (pulse-code modulation; in fact, plain u-law as before); X X- ADPCM_32 (Adaptive Delta PCM, which takes only 32 kbit/sec with only X a slight loss in quality); X X- ADPCM_32_W_STATE, which is the same as ADPCM_32 but adds three bytes X of state for the encoder to reduce noise (this format is not X understood by IVS). X The default encoding used by broadcast is PCM_64; use the "-a" option to use ADPCM_32_W_STATE, or "-A" for ADPCM_32. The radio program recognizes the encoding from the data packet header and so it does not need an option to select the encoding. X Changes by Alexander Dupuy (thank you Alexander!): X Makefile: added a sunos4.1.2 target for our hacked version of 4.1.2 with X multicasts (a better name would be sun4.1-multi, since multicasting X is not standard in 4.1.2 (maybe in Solaris 2.0?). X broadcast.c: add a -m (multicast ttl) option, which sets the multicast ttl to X control the range over which multicast packets are forwarded. X this is necessary if you want multi-subnet multicasts. X broadcast.c: use $HOME/.CD and $HOME/.CDlog as default playfiles - this is a X bit more portable, as most sites will try to make sure that X users' home directories are accessible via the same path name on X all machines. It still fails (for .CDlog) when that is not true. X broadcast.c: if compiled with DEFMCAST defined as a valid multicast address radio.c: and HAVE_MCAST defined, broadcast and radio programs will default X to the multicast address DEFMCAST instead of broadcast. X broadcast.c: increase the maximum size of control packets to 512 bytes, to radio.c: support longer song titles (including artist and track title) X which WorkMan typically generates. Note that radio is also X changed to use a larger control packet size, since it uses the X length of incoming packets to determine whether they are control X or data (this is arguably a bug). X radio.c: attempt hostname lookup on -m (multicast) address argument, since it X is possible to put multicast addresses in /etc/hosts, NIS, and even, X with a bit of work, DNS. X broadcast.man: updated to reflect user-visible changes to the broadcast and radio.man: radio programs. X X Changes in 2.0 patchlevel 1 X--------------------------- X On the sun and sgi, radio tries to open a connection to the X server X(specified by the $DISPLAY environment variable) and every now and then makes a small request to exercise the connection. This ensures that if the user logs out, radio will quit. If no connection to the X server can be made, these checks are not made and a warning is printed that reminds the user to kill radio when logging out. X The usage message is more informative. X The new option '-t' (tee) sends output to both stdout and the audio device. Thanks to Scott Hazen Mueller for suggesting this. X The experimental option '-m mcastgrp' (for SGI only) specifies a multicast group. By multicasting instead of broadcasting, you can reduce the load on hosts that aren't listening (see the man page). X X Changes since version 1.0 patchlevel 4 X-------------------------------------- X X(Skip to the next section if you aren't already using version 1.0 of radio.) X The source structure has been changed -- all files are in one directory now. X More Python programs have been provided, and the existing ones have been improved. (Translations to C will be accepted and may end up in a future distribution -- here's your chance to gain world popularity!) X Building for the Sun now requires an explicit choice between sun4.0 and sun4.1 -- "make sun" no longer works. X The radio program can now be "paused" by a separate tuner program. This means you don't have to kill the radio process if you want a few minutes of silence. X The broadcast program now broadcasts "station call" messages to a fixed port twice a minute, as a service to more sophisticated tuner programs. The Python program "stations.py" can be used to display these station calls (in a primitive manner). X The broadcast program now implements silence suppression: if the input is silent longer than 20 seconds it stops transmitting packets, keeping network overhead low. (You may have to tweak the level -- our typical "silent" input is rather noisy, so we set the livel rather high.) X Many minor changes and bugfixes. X X Building and installing X----------------------- X XFor SunOS 4.1 or higher (assuming the audio library is in X/usr/demo/SOUND), type "make sun4.1". For SGI IRIX, type "make sgi". XFor the NeXT, type "make next". This should produce binaries for X"radio" and "broadcast". For the SGI it also produces binaries X"recordulaw" and "playulaw"; for the NeXT, it also builds "sndulaw". Read the Makefile for details -- it's pretty trivial. X X(For SunOS 4.0, you may try "make sun4.0" instead. This does not make the assumption that the audio library is in /usr/demo/SOUND. Edit the Makefile if necessary to accomodate other locations.) X XFor SGI IRIX, the Makefile builds the "recordulaw" and "playulaw" programs. "recordulaw" uses the IRIX audio library to sample the audio input and convert it to U-LAW format. "playulaw" does the reverse (it is not actually used but provided as a convenience). The audio library is available on IRIS 4.0 and on IRIS 3.3.2 or higher. X Install the "radio" program on a convenient public place (where potential listeners can find it, e.g., /usr/local/bin); install X"broadcast" on a convenient place for yourself (assuming you're the one doing transmissions). The "recordulaw" or "sndulaw" programs, if needed, should be installed together with "broadcast". On an SGI system you may install "playulaw" if you like. X X Usage -- transmissions X---------------------- X X(See the man page for broadcast for more details.) X To start transmissions on Sun Sparcs, run this command (probably in the background, once you've debugged your audio setup): X X broadcast -p port 'adpcm.c' <<'END_OF_FILE' X/*********************************************************** Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. X X All Rights Reserved X Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. X STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* X** Intel/DVI ADPCM coder/decoder. X** X** The algorithm for this coder was taken from the IMA Compatability Project X** proceedings, Vol 2, Number 2; May 1992. X** X** Version 1.1, 16-Dec-92. X** X** Change log: X** - Fixed a stupid bug, where the delta was computed as X** stepsize*code/4 in stead of stepsize*(code+0.5)/4. The old behavior can X** still be gotten by defining STUPID_V1_BUG. X*/ X X#include "adpcm.h" X X#ifndef __STDC__ X#define signed X#endif X X/* Intel ADPCM step variation table */ static int indexTable[16] = { X -1, -1, -1, -1, 2, 4, 6, 8, X -1, -1, -1, -1, 2, 4, 6, 8, X}; X static int stepsizeTable[89] = { X 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, X 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, X 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, X 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, X 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, X 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, X 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, X 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, X 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 X}; X void adpcm_coder(indata, outdata, len, state) X short indata[]; X char outdata[]; X int len; X struct adpcm_state *state; X{ X short *inp; /* Input buffer pointer */ X signed char *outp; /* output buffer pointer */ X int val; /* Current input sample value */ X int sign; /* Current adpcm sign bit */ X int delta; /* Current adpcm output value */ X int step; /* Stepsize */ X int valprev; /* virtual previous output value */ X int vpdiff; /* Current change to valprev */ X int index; /* Current step change index */ X int outputbuffer; /* place to keep previous 4-bit value */ X int bufferstep; /* toggle between outputbuffer/output */ X X outp = (signed char *)outdata; X inp = indata; X X if (state) { X valprev = state->valprev; X index = state->index; X } X else { X valprev = 0; X index = 0; X } X step = stepsizeTable[index]; X X bufferstep = 1; X X for ( ; len > 0 ; len-- ) { X val = *inp++; X X /* Step 1 - compute difference with previous value */ X delta = val - valprev; X sign = (delta < 0) ? 8 : 0; X if ( sign ) delta = (-delta); X X /* Step 2 - Divide and clamp */ X#ifdef NODIVMUL X { X int tmp = 0; X#ifdef STUPID_V1_BUG X vpdiff = 0; X#else X vpdiff = (step >> 3); X#endif /* STUPID_V1_BUG */ X if ( delta > step ) { X tmp = 4; X delta -= step; X vpdiff += step; X } X step >>= 1; X if ( delta > step ) { X tmp |= 2; X delta -= step; X vpdiff += step; X } X step >>= 1; X if ( delta > step ) { X tmp |= 1; X vpdiff += step; X } X delta = tmp; X } X#else X delta = (delta<<2) / step; X if ( delta > 7 ) delta = 7; X X#ifdef STUPID_V1_BUG X vpdiff = (delta*step) >> 2; X#else X vpdiff = ((delta*step) >> 2) + (step >> 3); X#endif /* STUPID_V1_BUG */ X#endif /* NODIVMUL */ X X /* Step 3 - Update previous value */ X if ( sign ) X valprev -= vpdiff; X else X valprev += vpdiff; X X /* Step 4 - Clamp previous value to 16 bits */ X if ( valprev > 32767 ) X valprev = 32767; X else if ( valprev < -32768 ) X valprev = -32768; X X /* Step 5 - Assemble value, update index and step values */ X delta |= sign; X X index += indexTable[delta]; X if ( index < 0 ) index = 0; X if ( index > 88 ) index = 88; X step = stepsizeTable[index]; X X /* Step 6 - Output value */ X if ( bufferstep ) { X outputbuffer = (delta << 4) & 0xf0; X } else { X *outp++ = (delta & 0x0f) | outputbuffer; X } X bufferstep = !bufferstep; X } X X /* Output last step, if needed */ X if ( !bufferstep ) X *outp++ = outputbuffer; X X if (state) { X state->valprev = valprev; X state->index = index; X } X} X void adpcm_decoder(indata, outdata, len, state) X char indata[]; X short outdata[]; X int len; X struct adpcm_state *state; X{ X signed char *inp; /* Input buffer pointer */ X short *outp; /* output buffer pointer */ X int sign; /* Current adpcm sign bit */ X int delta; /* Current adpcm output value */ X int step; /* Stepsize */ X int valprev; /* virtual previous output value */ X int vpdiff; /* Current change to valprev */ X int index; /* Current step change index */ X int inputbuffer; /* place to keep next 4-bit value */ X int bufferstep; /* toggle between inputbuffer/input */ X X outp = outdata; X inp = (signed char *)indata; X X if (state) { X valprev = state->valprev; X index = state->index; X } X else { X valprev = 0; X index = 0; X } X step = stepsizeTable[index]; X X bufferstep = 0; X X for ( ; len > 0 ; len-- ) { X X /* Step 1 - get the delta value and compute next index */ X if ( bufferstep ) { X delta = inputbuffer & 0xf; X } else { X inputbuffer = *inp++; X delta = (inputbuffer >> 4) & 0xf; X } X bufferstep = !bufferstep; X X /* Step 2 - Find new index value (for later) */ X index += indexTable[delta]; X if ( index < 0 ) index = 0; X if ( index > 88 ) index = 88; X X /* Step 3 - Separate sign and magnitude */ X sign = delta & 8; X delta = delta & 7; X X /* Step 4 - update output value */ X#ifdef NODIVMUL X#ifdef STUPID_V1_BUG X vpdiff = 0; X#else X vpdiff = step >> 1; X#endif /* STUPID_V1_BUG */ X if ( delta & 4 ) vpdiff += (step << 2); X if ( delta & 2 ) vpdiff += (step << 1); X if ( delta & 1 ) vpdiff += step; X vpdiff >>= 2; X#else X#ifdef STUPID_V1_BUG X vpdiff = ((delta*step) >> 2); X#else X vpdiff = ((delta*step) >> 2) + (step >> 3); X#endif /* STUPID_V1_BUG */ X#endif /* ! NODIVMUL */ X if ( sign ) X valprev -= vpdiff; X else X valprev += vpdiff; X X /* Step 5 - clamp output value */ X if ( valprev > 32767 ) X valprev = 32767; X else if ( valprev < -32768 ) X valprev = -32768; X X /* Step 6 - Update step value */ X step = stepsizeTable[index]; X X /* Step 7 - Output value */ X *outp++ = valprev; X } X X if (state) { X state->valprev = valprev; X state->index = index; X } X} END_OF_FILE if test 7085 -ne `wc -c <'adpcm.c'`; then echo shar: \"'adpcm.c'\" unpacked with wrong size! fi # end of 'adpcm.c' fi if test -f 'adpcm.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'adpcm.h'\" else echo shar: Extracting \"'adpcm.h'\" \(563 characters\) sed "s/^X//" >'adpcm.h' <<'END_OF_FILE' X/* X** adpcm.h - include file for adpcm coder. X** X** Version 1.0, 7-Jul-92. X*/ X struct adpcm_state { X short valprev; /* Previous output value */ X char index; /* Index into stepsize table */ X}; X X#ifdef __STDC__ X#define ARGS(x) x X#else X#define ARGS(x) () X#endif X void adpcm_coder ARGS((short [], char [], int, struct adpcm_state *)); void adpcm_decoder ARGS((char [], short [], int, struct adpcm_state *)); void ulaw_adpcm_coder ARGS((char [], char [], int, struct adpcm_state *)); void adpcm_ulaw_decoder ARGS((char [], char [], int, struct adpcm_state *)); END_OF_FILE if test 563 -ne `wc -c <'adpcm.h'`; then echo shar: \"'adpcm.h'\" unpacked with wrong size! fi # end of 'adpcm.h' fi if test -f 'broadcast.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'broadcast.man'\" else echo shar: Extracting \"'broadcast.man'\" \(7425 characters\) sed "s/^X//" >'broadcast.man' <<'END_OF_FILE' X.TH BROADCAST 1 X.SH NAME broadcast \- send audio UDP packets to be received by radio X.SH SYNOPSIS X.B broadcast X[ X.B "\-a" X] [ X.B "\-A" X] [ X.BI "\-b " addr X] ... [ X.BI "\-c " port X] [ X.BI \-d X] X [ X.BI "\-m " ttl X] [ X.BI \-n X] [ X.BI "\-p " port X] [ X.BI \-t X] X [ X.BI "\-L " logfile X] [ X.BI "-N " name X] [ X.BI "\P " programfile X] X.SH DESCRIPTION X.I Broadcast reads audio data in U-LAW format (8000 samples/second, 1 byte/sample, logarithmically encoded) from standard input, chops it up into packets of about 1400 bytes each, and transmits these as UDP broadcast packets. On a typical ethernet, this uses about 1 percent of the net available bandwith (less than 6 maximum-size packets per second). If this is still too much, the X.B \-a option can cut the required bandwidth in half. X.PP The program X.IR radio (1) listens for these packets, reassembles them and makes the encoded sound audible, given suitable hardware. X.PP It is possible to use multiple transmission stations (each identified by a different UDP port), and to transmit to multiple connected subnets simultaneously, as long as the gateways let UDP broadcast packets through. XEach transmission station should run on a different host though. X.SH OPTIONS X.TP 10 X.BR "\-a" Use ADPCM (Adaptive Delta Pulse Code Modulation) to compress the audio data. It sends out packets at the same rate, but the packet size is cut in half. This saves about 50 percent of the required network bandwidth, at the cost of some CPU time (for the receivers as well as as for the sender). There is a slight degradation in sound quality, but the quality is actually still quite good. The receiver adapts itself automatically to the data format. X.TP 10 X.BR "\-A" Use a variant on ADPCM (Adaptive Delta Pulse Code Modulation) which is compatible the IVS program from INRIA. X.TP 10 X.BI "\-b " addr IP address to send to. The default is either the local net broadcast address or a multicast address assigned to radio if the host supports IP multicasts. The address may be a host name (for unicast), an IP broadcast address, or an IP multicast address (addresses beginning with 224). More than one X.B \-b option may be given; the data is sent to each address. X.TP 10 X.BI "\-c " port Use this UDP port number as control port (default 54320). Normally you never need to change this; the control port is used by optional ``tuner'' software (distributed separately). X.TP 10 X.B \-d Turn on debugging (a message on stderr for each 8 packets sent). X.TP 10 X.BI "\-m " ttl Use this to specify a multicast TTL, to control how far the multicasts will propagate. A value of 0 restricts them to the same host, X1 to the same subnet, 32 to the same ``site,'' 64 to the same ``region,'' X128 to the same continent, and 255 is unrestricted. The default is 32. Note that this option only has an effect if your machine supports multicasts and you specify a multicast address with the X.B \-b option. X.TP 10 X.B \-n No silence suppression. Normally, when the input contains more than 20 seconds of silence, output packets are suppressed until some noise is detected again. This option turns off that feature. X.TP 10 X.BI "\-p " port Transmit to this UDP port number (default 54321). X.TP 10 X.B \-t When the input is faster than real time, e.g., read from a file, this option ensures that the packets are sent out at the correct rate (8000 bytes/sec). Normally, it is presumed that the standard input takes care of this. X.TP 10 X.BI "\-L " logfile The filename of the file where recent program information is logged. Typically, each time the current program information is changed it is also appended to this file. Default is $HOME/.CDlog. X.TP 10 X.BI "\-N " name The name of the station. Default the current username. X.TP 10 X.BI "\-P " programfile The name of the file where current program information is kept (one line). Typically, this file contains three colon-separated fields: performer, composer, and title, where the composer field is only used for classical music. Default is $HOME/.CD. X.SH TYPICAL USAGE Due to the different interface to audio input hardware on different systems, transmissions are started differently on different platforms. X.PP To start transmissions on Sun Sparcs, run this command (probably in the background, once you've debugged your audio setup): X.IP broadcast -p \fIport\fP 'libst.c' <<'END_OF_FILE' X/* libst.c - portable sound tools library X*/ X X/* X** This routine converts from linear to ulaw. X** X** Craig Reese: IDA/Supercomputing Research Center X** Joe Campbell: Department of Defense X** 29 September 1989 X** X** References: X** 1) CCITT Recommendation G.711 (very difficult to follow) X** 2) "A New Digital Technique for Implementation of Any X** Continuous PCM Companding Law," Villeret, Michel, X** et al. 1973 IEEE Int. Conf. on Communications, Vol 1, X** 1973, pg. 11.12-11.17 X** 3) MIL-STD-188-113,"Interoperability and Performance Standards X** for Analog-to_Digital Conversion Techniques," X** 17 February 1987 X** X** Input: Signed 16 bit linear sample X** Output: 8 bit ulaw sample X*/ X X/* #define ZEROTRAP /* turn on the trap as per the MIL-STD */ X#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ X#define CLIP 32635 X unsigned char st_linear_to_ulaw( sample ) int sample; X { X static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, X 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, X 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, X 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, X 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, X 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, X 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, X 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, X 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, X 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, X 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, X 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, X 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, X 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, X 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, X 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; X int sign, exponent, mantissa; X unsigned char ulawbyte; X X /* Get the sample into sign-magnitude. */ X sign = (sample >> 8) & 0x80; /* set aside the sign */ X if ( sign != 0 ) sample = -sample; /* get magnitude */ X if ( sample > CLIP ) sample = CLIP; /* clip the magnitude */ X X /* Convert from 16 bit linear to ulaw. */ X sample = sample + BIAS; X exponent = exp_lut[( sample >> 7 ) & 0xFF]; X mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F; X ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa ); X#ifdef ZEROTRAP X if ( ulawbyte == 0 ) ulawbyte = 0x02; /* optional CCITT trap */ X#endif X X return ulawbyte; X } X X/* X** This routine converts from ulaw to 16 bit linear. X** X** Craig Reese: IDA/Supercomputing Research Center X** 29 September 1989 X** X** References: X** 1) CCITT Recommendation G.711 (very difficult to follow) X** 2) MIL-STD-188-113,"Interoperability and Performance Standards X** for Analog-to_Digital Conversion Techniques," X** 17 February 1987 X** X** Input: 8 bit ulaw sample X** Output: signed 16 bit linear sample X*/ X int st_ulaw_to_linear_slow( ulawbyte ) unsigned char ulawbyte; X { X static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 }; X int sign, exponent, mantissa, sample; X X ulawbyte = ~ ulawbyte; X sign = ( ulawbyte & 0x80 ); X exponent = ( ulawbyte >> 4 ) & 0x07; X mantissa = ulawbyte & 0x0F; X sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) ); X if ( sign != 0 ) sample = -sample; X X return sample; X } END_OF_FILE if test 3474 -ne `wc -c <'libst.c'`; then echo shar: \"'libst.c'\" unpacked with wrong size! fi # end of 'libst.c' fi if test -f 'libst.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libst.h'\" else echo shar: Extracting \"'libst.h'\" \(3224 characters\) sed "s/^X//" >'libst.h' <<'END_OF_FILE' X/* libst.h - include file for portable sound tools library X** X** Copyright (C) 1989 by Jef Poskanzer. X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, provided X** that the above copyright notice appear in all copies and that both that X** copyright notice and this permission notice appear in supporting X** documentation. This software is provided "as is" without express or X** implied warranty. X*/ X X#define SAMPLES_PER_SECOND 8192 X X#define MINLIN -32768 X#define MAXLIN 32767 X#define LINCLIP(x) do { if ( x < MINLIN ) x = MINLIN ; else if ( x > MAXLIN ) x = MAXLIN; } while ( 0 ) X unsigned char st_linear_to_ulaw( /* int sample */ ); int st_ulaw_to_linear_slow( /* unsigned char ulawbyte */ ); X X/* X** This macro converts from ulaw to 16 bit linear, faster. X** X** Jef Poskanzer X** 23 October 1989 X** X** Input: 8 bit ulaw sample X** Output: signed 16 bit linear sample X*/ X#define st_ulaw_to_linear(ulawbyte) ulaw_table[ulawbyte] X static int ulaw_table[256] = { X -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, X -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, X -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, X -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, X -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, X -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, X -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, X -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, X -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, X -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, X -876, -844, -812, -780, -748, -716, -684, -652, X -620, -588, -556, -524, -492, -460, -428, -396, X -372, -356, -340, -324, -308, -292, -276, -260, X -244, -228, -212, -196, -180, -164, -148, -132, X -120, -112, -104, -96, -88, -80, -72, -64, X -56, -48, -40, -32, -24, -16, -8, 0, X 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, X 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, X 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, X 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, X 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, X 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, X 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, X 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, X 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, X 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, X 876, 844, 812, 780, 748, 716, 684, 652, X 620, 588, 556, 524, 492, 460, 428, 396, X 372, 356, 340, 324, 308, 292, 276, 260, X 244, 228, 212, 196, 180, 164, 148, 132, X 120, 112, 104, 96, 88, 80, 72, 64, X 56, 48, 40, 32, 24, 16, 8, 0 }; END_OF_FILE if test 3224 -ne `wc -c <'libst.h'`; then echo shar: \"'libst.h'\" unpacked with wrong size! fi # end of 'libst.h' fi if test -f 'nielsen.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'nielsen.py'\" else echo shar: Extracting \"'nielsen.py'\" \(2897 characters\) sed "s/^X//" >'nielsen.py' <<'END_OF_FILE' X#! /ufs/guido/bin/sgi/python X X# /*********************************************************** X# Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The X# Netherlands. X# X# All Rights Reserved X# X# Permission to use, copy, modify, and distribute this software and its X# documentation for any purpose and without fee is hereby granted, X# provided that the above copyright notice appear in all copies and that X# both that copyright notice and this permission notice appear in X# supporting documentation, and that the names of Stichting Mathematisch X# Centrum or CWI not be used in advertising or publicity pertaining to X# distribution of the software without specific, written prior permission. X# X# STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO X# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND X# FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE X# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES X# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN X# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT X# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X# X# ******************************************************************/ X X# Radio listening statistics. X# X# usage: nielsen [-w] [port] X# -w print who's logged on (slow) X# port alternate port to broadcast to X# X# XXX should understand -b options as well, instead of hardwiring addresses. X import sys, os, time, string from socket import * try: X # 'nis' is an optional module which interfaces to NIS (a.k.a. YP) X import nis except ImportError: X # If nis doesn't exist, too bad -- don't print hostnames then X nis = None X addrlist = '192.16.184.0', '192.16.191.0', '192.16.201.255' port = 54320 who = 0 if sys.argv[1:2] == ['-w']: who = 1; sys.argv[1:2] = [] if sys.argv[1:]: port = eval(sys.argv[1]) X s = socket(AF_INET, SOCK_DGRAM) s.allowbroadcast(1) for addr in addrlist: X s.sendto('radio:i', (addr, port)) X TIMEOUT = 7 X try: X while 1: X # Time-out if no next response within TIMEOUT seconds X for i in range(TIMEOUT): X if s.avail(): break X else: time.sleep(1) X else: X print 'Time-out -- assume no more responses.' X break # out of the enclosing while loop X data, (host, port) = s.recvfrom(1400) X print data, host, X try: X response = nis.match(host, 'hosts.byaddr') X words = string.split(response) X print words[1], X except nis.error: X pass X print X if who: X cmd = 'rusers ' + host X line = os.popen(cmd, 'r').read() X words = string.split(line) X del words[0] X for w in words[:]: X if words.count(w) > 1: words.remove(w) X words.sort() X for w in words: print w, X print X # Old version using rsh who: X # cmd = 'who | sed \'s/ .*//\' | sort -u' X # sts = os.system('rsh ' + host + ' "' + cmd + '"') except KeyboardInterrupt: X pass END_OF_FILE if test 2897 -ne `wc -c <'nielsen.py'`; then echo shar: \"'nielsen.py'\" unpacked with wrong size! fi chmod +x 'nielsen.py' # end of 'nielsen.py' fi if test -f 'patchlevel.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'patchlevel.h'\" else echo shar: Extracting \"'patchlevel.h'\" \(21 characters\) sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE' X#define PATCHLEVEL 2 END_OF_FILE if test 21 -ne `wc -c <'patchlevel.h'`; then echo shar: \"'patchlevel.h'\" unpacked with wrong size! fi # end of 'patchlevel.h' fi if test -f 'playulaw.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'playulaw.c'\" else echo shar: Extracting \"'playulaw.c'\" \(4154 characters\) sed "s/^X//" >'playulaw.c' <<'END_OF_FILE' X/*********************************************************** Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. X X All Rights Reserved X Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. X STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* Play ulaw audio data read from stdin */ X X#define BUFFERSIZE 4000 X X#ifdef sgi X#define USE_AL X#endif X#ifdef sun X#define USE_SUN X#endif X X#include X#include X#include X#include X#include X X#include X#include X#include X#include X X#ifdef USE_AL X#include X#include "libst.h" X long savestate[] = { X AL_OUTPUT_RATE, 0, X}; X#endif X X#ifdef USE_SUN X#include X#endif X X/* getopt() interface */ extern int optind; extern char * optarg; X X/* Forward */ void cleanup_handler(); X X/* Globals */ char *progname; X main(argc, argv) X int argc; X char **argv; X{ X char buf[BUFFERSIZE]; X int n; X int c; X int ifd, ofd; X int sts = 0; X#ifdef USE_AL X short obuf[BUFFERSIZE]; X ALport aport; X ALconfig config; X int i; X long pvbuf[2]; X#endif X X progname = argv[0]; X while ((c = getopt(argc, argv, "")) != EOF) { X switch (c) { X case '?': X usage(); X } X } X X if (optind >= argc) { X ifd = fileno(stdin); X } X else { X if (optind+1 < argc) X usage(); X ifd = open(argv[optind], 0); X if (ifd < 0) { X perror(argv[optind]); X exit(1); X } X } X X#ifdef USE_AL X /* Fetch the original state */ X ALgetparams(AL_DEFAULT_DEVICE, savestate, X sizeof(savestate) / sizeof(long)); X X /* Set signal handlers */ X signal(SIGINT, cleanup_handler); X signal(SIGTERM, cleanup_handler); X X /* Configure and open an SGI audio port */ X config = ALnewconfig(); X ALsetchannels(config, AL_MONO); X ALsetwidth(config, AL_SAMPLE_16); X ALsetqueuesize(config, 16000); /* 2 seconds slop */ X aport = ALopenport("radio", "w", config); X if (aport == NULL) { X perror("ALopenport"); X exit(1); X } X X /* Set the output sampling rate to 8000 Hz */ X /* Do this after ALopenport so we needn't undo it if that fails */ X pvbuf[0] = AL_OUTPUT_RATE; X pvbuf[1] = AL_RATE_8000; X ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L); X#else X /* Write to /dev/audio */ X if ((ofd = open("/dev/audio", O_WRONLY | O_NDELAY)) < 0) { X perror("/dev/audio"); X exit(1); X } X#endif X X for (;;) { X n = read(ifd, buf, BUFFERSIZE); X if (n <= 0) { X if (n < 0) { X perror("read"); X sts = 1; X } X break; X } X#ifdef USE_AL X for (i = 0; i < n; i++) X obuf[i] = st_ulaw_to_linear(buf[i]); X ALwritesamps(aport, obuf, (long)n); X#else X if (write(ofd, buf, n) != n) { X perror("write"); X sts = 1; X break; X } X#endif X } X X#ifdef USE_AL X /* Wait until all sound has played */ X while(ALgetfilled(aport) > 0) /* still sound to play */ X sginap(1); /* sleep for 1/60 of a second */ X X /* Restore the output sampling rate */ X ALsetparams(AL_DEFAULT_DEVICE, savestate, X sizeof(savestate) / sizeof(long)); X#endif X X exit(sts); X} X usage() X{ X fprintf(stderr, "usage: %s [file]\n", progname); X exit(2); X} X X#ifdef USE_AL X void cleanup_handler(sig) X int sig; X{ X signal(sig, SIG_DFL); X ALsetparams(AL_DEFAULT_DEVICE, savestate, X sizeof(savestate) / sizeof(long)); X kill(getpid(), sig); X} X X#endif /* USE_AL */ END_OF_FILE if test 4154 -ne `wc -c <'playulaw.c'`; then echo shar: \"'playulaw.c'\" unpacked with wrong size! fi # end of 'playulaw.c' fi if test -f 'radio.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'radio.h'\" else echo shar: Extracting \"'radio.h'\" \(2085 characters\) sed "s/^X//" >'radio.h' <<'END_OF_FILE' X/*********************************************************** Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. X X All Rights Reserved X Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. X STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* Constants shared by radio.c and broadcast.c */ X X#define BCASTCTLPORT 54319 X#define RADIOCTLPORT 54320 X#define RCVPORT 54321 X#define SENDPORT 54318 X#define INFOPORT 54317 X X#define SAMPLINGRATE 8000 X X#define BUFFERSIZE 1400 X#define CTLPKTSIZE 512 X#define INFOFREQ ((30*SAMPLINGRATE) / BUFFERSIZE) X X#define HEADERSIZE 2 /* IVS header: 2 bytes (type, encoding) */ X X#define TYPE_MASK (3<<6) X#define AUDIO_TYPE (2<<6) X X#define PCM_64 0 X#define PCM_32 1 X#define ADPCM_32 2 X#define VADPCM 3 X#define ADPCM_32_W_STATE 66 X X#ifndef DEFMCAST X#define DEFMCAST "224.0.2.5" X#endif X X#ifndef MULTICAST_TTL X#define MULTICAST_TTL 32 X#endif X X#define VERSION "2.0" X X#ifdef sgi X#define USE_AL X#define CHECK_X_SERVER X#define HAVE_MCAST X#endif X X#ifdef sun X#define SUNHACKS X#define USE_SUN X#define CHECK_X_SERVER X#endif X X#ifdef NeXT X#define USE_NX X#endif END_OF_FILE if test 2085 -ne `wc -c <'radio.h'`; then echo shar: \"'radio.h'\" unpacked with wrong size! fi # end of 'radio.h' fi if test -f 'radio.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'radio.man'\" else echo shar: Extracting \"'radio.man'\" \(4529 characters\) sed "s/^X//" >'radio.man' <<'END_OF_FILE' X.TH RADIO 1 X.SH NAME radio \- receive audio UDP packets transmitted by broadcast X.SH SYNOPSIS X.B radio X[ X.B \-c X.I port X] [ X.B \-d X] [ X.B \-f X] [ X.B \-l X.I addr X] [ X.B \-m X.I mcastgrp X] X [ X.B \-n X] [ X.B \-p X.I port X] [ X.B -r X.I addr X] [ X.B \-s X] [ X.B \-t X] [ X.B \-v X.I volume X] X.SH DESCRIPTION X.I Radio allows you to listen to audio transmitted as UDP packets on a local area network by X.IR broadcast (1). Obviously, this requires a workstation with audio hardware; currently the program works on SGI Indigo and 4D/35 workstations, Sun Sparcs, and all NeXTs. X.PP X.I Radio is normally run in the background. You may need a system-specific tool to change the volume or direct the output to the speaker or headphone jack; e.g., on an SGI, you would use X.IR apanel (1); X on a Sun you would use X.IR gaintool (1) or, when using X, X.IR x_gaintool (1) X(these programs can be found in /usr/demo/SOUND in SunOS 4.1). With OpenWindows 3.0, you can use X.IR audiotool (1). X(On the NeXT, just use the volume keys on the keyboard.) X.PP Some loss of UDP packets is tolerated; this is heard as short interruptions of the sound. X.SH OPTIONS X.TP 10 X.BI "\-c " port Use this UDP port number as control port (default 54320). Normally you never need to change this; the control port is used by optional ``tuner'' software (not distributed) and possibly by listener polling programs. X.TP 10 X.B \-d Turn on debugging (a message on stderr for each 8 packets received, and when rare or unexpected events happen). X.TP 10 X.B \-f XFilter mode: write the U-LAW audio data to stdout instead of sending it to the audio hardware. X.TP 10 X.BI "\-l " addr Listen only for packets to IP address X.I addr X(useful for forwarding stations). X.TP 10 X.BI "\-m " mcastgrp Multicast group. This only makes sense if the same multicast group is passed to the X.B \-b option of X.IR broadcast (1). Using multicasting instead of broadcasting reduces the load on machines that aren't listening. You should use the same multicast group for all stations on the local network. X(Note that even if a multicast group is specified, stations using broadcasts can still be picked up by radio). X.TP 10 X.B \-n Noninterruptable mode (Sun Sparc only). By default, X.I radio notices when another program wants to open the audio output device, and temporarily ``backs off'' until the other program is finished, hoping it won't take too long. This option turns off that feature. X.TP 10 X.BI "\-p " port Receive packets sent to this UDP port number (default 54321). This corresponds to the port used by X.I broadcast. Port numbers 1..99 are shorthands for 54321..54419. X.TP 10 X.BI "\-r " addr Listen only for packets from IP address X.I addr X(useful for forwarding stations). X.TP 10 X.B \-s Secure mode: don't listen to the control port. This is for really paranoid users: in theory, any user on the net can override the port specified with \fB\-p\fP by sending a control message to the control port of your radio program. X.TP 10 X.B \-t Tee mode: write the U-LAW audio data to stdout as well as sending it to the audio hardware. X.TP 10 X.BI "\-v " volume Set the initial volume, on a scale from 0 to 100. (SGI and Sun Sparc only.) By default, the volume is left unchanged. When the volume is specified this way, its original value is restored when the program exits. X.SH AUTHOR Guido van Rossum X.SH VERSION This manual page documents radio version 2.0, patchlevel 1. X.SH SEE ALSO broadcast(1) X.SH COPYRIGHT Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. X X All Rights Reserved X Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. X STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. END_OF_FILE if test 4529 -ne `wc -c <'radio.man'`; then echo shar: \"'radio.man'\" unpacked with wrong size! fi # end of 'radio.man' fi if test -f 'recordlinear.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'recordlinear.c'\" else echo shar: Extracting \"'recordlinear.c'\" \(3541 characters\) sed "s/^X//" >'recordlinear.c' <<'END_OF_FILE' X/*********************************************************** Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. X X All Rights Reserved X Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. X STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* Record SGI audio data and output it as 8 kHz signed 16-bits samples, X converting the sampling rate and encoding on the fly. X This writes to stdout. X X Caveats: X - since it uses an audio port, of which there can only be 4 open X at a time, running several copies is not a good idea; X see broadcast.c and radio.c for a distribution mechanism. X X To do: X - support the other three sampling rates X*/ X X#include X#include X int inrate; X X#define OUTRATE 8000 X#define INBUFSIZE 48000 X main(argc, argv) X int argc; X char **argv; X{ X short inbuf[INBUFSIZE]; X short outbuf[8000]; X ALconfig c; X ALport p; X int n; X int insamps; X int sts = 0; X X checkinrate(); X insamps = calcinsamps(); X X c = ALnewconfig(); X if (c == NULL) { X perror("ALnewconfig"); X exit(1); X } X ALsetwidth(c, AL_SAMPLE_16); X ALsetchannels(c, AL_MONO); X X p = ALopenport(argv[0], "r", c); X if (p == NULL) { X perror("ALopenport"); X exit(1); X } X X for (;;) { X checkinrate(); X insamps = calcinsamps(); X ALreadsamps(p, (void *)inbuf, insamps); X n = convert(inbuf, insamps, outbuf); X n = n * sizeof(short); X if (write(1, (char *)outbuf, n) != n) { X perror("write error"); X sts = 1; X break; X } X } X X exit(sts); X} X int calcinsamps() X{ X int insamps = inrate/2; X if (insamps > INBUFSIZE) X insamps = INBUFSIZE; X return insamps; X} X checkinrate() X{ X inrate = getinrate(); X if ((inrate/OUTRATE)*OUTRATE != inrate) { X fprintf(stderr, X "current sampling rate (%d) is not a multiple of %d\n", X inrate, OUTRATE); X exit(1); X } X} X int getinrate() X{ X long PVbuffer[2]; X X PVbuffer[0] = AL_INPUT_RATE; X ALgetparams(AL_DEFAULT_DEVICE, PVbuffer, 2); X return PVbuffer[1]; X} X int convert(inbuf, n, outbuf) X short *inbuf; X int n; X short *outbuf; X{ X register short *inp = inbuf; X register short *inend = inbuf + n; X register int di = inrate/OUTRATE; X register int x; X register short *outp = outbuf; X X while (inp < inend) { X switch (di) { X case 1: X *outp++ = *inp++; X break; X case 2: X x = *inp++; X x += *inp++; X *outp++ = x >> 1; X break; X case 4: X x = *inp++; X x += *inp++; X x += *inp++; X x += *inp++; X *outp++ = x >> 2; X break; X case 6: X x = *inp++; X x += *inp++; X x += *inp++; X x += *inp++; X x += *inp++; X x += *inp++; X *outp++ = x / 24; X break; X } X } X X return outp - outbuf; X} END_OF_FILE if test 3541 -ne `wc -c <'recordlinear.c'`; then echo shar: \"'recordlinear.c'\" unpacked with wrong size! fi # end of 'recordlinear.c' fi if test -f 'recordulaw.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'recordulaw.c'\" else echo shar: Extracting \"'recordulaw.c'\" \(4711 characters\) sed "s/^X//" >'recordulaw.c' <<'END_OF_FILE' X/*********************************************************** Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. X X All Rights Reserved X Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. X STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* Record SGI audio data and output it at 8 kHz to Sparc uLAW format, X converting the sampling rate and encoding on the fly. X This writes to stdout -- use rsh to pipe it to /dev/audio on a Sparc. X No Sun audio header is added. X X Caveats: X - since it uses an audio port, of which there can only be 4 open X at a time, running several copies is not a good idea; X see broadcast.c and radio.c for a distribution mechanism. X X To do: X - support the other three sampling rates X*/ X X#include X#include X int inrate; X X#define OUTRATE 8000 X#define INBUFSIZE 48000 X main(argc, argv) X int argc; X char **argv; X{ X short inbuf[INBUFSIZE]; X char outbuf[8000]; X ALconfig c; X ALport p; X int n; X int insamps; X int sts = 0; X X checkinrate(); X insamps = calcinsamps(); X X c = ALnewconfig(); X if (c == NULL) { X perror("ALnewconfig"); X exit(1); X } X ALsetwidth(c, AL_SAMPLE_16); X ALsetchannels(c, AL_MONO); X X p = ALopenport(argv[0], "r", c); X if (p == NULL) { X perror("ALopenport"); X exit(1); X } X X initcvt(); X X for (;;) { X checkinrate(); X insamps = calcinsamps(); X ALreadsamps(p, (void *)inbuf, insamps); X n = convert(inbuf, insamps, outbuf); X if (write(1, outbuf, n) != n) { X perror("write error"); X sts = 1; X break; X } X } X X exit(sts); X} X int calcinsamps() X{ X int insamps = inrate/2; X if (insamps > INBUFSIZE) X insamps = INBUFSIZE; X return insamps; X} X checkinrate() X{ X inrate = getinrate(); X if ((inrate/OUTRATE)*OUTRATE != inrate) { X fprintf(stderr, X "current sampling rate (%d) is not a multiple of %d\n", X inrate, OUTRATE); X exit(1); X } X} X int getinrate() X{ X long PVbuffer[2]; X X PVbuffer[0] = AL_INPUT_RATE; X ALgetparams(AL_DEFAULT_DEVICE, PVbuffer, 2); X return PVbuffer[1]; X} X X/* Convert a bufferful of data from SGI to uLAW format X - inrate samples/sec --> 8000 samples/sec X - 16 bit linear encoding --> 8 bit uLAW encoding X*/ X extern unsigned char *cvtvec; /* Forward */ X int convert(inbuf, n, outbuf) X short *inbuf; X int n; X unsigned char *outbuf; X{ X register short *inp = inbuf; X register short *inend = inbuf + n; X register int di = inrate/OUTRATE; X register int x; X register unsigned char *outp = outbuf; X X while (inp < inend) { X switch (di) { X case 1: X *outp++ = cvtvec[*inp++ >> 2]; X break; X case 2: X x = *inp++; X x += *inp++; X *outp++ = cvtvec[x >> 3]; X break; X case 4: X x = *inp++; X x += *inp++; X x += *inp++; X x += *inp++; X *outp++ = cvtvec[x >> 4]; X break; X case 6: X x = *inp++; X x += *inp++; X x += *inp++; X x += *inp++; X x += *inp++; X x += *inp++; X *outp++ = cvtvec[x / 24]; X break; X } X } X X return outp - outbuf; X} X X X/* convert two's complement ch (1+13 bits) into uLAW format (8 bits) */ X unsigned int cvt(ch) int ch; X{ X int mask; X X if (ch < 0) { X ch = -ch; X mask = 0x7f; X } else { X mask = 0xff; X } X X if (ch < 32) { X ch = 0xF0 | 15 - (ch / 2); X } else if (ch < 96) { X ch = 0xE0 | 15 - (ch - 32) / 4; X } else if (ch < 224) { X ch = 0xD0 | 15 - (ch - 96) / 8; X } else if (ch < 480) { X ch = 0xC0 | 15 - (ch - 224) / 16; X } else if (ch < 992) { X ch = 0xB0 | 15 - (ch - 480) / 32; X } else if (ch < 2016) { X ch = 0xA0 | 15 - (ch - 992) / 64; X } else if (ch < 4064) { X ch = 0x90 | 15 - (ch - 2016) / 128; X } else if (ch < 8160) { X ch = 0x80 | 15 - (ch - 4064) / 256; X } else { X ch = 0x80; X } X X return (mask & ch); X} X unsigned char cvttab[1<<14]; unsigned char *cvtvec = &cvttab[1<<13]; X initcvt() X{ X int i; X for (i = -(1<<13); i < (1<<13); i++) X cvtvec[i] = cvt(i); X} END_OF_FILE if test 4711 -ne `wc -c <'recordulaw.c'`; then echo shar: \"'recordulaw.c'\" unpacked with wrong size! fi # end of 'recordulaw.c' fi if test -f 'sndulaw.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'sndulaw.c'\" else echo shar: Extracting \"'sndulaw.c'\" \(2972 characters\) sed "s/^X//" >'sndulaw.c' <<'END_OF_FILE' X/* X * Author : Reimer A. Mellin X * Date : 4.12.1991 X * no copyrights X * X * X * ulaw: based on recordchaintest.c X * it writes a endless stream of Sound to stdout until terminated or X * interrupted. X * sndrecord can't be used, since it can not write to stdout :-( X */ X X#import X#import X#import X X#define NUM_BUFFERS 5 X#define BUF_SIZE 8000 X static SNDSoundStruct *buffers[NUM_BUFFERS]; static FILE *sfp; X static void record(int tag); X static int recordDone(SNDSoundStruct *s, int tag, int err) X/* X * Called when a buffer has been recorded. X * Appends the buffer to the soundfile. X */ X{ X if (err) X fprintf(stderr, "recordDone: %s\n", SNDSoundError(err)); X if (fwrite((void *)((char *)s + s->dataLocation), 1, s->dataSize, sfp) != X s->dataSize) X fprintf(stderr, "recordDone: could not write data to soundfile\n"); X return 0; X} X static void record(int bufNum) X/* X * Initiates recording into a buffers[bufNum]. X */ X{ X int err; X X X if (err = SNDStartRecording(buffers[bufNum], bufNum+1, 0, 0, SND_NULL_FUN, X recordDone)) X fprintf(stderr, "record: %s\n", SNDSoundError(err)); X} X static void init(int n, int size) X/* X * Allocate n sound buffers. X * Creates the soundfile. X */ X{ X int i, err; X SNDSoundStruct s; X X for (i = 0; i < n; i++) X if (err = SNDAlloc(&buffers[i], size, SND_FORMAT_MULAW_8, X SND_RATE_CODEC, 1, 4)) X fprintf(stderr, "init: %s\n", SNDSoundError(err)); X X s.magic = SND_MAGIC; X s.dataLocation = sizeof(SNDSoundStruct); X s.dataSize = 0; X s.dataFormat = SND_FORMAT_MULAW_8; X s.samplingRate = SND_RATE_CODEC; X s.channelCount = 1; X (void)strcpy( s.info, "ram"); X if (fwrite((void *)&s, sizeof(SNDSoundStruct), 1, sfp) != 1) X fprintf(stderr, "init: could not write dummy header to soundfile\n"); X} X static void cleanup(void) X/* X * Write the soundfile header. X */ X{ X SNDSoundStruct s; X X s.magic = SND_MAGIC; X s.dataLocation = sizeof(SNDSoundStruct); X s.dataSize = 0; X s.dataFormat = SND_FORMAT_MULAW_8; X s.samplingRate = SND_RATE_CODEC; X s.channelCount = 1; X (void)strcpy( s.info, "ram"); X X if(!isatty(fileno(sfp))) { X rewind(sfp); X if (fwrite((void *)&s, sizeof(SNDSoundStruct), 1, sfp) != 1) X fprintf(stderr, "cleanup: could not write header to soundfile\n"); X } X fflush(sfp); X exit(0); X} X main(int argc, char *argv[]) X{ X int i; X X if( argc > 1 ) { X fprintf(stderr, "%s: Records sound from CODEC and writes it to stdout\n", X argv[0]); X exit(1); X } X sfp = stdout; X (void)signal( SIGTERM, (void *)cleanup); X (void)signal( SIGINT, (void *)cleanup); X X /* prepare sound and start the first 5 recordings */ X init(NUM_BUFFERS, BUF_SIZE); X for (i = 0; i < NUM_BUFFERS; i++) { X record(i); X } X for(;;){ X /* As soon as the first is finished, restart it */ X for (i = 0; i < NUM_BUFFERS; i++) { X SNDWait(i+1); X record(i); X } X } X cleanup(); X} END_OF_FILE if test 2972 -ne `wc -c <'sndulaw.c'`; then echo shar: \"'sndulaw.c'\" unpacked with wrong size! fi # end of 'sndulaw.c' fi if test -f 'socklib.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'socklib.c'\" else echo shar: Extracting \"'socklib.c'\" \(3341 characters\) sed "s/^X//" >'socklib.c' <<'END_OF_FILE' X/*********************************************************** Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. X X All Rights Reserved X Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. X STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* Socket-related subroutines shared by broadcast and radio */ X X#include X#include X#include X#include X#include X X#include X#include X#include X#include X int opensock(sockdesc, localname, localport, remotename, remoteport, broadcast) X char *sockdesc; X char *localname; X int localport; X char *remotename; X int remoteport; X int broadcast; X{ X int s; X struct sockaddr_in sin; X char desc[512]; X X s = socket(AF_INET, SOCK_DGRAM, 0); X if (s < 0) { X sprintf(desc, "socket(%s)", sockdesc); X perror(desc); X exit(1); X } X memset((char *)&sin, '\0', sizeof(sin)); X if(localname) { X setipaddr(localname, &sin); X } X else { X sin.sin_addr.s_addr = INADDR_ANY; X sin.sin_family = AF_INET; X } X sin.sin_port = htons(localport); X X#ifdef SO_REUSEPORT X if (!broadcast) { X int on = 1; X if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, X &on, sizeof (on)) < 0) { X sprintf(desc,"setsockopt(%s, SO_REUSEPORT)", sockdesc); X perror(desc); X /* Don't exit -- this isn't fatal */ X } X } X#endif X X if (bind(s, &sin, sizeof sin) < 0) { X sprintf(desc,"bind(%s)", sockdesc); X perror(desc); X exit(1); X } X X if(remotename) { X memset((char *)&sin, '\0', sizeof(sin)); X setipaddr(remotename, &sin); X sin.sin_port = htons(remoteport); X X if (connect(s, &sin, sizeof sin) < 0) { X sprintf(desc, "connect(%s)", sockdesc); X perror(desc); X exit(1); X } X } X X if(broadcast) { X int on = 1; X if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, X &on, sizeof (on)) < 0) { X sprintf(desc,"setsockopt(%s, SO_BROADCAST)", sockdesc); X perror(desc); X exit(1); X } X } X return s; X} X int setipaddr(name, addr_ret) X char *name; X struct sockaddr_in *addr_ret; X{ X struct hostent *hp; X X if((hp = gethostbyname(name)) == NULL) { X if((addr_ret->sin_addr.s_addr = inet_addr(name)) == -1) { X return(-1); X } X } X else { X memcpy((char *) &addr_ret->sin_addr, hp->h_addr, hp->h_length); X } X addr_ret->sin_family = AF_INET; X return 4; X} END_OF_FILE if test 3341 -ne `wc -c <'socklib.c'`; then echo shar: \"'socklib.c'\" unpacked with wrong size! fi # end of 'socklib.c' fi if test -f 'stations.pl' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stations.pl'\" else echo shar: Extracting \"'stations.pl'\" \(854 characters\) sed "s/^X//" >'stations.pl' <<'END_OF_FILE' X#!/usr/bin/perl X## X## Find radio stations X## X## (A small subset of the functionality of stations.py for now) X## X## Written by; Jeff Beadles jeff@onion.rain.com X## X# this emulates #! processing on machines that don't support it. eval "exec /usr/bin/perl -S $0 $*" X if $running_under_some_shell_and_not_perl; X require 'sys/socket.ph'; X X($name, $aliases, $proto) = getprotobyname('udp'); X X$this = pack('S n a4 x8' , &AF_INET, 54317, "\0\0\0\0"); X socket(S, &AF_INET, &SOCK_DGRAM, $proto) || die "socket: $!"; bind(S, $this) || die "bind: $!"; X while (1) { X recv(S, $buf, 1024, 0) || die "recv: $!\n"; X chop($buf); X ($t_radio,$t_s,$t_name,$t_port,$t_xmit,$t_log,$t_age) = split(/:/,$buf,7); X print "Bogus message '$buf'\n" if ($t_radio ne "radio"); X print "Receiving station '$t_name' on port $t_port\n"; X} END_OF_FILE if test 854 -ne `wc -c <'stations.pl'`; then echo shar: \"'stations.pl'\" unpacked with wrong size! fi chmod +x 'stations.pl' # end of 'stations.pl' fi if test -f 'stations.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stations.py'\" else echo shar: Extracting \"'stations.py'\" \(3128 characters\) sed "s/^X//" >'stations.py' <<'END_OF_FILE' X#! /usr/local/bin/python X X# /*********************************************************** X# Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The X# Netherlands. X# X# All Rights Reserved X# X# Permission to use, copy, modify, and distribute this software and its X# documentation for any purpose and without fee is hereby granted, X# provided that the above copyright notice appear in all copies and that X# both that copyright notice and this permission notice appear in X# supporting documentation, and that the names of Stichting Mathematisch X# Centrum or CWI not be used in advertising or publicity pertaining to X# distribution of the software without specific, written prior permission. X# X# STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO X# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND X# FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE X# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES X# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN X# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT X# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X# X# ******************************************************************/ X X# Print station call packets received from broadcast programs around the net. X import time import string import os from stat import * from socket import * X##from SOCKET import * X INFOPORT = 54317 BCASTCTLPORT = 54319 X def main(): X s = socket(AF_INET, SOCK_DGRAM) X## s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) # Python 0.9.7 or higher X s.allowbroadcast(1) # Python 0.9.6 X s.bind('', INFOPORT) X s.sendto('radio:s', ('', BCASTCTLPORT)) X while 1: X data, sender = s.recvfrom(100) X if data[:7] == 'radio:S': X name, prt, tr, log, age, prg = decodeinfo(data) X print name+':', prg, X if age >= 0: print '(' + formatage(age) + ')', X print X elif data[:6] == 'radio:': X print 'bad control packet:', `data` X else: X print 'bad packet received' X X def formatage(age): X if age < 60: return `age` + ' sec' X if age < 3600: return `age/60` + ' min' X if age < 24*3600: return `age/3600` + ' hrs' X return `age/(24*3600)` + ' days' X def decodeinfo(data): X fields = string.splitfields(data, ':') X name = fields[2] X port = eval(fields[3]) X if fields[4:]: X transmitting = eval(fields[4]) X logfile = fields[5] X age = eval(fields[6]) X contents = string.joinfields(fields[7:], ':') X else: X transmitting = -1 X programfile = '/ufs/' + name + '/CD' X logfile = programfile + 'log' X age = getage(programfile) X if age == None: X age = -1 X contents = getcontents(programfile) X if contents == None: X contents = '???' X return name, port, transmitting, logfile, age, contents X return None X def getcontents(filename): X try: X f = open(filename, 'r') X except IOError: X return None X res = f.readline() X f.close() X return string.strip(res) X def getage(filename): X try: X st = os.stat(filename) X except os.error: X return None X return time.time() - st[ST_MTIME] X X try: X main() except KeyboardInterrupt: X print X print '[Interrupt]' END_OF_FILE if test 3128 -ne `wc -c <'stations.py'`; then echo shar: \"'stations.py'\" unpacked with wrong size! fi # end of 'stations.py' fi if test -f 'ttytuner.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ttytuner.py'\" else echo shar: Extracting \"'ttytuner.py'\" \(7530 characters\) sed "s/^X//" >'ttytuner.py' <<'END_OF_FILE' X#!/usr/local/bin/python X X# /*********************************************************** X# Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The X# Netherlands. X# X# All Rights Reserved X# X# Permission to use, copy, modify, and distribute this software and its X# documentation for any purpose and without fee is hereby granted, X# provided that the above copyright notice appear in all copies and that X# both that copyright notice and this permission notice appear in X# supporting documentation, and that the names of Stichting Mathematisch X# Centrum or CWI not be used in advertising or publicity pertaining to X# distribution of the software without specific, written prior permission. X# X# STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO X# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND X# FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE X# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES X# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN X# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT X# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X# X# ******************************************************************/ X X# A tuner to control radio programs, by Jack Jansen. X import sys import os import time import socket import time import string import getopt from stat import ST_MTIME X X RADIOCTLPORT=54320 TRANSMITTERCTLPORT=54319 CTLWS=socket.gethostname() X X# The list of networks to broadcast on, when looking for radio X# stations. This should somehow be gotten differently. X# MCASTLIST = ['192.16.184.0', '192.16.191.0', '192.16.201.255'] X# MCASTLIST = ['192.16.201.255'] X class struct(): pass info = struct() X X# X# sendsock - send a message (and get optional reply) X# def sendsock(host, port, msg, needrepl): X try: X host = socket.gethostbyname(host) X s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) X s.sendto(msg, (host,port)) X if needrepl: X # Loop for max. 2.5 seconds waiting for a reply X i = 0 X while i < 5 and not s.avail(): X time.millisleep(500) X i = i + 1 X if not s.avail(): X print 'Radio program not responding' X return '' X return s.recv(500) X except socket.error: X print 'Incorrect radio settings' X if needrepl: X return '' X else: X return X# X# sendmulti - send a multicast message (and get replies) X# def sendmulti(mcastlist, port, msg): X rv = [] X try: X s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) X s.allowbroadcast(1) X for host in mcastlist: X s.sendto(msg, (host,port)) X # Loop for max. 2.5 seconds waiting for a reply X i = 0 X while i < 25: X time.millisleep(100) X i = i + 1 X if s.avail(): X rv.append(s.recv(500)) X except socket.error: X print 'Incorrect mcast settings' X return rv X# X# getstationinfo - Return playlist, current and playing time (in minutes). X# Returns a triple (playlist-filename, current record, playing time) X# def getstationinfo(info): X name = info[0] X if len(info) > 3: X playlist = info[3] X else: X playlist = '/ufs/' + name + '/CDlog' X if len(info) > 5: X since = eval(info[4]) X cur = string.joinfields(info[5:], ':') X else: X curfn = '/ufs/' + name + '/CD' X try: X curf = open(curfn,'r') X cur = curf.readline() X curf.close() X except IOError: X cur = '???' X if cur[-1:] == '\n': X cur = cur[:-1] X try: X sb = os.stat(curfn) X since = time.time() - sb[ST_MTIME] X except os.error: X since = -1 X if since >= 0: since = since / 60 # Convert to minutes X if since < 0: X str = '??' X elif since < 60: X str = `since` + ' mins' X else: X since = since / 60 X if since < 24: X str = `since` + ' hrs' X else: X str = `since / 24` + ' days' X return playlist, cur, str X X# X# updateinfo - Update one of the views with info on station 'name' X# def printinfo(info): X name = info[0] X print 'Station '+ name + ':' X print '\tPort ' + `info[1]` X if name == '' or name[:3] == '???': X print '\tNo information on station' X else: X try: X p, c, t = getstationinfo(info) X except IOError: X return X if c <> '' and c <> '???': X print '\tCurrently playing: ' + c X if t <> '??': X print '\tSince: ' + t X if p <> '': X print '\tPlaylist in file: ' + p X X# X# getstations - Return an array of (stationname, stationport) X# listing all available stations. X# def getstations(): X stations = [] X raw = sendmulti(MCASTLIST, TRANSMITTERCTLPORT, 'radio:s') X for i in raw: X if i[:7] == 'radio:S': X fields = string.splitfields(i,':')[2:] X fields[1] = string.atoi(fields[1]) X stations.append(fields) X else: X print 'Funny reply from transmitter:', i[:7] X return stations X X# X# getcurstation - Return (name,port) for station to which radio X# on workstation ws is currently tuned to. X# def getcurstation(stationlist, ws, port): X rv = sendsock(ws, port, 'radio:i', 1) X if rv == '': X return ('',0) X if rv[0:8] <> 'radio:I:': X print 'Illegal reply from radio:',rv X return ('',0) X # Remove optional pause field X rv = rv[8:] X rv = string.splitfields(rv,':') X if len(rv) == 1: # Old: port X tport = string.atoi(rv[0]) X playing = 1 X elif len(rv) == 2: # newer: playing, port X tport = string.atoi(rv[1]) X playing = string.atoi(rv[0]) X elif len(rv) == 3: # Still newer: playing, port, version X tport = string.atoi(rv[1]) X playing = string.atoi(rv[0]) X else: # Too new X print 'Unknown reply to info: ', rv X for i in stationlist: X if i[1] == tport: X return (i, playing) X return (('???(port '+`tport`+')' ,tport), playing) X def main(): X radio_port = RADIOCTLPORT X radio_ws = CTLWS X try: X optlist, args = getopt.getopt(sys.argv[1:], 'w:p:lLcPCT') X mode = '' X for o, a in optlist: X if o == '-w': X radio_ws = a X elif o == '-p': X radio_port = string.atoi(a) X elif mode == '': X mode = o[1] X else: X raise getopt.error X if len(args) + len(mode) <> 1: X raise getopt.error X except getopt.error: X print 'Usage: '+sys.argv[0]+' [options] command' X print 'Options:' X print '\t-w ws\tControl radio on workstation ws' X print '\t-p port\tControl radio on port port' X print 'Command:' X print '\t-l\tList names of active stations' X print '\t-L\tList names and info of active stations' X print '\t-c\tList info on current station' X print '\t-P\tTemporarily suspend radio, freeing port' X print '\t-C\tContinue radio' X print '\t-T\tToggle suspend/continue' X print '\tstation\tTune to new station' X sys.exit(1) X X # X # First, do pause/continue command. X # X if mode == 'P': X sendsock(radio_ws, radio_port, 'radio:0', 0) X sys.exit(0) X if mode == 'C': X sendsock(radio_ws, radio_port, 'radio:1', 0) X sys.exit(0) X if mode == 'T': X cn, playing = getcurstation([], radio_ws, radio_port) X sendsock(radio_ws, radio_port, 'radio:'+`not playing`, 0) X sys.exit(0) X # X # And list of new stations X # X stations = getstations() X # X # Set info for current station X # X if mode == '' or mode == 'c': X cn, playing = getcurstation(stations,radio_ws, radio_port) X if mode == 'l': X for i in stations: X print i[0] X elif mode == 'L': X for i in stations: X printinfo(i) X elif mode == 'c': X printinfo(cn) X else: X for i in range(len(stations)): X if stations[i][0] == args[0]: X sendsock(radio_ws, radio_port, \ X 'radio:t:' + `stations[i][1]`, 0) X sys.exit(0) X print 'No such station: ', args[0] X X X main() X X# Local variables: X# py-indent-offset: 4 X# end: END_OF_FILE if test 7530 -ne `wc -c <'ttytuner.py'`; then echo shar: \"'ttytuner.py'\" unpacked with wrong size! fi chmod +x 'ttytuner.py' # end of 'ttytuner.py' fi if test -f 'ulawadpcm.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ulawadpcm.c'\" else echo shar: Extracting \"'ulawadpcm.c'\" \(7209 characters\) sed "s/^X//" >'ulawadpcm.c' <<'END_OF_FILE' X/*********************************************************** Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. X X All Rights Reserved X Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. X STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X X******************************************************************/ X X/* X** Intel/DVI ADPCM coder/decoder. X** X** The algorithm for this coder was taken from the IMA Compatability Project X** proceedings, Vol 2, Number 2; May 1992. X** X** Version 1.1, 16-Dec-92. X** X** Change log: X** - Fixed a stupid bug, where the delta was computed as X** stepsize*code/4 in stead of stepsize*(code+0.5)/4. The old behavior can X** still be gotten by defining STUPID_V1_BUG. X*/ X X#include "adpcm.h" X#include "libst.h" X X#ifndef __STDC__ X#define signed X#endif X X/* Intel ADPCM step variation table */ static int indexTable[16] = { X -1, -1, -1, -1, 2, 4, 6, 8, X -1, -1, -1, -1, 2, 4, 6, 8, X}; X static int stepsizeTable[89] = { X 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, X 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, X 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, X 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, X 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, X 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, X 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, X 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, X 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 X}; X void ulaw_adpcm_coder(indata, outdata, len, state) X char indata[]; X char outdata[]; X int len; X struct adpcm_state *state; X{ X unsigned char *inp; /* Input buffer pointer */ X signed char *outp; /* output buffer pointer */ X /* XXX why must outp be signed? */ X int val; /* Current input sample value */ X int sign; /* Current adpcm sign bit */ X int delta; /* Current adpcm output value */ X int step; /* Stepsize */ X int valprev; /* virtual previous output value */ X int vpdiff; /* Current change to valprev */ X int index; /* Current step change index */ X int outputbuffer; /* place to keep previous 4-bit value */ X int bufferstep; /* toggle between outputbuffer/output */ X X outp = (signed char *)outdata; X inp = (unsigned char *)indata; X X if (state) { X valprev = state->valprev; X index = state->index; X } X else { X valprev = 0; X index = 0; X } X step = stepsizeTable[index]; X X bufferstep = 1; X X for ( ; len > 0 ; len-- ) { X val = st_ulaw_to_linear(*inp++); X X /* Step 1 - compute difference with previous value */ X delta = val - valprev; X sign = (delta < 0) ? 8 : 0; X if ( sign ) delta = (-delta); X X /* Step 2 - Divide and clamp */ X#ifdef NODIVMUL X { X int tmp = 0; X#ifdef STUPID_V1_BUG X vpdiff = 0; X#else X vpdiff = (step >> 3); X#endif /* STUPID_V1_BUG */ X if ( delta > step ) { X tmp = 4; X delta -= step; X vpdiff += step; X } X step >>= 1; X if ( delta > step ) { X tmp |= 2; X delta -= step; X vpdiff += step; X } X step >>= 1; X if ( delta > step ) { X tmp |= 1; X vpdiff += step; X } X delta = tmp; X } X#else X delta = (delta<<2) / step; X if ( delta > 7 ) delta = 7; X X#ifdef STUPID_V1_BUG X vpdiff = (delta*step) >> 2; X#else X vpdiff = ((delta*step) >> 2) + (step >> 3); X#endif /* STUPID_V1_BUG */ X#endif /* NODIVMUL */ X X /* Step 3 - Update previous value */ X if ( sign ) X valprev -= vpdiff; X else X valprev += vpdiff; X X /* Step 4 - Clamp previous value to 16 bits */ X if ( valprev > 32767 ) X valprev = 32767; X else if ( valprev < -32768 ) X valprev = -32768; X X /* Step 5 - Assemble value, update index and step values */ X delta |= sign; X X index += indexTable[delta]; X if ( index < 0 ) index = 0; X if ( index > 88 ) index = 88; X step = stepsizeTable[index]; X X /* Step 6 - Output value */ X if ( bufferstep ) { X outputbuffer = (delta << 4) & 0xf0; X } else { X *outp++ = (delta & 0x0f) | outputbuffer; X } X bufferstep = !bufferstep; X } X X /* Output last step, if needed */ X if ( !bufferstep ) X *outp++ = outputbuffer; X X if (state) { X state->valprev = valprev; X state->index = index; X } X} X void adpcm_ulaw_decoder(indata, outdata, len, state) X char indata[]; X char outdata[]; X int len; X struct adpcm_state *state; X{ X signed char *inp; /* Input buffer pointer */ X char *outp; /* output buffer pointer */ X int sign; /* Current adpcm sign bit */ X int delta; /* Current adpcm output value */ X int step; /* Stepsize */ X int valprev; /* virtual previous output value */ X int vpdiff; /* Current change to valprev */ X int index; /* Current step change index */ X int inputbuffer; /* place to keep next 4-bit value */ X int bufferstep; /* toggle between inputbuffer/input */ X X outp = outdata; X inp = (signed char *)indata; X X if (state) { X valprev = state->valprev; X index = state->index; X } X else { X valprev = 0; X index = 0; X } X step = stepsizeTable[index]; X X bufferstep = 0; X X for ( ; len > 0 ; len-- ) { X X /* Step 1 - get the delta value and compute next index */ X if ( bufferstep ) { X delta = inputbuffer & 0xf; X } else { X inputbuffer = *inp++; X delta = (inputbuffer >> 4) & 0xf; X } X bufferstep = !bufferstep; X X /* Step 2 - Find new index value (for later) */ X index += indexTable[delta]; X if ( index < 0 ) index = 0; X if ( index > 88 ) index = 88; X X /* Step 3 - Separate sign and magnitude */ X sign = delta & 8; X delta = delta & 7; X X /* Step 4 - update output value */ X#ifdef NODIVMUL X#ifdef STUPID_V1_BUG X vpdiff = 0; X#else X vpdiff = step >> 1; X#endif /* STUPID_V1_BUG */ X if ( delta & 4 ) vpdiff += (step << 2); X if ( delta & 2 ) vpdiff += (step << 1); X if ( delta & 1 ) vpdiff += step; X vpdiff >>= 2; X#else X#ifdef STUPID_V1_BUG X vpdiff = ((delta*step) >> 2); X#else X vpdiff = ((delta*step) >> 2) + (step >> 3); X#endif /* STUPID_V1_BUG */ X#endif /* ! NODIVMUL */ X if ( sign ) X valprev -= vpdiff; X else X valprev += vpdiff; X X /* Step 5 - clamp output value */ X if ( valprev > 32767 ) X valprev = 32767; X else if ( valprev < -32768 ) X valprev = -32768; X X /* Step 6 - Update step value */ X step = stepsizeTable[index]; X X /* Step 7 - Output value */ X *outp++ = st_linear_to_ulaw(valprev); X } X X if (state) { X state->valprev = valprev; X state->index = index; X } X} END_OF_FILE if test 7209 -ne `wc -c <'ulawadpcm.c'`; then echo shar: \"'ulawadpcm.c'\" unpacked with wrong size! fi # end of 'ulawadpcm.c' fi echo shar: End of archive 1 \(of 2\). cp /dev/null ark1isdone MISSING="" for I in 1 2 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked both archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0