This is zsndplay.c in view mode; [Download] [Up]
/*********************************************************************/
/* */
/* Programmer: */
/* Olaf Mueller <olaf@orest.escape.de> */
/* */
/* Purpose: */
/* Answering Machine */
/* playing ZyXEL voice on NeXT sound system */
/* */
/* History: */
/* 29-08-96 Initial Release Olaf Mueller */
/* */
/* Notes: */
/* I confess, i have no idea what I am programming here. */
/* The Zyxel algorithm is completeley unknown for me. */
/* This code is a result of reverse engineering of the old */
/* am.1.16 code. */
/* Probably it is full of errors, but who cares. It works for me */
/* Olaf */
/* */
/*********************************************************************/
#include "zyxel.h"
static short ad2_to_lin16 (unsigned char dataByte)
{
int M [] = { 0x3800 , 0x5600 } ;
static int delta = 5 ;
static int val = 0 ;
char signBit = dataByte & 0x02 ;
dataByte &= 0x01 ;
if (!signBit)
val += dataByte * delta + delta >> 1 ;
else
val -= dataByte * delta + delta >> 1 ;
if (val < -0x7ffe)
val = -0x7ffe ;
else if (val > 0x7ffe)
val = 0x7ffe ;
delta = (M [dataByte] * delta + 0x2000) >> 14 ;
if (delta < 5)
delta = 5 ;
return (short) val ;
}
static short ad3_to_lin16 (unsigned char dataByte)
{
int M [] = { 0x399A , 0x3A9F , 0x4D14 , 0x6607 } ;
static int delta = 5 ;
static int val = 0 ;
char signBit = dataByte & 0x04 ;
dataByte &= 0x03 ;
/******* This part is modified for the Firmware > 6.10 **************/
val = (val * 3973 + 2048) / 4096 ;
/********************************************************************/
if ((delta & 1) && !signBit)
++val ;
if (!signBit)
val += dataByte * delta + delta >> 1 ;
else
val -= dataByte * delta + delta >> 1 ;
#if 0
if (val <= -0x7ffe || val >= 0x7ffe)
val = 0;
#endif
if (val < -0x7ffe)
val = -0x7ffe ;
else if (val > 0x7ffe)
val = 0x7ffe ;
delta = (M [dataByte] * delta + 0x2000) >> 14 ;
if (delta < 5)
delta = 5 ;
return (short) val ;
}
#include <libc.h>
static long ad2_to_snd (ZyxelSND *zsnd,short *data)
{
long sndsamples = 0 ;
unsigned char zbyte ;
int ii ;
for (ii = 0 ; ii < zsnd->voicelen ; ii++)
{
zbyte = *(zsnd->voice + ii) ;
*data++ = NXSwapHostShortToBig (ad2_to_lin16(zbyte >> 6)) ;
*data++ = NXSwapHostShortToBig (ad2_to_lin16(zbyte >> 4)) ;
*data++ = NXSwapHostShortToBig (ad2_to_lin16(zbyte >> 2)) ;
*data++ = NXSwapHostShortToBig (ad2_to_lin16(zbyte)) ;
sndsamples += 4 ;
}
return sndsamples ;
}
static long ad3_to_snd (ZyxelSND *zsnd,short *data)
{
long sndsamples = 0 ;
unsigned char zbyte ;
int ii ;
int icnt = 3 , restbyte = 0 ;
for (ii = 0 ; ii < zsnd->voicelen ; ii++)
{
zbyte = *(zsnd->voice + ii) ;
switch (icnt)
{
case 3:
*data++ = NXSwapHostShortToBig (ad3_to_lin16(zbyte >> 5)) ;
*data++ = NXSwapHostShortToBig (ad3_to_lin16(zbyte >> 2)) ;
restbyte = zbyte << 1 ;
sndsamples += 2 ;
break ;
case 2:
*data++ = NXSwapHostShortToBig (ad3_to_lin16(restbyte | (zbyte >> 7))) ;
*data++ = NXSwapHostShortToBig (ad3_to_lin16(zbyte >> 4)) ;
*data++ = NXSwapHostShortToBig (ad3_to_lin16(zbyte >> 1)) ;
restbyte = zbyte << 2 ;
sndsamples += 3 ;
break ;
case 1:
*data++ = NXSwapHostShortToBig (ad3_to_lin16(restbyte | (zbyte >> 6))) ;
*data++ = NXSwapHostShortToBig (ad3_to_lin16(zbyte >> 3)) ;
*data++ = NXSwapHostShortToBig (ad3_to_lin16(zbyte)) ;
sndsamples += 3 ;
break ;
}
if (--icnt == 0)
icnt = 3 ;
}
return sndsamples ;
}
static void PrintUsage (void)
{
printf ("usage: zsndplay [-h] [-c] <Zyxel_voice_file>\n") ;
printf (" use option -c for converting to 8012Hz, 8bit mulaw\n") ;
}
#import <sound/sound.h>
static int endSound (SNDSoundStruct *sound,int tag,int err)
{
exit (0) ;
}
int main (int argc,char *argv[])
{
int rc , opt , optconvert = 0 , slen = 0 ;
ZyxelSND zsnd ;
SNDSoundStruct *sndp ;
char *soundfile = NULL ;
/*****
***** we scan options and parameters
*****/
while ((opt = getopt(argc,argv,"ch")) != -1)
{
switch (opt)
{
case 'c':
optconvert = 1 ;
break ;
case 'h':
PrintUsage () ;
return 2 ;
case '?' :
return 1 ;
}
}
if (argc - optind != 1)
{
PrintUsage () ;
return 2 ;
}
if ((rc = ZSNDread (argv[optind],&zsnd)) != 0)
{
switch (rc)
{
case ZYX_NOZYXELSTRUCT:
printf ("zsndplay: Not a ZyXEL voice file.\n") ;
break ;
case ZYX_NOMODE:
printf ("zsndplay: Not a ZyXEL voice file (Mode is not voice).\n") ;
break ;
case ZYX_NOVOICE:
printf ("zsndplay: Not a ZyXEL voice file (Unknown voice type).\n") ;
break ;
default:
printf ("zsndplay: General problems reading ZyXEL voice file.\n") ;
break ;
}
return 1 ;
}
if (zsnd.zyxel.voice == ZYX_CLP)
{
printf ("zsndplay: Unsupported ZyXEL voice format CELP.\n") ;
return 1 ;
}
switch (zsnd.zyxel.voice)
{
case ZYX_AD3:
printf ("zsnd2snd: Playing ZyXEL voice file with format ADPCM3.\n") ;
slen = zsnd.voicelen * 8 / 3 ;
soundfile = malloc (sizeof(SNDSoundStruct) + slen * sizeof(short)) ;
ad3_to_snd (&zsnd,(short*)(soundfile+sizeof(SNDSoundStruct))) ;
break ;
case ZYX_AD2:
printf ("zsnd2snd: Playing ZyXEL voice file with format ADPCM2.\n") ;
slen = zsnd.voicelen * 4 ;
soundfile = malloc (sizeof(SNDSoundStruct) + slen * sizeof(short)) ;
ad2_to_snd (&zsnd,(short*)(soundfile+sizeof(SNDSoundStruct))) ;
break ;
}
ZSNDfree (&zsnd) ;
sndp = (SNDSoundStruct*)soundfile ;
sndp->magic = SND_MAGIC ;
sndp->dataLocation = sizeof(SNDSoundStruct) ;
sndp->dataSize = slen * sizeof(short) ;
sndp->dataFormat = SND_FORMAT_LINEAR_16 ;
sndp->samplingRate = 9600 ;
sndp->channelCount = 1 ;
if (optconvert)
{
SNDSoundStruct *sndpc , snd ;
snd.magic = SND_MAGIC;
snd.dataFormat = SND_FORMAT_MULAW_8 ;
snd.samplingRate = 8012 ;
snd.channelCount = 1 ;
sndpc = &snd ;
SNDConvertSound (sndp,&sndpc) ;
sndp = sndpc ;
}
SNDStartPlaying (sndp,0,0,0,SND_NULL_FUN,endSound) ;
while (1)
sleep (1000) ;
return 0 ;
}These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.