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

  1.  
  2. #include <exec/exec.h>
  3.  
  4. #include <devices/ahi.h>
  5. #include <libraries/ahi_sub.h>
  6. #include <libraries/toccata.h>
  7.  
  8. #include <dos/dos.h>
  9.  
  10. #include <proto/exec.h>
  11. #include <proto/utility.h>
  12. #include <proto/ahi_sub.h>
  13. #include <clib/toccata_protos.h>
  14. #include <pragmas/toccata_pragmas.h>
  15.  
  16. #include "toccata.h"
  17.  
  18. #define EQ ==
  19. #define dd ((struct toccata *) AudioCtrl->ahiac_DriverData)
  20.  
  21. #define PLAYBUFFERSIZE 128*4      // in samples
  22. #define PLAYIRQSIZE    1<<9       // 5=32, 6=64, ... 9=512
  23. #define RECBUFFERSIZE  128*50     // in samples
  24.  
  25. extern char __far _LibID[];
  26. extern char __far _LibName[];
  27.  
  28. extern void __asm RecordFunc(void);
  29. extern void __asm PlayFuncMono(void);
  30. extern void __asm PlayFuncStereo(void);
  31.  
  32. struct Library        *UtilityBase=NULL;
  33. struct Library        *AHIsubBase=NULL;
  34. struct ToccataBase    *ToccataBase=NULL;
  35.  
  36. #define INPUTS 5
  37.  
  38. const static STRPTR Inputs[] =
  39. { "Line",
  40.   "Aux1",
  41.   "Mic",
  42.   "Mic as Line",
  43.   "Mixer"
  44. };
  45.  
  46. const static ULONG inputmap[] =
  47. { TINPUT_Line,
  48.   TINPUT_Aux1,
  49.   TINPUT_Mic,
  50.   TINPUT_Mic,
  51.   TINPUT_Mix
  52. };
  53.  
  54. const static ULONG micgainmap[] =
  55. { FALSE,
  56.   FALSE,
  57.   FALSE,
  58.   TRUE,
  59.   FALSE
  60. };
  61.  
  62.  
  63. int  __saveds __asm __UserLibInit (register __a6 struct Library *libbase)
  64. {
  65.   AHIsubBase=libbase;
  66.  
  67.   if(!(UtilityBase=OpenLibrary("utility.library",37)))
  68.   {
  69.     Alert(AN_Unknown|AG_OpenLib|AO_UtilityLib);
  70.     return 1;
  71.   }
  72.  
  73.   if(!(ToccataBase=(struct ToccataBase *)OpenLibrary("toccata.library",TOCCATA_LIB_VERSION)))
  74.   {
  75.     Alert(AN_Unknown|AG_OpenLib|AO_Unknown);
  76.     return 1;
  77.   }
  78.  
  79.   return 0;
  80. }
  81.  
  82. void __saveds __asm __UserLibCleanup (register __a6 struct Library *libbase)
  83. {
  84.   if(UtilityBase)   { CloseLibrary(UtilityBase); UtilityBase=NULL; }
  85.   if(ToccataBase)   { CloseLibrary((struct Library *)ToccataBase); ToccataBase=NULL; }
  86. }
  87.  
  88. ULONG __asm __saveds intAHIsub_AllocAudio(
  89.     register __a1 struct TagItem *tagList,
  90.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  91. {
  92.   if(AudioCtrl->ahiac_DriverData=AllocVec(sizeof(struct toccata),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR))
  93.   {
  94.     dd->t_AHIsubBase=AHIsubBase;
  95.     dd->t_TocSamples=PLAYBUFFERSIZE;
  96.  
  97. /*
  98. ** This one is just to keep the $#£@$£#"% T_RawPlayback() happy.
  99. ** Thank you so very much, MacroSystem, for documenting that TT_ErrorTask and
  100. ** TT_ErrorMask must be specified for T_RawPlayback() but not T_Capture().
  101. ** After all, spending four days trying to figure out how to get T_RawPlayback()
  102. ** work is exactly my idea of fun. Or maybe not.
  103. ** Funny it should have to take a disassembly of 'toccata.library' to figure out
  104. ** how to use it.
  105. */
  106.  
  107.     dd->t_ErrorTask=FindTask(NULL);
  108.     dd->t_ErrorSignal=AllocSignal(-1);
  109.     if(dd->t_ErrorSignal != -1)
  110.     {
  111.       AudioCtrl->ahiac_MixFreq=T_FindFrequency(AudioCtrl->ahiac_MixFreq);
  112.  
  113.       if(ToccataBase->tb_HardInfo)         // Check if hardware is present...
  114.       {
  115.         T_SaveSettings(0);                 // Save state
  116.         T_Stop(TSF_DONTSAVECACHE);
  117.         T_SetPartTags(                     // Reset
  118.             PAT_InputVolumeLeft,0,
  119.             PAT_InputVolumeRight,0,
  120.             PAT_OutputVolumeLeft,0,
  121.             PAT_OutputVolumeRight,0,
  122.             PAT_LoopbackVolume,-64,
  123.             PAT_Input,TINPUT_Line,
  124.             PAT_Mode,TMODE_LINEAR_16_S,
  125.             PAT_Frequency,ToccataBase->tb_HardInfo->hi_MaxFrequency,
  126.             TAG_DONE);
  127.         return AHISF_KNOWSTEREO|AHISF_CANRECORD|AHISF_MIXING|AHISF_TIMING;
  128.       }
  129.     }
  130.   }
  131.   return AHISF_ERROR;
  132. }
  133.  
  134. void __asm __saveds intAHIsub_FreeAudio(
  135.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  136. {
  137.   if(AudioCtrl->ahiac_DriverData)
  138.   {
  139.     FreeSignal(dd->t_ErrorSignal);
  140.     FreeVec(AudioCtrl->ahiac_DriverData);
  141.     AudioCtrl->ahiac_DriverData=NULL;
  142.     T_LoadSettings(0);                 // Restore state
  143.   }
  144. }
  145.  
  146.  
  147.  
  148. ULONG __asm __saveds intAHIsub_Start(
  149.     register __d0 ULONG Flags,
  150.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  151. {
  152.  
  153.   AHIsub_Stop(AHISF_PLAY|AHISF_RECORD,AudioCtrl);       // Only half duplex!
  154.  
  155.   if(Flags & AHISF_PLAY)
  156.   {
  157.     ULONG toccata_mode;
  158.     ULONG toccata_size;
  159.  
  160.     if(!(dd->t_PlaySoftInt=AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR)))
  161.       return AHIE_NOMEM;
  162.  
  163.     switch(AudioCtrl->ahiac_BuffType)
  164.     {
  165.       case AHIST_M16S:
  166.         dd->t_PlaySoftInt->is_Code=(void (* )())PlayFuncMono;
  167.         toccata_mode=TMODE_LINEAR_16;
  168.         toccata_size=dd->t_TocSamples<<1;
  169.         break;
  170.       case AHIST_S16S:
  171.         dd->t_PlaySoftInt->is_Code=(void (* )())PlayFuncStereo;
  172.         toccata_mode=TMODE_LINEAR_16_S;
  173.         toccata_size=dd->t_TocSamples<<2;
  174.         break;
  175.       default:
  176.         return AHIE_BADSAMPLETYPE;
  177.     }
  178.  
  179.     if(!(dd->t_SampBuffer1=AllocVec(toccata_size,MEMF_PUBLIC|MEMF_ANY)))
  180.       return AHIE_NOMEM;
  181.  
  182.     if(!(dd->t_SampBuffer2=AllocVec(toccata_size,MEMF_PUBLIC|MEMF_ANY)))
  183.       return AHIE_NOMEM;
  184.  
  185.     if(!(dd->t_MixBuffer=AllocVec(AudioCtrl->ahiac_BuffSize,MEMF_PUBLIC|MEMF_ANY)))
  186.       return AHIE_NOMEM;
  187.  
  188.     dd->t_PlaySoftInt->is_Node.ln_Type=NT_INTERRUPT;
  189.     dd->t_PlaySoftInt->is_Node.ln_Name=_LibName;
  190.     dd->t_PlaySoftInt->is_Data=AudioCtrl;
  191.  
  192.     if(!T_RawPlaybackTags(
  193.           TT_ErrorTask, dd->t_ErrorTask,
  194.           TT_ErrorMask, (1L << dd->t_ErrorSignal),
  195.           TT_Mode, toccata_mode,
  196.           TT_Frequency, AudioCtrl->ahiac_MixFreq,
  197.           TT_RawBuffer1, dd->t_SampBuffer1,
  198.           TT_RawBuffer2, dd->t_SampBuffer2,
  199.           TT_BufferSize, toccata_size,
  200.           TT_RawIrqSize, PLAYIRQSIZE,
  201.           TT_RawInt, dd->t_PlaySoftInt,
  202.           TAG_DONE))
  203.     {
  204.       T_Stop(TSF_DONTSAVECACHE);
  205.       return AHIE_UNKNOWN;
  206.     }
  207.   }
  208.  
  209.   if(Flags & AHISF_RECORD)
  210.   {
  211.     if(!(dd->t_RecBuffer=AllocVec(RECBUFFERSIZE<<2,MEMF_PUBLIC|MEMF_ANY)))
  212.       return AHIE_NOMEM;
  213.     if(!(dd->t_RecMessage=AllocVec(sizeof(struct AHIRecordMessage),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR)))
  214.       return AHIE_NOMEM;
  215.  
  216.     dd->t_RecMessage->ahirm_Type=AHIST_S16S;
  217.     dd->t_RecMessage->ahirm_Buffer=dd->t_RecBuffer;
  218.  
  219.     if(!T_CaptureTags(
  220.         TT_BufferSize,RECBUFFERSIZE<<2,
  221.         TT_Save, RecordFunc,
  222.         TT_CBParamA1, AudioCtrl,
  223.         TT_Mode, TMODE_LINEAR_16_S,
  224.         TT_Frequency, AudioCtrl->ahiac_MixFreq,
  225.         TT_Flags, TTF_READYRETURN,
  226.         TAG_DONE))
  227.     {
  228.       T_Stop(TSF_DONTSAVECACHE);
  229.       return AHIE_UNKNOWN;
  230.     }
  231.   }
  232.  
  233.   return AHIE_OK;
  234. }
  235.  
  236. /*
  237. void __asm __saveds __interrupt intAHIsub_Update(
  238.     register __d0 ULONG Flags,
  239.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  240. {
  241. }
  242. */
  243.  
  244. void __asm __saveds intAHIsub_Stop(
  245.     register __d0 ULONG Flags,
  246.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  247. {
  248.   if(Flags & AHISF_PLAY)
  249.   {
  250.     T_Stop(TSF_DONTSAVECACHE);
  251.  
  252.     FreeVec(dd->t_MixBuffer);
  253.     dd->t_MixBuffer=NULL;
  254.     FreeVec(dd->t_SampBuffer1);
  255.     dd->t_SampBuffer1=NULL;
  256.     FreeVec(dd->t_SampBuffer2);
  257.     dd->t_SampBuffer2=NULL;
  258.     FreeVec(dd->t_PlaySoftInt);
  259.     dd->t_PlaySoftInt=NULL;
  260.   }
  261.  
  262.   if(Flags & AHISF_RECORD)
  263.   {
  264.     T_Stop(TSF_DONTSAVECACHE);
  265.  
  266.     FreeVec(dd->t_RecBuffer);
  267.     dd->t_RecBuffer=NULL;
  268.   }
  269. }
  270.  
  271.  
  272.  
  273. LONG __asm __saveds intAHIsub_GetAttr(
  274.     register __d0 ULONG Attribute,
  275.     register __d1 LONG Argument,
  276.     register __d2 LONG Default,
  277.     register __a1 struct TagItem *tagList,
  278.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  279. {
  280.   switch(Attribute)
  281.   {
  282.     case AHIDB_Bits:
  283.       return 16;
  284.     case AHIDB_Frequencies:
  285.     {
  286.       ULONG freq=NULL;
  287.       LONG  freqs=0;
  288.       while(freq=T_NextFrequency(freq))
  289.         freqs++;
  290.       return freqs;
  291.     }
  292.     case AHIDB_Frequency: // Index->Frequency
  293.     {
  294.       ULONG freq=NULL;
  295.       LONG  i;
  296.       for(i=0; i<=Argument ; i++)
  297.         freq=T_NextFrequency(freq);
  298.       return (LONG) freq;
  299.     }    
  300.     case AHIDB_Index: // Frequency->Index
  301.     {  
  302.       ULONG freq=NULL,realfreq=T_FindFrequency(Argument);
  303.       LONG  index=0;
  304.       while((freq=T_NextFrequency(freq)) != realfreq)
  305.         index++;
  306.       return index;
  307.     }
  308.     case AHIDB_Author:
  309.       return (LONG) "Martin 'Leviticus' Blom";
  310.     case AHIDB_Copyright:
  311.       return (LONG) "Public Domain";
  312.     case AHIDB_Version:
  313.       return (LONG) _LibID;
  314.     case AHIDB_Annotation:
  315.       return (LONG) "Based on code by Pauli Porkka, Peter Kunath and Frank Riffel.";
  316.     case AHIDB_Record:
  317.       return TRUE;
  318.     case AHIDB_FullDuplex:
  319.       return FALSE;
  320.     case AHIDB_Realtime:
  321.       return TRUE;
  322.     case AHIDB_MaxPlaySamples:
  323.       return Default+PLAYBUFFERSIZE;
  324.     case AHIDB_MaxRecordSamples:
  325.       return RECBUFFERSIZE;
  326.     case AHIDB_MinMonitorVolume:
  327.       return 0x00000;
  328.     case AHIDB_MaxMonitorVolume:
  329.       return 0x10000;
  330.     case AHIDB_MinInputGain:
  331.       return 0x10000;
  332.     case AHIDB_MaxInputGain:
  333.       return 0xd55d0;           // 13.335<<16 == +22.5 dB
  334.     case AHIDB_MinOutputVolume:
  335.       return 0x00000;
  336.     case AHIDB_MaxOutputVolume:
  337.       return 0x10000;
  338.     case AHIDB_Inputs:
  339.       return INPUTS;
  340.     case AHIDB_Input:
  341.     {
  342.       return (LONG) Inputs[Argument];
  343.     }
  344.     case AHIDB_Outputs:
  345.       return 1;
  346.     case AHIDB_Output:
  347.       return (LONG) "Line";     // We have only one output!
  348.     default:
  349.       return Default;
  350.   }
  351. }
  352.  
  353. const static LONG negboundaries[] =
  354. {
  355.   65536,55141,46395,39037,32845,27636,23253,19565,16461,13850,11654,9805,8250,
  356.   6941,5840,4914,4135,3479,2927,2463,2072,1743,1467,1234,1038,873,735,618,520,
  357.   438,368,310,260,219,184,155,130,110,92,77,65,55,46,39,32,27,23,19,16,13,11,9,
  358.   8,6,5,4,4,3,2,2,2,1,1,1,0
  359. };
  360.  
  361. LONG fixed2negdbvalue( LONG volume)
  362. {
  363.   LONG i=0;
  364.  
  365.   while(volume >= negboundaries[i])
  366.     i++;
  367.   return(-i);
  368. }
  369.  
  370. const static LONG posboundaries[] =
  371. {
  372.   65536,77889,92572,110022,130761,155410,184705,219522,260903,
  373.   310084,368536,438005,520570,618699,735326,873936
  374. };
  375.  
  376. LONG fixed2posdbvalue( LONG volume)
  377. {
  378.   LONG i=0;
  379.  
  380.   while((volume >= posboundaries[i+1]) && i<15)
  381.     i++;
  382.   return(i);
  383. }
  384.  
  385. LONG __asm __saveds __interrupt intAHIsub_HardwareControl(
  386.     register __d0 ULONG attribute,
  387.     register __d1 LONG argument,
  388.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  389. {
  390.   LONG rc=TRUE;
  391.  
  392.   if(ToccataBase->tb_HardInfo)         // Check if hardware is present...
  393.   {
  394.     switch (attribute)
  395.     {
  396.       case AHIC_MonitorVolume:
  397.         T_SetPartTags(PAT_LoopbackVolume, fixed2negdbvalue(argument), TAG_DONE);
  398.         break;
  399.       case AHIC_MonitorVolume_Query:
  400.         T_GetPartTags(PAT_LoopbackVolume, &rc, TAG_DONE);
  401.         rc=negboundaries[-rc];
  402.         break;
  403.       case AHIC_InputGain:
  404.         T_SetPartTags(PAT_InputVolumeLeft, fixed2posdbvalue(argument),
  405.                       PAT_InputVolumeRight, fixed2posdbvalue(argument), TAG_DONE);
  406.         break;
  407.       case AHIC_InputGain_Query:
  408.         T_GetPartTags(PAT_InputVolumeLeft, &rc, TAG_DONE);
  409.         rc=negboundaries[rc];
  410.         break;
  411.       case AHIC_OutputVolume:
  412.         T_SetPartTags(PAT_OutputVolumeLeft, fixed2negdbvalue(argument),
  413.                       PAT_OutputVolumeRight, fixed2negdbvalue(argument), TAG_DONE);
  414.         break;
  415.       case AHIC_OutputVolume_Query:
  416.         T_GetPartTags(PAT_OutputVolumeLeft, &rc, TAG_DONE);
  417.         rc=negboundaries[-rc];
  418.         break;
  419.       case AHIC_Input:
  420.         dd->t_Input=argument;
  421.         T_SetPartTags(PAT_Input,   inputmap[argument],
  422.                       PAT_MicGain, micgainmap[argument], TAG_DONE);
  423.         break;
  424.       case AHIC_Input_Query:
  425.         rc=dd->t_Input;
  426.         break;
  427.       case AHIC_Output_Query:
  428.         rc=0;                           // There is only one output
  429.         break;
  430.       default:
  431.         rc=FALSE;
  432.         break;
  433.     }
  434.   }
  435.   else
  436.     rc=FALSE;
  437.   return rc;
  438. }
  439.