Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2017-01

Array as result in function.

23 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

fredvs

Hello.

With this code, the result of the function does not have same format as the array input:

Why ?

type
  TArFloat = array of cfloat;
function array_in_out(arrayin: TArFloat): TArFloat;
begin
result := arrayin;
end;

Some more explaination.

If in a code I use:
var
thebuffer: TArFloat;
// thebuffer was filled with some float-samples
thebuffer := array_in_out(thebuffer);

It is not neutral, the data are affected (in audio the data are noisy).

What is wrong ?

Thanks.

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366.html Sent from the Free Pascal - General mailing list .
silvioprog
to fredvs
fredvs wrote 15 lines
Hello. With this code, the result of the function does not have same format as the array input: Why ? type TArFloat = array of cfloat; function array_in_out(arrayin: TArFloat): TArFloat; begin result := arrayin; end;

It works fine here. Eg:

=== begin code ===

type
  TArFloat = array of cfloat;
function array_in_out(arrayin: TArFloat): TArFloat;
var
  i: byte;
begin
  for i := low(arrayin) to high(arrayin) do
    arrayin[i] *= 10;
  Result := arrayin;
end;

...

var
  item: cfloat;
  thebuffer: TArFloat;
begin
  SetLength(thebuffer, 3);
  thebuffer[0] := 1;
  thebuffer[1] := 2;
  thebuffer[2] := 3;
  WriteLn('before');
  for item in thebuffer do
    WriteLn(item.ToString);
  thebuffer := array_in_out(thebuffer);
  WriteLn('after x10');
  for item in thebuffer do
    WriteLn(item.ToString);
end;
// output:

before
1
2
3
after x10
10
20
30

=== end code ===

Show quoted text 14 lines
Some more explaination. If in a code I use: var thebuffer: TArFloat; // thebuffer was filled with some float-samples thebuffer := array_in_out(thebuffer); It is not neutral, the data are affected (in audio the data are noisy). What is wrong ?

Are you using that function as callback with some (C/C++) library? If so, check its parameter calling convention, declaring it as `function array_in_out(arrayin: TArFloat): TArFloat; cdecl;`.

Thanks. Fre;D
Silvio Clécio
Martin Schreiber
to fredvs: Hello. With this code, the result of the function does not have same format as the array…
fredvs wrote 5 lines
function array_in_out(arrayin: TArFloat): TArFloat; begin result := arrayin; end;

Do you change items of "arrayin" later? If so the items of the result array will be changed too, dynamic array assignment copies the data pointer only. http://www.freepascal.org/docs-html/current/ref/refsu15.html#x39-520003.3.1

Use
"
function array_in_out(arrayin: TArFloat): TArFloat;
begin
 result:= copy(arrayin);
end;
"
if the result array must be independent.

Martin

Jürgen Hestermann
to Martin Schreiber
Martin Schreiber wrote 16 lines
On Thursday 19 January 2017 22:50:36 fredvs wrote: > function array_in_out(arrayin: TArFloat): TArFloat; > begin > result := arrayin; > end; Do you change items of "arrayin" later? If so the items of the result array will be changed too, dynamic array assignment copies the data pointer only. http://www.freepascal.org/docs-html/current/ref/refsu15.html#x39-520003.3.1 Use " function array_in_out(arrayin: TArFloat): TArFloat; begin result:= copy(arrayin); end; " if the result array must be independent.

While the original Pascal language was clear and logical, it has become ambiguous with managed types.

In this declaration

var X : int64;

"X" always means the 8 bytes that hold the integer. "@X" always means the 4 bytes of the *address* where the 8 bytes start. Here you are always aware what is meant:
Either the data or the address of the data (pointer).

In this declaration:

var A : array of int64;

"A" means the (elements of the) array if you index it as in "A[7]" but it means the (4 byte) pointer to the first element if you use it as function parameter or in assignments.

And even worse, *some* managed types (like strings) have "copy-on-write".

IMO this is all very confusing and leads to a lot of hard to spot bugs but it cannot be changed anymore.

fredvs
to Jürgen Hestermann

Thanks very much for answers.

@ silvioprog:

using that function as callback with some (C/C++) library?

Yes and check its parameter calling convention is ok.

@ Martin.

result:= copy(arrayin);

Ha, I did not know this one.
I will try it (and write you asap).

Many thanks.

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366p5727375.html Sent from the Free Pascal - General mailing list .
Sven Barth
to fredvs
"fredvs" wrote 8 lines
Thanks very much for answers. @ silvioprog: > using that function as callback with some (C/C++) library? Yes and check its parameter calling convention is ok.

You shouldn't use Pascal arrays when interfacing with C/C++ code as especially dynamic arrays have a different format (though you can pass a pointer to the first array element).

Maybe show us how the original C function looks like.

Regards,
Sven

fredvs
to Sven Barth

Hello.

Some more investigations.

Let say we have a array of float of length = 100 (arrayin):

setlength(arrayin,100);

A external library fill this array with 80 samples (ouframes).

When using that arrayin pure (without any dsp) the sound is pure too.

If using:

function arraycopy(arrayin : Tarrayfloat): Tarrayfloat;
begin
result := arrayin;
end;

==> Bad noisy sound, even using

but if using:

function arraycopy(arrayin : Tarrayfloat; outfames: integer): Tarrayfloat;
begin
SetLength(arrayin, outframes);
result := arrayin;
end;

===> OK, perfect sound.

Why ?

_____________________________________

You shouldn't use Pascal arrays when interfacing with C/C++ code as especially dynamic arrays have a different format (though you can pass a pointer to the first array element).

Huh, what do you propose instead, I am totally open to new idea ? (But using dynamic arrays gives me lovely results).

Maybe show us how the original C function looks like.

All the audio-wrappers use buffers to store the data. I use dynamic arrays for that buffers.

In https://github.com/fredvs/uos there are Pascal wrappers to C libraries:

uos_Portaudio.pas
uos_Mpg123.pas
uos_SoundFile.pas
uos_Opus.pas
uos_AAC.pas
uos_SoundTouch.pas

...

Thanks.

Fre;D

Thanks.

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366p5727378.html Sent from the Free Pascal - General mailing list .
fredvs
to fredvs

Hello.

Hum,...

I am guilty. ;-(

There was a SetLength(Bufferin, x) hidden.

So the length of bufferin into the function was not the same as the "pure" one.

So, to resume:

If using:

function arraycopy(arrayin : Tarrayfloat): Tarrayfloat;
begin
result := arrayin;
end;

==> Perfect, the input arrayin = result. ;-(

Sorry for the noise (but I m still open for other solutions than dealing with dynamic arrays).
(But dynamic arrays are wow).

Thanks.

Fre;D

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366p5727379.html Sent from the Free Pascal - General mailing list .
silvioprog
to fredvs

On Fri, Jan 20, 2017 at 1:12 PM, fredvs wrote:
[...]

Please look at Sven's warn regarding Pascal arrays mixed with C arrays.

Could you show us the original C function?

Silvio Clécio
fredvs
to silvioprog

Here, for example from OpusFile.h =>

OP_WARN_UNUSED_RESULT int op_read_float(OggOpusFile *_of,
 float *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1);

Translated in fpc with:

op_read: function(OpusFile: TOggOpusFile; var pcm; SampleCount: Integer; li:
pointer): Integer;
And used like this:
BufferIn : array of cfloat;
outframes := op_read_float(HandleOF,BufferIn[0],Wantframes *Channels, nil);

The nice thing is that BufferIn can be used for portaudio, soundfile, mpg123, aac buffers and is working like charm.

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366p5727381.html Sent from the Free Pascal - General mailing list .
silvioprog
to fredvs
fredvs wrote 18 lines
Here, for example from OpusFile.h => OP_WARN_UNUSED_RESULT int op_read_float(OggOpusFile *_of, float *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1); Translated in fpc with: op_read: function(OpusFile: TOggOpusFile; var pcm; SampleCount: Integer; li: pointer): Integer; And used like this: BufferIn : array of cfloat; outframes := op_read_float(HandleOF,BufferIn[0],Wantframes *Channels, nil);

You should keep the Pascal code syntax closest to the C one, something like this:

uses ctypes;

POggOpusFile = ^TOggOpusFile
TOggOpusFile = record // please check if original C struct uses some alignment ...
end;

function op_read_float(_of: POggOpusFile; _pcm: Pcfloat; _buf_size: cint;
_li: pcint): cint; cdecl; ... blah blah blah
// or dynamic loading like you showed (on Delphi you can use the `delayed`
keyword instead of declaring `GetProcedureAddress` by hand :-) )
{$MACRO ON}
{$DEFINE OP_ARG_NONNULL := op_read_float}

It is useful when we need to translate the examples.

It seems that function just increment the address of a (float) buffer, so:

var
...
  buf: pcfloat;
begin
  ... HandleOF/buf initialization etc. ...
  outframes := OP_ARG_NONNULL(HandleOF, buf, Wantframes * Channels, nil);
... code ...
  buf += (Wantframes * Channels) * sizeof(cfloat) // or inc(buf,
(Wantframes * Channels) * sizeof(cfloat));
( you can try "buf += Wantframes * Channels; // or inc(buf, Wantframes *
Channels);" too )

I'm not sure if it works, but you can check it by yourself. :-)

The nice thing is that BufferIn can be used for portaudio, soundfile, mpg123, aac buffers and is working like charm.

Awesome. :-)

Fre;D

----- Many thanks ;-)
Silvio Clécio
silvioprog
to silvioprog

On Fri, Jan 20, 2017 at 5:14 PM, silvioprog wrote: [...]

It seems that function just increment the address of a (float) buffer, so:

I meant "It seems that function just fill a (float) buffer". ^^'

Silvio Clécio
fredvs
to silvioprog

Hello Silvio.

Wow, thanks, I will study it deep.

By the way, the Opus Pascal wrappers are working.
You may listen, seek, saving to file, apply dsp,.. to Opus files. You may try SimplePlayer demo in uos (all libraries and Opus-audiofile included):

https://github.com/fredvs/uos

PS: BufferIn is working only if it is a array of cfloat (from ctypes.pas). With array of double, array of float,.. it does not work.

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366p5727384.html Sent from the Free Pascal - General mailing list .
fredvs
to silvioprog: You should keep the Pascal code syntax closest to the C one, something like this: uses…

Re-hello.

Ok, thanks Silvio, I will take this one from your advice, it works like charm:

type
  TOggOpusFile = THandle;
  TDArFloat = array of cfloat;
  PDArFloat = ^TDArFloat;
op_read: function(OpusFile: TOggOpusFile; pcm : PDArFloat; SampleCount:
Integer; li: pointer): Integer;
op_read_float: function(OpusFile: TOggOpusFile; pcm : PDArFloat;
SampleCount: Integer; li: pointer): Integer;

Many thanks.

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366p5727385.html Sent from the Free Pascal - General mailing list .
silvioprog
to fredvs: Hello Silvio. Wow, thanks, I will study it deep. By the way, the Opus Pascal wrappers are…
fredvs wrote 13 lines
Hello Silvio. Wow, thanks, I will study it deep. By the way, the Opus Pascal wrappers are working. You may listen, seek, saving to file, apply dsp,.. to Opus files. You may try SimplePlayer demo in uos (all libraries and Opus-audiofile included): https://github.com/fredvs/uos PS: BufferIn is working only if it is a array of cfloat (from ctypes.pas). With array of double, array of float,.. it does not work.

Yes, because C `float`'s size is 4, and Pascal `double`'s, 8. Pascal `cfloat` is just a alias to `single`, 4. :-) Try two tests:

$ echo -e '#include <stdio.h>\nint main(){printf("size of float: %zu\\n", sizeof(float));return 0;}' > fredvs.c && gcc -o fredvs fredvs.c && clear && ./fredvs # it prints "size of float: 4" on your terminal

and:

$ echo "program fredvs;begin writeln('sizeof double: ', sizeof(double));writeln('size of single: ', sizeof(single));end." > fredvs.pp && fpc fredvs.pp && clear && ./fredvs # it prints "sizeof double: 8" and "size of single: 4" on your terminal

Some useful links:

FPC Real types:
http://freepascal.org/docs-html/ref/refsu6.html#x28-310003.1.2 C - Data Types: https://www.tutorialspoint.com/cprogramming/c_data_types.htm Delphi to C++ types mapping:
http://docwiki.embarcadero.com/RADStudio/Berlin/en/Delphi_to_C%2B%2B_types_mapping

Fre;D

----- Many thanks ;-)
Silvio Clécio
silvioprog
to fredvs: Re-hello. Ok, thanks Silvio, I will take this one from your advice, it works like charm:…
fredvs wrote 8 lines
Re-hello. Ok, thanks Silvio, I will take this one from your advice, it works like charm: type TOggOpusFile = THandle;

Hm... you should keep the same C data types. :-) I took a look at `OggOpusFile` type, it is a struct:

https://github.com/gcp/opusfile/blob/9a9825df0319138fe845cbb19c250b642965c4b1/include/opusfile.h#L133

so on Pascal it makes more sense declared as:

type
  POggOpusFile = ^OggOpusFile;
  OggOpusFile = record
  end;

and finally:

op_read: function(OpusFile: POggOpusFile; ...

`PDArFloat` seems OK to `op_read_float`, but notice last comment regarding `_pcm`.

"li: pointer" should be "li: pcint" in both funcs.

go slowly: these changes can raise new errors on your code. :-)

  TDArFloat = array of cfloat;
Show quoted text 5 lines
PDArFloat = ^TDArFloat; op_read: function(OpusFile: TOggOpusFile; pcm : PDArFloat; SampleCount: Integer; li: pointer): Integer;

`_pcm` on original code is an `int16` buffer... consider to using `cint16`:

https://github.com/gcp/opusfile/blob/9a9825df0319138fe845cbb19c250b642965c4b1/include/opusfile.h#L1873

op_read_float: function(OpusFile: TOggOpusFile; pcm : PDArFloat;
Show quoted text 5 lines
SampleCount: Integer; li: pointer): Integer; Many thanks. Fre;D
Silvio Clécio
silvioprog
to silvioprog

On Fri, Jan 20, 2017 at 9:06 PM, silvioprog wrote: [...]

`_pcm` on original code is an `int16` buffer... consider to using `cint16`:

Damn Gmail's Ctrl+Enter. -.-'

I meant: "`_pcm` on original code is an `int16` buffer... consider to using `*pcint16*`:"

Silvio Clécio
Sven Barth
to fredvs: Re-hello. Ok, thanks Silvio, I will take this one from your advice, it works like charm:…
fredvs wrote 14 lines
Re-hello. Ok, thanks Silvio, I will take this one from your advice, it works like charm: type TOggOpusFile = THandle; TDArFloat = array of cfloat; PDArFloat = ^TDArFloat; op_read: function(OpusFile: TOggOpusFile; pcm : PDArFloat; SampleCount: Integer; li: pointer): Integer; op_read_float: function(OpusFile: TOggOpusFile; pcm : PDArFloat; SampleCount: Integer; li: pointer): Integer;

Gah! No!

If a C function has a parameter of e.g. "float*" and it's an array you should use the same type in FPC, in that case "pcfloat". *DO NOT* use a Pascal dynamic array or (even worse) a pointer to a Pascal dynamic array.

You can of course use a Pascal array when calling it like this:

op_read_float(f, @arr[0], 42, whatever);

If the C code however is the one allocating the array (in which case the type is usually a pointer to a pointer, like "float**" or "^pcfloat" in Pascal) then you *must not* use a Pascal array, but instead simply pass in a "pcfloat" variable like this:

some_func(@mypcfloat);

(though in that case to avoid confusion you *might* declare the parameter as "var arg: pcfloat" or "out arg: pcfloat" which would be the equivalent and then using "somefunc(mypcfloat) would work as well")

You can then access the C array like you'd do with a Pascal array with "[]", like "mypcfloat[42]". Of course the C function should also tell you the resulting length somehow ;)

I hope this clears up a few points for mixing C and Pascal arrays.

Regards,
Sven

fredvs
to silvioprog: Yes, because C `float`'s size is 4, and Pascal `double`'s, 8. Pascal `cfloat` is just a…

@ Silvio

Try two tests: $ echo -e '#include <stdio.h>\nint main(){printf("size of float: %zu\\n",

sizeof(float));return 0;}'

fredvs.c && gcc -o fredvs fredvs.c && clear && ./fredvs # it prints "size of float: 4" on your terminal

==> size of float: 4

$ echo "program fredvs;begin writeln('sizeof double: ', sizeof(double));writeln('size of single: ', sizeof(single));end." fredvs.pp && fpc fredvs.pp && clear && ./fredvs # it prints "sizeof double: 8" and "size of single: 4

==> sizeof double: 8
size of single: 4

Indeed, not the same.

@ Sven.

Many thanks for your tips.
I will study it deeply and see (+understand) what is wrong in my code.

The most strange is that with my code it is working perfectly.

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366p5727390.html Sent from the Free Pascal - General mailing list .
Vojtěch Čihák
to fredvs: Re-hello. Ok, thanks Silvio, I will take this one from your advice, it works like charm:…

Hi,
 
that's why portaudio.pp declares types like this:
 
PaStream = Pointer;
PPaStream = ^PaStream;
PPPaStream = ^PPaStream;
 
V.
______________________________________________________________

Show quoted text 5 lines
Od: Sven Barth Komu: Datum: 21.01.2017 12:29 Předmět: Re: [fpc-pascal] Array as result in function.

If the C code however is the one allocating the array (in which case the type is usually a pointer to a pointer, like "float**" or "^pcfloat" in Pascal) then you *must not* use a Pascal array, but instead simply pass in a "pcfloat" variable like this:

 some_func(@mypcfloat);

I hope this clears up a few points for mixing C and Pascal arrays.

Regards,
Sven

fredvs
to Sven Barth: Gah! No! If a C function has a parameter of e.g. "float*" and it's an array you should…

Hello everybody.

Do you agree with this ? :

type
  TOggOpusFile = ^OggOpusFile;
  OggOpusFile = record
  end;
op_read: function(OpusFile: TOggOpusFile; pcm : pcfloat; SampleCount:
Integer; li: pointer): Integer;
op_read_float: function(OpusFile: TOggOpusFile; pcm : pcfloat; SampleCount:
Integer; li: pointer): Integer;
op_read_stereo: function(OpusFile: TOggOpusFile; pcm : pcfloat; SampleCount:
Integer): Integer;
op_read_float_stereo: function(OpusFile: TOggOpusFile; pcm : pcfloat;
SampleCount: Integer): Integer;

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366p5727392.html Sent from the Free Pascal - General mailing list .
silvioprog
to fredvs
fredvs wrote 12 lines
Hello everybody. Do you agree with this ? : type TOggOpusFile = ^OggOpusFile; OggOpusFile = record end; op_read: function(OpusFile: TOggOpusFile; pcm : pcfloat; SampleCount: Integer; li: pointer): Integer;

It's almost there. :-)

Notice my message regarding the op_read's pcm and li parameters type ...

op_read_float: function(OpusFile: TOggOpusFile; pcm : pcfloat; SampleCount:

Show quoted text 11 lines
Integer; li: pointer): Integer; op_read_stereo: function(OpusFile: TOggOpusFile; pcm : pcfloat; SampleCount: Integer): Integer; op_read_float_stereo: function(OpusFile: TOggOpusFile; pcm : pcfloat; SampleCount: Integer): Integer; Fre;D ----- Many thanks ;-)
Silvio Clécio
fredvs
to silvioprog

And this one ?

op_read: function(OpusFile: TOggOpusFile; pcm : pcint; SampleCount: Integer;
li: pcint): Integer;
op_read_float: function(OpusFile: TOggOpusFile; pcm : pcfloat; SampleCount:
Integer; li: pcint): Integer;
op_read_stereo: function(OpusFile: TOggOpusFile; pcm : pcint; SampleCount:
Integer): Integer;
op_read_float_stereo: function(OpusFile: TOggOpusFile; pcm : pcfloat;
SampleCount: Integer): Integer;

PS: I agree with you : op_read needs a pcm=pcint.
Is it a big crime to use pcm=pcfloat ?
This because I want to use the same main buffer for all formats (16int, 32int and float 32).
And because it is working perfectly.

But, yes, maybe using a int-temp-buffer and then copy its data to the main float-buffer would be more academic.

Other thing.

On Linux, LibOpus.so and LibOpusFile.so home-compiled are working like charms.

Sadly, on Windows, using the pre-compiled dll downloaded from Opus-site, I have problem with OpusFile.dll.

I have checked the dependencies, they are installed.

Opus.dll loads and all methods can be accessed.

But with OpusFile.dll, it loads but trying to access any method gives:

Program received signal SIGSEGV, Segmentation fault. 0x74728ff0 in strlen () from C:\WINDOWS\SYSTEM32\msvcrt.dll

Aaargh, Google did not help.

Many thanks.

Fre;D

-----
Many thanks ;-)

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Array-as-result-in-function-tp5727366p5727394.html Sent from the Free Pascal - General mailing list .