1 |
/* |
---|
2 |
* FreeBob Backend for Jack |
---|
3 |
* FreeBob = Firewire (pro-)audio for linux |
---|
4 |
* |
---|
5 |
* http://freebob.sf.net |
---|
6 |
* http://jackit.sf.net |
---|
7 |
* |
---|
8 |
* Copyright (C) 2005 Pieter Palmers <pieterpalmers@users.sourceforge.net> |
---|
9 |
* |
---|
10 |
* This program is free software; you can redistribute it and/or modify |
---|
11 |
* it under the terms of the GNU General Public License as published by |
---|
12 |
* the Free Software Foundation; either version 2 of the License, or |
---|
13 |
* (at your option) any later version. |
---|
14 |
* |
---|
15 |
* This program is distributed in the hope that it will be useful, |
---|
16 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
17 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
18 |
* GNU General Public License for more details. |
---|
19 |
* |
---|
20 |
* You should have received a copy of the GNU General Public License |
---|
21 |
* along with this program; if not, write to the Free Software |
---|
22 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
23 |
*/ |
---|
24 |
|
---|
25 |
/* |
---|
26 |
* Main Jack driver entry routines |
---|
27 |
* |
---|
28 |
*/ |
---|
29 |
|
---|
30 |
#include <math.h> |
---|
31 |
#include <stdio.h> |
---|
32 |
#include <memory.h> |
---|
33 |
#include <unistd.h> |
---|
34 |
#include <stdlib.h> |
---|
35 |
#include <errno.h> |
---|
36 |
#include <stdarg.h> |
---|
37 |
#include <sys/mman.h> |
---|
38 |
|
---|
39 |
#include <jack/types.h> |
---|
40 |
#include <jack/internal.h> |
---|
41 |
#include <jack/engine.h> |
---|
42 |
#include <sysdeps/time.h> |
---|
43 |
|
---|
44 |
#include "freebob_driver.h" |
---|
45 |
|
---|
46 |
#define SAMPLE_MAX_24BIT 8388608.0f |
---|
47 |
#define SAMPLE_MAX_16BIT 32768.0f |
---|
48 |
|
---|
49 |
static int freebob_driver_stop (freebob_driver_t *driver); |
---|
50 |
|
---|
51 |
#ifdef FREEBOB_DRIVER_WITH_MIDI |
---|
52 |
static freebob_driver_midi_handle_t *freebob_driver_midi_init(freebob_driver_t *driver); |
---|
53 |
static void freebob_driver_midi_finish (freebob_driver_midi_handle_t *m); |
---|
54 |
#endif |
---|
55 |
|
---|
56 |
static int |
---|
57 |
freebob_driver_attach (freebob_driver_t *driver) |
---|
58 |
{ |
---|
59 |
char buf[64]; |
---|
60 |
channel_t chn; |
---|
61 |
jack_port_t *port; |
---|
62 |
int port_flags; |
---|
63 |
|
---|
64 |
driver->engine->set_buffer_size (driver->engine, driver->period_size); |
---|
65 |
driver->engine->set_sample_rate (driver->engine, driver->sample_rate); |
---|
66 |
|
---|
67 |
port_flags = JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal; |
---|
68 |
|
---|
69 |
driver->capture_nchannels=freebob_streaming_get_nb_capture_streams(driver->dev); |
---|
70 |
|
---|
71 |
for (chn = 0; chn < driver->capture_nchannels; chn++) { |
---|
72 |
|
---|
73 |
freebob_streaming_get_capture_stream_name(driver->dev, chn, buf, sizeof(buf) - 1); |
---|
74 |
|
---|
75 |
if(freebob_streaming_get_capture_stream_type(driver->dev, chn) != freebob_stream_type_audio) { |
---|
76 |
printMessage ("Don't register capture port %s\n", buf); |
---|
77 |
// continue; |
---|
78 |
// we have to add a NULL entry in the list to be able to loop over the channels in the read/write routines |
---|
79 |
driver->capture_ports = |
---|
80 |
jack_slist_append (driver->capture_ports, NULL); |
---|
81 |
} else { |
---|
82 |
printMessage ("Registering capture port %s\n", buf); |
---|
83 |
if ((port = jack_port_register (driver->client, buf, |
---|
84 |
JACK_DEFAULT_AUDIO_TYPE, |
---|
85 |
port_flags, 0)) == NULL) { |
---|
86 |
jack_error ("FREEBOB: cannot register port for %s", buf); |
---|
87 |
break; |
---|
88 |
} |
---|
89 |
driver->capture_ports = |
---|
90 |
jack_slist_append (driver->capture_ports, port); |
---|
91 |
} |
---|
92 |
|
---|
93 |
|
---|
94 |
// jack_port_set_latency (port, driver->period_size); |
---|
95 |
|
---|
96 |
} |
---|
97 |
|
---|
98 |
port_flags = JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal; |
---|
99 |
|
---|
100 |
driver->playback_nchannels=freebob_streaming_get_nb_playback_streams(driver->dev); |
---|
101 |
|
---|
102 |
for (chn = 0; chn < driver->playback_nchannels; chn++) { |
---|
103 |
|
---|
104 |
freebob_streaming_get_playback_stream_name(driver->dev, chn, buf, sizeof(buf) - 1); |
---|
105 |
|
---|
106 |
if(freebob_streaming_get_playback_stream_type(driver->dev, chn) != freebob_stream_type_audio) { |
---|
107 |
printMessage ("Don't register playback port %s\n", buf); |
---|
108 |
// continue; |
---|
109 |
// we have to add a NULL entry in the list to be able to loop over the channels in the read/write routines |
---|
110 |
driver->playback_ports = |
---|
111 |
jack_slist_append (driver->playback_ports, NULL); |
---|
112 |
} else { |
---|
113 |
printMessage ("Registering playback port %s\n", buf); |
---|
114 |
if ((port = jack_port_register (driver->client, buf, |
---|
115 |
JACK_DEFAULT_AUDIO_TYPE, |
---|
116 |
port_flags, 0)) == NULL) { |
---|
117 |
jack_error ("FREEBOB: cannot register port for %s", buf); |
---|
118 |
break; |
---|
119 |
} |
---|
120 |
driver->playback_ports = |
---|
121 |
jack_slist_append (driver->playback_ports, port); |
---|
122 |
} |
---|
123 |
// jack_port_set_latency (port, (driver->period_size * (driver->user_nperiods - 1)) + driver->playback_frame_latency); |
---|
124 |
|
---|
125 |
} |
---|
126 |
|
---|
127 |
return jack_activate (driver->client); |
---|
128 |
} |
---|
129 |
|
---|
130 |
static int |
---|
131 |
freebob_driver_detach (freebob_driver_t *driver) |
---|
132 |
{ |
---|
133 |
JSList *node; |
---|
134 |
|
---|
135 |
if (driver->engine == NULL) { |
---|
136 |
return 0; |
---|
137 |
} |
---|
138 |
|
---|
139 |
for (node = driver->capture_ports; node; |
---|
140 |
node = jack_slist_next (node)) { |
---|
141 |
jack_port_unregister (driver->client, |
---|
142 |
((jack_port_t *) node->data)); |
---|
143 |
} |
---|
144 |
|
---|
145 |
jack_slist_free (driver->capture_ports); |
---|
146 |
driver->capture_ports = 0; |
---|
147 |
|
---|
148 |
for (node = driver->playback_ports; node; |
---|
149 |
node = jack_slist_next (node)) { |
---|
150 |
jack_port_unregister (driver->client, |
---|
151 |
((jack_port_t *) node->data)); |
---|
152 |
} |
---|
153 |
|
---|
154 |
jack_slist_free (driver->playback_ports); |
---|
155 |
driver->playback_ports = 0; |
---|
156 |
|
---|
157 |
return 0; |
---|
158 |
|
---|
159 |
} |
---|
160 |
|
---|
161 |
static inline void |
---|
162 |
freebob_driver_read_from_channel (freebob_driver_t *driver, |
---|
163 |
channel_t channel, |
---|
164 |
jack_default_audio_sample_t *dst, |
---|
165 |
jack_nframes_t nsamples) |
---|
166 |
{ |
---|
167 |
|
---|
168 |
freebob_sample_t buffer[nsamples]; |
---|
169 |
char *src=(char *)buffer; |
---|
170 |
|
---|
171 |
freebob_streaming_read(driver->dev, channel, buffer, nsamples); |
---|
172 |
|
---|
173 |
#if 0 |
---|
174 |
int i=0; |
---|
175 |
if(channel==0) { |
---|
176 |
jack_error("Read for channel %d",channel); |
---|
177 |
for (i=0;i<nsamples;i+=8) { |
---|
178 |
fprintf(stderr," %08X %08X %08X %08X %08X %08X %08X %08X\n", |
---|
179 |
buffer[i], |
---|
180 |
buffer[i+1], |
---|
181 |
buffer[i+2], |
---|
182 |
buffer[i+3], |
---|
183 |
buffer[i+4], |
---|
184 |
buffer[i+5], |
---|
185 |
buffer[i+6], |
---|
186 |
buffer[i+7] |
---|
187 |
); |
---|
188 |
} |
---|
189 |
} |
---|
190 |
#endif |
---|
191 |
/* ALERT: signed sign-extension portability !!! */ |
---|
192 |
|
---|
193 |
while (nsamples--) { |
---|
194 |
int x; |
---|
195 |
#if __BYTE_ORDER == __LITTLE_ENDIAN |
---|
196 |
memcpy((char*)&x + 1, src, 3); |
---|
197 |
#elif __BYTE_ORDER == __BIG_ENDIAN |
---|
198 |
memcpy(&x, src, 3); |
---|
199 |
#endif |
---|
200 |
x >>= 8; |
---|
201 |
*dst = x / SAMPLE_MAX_24BIT; |
---|
202 |
dst++; |
---|
203 |
src += sizeof(freebob_sample_t); |
---|
204 |
} |
---|
205 |
|
---|
206 |
} |
---|
207 |
|
---|
208 |
static int |
---|
209 |
freebob_driver_read (freebob_driver_t * driver, jack_nframes_t nframes) |
---|
210 |
{ |
---|
211 |
jack_default_audio_sample_t* buf; |
---|
212 |
channel_t chn; |
---|
213 |
JSList *node; |
---|
214 |
jack_port_t* port; |
---|
215 |
|
---|
216 |
freebob_sample_t nullbuffer[nframes]; |
---|
217 |
|
---|
218 |
freebob_streaming_stream_type stream_type; |
---|
219 |
|
---|
220 |
printEnter(); |
---|
221 |
|
---|
222 |
for (chn = 0, node = driver->capture_ports; node; node = jack_slist_next (node), chn++) { |
---|
223 |
stream_type = freebob_streaming_get_capture_stream_type(driver->dev, chn); |
---|
224 |
if(stream_type == freebob_stream_type_audio) { |
---|
225 |
port = (jack_port_t *) node->data; |
---|
226 |
|
---|
227 |
buf = jack_port_get_buffer (port, nframes); |
---|
228 |
if(!buf) buf=nullbuffer; |
---|
229 |
|
---|
230 |
freebob_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(buf), freebob_buffer_type_float); |
---|
231 |
} else if(stream_type == freebob_stream_type_midi) { |
---|
232 |
// these should be read/written with the per-stream functions |
---|
233 |
|
---|
234 |
} else { // empty other buffers without doing something with them |
---|
235 |
freebob_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(nullbuffer), freebob_buffer_type_uint24); |
---|
236 |
} |
---|
237 |
} |
---|
238 |
|
---|
239 |
// now transfer the buffers |
---|
240 |
freebob_streaming_transfer_capture_buffers(driver->dev); |
---|
241 |
|
---|
242 |
printExit(); |
---|
243 |
|
---|
244 |
return 0; |
---|
245 |
|
---|
246 |
} |
---|
247 |
|
---|
248 |
static inline void |
---|
249 |
freebob_driver_write_to_channel (freebob_driver_t *driver, |
---|
250 |
channel_t channel, |
---|
251 |
jack_default_audio_sample_t *buf, |
---|
252 |
jack_nframes_t nsamples) |
---|
253 |
{ |
---|
254 |
long long y; |
---|
255 |
freebob_sample_t buffer[nsamples]; |
---|
256 |
unsigned int i=0; |
---|
257 |
char *dst=(char *)buffer; |
---|
258 |
|
---|
259 |
// convert from float to integer |
---|
260 |
for(;i<nsamples;i++) { |
---|
261 |
y = (long long)(*buf * SAMPLE_MAX_24BIT); |
---|
262 |
|
---|
263 |
if (y > (INT_MAX >> 8 )) { |
---|
264 |
y = (INT_MAX >> 8); |
---|
265 |
} else if (y < (INT_MIN >> 8 )) { |
---|
266 |
y = (INT_MIN >> 8 ); |
---|
267 |
} |
---|
268 |
#if __BYTE_ORDER == __LITTLE_ENDIAN |
---|
269 |
memcpy (dst, &y, 3); |
---|
270 |
#elif __BYTE_ORDER == __BIG_ENDIAN |
---|
271 |
memcpy (dst, (char *)&y + 5, 3); |
---|
272 |
#endif |
---|
273 |
dst += sizeof(freebob_sample_t); |
---|
274 |
buf++; |
---|
275 |
} |
---|
276 |
|
---|
277 |
// write to the freebob streaming device |
---|
278 |
freebob_streaming_write(driver->dev, channel, buffer, nsamples); |
---|
279 |
|
---|
280 |
} |
---|
281 |
|
---|
282 |
static int |
---|
283 |
freebob_driver_write (freebob_driver_t * driver, jack_nframes_t nframes) |
---|
284 |
{ |
---|
285 |
channel_t chn; |
---|
286 |
JSList *node; |
---|
287 |
jack_default_audio_sample_t* buf; |
---|
288 |
|
---|
289 |
jack_port_t *port; |
---|
290 |
|
---|
291 |
freebob_streaming_stream_type stream_type; |
---|
292 |
|
---|
293 |
freebob_sample_t nullbuffer[nframes]; |
---|
294 |
|
---|
295 |
memset(&nullbuffer,0,nframes*sizeof(freebob_sample_t)); |
---|
296 |
|
---|
297 |
printEnter(); |
---|
298 |
|
---|
299 |
driver->process_count++; |
---|
300 |
|
---|
301 |
assert(driver->dev); |
---|
302 |
|
---|
303 |
if (driver->engine->freewheeling) { |
---|
304 |
return 0; |
---|
305 |
} |
---|
306 |
|
---|
307 |
for (chn = 0, node = driver->playback_ports; node; node = jack_slist_next (node), chn++) { |
---|
308 |
stream_type=freebob_streaming_get_playback_stream_type(driver->dev, chn); |
---|
309 |
if(stream_type == freebob_stream_type_audio) { |
---|
310 |
port = (jack_port_t *) node->data; |
---|
311 |
|
---|
312 |
buf = jack_port_get_buffer (port, nframes); |
---|
313 |
if(!buf) buf=nullbuffer; |
---|
314 |
|
---|
315 |
freebob_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(buf), freebob_buffer_type_float); |
---|
316 |
|
---|
317 |
} else if(stream_type == freebob_stream_type_midi) { |
---|
318 |
// these should be read/written with the per-stream functions |
---|
319 |
|
---|
320 |
} else { // empty other buffers without doing something with them |
---|
321 |
freebob_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(nullbuffer), freebob_buffer_type_uint24); |
---|
322 |
} |
---|
323 |
} |
---|
324 |
|
---|
325 |
freebob_streaming_transfer_playback_buffers(driver->dev); |
---|
326 |
|
---|
327 |
printExit(); |
---|
328 |
|
---|
329 |
return 0; |
---|
330 |
} |
---|
331 |
|
---|
332 |
//static inline jack_nframes_t |
---|
333 |
static jack_nframes_t |
---|
334 |
freebob_driver_wait (freebob_driver_t *driver, int extra_fd, int *status, |
---|
335 |
float *delayed_usecs) |
---|
336 |
{ |
---|
337 |
int nframes; |
---|
338 |
jack_time_t wait_enter; |
---|
339 |
jack_time_t wait_ret; |
---|
340 |
|
---|
341 |
printEnter(); |
---|
342 |
|
---|
343 |
wait_enter = jack_get_microseconds (); |
---|
344 |
if (wait_enter > driver->wait_next) { |
---|
345 |
/* |
---|
346 |
* This processing cycle was delayed past the |
---|
347 |
* next due interrupt! Do not account this as |
---|
348 |
* a wakeup delay: |
---|
349 |
*/ |
---|
350 |
driver->wait_next = 0; |
---|
351 |
driver->wait_late++; |
---|
352 |
} |
---|
353 |
// *status = -2; interrupt |
---|
354 |
// *status = -3; timeout |
---|
355 |
// *status = -4; extra FD |
---|
356 |
|
---|
357 |
nframes=freebob_streaming_wait(driver->dev); |
---|
358 |
|
---|
359 |
wait_ret = jack_get_microseconds (); |
---|
360 |
|
---|
361 |
if (driver->wait_next && wait_ret > driver->wait_next) { |
---|
362 |
*delayed_usecs = wait_ret - driver->wait_next; |
---|
363 |
} |
---|
364 |
driver->wait_last = wait_ret; |
---|
365 |
driver->wait_next = wait_ret + driver->period_usecs; |
---|
366 |
driver->engine->transport_cycle_start (driver->engine, wait_ret); |
---|
367 |
|
---|
368 |
// transfer the streaming buffers |
---|
369 |
// we now do this in the read/write functions |
---|
370 |
// freebob_streaming_transfer_buffers(driver->dev); |
---|
371 |
|
---|
372 |
if (nframes < 0) { |
---|
373 |
*status=0; |
---|
374 |
|
---|
375 |
return 0; |
---|
376 |
//nframes=driver->period_size; //debug |
---|
377 |
} |
---|
378 |
|
---|
379 |
*status = 0; |
---|
380 |
driver->last_wait_ust = wait_ret; |
---|
381 |
|
---|
382 |
// FIXME: this should do something more usefull |
---|
383 |
*delayed_usecs = 0; |
---|
384 |
|
---|
385 |
printExit(); |
---|
386 |
|
---|
387 |
return nframes - nframes % driver->period_size; |
---|
388 |
|
---|
389 |
} |
---|
390 |
|
---|
391 |
static int |
---|
392 |
freebob_driver_run_cycle (freebob_driver_t *driver) |
---|
393 |
{ |
---|
394 |
jack_engine_t *engine = driver->engine; |
---|
395 |
int wait_status=0; |
---|
396 |
float delayed_usecs=0.0; |
---|
397 |
|
---|
398 |
jack_nframes_t nframes = freebob_driver_wait (driver, -1, &wait_status, |
---|
399 |
&delayed_usecs); |
---|
400 |
|
---|
401 |
if ((wait_status < 0)) { |
---|
402 |
jack_error( "wait status < 0! (= %d)\n",wait_status); |
---|
403 |
return -1; |
---|
404 |
} |
---|
405 |
|
---|
406 |
if ((nframes == 0)) { |
---|
407 |
/* we detected an xrun and restarted: notify |
---|
408 |
* clients about the delay. */ |
---|
409 |
jack_error( "xrun detected\n"); |
---|
410 |
engine->delay (engine, delayed_usecs); |
---|
411 |
return 0; |
---|
412 |
} |
---|
413 |
|
---|
414 |
return engine->run_cycle (engine, nframes, delayed_usecs); |
---|
415 |
|
---|
416 |
} |
---|
417 |
/* |
---|
418 |
* in a null cycle we should discard the input and write silence to the outputs |
---|
419 |
*/ |
---|
420 |
static int |
---|
421 |
freebob_driver_null_cycle (freebob_driver_t* driver, jack_nframes_t nframes) |
---|
422 |
{ |
---|
423 |
jack_error("Null cycle...\n"); |
---|
424 |
channel_t chn; |
---|
425 |
JSList *node; |
---|
426 |
snd_pcm_sframes_t nwritten; |
---|
427 |
|
---|
428 |
freebob_streaming_stream_type stream_type; |
---|
429 |
|
---|
430 |
jack_default_audio_sample_t buff[nframes]; |
---|
431 |
jack_default_audio_sample_t* buffer=(jack_default_audio_sample_t*)buff; |
---|
432 |
|
---|
433 |
printEnter(); |
---|
434 |
|
---|
435 |
memset(buffer,0,nframes*sizeof(jack_default_audio_sample_t)); |
---|
436 |
|
---|
437 |
assert(driver->dev); |
---|
438 |
|
---|
439 |
if (driver->engine->freewheeling) { |
---|
440 |
return 0; |
---|
441 |
} |
---|
442 |
|
---|
443 |
// write silence to buffer |
---|
444 |
nwritten = 0; |
---|
445 |
|
---|
446 |
for (chn = 0, node = driver->playback_ports; node; node = jack_slist_next (node), chn++) { |
---|
447 |
stream_type=freebob_streaming_get_playback_stream_type(driver->dev, chn); |
---|
448 |
|
---|
449 |
if(stream_type == freebob_stream_type_audio) { |
---|
450 |
freebob_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(buffer), freebob_buffer_type_float); |
---|
451 |
|
---|
452 |
} else if(stream_type == freebob_stream_type_midi) { |
---|
453 |
// these should be read/written with the per-stream functions |
---|
454 |
|
---|
455 |
} else { // empty other buffers without doing something with them |
---|
456 |
freebob_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(buffer), freebob_buffer_type_uint24); |
---|
457 |
} |
---|
458 |
} |
---|
459 |
|
---|
460 |
freebob_streaming_transfer_playback_buffers(driver->dev); |
---|
461 |
|
---|
462 |
// read & discard from input ports |
---|
463 |
for (chn = 0, node = driver->capture_ports; node; node = jack_slist_next (node), chn++) { |
---|
464 |
stream_type=freebob_streaming_get_capture_stream_type(driver->dev, chn); |
---|
465 |
if(stream_type == freebob_stream_type_audio) { |
---|
466 |
freebob_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(buffer), freebob_buffer_type_float); |
---|
467 |
|
---|
468 |
} else if(stream_type == freebob_stream_type_midi) { |
---|
469 |
|
---|
470 |
} else { // empty other buffers without doing something with them |
---|
471 |
} |
---|
472 |
} |
---|
473 |
|
---|
474 |
// now transfer the buffers |
---|
475 |
freebob_streaming_transfer_capture_buffers(driver->dev); |
---|
476 |
|
---|
477 |
printExit(); |
---|
478 |
return 0; |
---|
479 |
} |
---|
480 |
|
---|
481 |
static int |
---|
482 |
freebob_driver_start (freebob_driver_t *driver) |
---|
483 |
{ |
---|
484 |
jack_error("Driver start...\n"); |
---|
485 |
return freebob_streaming_start(driver->dev); |
---|
486 |
|
---|
487 |
} |
---|
488 |
|
---|
489 |
static int |
---|
490 |
freebob_driver_stop (freebob_driver_t *driver) |
---|
491 |
{ |
---|
492 |
jack_error("Driver stop...\n"); |
---|
493 |
|
---|
494 |
return freebob_streaming_stop(driver->dev); |
---|
495 |
} |
---|
496 |
|
---|
497 |
|
---|
498 |
static int |
---|
499 |
freebob_driver_bufsize (freebob_driver_t* driver, jack_nframes_t nframes) |
---|
500 |
{ |
---|
501 |
jack_error("Buffer size change requested!!!\n"); |
---|
502 |
|
---|
503 |
/* |
---|
504 |
driver->period_size = nframes; |
---|
505 |
driver->period_usecs = |
---|
506 |
(jack_time_t) floor ((((float) nframes) / driver->sample_rate) |
---|
507 |
* 1000000.0f); |
---|
508 |
*/ |
---|
509 |
|
---|
510 |
/* tell the engine to change its buffer size */ |
---|
511 |
//driver->engine->set_buffer_size (driver->engine, nframes); |
---|
512 |
|
---|
513 |
return -1; // unsupported |
---|
514 |
} |
---|
515 |
|
---|
516 |
typedef void (*JackDriverFinishFunction) (jack_driver_t *); |
---|
517 |
|
---|
518 |
freebob_driver_t * |
---|
519 |
freebob_driver_new (jack_client_t * client, |
---|
520 |
char *name, |
---|
521 |
freebob_jack_settings_t *params) |
---|
522 |
{ |
---|
523 |
freebob_driver_t *driver; |
---|
524 |
freebob_device_info_t device_info; |
---|
525 |
freebob_options_t device_options; |
---|
526 |
|
---|
527 |
assert(params); |
---|
528 |
|
---|
529 |
driver = calloc (1, sizeof (freebob_driver_t)); |
---|
530 |
|
---|
531 |
/* Setup the jack interfaces */ |
---|
532 |
jack_driver_nt_init ((jack_driver_nt_t *) driver); |
---|
533 |
|
---|
534 |
driver->nt_attach = (JackDriverNTAttachFunction) freebob_driver_attach; |
---|
535 |
driver->nt_detach = (JackDriverNTDetachFunction) freebob_driver_detach; |
---|
536 |
driver->nt_start = (JackDriverNTStartFunction) freebob_driver_start; |
---|
537 |
driver->nt_stop = (JackDriverNTStopFunction) freebob_driver_stop; |
---|
538 |
driver->nt_run_cycle = (JackDriverNTRunCycleFunction) freebob_driver_run_cycle; |
---|
539 |
driver->null_cycle = (JackDriverNullCycleFunction) freebob_driver_null_cycle; |
---|
540 |
driver->write = (JackDriverReadFunction) freebob_driver_write; |
---|
541 |
driver->read = (JackDriverReadFunction) freebob_driver_read; |
---|
542 |
driver->nt_bufsize = (JackDriverNTBufSizeFunction) freebob_driver_bufsize; |
---|
543 |
|
---|
544 |
/* copy command line parameter contents to the driver structure */ |
---|
545 |
memcpy(&driver->settings,params,sizeof(freebob_jack_settings_t)); |
---|
546 |
|
---|
547 |
/* prepare all parameters */ |
---|
548 |
driver->sample_rate = params->sample_rate; |
---|
549 |
driver->period_size = params->period_size; |
---|
550 |
driver->last_wait_ust = 0; |
---|
551 |
|
---|
552 |
driver->period_usecs = |
---|
553 |
(jack_time_t) floor ((((float) driver->period_size) * 1000000.0f) / driver->sample_rate); |
---|
554 |
|
---|
555 |
driver->client = client; |
---|
556 |
driver->engine = NULL; |
---|
557 |
|
---|
558 |
device_options.sample_rate=params->sample_rate; |
---|
559 |
device_options.period_size=params->period_size; |
---|
560 |
device_options.nb_buffers=params->buffer_size; |
---|
561 |
device_options.iso_buffers=params->iso_buffers; |
---|
562 |
device_options.iso_prebuffers=params->iso_prebuffers; |
---|
563 |
device_options.iso_irq_interval=params->iso_irq_interval; |
---|
564 |
device_options.node_id=params->node_id; |
---|
565 |
device_options.port=params->port; |
---|
566 |
|
---|
567 |
/* packetizer thread options */ |
---|
568 |
|
---|
569 |
device_options.realtime=FREEBOB_USE_RT; |
---|
570 |
device_options.packetizer_priority=FREEBOB_RT_PRIORITY_PACKETIZER; |
---|
571 |
|
---|
572 |
driver->dev=freebob_streaming_init(&device_info,device_options); |
---|
573 |
|
---|
574 |
if(!driver->dev) { |
---|
575 |
jack_error("FREEBOB: Error creating virtual device"); |
---|
576 |
jack_driver_nt_finish ((jack_driver_nt_t *) driver); |
---|
577 |
free (driver); |
---|
578 |
return NULL; |
---|
579 |
} |
---|
580 |
|
---|
581 |
#ifdef FREEBOB_DRIVER_WITH_MIDI |
---|
582 |
driver->midi_handle=freebob_driver_midi_init(driver); |
---|
583 |
if(!driver->midi_handle) { |
---|
584 |
jack_error("FREEBOB: Error creating midi device"); |
---|
585 |
jack_driver_nt_finish ((jack_driver_nt_t *) driver); |
---|
586 |
free (driver); |
---|
587 |
return NULL; |
---|
588 |
} |
---|
589 |
#endif |
---|
590 |
|
---|
591 |
jack_error("FREEBOB: Driver compiled on %s %s", __DATE__, __TIME__); |
---|
592 |
jack_error("FREEBOB: Created driver %s", name); |
---|
593 |
jack_error(" period_size: %d", driver->period_size); |
---|
594 |
jack_error(" period_usecs: %d", driver->period_usecs); |
---|
595 |
jack_error(" sample rate: %d", driver->sample_rate); |
---|
596 |
if (device_options.realtime) { |
---|
597 |
jack_error(" running with Realtime scheduling, priority %d", device_options.packetizer_priority); |
---|
598 |
} else { |
---|
599 |
jack_error(" running without Realtime scheduling"); |
---|
600 |
} |
---|
601 |
|
---|
602 |
|
---|
603 |
|
---|
604 |
return (freebob_driver_t *) driver; |
---|
605 |
|
---|
606 |
} |
---|
607 |
|
---|
608 |
static void |
---|
609 |
freebob_driver_delete (freebob_driver_t *driver) |
---|
610 |
{ |
---|
611 |
|
---|
612 |
freebob_streaming_finish(driver->dev); |
---|
613 |
|
---|
614 |
#ifdef FREEBOB_DRIVER_WITH_MIDI |
---|
615 |
freebob_driver_midi_finish(driver->midi_handle); |
---|
616 |
#endif |
---|
617 |
|
---|
618 |
jack_driver_nt_finish ((jack_driver_nt_t *) driver); |
---|
619 |
free (driver); |
---|
620 |
} |
---|
621 |
|
---|
622 |
#ifdef FREEBOB_DRIVER_WITH_MIDI |
---|
623 |
/* |
---|
624 |
* MIDI support |
---|
625 |
*/ |
---|
626 |
|
---|
627 |
// the thread that will queue the midi events from the seq to the stream buffers |
---|
628 |
|
---|
629 |
void * freebob_driver_midi_queue_thread(void *arg) |
---|
630 |
{ |
---|
631 |
freebob_driver_midi_handle_t *m=(freebob_driver_midi_handle_t *)arg; |
---|
632 |
assert(m); |
---|
633 |
snd_seq_event_t *ev; |
---|
634 |
unsigned char work_buffer[MIDI_TRANSMIT_BUFFER_SIZE]; |
---|
635 |
int bytes_to_send; |
---|
636 |
int b; |
---|
637 |
int i; |
---|
638 |
|
---|
639 |
jack_error ("FREEBOB: MIDI queue thread started"); |
---|
640 |
|
---|
641 |
while(1) { |
---|
642 |
// get next event, if one is present |
---|
643 |
while ((snd_seq_event_input(m->seq_handle, &ev) > 0)) { |
---|
644 |
// get the port this event is originated from |
---|
645 |
freebob_midi_port_t *port=NULL; |
---|
646 |
for (i=0;i<m->nb_output_ports;i++) { |
---|
647 |
if(m->output_ports[i]->seq_port_nr == ev->dest.port) { |
---|
648 |
port=m->output_ports[i]; |
---|
649 |
break; |
---|
650 |
} |
---|
651 |
} |
---|
652 |
|
---|
653 |
if(!port) { |
---|
654 |
jack_error ("FREEBOB: Could not find target port for event: dst=%d src=%d\n", ev->dest.port, ev->source.port); |
---|
655 |
|
---|
656 |
break; |
---|
657 |
} |
---|
658 |
|
---|
659 |
// decode it to the work buffer |
---|
660 |
if((bytes_to_send = snd_midi_event_decode ( port->parser, |
---|
661 |
work_buffer, |
---|
662 |
MIDI_TRANSMIT_BUFFER_SIZE, |
---|
663 |
ev))<0) |
---|
664 |
{ // failed |
---|
665 |
jack_error ("FREEBOB: Error decoding event for port %d (errcode=%d)\n", port->seq_port_nr,bytes_to_send); |
---|
666 |
bytes_to_send=0; |
---|
667 |
//return -1; |
---|
668 |
} |
---|
669 |
|
---|
670 |
for(b=0;b<bytes_to_send;b++) { |
---|
671 |
freebob_sample_t tmp_event=work_buffer[b]; |
---|
672 |
if(freebob_streaming_write(m->dev, port->stream_nr, &tmp_event, 1)<1) { |
---|
673 |
jack_error ("FREEBOB: Midi send buffer overrun\n"); |
---|
674 |
} |
---|
675 |
} |
---|
676 |
|
---|
677 |
} |
---|
678 |
|
---|
679 |
// sleep for some time |
---|
680 |
usleep(MIDI_THREAD_SLEEP_TIME_USECS); |
---|
681 |
} |
---|
682 |
return NULL; |
---|
683 |
} |
---|
684 |
|
---|
685 |
// the dequeue thread (maybe we need one thread per stream) |
---|
686 |
void *freebob_driver_midi_dequeue_thread (void *arg) { |
---|
687 |
freebob_driver_midi_handle_t *m=(freebob_driver_midi_handle_t *)arg; |
---|
688 |
|
---|
689 |
int i; |
---|
690 |
int s; |
---|
691 |
|
---|
692 |
int samples_read; |
---|
693 |
|
---|
694 |
assert(m); |
---|
695 |
|
---|
696 |
while(1) { |
---|
697 |
// read incoming events |
---|
698 |
|
---|
699 |
for (i=0;i<m->nb_input_ports;i++) { |
---|
700 |
unsigned int buff[64]; |
---|
701 |
|
---|
702 |
freebob_midi_port_t *port=m->input_ports[i]; |
---|
703 |
|
---|
704 |
if(!port) { |
---|
705 |
jack_error("FREEBOB: something went wrong when setting up the midi input port map (%d)",i); |
---|
706 |
} |
---|
707 |
|
---|
708 |
do { |
---|
709 |
samples_read=freebob_streaming_read(m->dev, port->stream_nr, buff, 64); |
---|
710 |
|
---|
711 |
for (s=0;s<samples_read;s++) { |
---|
712 |
unsigned int *byte=(buff+s) ; |
---|
713 |
snd_seq_event_t ev; |
---|
714 |
if ((snd_midi_event_encode_byte(port->parser,(*byte) & 0xFF, &ev)) > 0) { |
---|
715 |
// a midi message is complete, send it out to ALSA |
---|
716 |
snd_seq_ev_set_subs(&ev); |
---|
717 |
snd_seq_ev_set_direct(&ev); |
---|
718 |
snd_seq_ev_set_source(&ev, port->seq_port_nr); |
---|
719 |
snd_seq_event_output_direct(port->seq_handle, &ev); |
---|
720 |
} |
---|
721 |
} |
---|
722 |
} while (samples_read>0); |
---|
723 |
} |
---|
724 |
|
---|
725 |
// sleep for some time |
---|
726 |
usleep(MIDI_THREAD_SLEEP_TIME_USECS); |
---|
727 |
} |
---|
728 |
return NULL; |
---|
729 |
} |
---|
730 |
|
---|
731 |
static freebob_driver_midi_handle_t *freebob_driver_midi_init(freebob_driver_t *driver) { |
---|
732 |
// int err; |
---|
733 |
|
---|
734 |
char buf[256]; |
---|
735 |
channel_t chn; |
---|
736 |
int nchannels; |
---|
737 |
int i=0; |
---|
738 |
|
---|
739 |
freebob_device_t *dev=driver->dev; |
---|
740 |
|
---|
741 |
assert(dev); |
---|
742 |
|
---|
743 |
freebob_driver_midi_handle_t *m=calloc(1,sizeof(freebob_driver_midi_handle_t)); |
---|
744 |
if (!m) { |
---|
745 |
jack_error("FREEBOB: not enough memory to create midi structure"); |
---|
746 |
return NULL; |
---|
747 |
} |
---|
748 |
|
---|
749 |
if (snd_seq_open(&m->seq_handle, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) { |
---|
750 |
jack_error("FREEBOB: Error opening ALSA sequencer."); |
---|
751 |
free(m); |
---|
752 |
return NULL; |
---|
753 |
} |
---|
754 |
|
---|
755 |
snd_seq_set_client_name(m->seq_handle, "FreeBoB Jack MIDI"); |
---|
756 |
|
---|
757 |
// find out the number of midi in/out ports we need to setup |
---|
758 |
nchannels=freebob_streaming_get_nb_capture_streams(dev); |
---|
759 |
|
---|
760 |
m->nb_input_ports=0; |
---|
761 |
|
---|
762 |
for (chn = 0; chn < nchannels; chn++) { |
---|
763 |
if(freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) { |
---|
764 |
m->nb_input_ports++; |
---|
765 |
} |
---|
766 |
} |
---|
767 |
|
---|
768 |
m->input_ports=calloc(m->nb_input_ports,sizeof(freebob_midi_port_t *)); |
---|
769 |
if(!m->input_ports) { |
---|
770 |
jack_error("FREEBOB: not enough memory to create midi structure"); |
---|
771 |
free(m); |
---|
772 |
return NULL; |
---|
773 |
} |
---|
774 |
|
---|
775 |
i=0; |
---|
776 |
for (chn = 0; chn < nchannels; chn++) { |
---|
777 |
if(freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) { |
---|
778 |
m->input_ports[i]=calloc(1,sizeof(freebob_midi_port_t)); |
---|
779 |
if(!m->input_ports[i]) { |
---|
780 |
// fixme |
---|
781 |
jack_error("FREEBOB: Could not allocate memory for seq port"); |
---|
782 |
continue; |
---|
783 |
} |
---|
784 |
|
---|
785 |
freebob_streaming_get_capture_stream_name(dev, chn, buf, sizeof(buf) - 1); |
---|
786 |
jack_error("FREEBOB: Register MIDI IN port %s\n", buf); |
---|
787 |
|
---|
788 |
m->input_ports[i]->seq_port_nr=snd_seq_create_simple_port(m->seq_handle, buf, |
---|
789 |
SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, |
---|
790 |
SND_SEQ_PORT_TYPE_MIDI_GENERIC); |
---|
791 |
|
---|
792 |
if(m->input_ports[i]->seq_port_nr<0) { |
---|
793 |
jack_error("FREEBOB: Could not create seq port"); |
---|
794 |
m->input_ports[i]->stream_nr=-1; |
---|
795 |
m->input_ports[i]->seq_port_nr=-1; |
---|
796 |
} else { |
---|
797 |
m->input_ports[i]->stream_nr=chn; |
---|
798 |
m->input_ports[i]->seq_handle=m->seq_handle; |
---|
799 |
if (snd_midi_event_new ( ALSA_SEQ_BUFF_SIZE, &(m->input_ports[i]->parser)) < 0) { |
---|
800 |
fprintf(stderr, "FREEBOB: could not init parser for MIDI IN port %d\n",i); |
---|
801 |
m->input_ports[i]->stream_nr=-1; |
---|
802 |
m->input_ports[i]->seq_port_nr=-1; |
---|
803 |
} |
---|
804 |
} |
---|
805 |
|
---|
806 |
i++; |
---|
807 |
} |
---|
808 |
} |
---|
809 |
|
---|
810 |
// playback |
---|
811 |
nchannels=freebob_streaming_get_nb_playback_streams(dev); |
---|
812 |
|
---|
813 |
m->nb_output_ports=0; |
---|
814 |
|
---|
815 |
for (chn = 0; chn < nchannels; chn++) { |
---|
816 |
if(freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) { |
---|
817 |
m->nb_output_ports++; |
---|
818 |
} |
---|
819 |
} |
---|
820 |
|
---|
821 |
m->output_ports=calloc(m->nb_output_ports,sizeof(freebob_midi_port_t *)); |
---|
822 |
if(!m->output_ports) { |
---|
823 |
jack_error("FREEBOB: not enough memory to create midi structure"); |
---|
824 |
for (i = 0; i < m->nb_input_ports; i++) { |
---|
825 |
free(m->input_ports[i]); |
---|
826 |
} |
---|
827 |
free(m->input_ports); |
---|
828 |
free(m); |
---|
829 |
return NULL; |
---|
830 |
} |
---|
831 |
|
---|
832 |
i=0; |
---|
833 |
for (chn = 0; chn < nchannels; chn++) { |
---|
834 |
if(freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) { |
---|
835 |
m->output_ports[i]=calloc(1,sizeof(freebob_midi_port_t)); |
---|
836 |
if(!m->output_ports[i]) { |
---|
837 |
// fixme |
---|
838 |
jack_error("FREEBOB: Could not allocate memory for seq port"); |
---|
839 |
continue; |
---|
840 |
} |
---|
841 |
|
---|
842 |
freebob_streaming_get_playback_stream_name(dev, chn, buf, sizeof(buf) - 1); |
---|
843 |
jack_error("FREEBOB: Register MIDI OUT port %s\n", buf); |
---|
844 |
|
---|
845 |
m->output_ports[i]->seq_port_nr=snd_seq_create_simple_port(m->seq_handle, buf, |
---|
846 |
SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, |
---|
847 |
SND_SEQ_PORT_TYPE_MIDI_GENERIC); |
---|
848 |
|
---|
849 |
|
---|
850 |
if(m->output_ports[i]->seq_port_nr<0) { |
---|
851 |
jack_error("FREEBOB: Could not create seq port"); |
---|
852 |
m->output_ports[i]->stream_nr=-1; |
---|
853 |
m->output_ports[i]->seq_port_nr=-1; |
---|
854 |
} else { |
---|
855 |
m->output_ports[i]->stream_nr=chn; |
---|
856 |
m->output_ports[i]->seq_handle=m->seq_handle; |
---|
857 |
if (snd_midi_event_new ( ALSA_SEQ_BUFF_SIZE, &(m->output_ports[i]->parser)) < 0) { |
---|
858 |
fprintf(stderr, "FREEBOB: could not init parser for MIDI OUT port %d\n",i); |
---|
859 |
m->output_ports[i]->stream_nr=-1; |
---|
860 |
m->output_ports[i]->seq_port_nr=-1; |
---|
861 |
} |
---|
862 |
} |
---|
863 |
|
---|
864 |
i++; |
---|
865 |
} |
---|
866 |
} |
---|
867 |
|
---|
868 |
|
---|
869 |
// start threads |
---|
870 |
m->dev=dev; |
---|
871 |
|
---|
872 |
m->queue_thread_priority=FREEBOB_RT_PRIORITY_MIDI; |
---|
873 |
m->queue_thread_realtime=FREEBOB_USE_RT; |
---|
874 |
|
---|
875 |
if (jack_client_create_thread(NULL, &m->queue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_queue_thread, (void *)m)) { |
---|
876 |
jack_error("FREEBOB: cannot create midi queueing thread"); |
---|
877 |
free(m); |
---|
878 |
return NULL; |
---|
879 |
} |
---|
880 |
|
---|
881 |
if (jack_client_create_thread(NULL, &m->dequeue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_dequeue_thread, (void *)m)) { |
---|
882 |
jack_error("FREEBOB: cannot create midi dequeueing thread"); |
---|
883 |
free(m); |
---|
884 |
return NULL; |
---|
885 |
} |
---|
886 |
return m; |
---|
887 |
} |
---|
888 |
|
---|
889 |
static void |
---|
890 |
freebob_driver_midi_finish (freebob_driver_midi_handle_t *m) |
---|
891 |
{ |
---|
892 |
assert(m); |
---|
893 |
|
---|
894 |
int i; |
---|
895 |
|
---|
896 |
pthread_cancel (m->queue_thread); |
---|
897 |
pthread_join (m->queue_thread, NULL); |
---|
898 |
|
---|
899 |
pthread_cancel (m->dequeue_thread); |
---|
900 |
pthread_join (m->dequeue_thread, NULL); |
---|
901 |
|
---|
902 |
|
---|
903 |
for (i=0;i<m->nb_input_ports;i++) { |
---|
904 |
free(m->input_ports[i]); |
---|
905 |
|
---|
906 |
} |
---|
907 |
free(m->input_ports); |
---|
908 |
|
---|
909 |
for (i=0;i<m->nb_output_ports;i++) { |
---|
910 |
free(m->output_ports[i]); |
---|
911 |
} |
---|
912 |
free(m->output_ports); |
---|
913 |
|
---|
914 |
free(m); |
---|
915 |
} |
---|
916 |
#endif |
---|
917 |
/* |
---|
918 |
* dlopen plugin stuff |
---|
919 |
*/ |
---|
920 |
|
---|
921 |
const char driver_client_name[] = "freebob_pcm"; |
---|
922 |
|
---|
923 |
const jack_driver_desc_t * |
---|
924 |
driver_get_descriptor () |
---|
925 |
{ |
---|
926 |
jack_driver_desc_t * desc; |
---|
927 |
jack_driver_param_desc_t * params; |
---|
928 |
unsigned int i; |
---|
929 |
|
---|
930 |
desc = calloc (1, sizeof (jack_driver_desc_t)); |
---|
931 |
|
---|
932 |
strcpy (desc->name, "freebob"); |
---|
933 |
desc->nparams = 8; |
---|
934 |
|
---|
935 |
params = calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); |
---|
936 |
desc->params = params; |
---|
937 |
|
---|
938 |
i = 0; |
---|
939 |
strcpy (params[i].name, "port"); |
---|
940 |
params[i].character = 'd'; |
---|
941 |
params[i].type = JackDriverParamUInt; |
---|
942 |
params[i].value.ui = 0; |
---|
943 |
strcpy (params[i].short_desc, "The FireWire port to use"); |
---|
944 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
945 |
|
---|
946 |
i++; |
---|
947 |
strcpy (params[i].name, "node"); |
---|
948 |
params[i].character = 'n'; |
---|
949 |
params[i].type = JackDriverParamUInt; |
---|
950 |
params[i].value.ui = -1; |
---|
951 |
strcpy (params[i].short_desc, "Node id of the BeBoB device"); |
---|
952 |
strcpy (params[i].long_desc, "The node id of the BeBoB device on the FireWire bus\n" |
---|
953 |
"(use -1 to use scan all devices on the bus)"); |
---|
954 |
i++; |
---|
955 |
strcpy (params[i].name, "period-size"); |
---|
956 |
params[i].character = 'p'; |
---|
957 |
params[i].type = JackDriverParamUInt; |
---|
958 |
params[i].value.ui = 512; |
---|
959 |
strcpy (params[i].short_desc, "Period size"); |
---|
960 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
961 |
|
---|
962 |
i++; |
---|
963 |
strcpy (params[i].name, "nb-buffers"); |
---|
964 |
params[i].character = 'r'; |
---|
965 |
params[i].type = JackDriverParamUInt; |
---|
966 |
params[i].value.ui = 3; |
---|
967 |
strcpy (params[i].short_desc, "Number of periods to buffer"); |
---|
968 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
969 |
|
---|
970 |
i++; |
---|
971 |
strcpy (params[i].name, "buffer-size"); |
---|
972 |
params[i].character = 'b'; |
---|
973 |
params[i].type = JackDriverParamUInt; |
---|
974 |
params[i].value.ui = 100U; |
---|
975 |
strcpy (params[i].short_desc, "The RAW1394 buffer size to use (in frames)"); |
---|
976 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
977 |
|
---|
978 |
i++; |
---|
979 |
strcpy (params[i].name, "prebuffer-size"); |
---|
980 |
params[i].character = 's'; |
---|
981 |
params[i].type = JackDriverParamUInt; |
---|
982 |
params[i].value.ui = 0U; |
---|
983 |
strcpy (params[i].short_desc, "The RAW1394 pre-buffer size to use (in frames)"); |
---|
984 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
985 |
|
---|
986 |
i++; |
---|
987 |
strcpy (params[i].name, "irq-interval"); |
---|
988 |
params[i].character = 'i'; |
---|
989 |
params[i].type = JackDriverParamUInt; |
---|
990 |
params[i].value.ui = 4U; |
---|
991 |
strcpy (params[i].short_desc, "The interrupt interval to use (in packets)"); |
---|
992 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
993 |
|
---|
994 |
i++; |
---|
995 |
strcpy (params[i].name, "samplerate"); |
---|
996 |
params[i].character = 'a'; |
---|
997 |
params[i].type = JackDriverParamUInt; |
---|
998 |
params[i].value.ui = 44100U; |
---|
999 |
strcpy (params[i].short_desc, "The sample rate"); |
---|
1000 |
strcpy (params[i].long_desc, params[i].short_desc); |
---|
1001 |
|
---|
1002 |
return desc; |
---|
1003 |
} |
---|
1004 |
|
---|
1005 |
|
---|
1006 |
jack_driver_t * |
---|
1007 |
driver_initialize (jack_client_t *client, JSList * params) |
---|
1008 |
{ |
---|
1009 |
jack_driver_t *driver; |
---|
1010 |
|
---|
1011 |
const JSList * node; |
---|
1012 |
const jack_driver_param_t * param; |
---|
1013 |
|
---|
1014 |
freebob_jack_settings_t cmlparams; |
---|
1015 |
|
---|
1016 |
|
---|
1017 |
cmlparams.period_size_set=0; |
---|
1018 |
cmlparams.sample_rate_set=0; |
---|
1019 |
cmlparams.fifo_size_set=0; |
---|
1020 |
cmlparams.table_size_set=0; |
---|
1021 |
cmlparams.iso_buffers_set=0; |
---|
1022 |
cmlparams.iso_prebuffers_set=0; |
---|
1023 |
cmlparams.iso_irq_interval_set=0; |
---|
1024 |
cmlparams.buffer_size_set=0; |
---|
1025 |
cmlparams.port_set=0; |
---|
1026 |
cmlparams.node_id_set=0; |
---|
1027 |
|
---|
1028 |
/* default values */ |
---|
1029 |
cmlparams.period_size=512; |
---|
1030 |
cmlparams.sample_rate=44100; |
---|
1031 |
cmlparams.iso_buffers=100; |
---|
1032 |
cmlparams.iso_prebuffers=0; |
---|
1033 |
cmlparams.iso_irq_interval=4; |
---|
1034 |
cmlparams.buffer_size=3; |
---|
1035 |
cmlparams.port=0; |
---|
1036 |
cmlparams.node_id=-1; |
---|
1037 |
|
---|
1038 |
for (node = params; node; node = jack_slist_next (node)) |
---|
1039 |
{ |
---|
1040 |
param = (jack_driver_param_t *) node->data; |
---|
1041 |
|
---|
1042 |
switch (param->character) |
---|
1043 |
{ |
---|
1044 |
case 'd': |
---|
1045 |
cmlparams.port = param->value.ui; |
---|
1046 |
cmlparams.port_set=1; |
---|
1047 |
break; |
---|
1048 |
case 'n': |
---|
1049 |
cmlparams.node_id = param->value.ui; |
---|
1050 |
cmlparams.node_id_set=1; |
---|
1051 |
break; |
---|
1052 |
case 'p': |
---|
1053 |
cmlparams.period_size = param->value.ui; |
---|
1054 |
cmlparams.period_size_set = 1; |
---|
1055 |
break; |
---|
1056 |
case 'b': |
---|
1057 |
cmlparams.iso_buffers = param->value.ui; |
---|
1058 |
cmlparams.iso_buffers_set = 1; |
---|
1059 |
break; |
---|
1060 |
case 'r': |
---|
1061 |
cmlparams.buffer_size = param->value.ui; |
---|
1062 |
cmlparams.buffer_size_set = 1; |
---|
1063 |
break; |
---|
1064 |
case 's': |
---|
1065 |
cmlparams.iso_prebuffers = param->value.ui; |
---|
1066 |
cmlparams.iso_prebuffers_set = 1; |
---|
1067 |
break; |
---|
1068 |
case 'i': |
---|
1069 |
cmlparams.iso_irq_interval = param->value.ui; |
---|
1070 |
cmlparams.iso_irq_interval_set = 1; |
---|
1071 |
break; |
---|
1072 |
case 'a': |
---|
1073 |
cmlparams.sample_rate = param->value.ui; |
---|
1074 |
cmlparams.sample_rate_set = 1; |
---|
1075 |
break; |
---|
1076 |
} |
---|
1077 |
} |
---|
1078 |
|
---|
1079 |
driver=(jack_driver_t *)freebob_driver_new (client, "freebob_pcm", &cmlparams); |
---|
1080 |
|
---|
1081 |
return driver; |
---|
1082 |
} |
---|
1083 |
|
---|
1084 |
void |
---|
1085 |
driver_finish (jack_driver_t *driver) |
---|
1086 |
{ |
---|
1087 |
freebob_driver_t *drv=(freebob_driver_t *) driver; |
---|
1088 |
|
---|
1089 |
freebob_driver_delete (drv); |
---|
1090 |
|
---|
1091 |
} |
---|