wave.c error

Hello,

I’m new to sound program, but must a write an app that plays a .wav and changes the volume to both left and right speakers. I downloaded the wave.c program in the audio online docs. It compiled fine and does play .wav files. However, when entering the keyboard options (q,a,w, etc.) that change the volume, I get an error on the snd_mixer_group_write(). It is an “Input/output error”. I can change the master volume (and balance) on the desktop and using the photon mixer. I have a soundblaster pci128 card. Any ideas as to why the function is failing?

Alec Gorjestani
University of Minnesota

Still no responses to this. I need to know whether I can do this job in
RTP. Is the sample code flawed? Is there a bug in the library or driver?
If so, can this be fixed soon? Without a response, I cannot make a good
decision on how to proceed (i.e. stick with rtp or switch operating
systems).

Thanks in advance,
Alec



Hello,

I’m new to sound program, but must a write an app that plays a .wav and
changes the volume to both left and right speakers. I downloaded the wave.c

program in the audio online docs. It compiled fine and does play .wav
files. However, when entering the keyboard options (q,a,w, etc.) that
change the volume, I get an error on the snd_mixer_group_write(). It is an
“Input/output error”. I can change the master volume (and balance) on the
desktop and using the photon mixer. I have a soundblaster pci128 card. Any
ideas as to why the function is failing?

Alec Gorjestani
University of Minnesota

Alec Gorjestani <alecg@me.umn.edu> wrote:

Still no responses to this. I need to know whether I can do this job in
RTP. Is the sample code flawed? Is there a bug in the library or driver?
If so, can this be fixed soon? Without a response, I cannot make a good
decision on how to proceed (i.e. stick with rtp or switch operating
systems).

Thanks in advance,
Alec

I’l check with development to see if the docs/example needs revising…

-Donna


Hello,

I’m new to sound program, but must a write an app that plays a .wav and
changes the volume to both left and right speakers. I downloaded the wave.c
program in the audio online docs. It compiled fine and does play .wav
files. However, when entering the keyboard options (q,a,w, etc.) that
change the volume, I get an error on the snd_mixer_group_write(). It is an
“Input/output error”. I can change the master volume (and balance) on the
desktop and using the photon mixer. I have a soundblaster pci128 card. Any
ideas as to why the function is failing?

Alec Gorjestani
University of Minnesota

Alec,

The flaw is definitely in the example, not the driver or library.
The mixer app uses the same API calls as the example.
I am really sorry that we left you hanging. Somehow I must have
missed your question the first time around.
We fixed the example when it was first reported a while ago but it
hasn’t propogated out yet. I will see about getting you a copy.

brb,
James M.

Alec Gorjestani <alecg@me.umn.edu> wrote:

Still no responses to this. I need to know whether I can do this job in
RTP. Is the sample code flawed? Is there a bug in the library or driver?
If so, can this be fixed soon? Without a response, I cannot make a good
decision on how to proceed (i.e. stick with rtp or switch operating
systems).

Thanks in advance,
Alec



Hello,

I’m new to sound program, but must a write an app that plays a .wav and
changes the volume to both left and right speakers. I downloaded the wave.c
program in the audio online docs. It compiled fine and does play .wav
files. However, when entering the keyboard options (q,a,w, etc.) that
change the volume, I get an error on the snd_mixer_group_write(). It is an
“Input/output error”. I can change the master volume (and balance) on the
desktop and using the photon mixer. I have a soundblaster pci128 card. Any
ideas as to why the function is failing?

Alec Gorjestani
University of Minnesota

Alec,

Here is the latest wave.c example source.
I just compiled and ran it to confirm that it should
work for you.
Please post any further problems or questions that you might
have with it.

James M.




#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/termio.h>
#include <sys/types.h>
#include <unistd.h>

#include <sys/asoundlib.h>


const char *kRiffId = “RIFF”;
const char *kWaveId = “WAVE”;

typedef struct
{
char tag[4];
long length;
}
RiffTag;

typedef struct
{
char Riff[4];
long Size;
char Wave[4];
}
RiffHdr;


typedef struct
{
short FormatTag;
short Channels;
long SamplesPerSec;
long AvgBytesPerSec;
short BlockAlign;
short BitsPerSample;
}
WaveHdr;


int
err (char *msg)
{
perror (msg);
return -1;
}


int
FindTag (FILE * fp, const char *tag)
{
int retVal;
RiffTag tagBfr =
{"", 0};

retVal = 0;

// Keep reading until we find the tag or hit the EOF.
while (fread ((unsigned char *) &tagBfr, sizeof (tagBfr), 1, fp))
{

// If this is our tag, set the length and break.
if (strncmp (tag, tagBfr.tag, sizeof tagBfr.tag) == 0)
{
retVal = tagBfr.length;
break;
}

// Skip ahead the specified number of bytes in the stream
fseek (fp, tagBfr.length, SEEK_CUR);
}

// Return the result of our operation
return (retVal);
}


int
CheckHdr (FILE * fp)
{
RiffHdr riffHdr =
{"", 0};

// Read the header and, if successful, play the file
// file or WAVE file.
if (fread ((unsigned char *) &riffHdr, sizeof (RiffHdr), 1, fp) == 0)
return 0;

if (strncmp (riffHdr.Riff, kRiffId, strlen (kRiffId)) ||
strncmp (riffHdr.Wave, kWaveId, strlen (kWaveId)))
return -1;

return 0;
}


int
dev_raw (int fd)
{
struct termios termios_p;

if (tcgetattr (fd, &termios_p))
return (-1);

termios_p.c_cc[VMIN] = 1;
termios_p.c_cc[VTIME] = 0;
termios_p.c_lflag &= ~(ECHO | ICANON | ISIG |
ECHOE | ECHOK | ECHONL);
termios_p.c_oflag &= ~(OPOST);
return (tcsetattr (fd, TCSANOW, &termios_p));
}

int
dev_unraw (int fd)
{
struct termios termios_p;

if (tcgetattr (fd, &termios_p))
return (-1);

termios_p.c_lflag |= (ECHO | ICANON | ISIG |
ECHOE | ECHOK | ECHONL);
termios_p.c_oflag |= (OPOST);
return (tcsetattr (fd, TCSAFLUSH, &termios_p));
}


//*****************************************************************************
/* INDENT-OFF */
#ifdef __USAGE
%C[Options] *

Options:
-a[card#:]<dev#> the card & device number to play out on
#endif
/* INDENT-ON /
//
****************************************************************************


int
main (int argc, char **argv)
{
int card = -1;
int dev = 0;
snd_pcm_t *pcm_handle;
FILE *file1;
WaveHdr wavHdr1;
int mSamples;
int mSampleRate;
int mSampleChannels;
int mSampleBits;
char *mSampleBfr1;

int rtn;
snd_pcm_channel_info_t pi;
snd_mixer_t *mixer_handle;
snd_mixer_group_t group;
snd_pcm_channel_params_t pp;
snd_pcm_channel_setup_t setup;
int bsize, n, N = 0, c;
fd_set rfds, wfds;


while ((c = getopt (argc, argv, “a:”)) != EOF)
{
switch (c)
{
case ‘a’:
if (strchr (optarg, ‘:’))
{
card = atoi (optarg);
dev = atoi (strchr (optarg, ‘:’) + 1);
}
else
dev = atoi (optarg);
printf (“Using card %d device %d \n”, card, dev);
break;
default:
return 1;
}
}

setvbuf (stdin, NULL, _IONBF, 0);
if (card == -1)
{
if ((rtn = snd_pcm_open_preferred (&pcm_handle, &card, &dev, SND_PCM_OPEN_PLAYBACK)) < 0)
return err (“device open”);
}
else
{
if ((rtn = snd_pcm_open (&pcm_handle, card, dev, SND_PCM_OPEN_PLAYBACK)) < 0)
return err (“device open”);
}

if (argc < 2)
return err (“no file specified”);

if ((file1 = fopen (argv[optind], “r”)) == 0)
return err (“file open #1”);

if (CheckHdr (file1) == -1)
return err (“CheckHdr #1”);

mSamples = FindTag (file1, "fmt ");
fread (&wavHdr1, sizeof (wavHdr1), 1, file1);
fseek (file1, (mSamples - sizeof (WaveHdr)), SEEK_CUR);

mSampleRate = wavHdr1.SamplesPerSec;
mSampleChannels = wavHdr1.Channels;
mSampleBits = wavHdr1.BitsPerSample;

printf (“SampleRate = %d, Channels = %d, SmapleBits = %d\n”, mSampleRate, mSampleChannels, mSampleBits);

/* disabling mmap is not actually required in this example but it is included to

  • demonstrate how it is used when it is required.
    */
    if ((rtn = snd_pcm_plugin_set_disable (pcm_handle, PLUGIN_DISABLE_MMAP)) < 0)
    {
    fprintf (stderr, “snd_pcm_plugin_set_disable failed: %s\n”, snd_strerror (rtn));
    return -1;
    }

memset (&pi, 0, sizeof (pi));
pi.channel = SND_PCM_CHANNEL_PLAYBACK;
if ((rtn = snd_pcm_plugin_info (pcm_handle, &pi)) < 0)
{
fprintf (stderr, “snd_pcm_plugin_info failed: %s\n”, snd_strerror (rtn));
return -1;
}

memset (&pp, 0, sizeof (pp));

pp.mode = SND_PCM_MODE_BLOCK;
pp.channel = SND_PCM_CHANNEL_PLAYBACK;
pp.start_mode = SND_PCM_START_FULL;
pp.stop_mode = SND_PCM_STOP_STOP;

pp.buf.block.frag_size = pi.max_fragment_size;
pp.buf.block.frags_max = 1;
pp.buf.block.frags_min = 1;

pp.format.interleave = 1;
pp.format.rate = mSampleRate;
pp.format.voices = mSampleChannels;

if (mSampleBits == :sunglasses:
pp.format.format = SND_PCM_SFMT_U8;
else
pp.format.format = SND_PCM_SFMT_S16_LE;

if ((rtn = snd_pcm_plugin_params (pcm_handle, &pp)) < 0)
{
fprintf (stderr, “snd_pcm_plugin_params failed: %s\n”, snd_strerror (rtn));
return -1;
}

if ((rtn = snd_pcm_plugin_prepare (pcm_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
fprintf (stderr, “snd_pcm_plugin_prepare failed: %s\n”, snd_strerror (rtn));


memset (&setup, 0, sizeof (setup));
memset (&group, 0, sizeof (group));
setup.channel = SND_PCM_CHANNEL_PLAYBACK;
setup.mixer_gid = &group.gid;
if ((rtn = snd_pcm_plugin_setup (pcm_handle, &setup)) < 0)
{
fprintf (stderr, “snd_pcm_plugin_setup failed: %s\n”, snd_strerror (rtn));
return -1;
}
printf (“Format %s \n”, snd_pcm_get_format_name (setup.format.format));
printf (“Frag Size %d \n”, setup.buf.block.frag_size);
printf (“Rate %d \n”, setup.format.rate);
bsize = setup.buf.block.frag_size;

if (group.gid.name[0] == 0)
{
printf (“Mixer Pcm Group [%s] Not Set \n”, group.gid.name);
exit (-1);
}
printf (“Mixer Pcm Group [%s]\n”, group.gid.name);
if ((rtn = snd_mixer_open (&mixer_handle, card, setup.mixer_device)) < 0)
{
fprintf (stderr, “snd_mixer_open failed: %s\n”, snd_strerror (rtn));
return -1;
}

mSamples = FindTag (file1, “data”);

mSampleBfr1 = malloc (bsize);
FD_ZERO (&rfds);
FD_ZERO (&wfds);
n = 1;
while (N < mSamples && n > 0)
{
FD_SET (STDIN_FILENO, &rfds);
FD_SET (snd_mixer_file_descriptor (mixer_handle), &rfds);
FD_SET (snd_pcm_file_descriptor (pcm_handle, SND_PCM_CHANNEL_PLAYBACK), &wfds);

rtn = max (snd_mixer_file_descriptor (mixer_handle),
snd_pcm_file_descriptor (pcm_handle, SND_PCM_CHANNEL_PLAYBACK));

if (select (rtn + 1, &rfds, &wfds, NULL, NULL) == -1)
return err (“select”);


if (FD_ISSET (STDIN_FILENO, &rfds))
{
if ((rtn = snd_mixer_group_read (mixer_handle, &group)) < 0)
fprintf (stderr, “snd_mixer_group_read failed: %s\n”, snd_strerror (rtn));

dev_raw (fileno (stdin));
c = getc (stdin);
dev_unraw (fileno (stdin));
if (c != EOF)
{
switch (c)
{
case ‘q’:
group.volume.names.front_left += 10;
break;
case ‘a’:
group.volume.names.front_left -= 10;
break;
case ‘w’:
group.volume.names.front_left += 10;
group.volume.names.front_right += 10;
break;
case ‘s’:
group.volume.names.front_left -= 10;
group.volume.names.front_right -= 10;
break;
case ‘e’:
group.volume.names.front_right += 10;
break;
case ‘d’:
group.volume.names.front_right -= 10;
break;
}
if (group.volume.names.front_left > group.max)
group.volume.names.front_left = group.max;
if (group.volume.names.front_left < group.min)
group.volume.names.front_left = group.min;
if (group.volume.names.front_right > group.max)
group.volume.names.front_right = group.max;
if (group.volume.names.front_right < group.min)
group.volume.names.front_right = group.min;
if ((rtn = snd_mixer_group_write (mixer_handle, &group)) < 0)
fprintf (stderr, “snd_mixer_group_write failed: %s\n”, snd_strerror (rtn));
}
else
exit (0);

printf (“Volume Now at %d:%d \n”,
100 * (group.volume.names.front_left - group.min) / (group.max - group.min),
100 * (group.volume.names.front_right - group.min) / (group.max - group.min));

}

if (FD_ISSET (snd_mixer_file_descriptor (mixer_handle), &rfds))
{
snd_mixer_callbacks_t callbacks =
{0, 0, 0, 0};

snd_mixer_read (mixer_handle, &callbacks);
}

if (FD_ISSET (snd_pcm_file_descriptor (pcm_handle, SND_PCM_CHANNEL_PLAYBACK), &wfds))
{
snd_pcm_channel_status_t status;
int written = 0;

if ((n = fread (mSampleBfr1, 1, min (mSamples - N, bsize), file1)) <= 0)
continue;
written = snd_pcm_plugin_write (pcm_handle, mSampleBfr1, n);
if (written < n)
{
memset (&status, 0, sizeof (status));
if (snd_pcm_plugin_status (pcm_handle, &status) < 0)
{
fprintf (stderr, “underrun: playback channel status error\n”);
exit (1);
}

if (status.status == SND_PCM_STATUS_READY ||
status.status == SND_PCM_STATUS_UNDERRUN)
{
if (snd_pcm_plugin_prepare (pcm_handle, SND_PCM_CHANNEL_PLAYBACK) < 0)
{
fprintf (stderr, “underrun: playback channel prepare error\n”);
exit (1);
}
}
if (written < 0)
written = 0;
written += snd_pcm_plugin_write (pcm_handle, mSampleBfr1 + written, n - written);
}
N += written;
}
}

n = snd_pcm_plugin_flush (pcm_handle, SND_PCM_CHANNEL_PLAYBACK);

rtn = snd_mixer_close (mixer_handle);
rtn = snd_pcm_close (pcm_handle);
fclose (file1);
return (0);
}