mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1097 lines
30 KiB
1097 lines
30 KiB
/****************************************************************************
|
|
* NCSA Mosaic for Microsoft Windows *
|
|
* Software Development Group *
|
|
* National Center for Supercomputing Applications *
|
|
* University of Illinois at Urbana-Champaign *
|
|
* 605 E. Springfield, Champaign, IL 61820 *
|
|
* [email protected] *
|
|
* *
|
|
* Copyright (C) 1993, 1994, Board of Trustees of the University of Illinois *
|
|
* *
|
|
* NCSA Mosaic software, both binary and source (hereafter, Software) is *
|
|
* copyrighted by The Board of Trustees of the University of Illinois *
|
|
* (UI), and ownership remains with the UI. *
|
|
* *
|
|
* The UI grants you (hereafter, Licensee) a license to use the Software *
|
|
* for academic, research and internal business purposes only, without a *
|
|
* fee. Licensee may distribute the binary and source code (if released) *
|
|
* to third parties provided that the copyright notice and this statement *
|
|
* appears on all copies and that no charge is associated with such *
|
|
* copies. *
|
|
* *
|
|
* Licensee may make derivative works. However, if Licensee distributes *
|
|
* any derivative work based on or derived from the Software, then *
|
|
* Licensee will (1) notify NCSA regarding its distributing of the *
|
|
* derivative work, and (2) clearly notify users that such derivative *
|
|
* work is a modified version and not the original NCSA Mosaic *
|
|
* distributed by the UI. *
|
|
* *
|
|
* Any Licensee wishing to make commercial use of the Software should *
|
|
* contact the UI, c/o NCSA, to negotiate an appropriate license for such *
|
|
* commercial use. Commercial use included (1) integration of all or *
|
|
* part of the source code into a product for sale or license by or on *
|
|
* behalf of Licensee to third parties, or (2) distribution of the binary *
|
|
* code or source code to third parties that need it to utilize a *
|
|
* commercial product sold or licensed by or on behalf of Licensee. *
|
|
* *
|
|
* UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
|
|
* ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
|
|
* WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
|
|
* USERS OF THIS SOFTWARE. *
|
|
* *
|
|
* By using or copying this Software, Licensee agrees to abide by the *
|
|
* copyright law and all other applicable laws of the U.S. including, but *
|
|
* not limited to, export control laws, and the terms of this license. *
|
|
* UI shall have the right to terminate this license immediately by *
|
|
* written notice upon Licensee's breach of, or non-compliance with, any *
|
|
* of its terms. Licensee may be held legally responsible for any *
|
|
* copyright infringement that is caused or encouraged by Licensee's *
|
|
* failure to abide by the terms of this license. *
|
|
* *
|
|
****************************************************************************/
|
|
|
|
/*
|
|
Enhanced NCSA Mosaic from Spyglass
|
|
"Guitar"
|
|
|
|
Copyright 1994 Spyglass, Inc.
|
|
All Rights Reserved
|
|
|
|
Author(s):
|
|
Albert Lee [email protected]
|
|
|
|
Adapted from NCSA's AU.CPP. Significant changes have been made to code.
|
|
*/
|
|
|
|
#include "all.h"
|
|
#include "history.h"
|
|
|
|
#ifdef FEATURE_SOUND_PLAYER
|
|
|
|
#define BLOCK_SIZE 32768
|
|
|
|
int device_capability = DEVICE_8BIT;
|
|
|
|
static BOOL bInitialized = FALSE;
|
|
struct hash_table gSoundCache;
|
|
|
|
PRIVATE BOOL AuDecodeCharacter(struct SoundInfo *si, char c);
|
|
|
|
static short int ulaw_table[256] =
|
|
{
|
|
-32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
|
|
-23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
|
|
-15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
|
|
-11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
|
|
-7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
|
|
-5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
|
|
-3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
|
|
-2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
|
|
-1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
|
|
-1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
|
|
-876, -844, -812, -780, -748, -716, -684, -652,
|
|
-620, -588, -556, -524, -492, -460, -428, -396,
|
|
-372, -356, -340, -324, -308, -292, -276, -260,
|
|
-244, -228, -212, -196, -180, -164, -148, -132,
|
|
-120, -112, -104, -96, -88, -80, -72, -64,
|
|
-56, -48, -40, -32, -24, -16, -8, 0,
|
|
32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
|
|
23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
|
|
15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
|
|
11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
|
|
7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
|
|
5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
|
|
3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
|
|
2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
|
|
1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
|
|
1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
|
|
876, 844, 812, 780, 748, 716, 684, 652,
|
|
620, 588, 556, 524, 492, 460, 428, 396,
|
|
372, 356, 340, 324, 308, 292, 276, 260,
|
|
244, 228, 212, 196, 180, 164, 148, 132,
|
|
120, 112, 104, 96, 88, 80, 72, 64,
|
|
56, 48, 40, 32, 24, 16, 8, 0 };
|
|
|
|
|
|
void swapLongs(unsigned long *data, int n)
|
|
{
|
|
int idx;
|
|
unsigned char b;
|
|
unsigned char *bptr;
|
|
|
|
bptr = (unsigned char *) data;
|
|
for (idx = 0; idx < n; idx++, bptr += 4)
|
|
{
|
|
b = bptr[0];
|
|
bptr[0] = bptr[3];
|
|
bptr[3] = b;
|
|
b = bptr[1];
|
|
bptr[1] = bptr[2];
|
|
bptr[2] = b;
|
|
}
|
|
}
|
|
|
|
void swapShorts(unsigned short int *data, int n)
|
|
{
|
|
int idx;
|
|
unsigned char b;
|
|
unsigned char *bptr;
|
|
|
|
bptr = (unsigned char *) data;
|
|
for (idx = 0; idx < n; idx++, bptr += 2)
|
|
{
|
|
b = bptr[0];
|
|
bptr[0] = bptr[1];
|
|
bptr[1] = b;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL AuProcess(struct SoundInfo *si, const char *pszURL)
|
|
{
|
|
int i;
|
|
FILE *fp;
|
|
char *buf;
|
|
long size;
|
|
char status[128];
|
|
|
|
#ifdef WIN32
|
|
GetSoundCapability(); /* determine if 16-bit sound can be played */
|
|
#endif
|
|
|
|
si->count = 0;
|
|
si->bValid = TRUE;
|
|
si->state = 0;
|
|
si->magic = 0;
|
|
si->buf = NULL;
|
|
si->style = SIGN2;
|
|
si->size = 0;
|
|
si->swap = 0;
|
|
si->buf_size = 0;
|
|
si->data_size = (unsigned long) -1;
|
|
si->loc = 0;
|
|
|
|
fp = fopen(si->fsOrig, "rb");
|
|
if (!fp)
|
|
return FALSE;
|
|
|
|
fseek(fp, 0, SEEK_END);
|
|
size = ftell(fp);
|
|
fseek(fp, 0, SEEK_SET);
|
|
buf = GTR_MALLOC(size);
|
|
if (buf == NULL)
|
|
{
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
GTR_formatmsg(RES_STRING_AU1,status,sizeof(status));
|
|
WAIT_Push(si->tw_refer, waitNoInteract, status);
|
|
WAIT_SetRange(si->tw_refer, 0, 100, size);
|
|
|
|
// BUGBUG jcordell 06-23-95: fread failure not checked
|
|
fread(buf, 1, size, fp);
|
|
fclose(fp);
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
if (si->bValid) {
|
|
if ( !AuDecodeCharacter(si, buf[i]) ) {
|
|
si->bValid = FALSE;
|
|
break;
|
|
}
|
|
} else
|
|
break;
|
|
}
|
|
|
|
WAIT_Pop(si->tw_refer);
|
|
GTR_FREE(buf);
|
|
|
|
si->bValid = (si->bValid &&
|
|
(si->channels == 1 || si->channels == 2) &&
|
|
si->sample_rate >= 1000 &&
|
|
(si->size == 1 || si->size == 2));
|
|
if (si->bValid)
|
|
CreateSoundPlayer(si, pszURL);
|
|
else
|
|
ERR_ReportError(si->tw_refer, errInvalidSoundFormat, "", "");
|
|
|
|
return (si->bValid);
|
|
}
|
|
|
|
PRIVATE BOOL AuDecodeCharacter(struct SoundInfo *si, char c)
|
|
{
|
|
static unsigned long hdr;
|
|
static unsigned long chunksize;
|
|
static unsigned short int wTmp;
|
|
short int *ibuf;
|
|
char *buf2;
|
|
char *pb;
|
|
|
|
si->count++;
|
|
// BUGBUG performance: jcordell -- we could do the WAIT_SetTherm less often
|
|
WAIT_SetTherm(si->tw_refer, si->count);
|
|
|
|
switch (si->state)
|
|
{
|
|
case STATE_SPIN:
|
|
/* In case our data is bad or our state machine is hosed, just forget any data that comes in. */
|
|
si->bValid = FALSE;
|
|
break;
|
|
|
|
/* Read in the magic number */
|
|
case 0:
|
|
hdr = 0;
|
|
chunksize = 0;
|
|
wTmp = 0;
|
|
si->magic = (unsigned long) c;
|
|
si->state++;
|
|
break;
|
|
|
|
case 1:
|
|
si->magic |= ((unsigned long) c) << 8;
|
|
si->state++;
|
|
break;
|
|
|
|
case 2:
|
|
si->magic |= ((unsigned long) c) << 16;
|
|
si->state++;
|
|
break;
|
|
|
|
case 3:
|
|
si->magic |= ((unsigned long) c) << 24;
|
|
si->state++;
|
|
|
|
if (si->magic == DEC_INV_MAGIC)
|
|
{
|
|
XX_DMsg(DBG_MM, ("Found inverted DEC magic word (AU)\n"));
|
|
si->type = SOUND_AU;
|
|
si->swap = 1;
|
|
}
|
|
else if (si->magic == SUN_INV_MAGIC)
|
|
{
|
|
XX_DMsg(DBG_MM, ("Found inverted Sun/NeXT magic word (AU)\n"));
|
|
si->type = SOUND_AU;
|
|
si->swap = 1;
|
|
}
|
|
else if (si->magic == SUN_MAGIC)
|
|
{
|
|
XX_DMsg(DBG_MM, ("Found Sun/NeXT magic word (AU)\n"));
|
|
si->type = SOUND_AU;
|
|
si->swap = 0;
|
|
}
|
|
else if (si->magic == DEC_MAGIC)
|
|
{
|
|
XX_DMsg(DBG_MM, ("Found DEC magic word (AU)\n"));
|
|
si->type = SOUND_AU;
|
|
si->swap = 0;
|
|
}
|
|
else if (si->magic == AIFF_MAGIC)
|
|
{
|
|
XX_DMsg(DBG_MM, ("Found AIFF magic word (AIFF)\n"));
|
|
si->type = SOUND_AIFF;
|
|
si->swap = 0;
|
|
}
|
|
else if (si->magic == AIFF_INV_MAGIC)
|
|
{
|
|
XX_DMsg(DBG_MM, ("Found inverted AIFF magic word (AIFF)\n"));
|
|
si->type = SOUND_AIFF;
|
|
si->swap = 1;
|
|
}
|
|
else
|
|
{
|
|
XX_DMsg(DBG_MM, ("No magic word - trouble!\n"));
|
|
si->state = STATE_SPIN;
|
|
}
|
|
break;
|
|
|
|
/* Read the header size */
|
|
case 4:
|
|
si->hdr_size = (unsigned long) c;
|
|
si->state++;
|
|
break;
|
|
|
|
case 5:
|
|
si->hdr_size |= ((unsigned long) c) << 8;
|
|
si->state++;
|
|
break;
|
|
|
|
case 6:
|
|
si->hdr_size |= ((unsigned long) c) << 16;
|
|
si->state++;
|
|
break;
|
|
|
|
case 7:
|
|
si->hdr_size |= ((unsigned long) c) << 24;
|
|
si->state++;
|
|
if (si->swap)
|
|
swapLongs((unsigned long *) &si->hdr_size, 1);
|
|
|
|
if ((si->type == SOUND_AU) && (si->hdr_size >= SUN_HDRSIZE))
|
|
{
|
|
XX_DMsg(DBG_MM, ("Sun/DEC/NeXT header size: 0x%lx = %ld\n", si->hdr_size, si->hdr_size));
|
|
break;
|
|
}
|
|
|
|
if (si->type == SOUND_AIFF)
|
|
{
|
|
XX_DMsg(DBG_MM, ("AIFF total size: 0x%lx = %ld\n", si->hdr_size, si->hdr_size));
|
|
si->state = -1;
|
|
break;
|
|
}
|
|
|
|
XX_DMsg(DBG_MM, ("Incorrect header size\n"));
|
|
si->state=STATE_SPIN;
|
|
break;
|
|
|
|
/* Negative cases are all AIFF handling */
|
|
case -1:
|
|
hdr = ((unsigned long) c) << 24;
|
|
si->state--;
|
|
break;
|
|
|
|
case -2:
|
|
hdr |= ((unsigned long) c) << 16;
|
|
si->state--;
|
|
break;
|
|
|
|
case -3:
|
|
hdr |= ((unsigned long) c) << 8;
|
|
si->state--;
|
|
break;
|
|
|
|
case -4:
|
|
hdr |= ((unsigned long) c);
|
|
if (hdr != 0x41494646)
|
|
{
|
|
XX_DMsg(DBG_MM, ("FORM chunk does not specify AIFF type\n"));
|
|
si->state = STATE_SPIN;
|
|
break;
|
|
}
|
|
XX_DMsg(DBG_MM, ("FORM chunk specifies AIFF type\n"));
|
|
si->state--;
|
|
break;
|
|
|
|
case -5:
|
|
hdr = ((unsigned long) c) << 24;
|
|
si->state--;
|
|
break;
|
|
|
|
case -6:
|
|
hdr |= ((unsigned long) c) << 16;
|
|
si->state--;
|
|
break;
|
|
|
|
case -7:
|
|
hdr |= ((unsigned long) c) << 8;
|
|
si->state--;
|
|
break;
|
|
|
|
case -8:
|
|
hdr |= ((unsigned long) c);
|
|
si->state--;
|
|
break;
|
|
|
|
case -9:
|
|
chunksize = (unsigned long) c;
|
|
si->state--;
|
|
break;
|
|
|
|
case -10:
|
|
chunksize |= ((unsigned long) c) << 8;
|
|
si->state--;
|
|
break;
|
|
|
|
case -11:
|
|
chunksize |= ((unsigned long) c) << 16;
|
|
si->state--;
|
|
break;
|
|
|
|
case -12:
|
|
chunksize |= ((unsigned long) c) << 24;
|
|
swapLongs((unsigned long *) &chunksize, 1);
|
|
|
|
if (hdr == 0x434f4d4d)
|
|
{
|
|
XX_DMsg(DBG_MM, ("COMM chunk found\n"));
|
|
if (chunksize != 18)
|
|
{
|
|
XX_DMsg(DBG_MM, ("COMM chunk has incorrect chunksize 0x%lx\n", chunksize));
|
|
/*
|
|
// si->state = STATE_SPIN;
|
|
// break;
|
|
*/
|
|
}
|
|
si->state = -20;
|
|
break;
|
|
}
|
|
|
|
if (hdr == 0x53534e44)
|
|
{
|
|
XX_DMsg(DBG_MM, ("SSND chunk found\n"));
|
|
si->state = -14;
|
|
break;
|
|
}
|
|
XX_DMsg(DBG_MM, ("Unrecognized chunk 0x%lx found. Skipping\n", hdr));
|
|
si->state--;
|
|
break;
|
|
|
|
case -13:
|
|
chunksize--;
|
|
if (chunksize == 0)
|
|
si->state = -5;
|
|
break;
|
|
|
|
/* SSND chunk - read the offset */
|
|
case -14:
|
|
si->offset = (unsigned long) c;
|
|
si->state--;
|
|
break;
|
|
|
|
case -15:
|
|
si->offset |= ((unsigned long) c ) << 8;
|
|
si->state--;
|
|
break;
|
|
|
|
case -16:
|
|
si->offset |= ((unsigned long) c ) << 16;
|
|
si->state--;
|
|
break;
|
|
|
|
case -17:
|
|
si->offset |= ((unsigned long) c) << 24;
|
|
XX_DMsg(DBG_MM, ("AIFF offset is %lu\n",si->offset));
|
|
si->state--;
|
|
si->idx=0;
|
|
break;
|
|
|
|
case -18:
|
|
XX_DMsg(DBG_MM, ("Blocksize byte\n"));
|
|
if (c != 0)
|
|
{
|
|
XX_DMsg(DBG_MM, ("Blocksize is not zero!\n"));
|
|
si->state=STATE_SPIN;
|
|
break;
|
|
}
|
|
|
|
si->idx++;
|
|
if (si->idx > 3)
|
|
{
|
|
if (si->offset != 0)
|
|
si->state--;
|
|
else
|
|
{
|
|
si->buf = GTR_MALLOC(DATABLOCKSIZE);
|
|
if (si->buf == NULL)
|
|
return FALSE;
|
|
si->buf_size = DATABLOCKSIZE;
|
|
si->loc = 0;
|
|
si->state = 25;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case -19:
|
|
si->offset--;
|
|
if (si->offset == 0)
|
|
{
|
|
si->buf = GTR_MALLOC(DATABLOCKSIZE);
|
|
if (si->buf == NULL)
|
|
return FALSE;
|
|
si->buf_size = DATABLOCKSIZE;
|
|
si->loc = 0;
|
|
si->state=25;
|
|
}
|
|
break;
|
|
|
|
/* COMM chunk - Read the number of channels */
|
|
case -20:
|
|
wTmp = (unsigned short int) c;
|
|
si->state--;
|
|
break;
|
|
|
|
case -21:
|
|
wTmp |= ((unsigned short int) c) << 8;
|
|
swapShorts((unsigned short int *) &wTmp, 1);
|
|
si->channels = (unsigned long) wTmp;
|
|
XX_DMsg(DBG_MM, ("Number of channels: %ld\n",si->channels));
|
|
si->state--;
|
|
break;
|
|
|
|
/* Read the # of frames. (? Throw it away.) */
|
|
case -22:
|
|
case -23:
|
|
case -24:
|
|
case -25:
|
|
si->state--;
|
|
break;
|
|
|
|
case -26:
|
|
wTmp = (unsigned short int) c;
|
|
si->state--;
|
|
break;
|
|
|
|
case -27:
|
|
wTmp |= ((unsigned short int) c) << 8;
|
|
swapShorts((unsigned short int *) &wTmp, 1);
|
|
|
|
if (wTmp == 16)
|
|
si->size = SIZE_WORD;
|
|
else
|
|
si->size = SIZE_BYTE;
|
|
|
|
XX_DMsg(DBG_MM, ("Number of bits: %u\n", wTmp));
|
|
si->state--;
|
|
si->idx = 9;
|
|
break;
|
|
|
|
case -28:
|
|
si->temp[si->idx--] = (unsigned char) c;
|
|
if (si->idx < 0)
|
|
{
|
|
double dTmp = *((double *) si->temp);
|
|
|
|
si->sample_rate = (unsigned long) dTmp;
|
|
XX_DMsg(DBG_MM, ("Sample rate is %f\n", dTmp));
|
|
si->state = -5;
|
|
}
|
|
break;
|
|
|
|
/* 7<numbers>25 are AU handling */
|
|
/* Read the data size; may be ~0 meaning unspecified */
|
|
case 8:
|
|
si->data_size = (unsigned long) c;
|
|
si->state++;
|
|
break;
|
|
|
|
case 9:
|
|
si->data_size |= ((unsigned long) c) << 8;
|
|
si->state++;
|
|
break;
|
|
|
|
case 10:
|
|
si->data_size |= ((unsigned long) c) << 16;
|
|
si->state++;
|
|
break;
|
|
|
|
case 11:
|
|
si->data_size |= ((unsigned long) c) << 24;
|
|
si->state++;
|
|
if (si->swap)
|
|
swapLongs((unsigned long *) &si->data_size, 1);
|
|
XX_DMsg(DBG_MM, ("Data size: 0x%lx = %ld\n", si->data_size, si->data_size));
|
|
break;
|
|
|
|
/* Read the encoding; there are some more possibilities */
|
|
case 12:
|
|
si->encoding = (unsigned long) c;
|
|
si->state++;
|
|
break;
|
|
|
|
case 13:
|
|
si->encoding |= ((unsigned long) c) << 8;
|
|
si->state++;
|
|
break;
|
|
|
|
case 14:
|
|
si->encoding |= ((unsigned long) c) << 16;
|
|
si->state++;
|
|
break;
|
|
|
|
case 15:
|
|
si->encoding |= ((unsigned long) c) << 24;
|
|
si->state++;
|
|
if (si->swap)
|
|
swapLongs((unsigned long *) &si->encoding, 1);
|
|
|
|
/* Translate the encoding into style and size parameters */
|
|
|
|
switch (si->encoding)
|
|
{
|
|
case SUN_ULAW:
|
|
XX_DMsg(DBG_MM, ("Sun u-Law encoding\n"));
|
|
si->style = ULAW;
|
|
si->size = SIZE_BYTE;
|
|
break;
|
|
|
|
case SUN_LIN_8:
|
|
XX_DMsg(DBG_MM, ("Sun linear 8-bit encoding\n"));
|
|
si->style = SIGN2;
|
|
si->size = SIZE_BYTE;
|
|
break;
|
|
|
|
case SUN_LIN_16:
|
|
XX_DMsg(DBG_MM, ("Sun linear 16-bit encoding\n"));
|
|
si->style = SIGN2;
|
|
si->size = SIZE_WORD;
|
|
break;
|
|
|
|
default:
|
|
XX_DMsg(DBG_MM, ("Encoding: 0x%lx\n", si->encoding));
|
|
XX_DMsg(DBG_MM, ("Unsupported encoding in Sun/NeXT header. Only U-law, signed bytes, and signed words are supported\n"));
|
|
si->state = STATE_SPIN;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Read the sampling rate */
|
|
case 16:
|
|
si->sample_rate = (unsigned long) c;
|
|
si->state++;
|
|
break;
|
|
|
|
case 17:
|
|
si->sample_rate |= ((unsigned long) c) << 8;
|
|
si->state++;
|
|
break;
|
|
|
|
case 18:
|
|
si->sample_rate |= ((unsigned long) c) << 16;
|
|
si->state++;
|
|
break;
|
|
|
|
case 19:
|
|
si->sample_rate |= ((unsigned long) c) << 24;
|
|
si->state++;
|
|
if (si->swap)
|
|
swapLongs((unsigned long *) &si->sample_rate, 1);
|
|
XX_DMsg(DBG_MM, ("Sample rate: %ld Hz\n", si->sample_rate));
|
|
break;
|
|
|
|
/* Read the number of channels */
|
|
case 20:
|
|
si->channels = (unsigned long) c;
|
|
si->state++;
|
|
break;
|
|
|
|
case 21:
|
|
si->channels |= ((unsigned long) c) << 8;
|
|
si->state++;
|
|
break;
|
|
|
|
case 22:
|
|
si->channels |= ((unsigned long) c) << 16;
|
|
si->state++;
|
|
break;
|
|
|
|
case 23:
|
|
si->channels |= ((unsigned long) c) << 24;
|
|
si->state++;
|
|
|
|
if (si->swap)
|
|
swapLongs((unsigned long *) &si->channels, 1);
|
|
XX_DMsg(DBG_MM, ("Number of channels: %ld\n", si->channels));
|
|
|
|
si->hdr_size -= SUN_HDRSIZE; /* #bytes already read */
|
|
break;
|
|
|
|
/* Skip the info string in header */
|
|
case 24:
|
|
if (si->hdr_size > 0)
|
|
{
|
|
si->hdr_size--;
|
|
break;
|
|
}
|
|
else
|
|
si->state++;
|
|
|
|
if (si->data_size == -1)
|
|
{
|
|
si->buf = GTR_MALLOC(DATABLOCKSIZE);
|
|
if (si->buf == NULL)
|
|
return FALSE;
|
|
si->buf_size = DATABLOCKSIZE;
|
|
si->loc = 0;
|
|
if ((si->style == ULAW) && (device_capability != DEVICE_8BIT))
|
|
si->size = SIZE_WORD;
|
|
}
|
|
else
|
|
{
|
|
switch (si->size)
|
|
{
|
|
case SIZE_BYTE:
|
|
switch (si->style)
|
|
{
|
|
case SIGN2:
|
|
si->buf_size = si->data_size;
|
|
si->buf = GTR_MALLOC(si->buf_size);
|
|
if (si->buf == NULL)
|
|
return FALSE;
|
|
si->loc = 0;
|
|
break;
|
|
|
|
case ULAW:
|
|
si->buf_size = si->data_size * 2;
|
|
si->buf = GTR_MALLOC(si->buf_size);
|
|
if (si->buf == NULL)
|
|
return FALSE;
|
|
si->loc = 0;
|
|
if (device_capability != DEVICE_8BIT)
|
|
si->size = SIZE_WORD;
|
|
break;
|
|
default:
|
|
XX_DMsg(DBG_MM, ("Unsupported Format!\n"));
|
|
si->state = STATE_SPIN;
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case SIZE_WORD:
|
|
switch (si->style)
|
|
{
|
|
case SIGN2:
|
|
si->buf_size = si->data_size * 2;
|
|
si->buf = GTR_MALLOC(si->buf_size);
|
|
if (si->buf == NULL)
|
|
return FALSE;
|
|
si->loc = 0;
|
|
break;
|
|
|
|
default:
|
|
XX_DMsg(DBG_MM, ("Unsupported Format!\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Go ahead and drop through to next case */
|
|
|
|
case 25:
|
|
/* Read the data */
|
|
if (si->loc >= si->buf_size)
|
|
{
|
|
/* The following check doesn't seem to be needed, and
|
|
it also prohibits 11khz sound files from playing.
|
|
|
|
if (si->data_size != -1)
|
|
{
|
|
XX_DMsg(DBG_MM, ("Too many bytes in stream!\n"));
|
|
si->state=STATE_SPIN;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
*/
|
|
pb = GTR_REALLOC(si->buf, si->buf_size + DATABLOCKSIZE);
|
|
if (pb == NULL)
|
|
return FALSE;
|
|
si->buf = pb;
|
|
si->buf_size += DATABLOCKSIZE;
|
|
}
|
|
|
|
buf2= si->buf + si->loc;
|
|
|
|
if (si->style == ULAW)
|
|
{
|
|
/* use table from Posk stuff */
|
|
if (device_capability != DEVICE_8BIT)
|
|
{
|
|
ibuf = (short int *) buf2;
|
|
*ibuf = (short) ulaw_table[(unsigned char) c];
|
|
si->loc += 2;
|
|
}
|
|
else
|
|
{
|
|
*buf2 = (char) (((short) ulaw_table[(unsigned char) c]) / 256);
|
|
*buf2 ^= 128;
|
|
si->loc++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* style == SIGN2 */
|
|
switch (si->size)
|
|
{
|
|
case SIZE_BYTE:
|
|
*buf2 = c;
|
|
*buf2 = *buf2 ^ 0x7F;
|
|
break;
|
|
|
|
case SIZE_WORD:
|
|
*buf2 = c;
|
|
if (si->loc & 0x01)
|
|
{
|
|
if (si->swap)
|
|
{
|
|
c = buf2[0];
|
|
buf2[0] = buf2[1];
|
|
buf2[1] = c;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
XX_DMsg(DBG_MM, ("Unsupported option - not 8- or 16-bit size for SIGN2 encoding!\n"));
|
|
si->state = STATE_SPIN;
|
|
break;
|
|
}
|
|
|
|
si->loc++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void Sound_Callback( void *param,
|
|
const char *pszURL,
|
|
BOOL bAbort,
|
|
const char *pszFileHREF,
|
|
BOOL fDCache,
|
|
DCACHETIME dctExpires,
|
|
DCACHETIME dctLastModif)
|
|
{
|
|
struct SoundInfo *si;
|
|
|
|
si = (struct SoundInfo *) param;
|
|
Hash_FindOrAdd(&gSoundCache, (char *) pszURL, NULL, si);
|
|
|
|
if (bAbort) goto abortExit;
|
|
|
|
// if its a bksound, then don't show up in history
|
|
if ( ! si->fHidden )
|
|
GHist_Add((char *) pszURL, NULL, time(NULL), TRUE);
|
|
GTR_strncpy(si->szURL, pszURL, MAX_URL_STRING);
|
|
|
|
// if pszFileHREF is not NULL, then file wasn't copied, but passed as path
|
|
if (pszFileHREF)
|
|
{
|
|
if (si->fsOrig)
|
|
{
|
|
if (!si->bNoDeleteFile)
|
|
{
|
|
if (!si->fDCached)
|
|
remove(si->fsOrig); // remove the file if not cached to disk
|
|
}
|
|
GTR_FREE(si->fsOrig);
|
|
}
|
|
si->bNoDeleteFile = TRUE;
|
|
if (!(si->fsOrig = GTR_MALLOC(_MAX_PATH + 1)))
|
|
goto abortExit;
|
|
GTR_strncpy(si->fsOrig, pszFileHREF, _MAX_PATH);
|
|
}
|
|
|
|
switch (si->type)
|
|
{
|
|
case SOUND_AU:
|
|
si->fDCached = ( fDCache
|
|
&& gPrefs.bEnableDiskCache
|
|
&& FUpdateBuiltinDCache(WWW_AUDIO, pszURL, &si->fsOrig, dctExpires, dctLastModif, TRUE, si->tw));
|
|
AuProcess(si, pszURL);
|
|
break;
|
|
case SOUND_AIFF:
|
|
si->fDCached = ( fDCache
|
|
&& gPrefs.bEnableDiskCache
|
|
&& FUpdateBuiltinDCache(WWW_AIFF, pszURL, &si->fsOrig, dctExpires, dctLastModif, TRUE, si->tw));
|
|
AiffProcess(si, pszURL);
|
|
break;
|
|
}
|
|
ResetCIFEntryCurDoc(pszURL);
|
|
return;
|
|
|
|
abortExit:
|
|
if (bAbort)
|
|
{
|
|
if (si->fsOrig)
|
|
{
|
|
if ((!si->bNoDeleteFile) && (!si->fDCached))
|
|
{
|
|
remove(si->fsOrig); // remove the file if not cached to disk
|
|
}
|
|
GTR_FREE(si->fsOrig);
|
|
}
|
|
GTR_FREE(si);
|
|
}
|
|
}
|
|
|
|
HTStream *SoundPlayer_Present(struct Mwin *tw, HTRequest *request, void *param, HTFormat input_format, HTFormat output_format, HTStream *output_stream)
|
|
{
|
|
struct SoundInfo *si;
|
|
HTStream *me;
|
|
char path[_MAX_PATH + 1];
|
|
int format;
|
|
|
|
#ifdef WIN32
|
|
{
|
|
int available_device = 0;
|
|
|
|
available_device = waveOutGetNumDevs();
|
|
if (available_device == 0)
|
|
{
|
|
/* Can't play sound on this machine. Tell user. */
|
|
|
|
ERR_ReportError(tw, errNoSoundDevice, "", "");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
}
|
|
#endif /* WIN32 */
|
|
|
|
|
|
if (!bInitialized)
|
|
{
|
|
Hash_Init(&gSoundCache);
|
|
bInitialized = TRUE;
|
|
}
|
|
|
|
if (input_format == HTAtom_for("audio/basic"))
|
|
format = SOUND_AU;
|
|
else if (input_format == HTAtom_for("audio/aiff") ||
|
|
input_format == HTAtom_for("audio/x-aiff"))
|
|
format = SOUND_AIFF;
|
|
else
|
|
format = SOUND_INVALID;
|
|
|
|
if (format == SOUND_INVALID)
|
|
return NULL;
|
|
|
|
if (!(si = GTR_MALLOC(sizeof(struct SoundInfo))))
|
|
goto LError;
|
|
memset(si, 0, sizeof(struct SoundInfo));
|
|
|
|
si->type = format;
|
|
si->tw_refer = tw;
|
|
si->bNoDeleteFile = TRUE;
|
|
if (request->szLocalFileName)
|
|
{
|
|
if (!(si->fsOrig = GTR_MALLOC(_MAX_PATH + 1)))
|
|
goto LError;
|
|
strcpy(si->fsOrig, request->szLocalFileName);
|
|
request->nosavedlg = TRUE;
|
|
request->savefile = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (!request->fImgFromDCache)
|
|
{
|
|
// Get a temporary file name to pass to SaveLocally
|
|
if (!(si->fsOrig = GTR_MALLOC(_MAX_PATH + 1)))
|
|
goto LError;
|
|
if ( GetTempFileName(gPrefs.szCacheLocation, "A", 0, si->fsOrig) == 0 ) {
|
|
path[0] = 0;
|
|
PREF_GetTempPath(_MAX_PATH, path);
|
|
GetTempFileName(path, "A", 0, si->fsOrig);
|
|
}
|
|
request->savefile = si->fsOrig;
|
|
si->bNoDeleteFile = FALSE;
|
|
}
|
|
else
|
|
si->fsOrig = request->savefile;
|
|
|
|
}
|
|
request->nosavedlg = TRUE;
|
|
|
|
me = HTSaveWithCallback(tw, request, si, input_format, Sound_Callback);
|
|
|
|
return me;
|
|
|
|
LError:
|
|
if (si)
|
|
{
|
|
if (si->fsOrig)
|
|
GTR_FREE(si->fsOrig);
|
|
GTR_FREE(si);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL SoundPlayer_ShowCachedFile(const char *pszURL)
|
|
{
|
|
char *pURL;
|
|
struct SoundInfo *si;
|
|
|
|
if (!bInitialized)
|
|
return FALSE;
|
|
|
|
/* Check if a window with the given URL exists */
|
|
|
|
if (Hash_Find(&gSoundCache, (char *) pszURL, &pURL, (void **)&si) != -1)
|
|
{
|
|
#ifdef WIN32
|
|
if (IsWindow(si->hwnd))
|
|
{
|
|
/* If the window exists then check its enabled status. If it is
|
|
not enabled, it means that the error dialog is up. In this
|
|
case, let the error dialog become active. */
|
|
|
|
if (IsWindowEnabled(si->hwnd))
|
|
TW_RestoreWindow(si->hwnd);
|
|
else
|
|
TW_EnableModalChild(si->hwnd);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void SoundPlayer_CleanUp(void)
|
|
{
|
|
int count, i;
|
|
struct SoundInfo *si;
|
|
|
|
if (!bInitialized)
|
|
return;
|
|
|
|
#ifdef WIN32
|
|
SoundPlayer_FreeBitmaps();
|
|
#endif
|
|
/* Destroy all open windows */
|
|
|
|
count = Hash_Count(&gSoundCache);
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
Hash_GetIndexedEntry(&gSoundCache, i, NULL, NULL, (void **)&si);
|
|
#ifdef WIN32
|
|
if (IsWindow(si->hwnd))
|
|
DestroyWindow(si->hwnd);
|
|
GTR_FREE(si);
|
|
#endif
|
|
}
|
|
|
|
Hash_FreeContents(&gSoundCache);
|
|
}
|
|
|
|
#ifdef WIN32
|
|
HWND SoundPlayer_GetNextWindow(BOOL bStart)
|
|
{
|
|
static int current_index = 0;
|
|
struct SoundInfo *si;
|
|
|
|
if (bStart)
|
|
current_index = 0;
|
|
|
|
if (current_index >= Hash_Count(&gSoundCache))
|
|
return NULL;
|
|
|
|
if (!bStart)
|
|
current_index++;
|
|
|
|
if (current_index >= Hash_Count(&gSoundCache))
|
|
return NULL;
|
|
|
|
Hash_GetIndexedEntry(&gSoundCache, current_index, NULL, NULL, (void **) &si);
|
|
|
|
return (si->hwnd);
|
|
}
|
|
|
|
BOOL SoundPlayer_IsWindow(HWND hwnd)
|
|
{
|
|
int i;
|
|
struct SoundInfo *si;
|
|
|
|
for (i = 0; i < Hash_Count(&gSoundCache); i++)
|
|
{
|
|
Hash_GetIndexedEntry(&gSoundCache, i, NULL, NULL, (void **) &si);
|
|
if (si->hwnd == hwnd)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|