Sampler in ChucK
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.

170 lines
5.1KB

  1. //TODO: turn off adcThru when recording, and turn it back on afterwards
  2. //TODO: Effects break panning for some unknown reason
  3. //TODO varying number of bars
  4. NRev reverb => LPF lpf => HPF hpf => Dyno fxLimiter => dac;
  5. Dyno outputDryLeft => dac.left;
  6. Dyno outputDryRight => dac.right;
  7. fxLimiter.limit();
  8. outputDryLeft.limit();
  9. outputDryRight.limit();
  10. reverb @=> UGen @ outputWet; // Reference to wet output
  11. // Capture mic/line in and monitor through DAC. Limit
  12. adc => Dyno inputLimiter => Gain adcThru => fxLimiter; // Monitor input
  13. inputLimiter.limit();
  14. inputLimiter @=> UGen @ mainInput;
  15. // Default parameters
  16. 0 => float adcThruLevel;
  17. 1 => int adcThruMute;
  18. adcThruLevel * adcThruMute => adcThru.gain;
  19. 10000 => lpf.freq;
  20. 10 => hpf.freq;
  21. 2::second => dur globalLoopTime;
  22. // Plug in the pedals
  23. LoopPedal pedals[4];
  24. for( 0 => int i; i < pedals.cap(); i++ ) {
  25. pedals[i].recordFrom(mainInput);
  26. pedals[i].outputTo(outputWet, outputDryLeft, outputDryRight);
  27. }
  28. // Create the metronome
  29. Metronome metronome;
  30. spork ~metronome.run();
  31. // Start listening to OSC messages
  32. OscIn oin; 9000 => oin.port;
  33. oin.listenAll();
  34. OscMsg msg;
  35. // Event loop
  36. while (true) {
  37. oin => now;
  38. while (oin.recv(msg)) {
  39. if (msg.address=="/input") {
  40. msg.getFloat(0) => adc.gain;
  41. msg.getFloat(1) => adcThruLevel;
  42. adcThruLevel * adcThruMute => adcThru.gain;
  43. }
  44. else if(msg.address=="/delay") {
  45. msg.getFloat(0)::second => globalLoopTime;
  46. msg.getFloat(1) => float feedback;
  47. for( 0 => int i; i < pedals.cap(); i++ ) {
  48. pedals[i].setLoopPoint(globalLoopTime);
  49. pedals[i].setFeedback(feedback);
  50. }
  51. }
  52. else if(msg.address=="/channel") {
  53. msg.getInt(0) => int i;
  54. pedals[i].setGain(msg.getFloat(1));
  55. pedals[i].setPan(msg.getFloat(2));
  56. pedals[i].setWet(msg.getFloat(3));
  57. }
  58. else if(msg.address=="/multiplier"){
  59. msg.getInt(0) => int i;
  60. pedals[i].setLoopPoint(globalLoopTime * msg.getFloat(1));
  61. }
  62. else if(msg.address=="/arm") {
  63. msg.getInt(0) => int channel;
  64. (channel<0) => adcThruMute;
  65. adcThruLevel * adcThruMute => adcThru.gain;
  66. for( 0 => int i; i < pedals.cap(); i++ ) { pedals[i].arm(i==channel); }
  67. }
  68. else if(msg.address=="/metronome") {
  69. metronome.mute(msg.getInt(0));
  70. }
  71. else if(msg.address=="/clear") {
  72. msg.getInt(0) => int channel;
  73. pedals[channel].clear();
  74. }
  75. else if(msg.address=="/fx") {
  76. (100+msg.getFloat(0)*10000) => lpf.freq;
  77. (100+msg.getFloat(1)*10000) => hpf.freq;
  78. msg.getFloat(2) => reverb.mix;
  79. }
  80. else if(msg.address=="/master") {
  81. msg.getFloat(0) => float masterGain;
  82. masterGain => outputDryLeft.gain;
  83. masterGain => outputDryRight.gain;
  84. masterGain => fxLimiter.gain;
  85. }
  86. }
  87. }
  88. class LoopPedal
  89. {
  90. // We are wrapping a live sampler, LiSa
  91. LiSa sample;
  92. sample => Gain wet;
  93. sample => Pan2 dry;
  94. // Setup
  95. 10::second => sample.duration; // Allocate max 10 secs of memory
  96. 0::second => sample.recPos => sample.playPos;
  97. 1.0 => sample.feedback;
  98. 1 => sample.loop;
  99. dur loopTime;
  100. setLoopPoint(2::second);
  101. setWet(0.5);
  102. public void setLoopPoint( dur length ) {
  103. length => loopTime => sample.loopEnd => sample.loopEndRec;
  104. }
  105. public void setFeedback( float fb ) { fb => sample.feedback; }
  106. public void setGain( float gain ) { gain => sample.gain; }
  107. public void setPan( float pan ) { pan => dry.pan; }
  108. public void setWet( float ratio ) { ratio => wet.gain; 1-ratio => dry.gain;}
  109. public void clear() { sample.clear(); }
  110. public void recordFrom(UGen ugen) { ugen => sample; }
  111. // TODO: maybe this should be % looptime/multiplier?
  112. public dur remaining() { return loopTime - sample.playPos(); }
  113. public void outputTo(UGen wetSink, UGen drySinkLeft, UGen drySinkRight) {
  114. 1 => sample.play;
  115. wet => wetSink;
  116. dry.left => drySinkLeft;
  117. dry.right => drySinkRight;
  118. }
  119. public void arm(int value) {
  120. sample.playPos() => sample.recPos;
  121. value => sample.record;
  122. }
  123. }
  124. class Metronome
  125. {
  126. // A simple metronome
  127. SinOsc s => ADSR a;
  128. 60 => s.freq;
  129. 0.5 => s.gain;
  130. 0.6 => s.gain;
  131. a.set(0.001, .1, .5, .13);
  132. 10::ms => dur plipTime;
  133. fun void mute(int value) {
  134. if (value){ a => dac; } else { a =< dac; }
  135. }
  136. fun void run() {
  137. while(true) {
  138. // Compute the beat time
  139. globalLoopTime/4. - plipTime => dur beatTime;
  140. // Beep four times
  141. 0.15::second => a.releaseTime;
  142. a.keyOn(); plipTime => now; a.keyOff();
  143. beatTime => now;
  144. 0.1::second => a.releaseTime;
  145. a.keyOn(); plipTime => now; a.keyOff();
  146. beatTime => now;
  147. a.keyOn(); plipTime => now; a.keyOff();
  148. beatTime => now;
  149. a.keyOn(); plipTime => now; a.keyOff();
  150. pedals[0].remaining() => now; // Sync
  151. }
  152. }
  153. }