Skip to content

stephanpieterse/pyblend-animidi

Repository files navigation

PyBlend - ANIMIDI

This is a standalone python script generator inspired by Animusic.

It generates a script that is to be used in Blender, which populates the NLA with actions specified in the config file according to the events in a MIDI file. It can also generate a single consolidated action that transitions nicely for things like armatures.

MIDI Type 1 files are semi supported and tested. Type 0 and 2 files should work, but are not tested.

CSV files have been tested in the format made by midicsv.

Licence

 Copyright (C) 2021 Stephan Pieterse

    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 3 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, see .

Quick Usage

  • Write or get a song.
  • Generate MIDI and or a CSV file for it.
  • Create a blender file with basic animations that are properly labelled.
  • Get a nice visual idea and make it in blender.
  • Edit the config file to match the settings of your blender project. It can be a bit labour intensive, be sure to stay focused. Things are case sensitive.
  • Run the script in python (via command line or whatever preference)
python pyblend-animidi -c yourconfigfile.yml
  • In Blender, run the following in the interactive console: bpy.utils.execfile('/home/foo/bar/testscript.py') with your own filepath.
  • Alternatively, open the script in the text editor. Alt + P to run it, or press "Run Script"

Notes on the Blender project

Terminology

In the code, the object that is being animated is called a / the "guy". Guys don't have to exist in Blender but their settings do.

Config File

Config file is a yaml file, it should be fairly self explanatory and commented in the default config too. (config.example.yaml)
Please make sure of your indentation by checking the default config as well

midifile:
    # name of the input file to parse.
    name: "/home/stephan/dev/pyblend-animidi/test/test2.csv"
    # this can either be a csv or midi
    mode: csv

scriptOutput:
    # where to put the resulting script.
    name: "/home/stephan/dev/pyblend-animidi/test/testscript.py"

options:
    # the framerate in your blender file
    blendFramerate: 50
    # the frame range. the script won't calculate anything outside of this range.
    frameStart: 0
    frameEnd: 1000
    # instead of describing each action here, you can use an autonaming structure that you named in your blender file.
    useAutoGeneratedNames: False
    # you could use any seperator that doesn't make blender complain. underscores and periods are a safe bet.
    # valid actiontypes in your blender naming are:
    #   PRENOTE, NOTE, ATTACK, RELEASE, VIBRATO, WAIT, REST
    # at this point in time, if any action does not exist in blender, it will throw an error and fail
    # so use autonaming only for objects that have all action types!
    autoActionNameFormat: $objectname$.$actiontype$.$note$.$velocity$
    # the default time in ms to hold a note if no note end was found
    noteOffDefaultTime: 64

blenderobjects:
    # you put the guys in here

Cycle Sequences:

 cycle_sequences:
    # a name for the sequence, can be anything
    bassGuy:
        # a collection of objects. these must exist in the blenderObjects (guys) section. comma-seperated
        cycle_objects: armDing, armDing2
        # the channel that the sequence operates from. overrides guy config.
        channel: 2 

Guys

# this is a guy. there can be many guys.
piano_s:
        objectOptions:
            # object, material, shapekey, light, mat_nodes, particles, world, scene, camera.
            # object should also be used for armature.
            # constraints and modifiers, along with force fields and cloths etc. seem to all use the normal object action.
            objectType: shapekey
            # should the script create a duplicate of this object to animate? see animusic
            shouldCreate: False
            # should the script disable the object for rendering when the animation is complete
            destroyWhenDone: True
            # ADD, MULTIPLY, SUBTRACT, REPLACE
            defaultNLABlend: REPLACE
            # NOTHING, HOLD, HOLD_FORWARD
            defaultNLAHold: NOTHING
            defaultNLAAutoBlend: False
            # if the note is not animated in the config, use the default or skip it
            noDefaultAction: False
            # instead of using the nla to animate, create a new single action with the right keyframes.
            createNewAction: True
            # specified in milliseconds. can be negative. integers only
            objectDelay = 0
            # if this is True, the cycle_sequences section will be read and used along with the blenderObjects
            parseCycleSequences: True

        soundOptions:
            # until i can read this from the midi file, you can specify the values for each guys sound here. useful. specify all in milliseconds
            attack: 10
            release: 150
            vibratoRate: 0
            vibratoDelay: 1000
            # if this is specified, all note lengths will be set to this for this guy. if is present the script will assume you want it.
            overrideNoteLength: 250

        #this is the name of the object in blender. it should exist.
        name: Key
        # the midi channel that this guy plays. In CSV mode, this is the track
        channel: 1
        # the action to perform when nothing is happening.
        restAction: KeyAction
        # here you specify actions for different notes, if you leave out any the script will use the default. default is mandatory.
        notes:
            e4:
                attackAction: atta
                noteAction: KeyAction
                releaseAction: rele
                vibratoAction: vibr
            a5:
                attackAction: atta
                noteAction: KeyAction.001
                releaseAction: rele
                vibratoAction: vibr
            b4:
                noteAction: KeyAction.002
            d3:
                noteAction: KeyAction.001
            f3:
                noteAction: KeyAction.002
            c5:
                noteAction: KeyAction
            default:
                attackAction: atta
                noteAction: KeyAction.002
                releaseAction: rele
                vibratoAction: vibr

A Note on Actions

The formation of the actions is pretty much that of the sound.
prenote -> attack -> note -> (vibrato) -> release

For non-musical uses, only the note action is required, so you can use that.

Multiple Limbs on Guys

If you want one guy to do something that looks polyrhythmic (think two handed drumming) it'll be best to map each limb out to a different midi channel and link the actions appropriately. Or for basic stuff you can use cycling objects.

Cycling Objects

If you want to cycle the actions on a channel between objects, you can enable the cycle sequence parsing.
This will change which objects is being sent an action, one for each. Think alternating drumsticks on a drum.
If an object is in a cycle sequence, it's normal config channel will be ignored, and it will only be sent data from the channel specified in the cycle options.

Notes

Save a copy of your blend file befire doing anything. This is supposed to be non-destructive but I don't know how you'll use it.
To ensure everything should work fine, in the NLA editor, after creating all your actions, make sure everything has a fake user and is unlinked from the objects.
All note actions should have atleast 2 keyframes (time-wise), as this prevents odd behaviour with time / scaling. They can be one frame apart.
After the script ran in blender, go to the fcurve window, select all the objects, grab a single handle, move it a bit and then cancel. This recalculates the handles. I had a fix but it started deleting keyframes, and there is a fix in the newer versions of Blender apparently, but i want to keep it slightly backwards compatible.
Material and Shapekey and some other actions aren't that obvious to find, but they can be done from the NLA editor or the Outliner.

Troubleshooting

There is very limited error checking currently built into the script, but some sane default values. If it's not working, or not as expected, check the following:

  • Config file valid syntax
  • Config file correct naming and structure (Things are case sensitive!)
  • Blender objects and animations exist and have correct names
  • All Blender actions are fake usered and unlinked from objects.
  • Blender might also just exit if it ran out of memory.
  • Check the output script. If there are no START_ACTION or END_ACTION comments, there was no data parsed

I need more channels!

If one midi file doesn't have enough channels for you, create another instance with a new config and another midi file containing the rest of the channels.
The script can parse multiple config files from one instance.
This just outputs a script which blender reads. so it's pretty stackable.

I need more speed!

From python, generating a script to be used can take a few minutes.
From blender, running the script (which usually is a few thousand lines) could take anything from a few seconds to a couple of minutes.
Try importing for one channel at a time, or limiting the frame range you want animated to test everything out before running the full script.

Future Development

I am looking at building this into a full fledged Blender plugin, where everything can be managed from inside Blender.
Different animations / variations of them based on velocity.
Cutting vibrato animations instead of scaling them for more realism.

Technology Used

Bug reporting

Create an issue on GitHub.
If you think you have found a bug, you might need to submit the blend file, the midi / csv file, as well as the config file via e-mail, but this should only be for really strange errors.

About

A python script to interact with blender to easily create animations from MIDI or CSV files.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published