help with first ALSA program, please?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi All,

I have written an ALSA output program which is producing garbled results.

The results are the same when I wrote an equivalent program using 
RtAudio / ALSA.

The platform is an RK3066 based stick computer running Picuntu.

The sound file is processed by sndfile. Playing a sin wav at 375 Hz also 
produces unexpected results.

Playing the sound file with aplay works fine.

The sound file is verified to be a 32 bit float sampled at 48KHz and is 
monophonic as evidenced by this output:
> Number of channels: 1
> Sample rate: 48000
> Format: 10006
> Alsa device plughw:0,0 is open.
> Rate set to: 48000
> Buffer time set to: 2666
> Direction set to: 1
> Parameters are set.
> Audio interface is prepared.
> Exiting.

Given that aplay uses the hardware correctly and I believe is using 
sndfile to parse the file as I am, I am confused as to why RtAudio and 
ALSA-direct plays the same garbled result. This suggests a bad 
interaction between snfile and the ALSA subsystem caused by me (but I 
don't know where).

In my application, I will be processing 48KHz signals only, at 128 float 
(stereo or mono) samples at a time.

Here is the code - could someone offer advice?

#include <iostream>
#include <unistd.h>
#include <cstring>
#include <math.h>
#include <alsa/asoundlib.h>
#include <sndfile.h>

using namespace std;

#define    NSAMPLES    128

float buffer[NSAMPLES];

snd_pcm_t * playback_handle = NULL;
snd_pcm_hw_params_t * hw_params = NULL;

SNDFILE * sndfile = NULL;
SF_INFO sfinfo;

static char *playback_device = (char *) "plughw:0,0";

void SndFileClose()
{
     if (sndfile != NULL)
     {
         sf_close(sndfile);
     }
}

bool SndFileOpen(char * file_name)
{
     memset(&sfinfo, 0, sizeof(SF_INFO));

     if ((sndfile = sf_open(file_name, SFM_READ, &sfinfo)) == NULL)
     {
         cerr << "Opening: " << file_name << " failed - " << 
sf_strerror(NULL) << endl;
         return false;
     }

     if (sfinfo.channels < 1 || sfinfo.channels > 2)
     {
         cerr << "Number of channels in: " << file_name << " is: " << 
sfinfo.channels << endl;
         SndFileClose();
         return false;
     }

     cout << "Number of channels: " << sfinfo.channels << endl;
     cout << "Sample rate: " << sfinfo.samplerate << endl;
     cout << "Format: " << hex << sfinfo.format << dec << endl;
     return true;
}

int main(int argc, char * argv[])
{
     if (argc < 2)
     {
         cout << "usage: " << argv[0] << " <soundfile>" << endl;
         return -1;
     }

     if (!SndFileOpen(argv[1]))
     {
         return -1;
     }

     int err;

     if ((err = snd_pcm_open (&playback_handle, playback_device, 
SND_PCM_STREAM_PLAYBACK, 0)) < 0)
     {
         cout << "Cannot open audio device " << playback_device << endl;
         cout << snd_strerror(err) << endl;
         SndFileClose();
         return -1;
     }

     cout << "Alsa device " << playback_device << " is open." << endl;

     if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
     {
         cout << "Cannot allocate hardware parameter structure: " << endl;
         cout << snd_strerror(err) << endl;
         snd_pcm_close(playback_handle);
         SndFileClose();
         return -1;
     }

     if ((err = snd_pcm_hw_params_any(playback_handle, hw_params)) < 0)
     {
         cout << "Cannot initialize hardware parameter structure: " << endl;
         cout << snd_strerror(err) << endl;
         snd_pcm_hw_params_free(hw_params);
         snd_pcm_close(playback_handle);
         SndFileClose();
         return -1;
     }

     // NONINTERLEAVED as for this test I know I am writing MONO.
     if ((err = snd_pcm_hw_params_set_access(playback_handle, hw_params, 
SND_PCM_ACCESS_RW_NONINTERLEAVED)) < 0)
     {
         cout << "Cannot set access type: " << endl;
         cout << snd_strerror (err) << endl;
         snd_pcm_hw_params_free(hw_params);
         snd_pcm_close(playback_handle);
         SndFileClose();
         return -1;
     }

     // Also tried SND_PCM_FORMAT_FLOAT. RK3066 appears to be LE.
     if ((err = snd_pcm_hw_params_set_format (playback_handle, 
hw_params, SND_PCM_FORMAT_FLOAT_LE)) < 0) {
         fprintf (stderr, "cannot set sample format (%s)\n",
                 snd_strerror (err));
         exit (1);
     }

     unsigned int rate = 48000;

     if ((err = snd_pcm_hw_params_set_rate_near(playback_handle, 
hw_params, &rate, 0)) < 0)
     {
         cout << "Cannot set sample rate (48000):" << endl;
         cout << snd_strerror (err) << endl;
         snd_pcm_hw_params_free(hw_params);
         snd_pcm_close(playback_handle);
         SndFileClose();
         return -1;
     }

     cout << "Rate set to: " << rate << endl;

     // This test is MONO only.
     if ((err = snd_pcm_hw_params_set_channels(playback_handle, 
hw_params, 1)) < 0)
     {
         cout << "Cannot set channel count to 1:" << endl;
         cout << snd_strerror (err) << endl;
         snd_pcm_hw_params_free(hw_params);
         snd_pcm_close(playback_handle);
         SndFileClose();
         return -1;
     }

     // I am uncertain what buffer and period time do. The value below is
     // 128 / 48000 seconds expressed in microseconds. Adding the call
     // to set_buffer_time_near() did not improve or change the results.

     unsigned int buffer_time = int(1.0f / 48000.0f * 128.0f * 1000000.0f);

     int direction = 1;
     if ((err = snd_pcm_hw_params_set_buffer_time_near(playback_handle, 
hw_params, &buffer_time, &direction)) < 0)
     {
         cout << "Cannot set buffer time:" << endl;
         cout << snd_strerror (err) << endl;
         snd_pcm_hw_params_free(hw_params);
         snd_pcm_close(playback_handle);
         SndFileClose();
         return -1;
     }

     cout << "Buffer time set to: " << buffer_time << endl;
     cout << "Direction set to: " << direction << endl;

     if ((err = snd_pcm_hw_params(playback_handle, hw_params)) < 0)
     {
         cout << "Cannot set parameters:" << endl;
         cout << snd_strerror (err) << endl;
         snd_pcm_hw_params_free(hw_params);
         snd_pcm_close(playback_handle);
         SndFileClose();
         return -1;
     }

     cout << "Parameters are set." << endl;

     if ((err = snd_pcm_prepare(playback_handle)) < 0)
     {
         cout << "Cannot prepare audio interface for use:" << endl;
         cout << snd_strerror (err) << endl;
         snd_pcm_hw_params_free(hw_params);
         snd_pcm_close(playback_handle);
         SndFileClose();
         return -1;
     }

     cout << "Audio interface is prepared." << endl;

     int frames_read;

     void * buffer_array[1];

     buffer_array[0] = (void *) buffer;

     while ((frames_read = sf_readf_float(sndfile, buffer, NSAMPLES)) != 0)
     {
         if ((snd_pcm_writen(playback_handle, buffer_array, 
frames_read)) != frames_read)
         {
             cout << "Write to audio interface failed:" << endl;
             cout << snd_strerror (err) << endl;
             snd_pcm_hw_params_free(hw_params);
             snd_pcm_close(playback_handle);
             SndFileClose();
             return -1;
         }
     }

     cout << "Exiting." << endl;

     snd_pcm_hw_params_free (hw_params);
     snd_pcm_close(playback_handle);
     SndFileClose();
     return 0;
}

-- 
Perry Kivolowitz, VES


------------------------------------------------------------------------------
AlienVault Unified Security Management (USM) platform delivers complete
security visibility with the essential security capabilities. Easily and
efficiently configure, manage, and operate all of your security controls
from a single console and one unified framework. Download a free trial.
http://p.sf.net/sfu/alienvault_d2d
_______________________________________________
Alsa-user mailing list
Alsa-user@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/alsa-user




[Index of Archives]     [ALSA Devel]     [Linux Audio Users]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]

  Powered by Linux