diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
commit | 1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch) | |
tree | 4495d23e7b54ab5700e3839081e797c1eafe0db9 /tutorials/sndkit/dsp/recplay.c | |
download | oss4-1058def8e7827e56ce4a70afb4aeacb5dc44148f.tar.gz |
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'tutorials/sndkit/dsp/recplay.c')
-rw-r--r-- | tutorials/sndkit/dsp/recplay.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/tutorials/sndkit/dsp/recplay.c b/tutorials/sndkit/dsp/recplay.c new file mode 100644 index 0000000..62fdcf0 --- /dev/null +++ b/tutorials/sndkit/dsp/recplay.c @@ -0,0 +1,401 @@ +/* + * recplay.c + * + * A simple recording and playback program for OSS 4.0 + * or later. + * + * Copyright by Hannu Savolainen 1993-2004 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +/* #include <getopt.h> */ +#include <fcntl.h> +#include <string.h> +#include <soundcard.h> + +#define DEFAULT_DSP_SPEED 8000 + +#define RECORD 0 +#define PLAY 1 +#define AUDIO "/dev/dsp" + +int prof = APF_NORMAL; +int timelimit = 0, dsp_speed = DEFAULT_DSP_SPEED, dsp_channels = 1; +int samplefmt = AFMT_S16_LE; +int quiet_mode = 0; +int audio, abuf_size; +int direction, omode; +int blksize = 0; +int fragsize = 0; +char *audiobuf, c; + +char audio_name[64] = AUDIO; + +void recplay (char *name); +extern void describe_error (void); + +typedef struct +{ + char *name; + int fmt; + int bits; +} sample_fmt_t; + +static const sample_fmt_t formats[] = { + {"AFMT_MU_LAW", AFMT_MU_LAW}, + {"AFMT_A_LAW", AFMT_A_LAW}, + {"AFMT_IMA_ADPCM", AFMT_IMA_ADPCM}, + {"AFMT_U8", AFMT_U8, 8}, + {"AFMT_S16_LE", AFMT_S16_LE, 16}, + {"AFMT_S16_BE", AFMT_S16_BE, 16}, + {"AFMT_S8", AFMT_S8, 8}, + {"AFMT_U16_LE", AFMT_U16_LE, 16}, + {"AFMT_U16_BE", AFMT_U16_BE, 16}, + {"AFMT_MPEG", AFMT_MPEG}, + {"AFMT_AC3", AFMT_AC3}, + {"AFMT_VORBIS", AFMT_VORBIS}, + {"AFMT_S32_LE", AFMT_S32_LE, 32}, + {"AFMT_S32_BE", AFMT_S32_BE, 32}, + {"AFMT_FLOAT", AFMT_FLOAT}, + {"AFMT_S24_LE", AFMT_S24_LE, 24}, + {"AFMT_S24_BE", AFMT_S24_BE, 24}, + {"AFMT_SPDIF_RAW", AFMT_SPDIF_RAW}, + {"AFMT_S24_PACKED", AFMT_S24_PACKED, 24}, + {NULL, 0} +}; + +static int +set_samplefmt (char *fmt) +{ + int i; + + for (i = 0; formats[i].name != NULL; i++) + if (strcmp (formats[i].name, fmt) == 0) + { + return formats[i].fmt; + } + + fprintf (stderr, "Error: Unrecognized sample format '%s'\n", fmt); + exit (-1); +} + +int +main (int argc, char *argv[]) +{ + + char *command; + int tmp; + int i; + + command = argv[0]; + if (strstr (argv[0], "srec")) + { + direction = RECORD; + omode = O_RDONLY; + } + else if (strstr (argv[0], "splay")) + { + direction = PLAY; + omode = O_WRONLY; + } + else + { + fprintf (stderr, + "Error: command should be named either srec or splay\n"); + exit (1); + } + + while ((c = getopt (argc, argv, "pqs:St:b:d:B:f:F:c:")) != EOF) + switch (c) + { + case 'S': /* Stereo is obsolete - use -c instead */ + dsp_channels = 2; + break; + case 'c': + dsp_channels = atoi (optarg); + break; + case 'q': + quiet_mode = 1; + break; + case 's': + dsp_speed = atoi (optarg); + if (dsp_speed < 300) + dsp_speed *= 1000; + break; + case 't': + timelimit = atoi (optarg); + break; + + case 'b': /* Bits (obsolete) supports only 8 and 16 */ + samplefmt = atoi (optarg); + break; + + case 'F': + samplefmt = set_samplefmt (optarg); + break; + + case 'B': + blksize = atoi (optarg); + break; + + case 'd': + strncpy (audio_name, optarg, sizeof (audio_name) - 1); + break; + + case 'f': + fragsize = atoi (optarg); + if (fragsize == 0) + { + fprintf (stderr, "Bad fragment size (-f %s)\n", optarg); + exit (-1); + } + fragsize |= 0x7fff0000; + break; + + case 'p': + prof = APF_CPUINTENS; + break; + + default: + fprintf (stderr, + "Usage: %s [-q] [-c channels] [-t secs] [-s Hz] [-b 8|12|16] [-d device] [filename]\n", + command); + exit (-1); + } + + + audio = open (audio_name, omode, 0); + if (audio == -1) + { + perror (audio_name); + describe_error (); + exit (-1); + } + + if (fragsize != 0) + if (ioctl (audio, SNDCTL_DSP_SETFRAGMENT, &fragsize) == -1) + { + perror ("SETFRAGMENT"); + exit (-1); + } + + tmp = samplefmt; + ioctl (audio, SNDCTL_DSP_SETFMT, &tmp); + if (tmp != samplefmt) + { + fprintf (stderr, "Unable to set the requested sample format\n"); + + for (i = 0; formats[i].fmt != 0; i++) + if (formats[i].fmt == samplefmt) + { + fprintf (stderr, "The required format is %s (%08x)\n", + formats[i].name, formats[i].fmt); + break; + } + + for (i = 0; formats[i].fmt != 0; i++) + if (formats[i].fmt == tmp) + { + fprintf (stderr, "The device supports %s (%08x)\n", + formats[i].name, formats[i].fmt); + break; + } + exit (-1); + } + + ioctl (audio, SNDCTL_DSP_PROFILE, &prof); + + if (ioctl (audio, SNDCTL_DSP_CHANNELS, &dsp_channels) == -1) + { + fprintf (stderr, "%s: Unable to set the number of channels\n", command); + perror (audio_name); + exit (-1); + } + + if (ioctl (audio, SNDCTL_DSP_SPEED, &dsp_speed) == -1) + { + fprintf (stderr, "%s: Unable to set audio speed\n", command); + perror (audio_name); + exit (-1); + } + if (!quiet_mode) + { + fprintf (stderr, "Speed %d Hz ", dsp_speed); + fprintf (stderr, "%d channels ", dsp_channels); + + for (i = 0; formats[i].fmt != 0; i++) + if (formats[i].fmt == samplefmt) + { + fprintf (stderr, "Sample format is %s", formats[i].name); + if (formats[i].bits != 0) + fprintf (stderr, "(%d bits)", formats[i].bits); + break; + } + fprintf (stderr, "\n"); + } + + if (blksize > 0) + abuf_size = blksize; + else + { +#if 0 +/* + * There is no idea in using SNDCTL_DSP_GETBLKSIZE in applications like this. + * Using some fixed local buffer size will work equally well. + */ + ioctl (audio, SNDCTL_DSP_GETBLKSIZE, &abuf_size); + if (abuf_size < 1) + { + perror ("GETBLKSIZE"); + exit (-1); + } +#else + abuf_size = 1024; +#endif + } + + if ((audiobuf = malloc (abuf_size)) == NULL) + { + fprintf (stderr, "Unable to allocate input/output buffer\n"); + exit (-1); + } + + if (optind > argc - 1) + recplay (NULL); + else + while (optind <= argc - 1) + { + recplay (argv[optind++]); + } + + close (audio); + return 0; +} + +void +recplay (char *name) +{ + int fd, l; + + int count, c; + + if (!timelimit) + count = 0x7fffffff; + else + { + count = timelimit * dsp_speed * dsp_channels; + if (samplefmt != AFMT_U8) + count *= 2; /* TODO: This is bogus because just few formats are 16 bits */ + } + + if (direction == PLAY) + { + if (!name) + { + fd = 0; + name = "stdin"; + } + else + { + if ((fd = open (name, O_RDONLY, 0)) == -1) + { + perror (name); + exit (-1); + } + } + + while (count) + { + c = count; + + if (c > abuf_size) + c = abuf_size; + + if ((l = read (fd, audiobuf, c)) > 0) + { + if (write (audio, audiobuf, l) != l) + { + perror (audio_name); + exit (-1); + } + count -= l; + } + else + { + if (l == -1) + { + perror (name); + exit (-1); + } + count = 0; /* Stop */ + } + + } /* while (count) */ + if (fd != 0) + close (fd); + } + else + { + if (!name) + { + fd = 1; + name = "stdout"; + } + else + { + if ((fd = open (name, O_WRONLY | O_CREAT, 0666)) == -1) + { + perror (name); + exit (-1); + } + } + + while (count) + { + c = count; + if (c > abuf_size) + c = abuf_size; + + if ((l = read (audio, audiobuf, c)) > 0) + { + if (write (fd, audiobuf, l) != l) + { + perror (name); + exit (-1); + } + count -= l; + } + + if (l == -1) + { + perror (audio_name); + exit (-1); + } + } /* While count */ + + if (fd != 1) + close (fd); + } +} |