Recent

Author Topic: Generate square / sinusoidal waves  (Read 4667 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Generate square / sinusoidal waves
« Reply #15 on: January 13, 2021, 04:53:50 pm »
Now i have to produce square wave too, any idea how to do that?

Change the half-wave generation to a simple level rather than a sum of sin() functions. The other half-wave will (obviously) "just work".

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

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: Generate square / sinusoidal waves
« Reply #16 on: January 13, 2021, 05:25:22 pm »
> Now i have to produce square wave too, any idea how to do that?

Hello.

In the link I give you previously:

https://github.com/fredvs/alsa_sound.

In /alsa_sound/src/alsa_sound.pas:

Code: Pascal  [Select][+][-]
  1. function ALSAbeep(frequency, duration, volume: cint; warble: Boolean;
  2. WaveType: cint; CloseLib : boolean): Boolean; // WaveType: 0=sine, 1=square, 2=tooth

Just take a look at "WaveType" parameter ( 0=sine, 1=square, 2=tooth (or triangle)) and the code about it.

Code: Pascal  [Select][+][-]
  1. procedure SetWave (var SA: TAr360; WaveType, Volume: integer); inline;
  2. var i : integer;
  3. begin
  4.     if NOT (waveType in [0..2]) then waveType := 0;
  5.  
  6.          case WaveType of
  7.       0: begin
  8.           for I := 0 to 359 do
  9.           SA[I] := round(sin(pi * I / 180.0) * volume);  // create sine wave pattern
  10.          end;
  11.  
  12.       1: begin
  13.           for I := 0 to 359 do
  14.           if I < 180 then SA[i] := +1*volume else  SA[i] := -1* volume;//  sqare wave
  15.          end;
  16.  
  17.       2: begin
  18.           for I := 0 to 359 do
  19.           SA[i] := (round((360 - i)/180) -1)*volume;   //   saw tooth (triangle) wave
  20.          end;
  21.       end;
  22. end;

Fre;D
« Last Edit: January 13, 2021, 05:51:07 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Ramses

  • New Member
  • *
  • Posts: 41
Re: Generate square / sinusoidal waves
« Reply #17 on: January 15, 2021, 04:47:38 am »

Just take a look at "WaveType" parameter ( 0=sine, 1=square, 2=tooth (or triangle)) and the code about it.


Thanks for that! i have try it today, and it is very easy to use! thats exactly what i needed!

for now it seem to work great, so next week i will test it with an oscilloscope to make sure everything is ok, thats the next step.

So thanks again for your help!

Ramses

  • New Member
  • *
  • Posts: 41
Re: Generate square / sinusoidal waves
« Reply #18 on: January 15, 2021, 09:50:02 pm »
One more question:

when i use Alsabeep, My program freeze completely while the sound is playing, and i can not do anything or press any button while sound is playing.. is there any way to prevent program from freezing?

here is the code i use

Code: Pascal  [Select][+][-]
  1. ALSAbeep(40, 10000, 100, true,0, true);
  2.  

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Generate square / sinusoidal waves
« Reply #19 on: January 15, 2021, 10:05:36 pm »
Well, you don't show what the code /really/ is, only how you're calling it, and since it's obviously not something I wrote I can only make a couple of general suggestions.

The "right" way would probably be to put it in a thread, I don't know whether ALSA provides any equivalent functionality. Alternatively you could insert an Application.ProcessMessages into the loop, but (a) protect it in case you later move the code to a thread, (b) expect it to mess up latency, and (c) if you call it too often it will /really/ mess up latency... you probably don't need it more than 10 times a second.

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

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: Generate square / sinusoidal waves
« Reply #20 on: January 15, 2021, 11:31:22 pm »
One more question:

when i use Alsabeep, My program freeze completely while the sound is playing, and i can not do anything or press any button while sound is playing.. is there any way to prevent program from freezing?

here is the code i use

Code: Pascal  [Select][+][-]
  1. ALSAbeep(40, 10000, 100, true,0, true);
  2.  

Hello.

Like MarkMLI explained, you need to run ALSAbeep() inside a other thread if you want that your main thread still runs while the sound is playing,

Alternatively you may use a other library for that, like uos: https://github.com/fredvs/uos

Each player is a independent thread.

Take a look at example consolesynth.pas:

https://github.com/fredvs/uos/blob/master/examples/consolesynth.pas

I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Ramses

  • New Member
  • *
  • Posts: 41
Re: Generate square / sinusoidal waves
« Reply #21 on: January 17, 2021, 03:35:11 pm »
Like MarkMLI explained, you need to run ALSAbeep() inside a other thread if you want that your main thread still runs while the sound is playing,

Alternatively you may use a other library for that, like uos: https://github.com/fredvs/uos

Well, i have put a speaker on my raspberry, and i tried the library you told me, and i never figure out how to use it! i never get any sound on my speaker..I dont figure out how to use this library to generate a sound in my button...


So i have try to run ALSAbeep inside a thread, but after all day long of trying, iḿ still not able to do that.. i have read a LOT of documentation but it still not working... I dont figure out how to do that! (i know i'm a beginer in this)

I show you a very basic code that work, maybe you can tell me how to modify my code to make it work in a thread? or how to use the new library to generate sound when pressing my button?

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,alsa_sound;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     procedure Button1Click(Sender: TObject);
  17.   private
  18.  
  19.   public
  20.  
  21.   end;
  22.  
  23. var
  24.   Form1: TForm1;
  25.  
  26. implementation
  27.  
  28. {$R *.lfm}
  29.  
  30. { TForm1 }
  31.  
  32. procedure TForm1.Button1Click(Sender: TObject);
  33. begin
  34.   ALSAbeep(40, 10000, 100, true,0, true);
  35. end;
  36.  
  37. end.
  38.                                          

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: Generate square / sinusoidal waves
« Reply #22 on: January 17, 2021, 03:54:39 pm »
Like MarkMLI explained, you need to run ALSAbeep() inside a other thread if you want that your main thread still runs while the sound is playing,

Alternatively you may use a other library for that, like uos: https://github.com/fredvs/uos

Well, i have put a speaker on my raspberry, and i tried the library you told me, and i never figure out how to use it! i never get any sound on my speaker..I dont figure out how to use this library to generate a sound in my button...


Hello.

Here how to use uos:

1) Go on site: https://github.com/fredvs/uos
2) Click on the green button [ Code ] + Download ZIP.
3) Unzip the downloaded file somewhere.
4) Run Lazarus - Open Project
5) Choose in /uos/examples/ a demo project, for example  /uos/examples/simpleplayer.lpi (or in your case consolesynth.lpi)
6) Compile and run it using Lazarus.
7) Check the code to understand how it works.

Fre;D
« Last Edit: January 17, 2021, 03:56:49 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Generate square / sinusoidal waves
« Reply #23 on: January 17, 2021, 05:02:35 pm »
not working... I dont figure out how to do that! (i know i'm a beginer in this)

Not working HOW????? Where's your example code?????

Sorry, asking us to fix a not-quite-right attempt is one thing, but asking us to do it from scratch is something else entirely.

Did you try putting Application.ProcessMessages in your loop which was the fallback suggestion? What happened?

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

Ramses

  • New Member
  • *
  • Posts: 41
Re: Generate square / sinusoidal waves
« Reply #24 on: January 17, 2021, 06:11:34 pm »
Not working HOW????? Where's your example code?????

Did you try putting Application.ProcessMessages in your loop which was the fallback suggestion? What happened?


i have not posted any exemple code, because i tried to follow like 5 or 6 tutorial about "multithreading" that i found on the web, so i decided to not post all those "test" i made.....

For your last question, yes i have try putting Application.ProcessMessages: for example, have try to split the 10 second sound in 10 X 1 second song separate by "application.processmessages", but on the speaker the sound cut 10 time ( i hear a silence each time application.processmessages is called) ... i want to generate a wave with no "silence" in it..

now im looking at the library UOS (from the post of "Fred vS"), when i compile it i hear a sound in my speaker, but there is no graphical user interface, and i want to generate my wave by pressing a button, so iḿ actually trying to copy the code from "consolesynth" inside my graphical program, thats what iḿ working on...

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: Generate square / sinusoidal waves
« Reply #25 on: January 17, 2021, 06:20:36 pm »
now im looking at the library UOS (from the post of "Fred vS"), when i compile it i hear a sound in my speaker, but there is no graphical user interface, and i want to generate my wave by pressing a button, so iḿ actually trying to copy the code from "consolesynth" inside my graphical program, thats what iḿ working on...

Hello.

All the "consoleXXX.lpi" demos are console applications, no GUI applications, all others are GUI demos..

Did you try, like proposed in previous post, SimplePlayer.lpi demo, it is a graphical application using LCL (Lazarus component) ?


I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Ramses

  • New Member
  • *
  • Posts: 41
Re: Generate square / sinusoidal waves
« Reply #26 on: January 17, 2021, 06:50:43 pm »
Did you try, like proposed in previous post, SimplePlayer.lpi demo, it is a graphical application using LCL (Lazarus component) ?

yes i tried it, but for what i understand, this demo is made to play a song from my computer, and i dont figure out how to generate sin/square wave from it.. so not really what i need.. or maybe i have not understand correctly how to use it?

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: Generate square / sinusoidal waves
« Reply #27 on: January 17, 2021, 07:05:24 pm »
Did you try, like proposed in previous post, SimplePlayer.lpi demo, it is a graphical application using LCL (Lazarus component) ?

yes i tried it, but for what i understand, this demo is made to play a song from my computer, and i dont figure out how to generate sin/square wave from it.. so not really what i need.. or maybe i have not understand correctly how to use it?

Ok, last try.

In the graghic application that you have done, in the procedure Button1Click, insert the code of procedure TuosConsole.ConsolePlay; from uos demo consoleplay.pas

inside your Button1Click.

 
Code: Pascal  [Select][+][-]
  1. program consolesynth;
  2. ...
  3.  
  4. procedure TuosConsole.ConsolePlay;
  5.   begin
  6.   ...
  7.   // Copy all the code inside
  8.   end;

And paste into your project. 

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3. // Insert the code of procedure TuosConsole.ConsolePlay;
  4. end;
« Last Edit: January 17, 2021, 07:10:27 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Generate square / sinusoidal waves
« Reply #28 on: January 17, 2021, 07:17:52 pm »
Not working HOW????? Where's your example code?????

Did you try putting Application.ProcessMessages in your loop which was the fallback suggestion? What happened?

i have not posted any exemple code, because i tried to follow like 5 or 6 tutorial about "multithreading" that i found on the web, so i decided to not post all those "test" i made.....

FFS man, I'm trying to /help/ here: you've said you've tried something but it didn't work for you so SHOW US WHAT YOU TRIED! Post the whole project with your attempt at threads and we'll try to sort you out.

Quote
For your last question, yes i have try putting Application.ProcessMessages: for example, have try to split the 10 second sound in 10 X 1 second song separate by "application.processmessages", but on the speaker the sound cut 10 time ( i hear a silence each time application.processmessages is called) ... i want to generate a wave with no "silence" in it..

When I said "you probably don't need it more than 10 times a second" I meant "don't call it every millisecond". I definitely didn't mean "call it every second", since apart from anything else if you do that then your GUI will only come to life once a second. What's more if you look at the example I pointed you at in my Github repository it EXPLICITLY says

Code: Pascal  [Select][+][-]
  1. (* Output the buffer, retrying/recovering as necessary. If this is irregular or *)
  2. (* results in error messages, try increasing the value in the latency parameter *)
  3. (* to snd_pcm_set_params() above.                                               *)
  4.  

I don't put comments into code purely for the fun of it...

Somewhat later: I've added an APM to the outer loop, which was trivial since it was only running at 20Hz. I've heard no jitter etc. so far.

MarkMLl
« Last Edit: January 18, 2021, 10:40:33 am by 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

Ramses

  • New Member
  • *
  • Posts: 41
Re: Generate square / sinusoidal waves
« Reply #29 on: January 17, 2021, 07:51:39 pm »
In the graghic application that you have done, in the procedure Button1Click, insert the code of procedure TuosConsole.ConsolePlay; from uos demo consoleplay.pas


Ok, i have do that, now i got an error when i compile
Quote
Threading has been used before cthreads was initialized.
Make cthreads one of the first units in your uses clause.


and my code now look like that:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.  {$IFDEF UNIX}
  9.   cthreads,
  10.  {$ENDIF}
  11.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
  12.   uos_flat;
  13.  
  14. type
  15.  
  16.   { TForm1 }
  17.  
  18.   TForm1 = class(TForm)
  19.     Button1: TButton;
  20.     procedure Button1Click(Sender: TObject);
  21.   private
  22.  
  23.   public
  24.  
  25.   end;
  26.  
  27. var
  28.   Form1: TForm1;
  29.          res, x, y, z: integer;
  30.   ordir, opath, SoundFilename, PA_FileName, PC_FileName, SF_FileName, MP_FileName: string;
  31.   PlayerIndex1, InputIndex1, OutputIndex1: integer;
  32.  
  33. implementation
  34.  
  35. {$R *.lfm}
  36.  
  37. { TForm1 }
  38.  
  39. procedure TForm1.Button1Click(Sender: TObject);
  40. begin
  41.             ordir := IncludeTrailingBackslash(ExtractFilePath(ParamStr(0)));
  42.  
  43.  {$IFDEF Windows}
  44.      {$if defined(cpu64)}
  45.     PA_FileName := ordir + 'lib\Windows\64bit\LibPortaudio-64.dll';
  46.     SF_FileName := ordir + 'lib\Windows\64bit\LibSndFile-64.dll';
  47.      {$else}
  48.     PA_FileName := ordir + 'lib\Windows\32bit\LibPortaudio-32.dll';
  49.     SF_FileName := ordir + 'lib\Windows\32bit\LibSndFile-32.dll';
  50.      {$endif}
  51.     SoundFilename := ordir + 'sound\test.ogg';
  52.  {$ENDIF}
  53.  
  54.      {$if defined(CPUAMD64) and defined(linux) }
  55.   SF_FileName := ordir + 'lib/Linux/64bit/LibSndFile-64.so';
  56.   PA_FileName := ordir + 'lib/Linux/64bit/LibPortaudio-64.so';
  57.     SoundFilename := ordir + 'sound/test.ogg';
  58.    {$ENDIF}
  59.  
  60.    {$if defined(cpu86) and defined(linux)}
  61.     PA_FileName := ordir + 'lib/Linux/32bit/LibPortaudio-32.so';
  62.     SF_FileName := ordir + 'lib/Linux/32bit/LibSndFile-32.so';
  63.    SoundFilename := ordir + 'sound/test.ogg';
  64.    {$ENDIF}
  65.  
  66.   {$if defined(linux) and defined(cpuaarch64)}
  67.   PA_FileName := ordir + 'lib/Linux/aarch64_raspberrypi/libportaudio_aarch64.so';
  68.   SF_FileName := ordir + 'lib/Linux/aarch64_raspberrypi/libsndfile_aarch64.so';
  69.   SoundFilename := ordir + 'sound/test.ogg';
  70.   {$ENDIF}
  71.  
  72.   {$if defined(linux) and defined(cpuarm)}
  73.     PA_FileName := ordir + 'lib/Linux/arm_raspberrypi/libportaudio-arm.so';
  74.     SF_FileName := ordir + ordir + 'lib/Linux/arm_raspberrypi/libsndfile-arm.so';
  75.       SoundFilename := ordir + 'sound/test.ogg';
  76.    {$ENDIF}
  77.  
  78.  {$IFDEF freebsd}
  79.     {$if defined(cpu64)}
  80.     PA_FileName := ordir + 'lib/FreeBSD/64bit/libportaudio-64.so';
  81.     SF_FileName := ordir + 'lib/FreeBSD/64bit/libsndfile-64.so';
  82.     {$else}
  83.     PA_FileName := ordir + 'lib/FreeBSD/32bit/libportaudio-32.so';
  84.     SF_FileName := ordir + 'lib/FreeBSD/32bit/libsndfile-32.so';
  85.     {$endif}
  86.     SoundFilename := ordir + 'sound/test.ogg';
  87.  {$ENDIF}
  88.  
  89.  {$IFDEF Darwin}
  90.   {$IFDEF CPU32}
  91.     opath := ordir;
  92.     opath := copy(opath, 1, Pos('/UOS', opath) - 1);
  93.     PA_FileName := opath + '/lib/Mac/32bit/LibPortaudio-32.dylib';
  94.     SF_FileName := opath + '/lib/Mac/32bit/LibSndFile-32.dylib';
  95.     SoundFilename := ordir + '/sound/test.ogg';
  96.     {$ENDIF}
  97.  
  98.    {$IFDEF CPU64}
  99.     opath := ordir;
  100.     opath := copy(opath, 1, Pos('/UOS', opath) - 1);
  101.     PA_FileName := opath + '/lib/Mac/64bit/LibPortaudio-64.dylib';
  102.     SF_FileName := opath + '/lib/Mac/64bit/LibSndFile-64.dylib';
  103.     SoundFilename := ordir + '/sound/test.ogg';
  104.     {$ENDIF}
  105.  {$ENDIF}
  106.  
  107.     // Load the libraries
  108.     // function uos_loadlib(PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName, FaadFileName,  opusfilefilename: PChar) : LongInt;
  109.  
  110.     res := uos_LoadLib(PChar(PA_FileName), PChar(SF_FileName), nil, nil, nil, nil);
  111.  
  112.     writeln;
  113.     if res = 0 then
  114.       writeln('Libraries are loaded.')
  115.     else
  116.       writeln('Libraries did not load.');
  117.  
  118.     if res = 0 then
  119.     begin
  120.       writeln();
  121.  
  122.       //    writeln('Libraries version: '+ uos_GetInfoLibraries());
  123.  
  124.       //// Create the player.
  125.       //// PlayerIndex : from 0 to what your computer can do !
  126.       //// If PlayerIndex exists already, it will be overwriten...
  127.  
  128.       PlayerIndex1 := 0;
  129.  
  130.       if uos_CreatePlayer(PlayerIndex1) then
  131.       begin
  132.  
  133.         //// add a Input from audio-file with default parameters
  134.         //////////// PlayerIndex : Index of a existing Player
  135.         ////////// FileName : filename of audio file
  136.         //  result : -1 nothing created, otherwise Input Index in array
  137.  
  138.         InputIndex1 := uos_AddFromFile(PlayerIndex1, PChar((SoundFilename)), -1, -1, -1);
  139.  
  140.  
  141.         writeln('InputIndex1 = ' + IntToStr(InputIndex1));
  142.  
  143.         if InputIndex1 > -1 then
  144.         begin
  145.           //// add a Output into device with default parameters
  146.           //////////// PlayerIndex : Index of a existing Player
  147.           //  result : -1 nothing created, otherwise Output Index in array
  148.  
  149.        {$if defined(cpuarm) or defined(cpuaarch64)}  // need a lower latency
  150.         OutputIndex1 := uos_AddIntoDevOut(PlayerIndex1, -1, 0.3, -1, -1, -1, -1, -1) ;
  151.        {$else}
  152.          //OutputIndex1 := uos_AddIntoDevOut(PlayerIndex1);
  153.           OutputIndex1 := uos_AddIntoDevOut(PlayerIndex1, -1, -1, -1, -1, -1, -1, -1);
  154.        {$endif}
  155.  
  156.           writeln('OutputIndex1 = ' + IntToStr(OutputIndex1));
  157.  
  158.         //   uos_AddIntoFile(PlayerIndex1,pchar('/home/fred/mytest.ogg'), -1, -1, -1, -1, 3);
  159.  
  160.           if OutputIndex1 > -1 then
  161.           begin
  162.  
  163.             /////// everything is ready, here we are, lets play it...
  164.  
  165.             uos_Play(PlayerIndex1);
  166.  
  167.             sleep(1000);
  168.             writeln;
  169.             writeln('Title: ' + uos_InputGetTagTitle(PlayerIndex1, InputIndex1));
  170.             sleep(1500);
  171.             writeln();
  172.             writeln('Artist: ' + uos_InputGetTagArtist(PlayerIndex1, InputIndex1));
  173.             writeln;
  174.  
  175.             sleep(2000);
  176.           end;
  177.         end;
  178.       end;
  179.     end;
  180.  
  181. end;
  182.  
  183. end.
  184.  

So my "cthreads" is the first in "uses", but it told me "Make cthreads one of the first units in your uses clause." I dont see what iḿ doing wrong..

 

TinyPortal © 2005-2018