home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Sound / DelfAIFF / src / DelfAIFF.c < prev    next >
C/C++ Source or Header  |  1999-10-01  |  21KB  |  660 lines

  1. /*******************************************************************
  2.  
  3.     DelfAIFF
  4.  
  5.     plays AIFF files (16bit SSND and ADP4) using Delfina DSP
  6.  
  7.  
  8.     code by Smack/Infect!
  9.     based on the example program DelfPlay
  10.  
  11.  
  12.     v0.3  Fri 01-Oct-1999
  13.  
  14. *******************************************************************/
  15.  
  16.  
  17.  
  18. #define DELFINA_SAMPLES 2046    /* multiple of 6 (for ADPCM decoder) */
  19. #define LOADBUFFERS     32      /* number of segments in ring buffer */
  20.  
  21.  
  22.  
  23. #define __stdargs /* vbcc <-- get rid of warnings on asyncio's declarations */
  24.  
  25. #include <proto/exec.h>
  26. #include <proto/dos.h>
  27. #include <proto/asyncio.h>  /* SAS/C */
  28. /*#include <clib/asyncio_protos.h>*/  /* vbcc */
  29. #include <proto/timer.h>
  30. #include <libraries/reqtools.h>
  31. #include <proto/reqtools.h> /* SAS/C */
  32. /*#include <clib/reqtools_protos.h>*/ /* vbcc */
  33. #include <exec/interrupts.h>
  34. #include <exec/execbase.h>
  35. #include <libraries/delfina.h>
  36. #include <libraries/asyncio.h>
  37. #include <devices/timer.h>
  38. #include <math.h>
  39. #include <limits.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42.  
  43. #define ID_FORM 0x464F524D
  44. #define ID_AIFF 0x41494646
  45. #define ID_COMM 0x434F4D4D
  46. #define ID_SSND 0x53534E44
  47. #define ID_ADP4 0x41445034
  48.  
  49. double ConvertFromIeeeExtended(unsigned char* bytes);
  50.  
  51. static UBYTE version[]="$VER: DelfAIFF 0.3 (Fri 01-Oct-1999)";
  52. static UBYTE template[]="FILES/M,NOPLAY/S";
  53.  
  54. struct loadbuf {
  55.     UBYTE *ptr;
  56.     struct loadbuf *next;
  57. };
  58.  
  59. struct loadbuf load_buf[LOADBUFFERS];
  60. struct loadbuf *curr_load, *curr_play;
  61. far UBYTE load_memory[DELFINA_SAMPLES*4*LOADBUFFERS];
  62.  
  63. UBYTE get_delfina_48khz[32];    /* input buffer for GetVar() */
  64. ULONG delfina_48khz=0;
  65.  
  66. extern struct DelfObj DSP56K_PCM;
  67. extern struct DelfObj DSP56K_ADPCM4;
  68.  
  69. extern struct ExecBase *SysBase;
  70. struct Library *DelfinaBase=NULL;
  71. struct Library *AsyncIOBase=NULL;
  72. struct Library *TimerBase=NULL;
  73. struct ReqToolsBase *ReqToolsBase=NULL;
  74.  
  75. UBYTE rtfilename[128]={0};
  76. struct Task *mytask;
  77. ULONG loadsize, aiffbytes, bytes_loaded, bytes_played;
  78. ULONG buffers_filled, buffers_missed, slow_adpcm4;
  79. struct Interrupt delfint={0};
  80. struct DelfPrg *prg_pcm=NULL, *prg_adpcm4=NULL;
  81. struct DelfModule *mod_pcm=NULL;
  82. int key=0;
  83. int adp4,mono,freq,noplay,pause;
  84. ULONG delfmemtype;
  85. int rc=0;
  86.  
  87.  
  88.  
  89. /*
  90. **
  91. ** interrupt server (supplies Delfina with data) **
  92. **
  93. */
  94. void int_server(void)
  95. {
  96.     if(pause)
  97.     {
  98.         /*
  99.         ** mute **
  100.         */
  101.         Delf_Run( prg_pcm->prog+2, 99, DRUNF_ASYNCH, 0, 0, 0, 0);
  102.     }
  103.     else
  104.     {
  105.         if(buffers_filled>0)
  106.         {
  107.             int data2delfina=1;
  108.             if(adp4)
  109.             {
  110.                 /*
  111.                 ** check if ADPCM decoder is still busy **
  112.                 */
  113.                 if(!Delf_Peek(prg_adpcm4->ydata,DMEMF_YDATA))
  114.                 {
  115.                     /*
  116.                     ** copy ADPCM data to Delfina and start decoder **
  117.                     */
  118.                     Delf_CopyMem( curr_play->ptr,
  119.                                   (void*)(prg_adpcm4->ydata+1),
  120.                                   loadsize,
  121.                                   DCPF_FROM_AMY|DCPF_YDATA|DCPF_24BIT );
  122.                     Delf_Run( prg_adpcm4->prog+2, 99, DRUNF_ASYNCH,
  123.                               mono,
  124.                               Delf_Peek(prg_pcm->ydata,DMEMF_YDATA),
  125.                               0,0);
  126.                 }
  127.                 else
  128.                 {
  129.                     data2delfina=0;
  130.                     slow_adpcm4++;
  131.                 }
  132.             }
  133.             else
  134.             {
  135.                 /*
  136.                 ** copy PCM data to Delfina **
  137.                 */
  138.                 Delf_CopyMem( curr_play->ptr,
  139.                               (void*)Delf_Peek(prg_pcm->ydata,DMEMF_YDATA),
  140.                               loadsize,
  141.                               DCPF_FROM_AMY|delfmemtype|DCPF_16BITH );
  142.             }
  143.             if(data2delfina)
  144.             {
  145.                 bytes_played+=loadsize;
  146.                 buffers_filled--;
  147.                 curr_play=curr_play->next;
  148.             }
  149.         }
  150.         else buffers_missed++;
  151.     }
  152. }
  153.  
  154.  
  155.  
  156. /*
  157. **
  158. ** allocate Delfina resources **
  159. **
  160. */
  161. int init_delfina(void)
  162. {
  163.     if(noplay) return(0);
  164.  
  165.     delfmemtype= mono ? DMEMF_XDATA : DMEMF_LDATA;
  166.  
  167.     if (!(prg_pcm=Delf_AddPrg(&DSP56K_PCM))) {
  168.         printf("**not enough Delfina memory\n");
  169.         return(0);
  170.     }
  171.  
  172.     delfint.is_Code=(void(*)(void))int_server;
  173.     if (!(key=Delf_AddIntServer(prg_pcm->prog,&delfint))) {
  174.         printf("**couldn't create interrupt server\n");
  175.         return(0);
  176.     }
  177.  
  178.     Delf_Run(prg_pcm->prog,0,0, mono,0,freq,0);
  179.  
  180.     if (!(mod_pcm=Delf_AddModule(   DM_Inputs, 0,
  181.                                 DM_Outputs, 1,
  182.                                 DM_Code, prg_pcm->prog+4,
  183.                                 DM_Freq, 48000,     /* always 48kHz output */
  184.                                 DM_Name, "DelfAIFF", 0)))
  185.     {
  186.         printf("**couldn't create DelfModule\n");
  187.         return(0);
  188.     }
  189.  
  190.     if(adp4)
  191.     {
  192.         prg_adpcm4=Delf_AddPrg(&DSP56K_ADPCM4);
  193.         if(!prg_adpcm4) {
  194.             printf("**not enough Delfina memory\n");
  195.             return(0);
  196.         }
  197.         Delf_Run( prg_adpcm4->prog, 0, 0, 0, 0, 0, 0);
  198.     }
  199.  
  200.     return(1);
  201. }
  202.  
  203.  
  204.  
  205. /*
  206. **
  207. ** free Delfina resources **
  208. **
  209. */
  210. void cleanup_delfina(void)
  211. {
  212.     Disable();
  213.     if (key)        { Delf_RemIntServer(key); key=0; }
  214.     if (mod_pcm)    { Delf_RemModule(mod_pcm); mod_pcm=NULL; }
  215.     if (prg_adpcm4) { Delf_RemPrg(prg_adpcm4); prg_adpcm4=NULL; }
  216.     if (prg_pcm)    { Delf_RemPrg(prg_pcm); prg_pcm=NULL; }
  217.     Enable();
  218. }
  219.  
  220.  
  221.  
  222.     
  223.  
  224.  
  225. int main(void)
  226. {
  227.     struct RDArgs *rdargs;
  228.     LONG args[3]={0,0,0};
  229.     ULONG header_l[3], i, r1, taskpri;
  230.     ULONG sigs, aiffbits=0, aifftype=0;
  231.     UBYTE **files_pt, *filename, ende=0;
  232.     struct AsyncFile *file;
  233.     double duration, duration2;
  234.     ULONG minutes, seconds, millisec;
  235.     struct timeval time1,time2;
  236.     struct rtFileRequester *rtfilereq=NULL;
  237.     struct rtFileList *rtfilelist=NULL, *rtfilelist_curr=NULL;
  238.     BPTR lock_newdir=(BPTR)NULL, lock_olddir=(BPTR)NULL;
  239.     
  240.     /*
  241.     **
  242.     ** read args **
  243.     **
  244.     */
  245.     printf("\33[1m%s by Smack/Infect!\33[0m\n",&version[6]);
  246.     rdargs=ReadArgs(template,args,NULL);
  247.     files_pt=(UBYTE**)args[0];
  248.     noplay=args[1];
  249.  
  250.     /*
  251.     **
  252.     ** open libraries **
  253.     **
  254.     */
  255.     if (!(DelfinaBase=OpenLibrary("delfina.library",4))) {
  256.         printf("**unable to open delfina.library V4\n");
  257.         rc=20;
  258.         goto exit_clean;
  259.     }
  260.     if (!(AsyncIOBase=OpenLibrary("asyncio.library",39))) {
  261.         printf("**unable to open asyncio.library V39\n");
  262.         rc=20;
  263.         goto exit_clean;
  264.     }
  265.     TimerBase=(struct Library*)FindName(&SysBase->DeviceList,"timer.device");
  266.  
  267.     if(0<(GetVar("DELFINA_48KHZ",get_delfina_48khz,32,LV_VAR)))
  268.     {
  269.         delfina_48khz=strtoul(get_delfina_48khz,NULL,10);
  270.         printf("  ////read ENV: DELFINA_48KHZ = '%s' (%ldHz)\n",get_delfina_48khz,(long)delfina_48khz);
  271.         if(delfina_48khz==ULONG_MAX) delfina_48khz=0;
  272.     }
  273.     mytask=FindTask(NULL);
  274.  
  275.     /*
  276.     **
  277.     ** init load buffers **
  278.     **
  279.     */
  280.     for(i=0;i<LOADBUFFERS;i++)
  281.     {
  282.         load_buf[i].ptr =&load_memory[i*DELFINA_SAMPLES*4];
  283.         load_buf[i].next=&load_buf[i+1];
  284.     }
  285.     load_buf[LOADBUFFERS-1].next=&load_buf[0];
  286.  
  287.     /*
  288.     **
  289.     ** reqtools filerequester if no files specified **
  290.     **
  291.     */
  292.     if(!files_pt)
  293.     {
  294.         if((ReqToolsBase=(struct ReqToolsBase*)OpenLibrary("reqtools.library",38)))
  295.         {
  296.             if(!(rtfilereq=rtAllocRequest(RT_FILEREQ,NULL)))
  297.             {
  298.                 rc=10;
  299.                 goto exit_clean;
  300.             }
  301.         }
  302.         else
  303.         {
  304.             rc=5;
  305.             goto exit_clean;
  306.         }
  307.     }
  308.  
  309. next_filereq:
  310.     if(rtfilereq)
  311.     {
  312.         rtfilelist=rtFileRequest( rtfilereq, &rtfilename[0],
  313.                                   "DelfAIFF: select AIFF sound files",
  314.                                   RTFI_Flags, FREQF_MULTISELECT|FREQF_PATGAD,
  315.                                   TAG_DONE );
  316.         if(rtfilelist)
  317.         {
  318.             rtfilelist_curr=rtfilelist;
  319.             if(rtfilereq->Dir)
  320.             {
  321.                 lock_newdir=Lock(rtfilereq->Dir,SHARED_LOCK);
  322.                 lock_olddir=CurrentDir(lock_newdir);
  323.             }
  324.         }
  325.         else goto exit_clean;
  326.     }
  327.  
  328.     /*
  329.     **
  330.     ** files loop **
  331.     **
  332.     */
  333.     do
  334.     {
  335.         /*
  336.         **
  337.         ** get next filename **
  338.         **
  339.         */
  340.         if(rtfilelist)
  341.         {
  342.             if(rtfilelist_curr)
  343.             {
  344.                 filename=rtfilelist_curr->Name;
  345.                 rtfilelist_curr=rtfilelist_curr->Next;
  346.             }
  347.             else filename=NULL;
  348.         }
  349.         else filename=(*files_pt++);
  350.         if(!filename) break;
  351.         printf("\n  file: %s\n",filename);
  352.  
  353.         /*
  354.         **
  355.         ** open file **
  356.         **
  357.         */
  358.         if((file=OpenAsync(filename,MODE_READ,128*1024)))
  359.         {
  360.             /*
  361.             **
  362.             ** is it a "FORM AIFF" file? **
  363.             **
  364.             */
  365.             r1=ReadAsync(file,&header_l[0],3*4);
  366.             if( (header_l[0]==ID_FORM) &&
  367.                 (header_l[2]==ID_AIFF) &&
  368.                 (r1==3*4) )
  369.             {
  370.                 /*
  371.                 **
  372.                 ** read AIFF features **
  373.                 **
  374.                 */
  375.                 WORD aiff_error=0, header_ok=0, sound_ok=0;
  376.                 UWORD buf2;
  377.                 UBYTE buf10[10];
  378.                 do
  379.                 {
  380.                     /*
  381.                     ** IFF chunk header **
  382.                     */
  383.                     r1=ReadAsync(file,&header_l[0],2*4);
  384.                     if( r1==2*4 )
  385.                     {
  386.                         switch(header_l[0])
  387.                         {
  388.                             case ID_COMM:
  389.                                 /*
  390.                                 ** get features from COMM chunk **
  391.                                 */
  392.                                 if(header_l[1]==18)
  393.                                 {
  394.                                     ReadAsync(file,&buf2,2);     /* channels */
  395.                                     mono= buf2>1 ? 0 : 1;
  396.                                     ReadAsync(file,&buf10[0],4); /* frames */
  397.                                     ReadAsync(file,&buf2,2);     /* bits */
  398.                                     aiffbits=(ULONG)buf2;
  399.                                     ReadAsync(file,&buf10[0],10);/* rate */
  400.                                     freq=(ULONG)ConvertFromIeeeExtended(buf10);
  401.                                     header_ok=1;
  402.                                 }
  403.                                 else aiff_error=1; /* invalid COMM chunk */
  404.                                 break;
  405.                             case ID_SSND:
  406.                             case ID_ADP4:
  407.                                 /*
  408.                                 ** found sound data **
  409.                                 */
  410.                                 aifftype =header_l[0];
  411.                                 aiffbytes=header_l[1];
  412.                                 sound_ok=1;
  413.                                 if(!header_ok) aiff_error=1; /* no COMM chunk */
  414.                                 break;
  415.                             default:
  416.                                 /*
  417.                                 ** skip unknown chunk **
  418.                                 */
  419.                                 SeekAsync(file,(long)header_l[1],MODE_CURRENT);
  420.                         }
  421.                     }
  422.                     else aiff_error=1;
  423.                 } while(!sound_ok && !aiff_error);
  424.  
  425.                 if(!aiff_error && sound_ok && header_ok && aiffbits==16)
  426.                 {
  427.                     printf("  type: AIFF %s, %ldHz, %s\n",
  428.                         aifftype==ID_SSND?"SSND":"ADP4", (long)freq, mono?"mono":"stereo");
  429.                     /*
  430.                     **
  431.                     ** setup playback
  432.                     **
  433.                     */
  434.                     duration=(double)aiffbytes/2.0/(double)freq;    /* SSND */
  435.                     loadsize=DELFINA_SAMPLES*2;
  436.                     if(!mono)
  437.                     {
  438.                         duration/=2.0;
  439.                         loadsize*=2;
  440.                     }
  441.                     adp4=0;
  442.                     if(aifftype==ID_ADP4)    /* ADP4 */
  443.                     {
  444.                         adp4=1;
  445.                         duration*=4.0;
  446.                         loadsize>>=2;
  447.                     }
  448.                     millisec=(ULONG)(1000.0*modf(duration,&duration2));
  449.                     minutes=(ULONG)(duration2/60.0);
  450.                     seconds=(ULONG)(duration2-minutes*60.0);
  451.                     printf("  time: %02ld min %02ld.%03ld sec\n",
  452.                                 (long)minutes, (long)seconds, (long)millisec);
  453.                     if(delfina_48khz)
  454.                     {
  455.                         freq=(ULONG)((double)freq*48000.0/(double)delfina_48khz);
  456.                         printf("  ////adjusted freq:   %ldHz\n",(long)freq);
  457.                     }
  458.  
  459.                     /*
  460.                     **
  461.                     ** play file
  462.                     **
  463.                     */
  464.                     curr_load=curr_play=&load_buf[0];
  465.                     bytes_loaded=bytes_played=buffers_filled=buffers_missed=slow_adpcm4=0;
  466.                     pause=0;
  467.                     if(init_delfina())
  468.                     {
  469.                         printf("  playing..."); fflush(stdout);
  470.                         taskpri=SetTaskPri(mytask,9);
  471.                         GetSysTime(&time1);
  472.  
  473.                         while(1)
  474.                         {
  475.                             sigs=mytask->tc_SigRecvd;
  476.                             if(sigs&SIGBREAKF_CTRL_C)
  477.                             {
  478.                                 printf(" break CTRL-C\n");
  479.                                 mytask->tc_SigRecvd&=!SIGBREAKF_CTRL_C;
  480.                                 pause=1;
  481.                                 break;  /* exit loading-loop */
  482.                             }
  483.                             if(sigs&SIGBREAKF_CTRL_D)
  484.                             {
  485.                                 printf(" break CTRL-D\n");
  486.                                 mytask->tc_SigRecvd&=!SIGBREAKF_CTRL_D;
  487.                                 pause=1;
  488.                                 ende=1;
  489.                                 break;  /* exit loading-loop */
  490.                             }
  491.                             if(sigs&SIGBREAKF_CTRL_E)
  492.                             {
  493.                                 mytask->tc_SigRecvd&=!SIGBREAKF_CTRL_E;
  494.                                 if(pause)
  495.                                 {
  496.                                     printf("\n  playing..."); fflush(stdout);
  497.                                     pause=0;
  498.                                 }
  499.                                 else
  500.                                 {
  501.                                     pause=1;
  502.                                     printf(" pause"); fflush(stdout);
  503.                                 }
  504.                             }
  505.                             if( (buffers_filled<LOADBUFFERS) &&
  506.                                 (bytes_loaded<aiffbytes) )
  507.                             {
  508.                                 ReadAsync(file,curr_load->ptr,loadsize);
  509.                                 curr_load=curr_load->next;
  510.                                 bytes_loaded+=loadsize;
  511.                                 buffers_filled++;
  512.                             }
  513.                             else
  514.                             {
  515.                                 if( (bytes_loaded>=aiffbytes) &&
  516.                                     (bytes_played>=aiffbytes) )
  517.                                 {
  518.                                     printf(" done\n");
  519.                                     pause=1;
  520.                                     break;  /* exit loading-loop */
  521.                                 }
  522.                                 Delay(1);
  523.                             }
  524.                         }
  525.  
  526.                         GetSysTime(&time2);
  527.                         SetTaskPri(mytask,taskpri);
  528.                         if(buffers_missed>1)
  529.                         {
  530.                             printf("  note: irq was missing data %ld times\n",(long)buffers_missed-1);
  531.                         }
  532.                         if(slow_adpcm4)
  533.                         {
  534.                             printf("  note: ADPCM4 decoder finished late %ld times\n",(long)slow_adpcm4);
  535.                         }
  536.                         SubTime(&time2,&time1);
  537.                         millisec=(ULONG)((double)time2.tv_micro/1000.0);
  538.                         minutes=(ULONG)((double)time2.tv_secs/60.0);
  539.                         seconds=(ULONG)((double)time2.tv_secs-minutes*60.0);
  540.                         duration2=(double)time2.tv_secs+(double)time2.tv_micro/1000000.0;
  541.                         if(delfina_48khz)
  542.                         {
  543.                             printf("  ////elapsed time:    %02ld:%02ld.%03ld\n",
  544.                                     (long)minutes, (long)seconds, (long)millisec);
  545.                             printf("  ////measured: DELFINA_48KHZ = %ldHz\n",(long)(48000.0*duration/duration2));
  546.                         }
  547.                     }
  548.                     cleanup_delfina();
  549.                 }
  550.                 else printf("**file type not supported\n");
  551.             }
  552.             else printf("**not an AIFF file\n");
  553.             CloseAsync(file);
  554.         }
  555.         else printf("**unable to open file\n");
  556.     } while(!ende);
  557.  
  558.     if(rtfilelist)
  559.     {
  560.         if(lock_olddir) { CurrentDir(lock_olddir); lock_olddir=NULL; }
  561.         if(lock_newdir) { UnLock(lock_newdir); lock_newdir=NULL; }
  562.         rtFreeFileList(rtfilelist); rtfilelist=NULL;
  563.         if(!ende) goto next_filereq;
  564.     }
  565.  
  566. exit_clean:
  567.     if(rdargs) FreeArgs(rdargs);
  568.     if(rtfilereq) rtFreeRequest(rtfilereq);
  569.     if(ReqToolsBase) CloseLibrary((struct Library*)ReqToolsBase);
  570.     if(AsyncIOBase) CloseLibrary(AsyncIOBase);
  571.     if(DelfinaBase) CloseLibrary(DelfinaBase);
  572.     return(rc);
  573. }
  574.  
  575.  
  576.  
  577.  
  578.  
  579. /*
  580.  * C O N V E R T   F R O M   I E E E   E X T E N D E D  
  581.  */
  582.  
  583. /* 
  584.  * Copyright (C) 1988-1991 Apple Computer, Inc.
  585.  * All rights reserved.
  586.  *
  587.  * Machine-independent I/O routines for IEEE floating-point numbers.
  588.  *
  589.  * NaN's and infinities are converted to HUGE_VAL or HUGE, which
  590.  * happens to be infinity on IEEE machines.  Unfortunately, it is
  591.  * impossible to preserve NaN's in a machine-independent way.
  592.  * Infinities are, however, preserved on IEEE machines.
  593.  *
  594.  * These routines have been tested on the following machines:
  595.  *    Apple Macintosh, MPW 3.1 C compiler
  596.  *    Apple Macintosh, THINK C compiler
  597.  *    Silicon Graphics IRIS, MIPS compiler
  598.  *    Cray X/MP and Y/MP
  599.  *    Digital Equipment VAX
  600.  *
  601.  *
  602.  * Implemented by Malcolm Slaney and Ken Turkowski.
  603.  *
  604.  * Malcolm Slaney contributions during 1988-1990 include big- and little-
  605.  * endian file I/O, conversion to and from Motorola's extended 80-bit
  606.  * floating-point format, and conversions to and from IEEE single-
  607.  * precision floating-point format.
  608.  *
  609.  * In 1991, Ken Turkowski implemented the conversions to and from
  610.  * IEEE double-precision format, added more precision to the extended
  611.  * conversions, and accommodated conversions involving +/- infinity,
  612.  * NaN's, and denormalized numbers.
  613.  */
  614.  
  615. #ifndef HUGE_VAL
  616. # define HUGE_VAL HUGE
  617. #endif /*HUGE_VAL*/
  618.  
  619. # define UnsignedToFloat(u)         (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
  620.  
  621. /****************************************************************
  622.  * Extended precision IEEE floating-point conversion routine.
  623.  ****************************************************************/
  624.  
  625. double ConvertFromIeeeExtended(unsigned char* bytes /* LCN */)
  626. {
  627.     double    f;
  628.     int    expon;
  629.     unsigned long hiMant, loMant;
  630.     
  631.     expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
  632.     hiMant    =    ((unsigned long)(bytes[2] & 0xFF) << 24)
  633.             |    ((unsigned long)(bytes[3] & 0xFF) << 16)
  634.             |    ((unsigned long)(bytes[4] & 0xFF) << 8)
  635.             |    ((unsigned long)(bytes[5] & 0xFF));
  636.     loMant    =    ((unsigned long)(bytes[6] & 0xFF) << 24)
  637.             |    ((unsigned long)(bytes[7] & 0xFF) << 16)
  638.             |    ((unsigned long)(bytes[8] & 0xFF) << 8)
  639.             |    ((unsigned long)(bytes[9] & 0xFF));
  640.  
  641.     if (expon == 0 && hiMant == 0 && loMant == 0) {
  642.         f = 0;
  643.     }
  644.     else {
  645.         if (expon == 0x7FFF) {    /* Infinity or NaN */
  646.             f = HUGE_VAL;
  647.         }
  648.         else {
  649.             expon -= 16383;
  650.             f  = ldexp(UnsignedToFloat(hiMant), expon-=31);
  651.             f += ldexp(UnsignedToFloat(loMant), expon-=32);
  652.         }
  653.     }
  654.  
  655.     if (bytes[0] & 0x80)
  656.         return -f;
  657.     else
  658.         return f;
  659. }
  660.