[comp.sys.next] Showing off the sounds

peterd@cs.mcgill.ca (Peter Deutsch) (05/25/91)

----------------------------------------------------------------------

g'day, 

Here's a little bit of hacking that may or may not be of
interest. But first, some background:

For those who haven't seen it (or are cut off from the
alt.* hierarchy of Usenet) there is now a new group
alt.sex.sounds. In the finest hacker traditions, this has
contained almost nothing vaguely resembling an erotic
sound (like, a Rodney Dangerfiled joke! really, people..)
It's mostly unix weenies and amiga weenies and Mac weenies
arguing and sharing sound conversion info. For those who
can get it, check it out..

Now, the most "interesting" sound I saw/heard (in fact,
the only one I saw that would vaguely fit the mandate of
the newsgroup) was "Sally.snd", which is the diner scene
from "When Harry Met Sally" (and you should see the faces of
the DOS users in this place when I replaced the "Print out
of Paper" voice message with THAT!). Since I'm actually a
unix weenie myself, I of course spent half an hour
converting this to the appropriate format for NeXT,
discovering things about NeXT sounds, etc. This is an area
I hadn't explored before and I'm impressed. Well done,
NeXTites.

Anyways, to the hacking bit.

After playing with this osund on the NeXT for a while I
started getting ideas. Given that the original Sally.snd
file started life as an old style Sun sound file (no
format header) and we'd been playing it on the IPC to
verify this (in fact, the way we converted it was to load
up the demos sound program on the sun and let it handle
it. Since then I've learned about sndconvert), I had the
idea to try and play the sound across the network. I tried:

cat sally.snd | rsh machine.mcgill.ca -l root "cat - > /dev/audio"

and lo and behold it worked like a charm. No pauses,
nothing. This is fun.

My next idea was to look in the
NextDeveloper/Examples/Sound directory and see what I
could use. I noticed that all of these sample programs
seem to write recorded sounds out to a file. "That's no
good" I said.  So I hacked "recordtest.c" to write to
standard out (see below).I could now do this (I called the
compiled program "doit"):

doit | rsh machine.mcgill.ca -l root "cat - > /dev/audio"


And it worked like a charm. I spoke into the mike and it
came out on the Sun, after aa short delay. Now, it was
choppy (this program records a fragment of sound, then
plays it, then records some more, etc) so there are gaps
in the output, but it works. So, here's the project -
anybody want to convert this to use multiple Mach threads,
one recording one playing so we don't get the gaps? Add a
GUI so the front desk people can do departmental wide
paging, click on the face of someone to call them, maybe
have little phono plugs you drag into sockets to connect
to other machines?  The possibilities seem endless.

I hope to play with this some more (like, from NeXT to
NeXT, which is no big deal) but I wanted to share how easy
this was with you all. From first idea to talking across
the net to the Sun was no more than five minutes work.
Gosh, I love these little toys!

So, I hope this puts a few ideas in people's heads. I'm
going to keep playing and would be interested in hearing
from others working along simliar lines.

Enjoy...

				- peterd

----------------------------------------------------------------------

/*
 * recordtest - record many short soundfiles, 

Hacked to write to standard out instead of a file and loop
20 times then halt....

		- peterd (yeah, like I
		  gotta sign five minutes work...)
 */

#import <sound/sound.h>
#import <stdio.h>

main (int argc, char *argv[])
{
    int size, err, j;
    SNDSoundStruct *s[10], *s2;
/*
    if (argc < 2) {
	printf("usage : recordtest file ...\n");
	exit(0);
    }
*/  
    //
    // Allocate a fixed-sized buffer for each file
    //
    for (j=1; j<5; j++) {
	err = SNDAlloc(&s[j],4096,SND_FORMAT_MULAW_8,SND_RATE_CODEC,1,0);
	if (err) fprintf(stderr,"recordtest : cannot allocate buffers\n");
    }
    
    //
    // enqueue all the recording requests
    //
    fprintf(stderr, "recording...\n");
    for (j=1; j<20; j++) {
	fprintf(stderr,"recordtest : start recording\n");
	err = SNDStartRecording(s[1],0,1,0,0,0);
	if (err) fprintf(stderr,"recordtest : cannot start recording\n");
	fprintf(stderr,"recordtest : await recording\n");
        SNDWait(0);
	fprintf(stderr,"recordtest : done recording, now write\n");
	err = SNDWrite(1,s[1]);
	if (err) fprintf(stderr,"recordtest : cannot write output...\n" );
    }
    
    //
    // Wait for all of the requests to complete
    //
    
    //
    // Write out the files
    //
//    printf("writing files...\n");
    for (j=1; j<5; j++) {
    }
    
    exit(0);
}

lindner@cs.umn.edu (Paul Lindner) (05/25/91)

In <1991May24.230242.22506@cs.mcgill.ca> peterd@cs.mcgill.ca (Peter Deutsch) writes:

>So, I hope this puts a few ideas in people's heads. I'm
>going to keep playing and would be interested in hearing
>from others working along simliar lines.


>----------------------------------------------------------------------

>#import <sound/sound.h>
>#import <stdio.h>

>main (int argc, char *argv[])
[.... code deleted...]

Ha! I've already beat ya to it!  I hacked the same examples and came up with
with commands that play from stdin and record to stdout for the NeXT.

The problem around here is really sh**ty radio reception.  I swear that
our Csci building is just one big Focault cage.  However my office is in
another building, where I've set up an antenna.  Thus I set up a little
server on the next cube here in my office connected to the radio, that's
connected to the mongo antenna.

My little server sits at port 7000 and waits for connections.  When it
receives one it starts the record process and starts spewing forth sound
data across the socket.  The client receives this and pipes it into the
speaker on the local machine.

Essentially I now have KJJO and KFAI gateways.  I also pop a CD in my
Sun CD-ROM, start up a sound server on it, and then I run x_cdplayer
remotely.  I can change tracks on the client machine and actually hear
my changes.  (Just don't press the eject button, or else you'll have
a long run on your hands.)  In fact I had it running for three days
straight once.   (That's about 2.1 gig of sound transferred)

I also have digitized some of my favorite tunes to Optical Disk.  I'm
up to about 40 megs of sampled songs!  This fits in quite well with this
distributed database project of mine that utilizes the full text indexing
of the Next.  The sound server is patched into this database.  You can
choose from a menu/directory tree for the songs you want to hear.  The
only thing it doesn't have is a quarter slot on the side!  (Though if
ASCAP or BMI finds out, I may have to do that!)

So for all of you NeXT people, here's the play and record that work
flawlessly on pipes.  If anyone is interested in the server and clients
for sound (I call them radiod and radio), drop me a line.  It's pretty cool.


-------------------- play.c ------------------------------------------
/* derived from
 * recordchaintest.c - this test shows how to chain small recordings
 * and append them to a soundfile.
 * 
 * Play sound from a pipe.  An ugly hack by Paul Lindner
 * <lindner@boombox.micro.umn.edu>
 */ 
#import	<stdio.h>
#import	<sound/sound.h>

#define	NUM_BUFFERS	2
#define	BUF_SIZE	8192
#define	SECONDS		10000.0

static SNDSoundStruct *buffers[NUM_BUFFERS];
static int requestedDataSize, recordedDataSize = 0;
static int lastBufNum;

static void playit(int tag);

/*
 * Called before the sample is played
 */

static int beforePlay(SNDSoundStruct *s, int tag, int err)
{
     if (err)
	  fprintf(stderr, "beforePlay: %s\n", SNDSoundError(err));

    if (fread((void*)((char*)s + s->dataLocation), 1, s->dataSize, stdin) !=
	s->dataSize)
	fprintf(stderr, "playDone: could not read data to soundfile\n");
}

static int playDone(SNDSoundStruct *s, int tag, int err)
/*
 * Called when a buffer has been played.
 */
{
    playit((lastBufNum + 1) % NUM_BUFFERS);
    return 0;
}

static void playit(int bufNum)
/*
 * Initiates playing into a buffers[bufNum].
 */
{
    int err;
    static int tag = 1;
    
    lastBufNum = bufNum;
    if (err = SNDStartPlaying(buffers[bufNum], tag++, 0, 0, beforePlay,
				playDone))
        fprintf(stderr, "record: %s\n", SNDSoundError(err));
}


/*
 * Allocate n sound buffers.
 */
static void init(int n, int size)
{
    int i, err;
    SNDSoundStruct s;

    for (i = 0; i < n; i++)
        if (err = SNDAlloc(&buffers[i], size, SND_FORMAT_MULAW_8,
			   SND_RATE_CODEC, 1, 4))
	    fprintf(stderr, "init: %s\n", SNDSoundError(err));
}

static void startup(void)
/*
 * Read the soundfile header.
 */
{
    SNDSoundStruct s;

    s.magic = SND_MAGIC;
    s.dataLocation = sizeof(SNDSoundStruct);
    s.dataSize = recordedDataSize;
    s.dataFormat = SND_FORMAT_MULAW_8;
    s.samplingRate = SND_RATE_CODEC;
    s.channelCount = 1;

    if (fread((void *)&s, sizeof(SNDSoundStruct), 1, stdin) != 1)
	fprintf(stderr, "cleanup: could not read header\n");

/*    if (s.magic != SND_MAGIC)
	 fprintf(stderr, "Not a valid sound file....\n"), exit(-1);
*/
}

main(int argc, char *argv[])
{
    int i;

    requestedDataSize = SECONDS * SND_RATE_CODEC;
    startup();
    init(NUM_BUFFERS, BUF_SIZE);
    for (i=0; i<NUM_BUFFERS; i++)
		playit(i);
    SNDWait(0);
}


--------------------------- record.c  --------------------------------


/* derived from
 * recordchaintest.c - this test shows how to chain small recordings
 * and append them to a soundfile.
 *
 * Hacked by Paul Lindner <lindner@boombox.micro.umn.edu> to output
 * sound to a pipe instead of a file.  
 */ 
#import	<stdio.h>
#import	<sound/sound.h>

#define	NUM_BUFFERS	2
#define	BUF_SIZE	8192
#define	SECONDS		10000.0

static SNDSoundStruct *buffers[NUM_BUFFERS];
static FILE *sfp;
static int requestedDataSize, recordedDataSize = 0;
static int lastBufNum;

static void record(int tag);

static int recordDone(SNDSoundStruct *s, int tag, int err)
/*
 * Called when a buffer has been recorded.
 * Appends the buffer to the soundfile and initiates recording into it again.
 */
{
    if (recordedDataSize >= requestedDataSize)
	return 0;
    if (err)
        fprintf(stderr, "recordDone: %s\n", SNDSoundError(err));
    if (fwrite((void*)((char*)s + s->dataLocation), 1, s->dataSize, stdout) !=
	s->dataSize)
	fprintf(stderr, "recordDone: could not write data to soundfile\n");

    recordedDataSize += s->dataSize;
    record((lastBufNum + 1) % NUM_BUFFERS);
    return 0;
}

static void record(int bufNum)
/*
 * Initiates recording into a buffers[bufNum].
 */
{
    int err;
    static int tag = 1;
    
    lastBufNum = bufNum;
    if (err = SNDStartRecording(buffers[bufNum], tag++, 0, 0, SND_NULL_FUN,
				recordDone))
        fprintf(stderr, "record: %s\n", SNDSoundError(err));
}

static void init(int n, int size)
/*
 * Allocate n sound buffers.
 * Creates the soundfile.
 */
{
    int i, err;
    SNDSoundStruct s;

    for (i = 0; i < n; i++)
        if (err = SNDAlloc(&buffers[i], size, SND_FORMAT_MULAW_8,
			   SND_RATE_CODEC, 1, 4))
	    fprintf(stderr, "init: %s\n", SNDSoundError(err));
    if (fwrite((void *)&s, sizeof(SNDSoundStruct), 1, stdout) != 1)
	fprintf(stderr, "init: could not write dummy header to soundfile\n");
}

static void cleanup(void)
/*
 * Write the soundfile header.
 */
{
    SNDSoundStruct s;

    s.magic = SND_MAGIC;
    s.dataLocation = sizeof(SNDSoundStruct);
    s.dataSize = recordedDataSize;
    s.dataFormat = SND_FORMAT_MULAW_8;
    s.samplingRate = SND_RATE_CODEC;
    s.channelCount = 1;

    if (fwrite((void *)&s, sizeof(SNDSoundStruct), 1, stdout) != 1)
	fprintf(stderr, "cleanup: could not write header to soundfile\n");
}

main(int argc, char *argv[])
{
    int i;

    requestedDataSize = SECONDS * SND_RATE_CODEC;
    cleanup();
    init(NUM_BUFFERS, BUF_SIZE);
    for (i=0; i<NUM_BUFFERS; i++)
		record(i);
    SNDWait(0);
}




-- 
 |Paul Lindner   |lindner@boombox.micro.umn.edu  |"You have to spit 
 |University of  |U of Minn. ACM President       | to see the shine..." 
 |Minnesota MWNC |I.T. Sun/HP Sysadmin           | -- Babes in Toyland
///// / / /     /////// / / / /  /  /  /        //// / / / /  /  /  /   /

garton@cunixa.cc.columbia.edu (Bradford Garton) (05/25/91)

In article <1991May25.081857.27167@cs.umn.edu> lindner@cs.umn.edu (Paul Lindner) writes:
>
>I also have digitized some of my favorite tunes to Optical Disk.

Ack!  Ack!  Ack!  Later on in the article...

>        if (err = SNDAlloc(&buffers[i], size, SND_FORMAT_MULAW_8,
>			   SND_RATE_CODEC, 1, 4))

Hoo boy, this is one of my "hot buttons" -- doesn't it bother you at all
that your CD recordings now sound like a phone conversation to Anchorage?
We worry sooooo much about how many gazillion colors we can display on
billions of pixels, but then workstation manufacturers get away with saying
"digital sound!" when what they mean is "sound quality similar to cheap
analog c. 1957".  Sorry, but 8-bit/8k conversion just doesn't measure up in
my book (of course, I am a teeny-tiny bit prejudiced :-).  NeXT did a truly
wonderful thing by putting 16-bit, 44.1k d-to-a convertors as standard
equipment on the cube.  Let's push for a-to-d with similar specs!  On all
workstations!  Yeah!

Of course I realize the problems with net bandwidth, disk space, etc.
supporting this amount of data -- but soon it will be trivial, right?
And when it is...


>(Though if
>ASCAP or BMI finds out,

Indeed!  The SCMS/R-DAT controversy will look pretty silly once we're able
to ftp CD-quality sounds from our favorite archive.  What will those poor
record companies do?

I don't mean to denigrate your project -- I think it's a pretty cool idea.
I just hate the thought that CODEC might become "acceptable" sound quality.

Brad Garton
Music Dept.
brad@woof.columbia.edu

lindner@cs.umn.edu (Paul Lindner) (05/26/91)

In <1991May25.161653.28563@cunixf.cc.columbia.edu> garton@cunixa.cc.columbia.edu (Bradford Garton) writes:

>In article <1991May25.081857.27167@cs.umn.edu> lindner@cs.umn.edu (Paul Lindner) writes:

>>(Though if
>>ASCAP or BMI finds out,

>Indeed!  The SCMS/R-DAT controversy will look pretty silly once we're able
>to ftp CD-quality sounds from our favorite archive.  What will those poor
>record companies do?

>I don't mean to denigrate your project -- I think it's a pretty cool idea.
>I just hate the thought that CODEC might become "acceptable" sound quality.

I agree, MULAW is pretty crummy.  However right now I don't have the
hardware to do the A-D for CD quality. (I'm just using the microphone
jack with a voltage divider so I can use the line out of my stereo).  

Unfortunately Sun didn't have the foresight to put some decent sound on their
machines.  Though in the future it looks like they will, considering what's
in /etc/magic on a Sun:

>12     long            1               8-bit u-law,
>12     long            2               8-bit linear PCM,
>12     long            3               16-bit linear PCM,
>12     long            4               24-bit linear PCM,
>12     long            5               32-bit linear PCM,
>12     long            6               32-bit floating point,
>12     long            7               64-bit floating point,
>20     long            1               mono,
>20     long            2               stereo,
>20     long            4               quad,
>16     long            x               %d Hz

So we're stuck with the lowest common denominator which is 8bit mulaw.


I certainly hope that the record company execs are planning for a future 
where high speed networks and dense storage media are the norm.  Right
now our regional telephone company (US West) is doing research into
Metropolitan Area Networks.  According to informal sources it's going
to be a 600 Mbps SONET, with capability to go at even higher speeds.

I can see a future where the the record companies are just another node
on the net.  You'd pay a really small fee for every time you listen to
something.  (Sortof like a jukebox, essentially.)  This still doesn't leave
out the possibility of digitizing what you receive though.  There are
going to be some hard legal questions that will have to be answered in
the future.

-- 
 |Paul Lindner   |lindner@boombox.micro.umn.edu  |"You have to spit 
 |University of  |U of Minn. ACM President       | to see the shine..." 
 |Minnesota MWNC |I.T. Sun/HP Sysadmin           | -- Babes in Toyland
///// / / /     /////// / / / /  /  /  /        //// / / / /  /  /  /   /