root/trunk/libffado/tests/streaming/teststreaming3.cpp

Revision 833, 18.1 kB (checked in by ppalmers, 16 years ago)

merge api-cleanup branch (R808:832) into trunk

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Copyright (C) 2005-2007 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  * This program 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 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24
25 /**
26  * Test application for the direct decode stream API
27  * for floating point use
28  */
29
30 #include "config.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <signal.h>
37 #include <sched.h>
38
39 #include "libffado/ffado.h"
40
41 #include "debugmodule/debugmodule.h"
42
43 #include <math.h>
44 #include <argp.h>
45
46 int run;
47
48 DECLARE_GLOBAL_DEBUG_MODULE;
49
50 // Program documentation.
51 // Program documentation.
52 static char doc[] = "FFADO -- a driver for Firewire Audio devices (streaming test application)\n\n"
53                     ;
54
55 // A description of the arguments we accept.
56 static char args_doc[] = "";
57
58 struct arguments
59 {
60     long int verbose;
61     long int test_tone;
62     long int test_tone_freq;
63     long int period;
64     long int slave_mode;
65     long int snoop_mode;
66     long int nb_buffers;
67     long int sample_rate;
68     long int rtprio;
69     long int audio_buffer_type;
70     char* args[2];
71    
72 };
73
74 // The options we understand.
75 static struct argp_option options[] = {
76     {"verbose",  'v', "level",    0,  "Verbose level" },
77     {"rtprio",  'P', "prio",  0,  "Realtime priority (0 = no RT scheduling)" },
78     {"test-tone",  't', "bool",  0,  "Output test sine" },
79     {"test-tone-freq",  'f', "hz",  0,  "Test sine frequency" },
80     {"samplerate",  'r', "hz",  0,  "Sample rate" },
81     {"period",  'p', "frames",  0,  "Period (buffer) size" },
82     {"nb_buffers",  'n', "nb",  0,  "Nb buffers (periods)" },
83     {"slave_mode",  's', "bool",  0,  "Run in slave mode" },
84     {"snoop_mode",  'S', "bool",  0,  "Run in snoop mode" },
85     {"audio_buffer_type",  'b', "",  0,  "Datatype of audio buffers (0=float, 1=int24)" },
86     { 0 }
87 };
88
89 //-------------------------------------------------------------
90
91 // Parse a single option.
92 static error_t
93 parse_opt( int key, char* arg, struct argp_state* state )
94 {
95     // Get the input argument from `argp_parse', which we
96     // know is a pointer to our arguments structure.
97     struct arguments* arguments = ( struct arguments* ) state->input;
98     char* tail;
99
100     switch (key) {
101     case 'v':
102         if (arg) {
103             arguments->verbose = strtol( arg, &tail, 0 );
104             if ( errno ) {
105                 fprintf( stderr,  "Could not parse 'verbose' argument\n" );
106                 return ARGP_ERR_UNKNOWN;
107             }
108         }
109         break;
110     case 'P':
111         if (arg) {
112             arguments->rtprio = strtol( arg, &tail, 0 );
113             if ( errno ) {
114                 fprintf( stderr,  "Could not parse 'rtprio' argument\n" );
115                 return ARGP_ERR_UNKNOWN;
116             }
117         }
118         break;
119     case 'p':
120         if (arg) {
121             arguments->period = strtol( arg, &tail, 0 );
122             if ( errno ) {
123                 fprintf( stderr,  "Could not parse 'period' argument\n" );
124                 return ARGP_ERR_UNKNOWN;
125             }
126         }
127         break;
128     case 'n':
129         if (arg) {
130             arguments->nb_buffers = strtol( arg, &tail, 0 );
131             if ( errno ) {
132                 fprintf( stderr,  "Could not parse 'nb_buffers' argument\n" );
133                 return ARGP_ERR_UNKNOWN;
134             }
135         }
136         break;
137     case 'r':
138         if (arg) {
139             arguments->sample_rate = strtol( arg, &tail, 0 );
140             if ( errno ) {
141                 fprintf( stderr,  "Could not parse 'samplerate' argument\n" );
142                 return ARGP_ERR_UNKNOWN;
143             }
144         }
145         break;
146     case 't':
147         if (arg) {
148             arguments->test_tone = strtol( arg, &tail, 0 );
149             if ( errno ) {
150                 fprintf( stderr,  "Could not parse 'test-tone' argument\n" );
151                 return ARGP_ERR_UNKNOWN;
152             }
153         }
154         break;
155     case 'f':
156         if (arg) {
157             arguments->test_tone_freq = strtol( arg, &tail, 0 );
158             if ( errno ) {
159                 fprintf( stderr,  "Could not parse 'test-tone-freq' argument\n" );
160                 return ARGP_ERR_UNKNOWN;
161             }
162         }
163         break;
164     case 'b':
165         if (arg) {
166             arguments->audio_buffer_type = strtol( arg, &tail, 0 );
167             if ( errno ) {
168                 fprintf( stderr,  "Could not parse 'audio-buffer-type' argument\n" );
169                 return ARGP_ERR_UNKNOWN;
170             }
171         }
172         break;
173     case 's':
174         if (arg) {
175             arguments->slave_mode = strtol( arg, &tail, 0 );
176             if ( errno ) {
177                 fprintf( stderr,  "Could not parse 'slave_mode' argument\n" );
178                 return ARGP_ERR_UNKNOWN;
179             }
180         }
181         break;
182     case 'S':
183         if (arg) {
184             arguments->snoop_mode = strtol( arg, &tail, 0 );
185             if ( errno ) {
186                 fprintf( stderr,  "Could not parse 'snoop_mode' argument\n" );
187                 return ARGP_ERR_UNKNOWN;
188             }
189         }
190         break;
191     case ARGP_KEY_ARG:
192         break;
193     case ARGP_KEY_END:
194         break;
195     default:
196         return ARGP_ERR_UNKNOWN;
197     }
198     return 0;
199 }
200
201 // Our argp parser.
202 static struct argp argp = { options, parse_opt, args_doc, doc };
203
204 int set_realtime_priority(unsigned int prio)
205 {
206     debugOutput(DEBUG_LEVEL_NORMAL, "Setting thread prio to %u\n", prio);
207     if (prio > 0) {
208         struct sched_param schp;
209         /*
210         * set the process to realtime privs
211         */
212         memset(&schp, 0, sizeof(schp));
213         schp.sched_priority = prio;
214        
215         if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {
216             perror("sched_setscheduler");
217             return -1;
218         }
219   } else {
220         struct sched_param schp;
221         /*
222         * set the process to realtime privs
223         */
224         memset(&schp, 0, sizeof(schp));
225         schp.sched_priority = 0;
226        
227         if (sched_setscheduler(0, SCHED_OTHER, &schp) != 0) {
228             perror("sched_setscheduler");
229             return -1;
230         }
231   }
232   return 0;
233 }
234
235 static void sighandler (int sig)
236 {
237     run = 0;
238 }
239
240 int main(int argc, char *argv[])
241 {
242
243     struct arguments arguments;
244
245     // Default values.
246     arguments.test_tone         = 0;
247     arguments.test_tone_freq    = 1000;
248     arguments.verbose           = 6;
249     arguments.period            = 1024;
250     arguments.slave_mode        = 0;
251     arguments.snoop_mode        = 0;
252     arguments.nb_buffers        = 3;
253     arguments.sample_rate       = 44100;
254     arguments.rtprio            = 0;
255     arguments.audio_buffer_type = 0;
256    
257     // Parse our arguments; every option seen by `parse_opt' will
258     // be reflected in `arguments'.
259     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
260         debugError("Could not parse command line\n" );
261         return -1;
262     }
263
264     debugOutput(DEBUG_LEVEL_NORMAL, "verbose level = %d\n", arguments.verbose);
265     setDebugLevel(arguments.verbose);
266
267     int nb_in_channels=0, nb_out_channels=0;
268     int i=0;
269     int start_flag = 0;
270
271     float frame_counter = 0.0;
272     float sine_advance = 0.0;
273     float amplitude = 0.97;
274    
275     int nb_periods=0;
276
277     int min_ch_count=0;
278
279     float **audiobuffers_in;
280     float **audiobuffers_out;
281     float *nullbuffer;
282    
283     run=1;
284
285     debugOutput(DEBUG_LEVEL_NORMAL, "FFADO streaming test application (3)\n");
286
287     signal (SIGINT, sighandler);
288     signal (SIGPIPE, sighandler);
289
290     ffado_device_info_t device_info;
291     memset(&device_info,0,sizeof(ffado_device_info_t));
292
293     ffado_options_t dev_options;
294     memset(&dev_options,0,sizeof(ffado_options_t));
295
296     dev_options.sample_rate = arguments.sample_rate;
297     dev_options.period_size = arguments.period;
298
299     dev_options.nb_buffers = arguments.nb_buffers;
300
301     dev_options.realtime = (arguments.rtprio != 0);
302     dev_options.packetizer_priority = arguments.rtprio;
303    
304     dev_options.verbose = arguments.verbose;
305        
306     dev_options.slave_mode = arguments.slave_mode;
307     dev_options.snoop_mode = arguments.snoop_mode;
308    
309     sine_advance = 2.0*M_PI*arguments.test_tone_freq/((float)dev_options.sample_rate);
310
311     ffado_device_t *dev=ffado_streaming_init(device_info, dev_options);
312
313     if (!dev) {
314         debugError("Could not init Ffado Streaming layer\n");
315         exit(-1);
316     }
317     if (arguments.audio_buffer_type == 0) {
318         ffado_streaming_set_audio_datatype(dev, ffado_audio_datatype_float);
319     } else {
320         ffado_streaming_set_audio_datatype(dev, ffado_audio_datatype_int24);
321     }
322
323     nb_in_channels = ffado_streaming_get_nb_capture_streams(dev);
324     nb_out_channels = ffado_streaming_get_nb_playback_streams(dev);
325
326     if (nb_in_channels < nb_out_channels) {
327         min_ch_count = nb_in_channels;
328     } else {
329         min_ch_count = nb_out_channels;
330     }
331
332     /* allocate intermediate buffers */
333     audiobuffers_in = (float **)calloc(nb_in_channels, sizeof(float *));
334     for (i=0; i < nb_in_channels; i++) {
335         audiobuffers_in[i] = (float *)calloc(arguments.period+1, sizeof(float));
336
337         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
338             case ffado_stream_type_audio:
339                 /* assign the audiobuffer to the stream */
340                 ffado_streaming_set_capture_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
341                 ffado_streaming_capture_stream_onoff(dev, i, 1);
342                 break;
343                 // this is done with read/write routines because the nb of bytes can differ.
344             case ffado_stream_type_midi:
345                 // note that using a float * buffer for midievents is a HACK
346                 ffado_streaming_set_capture_stream_buffer(dev, i, (char *)(audiobuffers_in[i]));
347                 ffado_streaming_capture_stream_onoff(dev, i, 1);
348             default:
349                 break;
350         }
351     }
352
353     audiobuffers_out = (float **)calloc(nb_out_channels, sizeof(float));
354     for (i=0; i < nb_out_channels; i++) {
355         audiobuffers_out[i] = (float *)calloc(arguments.period+1, sizeof(float));
356
357         switch (ffado_streaming_get_playback_stream_type(dev,i)) {
358             case ffado_stream_type_audio:
359                 /* assign the audiobuffer to the stream */
360                 ffado_streaming_set_playback_stream_buffer(dev, i, (char *)(audiobuffers_out[i]));
361                 ffado_streaming_playback_stream_onoff(dev, i, 1);
362                 break;
363                 // this is done with read/write routines because the nb of bytes can differ.
364             case ffado_stream_type_midi:
365                 ffado_streaming_set_playback_stream_buffer(dev, i, (char *)(audiobuffers_out[i]));
366                 ffado_streaming_playback_stream_onoff(dev, i, 1);
367             default:
368                 break;
369         }
370     }
371    
372     nullbuffer = (float *)calloc(arguments.period+1, sizeof(float));
373    
374    
375 //     /* open the files to write to*/
376 //     FILE* fid_in[nb_in_channels];
377 //     char name[256];
378 //
379 //     for (i=0;i<nb_in_channels;i++) {
380 //         snprintf(name,sizeof(name),"in_ch_%02d",i);
381 //         fid_in[i]=fopen(name,"w");
382 //
383 //         ffado_streaming_get_capture_stream_name(dev,i,name,sizeof(name));
384 //         fprintf(fid_in[i], "Channel name: %s\n",name);
385 //         switch (ffado_streaming_get_capture_stream_type(dev,i)) {
386 //         case ffado_stream_type_audio:
387 //             fprintf(fid_in[i], "Channel type: audio\n");
388 //             break;
389 //         case ffado_stream_type_midi:
390 //             fprintf(fid_in[i], "Channel type: midi\n");
391 //             break;
392 //         case ffado_stream_type_unknown:
393 //             fprintf(fid_in[i],"Channel type: unknown\n");
394 //             break;
395 //         default:
396 //         case ffado_stream_type_invalid:
397 //             fprintf(fid_in[i],"Channel type: invalid\n");
398 //             break;
399 //         }
400 //     }
401
402     // start the streaming layer
403     if (ffado_streaming_prepare(dev)) {
404         debugFatal("Could not prepare streaming system\n");
405         ffado_streaming_finish(dev);
406         return -1;
407     }
408     start_flag = ffado_streaming_start(dev);
409    
410     set_realtime_priority(arguments.rtprio);
411     debugOutput(DEBUG_LEVEL_NORMAL, "Entering receive loop (IN: %d, OUT: %d)\n", nb_in_channels, nb_out_channels);
412     while(run && start_flag==0) {
413         ffado_wait_response response;
414         response = ffado_streaming_wait(dev);
415         if (response == ffado_wait_xrun) {
416             debugOutput(DEBUG_LEVEL_NORMAL, "Xrun\n");
417             ffado_streaming_reset(dev);
418             continue;
419         } else if (response == ffado_wait_error) {
420             debugError("fatal xrun\n");
421             break;
422         }
423         ffado_streaming_transfer_capture_buffers(dev);
424
425         if (arguments.test_tone) {
426             // generate the test tone
427             for (i=0; i<arguments.period; i++) {
428                 float v = amplitude * sin(sine_advance * (frame_counter + (float)i));
429                 if (arguments.audio_buffer_type == 0) {
430                     nullbuffer[i] = v;
431                 } else {
432                     v = (v * 2147483392.0);
433                     int32_t tmp = ((int) v);
434                     tmp = tmp >> 8;
435                     memcpy(&nullbuffer[i], &tmp, sizeof(float));
436                 }
437             }
438            
439             // copy the test tone to the audio buffers
440             for (i=0; i < nb_out_channels; i++) {
441                 if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
442                     memcpy((char *)(audiobuffers_out[i]), (char *)(nullbuffer), sizeof(float) * arguments.period);
443                 }
444             }
445         } else {
446             uint32_t *midibuffer;
447             int idx;
448             for (i=0; i < min_ch_count; i++) {
449                 switch (ffado_streaming_get_capture_stream_type(dev,i)) {
450                     case ffado_stream_type_audio:
451                         // if both channels are audio channels, copy the buffers
452                         if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_audio) {
453                             memcpy((char *)(audiobuffers_out[i]), (char *)(audiobuffers_in[i]), sizeof(float) * arguments.period);
454                         }
455                         break;
456                         // this is done with read/write routines because the nb of bytes can differ.
457                     case ffado_stream_type_midi:
458                         midibuffer=(uint32_t *)audiobuffers_in[i];
459                         for(idx=0; idx < arguments.period; idx++) {
460                             uint32_t midievent = *(midibuffer + idx);
461                             if(midievent & 0xFF000000) {
462                                 debugOutput(DEBUG_LEVEL_NORMAL, " Received midi event %08X at idx %d of period %d on port %d\n",
463                                             midievent, idx, nb_periods, i);
464                             }
465                         }
466                     default:
467                         break;
468                 }
469             }
470             for (i=0; i < nb_out_channels; i++) {
471                 if (ffado_streaming_get_playback_stream_type(dev,i) == ffado_stream_type_midi) {
472                     uint32_t *midievent = (uint32_t *)audiobuffers_out[i];
473                     *midievent = 0x010000FF;
474                     break;
475                 }
476             }
477
478         }
479
480         ffado_streaming_transfer_playback_buffers(dev);
481
482         nb_periods++;
483         frame_counter += arguments.period;
484
485 //         if((nb_periods % 32)==0) {
486 // //             debugOutput(DEBUG_LEVEL_NORMAL, "\r%05d periods",nb_periods);
487 //         }
488
489 //         for(i=0;i<nb_in_channels;i++) {
490 //             
491 //             
492 //             switch (ffado_streaming_get_capture_stream_type(dev,i)) {
493 //             case ffado_stream_type_audio:
494 //                 // no need to get the buffers manually, we have set the API internal buffers to the audiobuffer[i]'s
495 // //                 //samplesread=freebob_streaming_read(dev, i, audiobuffer[i], arguments.period);
496 //                 samplesread=arguments.period;
497 //                 break;
498 //             case ffado_stream_type_midi:
499 //                 //samplesread=ffado_streaming_read(dev, i, audiobuffers_out[i], arguments.period);
500 //                 break;
501 //                         default: break;
502 //             }
503 //     
504 // //               fprintf(fid_in[i], "---- Period read  (%d samples) ----\n",samplesread);
505 // //               hexDumpToFile(fid_in[i],(unsigned char*)audiobuffers_in[i],samplesread*sizeof(float)+1);
506 //         }
507
508 //         for(i=0;i<nb_out_channels;i++) {
509 //             float *buff;
510 //             int sampleswritten=0;
511 //             if (i<nb_in_channels) {
512 //                 buff=audiobuffers_out[i];
513 //             } else {
514 //                 buff=nullbuffer;
515 //             }
516 //             
517 //             switch (ffado_streaming_get_playback_stream_type(dev,i)) {
518 //             case ffado_stream_type_audio:
519 // //                  sampleswritten=freebob_streaming_write(dev, i, buff, arguments.period);
520 //                 sampleswritten=arguments.period;
521 //                 break;
522 //             case ffado_stream_type_midi:
523 // //                 sampleswritten=freebob_streaming_write(dev, i, buff, arguments.period);
524 //                 break;
525 //                         default: break;
526 //             }
527 // //               fprintf(fid_out[i], "---- Period write (%d samples) ----\n",sampleswritten);
528 // //               hexDumpToFile(fid_out[i],(unsigned char*)buff,sampleswritten*sizeof(ffado_sample_t));
529 //         }
530     }
531
532     debugOutput(DEBUG_LEVEL_NORMAL, "Exiting receive loop\n");
533    
534     ffado_streaming_stop(dev);
535     ffado_streaming_finish(dev);
536
537 //     for (i=0;i<nb_in_channels;i++) {
538 //         fclose(fid_in[i]);
539 //     }
540    
541     for (i=0;i<nb_in_channels;i++) {
542         free(audiobuffers_in[i]);
543         free(audiobuffers_out[i]);
544     }
545     free(nullbuffer);
546     free(audiobuffers_in);
547     free(audiobuffers_out);
548
549   return EXIT_SUCCESS;
550 }
Note: See TracBrowser for help on using the browser.