Hello all,
This is an XY midi mouse/trackpad.
It takes your mouse movement and converts it to a midi controller and a pitchbend.
There is a modwheel cc# 33 on the X axis,
and pitchbend on the Y axis.
It could have a gui to pick your cc#... an ini to write your midi port.
Other stuff?
I might include it in Keymce - as two midi controllers instead of pitchbend.
Mouse movement detection, by Serenity, found
here.Thanks to temp01, for finding it!
Code:
; Last edited 4/11/2010 9:33 PM by genmce
/*
Most of this is with help from Learningone and JimF as well as temp01 finding a code reference on ahk site. http://www.autohotkey.com/forum/topic7450.html by Serenity to detect mouse movement.
It uses JimF's edit of the general midi functions (Lazslo and TomB).
esc is currently used for triggering
* this currently works by holding the esc key, this will need to be moved.
* Fixed recenter issues.
* y axis will recenter on release of hotkey
* x axis will be remember for next time.
Consider a larger movement lane or a different hotkey for modwheel so they don't happen at the same time.
GPL
*/
;This gui is only for reference and testing, I don't think it will be needed, but perhaps it will....
CustomColor = C0C0C0 ;00FFFF ;EEAA99 ; Can be any RGB Color (it will be made Transparent below).
Gui +LastFound +AlwaysOnTop -Caption +ToolWindow ; +ToolWindow avoids a taskbar Button and an alt-tab Menu item.
Gui, Color, %CustomColor%
Gui, Font, s15 ; Set a large font size (32-point).
Gui, Add, Text, w300 gXYMouse vMyText cblue, ; XX & YY serve to auto-size the window.
WinSet, TransColor, %CustomColor% 150
CoordMode, Mouse, Screen
CenterX := A_ScreenWidth/2, CenterY := A_ScreenHeight/2 ; find the Center of the Screen
XmidiCalc := Centerx/64 ; set the value of Mouse movement to midi cc Range
YmidiCalc := CenterY/8192 ; set to midi pitch bend Range
SetFormat, Float, 0
channel := 1 ; midi channel to Send on
CCmod := 33 ; Fine Mod Wheel, ccmod = 33 ; probably leave it as fine mod wheel.... not sure about this.
pb := 8192 ; set pb to center
moveit = "" ; moveit to prevent repeating the mousemove to center multiple times.
modwheelPos := 0
;consider a var for speed of pitchbend or shorten the range to not get all the way out... not sure, have not tried it yet.
;======= midi port selection / open 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 = 0
OpenCloseMidiAPI()
h_midiout := midiOutOpen(MidiDevice)
;=========== run timer ==================================
SetTimer, XYMouse, 75 ; Run the timer below to
; =============== End autoexec =========================
Return
; =============== trigger the xymouse ======================
esc::
xyRun := 1 ; set var = 1 to show active and will Send midi ;Activate - hold key down like esc - this will need to change, I was thinking perhaps on f12, make a Toggle of the var. the display might help user know that they are active...
PBCenter := 1 ; not sure where I was going with that
IfEqual, moveit, ""
loop, 1
{
MouseMove, ModWheelPos, CenterY, 0
moveit := 1 ; mouse move is done.
}
IfEqual, moveit, 1
{
; do nothing, MouseMove already completed
}
Return
; ======== stop the xy mouse ====================
esc up:: ;
moveit = "" ; set mouse move var back to blank
xyRun := 0 ; set xy run to 0 so the timmer won't do anything
MouseGetPos, ModWheelPos , ; get last mouse x axis postion - remember x axis position
pb := 8192 ; set pb to center (no Bend)
midiOutShortMsg(h_midiout, (channel+ 223), (PB&0x7F), (PB>>7)) ; send midi pitch bend to center out midi port
Gui, hide
Return
; =============== xymouse routine =============
XYmouse: ; run the xy mouse sub
IfEqual, xyRun, 1 ; hotkey is held down so do the stuff below
{
MouseGetPos, sx, sy ; Get starting mouse postion
Gui, Show, xCenter y5 AutoSize NoActivate ; NoActivate avoids deactivating the currently active window. ;ONLY SHOW GUI WHILE ESC HELD DOWN.
Sleep, 100 ; not sure this is needed? Some kind of interval needed between MouseGetPos, hate to use a sleep
MouseGetPos, cx, cy
If (cx != sx or cy != sy)
{
; mouse has moved by more than 10 px - might need higher amount
If (cx > (sx+10) or cx < (sx-10)) ; mouse moved more than 10 px on x axis
{
XMidival := cx/XmidiCalc
midiOutShortMsg(h_midiout, Channel + 175, CCmod, xmidival)
}
If (cy > (sy+10) or cy < (sy-10)) ; Mouse moved more than 10 px on y axis
{
PB := (CenterY - cy)/YmidiCalc + 8192
midiOutShortMsg(h_midiout, (channel+ 223), (PB&0x7F), (PB>>7))
}
}
GuiControl,, MyText, ModWheel %XmidiVal%, PitchBend %pb% ; only to update the Gui
}
IfEqual, xyRun, 0
{
; hotkey is not held down so do nothing
}
Return
; =============== end ====================================
;THATS THE END OF MY STUFF (JimF) THE REST IS WHAT LASZLO AND PAXOPHOBE WERE USING ALREADY
;AHK FUNCTIONS FOR MIDI OUTPUT - calling winmm.dll
;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_multimedia_functions.asp
;Derived from Midi.ahk dated 29 August 2008 - streaming support removed
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 SHORT 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
}
;TrayTip,, %strh_midiout% , 20, 17
Return UInt@(&strh_midiout)
}
midiOutShortMsg(h_midiout, MidiStatus, 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 calling function splits it into two bytes
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%)
MsgBox, Handle-%h_midiout% Status-%MidiStatus% P1-%Param1% P2-%Param2%
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
}
;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)
}
Not ahk but, these programs look interesting.
http://www.analogx.com/contents/downloa ... eeware.htm
As well as
http://www.vimidi.com/