ftp.nice.ch/pub/next/unix/communication/newam.0.1.s.tar.gz#/newam-0.1/src/zsndplay.c

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.