Board index » delphi » HELP PLEASE: Low-level audio programming

HELP PLEASE: Low-level audio programming

Hello!

It is a few months ago I started in windows audio pragramming. It was very
hard to get any information about LOW-LEVEL audio programming. However I was
able to create a program that plays a sound in background, that is
continously generated in realtime.
This program works now, but it uses WINDOW message callbacks. These
callbacks are much too slow for realtime processing so I tried around with
callback FUNCTIONS but every time I start my program I get a General
Protection Fault and the program halts. I think I have done something wrong
with the callback function (the function does NOTHING); Maybe I gave the
function address in the wrong way to the "waveOutOpen" function. I even
don't know how I have to declare the function/procedure.

I have asked many people, but no one could help me yet.
So, if anyone is out there that can help me (maybe with an example program)
PLEASE CONTACT ME!!!!

P.S: I would prefer if you answer via e-mail: udo_giacomo...@rolmail.it or
u...@usa.net

Below is my program's source code...

--
Thank you
Udo Giacomozzi

--------------------------------------------------------------------
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  MMSYSTEM, StdCtrls;

type
  TCallBackFunction = function(Instance:Integer):integer;
  function MyCallBack(Instance:Integer):Integer; cdecl;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
    uDeviceID    : Word;
    lphWaveOut   : PHWaveOut;
    lpFormat     : PWaveFormatEx;
    Header       : PWaveHdr;
    Header2      : PWaveHdr;
    Buffer       : Array[0..10240] of Byte;
    Buffer2      : Array[0..10240] of Byte;
  public
    { Public-Deklarationen }
    procedure CallBack_Done(var Msg: TMessage); message MM_WOM_DONE;
    procedure CallBack_Open(var Msg: TMessage); message MM_WOM_OPEN;
    procedure CallBack_Close(var Msg: TMessage); message MM_WOM_CLOSE;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.CallBack_Done;
begin
  inherited;
  Application.MessageBox('Callback function was called: DONE',
        'Information from CALLBACK function', MB_OK);
end;

procedure TForm1.CallBack_Open;
begin
  inherited;
  Application.MessageBox('Wave device successfully opened!',
        'Information from CALLBACK function', MB_OK);
end;

procedure TForm1.CallBack_Close;
begin
  inherited;
  Application.MessageBox('Wave device successfully closed!',
        'Information from CALLBACK function', MB_OK);
end;

var
  CallBackused:Word;

function MyCallback;
begin
  Result:=0;
end;

const
  StrSize = 500;

procedure TForm1.FormCreate(Sender: TObject);
var Err:Integer;
  s:String;
  ps:PChar;
  ps2:Pchar;
  i:Integer;
  x:Byte;
begin
  uDeviceID:=0;

  New(lphWaveOut);
  New(lpFormat  );
  FillChar(lphWaveOut^, SizeOf(lphWaveOut^), 0);
  FillChar(lpFormat^,   SizeOf(lpFormat^), 0);

  Callbackused:=0;

  Getmem(ps,StrSize);

  // Fill buffer with something
  For i:=Low(Buffer) to High(Buffer) do
  begin
    Buffer[i]:=x;
    Inc(x,10);
  end;
  For i:=Low(Buffer2) to High(Buffer2) do
  begin
    Buffer2[i]:=x;
    Inc(x,5);
  end;

  // Fill format information

  lpFormat^.wFormatTag    := WAVE_FORMAT_PCM;
  lpFormat^.nChannels     := 1;
  lpFormat^.nSamplesPerSec := 44100;
  lpFormat^.nAvgBytesPerSec:= 44100;
  lpFormat^.nBlockAlign    := 1;
  lpFormat^.wBitsPerSample := 8;
  lpFormat^.cbSize         := 0;

  // Open sound device for OUTPUT

  Err:=waveOutOpen(lphWaveOut, uDeviceID, lpFormat,
{Handle, }DWORD(@MyCallback), 0, CALLBACK_Function);
  If Err <> 0 then
   begin
     waveOutGetErrorText(Err,ps,StrSize);
     Application.MessageBox(ps,'waveOutOpen ERROR!',MB_OK);

     Application.Terminate;
   end;

   // Prepare output HEADER
   New(Header);
   FillChar(Header^,SizeOf(Header^),0);
   Header^.lpData          := @Buffer;
   Header^.dwBufferLength  := SizeOf(Buffer);
   Header^.dwFlags         := 0;
   Err:=waveOutPrepareHeader(lphWaveOut^, Header, SizeOf(Header^));
   If Err <> 0 then
   begin
     waveOutGetErrorText(Err,ps,StrSize);
     Application.MessageBox(ps,'waveOutPrepareHeader ERROR!',MB_OK);

     Application.Terminate;
   end else Application.MessageBox('No error preparing
header.','Information',MB_OK);

   // Prepare output HEADER 2
   New(Header2);
   FillChar(Header2^,SizeOf(Header2^),0);
   Header2^.lpData          := @Buffer2;
   Header2^.dwBufferLength  := SizeOf(Buffer2);
   Header2^.dwFlags         := 0;
   Err:=waveOutPrepareHeader(lphWaveOut^, Header2, SizeOf(Header2^));
   If Err <> 0 then
   begin
     waveOutGetErrorText(Err,ps,StrSize);
     Application.MessageBox(ps,'waveOutPrepareHeader (2) ERROR!',MB_OK);

     Application.Terminate;
   end;

(**************************************************************************)

   Err:=waveOutWrite(lphWaveOut^, Header, SizeOf(Header^));
   If Err <> 0 then
   begin
     waveOutGetErrorText(Err,ps,StrSize);
     Application.MessageBox(ps,'waveOutWrite ERROR!',MB_OK);

     Application.Terminate;
   end;

   Err:=waveOutWrite(lphWaveOut^, Header2, SizeOf(Header2^));
   If Err <> 0 then
   begin
     waveOutGetErrorText(Err,ps,StrSize);
     Application.MessageBox(ps,'waveOutWrite (2) ERROR!',MB_OK);

     Application.Terminate;
   end else Application.MessageBox('No error playing
sound!.','Information',MB_OK);

(**************************************************************************)

   // Unprepare header
   Err:=waveOutUnprepareHeader(lphWaveOut^, Header, SizeOf(Header^));
   If Err <> 0 then
   begin
     waveOutGetErrorText(Err,ps,StrSize);
     Application.MessageBox(ps,'waveOutUnprepareHeader ERROR!',MB_OK);

     Application.Terminate;
   end;

   // Reset sound driver
   Err:=WaveOutReset(lphWaveOut^);
   If Err <> 0 then
   begin
     waveOutGetErrorText(Err,ps,StrSize);
     Application.MessageBox(ps,'waveOutReset ERROR!',MB_OK);

     Application.Terminate;
   end;

   // Close sound driver
   Err:=WaveOutClose(lphWaveOut^);
   If Err <> 0 then
   begin
     waveOutGetErrorText(Err,ps,StrSize);
     Application.MessageBox(ps,'waveOutClose ERROR!',MB_OK);

     Application.Terminate;
   end;

  Str(Err,s);
  s:='Callback function was called '+s+' times!'#0;
  ps:=@s[1];
  Application.MessageBox(ps,'Information',MB_OK);

   //Application.Terminate;
end;

end.

 

Re:HELP PLEASE: Low-level audio programming


In article <6o5525$1r7...@urano.inet.it>, udo_giacomo...@rolmail.net says...

   Go to my web site and download the TAudioIO component, its
www.cog.brown.edu/~mertus.  It does all you want except it does windowing
messages which is fast enough for real time.

-John_Mer...@Brown.edu

Quote

>Hello!

>It is a few months ago I started in windows audio pragramming. It was very
>hard to get any information about LOW-LEVEL audio programming. However I was
>able to create a program that plays a sound in background, that is
>continously generated in realtime.
>This program works now, but it uses WINDOW message callbacks. These
>callbacks are much too slow for realtime processing so I tried around with
>callback FUNCTIONS but every time I start my program I get a General
>Protection Fault and the program halts. I think I have done something wrong
>with the callback function (the function does NOTHING); Maybe I gave the
>function address in the wrong way to the "waveOutOpen" function. I even
>don't know how I have to declare the function/procedure.

>I have asked many people, but no one could help me yet.
>So, if anyone is out there that can help me (maybe with an example program)
>PLEASE CONTACT ME!!!!

>P.S: I would prefer if you answer via e-mail: udo_giacomo...@rolmail.it or
>u...@usa.net

>Below is my program's source code...

>--
>Thank you
>Udo Giacomozzi

>--------------------------------------------------------------------
>unit Unit1;

>interface

>uses
>  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
>  MMSYSTEM, StdCtrls;

>type
>  TCallBackFunction = function(Instance:Integer):integer;
>  function MyCallBack(Instance:Integer):Integer; cdecl;

>type
>  TForm1 = class(TForm)
>    Label1: TLabel;
>    procedure FormCreate(Sender: TObject);
>  private
>    { Private-Deklarationen }
>    uDeviceID    : Word;
>    lphWaveOut   : PHWaveOut;
>    lpFormat     : PWaveFormatEx;
>    Header       : PWaveHdr;
>    Header2      : PWaveHdr;
>    Buffer       : Array[0..10240] of Byte;
>    Buffer2      : Array[0..10240] of Byte;
>  public
>    { Public-Deklarationen }
>    procedure CallBack_Done(var Msg: TMessage); message MM_WOM_DONE;
>    procedure CallBack_Open(var Msg: TMessage); message MM_WOM_OPEN;
>    procedure CallBack_Close(var Msg: TMessage); message MM_WOM_CLOSE;
>  end;

>var
>  Form1: TForm1;

>implementation

>{$R *.DFM}

>procedure TForm1.CallBack_Done;
>begin
>  inherited;
>  Application.MessageBox('Callback function was called: DONE',
>        'Information from CALLBACK function', MB_OK);
>end;

>procedure TForm1.CallBack_Open;
>begin
>  inherited;
>  Application.MessageBox('Wave device successfully opened!',
>        'Information from CALLBACK function', MB_OK);
>end;

>procedure TForm1.CallBack_Close;
>begin
>  inherited;
>  Application.MessageBox('Wave device successfully closed!',
>        'Information from CALLBACK function', MB_OK);
>end;

>var
>  CallBackused:Word;

>function MyCallback;
>begin
>  Result:=0;
>end;

>const
>  StrSize = 500;

>procedure TForm1.FormCreate(Sender: TObject);
>var Err:Integer;
>  s:String;
>  ps:PChar;
>  ps2:Pchar;
>  i:Integer;
>  x:Byte;
>begin
>  uDeviceID:=0;

>  New(lphWaveOut);
>  New(lpFormat  );
>  FillChar(lphWaveOut^, SizeOf(lphWaveOut^), 0);
>  FillChar(lpFormat^,   SizeOf(lpFormat^), 0);

>  Callbackused:=0;

>  Getmem(ps,StrSize);

>  // Fill buffer with something
>  For i:=Low(Buffer) to High(Buffer) do
>  begin
>    Buffer[i]:=x;
>    Inc(x,10);
>  end;
>  For i:=Low(Buffer2) to High(Buffer2) do
>  begin
>    Buffer2[i]:=x;
>    Inc(x,5);
>  end;

>  // Fill format information

>  lpFormat^.wFormatTag    := WAVE_FORMAT_PCM;
>  lpFormat^.nChannels     := 1;
>  lpFormat^.nSamplesPerSec := 44100;
>  lpFormat^.nAvgBytesPerSec:= 44100;
>  lpFormat^.nBlockAlign    := 1;
>  lpFormat^.wBitsPerSample := 8;
>  lpFormat^.cbSize         := 0;

>  // Open sound device for OUTPUT

>  Err:=waveOutOpen(lphWaveOut, uDeviceID, lpFormat,
>{Handle, }DWORD(@MyCallback), 0, CALLBACK_Function);
>  If Err <> 0 then
>   begin
>     waveOutGetErrorText(Err,ps,StrSize);
>     Application.MessageBox(ps,'waveOutOpen ERROR!',MB_OK);

>     Application.Terminate;
>   end;

>   // Prepare output HEADER
>   New(Header);
>   FillChar(Header^,SizeOf(Header^),0);
>   Header^.lpData          := @Buffer;
>   Header^.dwBufferLength  := SizeOf(Buffer);
>   Header^.dwFlags         := 0;
>   Err:=waveOutPrepareHeader(lphWaveOut^, Header, SizeOf(Header^));
>   If Err <> 0 then
>   begin
>     waveOutGetErrorText(Err,ps,StrSize);
>     Application.MessageBox(ps,'waveOutPrepareHeader ERROR!',MB_OK);

>     Application.Terminate;
>   end else Application.MessageBox('No error preparing
>header.','Information',MB_OK);

>   // Prepare output HEADER 2
>   New(Header2);
>   FillChar(Header2^,SizeOf(Header2^),0);
>   Header2^.lpData          := @Buffer2;
>   Header2^.dwBufferLength  := SizeOf(Buffer2);
>   Header2^.dwFlags         := 0;
>   Err:=waveOutPrepareHeader(lphWaveOut^, Header2, SizeOf(Header2^));
>   If Err <> 0 then
>   begin
>     waveOutGetErrorText(Err,ps,StrSize);
>     Application.MessageBox(ps,'waveOutPrepareHeader (2) ERROR!',MB_OK);

>     Application.Terminate;
>   end;

>(**************************************************************************)

>   Err:=waveOutWrite(lphWaveOut^, Header, SizeOf(Header^));
>   If Err <> 0 then
>   begin
>     waveOutGetErrorText(Err,ps,StrSize);
>     Application.MessageBox(ps,'waveOutWrite ERROR!',MB_OK);

>     Application.Terminate;
>   end;

>   Err:=waveOutWrite(lphWaveOut^, Header2, SizeOf(Header2^));
>   If Err <> 0 then
>   begin
>     waveOutGetErrorText(Err,ps,StrSize);
>     Application.MessageBox(ps,'waveOutWrite (2) ERROR!',MB_OK);

>     Application.Terminate;
>   end else Application.MessageBox('No error playing
>sound!.','Information',MB_OK);

>(**************************************************************************)

>   // Unprepare header
>   Err:=waveOutUnprepareHeader(lphWaveOut^, Header, SizeOf(Header^));
>   If Err <> 0 then
>   begin
>     waveOutGetErrorText(Err,ps,StrSize);
>     Application.MessageBox(ps,'waveOutUnprepareHeader ERROR!',MB_OK);

>     Application.Terminate;
>   end;

>   // Reset sound driver
>   Err:=WaveOutReset(lphWaveOut^);
>   If Err <> 0 then
>   begin
>     waveOutGetErrorText(Err,ps,StrSize);
>     Application.MessageBox(ps,'waveOutReset ERROR!',MB_OK);

>     Application.Terminate;
>   end;

>   // Close sound driver
>   Err:=WaveOutClose(lphWaveOut^);
>   If Err <> 0 then
>   begin
>     waveOutGetErrorText(Err,ps,StrSize);
>     Application.MessageBox(ps,'waveOutClose ERROR!',MB_OK);

>     Application.Terminate;
>   end;

>  Str(Err,s);
>  s:='Callback function was called '+s+' times!'#0;
>  ps:=@s[1];
>  Application.MessageBox(ps,'Information',MB_OK);

>   //Application.Terminate;
>end;

>end.

Re:HELP PLEASE: Low-level audio programming


Udo,

You need to add the 'stdcall' keyword to your callback routine
declaration... Delphi's default calling convention is register,
but the API stuff is almost all stdcall.

Ken
--
Ken White
kwh...@westelcom.com

Clipper Functions for Delphi
http://members.aol.com/clipfunc/

Quote
Udo Giacomozzi wrote:

> Hello!

> It is a few months ago I started in windows audio pragramming. It was very
> hard to get any information about LOW-LEVEL audio programming. However I was
> able to create a program that plays a sound in background, that is
> continously generated in realtime.
> This program works now, but it uses WINDOW message callbacks. These
> callbacks are much too slow for realtime processing so I tried around with
> callback FUNCTIONS but every time I start my program I get a General
> Protection Fault and the program halts. I think I have done something wrong
> with the callback function (the function does NOTHING); Maybe I gave the
> function address in the wrong way to the "waveOutOpen" function. I even
> don't know how I have to declare the function/procedure.

> I have asked many people, but no one could help me yet.
> So, if anyone is out there that can help me (maybe with an example program)
> PLEASE CONTACT ME!!!!

> P.S: I would prefer if you answer via e-mail: udo_giacomo...@rolmail.it or
> u...@usa.net

> Below is my program's source code...

> --
> Thank you
> Udo Giacomozzi

> --------------------------------------------------------------------
> unit Unit1;

> interface

> uses
>   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
>   MMSYSTEM, StdCtrls;

> type
>   TCallBackFunction = function(Instance:Integer):integer;
>   function MyCallBack(Instance:Integer):Integer; cdecl;

> type
>   TForm1 = class(TForm)
>     Label1: TLabel;
>     procedure FormCreate(Sender: TObject);
>   private
>     { Private-Deklarationen }
>     uDeviceID    : Word;
>     lphWaveOut   : PHWaveOut;
>     lpFormat     : PWaveFormatEx;
>     Header       : PWaveHdr;
>     Header2      : PWaveHdr;
>     Buffer       : Array[0..10240] of Byte;
>     Buffer2      : Array[0..10240] of Byte;
>   public
>     { Public-Deklarationen }
>     procedure CallBack_Done(var Msg: TMessage); message MM_WOM_DONE;
>     procedure CallBack_Open(var Msg: TMessage); message MM_WOM_OPEN;
>     procedure CallBack_Close(var Msg: TMessage); message MM_WOM_CLOSE;
>   end;

> var
>   Form1: TForm1;

> implementation

> {$R *.DFM}

> procedure TForm1.CallBack_Done;
> begin
>   inherited;
>   Application.MessageBox('Callback function was called: DONE',
>         'Information from CALLBACK function', MB_OK);
> end;

> procedure TForm1.CallBack_Open;
> begin
>   inherited;
>   Application.MessageBox('Wave device successfully opened!',
>         'Information from CALLBACK function', MB_OK);
> end;

> procedure TForm1.CallBack_Close;
> begin
>   inherited;
>   Application.MessageBox('Wave device successfully closed!',
>         'Information from CALLBACK function', MB_OK);
> end;

> var
>   CallBackused:Word;

> function MyCallback;
> begin
>   Result:=0;
> end;

> const
>   StrSize = 500;

> procedure TForm1.FormCreate(Sender: TObject);
> var Err:Integer;
>   s:String;
>   ps:PChar;
>   ps2:Pchar;
>   i:Integer;
>   x:Byte;
> begin
>   uDeviceID:=0;

>   New(lphWaveOut);
>   New(lpFormat  );
>   FillChar(lphWaveOut^, SizeOf(lphWaveOut^), 0);
>   FillChar(lpFormat^,   SizeOf(lpFormat^), 0);

>   Callbackused:=0;

>   Getmem(ps,StrSize);

>   // Fill buffer with something
>   For i:=Low(Buffer) to High(Buffer) do
>   begin
>     Buffer[i]:=x;
>     Inc(x,10);
>   end;
>   For i:=Low(Buffer2) to High(Buffer2) do
>   begin
>     Buffer2[i]:=x;
>     Inc(x,5);
>   end;

>   // Fill format information

>   lpFormat^.wFormatTag    := WAVE_FORMAT_PCM;
>   lpFormat^.nChannels     := 1;
>   lpFormat^.nSamplesPerSec := 44100;
>   lpFormat^.nAvgBytesPerSec:= 44100;
>   lpFormat^.nBlockAlign    := 1;
>   lpFormat^.wBitsPerSample := 8;
>   lpFormat^.cbSize         := 0;

>   // Open sound device for OUTPUT

>   Err:=waveOutOpen(lphWaveOut, uDeviceID, lpFormat,
> {Handle, }DWORD(@MyCallback), 0, CALLBACK_Function);
>   If Err <> 0 then
>    begin
>      waveOutGetErrorText(Err,ps,StrSize);
>      Application.MessageBox(ps,'waveOutOpen ERROR!',MB_OK);

>      Application.Terminate;
>    end;

>    // Prepare output HEADER
>    New(Header);
>    FillChar(Header^,SizeOf(Header^),0);
>    Header^.lpData          := @Buffer;
>    Header^.dwBufferLength  := SizeOf(Buffer);
>    Header^.dwFlags         := 0;
>    Err:=waveOutPrepareHeader(lphWaveOut^, Header, SizeOf(Header^));
>    If Err <> 0 then
>    begin
>      waveOutGetErrorText(Err,ps,StrSize);
>      Application.MessageBox(ps,'waveOutPrepareHeader ERROR!',MB_OK);

>      Application.Terminate;
>    end else Application.MessageBox('No error preparing
> header.','Information',MB_OK);

>    // Prepare output HEADER 2
>    New(Header2);
>    FillChar(Header2^,SizeOf(Header2^),0);
>    Header2^.lpData          := @Buffer2;
>    Header2^.dwBufferLength  := SizeOf(Buffer2);
>    Header2^.dwFlags         := 0;
>    Err:=waveOutPrepareHeader(lphWaveOut^, Header2, SizeOf(Header2^));
>    If Err <> 0 then
>    begin
>      waveOutGetErrorText(Err,ps,StrSize);
>      Application.MessageBox(ps,'waveOutPrepareHeader (2) ERROR!',MB_OK);

>      Application.Terminate;
>    end;

> (**************************************************************************)

>    Err:=waveOutWrite(lphWaveOut^, Header, SizeOf(Header^));
>    If Err <> 0 then
>    begin
>      waveOutGetErrorText(Err,ps,StrSize);
>      Application.MessageBox(ps,'waveOutWrite ERROR!',MB_OK);

>      Application.Terminate;
>    end;

>    Err:=waveOutWrite(lphWaveOut^, Header2, SizeOf(Header2^));
>    If Err <> 0 then
>    begin
>      waveOutGetErrorText(Err,ps,StrSize);
>      Application.MessageBox(ps,'waveOutWrite (2) ERROR!',MB_OK);

>      Application.Terminate;
>    end else Application.MessageBox('No error playing
> sound!.','Information',MB_OK);

> (**************************************************************************)

>    // Unprepare header
>    Err:=waveOutUnprepareHeader(lphWaveOut^, Header, SizeOf(Header^));
>    If Err <> 0 then
>    begin
>      waveOutGetErrorText(Err,ps,StrSize);
>      Application.MessageBox(ps,'waveOutUnprepareHeader ERROR!',MB_OK);

>      Application.Terminate;
>    end;

>    // Reset sound driver
>    Err:=WaveOutReset(lphWaveOut^);
>    If Err <> 0 then
>    begin
>      waveOutGetErrorText(Err,ps,StrSize);
>      Application.MessageBox(ps,'waveOutReset ERROR!',MB_OK);

>      Application.Terminate;
>    end;

>    // Close sound driver
>    Err:=WaveOutClose(lphWaveOut^);
>    If Err <> 0 then
>    begin
>      waveOutGetErrorText(Err,ps,StrSize);
>      Application.MessageBox(ps,'waveOutClose ERROR!',MB_OK);

>      Application.Terminate;
>    end;

>   Str(Err,s);
>   s:='Callback function was called '+s+' times!'#0;
>   ps:=@s[1];
>   Application.MessageBox(ps,'Information',MB_OK);

>    //Application.Terminate;
> end;

> end.

Other Threads