 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
paxophobe
Joined: 10 Nov 2007 Posts: 93 Location: Second star to the right.... watching you.
|
Posted: Wed Jan 07, 2009 10:09 pm Post subject: |
|
|
Hi,
I made some keyjazz thing using the modified script from Laszlo. However, its _almost_ primetime. Theres just one bug I can't figure out.
I have started a thread in the "ask for help" section. Being as you guys are the midi gurus and a somewhat small demographic in relation to all that autohotkey encompasses, I thought I'd post the link to it here so as to get the most qualified people to at least glimpse the topic (the help section can move pretty quickly!)
thanks, heres the link: http://www.autohotkey.com/forum/viewtopic.php?p=242060#242060
thanks. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4516 Location: Boulder, CO
|
Posted: Wed Jan 07, 2009 10:24 pm Post subject: |
|
|
| see answer there |
|
| Back to top |
|
 |
genmce
Joined: 10 Jan 2009 Posts: 57 Location: Virginia
|
Posted: Sun Jan 11, 2009 4:23 am Post subject: |
|
|
| Laszlo wrote: | I am using a dllcall directly, for speed. If you have a pitch bend value 0 <= PB < 16384 (with the center value 8192 corresponding to no bend, 0 to the max downward bend and 16383 to the max upward bend), a possible call is | Code: | | DllCall("winmm.dll\midiOutShortMsg", UInt,h_midiout, UInt,(channel+0xDF)|(PB&0x7F)<<8|(PB>>7)<<16) ; channel = 1..16 |
That is, Param1 := PB & 127, Param2 := PB>>7. We need the bit-manipulation operations because only 7 bits of the PB value should be included in MIDI messages. |
I am having a heck of a time understanding this... I am obviously not a programmer.
I have attempted
| Code: |
; one pitchbend test
#NoEnv
#Include general functions.ahk ;laszlo's file from the midi output thread on ahk forum
/* I need help making 1 pitchbend work properly.
I need 1 keypress to make the pitchbend go up
and 1 to make it go down.
I will end up making 9 of these. On one each midi chan 1-9
From what I have done I can get a pitchbend to output,
however, i have not idea how to format param1 and param2 as you stated in
reply to someone else.
*/
;channel := 1 ; midi channel to send on
Param1 := PB & 127 ; I have no idea how to format this
Param2 := PB>>7 ; or this.....
; Create a dialog to select midi port
MsgBox 4, Enumerate Midi Outputs?
, Do you want to select from a list of midi outputs on this system
, and their associated IDs?`n`nIf you select NO, the default midi
output will be used.
IfMsgBox Yes
{
msg := "", NumPorts := MidiOutsEnumerate() ; fills global array
MidiOutPortName
Loop % NumPorts
{
Port := A_Index -1
msg := msg . "ID: " . Port . " --> " . MidiOutPortName%Port% . "`n"
}
InputBox MidiDevice, Select Midi Port, Enter the number of the port
you would like to use`n`n%msg%,, 450, % (NumPorts * 35 + 200),,,,,0
If (ErrorLevel)
Exit
}
Else MidiDevice = 1 ; default midi device (for me midi yoke #1)
;I am not sure where to put this next line.
DllCall("winmm.dll\midiOutShortMsg", UInt,h_midiout, UInt,(channel+0xDF)|
(PB&0x7F)<<8|(PB>>7)<<16) ; channel = 1..16
OpenCloseMidiAPI()
h_midiout := midiOutOpen(MidiDevice)
;Map a fader test 1
^1::midiOutShortMsg(h_midiout, "wheel", 1, 0, 16383) ; fader
^q::midiOutShortMsg(h_midiout, "wheel", 1, 0, 0) ; fader down
midiOutClose(h_midiout)
OpenCloseMidiAPI()
|
I can get the pitchbend to show up on midi ox however I can get values other than zeros.
Please help me get my keys outputing pitchbends.
I will also need to figure out how to have midi input from daw as the place to start the output values that this pitch bend outputs.
Did that make sense?
If you send me an email, I can explain in more detail.
genmce(at)yahoo.com
In the end I need to do this 9 times and have midi input to compare before sending pb data out.
Basically taking fader postion from daw to compare before sending the output from the key to midi fader script here back to daw
So I don't get fader jumps.
Thanks _________________ GenMce - a free generic midi controller to mackie emulation.
KeyMce - Better mackie emulator for pc keyboard. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4516 Location: Boulder, CO
|
Posted: Sun Jan 11, 2009 5:30 am Post subject: |
|
|
The following piece of code increases the pitch bend (PB) at the hotkey press of Ctrl-Alt-Up arrow, and decreases the bend at the hotkey Ctrl-Alt-Down arrow, on a computer keyboard. (I have not tried midi input.) | Code: | PB := 8192 ; initially no pitch bend
PBdelta = 33 ; the amount of change at a key press, set as you like
;...
^!up::
PB := PB+PBdelta < 16384 ? PB+PBdelta : 16383
DllCall("winmm.dll\midiOutShortMsg", UInt,h_midiout, UInt,(channel+0xDF)|(PB&0x7F)<<8|(PB>>7)<<16)
Return
^!down::
PB := PB-PBdelta > 0 ? PB-PBdelta : 0
DllCall("winmm.dll\midiOutShortMsg", UInt,h_midiout, UInt,(channel+0xDF)|(PB&0x7F)<<8|(PB>>7)<<16)
Return | You have to assign the desired pitch bend value to the variable PB. Your code did not do it. (It is similar to the wheel messages: you have to send the desired value in the short midi-out message.) |
|
| Back to top |
|
 |
genmce
Joined: 10 Jan 2009 Posts: 57 Location: Virginia
|
Posted: Sun Jan 11, 2009 1:27 pm Post subject: |
|
|
Thank you so much,
that is doing what it should!
Do I need to have a Return after every command?
Meaning if I have other keys converted to note on messages, do they need Return
Or just after the pitchbends because they are doing the dllcall?
Last edited by genmce on Sun Jan 11, 2009 2:46 pm; edited 1 time in total |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4516 Location: Boulder, CO
|
Posted: Sun Jan 11, 2009 4:18 pm Post subject: |
|
|
| The returns are terminating the hotkey subroutines. They start with a key combination and double colons (::). If some command follows in the same line, it is a one-line hotkey, which does not need a return. If the rest of the first line is blank, the subsequent lines of code are executed when the hokey is triggered, until the terminating Return. |
|
| Back to top |
|
 |
specter333
Joined: 15 Jan 2007 Posts: 19
|
Posted: Tue Jan 13, 2009 11:31 am Post subject: |
|
|
| Sean wrote: | | Laszlo wrote: | | Device -1,0,1... all give error code 2 (bad device ID), although the Select Midi Port inputbox lists ID: 0 --> Microsoft GS Wavetable SW Synth |
I think it's because he strangely hard coded DeviceID to 1 like
| Code: | midiOutOpen(1)
midiStreamOpen(1) |
Try to change 1 to 0 or -1. |
This fixed the problem I was having too. On my system ws synth is port 1 and my usb device is 0. Apparently the message box doesn't change the port since it always goes to port 1. I'm not a programmer but shouldn't the midiOutOpen be followed with the variable from the message box instead of just 1?
Anyway this tool is outstanding. I'm going to use it to control an old digital mixer I have that mixes my keyboards, my computer and other instruments. I'll be triggering the script from EventGhost so I'll be able to control all the volumes with a remote control. Thank you for writing this. |
|
| Back to top |
|
 |
specter333
Joined: 15 Jan 2007 Posts: 19
|
Posted: Tue Jan 13, 2009 7:26 pm Post subject: Digital Mixer Volume Control with MIDI |
|
|
Took me all night but I got this working. Since I have no programing experience I don't know if this is the best way to do this so please let me know if this needs to be changed.
Digital Mixer Volume Control with MIDI
| Code: | ;Open the Windows midi API dll
hModule := OpenMidiAPI()
;Open the midi port
h_midiout := midiOutOpen(0)
#Include Midi Functions.ahk
Hotkey, ^1,1up
Hotkey, !1,1dn
Pause
1up:
Loop, 10 {
a++
var%A_Index%:= a
ch:= % var%A_Index%
midiOutShortMsg(h_midiout, "CC", 1, 1, ch)
}
Return
1dn:
Loop, 10 {
a--
var%A_Index%:= a
ch:= % var%A_Index%
midiOutShortMsg(h_midiout, "CC", 1, 1, ch)
}
Return |
Thanks for this great code. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4516 Location: Boulder, CO
|
Posted: Tue Jan 13, 2009 7:49 pm Post subject: |
|
|
You can define hotkeys directly with "keyname::". The array var1, var2... is not used later, so get rid of it. If you want gradual change, add Sleep to the loop, otherwise remove the loop and increment/decrement "a" by 10. It is better to initialize "a" to your desired value. Check for overflow in "a": | Code: | #Include Midi Functions.ahk
;Open the Windows midi API dll
hModule := OpenMidiAPI()
;Open the midi port
h_midiout := midiOutOpen(0)
a := 64 ; initial value
Return ; end of the auto-execute section
^1::
Loop, 10 {
a := a < 127 ? a+1 : 127
midiOutShortMsg(h_midiout, "CC", 1, 1, a)
Sleep 33
}
Return
!1::
Loop, 10 {
a := a > 0 ? a-1 : 0
midiOutShortMsg(h_midiout, "CC", 1, 1, a)
Sleep 33
}
Return |
|
|
| Back to top |
|
 |
specter333
Joined: 15 Jan 2007 Posts: 19
|
Posted: Wed Jan 14, 2009 4:47 am Post subject: |
|
|
Thanks for the quick response and forgive me for not understanding but literally every thing I know about programing I learned from the AHK help file so I don't understand most of it, I don't even understand most of what I did, I just picked through other peoples code until I found parts that looked like would work for me.
| Laszlo wrote: | | The array var1, var2... is not used later, so get rid of it. | I don't see a var1, var2?
| Laszlo wrote: | | It is better to initialize "a" to your desired value. Check for overflow in "a" | I was thinking of writing "a" to an ini file, then the initial value would always be the where the volume was last set. Does this sound like a good idea? What is overflow? I'll try to find how to do this in the manual.
One big problem I had last night is when using a hotkey like "a::=64" I always got an error message "Problems sending to MIDI device" or something like that. Using the old code seemed to fix it.
This little project is something I've wanted to do for a long time inspired by how poor the Windows audio mixer is. Decreasing volume does very little between 100% and 10% then in the last 10% the volume drops rapidly making it very hard to get precise settings. Windows sounds tend to be too loud even at low levels and video is too quiet at 100% meaning I have to turn up the amp for video watching and back down for everything else. Using the linear faders of the mixer should help give control over levels and add headroom to turn up without having to get up.
I haven't had a chance to try the code you made yet but I'm sure it will work great. Thanks again for the help. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4516 Location: Boulder, CO
|
Posted: Wed Jan 14, 2009 7:29 am Post subject: |
|
|
| specter333 wrote: | | I don't see a var1, var2 | You have var%A_Index%, where A_Index is the internal loop variable, taking values 1,2,... This creates the array variables var1, var2,...
| specter333 wrote: | | writing "a" to an ini file, then the initial value would always be the where the volume was last set. | Good idea.
| specter333 wrote: | | What is overflow? | The volume can be 0...127. If you increment "a" beyond 127, you get unpredictable results in the MIDI command. Therefore, prevent it to go too large (>127) or negative.
| specter333 wrote: | | "a::=64" | It is not a hotkey. You write a key name, like ^1 for Ctrl+1, followed by double collon, alone in a line. This will be the name of a subroutine, activated when Ctrl and 1 is pressed together. The code until Return will be performed. |
|
| Back to top |
|
 |
specter333
Joined: 15 Jan 2007 Posts: 19
|
Posted: Fri Jan 16, 2009 3:34 am Post subject: |
|
|
As suspected your script works flawlessly. I did tweak it a little to get it to move smoother when controlled by the remote.
I didn't do a very good job with my hotkey sample before, I would have had to look it up to remember what exactly I'd done. The AHK instructions say to use one line unless your trigger multiple events, something like
Thanks again for your help. |
|
| Back to top |
|
 |
genmce
Joined: 10 Jan 2009 Posts: 57 Location: Virginia
|
Posted: Tue Feb 03, 2009 3:42 am Post subject: Please add general functions traymenu port selection. |
|
|
| Laszlo wrote: | After a couple of days debugging I ended up rewriting the whole code. Now it works with the default midi device: ID 0: Microsoft GS Wavetable SW Synth. Most of the changes were bug fixes and simplifications, to reduce code size. The hardest part is TomB's original discovery work, which made midi output possible from an AHK script.
|
Laszlo's general functions: unedited from this thread
| Code: | ;;;;;;;;; AHK functions for midi output by calling winmm.dll ;;;;;;;;;;
;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_multimedia_functions.asp
OpenCloseMidiAPI() { ; at the beginning to load, at the end to unload winmm.dll
Static hModule
If hModule
DllCall("FreeLibrary", UInt,hModule), hModule := ""
If (0 = hModule := DllCall("LoadLibrary",Str,"winmm.dll")) {
MsgBox Cannot load libray winmm.dll
Exit
}
}
;;;;;;;;;;;;;;; Functions for Sending Individual Messages ;;;;;;;;;;;;;;;
midiOutOpen(uDeviceID = 0) { ; Open midi port for sending individual midi messages --> handle
strh_midiout = 0000
result := DllCall("winmm.dll\midiOutOpen", UInt,&strh_midiout, UInt,uDeviceID, UInt,0, UInt,0, UInt,0, UInt)
If (result or ErrorLevel) {
MsgBox There was an error opening the midi port.`nError code %result%`nErrorLevel = %ErrorLevel%
Return -1
}
Return UInt@(&strh_midiout)
}
midiOutShortMsg(h_midiout, EventType, Channel, Param1, Param2) {
;h_midiout: handle to midi output device returned by midiOutOpen
;EventType, Channel combined -> MidiStatus byte: http://www.harmony-central.com/MIDI/Doc/table1.html
;Param3 should be 0 for PChange, ChanAT, or Wheel
;Wheel events: entire Wheel value in Param2 - the function splits it into two bytes
If (EventType = "NoteOn" OR EventType = "N1")
MidiStatus := 143 + Channel
Else If (EventType = "NoteOff" OR EventType = "N0")
MidiStatus := 127 + Channel
Else If (EventType = "CC")
MidiStatus := 175 + Channel
Else If (EventType = "PolyAT" OR EventType = "PA")
MidiStatus := 159 + Channel
Else If (EventType = "ChanAT" OR EventType = "AT")
MidiStatus := 207 + Channel
Else If (EventType = "PChange" OR EventType = "PC")
MidiStatus := 191 + Channel
Else If (EventType = "Wheel" OR EventType = "W") {
MidiStatus := 223 + Channel
Param2 := Param1 >> 8 ; MSB of wheel value
Param1 := Param1 & 0x00FF ; strip MSB
}
result := DllCall("winmm.dll\midiOutShortMsg", UInt,h_midiout, UInt, MidiStatus|(Param1<<8)|(Param2<<16), UInt)
If (result or ErrorLevel) {
MsgBox There was an error sending the midi event: (%result%`, %ErrorLevel%)
Return -1
}
}
midiOutClose(h_midiout) { ; Close MidiOutput
Loop 9 {
result := DllCall("winmm.dll\midiOutClose", UInt,h_midiout)
If !(result or ErrorLevel)
Return
Sleep 250
}
MsgBox Error in closing the midi output port. There may still be midi events being processed.
Return -1
}
;;;;;;;;;;;;;;; Functions for Stream Output ;;;;;;;;;;;;;;;
midiStreamOpen(DeviceID) { ; Open the midi port for streaming
;MMRESULT midiStreamOpen( --> handle to midi stream, used by midi stream out functions
;LPHMIDISTRM lphStream, Pointer to handle to stream - filled by call to midiStreamOpen
;LPUINT puDeviceID, Pointer to DeviceID
;DWORD cMidi, Always 1
;DWORD_PTR dwCallback, Pointer to callback function, event, etc. (0 = none)
;DWORD_PTR dwInstance, Number you can assign to this stream
;DWORD fdwOpen) Type of callback
VarSetCapacity(strh_stream, 4, 0)
result:=DllCall("winmm.dll\midiStreamOpen", UInt,&strh_stream, UIntP,DeviceID, UInt,1, UInt,0, UInt,0, UInt,0, UInt)
If (result or ErrorLevel) {
MsgBox There was an error opening the midi port.`nError code %result%`nErrorLevel = %ErrorLevel%
Return -1
}
Return UInt@(&strh_stream)
}
AddEventToBuffer(ByRef MidiBuffer, DeltaTime, EventType, Channel, Param1, Param2, NewBuffer = 0) {
; MIDIEVENT Structure
; DWORD dwDeltaTime; offset to time this event should be sent
; DWORD dwStreamID; streamID this should be sent to (assumed to always be 0 for our purposes)
; DWORD dwEvent; Event DWord (Highest byte is EventCode [shortMsg for us], followed by param2, param1, status)
; DWORD dwParms[]; not needed for short messages
; BufferSize = 12 * number of events
Static BufOffset = 0 ; keep track of where in the buffer the next event goes
If (NewBuffer)
BufOffset = 0
If (BufOffset + 12 > VarSetCapacity(MidiBuffer)) {
MsgBox Midi Buffer is full.`nEvent %EventType% %Channel% %Param1% %Param2%`n could not be added.
Return -1
}
If (EventType = "NoteOn" OR EventType = "N1") ; Calc MidiStatus byte (~ midiOutShortMsg Function)
MidiStatus := 143 + Channel
Else if (EventType = "NoteOff" OR EventType = "N0")
MidiStatus := 127 + Channel
Else if (EventType = "CC")
MidiStatus := 175 + Channel
Else if (EventType = "PolyAT" OR EventType = "PA")
MidiStatus := 159 + Channel
Else if (EventType = "ChanAT" OR EventType = "AT")
MidiStatus := 207 + Channel
Else if (EventType = "PChange" OR EventType = "PC")
MidiStatus := 191 + Channel
Else if (EventType = "Wheel" OR EventType = "W") {
MidiStatus := 223 + Channel
Param2 := Param1 >> 8
Param1 := Param1 & 0x00FF
}
Else {
MsgBox Invalid EventType.
Return -1
}
PokeInt(DeltaTime, &MidiBuffer+BufOffset)
PokeInt(0, &MidiBuffer+BufOffset+4)
PokeInt(MidiStatus|(Param1 << 8)|(Param2 << 16), &MidiBuffer+BufOffset+8)
BufOffset += 12
}
SetTempoAndTimebase(h_stream, BPM, PPQ) { ; BPM = tempo in Beats Per Minute, PPQ = ticks (Parts) Per Quarter note
VarSetCapacity(struct, 8) ; structure
PokeInt( 8, &struct) ; always = 8 (?)
PokeInt(PPQ, &struct+4) ; contains number of ticks per quarter note
result := DllCall("winmm.dll\midiStreamProperty", UInt,h_stream, UInt,&struct
, UInt,0x80000001, UInt) ; flags = MIDIPROPSET (0x80000000) and MIDIPROP_TIMEDIV (1)
If (result) {
MsgBox Error %result% in setting the Timebase
Return -1
}
PokeInt(6.e7//BPM,&struct+4) ; dwTempo as microseconds per quarter note
result := DllCall("winmm.dll\midiStreamProperty", UInt,h_stream, UInt,&struct
, UInt,0x80000002, UInt) ; flags = MIDIPROPSET (0x80000000) and MIDIPROP_TEMPO (2)
If (result) {
MsgBox Error %result% in setting the Tempo
Return -1
}
}
;MIDIHDR struct
; LPSTR lpData; pointer to midi data stream
; DWORD dwBufferLength; size of buffer
; DWORD dwBytesRecorded; number of bytes of actual midi data in buffer
; DWORD_PTR dwUser; custom user data
; DWORD dwFlags; should be 0
; struct midihdr_tag far * lpNext; do not use
; DWORD_PTR reserved; do not use
; DWORD dwOffset; offset generated by callback - not used in this routine
; DWORD_PTR dwReserved[4]; do not use
midiOutputBuffer(h_stream, ByRef MidiBuffer, BufSize, BufDur) { ; Play Midi Buffer... Buf-fer Dur-ation in ms
Global MIDIHDR ; other functions can access MIDIHDR
VarSetCapacity(MIDIHDR, 36, 0)
PokeInt(&MidiBuffer,&MIDIHDR)
PokeInt(BufSize, &MIDIHDR+4)
PokeInt(BufSize, &MIDIHDR+8) ; remaining props can all be 0
result := DllCall("winmm.dll\midiOutPrepareHeader", UInt,h_stream, UInt,&MIDIHDR, UInt,36, UInt) ; 36 = size of header
If (result) {
MsgBox Error %result% in midiOutPrepareHeader
Return -1
}
result := DllCall("winmm.dll\midiStreamOut", UInt,h_stream, UInt,&MIDIHDR, UInt,36, UInt) ; Queue up buffer, ready to play
If (result) {
MsgBox Error %result% in midiStreamOut
Return -1
}
result := DllCall("winmm.dll\midiStreamRestart", UInt,h_stream, UInt) ; Start playback
If (result) {
MsgBox Error %result% in midiStreamRestart
Return -1
}
Sleep %BufDur% ; Wait for duration of entire buffer
DllCall("winmm.dll\midiStreamStop", UInt, h_stream) ; Stop Stream - keeps it from sleep.
}
midiOutCloseStream(h_stream, ByRef MIDIHDR) { ; unprepare header and close stream
result := DllCall("winmm.dll\midiOutUnprepareHeader", UInt,h_stream, UInt,&MIDIHDR, UInt,36, UInt)
If (result) {
MsgBox Error %result% in midiOutUnprepareHeader
Return -1
}
result := DllCall("winmm.dll\midiStreamClose", UInt,h_stream, UInt) ; CloseMidiStream
If (result) {
MsgBox Error %result% in midiStreamClose
Return -1
}
}
;;;;;;;;;;;;;;; Utility Functions ;;;;;;;;;;;;;;;
MidiOutGetNumDevs() { ; Get number of midi output devices on system, first device has an ID of 0
Return DllCall("winmm.dll\midiOutGetNumDevs")
}
MidiOutNameGet(uDeviceID = 0) { ; Get name of a midiOut device for a given ID
;MIDIOUTCAPS struct
; WORD wMid;
; WORD wPid;
; MMVERSION vDriverVersion;
; CHAR szPname[MAXPNAMELEN];
; WORD wTechnology;
; WORD wVoices;
; WORD wNotes;
; WORD wChannelMask;
; DWORD dwSupport;
VarSetCapacity(MidiOutCaps, 50, 0) ; allows for szPname to be 32 bytes
OffsettoPortName := 8, PortNameSize := 32
result := DllCall("winmm.dll\midiOutGetDevCapsA", UInt,uDeviceID, UInt,&MidiOutCaps, UInt,50, UInt)
If (result OR ErrorLevel) {
MsgBox Error %result% (ErrorLevel = %ErrorLevel%) in retrieving the name of midi output %uDeviceID%
Return -1
}
VarSetCapacity(PortName, PortNameSize)
DllCall("RtlMoveMemory", Str,PortName, Uint,&MidiOutCaps+OffsettoPortName, Uint,PortNameSize)
Return PortName
}
MidiOutsEnumerate() { ; Returns number of midi output devices, creates global array MidiOutPortName with their names
Local NumPorts, PortID
MidiOutPortName =
NumPorts := MidiOutGetNumDevs()
Loop %NumPorts% {
PortID := A_Index -1
MidiOutPortName%PortID% := MidiOutNameGet(PortID)
}
Return NumPorts
}
UInt@(ptr) {
Return *ptr | *(ptr+1) << 8 | *(ptr+2) << 16 | *(ptr+3) << 24
}
PokeInt(p_value, p_address) { ; Windows 2000 and later
DllCall("ntdll\RtlFillMemoryUlong", UInt,p_address, UInt,4, UInt,p_value)
} |
Laszlo, or another...
Can you please make a midi port selection in a traymenu item called
midi_out port into your general functions.ahk (midi out)?
The midi_in_lib from orbik does this, but I can't, figure out how do it for the midi output part?
Rockum and I have something very interesting we have been collaborating on and will release it soon, but we have a few stumbling blocks, to making it look nice.
You have already helped a lot, but we need this part too.
Please!
Here is the code from orbik's midi_in_lib
| Code: |
midi_in_Open(defaultDevID = -1)
{
global
if ((midi_in_hModule := DllCall("LoadLibrary", Str,A_ScriptDir . "\midi_in.dll")) == 0)
{
MsgBox Cannot load library midi_in.dll"
return 1
}
if (defaultDevID >= DllCall("midi_in.dll\getNumDevs"))
defaultDevID := -1
midi_in_MakeTrayMenu(defaultDevID)
if (defaultDevID >= 0)
midi_in_OpenDevice(defaultDevID)
return 0
}
midi_in_MakeTrayMenu(defaultDevID)
{
numDevs := DllCall("midi_in.dll\getNumDevs")
global midi_in_lastSelectedMenuItem
Menu devNameMenu, Add, No input, sub_menu_openinput
Menu devNameMenu, Add ; separator
if (defaultDevID < 0)
midi_in_lastSelectedMenuItem := "No Input"
loop %numDevs%
{
devID := A_Index-1
if ((devName := DllCall("midi_in.dll\getDevName", Int,devID, Str)) == 0)
{
MsgBox, Error in creating midi input device list
return 1
}
Menu devNameMenu, Add, %devName%, sub_menu_openinput
if (devID == defaultDevID)
{
Menu devNameMenu, Check, %devName%
midi_in_lastSelectedMenuItem := devName
}
}
Menu TRAY, Add, MIDI-in device, :devNameMenu
}
sub_menu_openinput:
midi_in_OpenDevice(A_ThisMenuItemPos-3)
; Move the check mark to new position
Menu %A_ThisMenu%, Check, %A_ThisMenuItem%
Menu %A_ThisMenu%, Uncheck, %midi_in_lastSelectedMenuItem%
midi_in_lastSelectedMenuItem := A_ThisMenuItem
return
midi_in_OpenDevice(deviceID) ;deviceID < 0 means no input
{
Critical
midi_in_Stop()
Gui +LastFound
hWnd := WinExist()
curDevID := DllCall("midi_in.dll\getCurDevID", Int)
if (deviceID == curDevID)
return 0
if (curDevID >= 0)
result := DllCall("midi_in.dll\close")
if (result)
{
MsgBox Error closing midi device`nmidi_in.dll\close returned %result%
return 1
}
if (deviceID < 0)
return 0
result := DllCall("midi_in.dll\open", UInt,hWnd, Int,deviceID, Int)
if (result)
{
MsgBox Error opening midi device`nmidi_in.dll\open(%hWnd%, %deviceID%) returned %result%
return 1
}
; MsgBox Press OK to start midi input
midi_in_Start()
return 0
}
midi_in_Close()
{
global
if (midi_in_hModule)
DllCall("FreeLibrary", UInt,midi_in_hModule), midi_in_hModule := ""
}
midi_in_Start()
{
DllCall("midi_in.dll\start")
}
midi_in_Stop()
{
DllCall("midi_in.dll\stop")
}
listenNote(noteNumber, funcName, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
DllCall("midi_in.dll\listenNote", Int,noteNumber, Int,channel, Int,msgNum)
OnMessage(msgNum, funcName)
}
listenNoteRange(rangeStart, rangeEnd, funcName, flags=0, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
msgCount := DllCall("midi_in.dll\listenNoteRange", int,rangeStart, int,rangeEnd, int,(flags & 0x07), int,channel, int,msgNum)
if (msgCount <= 0)
return
if (flags & 0x01)
loop %msgCount%
{
OnMessage(msgNum, funcName . A_Index)
GoSub, sub_increase_msgnum
}
else
OnMessage(msgNum, funcName)
}
listenCC(ccNumber, funcName, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
DllCall("midi_in.dll\listenCC", Int,ccNumber, Int,channel, Int,msgNum)
OnMessage(msgNum, funcName)
}
listenWheel(funcName, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
DllCall("midi_in.dll\listenWheel", Int,channel, Int,msgNum)
OnMessage(msgNum, funcName)
}
listenChanAT(funcName, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
DllCall("midi_in.dll\listenChanAT", Int,channel, Int,msgNum)
OnMessage(msgNum, funcName)
}
getNoteOn(noteNumber, channel)
{
return DllCall("midi_in.dll\getNoteOn", Int,noteNumber, Int,channel)
}
getCC(ccNumber, channel)
{
return DllCall("midi_in.dll\getCC", Int,ccNumber, Int,channel)
}
getWheel(channel)
{
return DllCall("midi_in.dll\getWheel", Int,channel)
}
getChanAT(channel)
{
return DllCall("midi_in.dll\getChanAT", Int,channel)
}
sub_increase_msgnum:
if msgNum
msgNum++
else
msgNum := 0x2000
return
|
We just need the midi out port on the traymenu along with the midi in port (which is already there).
Here was my lame attempt ....
| Code: |
; This was copied from your file, general functions.
; I tired to insert my commented code into your general functions
; below this point
; above code snipped.
MidiOutsEnumerate() { ; Returns number of midi output devices, creates global array MidiOutPortName with their names
Local NumPorts, PortID
MidiOutPortName =
NumPorts := MidiOutGetNumDevs()
Loop %NumPorts% {
PortID := A_Index -1
MidiOutPortName%PortID% := MidiOutNameGet(PortID)
}
Return NumPorts
}
/*
midi_out_MakeTrayMenu(uDeviceID)
{
numDevs := MidiOutNameGet(PortID) ;DllCall("midi_in.dll\getNumDevs")
global midi_out_lastSelectedMenuItem
Menu devNameMenu, Add, No input, sub_menu_openOutput
Menu devNameMenu, Add ; separator
if (uDeviceID < 0)
midi_out_lastSelectedMenuItem := "No Output"
loop %numDevs%
{
uDeviceID := A_Index-1
if ((devName := DllCall("midi_in.dll\getDevName", Int,uDeviceID, Str)) == 0)
{
MsgBox, Error in creating midi output device list
return 1
}
Menu devNameMenu, Add, %devName%, sub_menu_openOutput
if (uDeviceID == defaultuDeviceID)
{
Menu devNameMenu, Check, %devName%
midi_out_lastSelectedMenuItem := devName
}
}
Menu TRAY, Add, MIDI-out device, :devNameMenu
}
sub_menu_openOutput:
midi_out_OpenDevice(A_ThisMenuItemPos-3)
; Move the check mark to new position
Menu %A_ThisMenu%, Check, %A_ThisMenuItem%
Menu %A_ThisMenu%, Uncheck, %midi_out_lastSelectedMenuItem%
midi_out_lastSelectedMenuItem := A_ThisMenuItem
return
*/
|
A million thanks to you! _________________ GenMce - a free generic midi controller to mackie emulation.
KeyMce - Better mackie emulator for pc keyboard. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4516 Location: Boulder, CO
|
Posted: Tue Feb 03, 2009 5:01 am Post subject: |
|
|
| Code: | Menu TRAY, Add, MIDI-out device, MOselect
MidiDev = 0 ; Default
;... you code here
Return
!z::ExitApp
MOselect:
Gui Add, DropDownList,% "w170 AltSubmit vMidiDev Choose" MidiDev+1, % MidiOutsList(NumPorts)
Gui Add, Button, , Cancel
Gui Add, Button, x+5, OK
Gui Show,, Midi Out
Return
ButtonOK:
Gui Submit
MidiDev -= 1 ; the 0-based index of the selected new Midi output device
ButtonCancel:
Gui Destroy
Return
MidiOutsList(ByRef NumPorts) { ; Returns a "|"-separated list of midi output devices
Local List, MidiOutCaps, PortName, result
VarSetCapacity(MidiOutCaps, 50, 0)
VarSetCapacity(PortName, 32) ; PortNameSize 32
NumPorts := DllCall("winmm.dll\midiOutGetNumDevs") ; #midi output devices on system, first device ID = 0
Loop %NumPorts% {
result := DllCall("winmm.dll\midiOutGetDevCapsA", UInt,A_Index-1, UInt,&MidiOutCaps, UInt,50, UInt)
If (result OR ErrorLevel) {
List .= "|-ERROR-"
Continue
}
DllCall("RtlMoveMemory", Str,PortName, UInt,&MidiOutCaps+8, UInt,32) ; PortNameOffset 8, PortNameSize 32
List .= "|" PortName
}
Return SubStr(List,2)
} |
|
|
| Back to top |
|
 |
genmce
Joined: 10 Jan 2009 Posts: 57 Location: Virginia
|
Posted: Tue Feb 03, 2009 8:04 pm Post subject: |
|
|
Thank you very much!
Especially for the quick response.
This is working, however, we have one more request.
Can you make it so the ports show up in a submenu of the MO menu for selection and which ever one is selected has a check mark.
Just like the midi_in menu in the midi_in_lib.ahk above?
We want user to be able to rt click on the tray icon then click the midi in or midi out ports to select from submenus.
Sorry to be picky... and sorry I have not quite grasped how to make this happen.
thanks again.
We are getting so close... _________________ GenMce - a free generic midi controller to mackie emulation.
KeyMce - Better mackie emulator for pc keyboard. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|