📄 audriv_mme.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*/#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include <stdio.h>#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include <mme/mme_api.h>#include "timidity.h"#include "aenc.h"#include "audriv.h"#include "timer.h"#define DATA_BLOCK_SIZE 2048#define DATA_BLOCK_NUM 48#define AUDIO_CLOSE_ID -1#define IS_AUDIO_PLAY_OPEN (play_wave_format && play_wave_format->hWave != AUDIO_CLOSE_ID)#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])struct wave_format_t{ HWAVE hWave; PCMWAVEFORMAT format; WAVEHDR waveHdr; UINT DevID;};static struct wave_format_t *play_wave_format = NULL;static MMTIME *wave_time_info = NULL;static LPDWORD lpdword_buff = NULL;static LPWAVEOUTCAPS wave_out_caps = NULL;#define AUDRIV_WRITE 1struct data_block_t{ LPSTR data; int data_start; int data_size; int blockno; int in_use; /* 0, AUDRIV_WRITE */ struct data_block_t *next;};static struct data_block_t all_data_block[DATA_BLOCK_NUM];static struct data_block_t *free_data_block;static int data_block_length; /* used data block length */void (* audriv_error_handler)(const char *errmsg) = NULL;static Bool audio_write_noblocking = False;static double play_start_time;static long play_counter, reset_samples;static int output_port = AUDRIV_OUTPUT_SPEAKER;char audriv_errmsg[BUFSIZ];static const char *mme_mmsyserr_code_string[] ={ "no error", "unspecified error", "device ID out of range", "driver failed enable", "device already allocated", "device handle is invalid", "no device driver present", "memory allocation error", "function isn't supported", "error value out of range", "invalid flag passed", "invalid parameter passed", "handle being used", "simultaneously on another", "thread (eg callback)", "Specified alias not found in WIN.INI",};static const char *mme_waverr_code_sring[] ={ "unsupported wave format", "still something playing", "header not prepared", "device is synchronous", "Device in use", "Device in use",};static const char *mme_midierr_code_sring[] ={ "header not prepared", "still something playing", "no current map", "hardware is still busy", "port no longer connected", "invalid setup",};static const char *mme_error_code_string(MMRESULT err_code){ if(err_code >= TIMERR_BASE) { switch(err_code) { case TIMERR_NOCANDO: return "request not completed"; case TIMERR_STRUCT: return "time struct size"; } return ""; } if(err_code >= MIDIERR_BASE) { err_code -= MIDIERR_BASE; if(err_code > ARRAY_SIZE(mme_midierr_code_sring)) return ""; return mme_midierr_code_sring[err_code]; } if(err_code >= WAVERR_BASE) { err_code -= WAVERR_BASE; if(err_code > ARRAY_SIZE(mme_waverr_code_sring)) return ""; return mme_waverr_code_sring[err_code]; } if(err_code > ARRAY_SIZE(mme_mmsyserr_code_string)) return ""; return mme_mmsyserr_code_string[err_code];}static void audriv_err(const char *msg){ strncpy(audriv_errmsg, msg, sizeof(audriv_errmsg) - 1); if(audriv_error_handler != NULL) audriv_error_handler(audriv_errmsg);}static struct data_block_t *new_data_block(){ struct data_block_t *p; if(free_data_block == NULL) return NULL; p = free_data_block; free_data_block = free_data_block->next; data_block_length++; p->next = NULL; p->data_start = 0; p->data_size = DATA_BLOCK_SIZE; return p;}static void reuse_data_block(int blockno){ if(all_data_block[blockno].in_use) { all_data_block[blockno].next = free_data_block; all_data_block[blockno].in_use = 0; free_data_block = all_data_block + blockno; data_block_length--; }}static void reset_data_block(void){ int i; all_data_block[0].blockno = 0; all_data_block[0].next = all_data_block + 1; for(i = 1; i < DATA_BLOCK_NUM - 1; i++) { all_data_block[i].blockno = i; all_data_block[i].in_use = 0; all_data_block[i].next = all_data_block + i + 1; } all_data_block[i].blockno = i; all_data_block[i].in_use = 0; all_data_block[i].next = NULL; free_data_block = all_data_block; data_block_length = 0;}Bool audriv_setup_audio(void)/* オ〖ディオの介袋步を乖いますˉ * 喇根した眷圭は True を·己窃した眷圭は False を手しますˉ */{ int i; play_wave_format = (struct wave_format_t *) mmeAllocMem(sizeof(struct wave_format_t)); if(play_wave_format == NULL) { audriv_err(mme_error_code_string(MMSYSERR_NOMEM)); return False; } play_wave_format->DevID = 0; wave_time_info = (MMTIME *)mmeAllocMem(sizeof(MMTIME)); if(wave_time_info == NULL) { audriv_free_audio(); audriv_err(mme_error_code_string(MMSYSERR_NOMEM)); return False; } lpdword_buff = (LPDWORD)mmeAllocMem(sizeof(DWORD)); if(lpdword_buff == NULL) { audriv_free_audio(); audriv_err(mme_error_code_string(MMSYSERR_NOMEM)); return False; } wave_out_caps = (LPWAVEOUTCAPS)mmeAllocMem(sizeof(WAVEOUTCAPS)); if(wave_out_caps == NULL) { audriv_free_audio(); audriv_err(mme_error_code_string(MMSYSERR_NOMEM)); return False; } all_data_block[0].data = mmeAllocBuffer(DATA_BLOCK_NUM * DATA_BLOCK_SIZE);#ifdef DEBUG printf("%d shared audio buffer memory is allocated.\n", DATA_BLOCK_NUM * DATA_BLOCK_SIZE);#endif /* DEBUG */ if(all_data_block[0].data == NULL) { audriv_free_audio(); audriv_err(mme_error_code_string(MMSYSERR_NOMEM)); return False; } for(i = 1; i < DATA_BLOCK_NUM; i++) all_data_block[i].data = all_data_block[0].data + i * DATA_BLOCK_SIZE; reset_data_block(); play_wave_format->hWave = AUDIO_CLOSE_ID; play_wave_format->format.wf.wFormatTag = WAVE_FORMAT_MULAW; play_wave_format->format.wf.nChannels = 1; play_wave_format->format.wf.nSamplesPerSec = 8000; play_wave_format->format.wf.nAvgBytesPerSec = 8000; play_wave_format->format.wf.nBlockAlign = 1; play_wave_format->format.wBitsPerSample = 8; audriv_play_open(); audriv_play_close(); return True;}void audriv_free_audio(void)/* audio の稿借妄を乖いますˉ */{ audriv_play_close(); if(all_data_block[0].data) mmeFreeBuffer(all_data_block[0].data); all_data_block[0].data = NULL; if(play_wave_format) mmeFreeMem(play_wave_format); play_wave_format = NULL; if(wave_time_info) mmeFreeMem(wave_time_info); wave_time_info = NULL; if(lpdword_buff) mmeFreeMem(lpdword_buff); lpdword_buff = NULL; if(wave_out_caps) mmeFreeMem(wave_out_caps); wave_out_caps = NULL;}static const char *callback_message_string(UINT msg){ switch(msg) { case WOM_OPEN: return "WOM_OPEN"; case WOM_CLOSE: return "WOM_CLOSE"; case WOM_DONE: return "WOM_DONE"; case WIM_OPEN: return "WIM_OPEN"; case WIM_CLOSE: return "WIM_CLOSE"; case WIM_DATA: return "WIM_DATA"; default: return "Unknown"; }}static void audriv_callback_mme(HANDLE Hwave, UINT wMsg, DWORD dwInstance, LPARAM lParam1, LPARAM lParam2){#ifdef DEBUGALL printf("audriv_callback_mme: mMsg=%d (%s)\n", wMsg, callback_message_string(wMsg));#endif if(wMsg == WOM_DONE) { WAVEHDR *wp = (WAVEHDR *)lParam1;#ifdef DEBUGALL printf("output wp->dwUser = %d\n", wp->dwUser);#endif reuse_data_block(wp->dwUser); }}#ifdef DEBUGstatic const char *ProductID_names(WORD id){ switch(id) { case MM_MIDI_MAPPER: return "MIDI Mapper"; case MM_WAVE_MAPPER: return "Wave Mapper"; case MM_SNDBLST_MIDIOUT: return "Sound Blaster MIDI output port"; case MM_SNDBLST_MIDIIN: return "Sound Blaster MIDI input port"; case MM_SNDBLST_SYNTH: return "Sound Blaster internal synthesizer"; case MM_SNDBLST_WAVEOUT: return "Sound Blaster waveform output"; case MM_SNDBLST_WAVEIN: return "Sound Blaster waveform input"; case MM_ADLIB: return "Ad Lib-compatible synthesizer"; case MM_MPU401_MIDIOUT: return "MPU401-compatible MIDI output port"; case MM_MPU401_MIDIIN: return "MPU401-compatible MIDI input port"; case MM_PC_JOYSTICK: return "Joystick adapter";#ifdef MM_DIGITAL_BBA case MM_DIGITAL_BBA: return "DEC BaseBoard Audio for ALPHA-AXP";#endif /* MM_DIGITAL_BBA */#ifdef MM_DIGITAL_J300AUDIO case MM_DIGITAL_J300AUDIO: return "DEC J300 TC option card";#endif /* MM_DIGITAL_J300AUDIO */#ifdef MM_DIGITAL_MSB case MM_DIGITAL_MSB: return "DEC Microsoft Sound Board compatible card";#endif /* MM_DIGITAL_MSB */#ifdef MM_DIGITAL_IMAADPCM case MM_DIGITAL_IMAADPCM: return "DEC IMA ADPCM ACM driver";#endif /* MM_DIGITAL_IMAADPCM */ } return "Unknown";}#endif /* DEBUG */Bool audriv_play_open(void)/* audio を遍琳脱に倡き·いつでも audriv_write() により遍琳材墙な * 觉轮にしますˉ贷に倡いている眷圭はなにも乖いませんˉ * 喇根した眷圭は True を·己窃した眷圭は False を手しますˉ */{ MMRESULT status; if(IS_AUDIO_PLAY_OPEN) return True; play_counter = 0; reset_samples = 0; play_wave_format->hWave = 0; status = waveOutOpen(&play_wave_format->hWave, WAVE_MAPPER, &play_wave_format->format.wf, audriv_callback_mme, NULL, CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE); if(status != MMSYSERR_NOERROR) { audriv_err(mme_error_code_string(status)); play_wave_format->hWave = AUDIO_CLOSE_ID; return False; } status = waveOutGetID(play_wave_format->hWave, &play_wave_format->DevID); if(status != MMSYSERR_NOERROR) { audriv_err(mme_error_code_string(status)); audriv_play_close(); return False; } status = waveOutGetDevCaps(play_wave_format->DevID, wave_out_caps, sizeof(WAVEOUTCAPS)); if(status != MMSYSERR_NOERROR) { audriv_err(mme_error_code_string(status)); audriv_play_close(); return False; }#ifdef DEBUG printf("Play Device ID: %d\n", play_wave_format->DevID);#ifdef MM_MICROSOFT if(wave_out_caps->wMid == MM_MICROSOFT) puts("Manufacture: Microsoft Corp.");#endif /* MM_MICROSOFT */#ifdef MM_DIGITAL if(wave_out_caps->wMid == MM_DIGITAL) puts("Manufacture: Digital Eq. Corp.");#endif /* MM_DIGITAL */ printf("Product: %s\n", ProductID_names(wave_out_caps->wPid)); printf("Version of the driver: %d\n", wave_out_caps->vDriverVersion); printf("Product name: %s\n", wave_out_caps->szPname);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -