home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / linux / mikmod-3.000 / mikmod-3 / mikmod-3.1.2 / drivers / drv_os2s.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-07  |  8.8 KB  |  344 lines

  1. /*  MikMod sound library
  2.     (c) 1998 Miodrag Vallat and others - see file AUTHORS for complete list
  3.  
  4.     This library is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU Library General Public License as
  6.     published by the Free Software Foundation; either version 2 of
  7.     the License, or (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU Library General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU Library General Public
  15.     License along with this library; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /*==============================================================================
  20.  
  21.   $Id: drv_os2s.c,v 1.10 1998/12/07 06:01:44 miod Exp $
  22.  
  23.   Mikmod driver for output on OS/2 using MMPM/2 MCI interface
  24.  
  25. ==============================================================================*/
  26.  
  27. /*
  28.  
  29.     Written by Stefan Tibus <Stefan.Tibus@ThePentagon.com>
  30.  
  31. */
  32.  
  33. #define INCL_DOS
  34. #define INCL_32
  35. #include <os2.h>
  36. #include <mcios2.h>
  37. #include <stdlib.h>
  38.  
  39. #include <mikmod_internals.h>
  40.  
  41. /* global variables */
  42. static MCI_OPEN_PARMS     mciOpenParms;
  43. static MCI_GENERIC_PARMS  mciGenericParms;
  44. static MCI_PLAY_PARMS     mciPlayParms;
  45. static MCI_WAVE_SET_PARMS mciWaveSetParms;
  46. static ULONG ulrc;
  47. static PVOID pBuffer=NULL;
  48. static TID tidUpdateBuffer=0;
  49. static INT iNext;
  50. static HEV hevPlay=0, hevUpdateBuffer=0; /* semaphore handles */
  51. static HTIMER htimerUpdateBuffer=0;
  52.  
  53. /* playlist-structure */
  54. typedef struct {
  55.     ULONG ulCommand;
  56.     ULONG ulOperand1;
  57.     ULONG ulOperand2;
  58.     ULONG ulOperand3;
  59. } PLAYLISTSTRUCTURE;
  60.  
  61. static PLAYLISTSTRUCTURE playList[3];
  62.  
  63. /* size of each buffer */
  64. #define FRAGSIZE 32768
  65. /* buffer count */
  66. #define UPDATES  2
  67. /* total buffer size */
  68. #define BUFFERSIZE (FRAGSIZE*UPDATES)
  69.  
  70. /* thread handling buffer-updates */
  71. static VOID APIENTRY OS2_Small_UpdateBufferThread(ULONG ul)
  72. {
  73.     ULONG ulPostCt; /* times a semaphor has been posted */
  74.  
  75.     while(1) {
  76.         /* wait for play */
  77.         DosWaitEventSem(hevPlay, SEM_INDEFINITE_WAIT);
  78.         /* wait for update */
  79.         DosWaitEventSem(hevUpdateBuffer, SEM_INDEFINITE_WAIT);
  80.         /* reset semaphore */
  81.         DosResetEventSem(hevUpdateBuffer, &ulPostCt);
  82.  
  83.         /* look which buffer to update */
  84.         if (playList[0].ulOperand3>0) {
  85.             /* first buffer is playing, update the second */
  86.             if (iNext==1) {
  87.                 if (!Player_Paused())
  88.                     playList[1].ulOperand2=VC_WriteBytes((SBYTE*)playList[1].ulOperand1,playList[1].ulOperand2);
  89.                 else
  90.                     VC_SilenceBytes((SBYTE*)playList[1].ulOperand1,playList[1].ulOperand2);
  91.                 playList[1].ulOperand3=0;
  92.                 iNext=0;
  93.             }
  94.         }
  95.         if (playList[1].ulOperand3>0) {
  96.             /* second buffer is playing, update the first */
  97.             if (iNext==0) {
  98.                 if (!Player_Paused())
  99.                     playList[0].ulOperand2=VC_WriteBytes((SBYTE*)playList[0].ulOperand1,playList[0].ulOperand2);
  100.                 else
  101.                     VC_SilenceBytes((SBYTE*)playList[0].ulOperand1,playList[0].ulOperand2);
  102.                 playList[0].ulOperand3=0;
  103.                 iNext=1;
  104.             }
  105.         }
  106.     }
  107. }
  108.  
  109. /* checks for availability of an OS/2 MCI-WAVEAUDIO-device */
  110. static BOOL OS2_Small_IsPresent(void)
  111. {
  112.     mciOpenParms.hwndCallback=(HWND) NULL;
  113.     mciOpenParms.usDeviceID=(USHORT) NULL;
  114.     mciOpenParms.pszDeviceType=(PSZ) MCI_DEVTYPE_WAVEFORM_AUDIO;
  115.     mciOpenParms.pszElementName=(PSZ) NULL;
  116.  
  117.     /* try to open WAVEAUDIO-device */
  118.     ulrc=mciSendCommand(0,MCI_OPEN,MCI_WAIT|MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE_ID,
  119.                         (PVOID)&mciOpenParms,0);
  120.  
  121.     if (ulrc)
  122.         return 0;
  123.     else {
  124.         mciGenericParms.hwndCallback=(HWND) NULL;
  125.         mciSendCommand(mciOpenParms.usDeviceID,MCI_CLOSE,MCI_WAIT,
  126.                        (PVOID)&mciGenericParms, 0);
  127.         return 1;
  128.     }
  129. }
  130.  
  131. BOOL OS2_Small_Init(VOID)
  132. {
  133.     ULONG ulInterval;
  134.     ULONG ulPostCt; /* times a semaphor has been posted */
  135.  
  136.     mciOpenParms.usDeviceID=0;
  137.  
  138.     /* allocate (commited) memory */
  139.     pBuffer=NULL;
  140.     DosAllocMem(&pBuffer,BUFFERSIZE,PAG_READ|PAG_WRITE|PAG_COMMIT);
  141.     if (!pBuffer) {
  142.         _mm_errno=MMERR_OUT_OF_MEMORY;
  143.         return 1;
  144.     }
  145.  
  146.     /* create playlist */
  147.     playList[0].ulCommand=DATA_OPERATION; /* play data */
  148.     playList[0].ulOperand1=(ULONG)pBuffer; /* buffer */
  149.     playList[0].ulOperand2=(ULONG)FRAGSIZE; /* size */
  150.     playList[0].ulOperand3=0; /* offset */
  151.  
  152.     playList[1].ulCommand=DATA_OPERATION;
  153.     playList[1].ulOperand1=(ULONG)pBuffer+(ULONG)FRAGSIZE;
  154.     playList[1].ulOperand2=(ULONG)FRAGSIZE;
  155.     playList[1].ulOperand3=0;
  156.  
  157.     playList[2].ulCommand=BRANCH_OPERATION; /* jump */
  158.     playList[2].ulOperand1=0;
  159.     playList[2].ulOperand2=0; /* destination */
  160.     playList[2].ulOperand3=0;
  161.  
  162.     mciOpenParms.hwndCallback=(HWND) NULL;
  163.     mciOpenParms.pszDeviceType=(PSZ) MCI_DEVTYPE_WAVEFORM_AUDIO;
  164.     mciOpenParms.pszElementName=(PSZ) &playList;
  165.  
  166.     /* open WAVEAUDIO-device */
  167.     ulrc=mciSendCommand(0,MCI_OPEN,MCI_WAIT|MCI_OPEN_TYPE_ID|MCI_OPEN_PLAYLIST,
  168.                         (PVOID)&mciOpenParms,0);
  169.     if (ulrc) {
  170.         _mm_errno=MMERR_OPENING_AUDIO;
  171.         return 1;
  172.     }
  173.  
  174.     mciWaveSetParms.hwndCallback=(HWND) NULL;
  175.     mciWaveSetParms.ulSamplesPerSec=md_mixfreq;
  176.     mciWaveSetParms.usBitsPerSample=(md_mode&DMODE_16BITS)?16:8;
  177.     mciWaveSetParms.usChannels=(md_mode&DMODE_STEREO)?2:1;
  178.     mciWaveSetParms.ulAudio=MCI_SET_AUDIO_ALL;
  179.  
  180.     /* set play-parameters */
  181.     ulrc=mciSendCommand(mciOpenParms.usDeviceID,MCI_SET,
  182.                         MCI_WAIT|MCI_WAVE_SET_SAMPLESPERSEC|
  183.                               MCI_WAVE_SET_BITSPERSAMPLE|MCI_WAVE_SET_CHANNELS,
  184.                         (PVOID)&mciWaveSetParms,0);
  185.     if (ulrc) {
  186.         _mm_errno=MMERR_OS2_MIXSETUP;
  187.         return 1;
  188.     }
  189.  
  190.     if (VC_Init()) return 1;
  191.  
  192.     /* setup semaphore for playing */
  193.     ulrc=DosCreateEventSem("\\SEM32\\libMikMod\\Play",&hevPlay,DC_SEM_SHARED,
  194.                            FALSE);
  195.     if (ulrc) {
  196.         _mm_errno=MMERR_OS2_SEMAPHORE;
  197.         return 1;
  198.     }
  199.     /* reset semaphore */
  200.     DosResetEventSem(hevPlay, &ulPostCt);
  201.  
  202.     /* setup semaphore for buffer-updates */
  203.     ulrc=DosCreateEventSem("\\SEM32\\libMikMod\\UpdateBuffer",&hevUpdateBuffer,
  204.                            DC_SEM_SHARED, FALSE);
  205.     if (ulrc) {
  206.         _mm_errno=MMERR_OS2_SEMAPHORE;
  207.         return 1;
  208.     }
  209.     /* reset semaphore */
  210.     DosResetEventSem(hevUpdateBuffer, &ulPostCt);
  211.  
  212.     /* setup timer for buffer-updates */
  213.     /* calculate interval in ms (2 possible updates while playing 1 block) */
  214.     ulInterval=1000L*FRAGSIZE/mciWaveSetParms.usChannels/
  215.                (mciWaveSetParms.usBitsPerSample/8)/
  216.                mciWaveSetParms.ulSamplesPerSec/UPDATES;
  217.     ulrc=DosStartTimer(ulInterval,(HSEM)hevUpdateBuffer,&htimerUpdateBuffer);
  218.     if (ulrc) {
  219.         _mm_errno=MMERR_OS2_TIMER;
  220.         return 1;
  221.     }
  222.  
  223.     // create thread for buffer-updates
  224.     ulrc=DosCreateThread(&tidUpdateBuffer,&OS2_Small_UpdateBufferThread,0,
  225.                          CREATE_READY|STACK_SPARSE,4096);
  226.     if (ulrc) {
  227.         _mm_errno=MMERR_OS2_THREAD;
  228.         return 1;
  229.     }
  230.  
  231.     return 0;
  232. }
  233.  
  234. static VOID OS2_Small_Exit(VOID)
  235. {
  236.     if(tidUpdateBuffer) {
  237.         DosKillThread(tidUpdateBuffer);
  238.         tidUpdateBuffer=0;
  239.     }
  240.     if(htimerUpdateBuffer) {
  241.         DosStopTimer(htimerUpdateBuffer);
  242.         htimerUpdateBuffer=0;
  243.     }
  244.     if(hevUpdateBuffer) {
  245.         DosCloseEventSem(hevUpdateBuffer);
  246.         hevUpdateBuffer=0;
  247.     }
  248.     if(hevPlay) {
  249.         DosCloseEventSem(hevPlay);
  250.         hevPlay=0;
  251.     }
  252.     VC_Exit();
  253.     if(mciOpenParms.usDeviceID) {
  254.         mciGenericParms.hwndCallback=(HWND) NULL;
  255.         mciSendCommand(mciOpenParms.usDeviceID,MCI_CLOSE,MCI_WAIT,
  256.                        (PVOID)&mciGenericParms,0);
  257.         mciOpenParms.usDeviceID=0;
  258.     }
  259.     if(pBuffer) {
  260.         DosFreeMem(pBuffer);
  261.         pBuffer=NULL;
  262.     }
  263. }
  264.  
  265. static BOOL OS2_Small_PlayStart(VOID)
  266. {
  267.     VC_SilenceBytes((SBYTE*)pBuffer,BUFFERSIZE);
  268.     VC_PlayStart();
  269.  
  270.     /* signal update of 1st. block (as soon as 2nd. plays) */
  271.     iNext=0;
  272.     playList[1].ulOperand3=0;
  273.     playList[0].ulOperand3=0;
  274.  
  275.     /* signal play */
  276.     DosPostEventSem(hevPlay);
  277.  
  278.     mciPlayParms.hwndCallback=(HWND) NULL;
  279.     mciPlayParms.ulFrom=0;
  280.     mciPlayParms.ulTo=0;
  281.  
  282.     /* no MCI_WAIT here, because we have to continue in our program */
  283.     ulrc=mciSendCommand(mciOpenParms.usDeviceID,MCI_PLAY,MCI_FROM,
  284.                         &mciPlayParms,0);
  285.     if (ulrc) {
  286.         _mm_errno=MMERR_OS2_MIXSETUP;
  287.         return 1;
  288.     }
  289.     return 0;
  290. }
  291.  
  292. static VOID OS2_Small_PlayStop(VOID)
  293. {
  294.     ULONG ulPostCt; /* times a semaphore has been posted */
  295.  
  296.     mciGenericParms.hwndCallback=(HWND) NULL;
  297.     ulrc=mciSendCommand(mciOpenParms.usDeviceID,MCI_STOP,MCI_WAIT,
  298.                         &mciGenericParms,0);
  299.     DosResetEventSem(hevPlay, &ulPostCt);
  300.  
  301.     VC_PlayStop();
  302. }
  303.  
  304. static VOID OS2_Small_Update(VOID)
  305. {
  306.     /* does nothing since buffer is updated in the background */
  307.     return;
  308. }
  309.  
  310. static BOOL OS2_Small_Reset(VOID)
  311. {
  312.     OS2_Small_Exit();
  313.     return OS2_Small_Init();
  314. }
  315.  
  316. MDRIVER drv_os2s=
  317. {
  318.     NULL,
  319.     "OS/2 small buffer",
  320.     "OS/2 MMPM/2 MCI driver (64kB buffer) v1.0",
  321.     0,
  322.     255,
  323.     OS2_Small_IsPresent,
  324.     VC_SampleLoad,
  325.     VC_SampleUnload,
  326.     VC_SampleSpace,
  327.     VC_SampleLength,
  328.     OS2_Small_Init,
  329.     OS2_Small_Exit,
  330.     OS2_Small_Reset,
  331.     VC_SetNumVoices,
  332.     OS2_Small_PlayStart,
  333.     OS2_Small_PlayStop,
  334.     OS2_Small_Update,
  335.     VC_VoiceSetVolume,
  336.     VC_VoiceSetFrequency,
  337.     VC_VoiceSetPanning,
  338.     VC_VoicePlay,
  339.     VC_VoiceStop,
  340.     VC_VoiceStopped,
  341.     VC_VoiceGetPosition,
  342.     VC_VoiceRealVolume,
  343. };
  344.