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.

176 lines
5.4KB

  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=="/direction"){
  63. msg.getInt(0) => int i;
  64. pedals[i].setDirection(msg.getFloat(1));
  65. }
  66. else if(msg.address=="/arm") {
  67. msg.getInt(0) => int channel;
  68. (channel<0) => adcThruMute;
  69. adcThruLevel * adcThruMute => adcThru.gain;
  70. for( 0 => int i; i < pedals.cap(); i++ ) { pedals[i].arm(i==channel); }
  71. }
  72. else if(msg.address=="/metronome") {
  73. metronome.mute(msg.getInt(0));
  74. }
  75. else if(msg.address=="/clear") {
  76. msg.getInt(0) => int channel;
  77. pedals[channel].clear();
  78. }
  79. else if(msg.address=="/fx") {
  80. (100+msg.getFloat(0)*10000) => lpf.freq;
  81. (100+msg.getFloat(1)*10000) => hpf.freq;
  82. msg.getFloat(2) => reverb.mix;
  83. }
  84. else if(msg.address=="/master") {
  85. msg.getFloat(0) => float masterGain;
  86. masterGain => outputDryLeft.gain;
  87. masterGain => outputDryRight.gain;
  88. masterGain => fxLimiter.gain;
  89. }
  90. }
  91. }
  92. class LoopPedal
  93. {
  94. // We are wrapping a live sampler, LiSa
  95. LiSa sample;
  96. sample => Gain wet;
  97. sample => Pan2 dry;
  98. // Setup
  99. 10::second => sample.duration; // Allocate max 10 secs of memory
  100. 0::second => sample.recPos => sample.playPos;
  101. 1.0 => sample.feedback;
  102. 1 => sample.loop;
  103. dur loopTime;
  104. setLoopPoint(2::second);
  105. setWet(0.5);
  106. public void setLoopPoint( dur length ) {
  107. length => loopTime => sample.loopEnd => sample.loopEndRec;
  108. }
  109. public void setDirection( float direction ) {
  110. direction => sample.rate;
  111. }
  112. public void setFeedback( float fb ) { fb => sample.feedback; }
  113. public void setGain( float gain ) { gain => sample.gain; }
  114. public void setPan( float pan ) { pan => dry.pan; }
  115. public void setWet( float ratio ) { ratio => wet.gain; 1-ratio => dry.gain;}
  116. public void clear() { sample.clear(); }
  117. public void recordFrom(UGen ugen) { ugen => sample; }
  118. // TODO: maybe this should be % looptime/multiplier?
  119. public dur remaining() { return loopTime - sample.playPos(); }
  120. public void outputTo(UGen wetSink, UGen drySinkLeft, UGen drySinkRight) {
  121. 1 => sample.play;
  122. wet => wetSink;
  123. dry.left => drySinkLeft;
  124. dry.right => drySinkRight;
  125. }
  126. public void arm(int value) {
  127. sample.playPos() => sample.recPos;
  128. value => sample.record;
  129. }
  130. }
  131. class Metronome
  132. {
  133. // A simple metronome
  134. SinOsc s => ADSR a;
  135. 60 => s.freq;
  136. 0.6 => s.gain;
  137. a.set(0.001, .1, .5, .13);
  138. 10::ms => dur plipTime;
  139. fun void mute(int value) {
  140. if (value){ a => dac; } else { a =< dac; }
  141. }
  142. fun void run() {
  143. while(true) {
  144. // Compute the beat time
  145. globalLoopTime/4. - plipTime => dur beatTime;
  146. // Beep four times
  147. 0.15::second => a.releaseTime;
  148. a.keyOn(); plipTime => now; a.keyOff();
  149. beatTime => now;
  150. 0.1::second => a.releaseTime;
  151. a.keyOn(); plipTime => now; a.keyOff();
  152. beatTime => now;
  153. a.keyOn(); plipTime => now; a.keyOff();
  154. beatTime => now;
  155. a.keyOn(); plipTime => now; a.keyOff();
  156. pedals[0].remaining() => now; // Sync
  157. }
  158. }
  159. }