home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / ImportWAVSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  15.2 KB  |  509 lines  |  [TEXT/KAHL]

  1. /* ImportWAVSample.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "ImportWAVSample.h"
  31. #include "MainWindowStuff.h"
  32. #include "Files.h"
  33. #include "Alert.h"
  34. #include "BufferedFileInput.h"
  35. #include "SampleConsts.h"
  36. #include "Memory.h"
  37. #include "DataMunging.h"
  38. #include "SampleObject.h"
  39.  
  40.  
  41. /* prototype for the function that actually does the work. */
  42. static MyBoolean        TryToImportWAVFile(BufferedInputRec* File, NumBitsType* NumBitsOut,
  43.                                             NumChannelsType* NumChannelsOut, char** RawDataPtrOut,
  44.                                             long* NumSampleFramesOut, long* SamplingRateOut);
  45.  
  46.  
  47. /* this routine asks for a file and tries to import the contents of that */
  48. /* file as a WAV sample.  it reports any errors to the user. */
  49. void                                ImportWAVSample(struct MainWindowRec* MainWindow)
  50.     {
  51.         FileSpec*                    FileLocation;
  52.  
  53.         CheckPtrExistence(MainWindow);
  54.  
  55.         /* get the file to be imported */
  56.         FileLocation = GetFileAny();
  57.         if (FileLocation != NIL)
  58.             {
  59.                 FileType*                    FileDescriptor;
  60.  
  61.                 if (OpenFile(FileLocation,&FileDescriptor,eReadOnly))
  62.                     {
  63.                         BufferedInputRec*    BufferedInputDescriptor;
  64.  
  65.                         BufferedInputDescriptor = NewBufferedInput(FileDescriptor);
  66.                         if (BufferedInputDescriptor != NIL)
  67.                             {
  68.                                 NumBitsType        NumBits;
  69.                                 NumChannelsType    NumChannels;
  70.                                 char*                    SampleData;
  71.                                 long                    NumFrames;
  72.                                 long                    SamplingRate;
  73.  
  74.                                 if (TryToImportWAVFile(BufferedInputDescriptor,&NumBits,&NumChannels,
  75.                                     &SampleData,&NumFrames,&SamplingRate))
  76.                                     {
  77.                                         SampleObjectRec*        ReturnedSampleObject;
  78.  
  79.                                         ReturnedSampleObject = MainWindowCopyRawSampleAndOpen(MainWindow,
  80.                                             SampleData,NumBits,NumChannels,0,0,0,0,0,0,0,SamplingRate,
  81.                                             261.625565300598635);
  82.                                         if (ReturnedSampleObject != NIL)
  83.                                             {
  84.                                                 char*                    Filename;
  85.  
  86.                                                 Filename = ExtractFileName(FileLocation);
  87.                                                 if (Filename != NIL)
  88.                                                     {
  89.                                                         /* we don't need to release the name */
  90.                                                         SampleObjectNewName(ReturnedSampleObject,Filename);
  91.                                                     }
  92.                                             }
  93.                                         ReleasePtr(SampleData);
  94.                                     }
  95.                                 EndBufferedInput(BufferedInputDescriptor);
  96.                             }
  97.                          else
  98.                             {
  99.                                 AlertHalt("There is not enough memory available to open the "
  100.                                     "requested file.",NIL);
  101.                             }
  102.                         CloseFile(FileDescriptor);
  103.                     }
  104.                  else
  105.                     {
  106.                         AlertHalt("The requested file could not be opened.",NIL);
  107.                     }
  108.                 DisposeFileSpec(FileLocation);
  109.             }
  110.     }
  111.  
  112.  
  113. typedef enum
  114.     {
  115.         eImportUnrecognizedFileFormat EXECUTE(= -5125),
  116.         eImportBadNumberOfChannels,
  117.         eImportNotAPCMFile,
  118.         eImportBadNumberOfBits
  119.     } ImportErrors;
  120.  
  121. /* RIFF file format, with WAVE information */
  122. /*  'RIFF' */
  123. /*  4-byte little endian length descriptor (minus 8 bytes for these 2 fields) */
  124. /*  'WAVE' */
  125. /*  'fmt ' */
  126. /*  4-byte little endian length descriptor for the 'fmt ' header block */
  127. /*      - this should be 16.  if not, then it's some other kind of WAV file */
  128. /*  2-byte little endian format descriptor.  this is always here. */
  129. /*      - 1 = PCM */
  130. /*  2-byte little endian number of channels. */
  131. /*  4-byte little endian sampling rate integer. */
  132. /*  4-byte little endian average bytes per second. */
  133. /*  2-byte little endian block align.  for 8-bit mono, this is 1; for 16-bit */
  134. /*    stereo, this is 4. */
  135. /*  2-byte little endian number of bits. */
  136. /*      - 8 = 8-bit */
  137. /*      - 16 = 16-bit */
  138. /*  'data' */
  139. /*  4-byte little endian length of sample data descriptor */
  140. /*  any length data.  8-bit data goes from 0..255, but 16-bit data goes */
  141. /*    from -32768 to 32767. */
  142. static MyBoolean        TryToImportWAVFile(BufferedInputRec* File, NumBitsType* NumBitsOut,
  143.                                             NumChannelsType* NumChannelsOut, char** RawDataPtrOut,
  144.                                             long* NumSampleFramesOut, long* SamplingRateOut)
  145.     {
  146.         char                            StringBuffer[4];
  147.         unsigned long            TotalFileLength;
  148.         unsigned long            HeaderLength;
  149.         unsigned short        DataTypeDescriptor;
  150.         unsigned short        NumberOfChannels;
  151.         unsigned long            SamplingRate;
  152.         unsigned long            AverageBytesPerSecond;
  153.         unsigned short        BlockAlignment;
  154.         unsigned short        NumberOfBitsRaw;
  155.         NumBitsType                NumBits;
  156.         NumChannelsType        NumChannels;
  157.         unsigned long            SampledNumberOfBytes;
  158.         unsigned long            NumberOfSampleFrames;
  159.         ImportErrors            Error EXECUTE(= (ImportErrors)0);
  160.  
  161.         CheckPtrExistence(File);
  162.  
  163.         /*  'RIFF' */
  164.         if (!ReadBufferedInput(File,4,StringBuffer))
  165.             {
  166.              FileErrorPoint:
  167.                 AlertHalt("Unable to read data from the file.",NIL);
  168.                 return False;
  169.             }
  170.         if (!MemEqu(StringBuffer,"RIFF",4))
  171.             {
  172.                 Error = eImportUnrecognizedFileFormat;
  173.              DoesntSeemToBeGoodFile1:
  174.                 switch (Error)
  175.                     {
  176.                         default:
  177.                             EXECUTE(PRERR(ForceAbort,"TryToImportWAVFile:  "
  178.                                 "unknown error code"));
  179.                             break;
  180.                         case eImportUnrecognizedFileFormat:
  181.                             AlertHalt("The file does not appear to be a WAV file.  Try importing "
  182.                                 "it as a RAW file.",NIL);
  183.                             break;
  184.                         case eImportBadNumberOfChannels:
  185.                             AlertHalt("Only files with 1 or 2 channels can be imported.",NIL);
  186.                             break;
  187.                         case eImportNotAPCMFile:
  188.                             AlertHalt("The file is not a PCM file.",NIL);
  189.                             break;
  190.                         case eImportBadNumberOfBits:
  191.                             AlertHalt("Only 8-bit or 16-bit files can be imported.",NIL);
  192.                             break;
  193.                     }
  194.                 return False;
  195.             }
  196.  
  197.         /*  4-byte little endian length descriptor (minus 8 bytes for these 2 fields) */
  198.         if (!ReadBufferedUnsignedLongLittleEndian(File,&TotalFileLength))
  199.             {
  200.                 goto FileErrorPoint;
  201.             }
  202.  
  203.         /*  'WAVE' */
  204.         if (!ReadBufferedInput(File,4,StringBuffer))
  205.             {
  206.                 goto FileErrorPoint;
  207.             }
  208.         if (!MemEqu(StringBuffer,"WAVE",4))
  209.             {
  210.                 Error = eImportUnrecognizedFileFormat;
  211.                 goto DoesntSeemToBeGoodFile1;
  212.             }
  213.  
  214.         /*  'fmt ' */
  215.         if (!ReadBufferedInput(File,4,StringBuffer))
  216.             {
  217.                 goto FileErrorPoint;
  218.             }
  219.         if (!MemEqu(StringBuffer,"fmt ",4))
  220.             {
  221.                 Error = eImportUnrecognizedFileFormat;
  222.                 goto DoesntSeemToBeGoodFile1;
  223.             }
  224.  
  225.         /*  4-byte little endian length descriptor for the 'fmt ' header block */
  226.         /*      - this should be 16.  if not, then it's some other kind of WAV file */
  227.         if (!ReadBufferedUnsignedLongLittleEndian(File,&HeaderLength))
  228.             {
  229.                 goto FileErrorPoint;
  230.             }
  231.         if (HeaderLength != 16)
  232.             {
  233.                 Error = eImportUnrecognizedFileFormat;
  234.                 goto DoesntSeemToBeGoodFile1;
  235.             }
  236.  
  237.         /*  2-byte little endian format descriptor.  this is always here. */
  238.         /*      - 1 = PCM */
  239.         if (!ReadBufferedUnsignedShortLittleEndian(File,&DataTypeDescriptor))
  240.             {
  241.                 goto FileErrorPoint;
  242.             }
  243.         if (DataTypeDescriptor != 1)
  244.             {
  245.                 Error = eImportNotAPCMFile;
  246.                 goto DoesntSeemToBeGoodFile1;
  247.             }
  248.  
  249.         /*  2-byte little endian number of channels. */
  250.         if (!ReadBufferedUnsignedShortLittleEndian(File,&NumberOfChannels))
  251.             {
  252.                 goto FileErrorPoint;
  253.             }
  254.         if ((NumberOfChannels != 1) && (NumberOfChannels != 2))
  255.             {
  256.                 Error = eImportBadNumberOfChannels;
  257.                 goto DoesntSeemToBeGoodFile1;
  258.             }
  259.  
  260.         /*  4-byte little endian sampling rate integer. */
  261.         if (!ReadBufferedUnsignedLongLittleEndian(File,&SamplingRate))
  262.             {
  263.                 goto FileErrorPoint;
  264.             }
  265.  
  266.         /*  4-byte little endian average bytes per second. */
  267.         if (!ReadBufferedUnsignedLongLittleEndian(File,&AverageBytesPerSecond))
  268.             {
  269.                 goto FileErrorPoint;
  270.             }
  271.  
  272.         /*  2-byte little endian block align.  for 8-bit mono, this is 1; for 16-bit */
  273.         /*    stereo, this is 4. */
  274.         if (!ReadBufferedUnsignedShortLittleEndian(File,&BlockAlignment))
  275.             {
  276.                 goto FileErrorPoint;
  277.             }
  278.  
  279.         /*  2-byte little endian number of bits. */
  280.         /*      - 8 = 8-bit */
  281.         /*      - 16 = 16-bit */
  282.         if (!ReadBufferedUnsignedShortLittleEndian(File,&NumberOfBitsRaw))
  283.             {
  284.                 goto FileErrorPoint;
  285.             }
  286.         switch (NumberOfBitsRaw)
  287.             {
  288.                 default:
  289.                     Error = eImportBadNumberOfBits;
  290.                     goto DoesntSeemToBeGoodFile1;
  291.                 case 8:
  292.                     NumBits = eSample8bit;
  293.                     break;
  294.                 case 16:
  295.                     NumBits = eSample16bit;
  296.                     break;
  297.             }
  298.  
  299.         /*  'data' */
  300.         if (!ReadBufferedInput(File,4,StringBuffer))
  301.             {
  302.                 goto FileErrorPoint;
  303.             }
  304.         if (!MemEqu(StringBuffer,"data",4))
  305.             {
  306.                 Error = eImportUnrecognizedFileFormat;
  307.                 goto DoesntSeemToBeGoodFile1;
  308.             }
  309.  
  310.         /*  4-byte little endian length of sample data descriptor */
  311.         if (!ReadBufferedUnsignedLongLittleEndian(File,&SampledNumberOfBytes))
  312.             {
  313.                 goto FileErrorPoint;
  314.             }
  315.  
  316.         /* calculate number of sample frames */
  317.         switch (NumBits)
  318.             {
  319.                 default:
  320.                     EXECUTE(PRERR(ForceAbort,"TryToImportWAVFile:  internal "
  321.                         "number of bits error"));
  322.                     break;
  323.                 case eSample8bit:
  324.                     switch (NumberOfChannels)
  325.                         {
  326.                             default:
  327.                                 EXECUTE(PRERR(ForceAbort,"TryToImportWAVFile:  internal "
  328.                                     "number of channels error"));
  329.                                 break;
  330.                             case 1:
  331.                                 NumberOfSampleFrames = SampledNumberOfBytes / 1;
  332.                                 break;
  333.                             case 2:
  334.                                 NumberOfSampleFrames = SampledNumberOfBytes / 2;
  335.                                 break;
  336.                             }
  337.                     break;
  338.                 case eSample16bit:
  339.                     switch (NumberOfChannels)
  340.                         {
  341.                             default:
  342.                                 EXECUTE(PRERR(ForceAbort,"TryToImportWAVFile:  internal "
  343.                                     "number of channels error"));
  344.                                 break;
  345.                             case 1:
  346.                                 NumberOfSampleFrames = SampledNumberOfBytes / 2;
  347.                                 break;
  348.                             case 2:
  349.                                 NumberOfSampleFrames = SampledNumberOfBytes / 4;
  350.                                 break;
  351.                             }
  352.                     break;
  353.             }
  354.  
  355.         /*  any length data.  8-bit data goes from 0..255, but 16-bit data goes */
  356.         /*    from -32768 to 32767. */
  357.         switch (NumberOfChannels)
  358.             {
  359.                 default:
  360.                     EXECUTE(PRERR(ForceAbort,"TryToImportWAVFile:  internal "
  361.                         "number of channels error"));
  362.                     break;
  363.                 case 1:
  364.                     NumChannels = eSampleMono;
  365.                     break;
  366.                 case 2:
  367.                     NumChannels = eSampleStereo;
  368.                     break;
  369.                 }
  370.         switch (NumBits)
  371.             {
  372.                 default:
  373.                     EXECUTE(PRERR(ForceAbort,"TryToImportWAVFile:  internal "
  374.                         "number of bits error"));
  375.                     break;
  376.                 case eSample8bit:
  377.                     switch (NumChannels)
  378.                         {
  379.                             default:
  380.                                 EXECUTE(PRERR(ForceAbort,"TryToImportWAVFile:  internal "
  381.                                     "number of channels error"));
  382.                                 break;
  383.                             case eSampleMono:
  384.                                 {
  385.                                     signed char*        Buffer;
  386.                                     long                        Scan;
  387.  
  388.                                     Buffer = (signed char*)AllocPtrCanFail(NumberOfSampleFrames,
  389.                                         "TryToImportWAVFile data block");
  390.                                     if (Buffer == NIL)
  391.                                         {
  392.                                             AlertHalt("There is not enough memory available to import "
  393.                                                 "the sample.",NIL);
  394.                                             return False;
  395.                                         }
  396.                                     for (Scan = 0; Scan < NumberOfSampleFrames; Scan += 1)
  397.                                         {
  398.                                             PRNGCHK(Buffer,&(Buffer[Scan]),sizeof(Buffer[Scan]));
  399.                                             if (!ReadBufferedSignedChar(File,&(Buffer[Scan])))
  400.                                                 {
  401.                                                     ReleasePtr((char*)Buffer);
  402.                                                     goto FileErrorPoint;
  403.                                                 }
  404.                                             Buffer[Scan] -= 128; /* change from unsigned to signed */
  405.                                         }
  406.                                     *RawDataPtrOut = (char*)Buffer;
  407.                                 }
  408.                                 break;
  409.                             case eSampleStereo:
  410.                                 {
  411.                                     signed char*        Buffer;
  412.                                     long                        Scan;
  413.  
  414.                                     Buffer = (signed char*)AllocPtrCanFail(NumberOfSampleFrames * 2,
  415.                                         "TryToImportWAVFile data block");
  416.                                     if (Buffer == NIL)
  417.                                         {
  418.                                             AlertHalt("There is not enough memory available to import "
  419.                                                 "the sample.",NIL);
  420.                                             return False;
  421.                                         }
  422.                                     for (Scan = 0; Scan < NumberOfSampleFrames * 2; Scan += 1)
  423.                                         {
  424.                                             /* alternates frames */
  425.                                             PRNGCHK(Buffer,&(Buffer[Scan]),sizeof(Buffer[Scan]));
  426.                                             if (!ReadBufferedSignedChar(File,&(Buffer[Scan])))
  427.                                                 {
  428.                                                     ReleasePtr((char*)Buffer);
  429.                                                     goto FileErrorPoint;
  430.                                                 }
  431.                                             Buffer[Scan] -= 128; /* change from unsigned to signed */
  432.                                         }
  433.                                     *RawDataPtrOut = (char*)Buffer;
  434.                                 }
  435.                                 break;
  436.                             }
  437.                     break;
  438.                 case eSample16bit:
  439.                     switch (NumChannels)
  440.                         {
  441.                             default:
  442.                                 EXECUTE(PRERR(ForceAbort,"TryToImportWAVFile:  internal "
  443.                                     "number of channels error"));
  444.                                 break;
  445.                             case eSampleMono:
  446.                                 {
  447.                                     signed short*        Buffer;
  448.                                     long                        Scan;
  449.  
  450.                                     Buffer = (signed short*)AllocPtrCanFail(NumberOfSampleFrames
  451.                                         * sizeof(short),"TryToImportWAVFile data block");
  452.                                     if (Buffer == NIL)
  453.                                         {
  454.                                             AlertHalt("There is not enough memory available to import "
  455.                                                 "the sample.",NIL);
  456.                                             return False;
  457.                                         }
  458.                                     for (Scan = 0; Scan < NumberOfSampleFrames; Scan += 1)
  459.                                         {
  460.                                             PRNGCHK(Buffer,&(Buffer[Scan]),sizeof(Buffer[Scan]));
  461.                                             if (!ReadBufferedSignedShortLittleEndian(File,&(Buffer[Scan])))
  462.                                                 {
  463.                                                     ReleasePtr((char*)Buffer);
  464.                                                     goto FileErrorPoint;
  465.                                                 }
  466.                                         }
  467.                                     *RawDataPtrOut = (char*)Buffer;
  468.                                 }
  469.                                 break;
  470.                             case eSampleStereo:
  471.                                 {
  472.                                     signed short*        Buffer;
  473.                                     long                        Scan;
  474.  
  475.                                     Buffer = (signed short*)AllocPtrCanFail(NumberOfSampleFrames
  476.                                         * sizeof(short) * 2,"TryToImportWAVFile data block");
  477.                                     if (Buffer == NIL)
  478.                                         {
  479.                                             AlertHalt("There is not enough memory available to import "
  480.                                                 "the sample.",NIL);
  481.                                             return False;
  482.                                         }
  483.                                     for (Scan = 0; Scan < NumberOfSampleFrames * 2; Scan += 1)
  484.                                         {
  485.                                             /* alternates frames */
  486.                                             PRNGCHK(Buffer,&(Buffer[Scan]),sizeof(Buffer[Scan]));
  487.                                             if (!ReadBufferedSignedShortLittleEndian(File,&(Buffer[Scan])))
  488.                                                 {
  489.                                                     ReleasePtr((char*)Buffer);
  490.                                                     goto FileErrorPoint;
  491.                                                 }
  492.                                         }
  493.                                     *RawDataPtrOut = (char*)Buffer;
  494.                                 }
  495.                                 break;
  496.                             }
  497.                     break;
  498.             }
  499.  
  500.         /* output parameters */
  501.         *NumBitsOut = NumBits;
  502.         *NumChannelsOut = NumChannels;
  503.         CheckPtrExistence(*RawDataPtrOut);
  504.         *NumSampleFramesOut = NumberOfSampleFrames;
  505.         *SamplingRateOut = SamplingRate;
  506.  
  507.         return True;
  508.     }
  509.