Solved

SB hardware prodramming

Posted on 1997-09-09
2
322 Views
Last Modified: 2010-04-04
Could you answer me, how to program under DELPHI 2.0 DAC, ADC and amplifiers of SB card
without direct ports access (through driver)?
I would like to use sound card as digital oscilloscope; for instance.
It's very desirable to have an example source code. Thank you in advance. Alexey.
0
Comment
Question by:alshar
2 Comments
 

Accepted Solution

by:
GarlicMan earned 200 total points
ID: 1344481
First, one doe not have to go to the SB driver level to get access to the DAC, ADC and amplifers of the SB card.  The low level WaveInXXX, WaveOutXXX routines should suffice.  These routines are also soundcard independent.  However, they are NOT
easy to use.  The following is an example DELPHI unit which does
low level WaveIn I/O.

Path: cocoa.brown.edu!news
From: John_Mertus@brown.edu (John_Mertus)
Newsgroups: comp.lang.pascal.delphi.misc
Subject: Low Level WaveIn routine
Date: 4 Sep 1997 19:06:28 GMT
Organization: Brown University, Providence, RI -- USA
Lines: 660
Message-ID: <5un0rk$po0@cocoa.brown.edu>
Reply-To: John_Mertus@brown.edu
NNTP-Posting-Host: cis-ts7-slip13.cis.brown.edu
Mime-Version: 1.0
Content-Type: Text/Plain; charset=US-ASCII
X-Newsreader: WinVN 0.99.7

   Enclosed is RECUNIT that is a unit that does the hard work, one calls it by

Var
   WaveRecorder : TWaveRecorder;

   WaveRecorder := TwaveRecorder(2048, 4);  // 4 buffers of size 2048 bytes

  { Set the sampling parameters }
  With WaveRecorder.pWavefmtEx Do
    Begin
     wFormatTag := WAVE_FORMAT_PCM;
     nChannels := 1;
     nSamplesPerSec := 20000;
     wBitsPerSample := 16;
     nAvgBytesPerSec := nSamplesPerSec*(wBitsPerSample div 8)*nChannels;
   End;

   //  Next is a kludge since I don't know how to get the address of
   //  the object itself

   WaveRecorder.SetupRecord(@WaveRecorder);


   // Now start recording with
   WaveRecorder.StartRecord;
   
    ... Each time a buffer is full, the WaveRecorder.Processbuffer
   routine is called.  

   //  Stop recording with
   WaveRecorder.StopRecord;
   WaveRecorder.Destroy;


{
  File Name: RECUNIT.PAS  V 1.01
  Created: Aug 19 1996 at 21:56 on IBM ThinkPad
  Revision #7: Aug 22 1997, 15:01 on IBM ThinkPad
                                        -John Mertus

  This unit contains necessary routines for doing recording.

  Version 1.00 is initial release
          1.01 Added TWaveInGetErrorText
}



{-----------------Unit-RECUNIT---------------------John Mertus---Aug 96---}

          Unit RECUNIT;


{*************************************************************************}
                            Interface

Uses
   Windows, MMSystem, SysUtils, MSACM;


{  The following defines a class TWaveRecorder for sound card input.  }
{  It is expected that a new class is derived from TWaveRecorder      }
{  that overrides TWaveRecorder.ProcessBuffer.  After the recorder is }
{  started, the procedure is called whenever a buffer of data has     }
{  been sampled.                                                      }

Const
   MAX_BUFFERS = 8;

type
  PWaveRecorder = ^TWaveRecorder;
  TWaveRecorder = class(TObject)
     Constructor Create(BfSize, TotalBuffers : Integer);
     Destructor  Destroy;      Override;
     Procedure   ProcessBuffer(uMsg : Word; P : Pointer; n : Integer);    
Virtual;

  private
     fBufferSize        : Integer;          // Requsted size of buffer
     BufIndex           : Integer;
     fTotalBuffers       : Integer;

     pWaveHeader        : Array [0..MAX_BUFFERS-1] of PWAVEHDR;
     hWaveHeader        : Array [0..MAX_BUFFERS-1] of THANDLE;
     hWaveBuffer        : Array [0..MAX_BUFFERS-1] of THANDLE;
     hWaveFmtEx         : THANDLE;
     dwByteDataSize     : DWORD;
     dwTotalWaveSize    : DWORD;

     RecordActive       : Boolean;
     bDeviceOpen        : Boolean;

     { Functions that no one needs to know about }
     Function InitWaveHeaders : Boolean;
     Function AllocPCMBuffers : Boolean;
     Procedure FreePCMBuffers;

     Function AllocWaveFormatEx : Boolean;
     Procedure FreeWaveFormatEx;

     Function AllocWaveHeaders : Boolean;
     Procedure FreeWaveHeader;

     Function AddNextBuffer : Boolean;
     Procedure CloseWaveDeviceRecord;

  public
    { Public declarations }
    pWaveFmtEx         : PWaveFormatEx;
    WaveBufSize        : Integer;          // Size aligned to nBlockAlign Field
    InitWaveRecorder   : Boolean;
    RecErrorMessage    : String;
    QueuedBuffers,
    ProcessedBuffers   : Integer;
    pWaveBuffer        : Array [0..MAX_BUFFERS-1] of lpstr;
    WaveIn             : HWAVEIN;  { Wavedevice handle }

    Procedure StopRecord;
    Function  StartRecord : Boolean;
    Function  SetupRecord(P : PWaveRecorder) : Boolean;

  end;

{*************************************************************************}
                           implementation

{-------------TWaveInGetErrorText------------John Mertus---14-June--97--}

   Function TWaveInGetErrorText(iErr : Integer) : String;

{ This puts the WaveIn error messages in a Pascal type format.          }
{ iErr is the error number                                              }
{                                                                       }
{**********************************************************************}
Var
  PlayInErrorMsgC   : Array [0..255] of Char;

Begin
  waveInGetErrorText(iErr,PlayInErrorMsgC,255);
  TWaveInGetErrorText := StrPas(PlayInErrorMsgC);
End;

{-------------InitWaveHeaders----------------John Mertus---14-June--97--}

   Function TWaveRecorder.AllocWaveFormatEx : Boolean;

{ Allocate the larget format size required from installed ACM's         }
{                                                                       }
{**********************************************************************}
Var
  MaxFmtSize : UINT;

BEGIN
  { maxFmtSize is the sum of sizeof(WAVEFORMATEX) + pwavefmtex.cbSize }
  If( acmMetrics( 0, ACM_METRIC_MAX_SIZE_FORMAT, maxFmtSize ) <> 0) Then
    Begin
      RecErrorMessage := 'Error getting the max compression format size';
      AllocWaveFormatEx := False;
      Exit;
    End;


  { allocate the WAVEFMTEX structure }
  hWaveFmtEx := GlobalAlloc(GMEM_MOVEABLE, maxFmtSize);
  If (hWaveFmtEx = 0) Then
    Begin
      RecErrorMessage := 'Error allocating memory for WaveFormatEx structure';
      AllocWaveFormatEx := False;
      Exit;
    End;

  pWaveFmtEx := PWaveFormatEx(GlobalLock(hWaveFmtEx));
  If (pWaveFmtEx = Nil) Then
    Begin
      RecErrorMessage := 'Error locking WaveFormatEx memory';
      AllocWaveFormatEx := False;
      Exit;
    End;

  { initialize the format to standard PCM }
  ZeroMemory( pwavefmtex, maxFmtSize );
  pwavefmtex.wFormatTag := WAVE_FORMAT_PCM;
  pwavefmtex.nChannels := 1;
  pwavefmtex.nSamplesPerSec := 20000;
  pwavefmtex.nBlockAlign := 1;
  pwavefmtex.wBitsPerSample := 16;
  pwavefmtex.nAvgBytesPerSec := pwavefmtex.nSamplesPerSec*
                                (pwavefmtex.wBitsPerSample div
8)*pwavefmtex.nChannels;
  pwavefmtex.cbSize := 0;

  { Success, go home }
  AllocWaveFormatEx := True;
end;

{-------------InitWaveHeaders----------------John Mertus---14-June--97--}

   Function TWaveRecorder.InitWaveHeaders : Boolean;

{ Allocate memory, zero out wave headers and initialize                 }
{                                                                       }
{**********************************************************************}
Var
  i : Integer;

BEGIN
  { make the wave buffer size a multiple of the block align... }
  WaveBufSize := fBufferSize - (fBufferSize mod pwavefmtex.nBlockAlign);

  { Set the wave headers }
  For i := 0 to fTotalBuffers-1 Do
    With pWaveHeader[i]^ Do
      Begin
        lpData := pWaveBuffer[i];         // address of the waveform buffer
        dwBufferLength := WaveBufSize; // length, in bytes, of the buffer
        dwBytesRecorded := 0;          // see below
        dwUser := 0;                   // 32 bits of user data
        dwFlags := 0;                  // see below
        dwLoops := 0;                  // see below
        lpNext := Nil;                 // reserved; must be zero
        reserved := 0;                 // reserved; must be zero
      End;

  InitWaveHeaders := TRUE;
END;


{-------------AllocWaveHeader----------------John Mertus---14-June--97--}

   Function TWaveRecorder.AllocWaveHeaders : Boolean;

{ Allocate and lock header memory                                       }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      hwaveheader[i] := GlobalAlloc( GMEM_MOVEABLE or GMEM_SHARE or
GMEM_ZEROINIT, sizeof(TWAVEHDR));
      if (hwaveheader[i] = 0) Then
        begin
          { NOTE: This could lead to a memory leak, fix someday }
          RecErrorMessage := 'Error allocating wave header memory';
          AllocWaveHeaders := FALSE;
          Exit;
        end;

      pwaveheader[i] := GlobalLock (hwaveheader[i]);
      If (pwaveheader[i] = Nil ) Then
        begin
         { NOTE: This could lead to a memory leak, fix someday }
          RecErrorMessage := 'Could not lock header memory for recording';
          AllocWaveHeaders := FALSE;
          Exit;
        end;

    End;

  AllocWaveHeaders := TRUE;
END;

{---------------FreeWaveHeader----------------John Mertus---14-June--97--}

   Procedure TWaveRecorder.FreeWaveHeader;

{ Just free up the memory AllocWaveHeaders allocated.                   }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      If (hWaveHeader[i] <> 0) Then
        Begin
          GlobalUnlock(hwaveheader[i]);
          GlobalFree(hwaveheader[i]);
          hWaveHeader[i] := 0;
        End
    end;
END;

{
{-------------AllocPCMBuffers----------------John Mertus---14-June--97--}

   Function TWaveRecorder.AllocPCMBuffers : Boolean;

{ Allocate and lock the waveform memory.                                }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      hWaveBuffer[i] := GlobalAlloc( GMEM_MOVEABLE or GMEM_SHARE, fBufferSize
);
      If (hWaveBuffer[i] = 0) Then
        begin
          { Possible Memory Leak here }
          RecErrorMessage := 'Error allocating wave buffer memory';
          AllocPCMBuffers := False;
          Exit;
        end;

      pWaveBuffer[i] := GlobalLock(hWaveBuffer[i]);
      If (pWaveBuffer[i] = Nil) Then
        begin
          { Possible Memory Leak here }
          RecErrorMessage := 'Error Locking wave buffer memory';
          AllocPCMBuffers := False;
          Exit;
        end;
      pWaveHeader[i].lpData := pWaveBuffer[i];
    End;

  AllocPCMBuffers := TRUE;
END;

{--------------FreePCMBuffers----------------John Mertus---14-June--97--}

   Procedure TWaveRecorder.FreePCMBuffers;

{ Free up the meomry AllocPCMBuffers used.                              }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      If (hWaveBuffer[i] <> 0) Then
        Begin
          GlobalUnlock( hWaveBuffer[i] );
          GlobalFree( hWaveBuffer[i] );
          hWaveBuffer[i] := 0;
          pWaveBuffer[i] := Nil;
        End;
    end;
END;

{--------------FreeWaveFormatEx--------------John Mertus---14-June--97--}

   Procedure TWaveRecorder.FreeWaveFormatEx;

{ This just frees up the ExFormat headers                               }
{                                                                       }
{***********************************************************************}
BEGIN
  If (pWaveFmtEx = Nil) Then Exit;
  GlobalUnlock(hWaveFmtEx);
  GlobalFree(hWaveFmtEx);
  pWaveFmtEx := Nil;
END;

{-------------TWaveRecorder.Create------------John Mertus-----Aug--97--}

   Constructor TWaveRecorder.Create(BFSize, TotalBuffers : Integer);

{  This sets up the wave headers, initializes the data pointers and    }
{  allocates the sampling buffers                                      }
{     BFSize is the size of the buffer in BYTES                        }
{                                                                      }
{**********************************************************************}
Var
  i : Integer;
BEGIN
   Inherited Create;
   For i := 0 to fTotalBuffers-1 Do
     Begin
       hWaveHeader[i] := 0;
       hWaveBuffer[i] := 0;
       pWaveBuffer[i] := Nil;
       pWaveFmtEx := Nil;
     End;
   fBufferSize := BFze                 }
{                                                                       }
{**********************************************************************}
Var
  i : Integer;

BEGIN
  { make the wave buffer size a multiple of the block align... }
  WaveBufSize := fBufferSize - (fBufferSize mod pwavefmtex.nBlockAlign)3e                 }
{                                                                       }
{**********************************************************************}
Var
  i : Integer;

BEGIN
  { make the wave buffer size a multiple of the block align... }
  WaveBufSize := fBufferSize - (fBufferSize mod pwavefmtex.nBlockAlign);

  { Set the wave headers }
  For i := 0 to fTotalBuffers-1 Do
    With pWaveHeader[i]^ Do
      Begin
        lpData := pWaveBuffer[i];         // address of the waveform buffer
        dwBufferLength := WaveBufSize; // length, in bytes, of the buffer
        dwBytesRecorded := 0;          // see below
        dwUser := 0;                   // 32 bits of user data
        dwFlags := 0;                  // see below
        dwLoops := 0;                  // see below
        lpNext := Nil;                 // reserved; must be zero
        reserved := 0;                 // reserved; must be zero
      End;

  InitWaveHeaders := TRUE;
END;


{-------------AllocWaveHeader----------------John Mertus---14-June--97--}

   Function TWaveRecorder.AllocWaveHeaders : Boolean;

{ Allocate and lock header memory                                       }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      hwaveheader[i] := GlobalAlloc( GMEM_MOVEABLE or GMEM_SHARE or
GMEM_ZEROINIT, sizeof(TWAVEHDR));
      if (hwaveheader[i] = 0) Then
        begin
          { NOTE: This could lead to a memory leak, fix someday }
          RecErrorMessage := 'Error allocating wave header memory';
          AllocWaveHeaders := FALSE;
          Exit;
        end;

      pwaveheader[i] := GlobalLock (hwaveheader[i]);
      If (pwaveheader[i] = Nil ) Then
        begin
         { NOTE: This could lead to a memory leak, fix someday }
          RecErrorMessage := 'Could not lock header memory for recording';
          AllocWaveHeaders := FALSE;
          Exit;
        end;

    End;

  AllocWaveHeaders := TRUE;
END;

{---------------FreeWaveHeader----------------John Mertus---14-June--97--}

   Procedure TWaveRecorder.FreeWaveHeader;

{ Just free up the memory AllocWaveHeaders allocated.                   }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      If (hWaveHeader[i] <> 0) Then
        Begin
          GlobalUnlock(hwaveheader[i]);
          GlobalFree(hwaveheader[i]);
          hWaveHeader[i] := 0;
        End
    end;
END;

{
{-------------AllocPCMBuffers----------------John Mertus---14-June--97--}

   Function TWaveRecorder.AllocPCMBuffers : Boolean;

{ Allocate and lock the waveform memory.                                }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      hWaveBuffer[i] := GlobalAlloc( GMEM_MOVEABze                 }
{                                                                       }
{**********************************************************************}
Var
  i : Integer;

BEGIN
  { make the wave buffer size a multiple of the block align... }
  WaveBufSize := fBufferSize - (fBufferSize mod pwavefmtex.nBlockAlign);

  { Set the wave headers }
  For i := 0 to fTotalBuffers-1 Do
    With pWaveHeader[i]^ Do
      Begin
        lpData := pWaveBuffer[i];         // address of the waveform buffer
        dwBufferLength := WaveBufSize; // length, in bytes, of the buffer
        dwBytesRecorded := 0;          // see below
        dwUser := 0;                   // 32 bits of user data
        dwFlags := 0;                  // see below
        dwLoops := 0;                  // see below
        lpNext := Nil;                 // reserved; must be zero
        reserved := 0;                 // reserved; must be zero
      End;

  InitWaveHeaders := TRUE;
END;


{-------------AllocWaveHeader----------------John Mertus---14-June--97--}

   Function TWaveRecorder.AllocWaveHeaders : Boolean;

{ Allocate and lock header memory                                       }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      hwaveheader[i] := GlobalAlloc( GMEM_MOVEABLE or GMEM_SHARE or
GMEM_ZEROINIT, sizeof(TWAVEHDR));
      if (hwaveheader[i] = 0) Then
        begin
          { NOTE: This could lead to a memory leak, fix someday }
          RecErrorMessage := 'Error allocating wave header memory';
          AllocWaveHeaders := FALSE;
          Exit;
        end;

      pwaveheader[i] := GlobalLock (hwaveheader[i]);
      If (pwaveheader[i] = Nil ) Then
        begin
         { NOTE: This could lead to a memory leak, fix someday }
          RecErrorMessage := 'Could not lock header memory for recording';
          AllocWaveHeaders := FALSE;
          Exit;
        end;

    End;

  AllocWaveHeaders := TRUE;
END;

{---------------FreeWaveHeader----------------John Mertus---14-June--97--}

   Procedure TWaveRecorder.FreeWaveHeader;

{ Just free up the memory AllocWaveHeaders allocated.                   }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      If (hWaveHeader[i] <> 0) Then
        Begin
          GlobalUnlock(hwaveheader[i]);
          GlobalFree(hwaveheader[i]);
          hWaveHeader[i] := 0;
        End
    end;
END;

{
{-------------AllocPCMBuffers----------------John Mertus---14-June--97--}

   Function TWaveRecorder.AllocPCMBuffers : Boolean;

{ Allocate and lock the waveform memory.                                }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
  For i := 0 to fTotalBuffers-1 Do
    begin
      hWaveBuffer[i] := GlobalAlloc( GMEM_MOVEABze                 }
{                                                                       }
{**********************************************************************}
Var
  i : Integer;

BEGIN
  { make the wave buffer size a multiple of the block align... }
  WaveBufSize := fBufferSize - (fBufferSize mod pwavefmtex.nBlockAlign);

  { Set the wave headers }
  For i := 0 to fTotalBuffers-1 Do
    With pWaveHeader[i]^ Do
      Begin
        lpData := pWaveBuffer[i];         // address of the waveform buffer
        dwBufferLength := WaveBufSize; // length, in bytes, of the buffer
        dwBytesRecorded := 0;          // see below
        dwUser := 0;                   // 32 bits of user data
        dwFlags := 0;                  // see below
        dwLoops := 0;                  // see below
        lpNext := Nil;                 // reserved; must be zero
        reserved := 0;  
0
 

Expert Comment

by:silex
ID: 3989742
The problem with this idea is the minimun input frequency that can be sampled, say 0.1 Hz... This wave would be filtered by the sound boad.
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Suggested Solutions

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now