├── .DS_Store ├── img_1.jpg ├── Launchpad-SysEx-Programs ├── image1.png ├── image2.png ├── Launchpad_mini_mk3_sysex.tox ├── Launchpad Programs │ ├── 17_OTO BAM.syx │ ├── 18_MFB-522.syx │ ├── 4_Piano To G.syx │ ├── 3_Piano Mom G.syx │ ├── 10_CC 0-63 To G.syx │ ├── 12_CC 64-127 To G.syx │ ├── 13_CC_74 0-63 G.syx │ ├── 14_CC_74 64-127 G.syx │ ├── 15_ProgChan0-63 G.syx │ ├── 2_Keyboard QWERTY.syx │ ├── 5_Notes 1-64 Mo G.syx │ ├── 6_Notes1-64 To G.syx │ ├── 9_CC 0-63 Mom G.syx │ ├── 11_CC 64-127 Mom G.syx │ ├── 16_ProgChan64-127 G.syx │ ├── 1_Keyboard Numbers.syx │ ├── 7_Notes65-128 Mo G.syx │ └── 8_Notes65-128 To G.syx ├── README.md ├── READ ME.txt └── Launchpad1_callbacks.py ├── Midi_Learn_Controller ├── Midi_Learn_Controller.tox ├── Midi_Learn_Controller_img1.png ├── Midi_Learn_Controller_img2.png ├── Midi_Learn_Controller_img3.png ├── Midi_Learn_Controller_img4.png ├── README.txt └── README.md └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/.DS_Store -------------------------------------------------------------------------------- /img_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/img_1.jpg -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/image1.png -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/image2.png -------------------------------------------------------------------------------- /Midi_Learn_Controller/Midi_Learn_Controller.tox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Midi_Learn_Controller/Midi_Learn_Controller.tox -------------------------------------------------------------------------------- /Midi_Learn_Controller/Midi_Learn_Controller_img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Midi_Learn_Controller/Midi_Learn_Controller_img1.png -------------------------------------------------------------------------------- /Midi_Learn_Controller/Midi_Learn_Controller_img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Midi_Learn_Controller/Midi_Learn_Controller_img2.png -------------------------------------------------------------------------------- /Midi_Learn_Controller/Midi_Learn_Controller_img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Midi_Learn_Controller/Midi_Learn_Controller_img3.png -------------------------------------------------------------------------------- /Midi_Learn_Controller/Midi_Learn_Controller_img4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Midi_Learn_Controller/Midi_Learn_Controller_img4.png -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad_mini_mk3_sysex.tox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad_mini_mk3_sysex.tox -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/17_OTO BAM.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/17_OTO BAM.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/18_MFB-522.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/18_MFB-522.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/4_Piano To G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/4_Piano To G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/3_Piano Mom G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/3_Piano Mom G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/10_CC 0-63 To G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/10_CC 0-63 To G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/12_CC 64-127 To G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/12_CC 64-127 To G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/13_CC_74 0-63 G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/13_CC_74 0-63 G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/14_CC_74 64-127 G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/14_CC_74 64-127 G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/15_ProgChan0-63 G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/15_ProgChan0-63 G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/2_Keyboard QWERTY.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/2_Keyboard QWERTY.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/5_Notes 1-64 Mo G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/5_Notes 1-64 Mo G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/6_Notes1-64 To G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/6_Notes1-64 To G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/9_CC 0-63 Mom G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/9_CC 0-63 Mom G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/11_CC 64-127 Mom G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/11_CC 64-127 Mom G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/16_ProgChan64-127 G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/16_ProgChan64-127 G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/1_Keyboard Numbers.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/1_Keyboard Numbers.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/7_Notes65-128 Mo G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/7_Notes65-128 Mo G.syx -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad Programs/8_Notes65-128 To G.syx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duarte-amorim/Touchdesigner/HEAD/Launchpad-SysEx-Programs/Launchpad Programs/8_Notes65-128 To G.syx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TouchDesigner Repository 2 | 3 | A TouchDesigner repository for TOX or TOE projects. 4 | 5 | ## Install TouchDesigner099 6 | https://derivative.ca/ 7 | 8 | ### TouchDesigner Example 9 | ![](img_1.jpg) 10 | 11 | 12 | -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/README.md: -------------------------------------------------------------------------------- 1 | # Launchpad Mini MK3 SysEx 2 | 3 | Tox for sending presets/programs, and other SysEx messages on the Novation Launchpad Mini MK3. 4 | 5 | ### Network Example 6 | ![](image1.png) 7 | 8 | ### Launchpad1 Operator Parameters Example 9 | ![](image2.png) 10 | 11 | ## Getting Started 12 | 13 | 1. Install TouchDesigner099 14 | 2. Open Launchpad_sysex_programs/Launchpad_mini_mk3_sysex.tox 15 | 3. Map the Launchpad Mini MK3: 'Dialogs' -> 'MIDI Device Mapper.' 16 | 17 | 18 | ## Compatibility 19 | 20 | TouchDesigner099 Build 2021.16960 21 | 22 | Novation Launchpad MK3 (Possibly others, I haven't tested) 23 | -------------------------------------------------------------------------------- /Midi_Learn_Controller/README.txt: -------------------------------------------------------------------------------- 1 | # MIDI Learn Controller 2 | 3 | MIDI Buttons with fast MIDI Learn to map and many other functions. 4 | 5 | ### Perform Mode Example 6 | ![](Midi_Learn_Controller_img1.png) 7 | 8 | ### Network Example 9 | ![](Midi_Learn_Controller_img2.png) 10 | 11 | ### Global Parameters Example 12 | ![](Midi_Learn_Controller_img3.png) 13 | 14 | ### Button Parameters Example 15 | ![](Midi_Learn_Controller_img4.png) 16 | 17 | 18 | ## Getting Started 19 | 20 | 1. Install TouchDesigner099 21 | 2. Open Midi_Learn_Controller/Midi_Learn_Controller.tox 22 | 3. Map the Midi_Buttons: 'Dialogs' -> 'MIDI Device Mapper.' 23 | 24 | 25 | ## Compatibility 26 | 27 | TouchDesigner099 Build 2023.11510 -------------------------------------------------------------------------------- /Midi_Learn_Controller/README.md: -------------------------------------------------------------------------------- 1 | # MIDI Learn Controller 2 | 3 | MIDI Buttons with fast MIDI Learn to map and many other functions. 4 | 5 | ### Perform Mode Example 6 | ![](Midi_Learn_Controller_img1.png) 7 | 8 | ### Network Example 9 | ![](Midi_Learn_Controller_img2.png) 10 | 11 | ### Global Parameters Example 12 | ![](Midi_Learn_Controller_img3.png) 13 | 14 | ### Button Parameters Example 15 | ![](Midi_Learn_Controller_img4.png) 16 | 17 | 18 | ## Getting Started 19 | 20 | 1. Install TouchDesigner099 21 | 2. Open Midi_Learn_Controller/Midi_Learn_Controller.tox 22 | 3. Map the Midi_Buttons: 'Dialogs' -> 'MIDI Device Mapper.' 23 | 24 | 25 | ## Compatibility 26 | 27 | TouchDesigner099 Build 2023.11510 28 | 29 | -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/READ ME.txt: -------------------------------------------------------------------------------- 1 | You can built and save new sysex programs/presets 2 | in the Novation Application Components with: 3 | File -> Save as 4 | 5 | ------------------------------------------------ 6 | !IMPORTANT! 7 | Don't forget to map the 8 | Launchpad Mini MK3 in Touchdesigner: 9 | 10 | Go to 'Dialogs'->'MIDI Device Mapper.' 11 | 12 | Create a new mapping. 13 | 14 | Select the second Launchpad Mini MK3 15 | device, in both 'In Device' and 16 | 'Out Device.' 17 | 18 | Check the ID of the 'midiout1' 19 | operator and ensure it is active. 20 | 21 | ------------------------------------------------ 22 | 23 | To use the "Pad_colour" 24 | operator, follow these steps: 25 | 26 | Go to the "Launchpad1" 27 | operator's parameters, 28 | page Launchpad SysEx. 29 | 30 | Select "4" (Programmer Mode) 31 | in the "Layout" parameter. 32 | 33 | ------------------------------------------------ 34 | 35 | Pads are: 36 | 37 | midi out - 0 Based Index: 38 | ch1n11 to n99 - Static colour 39 | ch2n11 to n99 - Flashing colour 40 | ch1n11 to n99 - Pulsing colour 41 | 42 | midi out - 1 Based Index: 43 | ch1n12 to n100 - Static colour 44 | ch2n12 to n100 - Flashing colour 45 | ch1n12 to n100 - Pulsing colour 46 | -------------------------------------------------------------------------------- /Launchpad-SysEx-Programs/Launchpad1_callbacks.py: -------------------------------------------------------------------------------- 1 | # me - this DAT 2 | # scriptOp - the OP which is cooking 3 | import os 4 | import time 5 | import string 6 | 7 | # Change the name here if you change the name of the script operator 8 | op_script_name = '' 9 | 10 | # Pulse counts of Lightpulse button 11 | light_pulse_count = 1 12 | previous_brightness = -1 13 | previous_layout = -1 14 | 15 | previous_dru_label_number = 0 16 | previous_key_label_number = 0 17 | previous_use_label_number = 0 18 | 19 | previous_dru_folder = None 20 | previous_key_folder = None 21 | previous_use_folder = None 22 | 23 | previous_midi_op_name = None 24 | 25 | dru_menu_files = "" 26 | key_menu_files = "" 27 | use_menu_files = "" 28 | 29 | 30 | error_message = ["OOPS!! no folder or no .syx files"] 31 | error_message2 = ["NO MIDI OUT CHOP"] 32 | error_message3 = ["MIDI OUT CHOP NOT ACTIVE"] 33 | 34 | 35 | def onSetupParameters(scriptOp): 36 | # Create Page 37 | page = scriptOp.appendCustomPage('Launchpad SysEx') 38 | 39 | # Midi 40 | scriptOp.clear() 41 | page.appendHeader("Header0", label='Midi') 42 | page.appendCHOP('Midiout', label='Midi Out Chop') 43 | 44 | # Layout Select 45 | sel = page.appendHeader('Header1', label='Layout Select') 46 | sel[0].startSection = True 47 | lay=page.appendHeader('Header2', label='Session/Default=0 Drums=1 Keys=2 User=3 Programmer Mode=4') 48 | lay = page.appendInt('Layout') 49 | lay[0].normMin = 0 50 | lay[0].normMax = 4 51 | lay[0].default = 0 52 | 53 | # Programs 54 | pro = page.appendHeader('Header3', label='Programs') 55 | pro[0].startSection = True 56 | 57 | page.appendToggle('Autosend', label='Auto Send Programs') 58 | page.appendToggle('Autolayout', label='Auto Select Layout') 59 | 60 | # Drums 61 | dru_menu = page.appendMenu('Drumsprog', label='Drums Program') 62 | dru_menu[0].menuLabels = dru_menu_files 63 | 64 | 65 | # Keys 66 | key_menu = page.appendMenu('Keysprog', label='Keys Program') 67 | key_menu[0].menuLabels = key_menu_files 68 | 69 | 70 | # User 71 | use_menu = page.appendMenu('Userprog', label='User Program') 72 | use_menu[0].menuLabels = use_menu_files 73 | 74 | # Resend 75 | page.appendPulse('Resendprog', label='ReSend All Selected Programs') 76 | 77 | # Folders 78 | page.appendFolder ('Drumsfolder', label='Drums SysEx Folder') 79 | page.appendFolder ('Keysfolder', label='Key SysEx Folder') 80 | page.appendFolder ('Userfolder', label='User SysEx Folder') 81 | 82 | # Light 83 | ligh = page.appendHeader('Header4', label='Light') 84 | ligh[0].startSection = True 85 | page.appendPulse('Light', label='Light on/off') 86 | 87 | # Brightness 88 | bri = page.appendInt('Brightness') 89 | bri[0].normMin = 0 90 | bri[0].normMax = 127 91 | bri[0].default = 127 92 | 93 | # Text Scrolling 94 | messag = page.appendHeader('Header5', label='Text Scrolling') 95 | messag[0].startSection = True 96 | page.appendStr('Text', label='Text Message') 97 | 98 | col = page.appendInt('Colour') 99 | col[0].normMin = 0 100 | col[0].normMax = 126 101 | col[0].default = 2 102 | 103 | spe = page.appendInt('Speed') 104 | spe[0].normMin = 0 105 | spe[0].normMax = 78 106 | spe[0].default = 10 107 | 108 | page.appendToggle('Loop', label='Loop') 109 | page.appendPulse('Start', label='Play Message') 110 | page.appendPulse('Stop', label='Stop Message') 111 | 112 | # Special Sysex 113 | spe_sysex = page.appendHeader('Header6', label='Special SysEx Message') 114 | spe_sysex[0].startSection = True 115 | page.appendStr('Messagesysex', label='Hexadecimal SysEx Message') 116 | page.appendPulse('Sendspsysex', label='Send Special Sysex') 117 | 118 | # Website 119 | website = page.appendHeader('Header7', label=' ') 120 | website[0].startSection = True 121 | page.appendPulse('Web', label="Made with 'love' by Duarte Amorim") 122 | page.appendHeader('Header8', label=' ') 123 | 124 | return page 125 | 126 | def onSetupParameters_Drums(scriptOp): 127 | page = scriptOp.appendCustomPage('Launchpad SysEx') 128 | dru_menu = page.appendMenu('Drumsprog', label='Drums Program') 129 | dru_menu[0].menuLabels = dru_menu_files 130 | return 131 | 132 | def onSetupParameters_Keys(scriptOp): 133 | page = scriptOp.appendCustomPage('Launchpad SysEx') 134 | key_menu = page.appendMenu('Keysprog', label='Keys Program') 135 | key_menu[0].menuLabels = key_menu_files 136 | return 137 | 138 | def onSetupParameters_User(scriptOp): 139 | page = scriptOp.appendCustomPage('Launchpad SysEx') 140 | use_menu = page.appendMenu('Userprog', label='User Program') 141 | use_menu[0].menuLabels = use_menu_files 142 | return 143 | 144 | 145 | def labels_sort(name): 146 | # Extract the numeric part by splitting on underscores 147 | parts = name.split("_") 148 | # Convert numeric parts to integers 149 | numeric_parts = [int(part) for part in parts if part.isdigit()] 150 | # If there are no numeric parts, assume a numeric part of 0 151 | if not numeric_parts: 152 | numeric_parts = [0] 153 | # Return a tuple of numeric parts and the original file name 154 | return (numeric_parts, name) 155 | 156 | 157 | 158 | ## -------------------------------------------------------------------------------------------------- 159 | ## -------------------------------------------------------------------------------------------------- 160 | 161 | def onCook(scriptOp): 162 | global previous_layout, op_script_name, previous_brightness, previous_midi_op_name, previous_dru_label_number, previous_key_label_number, previous_use_label_number, previous_dru_folder, previous_key_folder, previous_use_folder 163 | 164 | op_script_name = scriptOp.name 165 | midi_op_name = scriptOp.par.Midiout 166 | 167 | if midi_op_name != None: 168 | n = op(str(midi_op_name)) 169 | 170 | if op(str(midi_op_name)).par.active == False and op(str(midi_op_name)).type == "midiout": 171 | onSetupParameters_Drums(scriptOp) 172 | onSetupParameters_Keys(scriptOp) 173 | onSetupParameters_User(scriptOp) 174 | scriptOp.par.Drumsprog.menuLabels = error_message3 175 | scriptOp.par.Keysprog.menuLabels = error_message3 176 | scriptOp.par.Userprog.menuLabels = error_message3 177 | previous_dru_folder = None 178 | previous_key_folder = None 179 | previous_use_folder = None 180 | 181 | else: 182 | 183 | 184 | ## -------------- BRIGHTNESS -------------- 185 | 186 | brightness = int(scriptOp.par.Brightness) 187 | if brightness != previous_brightness: 188 | if 0 <= brightness <= 127: 189 | 190 | bright_number = int(scriptOp.par.Brightness) 191 | bright_number = format(bright_number, '02X') 192 | bright_sysex = "F0002029020D08" + bright_number + "F7" 193 | # Convert bright_sysex hex to bytes 194 | sysex_bytes_bright = bytes.fromhex(bright_sysex) 195 | 196 | bright_number = int(scriptOp.par.Brightness) 197 | bright_number = format(bright_number, '02X') 198 | bright_sysex = "F0002029020D08" + bright_number + "F7" 199 | # Convert bright_sysex hex to bytes 200 | sysex_bytes_bright = bytes.fromhex(bright_sysex) 201 | n.send(sysex_bytes_bright) 202 | else: 203 | print('Brightness out of range. It should be within the range of 0 to 127.') 204 | 205 | previous_brightness = brightness 206 | 207 | 208 | ## -------------- LAYOUT SELECT -------------- 209 | 210 | layout = int(scriptOp.par.Layout) 211 | if layout != previous_layout: 212 | if 0 <= layout <= 4: 213 | 214 | layout_number = int(scriptOp.par.Layout) 215 | if layout_number == 0: 216 | layout_number = "00" 217 | elif 1 <= layout_number <= 3: 218 | layout_number = layout_number + 3 219 | layout_number = f'{layout_number:02}' 220 | elif layout_number == 4: 221 | layout_number = "7F" 222 | 223 | layout_sysex = "F0002029020D00" + str(layout_number) + "F7" 224 | sysex_bytes_layout = bytes.fromhex(layout_sysex) 225 | 226 | n.send(sysex_bytes_layout) 227 | previous_layout = layout 228 | 229 | 230 | 231 | ## -------------- DRUMS -------------- KEYS -------------- USER -------------- 232 | 233 | # Drums Keys User Labels 234 | dru_folder = str(scriptOp.par.Drumsfolder) 235 | key_folder = str(scriptOp.par.Keysfolder) 236 | use_folder = str(scriptOp.par.Userfolder) 237 | 238 | # Label Path Folder 239 | dru_folder_path = scriptOp.par.Drumsfolder.eval() 240 | key_folder_path = scriptOp.par.Keysfolder.eval() 241 | use_folder_path = scriptOp.par.Userfolder.eval() 242 | 243 | dru_menu_files = error_message 244 | key_menu_files = error_message 245 | use_menu_files = error_message 246 | 247 | dru_label = scriptOp.par.Drumsprog 248 | key_label = scriptOp.par.Keysprog 249 | use_label = scriptOp.par.Userprog 250 | 251 | dru_syx_found = False 252 | key_syx_found = False 253 | use_syx_found = False 254 | 255 | dru_file_bytes = bytes.fromhex("F0002029020DF7") 256 | key_file_bytes = bytes.fromhex("F0002029020DF7") 257 | use_file_bytes = bytes.fromhex("F0002029020DF7") 258 | 259 | auto_send = scriptOp.par.Autosend 260 | resend = scriptOp.par.Resendprog 261 | 262 | scriptOp_name = scriptOp.name 263 | 264 | 265 | # DRUMS ------------------------------------------------ 266 | 267 | # Iterate through the files in the folder 268 | if os.path.exists(dru_folder_path): 269 | for file_name in os.listdir(dru_folder_path): 270 | if file_name.endswith(".syx"): 271 | dru_syx_found = True 272 | break 273 | if (dru_folder != previous_dru_folder) or dru_label == "": 274 | # Empty labels 275 | onSetupParameters_Drums(scriptOp) 276 | # Check if the folder exists and is not empty 277 | if dru_folder_path and os.path.exists(dru_folder_path) and os.listdir(dru_folder_path) and dru_syx_found == True: 278 | # Get the list of file names in the folder 279 | dru_file_names = os.listdir(dru_folder_path) 280 | # Filter for .syx files, sort them with the custom labels_sort function 281 | dru_syx_files = sorted([f for f in dru_file_names if f.endswith('.syx')], key=labels_sort) 282 | # Set the menu labels to the extracted values 283 | dru_menu_files = dru_syx_files 284 | # Refresh new labels 285 | scriptOp.par.Drumsprog.menuLabels = dru_menu_files 286 | previous_dru_label_number = -1 287 | else: 288 | # Set the menu labels to the extracted values 289 | dru_menu_files = error_message 290 | # Refresh new labels 291 | scriptOp.par.Drumsprog.menuLabels = dru_menu_files 292 | previous_dru_folder = dru_folder 293 | 294 | if (dru_label != "" and dru_label != error_message): 295 | dru_file = str(scriptOp.par.Drumsprog.eval()) 296 | dru_label_number = int(scriptOp.par.Drumsprog) 297 | 298 | if dru_folder_path and os.path.exists(dru_folder_path) and os.listdir(dru_folder_path) and dru_syx_found == True: 299 | dru_all_path = dru_folder + "/" + dru_file 300 | with open(dru_all_path, "rb") as file: 301 | dru_bytes_file = file.read() 302 | dru_hex_file = dru_bytes_file.hex() 303 | char_dru_hex_list = list(dru_hex_file) 304 | char_dru_hex_list[20] = '0' 305 | char_dru_hex_list[21] = '4' 306 | final_dru_hex = ''.join(char_dru_hex_list) 307 | dru_file_bytes = bytes.fromhex(final_dru_hex) 308 | if (dru_label_number != previous_dru_label_number): 309 | if dru_label_number >= 0 and auto_send == True: 310 | n.send(dru_file_bytes) 311 | if scriptOp.par.Autolayout == True: 312 | layout_dru = "F0002029020D0004F7" 313 | layout_dru_bytes = bytes.fromhex(layout_dru) 314 | n.send(layout_dru_bytes) 315 | previous_dru_label_number = dru_label_number 316 | 317 | 318 | 319 | # KEYS ------------------------------------------------ 320 | 321 | if os.path.exists(key_folder_path): 322 | for file_name in os.listdir(key_folder_path): 323 | if file_name.endswith(".syx"): 324 | key_syx_found = True 325 | break 326 | if (key_folder != previous_key_folder) or key_label == "": 327 | onSetupParameters_Keys(scriptOp) 328 | 329 | if key_folder_path and os.path.exists(key_folder_path) and os.listdir(key_folder_path) and key_syx_found == True: 330 | key_file_names = os.listdir(key_folder_path) 331 | key_syx_files = sorted([f for f in key_file_names if f.endswith('.syx')], key=labels_sort) 332 | key_menu_files = key_syx_files 333 | scriptOp.par.Keysprog.menuLabels = key_menu_files 334 | previous_key_label_number = -1 335 | else: 336 | key_menu_files = error_message 337 | scriptOp.par.Keysprog.menuLabels = key_menu_files 338 | previous_key_folder = key_folder 339 | 340 | if (key_label != "" and key_label != error_message): 341 | key_file = str(scriptOp.par.Keysprog.eval()) 342 | key_label_number = int(scriptOp.par.Keysprog) 343 | 344 | if key_folder_path and os.path.exists(key_folder_path) and os.listdir(key_folder_path) and key_syx_found == True: 345 | key_all_path = key_folder + "/" + key_file 346 | with open(key_all_path, "rb") as file: 347 | key_bytes_file = file.read() 348 | key_hex_file = key_bytes_file.hex() 349 | char_key_hex_list = list(key_hex_file) 350 | char_key_hex_list[20] = '0' 351 | char_key_hex_list[21] = '5' 352 | final_key_hex = ''.join(char_key_hex_list) 353 | key_file_bytes = bytes.fromhex(final_key_hex) 354 | if (key_label_number != previous_key_label_number): 355 | if key_label_number >= 0 and auto_send == True: 356 | n.send(key_file_bytes) 357 | if scriptOp.par.Autolayout == True: 358 | layout_key = "F0002029020D0005F7" 359 | layout_key_bytes = bytes.fromhex(layout_key) 360 | n.send(layout_key_bytes) 361 | previous_key_label_number = key_label_number 362 | 363 | 364 | 365 | # USER ------------------------------------------------ 366 | 367 | if os.path.exists(use_folder_path): 368 | for file_name in os.listdir(use_folder_path): 369 | if file_name.endswith(".syx"): 370 | use_syx_found = True 371 | break 372 | if (use_folder != previous_use_folder) or use_label == "": 373 | onSetupParameters_User(scriptOp) 374 | 375 | if use_folder_path and os.path.exists(use_folder_path) and os.listdir(use_folder_path) and use_syx_found == True: 376 | use_file_names = os.listdir(use_folder_path) 377 | use_syx_files = sorted([f for f in use_file_names if f.endswith('.syx')], key=labels_sort) 378 | use_menu_files = use_syx_files 379 | scriptOp.par.Userprog.menuLabels = use_menu_files 380 | previous_use_label_number = -1 381 | else: 382 | use_menu_files = error_message 383 | scriptOp.par.Userprog.menuLabels = use_menu_files 384 | previous_use_folder = use_folder 385 | 386 | if (use_label != "" and use_label != error_message): 387 | use_file = str(scriptOp.par.Userprog.eval()) 388 | use_label_number = int(scriptOp.par.Userprog) 389 | 390 | if use_folder_path and os.path.exists(use_folder_path) and os.listdir(use_folder_path) and use_syx_found == True: 391 | use_all_path = use_folder + "/" + use_file 392 | with open(use_all_path, "rb") as file: 393 | use_bytes_file = file.read() 394 | use_hex_file = use_bytes_file.hex() 395 | char_use_hex_list = list(use_hex_file) 396 | char_use_hex_list[20] = '0' 397 | char_use_hex_list[21] = '6' 398 | final_use_hex = ''.join(char_use_hex_list) 399 | use_file_bytes = bytes.fromhex(final_use_hex) 400 | if (use_label_number != previous_use_label_number): 401 | if use_label_number >= 0 and auto_send == True: 402 | n.send(use_file_bytes) 403 | if scriptOp.par.Autolayout == True: 404 | layout_use = "F0002029020D0006F7" 405 | layout_use_bytes = bytes.fromhex(layout_use) 406 | n.send(layout_use_bytes) 407 | previous_use_label_number = use_label_number 408 | 409 | return (dru_file_bytes, key_file_bytes, use_file_bytes, scriptOp) 410 | 411 | 412 | else: 413 | onSetupParameters_Drums(scriptOp) 414 | onSetupParameters_Keys(scriptOp) 415 | onSetupParameters_User(scriptOp) 416 | scriptOp.par.Drumsprog.menuLabels = error_message2 417 | scriptOp.par.Keysprog.menuLabels = error_message2 418 | scriptOp.par.Userprog.menuLabels = error_message2 419 | previous_dru_folder = None 420 | previous_key_folder = None 421 | previous_use_folder = None 422 | 423 | scriptOp.clear() 424 | 425 | 426 | 427 | def find_non_hex_character_position(s): 428 | try: 429 | bytes.fromhex(s) 430 | return None # No exception raised, it's valid hex 431 | except ValueError as e: 432 | error_message = str(e) 433 | # Extract the position from the error message 434 | if "at position" in error_message: 435 | position_str = error_message.split("at position")[1].strip() 436 | if position_str.isdigit(): 437 | position = int(position_str) 438 | return position 439 | return None 440 | 441 | def insert_spaces_at_position(s, position): 442 | if position is not None: 443 | if 0 <= position < len(s): 444 | return s[:position] + " " + s[position] + " " + s[position + 1:] 445 | return s 446 | 447 | ## -------------------------------------------------------------------------------------------------- 448 | ## -------------------------------------------------------------------------------------------------- 449 | 450 | def onPulse(par): 451 | global op_script_name, light_pulse_count, op_script_name 452 | 453 | scriptOp = op(str(op_script_name)) 454 | midi_op_name = scriptOp.par.Midiout 455 | 456 | if midi_op_name != None: 457 | n = op(str(midi_op_name)) 458 | 459 | dru_file_bytes = onCook(scriptOp) 460 | key_file_bytes = onCook(scriptOp) 461 | use_file_bytes = onCook(scriptOp) 462 | 463 | ## -------------- RESEND -------------- 464 | 465 | if par.name == 'Resendprog': 466 | n.send(dru_file_bytes[0]) 467 | n.send(key_file_bytes[1]) 468 | n.send(use_file_bytes[2]) 469 | 470 | ## -------------- SPECIAL SYSEX MESSAGE -------------- 471 | 472 | special_sysex_mes = str(scriptOp.par.Messagesysex.eval()) 473 | special_sysex_mes = special_sysex_mes.replace(" ", "") 474 | if par.name == 'Sendspsysex' and special_sysex_mes != "": 475 | if len(special_sysex_mes) % 2 == 0: 476 | if par.name == 'Sendspsysex': 477 | position = find_non_hex_character_position(special_sysex_mes) 478 | if position is not None: 479 | special_sysex_mes_spaced = insert_spaces_at_position(special_sysex_mes, position) 480 | ui.messageBox('Special SysEX Message', f"The SysEx message you've written contains non-hexadecimal characters. \n\nError: Non-hexadecimal character found at position {position} \n\nPlease rewrite it, and don't forget to include 'F0' at the beginning and 'F7' at the end. \n:)") 481 | print (f"Error: Non-hexadecimal character found at position {position} in the message:\n{special_sysex_mes_spaced}") 482 | else: 483 | special_sysex_mes_bytes = bytes.fromhex(special_sysex_mes) 484 | n.send(special_sysex_mes_bytes) 485 | print("Special SysEx Message Sent") 486 | else: 487 | ui.messageBox('Special SysEX Message', "The SysEx message you've written must be a string with an even number of characters. \nPlease rewrite it, and don't forget to include 'F0' at the beginning and 'F7' at the end. \n:)") 488 | print("The SysEx message you've written must be a string with an even number of characters.") 489 | 490 | 491 | 492 | ## -------------- LIGHT -------------- 493 | # Light sysex hex_light_1 = off and hex_light_2 = on 494 | hex_light = "" 495 | hex_light_1 = "F0002029020D0900F7" 496 | hex_light_2 = "F0002029020D0901F7" 497 | 498 | # Handle pulses for the "Light" button 499 | if par.name == 'Light': 500 | light_pulse_count += 1 501 | # Increment the pulse count for 'Light' 502 | if light_pulse_count % 2 == 0: 503 | hex_light = hex_light_1 504 | else: 505 | hex_light = hex_light_2 506 | 507 | # Convert hex_light hex to bytes 508 | sysex_bytes_light = bytes.fromhex(hex_light) 509 | 510 | # If Pulse on = send sysex 511 | if par.name == 'Light': 512 | n.send(sysex_bytes_light) 513 | 514 | 515 | ## -------------- TEXT SCROLLING -------------- 516 | 517 | #text_message 518 | loop_toggle = scriptOp.par.Loop.eval() 519 | write_text = str(scriptOp.par.Text.eval()) 520 | 521 | if write_text == "": 522 | write_text_hex = "454D505459" 523 | else: 524 | write_text_hex = ''.join(f'{ord(char):02x}' for char in write_text) 525 | 526 | #text_colour 527 | colour_number = int(scriptOp.par.Colour)+1 528 | text_colour = format(colour_number, '02X') # Convert text to hex 529 | 530 | #text_speed 531 | speed_number = int(scriptOp.par.Speed)+1 532 | text_speed = "{:02}".format(speed_number) #allways 2 digits "01...79" 533 | 534 | #text_loop 535 | if loop_toggle: 536 | text_loop = "01" 537 | else: 538 | text_loop = "00" 539 | 540 | 541 | #text_play 542 | if par.name == 'Start': 543 | if 1 <= colour_number <= 127 and 1 <= speed_number <= 79: 544 | play_message = "F0002029020D07" + text_loop + text_speed + "00" + text_colour + write_text_hex + "F7" 545 | play_message_bytes = bytes.fromhex(play_message) 546 | n.send(play_message_bytes) 547 | else: 548 | print('Colour or Speed out of range. They should be within the ranges of 0 to 126 for Colour and 0 to 78 for Speed.') 549 | 550 | #text_stop 551 | stop_message = "F0002029020D070040000320F7" 552 | stop_message_bytes = bytes.fromhex(stop_message) 553 | 554 | if par.name == 'Stop': 555 | n.send(stop_message_bytes) 556 | 557 | if op(str(midi_op_name)).par.active == False and op(str(midi_op_name)).type == "midiout": 558 | print("Unable to send the message. \nOperator MIDI Out is not ACTIVE.") 559 | 560 | else: 561 | if par.name != 'Web': 562 | print("Unable to send the message. \nNo operator MIDI Out is selected in the 'Midi Out Chop' on this page.") 563 | 564 | 565 | 566 | 567 | ## -------------- WEB -------------- 568 | 569 | duarte = "https://www.duarteamorim.com/" 570 | if par.name == 'Web': 571 | ui.viewFile(duarte) 572 | 573 | 574 | return 575 | --------------------------------------------------------------------------------