Last active
October 26, 2018 18:48
-
-
Save natecraddock/edc9793630bd657c801c35d1bc8a05b7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Audio Visualizer Script | |
# Load the script into blender | |
# Make sure Auto Run Python scripts is enabled in your | |
# User preferences for the drivers | |
# Enjoy! | |
import bpy | |
import bmesh | |
import mathutils | |
import time | |
import math | |
import os | |
start = time.time() | |
# Set these variables to change things | |
initial = mathutils.Vector((0.0, 0.0, 0.0)) | |
radius = 1 | |
h = 2 | |
width = 4 | |
height = 20 | |
multiplier = 5 | |
min = 20 | |
max = 20000 | |
# Place the filepath of the song here | |
# You it looks relative to the .blend file path, so save your file | |
audio_file = 'dub.ogg' | |
#mat = bpy.data.materials['color'] | |
bpy.data.scenes['Scene'].frame_current = 1 | |
def cache_audio(): | |
fp = os.path.join(os.path.dirname(bpy.data.filepath), audio_file) | |
for sound in bpy.data.sounds: | |
if sound.filepath == fp and not sound.use_memory_cache: | |
sound.use_memory_cache = True | |
def add_driver_prop(entity, type, axis, data_path, expression): | |
# Adds a driver with the custom property as the variable to the object | |
# Type.. | |
driver = entity.driver_add(type, axis) | |
driver.driver.type = 'SCRIPTED' | |
v = driver.driver.variables.new() | |
v.name = 'data' | |
v.type = 'SINGLE_PROP' | |
t = v.targets[0] | |
t.id = bpy.context.scene.objects['Audio Data'] | |
t.data_path = data_path | |
driver.driver.expression = expression | |
def add_driver_prop_mat(entity, data_path, expression): | |
# Adds a driver with the custom property as the variable to the object | |
# Type.. | |
driver = entity.data.materials[entity.data.materials[0].name].node_tree.nodes['ColorRamp'].inputs['Fac'].driver_add('default_value') | |
driver.driver.type = 'SCRIPTED' | |
v = driver.driver.variables.new() | |
v.name = 'data' | |
v.type = 'SINGLE_PROP' | |
t = v.targets[0] | |
t.id = entity | |
t.data_path = data_path | |
driver.driver.expression = expression | |
def bake_audio(object, l, h, c): | |
object['audio_data_' + str(c)] = 0.0 | |
object.keyframe_insert(data_path='["audio_data_' + str(c)+ '"]') | |
back = bpy.context.area.type | |
bpy.context.area.type = 'GRAPH_EDITOR' | |
fp = os.path.join(os.path.dirname(bpy.data.filepath), audio_file) | |
bpy.ops.graph.sound_bake(filepath=fp, low=l, high=h, release=0.5) | |
bpy.context.area.type = back | |
def create_hex_geo(r, l, h): | |
# Creates a hexagon of radius r, at location l, with height h | |
# Returns the created hexagon | |
bm = bmesh.new() | |
verts = [] | |
# Create the vertices | |
for v in range(0, 360, 60): | |
x = r * math.cos(math.radians(v)) + l.x | |
y = r * math.sin(math.radians(v)) + l.y | |
z = l.z | |
co = (x, y, z) | |
bm.verts.new(co) | |
# Create face | |
bm.faces.new(bm.verts) | |
# Extrude height | |
extrude = bmesh.ops.extrude_discrete_faces(bm, faces=bm.faces) | |
for v in extrude['faces'][0].verts: | |
v.co.z += h | |
me = bpy.data.meshes.new("Mesh") | |
bm.to_mesh(me) | |
bm.free() | |
# Add the mesh to the scene | |
scene = bpy.context.scene | |
obj = bpy.data.objects.new("audio_vis_hex", me) | |
scene.objects.link(obj) | |
scene.objects.active = obj | |
obj.select = True | |
return obj | |
bpy.ops.object.empty_add(type='PLAIN_AXES', location=(0,0,0)) | |
empty = bpy.context.active_object | |
empty.name = "Audio Data" | |
m = math.pow((max - min), (1 / height)) | |
cache_audio() | |
# Create the grid | |
x_loc = 0 | |
y_loc = 0 | |
z_loc = 0 | |
c = 0 | |
for y in range(0, height): | |
if y % 2 == 0: | |
x_loc = 0 | |
else: | |
x_loc = (radius * 3) / 2 | |
# Create the row object | |
empty["audio_data_" + str(c)] = 0.0 | |
low = math.pow(m, c) + min | |
high = math.pow(m, c + 1) + min | |
empty.select = True | |
bake_audio(empty, low, high, c) | |
for f in empty.animation_data.action.fcurves: | |
f.select = False | |
for x in range(0, width): | |
x_loc += (radius * 3) | |
z_loc = initial.z | |
loc = mathutils.Vector((x_loc, y_loc, z_loc)) | |
obj = create_hex_geo(radius, loc, h) | |
# For now, call this.. Later we can fix the creation script | |
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') | |
# Attach the baked data to the z scale and location | |
add_driver_prop(obj, 'location', 2, '["audio_data_' + str(c) + '"]', "data * " + str(multiplier)) | |
add_driver_prop(obj, 'scale', 2, '["audio_data_' + str(c) + '"]', "data * " + str(multiplier)) | |
#material = bpy.data.materials['color'].copy() | |
#obj.data.materials.append(material) | |
#node = obj.data.materials[material.name].node_tree.nodes['ColorRamp'].inputs['Fac'] | |
#add_driver_prop_mat(obj, '["audio_data_' + str(c) + ']', "data") | |
# Deselect everything | |
bpy.ops.object.select_all(action='DESELECT') | |
c += 1 | |
y_loc += math.sqrt(3) / 2 | |
# Add the music to the VSE | |
bpy.context.area.type = 'SEQUENCE_EDITOR' | |
bpy.context.scene.sequence_editor_clear() | |
bpy.ops.sequencer.sound_strip_add(filepath = os.path.join(os.path.dirname(bpy.data.filepath), audio_file), frame_start = 1) | |
bpy.context.scene.frame_end = bpy.context.sequences[0].frame_final_duration | |
#bpy.ops.time.view_all() | |
bpy.context.area.type = 'TEXT_EDITOR' | |
end = time.time() | |
print("Time elapsed:", str(end - start)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment