summaryrefslogtreecommitdiffstats
path: root/mpeglib/lib/tplay
diff options
context:
space:
mode:
Diffstat (limited to 'mpeglib/lib/tplay')
-rw-r--r--mpeglib/lib/tplay/CHANGES154
-rw-r--r--mpeglib/lib/tplay/Makefile.am15
-rw-r--r--mpeglib/lib/tplay/README95
-rw-r--r--mpeglib/lib/tplay/au.cpp100
-rw-r--r--mpeglib/lib/tplay/tplayfunctions.cpp84
-rw-r--r--mpeglib/lib/tplay/tplayfunctions.h128
-rw-r--r--mpeglib/lib/tplay/wav.cpp91
7 files changed, 667 insertions, 0 deletions
diff --git a/mpeglib/lib/tplay/CHANGES b/mpeglib/lib/tplay/CHANGES
new file mode 100644
index 00000000..aad2446d
--- /dev/null
+++ b/mpeglib/lib/tplay/CHANGES
@@ -0,0 +1,154 @@
+Version 0.1, 2.4.1997:
+
+ - the first released version
+
+5.4.1997:
+
+ - audio sync added before changing parameters
+
+Version 0.2, 9.4.1997:
+
+ - it was useless to start producer as a thread;
+ it was made that way just for historical reasons.
+ only consumer is threaded now. this may result
+ as more robust behaviour.
+
+ - there are min and max sizes for block now. i'm
+ not sure yet what size for a block and the audio
+ buffer would be good. needs more research.
+
+ - fill_buffer function. fills the audio buffer
+ before use.
+
+Version 0.2.1, 15.4.1997:
+
+ - signal() seems to be a bad idea in a threaded
+ application like this. causes kernel oops in
+ the sound driver function audio_write (sometimes).
+ let's have faith on the kernel and remove it.
+
+Version 0.2.2, 17.4.1997 morning:
+
+ - the last block was written from very wrong point.
+
+ - block counting added. this makes stream ending
+ simpler and (hopefully) more robust.
+
+ - first lines for handling underflow (buffer empty)
+ situation.
+
+Version 0.3, 17.4.1997 afternoon:
+
+ - underflow handling should work now.
+
+ - function buffer_usage added. returns buffer usage
+ in percents. nowhere used yet.
+
+ - minimum block size increased to 16k.
+
+Version 0.3.1, 19.4.1997:
+
+ - GNU style options.
+
+ - option -v (or --version) added.
+
+ - buffer usage option -u (or --usage) added.
+
+Version 0.4, 2.5.1997:
+
+ - support for RIFF/WAVE (WAV) and Sun audio
+ (AU) files.
+
+ - swap endianness flag -x (or --swap) added.
+
+ - verbose mode flag -V (or --verbose) added.
+
+ - force raw flag -r (or --raw) added. WAV- or
+ AU-file headers are ignored if this flag is set.
+
+Version 0.4.1, 3.5.1997:
+
+ - sun header gives odd aligned starting point
+ for sample. temporary fix.
+
+ - read_big_endian_long returned wrong value if
+ sampling rate was 44100. this caused tplay
+ not to work with that speed when playing sun
+ audio or wav file. fixed now.
+
+Version 0.4.2, 7.5.1997:
+
+ - read_big_endian_long and similar functions:
+ parameter's type was char* and that was a bug.
+ changed to byte* (unsigned char *). conversion
+ should also be saner now.
+
+ - force playing -f (or --force) flag added. this
+ makes tplay to ignore sound driver's results
+ when changing parameters.
+
+Version 0.4.3, 12.5.1997:
+
+ - binary is statically linked to LinuxThreads
+ version 0.6 now.
+
+ - print sun header comment if verbose is requested.
+
+ - sun audio file's data stream starting pointer
+ is read and set from the header.
+
+ - to avoid rounding errors when playing 16bit
+ and/or stereo (au or wav) sample, data section
+ is moved now to the beginning of buffer before
+ playing.
+
+Version 0.5, 23.10.1997:
+
+ - set_audio_parameters() partly rewritten and
+ changes to open_audio().
+
+ - in some WAV-files, data-portion is not started
+ with 'data'-magic but 'INFO' instead. some
+ players don't even check that so tplay prints
+ just a warning message now if neither of these
+ magics exists.
+
+Version 0.5.1, 25.10.1997:
+
+ - printing of buffer usage changed from producer
+ to consumer. this makes this silly feature a bit
+ more informative as it is still active after the
+ producer has stopped. underflow situation (when
+ the big buffer needs to be refilled) is also
+ possible to show now.
+
+Version 0.5.2, 9.5.1998:
+
+ - Jerko Golubovic <jerko.golubovic@public.srce.hr>
+ kindly modified the code to support those soundcards
+ that may result slightly different sampling rate
+ than requested. he also provided RPM of tplay.
+
+ - added -D (or --device=DEVICE) flag for setting
+ audio device to be used.
+
+ - added feature to -B (or --buffer-size=SIZE) flag.
+ buffer size can be given in seconds now, too.
+
+Version 0.5.3, 11.5.1998:
+
+ - rewrite of playing routine to support multiple
+ sound samples from command line.
+
+Version 0.5.4, 19.5.1998:
+
+ - added -l (or --loop) flag to support looping sound
+ samples.
+
+ - sun port.
+
+Version 0.5.5, 24.5.1998:
+
+ - added environment variable TPLAYDEV, which sets the
+ audio device to be used. decoding of command line
+ options is moved from main() to another function.
diff --git a/mpeglib/lib/tplay/Makefile.am b/mpeglib/lib/tplay/Makefile.am
new file mode 100644
index 00000000..c83b25ea
--- /dev/null
+++ b/mpeglib/lib/tplay/Makefile.am
@@ -0,0 +1,15 @@
+# libtplay - Makefile.am
+
+
+EXTRA_DIST = CHANGES README
+
+INCLUDES = $(all_includes)
+
+
+noinst_LTLIBRARIES = libtplay.la
+
+noinst_HEADERS = tplayfunctions.h
+
+libtplay_la_SOURCES = au.cpp \
+ tplayfunctions.cpp wav.cpp
+
diff --git a/mpeglib/lib/tplay/README b/mpeglib/lib/tplay/README
new file mode 100644
index 00000000..275d6a9f
--- /dev/null
+++ b/mpeglib/lib/tplay/README
@@ -0,0 +1,95 @@
+This is a buffered audio player for Linux. POSIX-thread library is
+used. This is still considered BETA software and may not work as
+expected. Please mail me for bug reports, opinions or suggestions.
+
+This is primarily made for use with MPEG-decoders. They typically
+consume lots of CPU-time and some kind of audio buffer is needed to
+reduce cutting while writing to audio device. You can also play any
+audio files with tplay or use it with any program that writes audio
+data to standard out.
+
+RIFF/WAVE (WAV) and Sun audio (AU) file headers are recognized by
+now.
+
+Binary:
+
+In the source tree there is a readily compiled binary that is build
+under Linux/ELF 2.0.30 with libc 5.4.20 and LinuxThreads 0.6 (the
+thread library is statically linked).
+
+Command line options:
+
+ tplay [-hvVmuxrf] [-s Hz] [-b 8|16] [-B kilobytes] [filename]
+
+ -h, --help Print help, then exit
+ -v, --version Print version, then exit
+ -V, --verbose Print useful information about the sample
+ -x, --swap Swap endianness
+ -r, --raw Force raw audio format. Ignore headers.
+ -f, --force Force playing with any parameters
+ -m, --mono Mono sample
+ -u, --usage Print buffer usage while playing
+ -s, --speed=SPEED Sample speed (Hz)
+ -b, --bytes=BYTES Bytes in a sample
+ -B, --buffer-size=SIZE Buffer size in (kB)
+
+Buffer size is defaulted to 512k. It is about 3 seconds CD audio
+(44100Hz/sample, 16bytes, stereo). If filename is not given, standard
+input is used. If -x (or --swap) flag is set, the byte order of
+audio sample is swapped before playing. The default is Intel little-
+endian which is mostly used in x86 machines. The world outside Intel
+is big-endian.
+Option -r (or --raw) forces tplay to handle the sample as an raw
+PCM audio sample. Sun audio or WAV headers are ignored.
+
+Requirements:
+
+ - Linux 2.0 or newer with audio card support
+ - POSIX thread library
+ - Audio card
+
+There are several POSIX thread libraries available. I used
+LinuxThreads by Xavier Leroy (Xavier.Leroy@inria.fr). LinuxThreads
+library use clone() that is provided by Linux 2.0 kernel.
+
+The code:
+
+tplay starts one thread, named consumer, that reads circular audio
+buffer and writes it to audio device. The producer is a function that
+runs in parallel with the consumer and its task is to read the sample
+file or standard input and write this data to audio buffer to meet
+consumer's needs. Usually, the buffer is full but on the times when
+CPU-time is suddenly needed for other processes (usually: disk
+read/write), the producer can't write fast enough and consumer can use
+the buffer to keep audio stream uninterrupted. If the buffer is used
+and the producer is still unable to feed it fast enough, underflow
+situation is met and consumer waits for awhile (typically: one second)
+for the producer to fill the buffer again.
+
+Building:
+
+If you want to link tplay with static libpthread library, edit
+Makefile and uncomment preferred LIBS-setting there. Type:
+
+ - make
+ - make install
+ - make install.man
+
+Thanks:
+
+Jerko Golubovic <jerko.golubovic@public.srce.hr>
+Jukka Palviainen <oh3kjt@ele.tut.fi>
+
+TODO:
+
+Find out the best sizes for the audio buffer and one block.
+Better documentation.
+Better RIFF/WAVE checking.
+
+Ilkka Karvinen
+ik@iki.fi
+
+
+
+
+
diff --git a/mpeglib/lib/tplay/au.cpp b/mpeglib/lib/tplay/au.cpp
new file mode 100644
index 00000000..8880515f
--- /dev/null
+++ b/mpeglib/lib/tplay/au.cpp
@@ -0,0 +1,100 @@
+/*
+ * tplay - buffered audio player
+ *
+ * (c) 1997 ilkka karvinen <ik@iki.fi>
+ *
+ * Copyright under the GNU GENERAL PUBLIC LICENSE
+ * (see the file COPYING in this directory)
+ *
+ *
+ * SunOS audio file header functions.
+ * Reference: http://www.wotsit.org
+ */
+
+#include "tplayfunctions.h"
+
+/* read_au returns zero if Sun audio file format is found. */
+int read_au(struct info_struct* info,char * buffer) {
+ DWORD magic, start, end, encoding, speed, channels;
+ int bits;
+
+
+ /* If '.snd'-header exits, this should be an au-file */
+ magic = read_big_endian_long(buffer);
+ if (magic != SUN_MAGIC)
+ return (1);
+
+ start = read_big_endian_long(buffer + 0x04);
+ end = read_big_endian_long(buffer + 0x08);
+ encoding = read_big_endian_long(buffer + 0x0C);
+ speed = read_big_endian_long(buffer + 0x10);
+ channels = read_big_endian_long(buffer + 0x14);
+
+#ifdef DEBUG
+ printf("Sun audio file.\nspeed: %ld, start: %ld, end: %ld, \
+encoding: %X, channels: %ld\n",
+ speed, start, end, encoding, channels);
+ fflush(stdout);
+#endif
+
+ bits = DEFAULT_BITS;
+ switch (encoding) {
+ case 1:
+ die("8-bit ISDN u-law Sun audio file not supported");
+ break;
+ case 2:
+ bits = 8;
+ break;
+ case 3:
+ bits = 16;
+ break;
+ case 4:
+ die("24-bit linear PCM Sun audio file not supported");
+ break;
+ case 5:
+ die("32-bit linear PCM Sun audio file not supported");
+ break;
+ case 6:
+ die("32-bit IEEE floating point Sun audio file not supported");
+ break;
+ case 7:
+ die("64-bit IEEE floating point Sun audio file not supported");
+ break;
+ case 23:
+ die("8-bit ISDN u-law compressed(G.721 ADPCM) Sun audio file \
+not supported");
+ break;
+ default:
+ errdie("Unknown Sun audio file");
+ break;
+ }
+
+ info->filetype = SUN_FILE;
+
+ /* Set audio parameters */
+ info->speed = (int) speed;
+ info->bits = bits;
+ info->channels = (int) channels;
+
+ if (info->verbose) {
+ printf("Sun audio file: %ld samples/s, %d bits, %d channel(s).\n",
+ info->speed, info->bits, info->channels);
+ /*
+ if ((comment_size = start - SUN_HDRSIZE) > 0) {
+ printf("Header info: ");
+ for (i = 0; i < comment_size; i++)
+ nice_fputc((int) buffer[SUN_HDRSIZE + i], stdout);
+ printf("\n");
+ }
+ */
+ }
+
+ /* Move data to start from the beginning of the buffer. */
+ /* This is to ensure the correct behaviour of rounding when 16bits */
+ /* and/or stereo sample is to be played. */
+ memmove(buffer, buffer + (start + 1), info->blocksize - start - 1);
+
+ info->headerskip = (int) (start + 1);
+
+ return (0);
+}
diff --git a/mpeglib/lib/tplay/tplayfunctions.cpp b/mpeglib/lib/tplay/tplayfunctions.cpp
new file mode 100644
index 00000000..c105f4a2
--- /dev/null
+++ b/mpeglib/lib/tplay/tplayfunctions.cpp
@@ -0,0 +1,84 @@
+/*
+ * tplay - buffered audio player
+ *
+ * (c) 1997 ilkka karvinen <ik@iki.fi>
+ *
+ * Copyright under the GNU GENERAL PUBLIC LICENSE
+ * (see the file COPYING in this directory)
+ *
+ *
+ * common functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "tplayfunctions.h"
+
+DWORD read_big_endian_long(char * buf)
+{
+ DWORD byte0, byte1, byte2, byte3;
+ unsigned char* buffer=(unsigned char*) buf;
+
+ byte0 = (DWORD) buffer[0];
+ byte1 = (DWORD) buffer[1];
+ byte2 = (DWORD) buffer[2];
+ byte3 = (DWORD) buffer[3];
+ return (byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3);
+}
+
+void write_big_endian_long(char * buf, DWORD value)
+{
+ unsigned char* buffer=(unsigned char*) buf;
+ buffer[0] = (unsigned char) (value >> 24 & 0xFF);
+ buffer[1] = (unsigned char) (value >> 16 & 0xFF);
+ buffer[2] = (unsigned char) (value >> 8 & 0xFF);
+ buffer[3] = (unsigned char) (value & 0xFF);
+}
+
+DWORD read_little_endian_long(char* buf) {
+ DWORD byte0, byte1, byte2, byte3;
+ unsigned char* buffer=(unsigned char*) buf;
+
+ byte0 = (DWORD) buffer[0];
+ byte1 = (DWORD) buffer[1];
+ byte2 = (DWORD) buffer[2];
+ byte3 = (DWORD) buffer[3];
+ return (byte3 << 24 | byte2 << 16 | byte1 << 8 | byte0);
+}
+
+WORD read_little_endian_word(char * buf)
+{
+ WORD byte0, byte1;
+ unsigned char* buffer=(unsigned char*) buf;
+
+ byte0 = (WORD) buffer[0];
+ byte1 = (WORD) buffer[1];
+ return (byte1 << 8 | byte0);
+}
+
+void errprintf(char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+}
+
+
+
+void die(const char *str)
+{
+ fprintf(stderr, "%s: \n", str);
+ exit(-1);
+}
+
+void errdie(const char *str)
+{
+ fprintf(stderr, "Error: %s\n", str);
+ exit(-1);
+}
+
+
+
diff --git a/mpeglib/lib/tplay/tplayfunctions.h b/mpeglib/lib/tplay/tplayfunctions.h
new file mode 100644
index 00000000..0c159847
--- /dev/null
+++ b/mpeglib/lib/tplay/tplayfunctions.h
@@ -0,0 +1,128 @@
+/*
+ * tplay - buffered audio player header file
+ *
+ * (c) 1997 ilkka karvinen <ik@iki.fi>
+ *
+ * Copyright under the GNU GENERAL PUBLIC LICENSE
+ * (see the file COPYING in this directory)
+ *
+ */
+
+#ifndef __TPLAYCONTROL_H
+#define __TPLAYCONTROL_H
+
+extern "C" {
+#include <stdio.h>
+#include <string.h>
+}
+
+/* tplay version */
+#define MAJOR_VERSION 0
+#define MINOR_VERSION 5
+#define PATCHLEVEL 5
+
+/* Default audio parameters */
+#define DEFAULT_BITS 16
+#define DEFAULT_SPEED 44100
+#define DEFAULT_CHANNELS 2
+
+/* Audio memory pool. 512k is the default. */
+#define BUFFER_SIZE 0x80000
+
+/* The minimum and maximum buffer block sizes. */
+#if 0
+#define MIN_BLOCK_SIZE 0x4000 /* 16k */
+#else
+#define MIN_BLOCK_SIZE 4096
+#endif
+#define MAX_BLOCK_SIZE 0x10000 /* 64k */
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/* The maximum retry count for buffer fill tries. */
+#define RETRY_COUNT 5
+
+/* Magics. Little-endian. */
+#define RIFF_MAGIC 0x46464952 /* ASCII: 'RIFF' */
+#define WAVE_MAGIC 0x45564157 /* ASCII: 'WAVE' */
+#define DATA_MAGIC 0x61746164 /* ASCII: 'data' */
+#define INFO_MAGIC 0x4f464e49 /* ASCII: 'INFO' */
+#define SUN_MAGIC 0x2e736e64 /* ASCII: '.snd' */
+
+/* Magics. Big-endian. */
+#define SUN_INV_MAGIC 0x646e732e /* ASCII: '.snd' */
+
+/* Sun headersize */
+#define SUN_HDRSIZE 24
+
+/* File types */
+#define UNKNOWN_FILE 0
+#define RIFF_FILE 1
+#define SUN_FILE 2
+
+typedef unsigned long DWORD;
+typedef unsigned short WORD;
+
+/* Circular buffer info structure of audio data blocks. */
+/* declared in tplay.c */
+struct info_struct {
+ char *buffer; /* the audio data */
+ char *firstblock; /* pointer to the first block */
+ int readblock, writeblock; /* reading and writing block number */
+ long readcount, writecount;
+ int alldone;
+ int in_seconds;
+ double seconds;
+ int blocksize; /* size of one block */
+ int buffer_size; /* size of the buffer */
+ int number_of_blocks;
+ int last_block; /* -1 if not the last block */
+ int bytes_on_last_block;
+ int overflow;
+ int underflow;
+ int swap;
+ int forceraw;
+ int force;
+ int filetype;
+ int headerskip;
+ int audioset;
+ int show_usage;
+ DWORD speed;
+ int channels;
+ int bits;
+ char *progname;
+ char *device; /* Audio device name */
+ int loop;
+ int verbose;
+ int optind;
+};
+
+/* au.c */
+ int read_au(struct info_struct* info, char * buffer);
+
+/* wav.c */
+ int read_wav(struct info_struct* info, char * buffer);
+
+/* common.c */
+ DWORD read_big_endian_long(char * buffer);
+ void write_big_endian_long(char * buffer, DWORD value);
+ DWORD read_little_endian_long(char * buffer);
+ WORD read_little_endian_word(char * buffer);
+ void errprintf(char *fmt,...);
+ void warning(char *str);
+ void warning2(char *str1, char *str2);
+ void die(const char *str);
+ void errdie(const char *str);
+ void open_audio();
+ void set_audio_parameters();
+ void sync_audio(void);
+ void reset_audio(void);
+ void post_audio(void);
+ void destroy_buffer(void);
+ void nice_fputc(int c, FILE * fp);
+
+
+#endif
diff --git a/mpeglib/lib/tplay/wav.cpp b/mpeglib/lib/tplay/wav.cpp
new file mode 100644
index 00000000..ca284c37
--- /dev/null
+++ b/mpeglib/lib/tplay/wav.cpp
@@ -0,0 +1,91 @@
+/*
+ * tplay - buffered audio player
+ *
+ * (c) 1997 ilkka karvinen <ik@iki.fi>
+ *
+ * Copyright under the GNU GENERAL PUBLIC LICENSE
+ * (see the file COPYING in this directory)
+ *
+ *
+ * RIFF/WAVE file header checking.
+ * check_wav returns zero if RIFF/WAVE file format is found.
+ * Reference: http://www.wotsit.demon.co.uk/formats/wav/wav.txt
+ */
+
+#include "tplayfunctions.h"
+
+#include <iostream>
+
+using namespace std;
+
+int read_wav(struct info_struct* info, char * buffer) {
+ WORD format, channels, bits;
+ DWORD magic, samples_per_second, length, data_length;
+
+ magic = read_little_endian_long(buffer);
+ if (magic != RIFF_MAGIC) /* RIFF file? */
+ return (1);
+ magic = read_little_endian_long(buffer + 0x08);
+ if (magic != WAVE_MAGIC) /* WAVE file? */
+ return (1);
+ magic = read_little_endian_long(buffer + 0x24);
+ if ((magic != DATA_MAGIC) && (magic != INFO_MAGIC)) { /* data-portion there? */
+ cout << "Unknown WAV-header magic. Continuing anyway."<<endl;
+ }
+
+ length = read_little_endian_long(buffer + 0x10);
+
+ /* Subchunk length should be 16 here */
+ if (length != 16)
+ errdie("Unknown RIFF/WAVE header");
+
+ format = read_little_endian_word(buffer + 0x14);
+
+ switch (format) {
+ case 0x0001: /* PCM format */
+ break;
+ case 0x0101: /* mu-law */
+ die("Mu-law RIFF/WAVE audio file not supported");
+ break;
+ case 0x0102: /* a-law */
+ die("A-law RIFF/WAVE audio file not supported");
+ break;
+ case 0x0103: /* ADPCM */
+ die("ADPCM RIFF/WAVE audio file not supported");
+ break;
+ default:
+ errdie("Unknown RIFF/WAVE audio file format");
+ break;
+ }
+
+ info->filetype = RIFF_FILE;
+
+ channels = read_little_endian_word(buffer + 0x16);
+ samples_per_second = read_little_endian_long(buffer + 0x18);
+ cout << "samples_per_second:"<<samples_per_second<<endl;
+ bits = read_little_endian_word(buffer + 0x22);
+
+ if (bits == 12)
+ die("12 bits per sample not supported");
+
+ data_length = read_little_endian_long(buffer + 0x28);
+
+ /* Set audio parameters */
+ info->speed = (int) samples_per_second;
+ info->bits = (int) bits;
+ info->channels = (int) channels;
+
+ if (info->verbose)
+ printf("RIFF/WAVE audio file: %ld samples/s, %d bits, %d channel(s).\n",
+ info->speed, info->bits, info->channels);
+
+ /* Move data to start from the beginning of the buffer. */
+ /* This is to ensure the correct behaviour of rounding when 16bits */
+ /* and/or stereo sample is to be played. */
+ memmove(buffer, buffer + 0x2c, info->blocksize - 0x2c);
+
+ /* Save audio sample starting point */
+ info->headerskip = 0x2c;
+
+ return (0);
+}