/*

This software module was originally developed by 

Mike Guzewicz (E-mu Systems)


in the course of development of the MPEG-4 Audio (ISO/IEC 14496-3) standard. 
This software module is an implementation of a part of one or more 
MPEG-4 Audio (ISO/IEC 14496-3) tools as specified by the MPEG-4 Audio 
(ISO/IEC 14496-3). ISO/IEC gives users of the MPEG-4 Audio (ISO/IEC 14496-3) 
free license to this software module or modifications thereof for use 
in hardware or software products claiming conformance to the MPEG-4 Audio 
(ISO/IEC 14496-3). Those intending to use this software module in hardware 
or software products are advised that its use may infringe existing patents. 
The original developer of this software module and his/her company, the 
subsequent editors and their companies, and ISO/IEC have no liability for 
use of this software module or modifications thereof in an implementation. 
Copyright is not released for non MPEG-4 Audio (ISO/IEC 14496-3) conforming 
products. E-mu Systems retains full right to use the code for his/her own 
purpose, assign or donate the code to a third party and to inhibit third 
parties from using the code for non MPEG-4 Audio (ISO/IEC 14496-3) 
conforming products. This copyright notice must be included in all copies 
or derivative works. 

Copyright (C) 1997 E-mu Systems, Inc.

*/
     /*********************************************************************
     
     sfe_sfdetect.cpp
     
     
     
     *********************************************************************/

/*============================================================================
* @(#)sfdetect.cpp	1.2 13:56:04 3/22/95 13:56:06
*                          
*  FILE :   sfdetect.cpp
*
*  Description: 
* 
*  Search the Loaded HydraClass object for internal errors, repair if
*  desired and possible
*
*============================================================================
*/
#include "sfe_sfdetect.h"
#include "sfe_sfenum.h"

typedef struct sampleSpaceNodeTag
{
  DWORD start;
  DWORD end;
  struct sampleSpaceNodeTag *next;
} sampleSpaceNode;

/*============================================================================
*  VerifySFBData: Given a HydraClass object, search for internal errors.
*============================================================================
*/

BOOL sfDetectErrors::
VerifySFBData(HydraClass *pHF, DWORD sampleRAMSize)
{
  if(VerifyPDTAIndices(pHF) == FALSE) return FALSE;
  if(VerifySamplePoints(pHF, sampleRAMSize) == FALSE) return FALSE;
  return TRUE;
}

/*============================================================================
*  VerifyPDTAIndices: Given a HydraClass object, search for bad index values
*                     in the preset data.
*============================================================================
*/
BOOL sfDetectErrors::
VerifyPDTAIndices(HydraClass *pHF)
{

  WORD count, lastPBag, lastPGen, lastIBag, lastIGen;
  WORD lastPMod, lastIMod;

  // Step 0: Make sure all struct array counts are at least the minimum size.
  if (pHF->awStructSize[prstHdr]     < 2) return FALSE;
  if (pHF->awStructSize[prstBagNdx]  < 1) return FALSE;
  if (pHF->awStructSize[prstGenList] < 1) return FALSE;
  if (pHF->awStructSize[prstModList] < 1) return FALSE;
  if (pHF->awStructSize[inst]        < 2) return FALSE;
  if (pHF->awStructSize[instBagNdx]  < 1) return FALSE;
  if (pHF->awStructSize[instGenList] < 1) return FALSE;
  if (pHF->awStructSize[instModList] < 1) return FALSE;
  if (pHF->awStructSize[sampHdr]     < 1) return FALSE;

  // Step 1: Look for generator or modulator enums which are not in the
  //         valid range. This is a fixable corruption, in fact it may
  //         represent a FUTURE SoundFont. 
  //         If desired, change those which are exceed the maximum to NOP.
  //         Also, check out the INSTRUMENT and SAMPLE indices and verify
  //         their validity

  // Loop to struct size-2 because: 1. last index = struct size - 1, 
  //                                2. last index is the terminal and
  //                                   need not be considered

  // First the PGens...
  for (count = 0; count < pHF->awStructSize[prstGenList]-2; count++)
  {
    // This code is already in the sfReader. For an editor, this function
    // may be better served here.
    //if (pHF->pPGen[count].sfGenOper > endOper)
    //{
    //  pHF->pPGen[count].sfGenOper = nop;
    //}

    if (pHF->pPGen[count].sfGenOper == instrument)
    {
      if (pHF->pPGen[count].unAmt.shAmount > pHF->awStructSize[inst]-1)
      {
        // We have found an bad instrument index. 
        return FALSE;
      }
    }
  }

  // Now the IGens...
  for (count = 0; count < pHF->awStructSize[instGenList]-2; count++)
  {
    //if (pHF->pIGen[count].sfGenOper > endOper)
    //{
    //    pHF->pIGen[count].sfGenOper = nop;
    //}

    if (pHF->pIGen[count].sfGenOper == sampleId)
    {
      if (pHF->pIGen[count].unAmt.shAmount > 
                                     pHF->awStructSize[sampHdr]-1)
      {
        // We have found an bad sample index. 
        return FALSE;
      }
    }
  }

  //*************************************************************
  // Future loops for PMOD and IMOD will go here when necessary
  //*************************************************************

  // Step 2: Look for Preset Layer indices which exceed the maximum

  lastPBag = 0;
  for (count = 0; count < pHF->awStructSize[prstHdr]-2; count ++)
  {
    if ((pHF->pPHdr[count].wBagNdx > pHF->awStructSize[prstBagNdx] - 1) ||
        (pHF->pPHdr[count].wBagNdx < lastPBag))
    {
      // We have found a bad preset layer index. 
      return FALSE;
    }
    lastPBag = pHF->pPHdr[count].wBagNdx;
  }

  // Step 3: Look for bad Generator List and Modulator List Indices

  lastPGen = lastPMod = 0;
  for (count = 0; count < pHF->awStructSize[prstBagNdx]-2; count ++)
  {
    if ((pHF->pPBag[count].wGenNdx > pHF->awStructSize[prstGenList] - 1) ||
        (pHF->pPBag[count].wGenNdx < lastPGen))
    {
      // We have found a bad Generator List index.
      return FALSE;
    }
    lastPGen = pHF->pPBag[count].wGenNdx;

    if ((pHF->pPBag[count].wModNdx > pHF->awStructSize[prstModList] - 1) ||
        (pHF->pPBag[count].wModNdx < lastPMod))
    {
      // We have found a bad Modulator index.
      return FALSE;
    }
    lastPMod = pHF->pPBag[count].wModNdx;
  }

  // Step 3: Look for Instrment split indices which exceed the maximum

  lastIBag = 0;
  for (count = 0; count < pHF->awStructSize[inst]-2; count ++)
  {
    if ((pHF->pInst[count].wBagNdx > pHF->awStructSize[instBagNdx] - 1) ||
	(pHF->pInst[count].wBagNdx < lastIBag))
    {
      // We have found a bad instrument split index
      return FALSE;
    }
    lastIBag = pHF->pInst[count].wBagNdx;
  }

  // Step 4: Look for Instrument Generator List and Modulator List Indices
  //         which exceed the maximum.

  lastIGen = lastIMod = 0;
  for (count = 0; count < pHF->awStructSize[instBagNdx]-2; count ++)
  {
    if ((pHF->pIBag[count].wGenNdx > pHF->awStructSize[instGenList] - 1) ||
	(pHF->pIBag[count].wGenNdx < lastIGen))
    {
      // We have found a bad generator index 
      return FALSE;
    }
    lastIGen = pHF->pIBag[count].wGenNdx;

    if ((pHF->pIBag[count].wModNdx > pHF->awStructSize[instModList] - 1) ||
	(pHF->pIBag[count].wModNdx < lastIMod))
    {
      // We have found a bad modulator index 
      return FALSE;
    }
    lastIMod = pHF->pIBag[count].wModNdx;
  }

  // We have no index problems.
  return TRUE;
}

/*============================================================================
*  VerifySamplePoints: Given a HydraClass object, search for bad index values
*                      sample points
*============================================================================
*/
BOOL sfDetectErrors::
VerifySamplePoints(HydraClass *pHF, DWORD sampleSizeInBytes)
{
  WORD count, count1;
  DWORD start, end, startloop, endloop;
  BOOL validity, validity1;

  // Here we are looking for invalid loop points. A valid samples worth
  // of loop points looks like the following (not to scale):
  //
  //        =====================================.......
  //        |       |                 |         |  32  |
  //        =====================================.......
  //       start  startloop         endloop    end   next start
  //
  // Start is the beginning of the sample data, end is the end of the sample
  // data. Start must be less startloop, which must be less than endloop
  // which must be less than end + 32 (IE not in the next sample). The 
  // distance between startloop and endloop
  // should be at least 32 samples, but is not enforced by this function.
  // Finally, the start point of the following
  // sample must be at least 32 samples away from the end point of the 
  // current sample.
  //
  // Sample header data need NOT be in sequencial order, so the last 
  // stipulation is checked later.

  for (count = 0; count < pHF->awStructSize[sampHdr]-1; count++)
  {
    validity = FALSE;

    start     = pHF->pSHdr[count].dwStart;
    end       = pHF->pSHdr[count].dwEnd;
    startloop = pHF->pSHdr[count].dwStartloop;
    endloop   = pHF->pSHdr[count].dwEndloop;

    // SamplePointOffsets may allow some of these conditions, but
    // the sample information itself does not.
    if (startloop < start)          break;
    if (endloop   < startloop)      break;
    // if ((endloop - startloop) < SAMPLEBUFFER)) break;
    if ((end+SAMPLEBUFFER)       < endloop)      break;

    // If this is a ROM sample, we cannot detect for sample size limitations
    // without specific synthesizer information.
    if (((pHF->pSHdr[count].sfSampleType & romSample) == 0) &&
	 (end > sampleSizeInBytes/2))
      break;

    validity = TRUE;
  }

  if (validity == FALSE) 
    return validity;

  // In this loop, we check for overlapping samples. IE samples which 
  // by themselves are OK but lie inside the space of another sample.
  //
  //        =====================================.......
  //        |       |      32         |         |  32  |
  //        =====================================.......
  //       start  startloop         endloop    end   next start
  //
  //                       =====================================.......
  //                       |       |      32         |         |  32  |
  //                       =====================================.......
  //                       start  startloop         endloop    end   next start
  //
  // We must be able to take it for granted that all samples by themselves
  // are valid before making this check.
  // Note that overlap must not occur even in the buffer between end and 
  // next start. Finally, since sequential sample header data is not 
  // mandatory in a SoundFont bank, we need to use the two loop approach.
 

  for (count = 0; count < pHF->awStructSize[sampHdr]-1; count++)
  {
    validity = FALSE;

    for (count1 = 0; count1 < pHF->awStructSize[sampHdr]-1; count1++)
    {
      validity1 = FALSE;
	  // Check to see if for any given sample type (ROM or RAM), any one 
	  // sample's end point enters another sample's buffer space.  
      if 
		  // Don't check a sample with itself
		  ((count != count1) &&

		  // Don't check a ROM sample against a RAM sample
		  ((pHF->pSHdr[count].sfSampleType & romSample) == 
		   (pHF->pSHdr[count1].sfSampleType & romSample)) &&

		   // Make sure there is no overlap
	      (pHF->pSHdr[count].dwStart <  pHF->pSHdr[count1].dwEnd + SAMPLEBUFFER)
          &&
          (pHF->pSHdr[count].dwStart >= pHF->pSHdr[count1].dwStart)
		  ) 
				// Two distinct sample of the same type (ROM/RAM) have an overlap.
				// Bad deal!
				break; 
      validity1 = TRUE;
    }

    if (validity1 == FALSE) break;
    validity = TRUE;
  }
  

  return validity;
}
 
    
