root/trunk/freebobstreaming/freebob_driver.c

Revision 150, 29.0 kB (checked in by pieterpalmers, 18 years ago)

- implement ALSA SEQ midi support

- fixed some small midi-related things

- changed the debug printing to the jackd messagebuffer based approach

- some small modification to the counters

- modified the packet handling on order to support lower buffer sizes and a lower number of buffers.
- it is possible to compile non-poll based support too

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