davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

.wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 2:26 pm

hello,
how can I play a .wav file from my C/C++ program (Raspbian) ?
I am compiling via the Geany IDE,
the files are in my pi/sounds/ subdir,
playback via headphone jack or HDMI
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

User avatar
topguy
Posts: 5885
Joined: Tue Oct 09, 2012 11:46 am
Location: Trondheim, Norway

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 2:32 pm

Unless you need very detailed control over the playing you can use external programs like "paplay" ( http://manpages.ubuntu.com/manpages/wil ... lay.1.html ) or maybe "aplay" (http://linux.die.net/man/1/aplay).
Basically calling these programs with the "system()" call will probably get the job done.

You can experiment with the tools in the standard shell to find the correct parameters.

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 2:40 pm

thank you, but I would prefer to use a C API command like first opening a file to read and then just play it, no shell or external programs if possible.
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

User avatar
PeterO
Posts: 5066
Joined: Sun Jul 22, 2012 4:14 pm

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 3:29 pm

All you need to know....
http://www.alsa-project.org/alsa-doc/alsa-lib/
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 3:34 pm

hmmmh... thank you, but that's 2 numbers oversized.
I was thinking more of kind of a "Simple Audio Player" like I am used to for my Arduinos...:
https://www.arduino.cc/en/Tutorial/SimpleAudioPlayer
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

User avatar
PeterO
Posts: 5066
Joined: Sun Jul 22, 2012 4:14 pm

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 3:36 pm

Did you even look at the examples ?
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 3:41 pm

#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

User avatar
PeterO
Posts: 5066
Joined: Sun Jul 22, 2012 4:14 pm

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 3:54 pm

I give up.
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 3:59 pm

perhaps something like

Code: Select all

#include <audio.h>

pFile = fopen ("mysound.wav","r");
playwav(pFile);
fclose (pFile);
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 7409
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 5:17 pm

Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Thu May 19, 2016 5:56 pm

thank you, ALSA is still a lot more complicated than I thought it should be possible, and also there seem to be some issues about it (but I don't understand the detalis yet admittedly).
Perhaps a lib should be able to read the wav metadata automatically and then apply that on the wav data file to just play them and handle all those errors mentioned here automatically, too.
https://gist.github.com/ghedo/963382

Code: Select all

#include <audio.h>

unsigned char metadata[44];
pFile = fopen ("mysound.wav","r");
readwavmetadata(pFile, * metadata);
playwav(pFile, * metadata);
fclose (pFile);
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Fri May 20, 2016 3:29 pm

I happend to find
https://github.com/tinyalsa/tinyalsa

but how to install that?
There is no description how to do it... :?
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 7409
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: .wav file: play from a C/C++ program (Raspbian)

Fri May 20, 2016 3:35 pm

davenull wrote:I happend to find
https://github.com/tinyalsa/tinyalsa

but how to install that?
There is no description how to do it... :?
Had you tried

Code: Select all

git clone https://github.com/tinyalsa/tinyalsa.git
cd tinyalsa
make
?
I don't have a Pi to hand, but that built libtinyalso.so, tinycap, tinymix, minypcminfo, and tinyplay for me in the current directory.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Fri May 20, 2016 3:41 pm

yes, thank you, it did something, no errors!

now I have to find out how to make the libs work from a C program... :)
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 7409
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: .wav file: play from a C/C++ program (Raspbian)

Fri May 20, 2016 3:49 pm

If you haven't dabbled in git, do so. There's so much stuff on github, and it's the same mechanism to clone any of it.
If there's a file called "Makefile", then "make" is going to be the magic almost every time.
If there's a file called CMakeLists.txt. then "cmake" is going to be the answer, although it may need some extra runes. Cmake will create a set of Makefiles, so then you "make".
I know you use Geany as an IDE, but if you're pulling in other projects you may need to drop back to the command-line.

Look at the source for tinyplay

Code: Select all

play_sample(file, card, device, channels, rate, bits, period_size, period_count);
It's not doing the parsing of the WAV file header under play_sample, that's what the rest of tinyplay is doing.
Just make sure you add the right Makefile magic to make use of tinyalsa as a library.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Fri May 20, 2016 3:52 pm

yes, I always use Geany exclusively, I will never use the command line.

Other way round,
there must be a simple and convenient wav C/C++ API lib which can be compiled and used with Geany.

I have copied the tinyplay.c file into Geany and compiled, but there is a compilation error:

g++ -Wall -pthread -I/opt/vc/include -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads -c "tinyplay0000.c" -lshapes -lwiringPi -lrt -lpigpio -std=c++11 (im Verzeichnis: /home/pi/Desktop/pi/programs/soundprogs)
tinyplay0000.c:29:32: fatal error: tinyalsa/asoundlib.h: Datei oder Verzeichnis nicht gefunden
#include <tinyalsa/asoundlib.h>
^
compilation terminated.
Kompilierung fehlgeschlagen.
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 7409
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: .wav file: play from a C/C++ program (Raspbian)

Fri May 20, 2016 4:18 pm

davenull wrote:yes, I always use Geany exclusively, I will never use the command line.

Other way round,
there must be a simple and convenient wav C/C++ API lib which can be compiled and used with Geany.
Sorry, but you've now consigned yourself to a small community using one very specific tool. That is my cue to drop out of all discussion.
davenull wrote:I have copied the tinyplay.c file into Geany and compiled, but there is a compilation error:

g++ -Wall -pthread -I/opt/vc/include -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads -c "tinyplay0000.c" -lshapes -lwiringPi -lrt -lpigpio -std=c++11 (im Verzeichnis: /home/pi/Desktop/pi/programs/soundprogs)
tinyplay0000.c:29:32: fatal error: tinyalsa/asoundlib.h: Datei oder Verzeichnis nicht gefunden
#include <tinyalsa/asoundlib.h>
^
compilation terminated.
Kompilierung fehlgeschlagen.
Go and read up on how to add libraries and include paths within Geany. I could tell you how to do it in a Makefile (look at the example one with tinyalsa), but you're refusing to use the command-line or understand the underlying principles of how the build system works.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Fri May 20, 2016 6:51 pm

sorry, Geany is the only option.
My project is not playing just an audio file, my project is an autonomous mobile robot, using wiringPi, Arduinos as IO multiplexers by i2c and UART and USB-BT remote control, several sensors for a SLAM application, speech recognition, and a neural net - and into that project the wav processing has to be integrated.
All this I will not be able to manage by command lines, just by the Geany IDE. So I compellingly need the complete settings for Geany.
Unfortunately the tinyalsa's API user documentation is very poor.
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: .wav file: play from a C/C++ program (Raspbian)

Sat May 21, 2016 2:59 pm

update:
still faulty!

tinyalsa path:
/lib/tinyalsa/

g++ -Wall -pthread -I/opt/vc/include -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads -c "tinyplay0000.c" -lshapes -lwiringPi -lrt -lpigpio -I/lib/tinyalsa/include -L/lib/tinyalsa -ltinyalsa -std=c++11 (im Verzeichnis: /home/pi/Desktop/pi/programs/soundprogs)
tinyplay0000.c: In function ‘int check_param(pcm_params*, unsigned int, unsigned int, char*, char*)’:
tinyplay0000.c:201:43: error: invalid conversion from ‘unsigned int’ to ‘pcm_param’ [-fpermissive]
min = pcm_params_get_min(params, param);
^
In file included from tinyplay0000.c:29:0:
/lib/tinyalsa/include/tinyalsa/asoundlib.h:151:14: note: initializing argument 2 of ‘unsigned int pcm_params_get_min(pcm_params*, pcm_param)’
unsigned int pcm_params_get_min(struct pcm_params *pcm_params,
^
tinyplay0000.c:208:43: error: invalid conversion from ‘unsigned int’ to ‘pcm_param’ [-fpermissive]
max = pcm_params_get_max(params, param);
^
In file included from tinyplay0000.c:29:0:
/lib/tinyalsa/include/tinyalsa/asoundlib.h:153:14: note: initializing argument 2 of ‘unsigned int pcm_params_get_max(pcm_params*, pcm_param)’
unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
^
tinyplay0000.c: In function ‘int sample_is_playable(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int)’:
tinyplay0000.c:231:77: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");
^
tinyplay0000.c:231:77: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
tinyplay0000.c:232:88: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");
^
tinyplay0000.c:232:88: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
tinyplay0000.c:233:84: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");
^
tinyplay0000.c:233:84: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
tinyplay0000.c:234:92: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", "Hz");
^
tinyplay0000.c:234:92: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
tinyplay0000.c:235:90: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", "Hz");
^
tinyplay0000.c:235:90: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
tinyplay0000.c: In function ‘void play_sample(FILE*, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int)’:
tinyplay0000.c:277:25: error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]
buffer = malloc(size);
^
Kompilierung fehlgeschlagen.

Code: Select all

/* tinyplay.c
**
**  ver tinyplay0000
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**     * Redistributions of source code must retain the above copyright
**       notice, this list of conditions and the following disclaimer.
**     * Redistributions in binary form must reproduce the above copyright
**       notice, this list of conditions and the following disclaimer in the
**       documentation and/or other materials provided with the distribution.
**     * Neither the name of The Android Open Source Project nor the names of
**       its contributors may be used to endorse or promote products derived
**       from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/

#include <tinyalsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>

#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT  0x20746d66
#define ID_DATA 0x61746164

struct riff_wave_header {
    uint32_t riff_id;
    uint32_t riff_sz;
    uint32_t wave_id;
};

struct chunk_header {
    uint32_t id;
    uint32_t sz;
};

struct chunk_fmt {
    uint16_t audio_format;
    uint16_t num_channels;
    uint32_t sample_rate;
    uint32_t byte_rate;
    uint16_t block_align;
    uint16_t bits_per_sample;
};

static int close = 0;

void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels,
                 unsigned int rate, unsigned int bits, unsigned int period_size,
                 unsigned int period_count);

void stream_close(int sig)
{
    /* allow the stream to be closed gracefully */
    signal(sig, SIG_IGN);
    close = 1;
}

int main(int argc, char **argv)
{
    FILE *file;
    struct riff_wave_header riff_wave_header;
    struct chunk_header chunk_header;
    struct chunk_fmt chunk_fmt;
    unsigned int device = 0;
    unsigned int card = 0;
    unsigned int period_size = 1024;
    unsigned int period_count = 4;
    unsigned int channels = 2;
    unsigned int rate = 48000;
    unsigned int bits = 16;
    unsigned int is_raw = 0; /* Default wav file */
    char *filename;
    int more_chunks = 1;

    if (argc < 2) {
        fprintf(stderr, "Usage1: %s file.wav [-D card] [-d device] [-p period_size]"
                " [-n n_periods] \n", argv[0]);
        fprintf(stderr, "Usage2: %s file.raw [-D card] [-d device] [-p period_size] "
                "[-n n_periods] [-c channels] [-r rate] [-b bits] -i raw \n", argv[0]);
        return 1;
    }

    filename = argv[1];
    file = fopen(filename, "rb");
    if (!file) {
        fprintf(stderr, "Unable to open file '%s'\n", filename);
        return 1;
    }

    /* parse command line arguments */
    argv += 2;
    while (*argv) {
        if (strcmp(*argv, "-d") == 0) {
            argv++;
            if (*argv)
                device = atoi(*argv);
        }
        if (strcmp(*argv, "-p") == 0) {
            argv++;
            if (*argv)
                period_size = atoi(*argv);
        }
        if (strcmp(*argv, "-n") == 0) {
            argv++;
            if (*argv)
                period_count = atoi(*argv);
        }
        if (strcmp(*argv, "-D") == 0) {
            argv++;
            if (*argv)
                card = atoi(*argv);
        }
        if (strcmp(*argv, "-c") == 0) {
            argv++;
            if (*argv)
                channels = atoi(*argv);
        }
        if (strcmp(*argv, "-r") == 0) {
            argv++;
            if (*argv)
                rate = atoi(*argv);
        }
        if (strcmp(*argv, "-b") == 0) {
            argv++;
            if (*argv)
                bits = atoi(*argv);
        }
        if (strcmp(*argv, "-i") == 0) {
            argv++;
            if (*argv) {
                if (strcasecmp(*argv, "raw") == 0) {
                    is_raw = 1;
                }
            }
        }
        if (*argv)
            argv++;
    }

    if ( !is_raw ) {
        fread(&riff_wave_header, sizeof(riff_wave_header), 1, file);
        if ((riff_wave_header.riff_id != ID_RIFF) ||
            (riff_wave_header.wave_id != ID_WAVE)) {
            fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename);
            fclose(file);
            return 1;
        }
        do {
            fread(&chunk_header, sizeof(chunk_header), 1, file);
            switch (chunk_header.id) {
            case ID_FMT:
                fread(&chunk_fmt, sizeof(chunk_fmt), 1, file);
                /* If the format header is larger, skip the rest */
                if (chunk_header.sz > sizeof(chunk_fmt))
                    fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
                break;
            case ID_DATA:
                /* Stop looking for chunks */
                more_chunks = 0;
                break;
            default:
                /* Unknown chunk, skip bytes */
                fseek(file, chunk_header.sz, SEEK_CUR);
            }
        } while (more_chunks);
        channels = chunk_fmt.num_channels;
        rate = chunk_fmt.sample_rate;
        bits = chunk_fmt.bits_per_sample;
    }

    play_sample(file, card, device, channels, rate, bits, period_size, period_count);

    fclose(file);

    return 0;
}

int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
                 char *param_name, char *param_unit)
{
    unsigned int min;
    unsigned int max;
    int is_within_bounds = 1;

    min = pcm_params_get_min(params, param);
    if (value < min) {
        fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,
                param_unit, min, param_unit);
        is_within_bounds = 0;
    }

    max = pcm_params_get_max(params, param);
    if (value > max) {
        fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,
                param_unit, max, param_unit);
        is_within_bounds = 0;
    }

    return is_within_bounds;
}

int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels,
                        unsigned int rate, unsigned int bits, unsigned int period_size,
                        unsigned int period_count)
{
    struct pcm_params *params;
    int can_play;

    params = pcm_params_get(card, device, PCM_OUT);
    if (params == NULL) {
        fprintf(stderr, "Unable to open PCM device %u.\n", device);
        return 0;
    }

    can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");
    can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");
    can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");
    can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", "Hz");
    can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", "Hz");

    pcm_params_free(params);

    return can_play;
}

void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels,
                 unsigned int rate, unsigned int bits, unsigned int period_size,
                 unsigned int period_count)
{
    struct pcm_config config;
    struct pcm *pcm;
    char *buffer;
    int size;
    int num_read;

    memset(&config, 0, sizeof(config));
    config.channels = channels;
    config.rate = rate;
    config.period_size = period_size;
    config.period_count = period_count;
    if (bits == 32)
        config.format = PCM_FORMAT_S32_LE;
    else if (bits == 16)
        config.format = PCM_FORMAT_S16_LE;
    config.start_threshold = 0;
    config.stop_threshold = 0;
    config.silence_threshold = 0;

    if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) {
        return;
    }

    pcm = pcm_open(card, device, PCM_OUT, &config);
    if (!pcm || !pcm_is_ready(pcm)) {
        fprintf(stderr, "Unable to open PCM device %u (%s)\n",
                device, pcm_get_error(pcm));
        return;
    }

    size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
    buffer = malloc(size);
    if (!buffer) {
        fprintf(stderr, "Unable to allocate %d bytes\n", size);
        free(buffer);
        pcm_close(pcm);
        return;
    }

    printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits);

    /* catch ctrl-c to shutdown cleanly */
    signal(SIGINT, stream_close);

    do {
        num_read = fread(buffer, 1, size, file);
        if (num_read > 0) {
            if (pcm_write(pcm, buffer, num_read)) {
                fprintf(stderr, "Error playing sample\n");
                break;
            }
        }
    } while (!close && num_read > 0);

    free(buffer);
    pcm_close(pcm);
}
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

sheroy
Posts: 47
Joined: Fri Jun 14, 2013 5:34 pm

Re: .wav file: play from a C/C++ program (Raspbian)

Sun May 22, 2016 5:59 pm

To read a wav file you may refer to
http://soundfile.sapp.org/doc/WaveFormat/
for the file format and how to read, you may use pread.

use timing (from time.h) to read the sample at the right time and put out a voltage onto the DAC which a linear function of the sample read. Beware for data in 2's compliment form.

miaomiao
Posts: 22
Joined: Fri Jun 30, 2017 4:07 am

Re: .wav file: play from a C/C++ program (Raspbian)

Tue Jul 18, 2017 8:13 am

davenull wrote:hello,
how can I play a .wav file from my C/C++ program (Raspbian) ?
I am compiling via the Geany IDE,
the files are in my pi/sounds/ subdir,
playback via headphone jack or HDMI

Hi,I am same situation as you now. Using Geany and want to play a .wav file in C language. Have you solve the problem?Thank you

LdB
Posts: 1280
Joined: Wed Dec 07, 2016 2:29 pm

Re: .wav file: play from a C/C++ program (Raspbian)

Tue Jul 18, 2017 1:57 pm

It's not complex it's just an error with using deprecated functions so use the new ones that replaced them.

Don't have a Pi with linux to try it but it compiles without error so you never know you could be lucky

Code: Select all

/* tinyplay.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**     * Redistributions of source code must retain the above copyright
**       notice, this list of conditions and the following disclaimer.
**     * Redistributions in binary form must reproduce the above copyright
**       notice, this list of conditions and the following disclaimer in the
**       documentation and/or other materials provided with the distribution.
**     * Neither the name of The Android Open Source Project nor the names of
**       its contributors may be used to endorse or promote products derived
**       from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/

#include "tinyalsa/asoundlib.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>

struct cmd {
    const char *filename;
    const char *filetype;
    unsigned int card;
    unsigned int device;
    int flags;
    struct pcm_config config;
    unsigned int bits;
};

void cmd_init(struct cmd *cmd)
{
    cmd->filename = NULL;
    cmd->filetype = NULL;
    cmd->card = 0;
    cmd->device = 0;
    cmd->flags = PCM_OUT;
    cmd->config.period_size = 1024;
    cmd->config.period_count = 2;
    cmd->config.channels = 2;
    cmd->config.rate = 48000;
    cmd->config.format = PCM_FORMAT_S16_LE;
    cmd->config.silence_threshold = 1024 * 2;
    cmd->config.stop_threshold = 1024 * 2;
    cmd->config.start_threshold = 1024;
    cmd->bits = 16;
}

int cmd_parse_arg(struct cmd *cmd, int argc, const char **argv)
{
    if (argc < 1) {
        return 0;
    }

    if ((strcmp(argv[0], "-M") == 0) || (strcmp(argv[0], "--mmap") == 0)) {
        cmd->flags |= PCM_MMAP;
        return 1;
    }

    if (argv[0][0] != '-') {
        cmd->filename = argv[0];
        return 1;
    }

    if (argc < 2) {
        fprintf(stderr, "option '%s' is missing argument\n", argv[0]);
        return -1;
    }

    if ((strcmp(argv[0], "-D") == 0) || (strcmp(argv[0], "--card") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->card) != 1) {
            fprintf(stderr, "failed parsing card number '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-d") == 0) || (strcmp(argv[0], "--device") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->device) != 1) {
            fprintf(stderr, "failed parsing device number '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-p") == 0) || (strcmp(argv[0], "--period-size") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.period_size) != 1) {
            fprintf(stderr, "failed parsing period size '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-p") == 0) || (strcmp(argv[0], "--period-count") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.period_count) != 1) {
            fprintf(stderr, "failed parsing period count '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-c") == 0) || (strcmp(argv[0], "--channels") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.channels) != 1) {
            fprintf(stderr, "failed parsing channel count '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-r") == 0) || (strcmp(argv[0], "--rate") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.rate) != 1) {
            fprintf(stderr, "failed parsing rate '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-i") == 0) || (strcmp(argv[0], "--file-type") == 0)) {
        cmd->filetype = argv[1];
    } else {
        fprintf(stderr, "unknown option '%s'\n", argv[0]);
        return -1;
    }
    return 2;
}

int cmd_parse_args(struct cmd *cmd, int argc, const char **argv)
{
    int i = 0;
    while (i < argc) {
        int j = cmd_parse_arg(cmd, argc - i, &argv[i]);
        if (j < 0){
            break;
        }
        i += j;
    }

    if ((cmd->filename != NULL)
     && (cmd->filetype == NULL)) {
        cmd->filetype = strrchr(cmd->filename, '.');
        if (cmd->filetype != NULL) {
            cmd->filetype++;
        }
    }

    return i;
}

#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT  0x20746d66
#define ID_DATA 0x61746164

struct riff_wave_header {
    uint32_t riff_id;
    uint32_t riff_sz;
    uint32_t wave_id;
};

struct chunk_header {
    uint32_t id;
    uint32_t sz;
};

struct chunk_fmt {
    uint16_t audio_format;
    uint16_t num_channels;
    uint32_t sample_rate;
    uint32_t byte_rate;
    uint16_t block_align;
    uint16_t bits_per_sample;
};

struct ctx {
    struct pcm *pcm;

    struct riff_wave_header wave_header;
    struct chunk_header chunk_header;
    struct chunk_fmt chunk_fmt;

    FILE *file;
};

int ctx_init(struct ctx* ctx, const struct cmd *cmd)
{
    unsigned int bits = cmd->bits;
    struct pcm_config config = cmd->config;

    if (cmd->filename == NULL) {
        fprintf(stderr, "filename not specified\n");
        return -1;
    }

    ctx->file = fopen(cmd->filename, "rb");
    if (ctx->file == NULL) {
        fprintf(stderr, "failed to open '%s'\n", cmd->filename);
        return -1;
    }

    if ((cmd->filetype != NULL) && (strcmp(cmd->filetype, "wav") == 0)) {
        if (fread(&ctx->wave_header, sizeof(ctx->wave_header), 1, ctx->file) != 1){
            fprintf(stderr, "error: '%s' does not contain a riff/wave header\n", cmd->filename);
            fclose(ctx->file);
            return -1;
        }
        if ((ctx->wave_header.riff_id != ID_RIFF) ||
            (ctx->wave_header.wave_id != ID_WAVE)) {
            fprintf(stderr, "error: '%s' is not a riff/wave file\n", cmd->filename);
            fclose(ctx->file);
            return -1;
        }
	unsigned int more_chunks = 1;
        do {
            if (fread(&ctx->chunk_header, sizeof(ctx->chunk_header), 1, ctx->file) != 1){
                fprintf(stderr, "error: '%s' does not contain a data chunk\n", cmd->filename);
                fclose(ctx->file);
                return -1;
            }
            switch (ctx->chunk_header.id) {
            case ID_FMT:
                if (fread(&ctx->chunk_fmt, sizeof(ctx->chunk_fmt), 1, ctx->file) != 1){
                    fprintf(stderr, "error: '%s' has incomplete format chunk\n", cmd->filename);
                    fclose(ctx->file);
                    return -1;
                }
                /* If the format header is larger, skip the rest */
                if (ctx->chunk_header.sz > sizeof(ctx->chunk_fmt))
                    fseek(ctx->file, ctx->chunk_header.sz - sizeof(ctx->chunk_fmt), SEEK_CUR);
                break;
            case ID_DATA:
                /* Stop looking for chunks */
                more_chunks = 0;
                break;
            default:
                /* Unknown chunk, skip bytes */
                fseek(ctx->file, ctx->chunk_header.sz, SEEK_CUR);
            }
        } while (more_chunks);
        config.channels = ctx->chunk_fmt.num_channels;
        config.rate = ctx->chunk_fmt.sample_rate;
        bits = ctx->chunk_fmt.bits_per_sample;
    }

    if (bits == 8) {
        config.format = PCM_FORMAT_S8;
    } else if (bits == 16) {
        config.format = PCM_FORMAT_S16_LE;
    } else if (bits == 24) {
        config.format = PCM_FORMAT_S24_3LE;
    } else if (bits == 32) {
        config.format = PCM_FORMAT_S32_LE;
    } else {
        fprintf(stderr, "bit count '%u' not supported\n", bits);
        fclose(ctx->file);
        return -1;
    }

    ctx->pcm = pcm_open(cmd->card,
                        cmd->device,
                        cmd->flags,
                        &config);
    if (ctx->pcm == NULL) {
        fprintf(stderr, "failed to allocate memory for pcm\n");
        fclose(ctx->file);
        return -1;
    } else if (!pcm_is_ready(ctx->pcm)) {
        fprintf(stderr, "failed to open for pcm %u,%u\n", cmd->card, cmd->device);
        fclose(ctx->file);
        pcm_close(ctx->pcm);
        return -1;
    }

    return 0;
}

void ctx_free(struct ctx *ctx)
{
    if (ctx == NULL) {
        return;
    }
    if (ctx->pcm != NULL) {
        pcm_close(ctx->pcm);
    }
    if (ctx->file != NULL) {
        fclose(ctx->file);
    }
}

static int close = 0;

int play_sample(struct ctx *ctx);

void stream_close(int sig)
{
    /* allow the stream to be closed gracefully */
    signal(sig, SIG_IGN);
    close = 1;
}

void print_usage(const char *argv0)
{
    fprintf(stderr, "usage: %s file.wav [options]\n", argv0);
    fprintf(stderr, "options:\n");
    fprintf(stderr, "-D | --card   <card number>    The device to receive the audio\n");
    fprintf(stderr, "-d | --device <device number>  The card to receive the audio\n");
    fprintf(stderr, "-p | --period-size <size>      The size of the PCM's period\n");
    fprintf(stderr, "-n | --period-count <count>    The number of PCM periods\n");
    fprintf(stderr, "-i | --file-type <file-type >  The type of file to read (raw or wav)\n");
    fprintf(stderr, "-c | --channels <count>        The amount of channels per frame\n");
    fprintf(stderr, "-r | --rate <rate>             The amount of frames per second\n");
    fprintf(stderr, "-b | --bits <bit-count>        The number of bits in one sample\n");
    fprintf(stderr, "-M | --mmap                    Use memory mapped IO to play audio\n");
}


int main(int argc, const char **argv)
{
    struct cmd cmd;
    struct ctx ctx;

    if (argc < 2) {
        print_usage(argv[0]);
        return EXIT_FAILURE;
    }

    cmd_init(&cmd);
    if (cmd_parse_args(&cmd, argc - 1, &argv[1]) < 0) {
        return EXIT_FAILURE;
    }

    if (ctx_init(&ctx, &cmd) < 0) {
        return EXIT_FAILURE;
    }

    /* TODO get parameters from context */
    printf("playing '%s': %u ch, %u hz, %u bit\n",
           cmd.filename,
           cmd.config.channels,
           cmd.config.rate,
           cmd.bits);

    if (play_sample(&ctx) < 0) {
        ctx_free(&ctx);
        return EXIT_FAILURE;
    }

    ctx_free(&ctx);
    return EXIT_SUCCESS;
}

int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
                 char *param_name, char *param_unit)
{
    unsigned int min;
    unsigned int max;
    int is_within_bounds = 1;

    min = pcm_params_get_min(params, param);
    if (value < min) {
        fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,
                param_unit, min, param_unit);
        is_within_bounds = 0;
    }

    max = pcm_params_get_max(params, param);
    if (value > max) {
        fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,
                param_unit, max, param_unit);
        is_within_bounds = 0;
    }

    return is_within_bounds;
}

int sample_is_playable(const struct cmd *cmd)
{
    struct pcm_params *params;
    int can_play;

    params = pcm_params_get(cmd->card, cmd->device, PCM_OUT);
    if (params == NULL) {
        fprintf(stderr, "unable to open PCM %u,%u\n", cmd->card, cmd->device);
        return 0;
    }

    can_play = check_param(params, PCM_PARAM_RATE, cmd->config.rate, "sample rate", "hz");
    can_play &= check_param(params, PCM_PARAM_CHANNELS, cmd->config.channels, "sample", " channels");
    can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, cmd->bits, "bits", " bits");
    can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, cmd->config.period_size, "period size", "");
    can_play &= check_param(params, PCM_PARAM_PERIODS, cmd->config.period_count, "period count", "");

    pcm_params_free(params);

    return can_play;
}

int play_sample(struct ctx *ctx)
{
    char *buffer;
    int size;
    int num_read;

    size = pcm_frames_to_bytes(ctx->pcm, pcm_get_buffer_size(ctx->pcm));
    buffer = malloc(size);
    if (!buffer) {
        fprintf(stderr, "unable to allocate %d bytes\n", size);
        return -1;
    }

    /* catch ctrl-c to shutdown cleanly */
    signal(SIGINT, stream_close);

    do {
        num_read = fread(buffer, 1, size, ctx->file);
        if (num_read > 0) {
		if (pcm_writei(ctx->pcm, buffer,
			pcm_bytes_to_frames(ctx->pcm, num_read)) < 0) {
                fprintf(stderr, "error playing sample\n");
                break;
            }
        }
    } while (!close && num_read > 0);

    free(buffer);
    return 0;
}

miaomiao
Posts: 22
Joined: Fri Jun 30, 2017 4:07 am

Re: .wav file: play from a C/C++ program (Raspbian)

Wed Jul 19, 2017 1:41 am

LdB wrote:It's not complex it's just an error with using deprecated functions so use the new ones that replaced them.

Don't have a Pi with linux to try it but it compiles without error so you never know you could be lucky

Code: Select all

/* tinyplay.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**     * Redistributions of source code must retain the above copyright
**       notice, this list of conditions and the following disclaimer.
**     * Redistributions in binary form must reproduce the above copyright
**       notice, this list of conditions and the following disclaimer in the
**       documentation and/or other materials provided with the distribution.
**     * Neither the name of The Android Open Source Project nor the names of
**       its contributors may be used to endorse or promote products derived
**       from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/

#include "tinyalsa/asoundlib.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>

struct cmd {
    const char *filename;
    const char *filetype;
    unsigned int card;
    unsigned int device;
    int flags;
    struct pcm_config config;
    unsigned int bits;
};

void cmd_init(struct cmd *cmd)
{
    cmd->filename = NULL;
    cmd->filetype = NULL;
    cmd->card = 0;
    cmd->device = 0;
    cmd->flags = PCM_OUT;
    cmd->config.period_size = 1024;
    cmd->config.period_count = 2;
    cmd->config.channels = 2;
    cmd->config.rate = 48000;
    cmd->config.format = PCM_FORMAT_S16_LE;
    cmd->config.silence_threshold = 1024 * 2;
    cmd->config.stop_threshold = 1024 * 2;
    cmd->config.start_threshold = 1024;
    cmd->bits = 16;
}

int cmd_parse_arg(struct cmd *cmd, int argc, const char **argv)
{
    if (argc < 1) {
        return 0;
    }

    if ((strcmp(argv[0], "-M") == 0) || (strcmp(argv[0], "--mmap") == 0)) {
        cmd->flags |= PCM_MMAP;
        return 1;
    }

    if (argv[0][0] != '-') {
        cmd->filename = argv[0];
        return 1;
    }

    if (argc < 2) {
        fprintf(stderr, "option '%s' is missing argument\n", argv[0]);
        return -1;
    }

    if ((strcmp(argv[0], "-D") == 0) || (strcmp(argv[0], "--card") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->card) != 1) {
            fprintf(stderr, "failed parsing card number '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-d") == 0) || (strcmp(argv[0], "--device") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->device) != 1) {
            fprintf(stderr, "failed parsing device number '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-p") == 0) || (strcmp(argv[0], "--period-size") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.period_size) != 1) {
            fprintf(stderr, "failed parsing period size '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-p") == 0) || (strcmp(argv[0], "--period-count") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.period_count) != 1) {
            fprintf(stderr, "failed parsing period count '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-c") == 0) || (strcmp(argv[0], "--channels") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.channels) != 1) {
            fprintf(stderr, "failed parsing channel count '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-r") == 0) || (strcmp(argv[0], "--rate") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.rate) != 1) {
            fprintf(stderr, "failed parsing rate '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-i") == 0) || (strcmp(argv[0], "--file-type") == 0)) {
        cmd->filetype = argv[1];
    } else {
        fprintf(stderr, "unknown option '%s'\n", argv[0]);
        return -1;
    }
    return 2;
}

int cmd_parse_args(struct cmd *cmd, int argc, const char **argv)
{
    int i = 0;
    while (i < argc) {
        int j = cmd_parse_arg(cmd, argc - i, &argv[i]);
        if (j < 0){
            break;
        }
        i += j;
    }

    if ((cmd->filename != NULL)
     && (cmd->filetype == NULL)) {
        cmd->filetype = strrchr(cmd->filename, '.');
        if (cmd->filetype != NULL) {
            cmd->filetype++;
        }
    }

    return i;
}

#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT  0x20746d66
#define ID_DATA 0x61746164

struct riff_wave_header {
    uint32_t riff_id;
    uint32_t riff_sz;
    uint32_t wave_id;
};

struct chunk_header {
    uint32_t id;
    uint32_t sz;
};

struct chunk_fmt {
    uint16_t audio_format;
    uint16_t num_channels;
    uint32_t sample_rate;
    uint32_t byte_rate;
    uint16_t block_align;
    uint16_t bits_per_sample;
};

struct ctx {
    struct pcm *pcm;

    struct riff_wave_header wave_header;
    struct chunk_header chunk_header;
    struct chunk_fmt chunk_fmt;

    FILE *file;
};

int ctx_init(struct ctx* ctx, const struct cmd *cmd)
{
    unsigned int bits = cmd->bits;
    struct pcm_config config = cmd->config;

    if (cmd->filename == NULL) {
        fprintf(stderr, "filename not specified\n");
        return -1;
    }

    ctx->file = fopen(cmd->filename, "rb");
    if (ctx->file == NULL) {
        fprintf(stderr, "failed to open '%s'\n", cmd->filename);
        return -1;
    }

    if ((cmd->filetype != NULL) && (strcmp(cmd->filetype, "wav") == 0)) {
        if (fread(&ctx->wave_header, sizeof(ctx->wave_header), 1, ctx->file) != 1){
            fprintf(stderr, "error: '%s' does not contain a riff/wave header\n", cmd->filename);
            fclose(ctx->file);
            return -1;
        }
        if ((ctx->wave_header.riff_id != ID_RIFF) ||
            (ctx->wave_header.wave_id != ID_WAVE)) {
            fprintf(stderr, "error: '%s' is not a riff/wave file\n", cmd->filename);
            fclose(ctx->file);
            return -1;
        }
	unsigned int more_chunks = 1;
        do {
            if (fread(&ctx->chunk_header, sizeof(ctx->chunk_header), 1, ctx->file) != 1){
                fprintf(stderr, "error: '%s' does not contain a data chunk\n", cmd->filename);
                fclose(ctx->file);
                return -1;
            }
            switch (ctx->chunk_header.id) {
            case ID_FMT:
                if (fread(&ctx->chunk_fmt, sizeof(ctx->chunk_fmt), 1, ctx->file) != 1){
                    fprintf(stderr, "error: '%s' has incomplete format chunk\n", cmd->filename);
                    fclose(ctx->file);
                    return -1;
                }
                /* If the format header is larger, skip the rest */
                if (ctx->chunk_header.sz > sizeof(ctx->chunk_fmt))
                    fseek(ctx->file, ctx->chunk_header.sz - sizeof(ctx->chunk_fmt), SEEK_CUR);
                break;
            case ID_DATA:
                /* Stop looking for chunks */
                more_chunks = 0;
                break;
            default:
                /* Unknown chunk, skip bytes */
                fseek(ctx->file, ctx->chunk_header.sz, SEEK_CUR);
            }
        } while (more_chunks);
        config.channels = ctx->chunk_fmt.num_channels;
        config.rate = ctx->chunk_fmt.sample_rate;
        bits = ctx->chunk_fmt.bits_per_sample;
    }

    if (bits == 8) {
        config.format = PCM_FORMAT_S8;
    } else if (bits == 16) {
        config.format = PCM_FORMAT_S16_LE;
    } else if (bits == 24) {
        config.format = PCM_FORMAT_S24_3LE;
    } else if (bits == 32) {
        config.format = PCM_FORMAT_S32_LE;
    } else {
        fprintf(stderr, "bit count '%u' not supported\n", bits);
        fclose(ctx->file);
        return -1;
    }

    ctx->pcm = pcm_open(cmd->card,
                        cmd->device,
                        cmd->flags,
                        &config);
    if (ctx->pcm == NULL) {
        fprintf(stderr, "failed to allocate memory for pcm\n");
        fclose(ctx->file);
        return -1;
    } else if (!pcm_is_ready(ctx->pcm)) {
        fprintf(stderr, "failed to open for pcm %u,%u\n", cmd->card, cmd->device);
        fclose(ctx->file);
        pcm_close(ctx->pcm);
        return -1;
    }

    return 0;
}

void ctx_free(struct ctx *ctx)
{
    if (ctx == NULL) {
        return;
    }
    if (ctx->pcm != NULL) {
        pcm_close(ctx->pcm);
    }
    if (ctx->file != NULL) {
        fclose(ctx->file);
    }
}

static int close = 0;

int play_sample(struct ctx *ctx);

void stream_close(int sig)
{
    /* allow the stream to be closed gracefully */
    signal(sig, SIG_IGN);
    close = 1;
}

void print_usage(const char *argv0)
{
    fprintf(stderr, "usage: %s file.wav [options]\n", argv0);
    fprintf(stderr, "options:\n");
    fprintf(stderr, "-D | --card   <card number>    The device to receive the audio\n");
    fprintf(stderr, "-d | --device <device number>  The card to receive the audio\n");
    fprintf(stderr, "-p | --period-size <size>      The size of the PCM's period\n");
    fprintf(stderr, "-n | --period-count <count>    The number of PCM periods\n");
    fprintf(stderr, "-i | --file-type <file-type >  The type of file to read (raw or wav)\n");
    fprintf(stderr, "-c | --channels <count>        The amount of channels per frame\n");
    fprintf(stderr, "-r | --rate <rate>             The amount of frames per second\n");
    fprintf(stderr, "-b | --bits <bit-count>        The number of bits in one sample\n");
    fprintf(stderr, "-M | --mmap                    Use memory mapped IO to play audio\n");
}


int main(int argc, const char **argv)
{
    struct cmd cmd;
    struct ctx ctx;

    if (argc < 2) {
        print_usage(argv[0]);
        return EXIT_FAILURE;
    }

    cmd_init(&cmd);
    if (cmd_parse_args(&cmd, argc - 1, &argv[1]) < 0) {
        return EXIT_FAILURE;
    }

    if (ctx_init(&ctx, &cmd) < 0) {
        return EXIT_FAILURE;
    }

    /* TODO get parameters from context */
    printf("playing '%s': %u ch, %u hz, %u bit\n",
           cmd.filename,
           cmd.config.channels,
           cmd.config.rate,
           cmd.bits);

    if (play_sample(&ctx) < 0) {
        ctx_free(&ctx);
        return EXIT_FAILURE;
    }

    ctx_free(&ctx);
    return EXIT_SUCCESS;
}

int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
                 char *param_name, char *param_unit)
{
    unsigned int min;
    unsigned int max;
    int is_within_bounds = 1;

    min = pcm_params_get_min(params, param);
    if (value < min) {
        fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,
                param_unit, min, param_unit);
        is_within_bounds = 0;
    }

    max = pcm_params_get_max(params, param);
    if (value > max) {
        fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,
                param_unit, max, param_unit);
        is_within_bounds = 0;
    }

    return is_within_bounds;
}

int sample_is_playable(const struct cmd *cmd)
{
    struct pcm_params *params;
    int can_play;

    params = pcm_params_get(cmd->card, cmd->device, PCM_OUT);
    if (params == NULL) {
        fprintf(stderr, "unable to open PCM %u,%u\n", cmd->card, cmd->device);
        return 0;
    }

    can_play = check_param(params, PCM_PARAM_RATE, cmd->config.rate, "sample rate", "hz");
    can_play &= check_param(params, PCM_PARAM_CHANNELS, cmd->config.channels, "sample", " channels");
    can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, cmd->bits, "bits", " bits");
    can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, cmd->config.period_size, "period size", "");
    can_play &= check_param(params, PCM_PARAM_PERIODS, cmd->config.period_count, "period count", "");

    pcm_params_free(params);

    return can_play;
}

int play_sample(struct ctx *ctx)
{
    char *buffer;
    int size;
    int num_read;

    size = pcm_frames_to_bytes(ctx->pcm, pcm_get_buffer_size(ctx->pcm));
    buffer = malloc(size);
    if (!buffer) {
        fprintf(stderr, "unable to allocate %d bytes\n", size);
        return -1;
    }

    /* catch ctrl-c to shutdown cleanly */
    signal(SIGINT, stream_close);

    do {
        num_read = fread(buffer, 1, size, ctx->file);
        if (num_read > 0) {
		if (pcm_writei(ctx->pcm, buffer,
			pcm_bytes_to_frames(ctx->pcm, num_read)) < 0) {
                fprintf(stderr, "error playing sample\n");
                break;
            }
        }
    } while (!close && num_read > 0);

    free(buffer);
    return 0;
}

Thank you for reply,but I need to download a extra "tinyalsa/asoundlib.h" librabry is it?

LdB
Posts: 1280
Joined: Wed Dec 07, 2016 2:29 pm

Re: .wav file: play from a C/C++ program (Raspbian)

Wed Jul 19, 2017 3:56 am

You should have got all that when you installed the package .. see the instructions
(https://github.com/tinyalsa/tinyalsa)

sudo apt-add-repository ppa:taylorcholberton/tinyalsa
sudo apt-get update
sudo apt-get install tinyalsa
sudo apt-get install libtinyalsa-dev

The files just use the linux API there really isn't much to them.

1dot0
Posts: 430
Joined: Mon Nov 28, 2016 12:31 pm

Re: .wav file: play from a C/C++ program (Raspbian)

Wed Jul 19, 2017 5:20 am

LdB wrote:It's not complex it's just an error with using deprecated functions so use the new ones that replaced them.

Don't have a Pi with linux to try it but it compiles without error so you never know you could be lucky

Code: Select all

/* tinyplay.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**     * Redistributions of source code must retain the above copyright
**       notice, this list of conditions and the following disclaimer.
**     * Redistributions in binary form must reproduce the above copyright
**       notice, this list of conditions and the following disclaimer in the
**       documentation and/or other materials provided with the distribution.
**     * Neither the name of The Android Open Source Project nor the names of
**       its contributors may be used to endorse or promote products derived
**       from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/

#include "tinyalsa/asoundlib.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>

struct cmd {
    const char *filename;
    const char *filetype;
    unsigned int card;
    unsigned int device;
    int flags;
    struct pcm_config config;
    unsigned int bits;
};

void cmd_init(struct cmd *cmd)
{
    cmd->filename = NULL;
    cmd->filetype = NULL;
    cmd->card = 0;
    cmd->device = 0;
    cmd->flags = PCM_OUT;
    cmd->config.period_size = 1024;
    cmd->config.period_count = 2;
    cmd->config.channels = 2;
    cmd->config.rate = 48000;
    cmd->config.format = PCM_FORMAT_S16_LE;
    cmd->config.silence_threshold = 1024 * 2;
    cmd->config.stop_threshold = 1024 * 2;
    cmd->config.start_threshold = 1024;
    cmd->bits = 16;
}

int cmd_parse_arg(struct cmd *cmd, int argc, const char **argv)
{
    if (argc < 1) {
        return 0;
    }

    if ((strcmp(argv[0], "-M") == 0) || (strcmp(argv[0], "--mmap") == 0)) {
        cmd->flags |= PCM_MMAP;
        return 1;
    }

    if (argv[0][0] != '-') {
        cmd->filename = argv[0];
        return 1;
    }

    if (argc < 2) {
        fprintf(stderr, "option '%s' is missing argument\n", argv[0]);
        return -1;
    }

    if ((strcmp(argv[0], "-D") == 0) || (strcmp(argv[0], "--card") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->card) != 1) {
            fprintf(stderr, "failed parsing card number '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-d") == 0) || (strcmp(argv[0], "--device") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->device) != 1) {
            fprintf(stderr, "failed parsing device number '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-p") == 0) || (strcmp(argv[0], "--period-size") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.period_size) != 1) {
            fprintf(stderr, "failed parsing period size '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-p") == 0) || (strcmp(argv[0], "--period-count") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.period_count) != 1) {
            fprintf(stderr, "failed parsing period count '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-c") == 0) || (strcmp(argv[0], "--channels") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.channels) != 1) {
            fprintf(stderr, "failed parsing channel count '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-r") == 0) || (strcmp(argv[0], "--rate") == 0)) {
        if (sscanf(argv[1], "%u", &cmd->config.rate) != 1) {
            fprintf(stderr, "failed parsing rate '%s'\n", argv[1]);
            return -1;
        }
    } else if ((strcmp(argv[0], "-i") == 0) || (strcmp(argv[0], "--file-type") == 0)) {
        cmd->filetype = argv[1];
    } else {
        fprintf(stderr, "unknown option '%s'\n", argv[0]);
        return -1;
    }
    return 2;
}

int cmd_parse_args(struct cmd *cmd, int argc, const char **argv)
{
    int i = 0;
    while (i < argc) {
        int j = cmd_parse_arg(cmd, argc - i, &argv[i]);
        if (j < 0){
            break;
        }
        i += j;
    }

    if ((cmd->filename != NULL)
     && (cmd->filetype == NULL)) {
        cmd->filetype = strrchr(cmd->filename, '.');
        if (cmd->filetype != NULL) {
            cmd->filetype++;
        }
    }

    return i;
}

#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT  0x20746d66
#define ID_DATA 0x61746164

struct riff_wave_header {
    uint32_t riff_id;
    uint32_t riff_sz;
    uint32_t wave_id;
};

struct chunk_header {
    uint32_t id;
    uint32_t sz;
};

struct chunk_fmt {
    uint16_t audio_format;
    uint16_t num_channels;
    uint32_t sample_rate;
    uint32_t byte_rate;
    uint16_t block_align;
    uint16_t bits_per_sample;
};

struct ctx {
    struct pcm *pcm;

    struct riff_wave_header wave_header;
    struct chunk_header chunk_header;
    struct chunk_fmt chunk_fmt;

    FILE *file;
};

int ctx_init(struct ctx* ctx, const struct cmd *cmd)
{
    unsigned int bits = cmd->bits;
    struct pcm_config config = cmd->config;

    if (cmd->filename == NULL) {
        fprintf(stderr, "filename not specified\n");
        return -1;
    }

    ctx->file = fopen(cmd->filename, "rb");
    if (ctx->file == NULL) {
        fprintf(stderr, "failed to open '%s'\n", cmd->filename);
        return -1;
    }

    if ((cmd->filetype != NULL) && (strcmp(cmd->filetype, "wav") == 0)) {
        if (fread(&ctx->wave_header, sizeof(ctx->wave_header), 1, ctx->file) != 1){
            fprintf(stderr, "error: '%s' does not contain a riff/wave header\n", cmd->filename);
            fclose(ctx->file);
            return -1;
        }
        if ((ctx->wave_header.riff_id != ID_RIFF) ||
            (ctx->wave_header.wave_id != ID_WAVE)) {
            fprintf(stderr, "error: '%s' is not a riff/wave file\n", cmd->filename);
            fclose(ctx->file);
            return -1;
        }
	unsigned int more_chunks = 1;
        do {
            if (fread(&ctx->chunk_header, sizeof(ctx->chunk_header), 1, ctx->file) != 1){
                fprintf(stderr, "error: '%s' does not contain a data chunk\n", cmd->filename);
                fclose(ctx->file);
                return -1;
            }
            switch (ctx->chunk_header.id) {
            case ID_FMT:
                if (fread(&ctx->chunk_fmt, sizeof(ctx->chunk_fmt), 1, ctx->file) != 1){
                    fprintf(stderr, "error: '%s' has incomplete format chunk\n", cmd->filename);
                    fclose(ctx->file);
                    return -1;
                }
                /* If the format header is larger, skip the rest */
                if (ctx->chunk_header.sz > sizeof(ctx->chunk_fmt))
                    fseek(ctx->file, ctx->chunk_header.sz - sizeof(ctx->chunk_fmt), SEEK_CUR);
                break;
            case ID_DATA:
                /* Stop looking for chunks */
                more_chunks = 0;
                break;
            default:
                /* Unknown chunk, skip bytes */
                fseek(ctx->file, ctx->chunk_header.sz, SEEK_CUR);
            }
        } while (more_chunks);
        config.channels = ctx->chunk_fmt.num_channels;
        config.rate = ctx->chunk_fmt.sample_rate;
        bits = ctx->chunk_fmt.bits_per_sample;
    }

    if (bits == 8) {
        config.format = PCM_FORMAT_S8;
    } else if (bits == 16) {
        config.format = PCM_FORMAT_S16_LE;
    } else if (bits == 24) {
        config.format = PCM_FORMAT_S24_3LE;
    } else if (bits == 32) {
        config.format = PCM_FORMAT_S32_LE;
    } else {
        fprintf(stderr, "bit count '%u' not supported\n", bits);
        fclose(ctx->file);
        return -1;
    }

    ctx->pcm = pcm_open(cmd->card,
                        cmd->device,
                        cmd->flags,
                        &config);
    if (ctx->pcm == NULL) {
        fprintf(stderr, "failed to allocate memory for pcm\n");
        fclose(ctx->file);
        return -1;
    } else if (!pcm_is_ready(ctx->pcm)) {
        fprintf(stderr, "failed to open for pcm %u,%u\n", cmd->card, cmd->device);
        fclose(ctx->file);
        pcm_close(ctx->pcm);
        return -1;
    }

    return 0;
}

void ctx_free(struct ctx *ctx)
{
    if (ctx == NULL) {
        return;
    }
    if (ctx->pcm != NULL) {
        pcm_close(ctx->pcm);
    }
    if (ctx->file != NULL) {
        fclose(ctx->file);
    }
}

static int close = 0;

int play_sample(struct ctx *ctx);

void stream_close(int sig)
{
    /* allow the stream to be closed gracefully */
    signal(sig, SIG_IGN);
    close = 1;
}

void print_usage(const char *argv0)
{
    fprintf(stderr, "usage: %s file.wav [options]\n", argv0);
    fprintf(stderr, "options:\n");
    fprintf(stderr, "-D | --card   <card number>    The device to receive the audio\n");
    fprintf(stderr, "-d | --device <device number>  The card to receive the audio\n");
    fprintf(stderr, "-p | --period-size <size>      The size of the PCM's period\n");
    fprintf(stderr, "-n | --period-count <count>    The number of PCM periods\n");
    fprintf(stderr, "-i | --file-type <file-type >  The type of file to read (raw or wav)\n");
    fprintf(stderr, "-c | --channels <count>        The amount of channels per frame\n");
    fprintf(stderr, "-r | --rate <rate>             The amount of frames per second\n");
    fprintf(stderr, "-b | --bits <bit-count>        The number of bits in one sample\n");
    fprintf(stderr, "-M | --mmap                    Use memory mapped IO to play audio\n");
}


int main(int argc, const char **argv)
{
    struct cmd cmd;
    struct ctx ctx;

    if (argc < 2) {
        print_usage(argv[0]);
        return EXIT_FAILURE;
    }

    cmd_init(&cmd);
    if (cmd_parse_args(&cmd, argc - 1, &argv[1]) < 0) {
        return EXIT_FAILURE;
    }

    if (ctx_init(&ctx, &cmd) < 0) {
        return EXIT_FAILURE;
    }

    /* TODO get parameters from context */
    printf("playing '%s': %u ch, %u hz, %u bit\n",
           cmd.filename,
           cmd.config.channels,
           cmd.config.rate,
           cmd.bits);

    if (play_sample(&ctx) < 0) {
        ctx_free(&ctx);
        return EXIT_FAILURE;
    }

    ctx_free(&ctx);
    return EXIT_SUCCESS;
}

int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
                 char *param_name, char *param_unit)
{
    unsigned int min;
    unsigned int max;
    int is_within_bounds = 1;

    min = pcm_params_get_min(params, param);
    if (value < min) {
        fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,
                param_unit, min, param_unit);
        is_within_bounds = 0;
    }

    max = pcm_params_get_max(params, param);
    if (value > max) {
        fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,
                param_unit, max, param_unit);
        is_within_bounds = 0;
    }

    return is_within_bounds;
}

int sample_is_playable(const struct cmd *cmd)
{
    struct pcm_params *params;
    int can_play;

    params = pcm_params_get(cmd->card, cmd->device, PCM_OUT);
    if (params == NULL) {
        fprintf(stderr, "unable to open PCM %u,%u\n", cmd->card, cmd->device);
        return 0;
    }

    can_play = check_param(params, PCM_PARAM_RATE, cmd->config.rate, "sample rate", "hz");
    can_play &= check_param(params, PCM_PARAM_CHANNELS, cmd->config.channels, "sample", " channels");
    can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, cmd->bits, "bits", " bits");
    can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, cmd->config.period_size, "period size", "");
    can_play &= check_param(params, PCM_PARAM_PERIODS, cmd->config.period_count, "period count", "");

    pcm_params_free(params);

    return can_play;
}

int play_sample(struct ctx *ctx)
{
    char *buffer;
    int size;
    int num_read;

    size = pcm_frames_to_bytes(ctx->pcm, pcm_get_buffer_size(ctx->pcm));
    buffer = malloc(size);
    if (!buffer) {
        fprintf(stderr, "unable to allocate %d bytes\n", size);
        return -1;
    }

    /* catch ctrl-c to shutdown cleanly */
    signal(SIGINT, stream_close);

    do {
        num_read = fread(buffer, 1, size, ctx->file);
        if (num_read > 0) {
		if (pcm_writei(ctx->pcm, buffer,
			pcm_bytes_to_frames(ctx->pcm, num_read)) < 0) {
                fprintf(stderr, "error playing sample\n");
                break;
            }
        }
    } while (!close && num_read > 0);

    free(buffer);
    return 0;
}
that is also interesting to me, but where is a function to play just a .wav file by it's filename out of a proprietary source code, and how will the includes and the call have to look like, e.g.

Code: Select all

#include <cstring>
#include <whatever.h>

int main() {
   string filename;

   filename="/home/pi/sound/allsystemsworkperfectly.wav";   
   
   playwavfile(filename);  // <<<<<<<<<< ????
   
   return(0);
}
edit, test code simplified

and what will the compile parameters for Geany have to look like?

g++ -Wall -l?????? -L??????? -I??????? -o "%e" "%f" .... ?????

Return to “C/C++”