PDA

View Full Version : Mutlithreading



code_glitch
21-11-2010, 04:08 PM
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. 8)
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

code_glitch
21-11-2010, 05:07 PM
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:




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.

JSoftware
21-11-2010, 06:34 PM
Sure. Here's a snippet using TThread



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;

code_glitch
21-11-2010, 07:02 PM
cheers for that. Will start experimenting ASAP.

arthurprs
22-11-2010, 02:45 PM
I had similar problems when I was coding http://www.1clickmusic.net on the past, but with DirectSound. Your solution is the right one :)

code_glitch
22-11-2010, 05:40 PM
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...