This is a reinterpretation of the demo here:
http://equalarea.com/paul/alsa-audio.html#playex
There is a useful overview of the PCM interface that is a bit scary but not a terrible read here
http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html
EDIT: Here is the Astlye compliant version of the code with additional notes and highlighting of important areas:
(In the preferred style of Knc1)
Spoiler:
Code:
#include <alsa/asoundlib.h>
main (int argc, char *argv[])
{
// The err value being setup here would ordinarily
// be populated by error handling code that is "wrapped around"
// each of the calls to the alsa methods (in bold).
// I have left in one example of this construct on the snd_pcm_writei
// method to show how this works in practice. (At the end.)
// This repetitive construct is elided here for brevity, further examples
// can be found on previous posts on this thread
// i = index for looping over buffer at the end - It's a superfluous
// variable used only to illustrate buffer iteration and can be ignored
// err = alsa method return codes / frame counts etc...
int i, err;
// buf = An example data store to splat into buffer at the end
// You would fill a similar construct with something
// useful in the real world.
short buf[128];
// Declare an instance (or occurence if you prefer)
// of the special "Type" defined by Alsa
// This tells Alsa the card is an available sound device
// We use this name to reference the device in other calls
snd_pcm_t *playback_handle;
// Similarly we create a new "parameters" construct
// Simply creating the reference here is enough to create it
// You can use this to setup the card to your liking
// We do the bare minimum here to get us going
snd_pcm_hw_params_t *hw_params
// This is the 1st Alsa method we have called (directly anyway)
// note we reference the card via it's handle we just created
// Then we grab the first argument passed to the command line
// argv[1] gives us this value - an e.g is below.
// (like ./TestProgram hw:0 would return hw:0)
// At this stage we link the handle to the device hw:0 in this case
// (Further details of how devices are configed via conf files in earlier posts)
// We would get back an error code (into the err construct) at this
// stage if something was amiss in accessing the card (bad conf for e.g.)
// The full details of the enum SND_PCM_STREAM_ETC... can be
// viewed here the complete PCM command set here
snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0);
// This defines some space for our params constuct
// c is fussy about memory handling
// Make some space - remember to tidy it up after
// Malloc = Think "Memory Allocate"
snd_pcm_hw_params_malloc (&hw_params);
// This is defined in the ALSA Hardware section here
// Fill our params space with a full configuration construct for a PCM.
// Making use of the space we just made and created a skeleton for us
// Note we still reference the card via the handle from now on in
snd_pcm_hw_params_any (playback_handle, hw_params);
// Restrict a configuration space to contain only one access type.
// The full reference for the method is here
// I seemed to need to set this to just one type to get the card going.
// Perhaps setting one val is absolute minimum for configuration
// I am unsure but this got it working for me without going on to set
// the sample rate, access format etc. the full gory details are in the
// original demo, this is about getting the kindle going with minimum code
// the full tech ref for the enum SND_PCM_ACCESS_BLAH is here
// In essence it is pcm_read/write interleaved access
// Pcm means it's not done in memory it's (kinda) direct to card
// read/write means duplexing possible, Interleaving means that we
// alternate samples for the left and right channel (LR,LR,LR...).
// It's a very generic choice. You could "refine" this decision to your needs
snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
// The next utility method puts our params decisions in motion
// "Install one PCM hardware configuration chosen from a configuration
// space and snd_pcm_prepare it." say the docs here
// so as you can see this runs another method internally for us. Happy days.
snd_pcm_hw_params (playback_handle, hw_params);
// This simply tidies up the memory space from the param construct
// as we are done with it,
// it's always good practice in c to destruct your disused objects.
snd_pcm_hw_params_free (hw_params);
// Showtime, as shown here this "Prepare[s] PCM for use."
// All of these methods could have been wrapped in error handlers,
// only some of them have real value though, this is maybe one of them
snd_pcm_prepare (playback_handle);
// We are now ready to so some stuff so let's write some interleaved data.
// Everything after this point is "Program", we have done our job really.
// buf is just some 0 data 128 long,
// 128 is length of buf, effectively buf.length
// 10 is just a value to show looping - has no instrinsic meaning
// write 10 * 128 shorties via the handle using interleaved writing
// This says - in English-Psuedo-Code
// Try to write 128 shorts to the PCM
// If it fails a) return an error value for the process and Then
// b) exit the application with a code indicating Failure
// Do this ten times
for (i = 0; i < 10; ++i)
{ if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) {
fprintf (stderr, "write to audio interface failed (%s)\n",snd_strerror (err));
exit (1);
}
}
//Tidy up. Ref here
snd_pcm_close (playback_handle);
// Exit the application with a code indicating Success.
exit (0);
}
The Original thrust of the thread continues below.
Quote:
Originally Posted by geekmaster
I also include embedded references throughout my code showing WHERE I got my ideas, to prove that they are unencumbered by patents or viral licensing. [/COLOR]
|
This init code is simply boiled out of an Alsa init code example, 7-ish lines (as demoed below) and you are ready to play, not bad considering the hellatiously verbose constructs of alsa.
Here is the completed basic init code: (In GM's preferred compressed style)
Spoiler:
Code:
#include <alsa/asoundlib.h>
main (int argc, char *argv[]) {
//INIT BLOCK
int err; short buf[128]; snd_pcm_t *playback_handle;
snd_pcm_hw_params_t *hw_params;
snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0);
snd_pcm_hw_params_malloc (&hw_params);
snd_pcm_hw_params_any (playback_handle, hw_params);
snd_pcm_hw_params_set_access (playback_handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params (playback_handle, hw_params);
snd_pcm_hw_params_free (hw_params);
snd_pcm_prepare (playback_handle);
// Write something
snd_pcm_writei (playback_handle, buf, 128) ;
//Tidy up.
snd_pcm_close (playback_handle); exit (0);}
//Done.
The 'buf' is just to demonstrate something being pushed PCMwards. Obviously it's not required. Hacked and slashed demos. That's the best I can do with my current knowledge. See what tomorrow brings perhaps there is a quicker way. But I doubt it.
(I'll go fix the code in the post above, just in case someone tries it)