Recent

Author Topic: Help with Alsa C conversion.  (Read 8519 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: Help with Alsa C conversion.
« Reply #15 on: July 29, 2020, 03:57:40 pm »
marcov is saying that as long as the used library does not require you to free memory passed back from the library or to free memory passed into the library then you do not need cmem. A shared memory manager is only required if memory allocated in module A is freed in module B. Using memory allocated in module A in module B has never been a problem.

That seems reasonable, but my recollection is that- certainly at one time- if you wanted to do things like merge a menu defined (in a form) in a plugin into the main form, then you had to use cmem. I might have reason to play with this again at some point, in which case I'll report back.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Help with Alsa C conversion.
« Reply #16 on: July 29, 2020, 04:20:31 pm »
Because here you're mixing memory allocations of the different involved modules. It's already enough if module A tries to deallocate a string that was allocated in module B (and with reference counting that can happen rather quickly)

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: Help with Alsa C conversion.
« Reply #17 on: July 29, 2020, 04:33:42 pm »
Right. That was the additional case that I tried to highlight several messages ago.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

AL

  • Sr. Member
  • ****
  • Posts: 256
Re: Help with Alsa C conversion.
« Reply #18 on: July 29, 2020, 05:36:40 pm »
@warfley : Your code produce a sigsev at the freemem even using Cmem.
I did put Cmem as the first uses in lpr and in the unit.

I am working on the capture part now, I will surely need some guidance on this also.
Will post my work later.
Laz 3.1, fpc 3.2.2, Win10
Laz 3.1  fpc 3.2.2, MacOS Monterey running on VMWare/Win 10
Laz 3.1  fpc 3.2.2 Ubuntu 20.04

TRon

  • Hero Member
  • *****
  • Posts: 2398
Re: Help with Alsa C conversion.
« Reply #19 on: July 29, 2020, 06:09:17 pm »
@warfley : Your code produce a sigsev at the freemem even using Cmem.
I did put Cmem as the first uses in lpr and in the unit.
Show us some code, or it didn't happen  :D

Code: Pascal  [Select][+][-]
  1. program hinting;
  2.  
  3. // https://forum.lazarus.freepascal.org/index.php/topic,50782.15.html
  4.  
  5. {$MODE OBJFPC}{$H+}
  6.  
  7. uses
  8.   cmem, baseunix, sysutils, asoundlib;
  9.  
  10. procedure dohop;
  11. var
  12.   hints : ppchar;
  13.   err   : cint;
  14.   n     : ppchar;
  15.   name  : pchar;
  16.   desc  : pchar;
  17.   ioid  : pchar;
  18. begin
  19.   err := snd_device_name_hint(-1, 'pcm', @hints);
  20.   if (err = 0) then
  21.   begin
  22.     n := hints;
  23.     while n^ <> nil do
  24.     begin
  25.       name := snd_device_name_get_hint(n^, 'NAME');
  26.       desc := snd_device_name_get_hint(n^, 'DESC');
  27.       ioid := snd_device_name_get_hint(n^, 'IOID');
  28.  
  29.       if Assigned(name) and (name <> 'null') then
  30.       begin
  31.         WriteLn('       Name of device : ', name);
  32.         WriteLn('Description of device : ', desc);
  33.         WriteLn('   I/O type of device : ', ioid);
  34.         WriteLn;
  35.       end;
  36.  
  37.       if Assigned(name) then CMem.Free(name);
  38.       if Assigned(desc) then CMem.Free(desc);
  39.       if Assigned(ioid) then CMem.Free(ioid);
  40.  
  41.       inc(n);
  42.     end;
  43.  
  44.     // Free hints buffer
  45.     snd_device_name_free_hint(PPointer(hints));
  46.   end
  47.   else WriteLn('Unable to obtain device name hints');
  48. end;
  49.  
  50. begin
  51.   dohop;
  52. end.
  53.  

I've ran that on one of my pi/s:
Code: [Select]
./hinting
       Name of device : default:CARD=ALSA
Description of device : bcm2835 ALSA, bcm2835 ALSA
Default Audio Device
   I/O type of device : Output

       Name of device : sysdefault:CARD=ALSA
Description of device : bcm2835 ALSA, bcm2835 ALSA
Default Audio Device
   I/O type of device : Output

       Name of device : dmix:CARD=ALSA,DEV=0
Description of device : bcm2835 ALSA, bcm2835 ALSA
Direct sample mixing device
   I/O type of device : Output

       Name of device : dmix:CARD=ALSA,DEV=1
Description of device : bcm2835 ALSA, bcm2835 IEC958/HDMI
Direct sample mixing device
   I/O type of device : Output

       Name of device : dmix:CARD=ALSA,DEV=2
Description of device : bcm2835 ALSA, bcm2835 IEC958/HDMI1
Direct sample mixing device
   I/O type of device : Output

       Name of device : dsnoop:CARD=ALSA,DEV=0
Description of device : bcm2835 ALSA, bcm2835 ALSA
Direct sample snooping device
   I/O type of device : Output

       Name of device : dsnoop:CARD=ALSA,DEV=1
Description of device : bcm2835 ALSA, bcm2835 IEC958/HDMI
Direct sample snooping device
   I/O type of device : Output

       Name of device : dsnoop:CARD=ALSA,DEV=2
Description of device : bcm2835 ALSA, bcm2835 IEC958/HDMI1
Direct sample snooping device
   I/O type of device : Output

       Name of device : hw:CARD=ALSA,DEV=0
Description of device : bcm2835 ALSA, bcm2835 ALSA
Direct hardware device without any conversions
   I/O type of device : Output

       Name of device : hw:CARD=ALSA,DEV=1
Description of device : bcm2835 ALSA, bcm2835 IEC958/HDMI
Direct hardware device without any conversions
   I/O type of device : Output

       Name of device : hw:CARD=ALSA,DEV=2
Description of device : bcm2835 ALSA, bcm2835 IEC958/HDMI1
Direct hardware device without any conversions
   I/O type of device : Output

       Name of device : plughw:CARD=ALSA,DEV=0
Description of device : bcm2835 ALSA, bcm2835 ALSA
Hardware device with all software conversions
   I/O type of device : Output

       Name of device : plughw:CARD=ALSA,DEV=1
Description of device : bcm2835 ALSA, bcm2835 IEC958/HDMI
Hardware device with all software conversions
   I/O type of device : Output

       Name of device : plughw:CARD=ALSA,DEV=2
Description of device : bcm2835 ALSA, bcm2835 IEC958/HDMI1
Hardware device with all software conversions
   I/O type of device : Output

       Name of device : default:CARD=vc4hdmi
Description of device : vc4-hdmi,
Default Audio Device
   I/O type of device : Output

       Name of device : sysdefault:CARD=vc4hdmi
Description of device : vc4-hdmi,
Default Audio Device
   I/O type of device : Output

       Name of device : front:CARD=vc4hdmi,DEV=0
Description of device : vc4-hdmi,
Front speakers
   I/O type of device : Output

       Name of device : iec958:CARD=vc4hdmi,DEV=0
Description of device : vc4-hdmi,
IEC958 (S/PDIF) Digital Audio Output
   I/O type of device : Output

       Name of device : dmix:CARD=vc4hdmi,DEV=0
Description of device : vc4-hdmi,
Direct sample mixing device
   I/O type of device : Output

       Name of device : dsnoop:CARD=vc4hdmi,DEV=0
Description of device : vc4-hdmi,
Direct sample snooping device
   I/O type of device : Output

       Name of device : hw:CARD=vc4hdmi,DEV=0
Description of device : vc4-hdmi,
Direct hardware device without any conversions
   I/O type of device : Output

       Name of device : plughw:CARD=vc4hdmi,DEV=0
Description of device : vc4-hdmi,
Hardware device with all software conversions
   I/O type of device : Output

AL

  • Sr. Member
  • ****
  • Posts: 256
Re: Help with Alsa C conversion.
« Reply #20 on: July 30, 2020, 02:00:50 am »
Is there a way to increase microphone gain in ALSA?
I am using a Logitec USB on Ubuntu 20.04 and I need to be very close to the mic to record properly.
Thanks
Laz 3.1, fpc 3.2.2, Win10
Laz 3.1  fpc 3.2.2, MacOS Monterey running on VMWare/Win 10
Laz 3.1  fpc 3.2.2 Ubuntu 20.04

AL

  • Sr. Member
  • ****
  • Posts: 256
Re: Help with Alsa C conversion.
« Reply #21 on: July 30, 2020, 03:21:33 am »
Another question,  I would like to use the no Block version which uses threads.
Any hints on using this command:
Code: C  [Select][+][-]
  1.     if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE, block ? 0 : SND_PCM_NONBLOCK)) < 0) {
  2.         printf("Record open error: %s\n", snd_strerror(err));
  3.         return 0;

So far my code for capture is this:

P
Code: Pascal  [Select][+][-]
  1. Procedure StartRecording ;
  2. Const Buffer_Frames = NBPoints;  // in Main   =16384
  3. LABEL DoItAgain ;
  4.  
  5. Var i,err    : Integer;
  6.     //Samplerate     : Int32 = 8192 ; defined in Main
  7.     buffer           : Pchar ;
  8.  // Capture_handle   : Psnd_pcm_t ;  // declared as global to unit
  9.     hw_params        : Psnd_pcm_hw_params_t ;
  10.     format           : snd_pcm_format_t = SND_PCM_FORMAT_S16_LE ;  // 16 bits signed little endian
  11.     direction        : integer = 0 ;
  12.     //Channels       : int32 = 1 ; //mono    In Main
  13. begin
  14.   new(Capture_handle) ;
  15.   new(hw_params) ;
  16.  // volume adjust
  17.  //snd_mixer_selem_id_set_index(sid, 100);
  18. //snd_mixer_selem_id_set_name(sid, Pchar(deviceTable[MainForm.CBListDevices.itemIndex].iname));
  19.  
  20.                                                                                                                         //originally 0
  21.   err := snd_pcm_open(@capture_handle,Pchar(deviceTable[MainForm.CBListDevices.itemIndex].iname),SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK)  ;
  22.   If err < 0 then begin PostError('Error opening PCM') ; Exit ;end;
  23.  
  24.   err := snd_pcm_hw_params_malloc (@hw_params)  ;
  25.  
  26.   If err < 0 then begin PostError('Error hwparams'); Exit ;end;
  27.  
  28.   err := snd_pcm_hw_params_any (capture_handle, hw_params) ;
  29.   if err< 0 then begin PostError('Cannot initialize hardware parameter structure') ; Exit ; end ;
  30.                                                                   // SND_PCM_ACCESS_MMAP_NONINTERLEAVED
  31.   err := snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
  32.   if err < 0 then begin PostError('Cannot access PCM type');Exit;end;
  33.  
  34.   err := snd_pcm_hw_params_set_format (capture_handle, hw_params, format) ;
  35.   if err < 0 then begin Posterror('Cannot set format') ; Exit; end;
  36.  
  37.   err := snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, @samplerate, @direction);
  38.   if err < 0 then begin Posterror('Cannot set rate') ; Exit ; end;
  39.  
  40.   err := snd_pcm_hw_params_set_channels (capture_handle, hw_params, channels) ;   // 1 channel = mono
  41.   if err < 0 then begin PostError('Cannot set channel count') ; Exit ; end;
  42.  
  43.   err := snd_pcm_hw_params (capture_handle, hw_params) ;
  44.   if err < 0 then Begin PostError('Cannot set parameters') ; Exit ; end ;
  45.  
  46.   snd_pcm_hw_params_free (hw_params);
  47.  
  48.   err := snd_pcm_prepare (capture_handle) ;
  49.  
  50.   if err < 0 then begin PostError('Cannot prepare audio interface for use'); Exit ; end;
  51.  
  52.   buffer := malloc (Buffer_Frames * snd_pcm_format_width(format) DIV 8 * Channels);
  53.  // showmessage('Buffer allocated');
  54.  
  55. DoItAgain:
  56.   snd_pcm_wait(capture_handle, 2000);
  57.  
  58.   err := snd_pcm_readi (capture_handle, buffer, buffer_frames);
  59.  
  60.   if err <> buffer_frames then
  61.   begin
  62.         PostError ('Read from audio interface failed. Error = '+inttostr(err));
  63.  
  64. //*****************error -11 is reported here ************
  65.         exit ;
  66.   end
  67.   else
  68.   begin     //we have a full buffer
  69.    //    ShowMessage('Read successfull');
  70.    // here I need to transfer the buffer in the process buffer
  71.  
  72.    FillWord(SavedFrameData,length(SavedFrameData),0);  // remove garbage
  73.    move(buffer^,savedFrameData,buffer_frames*2) ;// CopyMemory(@savedFrameData, @buffer, buffer_frames*2 );     // 2 bytes per frame
  74.   Showmessage('Buffer copied') ;
  75.       // Find the max value
  76.        gMax := 0 ;
  77.        gMaxIndex := 0 ;
  78.        For i := 0 to  length(SavedFrameData)-1 do
  79.         begin
  80.          if abs(SavedFrameData[i])> gmax then       // use only positives values
  81.          begin
  82.           gMax := Abs( SavedFrameData[i]);
  83.           gMaxIndex := i ;
  84.          End;
  85.         End;
  86.         PostError('Gmax ' + inttostr(gmax));
  87.        showmessage('gMAx ' + inttostr(gmax)) ;
  88.        If gMax > gSensitivity then        // Check if level is higher than sensitivity set level
  89.         begin
  90.              MainForm.Timer1.Enabled := False ;      // stop visual buffer
  91.              MainForm.ProgressBar1.Position := 0;
  92.              MainForm.ProgressBar1.Update ;
  93.              MainForm.RBdataReady.checked := true ;     // set an event to draw graphs
  94.  
  95.         end   // Max > sensivity
  96.         else
  97.         begin
  98.          MainForm.ProgressBar1.Position := 0;
  99.          MainForm.ProgressBar1.Update ;
  100.          goto DoItAgain ;
  101.         end;
  102.       End ;    // end buffer complet
  103.       begin
  104.        MainForm.ProgressBar1.Position := 0;
  105.        MainForm.ProgressBar1.Update ;
  106.        goto DoItAgain ;
  107.       end;
  108.  
  109.     Processing := False   ;
  110.     free(Buffer) ;     // should it be free or freemem?
  111.    //showmessage('Buffer freed') ;
  112.    //snd_pcm_close (Capture_handle);
  113.   // ShowMessage( 'audio interface closed');
  114. // if assigned(capture_handle) then free(capture_handle) ;
  115. //  if assigned(hw_params) then free(hw_params) ;
  116. end;      
     

Still very preliminary, adapted from a C code,
It does work when I do not use the NONBLOCK parameter, but it freeze the GUI until finished.
I have added the Uses Cthreads but the 'magic' did not happened.
I guess there is a little more to it.
Laz 3.1, fpc 3.2.2, Win10
Laz 3.1  fpc 3.2.2, MacOS Monterey running on VMWare/Win 10
Laz 3.1  fpc 3.2.2 Ubuntu 20.04

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: Help with Alsa C conversion.
« Reply #22 on: July 30, 2020, 03:37:30 am »
You need to create a subclass of TThread class and do your magick in your subclass Execute method.

TRon

  • Hero Member
  • *****
  • Posts: 2398
Re: Help with Alsa C conversion.
« Reply #23 on: July 30, 2020, 06:15:51 am »
Another question,  I would like to use the no Block version which uses threads.
Which isn't any of your concern as the ALSA library does that. Of course it does have some implications such as some calls will return immediately without waiting.

Code: Pascal  [Select][+][-]
  1.   new(Capture_handle) ;
Why ?

Code: Pascal  [Select][+][-]
  1.   new(hw_params) ;
Why ?

Especially since you are using snd_pcm_hw_params_malloc, as it should.

Later on your code reads:
Code: Pascal  [Select][+][-]
  1. // if assigned(hw_params) then free(hw_params) ;
And that will throw you an error.

Use snd_pcm_hw_params_free() instead.

Code: Pascal  [Select][+][-]
  1. buffer := malloc (Buffer_Frames * snd_pcm_format_width(format) DIV 8 * Channels);
Although it can't hurt, but why not using FreePascal's memory functions here instead of cmem ?

cmem should only be used in case you need to free memory that was allocated by the c-library or in case the c-library free's your memory.

Quote
//*****************error -11 is reported here ************
Actually that is EAGAIN, see https://www.freepascal.org/docs-html/rtl/baseunix/esyseagain.html

Meaning that your buffer wasn't fully saturated and you need to make another call to read.


Code: Pascal  [Select][+][-]
  1. Showmessage('Buffer copied') ;
Better write something to a memo or some other method of outputting.

Code: Pascal  [Select][+][-]
  1.              MainForm.Timer1.Enabled := False ;      // stop visual buffer
using a timer ? To do what exactly ? Note that using a timer could screw things up for you considerably when used in combination with ALSA.

Code: Pascal  [Select][+][-]
  1.  goto DoItAgain ;
... well... i shouldn't have to go into that discussion as some members seem to think it is a perfectly valid method of using goto as long as the code is readable... in my book it is unnecessary evil which has no place at all in Pascal code.

I believe that in the particular case of your code a simple while true do begin (code) end, using continue and break should be able to do the trick as well. But I also believe your loop is wrong (see EAGAIN).

Code: Pascal  [Select][+][-]
  1. free(Buffer) ;     // should it be free or freemem?
  2.  
cmem.free since you allocated it with cmem.malloc.

Quote
It does work when I do not use the NONBLOCK parameter, but it freeze the GUI until finished.
Yeah, no wonder. You need to update the gui (application.processmessages)

Quote
I have added the Uses Cthreads but the 'magic' did not happened.
Threads need to be programmed. Your code doesn't magically becomes threaded by adding the threads unit to your uses clause.

Not that recording requires any threads. Because that is what the non-blocking is meant for, to give you time to update other stuff.

Always, always always use snd_pcm_close after a successful call to snd_pcm_open. ALSA is pretty peculiar when it comes to not releasing memory and/or handles and is able to drive you insane when you run such code multiple times, even after you have corrected your mistakes. Make sure to reset often in case you are starting to doubt yourself  :D

edit: added remarks on hw_params (de)allocaction as I initially missed that.
« Last Edit: July 30, 2020, 08:38:28 am by TRon »

julkas

  • Guest
Re: Help with Alsa C conversion.
« Reply #24 on: July 30, 2020, 09:21:40 am »
If you don't want cmem , you can call free().
Example - https://ideone.com/xN0Sg5

EDIT - IIRC Alsa is *NIX, so don't use cmem  only for one function, use cmem , if you really need it.
« Last Edit: July 30, 2020, 09:40:32 am by julkas »

AL

  • Sr. Member
  • ****
  • Posts: 256
Re: Help with Alsa C conversion.
« Reply #25 on: August 04, 2020, 03:33:57 am »
Thank you all for your comments.
Sorry for the reply delay,  I was out for a few days.
I will study that in the next days and possibly come back with more questions.
Laz 3.1, fpc 3.2.2, Win10
Laz 3.1  fpc 3.2.2, MacOS Monterey running on VMWare/Win 10
Laz 3.1  fpc 3.2.2 Ubuntu 20.04

AL

  • Sr. Member
  • ****
  • Posts: 256
Re: Help with Alsa C conversion.
« Reply #26 on: August 05, 2020, 03:48:12 am »
Here is my code for my 2 procedures.  Much better now.
Thanks to all especially TRon who put me on the right track.
I had to use Cmem only to free the name Hint.

There might be still unnecessary or missing code. Please let me know .  This is good education.



Code: Pascal  [Select][+][-]
  1. Procedure ListDevices ;     // this will list only input devices
  2. Var Hints   : PPointer ;
  3.     err,i   : integer;
  4.     n       : PPointer ;
  5.     Name,Desc,IOID :Pchar ;
  6.  
  7. begin
  8.   i := 0;
  9.   err := snd_device_name_hint(-1,'pcm', @Hints) ;
  10.   if err <> 0 then begin
  11.     ShowMessage('Error accessing devices, Error:'+ inttoStr(err));
  12.     exit ;
  13.   end;
  14.  // First count devices
  15.   n := Hints  ;
  16.    try
  17.     try
  18.      while (n^ <> nil) do
  19.      begin
  20.         name := snd_device_name_get_hint(n^,Pchar('NAME')) ;
  21.         desc := snd_device_name_get_hint(n^,'DESC') ;
  22.         IOID := snd_device_name_get_hint(n^,'IOID') ;
  23.        If IOID <> '' then
  24.           if IOID = 'Input' then  Inc (i) ;
  25.       Inc(N) ;
  26.       If assigned(name) then cmem.Free(Name);
  27.       If assigned(desc) then cmem.Free(Desc);
  28.       If assigned(IOID) then cmem.Free(IOID);
  29.       end;
  30.   except
  31.     on E: Exception do
  32.         ShowMessage(E.Message);
  33.    end;
  34.  
  35.   finally
  36.  
  37.   end;
  38.  
  39.   // second fill the array
  40.   setlength(DeviceTable,i )  ;  // last item is flag -1
  41.   n := Hints  ;
  42.   i := 0 ;
  43.    try
  44.     try
  45.      while (n^ <> nil)    do begin
  46.         name := snd_device_name_get_hint(n^,Pchar('NAME')) ;
  47.         desc := snd_device_name_get_hint(n^,'DESC') ;
  48.         IOID := snd_device_name_get_hint(n^,'IOID') ;
  49.        If IOID <> '' then
  50.           if IOID = 'Input' then
  51.                begin
  52.                //Showmessage(string(Name) + ' | ' + String(desc) + ' | ' + string(IOID)) ;
  53.                DeviceTable[i].iIndex := i ;
  54.                DeviceTable[i].iName := String(name) ;
  55.                DeviceTable[i].iDesc := String(desc) ;
  56.                Inc (i) ;
  57.                end;
  58.       Inc(N) ;
  59.       If assigned(name) then cmem.Free(Name);
  60.       If assigned(desc) then cmem.Free(Desc);
  61.       If assigned(IOID) then cmem.Free(IOID);
  62.       end;
  63.   except
  64.     on E: Exception do
  65.         ShowMessage(E.Message);
  66.    end;
  67.  
  68.   finally
  69.    DeviceTable[i].iIndex := -1 ;     // end of array is marked as -1
  70.   end;
  71.  
  72.   err := snd_device_name_free_hint (hints) ;
  73.   if err <> 0 then begin
  74.     ShowMessage('Error freeing hints, Error:'+ inttoStr(err));
  75.     exit ;
  76.   end;
  77. end;            
     

The next procedure will record 2 seconds of PCM to a buffer.   
Code: Pascal  [Select][+][-]
  1. Procedure StartRecording ;
  2. Const Buffer_Frames = NBPoints;  // in Main   = 16384
  3.  
  4. Var
  5.   // Samplerate       : Int32 = 8192 ; defined in Main
  6.   // Capture_handle   : Psnd_pcm_t ;  // declared as global to unit
  7.   // Channels         : int32 = 1 ; //mono    defined In Main
  8.      buffer           : Pchar ;
  9.      hw_params        : Psnd_pcm_hw_params_t ;
  10.      format           : snd_pcm_format_t = SND_PCM_FORMAT_S16_LE ;  // 16 bits signed little endian
  11.      direction        : integer = 0 ;
  12.      i,err            : Integer;
  13. begin
  14.                                                                                                                              //originally 0
  15.   err := snd_pcm_open(@capture_handle,Pchar(deviceTable[MainForm.CBListDevices.itemIndex].iname),SND_PCM_STREAM_CAPTURE,0 (*SND_PCM_NONBLOCK*))  ;
  16.   If err < 0 then begin PostError('Error opening PCM') ; Exit ;end;
  17.  
  18.   err := snd_pcm_hw_params_malloc (@hw_params)  ;
  19.   If err < 0 then begin PostError('Error hwparams'); Exit ;end;
  20.  
  21.   err := snd_pcm_hw_params_any (capture_handle, hw_params) ;
  22.   if err< 0 then begin PostError('Cannot initialize hardware parameter structure') ; Exit ; end ;
  23.                                                                   // SND_PCM_ACCESS_MMAP_NONINTERLEAVED
  24.   err := snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
  25.   if err < 0 then begin PostError('Cannot access PCM type');Exit;end;
  26.  
  27.   err := snd_pcm_hw_params_set_format (capture_handle, hw_params, format) ;
  28.   if err < 0 then begin Posterror('Cannot set format') ; Exit; end;
  29.  
  30.   err := snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, @samplerate, @direction);
  31.   if err < 0 then begin Posterror('Cannot set rate') ; Exit ; end;
  32.   if Direction  <> 0 then begin Posterror('Cannot set exact rate') ; Exit; end;
  33.  
  34.   err := snd_pcm_hw_params_set_channels (capture_handle, hw_params, channels) ;   // 1 channel = mono
  35.   if err < 0 then begin PostError('Cannot set channel count') ; Exit ; end;
  36.  
  37.   err := snd_pcm_hw_params (capture_handle, hw_params) ;
  38.   if err < 0 then Begin PostError('Cannot set parameters') ; Exit ; end ;
  39.  
  40.   snd_pcm_hw_params_free (hw_params);
  41.  
  42.   err := snd_pcm_prepare (capture_handle) ;
  43.   if err < 0 then begin PostError('Cannot prepare audio interface for use'); Exit ; end;
  44.  
  45.   buffer := GetMem (Buffer_Frames * snd_pcm_format_width(format) DIV 8 * Channels);
  46.  
  47. Repeat
  48.  
  49.   Application.processmessages ;
  50. //  snd_pcm_wait(capture_handle, 2000);
  51.   err := snd_pcm_readi (capture_handle, buffer, buffer_frames);
  52.  
  53.   if err <> buffer_frames then
  54.   begin
  55.         PostError ('Read from audio interface failed. Error = '+inttostr(err));
  56.         exit ;
  57.   end
  58.   else
  59.   begin     //we have a full buffer
  60.  
  61.    // here I need to transfer the buffer in the process buffer
  62.  
  63.    FillWord(SavedFrameData,length(SavedFrameData),0);  // remove garbage
  64.    Move(buffer^,SavedFrameData,buffer_frames*2) ;
  65.  
  66.    // Find the max value
  67.    gMax := 0 ;
  68.    gMaxIndex := 0 ;
  69.    For i := 0 to  length(SavedFrameData)-1 do
  70.       begin
  71.          if abs(SavedFrameData[i])> gmax then       // use only positives values
  72.          begin
  73.           gMax := Abs( SavedFrameData[i]);
  74.           gMaxIndex := i ;
  75.          End;
  76.       End;
  77.      If gMax > gSensitivity then        // Check if level is higher than sensitivity set level
  78.        begin
  79.           StopVisualBuffer ;
  80.           MainForm.RBdataReady.checked := true ;     // set an event to draw graphs
  81.        end   // gMax > sensivity
  82.        else
  83.        begin   // gMax is lower then sensitivity
  84.          ResetVisualBuffer ;
  85.        end;
  86.       End  ;   // end full buffer
  87.    until gMax > gSensitivity ;
  88.  
  89.    Processing := False   ;
  90.    FreeMem(Buffer) ;
  91.    //snd_pcm_close (Capture_handle)  is called from main by Stop Recording ;
  92.  
  93. end;
  94.  
  95. Procedure StopRecording ;
  96. begin
  97.     snd_pcm_Close (Capture_Handle) ;
  98. end;                                            
  99.  
The last problem I have is that I use a progress bar driven by a timer to show/imitate the buffer filling.  In windows and Mac the GUI does update.  In Linux I have not found a way yet.
During the read, the interface is not updated, so the progress bar does not grow!

Possibly the non Blocking might do the trick, but so far I have not found a way to use it.
Ideas welcome!

Thank you.
Laz 3.1, fpc 3.2.2, Win10
Laz 3.1  fpc 3.2.2, MacOS Monterey running on VMWare/Win 10
Laz 3.1  fpc 3.2.2 Ubuntu 20.04

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: Help with Alsa C conversion.
« Reply #27 on: August 05, 2020, 09:03:26 am »
The last problem I have is that I use a progress bar driven by a timer to show/imitate the buffer filling.  In windows and Mac the GUI does update.  In Linux I have not found a way yet.
During the read, the interface is not updated, so the progress bar does not grow!

Presumably you're referring to your snd_pcm_readi() call. I've used ALSA for MIDI where since it's in a background thread the GUI remains live, but otherwise you might have to transfer smaller chunks with an APM in the loop... which will obviously introduce the risk of latency problems.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

AL

  • Sr. Member
  • ****
  • Posts: 256
Re: Help with Alsa C conversion.
« Reply #28 on: August 06, 2020, 02:17:30 am »
Possibly I need to go interrupt-driven.
Not totally sure how to do it.  I need to do more reading  unless someone has some code to share.
Laz 3.1, fpc 3.2.2, Win10
Laz 3.1  fpc 3.2.2, MacOS Monterey running on VMWare/Win 10
Laz 3.1  fpc 3.2.2 Ubuntu 20.04

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
Re: Help with Alsa C conversion.
« Reply #29 on: August 06, 2020, 09:57:50 am »
Magic word is probably "event", not "interrupt". I've not done it but there's a couple of hints at the end of https://www.linuxjournal.com/article/6735

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018