ftp.nice.ch/pub/next/unix/communication/am.1.16.NIHS.bs.tar.gz#/am.1.16.NIHS.bs/src/cnv.c

This is cnv.c in view mode; [Download] [Up]

/*
	cnv.c 
	
	author	:	jolly - alias Patrick
	version	:	1.00
	
	additional remark : lines between the defines FROM_Thomas_Funke are added from
	                    Thomas Funke - thf@z*.de
						
	ADPCM3 support added by kiwi@belly, April '94
*/

#import <libc.h>
#import <sound/sound.h>
#import "precomp.h"

void cnv_snd(char *newdir,char *outdir,char *fname)
{
	struct	zyxel header;
	char str[MAXPATHLEN];
	char str2[MAXPATHLEN];
	FILE *feil,*infd,*outfd;
	
	feil=tmpfile();
	sprintf(str,"%s/%s%s",newdir,fname,Z_EXT);
	infd=fopen(str,"r");
	if(infd==NULL) log("cnv_snd: no infile %s", str);
	else
	{
		sprintf(str2,"%s/conv.snd",outdir);
		outfd=fopen(str2,"w+");
		if(outfd==NULL) log("cnv_snd: error opening outfile %s",str2);
		else
		{
			fread(&header,sizeof(struct zyxel),1,infd);
			switch(isZyXEL(&header))
			{
				case ZYX_AD2: ad2(feil,infd);lin96_to_mulaw(feil,outfd);break;
				case ZYX_AD3: ad3(feil,infd);lin96_to_mulaw(feil,outfd);break;
				default				:return;
			}
			fclose(outfd);
		}
		fclose(infd);

		/* The nohup prevents the sndconvert being killed by am's Hangup.
			Absolute paths are needed because the chdir(PATH) in am.c doesn't
			affect the CWD of the shell.
			kiwi@belly
			
			NEEDS WORK
			*/
		sprintf(str,"nohup sndconvert -o %s/%s/%s.snd -f 1 -s 8012 %s/%s >/dev/console 2>&1 &",
									PATH,outdir,fname,PATH,str2);
#if DEBUG
		log(str);
#endif
		system(str);
	}
	return;
}



void ad2(FILE *feil,FILE *infd)
{
	u_char	buf;
	short	sample[4];

#ifndef __BIG_ENDIAN__
	char	*little_endian=(char *)sample;
#endif
	do
	{
		fread(&buf,1,1,infd);
		if(buf==DLE)
		{
			fread(&buf,1,1,infd);
			if(buf!=DLE) fread(&buf,1,1,infd);
		}
		sample[0]=ad2_to_lin16( (buf&0xc0)>>6);
		sample[1]=ad2_to_lin16( (buf&0x30)>>4);	
		sample[2]=ad2_to_lin16( (buf&0x0c)>>2);
		sample[3]=ad2_to_lin16( (buf&0x03) );

#ifdef __BIG_ENDIAN__
		fwrite(sample,sizeof(short),4,feil);
#else
		fwrite(little_endian+1,sizeof(char),1,feil);
		fwrite(little_endian+0,sizeof(char),1,feil);
		fwrite(little_endian+3,sizeof(char),1,feil);
		fwrite(little_endian+2,sizeof(char),1,feil);
		fwrite(little_endian+5,sizeof(char),1,feil);
		fwrite(little_endian+4,sizeof(char),1,feil);
		fwrite(little_endian+7,sizeof(char),1,feil);
		fwrite(little_endian+6,sizeof(char),1,feil);
#endif
	}
	while(!feof(infd));
}


/* pos needs to be reset when starting new conversion, so I moved it
	out of con_ad3 (pos is the byte position relative to start of sample)
*/
static int pos = 0;

void con_ad3(u_char buf, FILE *feil)
{
	static int Pack;
	static short	sample[8];
#ifndef __BIG_ENDIAN__
	char	*little_endian=(char *)sample;
#endif

	switch(pos)
	{
		case 0: sample[0]=ad3_to_lin16((buf&0xe0)>>5) ; /* XXX- ---- */
				sample[1]=ad3_to_lin16((buf&0x1c)>>2) ; /* ---X XX-- */
				Pack = (buf&0x03)<<1 ;
				break;
		case 1: sample[2]=ad3_to_lin16(Pack|((buf&0x80)>>7)) ;
				sample[3]=ad3_to_lin16((buf&0x70)>>4) ; /* -XXX ---- */
				sample[4]=ad3_to_lin16((buf&0x0e)>>1) ; /* ---- XXX- */
				Pack = (buf&0x01)<<2 ;
				break;
		case 2: sample[5]=ad3_to_lin16(Pack|((buf&0xc0)>>6)) ;
				sample[6]=ad3_to_lin16((buf&0x38)>>3) ; /* --XX X--- */
				sample[7]=ad3_to_lin16(buf&0x07) ;      /* ---- -XXX */

#ifdef __BIG_ENDIAN__
				fwrite(sample,sizeof(short),8,feil);
#else
				fwrite(little_endian+1,sizeof(char),1,feil);
				fwrite(little_endian+0,sizeof(char),1,feil);
				fwrite(little_endian+3,sizeof(char),1,feil);
				fwrite(little_endian+2,sizeof(char),1,feil);
				fwrite(little_endian+5,sizeof(char),1,feil);
				fwrite(little_endian+4,sizeof(char),1,feil);
				fwrite(little_endian+7,sizeof(char),1,feil);
				fwrite(little_endian+6,sizeof(char),1,feil);
				fwrite(little_endian+9,sizeof(char),1,feil);
				fwrite(little_endian+8,sizeof(char),1,feil);
				fwrite(little_endian+11,sizeof(char),1,feil);
				fwrite(little_endian+10,sizeof(char),1,feil);
				fwrite(little_endian+13,sizeof(char),1,feil);
				fwrite(little_endian+12,sizeof(char),1,feil);
				fwrite(little_endian+15,sizeof(char),1,feil);
				fwrite(little_endian+14,sizeof(char),1,feil);
#endif

				break;
	};
	
	pos++;
	if(pos == 3) pos = 0;
}


void ad3(FILE *feil,FILE *infd)
{
	u_char	buf;

	pos = 0;	/* starting at position zero (see con_ad3 for details) */
	
	do
	{
		fread(&buf,1,1,infd);
		if(buf==DLE)
		{
			fread(&buf,1,1,infd);
			if(buf!=DLE)
			{
				/* This is a workaround for a bug in rec_message, but
				   since rec_message was fixed, it shouldn't be triggered
				   in future recordings (see DOUBLE_DLE in am.c)
				   kiwi@belly
				  */
				fprintf(stderr, "Bug triggered with %x\n",buf);
				con_ad3(0x10, feil);
			}
		}
		con_ad3(buf, feil);		
	}
	while(!feof(infd));
}



short ad2_to_lin16(u_char c)
{
		static	int M[]={0x3800,0x5600};
		static	int	A=0;
		static	int	delta=5;
		
		static	char	sign;
		static	char	data;

        sign=c>>1;
        data=c&1;
              
#define FROM_Thomas_Funke
 
    if (!sign)
	A += delta * data + 0.5 *delta;
    else
	A -= delta * data + 0.5 *delta;

    if (A <= -0x7ffe)
	A = -0x7ffe;
    else {
	if (A >= 0x7ffe)
	    A = 0x7ffe;
    }
    

    delta = M[(int)data] * delta;
    delta += 0x2000;
    delta >>= 14; // div 16384
    if (delta < 5)
	delta = 5;

#undef FROM_Thomas_Funke

	return A;
}


/*********************
ADPCM3 conversion was included by kiwi@belly on 31.3.94.
The code is based heavily on a program source by ZyXEL Corporation.
I just adapted it to fit in here.
kiwi@belly
**********************/


short ad3_to_lin16(u_char c)
{
	static	int M[]={0x399A, 0x3A9F, 0x4D14, 0x6607 };
	static	int	A=0;
	static	int	delta=5;
	
	static	char	sign;
	static	char	data;

	int     TmpMax ;
	long    t0 ;
	
	/******* This part is modified for the Firmware > 6.10 **************/
	    t0 = (long)A ;      	      
	    t0 *= 3973 ;          
	    t0 += 2048 ;      
	    t0 /= 4096 ;               
	    A = (int)t0 ;   
	/********************************************************************/

	sign=c & 4;
	data=c & 3;
	
	if ( (delta&1) && !sign )
			++A ;

	/* calculate A */
	TmpMax  = (delta>>1) ;
	while ( data-- )
			TmpMax += delta ;
	if ( sign )
			A -= TmpMax ;
	else
			A += TmpMax ;

	if (A <= -0x7ffe)
	A = 0;
	else {
	if (A >= 0x7ffe)
		A = 0;
	}

	/* calc new delta */
	
	delta = delta * M[(int)c & 3];
	delta += 0x2000;
	delta >>= 14; // div 16384

	if(delta <1) delta=1;
				
	return A;
}

/* */

void lin96_to_mulaw(FILE *feil,FILE *outfd)
{
	int	len;
	SNDSoundStruct	snd;
	short	sample[6];

	len=ftell(feil);
	rewind(feil);

    snd.magic			=htonl(SND_MAGIC);
    snd.dataLocation	=htonl(sizeof(SNDSoundStruct));
    snd.dataSize		=htonl((long)len/sizeof(short));    
    snd.dataFormat		=htonl(SND_FORMAT_LINEAR_16);
    snd.samplingRate	=htonl(9600);
    snd.channelCount	=htonl(1);
    strcpy(snd.info,"jr"); // yep Jolly Roger !
	
	fwrite(&snd,sizeof(SNDSoundStruct),1,outfd);
	do
	{
		fread(sample,sizeof(short),1,feil);
		fwrite(sample,sizeof(short),1,outfd );
	}
	while(!feof(feil));

	return;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.