>> Название клавиш должно начинаться с названия инструмента, а заканчиваться буквами, соответствующими ноте, например: "Piano_C2". ... это хорошая идея ...>> Только, не создаём action для каждой ноты, а создаём анимацию каждого объекта - клавиши3д.... каким образом узнать какой тип анимации нужно создать по указанной ноте для конкретного объекта - клавиши3д? ...
>> Твой код очень подходит для клавишных инструментов, и файл .blend , который ты предоставил, это хорошо демонстрирует.... в том файле не было кода который создавал анимацию, там был код который создавал копии действия и расставлял эти действия в нужные места ...... поэтому вопрос остаётся открытым - каким образом узнать какой тип анимации (или какую анимацию) нужно создать по указанной ноте для конкретного объекта - клавиши3д? ...
>> Location по Z.... на какую величину, какой формы? ...
tree = ET.parse(self.filepath) node = tree.getroot() for head in node.findall('song'): for child_song in head.findall('trackcontainer'): for child_trackcontainer in child_song.findall('track'): for child_track in child_trackcontainer.findall('pattern'): for child_pattern in child_track.findall('note'): print(child_pattern)
def mmp_parse(node): if node.tag=='pattern': notes={} for note in node: key = note.attrib['key'].zfill(3) if not (key in notes): notes[key] = [] note=(int(note.attrib['pos']), int(note.attrib['len']), int(note.attrib['vol'])) notes[key].append(note) if len(notes)>0: return [{'name':node.attrib['name'], 'pos':int(node.attrib['pos']), 'len':int(node.attrib['len']), 'notes':notes}] return [] patterns = [] for child in node: patterns.extend(mmp_parse(child)) return patterns
>>Чтобы было понятней, вот словарь, написанный для одной октавы:... кстати, ты сможешь сделать весь словарь ...
notes_data = { 0: ["До_4","c4","C4"], 1: ["До_диез_4","Ре_бемоль_4","cis4","des4","C-sharp4","D-flat4"], 2: ["Ре_4","d4","D4"], 3: ["Ре_диез_4","Ми_бемоль_4","dis4","es4","D-sharp4","E-flat4"], 4: ["Ми_4","e4","E4"], 5: ["Фа_4","f4","F4"], 6: ["Фа_диез_4","Соль_бемоль_4","fis4","ges4","F-sharp4","G-flat4"], 7: ["Соль_4","g4","G4"], 8: ["Соль_диез_4","Ля_бемоль_4","gis4","as4","G-sharp4","A-flat4"], 9: ["Ля_4","a4","A4"], 10: ["Ля_диез_4","Си_бемоль_4","ais4","b4","A-sharp4","B-flat4"], 11: ["Си_4","h4","B4"]}notes = {}for o in range(9): for i in range(12): key = i + (o*9) a=notes_data[i] n = [] for s in a: s = s.replace("4","%s"%o) n.append(s) notes[key] = nprint(notes)
bpm = None for head in node.findall('head'): if 'bpm' in head.attrib: bpm = int(head.attrib['bpm']) if not bpm: for child in head.findall('bpm'): if 'value' in child.attrib: bpm = int(child.attrib['value'])
def data_from_mmp(path,name): filename=path+name+'.mmp' node = mmp_load(filename) bpm = 120 elem = node.find('.//head') if elem: if 'bpm' in elem.attrib: bpm = int(elem.attrib['bpm']) else: elem = node.find('.//bpm') bpm = int(elem.attrib['value']) return {'tempo':bpm, 'patterns':mmp_parse(node)}
# ##### BEGIN GPL LICENSE BLOCK ####### This program is free software; you can redistribute it and/or# modify it under the terms of the GNU General Public License# as published by the Free Software Foundation; either version 2# of the License, or (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software Foundation,# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.## ##### END GPL LICENSE BLOCK #####import os, subprocessimport bpyfrom bpy.props import *from bpy_extras.io_utils import ImportHelperimport xml.etree.ElementTree as ETbl_info = { "name": "Import LMMP Pattern to Scene (.mmp)", "author": "blender-3d.ru/forum", "version": (0, 0, 1), "blender": (2, 78, 0), "location": "File > Import > LMMP Pattern to Scene(.mmp)", "description": "Imports LMMP files as a series of animation properties", "category": "Import-Export",}"""This script imports LMMP files into 3D Scenes (.mmp)"""def fingers_item_callback(self, context): ob = context.object items = [("1", "1", ""), ("2", "2", ""), ("3", "3", ""), ("4", "4", ""), ("5", "5", "")] if ob.instrument_type == 'guitar': items = [("b", "B", ""), ("1", "1", ""), ("2", "2", ""), ("3", "3", ""), ("4", "4", "")] return itemsclass MusicPatternSettings(bpy.types.PropertyGroup): @classmethod def register(cls): bpy.types.TextCurve.music_pattern = PointerProperty( name="Music Pattern Settings", description="", type=cls, ) autocreate = BoolProperty() midi_data_object = StringProperty() musician_instrument = bpy.props.EnumProperty( name="Musician or Instrument", items=( ("instrument", "Instrument", ""), ("musician", "Musician", "")), default="instrument") instrument_type = bpy.props.EnumProperty( name="Instrument Type", items=( ("bowed", "Bowed Strings", ""), ("brass", "Brass Instruments", ""), ("guitar", "Guitar family", ""), ("keyboard", "Keyboard instruments", ""), ("percussion", "Percussion instruments", ""), ("woodwind", "Woodwind", "")), default="keyboard") @classmethod def unregister(cls): del bpy.types.TextCurve.music_patternclass NoteSettingItem(bpy.types.PropertyGroup): name = bpy.props.StringProperty() index = bpy.props.IntProperty() volume = bpy.props.IntProperty() position = bpy.props.IntProperty() duration = bpy.props.IntProperty() hands = bpy.props.EnumProperty( name="Hands", items=( ("left", "Left", ""), ("right", "Right", ""), ("both", "Both", "")), default="right") left_hand = bpy.props.EnumProperty( name="motion_left_hand", items=( ("up", "Up", ""), ("down", "Down", ""), ("blow", "Blow", ""), ("fingers", "Fingers", "")), default="blow") fingers_left = bpy.props.EnumProperty( name="Fingers Left Hand", items=fingers_item_callback) finger_connect_left = bpy.props.BoolProperty() right_hand = bpy.props.EnumProperty( name="motion_right_hand", items=( ("up", "Up", ""), ("down", "Down", ""), ("blow", "Blow", ""), ("fingers", "Fingers", "")), default="blow") fingers_right = bpy.props.EnumProperty( name="Fingers Right Hand", items=fingers_item_callback) finger_connect_right = bpy.props.BoolProperty()class View3DPanel(): bl_space_type = 'VIEW_3D' bl_region_type = 'TOOLS'class VIEW3D_PT_lmms(View3DPanel, bpy.types.Panel): bl_category = "Animation" bl_context = "objectmode" bl_label = "Musicians Animation with LMMS" def draw(self, context): ob=context.object note = 0 if ob and ob.type == 'FONT' and len(ob.data.notes) > 0: layout = self.layout layout.prop_search(ob,"midi_data_object",context.blend_data,'objects',text='Musician') layout.prop(ob,"auto") ctx = ob.data.notes[note] #develop layout.prop(ctx,"name") layout.prop(ctx,"volume") layout.prop(ctx,"position") layout.prop(ctx,"duration") layout.label('Hands:') layout.prop(ctx,"hands",expand = True) if ctx.hands in {'left','both'}: layout.label('Left hand:') layout.prop(ctx,"left_hand",expand = True) if ctx.left_hand in {'fingers'}: box = layout.box() box.label('Fingers left hand') box.prop(ctx,"fingers_left",text="1") box.prop(ctx,"finger_connect_left",text="Leave Pressed") if ctx.hands in {'right','both'}: layout.label('Right hand:') layout.prop(ctx,"right_hand",expand = True) if ctx.right_hand in {'fingers'}: box = layout.box() box.label('Fingers right hand') box.prop(ctx,"fingers_right",text="1") box.prop(ctx,"finger_connect_right",text="Leave Pressed") scale = 1offset = 0scene = Nonestartframe = 0class LMMPPatternToScene(bpy.types.Operator, ImportHelper): bl_idname = "import.lmmp_pattern_to_scene" bl_label = "LMMP Pattern to Scene" bl_description = "Imports notes from LMMP files into 3D Scenes" bl_options = {'REGISTER', 'UNDO'} filename_ext = {".mmp"} filter_glob = StringProperty( default="*.mmp", options={'HIDDEN'}, ) Offset = FloatProperty(name="Offset Frame", description="Offset frame", min=0, default=1) DefaultTicksPerTact = FloatProperty(name="Default Ticks Per Tact", description="Default ticks per tact", min=16, default=192) def draw(self, context): layout = self.layout box = layout.box() box.label('LMMP Pattern:', icon='SORTSIZE') box.prop(self, 'Offset') box.prop(self, 'DefaultTicksPerTact') def execute(self, context): scene = context.scene fps = scene.render.fps layers = 20*[False] layers[0]=True tree = ET.parse(self.filepath) node = tree.getroot() bpm = None for head in node.findall('head'): if 'bpm' in head.attrib: bpm = int(head.attrib['bpm']) if not bpm: for child in head.findall('bpm'): if 'value' in child.attrib: bpm = int(child.attrib['value']) scale = 60/bpm/(self.DefaultTicksPerTact/4)*fps location = 0 for head in node.findall('song'): for child_song in head.findall('trackcontainer'): for child_trackcontainer in child_song.findall('track'): for child_track in child_trackcontainer.findall('pattern'): tname=child_track.attrib['name'] tpos=int(child_track.attrib['pos']) tlen=int(child_track.attrib['len']) bpy.ops.object.text_add(location=(0, 0, location), layers=layers) ob = bpy.context.object ob.data.body = tname ob.name = tname location += 0.1 for pnote in child_track.findall('note'): note = ob.data.notes.add() key=pnote.attrib['key'] pos=int(pnote.attrib['pos']) len=int(pnote.attrib['len']) vol=int(pnote.attrib['vol']) note.name = note.index = note.volume = note.position = note.duration = return {'FINISHED'}def menu_func(self, context): self.layout.operator(LMMPPatternToScene.bl_idname, text="LMMP Pattern to Scene (.mmp)", icon='PLUGIN')def register(): bpy.utils.register_module(__name__) bpy.types.INFO_MT_file_import.append(menu_func) bpy.types.TextCurve.notes = bpy.props.CollectionProperty(type=NoteSettingItem)def unregister(): bpy.utils.unregister_module(__name__) bpy.types.INFO_MT_file_import.remove(menu_func) del bpy.types.TextCurve.notesif __name__ == "__main__": register()