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

Revision 247, 30.1 kB (checked in by pieterpalmers, 16 years ago)

- added a modified jackd backend for version 2.0

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