From 95a37b7c82be7c95013781819a41cd0e5bc406b8 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Mon, 23 Jan 2012 10:43:32 +0000 Subject: [PATCH] fpsound: Starts adjusting the openal code git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2261 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/fpsound/example/mainform.lfm | 3 +- components/fpsound/example/mainform.pas | 12 +- components/fpsound/example/soundtest.lpi | 3 - components/fpsound/fpsound.pas | 70 ++++++++++- components/fpsound/fpsound_openal.pas | 142 ++++++++++++----------- components/fpsound/fpsound_wav.pas | 1 + 6 files changed, 154 insertions(+), 77 deletions(-) diff --git a/components/fpsound/example/mainform.lfm b/components/fpsound/example/mainform.lfm index 01333fb4f..095e09fbc 100644 --- a/components/fpsound/example/mainform.lfm +++ b/components/fpsound/example/mainform.lfm @@ -6,6 +6,7 @@ object Form1: TForm1 Caption = 'Form1' ClientHeight = 240 ClientWidth = 320 + OnCreate = FormCreate LCLVersion = '0.9.31' object btnOpenPlayAndClose: TButton Left = 12 @@ -18,7 +19,7 @@ object Form1: TForm1 end object pathEdit: TFileNameEdit Left = 12 - Height = 25 + Height = 21 Top = 13 Width = 268 FileName = '/home/felipe/Programas/lazarus-ccr/components/fpsound/testsounds/test.wav' diff --git a/components/fpsound/example/mainform.pas b/components/fpsound/example/mainform.pas index 00c64f62f..acc8546f0 100644 --- a/components/fpsound/example/mainform.pas +++ b/components/fpsound/example/mainform.pas @@ -16,6 +16,7 @@ type btnOpenPlayAndClose: TButton; pathEdit: TFileNameEdit; procedure btnOpenPlayAndCloseClick(Sender: TObject); + procedure FormCreate(Sender: TObject); private { private declarations } public @@ -39,7 +40,16 @@ var begin lSoundDoc := TSoundDocument.Create; lSoundDoc.LoadFromFile(pathEdit.FileName); - lSoundDoc.Free; + lSoundDoc.SetSoundPlayer(spOpenAL); + lSoundDoc.Play; +end; + +procedure TForm1.FormCreate(Sender: TObject); +begin + {$ifdef Windows} + pathEdit.FileName := ExtractFilePath(Application.ExeName) + '..\testsounds\test.wav'; + pathEdit.FileName := SysUtils.ExpandFileName(pathEdit.FileName); + {$endif} end; end. diff --git a/components/fpsound/example/soundtest.lpi b/components/fpsound/example/soundtest.lpi index 714ac7fa2..ce81d055a 100644 --- a/components/fpsound/example/soundtest.lpi +++ b/components/fpsound/example/soundtest.lpi @@ -68,9 +68,6 @@ - - - diff --git a/components/fpsound/fpsound.pas b/components/fpsound/fpsound.pas index 0e93b6584..ef8947afe 100644 --- a/components/fpsound/fpsound.pas +++ b/components/fpsound/fpsound.pas @@ -35,7 +35,11 @@ type TSoundPlayer = class public constructor Create; virtual; + procedure Initialize; virtual; abstract; + procedure Finalize; virtual; abstract; procedure Play(ASound: TSoundDocument); virtual; abstract; + procedure Pause(ASound: TSoundDocument); virtual; abstract; + procedure Stop(ASound: TSoundDocument); virtual; abstract; end; // Sound data representation @@ -46,12 +50,22 @@ type // A Key element sets the basic information of the music for the following samples, // such as sample rate. It has no sample data in itself TSoundKeyElement = class(TSoundElement) + public SampleRate: Cardinal; // example values: 8000, 44100, etc. + BitsPerSample: Byte; // Tipical values: 8 and 16 Channels: Byte; // Number of channels end; TSoundSample = class(TSoundElement) - ChannelValues: array of Integer; + public + ChannelValues: array of SmallInt; + end; + + { TSoundThread } + + TSoundThread = class(TThread) + protected + procedure Execute; override; end; { TSoundDocument } @@ -60,6 +74,7 @@ type private AStream: TStream; FPlayer: TSoundPlayer; + FCurElementIndex: Integer; FSoundData: TFPList; // of TSoundElement public constructor Create; virtual; @@ -71,9 +86,14 @@ type // Document edition methods procedure Clear; procedure AddSoundElement(const AElement: TSoundElement); + function GetSoundElement(const AIndex: Integer): TSoundElement; + function GetSoundElementCount: Integer; + function GetFirstSoundElement: TSoundKeyElement; + function GetNextSoundElement: TSoundElement; // Document playing methods procedure Play; procedure Pause; + procedure Stop; procedure Seek(ANewPos: Double); procedure SetSoundPlayer(AKind: TSoundPlayerKind); end; @@ -110,6 +130,13 @@ begin Result := GSoundReaders[AFormat]; end; +{ TSoundThread } + +procedure TSoundThread.Execute; +begin + +end; + { TSoundPlayer } constructor TSoundPlayer.Create; @@ -187,24 +214,61 @@ begin FSoundData.Add(AElement); end; +function TSoundDocument.GetSoundElement(const AIndex: Integer): TSoundElement; +begin + Result := TSoundElement(FSoundData.Items[AIndex]); +end; + +function TSoundDocument.GetSoundElementCount: Integer; +begin + Result := FSoundData.Count; +end; + +function TSoundDocument.GetFirstSoundElement: TSoundKeyElement; +begin + if GetSoundElementCount() = 0 then + Result := nil + else + Result := GetSoundElement(0) as TSoundKeyElement; + FCurElementIndex := 1; +end; + +function TSoundDocument.GetNextSoundElement: TSoundElement; +begin + if GetSoundElementCount() >= FCurElementIndex then Exit(nil); + Result := GetSoundElement(FCurElementIndex); + Inc(FCurElementIndex); +end; + procedure TSoundDocument.Play; begin - + if FPlayer = nil then Exit; + FPlayer.Play(Self); end; procedure TSoundDocument.Pause; begin + if FPlayer = nil then Exit; + FPlayer.Pause(Self); +end; +procedure TSoundDocument.Stop; +begin + if FPlayer = nil then Exit; + FPlayer.Stop(Self); + FPlayer.Finalize; end; procedure TSoundDocument.Seek(ANewPos: Double); begin + if FPlayer = nil then Exit; end; procedure TSoundDocument.SetSoundPlayer(AKind: TSoundPlayerKind); begin - + Stop; + FPlayer := GSoundPlayers[AKind]; end; var diff --git a/components/fpsound/fpsound_openal.pas b/components/fpsound/fpsound_openal.pas index caf1760c0..efdad82ef 100644 --- a/components/fpsound/fpsound_openal.pas +++ b/components/fpsound/fpsound_openal.pas @@ -20,6 +20,9 @@ var al_context : PALCcontext; type + + { TOpenALPlayer } + TOpenALPlayer = class(TSoundPlayer) private { buffer : Cardinal; @@ -43,13 +46,14 @@ type al_rate : Longword; wave : TWaveReader; public + procedure Initialize; override; + procedure Finalize; override; + procedure Play(ASound: TSoundDocument); override; + procedure AdjustToKeyElement(AElement: TSoundKeyElement); //procedure OPCSoundPlayStreamEx(AStream: TStream); - procedure OPCSoundOpenALPlay(); - procedure OPCSoundOpenALLoadWavFromStream(AStream: TStream); - procedure OPCSoundOpenALInitialize(); - procedure OPCSoundOpenALFinalize(); procedure alStop; function alProcess: Boolean; + procedure alFillBuffer(ASound: TSoundDocument; AKeyElement: TSoundKeyElement); end; @@ -314,22 +318,71 @@ begin Result := True; end; -procedure TOpenALPlayer.OPCSoundOpenALPlay(); +procedure TOpenALPlayer.alFillBuffer(ASound: TSoundDocument; AKeyElement: TSoundKeyElement); +var + lCurSample: TSoundSample; + lReadCount: Integer = 0; +begin + while lReadCount < al_bufsize do + begin + lCurSample := ASound.GetNextSoundElement() as TSoundSample; + if lCurSample = nil then Exit; + + lReadCount := lReadCount + AKeyElement.BitsPerSample div 8; + + if AKeyElement.BitsPerSample = 8 then + PByte(al_readbuf)[lReadCount] := Lo(lCurSample.ChannelValues[0]) + else + PWord(al_readbuf)[lReadCount div 2] := Word(lCurSample.ChannelValues[0]) + end; +end; + +procedure TOpenALPlayer.Initialize; +begin + alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); + alGenSources(1, @al_source); + alGenBuffers(al_bufcount, @al_buffers); + + GetMem(al_readbuf, al_bufsize); +end; + +procedure TOpenALPlayer.Finalize; +begin + // finalize openal + alDeleteSources(1, @al_source); + alDeleteBuffers(al_bufcount, @al_buffers); + FreeMem(al_readbuf); + +// wave.fStream := nil; +// source := nil; + + // finalize codec + wave.Free; + + // close file +// source.Free; +end; + +procedure TOpenALPlayer.Play(ASound: TSoundDocument); var i: Integer; queued : Integer; done : Boolean; + lKeyElement: TSoundKeyElement; begin - if not OPCSoundStreamIsLoaded then Exit; + // First adjust to the first key element + lKeyElement := ASound.GetFirstSoundElement(); + AdjustToKeyElement(lKeyElement); + // Now clean up the source alSourceStop(al_source); alSourceRewind(al_source); alSourcei(al_source, AL_BUFFER, 0); for i := 0 to al_bufcount - 1 do begin -//f/ if wave.ReadBuf(al_readbuf^, al_bufsize) = 0 then - Break; + // Fill the buffer + AlFillBuffer(ASound, lKeyElement); alBufferData(al_buffers[i], al_format, al_readbuf, al_bufsize, al_rate); alSourceQueueBuffers(al_source, 1, @al_buffers[i]); @@ -350,45 +403,26 @@ begin until done; end; -procedure TOpenALPlayer.OPCSoundOpenALLoadWavFromStream(AStream: TStream); -var - Filename: String; - queued : Integer; - done : Boolean; +procedure TOpenALPlayer.AdjustToKeyElement(AElement: TSoundKeyElement); begin - if AStream = nil then - begin - OPCSoundStreamIsLoaded := False; - Exit; - end - else - OPCSoundStreamIsLoaded := True; - - FreeAndNil(source); // define codec - source := AStream; + //source := AStream; // inittialize codec - wave:=TWaveReader.Create; -//f/ if not wave.LoadFromStream(source) then - raise Exception.Create('[OPCSoundLoadWavFromStream] unable to read WAVE format'); - - if wave.fmt.Format<>1 then - raise Exception.Create('[OPCSoundLoadWavFromStream] WAVE files with compression aren''t supported'); - - if wave.fmt.Channels=2 then begin - if wave.fmt.BitsPerSample=8 then al_format:=AL_FORMAT_STEREO8 - else al_format:=AL_FORMAT_STEREO16 - end else begin - if wave.fmt.BitsPerSample=8 then al_format:=AL_FORMAT_MONO8 + if AElement.Channels = 1 then + begin + if AElement.BitsPerSample=8 then al_format:=AL_FORMAT_MONO8 else al_format:=AL_FORMAT_MONO16 + end + else + begin + if AElement.BitsPerSample=8 then al_format := AL_FORMAT_STEREO8 + else al_format:=AL_FORMAT_STEREO16 end; - codec_bs:=2*wave.fmt.Channels; - - //al_bufsize := 20000 - (20000 mod codec_bs); + codec_bs:=2*AElement.Channels; al_bufsize := 20000 - (20000 mod codec_bs); - al_rate:=wave.fmt.SampleRate; + al_rate:=AElement.SampleRate; // WriteLn('Blocksize : ', codec_bs); // WriteLn('Rate : ', wave.fmt.SampleRate); // WriteLn('Channels : ', wave.fmt.Channels); @@ -398,35 +432,5 @@ begin alProcess(); end; -procedure TOpenALPlayer.OPCSoundOpenALInitialize(); -begin - OPCSoundWasInitialized := True; - - alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); - alGenSources(1, @al_source); - alGenBuffers(al_bufcount, @al_buffers); - - GetMem(al_readbuf, al_bufsize); -end; - -procedure TOpenALPlayer.OPCSoundOpenALFinalize(); -begin - // finalize openal - alDeleteSources(1, @al_source); - alDeleteBuffers(al_bufcount, @al_buffers); - FreeMem(al_readbuf); - -// wave.fStream := nil; -// source := nil; - - // finalize codec - wave.Free; - - // close file -// source.Free; -end; - -finalization - //if OPCSoundWasInitialized then OPCSoundOpenALFinalize(); end. diff --git a/components/fpsound/fpsound_wav.pas b/components/fpsound/fpsound_wav.pas index 0c8bd33c7..1f21b9ea3 100644 --- a/components/fpsound/fpsound_wav.pas +++ b/components/fpsound/fpsound_wav.pas @@ -118,6 +118,7 @@ begin // Store the data in the document lKeyElement := TSoundKeyElement.Create; lKeyElement.SampleRate := fmt.SampleRate; + lKeyElement.BitsPerSample := fmt.BitsPerSample; lKeyElement.Channels := fmt.Channels; ADest.AddSoundElement(lKeyElement); end;