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

Revision 249, 31.0 kB (checked in by pieterpalmers, 18 years ago)

- Extensive documentation update.

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