home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 1 / Mecomp-CD.iso / amiga / player / ahi / developer / drivers / filesave / filesave.c < prev    next >
C/C++ Source or Header  |  1996-11-01  |  23KB  |  852 lines

  1.  
  2. #define NO_PROTOS
  3. #define NO_SAS_PRAGMAS
  4. #include <iffp/8svx.h>
  5. #undef NO_PROTOS
  6. #undef NO_SAS_PRAGMAS
  7.  
  8. #include <exec/exec.h>
  9. #include <devices/ahi.h>
  10. #include <dos/dos.h>
  11. #include <dos/dostags.h>
  12. #include <graphics/gfxbase.h>
  13. #include <libraries/ahi_sub.h>
  14. #include <libraries/asl.h>
  15. #include <datatypes/datatypes.h>
  16. #include <datatypes/soundclass.h>
  17. #include <proto/asl.h>
  18. #include <proto/exec.h>
  19. #include <proto/dos.h>
  20. #include <proto/intuition.h>
  21. #include <proto/utility.h>
  22. #include <proto/datatypes.h>
  23. #include <proto/ahi_sub.h>
  24. #include <stdlib.h>
  25. #include "filesave.h"
  26.  
  27. #define EQ ==
  28. #define dd ((struct filesave *) AudioCtrl->ahiac_DriverData)
  29.  
  30. #define SAVEBUFFERSIZE 100000   // in samples (min)
  31. #define RECBUFFERSIZE  10000    // in samples
  32.  
  33. extern char __far _LibID[];
  34. extern char __far _LibName[];
  35.  
  36. extern void KPrintF(char *fmt,...);
  37.  
  38. #define FREQUENCIES 19
  39. const ULONG  frequency[FREQUENCIES] =
  40. {
  41.   8000,     // µ- and A-Law
  42.   9600,     // DAT/5
  43.   11025,    // CD/4
  44.   12000,    // DAT/4
  45.   14700,    // CD/3
  46.   16000,    // DAT/3
  47.   17640,    // CD/2.5
  48.   18900,
  49.   19200,    // DAT/2.5
  50.   22050,    // CD/2
  51.   24000,    // DAT/2
  52.   29400,    // CD/1.5
  53.   32000,    // DAT/1.5
  54.   37800,
  55.   44056,    // Some kind of video rate
  56.   44100,    // CD
  57.   48000,    // DAT
  58.   88200,    // CD*2
  59.   96000     // DAT*2
  60. };
  61.  
  62. extern void SlaveEntry(void);
  63. extern void RecSlaveEntry(void);
  64. void ulong2extended (ULONG in, extended *ex);
  65.  
  66. struct DosLibrary     *DOSBase=NULL;
  67. struct Library        *UtilityBase=NULL;
  68. struct Library        *AslBase=NULL;
  69. struct IntuitionBase  *IntuitionBase=NULL;
  70. struct Library        *AHIsubBase=NULL;
  71. struct Library        *DataTypesBase=NULL;
  72. struct GfxBase        *GfxBase=NULL;
  73.  
  74. int  __saveds __asm __UserLibInit (register __a6 struct Library *libbase)
  75. {
  76.   AHIsubBase=libbase;
  77.  
  78.   if(!(AslBase=OpenLibrary("asl.library",37)))
  79.   {
  80.     Alert(AN_Unknown|AG_OpenLib|AO_Unknown);
  81.     return 1;
  82.   }
  83.  
  84.   if(!(DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37)))
  85.   {
  86.     Alert(AN_Unknown|AG_OpenLib|AO_DOSLib);
  87.     return 1;
  88.   }
  89.  
  90.   if(!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37)))
  91.   {
  92.     Alert(AN_Unknown|AG_OpenLib|AO_GraphicsLib);
  93.     return 1;
  94.   }
  95.  
  96.   if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  97.   {
  98.     Alert(AN_Unknown|AG_OpenLib|AO_Intuition);
  99.     return 1;
  100.   }
  101.  
  102.   if(!(UtilityBase=OpenLibrary("utility.library",37)))
  103.   {
  104.     Alert(AN_Unknown|AG_OpenLib|AO_UtilityLib);
  105.     return 1;
  106.   }
  107.  
  108. // Don't fail if this one doesn't open!
  109.   DataTypesBase=OpenLibrary("datatypes.library",39);
  110.  
  111.   return 0;
  112. }
  113.  
  114. void __saveds __asm __UserLibCleanup (register __a6 struct Library *libbase)
  115. {
  116.   if(AslBase)       { CloseLibrary(AslBase); AslBase=NULL; }
  117.   if(DOSBase)       { CloseLibrary((struct Library *)DOSBase); DOSBase=NULL; }
  118.   if(GfxBase)       { CloseLibrary((struct Library *)GfxBase); GfxBase=NULL; }
  119.   if(IntuitionBase) { CloseLibrary((struct Library *)IntuitionBase); IntuitionBase=NULL; }
  120.   if(UtilityBase)   { CloseLibrary(UtilityBase); UtilityBase=NULL; }
  121.   if(DataTypesBase) { CloseLibrary(DataTypesBase); DataTypesBase=NULL; }
  122. }
  123.  
  124. ULONG __asm __saveds intAHIsub_AllocAudio(
  125.     register __a1 struct TagItem *tagList,
  126.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  127. {
  128.  
  129.   if(AudioCtrl->ahiac_DriverData=AllocVec(sizeof(struct filesave),MEMF_CLEAR))
  130.   {
  131.     dd->fs_AHIsubBase=AHIsubBase;
  132.     dd->fs_DisableSignal=-1;
  133.     dd->fs_EnableSignal=-1;
  134.     dd->fs_SlaveSignal=-1;
  135.     dd->fs_MasterSignal=AllocSignal(-1);
  136.     dd->fs_MasterTask=(struct Process *)FindTask(NULL);
  137.  
  138.     dd->fs_RecSlaveSignal=-1;
  139.     dd->fs_RecMasterSignal=AllocSignal(-1);
  140.   }
  141.   else
  142.     return AHISF_ERROR;
  143.   if((dd->fs_MasterSignal EQ -1) || (dd->fs_RecMasterSignal EQ -1))
  144.     return AHISF_ERROR;
  145.  
  146.   dd->fs_Format=GetTagData(AHIDB_FileSaveFormat,FORMAT_8SVX,tagList);
  147.  
  148.   if(!(dd->fs_FileReq=AllocAslRequestTags(ASL_FileRequest,
  149.       ASLFR_InitialFile,
  150.           (dd->fs_Format EQ FORMAT_8SVX ? ".8SVX" :
  151.             (dd->fs_Format EQ FORMAT_AIFF ? ".AIFF" :
  152.               (dd->fs_Format EQ FORMAT_AIFC ? ".AIFC" : ""))),
  153.       ASLFR_DoSaveMode,TRUE,
  154.       ASLFR_RejectIcons,TRUE,
  155.       ASLFR_TitleText,_LibID,
  156.       TAG_DONE)))
  157.     return AHISF_ERROR;
  158.  
  159.   if(!(dd->fs_RecFileReq=AllocAslRequestTags(ASL_FileRequest,
  160.       ASLFR_RejectIcons,TRUE,
  161.       ASLFR_TitleText,"Select a sound sample",
  162.       TAG_DONE)))
  163.     return AHISF_ERROR;
  164.  
  165.   return AHISF_KNOWHIFI|AHISF_KNOWSTEREO|AHISF_CANRECORD|AHISF_MIXING|AHISF_TIMING;
  166. }
  167.  
  168. void __asm __saveds intAHIsub_FreeAudio(
  169.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  170. {
  171.   if(AudioCtrl->ahiac_DriverData)
  172.   {
  173.     FreeAslRequest(dd->fs_FileReq);
  174.     FreeAslRequest(dd->fs_RecFileReq);
  175.     FreeSignal(dd->fs_MasterSignal);
  176.     FreeSignal(dd->fs_RecMasterSignal);
  177.     FreeVec(AudioCtrl->ahiac_DriverData);
  178.     AudioCtrl->ahiac_DriverData=NULL;
  179.   }
  180. }
  181.  
  182. ULONG __asm __saveds intAHIsub_Start(
  183.     register __d0 ULONG Flags,
  184.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  185. {
  186.  
  187.   AHIsub_Stop(Flags,AudioCtrl);
  188.  
  189.   if(Flags & AHISF_PLAY)
  190.   {
  191.     ULONG savebufferlength;
  192.  
  193.     if(!(dd->fs_MixBuffer=AllocVec(AudioCtrl->ahiac_BuffSize,MEMF_ANY)))
  194.       return AHIE_NOMEM;
  195.  
  196.     dd->fs_SaveBufferSize=AudioCtrl->ahiac_MaxBuffSamples;
  197.     if(AudioCtrl->ahiac_Flags & AHIACF_STEREO)
  198.       dd->fs_SaveBufferSize <<=1;
  199.     if(dd->fs_SaveBufferSize < SAVEBUFFERSIZE)
  200.       dd->fs_SaveBufferSize = SAVEBUFFERSIZE;
  201.  
  202.     savebufferlength = dd->fs_SaveBufferSize;
  203.     if((dd->fs_Format EQ FORMAT_AIFF) || (dd->fs_Format EQ FORMAT_AIFC))
  204.       savebufferlength <<=1;
  205.  
  206.     if(!(dd->fs_SaveBuffer=AllocVec(savebufferlength,MEMF_ANY)))
  207.       return AHIE_NOMEM;
  208.  
  209.     if(AslRequestTags(dd->fs_FileReq,TAG_DONE))
  210.     {
  211.       Forbid();
  212.       if(dd->fs_SlaveTask=CreateNewProcTags(
  213.           NP_Entry,SlaveEntry,
  214.           NP_Name,_LibName,
  215.           NP_Priority,-1,               // It's a number cruncher...
  216.           TAG_DONE))
  217.         dd->fs_SlaveTask->pr_Task.tc_UserData=AudioCtrl;
  218.       Permit();
  219.       if(dd->fs_SlaveTask)
  220.       {
  221.         Wait(1L<<dd->fs_MasterSignal);  // Wait for slave to come alive
  222.         if(dd->fs_SlaveTask EQ NULL)    // Is slave alive or dead?
  223.           return AHIE_UNKNOWN;
  224.       }
  225.       else
  226.         return AHIE_NOMEM;
  227.     }
  228.     else
  229.       if(IoErr())
  230.         return AHIE_NOMEM;    //error occured
  231.       else
  232.         return AHIE_ABORTED;  //requester cancelled
  233.   }
  234.  
  235.   if(Flags & AHISF_RECORD)
  236.   {
  237.     if(!(dd->fs_RecBuffer=AllocVec(RECBUFFERSIZE*4,MEMF_ANY)))
  238.       return AHIE_NOMEM;
  239.  
  240.     if(AslRequestTags(dd->fs_RecFileReq,TAG_DONE))
  241.     {
  242.       Delay(TICKS_PER_SECOND);         // Wait for window to close etc...
  243.       Forbid();
  244.       if(dd->fs_RecSlaveTask=CreateNewProcTags(
  245.           NP_Entry,RecSlaveEntry,
  246.           NP_Name,_LibName,
  247.           NP_Priority,1,               // Make it steady...
  248.           TAG_DONE))
  249.         dd->fs_RecSlaveTask->pr_Task.tc_UserData=AudioCtrl;
  250.       Permit();
  251.       if(dd->fs_RecSlaveTask)
  252.       {
  253.         Wait(1L<<dd->fs_RecMasterSignal);  // Wait for slave to come alive
  254.         if(dd->fs_RecSlaveTask EQ NULL)    // Is slave alive or dead?
  255.           return AHIE_UNKNOWN;
  256.       }
  257.       else
  258.         return AHIE_NOMEM;
  259.     }
  260.     else
  261.       if(IoErr())
  262.         return AHIE_NOMEM;    //error occured
  263.       else
  264.         return AHIE_ABORTED;  //requester cancelled
  265.   }
  266.  
  267.   return AHIE_OK;
  268. }
  269.  
  270.  
  271. void __asm __saveds intAHIsub_Update(
  272.     register __d0 ULONG Flags,
  273.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  274. {
  275. }
  276.  
  277.  
  278. void __asm __saveds intAHIsub_Stop(
  279.     register __d0 ULONG Flags,
  280.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  281. {
  282.   if(Flags & AHISF_PLAY)
  283.   {
  284.     if(dd->fs_SlaveTask)
  285.     {
  286.       if(dd->fs_SlaveSignal != -1)
  287.         Signal((struct Task *)dd->fs_SlaveTask,1L<<dd->fs_SlaveSignal); // Kill him!
  288.       Wait(1L<<dd->fs_MasterSignal);  // Wait for slave to die
  289.     }
  290.     FreeVec(dd->fs_MixBuffer);
  291.     dd->fs_MixBuffer=NULL;
  292.     FreeVec(dd->fs_SaveBuffer);
  293.     dd->fs_SaveBuffer=NULL;
  294.   }
  295.  
  296.   if(Flags & AHISF_RECORD)
  297.   {
  298.     if(dd->fs_RecSlaveTask)
  299.     {
  300.       if(dd->fs_RecSlaveSignal != -1)
  301.         Signal((struct Task *)dd->fs_RecSlaveTask,1L<<dd->fs_RecSlaveSignal); // Kill him!
  302.       Wait(1L<<dd->fs_RecMasterSignal);  // Wait for slave to die
  303.     }
  304.     FreeVec(dd->fs_RecBuffer);
  305.     dd->fs_RecBuffer=NULL;
  306.   }
  307. }
  308.  
  309.  
  310.  
  311. LONG __asm __saveds intAHIsub_GetAttr(
  312.     register __d0 ULONG Attribute,
  313.     register __d1 LONG Argument,
  314.     register __d2 LONG Default,
  315.     register __a1 struct TagItem *tagList,
  316.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  317. {
  318.   int i;
  319.   switch(Attribute)
  320.   {
  321.   case AHIDB_Bits:
  322.     if(GetTagData(AHIDB_FileSaveFormat,FORMAT_8SVX,tagList) EQ FORMAT_8SVX)
  323.       return 8;
  324.     else
  325.       return 16;
  326.   case AHIDB_Frequencies:
  327.     return FREQUENCIES;
  328.   case AHIDB_Frequency: // Index->Frequency
  329.     return (LONG) frequency[Argument];
  330.   case AHIDB_Index: // Frequency->Index
  331.     if(Argument<=frequency[0])
  332.       return 0;
  333.     if(Argument>=frequency[FREQUENCIES-1])
  334.       return FREQUENCIES-1;
  335.     for(i=1;i<FREQUENCIES;i++)
  336.       if(frequency[i]>Argument)
  337.       {
  338.         if( (Argument-frequency[i-1]) < (frequency[i]-Argument) )
  339.           return i-1;
  340.         else
  341.           return i;
  342.       }
  343.     return NULL;  // Will not happen
  344.   case AHIDB_Author:
  345.     return (LONG) "Martin 'Leviticus' Blom";
  346.   case AHIDB_Copyright:
  347.     return (LONG) "Public Domain";
  348.   case AHIDB_Version:
  349.     return (LONG) _LibID;
  350.   case AHIDB_Record:
  351.   case AHIDB_FullDuplex:
  352.     return TRUE;
  353.   case AHIDB_MaxRecordSamples:
  354.     return RECBUFFERSIZE;
  355.   case AHIDB_Realtime:
  356.     return FALSE;
  357.   case AHIDB_Inputs:
  358.     return 1;
  359.   case AHIDB_Input:
  360.     return (LONG) "File";    // We have only one input!
  361.   case AHIDB_Outputs:
  362.     return 1;
  363.   case AHIDB_Output:
  364.     return (LONG) "File";    // We have only one output!
  365.   default:
  366.     return Default;
  367.   }
  368. }
  369.  
  370.  
  371. ULONG __asm __saveds intAHIsub_HardwareControl(
  372.     register __d0 ULONG attribute,
  373.     register __d1 LONG argument,
  374.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  375. {
  376.   return NULL;
  377. }
  378.  
  379. /*
  380. ** Unused LVOs follows...
  381. */
  382.  
  383. ULONG __asm __saveds intAHIsub_SetVol(
  384.     register __d0 UWORD channel,
  385.     register __d1 Fixed volume,
  386.     register __d2 sposition pan,
  387.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
  388.     register __d3 ULONG Flags)
  389. {
  390.   return AHIS_UNKNOWN;
  391. }
  392.  
  393. ULONG __asm __saveds intAHIsub_SetFreq(
  394.     register __d0 UWORD channel,
  395.     register __d1 ULONG freq,
  396.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
  397.     register __d2 ULONG flags )
  398. {
  399.   return AHIS_UNKNOWN;
  400. }
  401.  
  402. ULONG __asm __saveds intAHIsub_SetSound(
  403.     register __d0 UWORD channel,
  404.     register __d1 UWORD sound,
  405.     register __d2 ULONG offset,
  406.     register __d3 LONG length,
  407.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
  408.     register __d4 ULONG flags )
  409. {
  410.   return AHIS_UNKNOWN;
  411. }
  412.  
  413.  
  414. ULONG __asm __saveds intAHIsub_SetEffect (
  415.     register __a0 APTR effect,
  416.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  417. {
  418.   return AHIS_UNKNOWN;
  419. }
  420.  
  421. ULONG __asm __saveds intAHIsub_LoadSound(
  422.     register __d0 UWORD sound,
  423.     register __d1 ULONG type,
  424.     register __a0 APTR info,
  425.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  426. {
  427.   return AHIS_UNKNOWN;
  428. }
  429.  
  430. ULONG __asm __saveds intAHIsub_UnloadSound(
  431.     register __d0 UWORD sound,
  432.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  433. {
  434.   return AHIS_UNKNOWN;
  435. }
  436.  
  437.  
  438.  
  439. /*
  440. ** The slave process
  441. */
  442.  
  443. void __asm __saveds SlaveTask(register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  444. // SlaveEntry() will set up register a2 and a6 for us. __saveds takes care of a4.
  445. {
  446.   struct {
  447.     ULONG                 FORMid;
  448.     ULONG                 FORMsize;
  449.     ULONG                 AIFCid;
  450.  
  451.     ULONG                 FVERid;
  452.     ULONG                 FVERsize;
  453.     FormatVersionHeader   FVERchunk;
  454.  
  455.     ULONG                 COMMid;
  456.     ULONG                 COMMsize;
  457.     ExtCommonChunk        COMMchunk;
  458.  
  459.     ULONG                 SSNDid;
  460.     ULONG                 SSNDsize;
  461.     SampledSoundHeader    SSNDchunk;
  462.   } AIFCheader = 
  463.     { // All NULLs will be filled later.
  464.       ID_FORM,NULL,ID_AIFC,
  465.       ID_FVER,sizeof(FormatVersionHeader),{AIFCVersion1},
  466.       ID_COMM,sizeof(ExtCommonChunk),{NULL,NULL,16,{NULL},NO_COMPRESSION,
  467.           sizeof("not compressed")-1,'n','o','t',' ','c','o','m','p','r','e','s','s','e','d'},
  468.       ID_SSND,NULL,{0,0}
  469.     };
  470.   struct {
  471.     ULONG                 FORMid;
  472.     ULONG                 FORMsize;
  473.     ULONG                 AIFFid;
  474.  
  475.     ULONG                 COMMid;
  476.     ULONG                 COMMsize;
  477.     CommonChunk           COMMchunk;
  478.  
  479.     ULONG                 SSNDid;
  480.     ULONG                 SSNDsize;
  481.     SampledSoundHeader    SSNDchunk;
  482.   } AIFFheader = 
  483.     { // All NULLs will be filled later.
  484.       ID_FORM,NULL,ID_AIFF,
  485.       ID_COMM,sizeof(CommonChunk),{NULL,NULL,16,{NULL}},
  486.       ID_SSND,NULL,{0,0}
  487.     };
  488.   struct {
  489.     ULONG                 FORMid;
  490.     ULONG                 FORMsize;
  491.     ULONG                 EIGHTSVXid;
  492.  
  493.     ULONG                 VHDRid;
  494.     ULONG                 VHDRsize;
  495.     Voice8Header          VHDRchunk;
  496.  
  497.     ULONG                 BODYid;
  498.     ULONG                 BODYsize;
  499.   } EIGHTSVXheader = 
  500.     { // All NULLs will be filled later.
  501.       ID_FORM,NULL,ID_8SVX,
  502.       ID_VHDR,sizeof(Voice8Header),{NULL,0,0,NULL,1,sCmpNone,0x10000},
  503.       ID_BODY,NULL
  504.     };
  505.   struct EasyStruct req = {
  506.     sizeof (struct EasyStruct),
  507.     0,
  508.     _LibID,
  509.     "Rendering finished.\nTo futher improve the quality of the sample,\nyou can raise the volume to %ld%%%sand render again.",
  510.     "OK",
  511.   };
  512.  
  513.   BPTR lock=NULL,cd,file=NULL;
  514.   ULONG signals,i,maxVolume=0;
  515.   ULONG samples,length,offset=0,bytesInBuffer=0,samplesWritten=0,bytesWritten=0;
  516.  
  517. // We cannot handle stereo 8SVXs!
  518.   if( (dd->fs_Format EQ FORMAT_8SVX) &&
  519.       (AudioCtrl->ahiac_Flags & AHIACF_STEREO) )
  520.     goto quit;
  521.  
  522.   if((dd->fs_DisableSignal=AllocSignal(-1)) EQ -1)
  523.     goto quit;
  524.   if((dd->fs_EnableSignal=AllocSignal(-1)) EQ -1)
  525.     goto quit;
  526.   if((dd->fs_SlaveSignal=AllocSignal(-1)) EQ -1)
  527.     goto quit;
  528.  
  529.   if(!(lock=Lock(dd->fs_FileReq->fr_Drawer,ACCESS_READ)))
  530.     goto quit;
  531.   cd=CurrentDir(lock);
  532.   if(!(file=Open(dd->fs_FileReq->fr_File,MODE_NEWFILE)))
  533.     goto quit;
  534.  
  535.   switch(dd->fs_Format)
  536.   {
  537.     case FORMAT_8SVX:
  538.       Write(file,&EIGHTSVXheader,sizeof EIGHTSVXheader);
  539.       break;
  540.     case FORMAT_AIFF:
  541.       Write(file,&AIFFheader,sizeof AIFFheader);
  542.       break;
  543.     case FORMAT_AIFC:
  544.       Write(file,&AIFCheader,sizeof AIFCheader);
  545.       break;
  546.   }
  547.  
  548.   // Everything set up. Tell Master we're alive and healthy.
  549.   Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
  550.  
  551.   for(;;)
  552.   {
  553.     signals=SetSignal(0L,0L);
  554.     if(signals & (SIGBREAKF_CTRL_C | 1L<<dd->fs_SlaveSignal))
  555.       break;
  556.     if(signals & (1L<<dd->fs_EnableSignal | 1L<<dd->fs_DisableSignal) EQ 1L<<dd->fs_DisableSignal)
  557.       Wait(1L<<dd->fs_EnableSignal);
  558.     CallHookPkt(AudioCtrl->ahiac_PlayerFunc,AudioCtrl,NULL);
  559.     CallHookPkt(AudioCtrl->ahiac_MixerFunc,AudioCtrl,dd->fs_MixBuffer);
  560.  
  561.     samples=AudioCtrl->ahiac_BuffSamples*(AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
  562.  
  563. // Search for loudest part in sample
  564.     if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  565.     {
  566.       for(i=0;i<samples;i++)
  567.         if(abs(((LONG *)dd->fs_MixBuffer)[i])>maxVolume)
  568.           maxVolume=abs(((LONG *)dd->fs_MixBuffer)[i]);
  569.     }
  570.     else
  571.     {
  572.       for(i=0;i<samples;i++)
  573.         if(abs(((WORD *)dd->fs_MixBuffer)[i])>maxVolume)
  574.           maxVolume=abs(((WORD *)dd->fs_MixBuffer)[i]);
  575.     }
  576.  
  577.     if(offset+samples >= dd->fs_SaveBufferSize)
  578.     {
  579.       if(Write(file,dd->fs_SaveBuffer,bytesInBuffer) != bytesInBuffer)
  580.         break;
  581.       offset=0;
  582.       bytesInBuffer=0;
  583.     }
  584.  
  585.     switch(dd->fs_Format)
  586.     {
  587.       case FORMAT_8SVX:
  588.         if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  589.         {
  590.           BYTE *dest=&((BYTE *) dd->fs_SaveBuffer)[offset];
  591.           LONG *source=dd->fs_MixBuffer;
  592.  
  593.           for(i=0;i<samples;i++)
  594.             *dest++=*source++ >> 24;
  595.         }
  596.         else
  597.         {
  598.           BYTE *dest=&((BYTE *) dd->fs_SaveBuffer)[offset];
  599.           WORD *source=dd->fs_MixBuffer;
  600.  
  601.           for(i=0;i<samples;i++)
  602.             *dest++=*source++ >> 8;
  603.         }
  604.         length=samples;
  605.         break;
  606.  
  607.       case FORMAT_AIFF:
  608.       case FORMAT_AIFC:
  609.         if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  610.         {
  611.           WORD *dest=&((WORD *) dd->fs_SaveBuffer)[offset];
  612.           LONG *source=dd->fs_MixBuffer;
  613.  
  614.           for(i=0;i<samples;i++)
  615.             *dest++=*source++ >> 16;
  616.         }
  617.         else
  618.         {
  619.           WORD *dest=&((WORD *) dd->fs_SaveBuffer)[offset];
  620.           WORD *source=dd->fs_MixBuffer;
  621.  
  622.           for(i=0;i<samples;i++)
  623.             *dest++=*source++;
  624.         }
  625.         length=samples*2;
  626.         break;
  627.     }
  628.  
  629.     offset += samples;
  630.     samplesWritten += AudioCtrl->ahiac_BuffSamples;
  631.     bytesWritten += length;
  632.     bytesInBuffer += length;
  633.  
  634.   }
  635.  
  636.   Write(file,dd->fs_SaveBuffer,bytesInBuffer);
  637.  
  638.   switch(dd->fs_Format)
  639.   {
  640.     case FORMAT_8SVX:
  641.       EIGHTSVXheader.FORMsize=sizeof(EIGHTSVXheader)-8+bytesWritten;
  642.       EIGHTSVXheader.VHDRchunk.oneShotHiSamples=samplesWritten;
  643.       EIGHTSVXheader.VHDRchunk.samplesPerSec=AudioCtrl->ahiac_MixFreq;
  644.       EIGHTSVXheader.BODYsize=bytesWritten;
  645.       if(bytesWritten & 1)
  646.         FPutC(file,'\0');   // Pad to even
  647.       Seek(file,0,OFFSET_BEGINNING);
  648.       Write(file,&EIGHTSVXheader,sizeof EIGHTSVXheader);
  649.       break;
  650.  
  651.     case FORMAT_AIFF:
  652.       AIFFheader.FORMsize=sizeof(AIFFheader)-8+bytesWritten;
  653.       AIFFheader.COMMchunk.numChannels=(AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
  654.       AIFFheader.COMMchunk.numSampleFrames=samplesWritten;
  655.       ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFFheader.COMMchunk.sampleRate);
  656.       AIFFheader.SSNDsize=sizeof(SampledSoundHeader)+bytesWritten;
  657.       Seek(file,0,OFFSET_BEGINNING);
  658.       Write(file,&AIFFheader,sizeof AIFFheader);
  659.       break;
  660.  
  661.     case FORMAT_AIFC:
  662.       AIFCheader.FORMsize=sizeof(AIFCheader)-8+bytesWritten;
  663.       AIFCheader.COMMchunk.numChannels=(AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
  664.       AIFCheader.COMMchunk.numSampleFrames=samplesWritten;
  665.       ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFCheader.COMMchunk.sampleRate);
  666.       AIFCheader.SSNDsize=sizeof(SampledSoundHeader)+bytesWritten;
  667.       Seek(file,0,OFFSET_BEGINNING);
  668.       Write(file,&AIFCheader,sizeof AIFCheader);
  669.       break;
  670.   }
  671.  
  672.   if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  673.     maxVolume >>=16;
  674.  
  675.   if(maxVolume!=0)
  676.     EasyRequest(NULL, &req, NULL, 3276800/maxVolume,
  677.       AudioCtrl->ahiac_MixFreq<frequency[FREQUENCIES-1] ? ",\nincrease the mixing frequency " : "\n");
  678.  
  679. quit:
  680.   if(file)
  681.     Close(file);
  682.   CurrentDir(cd);
  683.   if(lock)
  684.     UnLock(lock);
  685.  
  686.   Forbid();
  687.   dd->fs_SlaveTask=NULL;
  688.   FreeSignal(dd->fs_DisableSignal);
  689.   FreeSignal(dd->fs_EnableSignal);
  690.   FreeSignal(dd->fs_SlaveSignal);
  691.   dd->fs_DisableSignal=-1;
  692.   dd->fs_EnableSignal=-1;
  693.   dd->fs_SlaveSignal=-1;
  694.   // Tell the Master we're dying
  695.   Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
  696.   // Multitaking will resume when we are dead.
  697. }
  698.  
  699. /*
  700. ** Apple's 80-bit SANE extended has the following format:
  701.  
  702.  1       15      1            63
  703. +-+-------------+-+-----------------------------+
  704. |s|       e     |i|            f                |
  705. +-+-------------+-+-----------------------------+
  706.   msb        lsb   msb                       lsb
  707.  
  708. The value v of the number is determined by these fields as follows:
  709. If 0 <= e < 32767,              then v = (-1)^s * 2^(e-16383) * (i.f).
  710. If e == 32767 and f == 0,       then v = (-1)^s * (infinity), regardless of i.
  711. If e == 32767 and f != 0,       then v is a NaN, regardless of i.
  712. */
  713.  
  714. void ulong2extended (ULONG in, extended *ex)
  715. {
  716.   ex->exponent=31+16383;
  717.   ex->mantissa[1]=0;
  718.   while(!(in & 0x80000000))
  719.   {
  720.     ex->exponent--;
  721.     in<<=1;
  722.   }
  723.   ex->mantissa[0]=in;
  724. }
  725.  
  726.  
  727.  
  728. /*
  729. ** The record slave process
  730. */
  731.  
  732. void __asm __saveds RecSlaveTask(register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  733. // RecSlaveEntry() will set up register a2 and a6 for us. __saveds takes care of a4.
  734. {
  735.   ULONG   signals;
  736.   BPTR    lock=NULL,cd,file=NULL;
  737.   Object *o=NULL;
  738.   BYTE   *samples=NULL;
  739.   ULONG   length=NULL;
  740.   ULONG   count=0,offs=0,i;
  741.  
  742.   struct AHIRecordMessage RecordMessage=
  743.   {
  744.     AHIST_S16S,
  745.     NULL,
  746.     RECBUFFERSIZE
  747.   };
  748.  
  749.   RecordMessage.ahirm_Buffer=dd->fs_RecBuffer;
  750.  
  751.   if(!(lock=Lock(dd->fs_RecFileReq->fr_Drawer,ACCESS_READ)))
  752.     goto quit;
  753.   cd=CurrentDir(lock);
  754.  
  755.   if(DataTypesBase)
  756.   {
  757.     if (!(o = NewDTObject (dd->fs_RecFileReq->fr_File,
  758.         DTA_GroupID,GID_SOUND,
  759.         TAG_DONE)))
  760.       goto quit;
  761.  
  762.     GetDTAttrs(o,
  763.       SDTA_Sample,&samples,
  764.       SDTA_SampleLength,&length,
  765.       TAG_DONE);
  766.   }
  767.   else // datatypes.library not open. Open the selected file as raw 8 bit signed instead.
  768.   {
  769.     if(!(file=Open(dd->fs_RecFileReq->fr_File,MODE_OLDFILE)))
  770.       goto quit;
  771.     Seek(file,0,OFFSET_END);
  772.     length=Seek(file,0,OFFSET_BEGINNING);
  773.     if(!(samples=AllocVec(length,MEMF_ANY)))
  774.       goto quit;
  775.     if(length != Read(file,samples,length))
  776.       goto quit;
  777.   }
  778.  
  779.   if(!samples || !length )
  780.     goto quit;
  781.  
  782.   if((dd->fs_RecSlaveSignal=AllocSignal(-1)) EQ -1)
  783.     goto quit;
  784.  
  785. // Everything set up. Tell Master we're alive and healthy.
  786.     Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_RecMasterSignal);
  787.  
  788.     for(;;)
  789.     {
  790.       signals=SetSignal(0L,0L);
  791.       if(signals & (SIGBREAKF_CTRL_C | 1L<<dd->fs_RecSlaveSignal))
  792.         break;
  793.  
  794.       for(;;)
  795.       {
  796.         if(count+RECBUFFERSIZE-offs < length)
  797.         {
  798. // End of sample will not be reached; just fill to the end of dd->fs_RecBuffer.
  799.           for(i=RECBUFFERSIZE-offs;i>0;i--)
  800.           {
  801.             dd->fs_RecBuffer[(offs)<<1]=
  802.             dd->fs_RecBuffer[((offs++)<<1)+1]=
  803.             samples[count++]<<8;
  804.           }
  805.           offs=0;
  806.           break;
  807.         }
  808.         else
  809.         {
  810. // End of sample will be reached. Fill part of buffer, and iterate (== don't break).
  811.           for(i=length-count;i>0;i--)
  812.           {
  813.             dd->fs_RecBuffer[(offs)<<1]=
  814.             dd->fs_RecBuffer[((offs++)<<1)+1]=
  815.             samples[count++]<<8;
  816.           }
  817.           count=0;
  818.         }
  819.  
  820.       }
  821.  
  822.       CallHookPkt(AudioCtrl->ahiac_SamplerFunc,AudioCtrl,&RecordMessage);
  823.       Delay(50*RECBUFFERSIZE/AudioCtrl->ahiac_MixFreq);
  824.     }
  825.  
  826. quit:
  827. // Get rid of object
  828.   if(DataTypesBase)
  829.   {
  830.     if(o)
  831.       DisposeDTObject (o);
  832.   }
  833.   else // datatypes.library not open.
  834.   {
  835.     if(samples)
  836.       FreeVec(samples);
  837.     if(file)
  838.       Close(file);
  839.   }
  840.   CurrentDir(cd);
  841.   if(lock)
  842.     UnLock(lock);
  843.  
  844.   Forbid();
  845.   dd->fs_RecSlaveTask=NULL;
  846.   FreeSignal(dd->fs_RecSlaveSignal);
  847.   dd->fs_RecSlaveSignal=-1;
  848.   // Tell the Master we're dying
  849.   Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_RecMasterSignal);
  850.   // Multitaking will resume when we are dead.
  851. }
  852.