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