home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD2.bin / bbs / util / macsnd_dt-1.7.lha / MacSND_dt / Source / Class.c next >
C/C++ Source or Header  |  1994-12-15  |  8KB  |  403 lines

  1. /*
  2. **    MacSND DataType
  3. **
  4. **    Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  5. **        Public domain
  6. **
  7. ** :ts=4
  8. */
  9.  
  10. #include "Global.h"
  11.  
  12.     // Maximum supported replay rate, as per the "Amiga Hardware Reference Manual"
  13.  
  14. #define MAX_SAMPLE_RATE 28867
  15.  
  16.     // The minimum sample rate we will allow when scaling a sound down
  17.  
  18. #define MIN_SAMPLE_RATE 5563
  19.  
  20.     // How many bytes to read in one piece
  21.  
  22. #define MIN_FRAME_RATE    (2048 * 8)
  23.  
  24.     /* ConvertSample(const UBYTE *Src,BYTE *Dst,LONG NumSamples,const LONG Skip):
  25.      *
  26.      *    Convert the native Macintosh format sample data into plain
  27.      *    signed 8 bits/sample Amiga data
  28.      */
  29.  
  30. STATIC VOID __regargs
  31. ConvertSample(const UBYTE *Src,BYTE *Dst,LONG NumSamples,const LONG Skip)
  32. {
  33.     LONG    SkipCount;
  34.     UBYTE    Value;
  35.  
  36.         // Make sure that the first sample is converted
  37.  
  38.     SkipCount = 1;
  39.  
  40.         // Convert all the samples if possible
  41.  
  42.     while(NumSamples-- > 0)
  43.     {
  44.             // It's easy to convert a Macintosh sample :^)
  45.  
  46.         Value = *(Src++) ^ 0x80;
  47.  
  48.             // Store this sample value?
  49.  
  50.         if(--SkipCount < 1)
  51.         {
  52.                 // Keep this sample
  53.  
  54.             *Dst++ = (BYTE)Value;
  55.  
  56.                 // Skip the next samples if necessary
  57.  
  58.             SkipCount = Skip;
  59.         }
  60.     }
  61. }
  62.  
  63.     /* GetSND(Object *object,struct TagItem *Tags,struct ClassBase *ClassBase):
  64.      *
  65.      *    Convert a Macintosh "snd " resource into a DataTypes object
  66.      */
  67.  
  68. STATIC BOOL __regargs
  69. GetSND(Object *object,struct TagItem *Tags,struct ClassBase *ClassBase)
  70. {
  71.     struct VoiceHeader    *VoiceHeader    = NULL;
  72.     BPTR                 File            = NULL;
  73.     LONG                 Error            = 0;
  74.     STRPTR                 Title            = (STRPTR)GetTagData(DTA_Name,NULL,Tags);
  75.     BOOL                 Result         = FALSE;
  76.  
  77.         // Get the basic data
  78.  
  79.     GetDTAttrs(object,
  80.         SDTA_VoiceHeader,    &VoiceHeader,
  81.         DTA_Handle,         &File,
  82.     TAG_DONE);
  83.  
  84.         // Do we have everything we need?
  85.  
  86.     if(File && VoiceHeader && Title)
  87.     {
  88.         BPTR FileHandle;
  89.  
  90.             // Open the file
  91.  
  92.         if(FileHandle = Open(Title,MODE_OLDFILE))
  93.         {
  94.             struct SoundDataHeader    Header;
  95.             BOOL                    GotIt = FALSE;
  96.  
  97.                 // Add some cache
  98.  
  99.             SetVBuf(FileHandle,NULL,BUF_FULL,4096);
  100.  
  101.                 // Read the MacBinary header if possible
  102.  
  103.             if(ReadMacBinaryHeader(FileHandle,&Error,SysBase,DOSBase))
  104.             {
  105.                     // If it's a MacBinary format file, read the rest
  106.  
  107.                 if(ScanResource(FileHandle,&Header,&Error,SysBase,DOSBase))
  108.                     GotIt = TRUE;
  109.             }
  110.  
  111.                 // So it's not a MacBinary format file
  112.  
  113.             if(!GotIt)
  114.             {
  115.                     // Return to the beginning of the file
  116.  
  117.                 if(Seek(FileHandle,0,OFFSET_BEGINNING) != -1)
  118.                 {
  119.                         // Look for "snd " resources
  120.  
  121.                     if(ScanResource(FileHandle,&Header,&Error,SysBase,DOSBase))
  122.                         GotIt = TRUE;
  123.                 }
  124.             }
  125.  
  126.                 // Did we get anything?
  127.  
  128.             if(GotIt)
  129.             {
  130.                 BYTE    *Sample = NULL;
  131.                 UBYTE    *Source;
  132.                 ULONG     Memory;
  133.                 LONG     Rate,Size,Skip,Frame;
  134.  
  135.                     // Fill in the basic data
  136.  
  137.                 Rate    = Header . SampleRate;
  138.                 Size    = Header . SampleSize;
  139.                 Skip    = 1;
  140.  
  141.                     // Don't waste too much memory for reading
  142.  
  143.                 if(Header . SampleSize < MIN_FRAME_RATE)
  144.                     Frame = Header . SampleSize;
  145.                 else
  146.                     Frame = MIN_FRAME_RATE;
  147.  
  148.                     // sound.datatype v40 no longer requires
  149.                     // the entire sample to reside in chip memory
  150.  
  151.                 if(SuperClassBase -> lib_Version > 39)
  152.                     Memory = MEMF_ANY;
  153.                 else
  154.                     Memory = MEMF_CHIP;
  155.  
  156.                     // Scale the sound down if the Amiga sound hardware
  157.                     // would be unable to handle the replay rate
  158.  
  159.                 while(Size > 0 && Rate > MIN_SAMPLE_RATE && Rate > MAX_SAMPLE_RATE)
  160.                 {
  161.                     Size    /= 2;
  162.                     Rate    /= 2;
  163.                     Skip    *= 2;
  164.                 }
  165.  
  166.                     // Allocate the read buffer
  167.  
  168.                 if(Source = AllocVec(Frame,MEMF_ANY))
  169.                 {
  170.                         // Try to allocate memory for the sample data
  171.  
  172.                     while(!(Sample = AllocVec(Size,Memory | MEMF_CLEAR)) && Size > 0 && Rate > MIN_SAMPLE_RATE)
  173.                     {
  174.                             // Scale it down if necessary
  175.  
  176.                         Size    /= 2;
  177.                         Rate    /= 2;
  178.                         Skip    *= 2;
  179.                     }
  180.  
  181.                         // Did we get anything?
  182.  
  183.                     if(!Sample)
  184.                         Error = ERROR_NO_FREE_STORE;
  185.                 }
  186.                 else
  187.                     Error = ERROR_NO_FREE_STORE;
  188.  
  189.                     // Did we get what we wanted?
  190.  
  191.                 if(Sample && !Error)
  192.                 {
  193.                     BYTE    *Dst    = Sample;
  194.                     LONG     Total    = Header . SampleSize,
  195.                              Needed;
  196.  
  197.                         // Read the source data
  198.  
  199.                     while(!Error && Total > 0)
  200.                     {
  201.                         if(Frame > Total)
  202.                             Needed = Total;
  203.                         else
  204.                             Needed = Frame;
  205.  
  206.                         if(Read(FileHandle,Source,Needed) == Needed)
  207.                         {
  208.                                 // Convert the source data
  209.  
  210.                             ConvertSample(Source,Dst,Needed,Skip);
  211.  
  212.                             Total    -= Needed;
  213.                             Dst     += Needed;
  214.                         }
  215.                         else
  216.                             Error = IoErr();
  217.                     }
  218.  
  219.                         // No read error so far?
  220.  
  221.                     if(!Error)
  222.                     {
  223.                         BYTE    Smallest,Largest;
  224.                         LONG    i;
  225.  
  226.                             // Initialize the voice header
  227.  
  228.                         memset(VoiceHeader,0,sizeof(struct VoiceHeader));
  229.  
  230.                         VoiceHeader -> vh_OneShotHiSamples    = Size;
  231.                         VoiceHeader -> vh_SamplesPerSec     = Rate;
  232.                         VoiceHeader -> vh_Octaves            = 1;
  233.                         VoiceHeader -> vh_Compression        = CMP_NONE;
  234.                         VoiceHeader -> vh_Volume            = 64;
  235.  
  236.                             // Look for the smallest and the largest
  237.                             // sample value
  238.  
  239.                         Smallest    = 127;
  240.                         Largest     = -128;
  241.                         Dst         = Sample;
  242.  
  243.                         for(i = 0 ; i < Size ; i++)
  244.                         {
  245.                             if(Dst[i] < Smallest)
  246.                                 Smallest = Dst[i];
  247.  
  248.                             if(Dst[i] > Largest)
  249.                                 Largest = Dst[i];
  250.                         }
  251.  
  252.                             // Does it use the full range?
  253.  
  254.                         if(Smallest > -128 || Largest < 127)
  255.                         {
  256.                             BYTE    Table[256],*Index;
  257.                             WORD    j;
  258.  
  259.                                 // Point it into the middle
  260.  
  261.                             Index = &Table[128];
  262.  
  263.                                 // Scale the negative values
  264.                                 // to use the full dynamic
  265.                                 // amplitude range
  266.  
  267.                             for(j = Smallest ; j < 0 ; j++)
  268.                                 Index[j] = (-128 * j) / Smallest;
  269.  
  270.                                 // Cut off anything below the
  271.                                 // smallest value
  272.  
  273.                             for(j = -128 ; j < Smallest ; j++)
  274.                                 Index[j] = -128;
  275.  
  276.                             Index[0] = 0;
  277.  
  278.                                 // Scale the positive values
  279.                                 // to use the full dynamic
  280.                                 // amplitude range
  281.  
  282.                             for(j = 1 ; j <= Largest ; j++)
  283.                                 Index[j] = (127 * j) / Largest;
  284.  
  285.                                 // Cut off anything above the
  286.                                 // largest value
  287.  
  288.                             for(j = Largest + 1 ; j < 256 ; j++)
  289.                                 Index[j] = 127;
  290.  
  291.                                 // Make the data use the full range
  292.  
  293.                             Dst = Sample;
  294.  
  295.                             for(i = 0 ; i < Size ; i++)
  296.                                 Dst[i] = Index[Dst[i]];
  297.                         }
  298.  
  299.                             // Fill in the remaining information
  300.  
  301.                         SetDTAttrs(object,NULL,NULL,
  302.                             DTA_ObjName,        Title,
  303.                             SDTA_Sample,        Sample,
  304.                             SDTA_SampleLength,    VoiceHeader -> vh_OneShotHiSamples,
  305.                             SDTA_Period,        (ULONG)(SysBase -> ex_EClockFrequency * 5) / (ULONG)VoiceHeader -> vh_SamplesPerSec,
  306.                             SDTA_Volume,        64,
  307.                             SDTA_Cycles,        1,
  308.                         TAG_DONE);
  309.  
  310.                             // Successful conversion
  311.  
  312.                         Result = TRUE;
  313.                     }
  314.                 }
  315.  
  316.                     // No success?
  317.  
  318.                 if(Error)
  319.                     Result = FALSE;
  320.  
  321.                     // Clean up...
  322.  
  323.                 if(Source)
  324.                     FreeVec(Source);
  325.  
  326.                 if(Sample && !Result)
  327.                     FreeVec(Sample);
  328.             }
  329.             else
  330.                 Error = ERROR_OBJECT_NOT_FOUND;
  331.  
  332.             Close(FileHandle);
  333.         }
  334.         else
  335.             Error = IoErr();
  336.     }
  337.     else
  338.         Error = ERROR_OBJECT_NOT_FOUND;
  339.  
  340.         // Set the error code
  341.  
  342.     if(Error)
  343.         SetIoErr(Error);
  344.  
  345.     return(Result);
  346. }
  347.  
  348.     /* RealClassDispatch():
  349.      *
  350.      *    The class dispatcher routine.
  351.      */
  352.  
  353. STATIC Object * __stdargs
  354. RealClassDispatch(Class *class,Object *object,Msg msg)
  355. {
  356.     struct ClassBase    *ClassBase = (struct ClassBase *)class -> cl_UserData;
  357.     Object                *Result;
  358.  
  359.         // What message is it?
  360.  
  361.     switch(msg -> MethodID)
  362.     {
  363.             // Create a new instance
  364.  
  365.         case OM_NEW:
  366.  
  367.             if(Result = (Object *)DoSuperMethodA(class,object,msg))
  368.             {
  369.                 if(!GetSND(Result,((struct opSet *)msg) -> ops_AttrList,ClassBase))
  370.                 {
  371.                     CoerceMethod(class,Result,OM_DISPOSE);
  372.  
  373.                     Result = NULL;
  374.                 }
  375.             }
  376.  
  377.             break;
  378.  
  379.             // Let the superclass handle the rest
  380.  
  381.         default:
  382.  
  383.             Result = (Object *)DoSuperMethodA(class,object,msg);
  384.  
  385.             break;
  386.     }
  387.  
  388.     return(Result);
  389. }
  390.  
  391.     /* ClassDispatch():
  392.      *
  393.      *    The frontend to the real class dispatcher routine.
  394.      */
  395.  
  396. Object * __saveds __asm
  397. ClassDispatch(register __a0 Class *class,register __a2 Object *object,register __a1 Msg msg)
  398. {
  399.     LONG Success;
  400.  
  401.     return((Object *)StackCall(&Success,8192,3,(LONG (* __stdargs)(...))RealClassDispatch,class,object,msg));
  402. }
  403.