Mercurial > hg > xemacs-beta
view src/miscplay.c @ 5882:bbe4146603db
Reduce regexp usage, now CL-oriented non-regexp code available, core Lisp
lisp/ChangeLog addition:
2015-04-01 Aidan Kehoe <kehoea@parhasard.net>
When calling #'string-match with a REGEXP without regular
expression special characters, call #'search, #'mismatch, #'find,
etc. instead, making our code less likely to side-effect other
functions' match data and a little faster.
* apropos.el (apropos-command):
* apropos.el (apropos):
Call (position ?\n ...) rather than (string-match "\n" ...) here.
* buff-menu.el:
* buff-menu.el (buffers-menu-omit-invisible-buffers):
Don't fire up the regexp engine just to check if a string starts
with a space.
* buff-menu.el (select-buffers-tab-buffers-by-mode):
Don't fire up the regexp engine just to compare mode basenames.
* buff-menu.el (format-buffers-tab-line):
* buff-menu.el (build-buffers-tab-internal): Moved to being a
label within the following.
* buff-menu.el (buffers-tab-items): Use the label.
* bytecomp.el (byte-compile-log-1):
Don't fire up the regexp engine just to look for a newline.
* cus-edit.el (get):
Ditto.
* cus-edit.el (custom-variable-value-create):
Ditto, but for a colon.
* descr-text.el (describe-text-sexp):
Ditto.
* descr-text.el (describe-char-unicode-data):
Use #'split-string-by-char given that we're just looking for a
semicolon.
* descr-text.el (describe-char):
Don't fire up the regexp engine just to look for a newline.
* disass.el (disassemble-internal):
Ditto.
* files.el (file-name-sans-extension):
Implement this using #'position.
* files.el (file-name-extension):
Correct this function's docstring, implement it in terms of
#'position.
* files.el (insert-directory):
Don't fire up the regexp engine to split a string by space; don't
reverse the list of switches, this is actually a longstand bug as
far as I can see.
* gnuserv.el (gnuserv-process-filter):
Use #'position here, instead of consing inside #'split-string
needlessly.
* gtk-file-dialog.el (gtk-file-dialog-update-dropdown):
Use #'split-string-by-char here, don't fire up #'split-string for
directory-sep-char.
* gtk-font-menu.el (hack-font-truename):
Implement this more cheaply in terms of #'find,
#'split-string-by-char, #'equal, rather than #'string-match,
#'split-string, #'string-equal.
* hyper-apropos.el (hyper-apropos-grok-functions):
* hyper-apropos.el (hyper-apropos-grok-variables):
Look for a newline using #'position rather than #'string-match in
these functions.
* info.el (Info-insert-dir):
* info.el (Info-insert-file-contents):
* info.el (Info-follow-reference):
* info.el (Info-extract-menu-node-name):
* info.el (Info-menu):
Look for fixed strings using #'position or #'search as appropriate
in this file.
* ldap.el (ldap-decode-string):
* ldap.el (ldap-encode-string):
#'encode-coding-string, #'decode-coding-string are always
available, don't check if they're fboundp.
* ldap.el (ldap-decode-address):
* ldap.el (ldap-encode-address):
Use #'split-string-by-char in these functions.
* lisp-mnt.el (lm-creation-date):
* lisp-mnt.el (lm-last-modified-date):
Don't fire up the regexp engine just to look for spaces in this file.
* menubar-items.el (default-menubar):
Use (not (mismatch ...)) rather than #'string-match here, for
simple regexp.
Use (search "beta" ...) rather than (string-match "beta" ...)
* menubar-items.el (sort-buffers-menu-alphabetically):
* menubar-items.el (sort-buffers-menu-by-mode-then-alphabetically):
* menubar-items.el (group-buffers-menu-by-mode-then-alphabetically):
Don't fire up the regexp engine to check if a string starts with
a space or an asterisk.
Use the more fine-grained results of #'compare-strings; compare
case-insensitively for the buffer menu.
* menubar-items.el (list-all-buffers):
* menubar-items.el (tutorials-menu-filter):
Use #'equal rather than #'string-equal, which, in this context,
has the drawback of not having a bytecode, and no redeeming
features.
* minibuf.el:
* minibuf.el (un-substitute-in-file-name):
Use #'count, rather than counting the occurences of $ using the
regexp engine.
* minibuf.el (read-file-name-internal-1):
Don't fire up the regexp engine to search for ?=.
* mouse.el (mouse-eval-sexp):
Check for newline with #'find.
* msw-font-menu.el (mswindows-reset-device-font-menus):
Split a string by newline with #'split-string-by-char.
* mule/japanese.el:
* mule/japanese.el ("Japanese"):
Use #'search rather than #'string-match; canoncase before
comparing; fix a bug I had introduced where I had been making case
insensitive comparisons where the case mattered.
* mule/korea-util.el (default-korean-keyboard):
Look for ?3 using #'find, not #'string-march.
* mule/korea-util.el (quail-hangul-switch-hanja):
Search for a fixed string using #'search.
* mule/mule-cmds.el (set-locale-for-language-environment):
#'position, #'substitute rather than #'string-match,
#'replace-in-string.
* newcomment.el (comment-make-extra-lines):
Use #'search rather than #'string-match for a simple string.
* package-get.el (package-get-remote-filename):
Use #'position when looking for ?@
* process.el (setenv):
* process.el (read-envvar-name):
Use #'position when looking for ?=.
* replace.el (map-query-replace-regexp):
Use #'split-string-by-char instead of using an inline
implementation of it.
* select.el (select-convert-from-cf-text):
* select.el (select-convert-from-cf-unicodetext):
Use #'position rather than #'string-match in these functions.
* setup-paths.el (paths-emacs-data-root-p):
Use #'search when looking for simple string.
* sound.el (load-sound-file):
Use #'split-string-by-char rather than an inline reimplementation
of same.
* startup.el (splash-screen-window-body):
* startup.el (splash-screen-tty-body):
Search for simple strings using #'search.
* version.el (emacs-version):
Ditto.
* x-font-menu.el (hack-font-truename):
Implement this more cheaply in terms of #'find,
#'split-string-by-char, #'equal, rather than #'string-match,
#'split-string, #'string-equal.
* x-font-menu.el (x-reset-device-font-menus-core):
Use #'split-string-by-char here.
* x-init.el (x-initialize-keyboard):
Search for a simple string using #'search.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Wed, 01 Apr 2015 14:28:20 +0100 |
parents | ecf1ebac70d8 |
children |
line wrap: on
line source
/* miscplay.c - general routines related to playing sounds ** ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de) ** This was sawed out from version 1.3 of linuxplay.c by ** Robert Bihlmeyer <robbe@orcus.priv.at>. ** ** Parts of this code were inspired by sunplay.c, which is copyright 1989 by ** Jef Poskanzer and 1991,92 by Jamie Zawinski; c.f. sunplay.c for further ** information. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ /* Synched up with: Not in FSF. */ /* This file Mule-ized by Ben Wing, 5-15-01. */ #include <config.h> #include "lisp.h" #include "miscplay.h" #include "sound.h" #include "syssignal.h" #include "sysfile.h" /* Maintain global variable for keeping parser state information; this struct is set to zero before the first invocation of the parser. The use of a global variable prevents multiple concurrent executions of this code, but this does not happen anyways... */ enum wvState { wvMain, wvSubchunk, wvOutOfBlock, wvSkipChunk, wvSoundChunk, wvFatal, wvFatalNotify }; static union { struct { int align; enum wvState state; size_t left; Binbyte leftover[HEADERSZ]; signed long chunklength; } wave; struct { int align; int isdata; int skipping; size_t left; Binbyte leftover[HEADERSZ]; } audio; } parsestate; /* Use a global buffer as scratch-pad for possible conversions of the sampling format */ Binbyte miscplay_sndbuf[SNDBUFSZ]; /* Initialize global parser state information to zero */ void reset_parsestate() { memset(&parsestate,0,sizeof(parsestate)); } /* Verify that we could fully parse the entire soundfile; this is needed only for files in WAVE format */ int parse_wave_complete() { if (parsestate.wave.state != wvOutOfBlock && parsestate.wave.state != wvFatal) { sound_warn("Unexpected end of WAVE file"); return 0; } else return 1; } /* There is no special treatment required for parsing raw data files; we assume that these files contain data in 8bit unsigned format that has been sampled at 8kHz; there is no extra header */ static size_t parseraw(void **data,size_t *sz,void **outbuf) { int rc = *sz; *outbuf = *data; *sz = 0; return(rc); } /* Currently we cannot cope with files in VOC format; if you really need to play these files, they should be converted by using SOX */ static size_t parsevoc(void **UNUSED (data), size_t *UNUSED (sz), void **UNUSED (outbuf)) { return(0); } /* We need to perform some look-ahead in order to parse files in WAVE format; this might require re-partioning of the data segments if headers cross the boundaries between two read operations. This is done in a two-step way: first we request a certain amount of bytes... */ static int waverequire(void **data,size_t *sz,size_t rq) { int rc = 1; if (rq > HEADERSZ) { sound_warn("Header size exceeded while parsing WAVE file"); parsestate.wave.state = wvFatal; *sz = 0; return(0); } if ((rq -= parsestate.wave.left) <= 0) return(rc); if (rq > *sz) {rq = *sz; rc = 0;} memcpy(parsestate.wave.leftover+parsestate.wave.left, *data,rq); parsestate.wave.left += rq; (*(Binbyte **)data) += rq; *sz -= rq; return(rc); } /* ...and next we remove this many bytes from the buffer */ static inline void waveremove(size_t rq) { if (parsestate.wave.left <= rq) parsestate.wave.left = 0; else { parsestate.wave.left -= rq; memmove(parsestate.wave.leftover, parsestate.wave.leftover+rq, parsestate.wave.left); } return; } /* Sound files in WAVE format can contain an arbitrary amount of tagged chunks; this requires quite some effort for parsing the data */ static size_t parsewave(void **data,size_t *sz,void **outbuf) { for (;;) switch (parsestate.wave.state) { case wvMain: if (!waverequire(data,sz,20)) return(0); /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ parsestate.wave.chunklength = parsestate.wave.leftover[16] + 256*(parsestate.wave.leftover[17] + 256*(parsestate.wave.leftover[18] + 256*parsestate.wave.leftover[19])); waveremove(20); parsestate.wave.state = wvSubchunk; break; case wvSubchunk: if (!waverequire(data,sz,parsestate.wave.chunklength)) return(0); parsestate.wave.align = parsestate.wave.chunklength < 14 ? 1 : parsestate.wave.leftover[12]; if (parsestate.wave.align != 1 && parsestate.wave.align != 2 && parsestate.wave.align != 4) { sound_warn("Illegal datawidth detected while parsing WAVE file"); parsestate.wave.state = wvFatal; } else parsestate.wave.state = wvOutOfBlock; waveremove(parsestate.wave.chunklength); break; case wvOutOfBlock: if (!waverequire(data,sz,8)) return(0); /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ parsestate.wave.chunklength = parsestate.wave.leftover[4] + 256*(parsestate.wave.leftover[5] + 256*(parsestate.wave.leftover[6] + 256*(parsestate.wave.leftover[7] & 0x7F))); if (memcmp(parsestate.wave.leftover,"data",4)) parsestate.wave.state = wvSkipChunk; else parsestate.wave.state = wvSoundChunk; waveremove(8); break; case wvSkipChunk: if (parsestate.wave.chunklength > 0 && *sz > 0 && (signed long)*sz < (signed long)parsestate.wave.chunklength) { parsestate.wave.chunklength -= *sz; *sz = 0; } else { if (parsestate.wave.chunklength > 0 && *sz > 0) { *sz -= parsestate.wave.chunklength; (*(Binbyte **)data) += parsestate.wave.chunklength; } parsestate.wave.state = wvOutOfBlock; } break; case wvSoundChunk: { size_t count,rq; if (parsestate.wave.left) { /* handle leftover bytes from last alignment operation */ count = parsestate.wave.left; rq = HEADERSZ-count; if (rq > (size_t) parsestate.wave.chunklength) rq = parsestate.wave.chunklength; if (!waverequire(data,sz,rq)) { parsestate.wave.chunklength -= parsestate.wave.left - count; return(0); } parsestate.wave.chunklength -= rq; *outbuf = parsestate.wave.leftover; parsestate.wave.left = 0; return(rq); } if (*sz >= (size_t) parsestate.wave.chunklength) { count = parsestate.wave.chunklength; rq = 0; } else { count = *sz; count -= rq = count % parsestate.wave.align; } *outbuf = *data; (*(Binbyte **)data) += count; *sz -= count; if ((parsestate.wave.chunklength -= count) < parsestate.wave.align) { parsestate.wave.state = wvOutOfBlock; /* Some broken software (e.g. SOX) attaches junk to the end of a sound chunk; so, let's ignore this... */ if (parsestate.wave.chunklength) parsestate.wave.state = wvSkipChunk; } else if (rq) /* align data length to a multiple of datasize; keep additional data in "leftover" buffer --- this is necessary to ensure proper functioning of the sndcnv... routines */ waverequire(data,sz,rq); return(count); } case wvFatalNotify: sound_warn("Irrecoverable error while parsing WAVE file"); parsestate.wave.state = wvFatal; break; case wvFatal: default: *sz = 0; return(0); } } /* Strip the header from files in Sun/DEC audio format; this requires some extra processing as the header can be an arbitrary size and it might result in alignment errors for subsequent conversions --- thus we do some buffering, where needed */ static size_t parsesundecaudio(void **data,size_t *sz,void **outbuf) { /* There is data left over from the last invocation of this function; join it with the new data and return a sound chunk that is as big as a single entry */ if (parsestate.audio.left) { if (parsestate.audio.left + *sz > (size_t) parsestate.audio.align) { int count; memmove(parsestate.audio.leftover + parsestate.audio.left, *data, count = parsestate.audio.align - parsestate.audio.left); *outbuf = parsestate.audio.leftover; *sz -= count; *data = (*(CBinbyte **)data) + count; parsestate.audio.left = 0; return(parsestate.audio.align); } else { /* We need even more data in order to get one complete single entry! */ memmove(parsestate.audio.leftover + parsestate.audio.left, *data, *sz); *data = (*(CBinbyte **)data) + *sz; parsestate.audio.left += *sz; *sz = 0; return(0); } } /* This is the main sound chunk, strip of any extra data that does not fit the alignment requirements and move these bytes into the leftover buffer*/ if (parsestate.audio.isdata) { int rc = *sz; *outbuf = *data; if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) { memmove(parsestate.audio.leftover, (CBinbyte *)*outbuf + rc - parsestate.audio.left, parsestate.audio.left); rc -= parsestate.audio.left; } *sz = 0; return(rc); } /* This is the first invocation of this function; we need to parse the header information and determine how many bytes we need to skip until the start of the sound chunk */ if (!parsestate.audio.skipping) { Binbyte *header = (Binbyte *) *data; if (*sz < 8) { sound_warn("Irrecoverable error while parsing Sun/DEC audio file"); return(0); } /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ if (header[3]) { /* Sun audio (big endian) */ parsestate.audio.align = ((header[15] > 2)+1)*header[23]; parsestate.audio.skipping = header[7]+256*(header[6]+256* (header[5]+256*header[4])); } else { /* DEC audio (little endian) */ parsestate.audio.align = ((header[12] > 2)+1)*header[20]; parsestate.audio.skipping = header[4]+256*(header[5]+256* (header[6]+256*header[7])); }} /* We are skipping extra data that has been attached to header; most usually this will be just a comment, such as the original filename and/or the creation date. Make sure that we do not return less than one single sound sample entry to the caller; if this happens, rather decide to move those few bytes into the leftover buffer and deal with it later */ if (*sz >= (size_t) parsestate.audio.skipping) { /* Skip just the header information and return the sound chunk */ int rc = *sz - parsestate.audio.skipping; *outbuf = (CBinbyte *)*data + parsestate.audio.skipping; if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) { memmove(parsestate.audio.leftover, (CBinbyte *)*outbuf + rc - parsestate.audio.left, parsestate.audio.left); rc -= parsestate.audio.left; } *sz = 0; parsestate.audio.skipping = 0; parsestate.audio.isdata++; return(rc); } else { /* Skip everything */ parsestate.audio.skipping -= *sz; return(0); } } /* If the soundcard could not be set to natively support the data format, we try to do some limited on-the-fly conversion to a different format; if no conversion is needed, though, we can output directly */ size_t sndcnvnop(void **data,size_t *sz,void **outbuf) { int rc = *sz; *outbuf = *data; *sz = 0; return(rc); } /* Convert 8 bit unsigned stereo data to 8 bit unsigned mono data */ size_t sndcnv8U_2mono(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; count = *sz / 2; if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; while (count--) { *dest++ = (Binbyte)(((int)*(src) + (int)*(src+1)) / 2); src += 2; } *data = src; return(rc); } /* Convert 8 bit signed stereo data to 8 bit signed mono data */ size_t sndcnv8S_2mono(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc, count; count = *sz / 2; if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; while (count--) { *dest++ = (Binbyte)(((int)*((SBinbyte *)(src)) + (int)*((SBinbyte *)(src+1))) / 2); src += 2; } *data = src; return(rc); } /* Convert 8 bit signed stereo data to 8 bit unsigned mono data */ size_t sndcnv2monounsigned(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; count = *sz / 2; if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; while (count--) { *dest++ = (Binbyte)(((int)*((SBinbyte *)(src)) + (int)*((SBinbyte *)(src+1))) / 2) ^ 0x80; src += 2; } *data = src; return(rc); } /* Convert 8 bit signed mono data to 8 bit unsigned mono data */ size_t sndcnv2unsigned(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; count = *sz; if (count > SNDBUFSZ) { *sz -= SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; while (count--) *dest++ = *(src)++ ^ 0x80; *data = src; return(rc); } /* Convert a number in the range -32768..32767 to an 8 bit ulaw encoded number --- I hope, I got this conversion right :-) */ static inline SBinbyte int2ulaw(int i) { /* Lookup table for fast calculation of number of bits that need shifting*/ static short int t_bits[128] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; REGISTER int bits,logi; /* unrolling this condition (hopefully) improves execution speed */ if (i < 0) { if ((i = (132-i)) > 0x7FFF) i = 0x7FFF; logi = (i >> ((bits = t_bits[i/256])+4)); return((bits << 4 | logi) ^ 0x7F); } else { if ((i = 132+i) > 0x7FFF) i = 0x7FFF; logi = (i >> ((bits = t_bits[i/256])+4)); return(~(bits << 4 | logi)); } } /* Convert from 8 bit ulaw mono to 8 bit linear mono */ size_t sndcnvULaw_2linear(void **data,size_t *sz,void **outbuf) { /* conversion table stolen from Linux's ulaw.h */ static Binbyte ulaw_dsp[] = { 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 124, 125, 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 253, 249, 245, 241, 237, 233, 229, 225, 221, 217, 213, 209, 205, 201, 197, 193, 190, 188, 186, 184, 182, 180, 178, 176, 174, 172, 170, 168, 166, 164, 162, 160, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 143, 142, 142, 141, 141, 140, 140, 139, 139, 138, 138, 137, 137, 136, 136, 135, 135, 135, 134, 134, 134, 134, 133, 133, 133, 133, 132, 132, 132, 132, 131, 131, 131, 131, 131, 131, 130, 130, 130, 130, 130, 130, 130, 130, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, }; Binbyte *p=(Binbyte *)*data; *outbuf = *data; while ((*sz)--) { *p = ulaw_dsp[*p]; p++; } *sz = 0; *data = p; return p - (Binbyte *)*outbuf; } /* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */ size_t sndcnvULaw_2mono(void **data,size_t *sz,void **outbuf) { static short int ulaw2int[256] = { /* Precomputed lookup table for conversion from ulaw to 15 bit signed */ -16062,-15550,-15038,-14526,-14014,-13502,-12990,-12478, -11966,-11454,-10942,-10430, -9918, -9406, -8894, -8382, -7998, -7742, -7486, -7230, -6974, -6718, -6462, -6206, -5950, -5694, -5438, -5182, -4926, -4670, -4414, -4158, -3966, -3838, -3710, -3582, -3454, -3326, -3198, -3070, -2942, -2814, -2686, -2558, -2430, -2302, -2174, -2046, -1950, -1886, -1822, -1758, -1694, -1630, -1566, -1502, -1438, -1374, -1310, -1246, -1182, -1118, -1054, -990, -942, -910, -878, -846, -814, -782, -750, -718, -686, -654, -622, -590, -558, -526, -494, -462, -438, -422, -406, -390, -374, -358, -342, -326, -310, -294, -278, -262, -246, -230, -214, -198, -186, -178, -170, -162, -154, -146, -138, -130, -122, -114, -106, -98, -90, -82, -74, -66, -60, -56, -52, -48, -44, -40, -36, -32, -28, -24, -20, -16, -12, -8, -4, +0, +16062,+15550,+15038,+14526,+14014,+13502,+12990,+12478, +11966,+11454,+10942,+10430, +9918, +9406, +8894, +8382, +7998, +7742, +7486, +7230, +6974, +6718, +6462, +6206, +5950, +5694, +5438, +5182, +4926, +4670, +4414, +4158, +3966, +3838, +3710, +3582, +3454, +3326, +3198, +3070, +2942, +2814, +2686, +2558, +2430, +2302, +2174, +2046, +1950, +1886, +1822, +1758, +1694, +1630, +1566, +1502, +1438, +1374, +1310, +1246, +1182, +1118, +1054, +990, +942, +910, +878, +846, +814, +782, +750, +718, +686, +654, +622, +590, +558, +526, +494, +462, +438, +422, +406, +390, +374, +358, +342, +326, +310, +294, +278, +262, +246, +230, +214, +198, +186, +178, +170, +162, +154, +146, +138, +130, +122, +114, +106, +98, +90, +82, +74, +66, +60, +56, +52, +48, +44, +40, +36, +32, +28, +24, +20, +16, +12, +8, +4, +0}; REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; count = *sz / 2; if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; while (count--) { /* it is not possible to directly interpolate between two ulaw encoded data bytes, thus we need to convert to linear format first and later we convert back to ulaw format */ *dest++ = int2ulaw(ulaw2int[*src] + ulaw2int[*(src+1)]); src += 2; } *data = src; return(rc); } size_t sndcnv16swap(void **data,size_t *sz,void **outbuf) { size_t cnt = *sz / 2; unsigned short *p; *outbuf = *data; p = (unsigned short *) *outbuf; while (cnt--) { *p = ((*p & 0x00ff) << 8) | (*p >> 8); p++; } *data = p; cnt = *sz; *sz = 0; return cnt; } /* Convert 16 bit little endian signed stereo data to 16 bit little endian signed mono data */ size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; signed short i; count = *sz / 2; if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; for (count /= 2; count--; ) { i = ((int)(src[0]) + 256*(int)(src[1]) + (int)(src[2]) + 256*(int)(src[3])) / 2; src += 4; *dest++ = (Binbyte)(i & 0xFF); *dest++ = (Binbyte)((i / 256) & 0xFF); } *data = src; return(rc); } /* Convert 16 bit big endian signed stereo data to 16 bit big endian signed mono data */ size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; signed short i; count = *sz / 2; if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; for (count /= 2; count--; ) { i = ((int)(src[1]) + 256*(int)(src[0]) + (int)(src[3]) + 256*(int)(src[2])) / 2; src += 4; *dest++ = (Binbyte)((i / 256) & 0xFF); *dest++ = (Binbyte)(i & 0xFF); } *data = src; return(rc); } /* Convert 16 bit little endian signed data to 8 bit unsigned data */ size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; count = *sz / 2; if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; while (count--) { *dest++ = (Binbyte)(((SBinbyte *)src)[1] ^ (SBinbyte)0x80); src += 2; } *data = src; return(rc); } /* Convert 16 bit big endian signed data to 8 bit unsigned data */ size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; count = *sz / 2; if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; while (count--) { *dest++ = (Binbyte)(((SBinbyte *)src)[0] ^ (SBinbyte)0x80); src += 2; } *data = src; return(rc); } /* Convert 16 bit little endian signed stereo data to 8 bit unsigned mono data */ size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; count = *sz / 4; if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; while (count--) { *dest++ = (Binbyte)(((int)((SBinbyte *)src)[1] + (int)((SBinbyte *)src)[3]) / 2 ^ 0x80); src += 4; } *data = src; return(rc); } /* Convert 16 bit big endian signed stereo data to 8 bit unsigned mono data */ size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf) { REGISTER Binbyte *src; REGISTER Binbyte *dest; int rc,count; count = *sz / 4; if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; } else *sz = 0; rc = count; src = (Binbyte *) *data; *outbuf = dest = miscplay_sndbuf; while (count--) { *dest++ = (Binbyte)(((int)((SBinbyte *)src)[0] + (int)((SBinbyte *)src)[2]) / 2 ^ 0x80); src += 4; } *data = src; return(rc); } /* Look at the header of the sound file and try to determine the format; we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything else is assumed to be raw 8 bit unsigned data sampled at 8kHz */ fmtType analyze_format(Binbyte *format,int *fmt,int *speed, int *tracks, size_t (**parsesndfile)(void **,size_t *sz, void **)) { /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ if (!memcmp(format,"Creative Voice File\x1A\x1A\x00",22) && (format[22]+256*format[23]) == ((0x1233-format[24]-256*format[25])&0xFFFF)) { /* VOC */ *fmt = AFMT_U8; *speed = 8000; *tracks = 2; *parsesndfile = parsevoc; return(fmtVoc); } else if (!memcmp(format,"RIFF",4) && !memcmp(format+8,"WAVEfmt ",8)) { /* WAVE */ if (memcmp(format+20,"\001\000\001"/* PCM mono */,4) && memcmp(format+20,"\001\000\002"/* PCM stereo */,4)) return(fmtIllegal); *fmt = (format[32]/(*tracks = format[22])) == 1 ? AFMT_U8 : AFMT_S16_LE; /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ *speed = format[24]+256*(format[25]+256* (format[26]+256*format[27])); *parsesndfile = parsewave; return(fmtWave); } else if (!memcmp(format,".snd",4)) { /* Sun Audio (big endian) */ if (format[7]+256*(format[6]+256*(format[5]+256*format[4])) < 24) { *fmt = AFMT_MU_LAW; *speed = 8000; *tracks = 1; *parsesndfile = parsesundecaudio; return(fmtSunAudio); } if (!memcmp(format+12,"\000\000\000\001",4)) *fmt = AFMT_MU_LAW; else if (!memcmp(format+12,"\000\000\000\002",4)) *fmt = AFMT_S8; else if (!memcmp(format+12,"\000\000\000\003",4)) *fmt = AFMT_S16_BE; else return(fmtIllegal); /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ *speed = format[19]+256*(format[18]+256* (format[17]+256*format[16])); *tracks = format[23]; *parsesndfile = parsesundecaudio; return(fmtSunAudio); } else if (!memcmp(format,".sd",4)) { /* DEC Audio (little endian) */ if (format[4]+256*(format[5]+256*(format[6]+256*format[7])) < 24) { *fmt = AFMT_MU_LAW; *speed = 8000; *tracks = 1; *parsesndfile = parsesundecaudio; return(fmtSunAudio); } if (!memcmp(format+12,"\001\000\000",4)) *fmt = AFMT_MU_LAW; else if (!memcmp(format+12,"\002\000\000",4)) *fmt = AFMT_S8; else if (!memcmp(format+12,"\003\000\000",4)) *fmt = AFMT_S16_LE; else return(fmtIllegal); /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ *speed = format[16]+256*(format[17]+256* (format[18]+256*format[19])); *tracks = format[20]; *parsesndfile = parsesundecaudio; return(fmtSunAudio); } else { *fmt = AFMT_U8; *speed = 8000; *tracks = 1; *parsesndfile = parseraw; return(fmtRaw); } }