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');