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 ///// / / / /////// / / / / / / / //// / / / / / / / /