Problem?
When making videos, sometimes you want to add some text animations. And since not everyone has access to commercial tools like After Effects, it would be nice if a free alternative existed.
Hobbyist blog about all things software. Any correspondence of this blog's name to names of individuals, organizations, companies, products or other blogs is pure coincidence.
timer = Timer.new()timer.autostart = truetimer.one_shot = falsetimer.wait_time = 0.1timer.connect("timeout", self, "_on_timeout")add_child(timer)
extends Sprite func _ready(): get_tree().get_root().get_node("RootNode").register_dual_arg_callback("/set/xy", get_node("."), "set_xy") func set_xy(x, y): self.position.x = x self.position.y = y
(
b = NetAddr.new("127.0.0.1", 4242); // create the NetAddr b.sendMsg("/set/xy", 650, 200);
)
extends Node2D var IP_CLIENT var PORT_CLIENT var PORT_SERVER = 4242 # change me if you like! var IP_SERVER = "127.0.0.1" # change me if you like! var socketUDP = PacketPeerUDP.new() var observers = Dictionary() func register_single_arg_callback(oscaddress, node, functionname): observers[oscaddress] = [1, node, functionname] func register_dual_arg_callback(oscaddress, node, functionname): observers[oscaddress] = [2, node, functionname] func _ready(): OS.set_low_processor_usage_mode(true) start_server() func all_zeros(lst): if lst == []: return true for el in lst: if el != 0: return false return true func _process(_delta): if socketUDP.get_available_packet_count() > 0: var array_bytes = socketUDP.get_packet() #var IP_CLIENT = socketUDP.get_packet_ip() #var PORT_CLIENT = socketUDP.get_packet_port() var stream = StreamPeerBuffer.new() stream.set_data_array(array_bytes) stream.set_big_endian(true) var address_finished = false var type_finished = false var address = "" var type = ""
# parse osc address while not address_finished: for _i in range(4): var addrpart = stream.get_u8() if addrpart != 0: address += char(addrpart) if addrpart == 0: address_finished = true
# parse osc type list while not type_finished: for _i in range(4): var c = stream.get_u8() if c != 0 and char(c) != ",": type += char(c) if c == 0: type_finished = true
# decode values from the stream var values = [] for type_id in type: if type_id == "i": var intval = stream.get_32() values.append(intval) elif type_id == "f": var floatval = stream.get_float() values.append(floatval) elif type_id == "s": var stringval = "" var string_finished = false while not string_finished: for _i in range(4): var ch = stream.get_u8() if ch != 0: stringval += char(ch) else: string_finished = true values.append(stringval) elif type_id == "b": var data = [] var count = stream.get_u32() var idx = 0 var blob_finished = false while not blob_finished: for _i in range(4): var ch = stream.get_u8() if idx < count: data.append(ch) idx += 1 if idx >= count: blob_finished = true values.append(data) else: printt("type " + type_id +" not yet supported") if observers.has(address): var observer = observers[address] var number_args = observer[0] var nodepath = observer[1] var funcname = observer[2] if number_args == 1: nodepath.call(funcname, values[0]) elif number_args == 2: nodepath.call(funcname, values[0], values[1]) func start_server(): if (socketUDP.listen(PORT_SERVER) != OK): printt("Error listening on port: " + str(PORT_SERVER)) else: printt("Listening on port: " + str(PORT_SERVER)) func _exit_tree(): socketUDP.close()
~n = [60, 64, 67]; // c major chord
Quarks.install("https://github.com/shimpe/panola");
~n = Panola("c4 e4 g4").midinotePattern.asStream.all;
( s.waitForBoot({ var arp = Pbind( \instrument, \default, \midinote, Plazy { var n0, n1, n2; ~n = ~n ?? [Rest(1)]; n0 = ~n[0] ?? Rest(1); n1 = ~n[1] ?? ~n[0]; n2 = ~n[2] ?? ~n[0]; Pseq([n0, n2, n1, n2]) }, \dur, Pseq([1,1,1,1].normalizeSum*2) ); if (~player.notNil) { ~player.stop; }; ~player = Pn(arp).play; }); )
if (~player.notNil) { ~player.stop; }; // call stop if not stopped already ~player = Pn(arp).play;
~n = [60, 64, 67 ];
~n =[ 60, 65, 69 ];
~n =[ 59, 65, 67 ];
Exercise: adapt the code to make an arpeggio based on the first four notes of a list of input notes.
Exercise: adapt the code to use different durations for different notes
( s.waitForBoot({ var right, left; ~n = ~n ?? [Rest(1)]; right = Pbind( \instrument, \default, \midinote, Plazy { var n0, n1, n2; ~n = ~n ?? [Rest(1)]; n0 = ~n[0] ?? Rest(1); n1 = ~n[1] ?? ~n[0]; n2 = ~n[2] ?? ~n[0]; Pseq([ n0, n2, n1, n2 ] ++ (([ n0, n2, n1, n2 ] + 12)!2).flatten) }, \dur, Pseq([1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ].normalizeSum*2) ); left = Pbind( \instrument, \default, \midinote, Plazy { var n0, n1, n2; ~n = ~n ?? [Rest(1)]; n0 = ~n[0] ?? Rest(1); n1 = ~n[1] ?? ~n[0]; n2 = ~n[2] ?? ~n[0]; Pseq([ n0, n2, n0, n2, n0, n2, n0, n2] - 12) }, \dur, Pseq([1, 1, 1, 1, 1, 1, 1, 1].normalizeSum*2) ); if (~player.notNil) { ~player.stop; }; ~player = Pn(Ppar([right,left])).play; }); )
Exercise: define some percussion instruments and add some percussion to the fragment.
( MIDIdef.freeAll; MIDIClient.init; MIDIIn.connectAll; )
~n = ~note_table.selectIndices({|item, i| item != 0}); if (~n == []) { ~n = nil; };
( MIDIdef.freeAll; MIDIClient.init; MIDIIn.connectAll; ) ( s.waitForBoot({ var right, left; ~note_table = 0!127; MIDIdef.noteOn( \mynoteonhandler, // just a name for this handler { |val, num, chan, src| num.debug("num"); ~note_table[num] = 1; // update note table and update ~n ~n = ~note_table.selectIndices({|item, i| item != 0}).postln; } ); MIDIdef.noteOff( \mynoteoffhandler, // just a name for this handler { |val, num, chan, src| num.debug("num"); ~note_table[num] = 0; // update note table and update ~n } ); right = Pbind( \instrument, \default, \midinote, Plazy { var n0, n1, n2; ~n = ~n ?? [Rest(1)]; n0 = ~n[0] ?? Rest(1); n1 = ~n[1] ?? ~n[0]; n2 = ~n[2] ?? ~n[0]; Pxrand([ n0, n2, n1, n2 ] ++ (([ n0, n2, n1, n2 ] + 12)!2).flatten) }, \dur, Pseq([1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ].normalizeSum*2) ); left = Pbind( \instrument, \default, \midinote, Plazy { var n0, n1, n2; ~n = ~n ?? [Rest(1)]; n0 = ~n[0] ?? Rest(1); n1 = ~n[1] ?? ~n[0]; n2 = ~n[2] ?? ~n[0]; Pseq([ n0, n2, n0, n2, n0, n2, n0, n2] - 12) }, \dur, Pseq([1, 1, 1, 1, 1, 1, 1, 1].normalizeSum*2) ); if (~player.notNil) { ~player.stop; }; ~player = Pn(Ppar([right,left])).play; }); )
( s.waitForBoot({ var right, left; var n0, n1, n2; MIDIdef.freeAll; if (~midi_initialized.isNil) { MIDIClient.init; MIDIIn.connectAll; ~midi_initialized = 1; }; ~note_table = 0!127; ~n = nil; MIDIdef.noteOn( \mynoteonhandler, // just a name for this handler { |val, num, chan, src| ~note_table[num] = 1; // update note table and update ~n ~n = ~note_table.selectIndices({|item, i| item != 0}); } ); MIDIdef.noteOff( \mynoteoffhandler, // just a name for this handler { |val, num, chan, src| ~note_table[num] = 0; // update note table and update ~n /* // enable next two lines only if you want arpeggios to stop playing // when you release the midi keys ~n = ~note_table.selectIndices({|item, i| item != 0}); if (~n == []) { ~n = nil; }; */ } ); n0 = Plazy { if (~n.isNil) { Pseq([Rest(1)]); } { ~n[0] ?? Pseq([Rest(1)]); }; }; n1 = Plazy { if (~n.isNil) { Pseq([Rest(1)]); } { Pseq([~n[1] ?? ~n[0]]); }; }; n2 = Plazy { if (~n.isNil) { Pseq([Rest(1)]); } { Pseq([~n[2] ?? ~n[0]]); }; }; right = Pbind( \instrument, \default, \midinote, Pseq([ n0, n2, n1, n2] ++ (([ n0, n2, n1, n2] + 12)!2).flatten), \dur, Pseq([1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ].normalizeSum*2) ); left = Pbind( \instrument, \default, \midinote, Pseq([ n0, n2, n0, n2, n0, n2, n0, n2] - 12), \dur, Pseq([1, 1, 1, 1, 1, 1, 1, 1].normalizeSum*2) ); if (~player.notNil) { ~player.stop; }; ~player = Pn(Ppar([right,left])).play; }); )
( s.waitForBoot({ var right, left; var n0, n1, n2; var note_getter; MIDIdef.freeAll; if (~midi_initilized.isNil) { MIDIClient.init; MIDIIn.connectAll; ~midi_initialized = 1; }; ~note_table = 0!127; ~n = nil; MIDIdef.noteOn( \mynoteonhandler, // just a name for this handler { |val, num, chan, src| ~note_table[num] = 1; // update note table and update ~n ~n = ~note_table.selectIndices({|item, i| item != 0}); } ); MIDIdef.noteOff( \mynoteoffhandler, // just a name for this handler { |val, num, chan, src| ~note_table[num] = 0; // update note table and update ~n /* // only enable the following lines if you want the arpeggio to stop as soon as you release the keys ~n = ~note_table.selectIndices({|item, i| item != 0}); if (~n == []) { ~n = nil; }; */ } ); note_getter = { | index | Plazy { if (~n.isNil) { Pseq([Rest(1)]); } { ~n[index] ?? (~n[0] ?? Pseq([Rest(1)])); }; }; }; n0 = note_getter.(0); n1 = note_getter.(1); n2 = note_getter.(2); right = Pbind( \instrument, \default, \midinote, Pseq([ n0, n2, n1, n2] ++ (([ n0, n2, n1, n2] + 12)!2).flatten), \dur, Pseq([1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ].normalizeSum*2) ); left = Pbind( \instrument, \default, \midinote, Pseq([ n0, n2, n0, n2, n0, n2, n0, n2] - 12), \dur, Pseq([1, 1, 1, 1, 1, 1, 1, 1].normalizeSum*2) ); if (~player.notNil) { ~player.stop; }; ~player = Pn(Ppar([right,left])).play; }); ) )
~walsh_transform.(values:[-1,1,0,2]);we get back the expected result:
[0.5,-0.5,0,-1]And to check that the inverse transform works as expected:
~walsh_transform.(values:~walsh_transform.(values:[-1,1,0,2]), rescale:false);gives the original signal:
[-1,1,0,2].