OmniPlay
version 1.21

A Multiple-Format Sound Player for the Amiga



BACKGROUND
----------
In the beginning, the Amiga could play sounds.  Few other machines
could go beyond beeps, bells, and simple waveform descriptions.  In
the last few years, however, many manufacturers have been developing
sampled sound playback hardware for their computers, and with almost
every new sound generation system, there's a new sound file format.
While it's much easier now to find interesting samples, it's much
harder to listen to them.  Tools are constantly developed on every
platform to read one format and save it as something a local player
program recognizes.  There have been many primitive converters for
many types of machine, usually converting only one type of file to
one other type of file.  It was a mess.

A couple of years ago, Lance Norskog began work on the Sound
Exchange, a program and linker library kit that could both read and
write almost any sound file type, and handle data flow between them.
It was originally created for Unix, but recently it's been ported to
a number of other platforms, as well.  Finally, it was possible to
deal with almost any sound in existence.  But you *still* had to
figure what a file was, then convert it to something you know, and
find a good player for that format.


THIS PROGRAM
------------
I've heard lots of requests lately on Usenet for Amiga programs that
will play XXXX-format sound files.  The standard answer, with which I
agreed, has always been "Use MegaMondo Bigtime Sound Converter
(sorry, no cute acronym) to change your SPIFF file to IFF, then play
it with Killer Buttkick Sound Player (version 2.1 only!)."

Previously, I had ported SOX to the Amiga as a temporary solution to
the myriad of unplayable sound formats, but almost everyone finds
that while SOX is quite flexible, it's just plain slow.  Mike Cramer
has been steadily developing a fast Amiga-only sound file converter,
but the fact remains that it's a converter and not a player.  This is
fine, but sometimes you just want to play a file without changing it.
Besides, some formats (such as u-law, 16-bit WAV, 16-bit AIFF, and
16-bit .snd) store data that would be lost forever by conversion,
but merely playing the files only loses the data for the duration of
playback.  Finally I started thinking: "I've got to write most of the
essential bits anyway for this other program I'm doing, so I might as
well code the file reader and playroutine now to satisfy everyone."

Well, here you go.  OmniPlay is an Amiga sound player that reads
and plays IFF-8SVX, IFF-AIFF, Sun .au, NeXT .snd (u-law, linear-8,
linear-16), WAV, VOC, signed raw, unsigned raw, and raw u-law sound
formats.  OmniPlay determines the sound type on its own, so you
needn't tell it what format something is (although you can if you
wish), and it reads all relevant playback information from headered
formats (although you can override these on the command line).
Additionally, optional properties of a formatted sound (e.g., IFF's
NAME, AUTH, etc.) are printed to the output stream (usually console)
whenever encountered in a file (although this behavior can be
suppressed on the command line).  OmniPlay also plays PowerPacked
sounds, as long as they decompress to one of the above formats.
Furthermore, OmniPlay is as fast or faster than the average sound
converter, and can parse a sound file quickly enough to keep up with
the audio device.  Unless you need IFF sounds for another
application, there's no real need to convert sounds.


COMMAND SYNTAX
--------------
> oplay [-r rate] [-v volume] [-b buffersize] [-c l|r|e] [-o 0|1]
	[-p pri] [-w ticks] [-f a|l|s|u] [-s 0|1] [-d PAL|NTSC]
	[-g 0|1] [-m 0|1] [-a factor] [-W filename] [-i 0|1]
	[-O filespec] [-- file] file [file [...] ]

-r:	Override default playback rate with rate.
-v:	Override default playback volume with volume.
-b:	Set size of one buffer (both are the same size).
-o:	Play everything at once.
-c:	Set channel for playback.  Left, Right, or Either.
-p:	Set oplay's task priority.
-f:	Force playback as Auto, u-Law, Signed raw, or Unsigned raw
-w:	Pause/Wait for ticks * 1/50 second.
-s:	Show (1) or don't show (0) optional properties.
-d:	Set electrical standard (PAL or NTSC).
-g:	Generate log tables for ulaw files.
-m:	Show u-law maximum encoded value.
-a:	Amplify by multiplying sound by an integer.
-W:	Write sound as an IFF to "filename".
-i:	Display more info on sound file.
-O:	A file name or window spec to receive output.
--:	Prevent option parsing for this argument.

	Why you'd want to use these options:

	-r:	Just to see what it sounds like that way, or to set
		the playback rate for an unheadered (raw) sound.
		Default: format-specified, or 10000 (8000 for ulaw, 
		11395 for unsigned).
	-v:	To control gain on a "hot" sound.  Range is 0 to 64.
		Default: 64.
	-b:	To define how much data is read between buffer-
		loading.  Default: 4000 (bytes).
	-o:	If you don't want OmniPlay to continuously read while
		playing, set this to 1.  OmniPlay will find the size
		of its input and adjust the buffer size so that it
		can read all of the file in one shot, rather than
		reading during playback.  Using "-o0" means that
		only one bufferfull is read at a time, so you get
		immediate playback and continuous disk access.  Use
		"-o1" to play from floppy, slow NFS volumes, or other
		slow devices without choppiness.  Naturally, you must
		have enough RAM to load the whole sound to do this.
		"-o1" also overrides any value you set for "-b".
		Buffers under "-o1" are defined as half the size of
		the sound file plus one; a 20000-byte file uses
		buffers of 10001 bytes, and a 9999-byte file uses
		5000 bytes.  Default: 0.
	-c:	Oh, I don't know.  "Either" means to take whatever
		channel is available first, and is the default.
	-p:	This was for debugging, originally -- when an input
		handler hung, I wanted oplay not to hog the system
		while I figured out what it shouldn't have assumed
		about its input.  You might use it, for example, to
		play a long sound in the background, but not to use
		CPU time that could be used by your PostScript
		interpreter, compiler, archiver, or any CPU-
		intensive program.  Default: -1.
	-f:	Suppose, just suppose, you have a WAV file, say, that
		OmniPlay refuses to read.  You can make it play it in
		8 bits with "-fu".  For AIFF, .au/.snd (linear), or
		8SVX, use "-fs"; for WAV & VOC, use "-fu"; for
		.au/.snd (u-law), use "-fl".  Like "-r" and "-v",
		this option maintains control until disabled.  To
		disable, use "-fa" (for auto).  Default: a.
	-w:	You can cause simple scripting by making oplay pause
		for some amount of time before going on to the next
		sound.  Note that wait-times are measured in 1/50
		seconds for precision.  Default: 0.
	-s:	If you don't care what program digitized the sound,
		or think that console output would interfere with
		whatever else is going on, you can use "-s0".
		Default: 1 (property notification on).
	-d:	If you have an NTSC Whoppin' Agnus booted into PAL
		mode (or vice versa, for whataver reason), you
		should set this to what you really are.
		Default: whataver GfxBase says, or NTSC if GfxBase
		doesn't say "PAL" or "NTSC".
	-g:	U-law files are 14-bit samples logarithmically
		encoded to 8 bits.  To play these files, OmniPlay
		must convert u-law encoding to 8-bit linear, which
		requires the generation of "log tables" which equate
		encoded values to linear values.  Computing this
		table can take some time, especially for large u-law
		files.  This option defines whether log tables are
		generated for the special characteristics of an
		individual u-law file ("-g1"), or computed for a
		generic u-law of full 14-bit resolution ("-g0").
		The latter is much faster, since it doesn't have to
		scan the file for a maximum encoding value, but can
		produce output that's significantly less audible than
		that produced with a customized log table.  Most of
		my u-law sounds, however, *do* use full resolution,
		so "-g0" is acceptable.  Default: 0.
	-m:	If a u-law file plyed with "-g0" set isn't very loud,
		you might want to check its maximum encoding value.
		"-m1" causes OmniPlay to print this maximum; "-m0"
		suppresses it.  If the maximum is less than, say,
		20,000, you might get better sound quality by using
		"-g1" (at the expense of calculation time).
		Default: 0.
	-a:	Many sounds are digitized at low gain, so that not
		only resolution (therefore quality) is lost, but the
		volume of the sound is quite low -- often completely
		inaudible.  Using this option, you can amplify the
		sound's volume (but not its quality) by any integral
		amount.  Default: 1 (= 100%).
	-A:	"-a" acts strangely if you use a large ratio (this
		behavior is documented in "CHANGES.doc"), so this
		option corrects that.  It's somewhat slower,
		however.  Default: 1 (=100%).
	-W:	Well, it was easy to do, so I did.  This option
		creates an IFF-8SVX file for the sound you're
		playing.  It duplicates any optional properties from
		IFF, AIFF, or WAVE files.  If the source file
		contains an annotation, it is copied; otherwise,
		oplay inserts its own.  This option is valid for
		ONE FILE ONLY.  To write multiple conversions, you
		must use "-W" before each file to be converted.
		Default: none.
	-i:	Displays extra info on the current sound.  Best used
		in conjunction with "-s1".  Shows the sampling rate,
		buffer size, sound length, volume, and style (i.e.,
		signed/unsigned/u-law, 8-bit/16-bit) of the sound.
		Default: 0.
	-O:	Say you want a nasty Workbench window to say  what's
		up in OmniPlay.  You can do this with output
		redirection.  However, the new OMNIPLAY environment
		variable, which can be used to store your very own
		OmniPlay defaults, can't use such a redirection since
		redirection is a shell feature.  This  option is
		equivalent to  file redirection, except that it can
		be parsed by OmniPlay instead of the shell.  One of
		the sample environment variables has an example of
		window redirection.  Default: none.
	--:	If you've a sound file called "-whack", oplay would
		give you an error for "oplay -whack" since
		1) "hack" is not a number (see "-w"), and 2) there's
		no filename to play.  Use "oplay ---whack" to remedy
		this.  Basically, it means that the next argument is
		a file, not an option.  Default: none.

Option arguments are allowed, but not required, to be separated from
the corresponding option switch by whitespace (either spaces or
tabs).

Note that none of the options are necessary for playback, but they
might help you get the best sound quality from a file.


EXAMPLES
--------

oplay -r15000 IllBeBack
	play file "IllBeBack" at 15,000 Hz.

oplay -r12000 IllBeBack -r 18000 Mr.Ed
	play "IllBeBack" at 12,000 Hz, then play "Mr.Ed" at 18,000 Hz.

oplay ---bigboom -p75 -c r sounds:loudcrash
	play "-bigboom" from the first available channel, wait 1.5
	seconds, and play "sounds:loudcrash" from the right channel.

oplay -b10000 df0:toilet.aiff
	set buffer size to 10,000 bytes and play "df0:toilet.aiff".
	Note: "df0:toilet.aiff" will play correctly even if it's
	not an AIFF file because of auto-detect and because you
	didn't specify a forced file type.

oplay -v 16 dialtone -v0 busysignal
	play "dialtone" at 1/4 maximum volume, then play "busysignal"
	at whataver its prerecorded colume is.  If "busysignal" has
	no prerecorded volume, play it at full.

oplay -p1 reallybig.snd -p -1 normal.snd
	play "reallybig.snd" at priority 1, then "normal.snd" at
	priority -1.

oplay -o -b1000 evenbigger.wav -o0 tiny.voc
	play "evenbigger.wav" in one shot.  "-b" option defines the
	new default buffer size, but this default is ignored until
	"tiny.voc" is played.  Buffers for "evenbigger.wav" are both
	half the size of the file plus one byte.


MISCELLANY
----------
OmniPlay is residentable.  If you use it a lot, you can make it
resident with the AmigADOS "resident" command, as in:
"resident oplay".  Residenting OmniPlay swallows just under 24 K,
so it's pretty much worth it.

The environment variable OMNIPLAY is now read prior to any command-
line arguments.  Use this to set global defaults for all invocations
of oplay.  The environment takes the same format as the command line.
Maximum environment length is 256 bytes.  The directory env/ contains
examples of some OMNIPLAY variables you might want to use.

OmniPlay uses double-buffering for seamless playback.  This means
that one buffer is played while the next one is filled from disk,
then the second is played while the first is refilled.  The slower
your input device, the larger your buffers should be.  (Technical
note: the buffer-loading, including conversion from 16-bit, u-law,
unsigned, or little-endian, seems to be fast enough even at priority
of -1.  If you find that this is not true on your machine, try
bumping the priority a little.  If it's still not acceptable, let me
know.  At present, the reloader is a function, so it carries the
time overhead associated with calling a function.  I could move this
inline, at a small increase in code size, to speed it up (though
obviously I'd rather not if possible).  I have made OmniPlay pause
by loading a large imploded program during playback, but this is an
expected side-effect which shouldn't occur often.  Raising the
priority will cure this, too.  If you ever want to play a really long
file while you might be doing some CPU-intensive activity, and you'd
prefer good sound over fast math, you can place "-p" options around
the filename, e.g. "oplay ... -p1 bigsound.wav16 -p0 ...".  (16-bit
WAVs are possibly the slowest in conversion, since samples must be
downshifted to 8-bits after converting from little-endian words.))

Automatic type identification is performed by examining the sound
file, so you almost never need to tell OmniPlay what format a
sound is.  Filename extensions are meaningless to OmniPlay.
Autotyping of formatted sounds is fast, but autotyping unheadered
sounds can take a while on big files.

PowerPacked sound files are supported, but only when using the
automatic type-identifier.  You'll need enough free storage in your
t: directory to hold the decompressed file until it's through
playing.  You also need enough free RAM to perform the decompression.
To decrunch PP sound files, you need to have powerpacker.library
either in your libs: directory, or already loaded into the resident
shared library list.  If powerpacker.library is not available,
OmniPlay will still work -- it just won't be able to play PowerPacked
files (you'll get a notice if you try to play one).

Choosing a channel of "either" ("-c e") causes OmniPlay to use the
first channel it can get.  Pecking order is: ch. 0 (L), ch. 1 (R),
ch. 3 (L), ch. 2 (R).

If you use "-v" or "-r" to override the default playback volume or
rate, the value you specify will be the new default until OmniPlay
encounters another "-v" or "-r".  To use the sound file's prerecorded
volume or rate again, use "-v0" or "-r0".

Same idea for "-f"; use "-fa" to shut off type override.

Files which end in .au can be one of several things: 1) headered
u-law; 2) headered linear; 3) unheadered u-law.  If the "auto" type
(i.e., default as in "oplay smile.au") doesn't sound right, try
"oplay -fl smile.au".  OmniPlay should be able to get it right as
long as there's a header.  Even if there's not, the automatic type-
identifier should discover that it's a u-law file and play as such.

Likewise, files which end in ".snd" are ambiguous.  Sometimes,
they're unsigned raw, sometimes headered u-law, sometimes headered
linear (-8 or -16), sometimes even signed raw.  Again, OmniPlay will
probably get it right, but if it sounds like garbage, try to force
it with the "-f" option (use whatever argument works).

Note that when playing raw sounds, OmniPlay pauses for any number
of nanoseconds while it figures out what sort of raw file this is.
This timeout can be avoided by specifying some raw format with the
"-f" option.  Also, you may experience some slowdown in 16-bit or
u-law sounds on slow machines with small buffers.  This is because
OmniPlay does some conversions during playback so as not to have to
load everything in at once.  Using a buffer half as big as the sound
will cure this completely (this is done automatically with the "-o1"
option); using a smaller, but still large, buffer will make it break
less often.

It is recommended that when playing u-law files (typically ending in
".au" or ".snd"), you use the default of "-g0".  Scanning the file,
as explained above, can take much time; my A3000 (68030, data & cache
burst on) took about 33 secs to scan a 1.2 M u-law file.  Since
scanning involves part of the u-law decoding, the limiting factor on
fast input devices such as hard disks or RAM: is computation speed
rather than access time.  Obviously, then, it would take a slower
Amiga more time to scan.  Using "-g0" avoids the scan, enabling
OmniPlay to begin playback immediately.  As suggested before,
there can be some loss of volume *and* quality in this method; if
you're concerned about this, use "-g1" to get the best possible
quality.  You can use "-m1" to find out whether you're really gaining
anything by doing this; if the reported maximum is 32124, the "-g0"
default will produce the same output as "-g1".  Maxima are
logarithmic and increasing, so if you're (logarithmically speaking)
close to 32124, you're getting nearly the best playback possible.

OmniPlay now uses a precomputed logarithm-to-linear conversion table
for part of the u-law decoding process (not affecting the final
output at all), so u-law lag-time before playback is about 55% less
than the lag-time before output in most u-law converters.  This table
adds aproximately 1K to the size of the OmniPlay executable.

OmniPlay has no Intuition front-end, since I consider them
extraneous on such projects as this.  Again, let me know if this
is essential to you.  (You can sort of give it one by redirecting
standard output to a CON: window, e.g.,
"oplay K00L.biff <>CON:0/0/640/60/OmniPlay".)

To break OmniPlay during playback, send it a C-break
(SIGBREAKF_CTRL_C) either by hitting CTRL-C in the CLI input stream
it started from, or by issuing the command "break <clinumber>" (or
with some system monitor such as ARTM).

OmniPlay is sensitive to the difference between PAL and NTSC in
sound playback.  It determines what system you have by querying
GfxBase.  Since v0.8, there's a command-line option so that you can
tell OmniPlay what standard you're running under if, for example,
you have an NTSC Obese Agnus running in PAL mode (GfxBase will say
you're PAL, when, so far as audio is concerned, you're still an NTSC
machine).

OmniPlay was written in C.  It now compiles under both DICE and
SAS/C.  It should be easily portable to other Amiga C environments;
if you perform the changes to make it compile under another system,
please send me your version and I'll try to make the distribution
work for them all.


LEGAL STUFF
-----------
(1) The unmodified program designated "OmniPlay", or "oplay" for
short (as well as any product of the union between any compiler and
the unmodified source code), is Freeware (I hear that's the term in
vogue).  If you like it and have a need for it, then you're
morally obligated to use it.  You may spread it anywhere, any
time, any way you choose.  You can even make changes to the binary
and distribute them separately (see (2)), but I'd prefer that you
don't.

(2) Modified copies of the program, as produced by binary patching or
by disassembly, recoding, and reassembly, or by recompiling modified
source code in C, may be distributed freely, but only if the name of
the resulting binary file is not labelled "OmniPlay" or "oplay", or
contains some word or phrase such as "patch" to indicate that it is
not the original OmniPlay.

(3) Source code, except where noted as the product of another mind,
is placed into the public domain.  It may be freely copied,
distributed, modified, disemboweled, shredded, or reconstructed for
any purpose, public or private, commercial or free, excepting those
prohibited in (2) and (4).

(4) Files containing copies of substantial portions of the OmniPlay
source code, with no significant changes, may not be distributed
or compiled as a sound player program.

Basically, the program is yours, but the source code and names are
mine.  You have permission to copy small components of the source
code for any use, but large sections may not be duplicated except
with explicit permission from me, either in written or electronic
form.

If you doubt whether a particular usage is fair, contact me anyway.
You'll probably get either "okay" or "that's not my jurisdiction".
My primary concern in placing restrictions on duplication is
avoiding unnecessary confusion to the user.

OmniPlay is presented with no guarantee of functionality or safe
operation.  In using this program, you agree that I am absolved of
any and all liability.  This said, I have made efforts to protect
OmniPlay's integrity by testing under Enforcer and Mungwall, and
I'm pretty sure nothing rotten is going to happen.  If something
rotten *does* happen (or if you like the idea, but not the method),
please let me know.  I'll do my best to provide prompt bug fixes, and
to update OmniPlay's format support as I receive new format
information.  If you have a format you'd like to see supported, tell
me about it.  Send me some samples in that format.  Point me to the
specs.  I'll work on it.  (I've heard that one floppy can be sent in
a standard envelope through U.S. Mail first-class postage.)


BUGS
----
(version 1.21)
- I've made OmniPlay agree with every VOC, WAV, or AIFF file that
  I own, but it's possible that it doesn't work with them all.  In
  particular, compression and VOC silences are not supported since I
  have no documentation on how these are decoded.  Please send me any
  information you have on these.
- Stereo playback is still busted.  As the command line goes, asking
  for "stereo" equates to asking for "either".


CREDITS
-------
Thanks for code and suggestions to:

- Guido van Rossum, for the raw audio type-guesser, and for the
  Usenet comp.binaries.sounds.d Audio Formats Guide.

- Dave Schreiber, for DSound source code's availability.  This is
  where I started learning to program the audio.device, and my
  playroutine is largely modelled after his.

- Nico François, for the powerpacker.library and PowerPacker
  compression format.

- Malcolm Slaney and Ken Turkowski of Apple Computer for
  ConvertIeeeExtended(), the basis for the AIFF rate converter in
  OmniPlay, which AudioMaster desperately needs incidentally.

- Michael Boehnisch, author of ulawto8svx, for the reproduction of
  the u-law decoder;

- Brian Foley, for the u-law decoder itself;

- Mike Cramer, author of SoundZAP, for more examples of its use.

- All contributors to SOX, the Sound Exchange, for the idea of a
  multi-format player and for example code.

- Chris Wichura, Amish Dave, and Matt Simmons for pre-release
  comments and suggestions.  Special thanks to Chris for his many
  suggestions on how to implement stuff I wasn't familiar with, and
  for good example source code.

- Authors of quality free software, for quality free software.


ABOUT ME
--------
You can reach me at:

(U.S. Mail; this is a new address)
David Champion
951 E. 54th Place #3
Chicago, IL 60637
U.S.A.

(Internet, for a long time yet)
dgc3@midway.uchicago.edu  (preferred over tira)
champion@tira.uchicago.edu
siduri@amber.uchicago.edu (NeXT-Mail accepted, preferably with
			   a .snd attachment :-)
