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

Revision 312, 31.7 kB (checked in by jwoithe, 16 years ago)

MOTU: fix xrun recovery glitches inadvertantly introduced in r309.
MOTU: preliminary MIDI port support. Rate control still needs to be added so it probably won't work in its current form yet. MIDI has not yet been tested.
MOTU: tweaks to receive/transmit missed cycle detection.
jack driver: during driver shutdown don't try to free NULL ports created for non-audio ports during initialisation to preserve device port index locations.

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 #endif 
237         driver->midi_handle=NULL;
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, &wait_status,
452                                                    &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
645         if(!params->capture_ports) {
646                 driver->device_options.directions |= FREEBOB_IGNORE_CAPTURE;
647         }
648
649         if(!params->playback_ports) {
650                 driver->device_options.directions |= FREEBOB_IGNORE_PLAYBACK;
651         }
652
653         debugPrint(DEBUG_LEVEL_STARTUP, " Driver compiled on %s %s", __DATE__, __TIME__);
654         debugPrint(DEBUG_LEVEL_STARTUP, " Created driver %s", name);
655         debugPrint(DEBUG_LEVEL_STARTUP, "            period_size: %d", driver->period_size);
656         debugPrint(DEBUG_LEVEL_STARTUP, "            period_usecs: %d", driver->period_usecs);
657         debugPrint(DEBUG_LEVEL_STARTUP, "            sample rate: %d", driver->sample_rate);
658
659         return (freebob_driver_t *) driver;
660
661 }
662
663 static void
664 freebob_driver_delete (freebob_driver_t *driver)
665 {
666         jack_driver_nt_finish ((jack_driver_nt_t *) driver);
667         free (driver);
668 }
669
670 #ifdef FREEBOB_DRIVER_WITH_MIDI
671 /*
672  * MIDI support
673  */
674
675 // the thread that will queue the midi events from the seq to the stream buffers
676
677 void * freebob_driver_midi_queue_thread(void *arg)
678 {
679         freebob_driver_midi_handle_t *m=(freebob_driver_midi_handle_t *)arg;
680         assert(m);
681         snd_seq_event_t *ev;
682         unsigned char work_buffer[MIDI_TRANSMIT_BUFFER_SIZE];
683         int bytes_to_send;
684         int b;
685         int i;
686
687         printMessage("MIDI queue thread started");
688
689         while(1) {
690                 // get next event, if one is present
691                 while ((snd_seq_event_input(m->seq_handle, &ev) > 0)) {
692                         // get the port this event is originated from
693                         freebob_midi_port_t *port=NULL;
694                         for (i=0;i<m->nb_output_ports;i++) {
695                                 if(m->output_ports[i]->seq_port_nr == ev->dest.port) {
696                                         port=m->output_ports[i];
697                                         break;
698                                 }
699                         }
700        
701                         if(!port) {
702                                 printError(" Could not find target port for event: dst=%d src=%d", ev->dest.port, ev->source.port);
703
704                                 break;
705                         }
706                        
707                         // decode it to the work buffer
708                         if((bytes_to_send = snd_midi_event_decode ( port->parser,
709                                 work_buffer,
710                                 MIDI_TRANSMIT_BUFFER_SIZE,
711                                 ev))<0)
712                         { // failed
713                                 printError(" Error decoding event for port %d (errcode=%d)", port->seq_port_nr,bytes_to_send);
714                                 bytes_to_send=0;
715                                 //return -1;
716                         }
717        
718                         for(b=0;b<bytes_to_send;b++) {
719                                 freebob_sample_t tmp_event=work_buffer[b];
720                                 if(freebob_streaming_write(m->dev, port->stream_nr, &tmp_event, 1)<1) {
721                                         printError(" Midi send buffer overrun");
722                                 }
723                         }
724        
725                 }
726
727                 // sleep for some time
728                 usleep(MIDI_THREAD_SLEEP_TIME_USECS);
729         }
730         return NULL;
731 }
732
733 // the dequeue thread (maybe we need one thread per stream)
734 void *freebob_driver_midi_dequeue_thread (void *arg) {
735         freebob_driver_midi_handle_t *m=(freebob_driver_midi_handle_t *)arg;
736
737         int i;
738         int s;
739        
740         int samples_read;
741
742         assert(m);
743
744         while(1) {
745                 // read incoming events
746        
747                 for (i=0;i<m->nb_input_ports;i++) {
748                         unsigned int buff[64];
749        
750                         freebob_midi_port_t *port=m->input_ports[i];
751                
752                         if(!port) {
753                                 printError(" something went wrong when setting up the midi input port map (%d)",i);
754                         }
755                
756                         do {
757                                 samples_read=freebob_streaming_read(m->dev, port->stream_nr, buff, 64);
758                        
759                                 for (s=0;s<samples_read;s++) {
760                                         unsigned int *byte=(buff+s) ;
761                                         snd_seq_event_t ev;
762                                         if ((snd_midi_event_encode_byte(port->parser,(*byte) & 0xFF, &ev)) > 0) {
763                                                 // a midi message is complete, send it out to ALSA
764                                                 snd_seq_ev_set_subs(&ev); 
765                                                 snd_seq_ev_set_direct(&ev);
766                                                 snd_seq_ev_set_source(&ev, port->seq_port_nr);
767                                                 snd_seq_event_output_direct(port->seq_handle, &ev);                                             
768                                         }
769                                 }
770                         } while (samples_read>0);
771                 }
772
773                 // sleep for some time
774                 usleep(MIDI_THREAD_SLEEP_TIME_USECS);
775         }
776         return NULL;
777 }
778
779 static freebob_driver_midi_handle_t *freebob_driver_midi_init(freebob_driver_t *driver) {
780 //      int err;
781
782         char buf[256];
783         channel_t chn;
784         int nchannels;
785         int i=0;
786
787         freebob_device_t *dev=driver->dev;
788
789         assert(dev);
790
791         freebob_driver_midi_handle_t *m=calloc(1,sizeof(freebob_driver_midi_handle_t));
792         if (!m) {
793                 printError("not enough memory to create midi structure");
794                 return NULL;
795         }
796
797         if (snd_seq_open(&m->seq_handle, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) {
798                 printError("Error opening ALSA sequencer.");
799                 free(m);
800                 return NULL;
801         }
802
803         snd_seq_set_client_name(m->seq_handle, "FreeBoB Jack MIDI");
804
805         // find out the number of midi in/out ports we need to setup
806         nchannels=freebob_streaming_get_nb_capture_streams(dev);
807
808         m->nb_input_ports=0;
809
810         for (chn = 0; chn < nchannels; chn++) {
811                 if(freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) {
812                         m->nb_input_ports++;
813                 }
814         }
815
816         m->input_ports=calloc(m->nb_input_ports,sizeof(freebob_midi_port_t *));
817         if(!m->input_ports) {
818                 printError("not enough memory to create midi structure");
819                 free(m);
820                 return NULL;
821         }
822
823         i=0;
824         for (chn = 0; chn < nchannels; chn++) {
825                 if(freebob_streaming_get_capture_stream_type(dev, chn) == freebob_stream_type_midi) {
826                         m->input_ports[i]=calloc(1,sizeof(freebob_midi_port_t));
827                         if(!m->input_ports[i]) {
828                                 // fixme
829                                 printError("Could not allocate memory for seq port");
830                                 continue;
831                         }
832
833                         freebob_streaming_get_capture_stream_name(dev, chn, buf, sizeof(buf) - 1);
834                         printMessage("Register MIDI IN port %s", buf);
835
836                         m->input_ports[i]->seq_port_nr=snd_seq_create_simple_port(m->seq_handle, buf,
837                                 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
838                                 SND_SEQ_PORT_TYPE_MIDI_GENERIC);
839
840                         if(m->input_ports[i]->seq_port_nr<0) {
841                                 printError("Could not create seq port");
842                                 m->input_ports[i]->stream_nr=-1;
843                                 m->input_ports[i]->seq_port_nr=-1;
844                         } else {
845                                 m->input_ports[i]->stream_nr=chn;
846                                 m->input_ports[i]->seq_handle=m->seq_handle;
847                                 if (snd_midi_event_new  ( ALSA_SEQ_BUFF_SIZE, &(m->input_ports[i]->parser)) < 0) {
848                                         printError("could not init parser for MIDI IN port %d",i);
849                                         m->input_ports[i]->stream_nr=-1;
850                                         m->input_ports[i]->seq_port_nr=-1;
851                                 } else {
852                                         if(freebob_streaming_set_capture_buffer_type(dev, chn, freebob_buffer_type_midi)) {
853                                                 printError(" cannot set port buffer type for %s", buf);
854                                                 m->input_ports[i]->stream_nr=-1;
855                                                 m->input_ports[i]->seq_port_nr=-1;
856                                         }
857                                         if(freebob_streaming_capture_stream_onoff(dev, chn, 1)) {
858                                                 printError(" cannot enable port %s", buf);
859                                                 m->input_ports[i]->stream_nr=-1;
860                                                 m->input_ports[i]->seq_port_nr=-1;
861                                         }
862
863                                 }
864                         }
865
866                         i++;
867                 }
868         }
869
870         // playback
871         nchannels=freebob_streaming_get_nb_playback_streams(dev);
872
873         m->nb_output_ports=0;
874
875         for (chn = 0; chn < nchannels; chn++) {
876                 if(freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) {
877                         m->nb_output_ports++;
878                 }
879         }
880
881         m->output_ports=calloc(m->nb_output_ports,sizeof(freebob_midi_port_t *));
882         if(!m->output_ports) {
883                 printError("not enough memory to create midi structure");
884                 for (i = 0; i < m->nb_input_ports; i++) {       
885                         free(m->input_ports[i]);
886                 }
887                 free(m->input_ports);
888                 free(m);
889                 return NULL;
890         }
891
892         i=0;
893         for (chn = 0; chn < nchannels; chn++) {
894                 if(freebob_streaming_get_playback_stream_type(dev, chn) == freebob_stream_type_midi) {
895                         m->output_ports[i]=calloc(1,sizeof(freebob_midi_port_t));
896                         if(!m->output_ports[i]) {
897                                 // fixme
898                                 printError("Could not allocate memory for seq port");
899                                 continue;
900                         }
901
902                         freebob_streaming_get_playback_stream_name(dev, chn, buf, sizeof(buf) - 1);
903                         printMessage("Register MIDI OUT port %s", buf);
904
905                         m->output_ports[i]->seq_port_nr=snd_seq_create_simple_port(m->seq_handle, buf,
906                                 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
907                                 SND_SEQ_PORT_TYPE_MIDI_GENERIC);
908
909
910                         if(m->output_ports[i]->seq_port_nr<0) {
911                                 printError("Could not create seq port");
912                                 m->output_ports[i]->stream_nr=-1;
913                                 m->output_ports[i]->seq_port_nr=-1;
914                         } else {
915                                 m->output_ports[i]->stream_nr=chn;
916                                 m->output_ports[i]->seq_handle=m->seq_handle;
917                                 if (snd_midi_event_new  ( ALSA_SEQ_BUFF_SIZE, &(m->output_ports[i]->parser)) < 0) {
918                                         printError("could not init parser for MIDI OUT port %d",i);
919                                         m->output_ports[i]->stream_nr=-1;
920                                         m->output_ports[i]->seq_port_nr=-1;
921                                 } else {
922                                         if(freebob_streaming_set_playback_buffer_type(dev, chn, freebob_buffer_type_midi)) {
923                                                 printError(" cannot set port buffer type for %s", buf);
924                                                 m->input_ports[i]->stream_nr=-1;
925                                                 m->input_ports[i]->seq_port_nr=-1;
926                                         }
927                                         if(freebob_streaming_playback_stream_onoff(dev, chn, 1)) {
928                                                 printError(" cannot enable port %s", buf);
929                                                 m->input_ports[i]->stream_nr=-1;
930                                                 m->input_ports[i]->seq_port_nr=-1;
931                                         }
932                                 }
933                         }
934
935                         i++;
936                 }
937         }
938
939         m->dev=dev;
940         m->driver=driver;
941
942         return m;
943 }
944
945 static int
946 freebob_driver_midi_start (freebob_driver_midi_handle_t *m)
947 {
948         assert(m);
949         // start threads
950
951         m->queue_thread_realtime=(m->driver->engine->control->real_time? 1 : 0);
952         m->queue_thread_priority=
953                 m->driver->engine->control->client_priority +
954                 FREEBOB_RT_PRIORITY_MIDI_RELATIVE;
955
956         if (m->queue_thread_priority>98) {
957                 m->queue_thread_priority=98;
958         }
959         if (m->queue_thread_realtime) {
960                 printMessage("MIDI threads running with Realtime scheduling, priority %d",
961                            m->queue_thread_priority);
962         } else {
963                 printMessage("MIDI threads running without Realtime scheduling");
964         }
965
966         if (jack_client_create_thread(NULL, &m->queue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_queue_thread, (void *)m)) {
967                 printError(" cannot create midi queueing thread");
968                 return -1;
969         }
970
971         if (jack_client_create_thread(NULL, &m->dequeue_thread, m->queue_thread_priority, m->queue_thread_realtime, freebob_driver_midi_dequeue_thread, (void *)m)) {
972                 printError(" cannot create midi dequeueing thread");
973                 return -1;
974         }
975         return 0;
976 }
977
978 static int
979 freebob_driver_midi_stop (freebob_driver_midi_handle_t *m)
980 {
981         assert(m);
982
983         pthread_cancel (m->queue_thread);
984         pthread_join (m->queue_thread, NULL);
985
986         pthread_cancel (m->dequeue_thread);
987         pthread_join (m->dequeue_thread, NULL);
988         return 0;
989
990 }
991
992 static void
993 freebob_driver_midi_finish (freebob_driver_midi_handle_t *m)
994 {
995         assert(m);
996
997         int i;
998         // TODO: add state info here, if not stopped then stop
999
1000         for (i=0;i<m->nb_input_ports;i++) {
1001                 free(m->input_ports[i]);
1002
1003         }
1004         free(m->input_ports);
1005
1006         for (i=0;i<m->nb_output_ports;i++) {
1007                 free(m->output_ports[i]);
1008         }
1009         free(m->output_ports);
1010
1011         free(m);
1012 }
1013 #endif 
1014 /*
1015  * dlopen plugin stuff
1016  */
1017
1018 const char driver_client_name[] = "freebob_pcm";
1019
1020 const jack_driver_desc_t *
1021 driver_get_descriptor ()
1022 {
1023         jack_driver_desc_t * desc;
1024         jack_driver_param_desc_t * params;
1025         unsigned int i;
1026
1027         desc = calloc (1, sizeof (jack_driver_desc_t));
1028
1029         strcpy (desc->name, "freebob");
1030         desc->nparams = 6;
1031  
1032         params = calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
1033         desc->params = params;
1034
1035         i = 0;
1036         strcpy (params[i].name, "device");
1037         params[i].character  = 'd';
1038         params[i].type       = JackDriverParamString;
1039         strcpy (params[i].value.str,  "hw:0");
1040         strcpy (params[i].short_desc, "The FireWire device to use. Format is: 'hw:port[,node]'.");
1041         strcpy (params[i].long_desc,  params[i].short_desc);
1042        
1043         i++;
1044         strcpy (params[i].name, "period");
1045         params[i].character  = 'p';
1046         params[i].type       = JackDriverParamUInt;
1047         params[i].value.ui   = 1024;
1048         strcpy (params[i].short_desc, "Frames per period");
1049         strcpy (params[i].long_desc, params[i].short_desc);
1050        
1051         i++;
1052         strcpy (params[i].name, "nperiods");
1053         params[i].character  = 'n';
1054         params[i].type       = JackDriverParamUInt;
1055         params[i].value.ui   = 3;
1056         strcpy (params[i].short_desc, "Number of periods of playback latency");
1057         strcpy (params[i].long_desc, params[i].short_desc);
1058
1059         i++;
1060         strcpy (params[i].name, "rate");
1061         params[i].character  = 'r';
1062         params[i].type       = JackDriverParamUInt;
1063         params[i].value.ui   = 48000U;
1064         strcpy (params[i].short_desc, "Sample rate");
1065         strcpy (params[i].long_desc, params[i].short_desc);
1066
1067         i++;
1068         strcpy (params[i].name, "capture");
1069         params[i].character  = 'i';
1070         params[i].type       = JackDriverParamUInt;
1071         params[i].value.ui   = 1U;
1072         strcpy (params[i].short_desc, "Provide capture ports.");
1073         strcpy (params[i].long_desc, params[i].short_desc);
1074
1075         i++;
1076         strcpy (params[i].name, "playback");
1077         params[i].character  = 'o';
1078         params[i].type       = JackDriverParamUInt;
1079         params[i].value.ui   = 1U;
1080         strcpy (params[i].short_desc, "Provide playback ports.");
1081         strcpy (params[i].long_desc, params[i].short_desc);
1082
1083         return desc;
1084 }
1085
1086
1087 jack_driver_t *
1088 driver_initialize (jack_client_t *client, JSList * params)
1089 {
1090         jack_driver_t *driver;
1091
1092     unsigned int port=0;
1093     unsigned int node_id=-1;
1094     int nbitems;
1095      
1096         const JSList * node;
1097         const jack_driver_param_t * param;
1098
1099         freebob_jack_settings_t cmlparams;
1100        
1101     char *device_name="hw:0";
1102      
1103         cmlparams.period_size_set=0;
1104         cmlparams.sample_rate_set=0;
1105         cmlparams.buffer_size_set=0;
1106         cmlparams.port_set=0;
1107         cmlparams.node_id_set=0;
1108
1109         /* default values */
1110         cmlparams.period_size=1024;
1111         cmlparams.sample_rate=48000;
1112         cmlparams.buffer_size=3;
1113         cmlparams.port=0;
1114         cmlparams.node_id=-1;
1115         cmlparams.playback_ports=1;
1116         cmlparams.capture_ports=1;
1117        
1118         for (node = params; node; node = jack_slist_next (node))
1119         {
1120                 param = (jack_driver_param_t *) node->data;
1121
1122                 switch (param->character)
1123                 {
1124                 case 'd':
1125                         device_name = strdup (param->value.str);
1126                         break;
1127                 case 'p':
1128                         cmlparams.period_size = param->value.ui;
1129                         cmlparams.period_size_set = 1;
1130                         break;
1131                 case 'n':
1132                         cmlparams.buffer_size = param->value.ui;
1133                         cmlparams.buffer_size_set = 1;
1134                         break;       
1135                 case 'r':
1136                         cmlparams.sample_rate = param->value.ui;
1137                         cmlparams.sample_rate_set = 1;
1138                         break;
1139                 case 'i':
1140                         cmlparams.capture_ports = param->value.ui;
1141                         break;
1142                 case 'o':
1143                         cmlparams.playback_ports = param->value.ui;
1144                         break;
1145                 }
1146         }
1147        
1148     nbitems=sscanf(device_name,"hw:%u,%u",&port,&node_id);
1149     if (nbitems<2) {
1150         nbitems=sscanf(device_name,"hw:%u",&port);
1151      
1152         if(nbitems < 1) {
1153             free(device_name);
1154             printError("device (-d) argument not valid\n");
1155             return NULL;
1156         } else {
1157             cmlparams.port = port;
1158             cmlparams.port_set=1;
1159            
1160             cmlparams.node_id = -1;
1161             cmlparams.node_id_set=0;
1162         }
1163      } else {
1164         cmlparams.port = port;
1165         cmlparams.port_set=1;
1166        
1167         cmlparams.node_id = node_id;
1168         cmlparams.node_id_set=1;
1169      }
1170
1171     jack_error("Freebob using Firewire port %d, node %d",cmlparams.port,cmlparams.node_id);
1172    
1173         driver=(jack_driver_t *)freebob_driver_new (client, "freebob_pcm", &cmlparams);
1174
1175         return driver;
1176 }
1177
1178 void
1179 driver_finish (jack_driver_t *driver)
1180 {
1181         freebob_driver_t *drv=(freebob_driver_t *) driver;
1182         // If jack hasn't called the detach method, do it now.  As of jack 0.101.1
1183         // the detach method was not being called explicitly on closedown, and
1184         // we need it to at least deallocate the iso resources.
1185         if (drv->dev != NULL)
1186                 freebob_driver_detach(drv);
1187         freebob_driver_delete (drv);
1188 }
Note: See TracBrowser for help on using the browser.