diff options
Diffstat (limited to 'tutorials/sndkit/dsp')
-rw-r--r-- | tutorials/sndkit/dsp/Makefile | 31 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/Readme | 13 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/help.c | 75 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/recplay.c | 401 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/str/Makefile | 34 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/str/Readme | 142 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/str/str.c | 295 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/str/str.h | 74 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/str/strplay.c | 575 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/vplay/Makefile | 20 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/vplay/Readme | 69 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/vplay/etc.magic.vplay | 16 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/vplay/fmtheaders.h | 108 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/vplay/vplay.c | 1012 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/vplay_vxworks/Makefile | 12 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/vplay_vxworks/fmtheaders.h | 119 | ||||
-rw-r--r-- | tutorials/sndkit/dsp/vplay_vxworks/vplay_vxworks.c | 694 |
17 files changed, 3690 insertions, 0 deletions
diff --git a/tutorials/sndkit/dsp/Makefile b/tutorials/sndkit/dsp/Makefile new file mode 100644 index 0000000..1cfa1ec --- /dev/null +++ b/tutorials/sndkit/dsp/Makefile @@ -0,0 +1,31 @@ +#CC = gcc +#CFLAGS = -O6 -m486 -funroll-loops -Wall +CFLAGS = -O -I../../../include +#LD = gcc +LD = cc +#LDFLAGS = -s -N +LDFLAGS = -s + +INSTALLDIR = /usr/local/bin + +.c.o: +# $(CC) -c $(CFLAGS) -o $*.o $< + $(CC) -c $(CFLAGS) $< + +all: srec + +install: all + cp srec $(INSTALLDIR) + ln -sf $(INSTALLDIR)/srec $(INSTALLDIR)/splay + chown root $(INSTALLDIR)/splay $(INSTALLDIR)/srec + chmod 755 $(INSTALLDIR)/splay $(INSTALLDIR)/srec + cd str;make install + +srec: recplay.o help.o + $(LD) $(LDFLAGS) recplay.o help.o -o srec + +clean: + rm -f $(OBJS) *.o srec a.out core + cd str;make clean + +recplay.o: recplay.c diff --git a/tutorials/sndkit/dsp/Readme b/tutorials/sndkit/dsp/Readme new file mode 100644 index 0000000..9410464 --- /dev/null +++ b/tutorials/sndkit/dsp/Readme @@ -0,0 +1,13 @@ +srec and splay utilities (recplay.c) +==================================== + +Run "make install" to install "splay" and "srec" into /usr/local/bin. + +These programs support recording and playback of digitized +voice. There is several possible parameters to these programs. +Try "srec -h" and "splay -h" for further information. + +The vplay -program in the vplay directory is a improved version of +the recplay.c. + +NOTE! The str program has been moved to the subdirectory ./str diff --git a/tutorials/sndkit/dsp/help.c b/tutorials/sndkit/dsp/help.c new file mode 100644 index 0000000..5b0156c --- /dev/null +++ b/tutorials/sndkit/dsp/help.c @@ -0,0 +1,75 @@ +/* + * help.c + * + * Some error printing routines. + * + * Copyright by Hannu Savolainen 1993 + * + * 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 <errno.h> + +void +describe_error (void) +{ + switch (errno) + { + case ENODEV: + fprintf (stderr, "The device file was found in /dev but\n" + "OSS is not loaded. You need to load it by executing\n" + "the soundon command.\n"); + break; + + case ENXIO: + fprintf (stderr, "There are no sound devices available.\n" + "The most likely reason is that the device you have\n" + "is malfunctioning or it's not supported by OSS.\n" + "\n" + + "NOTE! It may be necessary to reboot the system after installing OSS\n" +#ifdef LICENSED_VERSION + "\n" + "If you are a licensed customer then please fill the problem report at\n" + "http://www.opensound.com/support.cgi\n" +#endif + ); + break; + + case ENOSPC: + fprintf (stderr, "Your system cannot allocate memory for the device\n" + "buffers. Reboot your machine and try again.\n"); + break; + + case ENOENT: + fprintf (stderr, "The device file is missing from /dev.\n" + "Perhaps you have not installed and started Open Sound System yet\n"); + break; + + + case EBUSY: + fprintf (stderr, "The device is busy. There is some other application\n" + "using it.\n"); + + default:; + } +} 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); + } +} diff --git a/tutorials/sndkit/dsp/str/Makefile b/tutorials/sndkit/dsp/str/Makefile new file mode 100644 index 0000000..d0fb544 --- /dev/null +++ b/tutorials/sndkit/dsp/str/Makefile @@ -0,0 +1,34 @@ +#CC = gcc +#CFLAGS = -O6 -m486 -funroll-loops -Wall +#LD = gcc +#LDFLAGS = -s -N +CC = cc +CFLAGS = -O +LD = cc +LDFLAGS = -s + +INSTALLDIR = /usr/local/bin + +OBJS = str.o strplay.o ../help.o + +.c.o: +# $(CC) -c $(CFLAGS) -o $*.o $< + $(CC) -c $(CFLAGS) $< + +all: str + +install: all + cp str $(INSTALLDIR) + chown root $(INSTALLDIR)/str + chmod 755 $(INSTALLDIR)/str + ln -f $(INSTALLDIR)/str $(INSTALLDIR)/str15 + ln -f $(INSTALLDIR)/str $(INSTALLDIR)/str32 + +str: $(OBJS) + $(LD) $(LDFLAGS) $(OBJS) -o str + +clean: + rm -f $(OBJS) str a.out core + +str.o: str.c str.h +strplay.o: strplay.c str.h diff --git a/tutorials/sndkit/dsp/str/Readme b/tutorials/sndkit/dsp/str/Readme new file mode 100644 index 0000000..1d7b28f --- /dev/null +++ b/tutorials/sndkit/dsp/str/Readme @@ -0,0 +1,142 @@ +SparcTracker ver. 1.2 by Liam Corner and Marc Espie +=================================================== + +NOTE! This is an old and obsolete version. The latest version is + called tracker-3.19. + +#ifdef linux +This version contains some minor modifications for Linux by Hannu Savolainen +(hannu@voxware.pp.fi) and Leif Kornstaedt (l_kornst@informatik.uni-kl.de). + +Have a look at the options in the Makefile (e.g. the -m486 option) and at +the str.h header file, in which you may configure some things. + +Please edit DSP_SPEED in the file str.h before compiling. The default +setting for output frequency is 23 kHz, which may be too fast for 386/386sx +machines. At least you have to change it if there happens to be short +pauses in playback. +#endif + +Well, here they are the first tracker module players for the Sun +Sparcstations. There are 2 players, one for the 15 sample modules and one for +the 32 sample ones (or should that be 31 :-). The code is not that different, +but I could not be bothered to write an auto detection routine that worked on +standard input. + + +Usage +----- + +Usage is very simple, either give the player the filename of the module, or if +the module is compressed(frozen) you can zcat(fcat) and pipe the result into +the player thus : + + str32 -h + str32 [options] module ... + zcat module.z | str32 [options] + fcat module.F | str32 [options] + +If you have a new module and are unsure of which player (str15 or str32) to +use then try both. If you choose the wrong one then you may get an error +message or nothing at all will happen (except maybe a core dump :-). For +this reason I keep my trackers in separate directories so that I know which +player to use. + +Not many effects are implemented, so the result may not be exactly the same as +an Amiga player, but it is usually OK. The sound quality of the /dev/audio is +not too hot, so some sounds are lost, usually the bass. + +Options +------- + +This version acceps several command line options: + + -s kHz Sets the playback speed. For example + str32 -s 20 plays the module with + 22 kHz sampling frequency. + -S Plays the module in stereo. + -c Non-stop mode. + -q Quiet. + -b bits Sets the sample size (8 or 16 bits). + -o file Redirects output to a file or + another device. + +Errors +------ + +The only error not totally self-explanatory is the 'corrupt input file' one. +This sometimes indicates that you have used the wrong player, but +occassionally it may be that the module is too short by a few bytes. I have +only come accross this in a couple of cases and just appending a few null +bytes to the end usually cures this. + + +The Future +---------- + +I may get around to combining the players into a single program and enhancing +the error detection a bit, but then again I might not :-). If anyone else +wants to add these functions, add more effects or correct any errors there may +be in the current programs then please go ahead - I hope the code is +understandable enough for you. + + +Copyright Stuff +--------------- + +Most of the code is copyright me. The convert routine is copyright Rich +Gopstein and was borrowed from the iff2ulaw utility. The code is freely +distributable as long as this message and the copyright messages in the source +are included. You are welcome to update the source code. + + + Liam Corner - University of Warwick - 1st November 1991 + + csubt@csv.warwick.ac.uk + zenith@dcs.warwick.ac.uk + + + +Version 1.2 - 3rd November 1991 +------------------------------- + +Thanks to Marc Espie for doing most of the first update. There is now only +one player str15 and a link from str32 to str15, so you will still have to +choose the correct player for a given module. There is now output showing +module name, sample names and progress through the module as it plays. More +effects are implemented and a bug with the sample repeat loop has been fixed. + + +Patch 08/27/92 by Hannu Savolainen +---------------------------------- + +Modified to use integer arithmetic. + + +Version 1.5 - 31st January 1993 by Leif Kornstaedt +-------------------------------------------------- + +- Now all standard NoiseTracker 1.0 effects should be implemented correctly, + as well as some bugs fixed (and the step_table calculations more accurate). + +- Some command line options have been added, namely: + + -v verbose: the score is shown while playing + -z zcat is applied to the files before playing + +- You can now give a default path to search modules when they are not found + in the current working directory. E. g. using /bin/bash do + +$ export MODPATH=/usr/local/lib/mod/tracks15:/usr/local/lib/mod/tracks32 + + +TODO: + +- automatically determine the number of instruments instead of having + str15 and str32 (by testing 'M.K.' sig) +- insert a shuffle mode: let the player play all songs in the module + path, but shuffled like a CD player does. + + +Please let me know if you find something to ameliorate. -- L. K. +l_kornst@informatik.uni-kl.de diff --git a/tutorials/sndkit/dsp/str/str.c b/tutorials/sndkit/dsp/str/str.c new file mode 100644 index 0000000..4c999ca --- /dev/null +++ b/tutorials/sndkit/dsp/str/str.c @@ -0,0 +1,295 @@ +/************************************************************************/ +/* */ +/* str.c - plays sound-/noisetracker files on a SparcStation */ +/* */ +/* Authors: */ +/* Liam Corner - zenith@dcs.warwick.ac.uk */ +/* Marc Espie - espie@dmi.ens.fr */ +/* Minor modificatios for Linux by */ +/* Hannu Savolainen - hannu@voxware.pp.fi */ +/* Command-line switches added by */ +/* Muhammad Saggaf - alsaggaf@erl.mit.edu */ +/* Leif Kornstaedt - l_kornst@informatik.uni-kl.de */ +/* Relaxed program name checking */ +/* Craig Metz - cmetz@thor.tjhsst.edu */ +/* Stereo and 16 bit support by */ +/* Hannu */ +/* Some effects and minor bugfixes/ameliorations by */ +/* Leif Kornstaedt - l_kornst@informatik.uni-kl.de */ +/* */ +/* Version: 1.20 - 3 November 1991 / 31 January 1993 */ +/* 01/31/93 effects added */ +/* by Leif Kornstaedt */ +/* 08/27/92 modified to use integer arithmetic */ +/* 08/31/92 SB Pro stereo support */ +/* by Hannu Savolainen */ +/* */ +/************************************************************************/ + +#include <stdio.h> +#include <malloc.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <sys/stat.h> + +#include <sys/soundcard.h> +#include "str.h" + +/* output file name or dsp device */ +char AUDIO[256] = AUDIONAME; + +int audio; /* file handle */ +unsigned char *audiobuf; +int abuf_size; +int abuf_ptr; + +/* for analyzing the command line: */ +char *command; /* the actual command name used (argv[0]) */ +int loop_forever = FALSE; +int quiet_mode = FALSE, verbose_mode = FALSE; +static int use_zcat = FALSE; +int mute[4] = { FALSE, FALSE, FALSE, FALSE }; +int dsp_stereo = DSP_DEFAULT_STEREO; +int dsp_samplesize = DSP_DEFAULT_SAMPLESIZE; +long dsp_speed = DEFAULT_DSP_SPEED; + +FILE *fp; + +void play_song (void); +extern void describe_error (void); /* from ../help.c */ + +void +usage (command) + char *command; +{ + fprintf (stderr, "Usage: %s [ -cqvzS1234 -b size -s kHz -o output_file ] " + "[ filename ... ]\n", command); + fprintf (stderr, "\t-c\t\tplay infinitely\n" + "\t-q\t\tquiet mode\n" + "\t-v\t\tverbose mode\n" + "\t-z\t\tuse zcat on file\n" + "\t-1234\t\tmute voices 1, 2, 3 or 4\n" + "\t-S\t\ttoggle stereo\n" + "\t-b size\t\tset sample size (8 or 16 bits)\n" + "\t-s kHz\t\tuse sampling speed kHz\n" + "\t-o file\t\tredirect output to a file\n"); + exit (EXIT_FAILURE); +} + +char * +find_file (name) + char *name; +{ + char *dirs; + struct stat statbuffer; + static char fname[256]; + + strcpy (fname, name); + if (stat (fname, &statbuffer) != -1 && errno != ENOENT) + return fname; + else + { + dirs = getenv ("MODPATH"); + while (dirs != NULL && strlen (dirs)) + { + if (strchr (dirs, ':') != NULL) + { + strncpy (fname, dirs, strchr (dirs, ':') - dirs); + fname[strchr (dirs, ':') - dirs] = '\0'; + } + else + strcpy (fname, dirs); + if (fname[strlen (fname) - 1] != '/') + strcat (fname, "/"); + strcat (fname, name); + if (stat (fname, &statbuffer) != -1 && errno != ENOENT) + return fname; + if ((dirs = strchr (dirs, ':')) != NULL) + dirs++; + } + } + + return NULL; +} + +int +main (argc, argv) + int argc; + char *argv[]; +{ + int outdev, c; + struct stat statbuffer; + int opmode = O_WRONLY; /* mode for opening the output device */ + char zcat_cmd[256]; + char *currfile; + + command = argv[0]; + + while ((c = getopt (argc, argv, "cqvz1234Sb:s:o:")) != EOF) + switch (c) + { + case 'c': /* play infinitely */ + loop_forever = TRUE; + break; + case 'q': /* quiet mode */ + quiet_mode = TRUE; + break; + case 'v': /* verbose mode */ + verbose_mode = TRUE; + break; + case 'z': /* use zcat on file */ + use_zcat = TRUE; + break; + case '1': + case '2': + case '3': + case '4': + mute[c - '1'] = TRUE; + break; + case 'S': /* toggle stereo */ + dsp_stereo = !DSP_DEFAULT_STEREO; + break; + case 'b': /* sample size */ + dsp_samplesize = atoi (optarg); + break; + case 's': /* dsp speed */ + dsp_speed = atoi (optarg); + if (dsp_speed < 300) + dsp_speed *= 1000; + break; + case 'o': /* output file */ + strcpy (AUDIO, optarg); + break; + default: + usage (command); + } + + /* output to a character device (TRUE) or a file (FALSE)? */ + outdev = !stat (AUDIO, &statbuffer) && S_ISCHR (statbuffer.st_mode); + + if (!outdev) + opmode |= O_CREAT; /* file: create it */ + if ((audio = open (AUDIO, opmode, 0)) == -1) + { + perror (AUDIO); + describe_error (); + exit (EXIT_FAILURE); + } + + + if (outdev) + { /* set dsp parameters */ + if (ioctl (audio, SNDCTL_DSP_SETFMT, &dsp_samplesize) == -1) + dsp_samplesize = 8; + if (ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo) == -1) + dsp_stereo = FALSE; + if (ioctl (audio, SNDCTL_DSP_SPEED, &dsp_speed) == -1) + { + fprintf (stderr, "%s: unable to set playback speed\n", command); + perror (AUDIO); + exit (EXIT_FAILURE); + } + if (!quiet_mode) + printf ("Playback speed %d Hz (%s) %d bits/sample.\n", dsp_speed, + dsp_stereo ? "stereo" : "mono", dsp_samplesize); + } + + if (outdev) + { /* get the dsp buffer size */ +#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 ("audio_size"); + close (audio); + exit (EXIT_FAILURE); + } +#else + abuf_size = 1024; +#endif + } + else + { /* to a file: use block size of 1kB */ + abuf_size = 1024; + loop_forever = 0; + } + + if ((audiobuf = malloc (abuf_size)) == NULL) + { + fprintf (stderr, "%s: unable to allocate output buffer\n", command); + close (audio); + exit (EXIT_FAILURE); + } + abuf_ptr = 0; + + if (optind > argc - 1) + { + if (use_zcat) + { + if ((fp = popen (ZCAT, "rb")) == NULL) + { + fprintf (stderr, "%s: can't execute " ZCAT ".\n", command); + return (EXIT_FAILURE); + } + } + else + fp = stdin; + play_song (); + if (use_zcat) + pclose (fp); + } + else + while (optind <= argc - 1) + if ((currfile = find_file (argv[optind])) == NULL) + { + fprintf (stderr, "%s: can't find file %s - skipping.\n", + command, argv[optind]); + optind++; + } + else if (use_zcat) + { + if ((fp = popen (strcat (strcpy (zcat_cmd, ZCAT " "), + currfile), "rb")) == NULL) + { + fprintf (stderr, "%s: can't execute " ZCAT " %s.\n", + command, currfile); + exit (EXIT_FAILURE); + } + else + { + play_song (); + pclose (fp); + if (!loop_forever) + optind++; + } + } + else + { + if ((fp = fopen (currfile, "rb")) == NULL) + { + fprintf (stderr, "%s: unable to open tune file %s.\n", + command, currfile); + exit (EXIT_FAILURE); + } + else + { + play_song (); + fclose (fp); + if (!loop_forever) + optind++; + } + } + + if (abuf_ptr) + write (audio, audiobuf, abuf_ptr); + close (audio); + + return EXIT_SUCCESS; +} diff --git a/tutorials/sndkit/dsp/str/str.h b/tutorials/sndkit/dsp/str/str.h new file mode 100644 index 0000000..308d671 --- /dev/null +++ b/tutorials/sndkit/dsp/str/str.h @@ -0,0 +1,74 @@ +#define FALSE 0 +#define TRUE 1 + +/* Default device for output */ +#define AUDIONAME "/dev/dsp" + +#define ZCAT "/usr/bin/zcat" + +/* Playback frequency in Hertz: + * + * 386SX -> 8000 (or 4000) + * 386/25 -> 12000 + * 486/50 -> 23000 + */ +#define DEFAULT_DSP_SPEED 44100 + +#define DSP_DEFAULT_STEREO TRUE + +/* The default sample size can be 8 or 16 bits/sample */ +#define DSP_DEFAULT_SAMPLESIZE 8 + +typedef struct +{ /*************************************/ + char *info; /* Sample data as a series of bytes */ + unsigned int length; /* Length of sample in bytes */ + int volume; /* Default volume 0-64 (min-max) */ + unsigned int rep_start; /* Byte offset of repeat start */ + unsigned int rep_end; /* Byte offset of repeat end */ +} +Voice; /*************************************/ + +typedef struct +{ /*************************************/ + int period[64][4]; /* Period (pitch) of note */ + char sample[64][4]; /* Sample number to use */ + char effect[64][4]; /* Effect number (command) */ + unsigned char params[64][4]; /* Effect parameters */ +} +Pattern; /*************************************/ + +typedef struct +{ /*************************************/ + unsigned int pointer; /* Current position in sample */ + unsigned int step; /* Sample offset increment */ + int samp; /* Number of sample currently used */ + int pitch; /* Current pitch */ + int volume; /* Volume of current note (0-64) */ + int doarp; /* TRUE if doing arpeggio */ + int arp[3]; /* The three notes in the arpeggio */ + int doslide; /* TRUE if doing slide */ + int slide; /* Slide speed and direction */ + int doporta; /* TRUE if doing portamento */ + int pitchgoal; /* Pitch to reach */ + int portarate; /* Rate at which to approach pitch */ + int dovib; /* TRUE if doing vibrato */ + int vibspeed; /* Speed of vibrato 0-15 << 2 */ + int vibamp; /* Amplitude 0-15 */ + int viboffs; /* Current offset in sine wave */ + int doslidevol; /* TRUE if doing volume slide */ + int volslide; /* Slide speed 0-64 */ +} +Channel; /*************************************/ + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define ABUF_SIZE abuf_size + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif diff --git a/tutorials/sndkit/dsp/str/strplay.c b/tutorials/sndkit/dsp/str/strplay.c new file mode 100644 index 0000000..82a3cda --- /dev/null +++ b/tutorials/sndkit/dsp/str/strplay.c @@ -0,0 +1,575 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#ifdef __STDC__ +#include <string.h> +#else /* __STDC__ */ +#include <strings.h> +#endif /* __STDC__ */ +#include <sys/types.h> + +#include <sys/soundcard.h> +#include "str.h" + +extern int audio; +extern unsigned char *audiobuf; +extern int abuf_ptr; +extern int abuf_size; + +extern char *command; +extern int quiet_mode, verbose_mode; +extern int mute[4]; +extern int dsp_stereo; +extern int dsp_samplesize; +extern long dsp_speed; + +extern FILE *fp; + +static int VSYNC; /* number of sample bytes to output in 1/50 sec */ + +static int notes, channel, vsync, bytes, pat_num; /* loop variables */ +static int note, pat; +static int end_pattern; + +/* song data and parameters */ +static int speed; +static char songlength, songrepeat, tune[128]; +static int nvoices; +static Voice voices[32]; +static char num_patterns; +static Pattern patterns[128]; +static Channel ch[4]; + +/* table for generating pitches */ +static int step_table[1024]; + +/* sine wave table for the vibrato effect */ +static int sin_table[] = { + 0x00, 0x18, 0x31, 0x4A, 0x61, 0x78, 0x8D, 0xA1, + 0xB4, 0xC5, 0xD4, 0xE0, 0xEB, 0xF4, 0xFA, 0xFD, + 0xFF, 0xFD, 0xFA, 0xF4, 0xEB, 0xE0, 0xD4, 0xC5, + 0xB4, 0xA1, 0x8D, 0x78, 0x61, 0x4A, 0x31, 0x18 +}; + +/* period table for notes C0-B2, used for arpeggio effect */ +static int periods[] = { + 0x358, 0x328, 0x2FA, 0x2D0, 0x2A6, 0x280, + 0x25C, 0x23A, 0x21A, 0x1FC, 0x1E0, 0x1C5, + 0x1AC, 0x194, 0x17D, 0x168, 0x153, 0x140, + 0x12E, 0x11D, 0x10D, 0x0FE, 0x0F0, 0x0E2, + 0x0D6, 0x0CA, 0x0BE, 0x0B4, 0x0AA, 0x0A0, + 0x097, 0x08F, 0x087, 0x07F, 0x078, 0x071 +}; + +/* skip n bytes of file f - stdin has no fseek */ +void +byteskip (f, n) + FILE *f; + int n; +{ + while (n--) + fgetc (f); +} + +/* get string of length <len> from file f */ +char * +getstring (f, len) + FILE *f; + int len; +{ + static char s[256]; + int i; + + for (i = 0; i < len; i++) + { + if ((s[i] = fgetc (f)) == '\1') + s[i] = '\0'; /* bug fix for some few modules */ + if (s[i] < 32 && s[i]) + { + fprintf (stderr, "This is not a string. Wrong format?\n"); + exit (EXIT_FAILURE); + } + } + s[len] = '\0'; + + return s; +} + +void +audioput (c) + int c; +{ + audiobuf[abuf_ptr++] = c; + if (abuf_ptr >= ABUF_SIZE) + { +#if 0 + int count; + + if (ioctl (audio, SNDCTL_DSP_GETODELAY, &count) == -1) + perror ("GETODELAY"); + printf ("%6d\n", count); +#endif + if (write (audio, audiobuf, abuf_ptr) == -1) + { + perror ("audio_write"); + exit (EXIT_FAILURE); + } + abuf_ptr = 0; + } +} + +void +audioput16 (c) + int c; +{ + audiobuf[abuf_ptr++] = c & 0xFF; + audiobuf[abuf_ptr++] = c >> 8; + if ((abuf_ptr + 1) >= ABUF_SIZE) + { + if (write (audio, audiobuf, abuf_ptr) == -1) + { + perror ("audio_write"); + exit (EXIT_FAILURE); + } + abuf_ptr = 0; + } +} + +void +play_song () +{ + int i; + + /* set up pitch table: + * 3576872 is the base clock frequency of the Amiga's Paula chip, + * the pitch i is the number of cycles between outputting two samples. + * => i / 3576872 is the delay between two bytes + * => our_freq * i / 3576872 is our delay. + * The 65536 are just there for accuracy of integer operations (<< 16). + */ + step_table[0] = 0; + for (i = 1; i < 1024; i++) + step_table[i] = (int) (((3575872.0 / dsp_speed) / i) * 65536.0); + + /* VSYNC is the number of bytes in 1/50 sec + * computed as freq * (1 / 50). + */ + VSYNC = (dsp_speed + 25) / 50; /* with round */ + + /* read song name */ + if (quiet_mode) + byteskip (fp, 20); + else + printf ("Module : %s\n\n", getstring (fp, 20)); + + /* determine number of voices from command name */ + nvoices = strstr (command, "15") == NULL ? 31 : 15; + + /* read in the sample information tables */ + voices[0].length = 0; + for (i = 1; i <= nvoices; i++) + { + /* sample name */ + if (quiet_mode) + byteskip (fp, 22); + else if (nvoices == 15) + printf ("%6d : %s\n", i, getstring (fp, 22)); + else + { + printf ("%6d : %22s", i, getstring (fp, 22)); + if (!(i & 1)) + printf ("\n"); + } + /* the sample length and repeat data are stored as numbers of words, + * we want the number of bytes << 16. + */ + voices[i].length = (fgetc (fp) << 25) | (fgetc (fp) << 17); + fgetc (fp); + if ((voices[i].volume = fgetc (fp)) > 64) + voices[i].volume = 64; + voices[i].rep_start = (fgetc (fp) << 25) | (fgetc (fp) << 17); + voices[i].rep_end = (fgetc (fp) << 25) | (fgetc (fp) << 17); + if (voices[i].rep_end <= 4 << 16) + voices[i].rep_end = 0; + else + { + voices[i].rep_end += voices[i].rep_start; + if (voices[i].rep_end > voices[i].length) + voices[i].rep_end = voices[i].length; + } + } + + /* read sequence data: length and repeat position */ + songlength = fgetc (fp); + songrepeat = fgetc (fp); + if (songrepeat > songlength) /* this is often buggy in modules */ + songrepeat = 0; + + /* read in the sequence and determine the number of patterns + * by looking for the highest pattern number. + */ + num_patterns = 0; + for (i = 0; i < 128; i++) + { + tune[i] = fgetc (fp); + if (tune[i] > num_patterns) + num_patterns = tune[i]; + } + num_patterns++; /* pattern numbers begin at 0 */ + + /* skip over sig in new modules (usually M.K.). + * note: this sig could be used for determining whether the module + * is of an old type (15 samples max) or new (up to 31 samples) + */ + if (nvoices == 31) + byteskip (fp, 4); + + /* read in the patterns. + * Each pattern consists of 64 lines, + * each containing data for the four voices. + */ + for (pat_num = 0; pat_num < num_patterns; pat_num++) + for (notes = 0; notes < 64; notes++) + for (channel = 0; channel < 4; channel++) + { + note = (fgetc (fp) << 8) | fgetc (fp); + patterns[pat_num].sample[notes][channel] = (note >> 8) & 0x10; + patterns[pat_num].period[notes][channel] = MIN (note & 0xFFF, 1023); + note = (fgetc (fp) << 8) | fgetc (fp); + patterns[pat_num].sample[notes][channel] |= note >> 12; + patterns[pat_num].effect[notes][channel] = (note >> 8) & 0xF; + patterns[pat_num].params[notes][channel] = note & 0xFF; + } + + /* store each sample as an array of char */ + for (i = 1; i <= nvoices; i++) + if (voices[i].length) + { + if ((voices[i].info = malloc (voices[i].length >> 16)) == NULL) + { + fprintf (stderr, "%s: can't allocate memory\n", command); + exit (EXIT_FAILURE); + } + fread (voices[i].info, 1, voices[i].length >> 16, fp); + if (voices[i].rep_end) + voices[i].length = voices[i].rep_end; + voices[i].rep_start -= voices[i].length; + } + + /* initialize global and channel replay data */ + speed = 6; + for (i = 0; i < 4; i++) + { + ch[i].pointer = 0; + ch[i].step = 0; + ch[i].volume = 0; + ch[i].pitch = 0; + } + + if (!quiet_mode) + if (verbose_mode) + printf ("\n"); + else + { + printf ("\nPosition (%d):", songlength); + fflush (stdout); + } + + + /*******************************/ + /* Here begins the replay part */ + /*******************************/ + + for (pat_num = 0; pat_num < songlength; pat_num++) + { + pat = tune[pat_num]; + + if (!quiet_mode) + if (verbose_mode) + printf (" --------------+--------------+--------------+-----" + "--------- %02X (%02X) = %02X\n", pat_num, + songlength, pat); + else + { + printf ("\r\t\t%3d", pat_num); + fflush (stdout); + } + + end_pattern = FALSE; + for (notes = 0; notes < 64; notes++) + { + int samp, pitch, cmd, para; + Channel *curch; + + if (!quiet_mode && verbose_mode) + printf ("%02X ", notes); + + curch = ch; + for (channel = 0; channel < 4; channel++, curch++) + { + samp = patterns[pat].sample[notes][channel]; + pitch = patterns[pat].period[notes][channel]; + cmd = patterns[pat].effect[notes][channel]; + para = patterns[pat].params[notes][channel]; + + if (verbose_mode && !quiet_mode) + if (pitch) + printf (" %03X %2X %X%02X%s", pitch, samp, cmd, para, + channel == 3 ? "\n" : " |"); + else + printf (" --- %2X %X%02X%s", samp, cmd, para, + channel == 3 ? "\n" : " |"); + + if (mute[channel]) + { + if (cmd == 0x0B || cmd == 0x0D || cmd == 0x0F) + switch (cmd) + { + case 0xB: /* Pattern jump */ + end_pattern = TRUE; + pat_num = (para & 0xF) + (10 * (para >> 4)); + break; + case 0xD: /* Pattern break */ + end_pattern = TRUE; + break; + case 0xF: /* Set speed */ + speed = para; + break; + } + continue; + } + + /* if a sample number is given, it is loaded and the note + * is restarted + */ + if (samp) + { + curch->samp = samp; + /* load new instrument */ + curch->volume = voices[samp].volume; + } + + if (samp || (pitch && cmd != 3)) + { + if (pitch) + curch->pitch = curch->arp[0] = pitch; + curch->pointer = 0; + curch->viboffs = 0; + } + + /* by default there is no effect */ + curch->doarp = FALSE; + curch->doslide = FALSE; + curch->doporta = FALSE; + curch->dovib = FALSE; + curch->doslidevol = FALSE; + + switch (cmd) + { /* Do effects */ + case 0: /* Arpeggio */ + if (para) + { + for (i = 0; i < 36 && periods[i] > curch->arp[0]; i++); + if (i + (para >> 4) < 36 && i + (para & 0xF) < 36) + { + curch->doarp = TRUE; + curch->arp[0] = periods[i]; + curch->arp[1] = periods[i + (para >> 4)]; + curch->arp[2] = periods[i + (para & 0xF)]; + } + } + break; + case 1: /* Portamento up */ + curch->doslide = TRUE; + if (para) + curch->slide = -para; + break; + case 2: /* Portamento down */ + curch->doslide = TRUE; + if (para) + curch->slide = para; + break; + case 3: /* Note portamento */ + curch->doporta = TRUE; + if (para) + curch->portarate = para; + if (pitch) + curch->pitchgoal = pitch; + break; + case 4: /* Vibrato */ + curch->dovib = TRUE; + if (para) + { + curch->vibspeed = (para >> 2) & 0x3C; + curch->vibamp = para & 0xF; + } + break; + case 0xA: /* Volume slide */ + curch->doslidevol = TRUE; + if (para) + { + if (!(para & 0xF0)) + curch->volslide = -para; + else + curch->volslide = (para >> 4); + } + break; + case 0xB: /* Pattern jump */ + end_pattern = TRUE; + pat_num = (para & 0xF) + (10 * (para >> 4)); + break; + case 0xC: /* Set volume */ + curch->volume = MIN (para, 64); + break; + case 0xD: /* Pattern break */ + end_pattern = TRUE; + break; + case 0xF: /* Set speed */ + speed = para; + break; + default: + /* printf(" [%d][%d] ", cmd, para); */ + break; + } + } + + { + register Channel *curch; + register Voice *curv; + + for (vsync = 0; vsync < speed; vsync++) + { + + ch[0].step = step_table[ch[0].pitch]; + ch[1].step = step_table[ch[1].pitch]; + ch[2].step = step_table[ch[2].pitch]; + ch[3].step = step_table[ch[3].pitch]; + + for (bytes = 0; bytes < VSYNC; bytes++) + { + int byte[2] = { 0, 0 }; + + curch = ch; + for (channel = 0; channel < 4; channel++, curch++) + { + if (!curch->samp || mute[channel]) + continue; + + curv = &voices[(int) curch->samp]; + + /* test for end of sample */ + if (curch->pointer >= curv->length) + if (!curv->rep_end) + continue; + else + curch->pointer += curv->rep_start; + + /* mix samples. + * the sample is read and multiplied by the volume + */ + if (curch->pointer < curv->length) + /* in stereo, channels 1 & 3 and 2 & 4 are mixed + * seperately + */ + byte[channel & dsp_stereo] += (int) + ((curv->info[curch->pointer >> 16]) * + ((int) curch->volume << 2)); + /* advance the sample pointer */ + curch->pointer += curch->step; + } + + /* output sample */ + if (dsp_samplesize == 8) + { + if (dsp_stereo) + { + byte[0] >>= 9; + audioput (byte[0] + 128); + byte[1] >>= 9; + audioput (byte[1] + 128); + } + else + audioput ((byte[0] >> 10) + 128); + } + else + { + if (dsp_stereo) + { + audioput16 (byte[0] >> 1); + audioput16 (byte[1] >> 1); + } + else + audioput16 (byte[0] >> 2); + } + } + + /* Do end of vsync */ + if (vsync == 0) + continue; + curch = ch; + for (channel = 0; channel < 4; channel++, curch++) + { + if (mute[channel]) + continue; + if (curch->doarp) + curch->pitch = curch->arp[vsync % 3]; + else if (curch->doslide) + { + curch->arp[0] += curch->slide; + curch->arp[0] = MIN (curch->arp[0], 1023); + curch->arp[0] = MAX (curch->arp[0], 113); + curch->pitch = curch->arp[0]; + } + else if (curch->doporta) + { + if (curch->arp[0] < curch->pitchgoal) + { + curch->arp[0] += curch->portarate; + if (curch->arp[0] > curch->pitchgoal) + curch->arp[0] = curch->pitchgoal; + } + else if (curch->arp[0] > curch->pitchgoal) + { + curch->arp[0] -= curch->portarate; + if (curch->arp[0] < curch->pitchgoal) + curch->arp[0] = curch->pitchgoal; + } + curch->pitch = curch->arp[0]; + } + else if (curch->dovib) + { + if (curch->viboffs & 0x80) + curch->pitch = curch->arp[0] - ((sin_table + [(curch-> + viboffs >> 2) & + 0x1F] * + curch-> + vibamp) >> 6); + else + curch->pitch = curch->arp[0] + ((sin_table + [(curch-> + viboffs >> 2) & + 0x1F] * + curch-> + vibamp) >> 6); + curch->viboffs += curch->vibspeed; + } + else if (curch->doslidevol) + { + curch->volume += curch->volslide; + if (curch->volume < 0) + curch->volume = 0; + else if (curch->volume >= 64) + curch->volume = 64; + } + } + } + } + if (end_pattern == 1) + break; + } + } + + if (!quiet_mode) + printf ("\n"); +} diff --git a/tutorials/sndkit/dsp/vplay/Makefile b/tutorials/sndkit/dsp/vplay/Makefile new file mode 100644 index 0000000..17bfd1e --- /dev/null +++ b/tutorials/sndkit/dsp/vplay/Makefile @@ -0,0 +1,20 @@ +#CC=gcc +#CFLAGS=-O6 -funroll-loops -Wall +CC=cc +CFLAGS=-O -Wall + +all: vplay vrec + +vplay: vplay.c fmtheaders.h + $(CC) $(CFLAGS) vplay.c -o vplay + strip vplay + +vrec: vplay + ln -s vplay vrec +clean: + rm -f vplay vrec *.o core + +install: vplay + cp vplay /usr/local/bin + rm -f /usr/local/bin/vrec + ln -s /usr/local/bin/vplay /usr/local/bin/vrec diff --git a/tutorials/sndkit/dsp/vplay/Readme b/tutorials/sndkit/dsp/vplay/Readme new file mode 100644 index 0000000..881393d --- /dev/null +++ b/tutorials/sndkit/dsp/vplay/Readme @@ -0,0 +1,69 @@ +Digitized Audio Utility for Linux ver. 0.3 +============================================ + +This directory contains vplay.c, a modified version of recplay.c. + +vrec and vplay +-------------- + +These programs can be used for recording and playing: + CREATIVE LABS VOICE files + MICROSOFT WAVE file (old format only (new format is handled as raw data)) + NeXT sound files (similar to Sun's .au format) + raw audio data. + +Both programs accept the same options: + + vrec [-qvwrS] [-s speed] [-t seconds] -b bits [filename1 ...] + vplay [-qvwrS] [-s speed] [-t seconds] -b bits [filename1 ...] + + -S Stereo (default is mono). + -s speed Sets the speed (default is 8 kHz). If the speed is + less than 300, it will be multiplied by 1000. + -t seconds Sets the recording (or playback) time in seconds. + (Default is no time limit). + -t bits Sets sample size (bits/sample). Possible values are + 8 and 16 (default 8). + -v record a CREATIVE LABS VOICE file (default) + -w record a MICROSOFT WAVE file + -r record raw data without header + -a record a NeXT sound file + -q quiet mode + + The options for speed, time etc. take only effect if you playing + raw data files (or recording). VOC and WAVE-files include this + information in their headers/internal structure. + If no filenames are given, stdout (vrec) or stdin (vplay) is used. + The -t parameter applies to each files. For example + + vrec -r -t 1 a b c + + records one second of audio data to each of the files a, b, and c and + + vplay -t 1 a b c + + plays the first second of each of the files a, b and c (if its + raw audio). + +Don't use higher recording speeds than your card supports. This error is not +always detected by the driver. + +vplay supports: + - the full CREATIVE LABS VOICE structure: + Silence, Repeat loops (on seekable input), Stereo, ASCII blocks, + blocks with different sampling rate + - on non-stereo cards (SB 1.0 - 2.0) 8 bit stereo files will be + played as mono (the first channel is used) + - on non-16-bit cards, 16 bit WAVE files will be played as 8 bit + (you can really play on a SB 1.0 a 16 bit stereo WAVE file, or + buy ...) + +unsupported: + - packed VOC files (because /dev/dsp can't it (yet ?)) + - multi block WAVE files (if there exists like VOC files, my specs + says no but RIFF definition yes ???) + - not PCM coded WAVE files (because I don't know other methods) + - more channel WAVE files (somebody has a quadrophonic sample?) + - alaw- or mulaw-encoded NeXt sound files + +Michael Beck beck@informatik.hu-berlin.de diff --git a/tutorials/sndkit/dsp/vplay/etc.magic.vplay b/tutorials/sndkit/dsp/vplay/etc.magic.vplay new file mode 100644 index 0000000..a0c5c29 --- /dev/null +++ b/tutorials/sndkit/dsp/vplay/etc.magic.vplay @@ -0,0 +1,16 @@ +# +# Creative Labs Voice file +# +0 string Creative\ Voice\ File Creative Labs Voice File +>19 byte 0x1A +>23 byte >0 - version %d +>22 byte >0 \b.%d +# +# Microsoft WAVE format +0 string RIFF Microsoft RIFF +>8 string WAVE - WAVE format +>34 short >0 %d bit +>22 short =1 Mono +>22 short =2 Stereo +>22 short >2 %d Channels +>24 long >0 %d Hz diff --git a/tutorials/sndkit/dsp/vplay/fmtheaders.h b/tutorials/sndkit/dsp/vplay/fmtheaders.h new file mode 100644 index 0000000..9afb0cd --- /dev/null +++ b/tutorials/sndkit/dsp/vplay/fmtheaders.h @@ -0,0 +1,108 @@ +#ifndef _FMTHEADERS_H +#define _FMTHEADERS_H 1 + +#include <sys/types.h> + +/* Definitions for .VOC files */ + +#define MAGIC_STRING "Creative Voice File\x1A" +#define ACTUAL_VERSION 0x010A +#define VOC_SAMPLESIZE 8 + +#define MODE_MONO 0 +#define MODE_STEREO 1 + +#define DATALEN(bp) ((u_long)(bp->datalen) | \ + ((u_long)(bp->datalen_m) << 8) | \ + ((u_long)(bp->datalen_h) << 16) ) + +typedef struct _vocheader +{ + u_char magic[20]; /* must be MAGIC_STRING */ + u_short headerlen; /* Headerlength, should be 0x1A */ + u_short version; /* VOC-file version */ + u_short coded_ver; /* 0x1233-version */ +} +VocHeader; + +typedef struct _blocktype +{ + u_char type; + u_char datalen; /* low-byte */ + u_char datalen_m; /* medium-byte */ + u_char datalen_h; /* high-byte */ +} +BlockType; + +typedef struct _voice_data +{ + u_char tc; + u_char pack; +} +Voice_data; + +typedef struct _ext_block +{ + u_short tc; + u_char pack; + u_char mode; +} +Ext_Block; + + +/* Definitions for Microsoft WAVE format */ + +#define RIFF 0x46464952 +#define WAVE 0x45564157 +#define FMT 0x20746D66 +#define DATA 0x61746164 +#define PCM_CODE 1 +#define WAVE_MONO 1 +#define WAVE_STEREO 2 + +/* it's in chunks like .voc and AMIGA iff, but my source say there + are in only in this combination, so I combined them in one header; + it works on all WAVE-file I have +*/ +typedef struct _waveheader +{ + u_long main_chunk; /* 'RIFF' */ + u_long length; /* filelen */ + u_long chunk_type; /* 'WAVE' */ + + u_long sub_chunk; /* 'fmt ' */ + u_long sc_len; /* length of sub_chunk, =16 */ + u_short format; /* should be 1 for PCM-code */ + u_short modus; /* 1 Mono, 2 Stereo */ + u_long sample_fq; /* frequence of sample */ + u_long byte_p_sec; + u_short byte_p_spl; /* samplesize; 1 or 2 bytes */ + u_short bit_p_spl; /* 8, 12 or 16 bit */ + + u_long data_chunk; /* 'data' */ + u_long data_length; /* samplecount */ +} +WaveHeader; + +typedef struct +{ + long magic; /* must be equal to SND_MAGIC */ + long dataLocation; /* Offset or pointer to the raw data */ + long dataSize; /* Number of bytes of data in the raw data */ + long dataFormat; /* The data format code */ + long samplingRate; /* The sampling rate */ + long channelCount; /* The number of channels */ +} +SndHeader; + +#define SND_MAGIC ((long int)0x2e736e64) + +#define SND_FORMAT_UNSPECIFIED (0) +#define SND_FORMAT_MULAW_8 (1) +#define SND_FORMAT_LINEAR_8 (2) +#define SND_FORMAT_LINEAR_16 (3) +#define SND_FORMAT_LINEAR_24 (4) +#define SND_FORMAT_LINEAR_32 (5) +#define SND_FORMAT_FLOAT (6) + +#endif diff --git a/tutorials/sndkit/dsp/vplay/vplay.c b/tutorials/sndkit/dsp/vplay/vplay.c new file mode 100644 index 0000000..afbc4d3 --- /dev/null +++ b/tutorials/sndkit/dsp/vplay/vplay.c @@ -0,0 +1,1012 @@ +/* + vplay.c - plays and records + CREATIVE LABS VOICE-files, Microsoft WAVE-files and raw data + + Autor: Michael Beck - beck@informatik.hu-berlin.de +*/ + +#include <stdio.h> +#include <malloc.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/soundcard.h> +#include "fmtheaders.h" +#include <netinet/in.h> + +#define DEFAULT_DSP_SPEED 8000 + +#define RECORD 0 +#define PLAY 1 +#define AUDIO "/dev/dsp" + +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#define d_printf(x) if (verbose_mode) fprintf x + +#define VOC_FMT 0 +#define WAVE_FMT 1 +#define RAW_DATA 2 +#define SND_FMT 3 + +/* global data */ + +int timelimit = 0, dsp_speed = DEFAULT_DSP_SPEED, dsp_stereo = 0; +int samplesize = 8; +int quiet_mode = 0; +int verbose_mode = 0; +int convert = 0; +int record_type = VOC_FMT; +u_long count; +int audio, abuf_size, zbuf_size; +int direction, omode; +u_char *audiobuf, *zerobuf; +char *command; +int vocminor, vocmajor; /* .VOC version */ + +/* defaults for playing raw data */ +struct +{ + int timelimit, dsp_speed, dsp_stereo, samplesize; +} +raw_info = +{ +0, DEFAULT_DSP_SPEED, 0, 8}; + +/* needed prototypes */ + +void record_play (char *name); +void start_voc (int fd, u_long count); +void start_wave (int fd, u_long count); +void start_snd (int fd, u_long count); +void end_voc (int fd); +void end_wave_raw (int fd); +void end_snd (int fd); +u_long calc_count (); + +struct fmt_record +{ + void (*start) (int fd, u_long count); + void (*end) (int fd); + char *what; +} +fmt_rec_table[] = +{ + { + start_voc, end_voc, "VOC"} + , + { + start_wave, end_wave_raw, "WAVE"} + , + { + NULL, end_wave_raw, "raw data"} + , + { + start_snd, end_snd, "SND"} +}; + +int +main (int argc, char *argv[]) +{ + int c, n = 0; + + command = argv[0]; + if (strstr (argv[0], "vrec")) + { + direction = RECORD; + omode = O_RDONLY; + } + else if (strstr (argv[0], "vplay")) + { + direction = PLAY; + omode = O_WRONLY; + } + else + { + fprintf (stderr, + "Error: command should be named either vrec or vplay\n"); + exit (1); + } + + while ((c = getopt (argc, argv, "aqs:St:b:vrwd")) != EOF) + switch (c) + { + case 'S': + dsp_stereo = raw_info.dsp_stereo = 1; + break; + case 'q': + quiet_mode = 1; + break; + case 'r': + record_type = RAW_DATA; + break; + case 'v': + record_type = VOC_FMT; + break; + case 'w': + record_type = WAVE_FMT; + break; + case 'a': + record_type = SND_FMT; + break; + case 's': + dsp_speed = atoi (optarg); + if (dsp_speed < 300) + dsp_speed *= 1000; + raw_info.dsp_speed = dsp_speed; + break; + case 't': + timelimit = raw_info.timelimit = atoi (optarg); + break; + case 'b': + samplesize = raw_info.samplesize = atoi (optarg); + break; + case 'd': + verbose_mode = 1; + quiet_mode = 0; + break; + default: + fprintf (stderr, + "Usage: %s [-qvwraS] [-t secs] [-s Hz] [-b 8|12|16] [filename]\n", + command); + exit (-1); + } + + audio = open (AUDIO, omode, 0); + if (audio == -1) + { + perror (AUDIO); + exit (-1); + } + + if (optind > argc - 1) + record_play (NULL); + else + while (optind <= argc - 1) + { + + if (n++ > 0) + if (ioctl (audio, SNDCTL_DSP_SYNC, NULL) < 0) + { + perror (AUDIO); + exit (-1); + } + + record_play (argv[optind++]); + } + close (audio); + return 0; +} + +/* + test, if it is a .VOC file and return >=0 if ok (this is the length of rest) + < 0 if not +*/ +int +test_vocfile (void *buffer) +{ + VocHeader *vp = buffer; + if (!strcmp ((const char *) vp->magic, MAGIC_STRING)) + { + vocminor = vp->version & 0xFF; + vocmajor = vp->version / 256; + if (vp->version != (0x1233 - vp->coded_ver)) + return -2; /* coded version mismatch */ + return vp->headerlen - sizeof (VocHeader); /* 0 mostly */ + } + return -1; /* magic string fail */ +} + +/* + test, if it's a .WAV file, 0 if ok (and set the speed, stereo etc.) + < 0 if not +*/ +int +test_wavefile (void *buffer) +{ + WaveHeader *wp = buffer; + if (wp->main_chunk == RIFF && wp->chunk_type == WAVE && + wp->sub_chunk == FMT && wp->data_chunk == DATA) + { + if (wp->format != PCM_CODE) + { + fprintf (stderr, "%s: can't play not PCM-coded WAVE-files\n", + command); + exit (-1); + } + if (wp->modus > 2) + { + fprintf (stderr, "%s: can't play WAVE-files with %d tracks\n", + command, wp->modus); + exit (-1); + } + dsp_stereo = (wp->modus == WAVE_STEREO) ? 1 : 0; + samplesize = wp->bit_p_spl; + dsp_speed = wp->sample_fq; + count = wp->data_length; + return 0; + } + return -1; +} + +/* +* test, if it's a .SND file, 0 if ok (and set the speed, stereo etc.) +* < 0 if not +*/ +int +test_sndfile (void *buffer, int fd) +{ + long infolen; + char *info; + SndHeader *snd = buffer; + + if (snd->magic == SND_MAGIC) + convert = 0; + else + { + if (htonl (snd->magic) == SND_MAGIC) + { + convert = 1; + snd->dataLocation = htonl (snd->dataLocation); + snd->dataSize = htonl (snd->dataSize); + snd->dataFormat = htonl (snd->dataFormat); + snd->samplingRate = htonl (snd->samplingRate); + snd->channelCount = htonl (snd->channelCount); + } + else + { + /* No SoundFile */ + return (-1); + } + } + switch (snd->dataFormat) + { + case SND_FORMAT_LINEAR_8: + samplesize = 8; + break; + case SND_FORMAT_LINEAR_16: + samplesize = 16; + break; + default: + fprintf (stderr, "%s: Unsupported SND_FORMAT\n", command); + exit (-1); + } + + dsp_stereo = (snd->channelCount == 2) ? 1 : 0; + dsp_speed = snd->samplingRate; + count = snd->dataSize; + + /* read Info-Strings */ + infolen = snd->dataLocation - sizeof (SndHeader); + info = (char *) malloc (infolen); + read (fd, info, infolen); + if (!quiet_mode) + fprintf (stderr, "SoundFile Info: %s\n", info); + free (info); + + return 0; +} + + +/* + writing zeros from the zerobuf to simulate silence, + perhaps it's enough to use a long var instead of zerobuf ? +*/ +void +write_zeros (unsigned x) +{ + unsigned l; + + while (x) + { + l = min (x, zbuf_size); + if (write (audio, (char *) zerobuf, l) != l) + { + perror (AUDIO); + exit (-1); + } + x -= l; + } +} + +/* if need a SYNC, + (is needed if we plan to change speed, stereo ... during output) +*/ +void +sync_dsp (void) +{ +#if 0 + if (ioctl (audio, SNDCTL_DSP_SYNC, NULL) < 0) + { + perror (AUDIO); + exit (-1); + } +#endif +} + +/* setting the speed for output */ +void +set_dsp_speed (int *dsp_speed) +{ + if (ioctl (audio, SNDCTL_DSP_SPEED, dsp_speed) < 0) + { + fprintf (stderr, "%s: unable to set audio speed\n", command); + perror (AUDIO); + exit (-1); + } +} + +/* if to_mono: + compress 8 bit stereo data 2:1, needed if we want play 'one track'; + this is usefull, if you habe SB 1.0 - 2.0 (I have 1.0) and want + hear the sample (in Mono) + if to_8: + compress 16 bit to 8 by using hi-byte; wave-files use signed words, + so we need to convert it in "unsigned" sample (0x80 is now zero) + + WARNING: this procedure can't compress 16 bit stereo to 16 bit mono, + because if you have a 16 (or 12) bit card you should have + stereo (or I'm wrong ?? ) + */ +u_long +one_channel (u_char * buf, u_long l, char to_mono, char to_8) +{ + register u_char *w = buf; + register u_char *w2 = buf; + char ofs = 0; + u_long incr = 0; + u_long c, ret; + + if (to_mono) + ++incr; + if (to_8) + { + ++incr; + ++w2; + ofs = 128; + } + ret = c = l >> incr; + incr = incr << 1; + + while (c--) + { + *w++ = *w2 + ofs; + w2 += incr; + } + return ret; +} + +/* + ok, let's play a .voc file +*/ +void +vplay (int fd, int ofs, char *name) +{ + int l, real_l; + BlockType *bp; + Voice_data *vd; + Ext_Block *eb; + u_long nextblock, in_buffer; + u_char *data = audiobuf; + char was_extended = 0, output = 0; + u_short *sp, repeat = 0; + u_long silence; + int filepos = 0; + char one_chn = 0; + +#define COUNT(x) nextblock -= x; in_buffer -=x ;data += x + + /* first SYNC the dsp */ + sync_dsp (); + + if (!quiet_mode) + fprintf (stderr, "Playing Creative Labs Voice file ...\n"); + + /* first we waste the rest of header, ugly but we don't need seek */ + while (ofs > abuf_size) + { + read (fd, (char *) audiobuf, abuf_size); + ofs -= abuf_size; + } + if (ofs) + read (fd, audiobuf, ofs); + + /* .voc files are 8 bit (now) */ + samplesize = VOC_SAMPLESIZE; + ioctl (audio, SNDCTL_DSP_SETFMT, &samplesize); + if (samplesize != VOC_SAMPLESIZE) + { + fprintf (stderr, "%s: unable to set 8 bit sample size!\n", command); + exit (-1); + } + /* and there are MONO by default */ + dsp_stereo = MODE_MONO; + ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo); + + in_buffer = nextblock = 0; + while (1) + { + Fill_the_buffer: /* need this for repeat */ + if (in_buffer < 32) + { + /* move the rest of buffer to pos 0 and fill the audiobuf up */ + if (in_buffer) + memcpy ((char *) audiobuf, data, in_buffer); + data = audiobuf; + if ((l = + read (fd, (char *) audiobuf + in_buffer, + abuf_size - in_buffer)) > 0) + in_buffer += l; + else if (!in_buffer) + { + /* the file is truncated, so simulate 'Terminator' + and reduce the datablock for save landing */ + nextblock = audiobuf[0] = 0; + if (l == -1) + { + perror (name); + exit (-1); + } + } + } + while (!nextblock) + { /* this is a new block */ + bp = (BlockType *) data; + COUNT (sizeof (BlockType)); + nextblock = DATALEN (bp); + if (output && !quiet_mode) + fprintf (stderr, "\n"); /* write /n after ASCII-out */ + output = 0; + switch (bp->type) + { + case 0: + d_printf ((stderr, "Terminator\n")); + return; /* VOC-file stop */ + case 1: + vd = (Voice_data *) data; + COUNT (sizeof (Voice_data)); + /* we need a SYNC, before we can set new SPEED, STEREO ... */ + sync_dsp (); + + if (!was_extended) + { + dsp_speed = (int) (vd->tc); + dsp_speed = 1000000 / (256 - dsp_speed); + d_printf ((stderr, "Voice data %d Hz\n", dsp_speed)); + if (vd->pack) + { /* /dev/dsp can't it */ + fprintf (stderr, "%s: can't play packed .voc files\n", + command); + return; + } + if (dsp_stereo) + { /* if we are in Stereo-Mode, switch back */ + dsp_stereo = MODE_MONO; + ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo); + } + } + else + { /* there was extended block */ + if (one_chn) /* if one Stereo fails, why test another ? */ + dsp_stereo = MODE_MONO; + else if (dsp_stereo) + { /* want Stereo */ + /* shit, my MACRO dosn't work here */ +#ifdef OSS_VERSION + if (ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo) < 0) + { +#else + if (dsp_stereo != + ioctl (audio, SNDCTL_DSP_STEREO, dsp_stereo)) + { +#endif + dsp_stereo = MODE_MONO; + fprintf (stderr, + "%s: can't play in Stereo; playing only one channel\n", + command); + one_chn = 1; + } + } + was_extended = 0; + } + set_dsp_speed (&dsp_speed); + break; + case 2: /* nothing to do, pure data */ + d_printf ((stderr, "Voice continuation\n")); + break; + case 3: /* a silence block, no data, only a count */ + sp = (u_short *) data; + COUNT (sizeof (u_short)); + dsp_speed = (int) (*data); + COUNT (1); + dsp_speed = 1000000 / (256 - dsp_speed); + sync_dsp (); + set_dsp_speed (&dsp_speed); + silence = (((u_long) * sp) * 1000) / dsp_speed; + d_printf ((stderr, "Silence for %ld ms\n", silence)); + write_zeros (*sp); + break; + case 4: /* a marker for syncronisation, no effect */ + sp = (u_short *) data; + COUNT (sizeof (u_short)); + d_printf ((stderr, "Marker %d\n", *sp)); + break; + case 5: /* ASCII text, we copy to stderr */ + output = 1; + d_printf ((stderr, "ASCII - text :\n")); + break; + case 6: /* repeat marker, says repeatcount */ + /* my specs don't say it: maybe this can be recursive, but + I don't think somebody use it */ + repeat = *(u_short *) data; + COUNT (sizeof (u_short)); + d_printf ((stderr, "Repeat loop %d times\n", repeat)); + if (filepos >= 0) /* if < 0, one seek fails, why test another */ + if ((filepos = lseek (fd, 0, 1)) < 0) + { + fprintf (stderr, + "%s: can't play loops; %s isn't seekable\n", + command, name); + repeat = 0; + } + else + filepos -= in_buffer; /* set filepos after repeat */ + else + repeat = 0; + break; + case 7: /* ok, lets repeat that be rewinding tape */ + if (repeat) + { + if (repeat != 0xFFFF) + { + d_printf ((stderr, "Repeat loop %d\n", repeat)); + --repeat; + } + else + d_printf ((stderr, "Neverending loop\n")); + lseek (fd, filepos, 0); + in_buffer = 0; /* clear the buffer */ + goto Fill_the_buffer; + } + else + d_printf ((stderr, "End repeat loop\n")); + break; + case 8: /* the extension to play Stereo, I have SB 1.0 :-( */ + was_extended = 1; + eb = (Ext_Block *) data; + COUNT (sizeof (Ext_Block)); + dsp_speed = (int) (eb->tc); + dsp_speed = 256000000L / (65536 - dsp_speed); + dsp_stereo = eb->mode; + if (dsp_stereo == MODE_STEREO) + dsp_speed = dsp_speed >> 1; + if (eb->pack) + { /* /dev/dsp can't it */ + fprintf (stderr, "%s: can't play packed .voc files\n", + command); + return; + } + d_printf ((stderr, "Extended block %s %d Hz\n", + (eb->mode ? "Stereo" : "Mono"), dsp_speed)); + break; + default: + fprintf (stderr, "%s: unknown blocktype %d. terminate.\n", + command, bp->type); + return; + } /* switch (bp->type) */ + } /* while (! nextblock) */ + /* put nextblock data bytes to dsp */ + l = min (in_buffer, nextblock); + if (l) + { + if (output && !quiet_mode) + write (2, data, l); /* to stderr */ + else + { + real_l = one_chn ? one_channel (data, l, one_chn, 0) : l; + if (write (audio, data, real_l) != real_l) + { + perror (AUDIO); + exit (-1); + } + } + COUNT (l); + } + } /* while(1) */ +} + +/* that was a big one, perhaps somebody split it :-) */ + +/* setting the globals for playing raw data */ +void +init_raw_data (void) +{ + timelimit = raw_info.timelimit; + dsp_speed = raw_info.dsp_speed; + dsp_stereo = raw_info.dsp_stereo; + samplesize = raw_info.samplesize; +} + +/* calculate the data count to read from/to dsp */ +u_long +calc_count (void) +{ + u_long count; + + if (!timelimit) + count = 0x7fffffff; + else + { + count = timelimit * dsp_speed; + if (dsp_stereo) + count *= 2; + if (samplesize != 8) + count *= 2; + } + return count; +} + +/* write a .VOC-header */ +void +start_voc (int fd, u_long cnt) +{ + VocHeader vh; + BlockType bt; + Voice_data vd; + Ext_Block eb; + + strcpy ((char *) vh.magic, MAGIC_STRING); + vh.headerlen = sizeof (VocHeader); + vh.version = ACTUAL_VERSION; + vh.coded_ver = 0x1233 - ACTUAL_VERSION; + + write (fd, &vh, sizeof (VocHeader)); + + if (dsp_stereo) + { + /* write a extended block */ + bt.type = 8; + bt.datalen = 4; + bt.datalen_m = bt.datalen_h = 0; + write (fd, &bt, sizeof (BlockType)); + eb.tc = (u_short) (65536 - 256000000L / (dsp_speed << 1)); + eb.pack = 0; + eb.mode = 1; + write (fd, &eb, sizeof (Ext_Block)); + } + bt.type = 1; + cnt += sizeof (Voice_data); /* Voice_data block follows */ + bt.datalen = (u_char) (cnt & 0xFF); + bt.datalen_m = (u_char) ((cnt & 0xFF00) >> 8); + bt.datalen_h = (u_char) ((cnt & 0xFF0000) >> 16); + write (fd, &bt, sizeof (BlockType)); + vd.tc = (u_char) (256 - (1000000 / dsp_speed)); + vd.pack = 0; + write (fd, &vd, sizeof (Voice_data)); +} + +/* write a WAVE-header */ +void +start_wave (int fd, u_long cnt) +{ + WaveHeader wh; + + wh.main_chunk = RIFF; + wh.length = cnt + sizeof (WaveHeader) - 8; + wh.chunk_type = WAVE; + wh.sub_chunk = FMT; + wh.sc_len = 16; + wh.format = PCM_CODE; + wh.modus = dsp_stereo ? 2 : 1; + wh.sample_fq = dsp_speed; + wh.byte_p_spl = ((samplesize == 8) ? 1 : 2) * (dsp_stereo ? 2 : 1); + wh.byte_p_sec = dsp_speed * wh.modus * wh.byte_p_spl; + wh.bit_p_spl = samplesize; + wh.data_chunk = DATA; + wh.data_length = cnt; + write (fd, &wh, sizeof (WaveHeader)); +} + +/* closing .VOC */ +void +end_voc (int fd) +{ + char dummy = 0; /* Write a Terminator */ + write (fd, &dummy, 1); + if (fd != 1) + close (fd); +} + +void +end_wave_raw (int fd) +{ /* only close output */ + if (fd != 1) + close (fd); +} + +void +start_snd (int fd, u_long count) +{ + SndHeader snd; + char *sndinfo = "Recorded by vrec\000"; + + snd.magic = SND_MAGIC; + snd.dataLocation = sizeof (SndHeader) + strlen (sndinfo); + snd.dataSize = count; + switch (samplesize) + { + case 8: + snd.dataFormat = SND_FORMAT_LINEAR_8; + break; + case 16: + snd.dataFormat = SND_FORMAT_LINEAR_16; + break; + default: + fprintf (stderr, + "%d bit: unsupported sample size for NeXt sound file!\n", + samplesize); + exit (-1); + } + snd.samplingRate = dsp_speed; + snd.channelCount = dsp_stereo ? 2 : 1; + + write (fd, &snd, sizeof (SndHeader)); + write (fd, sndinfo, strlen (sndinfo)); +} + +void +end_snd (int fd) +{ + if (fd != 1) + close (fd); +} + +/* playing/recording raw data, this proc handels WAVE files and + recording .VOCs (as one block) */ +void +recplay (int fd, int loaded, u_long count, int rtype, char *name) +{ + int l, real_l; + u_long c; + char one_chn = 0; + char to_8 = 0; + int tmps; + + sync_dsp (); + tmps = samplesize; + ioctl (audio, SNDCTL_DSP_SETFMT, &tmps); + if (tmps != samplesize) + { + fprintf (stderr, "%s: unable to set %d bit sample size", + command, samplesize); + if (samplesize == 16) + { + samplesize = 8; + ioctl (audio, SNDCTL_DSP_SETFMT, &samplesize); + if (samplesize != 8) + { + fprintf (stderr, "%s: unable to set 8 bit sample size!\n", + command); + exit (-1); + } + fprintf (stderr, "; playing 8 bit\n"); + to_8 = 1; + } + else + { + fprintf (stderr, "\n"); + exit (-1); + } + } +#ifdef OSS_VERSION + if (ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo) < 0) + { +#else + if (dsp_stereo != ioctl (audio, SNDCTL_DSP_STEREO, dsp_stereo)) + { +#endif + if (direction == PLAY) + { + fprintf (stderr, + "%s: can't play in Stereo; playing only one channel\n", + command); + dsp_stereo = MODE_MONO; + one_chn = 1; + } + else + { + fprintf (stderr, "%s: can't record in Stereo\n", command); + exit (-1); + } + } + set_dsp_speed (&dsp_speed); + if (!quiet_mode) + { + fprintf (stderr, "%s %s : ", + (direction == PLAY) ? "Playing" : "Recording", + fmt_rec_table[rtype].what); + if (samplesize != 8) + fprintf (stderr, "%d bit, ", samplesize); + fprintf (stderr, "Speed %d Hz ", dsp_speed); + fprintf (stderr, "%d bits ", samplesize); + fprintf (stderr, "%s ...\n", dsp_stereo ? "Stereo" : "Mono"); + } + + abuf_size = -1; +#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 (AUDIO); + exit (-1); + } +#endif + + zbuf_size = 256; + if ((audiobuf = (u_char *) malloc (abuf_size)) == NULL || + (zerobuf = (u_char *) malloc (zbuf_size)) == NULL) + { + fprintf (stderr, "%s: unable to allocate input/output buffer\n", + command); + exit (-1); + } + memset ((char *) zerobuf, 128, zbuf_size); + + if (direction == PLAY) + { + while (count) + { + c = count; + + if (c > abuf_size) + c = abuf_size; + + if ((l = read (fd, (char *) audiobuf + loaded, c - loaded)) > 0) + { + l += loaded; + loaded = 0; /* correct the count; ugly but ... */ + real_l = (one_chn + || to_8) ? one_channel (audiobuf, l, one_chn, + to_8) : l; + + /* change byte order if necessary */ + if (convert && (samplesize == 16)) + { + long i; + + for (i = 0; i < real_l; i += 2) + *((short *) (audiobuf + i)) = + htons (*((short *) (audiobuf + i))); + } + + if (write (audio, (char *) audiobuf, real_l) != real_l) + { + perror (AUDIO); + exit (-1); + } + count -= l; + } + else + { + if (l == -1) + { + perror (name); + exit (-1); + } + count = 0; /* Stop */ + } + } /* while (count) */ + } + else + { /* we are recording */ + + while (count) + { + c = count; + if (c > abuf_size) + c = abuf_size; + + if ((l = read (audio, (char *) audiobuf, c)) > 0) + { + if (write (fd, (char *) audiobuf, l) != l) + { + perror (name); + exit (-1); + } + count -= l; + } + + if (l == -1) + { + perror (AUDIO); + exit (-1); + } + } /* While count */ + } +} + +/* + let's play or record it (record_type says VOC/WAVE/raw) +*/ +void +record_play (char *name) +{ + int fd, ofs; + + if (direction == PLAY) + { + + if (!name) + { + fd = 0; + name = "stdin"; + } + else if ((fd = open (name, O_RDONLY, 0)) == -1) + { + perror (name); + exit (-1); + } + /* Read the smallest header first, then the + missing bytes for the next, etc. */ + + /* read SND-header */ + read (fd, (char *) audiobuf, sizeof (SndHeader)); + if (test_sndfile (audiobuf, fd) >= 0) + recplay (fd, 0, count, SND_FMT, name); + + else + { + /* read VOC-Header */ + read (fd, (char *) audiobuf + sizeof (SndHeader), + sizeof (VocHeader) - sizeof (SndHeader)); + if ((ofs = test_vocfile (audiobuf)) >= 0) + vplay (fd, ofs, name); + + else + { + /* read bytes for WAVE-header */ + read (fd, (char *) audiobuf + sizeof (VocHeader), + sizeof (WaveHeader) - sizeof (VocHeader)); + if (test_wavefile (audiobuf) >= 0) + recplay (fd, 0, count, WAVE_FMT, name); + else + { + /* should be raw data */ + init_raw_data (); + count = calc_count (); + recplay (fd, sizeof (WaveHeader), count, RAW_DATA, name); + } + } + } + if (fd != 0) + close (fd); + } + else + { /* recording ... */ + if (!name) + { + fd = 1; + name = "stdout"; + } + else + { + if ((fd = open (name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) + { + perror (name); + exit (-1); + } + } + count = calc_count () & 0xFFFFFFFE; + /* WAVE-file should be even (I'm not sure), but wasting one byte + isn't a problem (this can only be in 8 bit mono) */ + if (fmt_rec_table[record_type].start) + fmt_rec_table[record_type].start (fd, count); + recplay (fd, 0, count, record_type, name); + fmt_rec_table[record_type].end (fd); + } +} diff --git a/tutorials/sndkit/dsp/vplay_vxworks/Makefile b/tutorials/sndkit/dsp/vplay_vxworks/Makefile new file mode 100644 index 0000000..80c0746 --- /dev/null +++ b/tutorials/sndkit/dsp/vplay_vxworks/Makefile @@ -0,0 +1,12 @@ + +# Makefile for OSS/VxWorks +# + +CPU = I80486 +TOOL = gnu + +include $(WIND_BASE)/target/h/make/defs.bsp +include $(WIND_BASE)/target/h/make/make.$(CPU)$(TOOL) +include $(WIND_BASE)/target/h/make/defs.$(WIND_HOST_TYPE) + +exe: vplay.o diff --git a/tutorials/sndkit/dsp/vplay_vxworks/fmtheaders.h b/tutorials/sndkit/dsp/vplay_vxworks/fmtheaders.h new file mode 100644 index 0000000..4ba1302 --- /dev/null +++ b/tutorials/sndkit/dsp/vplay_vxworks/fmtheaders.h @@ -0,0 +1,119 @@ +#ifndef _FMTHEADERS_H +#define _FMTHEADERS_H 1 +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ + +#include <sys/types.h> + +/* Definitions for .VOC files */ + +#define MAGIC_STRING "Creative Voice File\x1A" +#define ACTUAL_VERSION 0x010A +#define VOC_SAMPLESIZE 8 + +#define MODE_MONO 0 +#define MODE_STEREO 1 + +#define DATALEN(bp) ((u_long)(bp->datalen) | \ + ((u_long)(bp->datalen_m) << 8) | \ + ((u_long)(bp->datalen_h) << 16) ) + +typedef struct _vocheader +{ + u_char magic[20]; /* must be MAGIC_STRING */ + u_short headerlen; /* Headerlength, should be 0x1A */ + u_short version; /* VOC-file version */ + u_short coded_ver; /* 0x1233-version */ +} +VocHeader; + +typedef struct _blocktype +{ + u_char type; + u_char datalen; /* low-byte */ + u_char datalen_m; /* medium-byte */ + u_char datalen_h; /* high-byte */ +} +BlockType; + +typedef struct _voice_data +{ + u_char tc; + u_char pack; +} +Voice_data; + +typedef struct _ext_block +{ + u_short tc; + u_char pack; + u_char mode; +} +Ext_Block; + + +/* Definitions for Microsoft WAVE format */ + +#define RIFF 0x46464952 +#define WAVE 0x45564157 +#define FMT 0x20746D66 +#define DATA 0x61746164 +#define PCM_CODE 1 +#define WAVE_MONO 1 +#define WAVE_STEREO 2 + +/* it's in chunks like .voc and AMIGA iff, but my source say there + are in only in this combination, so I combined them in one header; + it works on all WAVE-file I have +*/ +typedef struct _waveheader +{ + u_long main_chunk; /* 'RIFF' */ + u_long length; /* filelen */ + u_long chunk_type; /* 'WAVE' */ + + u_long sub_chunk; /* 'fmt ' */ + u_long sc_len; /* length of sub_chunk, =16 */ + u_short format; /* should be 1 for PCM-code */ + u_short modus; /* 1 Mono, 2 Stereo */ + u_long sample_fq; /* frequence of sample */ + u_long byte_p_sec; + u_short byte_p_spl; /* samplesize; 1 or 2 bytes */ + u_short bit_p_spl; /* 8, 12 or 16 bit */ + + u_long data_chunk; /* 'data' */ + u_long data_length; /* samplecount */ +} +WaveHeader; + +typedef struct +{ + long magic; /* must be equal to SND_MAGIC */ + long dataLocation; /* Offset or pointer to the raw data */ + long dataSize; /* Number of bytes of data in the raw data */ + long dataFormat; /* The data format code */ + long samplingRate; /* The sampling rate */ + long channelCount; /* The number of channels */ +} +SndHeader; + +#define SND_MAGIC ((long int)0x2e736e64) + +#define SND_FORMAT_UNSPECIFIED (0) +#define SND_FORMAT_MULAW_8 (1) +#define SND_FORMAT_LINEAR_8 (2) +#define SND_FORMAT_LINEAR_16 (3) +#define SND_FORMAT_LINEAR_24 (4) +#define SND_FORMAT_LINEAR_32 (5) +#define SND_FORMAT_FLOAT (6) + +#endif diff --git a/tutorials/sndkit/dsp/vplay_vxworks/vplay_vxworks.c b/tutorials/sndkit/dsp/vplay_vxworks/vplay_vxworks.c new file mode 100644 index 0000000..b10d35d --- /dev/null +++ b/tutorials/sndkit/dsp/vplay_vxworks/vplay_vxworks.c @@ -0,0 +1,694 @@ +/* + vplay.c - plays + CREATIVE LABS VOICE-files, Microsoft WAVE-files and raw data + + Autor: Michael Beck - beck@informatik.hu-berlin.de + + Modified for VxWorks by 4Front Technologies + + Usage: int play_wave (char *filename); +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <ioLib.h> +#include <sys/ioctl.h> +#include "soundcard.h" /* Edit this to contain the right location of soundcard.h */ +#include "fmtheaders.h" + +/* + * The following defines break support for .snd files. Implement these routines + * properly if you need to play them. + */ +#define htonl(x) x +#define htons(x) x + +#define DEFAULT_DSP_SPEED 8000 + +#define AUDIO "/oss/dsp" + +#ifndef min +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#endif +#define d_printf(x) if (verbose_mode) fprintf x + +#define VOC_FMT 0 +#define WAVE_FMT 1 +#define RAW_DATA 2 +#define SND_FMT 3 + +/* global data */ + +static int timelimit = 0, dsp_speed = DEFAULT_DSP_SPEED, dsp_stereo = 0; +static int samplesize = 8; +static int quiet_mode = 0; +static int verbose_mode = 0; +static int convert = 0; +static u_long count; +static int audio, abuf_size; +static int omode; +static u_char audiobuf[512]; +static int vocminor, vocmajor; /* .VOC version */ + +/* defaults for playing raw data */ +static struct +{ + int timelimit, dsp_speed, dsp_stereo, samplesize; +} +raw_info = +{ +0, DEFAULT_DSP_SPEED, 0, 8}; + +/* needed prototypes */ + +static int player (char *name); +static u_long calc_count (); + +int +play_wave (char *filename) +{ + omode = O_WRONLY; + + quiet_mode = 1; + + audio = open (AUDIO, omode, 0); + if (audio == -1) + { + perror (AUDIO); + return -1; + } + + if (player (filename) < 0) + return -1; + close (audio); + return 0; +} + +/* + test, if it is a .VOC file and return >=0 if ok (this is the length of rest) + < 0 if not +*/ +static int +test_vocfile (void *buffer) +{ + VocHeader *vp = buffer; + if (!strcmp ((const char *) vp->magic, MAGIC_STRING)) + { + vocminor = vp->version & 0xFF; + vocmajor = vp->version / 256; + if (vp->version != (0x1233 - vp->coded_ver)) + return -2; /* coded version mismatch */ + return vp->headerlen - sizeof (VocHeader); /* 0 mostly */ + } + return -1; /* magic string fail */ +} + +/* + test, if it's a .WAV file, 0 if ok (and set the speed, stereo etc.) + < 0 if not +*/ +static int +test_wavefile (void *buffer) +{ + WaveHeader *wp = buffer; + if (wp->main_chunk == RIFF && wp->chunk_type == WAVE && + wp->sub_chunk == FMT && wp->data_chunk == DATA) + { + if (wp->format != PCM_CODE) + { + fprintf (stderr, "Can't play non PCM-coded WAVE-files\n"); + return -1; + } + if (wp->modus > 2) + { + fprintf (stderr, "Can't play WAVE-files with %d tracks\n", + wp->modus); + return -1; + } + dsp_stereo = (wp->modus == WAVE_STEREO) ? 1 : 0; + samplesize = wp->bit_p_spl; + dsp_speed = wp->sample_fq; + count = wp->data_length; + return 0; + } + return -1; +} + +/* +* test, if it's a .SND file, 0 if ok (and set the speed, stereo etc.) +* < 0 if not +*/ +static int +test_sndfile (void *buffer, int fd) +{ + long infolen; + char *info; + SndHeader *snd = buffer; + + if (snd->magic == SND_MAGIC) + convert = 0; + else + { + if (htonl (snd->magic) == SND_MAGIC) + { + convert = 1; + snd->dataLocation = htonl (snd->dataLocation); + snd->dataSize = htonl (snd->dataSize); + snd->dataFormat = htonl (snd->dataFormat); + snd->samplingRate = htonl (snd->samplingRate); + snd->channelCount = htonl (snd->channelCount); + } + else + { + /* No SoundFile */ + return (-1); + } + } + switch (snd->dataFormat) + { + case SND_FORMAT_LINEAR_8: + samplesize = 8; + break; + case SND_FORMAT_LINEAR_16: + samplesize = 16; + break; + default: + fprintf (stderr, "Unsupported SND_FORMAT\n"); + return -1; + } + + dsp_stereo = (snd->channelCount == 2) ? 1 : 0; + dsp_speed = snd->samplingRate; + count = snd->dataSize; + + /* read Info-Strings */ + infolen = snd->dataLocation - sizeof (SndHeader); + info = (char *) malloc (infolen); + read (fd, info, infolen); + if (!quiet_mode) + fprintf (stderr, "SoundFile Info: %s\n", info); + free (info); + + return 0; +} + + +/* if need a SYNC, + (is needed if we plan to change speed, stereo ... during output) +*/ +static void +sync_dsp (void) +{ +} + +/* setting the speed for output */ +static int +set_dsp_speed (int *dsp_speed) +{ + if (ioctl (audio, SNDCTL_DSP_SPEED, dsp_speed) < 0) + { + fprintf (stderr, "Unable to set audio speed\n"); + perror (AUDIO); + return -1; + } + return 0; +} + +/* if to_mono: + compress 8 bit stereo data 2:1, needed if we want play 'one track'; + this is usefull, if you habe SB 1.0 - 2.0 (I have 1.0) and want + hear the sample (in Mono) + if to_8: + compress 16 bit to 8 by using hi-byte; wave-files use signed words, + so we need to convert it in "unsigned" sample (0x80 is now zero) + + WARNING: this procedure can't compress 16 bit stereo to 16 bit mono, + because if you have a 16 (or 12) bit card you should have + stereo (or I'm wrong ?? ) + */ +static u_long +one_channel (u_char * buf, u_long l, char to_mono, char to_8) +{ + register u_char *w = buf; + register u_char *w2 = buf; + char ofs = 0; + u_long incr = 0; + u_long c, ret; + + if (to_mono) + ++incr; + if (to_8) + { + ++incr; + ++w2; + ofs = 128; + } + ret = c = l >> incr; + incr = incr << 1; + + while (c--) + { + *w++ = *w2 + ofs; + w2 += incr; + } + return ret; +} + +/* + ok, let's play a .voc file +*/ +static int +vplay (int fd, int ofs, char *name) +{ + int l, real_l; + BlockType *bp; + Voice_data *vd; + Ext_Block *eb; + u_long nextblock, in_buffer; + u_char *data = audiobuf; + char was_extended = 0, output = 0; + u_short *sp, repeat = 0; + u_long silence; + int filepos = 0; + char one_chn = 0; + +#define COUNT(x) nextblock -= x; in_buffer -=x ;data += x + + /* first SYNC the dsp */ + sync_dsp (); + + if (!quiet_mode) + fprintf (stderr, "Playing Creative Labs Voice file ...\n"); + + /* first we waste the rest of header, ugly but we don't need seek */ + while (ofs > abuf_size) + { + read (fd, (char *) audiobuf, abuf_size); + ofs -= abuf_size; + } + if (ofs) + read (fd, audiobuf, ofs); + + /* .voc files are 8 bit (now) */ + samplesize = VOC_SAMPLESIZE; + ioctl (audio, SNDCTL_DSP_SETFMT, &samplesize); + if (samplesize != VOC_SAMPLESIZE) + { + fprintf (stderr, "Unable to set 8 bit sample size!\n"); + return -1; + } + /* and there are MONO by default */ + dsp_stereo = MODE_MONO; + ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo); + + in_buffer = nextblock = 0; + while (1) + { + Fill_the_buffer: /* need this for repeat */ + if (in_buffer < 32) + { + /* move the rest of buffer to pos 0 and fill the audiobuf up */ + if (in_buffer) + memcpy ((char *) audiobuf, data, in_buffer); + data = audiobuf; + if ((l = + read (fd, (char *) audiobuf + in_buffer, + abuf_size - in_buffer)) > 0) + in_buffer += l; + else if (!in_buffer) + { + /* the file is truncated, so simulate 'Terminator' + and reduce the datablock for save landing */ + nextblock = audiobuf[0] = 0; + if (l == -1) + { + perror (name); + return -1; + } + } + } + while (!nextblock) + { /* this is a new block */ + bp = (BlockType *) data; + COUNT (sizeof (BlockType)); + nextblock = DATALEN (bp); + if (output && !quiet_mode) + fprintf (stderr, "\n"); /* write /n after ASCII-out */ + output = 0; + switch (bp->type) + { + case 0: + d_printf ((stderr, "Terminator\n")); + return -1; /* VOC-file stop */ + case 1: + vd = (Voice_data *) data; + COUNT (sizeof (Voice_data)); + /* we need a SYNC, before we can set new SPEED, STEREO ... */ + sync_dsp (); + + if (!was_extended) + { + dsp_speed = (int) (vd->tc); + dsp_speed = 1000000 / (256 - dsp_speed); + d_printf ((stderr, "Voice data %d Hz\n", dsp_speed)); + if (vd->pack) + { /* /dev/dsp can't it */ + fprintf (stderr, "Can't play packed .voc files\n"); + return -1; + } + if (dsp_stereo) + { /* if we are in Stereo-Mode, switch back */ + dsp_stereo = MODE_MONO; + ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo); + } + } + else + { /* there was extended block */ + if (one_chn) /* if one Stereo fails, why test another ? */ + dsp_stereo = MODE_MONO; + else if (dsp_stereo) + { /* want Stereo */ + /* shit, my MACRO dosn't work here */ +#ifdef OSS_VERSION + if (ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo) < 0) + { +#else + if (dsp_stereo != + ioctl (audio, SNDCTL_DSP_STEREO, dsp_stereo)) + { +#endif + dsp_stereo = MODE_MONO; + fprintf (stderr, + "Can't play in Stereo; playing only one channel\n"); + one_chn = 1; + } + } + was_extended = 0; + } + if (set_dsp_speed (&dsp_speed) < 0) + return -1; + break; + case 2: /* nothing to do, pure data */ + d_printf ((stderr, "Voice continuation\n")); + break; + case 3: /* a silence block, no data, only a count */ + sp = (u_short *) data; + COUNT (sizeof (u_short)); + dsp_speed = (int) (*data); + COUNT (1); + dsp_speed = 1000000 / (256 - dsp_speed); + sync_dsp (); + if (set_dsp_speed (&dsp_speed) < 0) + return -1; + silence = (((u_long) * sp) * 1000) / dsp_speed; + d_printf ((stderr, "Silence for %ld ms\n", silence)); + break; + case 4: /* a marker for syncronisation, no effect */ + sp = (u_short *) data; + COUNT (sizeof (u_short)); + d_printf ((stderr, "Marker %d\n", *sp)); + break; + case 5: /* ASCII text, we copy to stderr */ + output = 1; + d_printf ((stderr, "ASCII - text :\n")); + break; + case 6: /* repeat marker, says repeatcount */ + /* my specs don't say it: maybe this can be recursive, but + I don't think somebody use it */ + repeat = *(u_short *) data; + COUNT (sizeof (u_short)); + d_printf ((stderr, "Repeat loop %d times\n", repeat)); + if (filepos >= 0) /* if < 0, one seek fails, why test another */ + if ((filepos = lseek (fd, 0, 1)) < 0) + { + fprintf (stderr, + "Can't play loops; %s isn't seekable\n", name); + repeat = 0; + } + else + filepos -= in_buffer; /* set filepos after repeat */ + else + repeat = 0; + break; + case 7: /* ok, lets repeat that be rewinding tape */ + if (repeat) + { + if (repeat != 0xFFFF) + { + d_printf ((stderr, "Repeat loop %d\n", repeat)); + --repeat; + } + else + d_printf ((stderr, "Neverending loop\n")); + lseek (fd, filepos, 0); + in_buffer = 0; /* clear the buffer */ + goto Fill_the_buffer; + } + else + d_printf ((stderr, "End repeat loop\n")); + break; + case 8: /* the extension to play Stereo, I have SB 1.0 :-( */ + was_extended = 1; + eb = (Ext_Block *) data; + COUNT (sizeof (Ext_Block)); + dsp_speed = (int) (eb->tc); + dsp_speed = 256000000L / (65536 - dsp_speed); + dsp_stereo = eb->mode; + if (dsp_stereo == MODE_STEREO) + dsp_speed = dsp_speed >> 1; + if (eb->pack) + { /* /dev/dsp can't it */ + fprintf (stderr, "Can't play packed .voc files\n"); + return -1; + } + d_printf ((stderr, "Extended block %s %d Hz\n", + (eb->mode ? "Stereo" : "Mono"), dsp_speed)); + break; + default: + fprintf (stderr, "Unknown blocktype %d. terminate.\n", + bp->type); + return -1; + } /* switch (bp->type) */ + } /* while (! nextblock) */ + /* put nextblock data bytes to dsp */ + l = min (in_buffer, nextblock); + if (l) + { + if (output && !quiet_mode) + write (2, data, l); /* to stderr */ + else + { + real_l = one_chn ? one_channel (data, l, one_chn, 0) : l; + if (write (audio, data, real_l) != real_l) + { + perror (AUDIO); + return -1; + } + } + COUNT (l); + } + } /* while(1) */ +} + +/* that was a big one, perhaps somebody split it :-) */ + +/* setting the globals for playing raw data */ +static void +init_raw_data (void) +{ + timelimit = raw_info.timelimit; + dsp_speed = raw_info.dsp_speed; + dsp_stereo = raw_info.dsp_stereo; + samplesize = raw_info.samplesize; +} + +/* calculate the data count to read from/to dsp */ +static u_long +calc_count (void) +{ + u_long count; + + if (!timelimit) + count = 0x7fffffff; + else + { + count = timelimit * dsp_speed; + if (dsp_stereo) + count *= 2; + if (samplesize != 8) + count *= 2; + } + return count; +} + +/* playing raw data, this proc handels WAVE files and + .VOCs (as one block) */ +static int +do_play (int fd, int loaded, u_long count, int rtype, char *name) +{ + int l, real_l; + u_long c; + char one_chn = 0; + char to_8 = 0; + int tmps; + + sync_dsp (); + tmps = samplesize; + ioctl (audio, SNDCTL_DSP_SETFMT, &tmps); + if (tmps != samplesize) + { + fprintf (stderr, "Unable to set %d bit sample size", samplesize); + if (samplesize == 16) + { + samplesize = 8; + ioctl (audio, SNDCTL_DSP_SETFMT, &samplesize); + if (samplesize != 8) + { + fprintf (stderr, "Unable to set 8 bit sample size!\n"); + return -1; + } + fprintf (stderr, "; playing 8 bit\n"); + to_8 = 1; + } + else + { + fprintf (stderr, "\n"); + return -1; + } + } +#ifdef OSS_VERSION + if (ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo) < 0) + { +#else + if (dsp_stereo != ioctl (audio, SNDCTL_DSP_STEREO, dsp_stereo)) + { +#endif + fprintf (stderr, "Can't play in Stereo; playing only one channel\n"); + dsp_stereo = MODE_MONO; + one_chn = 1; + } + if (set_dsp_speed (&dsp_speed) < 0) + return -1; + + abuf_size = 512; + + while (count) + { + c = count; + + if (c > abuf_size) + c = abuf_size; + + if ((l = read (fd, (char *) audiobuf + loaded, c - loaded)) > 0) + { + l += loaded; + loaded = 0; /* correct the count; ugly but ... */ + real_l = (one_chn + || to_8) ? one_channel (audiobuf, l, one_chn, to_8) : l; + + /* change byte order if necessary */ + if (convert && (samplesize == 16)) + { + long i; + + for (i = 0; i < real_l; i += 2) + *((short *) (audiobuf + i)) = + htons (*((short *) (audiobuf + i))); + } + + if (write (audio, (char *) audiobuf, real_l) != real_l) + { + perror (AUDIO); + return -1; + } + count -= l; + } + else + { + if (l == -1) + { + perror (name); + return -1; + } + count = 0; /* Stop */ + } + } /* while (count) */ + + return 0; +} + +/* + let's play) +*/ +static int +player (char *name) +{ + int fd, ofs; + + if (!name) + { + fd = 0; + name = "stdin"; + } + else if ((fd = open (name, O_RDONLY, 0)) == -1) + { + perror (name); + return -1; + } + /* Read the smallest header first, then the + missing bytes for the next, etc. */ + + /* read SND-header */ + read (fd, (char *) audiobuf, sizeof (SndHeader)); + if (test_sndfile (audiobuf, fd) >= 0) + { + if (do_play (fd, 0, count, SND_FMT, name) < 0) + return -1; + } + + else + { + /* read VOC-Header */ + read (fd, (char *) audiobuf + sizeof (SndHeader), + sizeof (VocHeader) - sizeof (SndHeader)); + if ((ofs = test_vocfile (audiobuf)) >= 0) + { + if (vplay (fd, ofs, name) < 0) + return -1; + } + + else + { + /* read bytes for WAVE-header */ + read (fd, (char *) audiobuf + sizeof (VocHeader), + sizeof (WaveHeader) - sizeof (VocHeader)); + if (test_wavefile (audiobuf) >= 0) + { + if (do_play (fd, 0, count, WAVE_FMT, name) < 0) + return -1; + } + else + { + /* should be raw data */ + init_raw_data (); + count = calc_count (); + if (do_play (fd, sizeof (WaveHeader), count, RAW_DATA, name) < + 0) + return -1; + } + } + } + if (fd != 0) + close (fd); + return 0; +} + +#if 0 +int +main (int agrc, char *argv[]) +{ + exit (play_wave (argv[1])); +} +#endif |