function mit cdecl in TForm

Für Probleme bezüglich Grafik, Audio, GL, ACS, ...
Antworten
Bernd
Beiträge: 27
Registriert: Mo 11. Jun 2007, 10:12
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

function mit cdecl in TForm

Beitrag von Bernd »

Hallo,
bin gerade dabei mich mit der Einbindung von PortAudio zu beschäftigen. Einiges geht schon, habe aber noch ein Problem.

Die Biblitheken für Portaudio sind ja in C geschrieben und so wird meine Funktion so deklariert:

Code: Alles auswählen

function audioCallback( ...) : CInt32; cdecl;
 
implementation
 
function audioCallback( ...) : CInt32; cdecl;
var
...
begin
  {berechnungen}
  result:= 0;
end;


Die Funktion wird dann so aktiviert/übergeben:

Code: Alles auswählen

//* Record some audio. -------------------------------------------- */
  err:= Pa_OpenDefaultStream( pStream,2, 2,
                              PA_SAMPLE_TYPE,
                              SAMPLE_RATE,
                              FRAMES_PER_BUFFER,
                       {$ifdef FPC}
                       PPaStreamCallback( @audioCallback),
                       {$ELSE}
                       @audioCallback,
                       {$ENDIF}
                       nil );


So funktioniert dies auch. Also die Funktion wird declariert und dann implementiert.
Nun wollte ich Daten aus der Berechnung im Form1 in einer Paintbox grafisch darstellen.
Da die Funktion nicht Bestandteil von Form1 ist klappt dies natürlich nicht so.

Nun dachte ich, steckst die Funktionsdeklaration einfach zu denen in Form1 und so könnte ich in der Funktion auf die Paintbox zugreifen.

Code: Alles auswählen

TForm1.function audioCallback( ...) : CInt32; cdecl;


Nun gibt es Konflikte mit der falschen Variablendeklaration.

Gibt es einen einfachen Weg die Daten aus der Funktion in ein Objekt von Form1 zu übertragen, oder muss ich mich da mit der Datensynchronisation zwischen Threats beschäftigen. Ist mir leider noch ein Brief mit sieben Siegeln :-((


Gruß Bernd

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: function mit cdecl in TForm

Beitrag von theo »

Bernd hat geschrieben:Gibt es einen einfachen Weg die Daten aus der Funktion in ein Objekt von Form1 zu übertragen, oder muss ich mich da mit der Datensynchronisation zwischen Threats beschäftigen. Ist mir leider noch ein Brief mit sieben Siegeln :-((


Das sind eigentlich zwei Fragen. Ich gehe mal nicht davon aus, dass die C Funktion in einem separaten Thread ausgeführt wird, sonst wird es viel schwieriger.

Du kannst in deinem Callback, wenn es in der gleichen Unit wie Form1 ist, auf Form1 einfach so zugreifen:

Code: Alles auswählen

function audioCallback( ...) : CInt32; cdecl;
var
...
begin
  {berechnungen}
  Form1.Edit1.Text:='test';   
  result:= 0;
end;

Bernd
Beiträge: 27
Registriert: Mo 11. Jun 2007, 10:12
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: function mit cdecl in TForm

Beitrag von Bernd »

Hallo theo,
danke für die Antwort. Ich habe dies gleich mal getestet, geht aber nicht wie gewünscht. Ich kann zwar die Zeile einfügen, es wird übersetzt und das Programm startet, aber wenn ich die Funktion AudioCallback starte kommt es zu einer Exception.

[img]
file:///home/bernd/Bilder/Bildschirmfoto%20-%2026.02.2012%20-%2017:44:31.png
[/img]
Bildschirmfoto klappt so nicht, sri.


Es ploppt anschließend der Assembler hoch. (nur Adressen und Punkte - kann ich nicht interpretieren)

Ich dachte die Funktion läuft in einem anderen Thread, da doch nur die Adresse an das andere Programm übergeben wird und das dann die Steuerung dieser Funktion übernimmt.
Da habe ich wohl etwas falsche Vorstellungen.


Mein Ziel war mittels

Code: Alles auswählen

// Zeichnet den Hintergrund
  ftemp.Canvas.Pen.Color := clWhite;
  ftemp.Canvas.Rectangle(0, 0, fTemp.Width, fTemp.Height);
  ftemp.Canvas.Pen.Color:= clred;
  ftemp.Canvas.Polyline(punkte);
   BitBlt(Form1.PaintBox1.Canvas.Handle,0,0,1024,100,ftemp.Canvas.Handle,0,0,SRCCOPY);


ein Bild des Tonsamples anzuzeigen. Später dann mehr.

Für einen ersten Test habe ich die Anzeige über einen Timer gemacht, der die oben gezeigten Codezeilen ausführt. Er holt die Punkte für die Polyline aus einem global definierten Array, auf welches nun beide Zugriff haben. Das geht nur begrenzte Zeit gut, da kommt es aus meiner Sicht bei gleichzeitigem Zugriff aus zwei Funktionen zum Absturz. Sollte auch nur ein Test sein ob ich die PortAudio-Funktionen verwenden kann und ist nicht sehr elegant.


Ich muß auch nicht eine Paintbox verwenden, gibt es eine andere Möglichkeit ein Bild auf den Schirm zu bekommen?


Gruß Bernd

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: function mit cdecl in TForm

Beitrag von theo »

Ja gut, wenn es wirklich so ist, musst du z.B. mit TCriticalSection arbeiten. Messages würden wohl unter Windows auch gehen.
Bin nicht absoluter Spezialist für dieses Thema.

Bernd
Beiträge: 27
Registriert: Mo 11. Jun 2007, 10:12
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: function mit cdecl in TForm

Beitrag von Bernd »

Dann muss ich mich wohl doch mal mit diesem Thema beschäftigen. Naja man lernt nie aus. Hab ja jetzt Zeit :-)

Danke erst mal fürs Mitdenken.
Tschüß

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: function mit cdecl in TForm

Beitrag von mse »

Ich würde im callback lediglich die Daten kopieren.

Code: Alles auswählen

Pseudo code:
var
 audiobuffer: array[0..FRAMES_PER_BUFFER-1] of ...
 audiobufferloaded: boolean;
 
function audioCallback( ...) : CInt32; cdecl;
begin
 application.lock;
    //ich weiss nicht, ob Lazarus diese Funktion hat, sonst eine
    //entsprechende Lazarus Synchronisierungsmethode verwenden
    //queueasynccall()?
 if not audiobufferloaded then begin //buffer ist frei
  move(...,audiobuffer,FRAMES_PER_BUFFER*sizeof(FRAME));
              //kopiere audiodaten in audiobuffer
  audiobufferloaded:= true;
 end;
 application.wakeupmainthread;
 application.unlock;
 result:= ...;
end;
 
 
procedure TForm1.onidleexe(var again: Boolean);
begin
 if audiobufferloaded then begin
  ...
   //daten verarbeiten
  audiobufferloaded:= false;
 end;
end;

Für lückenlosen Betrieb könnte auch mit zwei Puffer gearbeitet werden, welche wechselweise vom callback und der Auswerteroutine benützt werden. Statt Blockierung durch application.lock()/unlock() calls müssten die Puffer dann mit InterLockedExchange() oder ähnlich umgeschaltet werden. Falls die audiobufferloaded Variable nur mit threadsicheren Operationen bearbeitet wird (InterlockedIncrement(),InterlockedDecrement(),InterlockedExchange()), kann auf application.lock()/unlock() ebenfalls verzichtet werden. Dabei muss man dann aber tunlichst auf race conditions achten...
Das Datenkopieren könnte vielleicht vermieden werden, wenn man die Pufferadressen in PortAudio beeinflussen kann. Ich kenne PortAudio nicht.

Martin

Bernd
Beiträge: 27
Registriert: Mo 11. Jun 2007, 10:12
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: function mit cdecl in TForm

Beitrag von Bernd »

So ich habe es nun mit dem Beispiel lazarus/examples/multithreading/criticalsectionexample1.lpi also wie von theo vorgeschlagen gelöst.

Ich glaube der Vorschlag von mse ziehlt in die gleiche Richtung, nur eben zu Fuß erledigt, das Verriegeln der Variablen gegeneinander.

Leider habe ich nun zwei unabhängige Teile zu laufen - einmal die Funktion die ich an Portaudio übergeben habe - zum anderen den Timer der mir das Bild generiert. Beide Funktionen laufen nun asynchron zueinander. Im Kopf hatte ich aber am Ende der Funktion audioCallBack alles zu erledigen.

Also bekomme ich die audioCallBack Funktion nicht mit Form1 auf einfache Art zusammen, da die audioCallback Funktion an ein anderes Programm übergeben wird. Ich starte diese Funktion ja auch nicht in meinem eigenen Programm.

Noch eine Frage: Kann mir die AudioCallback-Funktion eine Nachricht schicken wenn sie fertig ist. Bräuchte ich keinen Timer.

Bernd

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: function mit cdecl in TForm

Beitrag von mse »

Bernd hat geschrieben:Noch eine Frage: Kann mir die AudioCallback-Funktion eine Nachricht schicken wenn sie fertig ist. Bräuchte ich keinen Timer.

Vielleicht liest du meinen Beitrag etwas genauer.

Antworten