jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
7.2KB

  1. /*
  2. Copyright (C) 2001 Paul Davis
  3. Copyright (C) 2002 Dave LaRose
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. $Id: hdsp.c,v 1.3 2005/09/29 14:51:59 letz Exp $
  16. */
  17. #if defined(HAVE_CONFIG_H)
  18. #include "config.h"
  19. #endif
  20. #include "hardware.h"
  21. #include "alsa_driver.h"
  22. #include "hdsp.h"
  23. #include "JackError.h"
  24. /* Constants to make working with the hdsp matrix mixer easier */
  25. static const int HDSP_MINUS_INFINITY_GAIN = 0;
  26. static const int HDSP_UNITY_GAIN = 32768;
  27. static const int HDSP_MAX_GAIN = 65535;
  28. /*
  29. * Use these two arrays to choose the value of the input_channel
  30. * argument to hsdp_set_mixer_gain(). hdsp_physical_input_index[n]
  31. * selects the nth optical/analog input. audio_stream_index[n]
  32. * selects the nth channel being received from the host via pci/pccard.
  33. */
  34. static const int hdsp_num_input_channels = 52;
  35. static const int hdsp_physical_input_index[] = {
  36. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
  37. 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};
  38. static const int hdsp_audio_stream_index[] = {
  39. 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
  40. 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
  41. /*
  42. * Use this array to choose the value of the output_channel
  43. * argument to hsdp_set_mixer_gain(). hdsp_physical_output_index[26]
  44. * and hdsp_physical_output_index[27] refer to the two "line out"
  45. * channels (1/4" phone jack on the front of digiface/multiface).
  46. */
  47. static const int hdsp_num_output_channels = 28;
  48. static const int hdsp_physical_output_index[] = {
  49. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
  50. 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};
  51. /* Function for checking argument values */
  52. static int clamp_int(int value, int lower_bound, int upper_bound)
  53. {
  54. if(value < lower_bound) {
  55. return lower_bound;
  56. }
  57. if(value > upper_bound) {
  58. return upper_bound;
  59. }
  60. return value;
  61. }
  62. /* Note(XXX): Maybe should share this code with hammerfall.c? */
  63. static void
  64. set_control_id (snd_ctl_elem_id_t *ctl, const char *name)
  65. {
  66. snd_ctl_elem_id_set_name (ctl, name);
  67. snd_ctl_elem_id_set_numid (ctl, 0);
  68. snd_ctl_elem_id_set_interface (ctl, SND_CTL_ELEM_IFACE_HWDEP);
  69. snd_ctl_elem_id_set_device (ctl, 0);
  70. snd_ctl_elem_id_set_subdevice (ctl, 0);
  71. snd_ctl_elem_id_set_index (ctl, 0);
  72. }
  73. /* The hdsp matrix mixer lets you connect pretty much any input to */
  74. /* any output with gain from -inf to about +2dB. Pretty slick. */
  75. /* This routine makes a convenient way to set the gain from */
  76. /* input_channel to output_channel (see hdsp_physical_input_index */
  77. /* etc. above. */
  78. /* gain is an int from 0 to 65535, with 0 being -inf gain, and */
  79. /* 65535 being about +2dB. */
  80. static int hdsp_set_mixer_gain(jack_hardware_t *hw, int input_channel,
  81. int output_channel, int gain)
  82. {
  83. hdsp_t *h = (hdsp_t *) hw->private_hw;
  84. snd_ctl_elem_value_t *ctl;
  85. snd_ctl_elem_id_t *ctl_id;
  86. int err;
  87. /* Check args */
  88. input_channel = clamp_int(input_channel, 0, hdsp_num_input_channels);
  89. output_channel = clamp_int(output_channel, 0, hdsp_num_output_channels);
  90. gain = clamp_int(gain, HDSP_MINUS_INFINITY_GAIN, HDSP_MAX_GAIN);
  91. /* Allocate control element and select "Mixer" control */
  92. snd_ctl_elem_value_alloca (&ctl);
  93. snd_ctl_elem_id_alloca (&ctl_id);
  94. set_control_id (ctl_id, "Mixer");
  95. snd_ctl_elem_value_set_id (ctl, ctl_id);
  96. /* Apparently non-standard and unstable interface for the */
  97. /* mixer control. */
  98. snd_ctl_elem_value_set_integer (ctl, 0, input_channel);
  99. snd_ctl_elem_value_set_integer (ctl, 1, output_channel);
  100. snd_ctl_elem_value_set_integer (ctl, 2, gain);
  101. /* Commit the mixer value and check for errors */
  102. if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) != 0) {
  103. jack_error ("ALSA/HDSP: cannot set mixer gain (%s)", snd_strerror (err));
  104. return -1;
  105. }
  106. /* Note (XXX): Perhaps we should maintain a cache of the current */
  107. /* mixer values, since it's not clear how to query them from the */
  108. /* hdsp hardware. We'll leave this out until a little later. */
  109. return 0;
  110. }
  111. static int hdsp_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask)
  112. {
  113. int i;
  114. /* For each input channel */
  115. for (i = 0; i < 26; i++) {
  116. /* Monitoring requested for this channel? */
  117. if(mask & (1<<i)) {
  118. /* Yes. Connect physical input to output */
  119. if(hdsp_set_mixer_gain (hw, hdsp_physical_input_index[i],
  120. hdsp_physical_output_index[i],
  121. HDSP_UNITY_GAIN) != 0) {
  122. return -1;
  123. }
  124. #ifdef CANNOT_HEAR_SOFTWARE_STREAM_WHEN_MONITORING
  125. /* ...and disconnect the corresponding software */
  126. /* channel */
  127. if(hdsp_set_mixer_gain (hw, hdsp_audio_stream_index[i],
  128. hdsp_physical_output_index[i],
  129. HDSP_MINUS_INFINITY_GAIN) != 0) {
  130. return -1;
  131. }
  132. #endif
  133. } else {
  134. /* No. Disconnect physical input from output */
  135. if(hdsp_set_mixer_gain (hw, hdsp_physical_input_index[i],
  136. hdsp_physical_output_index[i],
  137. HDSP_MINUS_INFINITY_GAIN) != 0) {
  138. return -1;
  139. }
  140. #ifdef CANNOT_HEAR_SOFTWARE_STREAM_WHEN_MONITORING
  141. /* ...and connect the corresponding software */
  142. /* channel */
  143. if(hdsp_set_mixer_gain (hw, hdsp_audio_stream_index[i],
  144. hdsp_physical_output_index[i],
  145. HDSP_UNITY_GAIN) != 0) {
  146. return -1;
  147. }
  148. #endif
  149. }
  150. }
  151. /* Cache the monitor mask */
  152. hw->input_monitor_mask = mask;
  153. return 0;
  154. }
  155. static int hdsp_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode)
  156. {
  157. // Empty for now, until Dave understands more about clock sync so
  158. // he can test.
  159. return -1;
  160. }
  161. static double hdsp_get_hardware_peak (jack_port_t *port, jack_nframes_t frame)
  162. {
  163. return 0;
  164. }
  165. static double hdsp_get_hardware_power (jack_port_t *port, jack_nframes_t frame)
  166. {
  167. return 0;
  168. }
  169. static void
  170. hdsp_release (jack_hardware_t *hw)
  171. {
  172. hdsp_t *h = (hdsp_t *) hw->private_hw;
  173. if (h != 0) {
  174. free (h);
  175. }
  176. }
  177. /* Mostly copied directly from hammerfall.c */
  178. jack_hardware_t *
  179. jack_alsa_hdsp_hw_new (alsa_driver_t *driver)
  180. {
  181. jack_hardware_t *hw;
  182. hdsp_t *h;
  183. hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t));
  184. /* Not using clock lock-sync-whatever in home hardware setup */
  185. /* yet. Will write this code when can test it. */
  186. /* hw->capabilities = Cap_HardwareMonitoring|Cap_AutoSync|Cap_WordClock|Cap_ClockMaster|Cap_ClockLockReporting; */
  187. hw->capabilities = Cap_HardwareMonitoring | Cap_HardwareMetering;
  188. hw->input_monitor_mask = 0;
  189. hw->private_hw = 0;
  190. hw->set_input_monitor_mask = hdsp_set_input_monitor_mask;
  191. hw->change_sample_clock = hdsp_change_sample_clock;
  192. hw->release = hdsp_release;
  193. hw->get_hardware_peak = hdsp_get_hardware_peak;
  194. hw->get_hardware_power = hdsp_get_hardware_power;
  195. h = (hdsp_t *) malloc (sizeof (hdsp_t));
  196. h->driver = driver;
  197. hw->private_hw = h;
  198. return hw;
  199. }