ftp.nice.ch/pub/next/unix/audio/sms.N.bs.tar.gz#/sms/smsAnal/smsAnal.c

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

/*
 *    main program for smsAnal
 *
 */
#include "../sms.h"
#include "smsAnal.h"

char pChTextString[1024];

#define USAGE "Usage: smsAnal [-d debugMode][-f format][-q soundType][-x analysisDirection][-s windowSize][-i windowType][-r frameRate][-j highestFreq][-k minPeakMag][-y refHarmonic][-u defaultFund][-l lowestFund][-h highestFund][-m minRefHarmMag][-z refHarmMagDiffFromMax][-n nGuides][-p nTrajectories][-v freqDeviation][-t peakContToGuide][-o fundContToGuide][-g cleanTraj][-a minTrajLength][-b maxSleepingTime][-e stochasticType][-c nStocCoeff] <inputSoundFile> <outputSmsFile>"


/* function to compute the SMS representation from a sound file
 *
 * SNDSoundStruct *pSoundHeader; 	pointer to input sound file
 * SMSHeader *pSmsHeader;		pointer to output SMS file
 * ANAL_PARAMS analParams;		analysis parameters
 */
static int ComputeSms (SNDSoundStruct *pSoundHeader, SMSHeader *pSmsHeader,
                       ANAL_PARAMS analParams)
{
	short *pSoundData = (short *) ((char *) pSoundHeader + 
	                               pSoundHeader->dataLocation);
	int nSoundSamples = pSoundHeader->dataSize / sizeof(short);				    
	char *pData = (char *) pSmsHeader->pChDataRecords;
	SMS_DATA smsData;
	int iStatus = 0, iSample = 0, sizeNewData = 0, iNextSizeRead = 0, 
	iDoAnalysis = 1, iRecord = 0;
  
	iNextSizeRead = (analParams.iDefaultSizeWindow + 1) / 2.0;
  
	if (analParams.iAnalysisDirection == REVERSE)
	{
		iSample = nSoundSamples;
		pData += (pSmsHeader->nRecords - 1) * pSmsHeader->iRecordBSize;
	}

	while(iDoAnalysis > 0)
	{
		if (analParams.iAnalysisDirection == REVERSE)
		{
			if ((iSample - iNextSizeRead) >= 0)
				sizeNewData = iNextSizeRead;
			else
				sizeNewData = iSample;
			iSample -= sizeNewData;
      	}
		else
		{
			iSample += sizeNewData;
			if((iSample + iNextSizeRead) < nSoundSamples)
				sizeNewData = iNextSizeRead;
			else
				sizeNewData = nSoundSamples - iSample;
		}

		if (setSmsRecord (pSmsHeader, pData, &smsData) < 0)
		{
			fprintf(stderr, "error: not enough memory for SMS file\n");
			fprintf(stderr, " iRecord = %d, nRecords %d\n", iRecord,
			        pSmsHeader->nRecords);
			break;
		}
		iStatus = SmsAnalysis (&pSoundData[iSample], sizeNewData, &smsData, 
		                       analParams, &iNextSizeRead);
		if (iStatus == 1)
		{
			if (analParams.iAnalysisDirection == REVERSE)
				pData -= pSmsHeader->iRecordBSize;
			else
				pData += pSmsHeader->iRecordBSize;
			if (iRecord % 10 == 0)
				fprintf (stderr,"%.2f ", 
				         iRecord / (float) pSmsHeader->iFrameRate);
			iRecord++;
		}
		else if (iStatus == -1)
		{
			iDoAnalysis = 0;
			pSmsHeader->nRecords = iRecord;
		}
	}
	pSmsHeader->fResidualPerc = FResidualPerc / iRecord;
	return (1);
}

/* function to initialize the input command  arguments
 * 
 * ARGUMENTS *pArguments;	command arguments 
 */
static int InitArguments (ARGUMENTS *pArguments)
{
	pArguments->iDebugMode = 0;
	pArguments->iFormat = FORMAT_HARMONIC;
	pArguments->iSoundType = TYPE_MELODY;
	pArguments->iAnalysisDirection = DIRECT;
	pArguments->fWindowSize = 3.5;
	pArguments->iWindowType = BLACKMAN_HARRIS_70;
	pArguments->iFrameRate = 400;
	pArguments->fHighestFreq = 12000.;
	pArguments->fMinPeakMag = 0;
	pArguments->fFreqDeviation = .45;
	pArguments->iRefHarmonic = 1;
	pArguments->fMinRefHarmMag = 30;
	pArguments->fRefHarmMagDiffFromMax = 30;
	pArguments->fDefaultFund = 100;
	pArguments->fLowestFund = 50;
	pArguments->fHighestFund = 1000;
	pArguments->nGuides = 100;
	pArguments->nTrajectories = 60;
	pArguments->fPeakContToGuide = .4;
	pArguments->fFundContToGuide = .5;
	pArguments->iCleanTraj = 1;
	pArguments->fMinTrajLength = .1;
	pArguments->fMaxSleepingTime = .1;
	pArguments->iStochasticType = STOC_MAG_ENV_TYPE;
	pArguments->nStochasticCoeff = 16;
	return (1);
}

/* save the arguments as a string in the header of the SMS file
 *
 * ARGUMENTS arguments;		user arguments
 */
static int SaveArguments (ARGUMENTS arguments)
{
  sprintf (pChTextString, 
           "format %d, soundType %d,  analysisDirection %d, windowSize %.2f, windowType %d, frameRate %d, highestFreq %.2f, minPeakMag %.2f, refHarmonic %d, minRefHarmMag %.2f, refHarmMagDiffFromMax %.2f, defaultFund %.2f, lowestFund %.2f, highestFund %.2f, nGuides %d, nTrajectories %d, freqDeviation %.2f,   peakContToGuide %.2f, fundContToGuide %.2f, cleantTraj %d, minTrajLength %.2f, maxSleepingTime %.2f,  stochasticType %d, nStocCoeff %d \n", 	
	     arguments.iFormat, arguments.iSoundType,
         arguments.iAnalysisDirection, arguments.fWindowSize, 
	     arguments.iWindowType, arguments.iFrameRate,
	     arguments.fHighestFreq, arguments.fMinPeakMag,
	     arguments.iRefHarmonic, arguments.fMinRefHarmMag, 
	     arguments.fRefHarmMagDiffFromMax,  
	     arguments.fDefaultFund, arguments.fLowestFund,
	     arguments.fHighestFund, arguments.nGuides,
	     arguments.nTrajectories, arguments.fFreqDeviation, 
	     arguments.fPeakContToGuide, arguments.fFundContToGuide,
	     arguments.iCleanTraj, arguments.fMinTrajLength,
	     arguments.fMaxSleepingTime,  arguments.iStochasticType,
	     arguments.nStochasticCoeff);
  
  return (1);
}
 
/* function to compute the record size from the command arguments
 *
 * ARGUMENTS *pArguments;	pointer to command arguments 
 */
static int computeRecordBSize (ARGUMENTS *pArguments)
{
	int iSize = 0, nGain = 1, nComp = 2;
  
	if (pArguments->iStochasticType == STOC_NONE)
		nGain = 0;

	if (pArguments->iFormat == FORMAT_HARMONIC_WITH_PHASE ||
	    pArguments->iFormat == FORMAT_INHARMONIC_WITH_PHASE)
		nComp = 3;
     
	iSize = sizeof (float) * (nComp * pArguments->nTrajectories + 
		pArguments->nStochasticCoeff + nGain);  
	return (iSize);
}	     

/* function to get the user arguments 
 *
 * char *argv[];		command line 
 * int argc;			number of command arguments
 * ARGUMENTS *pArguments;	command arguments
 */
static int GetArguments (char *argv[], int argc, ARGUMENTS *pArguments)
{
	int i;
    float frameRateOrOverlapFactor = 0;

	for (i=1; i<argc-2; i++) 
	{
		if (*(argv[i]++) == '-') 
		{
			switch (*(argv[i]++)) 
			{
				case 'd': if (sscanf(argv[i],"%d", 
				              &pArguments->iDebugMode) < 0)
					quit("Invalid debug mode");
					break;
				case 'f':  if (sscanf(argv[i],"%d", &pArguments->iFormat) < 1) 
					quit("Invalid format");
					break;
				case 'q': if (sscanf(argv[i],"%d", 
				              &pArguments->iSoundType) < 0) 
					quit("Invalid sound type");
					break;
				case 'x': if (sscanf(argv[i],"%d", 
				              &pArguments->iAnalysisDirection) < 0) 
					quit("Invalid value for analysis direction");
					break;
				case 'i': if (sscanf(argv[i],"%d", 
				              &pArguments->iWindowType) < 0) 
					quit("Invalid value for window type");
					break;
				case 's': if (sscanf(argv[i],"%f", 
				              &pArguments->fWindowSize) < 1)
					quit("Invalid window size");
					break;
				case 'r':  sscanf(argv[i],"%f", 
						  &frameRateOrOverlapFactor);
				break;
				case 'j': if (sscanf(argv[i],"%f", 
				              &pArguments->fHighestFreq) < 0) 
					quit("Invalid highestFreq");
					break;
				case 'k': if (sscanf(argv[i],"%f", 
				              &pArguments->fMinPeakMag) < 0) 
					quit("Invalid minimum peak magnitude");
					break;
				case 'y': if (sscanf(argv[i],"%d", 
				              &pArguments->iRefHarmonic) < 1) 
					quit("Invalid reference harmonic");
					break;
				case 'm': if (sscanf(argv[i],"%f", 
				              &pArguments->fMinRefHarmMag) < 0) 
					quit("Invalid minimum fundamental magnitude");
					break;
				case 'z': if (sscanf(argv[i],"%f", 
				              &pArguments->fRefHarmMagDiffFromMax) < 0) 
					quit("Invalid maximum fundamental magnitude difference \
								from maximum peak");
					break;
				case 'l': if (sscanf(argv[i],"%f",
				              &pArguments->fLowestFund) < 1) 
					quit("Invalid lowest fundamental");
					break;
				case 'h': if (sscanf(argv[i],"%f",
				              &pArguments->fHighestFund) < 1) 
					quit("Invalid highest fundamental");
					break;
				case 'u': if (sscanf(argv[i],"%f", 
				              &pArguments->fDefaultFund) < 1) 
					quit("Invalid default fundamental");
					break;
				case 'n': if (sscanf(argv[i],"%d", &pArguments->nGuides) < 1) 
					quit("Invalid number of guides");
					break;
				case 'p': if (sscanf(argv[i],"%d", 
				              &pArguments->nTrajectories) < 1) 
					quit("Invalid number of trajectories");
					break;
				case 'v': if (sscanf(argv[i],"%f", 
				              &pArguments->fFreqDeviation) < 0) 
					quit("Invalid frequency deviation");
					break;
				case 't': if (sscanf(argv[i],"%f",
				              &pArguments->fPeakContToGuide) < 0) 
					quit("Invalid peak contribution to guide");
					break;
				case 'o': if (sscanf(argv[i],"%f", 
				              &pArguments->fFundContToGuide) < 0) 
					quit("Invalid fundamental contribution to guide");
					break;
				case 'g': if (sscanf(argv[i],"%d", 
				              &pArguments->iCleanTraj) < 0) 
					quit("Invalid value for CleanTraj");
					break;
				case 'a': if (sscanf(argv[i],"%f",
				              &pArguments->fMinTrajLength) < 0) 
					quit("Invalid minimum trajectory length");
					break;
				case 'b': if (sscanf(argv[i],"%f", 
				              &pArguments->fMaxSleepingTime) < 0) 
					quit("Invalid minimum sleeping time");
					break;
				case 'c': if (sscanf(argv[i],"%d",
				              &pArguments->nStochasticCoeff) < 1) 
					quit("Invalid number of coefficients");
					break;
				case 'e': if (sscanf(argv[i],"%d",
				              &pArguments->iStochasticType) < 1) 
					quit("Invalid stochastic type");
					break;
				default:   quit(USAGE);
			}
		}
	}
  		
	if (frameRateOrOverlapFactor > 0.0)
		pArguments->iFrameRate = frameRateOrOverlapFactor;
	else if (frameRateOrOverlapFactor < 0.0)
	{ 
		/* -overlapFactor specified */
      	/* overlap ratio K = windowSize * frameRate / 
		   defaultFund = w * r / u => r = K * u / w */
		pArguments->iFrameRate = (int) ((-frameRateOrOverlapFactor) * 
			                             pArguments->fDefaultFund /
			                             pArguments->fWindowSize);
		printf("Frame rate = %d\n", pArguments->iFrameRate);
	}
	return (1);
}

/* function to fill SMS header of the output file
 *
 * SMSHeader *pSmsHeader; 	pointer to SMS header
 * int iRecordBSize;		size in bytes of an output record
 * int nRecords;		number of records in output file
 * ARGUMENTS arguments;		user arguments
 */
static int FillSmsHeader (SMSHeader *pSmsHeader, int iRecordBSize, 
                          int nRecords, ARGUMENTS arguments)
{
  initSmsHeader(pSmsHeader);
  pSmsHeader->iRecordBSize = iRecordBSize;
  pSmsHeader->nRecords = nRecords;
  pSmsHeader->iFormat = arguments.iFormat;
  pSmsHeader->iFrameRate = arguments.iFrameRate;
  pSmsHeader->iStochasticType = arguments.iStochasticType;
  pSmsHeader->nTrajectories = arguments.nTrajectories;
  pSmsHeader->nStochasticCoeff = arguments.nStochasticCoeff;
  pSmsHeader->pChDataRecords = (char *)pSmsHeader + pSmsHeader->iHeadBSize;
  pSmsHeader->fOriginalSRate = FSamplingRate;

  SaveArguments (arguments);
       
  pSmsHeader->nTextCharacters = strlen (pChTextString) + 1;
  pSmsHeader->pChTextCharacters = (char *) pChTextString;

  return (1);
}
   
/* function to fill the analysis parameters from the user arguments
 *
 * ARGUMENTS arguments;			user arguments
 * ANAL_PARAMS *pAnalParams;    	analysis parameters
 * SNDSoundStruct *pSoundHeader;	pointer to header of input sound
 * int iHopSize;			hop size of analysis frame
 */  
static int FillAnalParams (ARGUMENTS arguments, ANAL_PARAMS *pAnalParams,
                           SNDSoundStruct *pSoundHeader, int iHopSize)
{
	/* fill analysis parameters structure */
	pAnalParams->iDebugMode = arguments.iDebugMode;
	pAnalParams->iFormat = arguments.iFormat;
	pAnalParams->iSoundType = arguments.iSoundType;
	pAnalParams->iAnalysisDirection = arguments.iAnalysisDirection;
	pAnalParams->iSizeSound = pSoundHeader->dataSize / sizeof(short);
	pAnalParams->iWindowType = arguments.iWindowType;
	FSamplingRate = pAnalParams->fSamplingRate = pSoundHeader->samplingRate;
	FHalfSamplingRate = FSamplingRate / 2.0;
	pAnalParams->fSizeWindow = arguments.fWindowSize;
	pAnalParams->iDefaultSizeWindow = 
		(int)((pAnalParams->fSamplingRate / arguments.fDefaultFund) *
		pAnalParams->fSizeWindow / 2) * 2 + 1; /* odd length */
	pAnalParams->sizeHop = iHopSize;
	pAnalParams->fHighestFreq = arguments.fHighestFreq;
	pAnalParams->fMinPeakMag = arguments.fMinPeakMag;
	pAnalParams->iStochasticType = arguments.iStochasticType;  
	pAnalParams->fLowestFundamental = arguments.fLowestFund;
	pAnalParams->fHighestFundamental = arguments.fHighestFund;
	pAnalParams->fDefaultFundamental = arguments.fDefaultFund;
	pAnalParams->fPeakContToGuide = arguments.fPeakContToGuide;
	pAnalParams->fFundContToGuide = arguments.fFundContToGuide;
	pAnalParams->fFreqDeviation = arguments.fFreqDeviation;
	pAnalParams->nGuides = MAX (arguments.nGuides, arguments.nTrajectories);
	pAnalParams->iCleanTraj = arguments.iCleanTraj;
	pAnalParams->fMinRefHarmMag = arguments.fMinRefHarmMag;
	pAnalParams->fRefHarmMagDiffFromMax = arguments.fRefHarmMagDiffFromMax;
	pAnalParams->iRefHarmonic = arguments.iRefHarmonic;
	pAnalParams->iMinTrajLength = 
		arguments.fMinTrajLength * arguments.iFrameRate;
	pAnalParams->iMaxSleepingTime = 
		arguments.fMaxSleepingTime * arguments.iFrameRate;
	MaxDelayFrames = 
		MAX(pAnalParams->iMinTrajLength, pAnalParams->iMaxSleepingTime) + 2 +
			DELAY_FRAMES;
	FResidualPerc = 0;
	return (1);
}

/* main of the program
 *
 */
void main (int argc, char *argv[])
{
	char *pChInputSoundFile = NULL, *pChOutputSmsFile = NULL, *pChProgramName;
	int iRecordBSize, iHeadBSize, iDataBSize, iHopSize, nRecords, iError;
	ARGUMENTS arguments;
	SNDSoundStruct *pSoundHeader;
	SMSHeader *pSmsHeader;
	ANAL_PARAMS analParams;
  
	/* initialize arguments */
	InitArguments (&arguments);
  
	pChProgramName = argv[0];
	/* get user arguments */
	if (argc > 3) 
		GetArguments (argv, argc, &arguments);
	else if (argc < 2)
		quit(USAGE);
	pChInputSoundFile = argv[argc-2];
	pChOutputSmsFile = argv[argc-1];
  
	/* Read sound file */
	if (iError = SNDReadSoundfile (pChInputSoundFile, &pSoundHeader))
	{
		printf("%s: sound error: %s on %s\n", pChProgramName,
		       SNDSoundError(iError), pChInputSoundFile);
		exit(1);
	}
  
	/* Abort if unsupported format */
	if (pSoundHeader->dataFormat != SND_FORMAT_LINEAR_16)
	{
		fprintf (stderr, "%s: unsupported sound format: %d\n",
		         pChProgramName, pSoundHeader->dataFormat);
		exit(1);
	}
	/* Abort if multi-channel sound */
	if (pSoundHeader->channelCount > 1)
	{
		fprintf (stderr,"%s: multi-channel sound not supported", 
		         pChProgramName);
		exit(1);
	}
    
	/* check default fundamental */
	if (arguments.fDefaultFund < arguments.fLowestFund)
	{
		arguments.fDefaultFund = arguments.fLowestFund;
		fprintf (stderr,"fDefaultFundamental set to %f \n", 
			    arguments.fDefaultFund);
	}
	if (arguments.fDefaultFund > arguments.fHighestFund)
	{
		arguments.fDefaultFund = arguments.fHighestFund;
		fprintf (stderr,"fDefaultFundamental set to %f \n", 
		         arguments.fDefaultFund);
	}

	/* check if no stochastic component */
	if(arguments.iStochasticType == STOC_NONE)
		arguments.nStochasticCoeff = 0;

	iRecordBSize = computeRecordBSize (&arguments);
	iHopSize = (int)(pSoundHeader->samplingRate / 
		(float) arguments.iFrameRate);
	nRecords = 3 + pSoundHeader->dataSize / 
		(float) (sizeof(short) * iHopSize);
	iHeadBSize = sizeof(SMSHeader);
	iDataBSize = iRecordBSize * nRecords;
	/* allocate virtual memory for SMS file */
	if ((pSmsHeader =  
	     (SMSHeader *) malloc ((size_t)(iHeadBSize+iDataBSize))) == NULL)
		quit ("error allocating memory for SMS file");
  
	FillAnalParams (arguments, &analParams, pSoundHeader, iHopSize);

	FillSmsHeader (pSmsHeader, iRecordBSize, nRecords, arguments);
  
	if (analParams.iDebugMode == DEBUG_SYNC)
		createDebugFile (analParams);

	if (analParams.iDebugMode == DEBUG_RESIDUAL)
		createResidualFile (analParams);
		
	ComputeSms (pSoundHeader, pSmsHeader, analParams);
    
	writeSmsFile (pChOutputSmsFile, pSmsHeader);
  
	if (analParams.iDebugMode == DEBUG_RESIDUAL)
		writeResidualFile ();

	if (analParams.iDebugMode == DEBUG_SYNC)
		writeDebugFile ();

	SNDFree (pSoundHeader);
	free (pSmsHeader);
  
	 exit (0);
}

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