isolating part of elemnnt in a list - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: isolating part of elemnnt in a list (/thread-692.html) |
isolating part of elemnnt in a list - trepaning - Oct-29-2016 this is a list [['1 A'], ['2 B']] what I want to do is get at the number, add another number to it, and put it back together with the new number value. I am learning Python on my own, so am just looking for a pointer in the right direction on how to how to pull that number out, as no basic SPLIT seems to account for this type of list setup. I can provide more info if needed. Thanks for any info. moderator: feel free to correct TITLE spelling error of "element" for future search RE: isolating part of elemnnt in a list - Yoriz - Oct-29-2016 Need to get the 0 index of the first list and the 0 index of the inner list to be able to use split on '1 A'. >>> my_list = [['1 A'], ['2 B']] >>> a, b = my_list[0][0].split() >>> my_list[0][0] = '{} {}'.format(int(a)+10, b) >>> my_list [['11 A'], ['2 B']] >>> RE: isolating part of elemnnt in a list - buran - Oct-29-2016 Please, post your best try at the code. Note, that this is list of list, so maybe that is what confuses you.. RE: isolating part of elemnnt in a list - Larz60+ - Oct-29-2016 seems to me it would be a lot easier to build the list like: newlist = [[1, 'A'], [2, 'B']]then you can do your math without hassle, and convert back to a string only when displaying RE: isolating part of elemnnt in a list - trepaning - Oct-29-2016 Thank you for the info, I will try it out very shortly but I feel an explanation of the project will help here: I am learning Pythion because I use Blender and want to make an addon to speed up lip syncing. Here is a sample video of a lip sync test I made last week (audio recorded in my place, I play drums, I make animations): https://youtu.be/DB3MbDHIZOM I use PapagayoMod1.3 to create the lip sync DAT files. Papagayo can only work with a couple seconds of audio at a time, so I end up with a folder of DAT files. Here is what a DAT file looks like line by line: MohoSwitch1 1 FV 2 etcthe number is the frame #, the letters are the phoneme mouth shape. Because I am only able to create a few seconds at a time, each subsequent DAT file would be offset in the animation timeline BUT Papagayo creates each as though it started at frame #1. So, I need to strip out the first line of each DAT file, change the number on each line to the offset of that particular DAT file's placement on the timeline, write that to a new DAT file, then combine all those DAT files into a single DAT file for the current and capable Blender DAT importer to work. Originally, the plan was to create a new Blender addon, but I then realized the end result of my plan will create a single DAT file, so I will be able to simply use the current DAT importer addon as is. (I will make my own addon for more control at a later date) As it currently is, I need to import a DAT file, set the parameters, add it to the timeline, rinse, repeat. I want to have a single DAT file, as it will greatly reduce the time once I am in Blender. The number that will be added to the frame number for the offset will be taken from the filename (ie: 0234.dat to offset the frames within the file by 234 frames) This is the Python code I have right now: #run in working folder import os, csv os.makedirs('headerRemoved', exist_ok=True) #loop through files in directory for datFilename in os.listdir('.'): if not datFilename.endswith('.dat'): continue #skip non DAT files baseName = datFilename baseName = int(baseName[:-4]) #make string filename an integer print ('Removing header from ' + datFilename + '...') datRows = [] datFileObj = open(datFilename) readerObj = csv.reader(datFileObj) for row in readerObj: if readerObj.line_num == 1: continue #skip first row datRows.append(row) datFileObj.close() #write out dat file datFileObj = open(os.path.join('headerRemoved', datFilename), 'w', newline='') datWriter = csv.writer(datFileObj) for row in datRows: datWriter.writerow(row) datFileObj.close()And that is where my studies have got me so far! Okay I now have it changing the first frame # of the DAT files correctly, so that is progress! #run in working folder import os, csv os.makedirs('headerRemoved', exist_ok=True) #loop through files in directory for datFilename in os.listdir('.'): if not datFilename.endswith('.dat'): continue #skip non DAT files baseName = datFilename baseName = int(baseName[:-4]) #make string filename an integer print ('Removing header from ' + datFilename + '...') datRows = [] datFileObj = open(datFilename) readerObj = csv.reader(datFileObj) for row in readerObj: if readerObj.line_num == 1: continue #skip first row datRows.append(row) a, b = datRows[0][0].split() datRows[0][0] = '{} {}'.format(int(a)+baseName, b) datFileObj.close() #write out dat file datFileObj = open(os.path.join('headerRemoved', datFilename), 'w', newline='') datWriter = csv.writer(datFileObj) for row in datRows: datWriter.writerow(row) datFileObj.close() RE: isolating part of elemnnt in a list - Yoriz - Oct-29-2016 Could you give an example of what 3 actual DAT files would be named and contain in the format of 0000.DAT MohoSwitch1 1 FV 2 Eand then what the resulting single DAT file that had the data from the other 3 joined would look like. RE: isolating part of elemnnt in a list - trepaning - Oct-29-2016 00000.dat: MohoSwitch1 1 FV 2 L00234.dat: MohoSwitch1 1 AI 3 etc00564.dat: MohoSwitch1 1 rest 13 EFINAL.dat: 1 FV 2 L 235 AI 237 etc 565 rest 577 E The Final.DAT is not correct, as the current DAT importer for Blendet will strip out the first line, so the resulting DAT file needs to be as such: MohoSwitch1 1 FV 2 L 235 AI 237 etc 565 rest 577 E Also let me know how to properly format these code blocks, thanks. What dang button do I click? RE: isolating part of elemnnt in a list - Yoriz - Oct-29-2016 Forum help document > BBCode This code will create a single file from the .dat files in the folder import glob def yield_dat_file(file_name): with open(file_name) as file_obj: next(file_obj) for line in file_obj: frame, action = line.split() file_number, _ = file_name.split('.') yield int(file_number), int(frame), action def yield_all_dat_files(): dat_file_names = glob.glob('*.dat') for file_name in sorted(dat_file_names): for dat_row in yield_dat_file(file_name): yield dat_row def create_single_dat(): with open('FINAL.dat', 'w') as file_obj: file_obj.write('MohoSwitch1\n') for file_number, frame, action in yield_all_dat_files(): file_obj.write('{} {}\n'.format(file_number + frame, action)) create_single_dat()Final.dat MohoSwitch1 1 FV 2 L 235 AI 237 etc 565 rest 577 E RE: isolating part of elemnnt in a list - trepaning - Oct-29-2016 That absolutely does it, creating a DAT file that works perfectly in Blender and leaving the original files as they were. Straight off the top, thank you very much, that is truly amazing and I now see I can eventually create such ideas with speed and accuracy. I will continue reading the books and learning Python because I only read about the WITH keyword yesterday, so am well behind understanding what you have done, but I will get it figured out, that is not an issue. For additional fun and info, here is a screenshot of Blender showing the DAT importer GUI on the left of the window with the head (and the test Final.DAT result with accurate timeline plotting below) [Image: datImport.jpg] What I want to do with the importer is have it so: I can select a folder (Current addon only selects a file) Every DAT in the folder gets the options GUI in a stack for individual control but there is a Global option box with a radio button that turns off individual options if such fine tuning is not needed. Options can be turned on per DAT file even with Global options controlling remainder. There is one master PLOT KEYS TO TIMELINE button that iterates the entire stack. Offset is not needed if filename technique is used, but if not using filename, offset option is required per DAT file. There is one more option that would be handy but confusing to explain. Here is an attempt. Audacity is what I export the audio clips from. Audacity only displays 24 or 30 frames per second markers. The Papagayo and Blender project may be in a different frame rate, such as 12 frames per second or even 29.97fps. It is fast to note the numbers Audacity displays when exporting the audio clips and skip the little bit of math. Once the DAT is created with Papagayo and then imported into Blender, it would be useful to globally set the Audacity framerate the audio was sourced at, enter the frame # Audacity displayed, and let the Blender addon calculate the actual offset based off the project's fps. This would actually be useful even using the filename technique, as Audacity's frame number could be the filename, allowing for the project's fps to be determined later. The following is my bastardized version of the Blender addon code, posted simply for completeness of this project's original plan. Hey, it got me studying Python! Original Importer found here https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Import-Export/Lipsync_Importer bl_info = { "name": "TREPANING", "author": "blazilla", "version": (0, 5, 1), "blender": (2, 77, 0), "location": "3D window > Tool Shelf", "description": "Plot Moho (Papagayo dat) file to frames", "warning": "", "wiki_url": "", "tracker_url": "", "category": "Import-Export"} import bpy, re, os from bpy.props import * from bpy.props import IntProperty, FloatProperty, StringProperty global lastPhoneme lastPhoneme="nothing" datFile = os.listdir('C:\\dat') # ------------------------------------------------------------------------------- # reading imported file & creating keys def lipsyncer(): obj = bpy.context.object scn = bpy.context.scene f = open(scn.fpath) # importing file f.readline() # reading the 1st line that we don"t need for line in f: # removing new lines lsta = re.split("\n+", line) # building a list of frames & shapes indexes lst = re.split(":? ", lsta[0])# making a list of a frame & number frame = int(lst[0]) for key in obj.data.shape_keys.key_blocks: if lst[1] == key.name: createShapekey(key.name, frame) # creating keys with offset and eases for a phonem @ the frame def createShapekey(phoneme, frame): global lastPhoneme scn = bpy.context.scene obj = bpy.context.object objSK = obj.data.shape_keys offst = scn.offset # offset value skVlu = scn.skscale # shape key value #in case of Papagayo format if scn.regMenuTypes.enumFileTypes == '0' : frmIn = scn.easeIn # ease in value frmOut = scn.easeOut # ease out value hldIn = scn.holdGap # holding time value # inserting the In key only when phonem change or when blinking if lastPhoneme!=phoneme or eval(scn.regMenuTypes.enumModeTypes) == 1: objSK.key_blocks[phoneme].value=0.0 objSK.key_blocks[phoneme].keyframe_insert("value", -1, offst+frame-frmIn, "Lipsync") objSK.key_blocks[phoneme].value=skVlu objSK.key_blocks[phoneme].keyframe_insert("value", -1, offst+frame, "Lipsync") objSK.key_blocks[phoneme].value=skVlu objSK.key_blocks[phoneme].keyframe_insert("value", -1, offst+frame+hldIn, "Lipsync") objSK.key_blocks[phoneme].value=0.0 objSK.key_blocks[phoneme].keyframe_insert("value", -1, offst+frame+hldIn+frmOut, "Lipsync") lastPhoneme = phoneme # lipsyncer operation start class btn_lipsyncer(bpy.types.Operator): bl_idname = 'lipsync.go' bl_label = 'Start Processing' bl_description = 'Plots the voice file keys to timeline' def execute(self, context): scn = context.scene obj = context.active_object # testing if object is valid if obj!=None: if obj.type=="MESH": if obj.data.shape_keys!=None: if scn.fpath!='': lipsyncer() else: print ("select a Moho file") else: print("No shape keys") else: print ("Object is not a mesh") else: print ("Select object") return {'FINISHED'} #defining custom enumeratos class menuTypes(bpy.types.PropertyGroup): enumFileTypes = EnumProperty(items =(('0', 'Papagayo', ''), ), name = 'Choose FileType', default = '0') enumModeTypes = EnumProperty(items =(('0', 'Lipsyncer',''), ), name = 'The Mode is', default = '0') # drawing the user interface class LipSyncUI(bpy.types.Panel): bl_space_type = "VIEW_3D" bl_region_type = "TOOL_PROPS" bl_label = "Dat TREPANING LipSync Importer" newType= bpy.types.Scene newType.fpath = StringProperty(name="Import File ", description="Select your voice file", subtype="FILE_PATH") newType.skscale = FloatProperty(description="Smoothing shape key values", min=0.1, max=1.0, default=0.8) newType.offset = IntProperty(description="Offset your frames", default=0) newType.easeIn = IntProperty(description="Smoothing In curve", min=1, default=2) newType.easeOut = IntProperty(description="Smoothing Out curve", min=1, default=2) newType.holdGap = IntProperty(description="Holding for slow keys", min=0, default=3) def draw(self, context): obj = bpy.context.active_object scn = bpy.context.scene layout = self.layout col = layout.column() # showing the current object type if obj != None: if obj.type == "MESH": split = col.split(align=True) split.label(text="The active object is: ", icon="OBJECT_DATA") split.label(obj.name, icon="EDITMODE_HLT") else: col.label(text="The active object is not a Mesh!", icon="OBJECT_DATA") else: layout.label(text="No object is selected", icon="OBJECT_DATA") col.row().prop(scn.regMenuTypes, 'enumModeTypes') col.separator() # the lipsyncer panel if scn.regMenuTypes.enumModeTypes == '0': # Papagayo panel col.prop(context.scene, "fpath") split = col.split(align=True) split.label("Frame Offset :") split.prop(context.scene, "offset") #split = col.split(align=True) # split.label("Key Value :") # split.prop(context.scene, "skscale") split = col.split(align=True) split.prop(context.scene, "easeIn", "Ease In") split.prop(context.scene, "holdGap", "Hold Gap") split.prop(context.scene, "easeOut", "Ease Out") col.operator('lipsync.go', text='Plot Keys to the Timeline') # clearing vars def clear_properties(): # can happen on reload if bpy.context.scene is None: return props = ["fpath", "skscale", "offset", "easeIn", "easeOut", "holdGap"] for p in props: if p in bpy.types.Scene.bl_rna.properties: exec("del bpy.types.Scene."+p) if p in bpy.context.scene: del bpy.context.scene[p] # registering the script def register(): bpy.utils.register_module(__name__) bpy.types.Scene.regMenuTypes = PointerProperty(type = menuTypes) def unregister(): bpy.utils.unregister_module(__name__) del bpy.context.scene.regMenuTypes clear_properties() if __name__ == "__main__": register() RE: isolating part of elemnnt in a list - trepaning - Oct-30-2016 After a bit more thought, I realize the Blender addon project could be simplified by keeping the addon as is but have the selection choose a folder of DAT files, then have the addon run the code to create the Final.DAT from all the numbered DAT files in the folder, and, as a not required bonus, place that Final.DAT file into the selection field. Everything else could stay exactly as it is. A quick test shows the current addon can select a folder and fill the selection field with that folder path, even with no file selected. So, a separate button could be added that will call the Final.DAT creation code, using the folder path in the selection field as the working folder for the code. Then, the selection field can be used again to select that Final.DAT, or one could type Final.DAT into the selection field, or the code could append the folder path with the filename 'Final.DAT'. |