root/trunk/libffado/tests/streaming/testmidistreaming1.c

Revision 554, 13.9 kB (checked in by ppalmers, 16 years ago)

Merge echoaudio branch into trunk.

This adds support for the Echo Audiofire devices to FFADO. Possibly also other devices working with the Apple Class Driver will work with this code. It is not fully complete yet, but the main rework is
done.

First of all the IAvDevice class/interface is renamed to FFADODevice, in order to separate the AV/C code from the FFADO API code. A device supported by FFADO implements a FFADODevice.

The BeBoB device has been split up into three groups:
- libavc/* : all code and commands that are specified by AV/C specs. Note that a lot of the code that used to be in BeBoB::AvDevice? now resides in AVC::Unit
- genericavc/* : a FFADODevice that uses AV/C descriptors & commands for discovery and config
- bebob/* : the bebob FFADODevice that inherits from GenericAVC::AvDevice? but that uses BridgeCo? commands for discovery

Everything has been moved as high as possible in the class hierarchy. If necessary, a subclass that uses device specific commands is introduced (e.g. BeBoB::Plug inherits from AVC::Plug and uses the
BridgeCo? extended plug info command to discover it's properties).

There are some other fixes along the way that have been done too.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2007 by by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * FFADO is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * FFADO is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with FFADO; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA.
22  */
23
24
25 /**
26  * Test application for the direct decode stream API
27  * for floating point use
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <signal.h>
39 #include <libiec61883/iec61883.h>
40 #include <stdio.h>
41 #include <sys/select.h>
42 #include <signal.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <alsa/asoundlib.h>
46
47 #include "libffado/ffado.h"
48
49 #include "debugtools.h"
50 #define IEC61883_AM824_LABEL_MIDI_NO_DATA 0x80
51 #define IEC61883_AM824_LABEL_MIDI_1X      0x81
52 #define IEC61883_AM824_LABEL_MIDI_2X      0x82
53 #define IEC61883_AM824_LABEL_MIDI_3X      0x83
54        
55 #define ALSA_SEQ_BUFF_SIZE 1024
56 #define MAX_MIDI_PORTS   20
57 #define MIDI_TRANSMIT_BUFFER_SIZE 1024
58
59 int run;
60
61 static void sighandler (int sig)
62 {
63         run = 0;
64 }
65
66 typedef struct {
67         int seq_port_nr;
68         snd_midi_event_t *parser;
69         snd_seq_t *seq_handle;
70 } ffado_midi_port_t;
71
72 typedef struct {
73         snd_seq_t *seq_handle;
74         int nb_seq_ports;
75         ffado_midi_port_t *ports[MAX_MIDI_PORTS];
76 } ffado_midi_ports_t;
77
78 int open_seq(snd_seq_t **seq_handle, int in_ports[], int out_ports[], int num_in, int num_out);
79
80 /* Open ALSA sequencer with num_in writeable ports and num_out readable ports. */
81 /* The sequencer handle and the port IDs are returned.                        */ 
82 int open_seq(snd_seq_t **seq_handle, int in_ports[], int out_ports[], int num_in, int num_out) {
83
84         int l1;
85         char portname[64];
86
87         if (snd_seq_open(seq_handle, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) {
88                 fprintf(stderr, "Error opening ALSA sequencer.\n");
89                 return(-1);
90         }
91        
92         snd_seq_set_client_name(*seq_handle, "FreeBob MIDI I/O test");
93        
94         for (l1 = 0; l1 < num_in; l1++) {
95                 sprintf(portname, "MIDI OUT %d", l1);
96                 if ((in_ports[l1] = snd_seq_create_simple_port(*seq_handle, portname,
97                          SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
98                          SND_SEQ_PORT_TYPE_MIDI_GENERIC)) < 0) {
99                                  fprintf(stderr, "Error creating sequencer port.\n");
100                                  return(-1);
101                          }
102         }
103         for (l1 = 0; l1 < num_out; l1++) {
104                 sprintf(portname, "MIDI IN %d", l1);
105                 if ((out_ports[l1] = snd_seq_create_simple_port(*seq_handle, portname,
106                          SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
107                          SND_SEQ_PORT_TYPE_MIDI_GENERIC)) < 0) {
108                                  fprintf(stderr, "Error creating sequencer port.\n");
109                                  return(-1);
110                          }
111         }
112         return(0);
113 }
114
115 void decode_midi_byte (ffado_midi_port_t *port, int byte) {
116         snd_seq_event_t ev;
117         if ((snd_midi_event_encode_byte(port->parser,byte, &ev)) > 0) {
118 //              printf("message ok, sending it to %d\n", port->seq_port_nr);
119                 // a midi message is complete, send it out to ALSA
120                 snd_seq_ev_set_subs(&ev); 
121                 snd_seq_ev_set_direct(&ev);
122                 snd_seq_ev_set_source(&ev, port->seq_port_nr);
123                 snd_seq_event_output_direct(port->seq_handle, &ev);                                             
124         }       else {
125                
126         }
127 }
128
129 int encode_midi_bytes(ffado_midi_port_t *port, unsigned char *byte_buff, int len) {
130     static int cnt=0;
131     cnt++;
132     if (cnt>64) {
133         *byte_buff=0xFF;
134         return 1;
135     }
136     return 0;
137 }
138
139 int main(int argc, char *argv[])
140 {
141
142         #define PERIOD_SIZE 1024
143
144         int samplesread=0, sampleswritten=0;
145         int nb_in_channels=0, nb_out_channels=0;
146         int retval=0;
147         int i=0;
148         int start_flag = 0;
149
150         int nb_periods=0;
151
152         ffado_sample_t **audiobuffers_in;
153         ffado_sample_t **audiobuffers_out;
154         ffado_sample_t *nullbuffer;
155        
156         run=1;
157
158         printf("Ffado MIDI streaming test application (1)\n");
159
160         signal (SIGINT, sighandler);
161         signal (SIGPIPE, sighandler);
162
163         ffado_device_info_t device_info;
164
165         ffado_options_t dev_options;
166
167         dev_options.sample_rate=48000; // -1 = detect from discovery
168         dev_options.period_size=PERIOD_SIZE;
169
170         dev_options.nb_buffers=3;
171
172         dev_options.port=0;
173         dev_options.node_id=-1;
174        
175         dev_options.realtime=0;
176         dev_options.packetizer_priority=60;
177        
178         dev_options.directions=0;
179        
180         dev_options.verbose=5;
181        
182         dev_options.slave_mode=0;
183         dev_options.snoop_mode=0;
184
185         ffado_device_t *dev=ffado_streaming_init(&device_info, dev_options);
186         if (!dev) {
187                 fprintf(stderr,"Could not init Ffado Streaming layer\n");
188                 exit(-1);
189         }
190
191         nb_in_channels=ffado_streaming_get_nb_capture_streams(dev);
192         nb_out_channels=ffado_streaming_get_nb_playback_streams(dev);
193
194         int midi_in_nbchannels=0;
195         int midi_out_nbchannels=0;
196        
197         /* allocate intermediate buffers */
198         audiobuffers_in=calloc(nb_in_channels,sizeof(ffado_sample_t *));
199         audiobuffers_out=calloc(nb_in_channels,sizeof(ffado_sample_t));
200         for (i=0;i<nb_in_channels;i++) {
201                 audiobuffers_in[i]=calloc(PERIOD_SIZE+1,sizeof(ffado_sample_t));
202                 audiobuffers_out[i]=calloc(PERIOD_SIZE+1,sizeof(ffado_sample_t));
203                        
204                 switch (ffado_streaming_get_capture_stream_type(dev,i)) {
205                         case ffado_stream_type_audio:
206                                 /* assign the audiobuffer to the stream */
207                                 ffado_streaming_set_capture_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
208                                 ffado_streaming_set_capture_buffer_type(dev, i, ffado_buffer_type_float);
209                                 break;
210                                
211                         // this is done with read/write routines because the nb of bytes can differ.
212                         case ffado_stream_type_midi:
213                                 midi_in_nbchannels++;
214                         default:
215                                 break;
216                 }
217         }
218        
219         nullbuffer=calloc(PERIOD_SIZE+1,sizeof(ffado_sample_t));
220        
221         for (i=0;i<nb_out_channels;i++) {
222                 switch (ffado_streaming_get_capture_stream_type(dev,i)) {
223                         case ffado_stream_type_audio:
224                                 if (i<nb_in_channels) {
225                                         /* assign the audiobuffer to the stream */
226                                         ffado_streaming_set_playback_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
227                                         ffado_streaming_set_playback_buffer_type(dev, i, ffado_buffer_type_float);
228                                 } else {
229                                         ffado_streaming_set_playback_stream_buffer(dev, i, (char *)nullbuffer);
230                                         ffado_streaming_set_playback_buffer_type(dev, i, ffado_buffer_type_int24);     
231                                 }
232                                 break;
233                                 // this is done with read/write routines because the nb of bytes can differ.
234                         case ffado_stream_type_midi:
235                                 midi_out_nbchannels++;
236                         default:
237                                 break;
238                 }
239         }
240        
241         /* open the files to write to*/
242         FILE* fid_out[nb_out_channels];
243         FILE* fid_in[nb_in_channels];
244         char name[256];
245
246         for (i=0;i<nb_out_channels;i++) {
247                 snprintf(name,sizeof(name),"out_ch_%02d",i);
248
249                 fid_out[i]=fopen(name,"w");
250
251                 ffado_streaming_get_playback_stream_name(dev,i,name,sizeof(name));
252                 fprintf(fid_out[i],"Channel name: %s\n",name);
253                 switch (ffado_streaming_get_playback_stream_type(dev,i)) {
254                 case ffado_stream_type_audio:
255                         fprintf(fid_out[i],"Channel type: audio\n");
256                         break;
257                 case ffado_stream_type_midi:
258                         fprintf(fid_out[i],"Channel type: midi\n");
259                         break;
260                 case ffado_stream_type_unknown:
261                         fprintf(fid_out[i],"Channel type: unknown\n");
262                         break;
263                 default:
264                 case ffado_stream_type_invalid:
265                         fprintf(fid_out[i],"Channel type: invalid\n");
266                         break;
267                 }
268
269         }
270         for (i=0;i<nb_in_channels;i++) {
271                 snprintf(name,sizeof(name),"in_ch_%02d",i);
272                 fid_in[i]=fopen(name,"w");
273
274                 ffado_streaming_get_capture_stream_name(dev,i,name,sizeof(name));
275                 fprintf(fid_in[i], "Channel name: %s\n", name);
276                 switch (ffado_streaming_get_capture_stream_type(dev,i)) {
277                 case ffado_stream_type_audio:
278                         fprintf(fid_in[i], "Channel type: audio\n");
279                         break;
280                 case ffado_stream_type_midi:
281                         fprintf(fid_in[i], "Channel type: midi\n");
282                         break;
283                 case ffado_stream_type_unknown:
284                         fprintf(fid_in[i],"Channel type: unknown\n");
285                         break;
286                 default:
287                 case ffado_stream_type_invalid:
288                         fprintf(fid_in[i],"Channel type: invalid\n");
289                         break;
290                 }
291         }
292
293         // setup the ALSA midi seq clients
294         snd_seq_t *seq_handle;
295         int in_ports[midi_in_nbchannels], out_ports[midi_out_nbchannels];
296        
297     // open sequencer
298         // the number of midi ports is statically set to 2
299         if (open_seq(&seq_handle, in_ports, out_ports, midi_in_nbchannels, midi_out_nbchannels) < 0) {
300                 fprintf(stderr, "ALSA Error.\n");
301                 exit(1);
302         }
303
304         ffado_midi_port_t* midi_out_portmap[nb_out_channels];
305         ffado_midi_port_t* midi_in_portmap[nb_in_channels];
306        
307         int cnt=0;
308        
309         for (i=0;i<nb_out_channels;i++) {
310                 ffado_midi_port_t *midi_out_port;
311                 switch (ffado_streaming_get_playback_stream_type(dev,i)) {
312                         case ffado_stream_type_audio:
313                                 midi_out_portmap[i]=NULL;
314                                 break;
315                         case ffado_stream_type_midi:
316                                 midi_out_port=malloc(sizeof(ffado_midi_port_t));
317                                 if(!midi_out_port) {
318                                         fprintf(stderr, "Could not allocate memory for MIDI OUT port %d\n",i);
319                                         exit(1); // this could be/is a memory leak, I know...
320                                 } else {
321                                         midi_out_port->seq_port_nr=in_ports[cnt++];
322                                         midi_out_port->seq_handle=seq_handle;
323                                         if (snd_midi_event_new  ( ALSA_SEQ_BUFF_SIZE, &(midi_out_port->parser)) < 0) {
324                                                 fprintf(stderr, "ALSA Error: could not init parser for MIDI OUT port %d\n",i);
325                                                 exit(1); // this too
326                                         }   
327                                         midi_out_portmap[i]=midi_out_port;
328                                 }
329                                 break;
330                         default: break;
331                 }
332         }
333        
334         cnt=0;
335         for (i=0;i<nb_in_channels;i++) {
336                 ffado_midi_port_t *midi_in_port;
337                 switch (ffado_streaming_get_capture_stream_type(dev,i)) {
338                         case ffado_stream_type_audio:
339                                 midi_in_portmap[i]=NULL;
340                                 break;
341                         case ffado_stream_type_midi:
342                
343                                 midi_in_port=malloc(sizeof(ffado_midi_port_t));
344                                 if(!midi_in_port) {
345                                         fprintf(stderr, "Could not allocate memory for MIDI IN port %d\n",i);
346                                         exit(1); // this could be/is a memory leak, I know...
347                                 } else {
348                                         midi_in_port->seq_port_nr=out_ports[cnt++];
349                                         midi_in_port->seq_handle=seq_handle;
350                        
351                                         if (snd_midi_event_new  ( ALSA_SEQ_BUFF_SIZE, &(midi_in_port->parser)) < 0) {
352                                                 fprintf(stderr, "ALSA Error: could not init parser for MIDI IN port %d\n",i);
353                                                 exit(1); // this too
354                                         }   
355                                         midi_in_portmap[i]=midi_in_port;
356                                 }
357                                 break;
358                         default: break;
359                 }
360         }       
361        
362         // start the streaming layer
363         ffado_streaming_prepare(dev);
364         start_flag = ffado_streaming_start(dev);
365
366         fprintf(stderr,"Entering receive loop (%d,%d)\n",nb_in_channels,nb_out_channels);
367         while(run && start_flag==0) {
368                 retval = ffado_streaming_wait(dev);
369                 if (retval < 0) {
370                         fprintf(stderr,"Xrun\n");
371                         ffado_streaming_reset(dev);
372                         continue;
373                 }
374                
375 //              ffado_streaming_transfer_buffers(dev);
376                 ffado_streaming_transfer_capture_buffers(dev);
377                 ffado_streaming_transfer_playback_buffers(dev);
378                
379                 nb_periods++;
380
381                 if((nb_periods % 32)==0) {
382 //                      fprintf(stderr,"\r%05d periods",nb_periods);
383                 }
384
385                 for(i=0;i<nb_in_channels;i++) {
386                         int s;
387                        
388                         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
389                         case ffado_stream_type_audio:
390                                 // no need to get the buffers manually, we have set the API internal buffers to the audiobuffer[i]'s
391 //                              //samplesread=ffado_streaming_read(dev, i, audiobuffer[i], PERIOD_SIZE);
392                                 samplesread=PERIOD_SIZE;
393                                 break;
394                         case ffado_stream_type_midi:
395                                 samplesread=ffado_streaming_read(dev, i, audiobuffers_in[i], 64);
396                                 quadlet_t *buff=(quadlet_t *)audiobuffers_in[i];
397                                 if (samplesread) printf("RECV (CH %02X): ", i);
398                                 for (s=0;s<samplesread;s++) {
399                                         quadlet_t *byte=(buff+s) ;
400                                         printf("%08X ",*byte);
401                                         decode_midi_byte (midi_in_portmap[i], (*byte) & 0xFF);
402                                 }
403                                 if (samplesread) printf("\n");
404                                 if(samplesread>0) {
405                                         fprintf(fid_in[i], "---- Period read (%d samples) ----\n",samplesread);
406                                         hexDumpToFile(fid_in[i],(unsigned char*)audiobuffers_in[i],samplesread*sizeof(ffado_sample_t));
407                                 }
408                                 break;
409                         default: break;
410                         }
411 //                      fprintf(fid_in[i], "---- Period read (%d samples) ----\n",samplesread);
412 //                      hexDumpToFile(fid_in[i],(unsigned char*)buff,samplesread*sizeof(ffado_sample_t));
413        
414                 }
415
416                 for(i=0;i<nb_out_channels;i++) {
417                         ffado_sample_t *buff;
418                         int b=0;
419                         unsigned char* byte_buff;
420                        
421                         if (i<nb_in_channels) {
422                                 buff=audiobuffers_out[i];
423                         } else {
424                                 buff=nullbuffer;
425                         }
426                        
427                         switch (ffado_streaming_get_playback_stream_type(dev,i)) {
428                         case ffado_stream_type_audio:
429 //                              sampleswritten=ffado_streaming_write(dev, i, buff, PERIOD_SIZE);
430 //                              sampleswritten=PERIOD_SIZE;
431                                 break;
432                         case ffado_stream_type_midi:
433                                
434                                 #define max_midi_bytes_to_write PERIOD_SIZE/8
435                                 byte_buff=(unsigned char*)buff;
436                                
437                                 sampleswritten=encode_midi_bytes(midi_out_portmap[i], byte_buff, max_midi_bytes_to_write);
438                                 if (sampleswritten) printf("SEND (CH %02X): ", i);
439                                 for(b=0;b<sampleswritten;b++) {
440                                         ffado_sample_t tmp_event=*(byte_buff+b);
441                                         printf("%08X ",*(byte_buff+b));
442                                         ffado_streaming_write(dev, i, &tmp_event, 1);
443                                 }
444                                 if (sampleswritten) printf("\n");
445
446                                 fprintf(fid_out[i], "---- Period write (%d samples) ----\n",sampleswritten);
447                                 hexDumpToFile(fid_out[i],(unsigned char*)buff,sampleswritten*sizeof(ffado_sample_t));
448                                 break;
449                         default: break;
450                         }
451                 }
452
453         }
454
455         fprintf(stderr,"\n");
456
457         fprintf(stderr,"Exiting receive loop\n");
458        
459         ffado_streaming_stop(dev);
460
461         ffado_streaming_finish(dev);
462
463         for (i=0;i<nb_out_channels;i++) {
464                 fclose(fid_out[i]);
465
466         }
467         for (i=0;i<nb_in_channels;i++) {
468                 fclose(fid_in[i]);
469         }
470        
471         for (i=0;i<nb_in_channels;i++) {
472                 free(audiobuffers_in[i]);
473                 free(audiobuffers_out[i]);
474         }
475         free(nullbuffer);
476         free(audiobuffers_in);
477         free(audiobuffers_out);
478        
479         // free the MIDI to seq parsers and port structures
480         for(i=0;i<midi_in_nbchannels;i++) {
481                 ffado_midi_port_t *midi_in_port=midi_in_portmap[i];
482                
483                 if(midi_in_port) {
484                         snd_midi_event_free  (  midi_in_port->parser );
485                         free(midi_in_port);
486                 }
487         }
488         // free the MIDI to seq parsers and port structures
489         for(i=0;i<midi_out_nbchannels;i++) {
490                 ffado_midi_port_t *midi_out_port=midi_out_portmap[i];
491
492                 if(midi_out_port) {
493                         snd_midi_event_free  (  midi_out_port->parser );
494                         free(midi_out_port);
495                 }
496         }
497
498   return EXIT_SUCCESS;
499 }
Note: See TracBrowser for help on using the browser.