root/branches/libfreebob-2.0/support/jack/freebob_driver.c

Revision 302, 31.6 kB (checked in by jwoithe, 17 years ago)

jack driver: call detach() from finish() if detach() hasn't yet been called. This works around the fact that jack doesn't call detach() on close at this stage. Once this is fixed in jack the workaround can be removed.
C streaming API: set sample rate before device initialisation. This permits jackd to set the sample rate to that requested on the command line when starting jackd.
Motu device: start adding details to setSamplingFrequency() beyond that required for basic functionality.

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