예제 #1
0
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;
}
예제 #2
0
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 */
예제 #3
0
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;
}
예제 #4
0
/* 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;
}
예제 #5
0
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;
}
예제 #6
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;
}
예제 #7
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;
}