Browse Source

* Changed dynamic linking of vorbis, ogg, mad and openal for win32
* Extended madopenal.pas sample with oggvorbis support

git-svn-id: trunk@4670 -

ivost 19 years ago
parent
commit
a042d7eba7

+ 10 - 1
packages/extra/mad/mad.pas

@@ -31,9 +31,18 @@ uses
   ctypes;
 
 {$IFDEF WINDOWS}
-{$DEFINE DYNLINK}
+  {$DEFINE DYNLINK}
+{$ENDIF}
+
+{$IFDEF DYNLINK}
 const
+{$IF Defined(WINDOWS)}
   madlib = 'libmad.dll';
+{$ELSEIF Defined(UNIX)}
+  madlib = 'libmad.so';
+{$ELSE}
+  {$MESSAGE ERROR 'DYNLINK not supported'}
+{$IFEND}
 {$ELSE}
   {$LINKLIB mad}
 {$ENDIF}

+ 10 - 1
packages/extra/oggvorbis/ogg.pas

@@ -21,9 +21,18 @@ uses
   ctypes;
 
 {$IFDEF WINDOWS}
-{$DEFINE DYNLINK}
+  {$DEFINE DYNLINK}
+{$ENDIF}
+
+{$IFDEF DYNLINK}
 const
+{$IF Defined(WINDOWS)}
   ogglib = 'ogglib.dll';
+{$ELSEIF Defined(UNIX)}
+  ogglib = 'libogg.so';
+{$ELSE}
+  {$MESSAGE ERROR 'DYNLINK not supported'}
+{$IFEND}
 {$ELSE}
   {$LINKLIB ogg}
 {$ENDIF}

+ 26 - 8
packages/extra/oggvorbis/vorbis.pas

@@ -21,13 +21,26 @@ uses
   ctypes, ogg;
 
 {$IFDEF WINDOWS}
-{$DEFINE DYNLINK}
+  {$DEFINE DYNLINK}
+{$ENDIF}
+
+{$IFDEF DYNLINK}
 const
-  vorbislib = 'vorbislib.dll';
+{$IF Defined(WINDOWS)}
+  vorbislib     = 'vorbislib.dll';
   vorbisfilelib = 'vorbisfile.dll';
-  vorbisenclib = 'vorbisenclib.dll';
+  vorbisenclib  = 'vorbisenclib.dll';
+{$ELSEIF Defined(UNIX)}
+  vorbislib     = 'libvorbis.so';
+  vorbisfilelib = 'libvorbisfile.so';
+  vorbisenclib  = 'libvorbisenc.so';
+{$ELSE}
+  {$MESSAGE ERROR 'DYNLINK not supported'}
+{$IFEND}
 {$ELSE}
   {$LINKLIB vorbis}
+  {$LINKLIB vorbisfile}
+  {$LINKLIB vorbisenc}
 {$ENDIF}
 
 (***********************************************************************)
@@ -35,6 +48,8 @@ const
 (***********************************************************************)
 
 type
+  csize_t = culong;
+
   ppcfloat = ^pcfloat;
 
   pvorbis_info = ^vorbis_info;
@@ -254,11 +269,12 @@ type
  * unseekable
  *}
 
-  read_func  = function(ptr: pointer; size, nmemb: Longword; datasource: pointer): LongWord; cdecl;
+  read_func  = function(ptr: pointer; size, nmemb: csize_t; datasource: pointer): csize_t; cdecl;
   seek_func  = function(datasource: pointer; offset: ogg_int64_t; whence: cint): cint; cdecl;
   close_func = function(datasource: pointer): cint; cdecl;
   tell_func  = function(datasource: pointer): clong; cdecl;
 
+  pov_callbacks = ^ov_callbacks;
   ov_callbacks = record
     read            : read_func;
     seek            : seek_func;
@@ -274,6 +290,7 @@ const
   INITSET           = 4;
 
 type
+  POggVorbis_File = ^OggVorbis_File;
   OggVorbis_File = record
     datasource      : pointer; { pointer to a FILE *, etc. }
     seekable        : cint;
@@ -283,10 +300,10 @@ type
 
   { If the FILE handle isn't seekable (eg, a pipe), only the current stream appears }
     links           : cint;
-    offsets         : ^ogg_int64_t;
-    dataoffsets     : ^ogg_int64_t;
-    serialnos       : ^clong;
-    pcmlengths      : ^ogg_int64_t; { overloaded to maintain binary compatability; x2 size, stores both beginning and end values }
+    offsets         : pogg_int64_t;
+    dataoffsets     : pogg_int64_t;
+    serialnos       : pclong;
+    pcmlengths      : pogg_int64_t; { overloaded to maintain binary compatability; x2 size, stores both beginning and end values }
     vi              : pvorbis_info;
     vc              : pvorbis_comment;
 
@@ -370,6 +387,7 @@ const
   OV_ECTL_IBLOCK_SET           = $31;
 
 type
+  povectl_ratemanage_arg = ^ovectl_ratemanage_arg;
   ovectl_ratemanage_arg = record
     management_active        : cint;
 

+ 225 - 92
packages/extra/openal/examples/madopenal.pas

@@ -3,40 +3,33 @@ program test;
 {$mode objfpc}
 
 uses
-  classes, sysutils, openal, mad;
-
-const
-  BLOCK_SIZE            = 4*1152;
-  MAD_INPUT_BUFFER_SIZE = 5*8192;
-
-
-// Note: if you lower the bufcnt or bufsize, then you have to modify the polltime also!
-  bufcnt                = 4;
-  bufsize               = 4*BLOCK_SIZE;
-  polltime              = 100;
+  classes, sysutils, ctypes, openal, mad, ogg, vorbis;
 
 var
-// openal
-  device  : PALCdevice;
-  context : PALCcontext;
-  source  : ALuint;
-  buffers : array[0..bufcnt-1] of ALuint;
+  source     : TStream;
+  codec      : Integer;
+  codec_bs   : Longword;
+  codec_read : function(const Buffer: Pointer; const Count: Longword): Longword = nil;
+  codec_rate : Longword;
+  codec_chan : Longword;
+
 
 // mad
-  stream  : mad_stream;
-  frame   : mad_frame;
-  synth   : mad_synth;
-  inbuf   : array[0..MAD_INPUT_BUFFER_SIZE-1] of Byte;
+const
+  MAD_INPUT_BUFFER_SIZE = 5*8192;
 
-// others
-  mp3data : TStream;
+var
+  m_stream  : mad_stream;
+  m_frame   : mad_frame;
+  m_synth   : mad_synth;
+  m_inbuf   : array[0..MAD_INPUT_BUFFER_SIZE-1] of Byte;
 
-procedure mad_reset;
+{procedure mad_reset;
 begin
-  mad_stream_finish(stream);
-  mad_stream_init(stream);
-  mp3data.Position := 0;
-end;
+  mad_stream_finish(m_stream);
+  mad_stream_init(m_stream);
+  source.Position := 0;
+end;}
 
 function mad_read(const Buffer: Pointer; const Count: Longword): Longword;
 var
@@ -48,47 +41,44 @@ var
   ReadSize  : Integer;
   Output    : PSmallint;
 begin
-  if Count mod BLOCK_SIZE <> 0 then
-    Exit(0);
-
   Ofs := 0;
   Num := Count;
   while Num > 0 do
   begin
-    if (stream.buffer = nil) or (stream.error = MAD_ERROR_BUFLEN) then
+    if (m_stream.buffer = nil) or (m_stream.error = MAD_ERROR_BUFLEN) then
     begin
-      if Assigned(stream.next_frame) then
+      if Assigned(m_stream.next_frame) then
       begin
-        Remaining := PtrInt(stream.bufend) - PtrInt(stream.next_frame);
-        Move(stream.next_frame^, inbuf, Remaining);
-        ReadStart := Pointer(PtrInt(@inbuf) + Remaining);
+        Remaining := PtrInt(m_stream.bufend) - PtrInt(m_stream.next_frame);
+        Move(m_stream.next_frame^, m_inbuf, Remaining);
+        ReadStart := Pointer(PtrInt(@m_inbuf) + Remaining);
         ReadSize  := MAD_INPUT_BUFFER_SIZE - Remaining;
       end else begin
         ReadSize  := MAD_INPUT_BUFFER_SIZE;
-        ReadStart := @inbuf;
+        ReadStart := @m_inbuf;
         Remaining := 0;
       end;
 
-      ReadSize := mp3data.Read(ReadStart^, ReadSize);
+      ReadSize := source.Read(ReadStart^, ReadSize);
       if ReadSize = 0 then
         Break;
 
-      mad_stream_buffer(stream, @inbuf, ReadSize+Remaining);
-      stream.error := MAD_ERROR_NONE;
+      mad_stream_buffer(m_stream, @m_inbuf, ReadSize+Remaining);
+      m_stream.error := MAD_ERROR_NONE;
     end;
 
-    if mad_frame_decode(frame, stream) <> 0 then
+    if mad_frame_decode(m_frame, m_stream) <> 0 then
     begin
-      if MAD_RECOVERABLE(stream.error) or (stream.error = MAD_ERROR_BUFLEN) then
+      if MAD_RECOVERABLE(m_stream.error) or (m_stream.error = MAD_ERROR_BUFLEN) then
         Continue;
 
       Exit(0);
     end;
 
-    mad_synth_frame(synth, frame);
+    mad_synth_frame(m_synth, m_frame);
 
     Output := Pointer(PtrUInt(Buffer) + Ofs);
-    with synth do
+    with m_synth do
     if pcm.channels = 2 then
     begin
       for X := 0 to pcm.length -1 do
@@ -121,43 +111,117 @@ begin
       end;
     end;
 
-    Ofs := Ofs + PtrUInt(4*synth.pcm.length);
-    Num := Num - PtrUInt(4*synth.pcm.length);
+    Ofs := Ofs + PtrUInt(4*m_synth.pcm.length);
+    Num := Num - PtrUInt(4*m_synth.pcm.length);
   end;
 
   Result := Ofs;
 end;
 
+
+// oggvorbis
+var
+  ogg_vorbis    : OggVorbis_File;
+  ogg_callbacks : ov_callbacks;
+
+function ogg_read_func(ptr: pointer; size, nmemb: csize_t; datasource: pointer): csize_t; cdecl;
+begin
+  WriteLn('ogg_read_func');
+  Result := TStream(datasource).Read(ptr^, size*nmemb);
+end;
+
+function ogg_seek_func(datasource: pointer; offset: ogg_int64_t; whence: cint): cint; cdecl;
+begin
+  WriteLn('ogg_seek_func');
+  //TStream(datasource).Seek(offset, );
+  Result := -1;
+end;
+
+function ogg_close_func(datasource: pointer): cint; cdecl;
+begin
+  WriteLn('ogg_close_func');
+  TStream(datasource).Position := 0;
+  Result := 0;
+end;
+
+function ogg_tell_func(datasource: pointer): clong; cdecl;
+begin
+  WriteLn('ogg_tell_func');
+  Result := TStream(datasource).Position;
+end;
+
+{procedure ogg_reset;
+begin
+  ov_pcm_seek(ogg_vorbis, 0);
+end;}
+
+function ogg_read(const Buffer: Pointer; const Count: Longword): Longword;
+var
+  Ofs: Longword;
+  Num: Longword;
+begin
+  Ofs := 0;
+  Num := Count;
+
+  while Num > 0 do
+  begin
+    if ov_read(ogg_vorbis, Pointer(PtrUInt(Buffer) + Ofs), Num, 0, 2, 1, nil) < 0 then
+      Exit(0);
+
+    if Result = 0 then
+      Break;
+
+    Ofs := Ofs + Result;
+    Num := Num - Result;
+  end;
+
+  Result := Ofs;
+end;
+
+
+// openal
+const
+  al_format  : array[1..2] of ALenum = (AL_FORMAT_MONO16, AL_FORMAT_STEREO16);
+
+// Note: if you lower the al_bufcount, then you have to modify the al_polltime also!
+  al_bufcount           = 4;
+  al_polltime           = 100;
+
+var
+  al_device  : PALCdevice;
+  al_context : PALCcontext;
+  al_source  : ALuint;
+  al_buffers : array[0..al_bufcount-1] of ALuint;
+  al_bufsize : Longword;
+  al_readbuf : Pointer;
+
 procedure alPlay;
 var
   i: Integer;
-  t: array[0..bufsize-1] of Byte;
 begin
-  WriteLn('Play');
-
-  alSourceStop(source);
-  alSourceRewind(source);
-  alSourcei(source, AL_BUFFER, 0);
+  alSourceStop(al_source);
+  alSourceRewind(al_source);
+  alSourcei(al_source, AL_BUFFER, 0);
 
-  for i := 0 to bufcnt - 1 do
+  for i := 0 to al_bufcount - 1 do
   begin
-    if mad_read(@t, bufsize) = 0 then
+    if codec_read(al_readbuf, al_bufsize) = 0 then
       Break;
 
-    alBufferData(buffers[i], AL_FORMAT_STEREO16, @t, bufsize, 44100);
-    alSourceQueueBuffers(source, 1, @buffers[i]);
+    alBufferData(al_buffers[i], al_format[codec_chan], al_readbuf, al_bufsize, codec_rate);
+    alSourceQueueBuffers(al_source, 1, @al_buffers[i]);
   end;
 
   // Under windows, AL_LOOPING = AL_TRUE breaks queueing, no idea why
-  alSourcei(source, AL_LOOPING, AL_FALSE);
-  alSourcePlay(source);
+  alSourcei(al_source, AL_LOOPING, AL_FALSE);
+  alSourcePlay(al_source);
 end;
 
 procedure alStop;
 begin
-  alSourceStop(source);
-  alSourceRewind(source);
-  alSourcei(source, AL_BUFFER, 0);
+  alSourceStop(al_source);
+  alSourceRewind(al_source);
+  alSourcei(al_source, AL_BUFFER, 0);
   WriteLn('Stop');
 end;
 
@@ -165,21 +229,20 @@ function alProcess: Boolean;
 var
   processed : ALint;
   buffer    : ALuint;
-  t         : array[0..bufsize-1] of Byte;
 begin
-  alGetSourcei(source, AL_BUFFERS_PROCESSED, processed);
-  while (processed > 0) and (processed <= bufcnt) do
+  alGetSourcei(al_source, AL_BUFFERS_PROCESSED, processed);
+  while (processed > 0) and (processed <= al_bufcount) do
   begin
-    alSourceUnqueueBuffers(source, 1, @buffer);
+    alSourceUnqueueBuffers(al_source, 1, @buffer);
 
-    if mad_read(@t, bufsize) = 0 then
+    if codec_read(al_readbuf, al_bufsize) = 0 then
     begin
       alStop;
       Exit(False);
     end;
-    
-    alBufferData(buffer, AL_FORMAT_STEREO16, @t, bufsize, 44100);
-    alSourceQueueBuffers(source, 1, @buffer);
+
+    alBufferData(buffer, al_format[codec_chan], al_readbuf, al_bufsize, codec_rate);
+    alSourceQueueBuffers(al_source, 1, @buffer);
 
     Dec(processed);
   end;
@@ -189,41 +252,111 @@ end;
 
 var
   Filename: String;
+  ov: pvorbis_info;
 begin
+// define codec
+  {WriteLn('Define codec');
+  Writeln('  (1) mp3');
+  Writeln('  (2) ogg');
+  Write('Enter: '); ReadLn(codec);
+  Write('File: '); ReadLn(Filename);}
+
+  codec := 2;
+  Filename := '/test.ogg';
+
+
+// load file
+  source := TFileStream.Create(Filename, fmOpenRead);
+
+
+// inittialize codec
+  case codec of
+    1: // mad
+      begin
+        mad_stream_init(m_stream);
+        mad_frame_init(m_frame);
+        mad_synth_init(m_synth);
+        codec_bs   := 4*1152;
+        codec_read := @mad_read;
+        codec_rate := 44100;
+        codec_chan := 2;
+      end;
+
+    2: // oggvorbis
+      begin
+        WriteLn('a');
+
+        ogg_callbacks.read  := @ogg_read_func;
+        ogg_callbacks.seek  := @ogg_seek_func;
+        ogg_callbacks.close := @ogg_close_func;
+        ogg_callbacks.tell  := @ogg_tell_func;
+
+        //writeln(format('Foo: %p', [@ogg_callbacks]));
+
+        if ov_open_callbacks(source, ogg_vorbis, nil, 0, ogg_callbacks) >= 0 then
+        begin
+          WriteLn('b');
+          ov := ov_info(ogg_vorbis, -1);
+          codec_bs   := 4;
+          codec_read := @ogg_read;
+          codec_rate := ov^.rate;
+          codec_chan := ov^.channels;
+        end;
+      end;
+  end;
+
+  if not Assigned(codec_read) then
+    Exit;
+
+  al_bufsize := 20000 - (20000 mod codec_bs);
+  WriteLn('Codec Blocksize    : ', codec_bs);
+  WriteLn('Codec Rate         : ', codec_rate);
+  WriteLn('Codec Channels     : ', codec_chan);
+  WriteLn('OpenAL Buffers     : ', al_bufcount);
+  WriteLn('OpenAL Buffer Size : ', al_bufsize);
+
+
 // init openal
-  device := alcOpenDevice(nil);
-  context := alcCreateContext(device, nil);
-  alcMakeContextCurrent(context);
+  al_device := alcOpenDevice(nil);
+  al_context := alcCreateContext(al_device, nil);
+  alcMakeContextCurrent(al_context);
 
   alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
-  alGenSources(1, @source);
-  alGenBuffers(bufcnt, @buffers);
+  alGenSources(1, @al_source);
+  alGenBuffers(al_bufcount, @al_buffers);
 
-// init mad
-  mad_stream_init(stream);
-  mad_frame_init(frame);
-  mad_synth_init(synth);
+  GetMem(al_readbuf, al_bufsize);
 
-// load file
-  Write('Path to mp3 file: '); ReadLn(Filename);
-  mp3data := TFileStream.Create(Filename, fmOpenRead);
 
 // play
   alPlay;
   while alProcess do
-    Sleep(polltime);
+    Sleep(al_polltime);
 
-// close file
-  mp3data.Free;
+// finalize openal
+  alDeleteSources(1, @al_source);
+  alDeleteBuffers(al_bufcount, @al_buffers);
+  alcDestroyContext(al_context);
+  alcCloseDevice(al_device);
+  FreeMem(al_readbuf);
 
-// finalize mad
-  mad_synth_finish(synth);
-  mad_frame_finish(frame);
-  mad_stream_finish(stream);
 
-// finalize openal
-  alDeleteSources(1, @source);
-  alDeleteBuffers(bufcnt, @buffers);
-  alcDestroyContext(context);
-  alcCloseDevice(device);
+// finalize codec
+  case codec of
+    1: // mad
+      begin
+        mad_synth_finish(m_synth);
+        mad_frame_finish(m_frame);
+        mad_stream_finish(m_stream);
+      end;
+
+    2: // oggvorbis
+      begin
+        ov_clear(ogg_vorbis);
+      end;
+  end;
+
+
+// close file
+  source.Free;
 end.

+ 10 - 1
packages/extra/openal/openal.pas

@@ -8,9 +8,18 @@ uses
   ctypes;
 
 {$IFDEF WINDOWS}
-{$DEFINE DYNLINK}
+  {$DEFINE DYNLINK}
+{$ENDIF}
+
+{$IFDEF DYNLINK}
 const
+{$IF Defined(WINDOWS)}
   openallib = 'openal32.dll';
+{$ELSEIF Defined(UNIX)}
+  openallib = 'libopenal.so';
+{$ELSE}
+  {$MESSAGE ERROR 'DYNLINK not supported'}
+{$IFEND}
 {$ELSE}
   {$LINKLIB openal}
 {$ENDIF}