Hello,
I was strugglig with editing a tempomap that was created to a free time audio recording.
Everytime a marker is moved, the entire grid goes west because the subsequent markers BPM are overwritten by 'Time signature measure from time selection'.
An example:
Three markers, the first one states 76.0 BPM, the second one 75.0 BPM the third one 74.0.
if the second marker is moved left or right, the first and the second markers BPM need to be recalculated, but the third one must remain unchanged. Adjusting the first is easy:
select the area between the first and second and execute 'Time signature measure from time selection' this corrects the first marker and sets the second marker to the same BPM as the first.
Now repeat this for the area between the second an third marker and the second one is correct, but the third one is now the same BPM as the second one.
Now the third marker needs to be set to 74.0 (the value it initially had) to make everything correct.
When i found out that time markers are not accessable by an extension plugin and also navigation to timemarkers is not possible by commands, i tried several other methods like keyHooks and subclassing g_hwnd (which turned out to be the splash screen when the plug is initialized...) and others.
I finally ended up with the code below. this does the following: setting up a keyHook and a timer function.
The keyHook looks for a key events for the key "Y", when Key Down is recognized it remembers the current mouse position, when keyup is recognized it also stores the current mouse position and triggers a series of commands executed within the timer proc.
The timer Proc was required to give reaper the possibility to react to the simulated mouse and keyboard events.
The usage is as follows: make sure the marker before and after the marker that has been moved are visible, now move the mouse over the moved time marker, push and hold down the "Y" key, move the mouse over the time marker to the right and release the "Y" key.
The following command sequence is then executed:
.) edit the third marker (the one where "Y" was released) and copy the BPM to the clipboard
.) select area between the first and second timemarker and execute 'Time signature measure from time selection'
.) select area between the second and third timemarker and execute 'Time signature measure from time selection'
.) edit the third marker and paste the BPM from the clipboard
Its not very nicly and error save, but it works. Once time markes are accessable for plugins, i hope to be able to make it a bit more reliable.
Let me know if you have any problems with it or questions regarding the code or topic.
cheers
Code:
#include "reaper_plugin.h"
#include <stdio.h>
HWND g_hwnd;
accelerator_register_t MyKeyProcessor;
POINT ptKeyDown;
POINT ptKeyUp;
int hTimer;
int c;
extern "C"
{
int KeyHookProc(MSG *msg, accelerator_register_t *ctx) {
MSG MyMsg = *msg;
if (c==0) {
switch (MyMsg.message) {
case WM_KEYDOWN:
if (ptKeyDown.x==0 && MyMsg.wParam == 89) {
//MessageBox(g_hwnd,"KeyDown","KeyDown",MB_OK);
GetCursorPos(&ptKeyDown);
}
break;
case WM_KEYUP:
if (ptKeyDown.x!=0) {
//MessageBox(g_hwnd,"KeyUp","KeyUp",MB_OK);
GetCursorPos(&ptKeyUp);
//char sText[101];
//ZeroMemory(sText,101);
//sprintf(sText,"KeyDown: %d,%d KeyUp: %d,%d",ptKeyDown.x,ptKeyDown.y,ptKeyUp.x,ptKeyUp.y);
//MessageBox (g_hwnd,sText,"OK",MB_OK);
ptKeyDown.y = (ptKeyDown.y + ptKeyUp.y) / 2;
//ptKeyUp.y=ptKeyDown.y;
c=1;
}
break;
default: break;
}
}
return 0;
};
void KeyEvent (byte Key, bool Down) {
byte btFlags=(MapVirtualKey(Key, 2)==0)?KEYEVENTF_EXTENDEDKEY:0;
btFlags |= Down?0:KEYEVENTF_KEYUP;
byte btScan = MapVirtualKey(Key, 0);
/*char sText[101];
ZeroMemory(sText,101);
sprintf(sText,"Key: %d, btScan: %d, btFlags: %d",Key,btScan,btFlags);
MessageBox (g_hwnd,sText,"OK",MB_OK);*/
keybd_event(Key,btScan,btFlags,0);
}
void TimerProc(HWND hWnd, int Msg, int idEvent, int dwTime) {
if (c>0) {
c++;
switch (c) {
case 2:
//open Marker Edit Dialog for third (=second clicked marker) by double clicking it
mouse_event (MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
break;
case 3:
//copy BPM into clipboard and close window
//SendMessage(GetForegroundWindow(),WM_COPY,0,0); WM_COPY does not work?
KeyEvent(VK_CONTROL,true);
KeyEvent(67,true);
KeyEvent(VK_CONTROL,false);
KeyEvent(67,false);
KeyEvent(VK_ESCAPE, true);
KeyEvent(VK_ESCAPE, false);
break;
case 4:
// select area between first two time markers
SetCursorPos(ptKeyDown.x-(ptKeyUp.x-ptKeyDown.x)/2,ptKeyDown.y);
mouse_event (MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
break;
case 5:
//adjust first two markers
SendMessage(g_hwnd,WM_COMMAND,40338,0); //40338 Markers: Time signature measure from time selection
break;
case 6:
// select area between second and third time marker
SetCursorPos(ptKeyDown.x+(ptKeyUp.x-ptKeyDown.x)/2,ptKeyDown.y);
mouse_event (MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
break;
case 7:
//adjust markers
SendMessage(g_hwnd,WM_COMMAND,40338,0); //40338 Markers: Time signature measure from time selection
break;
case 8:
//open Marker Edit Dialog for third marker by double clicking it
SetCursorPos(ptKeyUp.x,ptKeyUp.y);
break;
case 9:
mouse_event (MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event (MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
break;
case 10:
//paste BPM and close window
KeyEvent(VK_CONTROL,true);
KeyEvent(86,true);
KeyEvent(VK_CONTROL,false);
KeyEvent(86,false);
KeyEvent (VK_RETURN, true);
KeyEvent (VK_RETURN, false);
break;
case 11:
c=0;
ptKeyDown.x=0;
break;
default:
break;
}
}
}
REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(REAPER_PLUGIN_HINSTANCE hInstance, reaper_plugin_info_t *rec)
{
if (!rec || rec->caller_version != REAPER_PLUGIN_VERSION || !rec->GetFunc)
return 0;
g_hwnd = rec->hwnd_main;
// register a key hook procedure:
MyKeyProcessor.translateAccel=&KeyHookProc;
MyKeyProcessor.isLocal=TRUE;
if (!rec->Register("accelerator",&MyKeyProcessor)) {
MessageBox(g_hwnd,"could not register hookProc!","BAD happened :(",MB_OK);
} else {
//MessageBox(g_hwnd,"hookProc registered successfully!","GOOD happened :)",MB_OK);
}
c=0;
hTimer=SetTimer(0,0,100,(TIMERPROC) TimerProc);
return 1;
}
}