ALSA in C++ - Making the minimal working code - c++

Topic
I would like to make the minimal working code to generate any kind of PCM sound using ALSA in C++ for a Linux computer.
Setup
I'm coding in C++ on Code::Blocks with Ubuntu 20.04.
Background
I used to make simple Arduino UNO programs doing sound processing and just needed to play raw PCM samples.
Issues
ALSA Project's Website is not very easy to understand.
I looked at c - ALSA tutorial required to find out that many links are expired.
I copy pasted the code of the minimal PCM example in C directly into a empty Code::Blocks project and I got that error:
||=== Build: Release in Test (compiler: GNU GCC Compiler) ===|
Test/main.cpp|5|fatal error: ../include/asoundlib.h: No such file or directory|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
Right in the first line of code which is #include "../include/asoundlib.h".
I'm guessing that the issue could be because I have to download something or add a linker for the compiler.
But I also think it may be an issue of C to C++ conversion meaning that this works in C but not in C++.
Do I have to add a linker for the compiler or download something to make the code working?
Then I looked on ALSA library and downloaded alsa-lib-1.2.3.tar.bz2.
I got an archive that looked to have the right things but I don't know how to handle it.
Then I found usr/include/sound/asound.h on my computer. It looks to be part of ALSA but when I changed the code to use it, it spat out a bunch of errors when used.
The code looks like following now:
/*
* This extra small demo sends a random samples to your speakers.
*/
#include <sound/asound.h>
#include <cstdio>
static char *device = "default"; /* playback device */
unsigned char buffer[16*1024]; /* some random data */
int main(void)
{
int err;
unsigned int i;
snd_pcm_t *handle;
snd_pcm_sframes_t frames;
for (i = 0; i < sizeof(buffer); i++)
buffer[i] = random() & 0xff;
if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
if ((err = snd_pcm_set_params(handle,
SND_PCM_FORMAT_U8,
SND_PCM_ACCESS_RW_INTERLEAVED,
1,
48000,
1,
500000)) < 0) { /* 0.5sec */
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
for (i = 0; i < 16; i++) {
frames = snd_pcm_writei(handle, buffer, sizeof(buffer));
if (frames < 0)
frames = snd_pcm_recover(handle, frames, 0);
if (frames < 0) {
printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
break;
}
if (frames > 0 && frames < (long)sizeof(buffer))
printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames);
}
/* pass the remaining samples, otherwise they're dropped in close */
err = snd_pcm_drain(handle);
if (err < 0)
printf("snd_pcm_drain failed: %s\n", snd_strerror(err));
snd_pcm_close(handle);
return 0;
}
And the errors are like that:
||=== Build: Release in Test (compiler: GNU GCC Compiler) ===|
Test/main.cpp|6|warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]|
Test/main.cpp||In function ‘int main()’:|
Test/main.cpp|12|error: ‘snd_pcm_t’ was not declared in this scope; did you mean ‘snd_pcm_info’?|
Test/main.cpp|12|error: ‘handle’ was not declared in this scope|
Test/main.cpp|16|error: ‘SND_PCM_STREAM_PLAYBACK’ was not declared in this scope; did you mean ‘SNDRV_PCM_STREAM_PLAYBACK’?|
Test/main.cpp|16|error: ‘snd_pcm_open’ was not declared in this scope; did you mean ‘snd_pcm_info’?|
Test/main.cpp|17|error: ‘snd_strerror’ was not declared in this scope|
||error: %s\n", snd_strerror(err));|
Test/main.cpp|21|error: ‘SND_PCM_FORMAT_U8’ was not declared in this scope; did you mean ‘SNDRV_PCM_FORMAT_U8’?|
Test/main.cpp|22|error: ‘SND_PCM_ACCESS_RW_INTERLEAVED’ was not declared in this scope; did you mean ‘SNDRV_PCM_ACCESS_RW_INTERLEAVED’?|
Test/main.cpp|20|error: ‘snd_pcm_set_params’ was not declared in this scope; did you mean ‘snd_pcm_sw_params’?|
Test/main.cpp|27|error: ‘snd_strerror’ was not declared in this scope|
||error: %s\n", snd_strerror(err));|
Test/main.cpp|31|error: ‘snd_pcm_writei’ was not declared in this scope|
Test/main.cpp|33|error: ‘snd_pcm_recover’ was not declared in this scope|
Test/main.cpp|35|error: ‘snd_strerror’ was not declared in this scope|
Test/main.cpp|42|error: ‘snd_pcm_drain’ was not declared in this scope|
Test/main.cpp|44|error: ‘snd_strerror’ was not declared in this scope|
Test/main.cpp|45|error: ‘snd_pcm_close’ was not declared in this scope|
||=== Build failed: 17 error(s), 1 warning(s) (0 minute(s), 0 second(s)) ===|

Follow these steps:
Install the ALSA development package, or make sure it is already installed. The name depends on your distribution. In my case (OpenSUSE Tumbleweed) it is alsa-devel. This will install the file asoundlib.h under the directory /usr/include/alsa.
Change the line in your code from #include "../include/asoundlib.h" to #include <alsa/asoundlib.h>. Notice the angular brackets instead of quotation marks.
The library which you want to link against is named libsound.so, so compile the program with a command like gcc -Wall pcm_min.c -lasound -o pcm_min
Run the program: ./pcm_min

Related

clang-tidy fails bugprone check

I'm experimenting with clang-tidy using the following file:
#include <stdio.h>
int main(int argc, char **argv)
{
int i=2; int j=1;
if (argc = 5) { return 2; }
while (i<argc) { j++; }
return 0;
}
I aim to detect the infinite loop with:
$ clang-tidy -checks=bugprone-infinite-loop main.c
but all that clang-tidy finds is the = instead of == thing:
Error while trying to load a compilation database:
Could not auto-detect compilation database for file "main.c"
No compilation database found in /home/oren or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or directory
json-compilation-database: Error while opening JSON database: No such file or directory
Running without flags.
1 warning generated.
/home/oren/main.c:6:11: warning: using the result of an assignment as a condition without parentheses [clang-diagnostic-parentheses]
if (argc = 5) { return 2; }
~~~~ ^ ~
( == )
/home/oren/main.c:6:11: note: place parentheses around the assignment to silence this warning
/home/oren/main.c:6:11: note: use '==' to turn this assignment into an equality comparison
You are using a feature from a yet unreleased version of LLVM (10.0.0).
On my system (windows) your file works as expected:
>clang-tidy10 -checks=bugprone-infinite-loop infloop.c --
1 warning generated.
\infloop.c:6:5: warning: this loop is infinite; none of its con
dition variables (i, argc) are updated in the loop body [bugprone-infinite-loop]
while (i<argc) { j++; }
^
The only modification I did on the file is removing the unecessary #include. I also added -- (double dash) to the command to get rid of missing compilation database errors. I am using a prebuilt binary from https://llvm.org/builds/
My best guess here is that you are using an older build of clang-tidy where this is not detected. For reference my version is 10.0.0-e20a1e486e1, you can see yours by running:
>clang-tidy --version
I'd also check if you are actually running the check(s) you are expected to run via:
$ clang-tidy -checks=bugprone-infinite-loop main.c --list-checks
P.S. The warning message you got at first was clang-diagnostic based, this has nothing to do with clang-tidy but rather with clang compilation

C++: <sys/sysctl.h> fails to declare functions CTL_HW and HW_NCPU

Aloha all!
I'm working with the following script (which I did not write). This is one of many files I've been working on modifying to initiate a build/make on Linux.
Everything I've found online suggests that sys/sysctl.h should properly declare these functions:
CTL_HW and HW_NCPU
However, running the following (called "machineInfo.cpp"):
#include "machineInfo.h"
#include <sys/sysctl.h>
#include <linux/sysctl.h>
#include <cstdio>
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
int StMachineInfo::numProcs(void) {
int numCPU = 0;
int nprocs;
size_t len = sizeof(nprocs);
static int mib[2] = { CTL_HW, HW_NCPU };
/* get the number of CPUs from the system */
sysctl(mib, 2, &numCPU, &len, NULL, 0);
if( numCPU < 1 )
{
mib[1] = HW_NCPU;
if (sysctl (mib, ARRAY_SIZE(mib), &nprocs, &len, NULL, 0) == 0 && len == sizeof (nprocs) && 0 < nprocs)
numCPU = nprocs;
if( numCPU < 1 )
numCPU = 1;
}
return numCPU;
}
...results in the following error output:
g++ -c machineInfo.cpp
machineInfo.cpp: In function ‘int StMachineInfo::numProcs()’:
machineInfo.cpp:14:24: error: ‘CTL_HW’ was not declared in this scope
static int mib[2] = { CTL_HW, HW_NCPU };
^
machineInfo.cpp:14:32: error: ‘HW_NCPU’ was not declared in this scope
static int mib[2] = { CTL_HW, HW_NCPU };
^
Makefile:33: recipe for target 'machineinfo.o' failed
make: *** [machineinfo.o] Error 1
Is there something wrong with the code itself? Or do I need to #include another header? I've experimented with this and Googled for a couple of hours, to no avail.
Many thanks,
Sean
I believe the problem here is that sysctl does not have a glibc wrapper on Linux. By my best understanding, those constants are only available on BSD.
I'd be happy to be proven wrong, as I'm trying to understand if this uname -p behavior could ever work on Linux.

How to handle eof() in platform independent code? C++

I have a c++ code where, I'm redirecting the stdout to a string. The code should be platform independent. In windows works fine, but under linux it doesn't builds.
Here is my code:
#include <fcntl.h>
int outBuffer[2];
int orgStdOutBuffer;
std::string stringBuff;
enum PIPES {READ, WRITE};
orgStdOutBuffer = dup(fileno(stdout));
outBuffer[READ] = 0;
outBuffer[WRITE] = 0;
if (_pipe(mStdOutBuffer, 65535, O_BINARY) == -1) {
return false;
}
fflush(stdout);
dup2(outBuffer[WRITE], fileno(stdout));
The problem is where I'm checking the end of the pipe:
if (!eof(outBuffer[READ])) {
stdOutBufferSize = read(outBuffer[READ], &(*stringBuff.begin()), buffSize);
}
Under linux gives the following error:
'eof' was not declared in this scope
'O_BINARY' was not declared in this scope
Can anybody help how can I make this code run under linux?

D Programming Language Tutorial - Area of a Circle - Error: Undefined identifier toFloat

I just started learning D. When I build this tutorial file: http://www.dprogramming.com/CA_prompt.html
(directly from the D site), I get these errors:
circle.d|24|Error: template std.stdio.readln cannot deduce function from argument types !()(File), candidates are:|
/usr/share/dmd/src/phobos/std/stdio.d|2818| std.stdio.readln(S = string)(dchar terminator = '\x0a') if (isSomeString!S)|
/usr/share/dmd/src/phobos/std/stdio.d|2851| std.stdio.readln(C)(ref C[] buf, dchar terminator = '\x0a') if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum))|
/usr/share/dmd/src/phobos/std/stdio.d|2858| std.stdio.readln(C, R)(ref C[] buf, R terminator) if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) && isBidirectionalRange!R && is(typeof(terminator.front == (dchar).init)))|
circle.d|25|Error: undefined identifier toFloat|
||=== Build failed: 5 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
Any ideas as to why?
Thanks in advance!
EDIT:
So I end up with this:
import std.conv;
import std.stdio;
import std.string;
import std.math;
const real pi = std.math.PI;
void main()
{
try
{
const char [] chRadius;
float r;
writef("Enter the radius: ");
chRadius = chomp(readln());
r = to!float(chRadius);
writefln("Circle area = %f", pi*r*r);
}
catch (Exception e)
{
writefln("catch %s", e.toString());
}
}
The build message is this:
||=== Build: Debug in Area of a Circle (compiler: Digital Mars D Compiler) ===|
circle.d|24|Error: cannot modify const expression chRadius|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
EDIT 2: Changed const char[] to string, and everything works! Thanks!
As #miken32 mentioned, that tutorial is pretty out of date -- the source given will need to be modified for a modern d compiler:
Call readln without arguments to read from stdin. You can use File.readln to read from a file handle, but in this case just use chRadius = chomp(readln())
use string instead of char[] (though you could also use const(char)[])
use to!float instead of toFloat. The !float indicates that the type float is a compile time argument to the generic function to
You've got some compilation errors because this tuto. is based on D1 (old, unmaintained, obsolete version of the lang.) and not D2 (actively developed and widely used version of the lang.)
If you want to compile this then setup D1 v 1.076 (bottom of the page).

Problem with LZO

So I am trying to use LZO in my application. Here is how I have included it:
#include "lzoconf.h"
#include "lzodefs.h"
#include "lzo1x.h"
/* portability layer */
static const char *progname = NULL;
#define WANT_LZO_MALLOC 1
#define WANT_XMALLOC 1
#include "portab.h"
Then in the application I do:
if (lzo_init() != LZO_E_OK)
{
printf("internal error - lzo_init() failed !!!\n");
printf("(this usually indicates a compiler bug - try recompiling\nwithout optimizations, and enable '-DLZO_DEBUG' for diagnostics)\n");
return 4;
}
It compiles ok. No errors or warnings during compilation.
When I try to run my application though, there are two errors:
/home/richard/client/src/portab.h:145: undefined reference to `__lzo_align_gap'
Which points at this line in portab.h:
if (__lzo_align_gap(p, (lzo_uint) sizeof(lzo_align_t)) != 0)
{
printf("%s: C library problem: malloc() returned mis-aligned pointer!\n", progname);
exit(1);
}
return p;
And in my application:
/home/richard/client/src/main.cc:108: undefined reference to `__lzo_init_v2'
Which points to:
if (lzo_init() != LZO_E_OK)
{
printf("internal error - lzo_init() failed !!!\n");
printf("(this usually indicates a compiler bug - try recompiling\nwithout optimizations, and enable '-DLZO_DEBUG' for diagnostics)\n");
return 4;
}
I have all the header files inside my source directory:
config.h
lzo1x.h
lzoconf.h
lzodefs.h
miniacc.h
portab.h
portab_a.h
What am I doing wrong?
I am compiling my application in Ubuntu 10.10 in Anjuta ide.
Headers is not enough, you need to link to the libraries. Have you read the documentation?