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.