Mercurial > hg > audiostuff
changeset 1:9cadc470e3da
reorganize, add more
author | pmeerw@pan |
---|---|
date | Fri, 30 Oct 2009 23:07:52 +0100 |
parents | deadffdf5d60 |
children | 13be24d74cd2 |
files | Makefile README.txt alsacap.c audiodelay.cpp audiodelay/Makefile audiodelay/audiodelay.cpp rtaudio-test.cpp |
diffstat | 7 files changed, 824 insertions(+), 150 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Fri Oct 30 23:07:52 2009 +0100 @@ -0,0 +1,23 @@ +PROGRAMS = audiodelay alsacap rtaudio-test +RM = rm -f + +CC = gcc +CXX = g++ +CFLAGS = -O2 -Wall + +all: $(PROGRAMS) + +alsacap: alsacap.c + $(CC) $(CFLAGS) -o $@ alsacap.c -lasound + +audiodelay: audiodelay.cpp + $(CXX) $(CFLAGS) -o $@ audiodelay.cpp -lpthread -lasound -lrtaudio + +rtaudio-test: rtaudio-test.cpp + $(CXX) $(CFLAGS) -o $@ rtaudio-test.cpp -lpthread -lasound -lrtaudio + +clean: + -$(RM) *.o $(PROGRAMS) *~ + +strip: + strip $(PROGRAMS)
--- a/README.txt Fri Oct 30 22:45:25 2009 +0100 +++ b/README.txt Fri Oct 30 23:07:52 2009 +0100 @@ -1,4 +1,4 @@ README audiodelay measures delay between audio output and record using RtAudio - +alsacap display ALSA sound card capabilities
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/alsacap.c Fri Oct 30 23:07:52 2009 +0100 @@ -0,0 +1,556 @@ +/* + * ALSA parameter test program + * + * compile with: gcc -o alsacap alsacap.c -lasound +*/ + + +/*============================================================================ + Includes +============================================================================*/ + +#include <stdlib.h> +#include <stdio.h> +#include <alsa/asoundlib.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> + +/*============================================================================ + Constant and type definitions +============================================================================*/ + +#define RATE_KHZ_LIMIT 200 + +#define HWP_END 0 +#define HWP_RATE 1 +#define HWP_NCH 2 +#define HWP_FORMAT 3 +#define SIZE_HWP 7 + +typedef struct { + int recdevices, verbose, card, dev; + char *device; + int hwparams[SIZE_HWP]; +} +aiopts; + + +/*============================================================================ + Global variables +============================================================================*/ + +static snd_ctl_t *handle= NULL; +static snd_pcm_t *pcm= NULL; +static snd_ctl_card_info_t *info; +static snd_pcm_info_t *pcminfo; +static snd_pcm_hw_params_t *pars; +static snd_pcm_format_mask_t *fmask; + + +/*============================================================================ + Prototypes +============================================================================*/ + +void usagemsg(int code); +void errnumarg(char optchar); +void errarg(char optchar); +void errtoomany(); + +void scancards(snd_pcm_stream_t stream, int thecard, int thedev); +int sc_errcheck(int retval, const char *doingwhat, int cardnr, int devnr); + +void testconfig(snd_pcm_stream_t stream, const char *device, const int *hwpars); +void tc_errcheck(int retval, const char *doingwhat); + +const char *alsaerrstr(const int errcode); +const char *dirstr(int dir); + +int parse_alsaformat(const char *fmtstr); +const char *alsafmtstr(int fmtnum); + +void printfmtmask(const snd_pcm_format_mask_t *fmask); + + +/*============================================================================ + Main program +============================================================================*/ + +int main(int argc, char **argv) +{ + aiopts options= { 0, 1, -1, -1, NULL }; + snd_pcm_stream_t stream; + char *argpar; + int argind, hwpind; + + snd_ctl_card_info_alloca(&info); + snd_pcm_info_alloca(&pcminfo); + snd_pcm_hw_params_alloca(&pars); + snd_pcm_format_mask_alloca(&fmask); + + hwpind= 0; + for( argind= 1; argind< argc; ++argind ) + { + if( argv[argind][0]!='-' ) { + fprintf(stderr, "Unrecognised command-line argument `%s'.\n", argv[argind]); + usagemsg(1); + } + if( argv[argind][2] ) argpar= argv[argind]+2; + else { + if( argind+1 >= argc ) argpar= NULL; + else argpar= argv[argind+1]; + } + if( argv[argind][1]=='h' || !strcmp(argv[argind]+1, "-help") ) + usagemsg(0); + else if( argv[argind][1]=='R' ) { + options.recdevices= 1; + argpar= NULL; // set to NULL if unused to keep track of next arg index + } + else if( argv[argind][1]=='C' ) { + if( !argpar || !isdigit(*argpar) ) errnumarg('C'); + options.card= strtol(argpar, NULL, 0); + } + else if( argv[argind][1]=='D' ) { + if( !argpar || !isdigit(*argpar) ) errnumarg('D'); + options.dev= strtol(argpar, NULL, 0); + } + else if( argv[argind][1]=='d' ) { + if( !argpar ) errarg('d'); + options.device= argpar; + } + else if( argv[argind][1]=='r' ) { + if( !argpar || !isdigit(*argpar) ) errnumarg('r'); + if( hwpind+3 > SIZE_HWP ) errtoomany(); + options.hwparams[hwpind++]= HWP_RATE; + options.hwparams[hwpind]= strtol(argpar, NULL, 0); + if( options.hwparams[hwpind] <= RATE_KHZ_LIMIT ) + options.hwparams[hwpind] *= 1000; // sanity check: Hz or kHz ? + ++hwpind; + } + else if( argv[argind][1]=='c' ) { + if( !argpar || !isdigit(*argpar) ) errnumarg('c'); + if( hwpind+3 > SIZE_HWP ) errtoomany(); + options.hwparams[hwpind++]= HWP_NCH; + options.hwparams[hwpind++]= strtol(argpar, NULL, 0); + } + else if( argv[argind][1]=='f' ) { + if( !argpar ) errarg('f'); + if( hwpind+3 > SIZE_HWP ) errtoomany(); + options.hwparams[hwpind++]= HWP_FORMAT; + options.hwparams[hwpind++]= parse_alsaformat(argpar); + } + else { + fprintf(stderr, "Unrecognised command-line option `%s'.\n", argv[argind]); + usagemsg(1); + } + if( argpar && !argv[argind][2] ) + ++argind; // additional increment if separate parameter argument was used + } + options.hwparams[hwpind]= HWP_END; + if( options.dev >= 0 && options.card < 0 ) { + fprintf(stderr, "The card has to be specified with -C if a device number is given (-D).\n"); + exit(1); + } + if( options.device && (options.card>=0 || options.dev>=0) ) { + fprintf(stderr, "Specifying a device name (-d) and a card and possibly device number (-C, -D) is mutually exclusive.\n"); + exit(1); + } + stream= options.recdevices? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK; + + if( !options.device ) + scancards(stream, options.card, options.dev); + else + testconfig(stream, options.device, options.hwparams); + + exit(0); +} + + + +/*============================================================================ + Usage message and command-line argument error functions +============================================================================*/ + +void usagemsg(int code) +{ + fprintf(stderr, "Usage: alsacap [-R] [-C <card #> [-D <device #>]]\n" + " alsacap [-R] -d <device name> [-r <rate>|-c <# of channels>|-f <sample format>]...\n" + "ALSA capability lister.\n" + "First form: Scans one or all soundcards known to ALSA for devices, \n" + "subdevices and parameter ranges. -R causes a scan for recording\n" + "rather than playback devices. The other options specify the sound\n" + "card and possibly the device by number.\n" + "Second form: Displays ranges of configuration parameters for the given\n" + "ALSA device. Unlike with the first form, a non-hardware device may be\n" + "given. Up to three optional command-line arguments fix the rate,\n" + "number of channels and sample format in the order in which they are\n" + "given. The remaining parameter ranges are output. If unique, the\n" + "number of significant bits of the sample values is output. (Some\n" + "sound cards ignore some of the bits.)\n"); + exit(code); +} + +void errnumarg(char optchar) +{ + fprintf(stderr, "The -%c option requires a numerical argument! Aborting.\n", optchar); + exit(1); +} + +void errarg(char optchar) +{ + fprintf(stderr, "The -%c option requires an argument! Aborting.\n", optchar); + exit(1); +} + +void errtoomany() +{ + fprintf(stderr, "Too many -r/-c/-f options given! (Maximum is %d.) Aborting.\n", (SIZE_HWP-1)/2); + exit(1); +} + + +/*============================================================================ + Function for scanning all cards +============================================================================*/ + +#define HWCARDTEMPL "hw:%d" +#define HWDEVTEMPL "hw:%d,%d" +#define HWDEVLEN 32 + +void scancards(snd_pcm_stream_t stream, int thecard, int thedev) +{ + char hwdev[HWDEVLEN+1]; + unsigned min, max; + int card, err, dev, subd, nsubd; + + printf("*** Scanning for %s devices", stream==SND_PCM_STREAM_CAPTURE? "recording" : "playback"); + if( thecard >= 0 ) + printf(" on card %d", thecard); + if( thedev >= 0 ) + printf(", device %d", thedev); + printf(" ***\n"); + hwdev[HWDEVLEN]= 0; + if( thecard >= 0 ) + card= thecard; + else { + card= -1; + if( snd_card_next(&card) < 0 ) + return; + } + while( card >= 0 ) + { + snprintf(hwdev, HWDEVLEN, HWCARDTEMPL, card); + err= snd_ctl_open(&handle, hwdev, 0); + if( sc_errcheck(err, "opening control interface", card, -1) ) goto nextcard; + err= snd_ctl_card_info(handle, info); + if( sc_errcheck(err, "obtaining card info", card, -1) ) { + snd_ctl_close(handle); + goto nextcard; + } + printf("Card %d, ID `%s', name `%s'\n", card, snd_ctl_card_info_get_id(info), + snd_ctl_card_info_get_name(info)); + if( thedev >= 0 ) + dev= thedev; + else { + dev= -1; + if( snd_ctl_pcm_next_device(handle, &dev) < 0 ) { + snd_ctl_close(handle); + goto nextcard; + } + } + while( dev >= 0 ) + { + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + snd_pcm_info_set_stream(pcminfo, stream); + err= snd_ctl_pcm_info(handle, pcminfo); + if( thedev<0 && err == -ENOENT ) goto nextdev; + if( sc_errcheck(err, "obtaining device info", card, dev) ) goto nextdev; + nsubd= snd_pcm_info_get_subdevices_count(pcminfo); + if( sc_errcheck(nsubd, "obtaining device info", card, dev) ) goto nextdev; + printf(" Device %d, ID `%s', name `%s', %d subdevices (%d available)\n", + dev, snd_pcm_info_get_id(pcminfo), snd_pcm_info_get_name(pcminfo), + nsubd, snd_pcm_info_get_subdevices_avail(pcminfo)); + snprintf(hwdev, HWDEVLEN, HWDEVTEMPL, card, dev); + err= snd_pcm_open(&pcm, hwdev, stream, SND_PCM_NONBLOCK); + if( sc_errcheck(err, "opening sound device", card, dev) ) goto nextdev; + err= snd_pcm_hw_params_any(pcm, pars); + if( sc_errcheck(err, "obtaining hardware parameters", card, dev) ) { + snd_pcm_close(pcm); + goto nextdev; + } + snd_pcm_hw_params_get_channels_min(pars, &min); + snd_pcm_hw_params_get_channels_max(pars, &max); + if( min == max ) + if( min == 1 ) printf(" 1 channel, "); + else printf(" %d channels, ", min); + else printf(" %u..%u channels, ", min, max); + snd_pcm_hw_params_get_rate_min(pars, &min, NULL); + snd_pcm_hw_params_get_rate_max(pars, &max, NULL); + printf("sampling rate %u..%u Hz\n Sample formats: ", min, max); + snd_pcm_hw_params_get_format_mask(pars, fmask); + printfmtmask(fmask); + snd_pcm_close(pcm); + printf("\n"); + pcm= NULL; + for( subd= 0; subd< nsubd; ++subd ) { + snd_pcm_info_set_subdevice(pcminfo, subd); + err= snd_ctl_pcm_info(handle, pcminfo); + if( sc_errcheck(err, "obtaining subdevice info", card, dev) ) goto nextdev; + printf(" Subdevice %d, name `%s'\n", subd, snd_pcm_info_get_subdevice_name(pcminfo)); + } +nextdev: + if( thedev >= 0 || snd_ctl_pcm_next_device(handle, &dev) < 0 ) + break; + } + snd_ctl_close(handle); +nextcard: + if( thecard >= 0 || snd_card_next(&card) < 0 ) + break; + } +} + + +int sc_errcheck(int retval, const char *doingwhat, int cardnr, int devnr) +{ + if( retval<0 ) { + if( devnr>= 0 ) + fprintf(stderr, "Error %s for card %d, device %d: %s. Skipping.\n", doingwhat, cardnr, devnr, alsaerrstr(retval)); + else + fprintf(stderr, "Error %s for card %d: %s. Skipping.\n", doingwhat, cardnr, alsaerrstr(retval)); + return 1; + } + return 0; +} + + + +/*============================================================================ + Function for investigating device configurations +============================================================================*/ + +void testconfig(snd_pcm_stream_t stream, const char *device, const int *hwpars) +{ + unsigned min, max, param; + int err, count, dir, result; + + printf("*** Exploring configuration space of device `%s' for %s ***\n", device, + stream==SND_PCM_STREAM_CAPTURE? "recording" : "playback"); + + if (stream==SND_PCM_STREAM_CAPTURE && stream==SND_PCM_STREAM_PLAYBACK) + dir = 0; + else if (stream==SND_PCM_STREAM_CAPTURE) + dir = -1; + else + dir = 1; + + err= snd_pcm_open(&pcm, device, stream, SND_PCM_NONBLOCK); + tc_errcheck(err, "opening sound device"); + err= snd_pcm_hw_params_any(pcm, pars); + tc_errcheck(err, "initialising hardware parameters"); + for( count= 0; hwpars[count]!=HWP_END; count += 2 ) + + switch(hwpars[count]) + { + case HWP_RATE:param= hwpars[count+1]; + err= snd_pcm_hw_params_set_rate_near(pcm, pars, ¶m, &result); + if( err<0 ) + fprintf(stderr, "Could not set sampling rate to %d Hz: %s. " + "Continuing regardless.\n", hwpars[count+1], alsaerrstr(err)); + else + printf("Set sampling rate %d Hz --> got %u Hz, %s requested.\n", hwpars[count+1], param, dirstr(dir)); + break; + case HWP_NCH:err= snd_pcm_hw_params_set_channels(pcm, pars, hwpars[count+1]); + if( err<0 ) + fprintf(stderr, "Could not set # of channels to %d: %s. " + "Continuing regardless.\n", hwpars[count+1], alsaerrstr(err)); + else + printf("Set number of channels to %d.\n", hwpars[count+1]); + break; + case HWP_FORMAT:err= snd_pcm_hw_params_set_format(pcm, pars, hwpars[count+1]); + if( err<0 ) + fprintf(stderr, "Could not set sample format to %s: %s." + " Continuing regardless.\n", alsafmtstr(hwpars[count+1]), alsaerrstr(err)); + else + printf("Set sample format to %s.\n", alsafmtstr(hwpars[count+1])); + break; + default: + break; + } + if( count>0 ) + printf("Parameter ranges remaining after these settings:\n"); + snd_pcm_hw_params_get_channels_min(pars, &min); + snd_pcm_hw_params_get_channels_max(pars, &max); + if( min==max ) + if( min==1 ) + printf("1 channel\n"); + else + printf("%u channels\n", min); + else + printf("%u..%u channels\n", min, max); + snd_pcm_hw_params_get_rate_min(pars, &min, NULL); + snd_pcm_hw_params_get_rate_max(pars, &max, NULL); + if( min==max ) + printf("Sampling rate %u Hz\nSample formats: ", min); + else + printf("Sampling rate %u..%u Hz\nSample formats: ", min, max); + snd_pcm_hw_params_get_format_mask(pars, fmask); + printfmtmask(fmask); + printf("\n"); + result= snd_pcm_hw_params_get_sbits(pars); + if( result >= 0 ) // only available if bit width of all formats is the same + printf("Significant bits: %d\n", result); + snd_pcm_close(pcm); +} + + +void tc_errcheck(int retval, const char *doingwhat) +{ + if( retval<0 ) { + fprintf(stderr, "Error %s: %s. Aborting.\n", doingwhat, alsaerrstr(retval)); + if( pcm ) + snd_pcm_close(pcm); + exit(1); + } +} + + +/*============================================================================ + String-building functions +============================================================================*/ + +struct alsaerr { int err; char *msg; }; +struct alsaerr aelist[]= { + {-EBADFD, "PCM device is in a bad state"}, + {-EPIPE, "An underrun occurred"}, + {-ESTRPIPE, "A suspend event occurred"}, + {-ENOTTY, "Hotplug device has been removed"}, + {-ENODEV, "Hotplug device has been removed"}, + {-ENOENT, "Device does not exist"}, + {0, NULL} +}; +const char *alsaerrstr(const int errcode) +{ + struct alsaerr *search; + + if( errcode >= 0 ) + return "No error"; + for( search= aelist; search->msg && search->err!=errcode; ++search); + if( search->msg ) + return search->msg; + else + return strerror(-errcode); +} + + +const char *dirstr(int dir) +{ + if( !dir ) + return "="; + else if( dir<0 ) + return "<"; + else + return ">"; +} + + +/*============================================================================ + Functions for parsing and string output of ALSA sample formats +============================================================================*/ + +struct fmtdef { char *fmtname; int format; }; +static struct fmtdef fmtlist[]= { + {"S8", SND_PCM_FORMAT_S8}, + {"U8", SND_PCM_FORMAT_U8}, + {"S16_LE", SND_PCM_FORMAT_S16_LE}, + {"S16_BE", SND_PCM_FORMAT_S16_BE}, + {"U16_LE", SND_PCM_FORMAT_U16_LE}, + {"U16_BE", SND_PCM_FORMAT_U16_BE}, + {"S24_LE", SND_PCM_FORMAT_S24_LE}, + {"S24_BE", SND_PCM_FORMAT_S24_BE}, + {"U24_LE", SND_PCM_FORMAT_U24_LE}, + {"U24_BE", SND_PCM_FORMAT_U24_BE}, + {"S32_LE", SND_PCM_FORMAT_S32_LE}, + {"S32_BE", SND_PCM_FORMAT_S32_BE}, + {"U32_LE", SND_PCM_FORMAT_U32_LE}, + {"U32_BE", SND_PCM_FORMAT_U32_BE}, + {"FLOAT_LE", SND_PCM_FORMAT_FLOAT_LE}, + {"FLOAT_BE", SND_PCM_FORMAT_FLOAT_BE}, + {"FLOAT64_LE", SND_PCM_FORMAT_FLOAT64_LE}, + {"FLOAT64_BE", SND_PCM_FORMAT_FLOAT64_BE}, + {"IEC958_SUBFRAME_LE", SND_PCM_FORMAT_IEC958_SUBFRAME_LE}, + {"IEC958_SUBFRAME_BE", SND_PCM_FORMAT_IEC958_SUBFRAME_BE}, + {"MU_LAW", SND_PCM_FORMAT_MU_LAW}, + {"A_LAW", SND_PCM_FORMAT_A_LAW}, + {"IMA_ADPCM", SND_PCM_FORMAT_IMA_ADPCM}, + {"MPEG", SND_PCM_FORMAT_MPEG}, + {"GSM", SND_PCM_FORMAT_GSM}, + {"SPECIAL", SND_PCM_FORMAT_SPECIAL}, + {"S24_3LE", SND_PCM_FORMAT_S24_3LE}, + {"S24_3BE", SND_PCM_FORMAT_S24_3BE}, + {"U24_3LE", SND_PCM_FORMAT_U24_3LE}, + {"U24_3BE", SND_PCM_FORMAT_U24_3BE}, + {"S20_3LE", SND_PCM_FORMAT_S20_3LE}, + {"S20_3BE", SND_PCM_FORMAT_S20_3BE}, + {"U20_3LE", SND_PCM_FORMAT_U20_3LE}, + {"U20_3BE", SND_PCM_FORMAT_U20_3BE}, + {"S18_3LE", SND_PCM_FORMAT_S18_3LE}, + {"S18_3BE", SND_PCM_FORMAT_S18_3BE}, + {"U18_3LE", SND_PCM_FORMAT_U18_3LE}, + {"U18_3BE", SND_PCM_FORMAT_U18_3BE}, + {"S16", SND_PCM_FORMAT_S16}, + {"U16", SND_PCM_FORMAT_U16}, + {"S24", SND_PCM_FORMAT_S24}, + {"U24", SND_PCM_FORMAT_U24}, + {"S32", SND_PCM_FORMAT_S32}, + {"U32", SND_PCM_FORMAT_U32}, + {"FLOAT", SND_PCM_FORMAT_FLOAT}, + {"FLOAT64", SND_PCM_FORMAT_FLOAT64}, + {"IEC958_SUBFRAME", SND_PCM_FORMAT_IEC958_SUBFRAME}, + {NULL, 0} +}; + +int parse_alsaformat(const char *fmtstr) +{ + struct fmtdef *search; + + for( search= fmtlist; search->fmtname && strcmp(search->fmtname, fmtstr); ++search ); + if( !search->fmtname ) { + fprintf(stderr, "Unknown sample format `%s'. Aborting.\n", fmtstr); + exit(1); + } + return search->format; +} + +const char *alsafmtstr(int fmtnum) +{ + struct fmtdef *search; + + for( search= fmtlist; search->fmtname && search->format!=fmtnum; ++search ); + if( !search->fmtname ) + return "(unknown)"; + else + return search->fmtname; +} + + +/*============================================================================ + Printout functions +============================================================================*/ + +void printfmtmask(const snd_pcm_format_mask_t *fmask) +{ + int fmt, prevformat= 0; + + for( fmt= 0; fmt <= SND_PCM_FORMAT_LAST; ++fmt ) + if( snd_pcm_format_mask_test(fmask, (snd_pcm_format_t)fmt) ) { + if( prevformat ) + printf(", "); + printf("%s", snd_pcm_format_name((snd_pcm_format_t)fmt)); + prevformat= 1; + } + if( !prevformat ) + printf("(none)"); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/audiodelay.cpp Fri Oct 30 23:07:52 2009 +0100 @@ -0,0 +1,131 @@ +/******************************************/ +/* + audiodelay.cpp + by Peter Meerwald, pmeerw@pmeerw.net, 2009. + + This program tests the delay between audio output and input. +*/ +/******************************************/ + +#include "RtAudio.h" +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <sys/time.h> +#include <time.h> + +const char *progname = "audiodelay"; + +typedef signed short AUDIOSAMPLE_TYPE; +#define FORMAT RTAUDIO_SINT16 + +static volatile unsigned int nmeasurements = 0; +static float accum_measurements = 0.0f; + +static int inout(void *out_buf, void *in_buf, unsigned int nbuf_frames, + double stream_time, RtAudioStreamStatus status, void *data) { + if (status) + printf("%s: stream over/underflow detected\n", progname); + + static unsigned int count_inout = 0; + static struct timeval tv_start; + static struct timeval tv_stop; + + AUDIOSAMPLE_TYPE *pout = (AUDIOSAMPLE_TYPE *)out_buf, *pin = (AUDIOSAMPLE_TYPE *)in_buf; + + memset(out_buf, 0, nbuf_frames*sizeof(AUDIOSAMPLE_TYPE) * 2); + if ((count_inout % (512*128/nbuf_frames)) == 0) { + for (unsigned int i = nbuf_frames/2-4; i < nbuf_frames/2+4; i++) { + pout[2*i] = 32000; + pout[2*i+1] = 32000; + } + + gettimeofday(&tv_start, 0); + } + + if (1) { + for (unsigned int i = 0; i < nbuf_frames; i++) { + if (pin[2*i] > 15000 || pin[2*i+1] > 15000) { + + gettimeofday(&tv_stop, 0); + + unsigned int msec = (tv_stop.tv_sec - tv_start.tv_sec) * 1000; + if (tv_stop.tv_usec < tv_start.tv_usec) + msec -= (tv_start.tv_usec - tv_stop.tv_usec) / 1000; + else + msec += (tv_stop.tv_usec - tv_start.tv_usec) / 1000; + + accum_measurements += msec; + nmeasurements++; + printf("%s: measured delay %u ms, offset %u, average %.2f\n", progname, msec, i, accum_measurements / nmeasurements); + + break; + } + } + } + + count_inout++; + + return 0; +} + +int main(int argc, char *argv[]) { + unsigned int channels = 2, sample_rate = 44100, buf_bytes, odevice = 0, idevice = 0, ioffset = 0, ooffset = 0; + + RtAudio adac; + if (adac.getDeviceCount() < 1) { + std::cout << "\nNo audio devices found!\n"; + exit(EXIT_FAILURE); + } + + // Let RtAudio print messages to stderr. + adac.showWarnings(true); + + // Set the same number of channels for both input and output. + unsigned int buf_frames = 128; + RtAudio::StreamParameters iparams, oparams; + iparams.deviceId = idevice; + iparams.nChannels = channels; + iparams.firstChannel = ioffset; + oparams.deviceId = odevice; + oparams.nChannels = channels; + oparams.firstChannel = ooffset; + + RtAudio::StreamOptions options; + options.flags = 0; // RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE, RTAUDIO_SCHEDULE_REALTIME + options.numberOfBuffers = 2; + options.priority = 0; // for RTAUDIO_SCHEDULE_REALTIME + + try { + adac.openStream(&oparams, &iparams, FORMAT, sample_rate, &buf_frames, &inout, (void *)&buf_bytes, &options); + } + catch (RtError& e) { + printf("%s: %s\n", progname, e.getMessage().c_str()); + exit(EXIT_FAILURE); + } + + buf_bytes = buf_frames * channels * sizeof(AUDIOSAMPLE_TYPE); + + try { + adac.startStream(); + + printf("%s: stream latency %ld frames, %d sample rate\n", progname, adac.getStreamLatency(), adac.getStreamSampleRate()); + + printf("%s: running ... press <enter> to quit (%d buffer frames)\n", progname, buf_frames); + getchar(); + + // Stop the stream. + adac.stopStream(); + } + catch (RtError& e) { + printf("%s: %s\n", progname, e.getMessage().c_str()); + goto cleanup; + } + +cleanup: + if (adac.isStreamOpen()) + adac.closeStream(); + + return 0; +}
--- a/audiodelay/Makefile Fri Oct 30 22:45:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -PROGRAMS = audiodelay -RM = rm -f - -CC = g++ -DEFS = -DHAVE_GETTIMEOFDAY -D__LINUX_ALSA__ -CFLAGS = -O2 -Wall -LIBRARY = -lpthread -lasound -lrtaudio - -all: $(PROGRAMS) - -audiodelay: audiodelay.cpp - $(CC) $(CFLAGS) $(DEFS) -o audiodelay audiodelay.cpp $(LIBRARY) - -clean: - -$(RM) *.o $(PROGRAMS) *~ - -strip: - strip $(PROGRAMS)
--- a/audiodelay/audiodelay.cpp Fri Oct 30 22:45:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/******************************************/ -/* - audiodelay.cpp - by Peter Meerwald, pmeerw@pmeerw.net, 2009. - - This program tests the delay between audio output and input. -*/ -/******************************************/ - -#include "RtAudio.h" -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <string.h> -#include <sys/time.h> -#include <time.h> - -const char *progname = "audiodelay"; - -typedef signed short AUDIOSAMPLE_TYPE; -#define FORMAT RTAUDIO_SINT16 - -static volatile unsigned int nmeasurements = 0; -static float accum_measurements = 0.0f; - -static int inout(void *out_buf, void *in_buf, unsigned int nbuf_frames, - double stream_time, RtAudioStreamStatus status, void *data) { - if (status) - printf("%s: stream over/underflow detected\n", progname); - - static unsigned int count_inout = 0; - static struct timeval tv_start; - static struct timeval tv_stop; - - AUDIOSAMPLE_TYPE *pout = (AUDIOSAMPLE_TYPE *)out_buf, *pin = (AUDIOSAMPLE_TYPE *)in_buf; - - memset(out_buf, 0, nbuf_frames*sizeof(AUDIOSAMPLE_TYPE) * 2); - if ((count_inout % (512*128/nbuf_frames)) == 0) { - for (unsigned int i = nbuf_frames/2-4; i < nbuf_frames/2+4; i++) { - pout[2*i] = 32000; - pout[2*i+1] = 32000; - } - - gettimeofday(&tv_start, 0); - } - - if (1) { - for (unsigned int i = 0; i < nbuf_frames; i++) { - if (pin[2*i] > 15000 || pin[2*i+1] > 15000) { - - gettimeofday(&tv_stop, 0); - - unsigned int msec = (tv_stop.tv_sec - tv_start.tv_sec) * 1000; - if (tv_stop.tv_usec < tv_start.tv_usec) - msec -= (tv_start.tv_usec - tv_stop.tv_usec) / 1000; - else - msec += (tv_stop.tv_usec - tv_start.tv_usec) / 1000; - - accum_measurements += msec; - nmeasurements++; - printf("%s: measured delay %u ms, offset %u, average %.2f\n", progname, msec, i, accum_measurements / nmeasurements); - - break; - } - } - } - - count_inout++; - - return 0; -} - -int main(int argc, char *argv[]) { - unsigned int channels = 2, sample_rate = 44100, buf_bytes, odevice = 0, idevice = 0, ioffset = 0, ooffset = 0; - - RtAudio adac; - if (adac.getDeviceCount() < 1) { - std::cout << "\nNo audio devices found!\n"; - exit(EXIT_FAILURE); - } - - // Let RtAudio print messages to stderr. - adac.showWarnings(true); - - // Set the same number of channels for both input and output. - unsigned int buf_frames = 128; - RtAudio::StreamParameters iparams, oparams; - iparams.deviceId = idevice; - iparams.nChannels = channels; - iparams.firstChannel = ioffset; - oparams.deviceId = odevice; - oparams.nChannels = channels; - oparams.firstChannel = ooffset; - - RtAudio::StreamOptions options; - options.flags = 0; // RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE, RTAUDIO_SCHEDULE_REALTIME - options.numberOfBuffers = 2; - options.priority = 0; // for RTAUDIO_SCHEDULE_REALTIME - - try { - adac.openStream(&oparams, &iparams, FORMAT, sample_rate, &buf_frames, &inout, (void *)&buf_bytes, &options); - } - catch (RtError& e) { - printf("%s: %s\n", progname, e.getMessage().c_str()); - exit(EXIT_FAILURE); - } - - buf_bytes = buf_frames * channels * sizeof(AUDIOSAMPLE_TYPE); - - try { - adac.startStream(); - - printf("%s: stream latency %ld frames, %d sample rate\n", progname, adac.getStreamLatency(), adac.getStreamSampleRate()); - - printf("%s: running ... press <enter> to quit (%d buffer frames)\n", progname, buf_frames); - getchar(); - - // Stop the stream. - adac.stopStream(); - } - catch (RtError& e) { - printf("%s: %s\n", progname, e.getMessage().c_str()); - goto cleanup; - } - -cleanup: - if (adac.isStreamOpen()) - adac.closeStream(); - - return 0; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rtaudio-test.cpp Fri Oct 30 23:07:52 2009 +0100 @@ -0,0 +1,113 @@ +#include <cmath> +#include <stdlib.h> +#include <iostream> +#include <vector> +#include "RtAudio.h" + +int myCallback(void *outputBuffer, void *inputBuffer, unsigned int bufferFrames, double streamTime, RtAudioStreamStatus status, void *userData) { + unsigned int i, j; + float *buffer = (float *) outputBuffer; + + if ( status ) + std::cout << "Stream underflow detected!" << std::endl; + + if (!buffer) + return 0; + + // Write interleaved audio data. + static int t = 0; + for ( i=0; i<bufferFrames/2; i++ ) { + for ( j=0; j<2; j++ ) { + *buffer++ = 0; // 0.25*cosf((t/(float)1000)); + + } + if (++t > 1000) t = 0; + } + + return 0; +} + +int main() { + RtAudio audio; + + // Determine the number of devices available + unsigned int devices = audio.getDeviceCount(); + std::cout << devices << " devices found\n"; + + // Scan through devices for various capabilities + RtAudio::DeviceInfo info; + for ( unsigned int i=0; i<devices; i++ ) { + + info = audio.getDeviceInfo( i ); + + if ( info.probed == true ) { + // Print, for example, the maximum number of output channels for each device + std::cout << "device: #" << i << " - " << info.name << "\n"; + std::cout << " output channels: " << info.outputChannels << "\n"; + std::cout << " input channels: " << info.inputChannels << "\n"; + std::cout << " duplex channels: " << info.duplexChannels << "\n"; + std::cout << " default input/output: " << info.isDefaultInput << " / " << info.isDefaultOutput << "\n"; + + std::cout << " sample rates:\n"; + for (std::vector<unsigned int>::iterator i = info.sampleRates.begin(); i != info.sampleRates.end(); i++) { + std::cout << " " << *i << "\n"; + } + std::cout << " data formats:\n"; + if (info.nativeFormats & RTAUDIO_SINT8) std::cout << " signed 8-bit\n"; + if (info.nativeFormats & RTAUDIO_SINT16) std::cout << " signed 16-bit\n"; + if (info.nativeFormats & RTAUDIO_SINT24) std::cout << " signed 24-bit\n"; + if (info.nativeFormats & RTAUDIO_SINT32) std::cout << " signed 32-bit\n"; + if (info.nativeFormats & RTAUDIO_FLOAT32) std::cout << " 32-bit float [-1,1]\n"; + if (info.nativeFormats & RTAUDIO_FLOAT64) std::cout << " 64-bit float [-1,1]\n"; + } + else + std::cout << "device: #" << i << " - not probed\n"; + } + + RtAudio::StreamParameters oparam; + oparam.deviceId = audio.getDefaultOutputDevice(); + oparam.nChannels = 1; + oparam.firstChannel = 0; + + RtAudio::StreamParameters iparam; + iparam.deviceId = audio.getDefaultInputDevice(); + iparam.nChannels = 1; + iparam.firstChannel = 0; + + + unsigned int sampleRate = 44100; + unsigned int bufferFrames = 256; // 256 sample frames + + RtAudio::StreamOptions options; + options.flags = 0; + options.numberOfBuffers = 2; + options.streamName = "test"; + + + try { + audio.openStream( &oparam, &iparam, RTAUDIO_FLOAT32, + sampleRate, &bufferFrames, &myCallback, (void*) 0, &options ); + audio.startStream(); + } + catch ( RtError& e ) { + std::cout << '\n' << e.getMessage() << '\n' << std::endl; + exit( EXIT_FAILURE ); + } + + char input; + std::cout << "\nPlaying ... press <enter> to quit.\n"; + std::cin.get( input ); + + try { + // Stop the stream + audio.stopStream(); + } + catch (RtError& e) { + e.printMessage(); + } + + if ( audio.isStreamOpen() ) + audio.closeStream(); + + return EXIT_SUCCESS; +}