Always-on computer music
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

83 lines
2.7KB

  1. // SVNVimStart
  2. s = Server.local;
  3. s.waitForBoot {
  4. var module, msg, modules;
  5. // Connect to OSC
  6. thisProcess.openUDPPort(5005);
  7. n = NetAddr.new("0.0.0.0", 5005);
  8. o = OSCFunc({ arg msg, time, addr, recvPort; [msg, time, addr, recvPort].postln; }, '/radio', n);
  9. // Create the synth definition and load it
  10. module = SynthDef.new(\module, {
  11. arg hue, saturation, value, pan, gain, octave, notefreq;
  12. var oscillator, noise, filter, panner, mixer, frequency, qfactor, lagtime, output, amplitude;
  13. // Dynamic time of the module
  14. lagtime = 100 / (2**octave);
  15. // Oscillator/filter frequency
  16. frequency = notefreq * (1 + (hue*0.01));
  17. //frequency = (130 + (hue * 130)) * (2 ** octave);
  18. //frequency = 130 * Scale.major.ratios[(hue * 12).asInteger];
  19. //frequency = (130 * frequency) * (2**octave);
  20. frequency = Lag.kr(frequency, lagtime/100);
  21. // Filtered saw oscillator
  22. oscillator = Mix.ar([SawDPW.ar(frequency), SawDPW.ar(frequency/2+0.5)]);
  23. filter = DFM1.ar(oscillator, frequency, saturation/2, 1.0, 0.0, 0.0006);
  24. // Noise
  25. qfactor = Lag.kr((1 - saturation)**4, lagtime);
  26. noise = Crackle.ar(1.99, 1.0);
  27. noise = BPF.ar(noise, frequency, qfactor);
  28. // Mix noise and saw
  29. mixer = Mix.ar([filter * saturation.sqrt(), 0.5 * noise*(1-saturation)]);
  30. // Apply pan
  31. panner = LinPan2.ar(mixer, pan);
  32. // Apply dynamics
  33. amplitude = Lag.kr(HPF.kr(value, 4 * hue / (lagtime)), lagtime);
  34. output = panner * amplitude;
  35. // Compress
  36. output = Compander.ar(output, output, 0.5, 0.3, 0.3, 0.1, lagtime);
  37. // Crank everything down
  38. output = output * 0.1;
  39. Out.ar(0, output);
  40. });
  41. module.load(s);
  42. s.sync;
  43. // Create multiple sound generators
  44. modules = Array.fill(12,
  45. {
  46. arg index;
  47. var pan, octave;
  48. pan = 0 - ((index % 4) - 1.5)/1.5;
  49. octave = (2 - (index / 4).floor);
  50. "Module %: Pan %, octave %\n".postf(index, pan.round(1e-1), octave.round(1e-1));
  51. Synth.new(\module,
  52. [\hue, 0.5, \saturation, 0.1, \value, 0.5, \pan, pan, \gain, 0.9, \octave, octave, \notefreq, Scale.major.degreeToFreq(index, 48.midicps, octave)]
  53. )
  54. }
  55. );
  56. // Hook up OSC
  57. f = { |msg, time, addr|
  58. if(msg[0] == '/radio') {
  59. if(msg[1]<modules.size){
  60. modules[msg[1]].set(\hue, msg[2]);
  61. modules[msg[1]].set(\saturation, msg[3]);
  62. modules[msg[1]].set(\value, msg[4]);
  63. }
  64. }
  65. };
  66. thisProcess.addOSCRecvFunc(f);
  67. };