How to set the default audio input for Delphi? - delphi

I wonder how I can to set my default audio capture device (microphone) through Delphi.
I'm trying to use the functions of mmsystem api, following my code
procedure TForm1.Button1Click(Sender: TObject);
var
DevOutCaps: TWaveOutCaps;
DevInCaps: TWaveInCaps;
n, i: Integer;
s: String;
begin
n := waveInGetNumDevs;
for i := 0 to n-1 do
begin
waveInGetDevCaps(i, #DevInCaps, SizeOf(DevInCaps));
s := PChar(#DevInCaps.szPname);
ListBox1.Items.Add(s);
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
Ndev : Integer;
Adev : Integer;
begin
Ndev := AudioInDeviceNameToDeviceID(ListBox1.Items.Strings[ListBox1.ItemIndex]);
Adev := GetWaveInDevice;
ShowMessage( IntToStr(Adev) );
ShowMessage(ListBox1.Items.Strings[ListBox1.ItemIndex]);
ShowMessage( IntToStr(Ndev) );
if waveInMessage(HWAVEIN(WAVE_MAPPER), DRVM_MAPPER_PREFERRED_SET, Adev, Ndev) = MMSYSERR_NOTSUPPORTED then
begin
MessageDlg('NOT SUPPORTED', mtInformation, [mbOK], 0);
end;
Preferably no third party components.
Thank you

The WinMM API would seem to be the way to go, using the DRVM_MAPPER_PREFERRED_SET message Apparently, it is supported although undocumented under Win32 :-
WinMM API

Related

Delphi How To Use Microsoft Speech Recognition API

I need some help with my code, my application supposed to get my voice and write everything i say in a TMemo component, but it's simply doesn't do anything
Here is my code:
Am using SAPI 5.4 Microsoft Speech Object Library
procedure TForm1.initRecognizer;
begin
// Create Voice Handler
SpVoice := TSpVoice.Create(nil);
//**//
// Create Reconizer Context
SpInProcRecoContext := TSpInProcRecoContext.Create(nil);
SpInProcRecoContext.OnHypothesis := SpInProcRecoContextHypothesis;
SpInProcRecoContext.OnRecognition := SpInProcRecoContextRecognition;
//**//
// Create Grammar Rule
RecoGrammar := SpInProcRecoContext.CreateGrammar(0);
RecoGrammar.DictationSetState(SGDSActive);
//**//
end;
procedure TForm1.SpInProcRecoContextHypothesis(ASender: TObject;
StreamNumber: Integer; StreamPosition: OleVariant;
const Result: ISpeechRecoResult);
begin
Memo1.Text := Result.PhraseInfo.GetText(0,-1,true);
end;
procedure TForm1.SpInProcRecoContextRecognition(ASender: TObject;
StreamNumber: Integer; StreamPosition: OleVariant;
RecognitionType: SpeechRecognitionType; const Result: ISpeechRecoResult);
begin
SpInProcRecoContext.Recognizer.AudioInput := Result;
Memo1.Text := Result.PhraseInfo.GetText(0,-1,true);
end;
Please If there's a fix Will appreciate it, thanks in advance.

Possible to loop only declared properties of a class?

The extended RTTI has the GetDeclaredProperties function which is exactly what i need, however i faced problems if i use the extended RTTI in multi-threading.
Therefore, i used GetPropList, but this gives me a list of all properties - not only published in the current class (or explicit stated).
i.e.
TBaseSettings = class(TPersistent)
published
property Charset: string read FCharset write FCharset;
end;
TBasicSettings = class(TBaseSettings)
published
property forums: Variant read fforums write fforums;
end;
TConcreteSettings = class(TBasicSettings)
published
property forums; // <-- make it explicit visible: OK
property prefix: Variant read fprefix write fprefix; // <-- OK
end;
I don't want to read the Charset property.
My first guess was to use a modified version of https://stackoverflow.com/a/1565686 to check for inheritance, but actually the forums property is also inherited.
Maybe this is not possible with the classic RTTI? I use Delphi 2010.
In case it's convenient to have your code calling GetDeclaredPropList in a similar way to calling GetPropList, see below.
Edit: I've rewritten the code in Delphi 7 and I believe it should work in Delphi 2010, too (which I don't have at hand).
type
PPropData = ^TPropData;
function AfterString(P: Pointer): Pointer;
begin
Result := Pointer(NativeUInt(P) + (PByte(P)^ + 1));
end;
function GetPropData(TypeData: PTypeData): PPropData;
begin
Result := AfterString(#TypeData^.UnitName);
end;
function NextPropInfo(PropInfo: PPropInfo): PPropInfo;
begin
Result := AfterString(#PropInfo^.Name);
end;
procedure GetDeclaredPropInfos(TypeInfo: PTypeInfo; PropList: PPropList);
var
TypeData: PTypeData;
PropData: PPropData;
PropInfo: PPropInfo;
I: Integer;
begin
TypeData := GetTypeData(TypeInfo);
PropData := GetPropData(TypeData);
FillChar(PropList^, Sizeof(PPropInfo) * PropData^.PropCount, 0);
PropInfo := PPropInfo(#PropData^.PropList);
for I := 0 to PropData^.PropCount - 1 do
begin
PropList^[I] := PropInfo;
PropInfo := NextPropInfo(PropInfo);
end;
end;
function GetDeclaredPropList(TypeInfo: PTypeInfo; out PropList: PPropList): Integer; overload;
begin
Result := GetPropData(GetTypeData(TypeInfo))^.PropCount;
if Result > 0 then
begin
GetMem(PropList, Result * SizeOf(Pointer));
GetDeclaredPropInfos(TypeInfo, PropList);
end;
end;
function GetDeclaredPropList(AObject: TObject; out PropList: PPropList): Integer; overload;
begin
Result := GetDeclaredPropList(PTypeInfo(AObject.ClassInfo), PropList);
end;
// example usage:
var
I, Count: Integer;
PropList: PPropList;
PropInfo: PPropInfo;
begin
Count := GetDeclaredPropList(TypeInfo(TConcreteSettings), PropList);
try
for I := 0 to Count - 1 do
begin
PropInfo := PropList^[I];
Writeln(PropInfo^.Name);
end;
finally
FreeMem(PropList);
end;
end.
var
TypeData: PTypeData;
PropData: PPropData;
PropInfo: PPropInfo;
I: Integer;
begin
TypeData := GetTypeData(TypeInfo(TConcreteSettings));
PropData := GetPropData(TypeData);
if Assigned(PropData) then
begin
PropInfo := #PropData^.PropList;
for I := 0 to PropData^.PropCount - 1 do
begin
Writeln(PropInfo^.Name);
PropInfo := NextPropInfo(PropInfo);
end;
end;
end;
For implementation of GetPropData and NextPropInfo see my other answer above.

How to capture and save to file from webcam using DSPack and Delphi 5

right now I'm trying to make a program using Delphi 5 to take a photo from webcam.
I'm using delphi 5 and DSPack 2.3.1 because many people suggest it, and yes this is my first time programming multimedia with delphi.
I've been able to list and add camera that connect to my computer dynamically. I'm also able to display what the webcam "see", opening a video and capture it.
But now I can't capture a picture from the webcam.
I have a TImage which I named "Image", to check the picture is captured or not. When I use my code to open a video and capture it, it displayed in the TImage. But when I try to capture a webcam, it's just blank and not capturing anything. The file I saved also blank.
Could someone check which part of my code goes wrong?
Thanks before...
here's part of my code
var SysDev: TSysDevEnum;
FotoBitmap: TBitmap;
implementation
{$R *.DFM}
procedure Form1.FormCreate(Sender: TObject);
var
i: integer;
Device: TMenuItem;
begin
SysDev:= TSysDevEnum.Create(CLSID_VideoInputDeviceCategory);
if SysDev.CountFilters > 0 then
for i := 0 to SysDev.CountFilters - 1 do
begin
Device := TMenuItem.Create(Devices);
Device.Caption := SysDev.Filters[i].FriendlyName;
Device.Tag := i;
Device.OnClick := OnSelectDevice;
Devices.Add(Device);
end;
end;
procedure Form1.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
begin
SysDev.Free;
FilterGraph.ClearGraph;
FilterGraph.Active := false;
end;
procedureForm1.OnSelectDevice(sender: TObject);
var
CaptureGraph: ICaptureGraphBuilder2;
SourceFilter, DestFilter: IBaseFilter;
begin
FilterGraph.ClearGraph;
FilterGraph.Active := false;
Filter.BaseFilter.Moniker := SysDev.GetMoniker(TMenuItem(Sender).tag);
Filter.FilterGraph := FilterGraph;
FilterGraph.Active := true;
FilterGraph.QueryInterface(ICaptureGraphBuilder2, CaptureGraph);
Filter.QueryInterface(IBaseFilter, SourceFilter);
VideoWindow.QueryInterface(IBaseFilter, DestFilter);
if Filter.BaseFilter.DataLength > 0 then
CaptureGraph.RenderStream(nil, nil, SourceFilter, nil, DestFilter);
FilterGraph.Play;
CaptureGraph := nil;
SourceFilter := nil;
DestFilter := nil;
end;
procedure Form1.SnapshotClick(Sender: TObject);
var dir : String;
begin
if edt_nama_foto.Text <> '' then begin
dir := ExtractFilePath(Application.ExeName);
FotoBitmap := TBitmap.Create;
try
SampleGrabber.GetBitmap(FotoBitmap);
SampleGrabber.GetBitmap(Image.Picture.Bitmap);
showmessage(dir + 'Image\Foto\' + edt_nama_foto.Text + '.bmp');
FotoBitmap.SaveToFile(dir + 'Image\Foto\' + edt_nama_foto.Text + '.bmp');
finally
FotoBitmap.Free;
end;
end;
end;
procedure Form1.btn_batalClick(Sender: TObject);
begin
modalresult:=mrCancel;
end;
procedure Form1.btn_simpanClick(Sender: TObject);
begin
If CheckbeforeOK then
begin
ModalResult :=mrOK;
end else begin
ModalResult := mrNone;
end;
end;
function Form1.CheckbeforeOK:Boolean;
var flag:boolean;
MasterDataSet:TQuery;
begin
Flag:=True;
if flag and not(checkedit(nil, nil, edt_nama_foto, edt_nama_foto.Text, 'Nama Foto'))
then begin
flag := False;
end else begin
Snapshot.Click;
end;
Result := flag;
end;
procedure Form1.SampleGrabberBuffer(sender: TObject;
SampleTime: Double; pBuffer: Pointer; BufferLen: Integer);
begin
Image.Picture.Bitmap.Canvas.Lock;
try
SampleGrabber.GetBitmap(Image.Picture.Bitmap, pBuffer, BufferLen);
finally
Image.Picture.Bitmap.Canvas.UnLock;
end;
end;
end.
The object which "transfers" video frame into image object is SampleGrabber:
SampleGrabber.GetBitmap(Image.Picture.Bitmap, pBuffer, BufferLen);
However it needs to be inserted in to filter graph when you build it, and you are apparently not doing it in your OnSelectDevice: there is no mention of SampleGrabber there at all. You need to include it into RenderStream call or otherwise get it inserted there so that video is streamed through it and your callback is called copying data into TImage.

Delphi 7 - Fetch value from a website

let's see if yaw can help me out here,
Supposing there's a link: www.example.com/test.html
Upon opening, it would show either 0 or 1.
I need to fetch that value. I.e.:
if internet.value := 0 then ShowMessage('False') else ShowMessage('True');
It could be using indy components or winsockets, how would I go about this one?
If you're talking about a plain text file containing just an integer value, you can use Indy for this e.g. this way. The following function returns True, when the page downloading succeeded and when the page contains an integer value, False otherwise. Please note, that I wrote it in browser so it's untested:
uses
IdHTTP;
function TryWebContentToInt(const AURL: string; out AValue: Integer): Boolean;
var
S: string;
IdHTTP: TIdHTTP;
begin
IdHTTP := TIdHTTP.Create(nil);
try
IdHTTP.HandleRedirects := True;
try
S := IdHTTP.Get(AURL);
Result := TryStrToInt(S, AValue);
except
Result := False;
end;
finally
IdHTTP.Free;
end;
end;
And the usage:
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
begin
if TryWebContentToInt('http://example.com/page.html', I) then
ShowMessage('Value: ' + IntToStr(I))
else
ShowMessage('Page downloading failed or it doesn''t contain an integer value!');
end;

How to display registry in A treeView in Delphi 7

I want to display a treeview with all the registry information in it ( i.e all the subkeys ). I have put together the following Fn to do the same. But i am getting the info of only one Key, not all. What is missing in my code ?
function TForm1.DisplayKeys(TreeNode : TTreeNode;KeyToSearch:String):String;
var
i: Integer;
RootKey : Integer;
NewTreeNode : TTreeNode;
str : TStringList;
// str2: TStringList;
begin
i:=0;
if reg.OpenKey(KeyToSearch,False) then
begin
str:=nil;
str:=TStringList.create;
reg.GetKeyNames(str);
//For all SubKeys
for i:=0 to str.Count-1 do
begin
NewTreeNode:=TreeView1.Items.AddChild(TreeNode, Str.Strings[i]);
if reg.HasSubKeys then
begin
DisplayKeys(NewTreeNode,Str.Strings[i]);
end;
end;
end;
the call to the Function is
procedure TForm1.FormCreate(Sender: TObject);
begin
reg:=nil;
reg:=TRegistry.create;
str2:=nil;
str2:=TStringList.create;
reg.RootKey:=HKEY_CURRENT_CONFIG;
TreeView1.Items.BeginUpdate; //prevents screen repaint every time node is added
DisplayKeys(nil,''); // call to fn here
TreeView1.Items.EndUpdate; // Nodes now have valid indexes
end;
Note that i am not getting any error, just that info is incomplete
Some problems:
You are using OpenKey which attempts to open the key with write access. Instead you should use OpenKeyReadOnly. If you really do mean to write to those keys then you will have to run elevated as an administrator.
You are failing to close the keys once you have finished with them.
More seriously, your use of relative registry keys is not sufficient. I believe you will need to pass around the full path to the key. I wrote a little demo console app to show what I mean:
program RegistryEnumerator;
{$APPTYPE CONSOLE}
uses
Classes, Windows, Registry;
var
Registry: TRegistry;
procedure DisplayKeys(const Key: string; const Depth: Integer);
var
i: Integer;
SubKeys: TStringList;
begin
if Registry.OpenKeyReadOnly(Key) then begin
Try
SubKeys := TStringList.Create;
Try
Registry.GetKeyNames(SubKeys);
for i := 0 to SubKeys.Count-1 do begin
Writeln(StringOfChar(' ', Depth*2) + SubKeys[i]);
DisplayKeys(Key + '\' + SubKeys[i], Depth+1);
end;
Finally
SubKeys.Free;
End;
Finally
Registry.CloseKey;
End;
end;
end;
begin
Registry := TRegistry.Create;
Try
Registry.RootKey := HKEY_CURRENT_CONFIG;
DisplayKeys('', 0);
Readln;
Finally
Registry.Free;
End;
end.
try this :-
procedure TForm1.Button1Click(Sender: TObject);
begin
TreeView1.Items.Clear;
path := Edit1.Text;
// reg.RootKey := HKEY_LOCAL_MACHINE ;
TreeView1.Items.BeginUpdate;
drawtreeview(nil, path);
TreeView1.Items.EndUpdate;
end;
procedure TForm1.drawtreeview( node: TTreeNode; name: string);
var
i: Integer;
NewTreeNode: TTreeNode;
str, str2 : TStringList;
reg : TRegistry;
begin
reg := TRegistry.Create;
reg.RootKey := HKEY_LOCAL_MACHINE;
i := 0;
if reg.OpenKeyReadOnly(name) then
begin
str := TStringList.create;
reg.GetKeyNames(str);
for i := 0 to str.Count - 1 do
begin
NewTreeNode := TreeView1.Items.AddChild(node, str.Strings[i]);
if reg.HasSubKeys then
begin
drawtreeview(NewTreeNode, name + '\' + str.Strings[i]);
end
else
ShowMessage('no sub keys');
end;
end;
reg.CloseKey;
reg.Free;
end;

Resources