Solved

How to Select Line-in from win95 Rec Control in software?

Posted on 1998-01-08
4
249 Views
Last Modified: 2010-04-04
I'm using Delphi2. I want to select the line-in from the win95 recording control. Also, I want to mute the line-in of the win95 volume control. How do I do that by software? Could someone please provide me with some example code to do these?
0
Comment
Question by:chrisyap
4 Comments
 
LVL 4

Expert Comment

by:itamar
ID: 1355993
I think it's worth to take a look at:

Information:
http://SunSITE.icm.edu.pl/delphi/ftp/d30share/volctrl3.txt

DownLoad:
http://SunSITE.icm.edu.pl/delphi/ftp/d30share/volctrl3.zip

I didn't try it, but I think it has a lot to do with your question.

IHTH,
Itamar
0
 

Author Comment

by:chrisyap
ID: 1355994
Itamar,
Thanks for the info, but I would like to find out exactly how to do it rather than depend on a component for this case.

Chris.

Someone please help!

0
 
LVL 8

Accepted Solution

by:
ZifNab earned 200 total points
ID: 1355995
I'm not sure, but this can help you (from UDDF) :

I've some interesting links, about wave routines, I can can send them to you also.

Low Level WaveIn routine

From: John_Mertus@brown.edu (John_Mertus)

A while back someone asked for code that allows one to process data from the input of a soundcard. Hopefully
this unit will show how to do this.

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 := BFSize;

   fTotalBuffers := TotalBuffers;
  { allocate memory for wave format structure }
  If(Not AllocWaveFormatEx) Then
    Begin
      InitWaveRecorder := FALSE;
      Exit;
    End;

  { find a device compatible with the available wave characteristics }
  If (waveInGetNumDevs < 1 ) Then
    Begin
      RecErrorMessage := 'No wave audio recording devices found';
      InitWaveRecorder := FALSE;
      Exit;
    End;

  { allocate the wave header memory }
  If (Not AllocWaveHeaders) Then
    Begin
      InitWaveRecorder := FALSE;
      Exit;
    End;

 { allocate the wave data buffer memory }
  If (Not AllocPCMBuffers)  Then
    Begin
      InitWaveRecorder := FALSE;
      Exit;
    End;

  InitWaveRecorder := TRUE;

END;

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

   Destructor TWaveRecorder.Destroy;

{ Just free up all memory allocated by InitWaveRecorder.                }
{                                                                       }
{***********************************************************************}

BEGIN
  FreeWaveFormatEx;
  FreePCMBuffers;
  FreeWaveHeader;
  Inherited Destroy;
END;

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

   Procedure TWaveRecorder.CloseWaveDeviceRecord;

{ Just close up the waveform device.                                    }
{                                                                       }
{***********************************************************************}
Var
  i : Integer;

BEGIN
   { if the device is already closed, just return }
   If (Not bDeviceOpen) Then Exit;

   { unprepare the headers }
   For i := 0 to fTotalBuffers-1 Do
    If (waveInUnprepareHeader(WaveIn, pWaveHeader[i], sizeof(TWAVEHDR)) <> 0 )
Then
      RecErrorMessage := 'Error in waveInUnprepareHeader';

   { save the total size recorded and update the display }
   dwTotalwavesize := dwBytedatasize;

   { close the wave input device }
   If (waveInClose(WaveIn) <> 0) Then
     RecErrorMessage := 'Error closing input device';

   { tell this function we are now closed }
   bDeviceOpen := FALSE;

END;

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

   Procedure TWaveRecorder.StopRecord;

{ This stops the recording and sets some flags.                         }
{                                                                       }
{***********************************************************************}
Var
  iErr : Integer;

BEGIN

  RecordActive := False;
  iErr := waveInReset(WaveIn);
  { stop recording and return queued buffers }
  If (iErr <> 0) Then
     Begin
        RecErrorMessage := 'Error in waveInReset';
     End;

  CloseWaveDeviceRecord;
END;

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

   Function TWaveRecorder.AddNextBuffer : Boolean;

{ This adds a buffer to the input queue and toggles buffer index.       }
{                                                                       }
{***********************************************************************}
Var
  iErr : Integer;

BEGIN
  { queue the buffer for input }
   iErr := waveInAddBuffer(WaveIn, pwaveheader[bufindex], sizeof(TWAVEHDR));
   If (iErr <> 0) Then
     begin
       StopRecord;
       RecErrorMessage := 'Error adding buffer' + TWaveInGetErrorText(iErr);
       AddNextBuffer := FALSE;
       Exit;
     end;

   { toggle for next buffer }
   bufindex := (bufindex+1) mod fTotalBuffers;
   QueuedBuffers := QueuedBuffers + 1;

   AddNextBuffer := TRUE;
END;


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

  Procedure BufferDoneCallBack(
    hW    : HWAVE;      // handle of waveform device
    uMsg  : DWORD;      // sent message
    dwInstance : DWORD; // instance data
    dwParam1 : DWORD;   // application-defined parameter
    dwParam2 : DWORD    // application-defined parameter
   );  stdcall;

{ This is called each time the wave device has info, e.g. fills a buffer}
{                                                                       }
{***********************************************************************}
Var
  BaseRecorder : PWaveRecorder;
BEGIN
  BaseRecorder := Pointer(DwInstance);
With BaseRecorder^ Do
  Begin
   ProcessBuffer(uMsg, pWaveBuffer[ProcessedBuffers Mod fTotalBuffers],
WaveBufSize);
   If (RecordActive) Then
      Case uMsg of
        WIM_DATA:
          Begin
            BaseRecorder.AddNextBuffer;
            ProcessedBuffers := ProcessedBuffers+1;
          End;
      End;
  End;
END;

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

   Function TWaveRecorder.StartRecord : Boolean;

{ This does all the work in creating the waveform recorder.             }
{                                                                       }
{***********************************************************************}
Var
  iErr, i : Integer;
 
BEGIN
  { start recording to first buffer }
  iErr := WaveInStart(WaveIn);
  If (iErr <> 0) Then
    begin
      CloseWaveDeviceRecord;
      RecErrorMessage := 'Error starting wave record: ' +
TWaveInGetErrorText(iErr);
    end;

   RecordActive := TRUE;

   { queue the next buffers }
   For i := 1 to fTotalBuffers-1 Do
     If (Not AddNextBuffer) Then
       Begin
         StartRecord := FALSE;
         Exit;
       End;

   StartRecord := True;
END;

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

   Function TWaveRecorder.SetupRecord(P : PWaveRecorder) : Boolean;

{ This does all the work in creating the waveform recorder.             }
{                                                                       }
{***********************************************************************}
Var
  iErr, i : Integer;

BEGIN
  dwTotalwavesize := 0;
  dwBytedatasize := 0;
  bufindex := 0;
  ProcessedBuffers := 0;
  QueuedBuffers := 0;

  { open the device for recording }
  iErr := waveInOpen(@WaveIn, WAVE_MAPPER, pWaveFmtEx,
Integer(@BufferDoneCallBack),
                 Integer(P), CALLBACK_FUNCTION + WAVE_ALLOWSYNC );
  If (iErr <> 0) Then
    Begin
      RecErrorMessage := 'Could not open the input device for recording: ' + ^M
+
                         TWaveInGetErrorText(iErr);
      SetupRecord := FALSE;
      Exit;
    End;

  { tell CloseWaveDeviceRecord() that the device is open }
  bDeviceOpen := TRUE;

  { prepare the headers }

  InitWaveHeaders();

  For i := 0 to fTotalBuffers-1 Do
    Begin
     iErr := waveInPrepareHeader( WaveIn, pWaveHeader[I], sizeof(TWAVEHDR));
       If (iErr <> 0) Then
         begin
           CloseWaveDeviceRecord;
           RecErrorMessage := 'Error preparing header for recording: ' + ^M +
                               TWaveInGetErrorText(iErr);
           SetupRecord := FALSE;
           Exit;
         end;
    End;

  { add the first buffer }
  If (Not AddNextBuffer) Then
    begin
      SetupRecord := FALSE;
      Exit;
    end;

   SetupRecord := TRUE;
END;

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

     Procedure   TWaveRecorder.ProcessBuffer(uMsg: Word; P : Pointer; n :
Integer);

{ Dummy procedure that is called when a buffer is ready.                }
{                                                                       }
{***********************************************************************}
BEGIN
END;

END.

Good luck!
Hope your something with this.
Zif.
0
 

Expert Comment

by:MorrisLockwood
ID: 8102998
Does anybody know how to do this for sounds GOING to the sound card without using an external cable link?

Morris
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Intraweb download file link ? 1 153
Delphi...Split view - idea? 1 87
Installshield for Embarcadero EX 10.1 Berlin 4 60
enhance the following code 3 37
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
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…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

789 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