📄 w32_a.c
字号:
/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp> Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi> This program is free software; you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA w32_a.c Functions to play sound on the Windows audio driver (Windows 95/98/NT). Modified by Masanao Izumo <mo@goice.co.jp>*/#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#ifdef __W32__#include "interface.h"#endif#include <stdio.h>#include <stdlib.h>#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include <windows.h>extern CRITICAL_SECTION critSect;/*****************************************************************************************************************************/#if defined(__CYGWIN32__) || defined(__MINGW32__)#ifdef HAVE_NEW_MMSYSTEM#include <mmsystem.h>#else/* On cygnus, there is not mmsystem.h for Multimedia API's. * mmsystem.h can not distribute becase of Microsoft Lisence * Then declare some of them here. **/#define WOM_OPEN 0x3BB#define WOM_CLOSE 0x3BC#define WOM_DONE 0x3BD#define WAVE_FORMAT_QUERY 0x0001#define WAVE_ALLOWSYNC 0x0002#define WAVE_FORMAT_PCM 1#define CALLBACK_FUNCTION 0x00030000l#define WAVERR_BASE 32#define WAVE_MAPPER (UINT)-1DECLARE_HANDLE(HWAVEOUT);DECLARE_HANDLE(HWAVE);typedef HWAVEOUT *LPHWAVEOUT;/* Define WAVEHDR, WAVEFORMAT structure */typedef struct wavehdr_tag{ LPSTR lpData; DWORD dwBufferLength; DWORD dwBytesRecorded; DWORD dwUser; DWORD dwFlags; DWORD dwLoops; struct wavehdr_tag *lpNext; DWORD reserved;} WAVEHDR;typedef struct{ WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; WORD wBitsPerSample; WORD cbSize;} WAVEFORMAT, WAVEFORMATEX, *LPWAVEFORMATEX;typedef struct waveoutcaps_tag{ WORD wMid; WORD wPid; UINT vDriverVersion;#define MAXPNAMELEN 32 char szPname[MAXPNAMELEN]; DWORD dwFormats; WORD wChannels; DWORD dwSupport;} WAVEOUTCAPS;typedef WAVEHDR * LPWAVEHDR;typedef WAVEFORMAT * LPWAVEFORMAT;typedef WAVEOUTCAPS * LPWAVEOUTCAPS;typedef UINT MMRESULT;MMRESULT WINAPI waveOutOpen(LPHWAVEOUT, UINT, LPWAVEFORMAT, DWORD, DWORD, DWORD);MMRESULT WINAPI waveOutClose(HWAVEOUT);MMRESULT WINAPI waveOutPrepareHeader(HWAVEOUT, LPWAVEHDR, UINT);MMRESULT WINAPI waveOutUnprepareHeader(HWAVEOUT, LPWAVEHDR, UINT);MMRESULT WINAPI waveOutWrite(HWAVEOUT, LPWAVEHDR, UINT);UINT WINAPI waveOutGetNumDevs(void);MMRESULT WINAPI waveOutReset(HWAVEOUT);MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);MMRESULT WINAPI waveOutGetDevCapsA(UINT, LPWAVEOUTCAPS, UINT);#define waveOutGetDevCaps waveOutGetDevCapsAMMRESULT WINAPI waveOutGetID(HWAVEOUT, UINT*);#endif#endif /* __CYGWIN32__ *//*****************************************************************************************************************************/#include "timidity.h"#include "output.h"#include "controls.h"#include "timer.h"#include "instrum.h"#include "playmidi.h"#include "mblock.h"#include "miditrace.h"#include "interface.h"#define NOT !static int open_output (void); /* 0=success, 1=warning, -1=fatal error */static void close_output (void);static int output_data (char * Data, int32 Size);static int acntl (int request, void * arg);#if defined ( IA_W32GUI ) || defined ( IA_W32G_SYN )//#if defined ( IA_W32GUI )volatile int data_block_bits = DEFAULT_AUDIO_BUFFER_BITS;volatile int data_block_num = 64;#endif#define DATA_BLOCK_SIZE (4 * AUDIO_BUFFER_SIZE)#define DATA_BLOCK_NUM (dpm.extra_param[0])struct MMBuffer{ int Number; int Prepared; // Non-zero if this buffer has been prepared. HGLOBAL hData; void * Data; HGLOBAL hHead; WAVEHDR * Head; struct MMBuffer * Next;};static struct MMBuffer * Buffers;static volatile struct MMBuffer * FreeBuffers;static volatile int NumBuffersInUse;static HWAVEOUT hDevice;static int BufferDelay; // in millisecondsstatic const int AllowSynchronousWaveforms = 1;/*****************************************************************************************************************************/static void CALLBACK OnPlaybackEvent (HWAVE hWave, UINT Msg, DWORD UserData, DWORD Param1, DWORD Param2);static void BufferPoolReset (void);static struct MMBuffer * GetBuffer ();static void PutBuffer (struct MMBuffer *);static const char * MMErrorMessage (MMRESULT Result);static void WaitForBuffer (int WaitForAllBuffers);/*****************************************************************************************************************************/static int detect(void);#define dpm w32_play_modePlayMode dpm ={ DEFAULT_RATE, PE_16BIT | PE_SIGNED, PF_PCM_STREAM|PF_CAN_TRACE|PF_BUFF_FRAGM_OPT, -1, {32}, "Windows audio driver", 'd', NULL, open_output, close_output, output_data, acntl, detect};/*****************************************************************************************************************************/static int open_output(void){ int i; int j; int IsMono; WAVEFORMATEX wf; WAVEOUTCAPS woc; MMRESULT Result; UINT DeviceID; if (dpm.extra_param[0] < 8) { ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Too small -B option: %d", dpm.extra_param[0]); dpm.extra_param[0] = 8; }/** Check if there is at least one audio device. **/ if (waveOutGetNumDevs() == 0) { ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "No audio devices present!"); return -1; }/** They can't mean these. **/ dpm.encoding &= ~(PE_ULAW | PE_ALAW | PE_BYTESWAP); if (dpm.encoding & PE_16BIT || dpm.encoding & PE_24BIT) dpm.encoding |= PE_SIGNED; else dpm.encoding &= ~PE_SIGNED; IsMono = (dpm.encoding & PE_MONO); memset(&wf, 0, sizeof(wf)); wf.wFormatTag = WAVE_FORMAT_PCM; wf.nChannels = IsMono ? 1 : 2; wf.nSamplesPerSec = dpm.rate; i = dpm.rate; j = 1; if (!IsMono) { i *= 2; j *= 2; } if (dpm.encoding & PE_24BIT) { i *= 3; j *= 3; } else if (dpm.encoding & PE_16BIT) { i *= 2; j *= 2; } wf.nAvgBytesPerSec = i; wf.nBlockAlign = j; if (dpm.encoding & PE_24BIT) { wf.wBitsPerSample = 24; } else if (dpm.encoding & PE_16BIT) { wf.wBitsPerSample = 16; } else { wf.wBitsPerSample = 8; } wf.cbSize = sizeof(WAVEFORMAT);/** Open the device. **/ { CHAR b[256]; wsprintf(b, "Opening device...\n"); OutputDebugString(b); } hDevice = 0; if (AllowSynchronousWaveforms) Result = waveOutOpen(&hDevice, WAVE_MAPPER, (LPWAVEFORMATEX) &wf, (DWORD) OnPlaybackEvent, 0, CALLBACK_FUNCTION | WAVE_ALLOWSYNC); else Result = waveOutOpen(&hDevice, WAVE_MAPPER, (LPWAVEFORMATEX) &wf, (DWORD) OnPlaybackEvent, 0, CALLBACK_FUNCTION); if (Result) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't open audio device: " "encoding=<%s>, rate=<%d>, ch=<%d>: %s", output_encoding_string(dpm.encoding), dpm.rate, wf.nChannels, MMErrorMessage(Result)); return -1; } else { CHAR b[256]; wsprintf(b, "Device opened.\n"); OutputDebugString(b); }/** Get the device ID. **/ DeviceID = 0; waveOutGetID(hDevice, &DeviceID);/** Get the device capabilities. **/ memset(&woc, 0, sizeof(WAVEOUTCAPS)); Result = waveOutGetDevCaps(DeviceID, &woc, sizeof(WAVEOUTCAPS)); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Device ID: %d", DeviceID); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Manufacture ID: %d", woc.wMid); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Product ID: %d", woc.wPid); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Driver version: %d", woc.vDriverVersion); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Product name: %s", woc.szPname); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Formats supported: 0x%08X", woc.dwFormats); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Max. channels: %d", woc.wChannels); ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Supported features: 0x%08X", woc.dwSupport);/** Calculate the buffer delay. **/ BufferDelay = AUDIO_BUFFER_SIZE; if (NOT (dpm.encoding & PE_MONO)) BufferDelay *= 2; if (dpm.encoding & PE_24BIT) BufferDelay *= 3; else if (dpm.encoding & PE_16BIT) BufferDelay *= 2; BufferDelay = (BufferDelay * 1000) / dpm.rate;/** Create the buffer pool. **/ Buffers = (struct MMBuffer *) safe_malloc(DATA_BLOCK_NUM * sizeof(struct MMBuffer)); for (i = 0; i < DATA_BLOCK_NUM; i++) { struct MMBuffer * b; b = &Buffers[i]; b->hData = GlobalAlloc(GMEM_ZEROINIT, DATA_BLOCK_SIZE); b->Data = GlobalLock (b->hData); b->hHead = GlobalAlloc(GMEM_ZEROINIT, sizeof(WAVEHDR)); b->Head = GlobalLock (b->hHead); } BufferPoolReset();/** Set the file descriptor. **/ dpm.fd = 0; return 0;}/*****************************************************************************************************************************/static void close_output(void){ int i; if (dpm.fd != -1) { WaitForBuffer(1); { CHAR b[256]; wsprintf(b, "Closing device...\n"); OutputDebugString(b); } waveOutReset(hDevice); waveOutClose(hDevice); { CHAR b[256]; wsprintf(b, "Device closed.\n"); OutputDebugString(b); } /** Free all buffers. **/ for (i = 0; i < DATA_BLOCK_NUM; i++) { struct MMBuffer * block; block = &Buffers[i];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -