home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / MULTIMED / MIKMOS2 / drv_os22.c < prev    next >
Text File  |  1996-12-31  |  22KB  |  588 lines

  1. /*
  2.  
  3. Name: DRV_OS2.C, 12/06/1996
  4.  
  5. Author: Stefan Tibus
  6.  
  7. Description: Experimental Mikmod driver for output on OS/2 MMPM/2 using MCI.
  8.  
  9. Method: Double-Buffer, automatic refill using timer-semaphore in own thread.
  10.  
  11. Portability: OS/2 Warp v3.0 (Connect) PM - WATCOM v10.x
  12.  
  13. Copyright (c) Stefan Tibus, all rights reserved
  14.  
  15. */
  16.  
  17. /*
  18.  
  19. Important:
  20.  
  21. This module is still in beta-state. There are no warranties at all.
  22. The author is not responsible for any problems you have with using this module.
  23.  
  24. - This code and any part of it may not be published without the authors explicit
  25.   permission.
  26. - This code may only be distributed in complete and unmodified form - as it is
  27.   now - and only for FREE !
  28. - The unmodified code may be used in your own developments and distributed with
  29.   them under the condition that there is a visible copyright message granting all
  30.   rights on this module to the author.
  31.   The copyright message has to contain the following:
  32.   "copyright (c) Stefan Tibus, all rights reserved"  (e.g. "parts copyright..." or
  33.   "OS/2-Sound-Driver copyright...")
  34. - Any commercial use requires a special permission of the author !
  35.  
  36. - You are free to make changes to the source-code for your own, private use only.
  37. - The modified code may not be published or distributed (separately or as part of
  38.   your developments) without the authors explicit permission.
  39.   Therefore it is necessary to report any changes to the author, with a description
  40.   of what it is doing and how it works.
  41.  
  42. - Any feedback is welcome !
  43.  
  44. e-mail: Stefan Tibus, 2:246/8722.20@FidoNet
  45.         Stefan.Tibus@ThePentagon.com
  46.  
  47. - The lines above may not be cut off this code.
  48.  
  49. */
  50.  
  51. #define INCL_DOS // include OS/2-DOS-functions
  52. #define INCL_DOSPROCESS // include process-management (threads,...)
  53. #define INCL_DOSMEMMGR // include memory-management
  54. #define INCL_32 // include 32Bit-functions
  55. #include <os2.h> // include OS/2-functions
  56. #include <mcios2.h> // include MCI-functions
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #include <string.h> // memset
  60. #include "mikmod.h"
  61.  
  62. static MCI_OPEN_PARMS mciOpenParms; // parameters for opening of an MCI-device
  63. static MCI_GENERIC_PARMS mciGenericParms; // generic parameters for an MCI-command
  64. static MCI_PLAY_PARMS mciPlayParms; // parameters for playing of an MCI-device
  65. static MCI_WAVE_SET_PARMS mciWaveSetParms; // parameters for setting of an WAVEAUDIO-MCI-device
  66. static ULONG rc; // general-use returncode
  67. static PVOID pSound; // pointer to soundbuffer
  68. static TID tidSound; // thread-ID of sound-thread
  69. static UINT uiNext; // signals next buffer to update
  70. static HEV hevSound; // handle for sound-eventsemaphore
  71. static HEV hevPlay; // handle for play-semaphore
  72. static HTIMER htimerSound; // handle for sound-timer
  73.  
  74. // typedef for playlist-structure
  75. typedef struct
  76. {
  77.    ULONG ulCommand; // playlist-command
  78.    ULONG ulOperand1; // 1st operand
  79.    ULONG ulOperand2; // 2nd operand
  80.    ULONG ulOperand3; // 3rd operand
  81. } PLAYLISTSTRUCTURE;
  82.  
  83. #define SOUND_BUFFER_UPDATE_SIZE 32768
  84. #define SOUND_BUFFER_UPDATES_PER_BLOCK 8
  85. #define SOUND_BUFFER_BLOCK_COUNT 2 // number of soundbuffer-blocks
  86.  
  87. static UINT SOUNDBUFFERUPDATESIZE=SOUND_BUFFER_UPDATE_SIZE;
  88. static UINT SOUNDBUFFERUPDATESPERBLOCK=SOUND_BUFFER_UPDATES_PER_BLOCK;
  89. static UINT SOUNDBUFFERBLOCKCOUNT=SOUND_BUFFER_BLOCK_COUNT; // number of soundbuffer-blocks
  90. static UINT SOUNDBUFFERBLOCKSIZE=SOUND_BUFFER_UPDATE_SIZE*SOUND_BUFFER_UPDATES_PER_BLOCK; // size of 1 soundbuffer-block
  91. static ULONG SOUNDBUFFERSIZE=SOUND_BUFFER_BLOCK_COUNT*SOUND_BUFFER_UPDATES_PER_BLOCK*SOUND_BUFFER_UPDATE_SIZE; // size of soundbuffer
  92. static PLAYLISTSTRUCTURE playList[SOUND_BUFFER_BLOCK_COUNT+1]; // array with playlist (count+1 commands)
  93.  
  94. // mixer-support, for use with SetAmpKnob:
  95. typedef enum KNOB_ {VOLUME, BALANCE, BASS, TREBLE} KNOB;
  96. BOOL OS2_MMPM2_LARGE_SetAmpKnob(KNOB eKnob, ULONG ulLevel);
  97.  
  98. // ***** SoundThread_LARGE *****
  99. // Does update of the soundbuffer
  100. VOID APIENTRY SoundThread_LARGE(ULONG ul)
  101. {
  102.    ULONG ulPostCt; // number of events happened
  103.    UINT uiCount; // counter
  104.  
  105.    ulPostCt=ul; // really does nothing, just to avoid warning
  106.  
  107.    while(1) // endless loop
  108.    {
  109.       // wait for play
  110.       DosWaitEventSem(hevPlay,SEM_INDEFINITE_WAIT);
  111. // s.t. das soll verhindern, das schon angefangen wird die Puffer zu aktualisieren, obwohl noch
  112. // kein Play erfolgt ist, das File evtl noch gar nicht geladen -> NULL-Zeiger-Fehler
  113.       // wait for timer
  114.       DosWaitEventSem(hevSound,SEM_INDEFINITE_WAIT);
  115.       // update next buffer-block corresponding to uiNext
  116.       if(uiNext==0)
  117.       { // 1st block
  118.          if (playList[SOUNDBUFFERBLOCKCOUNT-1].ulOperand3>0)
  119.          { // only if last block is currently playing
  120.             playList[uiNext].ulCommand=NOP_OPERATION;
  121.             // update 1st half-buffer
  122.             for (uiCount=0;uiCount<SOUNDBUFFERUPDATESPERBLOCK;uiCount++)
  123.             { // update entire block in several parts of < 64k
  124.                VC_WriteBytes((CHAR*)playList[uiNext].ulOperand1+(SOUNDBUFFERUPDATESIZE*uiCount),
  125.                   SOUNDBUFFERUPDATESIZE); // update block
  126.             }
  127.             playList[uiNext].ulOperand3=0; // reset play-position (necessary?) -> avoids updating before being played
  128.             playList[uiNext].ulCommand=DATA_OPERATION;
  129.             uiNext++; // increment counter -> signal update of the next block
  130.          }
  131.       }
  132.       else if(uiNext==SOUNDBUFFERBLOCKCOUNT-1)
  133.       { // last block
  134.          if (playList[uiNext-1].ulOperand3>0)
  135.          { // only if block before is currently playing
  136.             playList[uiNext].ulCommand=NOP_OPERATION;
  137.             // update 2nd=last half-buffer
  138.             for (uiCount=0;uiCount<SOUNDBUFFERUPDATESPERBLOCK;uiCount++)
  139.             { // update entire block in several parts of < 64k
  140.                VC_WriteBytes((CHAR*)playList[uiNext].ulOperand1+(SOUNDBUFFERUPDATESIZE*uiCount),
  141.                   SOUNDBUFFERUPDATESIZE); // update block
  142.             }
  143.             playList[uiNext].ulOperand3=0; // reset play-position (necessary?) -> avoids updating before being played
  144.             playList[uiNext].ulCommand=DATA_OPERATION;
  145.             uiNext=0; // reset counter -> signal update of first block (looping)
  146.          }
  147.       }
  148.       else
  149.       { // any block else
  150.          if (playList[uiNext-1].ulOperand3>0)
  151.          { // only if block before is currently playing
  152.             playList[uiNext].ulCommand=NOP_OPERATION;
  153.             // update half-buffer
  154.             for (uiCount=0;uiCount<SOUNDBUFFERUPDATESPERBLOCK;uiCount++)
  155.             { // update entire block in several parts of < 64k
  156.                VC_WriteBytes((CHAR*)playList[uiNext].ulOperand1+(SOUNDBUFFERUPDATESIZE*uiCount),
  157.                   SOUNDBUFFERUPDATESIZE); // update block
  158.             }
  159.             playList[uiNext].ulOperand3=0; // reset play-position (necessary?) -> avoids updating before being played
  160.             playList[uiNext].ulCommand=DATA_OPERATION;
  161.             uiNext++; // increment counter -> signal update of the next block
  162.          }
  163.       }
  164.       // reset timer-semaphore
  165.       DosResetEventSem(hevSound,&ulPostCt);
  166. /////      DosResetEventSem(hevSound,NULL);
  167. // s.t. wird " weggelassen, bleibt das semaphore gesetzt und man hat eine echte Endlosschleife,
  168. // die nicht auf den Timer wartet
  169.    }
  170. }
  171.  
  172. // ***** OS2_MMPM2_LARGE_IsThere *****
  173. // checks for availability of an OS/2 MCI-WAVEAUDIO-device
  174. BOOL OS2_MMPM2_LARGE_IsThere(VOID)
  175. {
  176.    // MCI: set open-parameters
  177.    mciOpenParms.hwndCallback=(HWND) NULL;                      
  178.    mciOpenParms.usDeviceID=(USHORT) NULL;                      
  179.    mciOpenParms.pszDeviceType=(PSZ) MCI_DEVTYPE_WAVEFORM_AUDIO;
  180.    mciOpenParms.pszElementName=(PSZ) NULL;                     
  181.  
  182.    // MCI: open WAVEAUDIO-device
  183.    rc=mciSendCommand(0, MCI_OPEN, MCI_WAIT|MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE_ID,
  184.       (PVOID) &mciOpenParms, 0);
  185.    // test returncode
  186.    if (rc==0)
  187.    { // good
  188.       // MCI: set generic parameters
  189.       mciGenericParms.hwndCallback=(HWND) NULL;
  190.       // MCI: close device
  191.       rc=mciSendCommand(mciOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
  192.          (PVOID) &mciGenericParms, 0);
  193.       // device is there -> return TRUE
  194.       return TRUE;
  195.    }
  196.    else
  197.       // unable to open device -> return FALSE
  198.       return FALSE;
  199. }
  200.  
  201. // ***** OS2_MMPM2_LARGE_Init *****
  202. // initializes the OS/2 MCI-WAVEAUDIO-device, allocates soundbuffer etc.
  203. BOOL OS2_MMPM2_LARGE_Init(VOID)
  204. {
  205.    ULONG ulInterval; // timer-interval
  206.    ULONG ulPostCt; // counter for semaphore-events
  207.    UINT uiCount; // counter
  208.  
  209.    // reset pointer to soundbuffer
  210.    pSound=NULL;
  211.    // allocate (commited) memory for soundbuffer
  212.    rc=DosAllocMem(&pSound,SOUNDBUFFERSIZE,PAG_READ|PAG_WRITE|PAG_COMMIT);
  213.    // test returncode
  214.    if (rc)
  215.    { // bad
  216.       // error during memory allocation
  217.       myerr="Memory allocation failed";
  218.       return FALSE;
  219.    }
  220.  
  221.    // initialize playlist
  222.    for (uiCount=0;uiCount<SOUNDBUFFERBLOCKCOUNT;uiCount++)
  223.    { // for each entry:
  224.       playList[uiCount].ulCommand=DATA_OPERATION; // play data
  225.       playList[uiCount].ulOperand1=(ULONG)pSound+(SOUNDBUFFERBLOCKSIZE*uiCount); // pointer to data
  226.       playList[uiCount].ulOperand2=(ULONG)SOUNDBUFFERBLOCKSIZE; // length of data
  227.       playList[uiCount].ulOperand3=0; // current-play-position (used to determine currently playing block)
  228.    }
  229.    // last entry:
  230.    playList[SOUNDBUFFERBLOCKCOUNT].ulCommand=BRANCH_OPERATION; // jump
  231.    playList[SOUNDBUFFERBLOCKCOUNT].ulOperand1=0; // nothing
  232.    playList[SOUNDBUFFERBLOCKCOUNT].ulOperand2=0; // target (block 0 i.e. 1st block)
  233.    playList[SOUNDBUFFERBLOCKCOUNT].ulOperand3=0; // nothing
  234.    // signal first block to be next
  235.    uiNext=0;
  236.    playList[SOUNDBUFFERBLOCKCOUNT-1].ulOperand3=1;
  237.  
  238.    // MCI: set open-parameters
  239.    mciOpenParms.hwndCallback=(HWND) NULL;
  240.    mciOpenParms.usDeviceID=(USHORT) NULL;
  241.    mciOpenParms.pszDeviceType=(PSZ) MCI_DEVTYPE_WAVEFORM_AUDIO;
  242.    mciOpenParms.pszElementName=(PSZ) &playList;
  243.    // MCI: open WAVEAUDIO-device
  244.    rc=mciSendCommand(0,MCI_OPEN, MCI_WAIT|MCI_OPEN_TYPE_ID|MCI_OPEN_PLAYLIST,
  245.       (PVOID) &mciOpenParms, 0);
  246.    // test returncode
  247.    if (rc)
  248.    { // bad
  249.       // error during opening of device
  250.       myerr="Cannot open WAVEAUDIO-device";
  251.       // free soundbuffer
  252.       DosFreeMem(pSound);
  253.       return FALSE;
  254.    }
  255.    // MCI: set waveset-parameters
  256.    mciWaveSetParms.hwndCallback=(HWND) NULL;
  257.    mciWaveSetParms.ulSamplesPerSec=md_mixfreq;
  258.    if (md_mode&DMODE_16BITS)
  259.    {
  260.       mciWaveSetParms.usBitsPerSample=16;
  261.    }
  262.    else
  263.    {
  264.       mciWaveSetParms.usBitsPerSample=8;
  265.    }
  266.    if (md_mode&DMODE_STEREO)
  267.    {
  268.       mciWaveSetParms.usChannels=2;
  269.    }
  270.    else
  271.    {
  272.       mciWaveSetParms.usChannels=1;
  273.    }
  274.    mciWaveSetParms.ulAudio=MCI_SET_AUDIO_ALL;
  275.    // MCI: set WAVEAUDIO-parameters
  276.    rc=mciSendCommand(mciOpenParms.usDeviceID,
  277.       MCI_SET,MCI_WAIT|MCI_WAVE_SET_SAMPLESPERSEC|MCI_WAVE_SET_BITSPERSAMPLE|MCI_WAVE_SET_CHANNELS,
  278.       (PVOID) &mciWaveSetParms, 0);
  279.    // test returncode
  280.    if (rc)
  281.    { // bad
  282.       // error during setting of waveaudio-parameters
  283.       myerr="Unable to set output parameters";
  284.       // MCI: set generic parameters
  285.       mciGenericParms.hwndCallback=(HWND) NULL;
  286.       // MCI: close device
  287.       rc=mciSendCommand(mciOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
  288.          (PVOID) &mciGenericParms, 0);
  289.       // free soundbuffer
  290.       DosFreeMem(pSound);
  291.       return FALSE;
  292.    }
  293.    // mikmod: initialize
  294.    if (!VC_Init())
  295.    { // bad
  296.       // mikmod-error
  297.       // MCI: set generic parameters
  298.       mciGenericParms.hwndCallback=(HWND) NULL;
  299.       // MCI: close device
  300.       rc=mciSendCommand(mciOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
  301.          (PVOID) &mciGenericParms, 0);
  302.       // free soundbuffer
  303.       DosFreeMem(pSound);
  304.       return FALSE;
  305.    }
  306.  
  307.    // create play-semaphore
  308.    rc=DosCreateEventSem("\\SEM32\\MikMod\\Play",&hevPlay,DC_SEM_SHARED,FALSE);
  309.    // test returncode
  310.    if (rc)
  311.    { // bad
  312.       // error during creation of semaphore
  313.       myerr="Cannot create play-semaphore";
  314.       // MCI: set generic parameters
  315.       mciGenericParms.hwndCallback=(HWND) NULL;
  316.       // MCI: close device
  317.       rc=mciSendCommand(mciOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
  318.          (PVOID) &mciGenericParms, 0);
  319.       // free soundbuffer
  320.       DosFreeMem(pSound);
  321.       return FALSE;
  322.    }
  323.    // reset play-semaphore
  324.    DosResetEventSem(hevPlay,&ulPostCt);
  325.  
  326.    // create sound-semaphore
  327.    rc=DosCreateEventSem("\\SEM32\\MikMod\\Sound",&hevSound,DC_SEM_SHARED,FALSE);
  328.    // test returncode
  329.    if (rc)
  330.    { // bad
  331.       // error during creation of semaphore
  332.       myerr="Cannot create sound-semaphore";
  333.       // close semaphore
  334.       DosCloseEventSem(hevPlay);
  335.       // MCI: set generic parameters
  336.       mciGenericParms.hwndCallback=(HWND) NULL;
  337.       // MCI: close device
  338.       rc=mciSendCommand(mciOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
  339.          (PVOID) &mciGenericParms, 0);
  340.       // free soundbuffer
  341.       DosFreeMem(pSound);
  342.       return FALSE;
  343.    }
  344.    // reset sound-semaphore
  345.    DosResetEventSem(hevSound,&ulPostCt);
  346.  
  347.    // calculate interval for sound-timer (1 times per block)
  348.    ulInterval=SOUNDBUFFERBLOCKSIZE*1000/1/(mciWaveSetParms.usChannels*
  349.       mciWaveSetParms.usBitsPerSample*mciWaveSetParms.ulSamplesPerSec);
  350. // s.t. 1 mal pro Block sollte wohl mindestens drin sein (normalerweise denke ich 2 mal)
  351. // also 2 bzw. 4 mal beim ganzen Puffer (in 2 Blöcken)
  352.    // start sound-timer
  353.    rc=DosStartTimer(ulInterval,(HSEM)hevSound,&htimerSound);
  354.    // test returncode
  355.    if (rc)
  356.    { // bad
  357.       // error during starting of timer
  358.       myerr="Cannot start timer";
  359.       // close semaphore
  360.       DosCloseEventSem(hevSound);
  361.       // close semaphore
  362.       DosCloseEventSem(hevPlay);
  363.       // MCI: set generic parameters
  364.       mciGenericParms.hwndCallback=(HWND) NULL;
  365.       // MCI: close device
  366.       rc=mciSendCommand(mciOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
  367.          (PVOID) &mciGenericParms, 0);
  368.       // free soundbuffer
  369.       DosFreeMem(pSound);
  370.       return FALSE;
  371.    }
  372.  
  373.    // create sound-thread
  374.    rc=DosCreateThread(&tidSound,&SoundThread_LARGE,0,CREATE_READY|STACK_SPARSE,4096);
  375.    // test returncode
  376.    if (rc)
  377.    { // bad
  378.       // error during creation of thread
  379.       myerr="Cannot create thread";
  380.       // stop timer
  381.       DosStopTimer(htimerSound);
  382.       // close semaphore
  383.       DosCloseEventSem(hevSound);
  384.       // close semaphore
  385.       DosCloseEventSem(hevPlay);
  386.       // MCI: set generic parameters
  387.       mciGenericParms.hwndCallback=(HWND) NULL;
  388.       // MCI: close device
  389.       rc=mciSendCommand(mciOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
  390.          (PVOID) &mciGenericParms, 0);
  391.       // free soundbuffer
  392.       DosFreeMem(pSound);
  393.       return FALSE;
  394.    }
  395.    // set priority of sound-thread
  396. //////   rc=DosSetPriority(PRTYS_THREAD,PRTYC_FOREGROUNDSERVER,0,tidSound);
  397. // s.t. PRTYC_FOREGROUNDSERVER gibt dem Thread eine DEUTLICH höhere Priorität,
  398. // solange er arbeitet (nicht wenn er auf ein semaphore wartet)
  399. // ich weiß nicht ob's tatsächlich was bringt ;-)
  400.  
  401.    // set volume to 80% and test returncode
  402.    if(!OS2_MMPM2_LARGE_SetAmpKnob(VOLUME,80))
  403.    { // bad
  404.       // error setting volume
  405.       myerr="Error setting volume";
  406.       return FALSE;
  407.    }
  408.    // if the program arrives here, everything is ok.
  409.    return TRUE;
  410. }
  411.  
  412. // ***** OS2_MMPM2_LARGE_Exit *****
  413. // closes the OS/2 MCI-WAVEAUDIO-device, frees soundbuffer etc.
  414. VOID OS2_MMPM2_LARGE_Exit(VOID)
  415. {
  416.    // stop sound-thread
  417.    DosKillThread(tidSound);
  418.  
  419.    // stop sound-timer
  420.    DosStopTimer(htimerSound);
  421.  
  422.    // close sound-semaphore
  423.    DosCloseEventSem(hevSound);
  424.  
  425.    // close play-semaphore
  426.    DosCloseEventSem(hevPlay);
  427.  
  428.    // close WAVEAUDIO device
  429.    // MCI: set generic parameters
  430.    mciGenericParms.hwndCallback=(HWND) NULL;
  431.    // MCI: close device
  432.    rc=mciSendCommand(mciOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
  433.       (PVOID) &mciGenericParms, 0);
  434.  
  435.    // free soundbuffer
  436.    DosFreeMem(pSound);
  437.  
  438.    // mikmod: Exit
  439.    VC_Exit();
  440. }
  441.  
  442. // ***** OS2_MMPM2_LARGE_PlayStart *****
  443. // starts playing the soundbuffer
  444. VOID OS2_MMPM2_LARGE_PlayStart(VOID)
  445. {
  446.    ULONG ulPostCt; // counter for play-(semaphore-)events
  447. /* reset soundbuffer(s) and rewind */
  448.    // reset play-semaphore
  449.    DosResetEventSem(hevPlay,&ulPostCt);
  450.    // reset soundbuffer(s)
  451.    memset(pSound,0,SOUNDBUFFERSIZE);
  452.    // MCI: set generic parameters
  453.    mciGenericParms.hwndCallback=(HWND) NULL;
  454.    // MCI: rewind
  455.    rc=mciSendCommand(mciOpenParms.usDeviceID,MCI_REWIND,MCI_WAIT,&mciGenericParms,0);
  456. /* ------------------------------- */
  457.  
  458. // initialize timer here instead of in Init ? -> no error message possible ?
  459.  
  460.    // mikmod: start playing
  461.    VC_PlayStart();
  462.  
  463.    // signal first block as next
  464.    uiNext=0;
  465.    // set play-semaphore
  466.    DosPostEventSem(hevPlay);
  467. //   // imitate playing of last block (necessary to update first block)
  468. //   playList[SOUNDBUFFERBLOCKCOUNT-1].ulOperand3=(ULONG)SOUNDBUFFERBLOCKSIZE-1;
  469. // s.t. warum auch immer es hilft - lassen wir's weg
  470.  
  471.    // MCI: set play-parameters
  472.    mciPlayParms.hwndCallback=(HWND) NULL;
  473.    mciPlayParms.ulFrom=0;
  474.    mciPlayParms.ulTo=0;
  475.    // MCI: start playing
  476.    rc=mciSendCommand(mciOpenParms.usDeviceID,MCI_PLAY,0,&mciPlayParms,0);
  477. }
  478.  
  479. // ***** OS2_MMPM2_LARGE_PlayStop *****
  480. // stopps playing
  481. VOID OS2_MMPM2_LARGE_PlayStop(VOID)
  482. {
  483.    ULONG ulPostCt; // counter for play-(semaphore-)events
  484.  
  485.    // MCI: set generic parameters
  486.    mciGenericParms.hwndCallback=(HWND) NULL;
  487.    // MCI: stop playing
  488.    rc=mciSendCommand(mciOpenParms.usDeviceID,MCI_STOP,MCI_WAIT,&mciGenericParms,0);
  489.  
  490.    // reset play-semaphore
  491.    DosResetEventSem(hevPlay,&ulPostCt);
  492. /////   DosResetEventSem(hevPlay,NULL);
  493. // s.t. da ulPostCt ein Rückgabewert ist, muß er doch nicht initialisiert werden, oder ?
  494.    // mikmod: stop playing
  495.    VC_PlayStop();
  496.  
  497. //   // stop sound-timer (if started in PlayStart)
  498. //   DosStopTimer(htimerSound);
  499. // s.t. wieso hast Du hier den Timer gestoppt ? es wird dann nur beim nächsten Lied weitergespielt,
  500. // wenn im Thread nicht auf den Timer gewartet wird ! (oder seh' ich das falsch ?)
  501. }
  502.  
  503. // ***** OS2_MMPM2_LARGE_Update *****
  504. // dummy, does nothing, buffers are updated in the backgrounf
  505. VOID OS2_MMPM2_LARGE_Update(VOID)
  506. {
  507.    // does nothing, buffers are updated in the background
  508.    return;
  509. // s.t. das return ist hier doch nicht notwendig ? oder ist das dann schneller ? ;-)
  510. }
  511.  
  512. // ***** OS2_MMPM2_LARGE_SetAmpKnob *****
  513. // do mixer settings
  514. BOOL OS2_MMPM2_LARGE_SetAmpKnob(KNOB eKnob, ULONG ulLevel)
  515. {                                                                
  516.    MCI_SET_PARMS mciSetParms;
  517.    ULONG ulSetWhich;
  518.  
  519.    // MCI: set parameters for MCI_SET
  520.    // set window-handle for callback
  521.    mciSetParms.hwndCallback=(HWND)NULL;
  522.    // select channels
  523.    mciSetParms.ulAudio=MCI_SET_AUDIO_ALL;
  524.    // set volume level
  525.    mciSetParms.ulLevel=ulLevel;
  526.    // set delay time
  527.    mciSetParms.ulOver=0;
  528.    // others (not affected, just to reset structure)
  529.    mciSetParms.ulItem=0;
  530.    mciSetParms.ulValue=0;
  531.    mciSetParms.ulTimeFormat=0;
  532.    mciSetParms.ulSpeedFormat=0;
  533.  
  534.    switch (eKnob)
  535.    {
  536.       case VOLUME:
  537.          ulSetWhich = MCI_SET_VOLUME;
  538.          break;
  539.       // not yet supported, reserved for future
  540.       // version with mixer support 
  541.       case BALANCE :
  542.          ulSetWhich = 0; // MCI_AMP_SET_BALANCE
  543.          break;
  544.       case BASS :
  545.          ulSetWhich = 0; // MCI_AMP_SET_BASS
  546.          break;
  547.       case TREBLE :
  548.          ulSetWhich = 0; // MCI_AMP_SET_TREBLE
  549.          break;
  550.       // MCI_AMP_SET_PITCH, MCI_AMP_SET_GAIN
  551.       default :
  552.          ulSetWhich = 0;
  553.          break;
  554.    }
  555.    // MCI: set device-parameters
  556.    rc=mciSendCommand(mciOpenParms.usDeviceID,
  557.       MCI_SET,
  558.       MCI_WAIT | MCI_SET_AUDIO | MCI_SET_ON | ulSetWhich,
  559.       &mciSetParms,0);
  560.    if(rc)
  561.    {
  562.       myerr="Error setting mixer";
  563.       return FALSE;
  564.    }   
  565.    return TRUE;
  566. // AMPMIX-devices bieten noch weiter Einstellungsmöglichkeiten über MCI_SET_ITEM
  567. }
  568.  
  569. DRIVER drv_os2_mmpm2_largebuffers= // driver-description for mikmod
  570. {
  571.    NULL, // next: pointer to next driver (used by mikmod?)
  572.    "OS/2 MMPM/2 MCI (large buffers)", // Name: name of driver
  573.    "Mikmod OS/2 MMPM/2 MCI driver v0.2ß (large buffers)", // Version: driver-version
  574.    OS2_MMPM2_LARGE_IsThere, // IsPresent: test presence of hardware
  575.    VC_SampleLoad, // SampleLoad: default-function
  576.    VC_SampleUnload, // SampleUnload: default-function
  577.    OS2_MMPM2_LARGE_Init, // Init: initialize hardware and soundbuffer
  578.    OS2_MMPM2_LARGE_Exit, // Exit: close hardware and soundbuffer
  579.    OS2_MMPM2_LARGE_PlayStart, // PlayStart: start playing
  580.    OS2_MMPM2_LARGE_PlayStop, // PlayStop: stop playing
  581.    OS2_MMPM2_LARGE_Update, // Update: update soundbuffer
  582.    VC_VoiceSetVolume, // VoiceSetVolume: default-function
  583.    VC_VoiceSetFrequency, // VoiceSetFrequency: default-function
  584.    VC_VoiceSetPanning, // VoiceSetPanning: default-function
  585.    VC_VoicePlay // VoicePlay: default-function
  586. //   OS2_MMPM2_LARGE_SetAmpKnob // SetAmpKnob: do mixer-output settings
  587. };
  588.