Delphi library for MIDI input/output? - delphi

What is a good Delphi library for MIDI input/output?

Are you sure that you really need a third-party library? If your needs are basic, the Windows API is all you need (using MMSystem).
var
mo: HMIDIOUT;
const
MIDI_NOTE_ON = $90;
MIDI_NOTE_OFF = $80;
MIDI_CHANGE_INSTRUMENT = $C0;
MIDI_DEVICE = 0;
MIDI_VEL = 108;
procedure MIDIInit;
begin
midiOutOpen(#mo, MIDI_DEVICE, 0, 0, CALLBACK_NULL);
SetPlaybackVolume($FFFFFFFF);
end;
function MIDIEncodeMessage(Msg, Param1, Param2: integer): integer;
begin
result := Msg + (Param1 shl 8) + (Param2 shl 16);
end;
procedure SetCurrentInstrument(CurrentInstrument: TMIDIInstrument);
begin
midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_CHANGE_INSTRUMENT, ord(CurrentInstrument), 0));
end;
procedure NoteOn(NewNote, NewIntensity: byte);
begin
midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_NOTE_ON, NewNote, NewIntensity));
end;
procedure NoteOff(NewNote, NewIntensity: byte);
begin
midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_NOTE_OFF, NewNote, NewIntensity));
end;
procedure SetPlaybackVolume(PlaybackVolume: cardinal);
begin
midiOutSetVolume(mo, PlaybackVolume);
end;
where the instruments are
type
TMIDIInstrument = (midiAcousticGrandPiano, midiBrightAcousticPiano,
midiElectricGrandPiano, midiHonkyTonkPiano,
midiRhodesPiano, midiChorusedPiano, midiHarpsichord,
midiClavinet, midiCelesta, midiGlockenspiel,
midiMusicBox, midiVibraphone, midiMarimba, midiXylophone,
midiTubularBells, midiDulcimer, midiHammondOrgan,
midiPercussiveOrgan, midiRockOrgan, midiChurchOrgan,
midiReedOrgan, midiAccordion, midiHarmonica,
midiTangoAccordion, midiAcousticGuitarNylon,
midiAcousticGuitarSteel, midiElectricGuitarJazz,
midiElectricGuitarClean, midiElectricGuitarMuted,
midiOverdrivenGuitar, midiDistortionGuitar,
midiGuitarHarmonics, midiAcousticBass, midiElectricBassFinger,
midiElectricBassPick, midiFretlessBass, midiSlapBass1,
midiSlapBass2, midiSynthBass1, midiSynthBass2, midiViolin,
midiViola, midiCello, midiContrabass, midiTremoloStrings,
midiPizzicatoStrings, midiOrchestralHarp, midiTimpani,
midiStringEnsemble1, midiStringEnsemble2, midiSynthStrings1,
midiSynthStrings2, midiChoirAahs, midiVoiceOohs,
midiSynthVoice, midiOrchestraHit, midiTrumpet, midiTrombone,
midiTuba, midiMutedTrumpet, midiFrenchHorn, midiBrassSection,
midiSynthBrass1, midiSynthBrass2, midiSopranoSax, midiAltoSax,
midiTenorSax, midiBaritoneSax, midiOboe, midiEnglishHorn,
midiBassoon, midiClarinet, midiPiccolo, midiFlute,
midiRecorder, midiPanFlute, midiBottleBlow, midiShakuhachi,
midiWhistle, midiOcarina, midiLead1Square,
midiLead2Sawtooth, midiLead3CalliopeLead, midiLead4ChiffLead,
midiLead5Charang, midiLead6Voice, midiLead7Fifths,
midiLead8BrassLead, midiPad1NewAge, midiPad2Warm,
midiPad3Polysynth, midiPad4Choir, midiPad5Bowed,
midiPad6Metallic, midiPad7Halo, midiPad8Sweep, midiEmpty0,
midiEmpty1, midiEmpty2, midiEmpty3, midiEmpty4, midiEmpty5,
midiEmpty6, midiEmpty7, midiEmpty8, midiEmpty9, midiEmpty10,
midiEmpty11, midiEmpty12, midiEmpty13, midiEmpty14,
midiEmpty15, midiEmpty16, midiEmpty17, midiEmpty18,
midiEmpty19, midiEmpty20, midiEmpty21, midiEmpty22,
midiEmpty23, midiGuitarFretNoise, midiBreathNoise,
midiSeashore, midiBirdTweet, midiTelephoneRing,
midiHelicopter, midiApplause, midiGunshot);
Try this:
procedure TForm1.FormCreate(Sender: TObject);
begin
MIDIInit;
SetCurrentInstrument(midiHarmonica);
NoteOn(50, 127);
sleep(200);
NoteOn(60, 127);
sleep(200);
NoteOn(70, 127);
sleep(200);
NoteOff(70, 127);
NoteOff(60, 127);
NoteOff(50, 127);
SetCurrentInstrument(midiAcousticGrandPiano);
NoteOn(70, 127);
NoteOn(80, 127);
sleep(1000);
SetCurrentInstrument(midiApplause);
NoteOn(64, 127);
sleep(2000);
NoteOff(64, 127);
end;

I've been using these components for ages:
http://bitbucket.org/h4ndy/midiio-dev
They've hardly ever failed on me, and unlike many other specialized Delphi components that have been around for this long, this code is pretty much alive (updates and improvements added recently).
Nothing fancy, but it's easy to use, fast, and rock solid. If you plan to do serious midi stuff, you'll eventually end up using this.

I've used these components for over 6 months now with great success. They should be evaluated with all the others in the follow up posts.
http://sourceforge.net/projects/midisequencer/

I have used BASS MIDI using the .NET wrapper with great success, and there are Delphi wrappers available for it too.

A very simple MIDI in/out class:
www.midimountain.com/delphi_midi.html
It looks like a good starting point if you would like to roll your own and use the windows API.

Just a small extra info: The SourceForge "dmidi" project is actually the same as the "midiio" on BitBucket (but the development happens here).

DMIDI project webpage

Mon 4/14/2014 9:49 am. Since I'm not allowed to comment, I'll try answering: I cast my living-in-the-past vote for the midimountain.com candidate. I got the demo_MidiDevices_D6.zip (get it on the page http://www.midimountain.com/delphi_midi.html, not the "download" link), unzipped it, and it compiled without incident in my antique Delphi 7 and ran. I haven't actually tested if it does MIDI, but it did show my menagerie of attached MIDI devices....

Related

I can not correctly translate the code from MSDN to Delphi. Section DirectShow Step 6. Add Support for COM

Please help me to translate the code. I don't know C++ well, but I know Delphi syntax well. I want to translate code from MSDN:
Step 6. Add Support for COM.
static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_RLEFilter,
CRleFilter::CreateInstance,
NULL,
NULL
}
};
and
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
I realized that the first line is a variable. But when translated, it does not work. Error:
This is a string and you defined it as WCHAR.
Next comes the description of the structure, but I do not know such a form.
The last line is also a variable, but it has a / and two values.
In general, I kind of understood the meaning, but do not understand how to write it.
The code roughly translates to Delphi as follows:
const
g_wszName: PWideChar = 'My RLE Encoder';
var
g_Templates: array[0..0] of CFactoryTemplate;
...
g_Templates[0].m_Name := g_wszName;
g_Templates[0].m_ClsID := #CLSID_RLEFilter;
g_Templates[0].m_lpfnNew := #CRleFilter.CreateInstance;
g_Templates[0].m_lpfnInit := nil;
g_Templates[0].m_pAMovieSetup_Filter := nil;
and
var
g_cTemplates: Integer;
...
//g_cTemplates := SizeOf(g_Templates) div SizeOf(g_Templates[0]);
g_cTemplates := Length(g_Templates);

Compare only time portion delphi given time in string

I want to execute code if the now time is over a certain time given in a string:
var
Time,mynowtime:TTime;
begin
mynowtime := ('24:00:00');
Time := Frac(Now);
if Time > mynowtime then
begin
ShowMessage(TimeToStr(Time));
end;
It gives me an error:
'24:00:00' is not a valid date and time.
as Ken White and Remy Lebeau said in Their comments, you can do it like this;
if CompareTime(Time(), EncodeTime(23, 0, 0, 0)) > 0 then
ShowMessage('it''s late');
if the time value is coming from an external source;
var
FmtStngs: TFormatSettings;
Begin
GetLocaleFormatSettings( GetThreadLocale, FmtStngs );
// set format settings, for more info have a look at the link below
if CompareTime(Time(), StrToTime('23:00:00', FmtStngs)) > 0 then
ShowMessage('it''s late');
End;
link

Meaning of error TSimpleCodec.Begin_EncryptMemory - Wrong mode

I am using Delphi XE6 and LockBox 3.4.3 to run the code actEncryptStringExecute. This code was posted as an answer to the question 'How to use AES-256 encryption in lockbox 3 using delphi'.
The error I get is TSimpleCodec.Begin_EncryptMemory - Wrong mode.
There is another question 'TSimpleCodec.Begin_EncryptMemory - Wrong mode' where the answer is "You don't need to do this if you are setting up the codec with design-time values. It's much easier to do at design-time. Just set the published properties as required".
TCodec properties are :-
AdvancedOptions2 = []
AsymetricKeySizeInBits = 1024
ChainMode = ECB (with block padding)
Cipher = Base64
CryptoLibrary = CryptographicLibrary1
Encoding = (TEncoding)
TCryptographicLibrary properties are :-
CustomCipher = (TCustomStreamCipher)
Name = CryptographicLibrary1
ParentLibrary =
The code is :-
var
base64CipherText : String;
PlainTextStr : String;
ReconstructedPlainTextStr : String;
procedure TForm1.btnEncryptClick(Sender: TObject);
begin
PlainTextStr := edtPlainText.Text;
Codec1.EncryptString(PlainTextStr, base64CipherText, TEncoding.Unicode);
lblEncrypted.Caption := base64CipherText;
Codec1.DecryptString(ReconstructedPlainTextStr, base64CipherText, TEncoding.Unicode);
lblReconstructed.Caption := base64CipherText;
end;
What do I need change at design time to get this most simple example to work?

Using Case Statement with String

Say i have a string
'SomeName'
and wanted the values return in a case statement. Can this bedone? Can strings be used in a case statement like so
Case 'SomeName' of
'bobby' : 2;
'tommy' :19;
'somename' :4000;
else
showmessage('Error');
end;
In Jcl library you have the StrIndex function StrIndex(Index, Array Of String) which works like this:
Case StrIndex('SomeName', ['bobby', 'tommy', 'somename']) of
0: ..code.. ;//bobby
1: ..code..;//tommy
2: ..code..;//somename
else
ShowMessage('error');
end.
The Delphi Case Statement only supports ordinal types. So you cannot use strings directly.
But exist another options like
build a function which returns a Integer (hash) based on a string
using generics and anonymous methods ( A generic case for strings)
using a function which receive an array of strings (Making a case for Strings, the sane way)
and so on.
#Daniel's answer pointed me in the right direction, but it took me a while to notice the "Jcl Library" part and the comments about the standard versions.
In [at least] XE2 and later, you can use:
Case IndexStr('somename', ['bobby', 'tommy', 'somename', 'george']) of
0: ..code..; // bobby
1: ..code..; // tommy
2: ..code..; // somename
-1: ShowMessage('Not Present'); // not present in array
else
ShowMessage('Default Option'); // present, but not handled above
end;
This version is case-sensitive, so if the first argument was 'SomeName' it would take the not present in array path. Use IndexText for case-insensitive comparison.
For older Delphi versions, use AnsiIndexStr or AnsiIndexText, respectively.
Kudos to #Daniel, #The_Fox, and #afrazier for most of the components of this answer.
Works on D7 and Delphi Seattle,
uses StrUtils (D7) system.Ansistring (Delphi Seattle)
case AnsiIndexStr(tipo, ['E','R'] ) of
0: result := 'yes';
1: result := 'no';
end;
I used AnsiStringIndex and works, but if you can convert to number without problems:
try
number := StrToInt(yourstring);
except
number := 0;
end;
try this it uses System.StrUtils
procedure TForm3.Button1Click(Sender: TObject);
const
cCaseStrings : array [0..4] of String = ('zero', 'one', 'two', 'three', 'four');
var
LCaseKey : String;
begin
LCaseKey := 'one';
case IndexStr(LCaseKey, cCaseStrings) of
0: ShowMessage('0');
1: ShowMessage('1');
2: ShowMessage('2');
else ShowMessage('-1');
end;
end;

How to create an XML file using TXML Document in Delphi 7

I have used the following code to create the XML Document :
procedure TForm1.btnCreateXMLClick(Sender: TObject);
var
rootName:string;
childName:string;
attrChild:string;
iXml: IDOMDocument;
iRoot, iNode, iNode2, iChild, iAttribute: IDOMNode;
begin
XMLDoc.Active:=false;
XMLDoc.XML.Text:='';
XMLDoc.Active:=true;
XMLDoc.FileName:='C:\Documents and Settings\a\Desktop\New Text Document.xml';
iXml := XmlDoc.DOMDocument;
//iRoot:=iXml.documentElement(iXml.createElement('xml'));
iRoot := iXml.appendChild(iXml.createElement ('xml'));
// node "test"
iNode := iRoot.appendChild (iXml.createElement ('test'));
iNode.appendChild (iXml.createElement ('test2'));
iChild := iNode.appendChild (iXml.createElement ('test3'));
iChild.appendChild (iXml.createTextNode('simple value'));
iNode.insertBefore (iXml.createElement ('test4'), iChild);
// node replication
iNode2 := iNode.cloneNode (True);
iRoot.appendChild (iNode2);
// add an attribute
iAttribute := iXml.createAttribute ('color');
iAttribute.nodeValue := 'red';
iNode2.attributes.setNamedItem (iAttribute);
// show XML in memo
memXMLOutput.Lines.Text:=FormatXMLData(XMLDoc.XML.Text);
end;
I get the output in memXMLOutput but the XML document does not show the output when seen in Notepad ot IE. where is the problem? Thanks in advance
Remove this:
XMLDoc.FileName:='C:\Documents and Settings\a\Desktop\New Text Document.xml';
and add something like this after the code is done creating the XML document:
XMLDoc.SaveToFile('C:\Documents and Settings\a\Desktop\New Text Document.xml');

Resources