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

📄 audio.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 4 页
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * Wine Driver for jack Sound Server *   http://jackit.sourceforge.net * * Copyright 1994 Martin Ayotte * Copyright 1999 Eric Pouech (async playing in waveOut/waveIn) * Copyright 2000 Eric Pouech (loops in waveOut) * Copyright 2002 Chris Morgan (jack 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 *//* * TODO: *  implement audio stream resampling for any arbitrary frequenty *    right now we use the winmm layer to do resampling although it would  *    be nice to have a full set of algorithms to choose from based on cpu  *    time *  implement wave-in support with jack * * FIXME: *  pause in waveOut during loop is not handled correctly */#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 "jack.h"#include "wine/debug.h"#ifdef HAVE_JACK_JACK_H#include <jack/jack.h>#endifWINE_DEFAULT_DEBUG_CHANNEL(wave);#ifdef HAVE_JACK_JACK_H#define MAKE_FUNCPTR(f) static typeof(f) * fp_##f = NULL;/* Function pointers for dynamic loading of libjack *//* these are prefixed with "fp_", ie. "fp_jack_client_new" */MAKE_FUNCPTR(jack_activate);MAKE_FUNCPTR(jack_connect);MAKE_FUNCPTR(jack_client_new);MAKE_FUNCPTR(jack_client_close);MAKE_FUNCPTR(jack_deactivate);MAKE_FUNCPTR(jack_set_process_callback);MAKE_FUNCPTR(jack_set_buffer_size_callback);MAKE_FUNCPTR(jack_set_sample_rate_callback);MAKE_FUNCPTR(jack_on_shutdown);MAKE_FUNCPTR(jack_get_sample_rate);MAKE_FUNCPTR(jack_port_register);MAKE_FUNCPTR(jack_port_get_buffer);MAKE_FUNCPTR(jack_get_ports);MAKE_FUNCPTR(jack_port_name);#undef MAKE_FUNCPTR/* define the below to work around a bug in jack where closing a port *//* takes a very long time, so to get around this we actually don't *//* close the port when the device is closed but instead mark the *//* corresponding device as unused */#define JACK_CLOSE_HACK    1typedef jack_default_audio_sample_t sample_t;typedef jack_nframes_t nframes_t;/* only allow 10 output devices through this driver, this ought to be adequate */#define MAX_WAVEOUTDRV  (10)#define MAX_WAVEINDRV   (1)/* 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    3typedef struct {    volatile int      state;      /* one of the WINE_WS_ manifest constants */    WAVEOPENDESC      waveDesc;    WORD              wFlags;    PCMWAVEFORMAT     format;    WAVEOUTCAPSA      caps;    WORD              wDevID;    jack_port_t*      out_port_l;   /* ports for left and right channels */    jack_port_t*      out_port_r;    jack_client_t*    client;    long              sample_rate;        /* jack server sample rate */#if JACK_CLOSE_HACK    BOOL              in_use; /* TRUE if this device is in use */#endif    char*             sound_buffer;    unsigned long     buffer_size;    DWORD             volume_left;    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 jack since opening */    DWORD	      bytesInJack; /* bytes that we wrote during the previous JACK_Callback() */    DWORD	      tickCountMS; /* time in MS of last JACK_Callback() */    /* synchronization stuff */    CRITICAL_SECTION    access_crst;} WINE_WAVEOUT;typedef struct {    volatile int    state;    WAVEOPENDESC    waveDesc;    WORD            wFlags;    PCMWAVEFORMAT   format;    LPWAVEHDR       lpQueuePtr;    DWORD           dwTotalRecorded;    WAVEINCAPSA     caps;    BOOL            bTriggerSupport;    /* synchronization stuff */    CRITICAL_SECTION    access_crst;} WINE_WAVEIN;static WINE_WAVEOUT WOutDev   [MAX_WAVEOUTDRV];static WINE_WAVEIN  WInDev    [MAX_WAVEINDRV ];static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid);static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo);static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force);static int JACK_OpenDevice(WINE_WAVEOUT* wwo);#if JACK_CLOSE_HACKstatic void	JACK_CloseDevice(WINE_WAVEOUT* wwo, BOOL close_client);#elsestatic void	JACK_CloseDevice(WINE_WAVEOUT* wwo);#endif/*======================================================================* *                  Low level WAVE implementation			* *======================================================================*/#define SAMPLE_MAX_16BIT  32767.0f/* Alsaplayer function that applies volume changes to a buffer *//* (C) Andy Lo A Foe *//* Length is in terms of 32 bit samples */void volume_effect32(void *buffer, int length, int left, int right){        short *data = (short *)buffer;        int i, v;            if (right == -1) right = left;         for(i = 0; i < length; i++) {                v = (int) ((*(data) * left) / 100);                *(data++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);                v = (int) ((*(data) * right) / 100);                *(data++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);        }}/* move 16 bit mono/stereo to 16 bit stereo */void sample_move_d16_d16(short *dst, short *src,                  unsigned long nsamples, int nChannels){  while(nsamples--)  {    *dst = *src;    dst++;    if(nChannels == 2) src++;    *dst = *src;    dst++;    src++;  }}/* convert from 16 bit to floating point *//* allow for copying of stereo data with alternating left/right *//* channels to a buffer that will hold a single channel stream *//* nsamples is in terms of 16bit samples *//* src_skip is in terms of 16bit samples */void sample_move_d16_s16 (sample_t *dst, short *src,                        unsigned long nsamples, unsigned long src_skip){  /* ALERT: signed sign-extension portability !!! */  while (nsamples--)  {    *dst = (*src) / SAMPLE_MAX_16BIT;    dst++;    src += src_skip;  }}       /* fill dst buffer with nsamples worth of silence */void sample_silence_dS (sample_t *dst, unsigned long nsamples){  /* ALERT: signed sign-extension portability !!! */  while (nsamples--)  {    *dst = 0;    dst++;  }}       /****************************************************************** *    JACK_callback *//* everytime the jack server wants something from us it calls this function, so we either deliver it some sound to play or deliver it nothing to play */int JACK_callback (nframes_t nframes, void *arg){  sample_t* out_l;  sample_t* out_r;  WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;  TRACE("wDevID: %d, nframes %ld\n", wwo->wDevID, nframes);  if(!wwo->client)    ERR("client is closed, this is weird...\n");      out_l = (sample_t *) fp_jack_port_get_buffer(wwo->out_port_l,       nframes);  out_r = (sample_t *) fp_jack_port_get_buffer(wwo->out_port_r,       nframes);  EnterCriticalSection(&wwo->access_crst);  if(wwo->state == WINE_WS_PLAYING)  {    DWORD jackBytesAvailableThisCallback = sizeof(sample_t) * nframes;    DWORD jackBytesLeft = sizeof(sample_t) * nframes;    DWORD inputBytesAvailable; /* number of bytes we have from the app, after conversion to 16bit stereo */    DWORD jackBytesToWrite; /* number of bytes we are going to write out, after conversion */    DWORD bytesInput; /* the number of bytes from the app */    DWORD appBytesToWrite; /* number of bytes from the app we are going to write */    long written = 0;    char* buffer;#if JACK_CLOSE_HACK    if(wwo->in_use == FALSE)    {      /* output silence if nothing is being outputted */      sample_silence_dS(out_l, nframes);      sample_silence_dS(out_r, nframes);      return 0;    }#endif    TRACE("wwo.state == WINE_WS_PLAYING\n");    /* see if our buffer is large enough for the data we are writing */    /* ie. Buffer_size < (bytes we already wrote + bytes we are going to write in this loop) */    if(wwo->buffer_size < jackBytesAvailableThisCallback)    {      ERR("for some reason JACK_BufSize() didn't allocate enough memory\n");      ERR("allocated %ld bytes, need %ld bytes\n", wwo->buffer_size,       jackBytesAvailableThisCallback);      LeaveCriticalSection(&wwo->access_crst);      return 0;    }    /* while we have jackBytesLeft and a wave header to be played */    while(jackBytesLeft && wwo->lpPlayPtr)    {      /* find the amount of audio to be played at this time */      bytesInput = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;      inputBytesAvailable = bytesInput;      /* calculate inputBytesAvailable based on audio format conversion */      if(wwo->format.wf.nChannels == 1)        inputBytesAvailable<<=1; /* multiply by two for mono->stereo conversion */      /* find the minimum of the inputBytesAvailable and the space available */      jackBytesToWrite = min(jackBytesLeft, inputBytesAvailable);      /* calculate appBytesToWrite based on audio format conversion */      appBytesToWrite = jackBytesToWrite;      if(wwo->format.wf.nChannels == 1)        appBytesToWrite>>=1; /* divide by two for stereo->mono conversion */      TRACE("jackBytesToWrite == %ld, appBytesToWrite == %ld\n", jackBytesToWrite, appBytesToWrite);      buffer = wwo->lpPlayPtr->lpData + wwo->dwPartialOffset;      /* convert from mono to stereo if necessary */      /* otherwise just memcpy to the output buffer */      if(wwo->format.wf.nChannels == 1)      {        sample_move_d16_d16((short*)wwo->sound_buffer +((jackBytesAvailableThisCallback - jackBytesLeft) / sizeof(short)),                 (short*)buffer, jackBytesToWrite, wwo->format.wf.nChannels);      } else /* just copy the memory over */      {        memcpy(wwo->sound_buffer + (jackBytesAvailableThisCallback - jackBytesLeft),                  buffer, jackBytesToWrite);      }      /* advance to the next wave header if possible, or advance pointer */      /* inside of the current header if we haven't completed it */      if(appBytesToWrite == bytesInput)      {        wodHelper_PlayPtrNext(wwo);            /* we wrote the whole waveheader, skip to the next one*/      }      else      {        wwo->dwPartialOffset+=appBytesToWrite; /* else advance by the bytes we took in to write */      }      written+=appBytesToWrite; /* add on what we wrote */      jackBytesLeft-=jackBytesToWrite; /* take away what was written in terms of output bytes */    }    wwo->tickCountMS = GetTickCount();    /* record the current time */    wwo->dwWrittenTotal+=written; /* update states on wave device */    wwo->dwPlayedTotal+=wwo->bytesInJack; /* we must have finished with the last bytes or we wouldn't be back inside of this callback again... */    wwo->bytesInJack = written; /* record the bytes inside of jack */    /* Now that we have finished filling the buffer either until it is full or until */    /* we have run out of application sound data to process, apply volume and output */    /* the audio to the jack server */    /* apply volume to the buffer */    /* NOTE: buffer_size >> 2 to convert from bytes to 16 bit stereo(32bit) samples */    volume_effect32(wwo->sound_buffer, (jackBytesAvailableThisCallback - jackBytesLeft)>>2, wwo->volume_left,        wwo->volume_right);    /* convert from stereo 16 bit to single channel 32 bit float */    /* for each jack server channel */    /* NOTE: we skip over two sample since we want to only get either the left or right channel */    sample_move_d16_s16(out_l, (short*)wwo->sound_buffer, (jackBytesAvailableThisCallback - jackBytesLeft)>>2, 2);    sample_move_d16_s16(out_r, (short*)wwo->sound_buffer + 1,        (jackBytesAvailableThisCallback - jackBytesLeft)>>2, 2);    /* see if we still have jackBytesLeft here, if we do that means that we    ran out of wave data to play and had a buffer underrun, fill in    the rest of the space with zero bytes */    if(jackBytesLeft)    {      ERR("buffer underrun of %ld bytes\n", jackBytesLeft);      sample_silence_dS(out_l + ((jackBytesAvailableThisCallback - jackBytesLeft) / sizeof(sample_t)), jackBytesLeft / sizeof(sample_t));      sample_silence_dS(out_r + ((jackBytesAvailableThisCallback - jackBytesLeft) / sizeof(sample_t)), jackBytesLeft / sizeof(sample_t));    }  }  else if(wwo->state == WINE_WS_PAUSED ||     wwo->state == WINE_WS_STOPPED ||    wwo->state == WINE_WS_CLOSED)  {      /* output silence if nothing is being outputted */

⌨️ 快捷键说明

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