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

📄 audio.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * Wine Driver for aRts Sound Server *   http://www.arts-project.org * * Copyright 1994 Martin Ayotte *           1999 Eric Pouech (async playing in waveOut/waveIn) *	     2000 Eric Pouech (loops in waveOut) *	     2002 Chris Morgan (aRts version of this file) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 *//* NOTE: *    with arts we cannot stop the audio that is already in *    the servers buffer, so to reduce delays during starting *    and stoppping of audio streams adjust the *    audio buffer size in the kde control center or in the *    artsd startup script * * FIXME: *	pause in waveOut does not work correctly in loop mode * * TODO: *	implement wave-in support with artsc *//*#define EMULATE_SB16*/#include "config.h"#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <string.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <fcntl.h>#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winerror.h"#include "wine/winuser16.h"#include "mmddk.h"#include "dsound.h"#include "dsdriver.h"#include "arts.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(wave);#ifdef HAVE_ARTS#include <artsc.h>#define BUFFER_SIZE		16 * 1024#define SPACE_THRESHOLD 	5 * 1024#define MAX_WAVEOUTDRV 	(10)/* state diagram for waveOut writing: * * +---------+-------------+---------------+---------------------------------+ * |  state  |  function   |     event     |            new state	     | * +---------+-------------+---------------+---------------------------------+ * |	     | open()	   |		   | STOPPED		       	     | * | PAUSED  | write()	   | 		   | PAUSED		       	     | * | STOPPED | write()	   | <thrd create> | PLAYING		  	     | * | PLAYING | write()	   | HEADER        | PLAYING		  	     | * | (other) | write()	   | <error>       |		       		     | * | (any)   | pause()	   | PAUSING	   | PAUSED		       	     | * | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) | * | (any)   | reset()	   | RESETTING     | STOPPED		      	     | * | (any)   | close()	   | CLOSING	   | CLOSED		      	     | * +---------+-------------+---------------+---------------------------------+ *//* states of the playing device */#define	WINE_WS_PLAYING		0#define	WINE_WS_PAUSED		1#define	WINE_WS_STOPPED		2#define WINE_WS_CLOSED		3/* events to be send to device */enum win_wm_message {    WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER,    WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING};typedef struct {    enum win_wm_message 	msg;	/* message identifier */    DWORD	                param;  /* parameter for this message */    HANDLE	                hEvent;	/* if message is synchronous, handle of event for synchro */} RING_MSG;/* implement an in-process message ring for better performance * (compared to passing thru the server) * this ring will be used by the input (resp output) record (resp playback) routine */#define ARTS_RING_BUFFER_INCREMENT      64typedef struct {    RING_MSG			* messages;    int                         ring_buffer_size;    int				msg_tosave;    int				msg_toget;    HANDLE			msg_event;    CRITICAL_SECTION		msg_crst;} ARTS_MSG_RING;typedef struct {    volatile int		state;			/* one of the WINE_WS_ manifest constants */    WAVEOPENDESC		waveDesc;    WORD			wFlags;    PCMWAVEFORMAT		format;    WAVEOUTCAPSA		caps;    /* arts information */    arts_stream_t 		play_stream;		/* the stream structure we get from arts when opening a stream for playing */    DWORD                       dwBufferSize;           /* size of whole buffer in bytes */    char*			sound_buffer;    long			buffer_size;    DWORD			volume_left;		/* volume control information */    DWORD			volume_right;    LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */    LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */    DWORD			dwPartialOffset;	/* Offset of not yet written bytes in lpPlayPtr */    LPWAVEHDR			lpLoopPtr;              /* pointer of first buffer in loop, if any */    DWORD			dwLoops;		/* private copy of loop counter */    DWORD			dwPlayedTotal;		/* number of bytes actually played since opening */    DWORD                       dwWrittenTotal;         /* number of bytes written to the audio device since opening */    /* synchronization stuff */    HANDLE			hStartUpEvent;    HANDLE			hThread;    DWORD			dwThreadID;    ARTS_MSG_RING		msgRing;} WINE_WAVEOUT;static WINE_WAVEOUT	WOutDev   [MAX_WAVEOUTDRV];static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid);/* These strings used only for tracing */static const char *wodPlayerCmdString[] = {    "WINE_WM_PAUSING",    "WINE_WM_RESTARTING",    "WINE_WM_RESETTING",    "WINE_WM_HEADER",    "WINE_WM_UPDATE",    "WINE_WM_BREAKLOOP",    "WINE_WM_CLOSING",};/*======================================================================* *                  Low level WAVE implementation			* *======================================================================*//* Volume functions derived from Alsaplayer source *//* length is the number of 16 bit samples */void volume_effect16(void *bufin, void* bufout, int length, int left,		int right, int 	nChannels){  short *d_out = (short *)bufout;  short *d_in = (short *)bufin;  int i, v;/*  TRACE("length == %d, nChannels == %d\n", length, nChannels);*/  if (right == -1) right = left;  for(i = 0; i < length; i+=(nChannels))  {    v = (int) ((*(d_in++) * left) / 100);    *(d_out++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);    if(nChannels == 2)    {      v = (int) ((*(d_in++) * right) / 100);      *(d_out++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);    }  }}/* length is the number of 8 bit samples */void volume_effect8(void *bufin, void* bufout, int length, int left,		int right, int 	nChannels){  BYTE *d_out = (BYTE *)bufout;  BYTE *d_in = (BYTE *)bufin;  int i, v;/*  TRACE("length == %d, nChannels == %d\n", length, nChannels);*/  if (right == -1) right = left;  for(i = 0; i < length; i+=(nChannels))  {    v = (BYTE) ((*(d_in++) * left) / 100);    *(d_out++) = (v>255) ? 255 : ((v<0) ? 0 : v);    if(nChannels == 2)    {      v = (BYTE) ((*(d_in++) * right) / 100);      *(d_out++) = (v>255) ? 255 : ((v<0) ? 0 : v);    }  }}/****************************************************************** *		ARTS_CloseDevice * */void		ARTS_CloseDevice(WINE_WAVEOUT* wwo){  arts_close_stream(wwo->play_stream); 	/* close the arts stream */  wwo->play_stream = (arts_stream_t*)-1;  /* free up the buffer we use for volume and reset the size */  if(wwo->sound_buffer)    HeapFree(GetProcessHeap(), 0, wwo->sound_buffer);  wwo->buffer_size = 0;}/****************************************************************** *		ARTS_Init */static int	ARTS_Init(void){  return arts_init();  /* initialize arts and return errorcode */}/****************************************************************** *		ARTS_WaveClose */LONG		ARTS_WaveClose(void){    int iDevice;    /* close all open devices */    for(iDevice = 0; iDevice < MAX_WAVEOUTDRV; iDevice++)    {      if(WOutDev[iDevice].play_stream != (arts_stream_t*)-1)      {        ARTS_CloseDevice(&WOutDev[iDevice]);      }    }    arts_free();    /* free up arts */    return 1;}/****************************************************************** *		ARTS_WaveInit * * Initialize internal structures from ARTS server info */LONG ARTS_WaveInit(void){    int 	i;    int		errorcode;    TRACE("called\n");    if ((errorcode = ARTS_Init()) < 0)    {	ERR("arts_init() failed (%d)\n", errorcode);	return -1;    }    /* initialize all device handles to -1 */    for (i = 0; i < MAX_WAVEOUTDRV; ++i)    {	WOutDev[i].play_stream = (arts_stream_t*)-1;	memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps)); /* zero out							caps values */    /* FIXME: some programs compare this string against the content of the registry     * for MM drivers. The names have to match in order for the program to work     * (e.g. MS win9x mplayer.exe)     */#ifdef EMULATE_SB16    	WOutDev[i].caps.wMid = 0x0002;    	WOutDev[i].caps.wPid = 0x0104;    	strcpy(WOutDev[i].caps.szPname, "SB16 Wave Out");#else    	WOutDev[i].caps.wMid = 0x00FF; 	/* Manufac ID */    	WOutDev[i].caps.wPid = 0x0001; 	/* Product ID */    /*    strcpy(WOutDev[i].caps.szPname, "OpenSoundSystem WAVOUT Driver");*/    	strcpy(WOutDev[i].caps.szPname, "CS4236/37/38");#endif    	WOutDev[i].caps.vDriverVersion = 0x0100;    	WOutDev[i].caps.dwFormats = 0x00000000;    	WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;    	WOutDev[i].caps.wChannels = 2;    	WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;    	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;	WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;    }    return 0;}/****************************************************************** *		ARTS_InitRingMessage * * Initialize the ring of messages for passing between driver's caller and playback/record * thread */static int ARTS_InitRingMessage(ARTS_MSG_RING* mr){    mr->msg_toget = 0;    mr->msg_tosave = 0;    mr->msg_event = CreateEventA(NULL, FALSE, FALSE, NULL);    mr->ring_buffer_size = ARTS_RING_BUFFER_INCREMENT;    mr->messages = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,mr->ring_buffer_size * sizeof(RING_MSG));    InitializeCriticalSection(&mr->msg_crst);    return 0;}/****************************************************************** *		ARTS_DestroyRingMessage * */static int ARTS_DestroyRingMessage(ARTS_MSG_RING* mr){    CloseHandle(mr->msg_event);    HeapFree(GetProcessHeap(),0,mr->messages);    DeleteCriticalSection(&mr->msg_crst);    return 0;}/****************************************************************** *		ARTS_AddRingMessage * * Inserts a new message into the ring (should be called from DriverProc derivated routines) */static int ARTS_AddRingMessage(ARTS_MSG_RING* mr, enum win_wm_message msg, DWORD param, BOOL wait){    HANDLE      hEvent = INVALID_HANDLE_VALUE;    EnterCriticalSection(&mr->msg_crst);    if ((mr->msg_toget == ((mr->msg_tosave + 1) % mr->ring_buffer_size)))    {	mr->ring_buffer_size += ARTS_RING_BUFFER_INCREMENT;	TRACE("mr->ring_buffer_size=%d\n",mr->ring_buffer_size);	mr->messages = HeapReAlloc(GetProcessHeap(),0,mr->messages, mr->ring_buffer_size * sizeof(RING_MSG));    }    if (wait)    {        hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);        if (hEvent == INVALID_HANDLE_VALUE)        {            ERR("can't create event !?\n");            LeaveCriticalSection(&mr->msg_crst);            return 0;        }        if (mr->msg_toget != mr->msg_tosave && mr->messages[mr->msg_toget].msg != WINE_WM_HEADER)            FIXME("two fast messages in the queue!!!!\n");        /* fast messages have to be added at the start of the queue */        mr->msg_toget = (mr->msg_toget + mr->ring_buffer_size - 1) % mr->ring_buffer_size;        mr->messages[mr->msg_toget].msg = msg;        mr->messages[mr->msg_toget].param = param;        mr->messages[mr->msg_toget].hEvent = hEvent;    }    else    {        mr->messages[mr->msg_tosave].msg = msg;        mr->messages[mr->msg_tosave].param = param;        mr->messages[mr->msg_tosave].hEvent = INVALID_HANDLE_VALUE;        mr->msg_tosave = (mr->msg_tosave + 1) % mr->ring_buffer_size;    }    LeaveCriticalSection(&mr->msg_crst);    SetEvent(mr->msg_event);    /* signal a new message */    if (wait)    {        /* wait for playback/record thread to have processed the message */        WaitForSingleObject(hEvent, INFINITE);        CloseHandle(hEvent);    }    return 1;}/****************************************************************** *		ARTS_RetrieveRingMessage * * Get a message from the ring. Should be called by the playback/record thread. */static int ARTS_RetrieveRingMessage(ARTS_MSG_RING* mr,                                   enum win_wm_message *msg, DWORD *param, HANDLE *hEvent){    EnterCriticalSection(&mr->msg_crst);    if (mr->msg_toget == mr->msg_tosave) /* buffer empty ? */    {        LeaveCriticalSection(&mr->msg_crst);	return 0;    }    *msg = mr->messages[mr->msg_toget].msg;    mr->messages[mr->msg_toget].msg = 0;    *param = mr->messages[mr->msg_toget].param;    *hEvent = mr->messages[mr->msg_toget].hEvent;    mr->msg_toget = (mr->msg_toget + 1) % mr->ring_buffer_size;    LeaveCriticalSection(&mr->msg_crst);    return 1;}/*======================================================================* *                  Low level WAVE OUT implementation			* *======================================================================*//************************************************************************** * 			wodNotifyClient			[internal] */static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2){    TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2);    switch (wMsg) {    case WOM_OPEN:    case WOM_CLOSE:    case WOM_DONE:	if (wwo->wFlags != DCB_NULL &&	    !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags, (HDRVR)wwo->waveDesc.hWave,			    wMsg, wwo->waveDesc.dwInstance, dwParam1, dwParam2)) {	    WARN("can't notify client !\n");	    return MMSYSERR_ERROR;	}	break;    default:	FIXME("Unknown callback message %u\n", wMsg);        return MMSYSERR_INVALPARAM;    }    return MMSYSERR_NOERROR;}/************************************************************************** * 				wodUpdatePlayedTotal	[internal] *

⌨️ 快捷键说明

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