How to use ALSA library ???

Linux specific forum
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

How to use ALSA library ???

Post 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
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to use ALSA library ???

Post 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()
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to use ALSA library ???

Post 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
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: How to use ALSA library ???

Post 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.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to use ALSA library ???

Post by infratec »

First you get the path of, for example, alsamixer:

Code: Select all

which alsamixer
Then you can use ldd to find against which libs it is linked:

Code: Select all

ldd /usr/bin/alsamixer
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.
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: How to use ALSA library ???

Post 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.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to use ALSA library ???

Post 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 :wink:

Look at the code above and the help about prototypes.
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: How to use ALSA library ???

Post 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.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to use ALSA library ???

Post 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. :wink:

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)
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: How to use ALSA library ???

Post 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.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to use ALSA library ???

Post by infratec »

Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: How to use ALSA library ???

Post 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 ?" :wink:

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
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to use ALSA library ???

Post 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.
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How to use ALSA library ???

Post 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
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: How to use ALSA library ???

Post 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
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
Post Reply