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

📄 alsa_a.c

📁 MIDI解码程序(用VC编写)
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- c-file-style: "gnu" -*-    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>    ALSA 0.[56] support by Katsuhiro Ueno <katsu@blue.sky.or.jp>                rewritten by Takashi Iwai <tiwai@suse.de>    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    alsa_a.c    Functions to play sound on the ALSA audio driver*/#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif/*ALSA header file*/#if HAVE_ALSA_ASOUNDLIB_H#define ALSA_PCM_OLD_HW_PARAMS_API#define ALSA_PCM_OLD_SW_PARAMS_API#include <alsa/asoundlib.h>#else#include <sys/asoundlib.h>#endif#if SND_LIB_MAJOR > 0#define ALSA_LIB  9#elif defined(SND_LIB_MINOR)#define ALSA_LIB  SND_LIB_MINOR#else#define ALSA_LIB  3#endif#if ALSA_LIB < 4typedef void  snd_pcm_t;#endif#include "timidity.h"#include "common.h"#include "output.h"#include "controls.h"#include "timer.h"#include "instrum.h"#include "playmidi.h"#include "miditrace.h"static int open_output(void); /* 0=success, 1=warning, -1=fatal error */static void close_output(void);static int output_data(char *buf, int32 nbytes);static int acntl(int request, void *arg);#if ALSA_LIB >= 5static int detect(void);#endif/* export the playback mode */#define dpm alsa_play_modePlayMode dpm = {  DEFAULT_RATE, PE_16BIT|PE_SIGNED, PF_PCM_STREAM|PF_CAN_TRACE|PF_BUFF_FRAGM_OPT,  -1,  {0}, /* default: get all the buffer fragments you can */  "ALSA pcm device", 's',  "", /* here leave it empty so that the pcm device name can be given       * via command line option.       */  open_output,  close_output,  output_data,  acntl,#if ALSA_LIB >= 5  detect#endif};/*************************************************************************//* We currently only honor the PE_MONO bit, the sample rate, and the   number of buffer fragments. We try 16-bit signed data first, and   then 8-bit unsigned if it fails. If you have a sound device that   can't handle either, let me know. *//*ALSA PCM handler*/static snd_pcm_t* handle = NULL;#if ALSA_LIB <= 5static int card = 0;static int device = 0;#endifstatic int total_bytes = -1;static int frag_size = 0;static int sample_shift = 0;static int output_counter;#if ALSA_LIB > 5static char *alsa_device_name(void){  if (dpm.name && *dpm.name)    return dpm.name;  else    return "alsa pcm";}#elsestatic char *alsa_device_name(void){  static char name[32];  sprintf(name, "card%d/device%d", card, device);  return name;}#endifstatic void error_report (int snd_error){  ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",	    alsa_device_name(), snd_strerror (snd_error));}#if ALSA_LIB < 6/*return value == 0 sucess               == -1 fails */static int check_sound_cards (int* card__, int* device__,			      const int32 extra_param[5]){  /*Search sound cards*/  struct snd_ctl_hw_info ctl_hw_info;  snd_pcm_info_t pcm_info;  snd_ctl_t* ctl_handle;  const char* env_sound_card = getenv ("TIMIDITY_SOUND_CARD");  const char* env_pcm_device = getenv ("TIMIDITY_PCM_DEVICE");  int tmp;  /*specify card*/  *card__ = 0;  if (env_sound_card != NULL)    *card__ = atoi (env_sound_card);  /*specify device*/  *device__ = 0;  if (env_pcm_device != NULL)    *device__ = atoi (env_pcm_device);  tmp = snd_cards ();  if (tmp == 0)    {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "No sound card found.");      return -1;    }  if (tmp < 0)    {      error_report (tmp);      return -1;    }  if (*card__ < 0 || *card__ >= tmp)    {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "There is %d sound cards."		" %d is invalid sound card. assuming 0.",		tmp, *card__);      *card__ = 0;    }  tmp = snd_ctl_open (&ctl_handle, *card__);  if (tmp < 0)    {      error_report (tmp);      return -1;    }  /*check whether sound card has pcm device(s)*/  tmp = snd_ctl_hw_info (ctl_handle, & ctl_hw_info);  if (ctl_hw_info.pcmdevs == 0)    {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,		"%d-th sound card(%s) has no pcm device",		ctl_hw_info.longname, *card__);      snd_ctl_close (ctl_handle);      return -1;    }  if (*device__ < 0 || *device__ >= ctl_hw_info.pcmdevs)    {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,		"%d-th sound cards(%s) has %d pcm device(s)."		" %d is invalid pcm device. assuming 0.",		*card__, ctl_hw_info.longname, ctl_hw_info.pcmdevs, *device__);      *device__ = 0;      if (ctl_hw_info.pcmdevs == 0)	{/*sound card has no pcm devices*/	  snd_ctl_close (ctl_handle);	  return -1;	}    }  /*check whether pcm device is able to playback*/  tmp = snd_ctl_pcm_info(ctl_handle, *device__, &pcm_info);  if (tmp < 0)    {      error_report (tmp);      snd_ctl_close (ctl_handle);      return -1;    }  if ((pcm_info.flags & SND_PCM_INFO_PLAYBACK) == 0)    {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,		"%d-th sound cards(%s), device=%d, "		"type=%d, flags=%d, id=%s, name=%s,"		" does not support playback",		*card__, ctl_hw_info.longname, ctl_hw_info.pcmdevs,		pcm_info.type, pcm_info.flags, pcm_info.id, pcm_info.name);      snd_ctl_close (ctl_handle);      return -1;    }  tmp = snd_ctl_close (ctl_handle);  if (tmp < 0)    {      error_report (tmp);      return -1;    }  return 0;}#endif#if ALSA_LIB > 5/*================================================================ * ALSA API version 0.9.x *================================================================*/static char *get_pcm_name(void){  char *name;  if (dpm.name && *dpm.name)    return dpm.name;  name = getenv("TIMIDITY_PCM_NAME");  if (! name || ! *name)    name = "default";  return name;}static void error_handle(const char *file, int line, const char *func, int err, const char *fmt, ...){}static int detect(void){  snd_pcm_t *pcm;  snd_lib_error_set_handler(error_handle);  if (snd_pcm_open(&pcm, get_pcm_name(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0)    return 0;  snd_pcm_close(pcm);  return 1; /* found */}/*return value == 0 sucess               == 1 warning               == -1 fails */static int open_output(void){  int orig_rate = dpm.rate;  int ret_val = 0;  int tmp, frags, r, pfds;  int rate;  snd_pcm_hw_params_t *pinfo;  snd_pcm_sw_params_t *swpinfo;  dpm.name = get_pcm_name();  snd_lib_error_set_handler(NULL);  tmp = snd_pcm_open(&handle, dpm.name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); /* avoid blocking by open */  if (tmp < 0) {    ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't open pcm device '%s'.", dpm.name);    return -1;  }  snd_pcm_nonblock(handle, 0); /* set back to blocking mode */  snd_pcm_hw_params_alloca(&pinfo);  snd_pcm_sw_params_alloca(&swpinfo);  if (snd_pcm_hw_params_any(handle, pinfo) < 0) {    ctl->cmsg(CMSG_ERROR, VERB_NORMAL,	      "ALSA pcm '%s' can't initialize hw_params",	      alsa_device_name());    snd_pcm_close(handle);    return -1;  }#ifdef LITTLE_ENDIAN#define S16_FORMAT	SND_PCM_FORMAT_S16_LE#define U16_FORMAT	SND_PCM_FORMAT_U16_LE#else#define S16_FORMAT	SND_PCM_FORMAT_S16_BE#define U16_FORMAT	SND_PCM_FORMAT_U16_LE#endif  dpm.encoding &= ~(PE_ULAW|PE_ALAW|PE_BYTESWAP);  /*check sample bit*/  if (snd_pcm_hw_params_test_format(handle, pinfo, S16_FORMAT) < 0 &&      snd_pcm_hw_params_test_format(handle, pinfo, U16_FORMAT) < 0)    dpm.encoding &= ~PE_16BIT; /*force 8bit samples*/  if (snd_pcm_hw_params_test_format(handle, pinfo, SND_PCM_FORMAT_U8) < 0 &&      snd_pcm_hw_params_test_format(handle, pinfo, SND_PCM_FORMAT_S8) < 0)    dpm.encoding |= PE_16BIT; /*force 16bit samples*/  /*check format*/  if (dpm.encoding & PE_16BIT) {    /*16bit*/    if (snd_pcm_hw_params_set_format(handle, pinfo, S16_FORMAT) == 0)      dpm.encoding |= PE_SIGNED;    else if (snd_pcm_hw_params_set_format(handle, pinfo, U16_FORMAT) == 0)      dpm.encoding &= ~PE_SIGNED;    else {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,		"ALSA pcm '%s' doesn't support 16 bit sample width",		alsa_device_name());      snd_pcm_close(handle);      return -1;    }  } else {    /*8bit*/    if (snd_pcm_hw_params_set_format(handle, pinfo, SND_PCM_FORMAT_U8) == 0)      dpm.encoding &= ~PE_SIGNED;    else if (snd_pcm_hw_params_set_format(handle, pinfo, SND_PCM_FORMAT_S8) == 0)      dpm.encoding |= PE_SIGNED;    else {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,		"ALSA pcm '%s' doesn't support 8 bit sample width",		alsa_device_name());      snd_pcm_close(handle);      return -1;    }  }  if (snd_pcm_hw_params_set_access(handle, pinfo,				   SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {    ctl->cmsg(CMSG_ERROR, VERB_NORMAL,	      "ALSA pcm '%s' doesn't support interleaved data",	      alsa_device_name());    snd_pcm_close(handle);    return -1;  }  /*check rate*/  r = snd_pcm_hw_params_get_rate_min(pinfo, NULL);  if (r >= 0 && r > dpm.rate) {    dpm.rate = r;    ret_val = 1;  }  r = snd_pcm_hw_params_get_rate_max(pinfo, NULL);  if (r >= 0 && r < dpm.rate) {    dpm.rate = r;    ret_val = 1;  }  if ((rate = snd_pcm_hw_params_set_rate_near(handle, pinfo, dpm.rate, 0)) < 0) {    ctl->cmsg(CMSG_ERROR, VERB_NORMAL,	      "ALSA pcm '%s' can't set rate %d",	      alsa_device_name(), dpm.rate);    snd_pcm_close(handle);    return -1;  }  /*check channels*/  if (dpm.encoding & PE_MONO) {    if (snd_pcm_hw_params_test_channels(handle, pinfo, 1) < 0)      dpm.encoding &= ~PE_MONO;  } else {    if (snd_pcm_hw_params_test_channels(handle, pinfo, 2) < 0)      dpm.encoding |= PE_MONO;  }      if (dpm.encoding & PE_MONO) {    if (snd_pcm_hw_params_set_channels(handle, pinfo, 1) < 0) {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,		"ALSA pcm '%s' can't set mono channel",		alsa_device_name());      snd_pcm_close(handle);      return -1;    }  } else {    if (snd_pcm_hw_params_set_channels(handle, pinfo, 2) < 0) {      ctl->cmsg(CMSG_ERROR, VERB_NORMAL,		"ALSA pcm '%s' can't set stereo channels",		alsa_device_name());      snd_pcm_close(handle);      return -1;    }  }  sample_shift = 0;  if (!(dpm.encoding & PE_MONO))    sample_shift++;  if (dpm.encoding & PE_16BIT)    sample_shift++;  /* Set buffer fragment size (in extra_param[1]) */  if (dpm.extra_param[1] != 0)    frag_size = dpm.extra_param[1];  else    frag_size = audio_buffer_size << sample_shift;  /* Set buffer fragments (in extra_param[0]) */  if (dpm.extra_param[0] == 0)    frags = 4;  else    frags = dpm.extra_param[0];

⌨️ 快捷键说明

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