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

📄 drv_osx.c

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	MikMod sound library
	(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
	complete list.

	This library is free software; you can redistribute it and/or modify
	it under the terms of the GNU Library General Public License as
	published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.
 
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Library General Public License for more details.
 
	You should have received a copy of the GNU Library General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA.
*/

/*==============================================================================

  $Id: drv_osx.c,v 1.5 2004/02/16 17:27:29 raph Exp $

  Driver for output via CoreAudio [MacOS X and Darwin].

==============================================================================*/

/*
        
	Written by Axel Wefers <awe@fruitz-of-dojo.de>
        
        Notes:
        - if HAVE_PTHREAD (config.h) is defined, an extra thread will be created to fill the buffers.
        - if HAVE_PTHREAD is defined, a double buffered method will be used.
        - if an unsupported frequency is selected [md_mixfreq], the native device frequency is used.
        - if mono playback is selected and is not supported by the device, we will emulate mono
          playback.
        - if stereo/surround playback is selected and is not supported by the device, DMODE_STEREO
          will be deactivated automagically.
   
   Bug fixes by Anders F Bjoerklund <afb@algonet.se>
   
   		Changes:
   		- cleared up in the macro jungle, to see what was going on in the code
   		- separated "has ability to use pthreads" from "wish to use pthreads"
   		- moved pthread_cond_wait inside the mutex lock, to avoid a deadlock [!]
   		- added more than one back buffer, currently left at eight or something
        - gave up on whole thread idea, since it stutters if you rescale a window
	    - moved a #pragma mark and added DRV_OSX/MISSING, for non-Darwin compiles
	    - added support for float-point buffers, to avoid the conversion and copying

	Future ideas: (TODO)
	
		- support possibly partially filled buffers from libmikmod
		- clean up the rest of the code and lose even more macros
		- use hardware preferred native size for the sample buffers
		
		- Altivec optimizations of the various vector transforms
	    - provide a PPC64 version of the library, for PowerMac G5

*/


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "mikmod_internals.h"

#ifdef DRV_OSX

//_______________________________________________________________________________________________INCLUDES

#pragma mark INCLUDES

#include <CoreAudio/AudioHardware.h>

#pragma mark -

//________________________________________________________________________________________________DEFINES

#pragma mark DEFINES

#define SOUND_BUFFER_SCALE_8BIT		(1.0f / 128.0f)	  /* CoreAudio requires float input.    */
#define SOUND_BUFFER_SCALE_16BIT	(1.0f / 32768.0f) /* CoreAudio requires float input.    */

#define SOUND_BUFFER_SIZE			4096	/* The buffersize libmikmod will use. */
#define USE_FILL_THREAD				0		/* Use an extra thread to fill the buffers ? */

#ifndef HAVE_PTHREAD
#undef USE_FILL_THREAD
#define USE_FILL_THREAD				0		/* must have pthread supports to use thread */
#endif

#define NUMBER_BACK_BUFFERS			8		/* Number of back buffers for the thread */
#define DEBUG_TRACE_THREADS			0

#pragma mark -

//_________________________________________________________________________________________________MACROS

#pragma mark MACROS

#define CHECK_ERROR(ERRNO, RESULT)	if (RESULT != kAudioHardwareNoError)      		   \
                                        {				         		   \
                                            _mm_errno = ERRNO;			 		   \
                                            return(1);				 		   \
                                        }

#define SET_PROPS()	if (AudioDeviceSetProperty (gSoundDeviceID, NULL, 0, 0,			   \
                                                    kAudioDevicePropertyStreamFormat,		   \
                                                    myPropertySize, &mySoundBasicDescription))	   \
                        {									   \
                            CHECK_ERROR								   \
                            (									   \
                                MMERR_OSX_BAD_PROPERTY,						   \
                                AudioDeviceGetProperty (gSoundDeviceID, 0, 0,			   \
                                                        kAudioDevicePropertyStreamFormat,	   \
                                                        &myPropertySize, &mySoundBasicDescription) \
                            );									   \
                        }

#define SET_STEREO()    switch (mySoundBasicDescription.mChannelsPerFrame) 			   \
                        {									   \
                            case 1: 								   \
                                md_mode &= ~DMODE_STEREO;					   \
                                gBufferMono2Stereo = 0;						   \
                                break;								   \
                            case 2:								   \
                                if (md_mode & DMODE_STEREO)					   \
                                    gBufferMono2Stereo = 0;					   \
                                else								   \
                                    gBufferMono2Stereo = 1;					   \
                                break;								   \
                            default:								   \
                                _mm_errno = MMERR_OSX_SET_STEREO;				   \
                                return(1);							   \
                        }

#define FILL_BUFFER(_buffer,_size)	\
								if (Player_Paused())						   \
                                {								   \
                                    MUTEX_LOCK (vars);						   \
                                    VC_SilenceBytes ((SBYTE*) (_buffer), (ULONG) (_size));		   \
                                    MUTEX_UNLOCK (vars);					   \
                                }								   \
                                else								   \
                                {								   \
                                    MUTEX_LOCK (vars);						   \
                                    VC_WriteBytes ((SBYTE*) (_buffer), (ULONG) ((_size)));		   \
                                    MUTEX_UNLOCK (vars);					   \
                                }


#pragma mark -

//_________________________________________________________________________________________________GLOBALS

#pragma mark GLOBALS

#if USE_FILL_THREAD

static pthread_t		gBufferFillThread;
static pthread_mutex_t		gBufferMutex;
static pthread_cond_t		gBufferCondition;
static Boolean			gExitBufferFillThread = 0;

static int					gCurrentPlayBuffer;
static int					gCurrentFillBuffer;
static unsigned char		*gSoundBackBuffer[NUMBER_BACK_BUFFERS];

#else

static unsigned char 		*gSoundBuffer = NULL;

#endif /* USE_FILL_THREAD */

static AudioDeviceID 		gSoundDeviceID;
static UInt32			gInBufferSize;
static Boolean			gIOProcIsInstalled = 0,
                                gDeviceHasStarted = 0,
                                gBufferMono2Stereo = 0;
static OSStatus			(*gAudioIOProc) (AudioDeviceID, const AudioTimeStamp *,
                                                 const AudioBufferList *, const AudioTimeStamp *,
                                                 AudioBufferList *, const AudioTimeStamp *, void *);

#pragma mark -

//____________________________________________________________________________________FUNCTION_pROTOTYPES

#pragma mark FUNCTION PROTOTYPES

#if USE_FILL_THREAD

static void * OSX_FillBuffer (void *);

#endif /* USE_FILL_THREAD */

static OSStatus OSX_AudioIOProc8Bit (AudioDeviceID, const AudioTimeStamp *,
									const AudioBufferList *, const AudioTimeStamp *, AudioBufferList *,
									const AudioTimeStamp *, void *);
static OSStatus OSX_AudioIOProc16Bit (AudioDeviceID, const AudioTimeStamp *,
									const AudioBufferList *, const AudioTimeStamp *, AudioBufferList *,
									const AudioTimeStamp *, void *);
static OSStatus OSX_AudioIOProcFloat (AudioDeviceID, const AudioTimeStamp *,
									const AudioBufferList *, const AudioTimeStamp *, AudioBufferList *,
									const AudioTimeStamp *, void *);

static BOOL OSX_IsPresent (void);
static BOOL OSX_Init (void);
static void OSX_Exit (void);
static BOOL OSX_PlayStart (void);
static void OSX_PlayStop (void);
static void OSX_Update (void);

#pragma mark -

//_______________________________________________________________________________________OSX_FillBuffer()

#if USE_FILL_THREAD

static void * OSX_FillBuffer (void *theID)
{
    unsigned char *buffer;
    int done;
    
    while (1)
    {
		done = 0;

		while (!done)
		{
	        // shall the thread exit?
	        if (gExitBufferFillThread) pthread_exit (NULL);

			pthread_mutex_lock (&gBufferMutex);
       	
       		if ((gCurrentFillBuffer+1) % NUMBER_BACK_BUFFERS != gCurrentPlayBuffer)
       		{
       		  #if DEBUG_TRACE_THREADS
				fprintf(stderr,"filling buffer #%d\n", gCurrentFillBuffer);
			  #endif

       			buffer = gSoundBackBuffer[gCurrentFillBuffer];
         		if (++gCurrentFillBuffer >= NUMBER_BACK_BUFFERS)
    				gCurrentFillBuffer = 0;	
				
					// fill the buffer...
				FILL_BUFFER (buffer, gInBufferSize);
			}
       		else
       		{
       			// we are caught up now, give it a rest
       			done = 1;
       		}
       		
       		pthread_mutex_unlock (&gBufferMutex);
       	}
       	
		pthread_mutex_lock (&gBufferMutex);
       	
         // wait for the next buffer-fill request...
		pthread_cond_wait (&gBufferCondition, &gBufferMutex);

		pthread_mutex_unlock (&gBufferMutex);
    }
    return (theID);
}

#endif /* USE_FILL_THREAD */

//__________________________________________________________________________________OSX_AudioIOProc8Bit()

static OSStatus OSX_AudioIOProc8Bit (AudioDeviceID 		inDevice,
                                     const AudioTimeStamp 	*inNow,
                                     const AudioBufferList 	*inInputData,
                                     const AudioTimeStamp 	*inInputTime,
                                     AudioBufferList		*outOutputData, 
                                     const AudioTimeStamp	*inOutputTime,
                                     void 			*inClientData)
{
    register float	*myOutBuffer = (float *) outOutputData->mBuffers[0].mData;
    register UInt8	*myInBuffer;
    register UInt32	i;

#if USE_FILL_THREAD

    pthread_mutex_lock (&gBufferMutex);
 
  #if DEBUG_TRACE_THREADS
 	fprintf(stderr,"playing buffer #%d\n", gCurrentPlayBuffer);
  #endif
   
    myInBuffer = (UInt8 *) gSoundBackBuffer[gCurrentPlayBuffer];
 	if (++gCurrentPlayBuffer >= NUMBER_BACK_BUFFERS)
    	gCurrentPlayBuffer = 0;	

    // fill her up, please ...
    pthread_cond_signal (&gBufferCondition);
	
	pthread_mutex_unlock (&gBufferMutex);

#else

	myInBuffer = (UInt8 *) gSoundBuffer;

	FILL_BUFFER(gSoundBuffer, gInBufferSize);

#endif /* USE_FILL_THREAD */

	if (gBufferMono2Stereo)
	{
		for (i = 0; i < SOUND_BUFFER_SIZE >> 1; i++)
		{
			myOutBuffer[1] = myOutBuffer[0] = (*myInBuffer++) * SOUND_BUFFER_SCALE_8BIT;
            myOutBuffer+=2;
        }
    }
    else
    {
    	for (i = 0; i < SOUND_BUFFER_SIZE; i++)
        {
        	*myOutBuffer++ = (*myInBuffer++) * SOUND_BUFFER_SCALE_8BIT;
        }
	}

	return 0;
}

//_________________________________________________________________________________OSX_AudioIOProc16Bit()

static OSStatus OSX_AudioIOProc16Bit (AudioDeviceID 		inDevice,
                                      const AudioTimeStamp 	*inNow,
                                      const AudioBufferList 	*inInputData,
                                      const AudioTimeStamp 	*inInputTime,
                                      AudioBufferList		*outOutputData, 
                                      const AudioTimeStamp	*inOutputTime,
                                      void 			*inClientData)
{
    register float	*myOutBuffer = (float *) outOutputData->mBuffers[0].mData;
    register SInt16	*myInBuffer;
    register UInt32	i;

#if USE_FILL_THREAD

	pthread_mutex_lock (&gBufferMutex);
 	
  #if DEBUG_TRACE_THREADS
 	fprintf(stderr,"playing buffer #%d\n", gCurrentPlayBuffer);
  #endif
                                      
 	myInBuffer = (SInt16 *) gSoundBackBuffer[gCurrentPlayBuffer];
 	if (++gCurrentPlayBuffer >= NUMBER_BACK_BUFFERS)
    	gCurrentPlayBuffer = 0;	

	// ... and check the oil too
    pthread_cond_signal (&gBufferCondition);

	pthread_mutex_unlock (&gBufferMutex);

#else

	myInBuffer = (SInt16 *) gSoundBuffer;

	FILL_BUFFER(gSoundBuffer, gInBufferSize);

#endif /* USE_FILL_THREAD */

	if (gBufferMono2Stereo)
	{
		for (i = 0; i < SOUND_BUFFER_SIZE >> 1; i++)
		{
			myOutBuffer[1] = myOutBuffer[0] = (*myInBuffer++) * SOUND_BUFFER_SCALE_16BIT;
            myOutBuffer+=2;
        }
    }
    else
    {
    	for (i = 0; i < SOUND_BUFFER_SIZE; i++)
        {
        	*myOutBuffer++ = (*myInBuffer++) * SOUND_BUFFER_SCALE_16BIT;
        }
	}

	return 0;
}

//_________________________________________________________________________________OSX_AudioIOProcFloat()

static OSStatus OSX_AudioIOProcFloat (AudioDeviceID 		inDevice,
                                      const AudioTimeStamp 	*inNow,
                                      const AudioBufferList 	*inInputData,
                                      const AudioTimeStamp 	*inInputTime,

⌨️ 快捷键说明

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