root/branches/streaming-rework/support/jack/freebob_driver.c

Revision 424, 32.5 kB (checked in by pieterpalmers, 15 years ago)

- The library can now be started in 'slave mode', creating a BounceSlaveDevice?.

On a discovering node, this slave device is discovered as a BounceDevice?.
Streaming does not work yet, something wrong with the timestamps.

- Implemented the 'snoop mode', that allows a client to 'snoop' the streams

between another host and a device. It is only implemented for BeBoB devices.
The channel numbers and stream configuration are automatically detected.
Note that it currently relies on a rather hackish support for reading the
{i,o}PCR plugs by using private functions of libiec61883

- changed jack backend to support these two new features

Line 
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         static int freebob_driver_midi_start (freebob_driver_midi_handle_t *m);
55         static int freebob_driver_midi_stop (freebob_driver_midi_handle_t *m);
56 #endif
57
58 // enable verbose messages
59 static int g_verbose=0;
60
61 static int
62 freebob_driver_attach (freebob_driver_t *driver)
63 {
64         char buf[64];
65         channel_t chn;
66         jack_port_t *port;
67         int port_flags;
68
69         g_verbose=driver->engine->verbose;
70         driver->device_options.verbose=g_verbose;
71
72         driver->engine->set_buffer_size (driver->engine, driver->period_size);
73         driver->engine->set_sample_rate (driver->engine, driver->sample_rate);
74
75         /* packetizer thread options */
76         driver->device_options.realtime=(driver->engine->control->real_time? 1 : 0);
77        
78         driver->device_options.packetizer_priority=driver->engine->control->client_priority +
79                 FREEBOB_RT_PRIORITY_PACKETIZER_RELATIVE;
80         if (driver->device_options.packetizer_priority>98) {
81                 driver->device_options.packetizer_priority=98;
82         }
83
84         driver->dev=freebob_streaming_init(&driver->device_info,driver->device_options);
85
86         if(!driver->dev) {
87                 printError("Error creating freebob streaming device");
88                 return -1;
89         }
90
91 #ifdef FREEBOB_DRIVER_WITH_MIDI
92         driver->midi_handle=freebob_driver_midi_init(driver);
93         if(!driver->midi_handle) {
94                 printError("-----------------------------------------------------------");
95                 printError("Error creating midi device!");
96                 printError("FreeBob will run without MIDI support.");
97                 printError("Consult the above error messages to solve the problem. ");
98                 printError("-----------------------------------------------------------\n\n");
99         }
100 #endif
101
102         if (driver->device_options.realtime) {
103                 printMessage("Streaming thread running with Realtime scheduling, priority %d",
104                            driver->device_options.packetizer_priority);
105         } else {
106                 printMessage("Streaming thread running without Realtime scheduling");
107         }
108
109         /* ports */
110         port_flags = JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal;
111
112         driver->capture_nchannels=freebob_streaming_get_nb_capture_streams(driver->dev);
113
114         for (chn = 0; chn < driver->capture_nchannels; chn++) {
115                
116                 freebob_streaming_get_capture_stream_name(driver->dev, chn, buf, sizeof(buf) - 1);
117                
118                 if(freebob_streaming_get_capture_stream_type(driver->dev, chn) != freebob_stream_type_audio) {
119                         printMessage ("Don't register capture port %s", buf);
120
121                         // we have to add a NULL entry in the list to be able to loop over the channels in the read/write routines
122                         driver->capture_ports =
123                                 jack_slist_append (driver->capture_ports, NULL);
124                 } else {
125                         printMessage ("Registering capture port %s", buf);
126                         if ((port = jack_port_register (driver->client, buf,
127                                                         JACK_DEFAULT_AUDIO_TYPE,
128                                                         port_flags, 0)) == NULL) {
129                                 printError (" cannot register port for %s", buf);
130                                 break;
131                         }
132                         driver->capture_ports =
133                                 jack_slist_append (driver->capture_ports, port);
134                         // setup port parameters
135                         if(freebob_streaming_set_capture_buffer_type(driver->dev, chn, freebob_buffer_type_float)) {
136                                 printError(" cannot set port buffer type for %s", buf);
137                         }
138                         if (freebob_streaming_set_capture_stream_buffer(driver->dev, chn, NULL)) {
139                                 printError(" cannot configure initial port buffer for %s", buf);
140                         }
141                         if(freebob_streaming_capture_stream_onoff(driver->dev, chn, 1)) {
142                                 printError(" cannot enable port %s", buf);
143                         }
144                 }
145 //              jack_port_set_latency (port, driver->period_size);
146
147         }
148        
149         port_flags = JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal;
150
151         driver->playback_nchannels=freebob_streaming_get_nb_playback_streams(driver->dev);
152
153         for (chn = 0; chn < driver->playback_nchannels; chn++) {
154
155                 freebob_streaming_get_playback_stream_name(driver->dev, chn, buf, sizeof(buf) - 1);
156                
157                 if(freebob_streaming_get_playback_stream_type(driver->dev, chn) != freebob_stream_type_audio) {
158                         printMessage ("Don't register playback port %s", buf);
159
160                         // we have to add a NULL entry in the list to be able to loop over the channels in the read/write routines
161                         driver->playback_ports =
162                                 jack_slist_append (driver->playback_ports, NULL);
163                 } else {
164                         printMessage ("Registering playback port %s", buf);
165                         if ((port = jack_port_register (driver->client, buf,
166                                                         JACK_DEFAULT_AUDIO_TYPE,
167                                                         port_flags, 0)) == NULL) {
168                                 printError(" cannot register port for %s", buf);
169                                 break;
170                         }
171                         driver->playback_ports =
172                                 jack_slist_append (driver->playback_ports, port);
173
174                         // setup port parameters
175                         if(freebob_streaming_set_playback_buffer_type(driver->dev, chn, freebob_buffer_type_float)) {
176                                 printError(" cannot set port buffer type for %s", buf);
177                         }
178                         if (freebob_streaming_set_playback_stream_buffer(driver->dev, chn, NULL)) {
179                                 printError(" cannot configure initial port buffer for %s", buf);
180                         }
181                         if(freebob_streaming_playback_stream_onoff(driver->dev, chn, 1)) {
182                                 printError(" cannot enable port %s", buf);
183                         }
184                 }
185 //              jack_port_set_latency (port, (driver->period_size * (driver->user_nperiods - 1)) + driver->playback_frame_latency);
186
187         }
188
189         if(!freebob_streaming_prepare(driver->dev)) {
190                 printError("Could not prepare streaming device!");
191                 return -1;
192         }
193        
194
195         return jack_activate (driver->client);
196 }
197
198 static int
199 freebob_driver_detach (freebob_driver_t *driver)
200 {
201         JSList *node;
202
203         if (driver->engine == NULL) {
204                 return 0;
205         }
206
207         for (node = driver->capture_ports; node;
208              node = jack_slist_next (node)) {
209                 // Don't try to unregister NULL entries added for non-audio
210                 // freebob ports by freebob_driver_attach().
211                 if (node->data != NULL) {
212                         jack_port_unregister (driver->client,
213                                               ((jack_port_t *) node->data));
214                 }
215         }
216
217         jack_slist_free (driver->capture_ports);
218         driver->capture_ports = 0;
219                
220         for (node = driver->playback_ports; node;
221              node = jack_slist_next (node)) {
222                 jack_port_unregister (driver->client,
223                                       ((jack_port_t *) node->data));
224         }
225
226         jack_slist_free (driver->playback_ports);
227         driver->playback_ports = 0;
228
229         freebob_streaming_finish(driver->dev);
230         driver->dev=NULL;
231
232 #ifdef FREEBOB_DRIVER_WITH_MIDI
233         if(driver->midi_handle) {
234                 freebob_driver_midi_finish(driver->midi_handle);       
235         }
236         driver->midi_handle=NULL;
237 #endif
238
239         return 0;
240
241 }
242
243 static inline void
244 freebob_driver_read_from_channel (freebob_driver_t *driver,
245                                channel_t channel,
246                                jack_default_audio_sample_t *dst,
247                                jack_nframes_t nsamples)
248 {
249        
250         freebob_sample_t buffer[nsamples];
251         char *src=(char *)buffer;
252        
253         freebob_streaming_read(driver->dev, channel, buffer, nsamples);
254        
255         /* ALERT: signed sign-extension portability !!! */
256
257         while (nsamples--) {
258                 int x;
259 #if __BYTE_ORDER == __LITTLE_ENDIAN
260                 memcpy((char*)&x + 1, src, 3);
261 #elif __BYTE_ORDER == __BIG_ENDIAN
262                 memcpy(&x, src, 3);
263 #endif
264                 x >>= 8;
265                 *dst = x / SAMPLE_MAX_24BIT;
266                 dst++;
267                 src += sizeof(freebob_sample_t);
268         }
269        
270 }
271
272 static int
273 freebob_driver_read (freebob_driver_t * driver, jack_nframes_t nframes)
274 {
275         jack_default_audio_sample_t* buf;
276         channel_t chn;
277         JSList *node;
278         jack_port_t* port;
279        
280         freebob_sample_t nullbuffer[nframes];
281
282         freebob_streaming_stream_type stream_type;
283        
284         printEnter();
285        
286         for (chn = 0, node = driver->capture_ports; node; node = jack_slist_next (node), chn++) {
287                 stream_type = freebob_streaming_get_capture_stream_type(driver->dev, chn);
288                 if(stream_type == freebob_stream_type_audio) {
289                         port = (jack_port_t *) node->data;
290
291                         buf = jack_port_get_buffer (port, nframes);
292                         if(!buf) buf=(jack_default_audio_sample_t*)nullbuffer;
293                                
294                         freebob_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(buf));
295                 }
296         }
297
298         // now transfer the buffers
299         freebob_streaming_transfer_capture_buffers(driver->dev);
300        
301         printExit();
302        
303         return 0;
304
305 }
306
307 static inline void
308 freebob_driver_write_to_channel (freebob_driver_t *driver,
309                               channel_t channel,
310                               jack_default_audio_sample_t *buf,
311                               jack_nframes_t nsamples)
312 {
313     long long y;
314         freebob_sample_t buffer[nsamples];
315         unsigned int i=0;       
316     char *dst=(char *)buffer;
317        
318         // convert from float to integer
319         for(;i<nsamples;i++) {
320                 y = (long long)(*buf * SAMPLE_MAX_24BIT);
321
322                 if (y > (INT_MAX >> 8 )) {
323                         y = (INT_MAX >> 8);
324                 } else if (y < (INT_MIN >> 8 )) {
325                         y = (INT_MIN >> 8 );
326                 }
327 #if __BYTE_ORDER == __LITTLE_ENDIAN
328                 memcpy (dst, &y, 3);
329 #elif __BYTE_ORDER == __BIG_ENDIAN
330                 memcpy (dst, (char *)&y + 5, 3);
331 #endif
332                 dst += sizeof(freebob_sample_t);
333                 buf++;
334         }
335        
336         // write to the freebob streaming device
337         freebob_streaming_write(driver->dev, channel, buffer, nsamples);
338        
339 }
340
341 static int
342 freebob_driver_write (freebob_driver_t * driver, jack_nframes_t nframes)
343 {
344         channel_t chn;
345         JSList *node;
346         jack_default_audio_sample_t* buf;
347
348         jack_port_t *port;
349
350         freebob_streaming_stream_type stream_type;
351
352         freebob_sample_t nullbuffer[nframes];
353
354         memset(&nullbuffer,0,nframes*sizeof(freebob_sample_t));
355
356         printEnter();
357
358         driver->process_count++;
359
360         assert(driver->dev);
361
362         if (driver->engine->freewheeling) {
363                 return 0;
364         }
365
366         for (chn = 0, node = driver->playback_ports; node; node = jack_slist_next (node), chn++) {
367                 stream_type=freebob_streaming_get_playback_stream_type(driver->dev, chn);
368                 if(stream_type == freebob_stream_type_audio) {
369                         port = (jack_port_t *) node->data;
370
371                         buf = jack_port_get_buffer (port, nframes);
372                         if(!buf) buf=(jack_default_audio_sample_t*)nullbuffer;
373                                
374                         freebob_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(buf));
375                 }
376         }
377
378         freebob_streaming_transfer_playback_buffers(driver->dev);
379
380         printExit();
381        
382         return 0;
383 }
384
385 //static inline jack_nframes_t
386 static jack_nframes_t
387 freebob_driver_wait (freebob_driver_t *driver, int extra_fd, int *status,
388                    float *delayed_usecs)
389 {
390         int nframes;
391         jack_time_t                   wait_enter;
392         jack_time_t                   wait_ret;
393        
394         printEnter();
395
396         wait_enter = jack_get_microseconds ();
397         if (wait_enter > driver->wait_next) {
398                 /*
399                         * This processing cycle was delayed past the
400                         * next due interrupt!  Do not account this as
401                         * a wakeup delay:
402                         */
403                 driver->wait_next = 0;
404                 driver->wait_late++;
405         }
406 // *status = -2; interrupt
407 // *status = -3; timeout
408 // *status = -4; extra FD
409
410         nframes=freebob_streaming_wait(driver->dev);
411        
412         wait_ret = jack_get_microseconds ();
413        
414         if (driver->wait_next && wait_ret > driver->wait_next) {
415                 *delayed_usecs = wait_ret - driver->wait_next;
416         }
417         driver->wait_last = wait_ret;
418         driver->wait_next = wait_ret + driver->period_usecs;
419         driver->engine->transport_cycle_start (driver->engine, wait_ret);
420        
421         // transfer the streaming buffers
422         // we now do this in the read/write functions
423 //      freebob_streaming_transfer_buffers(driver->dev);
424        
425         if (nframes < 0) {
426                 *status=0;
427                
428                 return 0;
429                 //nframes=driver->period_size; //debug
430         }
431
432         *status = 0;
433         driver->last_wait_ust = wait_ret;
434
435         // FIXME: this should do something more usefull
436         *delayed_usecs = 0;
437        
438         printExit();
439
440         return nframes - nframes % driver->period_size;
441        
442 }
443
444 static int
445 freebob_driver_run_cycle (freebob_driver_t *driver)
446 {
447         jack_engine_t *engine = driver->engine;
448         int wait_status=0;
449         float delayed_usecs=0.0;
450
451         jack_nframes_t nframes = freebob_driver_wait (driver, -1,
452            &wait_status, &delayed_usecs);
453        
454         if ((wait_status < 0)) {
455                 printError( "wait status < 0! (= %d)",wait_status);
456                 return -1;
457         }
458                
459         if ((nframes == 0)) {
460                 /* we detected an xrun and restarted: notify
461                  * clients about the delay. */
462                 printMessage("xrun detected");
463                 engine->delay (engine, delayed_usecs);
464                 return 0;
465         }
466        
467         return engine->run_cycle (engine, nframes, delayed_usecs);
468
469 }
470 /*
471  * in a null cycle we should discard the input and write silence to the outputs
472  */
473 static int
474 freebob_driver_null_cycle (freebob_driver_t* driver, jack_nframes_t nframes)
475 {
476         channel_t chn;
477         JSList *node;
478         snd_pcm_sframes_t nwritten;
479
480         freebob_streaming_stream_type stream_type;
481
482         jack_default_audio_sample_t buff[nframes];
483         jack_default_audio_sample_t* buffer=(jack_default_audio_sample_t*)buff;
484        
485         printEnter();
486
487         memset(buffer,0,nframes*sizeof(jack_default_audio_sample_t));
488        
489         assert(driver->dev);
490
491         if (driver->engine->freewheeling) {
492                 return 0;
493         }
494
495         // write silence to buffer
496         nwritten = 0;
497
498         for (chn = 0, node = driver->playback_ports; node; node = jack_slist_next (node), chn++) {
499                 stream_type=freebob_streaming_get_playback_stream_type(driver->dev, chn);
500
501                 if(stream_type == freebob_stream_type_audio) {
502                         freebob_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(buffer));
503                 }
504         }
505
506         freebob_streaming_transfer_playback_buffers(driver->dev);
507        
508         // read & discard from input ports
509         for (chn = 0, node = driver->capture_ports; node; node = jack_slist_next (node), chn++) {
510                 stream_type=freebob_streaming_get_capture_stream_type(driver->dev, chn);
511                 if(stream_type == freebob_stream_type_audio) {
512                         freebob_streaming_set_capture_stream_buffer(driver->dev, chn, (char *)(buffer));
513                 }
514         }
515
516         // now transfer the buffers
517         freebob_streaming_transfer_capture_buffers(driver->dev);
518                
519         printExit();
520         return 0;
521 }
522
523 static int
524 freebob_driver_start (freebob_driver_t *driver)
525 {
526         int retval=0;
527
528 #ifdef FREEBOB_DRIVER_WITH_MIDI
529         if(driver->midi_handle) {
530                 if((retval=freebob_driver_midi_start(driver->midi_handle))) {
531                         printError("Could not start MIDI threads");
532                         return retval;
533                 }
534         }
535 #endif 
536
537         if((retval=freebob_streaming_start(driver->dev))) {
538                 printError("Could not start streaming threads");
539 #ifdef FREEBOB_DRIVER_WITH_MIDI
540                 if(driver->midi_handle) {
541                         freebob_driver_midi_stop(driver->midi_handle);
542                 }
543 #endif 
544                 return retval;
545         }
546
547         return 0;
548
549 }
550
551 static int
552 freebob_driver_stop (freebob_driver_t *driver)
553 {
554         int retval=0;
555        
556 #ifdef FREEBOB_DRIVER_WITH_MIDI
557         if(driver->midi_handle) {
558                 if((retval=freebob_driver_midi_stop(driver->midi_handle))) {
559                         printError("Could not stop MIDI threads");
560                         return retval;
561                 }
562         }
563 #endif 
564         if((retval=freebob_streaming_stop(driver->dev))) {
565                 printError("Could not stop streaming threads");
566                 return retval;
567         }
568
569         return 0;
570 }
571
572
573 static int
574 freebob_driver_bufsize (freebob_driver_t* driver, jack_nframes_t nframes)
575 {
576         printError("Buffer size change requested but not supported!!!");
577
578         /*
579          driver->period_size = nframes; 
580         driver->period_usecs =
581                 (jack_time_t) floor ((((float) nframes) / driver->sample_rate)
582                                      * 1000000.0f);
583         */
584        
585         /* tell the engine to change its buffer size */
586         //driver->engine->set_buffer_size (driver->engine, nframes);
587
588         return -1; // unsupported
589 }
590
591 typedef void (*JackDriverFinishFunction) (jack_driver_t *);
592
593 freebob_driver_t *
594 freebob_driver_new (jack_client_t * client,
595                   char *name,
596                   freebob_jack_settings_t *params)
597 {
598         freebob_driver_t *driver;
599
600         assert(params);
601
602         if(freebob_get_api_version() != 2) {
603                 printError("Incompatible libfreebob version! (%s)", freebob_get_version());
604                 return NULL;
605         }
606
607         printMessage("Starting Freebob backend (%s)", freebob_get_version());
608
609         driver = calloc (1, sizeof (freebob_driver_t));
610
611         /* Setup the jack interfaces */ 
612         jack_driver_nt_init ((jack_driver_nt_t *) driver);
613
614         driver->nt_attach    = (JackDriverNTAttachFunction)   freebob_driver_attach;
615         driver->nt_detach    = (JackDriverNTDetachFunction)   freebob_driver_detach;
616         driver->nt_start     = (JackDriverNTStartFunction)    freebob_driver_start;
617         driver->nt_stop      = (JackDriverNTStopFunction)     freebob_driver_stop;
618         driver->nt_run_cycle = (JackDriverNTRunCycleFunction) freebob_driver_run_cycle;
619         driver->null_cycle   = (JackDriverNullCycleFunction)  freebob_driver_null_cycle;
620         driver->write        = (JackDriverReadFunction)       freebob_driver_write;
621         driver->read         = (JackDriverReadFunction)       freebob_driver_read;
622         driver->nt_bufsize   = (JackDriverNTBufSizeFunction)  freebob_driver_bufsize;
623        
624         /* copy command line parameter contents to the driver structure */
625         memcpy(&driver->settings,params,sizeof(freebob_jack_settings_t));
626        
627         /* prepare all parameters */
628         driver->sample_rate = params->sample_rate;
629         driver->period_size = params->period_size;
630         driver->last_wait_ust = 0;
631        
632         driver->period_usecs =
633                 (jack_time_t) floor ((((float) driver->period_size) * 1000000.0f) / driver->sample_rate);
634
635         driver->client = client;
636         driver->engine = NULL;
637
638         memset(&driver->device_options,0,sizeof(driver->device_options));       
639         driver->device_options.sample_rate=params->sample_rate;
640         driver->device_options.period_size=params->period_size;
641         driver->device_options.nb_buffers=params->buffer_size;
642         driver->device_options.node_id=params->node_id;
643         driver->device_options.port=params->port;
644         driver->device_options.slave_mode=params->slave_mode;
645         driver->device_options.snoop_mode=params->snoop_mode;
646
647         if(!params->capture_ports) {
648                 driver->device_options.directions |= FREEBOB_IGNORE_CAPTURE;
649         }
650
651         if(!params->playback_ports) {
652                 driver->device_options.directions |= FREEBOB_IGNORE_PLAYBACK;
653         }
654
655         debugPrint(DEBUG_LEVEL_STARTUP, " Driver compiled on %s %s", __DATE__, __TIME__);
656         debugPrint(DEBUG_LEVEL_STARTUP, " Created driver %s", name);
657         debugPrint(DEBUG_LEVEL_STARTUP, "            period_size: %d", driver->period_size);
658         debugPrint(DEBUG_LEVEL_STARTUP, "            period_usecs: %d", driver->period_usecs);
659         debugPrint(DEBUG_LEVEL_STARTUP, "            sample rate: %d", driver->sample_rate);
660
661         return (freebob_driver_t *) driver;
662
663 }
664
665 static void
666 freebob_driver_delete (freebob_driver_t *driver)
667 {
668         jack_driver_nt_finish ((jack_driver_nt_t *) driver);
669         free (driver);
670 }
671
672 #ifdef FREEBOB_DRIVER_WITH_MIDI
673 /*
674  * MIDI support
675  */
676
677 // the thread that will queue the midi events from the seq to the stream buffers
678
679 void * freebob_driver_midi_queue_thread(void *arg)
680 {
681         freebob_driver_midi_handle_t *m=(freebob_driver_midi_handle_t *)arg;
682         assert(m);
683         snd_seq_event_t *ev;
684         unsigned char work_buffer[MIDI_TRANSMIT_BUFFER_SIZE];
685         int bytes_to_send;
686         int b;
687         int i;
688
689         printMessage("MIDI queue thread started");
690
691         while(1) {
692                 // get next event, if one is present
693                 while ((snd_seq_event_input(m->seq_handle, &ev) > 0)) {
694                         // get the port this event is originated from
695                         freebob_midi_port_t *port=NULL;
696                         for (i=0;i<m->nb_output_ports;i++) {
697                                 if(m->output_ports[i]->seq_port_nr == ev->dest.port) {
698                                         port=m->output_ports[i];
699                                         break;
700                                 }
701                         }
702        
703                         if(!port) {
704                                 printError(" Could not find target port for event: dst=%d src=%d", ev->dest.port, ev->source.port);
705
706                                 break;
707                         }
708                        
709                         // decode it to the work buffer
710                         if((bytes_to_send = snd_midi_event_decode ( port->parser,
711                                 work_buffer,
712                                 MIDI_TRANSMIT_BUFFER_SIZE,
713                                 ev))<0)
714                         { // failed
715                                 printError(" Error decoding event for port %d (errcode=%d)", port->seq_port_nr,bytes_to_send);
716                                 bytes_to_send=0;
717                                 //return -1;
718                         }
719        
720                         for(b=0;b<bytes_to_send;b++) {
721                                 freebob_sample_t tmp_event=work_buffer[b];
722                                 if(freebob_streaming_write(m->dev, port->stream_nr, &tmp_event, 1)<1) {
723                                         printError(" Midi send buffer overrun");
724                                 }
725                         }
726        
727                 }
728
729                 // sleep for some time
730                 usleep(MIDI_THREAD_SLEEP_TIME_USECS);
731         }
732         return NULL;
733 }
734
735 // the dequeue thread (maybe we need one thread per stream)
736 void *freebob_driver_midi_dequeue_thread (void *arg) {
737         freebob_driver_midi_handle_t *m=(freebob_driver_midi_handle_t *)arg;
738
739         int i;
740         int s;
741        
742         int samples_read;
743
744         assert(m);
745
746         while(1) {
747                 // read incoming events
748        
749                 for (i=0;i<m->nb_input_ports;i++) {
750                         unsigned int buff[64];
751        
752                         freebob_midi_port_t *port=m->input_ports[i];
753                
754                         if(!port) {
755                                 printError(" something went wrong when setting up the midi input port map (%d)",i);
756                         }
757                
758                         do {
759                                 samples_read=freebob_streaming_read(m->dev, port->stream_nr, buff, 64);
760                        
761                                 for (s=0;s<samples_read;s++) {
762                                         unsigned int *byte=(buff+s) ;
763                                         snd_seq_event_t ev;
764                                         if ((snd_midi_event_encode_byte(port->parser,(*byte) & 0xFF, &ev)) > 0) {
765                                                 // a midi message is complete, send it out to ALSA
766                                                 snd_seq_ev_set_subs(&ev); 
767                                                 snd_seq_ev_set_direct(&ev);
768                                                 snd_seq_ev_set_source(&ev, port->seq_port_nr);
769                                                 snd_seq_event_output_direct(port->seq_handle, &ev);                                             
770                                         }
771                                 }
772                         } while (samples_read>0);
773                 }
774
775                 // sleep for some time
776                 usleep(MIDI_THREAD_SLEEP_TIME_USECS);
777         }
778         return NULL;
779 }
780
781 static freebob_driver_midi_handle_t *freebob_driver_midi_init(freebob_driver_t *driver) {
782 //      int err;
783
784         char buf[256];
785         channel_t chn;
786         int nchannels;
787         int i=0;
788
789         freebob_device_t *dev=driver->dev;
790
791         assert(dev);
792
793         freebob_driver_midi_handle_t *m=calloc(1,sizeof(freebob_driver_midi_handle_t));
794         if (!m) {
795                 printError("not enough memory to create midi structure");
796                 return NULL;
797         }
798
799         if (snd_seq_open(&m->seq_handle, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) {
800                 printError("Error opening ALSA sequencer.");
801                 free(m);
802                 return NULL;
803         }
804
805         snd_seq_set_client_name(m->seq_handle, "FreeBoB Jack MIDI");
806
807         // find out the number of midi in/out ports we need to setup
808         nchannels=freebob_streaming_get_nb_capture_streams(dev);
809
810         m->nb_input_ports=0;
811
812         for (chn = 0; chn < nchannels; chn++) {
813                 if(freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) {
814                         m->nb_input_ports++;
815                 }
816         }
817
818         m->input_ports=calloc(m->nb_input_ports,sizeof(freebob_midi_port_t *));
819         if(!m->input_ports) {
820                 printError("not enough memory to create midi structure");
821                 free(m);
822                 return NULL;
823         }
824
825         i=0;
826         for (chn = 0; chn < nchannels; chn++) {
827                 if(freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) {
828                         m->input_ports[i]=calloc(1,sizeof(freebob_midi_port_t));
829                         if(!m->input_ports[i]) {
830                                 // fixme
831                                 printError("Could not allocate memory for seq port");
832                                 continue;
833                         }
834
835                         freebob_streaming_get_capture_stream_name(dev, chn, buf, sizeof(buf) - 1);
836                         printMessage("Register MIDI IN port %s", buf);
837
838                         m->input_ports[i]->seq_port_nr=snd_seq_create_simple_port(m->seq_handle, buf,
839                                 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
840                                 SND_SEQ_PORT_TYPE_MIDI_GENERIC);
841
842                         if(m->input_ports[i]->seq_port_nr<0) {
843                                 printError("Could not create seq port");
844                                 m->input_ports[i]->stream_nr=-1;
845                                 m->input_ports[i]->seq_port_nr=-1;
846                         } else {
847                                 m->input_ports[i]->stream_nr=chn;
848                                 m->input_ports[i]->seq_handle=m->seq_handle;
849                                 if (snd_midi_event_new  ( ALSA_SEQ_BUFF_SIZE, &(m->input_ports[i]->parser)) < 0) {
850                                         printError("could not init parser for MIDI IN port %d",i);
851                                         m->input_ports[i]->stream_nr=-1;
852                                         m->input_ports[i]->seq_port_nr=-1;
853                                 } else {
854                                         if(freebob_streaming_set_capture_buffer_type(dev, chn, freebob_buffer_type_midi)) {
855                                                 printError(" cannot set port buffer type for %s", buf);
856                                                 m->input_ports[i]->stream_nr=-1;
857                                                 m->input_ports[i]->seq_port_nr=-1;
858                                         }
859                                         if(freebob_streaming_capture_stream_onoff(dev, chn, 1)) {
860                                                 printError(" cannot enable port %s", buf);
861                                                 m->input_ports[i]->stream_nr=-1;
862                                                 m->input_ports[i]->seq_port_nr=-1;
863                                         }
864
865                                 }
866                         }
867
868                         i++;
869                 }
870         }
871
872         // playback
873         nchannels=freebob_streaming_get_nb_playback_streams(dev);
874
875         m->nb_output_ports=0;
876
877         for (chn = 0; chn < nchannels; chn++) {
878                 if(freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) {
879                         m->nb_output_ports++;
880                 }
881         }
882
883         m->output_ports=calloc(m->nb_output_ports,sizeof(freebob_midi_port_t *));
884         if(!m->output_ports) {
885                 printError("not enough memory to create midi structure");
886                 for (i = 0; i < m->nb_input_ports; i++) {       
887                         free(m->input_ports[i]);
888                 }
889                 free(m->input_ports);
890                 free(m);
891                 return NULL;
892         }
893
894         i=0;
895         for (chn = 0; chn < nchannels; chn++) {
896                 if(freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) {
897                         m->output_ports[i]=calloc(1,sizeof(freebob_midi_port_t));
898                         if(!m->output_ports[i]) {
899                                 // fixme
900                                 printError("Could not allocate memory for seq port");
901                                 continue;
902                         }
903
904                         freebob_streaming_get_playback_stream_name(dev, chn, buf, sizeof(buf) - 1);
905                         printMessage("Register MIDI OUT port %s", buf);
906
907                         m->output_ports[i]->seq_port_nr=snd_seq_create_simple_port(m->seq_handle, buf,
908                                 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
909                                 SND_SEQ_PORT_TYPE_MIDI_GENERIC);
910
911
912                         if(m->output_ports[i]->seq_port_nr<0) {
913                                 printError("Could not create seq port");
914                                 m->output_ports[i]->stream_nr=-1;
915                                 m->output_ports[i]->seq_port_nr=-1;
916                         } else {
917                                 m->output_ports[i]->stream_nr=chn;
918                                 m->output_ports[i]->seq_handle=m->seq_handle;
919                                 if (snd_midi_event_new  ( ALSA_SEQ_BUFF_SIZE, &(m->output_ports[i]->parser)) < 0) {
920                                         printError("could not init parser for MIDI OUT port %d",i);
921                                         m->output_ports[i]->stream_nr=-1;
922                                         m->output_ports[i]->seq_port_nr=-1;
923                                 } else {
924                                         if(freebob_streaming_set_playback_buffer_type(dev, chn, freebob_buffer_type_midi)) {
925                                                 printError(" cannot set port buffer type for %s", buf);
926                                                 m->input_ports[i]->stream_nr=-1;
927                                                 m->input_ports[i]->seq_port_nr=-1;
928                                         }
929                                         if(freebob_streaming_playback_stream_onoff(dev, chn, 1)) {
930                                                 printError(" cannot enable port %s", buf);
931                                                 m->input_ports[i]->stream_nr=-1;
932                                                 m->input_ports[i]->seq_port_nr=-1;
933                                         }
934                                 }
935                         }
936
937                         i++;
938                 }
939         }
940
941         m->dev=dev;
942         m->driver=driver;
943
944         return m;
945 }
946
947 static int
948 freebob_driver_midi_start (freebob_driver_midi_handle_t *m)
949 {
950         assert(m);
951         // start threads
952
953         m->queue_thread_realtime=(m->driver->engine->control->real_time? 1 : 0);
954         m->queue_thread_priority=
955                 m->driver->engine->control->client_priority +
956                 FREEBOB_RT_PRIORITY_MIDI_RELATIVE;
957
958         if (m->queue_thread_priority>98) {
959                 m->queue_thread_priority=98;
960         }
961         if (m->queue_thread_realtime) {
962                 printMessage("MIDI threads running with Realtime scheduling, priority %d",
963                            m->queue_thread_priority);
964         } else {
965                 printMessage("MIDI threads running without Realtime scheduling");
966         }
967
968         if (jack_client_create_thread(NULL, &m->queue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_queue_thread, (void *)m)) {
969                 printError(" cannot create midi queueing thread");
970                 return -1;
971         }
972
973         if (jack_client_create_thread(NULL, &m->dequeue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_dequeue_thread, (void *)m)) {
974                 printError(" cannot create midi dequeueing thread");
975                 return -1;
976         }
977         return 0;
978 }
979
980 static int
981 freebob_driver_midi_stop (freebob_driver_midi_handle_t *m)
982 {
983         assert(m);
984
985         pthread_cancel (m->queue_thread);
986         pthread_join (m->queue_thread, NULL);
987
988         pthread_cancel (m->dequeue_thread);
989         pthread_join (m->dequeue_thread, NULL);
990         return 0;
991
992 }
993
994 static void
995 freebob_driver_midi_finish (freebob_driver_midi_handle_t *m)
996 {
997         assert(m);
998
999         int i;
1000         // TODO: add state info here, if not stopped then stop
1001
1002         for (i=0;i<m->nb_input_ports;i++) {
1003                 free(m->input_ports[i]);
1004
1005         }
1006         free(m->input_ports);
1007
1008         for (i=0;i<m->nb_output_ports;i++) {
1009                 free(m->output_ports[i]);
1010         }
1011         free(m->output_ports);
1012
1013         free(m);
1014 }
1015 #endif 
1016 /*
1017  * dlopen plugin stuff
1018  */
1019
1020 const char driver_client_name[] = "freebob_pcm";
1021
1022 const jack_driver_desc_t *
1023 driver_get_descriptor ()
1024 {
1025         jack_driver_desc_t * desc;
1026         jack_driver_param_desc_t * params;
1027         unsigned int i;
1028
1029         desc = calloc (1, sizeof (jack_driver_desc_t));
1030
1031         strcpy (desc->name, "freebob");
1032         desc->nparams = 8;
1033  
1034         params = calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
1035         desc->params = params;
1036
1037         i = 0;
1038         strcpy (params[i].name, "device");
1039         params[i].character  = 'd';
1040         params[i].type       = JackDriverParamString;
1041         strcpy (params[i].value.str,  "hw:0");
1042         strcpy (params[i].short_desc, "The FireWire device to use. Format is: 'hw:port[,node]'.");
1043         strcpy (params[i].long_desc,  params[i].short_desc);
1044        
1045         i++;
1046         strcpy (params[i].name, "period");
1047         params[i].character  = 'p';
1048         params[i].type       = JackDriverParamUInt;
1049         params[i].value.ui   = 1024;
1050         strcpy (params[i].short_desc, "Frames per period");
1051         strcpy (params[i].long_desc, params[i].short_desc);
1052        
1053         i++;
1054         strcpy (params[i].name, "nperiods");
1055         params[i].character  = 'n';
1056         params[i].type       = JackDriverParamUInt;
1057         params[i].value.ui   = 3;
1058         strcpy (params[i].short_desc, "Number of periods of playback latency");
1059         strcpy (params[i].long_desc, params[i].short_desc);
1060
1061         i++;
1062         strcpy (params[i].name, "rate");
1063         params[i].character  = 'r';
1064         params[i].type       = JackDriverParamUInt;
1065         params[i].value.ui   = 48000U;
1066         strcpy (params[i].short_desc, "Sample rate");
1067         strcpy (params[i].long_desc, params[i].short_desc);
1068
1069         i++;
1070         strcpy (params[i].name, "capture");
1071         params[i].character  = 'i';
1072         params[i].type       = JackDriverParamUInt;
1073         params[i].value.ui   = 1U;
1074         strcpy (params[i].short_desc, "Provide capture ports.");
1075         strcpy (params[i].long_desc, params[i].short_desc);
1076
1077         i++;
1078         strcpy (params[i].name, "playback");
1079         params[i].character  = 'o';
1080         params[i].type       = JackDriverParamUInt;
1081         params[i].value.ui   = 1U;
1082         strcpy (params[i].short_desc, "Provide playback ports.");
1083         strcpy (params[i].long_desc, params[i].short_desc);
1084
1085         i++;
1086         strcpy (params[i].name, "slave");
1087         params[i].character  = 'x';
1088         params[i].type       = JackDriverParamUInt;
1089         params[i].value.ui   = 0U;
1090         strcpy (params[i].short_desc, "Act as a BounceDevice slave");
1091         strcpy (params[i].long_desc, params[i].short_desc);
1092
1093         i++;
1094         strcpy (params[i].name, "slave");
1095         params[i].character  = 'X';
1096         params[i].type       = JackDriverParamUInt;
1097         params[i].value.ui   = 0U;
1098         strcpy (params[i].short_desc, "Operate in snoop mode");
1099         strcpy (params[i].long_desc, params[i].short_desc);
1100
1101         return desc;
1102 }
1103
1104
1105 jack_driver_t *
1106 driver_initialize (jack_client_t *client, JSList * params)
1107 {
1108         jack_driver_t *driver;
1109
1110     unsigned int port=0;
1111     unsigned int node_id=-1;
1112     int nbitems;
1113      
1114         const JSList * node;
1115         const jack_driver_param_t * param;
1116
1117         freebob_jack_settings_t cmlparams;
1118        
1119     char *device_name="hw:0";
1120      
1121         cmlparams.period_size_set=0;
1122         cmlparams.sample_rate_set=0;
1123         cmlparams.buffer_size_set=0;
1124         cmlparams.port_set=0;
1125         cmlparams.node_id_set=0;
1126
1127         /* default values */
1128         cmlparams.period_size=1024;
1129         cmlparams.sample_rate=48000;
1130         cmlparams.buffer_size=3;
1131         cmlparams.port=0;
1132         cmlparams.node_id=-1;
1133         cmlparams.playback_ports=1;
1134         cmlparams.capture_ports=1;
1135         cmlparams.slave_mode=0;
1136         cmlparams.snoop_mode=0;
1137        
1138         for (node = params; node; node = jack_slist_next (node))
1139         {
1140                 param = (jack_driver_param_t *) node->data;
1141
1142                 switch (param->character)
1143                 {
1144                 case 'd':
1145                         device_name = strdup (param->value.str);
1146                         break;
1147                 case 'p':
1148                         cmlparams.period_size = param->value.ui;
1149                         cmlparams.period_size_set = 1;
1150                         break;
1151                 case 'n':
1152                         cmlparams.buffer_size = param->value.ui;
1153                         cmlparams.buffer_size_set = 1;
1154                         break;       
1155                 case 'r':
1156                         cmlparams.sample_rate = param->value.ui;
1157                         cmlparams.sample_rate_set = 1;
1158                         break;
1159                 case 'i':
1160                         cmlparams.capture_ports = param->value.ui;
1161                         break;
1162                 case 'o':
1163                         cmlparams.playback_ports = param->value.ui;
1164                         break;
1165                 case 'x':
1166                         cmlparams.slave_mode = param->value.ui;
1167                         break;
1168                 case 'X':
1169                         cmlparams.snoop_mode = param->value.ui;
1170                         break;
1171                 }
1172         }
1173        
1174     nbitems=sscanf(device_name,"hw:%u,%u",&port,&node_id);
1175     if (nbitems<2) {
1176         nbitems=sscanf(device_name,"hw:%u",&port);
1177      
1178         if(nbitems < 1) {
1179             free(device_name);
1180             printError("device (-d) argument not valid\n");
1181             return NULL;
1182         } else {
1183             cmlparams.port = port;
1184             cmlparams.port_set=1;
1185            
1186             cmlparams.node_id = -1;
1187             cmlparams.node_id_set=0;
1188         }
1189      } else {
1190         cmlparams.port = port;
1191         cmlparams.port_set=1;
1192        
1193         cmlparams.node_id = node_id;
1194         cmlparams.node_id_set=1;
1195      }
1196
1197     jack_error("Freebob using Firewire port %d, node %d",cmlparams.port,cmlparams.node_id);
1198    
1199         driver=(jack_driver_t *)freebob_driver_new (client, "freebob_pcm", &cmlparams);
1200
1201         return driver;
1202 }
1203
1204 void
1205 driver_finish (jack_driver_t *driver)
1206 {
1207         freebob_driver_t *drv=(freebob_driver_t *) driver;
1208         // If jack hasn't called the detach method, do it now.  As of jack 0.101.1
1209         // the detach method was not being called explicitly on closedown, and
1210         // we need it to at least deallocate the iso resources.
1211         if (drv->dev != NULL)
1212                 freebob_driver_detach(drv);
1213         freebob_driver_delete (drv);
1214 }
Note: See TracBrowser for help on using the browser.