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

Revision 1254, 18.1 kB (checked in by ppalmers, 15 years ago)

split config.h into config/version/debug_config to allow for faster compilation (splits dependencies)

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