Andrew Lim avatar Andrew Lim committed e2308c3

initial commit

Comments (0)

Files changed (2)

+import win32gui
+import win32con
+import win32api
+import win32clipboard
+
+from ctypes import *
+import os
+import struct
+import wave
+
+'''
+ModPlug Tracker  IT
+|C-530v54...|D#530v54...|C-402v54...
+|........122|...........|...........
+|........444|...........|...........
+|.....v08...|.....v08...|===02......
+|........ZGE|...........|...........
+|...........|...........|...........
+'''
+
+#Register Hotkey Constants
+
+MOD_ALT = 1
+MOD_CONTROL = 2
+MOD_SHIFT = 4
+MOD_WIN = 8
+
+VK_LBUTTON = 0x01; VK_RBUTTON = 0x02; VK_CANCEL = 0x03; VK_MBUTTON = 0x04; VK_XBUTTON1 = 0x05; 
+VK_XBUTTON2 = 0x06; VK_BACK = 0x08; VK_TAB = 0x09; VK_CLEAR = 0x0C; VK_RETURN = 0x0D; 
+VK_SHIFT = 0x10; VK_CONTROL = 0x11; VK_MENU = 0x12; VK_PAUSE = 0x13; VK_CAPITAL = 0x14; 
+VK_KANA = 0x15; VK_HANGUEL = 0x15; VK_HANGUL = 0x15; VK_JUNJA = 0x17; VK_FINAL = 0x18; 
+VK_HANJA = 0x19; VK_KANJI = 0x19; VK_ESCAPE = 0x1B; VK_CONVERT = 0x1C; VK_NONCONVERT = 0x1D; 
+VK_ACCEPT = 0x1E; VK_MODECHANGE = 0x1F; VK_SPACE = 0x20; VK_PRIOR = 0x21; VK_NEXT = 0x22; 
+VK_END = 0x23; VK_HOME = 0x24; VK_LEFT = 0x25; VK_UP = 0x26; VK_RIGHT = 0x27; VK_DOWN = 0x28; 
+VK_SELECT = 0x29; VK_PRINT = 0x2A; VK_EXECUTE = 0x2B; VK_SNAPSHOT = 0x2C; VK_INSERT = 0x2D; 
+VK_DELETE = 0x2E; VK_HELP = 0x2F; 
+
+VK_0 = 0x30; VK_1 = 0x31; VK_2 = 0x32; VK_3 = 0x33
+VK_4 = 0x34; VK_5 = 0x35; VK_6 = 0x36; VK_7 = 0x37
+VK_8 = 0x38; VK_9 = 0x39; VK_A = 0x41; VK_B = 0x42
+VK_C = 0x43; VK_D = 0x44; VK_E = 0x45; VK_F = 0x46
+VK_G = 0x47; VK_H = 0x48; VK_I = 0x49; VK_J = 0x4A
+VK_K = 0x4B; VK_L = 0x4C; VK_M = 0x4D; VK_N = 0x4E
+VK_O = 0x4F; VK_P = 0x50; VK_Q = 0x51; VK_R = 0x52
+VK_S = 0x53; VK_T = 0x54; VK_U = 0x55; VK_V = 0x56
+VK_W = 0x57; VK_X = 0x58; VK_Y = 0x59; VK_Z = 0x5A
+
+VK_SLEEP = 0x5F; VK_NUMPAD0 = 0x60; VK_NUMPAD1 = 0x61; VK_NUMPAD2 = 0x62; VK_NUMPAD3 = 0x63; 
+VK_NUMPAD4 = 0x64; VK_NUMPAD5 = 0x65; VK_NUMPAD6 = 0x66; VK_NUMPAD7 = 0x67; VK_NUMPAD8 = 0x68;
+VK_NUMPAD9 = 0x69; VK_MULTIPLY = 0x6A; VK_ADD = 0x6B; VK_SEPARATOR = 0x6C; VK_SUBTRACT = 0x6D; 
+VK_DECIMAL = 0x6E; VK_DIVIDE = 0x6F; VK_F1 = 0x70; VK_F2 = 0x71; VK_F3 = 0x72; VK_F4 = 0x73; 
+VK_F5 = 0x74; VK_F6 = 0x75; VK_F7 = 0x76; VK_F8 = 0x77; VK_F9 = 0x78; VK_F10 = 0x79; 
+VK_F11 = 0x7A; VK_F12 = 0x7B; VK_F13 = 0x7C; VK_F14 = 0x7D; VK_F15 = 0x7E; VK_F16 = 0x7F; 
+VK_F17 = 0x80; VK_F18 = 0x81; VK_F19 = 0x82; VK_F20 = 0x83; VK_F21 = 0x84; VK_F22 = 0x85; 
+VK_F23 = 0x86; VK_F24 = 0x87; 
+
+VK_NUMLOCK = 0x90; VK_SCROLL = 0x91; VK_LSHIFT = 0xA0; VK_RSHIFT = 0xA1; VK_LCONTROL = 0xA2; 
+VK_RCONTROL = 0xA3; VK_LMENU = 0xA4; VK_RMENU = 0xA5; VK_BROWSER_BACK = 0xA6; 
+VK_BROWSER_FORWARD = 0xA7; VK_BROWSER_REFRESH = 0xA8; VK_BROWSER_STOP = 0xA9; 
+VK_BROWSER_SEARCH = 0xAA; VK_BROWSER_FAVORITES = 0xAB; VK_BROWSER_HOME = 0xAC; 
+VK_VOLUME_MUTE = 0xAD; VK_VOLUME_DOWN = 0xAE; VK_VOLUME_UP = 0xAF; VK_MEDIA_NEXT_TRACK = 0xB0; 
+VK_MEDIA_PREV_TRACK = 0xB1; VK_MEDIA_STOP = 0xB2; VK_MEDIA_PLAY_PAUSE = 0xB3; 
+VK_LAUNCH_MAIL = 0xB4; VK_LAUNCH_MEDIA_SELECT = 0xB5; VK_LAUNCH_APP1 = 0xB6; 
+VK_LAUNCH_APP2 = 0xB7; VK_OEM_1 = 0xBA; VK_OEM_PLUS = 0xBB; VK_OEM_COMMA = 0xBC; 
+VK_OEM_MINUS = 0xBD; VK_OEM_PERIOD = 0xBE; VK_OEM_2 = 0xBF; VK_OEM_3 = 0xC0; VK_OEM_4 = 0xDB; 
+VK_OEM_5 = 0xDC; VK_OEM_6 = 0xDD; VK_OEM_7 = 0xDE; VK_OEM_8 = 0xDF; VK_OEM_102 = 0xE2; 
+VK_PROCESSKEY = 0xE5; VK_PACKET = 0xE7; VK_ATTN = 0xF6; VK_CRSEL = 0xF7; VK_EXSEL = 0xF8; 
+VK_EREOF = 0xF9; VK_PLAY = 0xFA; VK_ZOOM = 0xFB; VK_NONAME = 0xFC; VK_PA1 = 0xFD; 
+VK_OEM_CLEAR = 0xFE; 
+
+
+NOTE_OFF = 255
+NOTE_CUT = 254
+NOTE_FADE = 253
+NOTE_NONE = -1
+notenames = ['C-','C#','D-','D#','E-','F-','F#','G-','G#','A-','A#','B-']
+
+
+def mpt_get_note_number(data):
+    nn = NOTE_NONE
+    if data in ['',"..."]:
+        nn = NOTE_NONE
+    elif data == "===":
+        nn = NOTE_OFF
+    elif data == "^^^":
+        nn = NOTE_CUT
+    elif data == "~~~":
+        nn = NOTE_FADE
+    else:
+        n = notenames.index(data[0:2])
+        o = int(data[2:3],16)
+        nn = o * 12 + n
+    return nn
+
+def mpt_get_note_name(nn):
+    if nn == NOTE_NONE: 
+        return "..."
+    elif nn == NOTE_OFF:
+        return "==="
+    elif nn == NOTE_CUT:
+        return "^^^"
+    elif nn == NOTE_FADE:
+        return "~~~"
+    else:
+        n = nn % 12
+        o = nn // 12
+        return "%s%X" % (notenames[n],o)
+
+def mpt_get_note_info(nn):
+    return { 'n': nn % 12, 'o': nn // 12, 'off': (nn == NOTE_OFF), 'cut': (nn == NOTE_CUT), 'fade': (nn == NOTE_FADE), 'none': (nn == NOTE_NONE) }
+
+def mpt_split_pattern(data):
+    '''
+    Returns
+    [ #row
+        [ #col
+            { note: int,
+              inst: int,
+              volcmd: str,
+              volval: int,
+              effcmd: str,
+              effval: int }
+        ]
+    ]
+    '''
+    lines = data.splitlines()
+    if lines[0] != "ModPlug Tracker  IT":
+        return None
+    rows = []
+    for row in lines[1:]:
+        columns = row[1:].split("|")
+        row = []
+        for col in columns:
+            colm = {}
+            colm['note'] = mpt_get_note_number(col[0:3])
+            colm['inst'] = int(col[3:5]) if col[3:5] not in ['','..'] else -1
+            colm['volcmd'] = col[5:6]
+            colm['volval'] = int(col[6:8]) if col[6:8] not in ['','..'] else -1
+            colm['effcmd'] = col[8:9]
+            colm['effval'] = int(col[9:11],16) if col[9:11] not in ['','..'] else -1
+            row.append(colm)
+        rows.append(row)
+    return rows
+
+def mpt_join_pattern(rows):
+    lines = []
+    lines.append("ModPlug Tracker  IT")
+    for rowm in rows:
+        row = ""
+        for colm in rowm:
+            row += "|"
+            row += mpt_get_note_name(colm['note'])
+            row += "%02d" % colm['inst'] if colm['inst'] > 0 else ".."
+            row += colm['volcmd'] if colm['volcmd'] != '' else '.'
+            row += "%02d" % colm['volval'] if colm['volval'] > -1 else ".."
+            row += colm['effcmd'] if colm['effcmd'] != '' else '.'
+            row += colm['effval'] if colm['effval'] > -1 else '..'
+        lines.append(row)
+    return '\r\n'.join(lines)
+
+def mpt_split_env(data):
+    '''
+    Returns 
+    { sustain_start: int,
+      sustain_end: int,
+      loop_start: int,
+      loop_end: int,
+      has_sustain: bool,
+      has_loop: bool,
+      has_carry: bool 
+      points: [ { x: int, y: int }] }
+    '''
+    lines = data.splitlines()
+    if lines[0] != "Modplug Tracker Envelope":
+        return None
+    headervals = lines[1].split(",")
+    nodes = int(headervals[0])
+    header = {}
+
+    for x in xrange(1,5):
+        header[['sustain_start','sustain_end','loop_start','loop_end'][x-1]] = int(headervals[x])
+    for x in xrange(5,8):
+        header[['has_sustain','has_loop','has_carry'][x-5]] = (int(headervals[x]) == 1)
+    off = 2
+    points = []
+    for n in xrange(nodes):
+        x,y = [int(x) for x in lines[off+n].split(",")]
+        points.append({ "x": x, "y": y })
+    header['points'] = points
+    return header
+
+def mpt_join_env(header):
+    lines = []
+    points = header['points']
+    lines.append("Modplug Tracker Envelope")
+    lines.append( 
+        ','.join(
+        ["%d" % len(points)] + 
+        ["%d" % header[key] for key in ['sustain_start','sustain_end','loop_start','loop_end']] +
+        [("1" if header[key] else "0") for key in ['has_sustain','has_loop','has_carry']]
+        )
+        )
+    for n in points:
+        lines.append("%d,%d" % (n['x'],n['y']))
+    lines.append("255")
+    return '\r\n'.join(lines)
+
+def mpt_new_env():
+    return {
+        'sustain_start': 0,
+        'sustain_end': 0,
+        'loop_start': 0,
+        'loop_end': 0,
+        'has_sustain': False,
+        'has_loop': False,
+        'has_carry': False,
+        'points': []
+    }
+def mpt_new_point(x,y):
+    return {'x':x,'y':y}
+
+class MainWindow:
+    def cleanwav(self):
+     if os.path.exists(self.tempfn):
+      os.remove(self.tempfn)
+
+    def __init__(self):
+       win32gui.InitCommonControls()
+       self.hinst = win32api.GetModuleHandle(None)
+    def CreateWindow(self):
+       className = self.RegisterClass()
+       self.BuildWindow(className)
+
+    def RegisterClass(self):
+       className = "TeSt"
+       message_map = {
+          win32con.WM_DESTROY: self.OnDestroy,
+          win32con.WM_SHOWWINDOW: self.OnCreate,
+          win32con.WM_HOTKEY: self.OnHotkey
+       }
+       wc = win32gui.WNDCLASS()
+       wc.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
+       wc.lpfnWndProc = message_map
+       wc.cbWndExtra = 0
+       wc.hCursor = win32gui.LoadCursor( 0, win32con.IDC_ARROW )
+       wc.hbrBackground = win32con.COLOR_WINDOW + 1
+       wc.hIcon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION)
+       wc.lpszClassName = className
+       # C code: wc.cbWndExtra = DLGWINDOWEXTRA + sizeof(HBRUSH) + (sizeof(COLORREF));
+       wc.cbWndExtra = win32con.DLGWINDOWEXTRA + struct.calcsize("Pi")
+       #wc.hIconSm = 0
+       classAtom = win32gui.RegisterClass(wc)
+       return className
+
+    def BuildWindow(self, className):
+       style = win32con.WS_OVERLAPPEDWINDOW
+       xstyle = win32con.WS_EX_LEFT
+       self.hwnd = win32gui.CreateWindow(className,
+                             "Modplug Paste Tool",
+                             style,
+                             win32con.CW_USEDEFAULT,
+                             win32con.CW_USEDEFAULT,
+                             500,
+                             400,
+                             0,
+                             0,
+                             self.hinst,
+                             None)
+       win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW)
+
+    def Activate(self):
+        win32gui.SetForegroundWindow(self.hwnd)
+
+    def RegisterHotkeys(self):
+        for hk in self.hotmap:
+            windll.user32.RegisterHotKey(self.hwnd,-1,hk['mod'],hk['vk'])
+    def MsgBox(self,text="",title="",msgtype=0L):
+        win32gui.MessageBox(self.hwnd,text,title,msgtype)
+
+    def GetClipboard(self):
+        win32clipboard.OpenClipboard()
+        data = win32clipboard.GetClipboardData()
+        win32clipboard.CloseClipboard()
+        return data
+    def SetClipboard(self,data):
+        win32clipboard.OpenClipboard()
+        win32clipboard.SetClipboardText(data)
+        win32clipboard.CloseClipboard()
+    def OnDestroy(self, hwnd, message, wparam, lparam):
+        win32gui.PostQuitMessage(0)
+        return True
+    def OnCreate(self, hwnd, message, wparam, lparam):
+        self.hotmap = hotmap
+        self.RegisterHotkeys()
+    def OnHotkey(self, hwnd, message, wparam, lparam):
+        for hk in self.hotmap:
+            if (hk['mod'] == (lparam & 0xFFFF)) and (hk['vk'] == ((lparam >> 16) & 0xFFFF)):
+               print "Handling: " + hk['title']
+               data = self.GetClipboard()
+               data = hk['handler'](data)
+               if data: self.SetClipboard(data)
+               return
+
+def MsgBox(text="",title="",msgtype=0L):
+    win32gui.MessageBox(win32gui.GetForegroundWindow(),text,title,msgtype)
+
+hotmap = []
+from pastelib import *
+
+def NotesToPitchEnv(data):
+    rows = mpt_split_pattern(data)
+    if not rows:
+        MsgBox("Need Pattern Data! Copy pattern pls")
+        return
+    col1 = [x[0] for x in rows]
+    basenote = -1
+    x = 0
+    env = mpt_new_env()
+    startpoint = 0
+    endpoint = 0
+    ly = -1
+    inturd = -1
+    steplen = -1
+    for row in col1:
+        if row['effcmd'] == 'S':
+            if row['effval'] == 0xB0:
+                startpoint = len(env['points'])
+            elif row['effval'] == 0xBF:
+                env['has_carry'] = True
+            elif row['effval'] == 0xB1:
+                endpoint = len(env['points'])+2
+                env['has_loop'] = True
+            else:
+                endpoint = len(env['points'])+2
+                env['has_sustain'] = True
+
+        if basenote == -1:
+            basenote = row['note']
+        if row['inst'] > 0:
+            steplen = row['inst']
+        if row['note'] not in [NOTE_OFF,NOTE_NONE,NOTE_FADE,NOTE_CUT]:
+            print row['note']
+            inturd = 32 + ((row['note'] - basenote) * 2)
+        if inturd < 0: inturd = 0
+        if inturd > 64: inturd = 64
+
+        if ly > -1:
+            env['points'].append(mpt_new_point(x,ly))
+        if ly != inturd:
+            env['points'].append(mpt_new_point(x,inturd))
+
+        ly = inturd
+        x += steplen
+
+    env['points'].append(mpt_new_point(x,ly))
+    if env['has_loop']:
+        env['loop_start'] = startpoint
+        env['loop_end'] = endpoint
+    elif env['has_sustain']:
+        env['sustain_start'] = startpoint
+        env['sustain_end'] = endpoint
+    return mpt_join_env(env)
+
+
+hotmap.append({ 
+        'title': 'Replace Note Offs with Note Cuts', 
+        'mod': MOD_WIN , 'vk': VK_X, 
+        'handler': lambda x: x.replace("===","^^^") })
+hotmap.append({ 
+        'title': 'Generate Pitch Envelope With Notes', 
+        'mod': MOD_WIN + MOD_ALT, 'vk': VK_Z, 
+        'handler': NotesToPitchEnv })
+
+
+
+
+w = MainWindow()
+w.CreateWindow()
+win32gui.PumpMessages()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.