From 148d4588c216f77b71eb1bdfe4ba3147712dab9c Mon Sep 17 00:00:00 2001 From: pbd Date: Fri, 20 Dec 2002 15:45:38 +0000 Subject: [PATCH] added new code for h/w monitoring with the RME HDSP interface git-svn-id: svn+ssh://jackaudio.org/trunk/jack@283 0c269be4-1314-0410-8aa9-9f06e86f4224 --- configure.in | 4 +- drivers/alsa/Makefile.am | 2 +- drivers/alsa/alsa_driver.c | 15 ++- drivers/alsa/hdsp.c | 214 +++++++++++++++++++++++++++++++++++++ jack/hdsp.h | 33 ++++++ 5 files changed, 263 insertions(+), 5 deletions(-) create mode 100644 drivers/alsa/hdsp.c create mode 100644 jack/hdsp.h diff --git a/configure.in b/configure.in index f18a920..dc91e5e 100644 --- a/configure.in +++ b/configure.in @@ -13,8 +13,8 @@ dnl micro version = incremented when implementation-only dnl changes are made dnl --- JACK_MAJOR_VERSION=0 -JACK_MINOR_VERSION=42 -JACK_MICRO_VERSION=2 +JACK_MINOR_VERSION=43 +JACK_MICRO_VERSION=0 dnl --- dnl HOWTO: updating the libjack interface version diff --git a/drivers/alsa/Makefile.am b/drivers/alsa/Makefile.am index b171d74..83afb1b 100644 --- a/drivers/alsa/Makefile.am +++ b/drivers/alsa/Makefile.am @@ -8,5 +8,5 @@ plugin_LTLIBRARIES = jack_alsa.la jack_alsa_la_LDFLAGS = -module jack_alsa_la_SOURCES = alsa_driver.c generic_hw.c memops.c \ - hammerfall.c ice1712.c + hammerfall.c hdsp.c ice1712.c jack_alsa_la_LIBADD = $(ALSA_LIBS) diff --git a/drivers/alsa/alsa_driver.c b/drivers/alsa/alsa_driver.c index 7c4c08e..6b7f453 100644 --- a/drivers/alsa/alsa_driver.c +++ b/drivers/alsa/alsa_driver.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,14 @@ alsa_driver_hammerfall_hardware (alsa_driver_t *driver) return 0; } +static int +alsa_driver_hdsp_hardware (alsa_driver_t *driver) + +{ + driver->hw = jack_alsa_hdsp_hw_new (driver); + return 0; +} + static int alsa_driver_ice1712_hardware (alsa_driver_t *driver) @@ -134,6 +143,10 @@ alsa_driver_hw_specific (alsa_driver_t *driver, int hw_monitoring) if ((err = alsa_driver_hammerfall_hardware (driver)) != 0) { return err; } + } else if (!strcmp(driver->alsa_driver, "H-DSP")) { + if ((err = alsa_driver_hdsp_hardware (driver)) !=0) { + return err; + } } else if (!strcmp(driver->alsa_driver, "ICE1712")) { if ((err = alsa_driver_ice1712_hardware (driver)) !=0) { return err; @@ -1139,7 +1152,6 @@ alsa_driver_process (alsa_driver_t *driver, jack_nframes_t nframes) } if (!driver->hw_monitoring) { - if (driver->playback_handle) { if (driver->all_monitor_in) { for (chn = 0; chn < driver->playback_nchannels; chn++) { @@ -1155,7 +1167,6 @@ alsa_driver_process (alsa_driver_t *driver, jack_nframes_t nframes) } } else { - if ((driver->hw->input_monitor_mask != driver->input_monitor_mask) && !driver->all_monitor_in) { driver->hw->set_input_monitor_mask (driver->hw, driver->input_monitor_mask); } diff --git a/drivers/alsa/hdsp.c b/drivers/alsa/hdsp.c new file mode 100644 index 0000000..0848bed --- /dev/null +++ b/drivers/alsa/hdsp.c @@ -0,0 +1,214 @@ +/* + Copyright (C) 2001 Paul Davis + Copyright (C) 2002 Dave LaRose + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include +#include +#include +#include +#include + +/* Constants to make working with the hdsp matrix mixer easier */ +static const int HDSP_MINUS_INFINITY_GAIN = 0; +static const int HDSP_UNITY_GAIN = 32768; +static const int HDSP_MAX_GAIN = 65535; + +/* + * Use these two arrays to choose the value of the input_channel + * argument to hsdp_set_mixer_gain(). hdsp_physical_input_index[n] + * selects the nth optical/analog input. audio_stream_index[n] + * selects the nth channel being received from the host via pci/pccard. + */ +static const int hdsp_num_input_channels = 52; +static const int hdsp_physical_input_index[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}; +static const int hdsp_audio_stream_index[] = { + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51}; + +/* + * Use this array to choose the value of the output_channel + * argument to hsdp_set_mixer_gain(). hdsp_physical_output_index[26] + * and hdsp_physical_output_index[27] refer to the two "line out" + * channels (1/4" phone jack on the front of digiface/multiface). + */ +static const int hdsp_num_output_channels = 28; +static const int hdsp_physical_output_index[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}; + + +/* Function for checking argument values */ +static int clamp_int(int value, int lower_bound, int upper_bound) +{ + if(value < lower_bound) { + return lower_bound; + } + if(value > upper_bound) { + return upper_bound; + } + return value; +} + +/* Note(XXX): Maybe should share this code with hammerfall.c? */ +static void +set_control_id (snd_ctl_elem_id_t *ctl, const char *name) +{ + snd_ctl_elem_id_set_name (ctl, name); + snd_ctl_elem_id_set_numid (ctl, 0); + snd_ctl_elem_id_set_interface (ctl, SND_CTL_ELEM_IFACE_PCM); + snd_ctl_elem_id_set_device (ctl, 0); + snd_ctl_elem_id_set_subdevice (ctl, 0); + snd_ctl_elem_id_set_index (ctl, 0); +} + +/* The hdsp matrix mixer lets you connect pretty much any input to */ +/* any output with gain from -inf to about +2dB. Pretty slick. */ +/* This routine makes a convenient way to set the gain from */ +/* input_channel to output_channel (see hdsp_physical_input_index */ +/* etc. above. */ +/* gain is an int from 0 to 65535, with 0 being -inf gain, and */ +/* 65535 being about 2dB. */ +static int hdsp_set_mixer_gain(jack_hardware_t *hw, int input_channel, + int output_channel, int gain) +{ + hdsp_t *h = (hdsp_t *) hw->private; + snd_ctl_elem_value_t *ctl; + snd_ctl_elem_id_t *ctl_id; + int err; + + /* Check args */ + input_channel = clamp_int(input_channel, 0, hdsp_num_input_channels); + output_channel = clamp_int(output_channel, 0, hdsp_num_output_channels); + gain = clamp_int(gain, HDSP_MINUS_INFINITY_GAIN, HDSP_MAX_GAIN); + + /* Allocate control element and select "Mixer" control */ + snd_ctl_elem_value_alloca (&ctl); + snd_ctl_elem_id_alloca (&ctl_id); + set_control_id (ctl_id, "Mixer"); + snd_ctl_elem_value_set_id (ctl, ctl_id); + + /* Apparently non-standard and unstable interface for the */ + /* mixer control. */ + snd_ctl_elem_value_set_integer (ctl, 0, input_channel); + snd_ctl_elem_value_set_integer (ctl, 1, output_channel); + snd_ctl_elem_value_set_integer (ctl, 2, gain); + + /* Commit the mixer value and check for errors */ + if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) != 0) { + jack_error ("ALSA/HDSP: cannot set mixer gain (%s)", snd_strerror (err)); + return -1; + } + + /* Note (XXX): Perhaps we should maintain a cache of the current */ + /* mixer values, since it's not clear how to query them from the */ + /* hdsp hardware. We'll leave this out until a little later. */ + return 0; +} + +static int hdsp_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) +{ + int i; + + /* For each input channel */ + for (i = 0; i < 26; i++) { + /* Monitoring requested for this channel? */ + if(mask & (1<input_monitor_mask = mask; + return 0; +} + + +static int hdsp_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) +{ + // Empty for now, until Dave understands more about clock sync so + // he can test. + return -1; +} + +void +jack_alsa_hdsp_release (jack_hardware_t *hw) + +{ + hdsp_t *h = (hdsp_t *) hw->private; + + if (h != 0) { + free (h); + } +} + +/* Mostly copied directly from hammerfall.c */ +jack_hardware_t * +jack_alsa_hdsp_hw_new (alsa_driver_t *driver) + +{ + jack_hardware_t *hw; + hdsp_t *h; + + hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t)); + + /* Not using clock lock-sync-whatever in home hardware setup */ + /* yet. Will write this code when can test it. */ + /* hw->capabilities = Cap_HardwareMonitoring|Cap_AutoSync|Cap_WordClock|Cap_ClockMaster|Cap_ClockLockReporting; */ + hw->capabilities = Cap_HardwareMonitoring; + hw->input_monitor_mask = 0; + hw->private = 0; + + hw->set_input_monitor_mask = hdsp_set_input_monitor_mask; + hw->change_sample_clock = hdsp_change_sample_clock; + hw->release = jack_alsa_hdsp_release; + + h = (hdsp_t *) malloc (sizeof (hdsp_t)); + h->driver = driver; + hw->private = h; + + return hw; +} diff --git a/jack/hdsp.h b/jack/hdsp.h new file mode 100644 index 0000000..bb1c625 --- /dev/null +++ b/jack/hdsp.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2001 Paul Davis + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#ifndef __jack_hdsp_h__ +#define __jack_hdsp_h__ + +#include + +typedef struct { + alsa_driver_t *driver; +} hdsp_t; + +jack_hardware_t * +jack_alsa_hdsp_hw_new (alsa_driver_t *driver); + +#endif /* __jack_hdsp_h__*/