Results 1 to 6 of 6

Thread: Mutlithreading

  1. #1
    PGD Staff code_glitch's Avatar
    Join Date
    Oct 2009
    Location
    UK (England, the bigger bit)
    Posts
    933
    Blog Entries
    45

    Mutlithreading

    In my quest for Prometheus_Audio I came across a small nuisance in how OpenAl works... Or rather common sense: I have to update buffers at least once every second at least.

    Prometheus is aimed at beginners, and I must say I'm not sure I want to tell them that if they want audio you have to call the update procedure at least once a second, depending on the bit rate of you audio file.

    My solution was to have Prometheus make a thread that would only run that loop.
    However, I did poke around for multi-threading and drew one major conclusion: headache. Anyways, always the optimist I thought it was easier than it looked and gave it a go. And guess what: I gots a headache too now...

    My question is: does anyone have a snippet that launches a thread that simply steps through a loop non-stop and how to get it working?

    Any help would be much appreciated; I'm totally confused d now...

    cheers,
    code_glitch
    I once tried to change the world. But they wouldn't give me the source code. Damned evil cunning.

  2. #2
    PGD Staff code_glitch's Avatar
    Join Date
    Oct 2009
    Location
    UK (England, the bigger bit)
    Posts
    933
    Blog Entries
    45
    Just another thing: I just finished this new version of Prometheus_Audio in OpenAl but no matter what I try I only get segmentation faults, exit codes and no sound:

    Code:
    unit Prometheus_Audio;
    
    {$Mode ObjFpc}
    
    interface
    
    uses
        sysutils,
        Classes,
        
        OpenAl;
    
    const
        ID_RIFF 				=	'RIFF';
        ID_WAVE 				=	'WAVE';
        ID_fmt  				=	'fmt ';
        ID_data 				=	'data';
    
        al_bufcount           		=	100;
        al_polltime           		=	1000;
    
        BufferSize				=	8192;
        
        MAX_AUDIOSTREAMS:	Int64		=	600;
    
    type
        TAlData = record
    	    Al_Device:		PALCdevice;
    	    Al_Context:		PALCcontext;
    	    Al_Source:		ALuint;
    	    Al_Format:		Integer;
    	    Al_Buffers:		array[0..al_bufcount-1] of ALuint;
    	    Al_Bufsize:		Longword;
    	    Al_Readbuf:		Pointer;
    	    Al_Rate:		Longword;
      
    	    Codec_bs:		Longword;
    	    Queued:		Integer;
    	end;
        TRiffHeader = record
    	    ID:			array [0..3] of char;
    	    Size:		Longword;
    	    Format:		array [0..3] of char;
    	end;
        TDataChunk = record
    	    Id:			array [0..3] of char;
    	    Size:		Longword;
    	end;
        TWaveFormat = record
    	    Id:			array [0..3] of char;
    	    Size:		Longword;
    	    Format:		Word;
    	    Channels:		Word;
    	    SampleRate:		Longword;
    	    ByteRate:		Longword;
    	    BlockAlign:		Word;
    	    BitsPerSample:	Word;
    	end;
        Audio = object
    	    Initialized:	Boolean;
    	    Loaded: 		Boolean;
    	    ChunkData:		TDataChunk;
    	    ChunkPos:		Int64;
    	    Pos:		Int64;
    	    EOF:		Boolean;
    	    fStream:		TStream;
    	    
    	    Result:		Boolean;
    	    
    	    Fmt: 		TWaveFormat;
    	    AlData:		TAlData;
    	    
    	    function ReadBuf(var Buffer; BufferSize: Integer): Integer;
    	    procedure Initialize();
    	end;
        pAudio = ^Audio;
        PrometheusAudioRec = record
    	    AudioStream:	array [1..600] of pAudio;
    	    ActiveStream:	array [1..600] of Boolean;
    	    TotalStreams:	Int64;
    	end;
    	
    var
        PrometheusAudio: PrometheusAudioRec;
    
    procedure LoadAudio(Src: String; Audio: pAudio);
    procedure PlayAudio(Audio: pAudio);
    procedure AudioProcess();
    
    implementation
    
    function AudioExists(Audio: pAudio): Boolean;
    var
        i: Int64;
        
    begin
        i := 0;
        repeat
    	i := i + 1;
    	until (i >= MAX_AUDIOSTREAMS) or (@PrometheusAudio.AudioStream[i] = @Audio);
    	
        if (i >= MAX_AUDIOSTREAMS) and (@PrometheusAudio.AudioStream[i] <> @Audio) then
    	AudioExists := False
        else
    	AudioExists := True;
    end;
    
    function Min(a,b: Integer): Integer;
    begin
      if a<b then Result:=a
      else Result:=b;
    end;
    
    procedure Audio.Initialize();
    begin
        
        AlData.Al_Bufsize := BufferSize;
        AlData.Al_Format := AL_FORMAT_STEREO16;
        AlData.Codec_bs := 2;
        AlData.Al_Device := alcOpenDevice(nil);
        AlData.Al_Context := alcCreateContext(AlData.Al_Device, nil);
        alcMakeContextCurrent(AlData.Al_Context);
        AlData.Al_Rate := 44100;
        
        AlDistanceModel( Al_Inverse_Distance_Clamped);
        AlGenSources(1, @AlData.Al_Source);
        AlGenBuffers(al_bufcount, @AlData.Al_Buffers);
        
        GetMem(AlData.Al_Readbuf, AlData.Al_Bufsize);
        
        Initialized := True;
    end;
    
    function Audio.ReadBuf(var Buffer; BufferSize: Integer): Integer;
    var
        Sz:		Integer;
        P:		PByteArray;
        I:		Integer;
    
    begin
        if Initialized = False then
    	Initialize();
    	
        FillChar(Buffer, BufferSize, 0);
        Result := 0;
        
        if eof then Exit;
        
        p := @Buffer;
         
        I := 0;
        while (not EOF) and (i < BufferSize) do
    	begin
    	    if ChunkPos >= ChunkData.Size then
    		begin
    		    if Pos < 0 then
    			fStream.Position := SizeOf(TRiffHeader) + Int64(Fmt.Size) + SizeOf(TDataChunk)
    		    else
    			fStream.Position := Pos + ChunkData.Size + SizeOf(ChunkData);
    		    
    		    EOF := pos >= fStream.Size;
    		    if not EOF then
    			begin
    			    Pos := fStream.Position;
    			    Sz := fStream.Read(ChunkData, SizeOf(ChunkData));
    			    ChunkData.Size := LEtoN(ChunkData.Size);
    			    if (Sz <> SizeOf(ChunkData)) or (ChunkData.Id <> ID_data) then
    				ChunkPos := ChunkData.Size
    			    else
    				ChunkPos := 0;
    			end;
    		end
    	    else
    		begin
    		    Sz := Min(BufferSize, ChunkData.Size - ChunkPos);
    		    fStream.Position := Pos + SizeOf(ChunkData) + ChunkPos;
    		    Sz := fStream.Read(P[I], Sz);
    		    if Sz < 0 then
    			exit;
    		    inc(ChunkPos, Sz);
    		    inc(I, Sz);
    		end;
    	end;
    end;
    
    procedure LoadAudio(Src: String; Audio: pAudio);
    var
        Riff:	TRiffHeader;
    
    begin
        if Audio^.Initialized = False then
    	Audio^.Initialize;
    	
        Audio^.fStream := TFileStream.Create(Src, fmOpenRead);
        
        Audio^.Loaded := True;
        
        try
    	Audio^.Result := Audio^.fStream.Read(Riff, SizeOf(Riff)) = SizeOf(Riff);
    	Riff.Size := LEtoN(Riff.Size);
    	
    	Audio^.Result := Audio^.Result and (Riff.ID = ID_RIFF) and (Riff.Format = ID_WAVE);
    	
    	if not Audio^.Result then
    	    Exit;
    	
    	Audio^.Result := Audio^.fStream.Read(Audio^.Fmt, SizeOf(Audio^.Fmt)) = SizeOf(Audio^.Fmt);
    	Audio^.Fmt.Size := LEtoN(Audio^.Fmt.Size);
    	Audio^.Fmt.Format := LEtoN(Audio^.Fmt.Format);
    	Audio^.Fmt.Channels := LEtoN(Audio^.Fmt.Channels);
    	Audio^.Fmt.SampleRate := LEtoN(Audio^.Fmt.SampleRate);
    	Audio^.Fmt.ByteRate := LEtoN(Audio^.Fmt.ByteRate);
    	Audio^.Fmt.BlockAlign := LEtoN(Audio^.Fmt.BlockAlign);
    	Audio^.Fmt.BitsPerSample := LEtoN(Audio^.Fmt.BitsPerSample);
    	
    	Audio^.Result := Audio^.Fmt.ID = ID_FMT;
    	Audio^.Pos := -1;
        except
    	Audio^.Result := False;
    	Exit;
        end;
        
        if AudioExists(Audio) = False then
    	begin
    	    PrometheusAudio.ActiveStream[PrometheusAudio.TotalStreams + 1] := True;
    	    PrometheusAudio.AudioStream[PrometheusAudio.TotalStreams + 1] := Audio;
    	    PrometheusAudio.TotalStreams := PrometheusAudio.TotalStreams + 1;
    	end;
    end;
    
    procedure PlayAudio(Audio: pAudio);
    var
        i: 		Int64;
    
    begin
        alSourceStop(Audio^.AlData.Al_Source);
        alSourceRewind(Audio^.AlData.Al_Source);
        alSourcei(Audio^.AlData.Al_Source, Al_Buffer, 0);
        
        
        for i := 0 to al_bufcount - 1 do
    	begin
    	    if Audio^.ReadBuf(Audio^.AlData.Al_Readbuf^, Audio^.AlData.Al_Bufsize) = 0 then
    		break;
    	    alBufferData(Audio^.AlData.Al_Buffers[i], Audio^.AlData.Al_Format, Audio^.AlData.Al_Readbuf, Audio^.AlData.Al_BufSize, Audio^.AlData.Al_Rate);
    	    alSourceQueueBuffers(Audio^.AlData.Al_Source, 1, @Audio^.AlData.Al_Buffers[i]);
    	end;
        
        
        alSourcei(Audio^.AlData.Al_Source, Al_Looping, AL_False);
        alSourcePlay(Audio^.AlData.Al_Source);
    end;
    
    function AlSubProcess(Audio: pAudio): Boolean;
    var
        Processed:	ALint;
        Buffer:	ALuint;
        Sz:		Integer;
    
    begin
        
        alGetSourcei(Audio^.AlData.Al_Source, Al_Buffers_Processed, Processed);
        while (processed > 0) and (processed <= al_bufcount) do
    	begin
    	    alSourceUnqueueBuffers(Audio^.AlData.Al_Source, 1, @Buffer);
    	    
    	    Sz := Audio^.ReadBuf(Audio^.AlData.Al_Readbuf, Audio^.AlData.Al_Bufsize);
    	    if Sz <= 0 then
    		begin
    		    Exit(False);
    		end;
    	    
    	    alBufferData(Buffer, Audio^.AlData.Al_Format, Audio^.AlData.Al_Readbuf, Sz, Audio^.AlData.Al_Rate);
    	    alSourceQueueBuffers(Audio^.AlData.Al_Source, 1, @Buffer);
    	    
    	    Dec(Processed);
    	end;
        
        Result := True;
    end;
    
    procedure AudioProcess();
    var
        i: Int64;
    
    begin
        i := 0;
        repeat
    	 i := i + 1;
    	 if PrometheusAudio.ActiveStream[i] = True then
    	    alSubProcess(PrometheusAudio.AudioStream[i]);
    	until i >= MAX_AUDIOSTREAMS;
    end;
    
    end.
    can any of you OpenAl savvy people see what's gone wrong in this? I suspect PlayAudio, LoadAudio and Audio.Initialize but cant see any errors... Sorry for the long code, but I trimmed it down as much as I could. Cheers for any help.
    I once tried to change the world. But they wouldn't give me the source code. Damned evil cunning.

  3. #3
    Sure. Here's a snippet using TThread

    Code:
    type
     TSomeThreadClass = class(TThread)
     protected
      procedure Execute; override;
     end;
    
    procedure TSomeThreadClass.Execute;
    begin
       //Initialize Stuff
       while not Terminated do
       begin
          //Do something
          //You may want to put a sleep(10) or something depending on how long time the task takes
       end;
       //Clean up stuff
    end;
    
    ...
    
    var SoundThread: TSomeThreadClass;
    begin
       SoundThread := TSomeThreadClass.Create(false); //Create the thread, s
       ...
       SoundThread.Terminate; //Tell thread to stop
       SoundThread.WaitFor; //Wait until thread exits
       SoundThread.Free;
    end;
    Peregrinus, expectavi pedes meos in cymbalis
    Nullus norvegicorum sole urinat

  4. #4
    PGD Staff code_glitch's Avatar
    Join Date
    Oct 2009
    Location
    UK (England, the bigger bit)
    Posts
    933
    Blog Entries
    45
    cheers for that. Will start experimenting ASAP.
    I once tried to change the world. But they wouldn't give me the source code. Damned evil cunning.

  5. #5
    I had similar problems when I was coding http://www.1clickmusic.net on the past, but with DirectSound. Your solution is the right one
    From brazil (:

    Pascal pownz!

  6. #6
    PGD Staff code_glitch's Avatar
    Join Date
    Oct 2009
    Location
    UK (England, the bigger bit)
    Posts
    933
    Blog Entries
    45
    Any thoughts on whats causing the audio screwup I posted about earlier? I posted it in this thread to avoid clutter since they were a bit related...
    I once tried to change the world. But they wouldn't give me the source code. Damned evil cunning.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •