Frate 0 Posted November 15, 2020 Hi everyone, first post for me so I shortly introduce myself. I'm Aerospace Eng. student in Italy, passionate about electronics, PCs and aviation. Learned Lazarus at high school, now moving to Delphi some personal projects. I'll drop here the code I'm having issues with: uses bass, [...] type TRadio = record counter : word; [...] function MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; // BLOCK TONE GENERATION end; type TRadioPointer = ^TRadio; function TRadio.MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; //3 var buf: ^WORD; i, k, len: Integer; ampl: real; j: word; begin // Does stuff using properties from TRadio inc(cunter); [...] Result := Alength; end; procedure initRadio(PRadio : TRadioPointer); //2 [...] begin [...] resultValue := BASS_StreamCreate(cSAMPLE_RATE, 2, 0, @PRadio^.MakeSine, nil); // Error here : E2036 Variable Required [...] end; procedure mainProgram; //1 var MyRadio : TRadio; begin initRadio(@MyRadio); end; What I'm trying to achieve : I'm using an audio library called Bass. I have to create a waveform (TRadio.MakeSine) using parameters from a TRadio record. There is no possibility to change the parameters on the MakeSine function because BASS_StreamCreate wants specific function paramters (so for instance I can't pass the TRadio.parameters directly to the MakeSine function). I decided to put MakeSine inside the TRadio record to allow access to the parameters i need (also for the program logic makes sense to do that). BASS_StreamCreate requires a pointer to MakeSine function as input (see reference below). The problem I have: When i try to pass the function pointer to StreamCreate i get error E2036 Variable Required. I don't understand what i'm doing wrong. Kindly asking for help Frate Bass reference: HSTREAM BASS_StreamCreate( DWORD freq, DWORD chans, DWORD flags, STREAMPROC *proc, void *user ); DWORD CALLBACK StreamProc( HSTREAM handle, void *buffer, DWORD length, void *user ); Share this post Link to post
FPiette 383 Posted November 15, 2020 1 hour ago, Frate said: When i try to pass the function pointer to StreamCreate i get error E2036 Variable Required. This usually hapend when a function has a var argument and you try to pass a property. Copy the property to a temporary variable, pass the variable as argument to the function, set the property with the [potentially new] temporary variable. 1 Share this post Link to post
Anders Melander 1783 Posted November 15, 2020 There are a few issues with your code and a few things that could be improved. 1) A member function has a hidden "self" parameter so in reality the signature of the MakeSine function you have declared looks like this: function MakeSine(const [ref] Self: TRadio; handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; If you want MakeSine declared as a member function then you need to declare it as a static class method: type TRadio = record ... class function MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; static; end; but then you lose the reference to self and can't access the member variables inside the method. I'm guessing that the user parameter is for passing context to the callback and if so you can achieve the same with an extra function: type TRadio = record ... private function DoMakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD): DWORD; public class function MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; static; end; class function TRadio.MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; begin Result := TRadioPointer(user).DoMakeSine(handle, buffer, Alength); end; function TRadio.DoMakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD): DWORD; begin ... end; begin // Pass TRadio pointer as the "user" parameter resultValue := BASS_StreamCreate(cSAMPLE_RATE, 2, 0, @TRadio.MakeSine, PRadio); end 2) The convention would be to name your TRadio pointer type "PRadio" type TRadio = record ... end; PRadio = ^TRadio; 3) You don't need to deference typed complex pointer types with ^ PRadio^.MakeSine // standard Pascal PRadio.MakeSine // allowed in Delphi 1 Share this post Link to post
Frate 0 Posted November 15, 2020 Thank you both for replying. @Anders MelanderThanks for your suggestions, I implemented your solution and at least i get no compiler error. I have to complete some other parts of the software before checking if everything works fine. Quote 2) The convention would be to name your TRadio pointer type "PRadio" By convention what would be an appropriate name for pointer variable of type PRadio? var ?MyRadioPointer? : PRadio; Quote 3) You don't need to deference typed complex pointer types with ^ Heritage from school 😉 Thanks again Frate Share this post Link to post
Anders Melander 1783 Posted November 15, 2020 10 minutes ago, Frate said: By convention what would be an appropriate name for pointer variable of type PRadio? I don't think there's a widely used convention for that. I would just name it "Radio". Share this post Link to post