summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkraxel <kraxel>2004-12-14 16:49:34 +0000
committerkraxel <kraxel>2004-12-14 16:49:34 +0000
commitaea8c3114791bc4320b0198274d0583970722bff (patch)
tree3c8c8872a73ced521109586908bb8c6b7364bfa3
downloadrecord-aea8c3114791bc4320b0198274d0583970722bff.tar.gz
Initial revision
-rw-r--r--record.c878
1 files changed, 878 insertions, 0 deletions
diff --git a/record.c b/record.c
new file mode 100644
index 0000000..28bbda3
--- /dev/null
+++ b/record.c
@@ -0,0 +1,878 @@
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <curses.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#ifdef HAVE_SOUNDCARD_H
+# include <soundcard.h>
+#endif
+#ifdef HAVE_SYS_SOUNDCARD_H
+# include <sys/soundcard.h>
+#endif
+
+/* -------------------------------------------------------------------- */
+
+static void
+tty_raw(void)
+{
+ initscr();
+ cbreak();
+ noecho();
+ keypad(stdscr,1);
+ refresh();
+}
+
+static void
+tty_restore(void)
+{
+ endwin();
+}
+
+/* -------------------------------------------------------------------- */
+
+static int sound_fd;
+static int sound_rcount;
+static unsigned int sound_blksize;
+static int16_t *sound_buffer;
+static int maxl,maxr;
+static int secl,secr;
+static int *histl,*histr,histn,histi;
+static float peak_seconds = 1.5;
+static char *audio_dev = "/dev/dsp";
+
+static int
+sound_open(int rate)
+{
+ int frag,afmt,channels,trigger,srate;
+
+ if (-1 == (sound_fd = open(audio_dev, O_RDONLY))) {
+ fprintf(stderr,"open %s: %s\n",audio_dev,strerror(errno));
+ exit(1);
+ }
+
+ frag = 0x7fff000d; /* 8k */
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_SETFRAGMENT, &frag))
+ perror("ioctl SNDCTL_DSP_SETFRAGMENT");
+
+ /* format */
+ afmt = AFMT_S16_LE;
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_SETFMT, &afmt)) {
+ perror("ioctl SNDCTL_DSP_SETFMT");
+ exit(1);
+ }
+ if (afmt != AFMT_S16_LE) {
+ fprintf(stderr,"can't set sound format to 16 bit (le)\n");
+ exit(1);
+ }
+
+ /* channels */
+ channels = 2;
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_CHANNELS, &channels)) {
+ perror("ioctl SNDCTL_DSP_CHANNELS");
+ exit(1);
+ }
+ if (channels != 2) {
+ fprintf(stderr,"can't record in stereo\n");
+ exit(1);
+ }
+
+ /* rate */
+ srate = rate;
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_SPEED, &srate)) {
+ perror("ioctl SNDCTL_DSP_SPEED");
+ exit(1);
+ }
+ /* accept +/- 1% */
+ if (srate < rate * 99 / 100 ||
+ srate > rate * 101 / 100) {
+ fprintf(stderr,"can't set sample rate to %d (got %d)\n",
+ rate,srate);
+ exit(1);
+ }
+
+ /* get block size */
+ if (-1 == ioctl(sound_fd, SNDCTL_DSP_GETBLKSIZE, &sound_blksize)) {
+ perror("ioctl SNDCTL_DSP_GETBLKSIZE");
+ exit(1);
+ }
+ if (0 == sound_blksize)
+ sound_blksize = 4096;
+ sound_buffer = malloc(sound_blksize);
+
+ /* peak level history */
+ histn = peak_seconds * rate * 4 / sound_blksize;
+ histl = malloc(histn * sizeof(int));
+ histr = malloc(histn * sizeof(int));
+ memset(histl,0,histn * sizeof(int));
+ memset(histr,0,histn * sizeof(int));
+
+ /* trigger record */
+ trigger = ~PCM_ENABLE_INPUT;
+ ioctl(sound_fd,SNDCTL_DSP_SETTRIGGER,&trigger);
+ trigger = PCM_ENABLE_INPUT;
+ ioctl(sound_fd,SNDCTL_DSP_SETTRIGGER,&trigger);
+
+ return sound_fd;
+}
+
+static int
+sound_read(void)
+{
+ unsigned int have;
+ int i,rc;
+ int16_t *v;
+
+ /* read */
+ for (have = 0;have < sound_blksize;) {
+ rc = read(sound_fd,sound_buffer+have,sound_blksize-have);
+ switch (rc) {
+ case -1:
+ if (EINTR != errno) {
+ perror("read sound");
+ exit(1);
+ }
+ break;
+ case 0:
+ fprintf(stderr,"Huh? got 0 bytes from sound device?\n");
+ exit(1);
+ default:
+ have += rc;
+
+ }
+ }
+
+ /* look for peaks */
+ maxl = 0;
+ maxr = 0;
+ for (i = sound_blksize>>2, v=sound_buffer; i > 0; i--) {
+ if (abs(*v) > maxl)
+ maxl = abs(*v);
+ v++;
+ if (abs(*v) > maxr)
+ maxr = abs(*v);
+ v++;
+ }
+
+ /* max for the last second */
+ histl[histi] = maxl;
+ histr[histi] = maxr;
+ histi++;
+ if (histn == histi)
+ histi = 0;
+
+ for (secl = 0, secr = 0, i = 0; i < histn; i++) {
+ if (secl < histl[i])
+ secl = histl[i];
+ if (secr < histr[i])
+ secr = histr[i];
+ }
+ sound_rcount++;
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
+
+char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
+char *config_names[SOUND_MIXER_NRDEVICES][4];
+
+static int mix;
+static int dev = -1;
+static int volume;
+static char *mixer_dev = "/dev/mixer";
+
+static int
+mixer_open(char *filename, char *device)
+{
+ int i, devmask;
+
+ if (-1 == (mix = open(filename,O_RDONLY))) {
+ fprintf(stderr,"open %s: %s\n",filename,strerror(errno));
+ exit(1);
+ }
+ if (-1 == ioctl(mix,MIXER_READ(SOUND_MIXER_DEVMASK),&devmask)) {
+ perror("mixer read devmask");
+ exit(1);
+ }
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+ if ((1<<i) & devmask && strcasecmp(names[i],device) == 0) {
+ if (-1 == ioctl(mix,MIXER_READ(i),&volume)) {
+ perror("mixer read volume");
+ exit(1);
+ } else {
+ dev = i;
+ }
+ }
+ }
+ if (-1 == dev) {
+ fprintf(stderr,"mixer: havn't found device '%s'\nmixer: available: ",device);
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if ((1<<i) & devmask)
+ fprintf(stderr," '%s'",names[i]);
+ fprintf(stderr,"\n");
+ exit(1);
+ }
+ return (-1 != dev) ? 0 : -1;
+}
+
+static void
+mixer_close(void)
+{
+ close(mix);
+ dev = -1;
+}
+
+static int
+mixer_get_volume(void)
+{
+ return (-1 == dev) ? -1 : (volume & 0x7f);
+}
+
+static int
+mixer_set_volume(int val)
+{
+ if (-1 == dev)
+ return -1;
+ val &= 0x7f;
+ volume = val | (val << 8);;
+ if (-1 == ioctl(mix,MIXER_WRITE(dev),&volume)) {
+ perror("mixer write volume");
+ return -1;
+ }
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* *.wav I/O stolen from cdda2wav */
+
+/* Copyright (C) by Heiko Eissfeldt */
+
+typedef uint8_t BYTE;
+typedef uint16_t WORD;
+typedef uint32_t DWORD;
+typedef uint32_t FOURCC; /* a four character code */
+
+/* flags for 'wFormatTag' field of WAVEFORMAT */
+#define WAVE_FORMAT_PCM 1
+
+/* MMIO macros */
+#define mmioFOURCC(ch0, ch1, ch2, ch3) \
+ ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
+ ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
+
+#define FOURCC_RIFF mmioFOURCC ('R', 'I', 'F', 'F')
+#define FOURCC_LIST mmioFOURCC ('L', 'I', 'S', 'T')
+#define FOURCC_WAVE mmioFOURCC ('W', 'A', 'V', 'E')
+#define FOURCC_FMT mmioFOURCC ('f', 'm', 't', ' ')
+#define FOURCC_DATA mmioFOURCC ('d', 'a', 't', 'a')
+
+typedef struct CHUNKHDR {
+ FOURCC ckid; /* chunk ID */
+ DWORD dwSize; /* chunk size */
+} CHUNKHDR;
+
+/* simplified Header for standard WAV files */
+typedef struct WAVEHDR {
+ CHUNKHDR chkRiff;
+ FOURCC fccWave;
+ CHUNKHDR chkFmt;
+ WORD wFormatTag; /* format type */
+ WORD nChannels; /* number of channels (i.e. mono, stereo, etc.) */
+ DWORD nSamplesPerSec; /* sample rate */
+ DWORD nAvgBytesPerSec; /* for buffer estimation */
+ WORD nBlockAlign; /* block size of data */
+ WORD wBitsPerSample;
+ CHUNKHDR chkData;
+} WAVEHDR;
+
+#define IS_STD_WAV_HEADER(waveHdr) ( \
+ waveHdr.chkRiff.ckid == FOURCC_RIFF && \
+ waveHdr.fccWave == FOURCC_WAVE && \
+ waveHdr.chkFmt.ckid == FOURCC_FMT && \
+ waveHdr.chkData.ckid == FOURCC_DATA && \
+ waveHdr.wFormatTag == WAVE_FORMAT_PCM)
+
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+#define le32_to_cpu(x) (x)
+#define le16_to_cpu(x) (x)
+
+/* -------------------------------------------------------------------- */
+
+static WAVEHDR fileheader;
+static size_t wav_size;
+static size_t done_size;
+
+static void
+wav_init_header(int rate)
+{
+ /* stolen from cdda2wav */
+ int nBitsPerSample = 16;
+ int channels = 2;
+
+ unsigned long nBlockAlign = channels * ((nBitsPerSample + 7) / 8);
+ unsigned long nAvgBytesPerSec = nBlockAlign * rate;
+ unsigned long temp = /* data length */ 0 +
+ sizeof(WAVEHDR) - sizeof(CHUNKHDR);
+
+ fileheader.chkRiff.ckid = cpu_to_le32(FOURCC_RIFF);
+ fileheader.fccWave = cpu_to_le32(FOURCC_WAVE);
+ fileheader.chkFmt.ckid = cpu_to_le32(FOURCC_FMT);
+ fileheader.chkFmt.dwSize = cpu_to_le32(16);
+ fileheader.wFormatTag = cpu_to_le16(WAVE_FORMAT_PCM);
+ fileheader.nChannels = cpu_to_le16(channels);
+ fileheader.nSamplesPerSec = cpu_to_le32(rate);
+ fileheader.nAvgBytesPerSec = cpu_to_le32(nAvgBytesPerSec);
+ fileheader.nBlockAlign = cpu_to_le16(nBlockAlign);
+ fileheader.wBitsPerSample = cpu_to_le16(nBitsPerSample);
+ fileheader.chkData.ckid = cpu_to_le32(FOURCC_DATA);
+ fileheader.chkRiff.dwSize = cpu_to_le32(temp);
+ fileheader.chkData.dwSize = cpu_to_le32(0 /* data length */);
+}
+
+static void
+wav_start_write(int fd,int rate)
+{
+ wav_init_header(rate);
+ lseek(fd,0,SEEK_SET);
+ write(fd,&fileheader,sizeof(WAVEHDR));
+ wav_size = 0;
+}
+
+static int
+wav_write_audio(int fd, void *data, int len)
+{
+ int rc;
+
+ rc = write(fd,data,len);
+ if (len == rc) {
+ wav_size += len;
+ return 0;
+ } else
+ return -1;
+}
+
+static void
+wav_stop_write(int fd)
+{
+ unsigned long temp = wav_size + sizeof(WAVEHDR) - sizeof(CHUNKHDR);
+
+ fileheader.chkRiff.dwSize = cpu_to_le32(temp);
+ fileheader.chkData.dwSize = cpu_to_le32(wav_size);
+ lseek(fd,0,SEEK_SET);
+ write(fd,&fileheader,sizeof(WAVEHDR));
+ done_size += wav_size;
+}
+
+/* -------------------------------------------------------------------- */
+
+static char full[] =
+"##################################################"
+"##################################################"
+"##################################################"
+"##################################################";
+
+static char empty[] =
+"--------------------------------------------------"
+"--------------------------------------------------"
+"--------------------------------------------------"
+"--------------------------------------------------";
+
+static char blank[] =
+" "
+" "
+" "
+" ";
+
+static char alive[] = "-\\|/";
+//static char alive[] = ".oOo";
+#define ALIVE(count) alive[count % (sizeof(alive)/sizeof(alive[0])-1)]
+
+static void
+print_bar(int line, char *name, int val1, int val2, int max)
+{
+ int total,len;
+
+ total = COLS-16;
+ len = val1*total/max;
+
+ mvprintw(line,0,"%-6s: %5d ",name,(val2 != -1) ? val2 : val1);
+ printw("%*.*s",len,len,full);
+ printw("%*.*s",total-len,total-len,empty);
+ if (val2 != -1)
+ mvprintw(line,14+val2*total/max,"|");
+}
+
+/* -------------------------------------------------------------------- */
+
+enum MODE {
+ NCURSES = 1,
+ CONSOLE = 2,
+};
+enum MODE mode = NCURSES;
+int stop,verbose;
+char *filename = "record";
+int rate = 44100;
+
+size_t tracksplits[100];
+size_t tracks;
+
+static void
+ctrlc(int signal)
+{
+ if (verbose)
+ fprintf(stderr,"\n%s - exiting\n",
+ sys_siglist[signal]);
+ stop = 1;
+}
+
+static int
+write_toc(char *wavfile, char *tocfile)
+{
+ FILE *fp;
+ int i,fs,ff,fl;
+
+ fp = fopen(tocfile,"w");
+ if (NULL == fp)
+ return -1;
+
+ fprintf(fp,
+ "// written by record -- (c) Gerd Knorr <kraxel@bytesex.org>\n"
+ "// use gcdmaster to edit\n"
+ "// use cdrdao to burn\n"
+ "\n"
+ "CD_DA\n"
+ "\n");
+ for (fs = 0, i = 0; i < tracks; fs = ff, i++) {
+ ff = tracksplits[i] / 2352;
+ fl = ff - fs;
+ fprintf(fp,
+ "TRACK AUDIO\n"
+ "AUDIOFILE \"%s\" %d:%02d:%02d %d:%02d:%02d\n"
+ "\n", wavfile,
+ fs/(75*60), (fs/75)%60, fs%75,
+ fl/(75*60), (fl/75)%60, fl%75);
+ }
+ fclose(fp);
+ return 0;
+}
+
+static int
+record_start(char *wavfile, char *tocfile, int *nr)
+{
+ int wav;
+
+ do {
+ sprintf(wavfile,"%s%03d.wav",filename,(*nr));
+ sprintf(tocfile,"%s%03d.toc",filename,(*nr));
+ (*nr)++;
+ wav = open(wavfile, O_WRONLY | O_EXCL | O_CREAT, 0666);
+ } while ((-1 == wav) && (EEXIST == errno));
+ if (-1 == wav) {
+ perror("open");
+ exit(1);
+ }
+ wav_start_write(wav,rate);
+ memset(tracksplits,0,sizeof(tracksplits));
+ tracks = 0;
+ return wav;
+}
+
+static void
+record_stop(int wav, char *wavfile, char *tocfile)
+{
+ if (tracks) {
+ tracksplits[tracks++] = wav_size;
+ write_toc(wavfile,tocfile);
+ }
+ wav_stop_write(wav);
+ close(wav);
+ switch (mode) {
+ case CONSOLE:
+ if (verbose)
+ printf("\n");
+ break;
+ case NCURSES:
+ mvprintw(3,0,"%*.*s",COLS-1,COLS-1,blank);
+ break;
+ }
+}
+
+static size_t
+parse_size(const char *arg)
+{
+ int value;
+ char mul[4];
+ off_t retval = -1;
+
+ if (2 != sscanf(arg,"%d%3s",&value,mul))
+ return 0;
+ if (0 == strcasecmp(mul,"g") ||
+ 0 == strcasecmp(mul,"gb"))
+ retval = (off_t)value * 1024 * 1024 * 1024;
+ if (0 == strcasecmp(mul,"m") ||
+ 0 == strcasecmp(mul,"mb"))
+ retval = (off_t)value * 1024 * 1024;
+ if (0 == strcasecmp(mul,"k") ||
+ 0 == strcasecmp(mul,"kb"))
+ retval = (off_t)value * 1024;
+ return retval;
+}
+
+static char*
+str_mb(off_t value)
+{
+ static char buf[32];
+
+ if (value > (1 << 30)) {
+ value = (value * 10) >> 30;
+ sprintf(buf,"%d.%d GB",(int)(value/10),(int)(value%10));
+ return buf;
+ }
+ if (value > (1 << 20)) {
+ value = (value * 10) >> 20;
+ sprintf(buf,"%d.%d MB",(int)(value/10),(int)(value%10));
+ return buf;
+ }
+ value >>= 10;
+ sprintf(buf,"%3d kB",(int)value);
+ return buf;
+}
+
+/* -------------------------------------------------------------------- */
+
+char *progname;
+char *input = "line";
+char *str_maxsize = "2GB";
+int level_trigger;
+
+static void
+usage(FILE *fp)
+{
+ fprintf(fp,
+ "\n"
+ "%s records sound in CD-Quality (44100/16bit/stereo).\n"
+ "It has a nice ascii-art input-level meter. It is a\n"
+ "interactive curses application. You'll need a fast\n"
+ "terminal, don't try this on a 9600 bps vt100...\n"
+ "\n"
+ "%s has several options:\n"
+ " -h this text\n"
+ " -o file output file basename [%s], a number and the .wav\n"
+ " extension are added by %s.\n"
+ " -i ctrl mixer control [%s]. This should be the one\n"
+ " where you can adjust the record level for\n"
+ " your audio source, \"line\", \"mic\" and \"igain\"\n"
+ " are good candidates.\n"
+ " -m dev set mixer device [%s]\n"
+ " -d dev set dsp device [%s]\n"
+ " -r rate set sample rate [%d]\n"
+ " -p sec peak seconds [%.1f]\n"
+ "\n"
+ "for non-interactive usage only:\n"
+ " -c enable console (non-interactive) mode\n"
+ " -v be verbose (show progress)\n"
+ " -t mm:ss limit the time to record. By default it records\n"
+ " until stopped by a signal (^C)\n"
+ " -s size set max file size [%s]. You have to give number\n"
+ " and unit without space inbetween, i.e. \"100mb\".\n"
+ " -n num limit amount of files recorded, quits when\n"
+ " reached.\n"
+ " -l signal level triggered recording.\n"
+ " -L level same as above + specify trigger level [%d]\n"
+ "\n",
+ progname,progname,filename,progname,
+ input,mixer_dev,audio_dev,
+ rate,peak_seconds,str_maxsize,
+ level_trigger ? level_trigger : 1000);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c,key,vol,delay,auto_adjust;
+ int record,nr,wav=0;
+ char *wavfile;
+ char *tocfile;
+ fd_set s;
+ int sec,maxhour,maxmin,maxsec;
+ int maxfiles = 0;
+ size_t maxsize;
+
+ /* init some vars */
+ progname = strrchr(argv[0],'/');
+ progname = progname ? progname+1 : argv[0];
+ maxsec = 0;
+ delay = 0;
+ auto_adjust = 1;
+ record = 0;
+ nr = 0;
+
+ /* parse options */
+ for (;;) {
+ if (-1 == (c = getopt(argc, argv, "vhlci:o:d:m:r:t:s:L:p:n:")))
+ break;
+ switch (c) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'l':
+ level_trigger = 1000;
+ break;
+ case 'L':
+ level_trigger = atoi(optarg);
+ break;
+ case 'i':
+ input = optarg;
+ break;
+ case 'o':
+ filename = optarg;
+ break;
+ case 'd':
+ audio_dev = optarg;
+ break;
+ case 'm':
+ mixer_dev = optarg;
+ break;
+ case 'c':
+ mode = CONSOLE;
+ break;
+ case 'r':
+ rate = atoi(optarg);
+ break;
+ case 'p':
+ peak_seconds = atof(optarg);
+ break;
+ case 't':
+ if (3 != sscanf(optarg,"%d:%d:%d",&maxhour,&maxmin,&maxsec)) {
+ maxhour = 0;
+ if (2 != sscanf(optarg,"%d:%d",&maxmin,&maxsec)) {
+ fprintf(stderr,"time parse error\n");
+ exit(1);
+ }
+ }
+ maxsec += maxmin * 60;
+ maxsec += maxhour * 60 * 60;
+ break;
+ case 's':
+ str_maxsize = optarg;
+ break;
+ case 'n':
+ maxfiles = atoi(optarg);
+ break;
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+ maxsize = parse_size(str_maxsize);
+ if (0 == maxsize) {
+ fprintf(stderr,"maxsize parse error [%s]\n",str_maxsize);
+ exit(1);
+ }
+
+ mixer_open(mixer_dev,input);
+ sound_open(rate);
+ wavfile = malloc(strlen(filename)+16);
+ tocfile = malloc(strlen(filename)+16);
+
+ if (mode == NCURSES) {
+ tty_raw();
+ atexit(tty_restore);
+ }
+
+ signal(SIGINT,ctrlc);
+ signal(SIGQUIT,ctrlc);
+ signal(SIGTERM,ctrlc);
+ signal(SIGHUP,ctrlc);
+
+ if (mode == NCURSES) {
+ mvprintw( 5,0,"record to %s*.wav",filename);
+ mvprintw( 7,0,"left/right adjust mixer level for \"%s\"",input);
+ mvprintw( 8,0,"space starts/stops recording");
+ /* line 9 is printed later */
+ mvprintw(10,0," auto-adjust reduces the record level on overruns");
+ mvprintw(11,0,"'N' next file (same as space twice, but without break)");
+ mvprintw(12,0,"'T' tracksplit (writes toc file)");
+ mvprintw(13,0,"'Q' quit");
+ mvprintw(LINES-3,0,"--");
+ mvprintw(LINES-2,0,"(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>");
+
+ for (;!stop;) {
+ refresh();
+ FD_ZERO(&s);
+ FD_SET(0,&s);
+ FD_SET(sound_fd,&s);
+ if (-1 == select(sound_fd+1,&s,NULL,NULL,NULL)) {
+ if (EINTR == errno)
+ continue;
+ perror("select");
+ break;
+ }
+
+ if (FD_ISSET(sound_fd,&s)) {
+ /* sound */
+ if (-1 == sound_read())
+ break;
+ if (delay)
+ delay--;
+ if (auto_adjust && (0 == delay) &&
+ (maxl >= 32767 || maxr >= 32767)) {
+ /* auto-adjust */
+ vol = mixer_get_volume();
+ vol--;
+ if (vol < 0)
+ vol = 0;
+ mixer_set_volume(vol);
+ delay = 3;
+ }
+ print_bar(0,input,mixer_get_volume(),-1,100);
+ print_bar(1,"left",maxl,secl,32768);
+ print_bar(2,"right",maxr,secr,32768);
+ mvprintw(9,0,"'A' toggle auto-adjust [%s] ",
+ auto_adjust ? "on" : "off");
+ if (record) {
+ wav_write_audio(wav,sound_buffer,sound_blksize);
+ sec = wav_size / (rate*4);
+ mvprintw(3,0,"%s: %3d:%02d (%s) ",wavfile,
+ sec/60,sec%60,str_mb(wav_size));
+ if (tracks) {
+ int f = tracksplits[tracks-1] / 2352;
+ printw(" | %d @ %d:%02d:%02d ",
+ tracks, f/(75*60), (f/75)%60, f%75);
+ }
+ } else {
+ mvprintw(3,0,"%c",ALIVE(sound_rcount));
+ }
+ }
+
+ if (FD_ISSET(0,&s)) {
+ /* tty in */
+ switch (key = getch()) {
+ case 'Q':
+ case 'q':
+ stop = 1;
+ break;
+ case 'A':
+ case 'a':
+ auto_adjust = !auto_adjust;
+ break;
+ case 'N':
+ case 'n':
+ if (record) {
+ record_stop(wav,wavfile,tocfile);
+ wav = record_start(wavfile,tocfile,&nr);
+ }
+ break;
+ case 'T':
+ case 't':
+ if (record && tracks < 98)
+ tracksplits[tracks++] = wav_size;
+ break;
+ case ' ':
+ if (!filename)
+ break;
+ if (!record) {
+ /* start */
+ wav = record_start(wavfile,tocfile,&nr);
+ record=1;
+ auto_adjust=0;
+ } else {
+ /* stop */
+ record_stop(wav,wavfile,tocfile);
+ record=0;
+ }
+ break;
+ case KEY_RIGHT:
+ vol = mixer_get_volume();
+ vol++;
+ if (vol > 100)
+ vol = 100;
+ mixer_set_volume(vol);
+ break;
+ case KEY_LEFT:
+ vol = mixer_get_volume();
+ vol--;
+ if (vol < 0)
+ vol = 0;
+ mixer_set_volume(vol);
+ break;
+ }
+ }
+ }
+ }
+
+ if (mode == CONSOLE) {
+ if (!level_trigger) {
+ wav = record_start(wavfile,tocfile,&nr);
+ record=1;
+ }
+
+ for (;!stop;) {
+ if (-1 == sound_read())
+ break;
+ if (level_trigger) {
+ if (!record &&
+ (maxl > level_trigger ||
+ maxr > level_trigger)) {
+ wav = record_start(wavfile,tocfile,&nr);
+ record=1;
+ }
+ if (record &&
+ secl < level_trigger &&
+ secr < level_trigger) {
+ record_stop(wav,wavfile,tocfile);
+ record=0;
+ if (maxfiles && nr == maxfiles)
+ break;
+ }
+ }
+ if (!record) {
+ printf("waiting for signal %c [%d/%d]... \r",
+ ALIVE(sound_rcount), maxl,maxr);
+ fflush(stdout);
+ continue;
+ }
+
+ sec = (done_size + wav_size) / (rate*4);
+ if (maxsec && sec >= maxsec)
+ break;
+ if (wav_size + sound_blksize + sizeof(WAVEHDR) > maxsize) {
+ record_stop(wav,wavfile,tocfile);
+ wav = record_start(wavfile,tocfile,&nr);
+ }
+ wav_write_audio(wav,sound_buffer,sound_blksize);
+ if (verbose) {
+ int total = 10;
+ int len = (maxl+maxr)*total/32768/2;
+ printf("|%*.*s%*.*s| %s %d:%02d",
+ len,len,full, total-len,total-len,empty,
+ wavfile,sec/60,sec%60);
+ if (maxsec)
+ printf("/%d:%02d",maxsec/60,maxsec%60);
+ printf(" (%s",str_mb(wav_size));
+ if (done_size)
+ printf(", %s total",str_mb(done_size + wav_size));
+ printf(") \r");
+ fflush(stdout);
+ }
+ }
+ }
+
+ if (record)
+ record_stop(wav,wavfile,tocfile);
+ mixer_close();
+ exit(0);
+}