⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audio_os2.c

📁 mpg123 是 MPEG 1.0/2.0/2.5 的实时播放软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
	audio_os2: OS/2 RealTime DART Engine

	copyright 1998-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
	see COPYING and AUTHORS files in distribution or http://mpg123.de
	initially written by Samuel Audet
*/

#define INCL_OS2MM
#define INCL_DOS
#define INCL_VIO
#define INCL_KBD
#include <os2.h>
#include <os2me.h>
#include <stdlib.h>
#include <ctype.h>

/* I guess this #ifndef could be removed now... */
#ifndef MPG123_INCLUDED
#include "config.h"
#include "mpg123.h"
#endif

/* complementary audio parameters */
int numbuffers = 32;     /* total audio buffers, _bare_ minimum = 4 (cuz of prio boost check) */
int lockdevice = FALSE;
USHORT volume = 100;
char *boostprio = NULL;
char *normalprio = NULL;
unsigned char boostclass = 3, normalclass = 2;
signed char   boostdelta = 0, normaldelta = 31;
unsigned char mmerror[160] = {0};
int playingframe;

/* audio buffers */
static ULONG ulMCIBuffers;

static MCI_AMP_OPEN_PARMS  maop = {0};
static MCI_MIXSETUP_PARMS  mmp = {0};
static MCI_BUFFER_PARMS    mbp = {0};
static MCI_GENERIC_PARMS   mgp = {0};
static MCI_SET_PARMS       msp = {0};
static MCI_STATUS_PARMS    mstatp = {0};
static MCI_MIX_BUFFER      *MixBuffers = NULL;

typedef struct
{
   MCI_MIX_BUFFER  *NextBuffer;
   int frameNum;
} BUFFERINFO;

BUFFERINFO *bufferinfo = NULL;


static HEV dataplayed = 0;
static ULONG resetcount;
static BOOL paused = FALSE;

static MCI_MIX_BUFFER *tobefilled, *playingbuffer = NULL, playedbuffer;
static void *pBufferplayed;

static BOOL nomoredata,nobuffermode,justflushed;

static TIB *mainthread; /* thread info to set thread priority */

ULONG keyboardtid;


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 /* will contain new data */,
                     1 );
      break;

   } /* end switch */

   return( TRUE );

} /* end DARTEvent */


static void MciError(ULONG ulError)
{
   unsigned char buffer[128];
   ULONG rc;

   rc = mciGetErrorString(ulError, buffer, sizeof(buffer));

   if (rc == MCIERR_SUCCESS)
      sprintf(mmerror,"MCI Error %d: %s\n",ULONG_LOWD(ulError),buffer);
   else
      sprintf(mmerror,"MCI Error %d: Cannot query error message.\n",ULONG_LOWD(rc));

   fprintf(stderr,"%s",mmerror);
}

int audio_set_volume(struct audio_info_struct *ai, USHORT setvolume)
{
   if(setvolume > 100) setvolume = 100;
   volume = setvolume; /* useful when device is closed and reopened */
   if(maop.usDeviceID)
   {
     memset(&msp,0,sizeof(msp));
     msp.ulAudio = MCI_SET_AUDIO_ALL;
     msp.ulLevel = setvolume;

     mciSendCommand(maop.usDeviceID, MCI_SET,
                    MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
                    &msp, 0);
   }
   return setvolume;
}

int audio_pause(struct audio_info_struct *ai, int pause)
{
   if(maop.usDeviceID)
   {
      if(pause)
         mciSendCommand(maop.usDeviceID, MCI_PAUSE,
                        MCI_WAIT,
                        &mgp, 0);
      else
         mciSendCommand(maop.usDeviceID, MCI_RESUME,
                        MCI_WAIT,
                        &mgp, 0);
   }
   return pause;
}

int audio_open(struct audio_info_struct *ai)
{
   ULONG rc,i;
   char *temp;
   ULONG openflags;
   PPIB ppib;
   USHORT bits;

   if(maop.usDeviceID) return (maop.usDeviceID);

   if(!ai) return -1;

   if(!ai->device) ai->device = "0";

   if(ai->rate < 0) ai->rate = 44100;
   if(ai->channels < 0) ai->channels = 2;
   if(ai->format < 0) ai->format = AUDIO_FORMAT_SIGNED_16;

   if(ai->format == AUDIO_FORMAT_SIGNED_16)
      bits = 16;
   else if(ai->format == AUDIO_FORMAT_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(ai->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 ai->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 = ai->rate;
   mmp.ulChannels = ai->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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -