View Single Post
Old 07-09-2012, 09:34 PM   #60
twobob
( ͡° ͜ʖ ͡°){ʇlnɐɟ ƃǝs}Týr
twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.
 
twobob's Avatar
 
Posts: 6,586
Karma: 6299993
Join Date: Jun 2012
Location: uti gratia usura (Yao ying da ying; Mo ying da yieng)
Device: PW-WIFI|K5-3G+WIFI| K4|K3-3G|DXG|K2| Rooted Nook Touch
Post Next up. something cool.

Okay, enough initialising. Let's hear something.

First off TURN YOUR VOLUME DOWN.
This demo is LOUD. I hope I SHOUTED that enough. I warned you.

Next up is the built version of the demo at
http://www.alsa-project.org/alsa-doc...c-example.html

It plays a simple sine wave to our speaker - pretty dull huh?
But it paves the wave for all kind of coolness so here's the blurb

Spoiler:

Code:
 /*
  *  This small demo sends a simple sinusoidal wave to your speakers.
  */

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sched.h>
 #include <errno.h>
 #include <getopt.h>
 #include <asoundlib.h>
 #include <sys/time.h>
 #include <math.h>

 static char *device = "hw:0,0";                     /* playback device */
 static snd_pcm_format_t format = SND_PCM_FORMAT_S16;    /* sample format */
 static unsigned int rate = 44100;                       /* stream rate */
 static unsigned int channels = 2;                       /* count of channels */
 static unsigned int buffer_time = 500000;               /* ring buffer length in us */
 static unsigned int period_time = 100000;               /* period time in us */
 static double freq = 440;                               /* sinusoidal wave frequency in Hz */
 static int verbose = 0;                                 /* verbose flag */
 static int resample = 1;                                /* enable alsa-lib resampling */
 static int period_event = 0;                            /* produce poll event after each period */

 static snd_pcm_sframes_t buffer_size;
 static snd_pcm_sframes_t period_size;
 static snd_output_t *output = NULL;

 static void generate_sine(const snd_pcm_channel_area_t *areas,
                           snd_pcm_uframes_t offset,
                           int count, double *_phase)
 {
         static double max_phase = 2. * M_PI;
         double phase = *_phase;
         double step = max_phase*freq/(double)rate;
         unsigned char *samples[channels];
         int steps[channels];
         unsigned int chn;
         int format_bits = snd_pcm_format_width(format);
         unsigned int maxval = (1 << (format_bits - 1)) - 1;
         int bps = format_bits / 8;  /* bytes per sample */
         int phys_bps = snd_pcm_format_physical_width(format) / 8;
         int big_endian = snd_pcm_format_big_endian(format) == 1;
         int to_unsigned = snd_pcm_format_unsigned(format) == 1;
         int is_float = (format == SND_PCM_FORMAT_FLOAT_LE ||
                         format == SND_PCM_FORMAT_FLOAT_BE);

         /* verify and prepare the contents of areas */
         for (chn = 0; chn < channels; chn++) {
                 if ((areas[chn].first % 8) != 0) {
                         printf("areas[%i].first == %i, aborting...\n", chn, areas[chn].first);
                         exit(EXIT_FAILURE);
                 }
                 samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
                 if ((areas[chn].step % 16) != 0) {
                         printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step);
                         exit(EXIT_FAILURE);
                 }
                 steps[chn] = areas[chn].step / 8;
                 samples[chn] += offset * steps[chn];
         }
         /* fill the channel areas */
         while (count-- > 0) {
                 union {
                         float f;
                         int i;
                 } fval;
                 int res, i;
                 if (is_float) {
                         fval.f = sin(phase) * maxval;
                         res = fval.i;
                 } else
                         res = sin(phase) * maxval;
                 if (to_unsigned)
                         res ^= 1U << (format_bits - 1);
                 for (chn = 0; chn < channels; chn++) {
                         /* Generate data in native endian format */
                         if (big_endian) {
                                 for (i = 0; i < bps; i++)
                                         *(samples[chn] + phys_bps - 1 - i) = (res >> i * 8) & 0xff;
                         } else {
                                 for (i = 0; i < bps; i++)
                                         *(samples[chn] + i) = (res >>  i * 8) & 0xff;
                         }
                         samples[chn] += steps[chn];
                 }
                 phase += step;
                 if (phase >= max_phase)
                         phase -= max_phase;
         }
         *_phase = phase;
 }

 static int set_hwparams(snd_pcm_t *handle,
                         snd_pcm_hw_params_t *params,
                         snd_pcm_access_t access)
 {
         unsigned int rrate;
         snd_pcm_uframes_t size;
         int err, dir;

         /* choose all parameters */
         err = snd_pcm_hw_params_any(handle, params);
         if (err < 0) {
                 printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
                 return err;
         }
         /* set hardware resampling */
         err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
         if (err < 0) {
                 printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
                 return err;
         }
         /* set the interleaved read/write format */
         err = snd_pcm_hw_params_set_access(handle, params, access);
         if (err < 0) {
                 printf("Access type not available for playback: %s\n", snd_strerror(err));
                 return err;
         }
         /* set the sample format */
         err = snd_pcm_hw_params_set_format(handle, params, format);
         if (err < 0) {
                 printf("Sample format not available for playback: %s\n", snd_strerror(err));
                 return err;
         }
         /* set the count of channels */
         err = snd_pcm_hw_params_set_channels(handle, params, channels);
         if (err < 0) {
                 printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
                 return err;
         }
         /* set the stream rate */
         rrate = rate;
         err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
         if (err < 0) {
                 printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
                 return err;
         }
         if (rrate != rate) {
                 printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
                 return -EINVAL;
         }
         /* set the buffer time */
         err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
         if (err < 0) {
                 printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
                 return err;
         }
         err = snd_pcm_hw_params_get_buffer_size(params, &size);
         if (err < 0) {
                 printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
                 return err;
         }
         buffer_size = size;
         /* set the period time */
         err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
         if (err < 0) {
                 printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
                 return err;
         }
         err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
         if (err < 0) {
                 printf("Unable to get period size for playback: %s\n", snd_strerror(err));
                 return err;
         }
         period_size = size;
         /* write the parameters to device */
         err = snd_pcm_hw_params(handle, params);
         if (err < 0) {
                 printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
                 return err;
         }
         return 0;
 }

 static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
 {
         int err;

         /* get the current swparams */
         err = snd_pcm_sw_params_current(handle, swparams);
         if (err < 0) {
                 printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
                 return err;
         }
         /* start the transfer when the buffer is almost full: */
         /* (buffer_size / avail_min) * avail_min */
         err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size);
         if (err < 0) {
                 printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
                 return err;
         }
         /* allow the transfer when at least period_size samples can be processed */
         /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
         err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size);
         if (err < 0) {
                 printf("Unable to set avail min for playback: %s\n", snd_strerror(err));
                 return err;
         }
         /* enable period events when requested */
         if (period_event) {
               //  err = snd_pcm_sw_params_set_period_event(handle, swparams, 1);
               //  if (err < 0) {
               //          printf("Unable to set period event: %s\n", snd_strerror(err));
               //          return err;
               //  }
         }
         /* write the parameters to the playback device */
         err = snd_pcm_sw_params(handle, swparams);
         if (err < 0) {
                 printf("Unable to set sw params for playback: %s\n", snd_strerror(err));
                 return err;
         }
         return 0;
 }

 /*
  *   Underrun and suspend recovery
  */

 static int xrun_recovery(snd_pcm_t *handle, int err)
 {
         if (verbose)
                 printf("stream recovery\n");
         if (err == -EPIPE) {    /* under-run */
                 err = snd_pcm_prepare(handle);
                 if (err < 0)
                         printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
                 return 0;
         } else if (err == -ESTRPIPE) {
                 while ((err = snd_pcm_resume(handle)) == -EAGAIN)
                         sleep(1);       /* wait until the suspend flag is released */
                 if (err < 0) {
                         err = snd_pcm_prepare(handle);
                         if (err < 0)
                                 printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
                 }
                 return 0;
         }
         return err;
 }

 /*
  *   Transfer method - write only
  */

 static int write_loop(snd_pcm_t *handle,
                       signed short *samples,
                       snd_pcm_channel_area_t *areas)
 {
         double phase = 0;
         signed short *ptr;
         int err, cptr;

         while (1) {
                 generate_sine(areas, 0, period_size, &phase);
                 ptr = samples;
                 cptr = period_size;
                 while (cptr > 0) {
                         err = snd_pcm_writei(handle, ptr, cptr);
                         if (err == -EAGAIN)
                                 continue;
                         if (err < 0) {
                                 if (xrun_recovery(handle, err) < 0) {
                                         printf("Write error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                                 break;  /* skip one period */
                         }
                         ptr += err * channels;
                         cptr -= err;
                 }
         }
 }

 /*
  *   Transfer method - write and wait for room in buffer using poll
  */

 static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, unsigned int count)
 {
         unsigned short revents;

         while (1) {
                 poll(ufds, count, -1);
                 snd_pcm_poll_descriptors_revents(handle, ufds, count, &revents);
                 if (revents & POLLERR)
                         return -EIO;
                 if (revents & POLLOUT)
                         return 0;
         }
 }

 static int write_and_poll_loop(snd_pcm_t *handle,
                                signed short *samples,
                                snd_pcm_channel_area_t *areas)
 {
         struct pollfd *ufds;
         double phase = 0;
         signed short *ptr;
         int err, count, cptr, init;

         count = snd_pcm_poll_descriptors_count (handle);
         if (count <= 0) {
                 printf("Invalid poll descriptors count\n");
                 return count;
         }

         ufds = malloc(sizeof(struct pollfd) * count);
         if (ufds == NULL) {
                 printf("No enough memory\n");
                 return -ENOMEM;
         }
         if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) {
                 printf("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err));
                 return err;
         }

         init = 1;
         while (1) {
                 if (!init) {
                         err = wait_for_poll(handle, ufds, count);
                         if (err < 0) {
                                 if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN ||
                                     snd_pcm_state(handle) == SND_PCM_STATE_SUSPENDED) {
                                         err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE;
                                         if (xrun_recovery(handle, err) < 0) {
                                                 printf("Write error: %s\n", snd_strerror(err));
                                                 exit(EXIT_FAILURE);
                                         }
                                         init = 1;
                                 } else {
                                         printf("Wait for poll failed\n");
                                         return err;
                                 }
                         }
                 }

                 generate_sine(areas, 0, period_size, &phase);
                 ptr = samples;
                 cptr = period_size;
                 while (cptr > 0) {
                         err = snd_pcm_writei(handle, ptr, cptr);
                         if (err < 0) {
                                 if (xrun_recovery(handle, err) < 0) {
                                         printf("Write error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                                 init = 1;
                                 break;  /* skip one period */
                         }
                         if (snd_pcm_state(handle) == SND_PCM_STATE_RUNNING)
                                 init = 0;
                         ptr += err * channels;
                         cptr -= err;
                         if (cptr == 0)
                                 break;
                         /* it is possible, that the initial buffer cannot store */
                         /* all data from the last period, so wait awhile */
                         err = wait_for_poll(handle, ufds, count);
                         if (err < 0) {
                                 if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN ||
                                     snd_pcm_state(handle) == SND_PCM_STATE_SUSPENDED) {
                                         err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE;
                                         if (xrun_recovery(handle, err) < 0) {
                                                 printf("Write error: %s\n", snd_strerror(err));
                                                 exit(EXIT_FAILURE);
                                         }
                                         init = 1;
                                 } else {
                                         printf("Wait for poll failed\n");
                                         return err;
                                 }
                         }
                 }
         }
 }

 /*
  *   Transfer method - asynchronous notification
  */

 struct async_private_data {
         signed short *samples;
         snd_pcm_channel_area_t *areas;
         double phase;
 };

 static void async_callback(snd_async_handler_t *ahandler)
 {
         snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
         struct async_private_data *data = snd_async_handler_get_callback_private(ahandler);
         signed short *samples = data->samples;
         snd_pcm_channel_area_t *areas = data->areas;
         snd_pcm_sframes_t avail;
         int err;

         avail = snd_pcm_avail_update(handle);
         while (avail >= period_size) {
                 generate_sine(areas, 0, period_size, &data->phase);
                 err = snd_pcm_writei(handle, samples, period_size);
                 if (err < 0) {
                         printf("Write error: %s\n", snd_strerror(err));
                         exit(EXIT_FAILURE);
                 }
                 if (err != period_size) {
                         printf("Write error: written %i expected %li\n", err, period_size);
                         exit(EXIT_FAILURE);
                 }
                 avail = snd_pcm_avail_update(handle);
         }
 }

 static int async_loop(snd_pcm_t *handle,
                       signed short *samples,
                       snd_pcm_channel_area_t *areas)
 {
         struct async_private_data data;
         snd_async_handler_t *ahandler;
         int err, count;

         data.samples = samples;
         data.areas = areas;
         data.phase = 0;
         err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, &data);
         if (err < 0) {
                 printf("Unable to register async handler\n");
                 exit(EXIT_FAILURE);
         }
         for (count = 0; count < 2; count++) {
                 generate_sine(areas, 0, period_size, &data.phase);
                 err = snd_pcm_writei(handle, samples, period_size);
                 if (err < 0) {
                         printf("Initial write error: %s\n", snd_strerror(err));
                         exit(EXIT_FAILURE);
                 }
                 if (err != period_size) {
                         printf("Initial write error: written %i expected %li\n", err, period_size);
                         exit(EXIT_FAILURE);
                 }
         }
         if (snd_pcm_state(handle) == SND_PCM_STATE_PREPARED) {
                 err = snd_pcm_start(handle);
                 if (err < 0) {
                         printf("Start error: %s\n", snd_strerror(err));
                         exit(EXIT_FAILURE);
                 }
         }

         /* because all other work is done in the signal handler,
            suspend the process */
         while (1) {
                 sleep(1);
         }
 }

 /*
  *   Transfer method - asynchronous notification + direct write
  */

 static void async_direct_callback(snd_async_handler_t *ahandler)
 {
         snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
         struct async_private_data *data = snd_async_handler_get_callback_private(ahandler);
         const snd_pcm_channel_area_t *my_areas;
         snd_pcm_uframes_t offset, frames, size;
         snd_pcm_sframes_t avail, commitres;
         snd_pcm_state_t state;
         int first = 0, err;

         while (1) {
                 state = snd_pcm_state(handle);
                 if (state == SND_PCM_STATE_XRUN) {
                         err = xrun_recovery(handle, -EPIPE);
                         if (err < 0) {
                                 printf("XRUN recovery failed: %s\n", snd_strerror(err));
                                 exit(EXIT_FAILURE);
                         }
                         first = 1;
                 } else if (state == SND_PCM_STATE_SUSPENDED) {
                         err = xrun_recovery(handle, -ESTRPIPE);
                         if (err < 0) {
                                 printf("SUSPEND recovery failed: %s\n", snd_strerror(err));
                                 exit(EXIT_FAILURE);
                         }
                 }
                 avail = snd_pcm_avail_update(handle);
                 if (avail < 0) {
                         err = xrun_recovery(handle, avail);
                         if (err < 0) {
                                 printf("avail update failed: %s\n", snd_strerror(err));
                                 exit(EXIT_FAILURE);
                         }
                         first = 1;
                         continue;
                 }
                 if (avail < period_size) {
                         if (first) {
                                 first = 0;
                                 err = snd_pcm_start(handle);
                                 if (err < 0) {
                                         printf("Start error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                         } else {
                                 break;
                         }
                         continue;
                 }
                 size = period_size;
                 while (size > 0) {
                         frames = size;
                         err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
                         if (err < 0) {
                                 if ((err = xrun_recovery(handle, err)) < 0) {
                                         printf("MMAP begin avail error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                                 first = 1;
                         }
                         generate_sine(my_areas, offset, frames, &data->phase);
                         commitres = snd_pcm_mmap_commit(handle, offset, frames);
                         if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
                                 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
                                         printf("MMAP commit error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                                 first = 1;
                         }
                         size -= frames;
                 }
         }
 }

 static int async_direct_loop(snd_pcm_t *handle,
                              signed short *samples ATTRIBUTE_UNUSED,
                              snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED)
 {
         struct async_private_data data;
         snd_async_handler_t *ahandler;
         const snd_pcm_channel_area_t *my_areas;
         snd_pcm_uframes_t offset, frames, size;
         snd_pcm_sframes_t commitres;
         int err, count;

         data.samples = NULL;    /* we do not require the global sample area for direct write */
         data.areas = NULL;      /* we do not require the global areas for direct write */
         data.phase = 0;
         err = snd_async_add_pcm_handler(&ahandler, handle, async_direct_callback, &data);
         if (err < 0) {
                 printf("Unable to register async handler\n");
                 exit(EXIT_FAILURE);
         }
         for (count = 0; count < 2; count++) {
                 size = period_size;
                 while (size > 0) {
                         frames = size;
                         err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
                         if (err < 0) {
                                 if ((err = xrun_recovery(handle, err)) < 0) {
                                         printf("MMAP begin avail error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                         }
                         generate_sine(my_areas, offset, frames, &data.phase);
                         commitres = snd_pcm_mmap_commit(handle, offset, frames);
                         if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
                                 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
                                         printf("MMAP commit error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                         }
                         size -= frames;
                 }
         }
         err = snd_pcm_start(handle);
         if (err < 0) {
                 printf("Start error: %s\n", snd_strerror(err));
                 exit(EXIT_FAILURE);
         }

         /* because all other work is done in the signal handler,
            suspend the process */
         while (1) {
                 sleep(1);
         }
 }

 /*
  *   Transfer method - direct write only
  */

 static int direct_loop(snd_pcm_t *handle,
                        signed short *samples ATTRIBUTE_UNUSED,
                        snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED)
 {
         double phase = 0;
         const snd_pcm_channel_area_t *my_areas;
         snd_pcm_uframes_t offset, frames, size;
         snd_pcm_sframes_t avail, commitres;
         snd_pcm_state_t state;
         int err, first = 1;

         while (1) {
                 state = snd_pcm_state(handle);
                 if (state == SND_PCM_STATE_XRUN) {
                         err = xrun_recovery(handle, -EPIPE);
                         if (err < 0) {
                                 printf("XRUN recovery failed: %s\n", snd_strerror(err));
                                 return err;
                         }
                         first = 1;
                 } else if (state == SND_PCM_STATE_SUSPENDED) {
                         err = xrun_recovery(handle, -ESTRPIPE);
                         if (err < 0) {
                                 printf("SUSPEND recovery failed: %s\n", snd_strerror(err));
                                 return err;
                         }
                 }
                 avail = snd_pcm_avail_update(handle);
                 if (avail < 0) {
                         err = xrun_recovery(handle, avail);
                         if (err < 0) {
                                 printf("avail update failed: %s\n", snd_strerror(err));
                                 return err;
                         }
                         first = 1;
                         continue;
                 }
                 if (avail < period_size) {
                         if (first) {
                                 first = 0;
                                 err = snd_pcm_start(handle);
                                 if (err < 0) {
                                         printf("Start error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                         } else {
                                 err = snd_pcm_wait(handle, -1);
                                 if (err < 0) {
                                         if ((err = xrun_recovery(handle, err)) < 0) {
                                                 printf("snd_pcm_wait error: %s\n", snd_strerror(err));
                                                 exit(EXIT_FAILURE);
                                         }
                                         first = 1;
                                 }
                         }
                         continue;
                 }
                 size = period_size;
                 while (size > 0) {
                         frames = size;
                         err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
                         if (err < 0) {
                                 if ((err = xrun_recovery(handle, err)) < 0) {
                                         printf("MMAP begin avail error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                                 first = 1;
                         }
                         generate_sine(my_areas, offset, frames, &phase);
                         commitres = snd_pcm_mmap_commit(handle, offset, frames);
                         if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
                                 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
                                         printf("MMAP commit error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                                 first = 1;
                         }
                         size -= frames;
                 }
         }
 }

 /*
  *   Transfer method - direct write only using mmap_write functions
  */

 static int direct_write_loop(snd_pcm_t *handle,
                              signed short *samples,
                              snd_pcm_channel_area_t *areas)
 {
         double phase = 0;
         signed short *ptr;
         int err, cptr;

         while (1) {
                 generate_sine(areas, 0, period_size, &phase);
                 ptr = samples;
                 cptr = period_size;
                 while (cptr > 0) {
                         err = snd_pcm_mmap_writei(handle, ptr, cptr);
                         if (err == -EAGAIN)
                                 continue;
                         if (err < 0) {
                                 if (xrun_recovery(handle, err) < 0) {
                                         printf("Write error: %s\n", snd_strerror(err));
                                         exit(EXIT_FAILURE);
                                 }
                                 break;  /* skip one period */
                         }
                         ptr += err * channels;
                         cptr -= err;
                 }
         }
 }

 /*
  *
  */

 struct transfer_method {
         const char *name;
         snd_pcm_access_t access;
         int (*transfer_loop)(snd_pcm_t *handle,
                              signed short *samples,
                              snd_pcm_channel_area_t *areas);
 };

 static struct transfer_method transfer_methods[] = {
         { "write", SND_PCM_ACCESS_RW_INTERLEAVED, write_loop },
         { "write_and_poll", SND_PCM_ACCESS_RW_INTERLEAVED, write_and_poll_loop },
         { "async", SND_PCM_ACCESS_RW_INTERLEAVED, async_loop },
         { "async_direct", SND_PCM_ACCESS_MMAP_INTERLEAVED, async_direct_loop },
         { "direct_interleaved", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_loop },
         { "direct_noninterleaved", SND_PCM_ACCESS_MMAP_NONINTERLEAVED, direct_loop },
         { "direct_write", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_write_loop },
         { NULL, SND_PCM_ACCESS_RW_INTERLEAVED, NULL }
 };

 static void help(void)
 {
         int k;
         printf(
 "Usage: pcm [OPTION]... [FILE]...\n"
 "-h,--help      help\n"
 "-D,--device    playback device\n"
 "-r,--rate      stream rate in Hz\n"
 "-c,--channels  count of channels in stream\n"
 "-f,--frequency sine wave frequency in Hz\n"
 "-b,--buffer    ring buffer size in us\n"
 "-p,--period    period size in us\n"
 "-m,--method    transfer method\n"
 "-o,--format    sample format\n"
 "-v,--verbose   show the PCM setup parameters\n"
 "-n,--noresample  do not resample\n"
 "-e,--pevent    enable poll event after each period\n"
 "\n");
         printf("Recognized sample formats are:");
         for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) {
                 const char *s = snd_pcm_format_name(k);
                 if (s)
                         printf(" %s", s);
         }
         printf("\n");
         printf("Recognized transfer methods are:");
         for (k = 0; transfer_methods[k].name; k++)
                 printf(" %s", transfer_methods[k].name);
         printf("\n");
 }

 int main(int argc, char *argv[])
 {
         struct option long_option[] =
         {
                 {"help", 0, NULL, 'h'},
                 {"device", 1, NULL, 'D'},
                 {"rate", 1, NULL, 'r'},
                 {"channels", 1, NULL, 'c'},
                 {"frequency", 1, NULL, 'f'},
                 {"buffer", 1, NULL, 'b'},
                 {"period", 1, NULL, 'p'},
                 {"method", 1, NULL, 'm'},
                 {"format", 1, NULL, 'o'},
                 {"verbose", 1, NULL, 'v'},
                 {"noresample", 1, NULL, 'n'},
                 {"pevent", 1, NULL, 'e'},
                 {NULL, 0, NULL, 0},
         };
         snd_pcm_t *handle;
         int err, morehelp;
         snd_pcm_hw_params_t *hwparams;
         snd_pcm_sw_params_t *swparams;
         int method = 0;
         signed short *samples;
         unsigned int chn;
         snd_pcm_channel_area_t *areas;

         snd_pcm_hw_params_alloca(&hwparams);
         snd_pcm_sw_params_alloca(&swparams);

         morehelp = 0;
         while (1) {
                 int c;
                 if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:m:o:vne", long_option, NULL)) < 0)
                         break;
                 switch (c) {
                 case 'h':
                         morehelp++;
                         break;
                 case 'D':
                         device = strdup(optarg);
                         break;
                 case 'r':
                         rate = atoi(optarg);
                         rate = rate < 4000 ? 4000 : rate;
                         rate = rate > 196000 ? 196000 : rate;
                         break;
                 case 'c':
                         channels = atoi(optarg);
                         channels = channels < 1 ? 1 : channels;
                         channels = channels > 1024 ? 1024 : channels;
                         break;
                 case 'f':
                         freq = atoi(optarg);
                         freq = freq < 50 ? 50 : freq;
                         freq = freq > 5000 ? 5000 : freq;
                         break;
                 case 'b':
                         buffer_time = atoi(optarg);
                         buffer_time = buffer_time < 1000 ? 1000 : buffer_time;
                         buffer_time = buffer_time > 1000000 ? 1000000 : buffer_time;
                         break;
                 case 'p':
                         period_time = atoi(optarg);
                         period_time = period_time < 1000 ? 1000 : period_time;
                         period_time = period_time > 1000000 ? 1000000 : period_time;
                         break;
                 case 'm':
                         for (method = 0; transfer_methods[method].name; method++)
                                         if (!strcasecmp(transfer_methods[method].name, optarg))
                                         break;
                         if (transfer_methods[method].name == NULL)
                                 method = 0;
                         break;
                 case 'o':
                         for (format = 0; format < SND_PCM_FORMAT_LAST; format++) {
                                 const char *format_name = snd_pcm_format_name(format);
                                 if (format_name)
                                         if (!strcasecmp(format_name, optarg))
                                         break;
                         }
                         if (format == SND_PCM_FORMAT_LAST)
                                 format = SND_PCM_FORMAT_S16;
                         if (!snd_pcm_format_linear(format) &&
                             !(format == SND_PCM_FORMAT_FLOAT_LE ||
                               format == SND_PCM_FORMAT_FLOAT_BE)) {
                                 printf("Invalid (non-linear/float) format %s\n",
                                        optarg);
                                 return 1;
                         }
                         break;
                 case 'v':
                         verbose = 1;
                         break;
                 case 'n':
                         resample = 0;
                         break;
                 case 'e':
                         period_event = 1;
                         break;
                 }
         }

         if (morehelp) {
                 help();
                 return 0;
         }

         err = snd_output_stdio_attach(&output, stdout, 0);
         if (err < 0) {
                 printf("Output failed: %s\n", snd_strerror(err));
                 return 0;
         }

         printf("Playback device is %s\n", device);
         printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);
         printf("Sine wave rate is %.4fHz\n", freq);
         printf("Using transfer method: %s\n", transfer_methods[method].name);

         if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
                 printf("Playback open error: %s\n", snd_strerror(err));
                 return 0;
         }

         if ((err = set_hwparams(handle, hwparams, transfer_methods[method].access)) < 0) {
                 printf("Setting of hwparams failed: %s\n", snd_strerror(err));
                 exit(EXIT_FAILURE);
         }
         if ((err = set_swparams(handle, swparams)) < 0) {
                 printf("Setting of swparams failed: %s\n", snd_strerror(err));
                 exit(EXIT_FAILURE);
         }

         if (verbose > 0)
                 snd_pcm_dump(handle, output);

         samples = malloc((period_size * channels * snd_pcm_format_physical_width(format)) / 8);
         if (samples == NULL) {
                 printf("No enough memory\n");
                 exit(EXIT_FAILURE);
         }

         areas = calloc(channels, sizeof(snd_pcm_channel_area_t));
         if (areas == NULL) {
                 printf("No enough memory\n");
                 exit(EXIT_FAILURE);
         }
         for (chn = 0; chn < channels; chn++) {
                 areas[chn].addr = samples;
                 areas[chn].first = chn * snd_pcm_format_physical_width(format);
                 areas[chn].step = channels * snd_pcm_format_physical_width(format);
         }

         err = transfer_methods[method].transfer_loop(handle, samples, areas);
         if (err < 0)
                 printf("Transfer failed: %s\n", snd_strerror(err));

         free(areas);
         free(samples);
         snd_pcm_close(handle);
         return 0;
         }


This was the first demo to work out-of-the-box on cross-compile. Happy days.

usage: ./sine

(it goes up to 5Khz), device hw ( hw:0 and synonyms ) is supported currently

install / uninstall: just copy / remove the file

Full listing of Usage: sine [OPTION]... [FILE]...
-h,--help help
-D,--device playback device
-r,--rate stream rate in Hz
-c,--channels count of channels in stream
-f,--frequency sine wave frequency in Hz
-b,--buffer ring buffer size in us
-p,--period period size in us
-m,--method transfer method
-o,--format sample format
-v,--verbose show the PCM setup parameters
-n,--noresample do not resample
-e,--pevent enable poll event after each period

Recognized sample formats are: S8 U8 S16_LE S16_BE U16_LE U16_BE S24_LE S24_BE U24_LE U24_BE S32_LE S32_BE U32_LE U32_BE FLOAT_LE FLOAT_BE FLOAT64_LE FLOAT64_BE IEC958_SUBFRAME_LE IEC958_SUBFRAME_BE MU_LAW A_LAW IMA_ADPCM MPEG GSM SPECIAL S24_3LE S24_3BE U24_3LE U24_3BE S20_3LE S20_3BE U20_3LE U20_3BE S18_3LE S18_3BE U18_3LE
Recognized transfer methods are: write write_and_poll async async_direct direct_interleaved direct_noninterleaved direct_write

WHAT IS ACTUALLY ATTACHED IS tones, THIS IS SIMPLY A MORE INTERESTING VARIATION OF THIS CODE. THANKS

TESTED ON ALL AUDIO CAPABLE KINDLES
Attached Files
File Type: gz tones.gz (13.3 KB, 1199 views)

Last edited by twobob; 07-12-2012 at 11:03 PM. Reason: I updated the static Alsalib to stop to broken alsa.conf request
twobob is offline   Reply With Quote