Re: Delphi and DSP
- From: MeMyselfAndI <agp001@xxxxxxxxxxxxxxx>
- Date: Fri, 30 Sep 2005 12:13:32 +1000
Jatin wrote:
MeMyselfAndI wrote:
Jatin -
No sound card can interpret data into sound. Sound cards take PCM data (ie: plain digital audio as in a .wav file or a CD) and convert it into analog signals. To get the physical parameters you told Marc about to come out as sound you need to write the interpretation rules into your program and get your program to create PCM data based on what information comes through the com port. (Incidentally, why not use a USB port)? You then use the windows sound playback routines to play those sounds. I've got a class that I use for playing buffers of wave data up to 8MB. I'll send it to you if you like.
I will appreciate if you can share the class with me.
Thanks,
Jatin ============
Okay, here it is...
Regards, Andrew
unit SimpleWaveIO;
{Last major modification: 23/08/00}
{Last minor modification: 08/08/01}
// Look at MMWPlay.pas to find out how to obtain deviceID's, product names and
// cast handles for wave out devices. Also find out how to obtain the complete
// details on device capabilities. Replace Force16Bit and PlayAs16 with code
// that will rescale data to whatever the device capabilities are.
// Write the class for recording wave data, and see to a proper inheritance
// pattern from TobjSimpleWaveIO, shifting fields that are applicable only to
// WaveOut operations downwards and those that may be shared (such as
// SetWaveFormatEx?) upwards.
// Try using the dwCallback parameter in WaveOutOpen to pass a pointer to a
// method which will refresh the waveheaders with new data when they have been
// played. This will consume less CPU time than the current design with a
// TTimer in constant progress.
interface
uses
Windows, SysUtils, MMSystem, Classes, AudioInfoStructures, RWAudioFile,
Streams, General, ExtCtrls, Dialogs;
const
uDeviceID_dflt : UINT = WAVE_MAPPER;
fdwOpen_dflt : DWORD = CALLBACK_NULL;
Callback_dflt : DWORD = 0;
TimeReportFmt = TIME_SAMPLES;
type
TenmTimeFormat = (tfSamples, tfMilliSecs, tfBytes, tfMIDI, tfSMPTE, tfTicks);
TenmWIOState = (prClosed, prIdle, prPaused, prPlaying, prRecording);
TobjSimpleWaveIO = class(TObject)
protected
WaveHdr : TWAVEHDR;
ptrWaveHdr : PWAVEHDR;
cbwh : UINT;
hndWaveOut : HWAVEOUT;
cbmmt : UINT;
mmt : TMMTIME;
pmmt : PMMTIME;
uDeviceID : UINT;
wfx : TWAVEFORMATEX;
MMReturn : MMResult;
dwCallback,
dwCallbackInstance : DWORD;
Stopping,
Creating,
Destroying,
Closing,
// FMute,
WaveOut,
MakeVoid,
FStopNow,
FCloseWhenDone : Boolean;
PtrRec : TrecSubPointer;
FState : TenmWIOState;
WaveSelect : PrecProcessData;
AudioInfo : PrecAudioInfo;
procedure SetTimeFormat (NewFmt: TenmTimeFormat);
function GetTimeFormat : TenmTimeFormat;
destructor Destroy; override;
procedure Initialise;
constructor Create;
public
function Stop : boolean;
function Pause : boolean;
function Resume : boolean;
function Close : boolean;
property StopNow : boolean read FStopNow write FStopNow;
property State : TenmWIOState read FState write FState;
property CloseWhenDone : boolean read FCloseWhenDone write FCloseWhenDone;
property TimeFormat : TenmTimeFormat read GetTimeFormat write SetTimeFormat;
// property Mute : Boolean read FMute write FMute;
end;
TobjPlaySound = class(TobjSimpleWaveIO)
private
cbwoc : UINT;
fdwOpen : DWORD;
woc : TWaveOutCapsA;
pwoc : PWaveOutCapsA;
Initialised : Boolean;
FFramesGot,
FramesReturned : Integer;
ptrBuffer : Pointer;
protected
procedure Initialise;
function GetFramesPosn : Integer;
function GetTimePosn : Integer;
function SetWaveFormatEx : TWAVEFORMATEX;
procedure DisposeWHDR;
public
function InitPlay (AudInf:PrecAudioInfo; WvSlct:PrecProcessData): Boolean;
function Play (ptrData:pointer): Boolean;
function NewPosition (WvSlct:PrecProcessData; ptrData:Pointer;
AState:TenmWIOState): Boolean;
function Stop: Boolean;
constructor Create;
property FramesPosn : integer read GetFramesPosn;
property TimePosn : integer read GetTimePosn;
property FramesGot : integer read FFramesGot;
property DeviceCaps : TWaveOutCapsA read woc;
end;
TobjRecdSound = class (TobjSimpleWaveIO)
public
function Recrd (AudInf: PrecAudioInfo; WvSlct: PrecProcessData): boolean;
end;
implementation
//----- TobjSimpleWaveIO -------------------------------------------------------
procedure TobjSimpleWaveIO.SetTimeFormat (NewFmt: TenmTimeFormat);
begin
case NewFmt of
tfMilliSecs : mmt.wType := TIME_MS;
tfSamples : mmt.wType := TIME_SAMPLES;
tfBytes : mmt.wType := TIME_BYTES;
tfMIDI : mmt.wType := TIME_MIDI;
tfSMPTE : mmt.wType := TIME_SMPTE;
tfTicks : mmt.wType := TIME_TICKS;
end;
end;
//----- TobjSimpleWaveIO -------------------------------------------------------
function TobjSimpleWaveIO.GetTimeFormat : TenmTimeFormat;
begin
case mmt.wType of
TIME_MS : Result := tfMilliSecs;
TIME_SAMPLES : Result := tfSamples;
TIME_BYTES : Result := tfBytes;
TIME_MIDI : Result := tfMIDI;
TIME_SMPTE : Result := tfSMPTE;
TIME_TICKS : Result := tfTicks;
end;
end;
//----- TobjSimpleWaveIO -------------------------------------------------------
procedure TobjSimpleWaveIO.Initialise;
begin
if (Stopping) or (Creating) then
begin
cbmmt := 0;
with mmt do
begin
wType := TIME_SAMPLES;
ms := 0;
sample := 0;
cb := 0;
ticks := 0;
hour := 0;
min := 0;
sec := 0;
frame := 0;
fps := 0;
dummy := 0;
songptrpos := 0;
end;
end;
if Destroying then pmmt := nil;
WaveHdr.lpData := nil;
if Closing then
begin
uDeviceID := 0;
with wfx do
begin
wFormatTag := 0;
nChannels := 0;
nSamplesPerSec := 0;
nAvgBytesPerSec := 0;
nBlockAlign := 0;
wBitsPerSample := 0;
end;
cbwh := 0;
end;
if Creating then
begin
ptrWaveHdr := @WaveHdr;
pmmt := @mmt;
uDeviceID := uDeviceID_dflt;
mmt.wType := TimeReportFmt;
State := prClosed;
end;
end;
//----- TobjSimpleWaveIO -------------------------------------------------------
destructor TobjSimpleWaveIO.Destroy;
begin
if integer(State) > integer (prIdle) then Stop;
Close;
Destroying := true;
Initialise;
inherited Destroy;
end;
//----- TobjSimpleWaveIO -------------------------------------------------------
constructor TobjSimpleWaveIO.Create;
begin
Inherited Create;
Creating := true;
Initialise;
Creating := false;
end;
//----- TobjSimpleWaveIO -------------------------------------------------------
function TobjSimpleWaveIO.Stop: boolean;
begin
Stopping := true;
StopNow := true;
Result := (State = prIdle) or (State = prClosed);
if not Result then Result := WaveOutReset (hndWaveOut) = MMSYSERR_NOERROR;
Initialise;
if Result then State := prIdle;
Stopping := false;
end;
//----- TobjSimpleWaveIO -------------------------------------------------------
function TobjSimpleWaveIO.Pause: boolean;
begin
Result := false;
if (State = prPlaying) or (State = prRecording) then
begin
Result := WaveOutPause (hndWaveOut) = MMSYSERR_NOERROR;
if Result then
begin
State := prPaused;
// Mute := true;
end;
end;
end;
//----- TobjSimpleWaveIO -------------------------------------------------------
function TobjSimpleWaveIO.Resume: boolean;
begin
Result := false;
if State <> prPaused then exit;
Result := WaveOutRestart (hndWaveOut) = MMSYSERR_NOERROR;
if Result then
begin
if WaveOut then State := prPlaying
else State := prRecording;
// Mute := false;
end;
end;
//----- TobjSimpleWaveIO -------------------------------------------------------
function TobjSimpleWaveIO.Close : boolean;
begin
if State <> prClosed then
begin
MMReturn := WaveOutClose(hndWaveOut);
Result := MMReturn = MMSYSERR_NOERROR;
if MMReturn = WAVERR_STILLPLAYING then
begin
Stop;
Result := WaveOutClose(hndWaveOut) = MMSYSERR_NOERROR;
end;
end else Result := true;
if Result then
begin
State := prClosed;
Closing := true;
Initialise;
Closing := false;
end;
end;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//----- TobjPlaySound ----------------------------------------------------------
procedure TobjPlaySound.Initialise;
begin
// inherited Initialise;
if Closing then
begin
hndWaveOut := 0;
cbwoc := 0;
fdwOpen := 0;
FramesReturned := 0;
end;
if Destroying then
begin
pwoc := nil;
end;
if Creating then
begin
pwoc := @woc;
fdwOpen := CALLBACK_NULL;
dwCallback := 0; //DWORD(@TobjPlaySound.WaveCallback);
dwCallbackInstance := 0; //DWORD(@WaveHdr);
WaveOut := true;
end;
end;
//----- TobjPlaySound ----------------------------------------------------------
procedure TobjPlaySound.DisposeWHDR;
begin
WaveOutUnprepareHeader (hndWaveOut, ptrWaveHdr, cbwh);
WaveHdr.lpData := nil;
end;
//----- TobjPlaySound ----------------------------------------------------------
function TobjPlaySound.GetFramesPosn : integer;
begin
if WaveOutGetPosition (hndWaveOut, pmmt, cbmmt) = MMSYSERR_NOERROR
then Result := mmt.sample div WaveSelect.ChnlsReqd
else Result := -1;
end;
//----- TobjPlaySound ----------------------------------------------------------
function TobjPlaySound.GetTimePosn : integer;
begin
if WaveOutGetPosition (hndWaveOut, pmmt, cbmmt) = MMSYSERR_NOERROR
then Result := mmt.ms
else Result := -1;
end;
//----- TobjPlaySound ----------------------------------------------------------
function TobjPlaySound.SetWaveFormatEx : TWAVEFORMATEX;
const DataTypeFlag = 1;
begin
With Result do
begin
wFormatTag := DataTypeFlag;
nChannels := WaveSelect.ChnlsReqd;
nSamplesPerSec := AudioInfo.Rate;
nAvgBytesPerSec := AudioInfo.BytesPSec;
nBlockAlign := AudioInfo.BlockAlign;
wBitsPerSample := AudioInfo.BitsPSmpl;
if wFormatTag = 1 then cbSize := 0 else cbSize := 256;
// 256 is arbitrary. Just for while PCM only is supported.
end;
end;
//----- TobjPlaySound ----------------------------------------------------------
function TobjPlaySound.InitPlay (AudInf: PrecAudioInfo;
WvSlct: PrecProcessData) : boolean;
begin
AudioInfo := AudInf;
WaveSelect := WvSlct;
wfx := SetWaveFormatEx;
cbwoc := SizeOf (woc);
cbmmt := SizeOf (mmt);
if WaveOutOpen (@hndWaveOut, uDeviceID, @wfx, dwCallback,
dwCallbackInstance, WAVE_FORMAT_QUERY) <> MMSYSERR_NOERROR then
begin
Result := false;
ShowMessage ('Audio format not supported by the wave out device.');
Close;
end
else begin
MMReturn := WaveOutOpen (@hndWaveOut, uDeviceID, @wfx, dwCallback,
dwCallbackInstance, CALLBACK_NULL);
Result := MMReturn = MMSYSERR_NOERROR; // Use of MMReturn for debugging only.
end;
if Result then
begin
State := prIdle;
Initialised := true;
end
else begin
ShowMessage ('Unable to open wave out device.');
Close;
end;
end;
//----- TobjPlaySound ----------------------------------------------------------
function TobjPlaySound.Play (ptrData: pointer) : boolean;
begin
Result := false;
if Initialised then
begin
WaveHdr.dwBufferLength := WaveSelect.SelectBytes;
WaveHdr.lpData := ptrData;
WaveHdr.dwFlags := 0;
cbwh := SizeOf (WaveHdr);
State := prPlaying;
MMReturn := WaveOutPrepareHeader (hndWaveOut, @WaveHdr, cbwh);
Result := MMReturn = MMSYSERR_NOERROR;
if not Result then
begin
Close;
ShowMessage ('Unable to prepare wave out header.');
Exit;
end
else begin
MMReturn := WaveOutWrite (hndWaveOut, @WaveHdr, cbwh);
Result := MMReturn = MMSYSERR_NOERROR;
if not Result then
begin
Close;
ShowMessage ('Unable to send data to wave out device.');
end
// Think up a new way to dispose of the Wave Header.
end;
end;
end;
//---- TobjPlaySound -----------------------------------------------------------------------
function TobjPlaySound.NewPosition (WvSlct:PrecProcessData; ptrData:Pointer;
AState:TenmWIOState) : boolean;
begin
Stop;
WaveSelect := WvSlct;
Initialised := true;
if (AState = prPlaying) then Result := Play (ptrData)
else if (AState = prPaused) then Result := Pause;
end;
//----- TobjPlaySound ----------------------------------------------------------
function TobjPlaySound.Stop : boolean;
begin
Result := inherited Stop;
DisposeWHDR;
end;
//----- TobjPlaySound ----------------------------------------------------------
constructor TobjPlaySound.Create;
begin
inherited Create;
Creating := true;
Initialise;
Creating := false;
end;
//==========================================================================================
//==========================================================================================
//----- TobjRecdSound ----------------------------------------------------------
function TobjRecdSound.Recrd (AudInf: PrecAudioInfo; WvSlct: PrecProcessData): boolean;
begin
Result := false;
{ Yet to write }
end;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
end.
- References:
- Delphi and DSP
- From: Jatin
- Re: Delphi and DSP
- From: MeMyselfAndI
- Re: Delphi and DSP
- From: Jatin
- Delphi and DSP
- Prev by Date: Re: FFT class or routines
- Next by Date: Re: Detecting Window
- Previous by thread: Re: Delphi and DSP
- Next by thread: Pascal Look - help you understand your pascal unit file
- Index(es):