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; }
static LONG APIENTRY DARTEvent(ULONG ulStatus, MCI_MIX_BUFFER *PlayedBuffer, ULONG ulFlags) { switch(ulFlags) { case MIX_STREAM_ERROR | MIX_WRITE_COMPLETE: /* error occur in device */ if ( ulStatus == ERROR_DEVICE_UNDERRUN) /* Write buffers to rekick off the amp mixer. */ mmp.pmixWrite( mmp.ulMixHandle, MixBuffers, ulMCIBuffers ); break; case MIX_WRITE_COMPLETE: /* for playback */ playingbuffer = ((BUFFERINFO *) PlayedBuffer->ulUserParm)->NextBuffer; /* the next three lines are only useful to audio_playing_samples() */ playedbuffer = *PlayedBuffer; playedbuffer.pBuffer = pBufferplayed; memcpy(playedbuffer.pBuffer, PlayedBuffer->pBuffer, PlayedBuffer->ulBufferLength); /* just too bad, the decoder fell behind... here we just keep the buffer to be filled in front of the playing one so that when the decoder kicks back in, we'll hear it in at the right time */ if(tobefilled == playingbuffer) { tobefilled = ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer; nomoredata = TRUE; } else { playingframe = ((BUFFERINFO *) playingbuffer->ulUserParm)->frameNum; /* if we're about to be short of decoder's data (2nd ahead buffer not filled), let's boost its priority! */ if(tobefilled == ( (BUFFERINFO *) ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer) DosSetPriority(PRTYS_THREAD,boostclass,boostdelta,mainthread->tib_ptib2->tib2_ultid); } /* empty the played buffer in case it doesn't get filled back */ memset(PlayedBuffer->pBuffer,0,PlayedBuffer->ulBufferLength); DosPostEventSem(dataplayed); mmp.pmixWrite( mmp.ulMixHandle, PlayedBuffer, 1 ); break; } /* end switch */ return( TRUE ); } /* end DARTEvent */
static void dump_buffer (int i) { static int index = 0; void *b; b = buffer; if (index + i > bsize) { do { DosRequestMutexSem (mutex, SEM_INDEFINITE_WAIT); if (ready != 0) { DosReleaseMutexSem(mutex); break; } DosReleaseMutexSem (mutex); DosSleep (20); } while (TRUE); MixBuffers[next].ulBufferLength = index; MixSetupParms.pmixWrite (MixSetupParms.ulMixHandle, &(MixBuffers[next]),1); ready--; next++; index = 0; if (next == BUFFERCOUNT) { next=0; } } memcpy (&((char*)MixBuffers[next].pBuffer)[index], b, i); index += i; }
/* Buffer update thread (created and called by DART) This is a high-priority thread used to compute and update the audio stream, automatically created by the DART subsystem. We compute the next audio buffer and feed it to the waveaudio device. */ static LONG APIENTRY Dart_UpdateBuffers(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) { /* sanity check */ if (!pBuffer) return TRUE; /* if we have finished a buffer, we're ready to play a new one */ if ((ulFlags == MIX_WRITE_COMPLETE) || ((ulFlags == (MIX_WRITE_COMPLETE | MIX_STREAM_ERROR)) && (ulStatus == ERROR_DEVICE_UNDERRUN))) { /* refill this audio buffer and feed it again */ MUTEX_LOCK(vars); if (Player_Paused_internal()) pBuffer->ulBufferLength = VC_SilenceBytes(pBuffer->pBuffer, BufferSize); else pBuffer->ulBufferLength = VC_WriteBytes(pBuffer->pBuffer, BufferSize); MUTEX_UNLOCK(vars); MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, pBuffer, 1); } return TRUE; }
int open_os2(audio_output_t *ao) { ULONG rc,i; char *temp; ULONG openflags; PPIB ppib; USHORT bits; if(maop.usDeviceID) return (maop.usDeviceID); if(!ai) return -1; if(!ao->device) ao->device = "0"; if(ao->rate < 0) ao->rate = 44100; if(ao->channels < 0) ao->channels = 2; if(ao->format < 0) ao->format = MPG123_ENC_SIGNED_16; if(ao->format == MPG123_ENC_SIGNED_16) bits = 16; else if(ao->format == MPG123_ENC_UNSIGNED_8) bits = 8; else return -1; /* open the mixer device */ memset (&maop, 0, sizeof(maop)); maop.usDeviceID = 0; maop.pszDeviceType = (PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, atoi(ao->device)); openflags = MCI_WAIT | MCI_OPEN_TYPE_ID; if(!lockdevice) openflags |= MCI_OPEN_SHAREABLE; rc = mciSendCommand(0, MCI_OPEN, openflags, &maop, 0); if (ULONG_LOWD(rc) != MCIERR_SUCCESS) { MciError(rc); maop.usDeviceID = 0; return(-1); } /* volume in ao->gain ?? */ /* Set the MCI_MIXSETUP_PARMS data structure to match the audio stream. */ memset(&mmp, 0, sizeof(mmp)); mmp.ulBitsPerSample = bits; mmp.ulFormatTag = MCI_WAVE_FORMAT_PCM; mmp.ulSamplesPerSec = ao->rate; mmp.ulChannels = ao->channels; /* Setup the mixer for playback of wave data */ mmp.ulFormatMode = MCI_PLAY; mmp.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; mmp.pmixEvent = DARTEvent; rc = mciSendCommand( maop.usDeviceID, MCI_MIXSETUP, MCI_WAIT | MCI_MIXSETUP_INIT, &mmp, 0 ); if ( ULONG_LOWD(rc) != MCIERR_SUCCESS ) { MciError(rc); maop.usDeviceID = 0; return(-1); } volume = audio_set_volume(ai,volume); /* Set up the BufferParms data structure and allocate * device buffers from the Amp-Mixer */ memset(&mbp, 0, sizeof(mbp)); free(MixBuffers); free(bufferinfo); if(numbuffers < 5) numbuffers = 5; if(numbuffers > 200) numbuffers = 200; MixBuffers = calloc(numbuffers, sizeof(*MixBuffers)); bufferinfo = calloc(numbuffers, sizeof(*bufferinfo)); ulMCIBuffers = numbuffers; mbp.ulNumBuffers = ulMCIBuffers; /* mbp.ulBufferSize = mmp.ulBufferSize; */ /* I don't like this... they must be smaller than 64KB or else the engine needs major rewrite */ mbp.ulBufferSize = audiobufsize; mbp.pBufList = MixBuffers; rc = mciSendCommand( maop.usDeviceID, MCI_BUFFER, MCI_WAIT | MCI_ALLOCATE_MEMORY, (PVOID) &mbp, 0 ); if ( ULONG_LOWD(rc) != MCIERR_SUCCESS ) { MciError(rc); maop.usDeviceID = 0; return(-1); } pBufferplayed = playedbuffer.pBuffer = calloc(1,audiobufsize); ulMCIBuffers = mbp.ulNumBuffers; /* never know! */ /* Fill all device buffers with zeros and set linked list */ for(i = 0; i < ulMCIBuffers; i++) { MixBuffers[i].ulFlags = 0; MixBuffers[i].ulBufferLength = mbp.ulBufferSize; memset(MixBuffers[i].pBuffer, 0, MixBuffers[i].ulBufferLength); MixBuffers[i].ulUserParm = (ULONG) &bufferinfo[i]; bufferinfo[i].NextBuffer = &MixBuffers[i+1]; } bufferinfo[i-1].NextBuffer = &MixBuffers[0]; /* Create a semaphore to know when data has been played by the DART thread */ DosCreateEventSem(NULL,&dataplayed,0,FALSE); playingbuffer = &MixBuffers[0]; tobefilled = &MixBuffers[1]; playingframe = 0; nomoredata = TRUE; nobuffermode = FALSE; justflushed = FALSE; if(boostprio) { temp = alloca(strlen(boostprio)+1); strcpy(temp,boostprio); boostdelta = atoi(temp+1); *(temp+1) = 0; boostclass = atoi(temp); } if(boostclass > 4) boostdelta = 3; if(boostdelta > 31) boostdelta = 31; if(boostdelta < -31) boostdelta = -31; if(normalprio) { temp = alloca(strlen(normalprio)+1); strcpy(temp,normalprio); normaldelta = atoi(temp+1); *(temp+1) = 0; normalclass = atoi(temp); } if(normalclass > 4) normaldelta = 3; if(normaldelta > 31) normaldelta = 31; if(normaldelta < -31) normaldelta = -31; DosGetInfoBlocks(&mainthread,&ppib); /* ppib not needed, but makes some DOSCALLS.DLL crash */ DosSetPriority(PRTYS_THREAD,boostclass,boostdelta,mainthread->tib_ptib2->tib2_ultid); /* Write buffers to kick off the amp mixer. see DARTEvent() */ rc = mmp.pmixWrite( mmp.ulMixHandle, MixBuffers, ulMCIBuffers ); return maop.usDeviceID; }
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; }
static int dart_init_sound (SINT16 *buffer) { int i, flags, device = 0; MCI_AMP_OPEN_PARMS AmpOpenParms; if ((bsize < BUF_MIN || bsize > BUF_MAX) && bsize != 0) { bsize = 16 * 1024; } else { bsize *= 1024; } MixBuffers[0].pBuffer = NULL; /* marker */ memset (&GenericParms,0,sizeof (MCI_GENERIC_PARMS)); /* open AMP device */ memset(&AmpOpenParms,0,sizeof(MCI_AMP_OPEN_PARMS)); AmpOpenParms.usDeviceID=0; AmpOpenParms.pszDeviceType = (PSZ) MAKEULONG (MCI_DEVTYPE_AUDIO_AMPMIX, (USHORT)device); flags = MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE; if (mciSendCommand (0,MCI_OPEN, flags, (PVOID)&AmpOpenParms,0) != MCIERR_SUCCESS) { return -1; } DeviceID=AmpOpenParms.usDeviceID; /* setup playback parameters */ memset(&MixSetupParms,0,sizeof(MCI_MIXSETUP_PARMS)); MixSetupParms.ulBitsPerSample = 16; MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM; MixSetupParms.ulSamplesPerSec = 22050; MixSetupParms.ulChannels = 1; MixSetupParms.ulFormatMode = MCI_PLAY; MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; MixSetupParms.pmixEvent = OS2_Dart_UpdateBuffers; if (mciSendCommand(DeviceID,MCI_MIXSETUP, MCI_WAIT | MCI_MIXSETUP_INIT, (PVOID)&MixSetupParms,0)!=MCIERR_SUCCESS) { mciSendCommand (DeviceID, MCI_CLOSE, MCI_WAIT, (PVOID)&GenericParms,0); return -1; } /* take in account the DART suggested buffer size... */ if( bsize == 0 ) { bsize=MixSetupParms.ulBufferSize; } BufferParms.ulNumBuffers = BUFFERCOUNT; BufferParms.ulBufferSize = bsize; BufferParms.pBufList = MixBuffers; if (mciSendCommand (DeviceID, MCI_BUFFER, MCI_WAIT | MCI_ALLOCATE_MEMORY, (PVOID)&BufferParms,0) != MCIERR_SUCCESS) { mciSendCommand (DeviceID, MCI_CLOSE, MCI_WAIT, (PVOID)&GenericParms,0); return -1; } for (i = 0 ; i < BUFFERCOUNT ; i++ ) { MixBuffers[i].ulBufferLength = bsize; } /* Start Playback */ memset (MixBuffers[0].pBuffer, /*32767*/0, bsize); memset (MixBuffers[1].pBuffer, /*32767*/0, bsize); MixSetupParms.pmixWrite (MixSetupParms.ulMixHandle,MixBuffers,2); return 0; }