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

📄 seq_alsa.c

📁 A GTK sound font editor. Sound font files are used to synthesize instruments from audio samples for
💻 C
字号:
/*================================================================== * seq_alsa.c - ALSA sequencer and virtual keyboard routines * * Smurf Sound Font Editor * Copyright (C) 1999-2001 Josh Green * * Some code and ideas used from the following: * aconnect (in alsa-utils package) and vkeybd * both programs are Copyright Takashi Iwai * * 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 or point your web browser to http://www.gnu.org. * * To contact the author of this program: * Email: Josh Green <jgreen@users.sourceforge.net> * Smurf homepage: http://smurf.sourceforge.net *==================================================================*/#include "config.h"/* only compile if ALSA_SUPPORT */#ifdef ALSA_SUPPORT#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <sys/poll.h>#include <glib.h>#include <string.h>#include "alsa.h"#include "seq_alsa.h"#include "i18n.h"#include "smurfcfg.h"#include "util.h"#include "wavetable.h"#include <sys/asoundlib.h>#ifdef NEW_ALSA_SEQ#define DEFAULT_SEQ_DEV "default"#else#define DEFAULT_SEQ_DEV "hw"#endifstatic void seq_alsa_send_event(int do_flush);snd_seq_t *seq_alsa_handle = NULL;static gint seq_alsa_usage_count = 0;gint seq_alsa_fd = -1;gint seq_alsa_vkeyb_conn_client = 0;gint seq_alsa_vkeyb_conn_port = 0;gboolean seq_alsa_vkeyb_active = FALSE;static gint seq_alsa_vkeyb_port;  /* virtual keyboard port (piano widget) */static snd_seq_event_t ev;/* load ALSA config vars (sequencer client:port to connect to) */voidseq_alsa_load_config (void){  if (strcmp (smurfcfg_get_val (SMURFCFG_SEQ_DRIVER)->v_string, "AUTO") != 0)    {      seq_alsa_vkeyb_conn_client =	smurfcfg_get_val (SMURFCFG_SEQ_ALSACLIENT)->v_int;      seq_alsa_vkeyb_conn_port =	smurfcfg_get_val (SMURFCFG_SEQ_ALSAPORT)->v_int;    }  else    seq_alsa_vkeyb_conn_client = 0; /* force "AUTO" detection */}/* open ALSA handle (used by ALSA MIDI thru drivers, and wavetable   driver when ALSA has support for patch loading) */gintseq_alsa_init (void){  int err;#ifdef NEW_ALSA  struct pollfd pfd;#endif  if (seq_alsa_usage_count)    {      seq_alsa_usage_count++;      return (OK);    }#ifdef NEW_ALSA  if ((err = snd_seq_open (&seq_alsa_handle, DEFAULT_SEQ_DEV,		    SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK)) < 0)    return (logit (LogFubar, _("Failed to open ALSA sequencer: %s"),			      snd_strerror (err)));  if ((err = snd_seq_nonblock (seq_alsa_handle, FALSE)) < 0)    {      snd_seq_close (seq_alsa_handle);      return (logit (LogFubar | LogErrno,		     _("Failed to set ALSA sequencer to non-blocking")));    }  /* grab one file descriptor POLL info structure */  err = snd_seq_poll_descriptors (seq_alsa_handle, &pfd, 1, POLLIN);  if (err <= 0 || !(pfd.events & POLLIN))    {      snd_seq_close (seq_alsa_handle);      return (logit (LogFubar,		    _("Failed to get ALSA sequencer file descriptor: %s"),		    snd_strerror (err)));    }  seq_alsa_fd = pfd.fd;  /* indicate sample caching support, ALSA 0.9.0beta3 works with sample caching     older versions <= 0.5.10b apparently don't (strange bahavior including     kernel oopses) */  wtbl_sample_cache_support = TRUE;#else  /* hmm, for some reason SND_SEQ_FILTER_BOUNCE doesn't work! */  if ((err = snd_seq_open (&seq_alsa_handle, SND_SEQ_OPEN_OUT)) < 0)    return (logit (LogFubar | LogErrno, _("Failed to open ALSA sequencer: %s"),		  snd_strerror (err)));  if (snd_seq_block_mode (seq_alsa_handle, FALSE) < 0)    return (logit (LogFubar | LogErrno,		   _("Failed to set ALSA sequencer to non-blocking")));  /* get the file descriptor for the opened sequencer handle */  if ((seq_alsa_fd = snd_seq_file_descriptor (seq_alsa_handle)) < 0)    {      snd_seq_close (seq_alsa_handle);      return (logit (LogFubar,		    _("Failed to get ALSA sequencer file descriptor: %s"),		    snd_strerror (seq_alsa_fd)));    }#endif  snd_seq_set_client_name (seq_alsa_handle, _("Smurf Sound Font Editor"));  snd_seq_ev_clear (&ev);  seq_alsa_usage_count++;  return (OK);}voidseq_alsa_close (void){  if (!seq_alsa_usage_count) return; /* ALSA handle opened? */  if (!--seq_alsa_usage_count)	/* no more drivers using ALSA handle? */    snd_seq_close (seq_alsa_handle); /* close ALSA handle */}gintseq_alsa_vkeyb_init (void){  gint client, port;  gint perm, type;  if (!seq_alsa_init ()) return (FAIL);  if ((seq_alsa_vkeyb_port = snd_seq_create_simple_port (seq_alsa_handle,	_("Smurf Virtual Keyboard"),	SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,	SND_SEQ_PORT_TYPE_APPLICATION)) < 0)    {      seq_alsa_close ();      return (logit (LogFubar | LogErrno,		     _("Failed to create ALSA virtual keyboard port")));    }  seq_alsa_vkeyb_active = TRUE;  client = seq_alsa_vkeyb_conn_client;  port = seq_alsa_vkeyb_conn_port;  if (client == 0)		/* "auto" detect WaveTable to sequence? */    {      log_message (_("Looking for ALSA WaveTable synth to sequence"));      perm = SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;      type = SND_SEQ_PORT_TYPE_MIDI_GENERIC;      /* probably not the best "auto" detection scheme, dependance on client	 name containing "WaveTable" is probably the first mistake, but user	 can set client:port manually in preferences */      if (!seq_alsa_find_port ("WaveTable", perm, type, &client, &port))	{  /* wavetable not found? then allow user to manually connect it */	  logit (LogWarn, _("Failed to find suitable synth, set manually in"			   " preferences or use ALSA aconnect utility"));	  return (OK);	}    }  log_message (_("Connecting Virtual Keyboard to ALSA client:port %d:%d"),		client, port);  if (snd_seq_connect_to (seq_alsa_handle,seq_alsa_vkeyb_port,client,port) < 0)    log_message (_("Failed to connect ALSA Virtual Keyboard to %d:%d"),		  client, port);  return (OK);}voidseq_alsa_vkeyb_close (void){  if (!seq_alsa_vkeyb_active) return;  if (snd_seq_delete_simple_port (seq_alsa_handle, seq_alsa_vkeyb_port) < 0)    logit (LogWarn, _("Failed to close Virtual Keyboard port"));  seq_alsa_close ();  seq_alsa_vkeyb_active = FALSE;}/* searches for an ALSA client whose client name matches the substring   "namematch" and the first port with permission "perm" and type "type" */#ifdef NEW_ALSA_SEQ		/* ALSA >= 0.9.0beta6 interface */gintseq_alsa_find_port (gchar *namematch, gint perm, gint type,		    gint *client, gint *port){  snd_seq_client_info_t *cinfo;  snd_seq_port_info_t *pinfo;  const gchar *getname;  snd_seq_client_info_alloca (&cinfo);  snd_seq_port_info_alloca (&pinfo);  snd_seq_client_info_set_client (cinfo, -1);  while (snd_seq_query_next_client (seq_alsa_handle, cinfo) >= 0)    {      getname = snd_seq_client_info_get_name (cinfo);      if (!namematch || strstr (getname, namematch))	{	  snd_seq_port_info_set_client	    (pinfo, snd_seq_client_info_get_client (cinfo));	  snd_seq_port_info_set_port (pinfo, -1);	  while (snd_seq_query_next_port (seq_alsa_handle, pinfo) >= 0)	    {	      if ((snd_seq_port_info_get_capability (pinfo) & perm) == perm		  && (snd_seq_port_info_get_type (pinfo) & type) == type)		{		  *client = snd_seq_port_info_get_client (pinfo);		  *port = snd_seq_port_info_get_port (pinfo);		  return (OK);		}	    }	}    }  return (FAIL);}#else  /* ALSA 0.9.0beta? - 0.9.0beta5 */gintseq_alsa_find_port (gchar *namematch, gint perm, gint type,		    gint *client, gint *port){  snd_seq_client_info_t cinfo;  snd_seq_port_info_t pinfo;  cinfo.client = -1;  cinfo.name[0] = 0;  cinfo.group[0] = 0;  while (snd_seq_query_next_client (seq_alsa_handle, &cinfo) >= 0)    {      if (!namematch || strstr (cinfo.name, namematch))	{	  pinfo.client = cinfo.client;	  pinfo.port = -1;	  pinfo.name[0] = 0;	  pinfo.group[0] = 0;	  while (snd_seq_query_next_port (seq_alsa_handle, &pinfo) >= 0)	    {	      if ((pinfo.capability & perm) == perm		  && (pinfo.type & type) == type)		{		  *client = cinfo.client;		  *port = pinfo.port;		  return (OK);		}	      pinfo.name[0] = 0;	      pinfo.group[0] = 0;	    }	}      cinfo.name[0] = 0;      cinfo.group[0] = 0;    }  return (FAIL);}#endif/* check if two ALSA client/port pairs are subscribed */#ifdef NEW_ALSA_SEQ		/* ALSA >= 0.9.0beta6 interface */gbooleanseq_alsa_is_subscribed (snd_seq_addr_t *src, snd_seq_addr_t *dest){  snd_seq_query_subscribe_t *query;  snd_seq_query_subscribe_alloca (&query);  snd_seq_query_subscribe_set_type (query, SND_SEQ_QUERY_SUBS_READ);  snd_seq_query_subscribe_set_index(query, 0);  while (snd_seq_query_port_subscribers(seq_alsa_handle, query) >= 0) {    const snd_seq_addr_t *addr;    addr = snd_seq_query_subscribe_get_addr(query);    if (addr->client == dest->client && addr->port == dest->port)      return (TRUE);    snd_seq_query_subscribe_set_index      (query, snd_seq_query_subscribe_get_index (query) + 1);  }  return (FALSE);}#else  /* ALSA 0.9.0beta? - 0.9.0beta5 or 0.5.x */gbooleanseq_alsa_is_subscribed (snd_seq_addr_t *src, snd_seq_addr_t *dest){  snd_seq_query_subs_t query;  memset (&query, sizeof (query), 0);  query.type = SND_SEQ_QUERY_SUBS_READ;  while (snd_seq_query_port_subscribers(seq_alsa_handle, &query) >= 0) {    if (query.addr.client == dest->client	&& query.addr.port == dest->port)      return (TRUE);    query.index++;  }  return (FALSE);}#endifstatic voidseq_alsa_send_event(int do_flush){  snd_seq_ev_set_subs (&ev);  snd_seq_ev_set_direct(&ev);  snd_seq_ev_set_source(&ev, seq_alsa_vkeyb_port);  snd_seq_event_output(seq_alsa_handle, &ev);#ifdef NEW_ALSA  if (do_flush)    snd_seq_drain_output (seq_alsa_handle);#else  if (do_flush)    snd_seq_flush_output (seq_alsa_handle);#endif}/* set patch bank for specified channel */voidseq_alsa_set_bank (gint chan, gint bank){#ifdef NEW_ALSA  snd_seq_ev_set_controller (&ev, chan, MIDI_CTL_MSB_BANK, bank);#else  snd_seq_ev_set_controller (&ev, chan, SND_MCTL_MSB_BANK, bank);#endif  seq_alsa_send_event (TRUE);}/* set patch preset for specified channel */voidseq_alsa_set_preset (gint chan, gint preset){  snd_seq_ev_set_pgmchange (&ev, chan, preset);  seq_alsa_send_event (TRUE);}/* Start note (note) on channel (chan) with velocity (vel) */voidseq_alsa_note_on (gint chan, gint note, gint vel){  snd_seq_ev_set_noteon (&ev, chan, note, vel);  seq_alsa_send_event (TRUE);}/* Stop note (note) on channel (chan) with velocity (vel) */voidseq_alsa_note_off (gint chan, gint note, gint vel){  snd_seq_ev_set_noteoff (&ev, chan, note, vel);  seq_alsa_send_event (TRUE);}/* Set midi bender control on channel (chan) to (bendval) */voidseq_alsa_pitch_bender (gint chan, gint bendval){  snd_seq_ev_set_pitchbend (&ev, chan, bendval);  seq_alsa_send_event (TRUE);}/* set bend range */voidseq_alsa_pitch_bend_range (gint chan, gint val){  ev.type = SND_SEQ_EVENT_REGPARAM;  ev.data.control.channel = chan;  ev.data.control.param = 0;	/* RPN type 0 is bend range */  ev.data.control.value = val << 7; /* value is stored in MSB of RPN value */  seq_alsa_send_event (TRUE);}/* set main volume */voidseq_alsa_main_volume (gint chan, gint val){#ifdef NEW_ALSA  snd_seq_ev_set_controller (&ev, chan, MIDI_CTL_MSB_MAIN_VOLUME, val);#else  snd_seq_ev_set_controller (&ev, chan, SND_MCTL_MSB_MAIN_VOLUME, val);#endif  seq_alsa_send_event (TRUE);}/* Set chorus amount */voidseq_alsa_chorus (gint chan, gint val){#ifdef NEW_ALSA  snd_seq_ev_set_controller (&ev, chan, MIDI_CTL_E3_CHORUS_DEPTH, val);#else  snd_seq_ev_set_controller (&ev, chan, SND_MCTL_E3_CHORUS_DEPTH, val);#endif  seq_alsa_send_event (TRUE);}/* Set reverb amount */voidseq_alsa_reverb (gint chan, gint val){#ifdef NEW_ALSA  snd_seq_ev_set_controller (&ev, chan, MIDI_CTL_E1_REVERB_DEPTH, val);#else  snd_seq_ev_set_controller (&ev, chan, SND_MCTL_E1_REVERB_DEPTH, val);#endif  seq_alsa_send_event (TRUE);}#endif /* #ifdef ALSA_SUPPORT */

⌨️ 快捷键说明

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