Hello everybody.
Have problems with Windows...
I want to do working many threads together and independently.
With Linux and OSX Thread.Start works great but with Windows it does not work.
In the code that follow at line 473 :
UOSSTREAM[x].Thread.Start;
Does not work with Windows, it only works with :
UOSSTREAM[x].Thread.Execute;
But then i cannot do Threads working together.
Here the full code.
Whats wrong ?
unit U_OS;
{*******************************************************************************
* United Openlibraries of Sound ( U_OS ) *
* -------------------------------------- *
* *
* United procedures to access Open Sound libraries *
* *
* *
* Lazarus Forum / Fred van Stappen / Fiens@hotmail.com *
* *
********************************************************************************
* second realease first changes: 2012-07-20 *
* second changes: 2012-07-31 *
* 3 th changes: 2012-11-13 * *
*******************************************************************************}
interface
uses
Classes, Forms, SysUtils, dialogs ,LazDyn_PortAudio, LazDyn_LibSndFile, LazDyn_Mpg123;
const
///// error
noError = 0;
FilePAError = 10;
LoadPAError = 11;
FileSFError = 20;
LoadSFError = 21;
FileMPError = 30;
LoadMPError = 31;
//////// UOS_load() flag
LoadAll = 0; // load all PortAudio + SndFile + MPG123
LoadPA = 1; // load only PortAudio
LoadSF = 2; // load only SndFile
LoadMP = 3; // load only MPG123
LoadPA_SF = 4; // load only PortAudio + SndFile
LoadPA_MP = 5; // load only PortAudio + MPG123
LoadSF_MP = 6; // load only SndFile + MPG123
Samplerate_root = 0;
type
TUOSThread = class(TThread)
private
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: boolean);
end;
type
TLoadResult = record
PAloadERROR : shortint;
SFloadERROR : shortint;
MPloadERROR : shortint;
PAinitError : integer;
MPinitError : integer;
end;
type
TStreaminfo= record
streamname : string;
Stream : PPaStream;
thread : TUOSThread;
StreamisOpen : boolean ;
DEVICE : integer ;
LATENCY : integer ;
OutputParameters : PaStreamParameters;
handle : pointer;
SFopenError : shortint;
MPopenError : shortint;
SFoutbuf : array [0..2047] of byte ;
MPoutbuf : array [0..2047] of byte ;
{$IFDEF Win32} //// Only Windows 32 bits
BufFrames : cardinal;
OutFrames : cardinal;
{$else}
BufFrames : Tsf_count_t;
OutFrames : Tsf_count_t;
{$endif}
Filename : string;
Status : shortint; //// stop = 0, play = 1, pause = 2
channels : integer;
format : integer;
frames : integer;
samplerateroot : integer;
samplerate : integer;
sections : integer;
seekable : integer;
encoding : integer;
title : string;
copyright : string;
software : string;
artist : string;
comment : string;
date : string;
tag : array[0..2] of Char; (**< Always the string "TAG", the classic intro. *)
album : string; (**< Album string. *)
genre : byte; (**< Genre index. *)
end;
var
UOSLoadFlag : shortint ;
UOSLoadResult : TLoadResult;
UOSDefOut : PaDeviceIndex;
UOSDEVinfo : PPaDeviceInfo;
UOSAPIinfo : PPaHostApiInfo;
UOSSTREAM : array of Tstreaminfo;
UOSSTREAMNUM : integer;
procedure UOS_Load(PA_FileName,SF_FileName,MP_FileName : AnsiString ; flag : shortint ); /////////// dynamic load libraries
procedure UOS_UnLoad() ;
procedure UOS_Init() ; ////// init libraries
procedure UOS_CreateStream(Soundfile:ansistring;UOS_STREAMNAME:string; SAMPLERATE:integer ; DEVICE:integer ; CHANNELS :integer; LATENCY:integer; SAMPLEFORMAT : string) ;
////////////// at Samplerate ( -1 is samplerate of Soundfile) ,
///////////// with device ( -1 is default device )
//////////////// with number of channels (-1 = channels of soundfile, 2 = stereo, -)
///////////// at latency ( -1 is latency suggested ) )
///////////// with sampleformat : int8 or int16 or int24 or int32 or float32
//////////// example : UOS_CreateStream('/home/user/test.mp3','testStream',-1,-1,-1,-1,'int16');
procedure UOS_Play(UOS_STREAMNAME:string) ; ////// or resume if song was paused
procedure UOS_Stop(UOS_STREAMNAME:string) ;
procedure UOS_Pause(UOS_STREAMNAME:string) ;
//procedure UOS_Position() ; // to do ....
implementation
procedure UOS_Stop(UOS_STREAMNAME:string) ;
var
x : integer ;
begin
x := 0 ;
while (x < ( Length(UOSSTREAM)) ) do begin
if (UOSSTREAM[x].streamname = UOS_STREAMNAME) then
begin
UOSSTREAM[x].status := 0 ;
exit;
end;
x := x + 1 ;
end;
end;
procedure UOS_Pause(UOS_STREAMNAME:string) ;
var
x : integer ;
begin
x := 0 ;
while (x < ( Length(UOSSTREAM)) ) do begin
if (UOSSTREAM[x].streamname = UOS_STREAMNAME) then
begin
UOSSTREAM[x].Status := 2 ;
exit;
end;
x := x + 1 ;
end;
end;
procedure UOS_CreateStream(Soundfile:ansistring;UOS_STREAMNAME:string; SAMPLERATE:integer ; DEVICE:integer ; CHANNELS :integer; LATENCY:integer; SAMPLEFORMAT : string) ; /// sampleformat : int8 or int16 or int24 or int32 or float32
var
x, x2, err : integer ;
sfInfo : TSF_INFO;
begin
if not fileexists(Soundfile) then MessageDlg (Soundfile + ' do not exists...', mtWarning,[mbYes],0) else
begin
x2 := 0 ;
err := -1 ;
while (x2 < ( Length(UOSSTREAM)) ) and (err <> 1) do begin
application.ProcessMessages;
if UOSSTREAM[x2].streamname = UOS_STREAMNAME then
begin
if UOSSTREAM[x2].StreamisOpen = true then
begin
UOSSTREAM[x2].status := 0 ;
application.ProcessMessages;
sleep(150) ; /////// < buffers need time to release (on some systems) !!!!
application.ProcessMessages;
end;
err := 1 ;
x := x2;
end;
x2 := x2 + 1
end;
x2 := 0 ;
if err = -1 then
while ( x2 < Length(UOSSTREAM)) and (err <> 2) do begin
if (UOSSTREAM[x2].streamname = '') then
begin
UOSSTREAM[x2].streamname:= UOS_STREAMNAME ;
UOSSTREAM[x2].status := 0 ;
UOSSTREAM[x2].StreamisOpen := false ;
x := x2 ;
err := 2 ;
end;
x2 := x2+1 ;
end;
if err = -1 then
begin
SetLength(UOSSTREAM, Length(UOSSTREAM) + 1) ;
UOSSTREAM[Length(UOSSTREAM)-1].streamname:= UOS_STREAMNAME ;
err := 0 ;
x := Length(UOSSTREAM)-1 ;
UOSSTREAM[x].StreamisOpen := false ;
UOSSTREAM[x].status := 0 ;
end;
if err <> -1 then begin
if UOSSTREAM[x].StreamisOpen = false then begin
if device = -1 then
UOSSTREAM[x].OutputParameters.Device := UOSDefOut else
UOSSTREAM[x].OutputParameters.Device := DEVICE;
if SAMPLEFORMAT = 'int8' then
UOSSTREAM[x].OutputParameters.SampleFormat := paint8 else
if SAMPLEFORMAT = 'int16' then
UOSSTREAM[x].OutputParameters.SampleFormat := paint16 else
if SAMPLEFORMAT = 'int32' then
UOSSTREAM[x].OutputParameters.SampleFormat := paint32 else
if SAMPLEFORMAT = 'float32' then
UOSSTREAM[x].OutputParameters.SampleFormat := pafloat32 else
UOSSTREAM[x].OutputParameters.SampleFormat := paint16 ;
if LATENCY = -1 then
UOSSTREAM[x].OutputParameters.SuggestedLatency :=
(Pa_GetDeviceInfo( UOSSTREAM[x].OutputParameters.device)^.defaultHighOutputLatency) * 1
else UOSSTREAM[x].OutputParameters.SuggestedLatency := Latency;
UOSSTREAM[x].OutputParameters.HostApiSpecificStreamInfo := nil;
UOSSTREAM[x].StreamisOpen := false ;
end;
end;
////////////////////////////
err := -1;
UOSSTREAM[x].MPopenError := - 1;
UOSSTREAM[x].SFOpenError := - 1;
if (UOSloadresult.SFloadERROR = 0) and ((UOSloadflag = LoadAll) or (UOSloadflag = LoadSF) or (UOSloadflag = LoadPA_SF) or
(UOSloadflag = LoadSF_MP)) then begin
UOSSTREAM[x].handle := sf_open(pchar(Soundfile),SFM_READ,sfInfo) ; (* try to open the file *)
If UOSSTREAM[x].handle = NIL then
begin
UOSSTREAM[x].SFOpenError := 1 ;
end
else
begin
UOSSTREAM[x].SFOpenError := 0;
UOSSTREAM[x].filename := Soundfile ;
UOSSTREAM[x].channels := SFinfo.channels;
UOSSTREAM[x].format := SFinfo.format;
UOSSTREAM[x].frames := SFinfo.frames;
UOSSTREAM[x].samplerate := SFinfo.samplerate;
UOSSTREAM[x].samplerateroot := SFinfo.samplerate;
UOSSTREAM[x].sections := SFinfo.sections;
UOSSTREAM[x].seekable := SFinfo.seekable;
UOSSTREAM[x].copyright:= sf_get_string(UOSSTREAM[x].handle,SF_STR_COPYRIGHT);
UOSSTREAM[x].software:= sf_get_string(UOSSTREAM[x].handle,SF_STR_SOFTWARE);
UOSSTREAM[x].comment:= sf_get_string(UOSSTREAM[x].handle,SF_STR_COMMENT);
UOSSTREAM[x].date := sf_get_string(UOSSTREAM[x].handle,SF_STR_DATE);
UOSSTREAM[x].BufFrames:= length(UOSSTREAM[x].SFoutbuf) ;
err := 0;
end;
end;
if ((UOSSTREAM[x].SFOpenError = 1) or (UOSSTREAM[x].SFOpenError = -1)) and (UOSLoadresult.MPloadERROR = 0)
and ((UOSloadflag = LoadAll) or (UOSloadflag = LoadMP) or (UOSloadflag = LoadPA_MP) or
(UOSloadflag = LoadSF_MP)) then begin
Err := -1;
UOSSTREAM[x].handle := mpg123_new( NIL, Err);
if Err = 0 then mpg123_open(UOSSTREAM[x].handle,pchar(Soundfile))
else UOSSTREAM[x].MPOpenError := 1 ;
if Err = 0 then Err := mpg123_getformat( UOSSTREAM[x].handle, UOSSTREAM[x].samplerate , UOSSTREAM[x].channels, UOSSTREAM[x].encoding) ;
if Err = 0 then begin
UOSSTREAM[x].MPOpenError := 0;
UOSSTREAM[x].filename := Soundfile ;
UOSSTREAM[x].samplerateroot := UOSSTREAM[x].samplerate;
UOSSTREAM[x].BufFrames:= length(UOSSTREAM[x].MPoutbuf) ;
end else UOSSTREAM[x].MPOpenError := 2 ;
end;
if err <> 0 then begin
MessageDlg ('Cannot Open ' + Soundfile + '...', mtWarning,[mbYes],0) ;
exit;
end
else begin
UOSSTREAM[x].streamname := UOS_STREAMNAME ;
UOSSTREAM[x].status := 0;
UOSSTREAM[x].StreamisOpen := false;
UOSSTREAM[x].OutFrames := 0;
if CHANNELS = -1 then UOSSTREAM[x].OutputParameters.channelCount:= UOSSTREAM[x].channels
else UOSSTREAM[x].OutputParameters.channelCount:= CHANNELS;
if SAMPLERATE = -1 then
Pa_OpenStream(@UOSSTREAM[x].Stream, nil, @UOSSTREAM[x].OutputParameters, UOSSTREAM[x].samplerate ,
64, paClipOff, nil,nil)
else Pa_OpenStream(@UOSSTREAM[x].Stream, nil, @UOSSTREAM[x].OutputParameters,SAMPLERATE ,
64, paClipOff, nil,nil) ;
////////////////
application.ProcessMessages;
UOSSTREAM[x].Thread := TUOSThread.Create(True); // With the True parameter it doesn't start automatically
UOSSTREAM[x].thread.FreeOnTerminate:=true;
if Assigned(UOSSTREAM[x].Thread.FatalException) then
raise UOSSTREAM[x].Thread.FatalException;
application.ProcessMessages
end;
end;
end;
/////////////////////
procedure TUOSThread.Execute;
VAR
x , err : integer ;
begin
x := UOSSTREAMNUM ;
if (UOSSTREAM[x].status = 1) and (UOSSTREAM[x].StreamisOpen = false) then
begin
UOSSTREAM[x].StreamisOpen := true;
Pa_StartStream(UOSSTREAM[X].stream) ;
application.ProcessMessages;
////////////////////////////////////////////////////
repeat
application.ProcessMessages;
if (UOSSTREAM[x].Status = 1) and (UOSSTREAM[x].handle <> nil) then
begin
if UOSSTREAM[x].SFOpenError = 0 then
begin
UOSSTREAM[x].OutFrames:= sf_read_short(UOSSTREAM[x].handle, @UOSSTREAM[x].SFoutbuf[0], UOSSTREAM[x].BufFrames ) ;
if (UOSSTREAM[x].OutFrames < UOSSTREAM[x].BufFrames) then UOSSTREAM[x].status := 0;
end
else if UOSSTREAM[x].MPOpenError = 0 then
begin
mpg123_read( UOSSTREAM[x].handle, @UOSSTREAM[x].MPoutbuf[0], UOSSTREAM[x].BufFrames, UOSSTREAM[x].OutFrames ) ;
if (UOSSTREAM[x].OutFrames < UOSSTREAM[x].BufFrames) then UOSSTREAM[x].status := 0;
end;
application.ProcessMessages;
if (UOSSTREAM[x].Status = 1) and (UOSSTREAM[x].handle <> nil) then
begin
if UOSSTREAM[x].SFOpenError = 0 then
begin
Pa_WriteStream( UOSSTREAM[x].Stream,@UOSSTREAM[x].SFoutbuf[0],Length(UOSstream[x].SFoutbuf) div 2) ;
end
else if UOSSTREAM[x].MPOpenError = 0 then
begin
Pa_WriteStream( UOSSTREAM[x].Stream,@UOSSTREAM[x].MPoutbuf[0],Length(UOSstream[x].MPoutbuf) div 4) ;
end;
end ;
end;
if UOSSTREAM[x].Status = 2 then
begin
sleep(100);
end;
err := 0;
application.ProcessMessages; //////////// important if we want to do something else in the program !
if UOSSTREAM[x].Status = 0 then err := 1 ;
until (err = 1);
end;
if(err = 1) then
begin
Pa_StopStream(UOSSTREAM[x].Stream);
Pa_CloseStream(UOSSTREAM[x].Stream);
UOSSTREAM[x].StreamisOpen := false ;
if UOSSTREAM[x].SFOpenError = 0 then sf_close(UOSSTREAM[x].handle);
if UOSSTREAM[x].MPOpenError = 0 then mpg123_close(UOSSTREAM[x].handle);
UOSSTREAM[x].thread.Terminate;
application.ProcessMessages;
end;
end;
////////////////////////////////////////////////////////////////////////////////////
procedure UOS_Play(UOS_STREAMNAME:string) ;
var
x : integer ;
begin
x := 0 ;
application.ProcessMessages;
while (x < ( Length(UOSSTREAM)) ) do begin
if(UOSSTREAM[x].streamname = UOS_STREAMNAME) then
begin
UOSSTREAM[x].Status := 1 ;
UOSSTREAMNUM := x ;
application.ProcessMessages;
UOSSTREAM[x].Thread.Start; //////// < here line 473 : Working with Linux and OSX, not Windows.
exit ;
end;
x := x + 1 ;
end;
end;
////////////////////////////////////////////////////////////////////
procedure UOS_Unload() ;
begin
Sf_Unload();
Mp_Unload();
Pa_Unload();
end;
///////////////////////////////////////////////////////////////////////////////
procedure UOS_Init() ;
begin
if (UOSLoadResult.MPloadERROR = 0) and ((UOSloadflag = LoadAll) or (UOSloadflag = LoadMP) or (UOSloadflag = LoadPA_MP) or
(UOSloadflag = LoadSF_MP)) then if mpg123_init()=MPG123_OK then UOSLoadResult.MPinitError := 0 else UOSLoadResult.MPinitError := 1;
IF (UOSLoadResult.PAloadERROR = 0) and ((UOSloadflag = LoadAll) or (UOSloadflag = LoadPA) or
(UOSloadflag = LoadPA_SF) or (UOSloadflag = LoadPA_MP)) Then begin
UOSLoadResult.PAinitError := Pa_Initialize();
if UOSLoadResult.PAinitError = 0 then begin
UOSDefOut := Pa_GetDefaultOutputDevice();
UOSDEVinfo:= Pa_GetDeviceInfo(UOSDefOut);
UOSAPIinfo:= Pa_GetHostApiInfo(UOSDEVinfo^.hostApi);
end;
end;
end;
procedure UOS_Load( PA_FileName,SF_FileName,MP_FileName : AnsiString ; flag : shortint ) ;
begin
UOSloadflag := flag ;
case flag of
LoadAll : begin
if not fileexists(PA_FileName) then UOSLoadResult.PAloadERROR:= 1 else
if Pa_Load (PA_FileName) then UOSLoadResult.PAloadERROR:= 0 else UOSLoadResult.PAloadERROR:= 2 ;
if not fileexists(SF_FileName) then UOSLoadResult.SFloadERROR:= 1 else
if Sf_Load (SF_FileName) then UOSLoadResult.SFloadERROR:= 0 else UOSLoadResult.SFloadERROR:= 2 ;
if not fileexists(MP_FileName) then UOSLoadResult.MPloadERROR := 1 else
if mp_Load (Mp_FileName) then UOSLoadResult.MPloadERROR := 0 else UOSLoadResult.MPloadERROR := 2 ;
end;
LoadPA : begin
if not fileexists(PA_FileName) then UOSLoadResult.PAloadERROR:= 1 else
if Pa_Load (PA_FileName) then UOSLoadResult.PAloadERROR:= 0 else UOSLoadResult.PAloadERROR:= 2 ;
end;
LoadSF : begin
if not fileexists(SF_FileName) then UOSLoadResult.SFloadERROR:= 1 else
if Sf_Load (SF_FileName) then UOSLoadResult.SFloadERROR:= 0 else UOSLoadResult.SFloadERROR:= 2 ;
end;
LoadMP : begin
if not fileexists(MP_FileName) then UOSLoadResult.MPloadERROR := 1 else
if mp_Load (Mp_FileName) then UOSLoadResult.MPloadERROR := 0 else UOSLoadResult.MPloadERROR := 2 ;
end;
LoadPA_SF : begin
if not fileexists(PA_FileName) then UOSLoadResult.PAloadERROR:= 1 else
if Pa_Load (PA_FileName) then UOSLoadResult.PAloadERROR:= 0 else UOSLoadResult.PAloadERROR:= 2 ;
if not fileexists(SF_FileName) then UOSLoadResult.SFloadERROR:= 1 else
if Sf_Load (SF_FileName) then UOSLoadResult.SFloadERROR:= 0 else UOSLoadResult.SFloadERROR:= 2 ;
end;
LoadPA_MP : begin
if not fileexists(MP_FileName) then UOSLoadResult.MPloadERROR := 1 else
if MP_Load (Mp_FileName) then UOSLoadResult.MPloadERROR := 0 else UOSLoadResult.MPloadERROR := 2 ;
if not fileexists(PA_FileName) then UOSLoadResult.PAloadERROR:= 1 else
if Pa_Load (PA_FileName) then UOSLoadResult.PAloadERROR:= 0 else UOSLoadResult.PAloadERROR:= 2 ;
end;
LoadSF_MP : begin
if not fileexists(SF_FileName) then UOSLoadResult.SFloadERROR:= 1 else
if SF_Load (SF_FileName) then UOSLoadResult.SFloadERROR:= 0 else UOSLoadResult.SFloadERROR:= 2 ;
if not fileexists(MP_FileName) then UOSLoadResult.MPloadERROR := 1 else
if mp_Load (Mp_FileName) then UOSLoadResult.MPloadERROR := 0 else UOSLoadResult.MPloadERROR := 2 ;
end;
end;
end;
constructor TUOSThread.Create(CreateSuspended: boolean);
begin
FreeOnTerminate := True;
inherited Create(CreateSuspended);
end;
initialization
SetLength(UOSSTREAM, 1) ;
UOSLoadResult.PAloadERROR := -1 ;
UOSLoadResult.SFloadERROR := -1 ;
UOSLoadResult.MPloadERROR := -1 ;
UOSLoadResult.PAinitError := -1 ;
UOSLoadResult.MPinitError := -1 ;
end.