Page 1 of 2
How to use ALSA library ???
Posted: Tue Dec 07, 2021 2:38 pm
by Joris
Hi,
Can anyone help with using the ALSA library (goal is to use it on the Raspberry Pi, but that should also be a Linux part).
https://www.alsa-project.org/alsa-doc/a ... index.html
I've been searching, looking, looking and looking for source examples, but not one in PB (all in C or equivalent, which is not very helpfull to me).
I know that the ALSA library is very extensive, but I have no experience whatsoever with programming on Linux (but APIs on Windows).
There are basic commands that can be called in the terminal, such as
aplay, amidi, amixer and so on.
How do you use these in PB or for example, the one below from that RawMidi interface API ?
snd_rawmidi_info_get_subdevices_count()
Do these functions and commands become part of the PB program when compiling or does the ALSA library have to be installed separately (by the end user) ?
Do I need this :
Result = OpenLibrary(#Library, Filename$)
Or do you do this with:
ImportC : .... : EndImport
Thanks
Re: How to use ALSA library ???
Posted: Wed Dec 08, 2021 10:22 pm
by infratec
Nothing for the ALSA problem, but ...
OpenLibrary() is for DynamicLinkedLibrarie (.dll) or SharedObject (.so) files.
Import is for static .lib or .a files.
SInce ALSA is delivered as .so file, you need to write a wrapper with LoadLibrary()
Re: How to use ALSA library ???
Posted: Wed Dec 08, 2021 10:44 pm
by infratec
Something like that:
Code: Select all
Enumeration
#SND_RAWMIDI_STREAM_OUTPUT
#SND_RAWMIDI_STREAM_INPUT
EndEnumeration
PrototypeC.l Prototype_snd_card_next(*card)
PrototypeC.l Prototype_snd_rawmidi_info_alloca(*info)
PrototypeC.l Prototype_snd_rawmidi_info_set_stream(*info, device.l)
PrototypeC.l Prototype_snd_ctl_rawmidi_info (*ctl, *info)
PrototypeC.l Prototype_snd_rawmidi_info_get_subdevices_count(*info)
PrototypeC.l Prototype_snd_ctl_open(*ctl, name.p-utf8, mode.l)
PrototypeC Prototype_snd_ctl_close(*ctl)
Global AlsaLib.i
Global snd_card_next.Prototype_snd_card_next
Global snd_rawmidi_info_alloca.Prototype_snd_rawmidi_info_alloca
Global snd_rawmidi_info_set_stream.Prototype_snd_rawmidi_info_set_stream
Global snd_rawmidi_info_get_subdevices_count.Prototype_snd_rawmidi_info_get_subdevices_count
Global snd_ctl_open.Prototype_snd_ctl_open
Global snd_ctl_close.Prototype_snd_ctl_close
Procedure.i LoadAlsaLib()
If AlsaLib = 0
AlsaLib = OpenLibrary(#PB_Any, "libasound.so.2")
If AlsaLib
snd_card_next = GetFunction(AlsaLib, "snd_card_next")
snd_rawmidi_info_alloca = GetFunction(AlsaLib, "snd_rawmidi_info_alloca")
snd_rawmidi_info_set_stream = GetFunction(AlsaLib, "snd_rawmidi_info_set_stream")
snd_rawmidi_info_get_subdevices_count = GetFunction(AlsaLib, "snd_rawmidi_info_get_subdevices_count")
snd_ctl_open = GetFunction(AlsaLib, "snd_ctl_open")
snd_ctl_close = GetFunction(AlsaLib, "snd_ctl_close")
EndIf
EndIf
ProcedureReturn AlsaLib
EndProcedure
Procedure CloseAlsaLib()
If AlsaLib
CloseLibrary(AlsaLib)
AlsaLib = 0
EndIf
EndProcedure
Define *Info, *Ctl
Define.l card, err, iSub
Define name$
If LoadAlsaLib()
card = -1
err = snd_card_next(@card)
If Not err
If card >= 0
name$ = "hw:" + Str(card)
Debug "Name: " + name$
err = snd_ctl_open(@*ctl, name$, 0)
If err = 0
Debug "Ok"
EndIf
; snd_rawmidi_info_alloca(@*Info)
; snd_rawmidi_info_set_stream(*Info, #SND_RAWMIDI_STREAM_INPUT)
; iSub = snd_rawmidi_info_get_subdevices_count(*Info)
; If iSub > 0
; ;Debug Info\
; EndIf
Else
Debug "No soundcard found"
EndIf
EndIf
EndIf
Re: How to use ALSA library ???
Posted: Thu Dec 09, 2021 10:26 am
by Joris
infratec, great.
Yet, one question where do you get that name : "libasound.so.2"
In different folders (lib etc.) on my PI, I didn't find anything like alsa.so extention.
I need to start learning using those Prototypes (I remember GFA basic' had something similar... years ago).
At least I have a starting point now.
Thanks a thousand times infratec.
Re: How to use ALSA library ???
Posted: Thu Dec 09, 2021 11:37 am
by infratec
First you get the path of, for example, alsamixer:
Then you can use ldd to find against which libs it is linked:
Result:
linux-vdso.so.1 (0x00007ffe007de000)
libformw.so.6 => /usr/lib/x86_64-linux-gnu/libformw.so.6 (0x00007f0bbcc76000)
libmenuw.so.6 => /usr/lib/x86_64-linux-gnu/libmenuw.so.6 (0x00007f0bbcc6a000)
libpanelw.so.6 => /usr/lib/x86_64-linux-gnu/libpanelw.so.6 (0x00007f0bbcc63000)
libncursesw.so.6 => /lib/x86_64-linux-gnu/libncursesw.so.6 (0x00007f0bbcc29000)
libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f0bbcbfb000)
libasound.so.2 => /usr/lib/x86_64-linux-gnu/libasound.so.2 (0x00007f0bbcafa000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0bbc975000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f0bbc970000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0bbc94f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0bbc78e000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f0bbc784000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0bbccb7000)
The only lib which has to do with 'a' or 'sound' was: libasound.so.2
Since all this libs are inthe searchpath, you don't need a path before the name.
Re: How to use ALSA library ???
Posted: Thu Dec 09, 2021 1:22 pm
by Joris
And so I come (very close) to that result you posted before.
Code: Select all
AlsaLib = OpenLibrary(#PB_Any, "libasound.so.2")
If ExamineLibraryFunctions(AlsaLib)
While NextLibraryFunction()
Debug LibraryFunctionName()
Wend
EndIf
Yet, these naming is different from the ones listed in the alsa-help (and debugged) ?
snd_rawmidi_info (snd_rawmidi_t *rmidi, snd_rawmidi_info_t *info)
PrototypeC.l Prototype_snd_ctl_rawmidi_info (*ctl, *info)
???
PrototypeC.l Prototype_snd_card_next(*card)
What about that ?
(do prototypes don't have to 'map a function') ?
Else if correct, how do they then ?
Or maybe it's just a difference by the alsa version ?
Thanks again infratec.
Re: How to use ALSA library ???
Posted: Thu Dec 09, 2021 1:48 pm
by infratec
I don't know what you mean with 'map'.
A prototype is something which declares the return value and the parameters of a function.
The name has nothing to do with the real function name.
You create a variable of the type of a prototype and assign the address of the wanted function.
Also the name of this variable has nothing to do with the name of the real function.
But it makes sense to use the same name
Look at the code above and the help about prototypes.
Re: How to use ALSA library ???
Posted: Thu Dec 09, 2021 3:08 pm
by Joris
The PB-helpfile says : "Prototype allows to declare a type which will map a function."
If the name is not according the function, how does it assign the address of the wanted function ?
Thanks again.
Re: How to use ALSA library ???
Posted: Thu Dec 09, 2021 3:13 pm
by infratec
A prototype does not assign something.
The 'assigning' is done by:
Code: Select all
snd_card_next = GetFunction(AlsaLib, "snd_card_next")
You don't look long enough at my code above.
The process is:
Code: Select all
PrototypeC.l Prototype_snd_card_next(*card)
Global snd_card_next.Prototype_snd_card_next
snd_card_next = GetFunction(AlsaLib, "snd_card_next")
Then you can use it:
Debug snd_card_next(*APointer)
Re: How to use ALSA library ???
Posted: Fri Dec 10, 2021 10:23 am
by Joris
I understand now how to set it up. Thanks for learning me this.
Only have to figure out what kind of variables and structeres have to be used in those prototypes.
I saw someone here had once made a parser for ALSA, but that download is gone. A pitty.
infratec thanks again.
Re: How to use ALSA library ???
Posted: Fri Dec 10, 2021 10:38 am
by infratec
Re: How to use ALSA library ???
Posted: Sat Dec 11, 2021 11:08 am
by Joris
infratec (or anyone else),
Figuring out the kind of variables and structeres...
How do I convert this in a PB version :
snd_card_get_longname(int card, char ** name)
I tried it compared to other functions you already gave in the sample above like :
snd_ctl_open (snd_ctl_t ** ctlp, const char * name, int mode)
Became this :
PrototypeC.l Prototype_snd_ctl_open(*ctl, name.p-utf8, mode.l)
So I tried this one :
PrototypeC.l Prototype_
snd_card_get_longname(idx.l, name.p-utf8)
But I don't get it good, as to me, I should be able to read the name with Peeks() thus it should be a adress not a character.
Those definitions in C++ are always so confusing : "why making it simple if it can be made difficult ?"
More of those confusing things :
typedef struct _snd_rawmidi_info snd_rawmidi_info_t
What kind of structure is that ? Where or what are those fileds ?
Yeah "why making it simple if... ?"
Thanks
Re: How to use ALSA library ???
Posted: Sat Dec 11, 2021 10:12 pm
by infratec
The parameter is a pointer to a pointer.
This is not directly doable in PB.
You can try this:
Code: Select all
PrototypeC.l Prototype_snd_card_get_longname(card.l, *namePtr)
Global snd_card_get_longname_.Prototype_snd_card_get_longname
snd_card_get_longname_ = GetFunction(AlsaLib, "snd_card_get_longname")
Procedure.s snd_card_get_longname(card.l)
Protected *Ptr, Result$
If snd_card_get_longname_(card, @*ptr) = 0
Result$ = PeekS(*Ptr, -1, #PB_UTF8)
FreeMemory(*Ptr) ; maybe this is not working
EndIf
ProcedureReturn Result$
EndProcedure
I use a help procedure to get the name.
But I can not test it. It is 'programmed' blind.
Re: How to use ALSA library ???
Posted: Sat Dec 11, 2021 10:52 pm
by mk-soft
Perhaps so ...
Code: Select all
PrototypeC.l Prototype_snd_card_get_longname(card.l, *namePtr)
Global snd_card_get_longname_.Prototype_snd_card_get_longname
snd_card_get_longname_ = GetFunction(AlsaLib, "snd_card_get_longname")
Procedure.s snd_card_get_longname(card.l)
Protected *Ptr.integer, Result$
If snd_card_get_longname_(card, *ptr) = 0
Result$ = PeekS(*Ptr\i, -1, #PB_UTF8)
;FreeMemory(*Ptr\i) ; This not working
EndIf
ProcedureReturn Result$
EndProcedure
Re: How to use ALSA library ???
Posted: Sun Dec 12, 2021 11:30 am
by Joris
Hi infratec and mk-soft,
Tried both source, but both give an error at the same position :
If snd_card_get_longname_(card, @*ptr) = 0 ;===> [ERROR] Invalid memory access.
If snd_card_get_longname_(card, *ptr) = 0 ;===> [ERROR] Invalid memory access.
debug snd_card_get_longname(0) ;1
The same error with 1.
Before I had tried by myself this :
If snd_card_get_longname(0, lname$)=0 ;===>no error
Debug lname$ :===> this gave me a number
;Debug PeekS(@lname$) ;===> I don't know if this is the correct manner, nothing useable.
EndIf
I hope someone can find this out, I'll keep on experimenting a while.
Thanks