#!/usr/bin/perl -w -I/usr/lib/lcaspeex use soundcard; use funkylevels; ### VALUES TO PLAY WITH ##################################################### $SOUND_DEVICE = "/dev/dsp"; # select recording format params: (see linux/soundcard.h) $ENCODING = AFMT_S16_LE; # (16-bit signed, little endian) # $ENCODING = AFMT_U8; # (8-bit unsigned universal standard) $STEREO = 0; # 0=mono, 1=stereo $RATE = 16000; # choices for speex: 8000, 16000, 32000 ############################################################################# $BYTE_RATE = 0; # to be set. $retry_count = 0; use Fcntl; use IO::Handle; STDERR->autoflush(1); sub cpack { my $location = shift; my $new = pack "L", $$location; $$location = $new; } sub cunpack { my $location = shift; my $new = unpack "L", $$location; $$location = $new; } sub opendsp { my ($encoding, $stereo, $rate) = @_; sysopen(DSP, $SOUND_DEVICE, O_RDONLY) || die "Couldn't open sound device $SOUND_DEVICE"; cpack \$encoding; cpack \$stereo; cpack \$rate; defined(ioctl(DSP, SNDCTL_DSP_SETFMT, $encoding)) || die "Couldn't set dsp format"; defined(ioctl(DSP, SNDCTL_DSP_STEREO, $stereo)) || die "Couldn't set dsp channels"; defined(ioctl(DSP, SNDCTL_DSP_SPEED, $rate)) || die "Couldn't set dsp rate"; cunpack \$encoding; cunpack \$stereo; cunpack \$rate; $BYTE_RATE = $RATE * ($STEREO+1) * $ENCODING/8; # dangerous hack (* $ENC/8) printf STDERR "Recording in %s at %d Hz with %s encoding (%d B/s)\n", ($STEREO==0)?"mono":"stereo", $RATE, ($ENCODING==AFMT_S16_LE)?"16-bit signed": ($ENCODING==AFMT_U8)?"8-bit unsigned":"unknown", $BYTE_RATE; 1; } sub closedsp { close DSP; } sub openspeex { # test for the existence of speexenc # should return 1 die "Couldn't find valid speexenc on \$PATH" if (system ("speexenc &> /dev/null")>>8 != 1); my $filename = shift; my $title = shift; $title =~ s/'/''/g; my $author = shift; $author =~ s/'/''/g; my $comment = shift; $comment =~ s/'/''/g; my $speexargs = ""; $speexargs .= "--title '$title' " if defined $title; $speexargs .= "--author '$author' " if defined $author; $speexargs .= "--comment '$comment' " if defined $comment; $speexargs .= "--narrowband " if $RATE==8000; $speexargs .= "--wideband " if $RATE==16000; $speexargs .= "--ultra-wideband " if $RATE==32000; $speexargs .= "--rate $RATE "; $speexargs .= "--stereo " if $STEREO==1; $speexargs .= "--le "; $speexargs .= "--lin$ENCODING "; #dangerous open(SPEEX, "| speexenc $speexargs - $filename 2>> speex.log") || die "Couldn't open $filename via speexenc for writing."; } sub closespeex { close SPEEX; } ############################################################################# use Time::Local; opendsp($ENCODING, $STEREO, $RATE); openspeex "recording.spx"; $chunksize = 128; for ($i = 0; $i < 5*$BYTE_RATE; $i+=$chunksize) { $count = sysread(DSP, $buffer, $chunksize); if (defined $count) { #print STDERR "#"; print SPEEX $buffer || die "Couldn't write to file"; addlevel $buffer; drawlevel; } else { # dont die "Error occured reading from dsp"; # just reopen the device and cross your fingers. close DSP; ($retry_count == 99) && die "Too many errors reading dsp"; print STDERR "Error reading from dsp. Retry #$count.\n"; opendsp($ENCODING, $STEREO, $RATE); $retry_count++; next; } } closedsp;