├── guide.tidal ├── README.md ├── customHydra.hs ├── hydra.js ├── startup.scd └── BootTidal.hs /guide.tidal: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | d0 $ slow 2 $ s "bd*<2 4 > sn*2" # hue (slow 3 $ sine) 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Tutorial de Tidal e Hydra via OSC 2 | 3 | Este es el repositorio de [ este video tutorial](https://youtu.be/t6KZ03Wp66M) 4 | 5 | Se ven 4 formas de enviar mensajes OSC de [tidalcycles](https://tidalcycles.org) a [hydra](https://hydra-editor.glitch.me/) 6 | 7 | 1. reenviar los eventos desde superdirt a hydra 8 | 2. enviar osc desde tidal tambien a hydra 9 | 3. enviar custom osc desde tidal a hydra 10 | 4. enviar los rms de los orbits desde superdirt a hydra 11 | 12 | Nota: Sólo funciona en Atom, ya que OSC no funciona en el browser. 13 | -------------------------------------------------------------------------------- /customHydra.hs: -------------------------------------------------------------------------------- 1 | -- 3. enviar custom osc desde tidal a hydra 2 | 3 | 4 | {-# LANGUAGE TypeSynonymInstances, FlexibleInstances, OverloadedStrings #-} 5 | 6 | import Sound.Tidal.Stream 7 | import Sound.Tidal.Pattern 8 | import Sound.Tidal.ParseBP 9 | import Sound.Tidal.Stream 10 | import Sound.Tidal.Context 11 | 12 | customHydra :: OSCTarget 13 | customHydra = (OSCTarget {oName = "customHydra", 14 | oAddress = "127.0.0.1", 15 | oPort = 5000, 16 | oPath = "/hue", 17 | oShape = Just [ 18 | ("hue", Just $ VF 0) 19 | ], 20 | oLatency = 0.1, 21 | oPreamble = [], 22 | oTimestamp = MessageStamp 23 | }) 24 | 25 | hue = pF "hue" 26 | -------------------------------------------------------------------------------- /hydra.js: -------------------------------------------------------------------------------- 1 | // 1. reenviar los eventos desde superdirt a hydra 2 | 3 | bd = 0 4 | msg.setPort(3333) 5 | msg.on('/bd', (args) => { 6 | bd = args[0]%1 7 | }) 8 | 9 | solid(0) 10 | .scale(()=>bd*2+1) 11 | .out() 12 | 13 | 14 | // 2. enviar osc desde tidal tambien a hydra 15 | // recibiendo de tidal los mismos 16 | // eventos que recibe superdirt 17 | bd = 0 18 | sn = 0 19 | msg.setPort(9999) 20 | msg.on('/play2', (args) => { 21 | o = {} 22 | for(let i =0;ibd) 36 | .scrollY(()=>sn) 37 | .out() 38 | 39 | 40 | // 3. enviar custom osc desde tidal a hydra 41 | hue = 0 42 | msg.setPort(5000) 43 | msg.on('/hue', (args) => { 44 | hue = args[0] 45 | }) 46 | 47 | 48 | solid(1,0,0).hue(()=>hue*3) 49 | .mult(noise(5).scale(0.1).thresh(0.8)) 50 | .out() 51 | 52 | 53 | // 4. enviar los rms de los orbits desde superdirt a hydra 54 | for(let i= 0;i<8;i++) 55 | window['d'+i] = 0 56 | msg.setPort(6666) 57 | msg.on('/rms', (args) => { 58 | // ["/rms", synthID, orbitIndex, peak1, …] 59 | const b = Buffer.from(args[0].data); 60 | const i = b.readInt32BE(20) 61 | window['d'+i] = b.readFloatBE(24) 62 | }) 63 | 64 | src(s0) 65 | .thresh(0.55) 66 | .mult(solid(0,0,1)) 67 | .scale(()=>d0+1) 68 | .out() 69 | -------------------------------------------------------------------------------- /startup.scd: -------------------------------------------------------------------------------- 1 | ( 2 | "SC_JACK_DEFAULT_INPUTS".setenv(""); 3 | "SC_JACK_DEFAULT_OUTPUTS".setenv(""); 4 | 5 | s.options.numBuffers = 1024 * 32; // increase this if you need to load more samples 6 | s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages 7 | s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes" 8 | s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary 9 | s.options.numInputBusChannels = 2; 10 | 11 | s.options.maxLogins=4; 12 | 13 | 14 | s.waitForBoot { 15 | ~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels 16 | ~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in) 17 | s.sync; 18 | // load samples (path containing a wildcard can be passed in) 19 | ~dirt.loadSoundFiles("/home/diegodorado/Music/tidal/samples/trap-samples/*"); 20 | 21 | s.sync; // wait for samples to be read 22 | ~dirt.start(57120, [0, 0, 0, 0, 0, 0, 0, 0]); 23 | s.sync; 24 | 25 | n = NetAddr("127.0.0.1", 6666); 26 | ~dirt.startSendRMS; 27 | OSCFunc({ |msg| 28 | defer { 29 | n.sendMsg("/rms", msg); 30 | } 31 | }, "/rms"); 32 | 33 | }; 34 | 35 | s.latency = 0.2; 36 | 37 | 38 | 39 | ); 40 | 41 | 42 | 43 | // 1. reenviar los eventos desde superdirt a hydra 44 | ( 45 | n = NetAddr("127.0.0.1",3333); 46 | 47 | ~dirt.receiveAction = { |e| 48 | if ( (e.at(\s)==\bd), 49 | { n.sendMsg("/bd", e.at(\cycle)); }, {} 50 | ); 51 | }; 52 | ) 53 | 54 | 55 | // 4. enviar los rms de los orbits desde superdirt a hydra 56 | ( 57 | n = NetAddr("127.0.0.1", 6666); 58 | ~dirt.startSendRMS; 59 | OSCFunc({ |msg| 60 | defer { 61 | n.sendMsg("/rms", msg); 62 | } 63 | }, "/rms"); 64 | ) 65 | -------------------------------------------------------------------------------- /BootTidal.hs: -------------------------------------------------------------------------------- 1 | :set -XOverloadedStrings 2 | :set prompt "" 3 | :set prompt-cont "" 4 | 5 | :load "customHydra.hs" 6 | 7 | import Sound.Tidal.Context 8 | 9 | -- total latency = oLatency + cFrameTimespan 10 | 11 | -- 2. enviar osc desde tidal tambien a hydra 12 | hydra = (superdirtTarget {oLatency = 0.01, oAddress = "127.0.0.1", oPort = 9999}) 13 | 14 | sc = (superdirtTarget {oLatency = 0.3, oAddress = "127.0.0.1", oPort = 57120}) 15 | 16 | -- customHydra: 3. enviar custom osc desde tidal a hydra 17 | 18 | 19 | tidal <- startMulti [customHydra,hydra, sc] (defaultConfig {cFrameTimespan = 0.1}) 20 | 21 | --tidal <- startTidal (superdirtTarget {oLatency = 0.3, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cFrameTimespan = 0.1}) 22 | 23 | 24 | :{ 25 | let p = streamReplace tidal 26 | hush = streamHush tidal 27 | list = streamList tidal 28 | mute = streamMute tidal 29 | unmute = streamUnmute tidal 30 | solo = streamSolo tidal 31 | unsolo = streamUnsolo tidal 32 | once = streamOnce tidal 33 | asap = once 34 | nudgeAll = streamNudgeAll tidal 35 | all = streamAll tidal 36 | resetCycles = streamResetCycles tidal 37 | setcps = asap . cps 38 | xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i 39 | xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i 40 | d0 = p 0 . (|< orbit 0) 41 | d1 = p 1 . (|< orbit 1) 42 | d2 = p 2 . (|< orbit 2) 43 | d3 = p 3 . (|< orbit 3) 44 | d4 = p 4 . (|< orbit 4) 45 | d5 = p 5 . (|< orbit 5) 46 | d6 = p 6 . (|< orbit 6) 47 | d7 = p 7 . (|< orbit 7) 48 | :} 49 | 50 | :{ 51 | let setI = streamSetI tidal 52 | setF = streamSetF tidal 53 | setS = streamSetS tidal 54 | setR = streamSetI tidal 55 | setB = streamSetB tidal 56 | :} 57 | 58 | setcps 1 59 | 60 | :set prompt "tidal> " 61 | --------------------------------------------------------------------------------