LONG APIENTRY DARTEvent (ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) { ULONG rc; switch (ulFlags) { case MIX_WRITE_COMPLETE: // // start the playback of the next buffer // rc=MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, &(buffers[play]), 1); // // get the sound mutex // if (DosRequestMutexSem(hmtxSnd, SEM_INDEFINITE_WAIT)) return TRUE; // // empty the buffer which was finished // memset(buffers[last].pBuffer, 0, BufferParms.ulBufferSize); // // point to the next playable buffer and remember this buffer // as the last one which was played // last = play++; play %= BufferParms.ulNumBuffers; // // release mutex // DosReleaseMutexSem(hmtxSnd); if (rc != MCIERR_SUCCESS) sound_err(dlog, rc, "Writing to Mixer (pmixWrite, MIX_WRITE_COMPLETE)."); return TRUE; case MIX_STREAM_ERROR | MIX_WRITE_COMPLETE: // 130 /* error occur in device */ switch (ulStatus) { case ERROR_DEVICE_UNDERRUN: // 5626 sound_err(dlog, ulStatus, "Device underrun."); play += 2; play %= BufferParms.ulNumBuffers; break; case ERROR_DEVICE_OVERRUN: // 5627 sound_err(dlog, ulStatus, "Device overrun."); break; } rc=MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, &(buffers[play]), 1); if (rc != MCIERR_SUCCESS) sound_err(dlog, rc, "Writing to Mixer (pmixWrite, MIX_STREAM_ERROR)."); return TRUE; } return TRUE; }
void set_volume(int vol) { ULONG rc; if ((rc=DosRequestMutexSem(hmtxOC, SEM_INDEFINITE_WAIT))) { log_warning(dlog, "set_volume, DosRequestMutexSem rc=%i", rc); return; } if (usDeviceID) { MCI_SET_PARMS MciSetParms; memset(&MciSetParms, 0, sizeof(MCI_SET_PARMS)); MciSetParms.ulLevel = vol; MciSetParms.ulAudio = MCI_SET_AUDIO_ALL; log_message(dlog, "Setting volume to %d%%", vol); rc = mciSendCommand(usDeviceID, MCI_SET, MCI_WAIT| MCI_SET_VOLUME|MCI_SET_AUDIO, (PVOID) &MciSetParms, 0); if (rc != MCIERR_SUCCESS) sound_err(dlog, rc, "Setting up Volume (MCI_SET)."); } volume=vol; DosReleaseMutexSem(hmtxOC); }
static int DartOpen(void) { ULONG rc; MCI_AMP_OPEN_PARMS AmpOpenParms; memset(&AmpOpenParms, 0, sizeof (MCI_AMP_OPEN_PARMS)); AmpOpenParms.usDeviceID = (USHORT) 0; AmpOpenParms.pszDeviceType = (PSZ) MCI_DEVTYPE_AUDIO_AMPMIX; AmpOpenParms.hwndCallback = 0; rc = mciSendCommand(0, MCI_OPEN, MCI_WAIT|MCI_OPEN_TYPE_ID|MCI_OPEN_SHAREABLE /* | MCI_DOS_QUEUE*/, (PVOID) &AmpOpenParms, 0); if (rc != MCIERR_SUCCESS) { usDeviceID = 0; sound_err(dlog, rc, "Opening DART (MCI_OPEN)."); return FALSE; } usDeviceID = AmpOpenParms.usDeviceID; return TRUE; }
void mute(int state) { ULONG rc; if ((rc=DosRequestMutexSem(hmtxOC, SEM_INDEFINITE_WAIT))) { log_warning(dlog, "mute, DosRequestMutexSem rc=%i", rc); return; } if (usDeviceID) { MCI_SET_PARMS MciSetParms; memset(&MciSetParms, 0, sizeof(MCI_SET_PARMS)); MciSetParms.ulAudio = MCI_SET_AUDIO_ALL; rc = mciSendCommand(usDeviceID, MCI_SET, MCI_WAIT|state|MCI_SET_AUDIO, (PVOID) &MciSetParms, 0); if (rc != MCIERR_SUCCESS) sound_err(dlog, rc, "Setting mute state (MCI_SET_ON/OFF)."); } DosReleaseMutexSem(hmtxOC); if (state==MCI_SET_ON) set_volume(volume); }
static void dart_close() { MCI_GENERIC_PARMS GenericParms = { 0 }; ULONG rc; // prevent sound from clicking mute(MUTE_ON); if ((rc = DosRequestMutexSem(hmtxOC, SEM_INDEFINITE_WAIT))) { log_warning(dlog, "dart_close, DosRequestMutexSem rc=%i", rc); return; } //DosRequestMutexSem(hmtxSnd, SEM_INDEFINITE_WAIT); for (rc = 0; rc < BufferParms.ulNumBuffers; rc++) { buffers[rc].ulFlags = MIX_BUFFER_EOS; } rc = mciSendCommand(usDeviceID, MCI_STOP, MCI_WAIT, (PVOID) &GenericParms, 0); if (rc != MCIERR_SUCCESS) { sound_err(dlog, rc, "Stopping device (MCI_STOP)."); } //log_message(LOG_DEFAULT, "sounddrv.c: Sound stopped."); rc = mciSendCommand(usDeviceID, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, (PVOID) &BufferParms, 0); if (rc != MCIERR_SUCCESS) { sound_err(dlog, rc, "Deallocating buffer (MCI_DEALLOCATE)."); } //log_message(LOG_DEFAULT, "sounddrv.c: Buffer deallocated."); /* rc = mciSendCommand(usDeviceID, MCI_MIXSETUP, MCI_WAIT|MCI_MIXSETUP_DEINIT, (PVOID) &MixSetupParms, 0); if (rc != MCIERR_SUCCESS) return sound_err(dlog, (rc, "DART_ERR_MIXSETUP_DEINIT");*/ DartClose(); lib_free(buffers); //log_message(LOG_DEFAULT, "sounddrv.c: Buffer freed."); DosReleaseMutexSem(hmtxOC); }
static void DartClose(void) { MCI_GENERIC_PARMS GenericParms = {0}; ULONG rc = mciSendCommand(usDeviceID, MCI_CLOSE, MCI_WAIT, (PVOID) &GenericParms, 0); if (rc != MCIERR_SUCCESS) sound_err(dlog, rc, "Closing Dart (MCI_CLOSE)."); log_message(dlog, "Sound closed."); usDeviceID = 0; }
static int dart_init(const char *param, int *speed, int *fragsize, int *fragnr, int *channels) { /* The application sends the MCI_MIX_SETUP message to the amp mixer to initialize the device for direct reading and writing of audio data in the correct mode and format-for example, PCM, MIDI, or MPEG audio. If waveform audio data will be played or recorded, the application fills in the ulDeviceType field with MCI_DEVICETYPE_WAVEFORM_AUDIO. It must also provide values for the following digital-audio-specific fields: format tag, bits per sample, number of samples per second, and number of channels.*/ // MCI_MIXSETUP informs the mixer device of the entry point // to report buffers being read or written. // We will also need to tell the mixer which media type // we will be streaming. In this case, we'll use // MCI_DEVTYPE_WAVEFORM_AUDIO. ULONG i, rc; if (DosRequestMutexSem(hmtxOC, SEM_IMMEDIATE_RETURN)) return TRUE; // --------- if (!DartOpen()) { DosReleaseMutexSem(hmtxOC); return 1; } // --------- memset(&MixSetupParms, 0, sizeof(MCI_MIXSETUP_PARMS)); MixSetupParms.ulBitsPerSample = 16; MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM; MixSetupParms.ulSamplesPerSec = *speed; MixSetupParms.ulChannels = *channels; /* Stereo/Mono */ MixSetupParms.ulFormatMode = MCI_PLAY; MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; // MCI_MIXSETUP_QUERYMODE // Queries a device to see if a specific mode is supported /* rc = mciSendCommand( usDeviceID, MCI_MIXSETUP, MCI_WAIT | MCI_MIXSETUP_QUERYMODE, (PVOID) &MixSetupParms, 0); if (rc != MCIERR_SUCCESS) return sound_err(dlog, (rc, "Can't play.");*/ // The mixer will inform us of entry points to // read/write buffers to and also give us a // handle to use with these entry points. MixSetupParms.pmixEvent = DARTEvent; // MCI_MIXSETUP_INIT (DEINIT) // Initializes the mixer for the correct mode (MCI_MIXSETUP_PARMS) rc = mciSendCommand(usDeviceID, MCI_MIXSETUP, MCI_WAIT|MCI_MIXSETUP_INIT, (PVOID) &MixSetupParms, 0); if (rc != MCIERR_SUCCESS) { sound_err(dlog, rc, "Initialising mixer device (MCI_MIXSETUP_INIT)."); DartClose(); DosReleaseMutexSem(hmtxOC); return 1; } //log_message(LOG_DEFAULT, "sounddart.c: %3i buffers � %6i bytes (suggested by dart)", MixSetupParms.ulNumBuffers, MixSetupParms.ulBufferSize); //log_message(LOG_DEFAULT, "sounddart.c: %3i buffers � %6i bytes (wanted by vice)", *fragnr, *fragsize*sizeof(SWORD)); /* After the mixer device is set up to use DART, the application instructs the device to allocate memory by sending the MCI_BUFFER message with the MCI_ALLOCATE_MEMORY flag set. The application uses the MCI_BUFFER_PARMS structure to specify the number of buffers it wants and the size to be used for each buffer. Note: Because of device driver restrictions, buffers are limited to 64KB on Intel-based systems. No such limit exists on PowerPC systems. The pBufList field contains a pointer to an array of MCI_MIX_BUFFER structures where the allocated information is to be returned.*/ buffers = lib_calloc(*fragnr, sizeof(MCI_MIX_BUFFER)); BufferParms.pBufList = buffers; BufferParms.ulNumBuffers = *fragnr; BufferParms.ulBufferSize = *fragsize*sizeof(SWORD); rc = mciSendCommand(usDeviceID, MCI_BUFFER, MCI_WAIT|MCI_ALLOCATE_MEMORY, (PVOID) &BufferParms, 0); if (rc != MCIERR_SUCCESS) { sound_err(dlog, rc, "Allocating Memory (MCI_ALLOCATE_MEMORY)."); DartClose(); DosReleaseMutexSem(hmtxOC); return 1; } // MCI driver will return the number of buffers it // was able to allocate // it will also return the size of the information // allocated with each buffer. if (*fragnr !=BufferParms.ulNumBuffers) { *fragnr = BufferParms.ulNumBuffers; log_message(dlog, "got %3i buffers � %6i bytes.", BufferParms.ulNumBuffers, BufferParms.ulBufferSize); } if (*fragsize!=BufferParms.ulBufferSize/sizeof(SWORD)) { *fragsize = BufferParms.ulBufferSize/sizeof(SWORD); log_message(dlog, "got %3i buffers � %6i bytes.", BufferParms.ulNumBuffers, BufferParms.ulBufferSize); } // SECURITY for *fragnr <2 ???? for (i=0; i<*fragnr; i++) memset(buffers[i].pBuffer, 0, BufferParms.ulBufferSize); // *fragsize*sizeof(SWORD)); mmtime = (float)*speed/1000; written = 0; rest = BufferParms.ulBufferSize; // Must write at least two buffers to start mixer play = 2; // this is the buffer which is played next last = 1; // this is the buffer which is played last before next pos = 0; // this is the position to which buffer we have to write MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, &(buffers[0]), 2); DosReleaseMutexSem(hmtxOC); mute(MUTE_OFF); return 0; }