From da1a26b895410c8bc3f27a33b5e525f14a2125ef Mon Sep 17 00:00:00 2001 From: RodZill4 Date: Mon, 24 Feb 2020 08:32:11 +0100 Subject: [PATCH] Added basic audio support --- addons/material_maker/engine/gen_audio.gd | 20 ++ addons/material_maker/engine/loader.gd | 3 +- addons/material_maker/nodes/io_types.mmt | 9 + .../material_maker/nodes/preview_sound.shader | 18 ++ material_maker/examples/audio.ptex | 264 ++++++++++++++++++ material_maker/examples/audio.ptex.import | 15 + material_maker/nodes/audio.gd | 66 +++++ material_maker/nodes/audio.tscn | 74 +++++ material_maker/nodes/debug.tscn | 4 +- .../widgets/node_editor/node_editor.gd | 1 + .../widgets/node_editor/node_editor.tscn | 2 - project.godot | 6 + 12 files changed, 478 insertions(+), 4 deletions(-) create mode 100644 addons/material_maker/engine/gen_audio.gd create mode 100644 addons/material_maker/nodes/preview_sound.shader create mode 100644 material_maker/examples/audio.ptex create mode 100644 material_maker/examples/audio.ptex.import create mode 100644 material_maker/nodes/audio.gd create mode 100644 material_maker/nodes/audio.tscn diff --git a/addons/material_maker/engine/gen_audio.gd b/addons/material_maker/engine/gen_audio.gd new file mode 100644 index 0000000..31d1133 --- /dev/null +++ b/addons/material_maker/engine/gen_audio.gd @@ -0,0 +1,20 @@ +tool +extends MMGenBase +class_name MMGenAudio + +""" +Dummy generator to get audio shaders from UI +""" + +func get_type() -> String: + return "audio" + +func get_type_name() -> String: + return "Audio" + +func get_input_defs() -> Array: + return [ { name="in", type="sound" } ] + + +func _serialize(data: Dictionary) -> Dictionary: + return data diff --git a/addons/material_maker/engine/loader.gd b/addons/material_maker/engine/loader.gd index 10f7ec4..cab71a9 100644 --- a/addons/material_maker/engine/loader.gd +++ b/addons/material_maker/engine/loader.gd @@ -72,7 +72,8 @@ func create_gen(data) -> MMGenBase: switch = MMGenSwitch, export = MMGenExport, comment = MMGenComment, - debug = MMGenDebug + debug = MMGenDebug, + audio = MMGenAudio } var generator = null for g in guess: diff --git a/addons/material_maker/nodes/io_types.mmt b/addons/material_maker/nodes/io_types.mmt index d1a8f66..4f0d301 100644 --- a/addons/material_maker/nodes/io_types.mmt +++ b/addons/material_maker/nodes/io_types.mmt @@ -79,6 +79,15 @@ "params":"p", "slot_type":3, "color":{ "r":1.0, "g":0.0, "b":1.0, "a":1.0 } + }, + { + "name":"sound", + "label":"Sound", + "type":"vec2", + "paramdefs":"vec3 t", + "params":"t", + "slot_type":4, + "color":{ "r":1.0, "g":1.0, "b":0.0, "a":1.0 } }, { "name":"any", diff --git a/addons/material_maker/nodes/preview_sound.shader b/addons/material_maker/nodes/preview_sound.shader new file mode 100644 index 0000000..93493f0 --- /dev/null +++ b/addons/material_maker/nodes/preview_sound.shader @@ -0,0 +1,18 @@ +vec2 __sound(vec3 uv) { + $(code) + return $(value); +} + +void fragment() { + vec3 uv = UV.xxx; + vec2 smin = vec2(1.0); + vec2 smax = vec2(-1.0); + for (int i = -5; i <=5; ++i) { + vec2 s = __sound(vec3(UV.x+float(i)/5.0/preview_size)); + smin = min(s, smin); + smax = max(s, smax); + } + vec2 y = vec2((0.5-UV.y)*2.1); + vec2 color = step(smin, y+4.0/preview_size)*step(y-4.0/preview_size, smax); + COLOR = vec4(color, max(color.x, color.y), 1.0); +} diff --git a/material_maker/examples/audio.ptex b/material_maker/examples/audio.ptex new file mode 100644 index 0000000..c9bcd72 --- /dev/null +++ b/material_maker/examples/audio.ptex @@ -0,0 +1,264 @@ +{ + "connections": [ + { + "from": "206_2", + "from_port": 0, + "to": "206_2_2", + "to_port": 0 + }, + { + "from": "206_2_2", + "from_port": 0, + "to": "206", + "to_port": 0 + }, + { + "from": "206_2_2", + "from_port": 0, + "to": "audio", + "to_port": 0 + } + ], + "label": "Graph", + "name": "59", + "node_position": { + "x": 0, + "y": 0 + }, + "nodes": [ + { + "name": "Material", + "node_position": { + "x": 184, + "y": -37 + }, + "parameters": { + "albedo_color": { + "a": 1, + "b": 1, + "g": 1, + "r": 1, + "type": "Color" + }, + "ao_light_affect": 1, + "depth_scale": 1, + "emission_energy": 1, + "metallic": 1, + "normal_scale": 1, + "roughness": 1, + "size": 11, + "subsurf_scatter_strength": 0 + }, + "type": "material" + }, + { + "name": "206", + "node_position": { + "x": -438.5, + "y": -376 + }, + "parameters": { + "attack": 0, + "decay": 0.4, + "release": 0.4, + "sustain": 0.25 + }, + "shader_model": { + "code": "", + "global": "float enveloppe(float time, float attack, float decay, float sustain, float release) {\n\tfloat rv = 0.0;\n\tif (time < attack) {\n\t\trv = time/attack;\n\t} else if (time < attack+decay) {\n\t\trv = 1.0-(1.0-sustain)*(time-attack)/(decay);\n\t} else {\n\t\trv = sustain-sustain*(time-attack-decay)/(release);\n\t}\n\treturn clamp(rv, 0.0, 1.0);\n}", + "inputs": [ + { + "default": "vec2(0.0)", + "label": "", + "name": "in", + "type": "sound" + } + ], + "instance": "", + "name": "Enveloppe", + "outputs": [ + { + "sound": "$in($uv)*enveloppe($uv.y, $attack, $decay, $sustain, $release)", + "type": "sound" + } + ], + "parameters": [ + { + "control": "None", + "default": 0.2, + "label": "Attack", + "max": 10, + "min": 0, + "name": "attack", + "step": 0.01, + "type": "float" + }, + { + "control": "None", + "default": 0.5, + "label": "Decay", + "max": 10, + "min": 0, + "name": "decay", + "step": 0.01, + "type": "float" + }, + { + "control": "None", + "default": 0.5, + "label": "Sustain", + "max": 1, + "min": 0, + "name": "sustain", + "step": 0.01, + "type": "float" + }, + { + "control": "None", + "default": 2, + "label": "Release", + "max": 10, + "min": 0, + "name": "release", + "step": 0.01, + "type": "float" + } + ] + }, + "type": "shader" + }, + { + "name": "206_2", + "node_position": { + "x": -432.5, + "y": -488 + }, + "parameters": { + "frequency": 930.2, + "type": 0 + }, + "shader_model": { + "code": "", + "global": "", + "inputs": [ + + ], + "instance": "", + "name": "Wave", + "outputs": [ + { + "sound": "vec2($type)", + "type": "sound" + } + ], + "parameters": [ + { + "default": 3, + "label": "Type", + "name": "type", + "type": "enum", + "values": [ + { + "name": "Sine", + "value": "sin($frequency*$uv.x*6.28)" + }, + { + "name": "Rect", + "value": "2.0*step(fract($frequency*$uv.x), 0.5)-1.0" + }, + { + "name": "Sawtooth", + "value": "2.0*fract($frequency*$uv.x)-1.0" + }, + { + "name": "Triangle", + "value": "4.0*abs(fract($frequency*$uv.x)-0.5)-1.0" + } + ] + }, + { + "control": "None", + "default": 440, + "label": "Frequency", + "max": 22000, + "min": 0, + "name": "frequency", + "step": 0.1, + "type": "float" + } + ] + }, + "type": "shader" + }, + { + "name": "audio", + "node_position": { + "x": -380.958374, + "y": -205.208374 + }, + "parameters": { + + }, + "seed_value": 8978, + "type": "audio" + }, + { + "name": "206_2_2", + "node_position": { + "x": -143.958374, + "y": -463.508362 + }, + "parameters": { + "amplitude": 0.056, + "speed": 0.98 + }, + "shader_model": { + "code": "", + "global": "", + "inputs": [ + { + "default": "0.0", + "label": "", + "name": "in", + "type": "sound" + } + ], + "instance": "", + "name": "Sine", + "outputs": [ + { + "sound": "$in(vec3($uv.x*(1.0+$amplitude*sin($uv.y*$speed*6.28318530718)/$uv.y), $uv.yz))", + "type": "sound" + } + ], + "parameters": [ + { + "control": "None", + "default": 0.1, + "label": "Amplitude", + "max": 0.5, + "min": 0, + "name": "amplitude", + "step": 0.001, + "type": "float" + }, + { + "control": "None", + "default": 2, + "label": "Speed", + "max": 20, + "min": 0, + "name": "speed", + "step": 0.01, + "type": "float" + } + ] + }, + "type": "shader" + } + ], + "parameters": { + + }, + "type": "graph" +} \ No newline at end of file diff --git a/material_maker/examples/audio.ptex.import b/material_maker/examples/audio.ptex.import new file mode 100644 index 0000000..1a1aba3 --- /dev/null +++ b/material_maker/examples/audio.ptex.import @@ -0,0 +1,15 @@ +[remap] + +importer="material_maker.import" +type="SpatialMaterial" +path="res://.import/audio.ptex-9e2c2e20f2d1e2d6957feaedacaf2a96.tres" + +[deps] + +source_file="res://material_maker/examples/audio.ptex" +dest_files=[ "res://.import/audio.ptex-9e2c2e20f2d1e2d6957feaedacaf2a96.tres" ] + +[params] + +render=false +scale=1.0 diff --git a/material_maker/nodes/audio.gd b/material_maker/nodes/audio.gd new file mode 100644 index 0000000..53d42cc --- /dev/null +++ b/material_maker/nodes/audio.gd @@ -0,0 +1,66 @@ +extends MMGraphNodeBase + +onready var playback = $AudioStreamPlayer.get_stream_playback() + +var samples_played = 0 + +func _ready(): + set_process(false) + +func set_generator(g) -> void: + .set_generator(g) + generator.connect("parameter_changed", self, "on_parameter_changed") + on_parameter_changed(null, null) + +func on_parameter_changed(p, v): + $Timer.start() + +func update_shader(): + var src = generator.get_source(0) + var result = { code="", sound="vec2(0.0)", globals=[] } + if src != null: + var context : MMGenContext = MMGenContext.new() + result = src.generator.get_shader_code("vec3(s2ttime(UV))", src.output_index, context) + while result is GDScriptFunctionState: + result = yield(result, "completed") + var code : String = "shader_type canvas_item;\n" + code += "render_mode blend_disabled;\n" + code += "uniform float start_time = 0.0;\n" + code += "const float buffer_size = 64.0;\n" + code += "float s2ttime(vec2 uv) {\nreturn start_time+(floor(uv.x*buffer_size)+buffer_size*floor(uv.y*buffer_size))/44100.0;\n}\n" + code += "vec4 au2tex(vec2 s) {\nvec2 v = floor((0.5+0.5*s)*65536.0);\nvec2 vl = mod(v, 256.0)/255.0;\nvec2 vh = floor(v/256.0)/255.0;\nreturn vec4(vh.x, vl.x, vh.y, vl.y);\n}\n" + for g in result.globals: + code += g + code += "void fragment() {\n" + code += result.code; + code += "COLOR = au2tex("+result.sound+");" + code += "}" + $ViewportContainer/Viewport/ColorRect.material.shader.code = code + samples_played = 0 + $ViewportContainer/Viewport/ColorRect.material.set_shader_param("start_time", 0.0) + +func _on_Button_pressed(): + if $AudioStreamPlayer.playing: + $AudioStreamPlayer.stop() + set_process(false) + $Button.text = "Play" + else: + update_shader() + samples_played = 0 + $ViewportContainer/Viewport/ColorRect.material.set_shader_param("start_time", 0.0) + $AudioStreamPlayer.play() + set_process(true) + $Button.text = "Stop" + +func _process(delta): + var image = $ViewportContainer/Viewport.get_texture().get_data() + var to_fill = min(playback.get_frames_available(), image.data.width*image.data.height) + var i : int = 0 + for j in range(to_fill): + var left = (image.data.data[i]+image.data.data[i+1]/256.0)/128.0-1.0 + var right = (image.data.data[i+2]+image.data.data[i+3]/256.0)/128.0-1.0 + playback.push_frame(Vector2(left, right)) + i += 4 + samples_played += to_fill + $ViewportContainer/Viewport/ColorRect.material.set_shader_param("start_time", samples_played/44100.0) + diff --git a/material_maker/nodes/audio.tscn b/material_maker/nodes/audio.tscn new file mode 100644 index 0000000..273d1fb --- /dev/null +++ b/material_maker/nodes/audio.tscn @@ -0,0 +1,74 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://material_maker/nodes/audio.gd" type="Script" id=1] + +[sub_resource type="AudioStreamGenerator" id=1] +buffer_length = 0.1 + +[sub_resource type="Shader" id=2] +resource_local_to_scene = true + +[sub_resource type="ShaderMaterial" id=3] +resource_local_to_scene = true +shader = SubResource( 2 ) + +[node name="Audio" type="GraphNode"] +margin_right = 96.0 +margin_bottom = 115.0 +title = "Audio" +show_close = true +slot/0/left_enabled = true +slot/0/left_type = 4 +slot/0/left_color = Color( 1, 1, 0, 1 ) +slot/0/right_enabled = false +slot/0/right_type = 0 +slot/0/right_color = Color( 1, 1, 1, 1 ) +slot/1/left_enabled = false +slot/1/left_type = 0 +slot/1/left_color = Color( 1, 1, 1, 1 ) +slot/1/right_enabled = false +slot/1/right_type = 0 +slot/1/right_color = Color( 1, 1, 1, 1 ) +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false, +"_editor_description_": "" +} + +[node name="Button" type="Button" parent="."] +margin_left = 16.0 +margin_top = 24.0 +margin_right = 80.0 +margin_bottom = 44.0 +text = "Play" + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] +stream = SubResource( 1 ) + +[node name="ViewportContainer" type="ViewportContainer" parent="."] +margin_left = 16.0 +margin_top = 45.0 +margin_right = 80.0 +margin_bottom = 109.0 +rect_min_size = Vector2( 64, 64 ) +mouse_filter = 2 + +[node name="Viewport" type="Viewport" parent="ViewportContainer"] +size = Vector2( 64, 64 ) +transparent_bg = true +handle_input_locally = false +usage = 0 +render_target_v_flip = true +render_target_update_mode = 3 + +[node name="ColorRect" type="ColorRect" parent="ViewportContainer/Viewport"] +material = SubResource( 3 ) +margin_right = 64.0 +margin_bottom = 64.0 +rect_min_size = Vector2( 64, 64 ) + +[node name="Timer" type="Timer" parent="."] +wait_time = 0.1 +one_shot = true +[connection signal="pressed" from="Button" to="." method="_on_Button_pressed"] +[connection signal="timeout" from="Timer" to="." method="update_shader"] diff --git a/material_maker/nodes/debug.tscn b/material_maker/nodes/debug.tscn index d60ec05..d5103c9 100644 --- a/material_maker/nodes/debug.tscn +++ b/material_maker/nodes/debug.tscn @@ -2,7 +2,6 @@ [ext_resource path="res://material_maker/nodes/debug.gd" type="Script" id=1] - [node name="Debug" type="GraphNode"] margin_right = 124.0 margin_bottom = 49.0 @@ -15,6 +14,9 @@ slot/0/right_enabled = false slot/0/right_type = 0 slot/0/right_color = Color( 1, 1, 1, 1 ) script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} [node name="Button" type="Button" parent="."] margin_left = 16.0 diff --git a/material_maker/widgets/node_editor/node_editor.gd b/material_maker/widgets/node_editor/node_editor.gd index fea99af..fe283a8 100644 --- a/material_maker/widgets/node_editor/node_editor.gd +++ b/material_maker/widgets/node_editor/node_editor.gd @@ -86,6 +86,7 @@ func _on_Apply_pressed() -> void: emit_signal("node_changed", get_model_data()) func _on_OK_pressed() -> void: + print("OK pressed") emit_signal("node_changed", get_model_data()) queue_free() diff --git a/material_maker/widgets/node_editor/node_editor.tscn b/material_maker/widgets/node_editor/node_editor.tscn index 9686391..a277d92 100644 --- a/material_maker/widgets/node_editor/node_editor.tscn +++ b/material_maker/widgets/node_editor/node_editor.tscn @@ -4,8 +4,6 @@ [ext_resource path="res://material_maker/widgets/node_editor/node_editor_item_list.gd" type="Script" id=2] [ext_resource path="res://material_maker/icons/icons.svg" type="Texture" id=3] - - [sub_resource type="AtlasTexture" id=1] flags = 4 atlas = ExtResource( 3 ) diff --git a/project.godot b/project.godot index 2bd16b2..e59eeec 100644 --- a/project.godot +++ b/project.godot @@ -14,6 +14,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://material_maker/widgets/float_edit.gd" }, { +"base": "MMGenBase", +"class": "MMGenAudio", +"language": "GDScript", +"path": "res://addons/material_maker/engine/gen_audio.gd" +}, { "base": "Node", "class": "MMGenBase", "language": "GDScript", @@ -141,6 +146,7 @@ _global_script_classes=[ { } ] _global_script_class_icons={ "MMFloatEdit": "", +"MMGenAudio": "", "MMGenBase": "", "MMGenBuffer": "", "MMGenComment": "",