Browse files

Merge branch 'granulator'

* granulator:
  Removes stray DS_Store file.
  gh-30: Adds thanks to Mayank for the granulator ugen in README.
  gh-30: Fixes bug when modulating numGrains.
  gh-30: Adds mul/add support to granulator.
  gh-30: Whitespace fixes.
  gh-30: Bug fixes and minor stylistic tweaks to granulator and demo.
  gh-30: Addes granular demo (from Mayank). Fixes a few minor bugs.
  changes according to colins feb 3 comments
  added granulator with control rates for all params
  Added first pass at Granulator
  • Loading branch information...
2 parents da07cb8 + 9422183 commit 6fa60a65cc01591d023e7b164e53b6567e46312f @colinbdclark committed Apr 7, 2013
Showing with 164 additions and 2 deletions.
  1. +3 −2 README.md
  2. +41 −0 demos/interactive/html/playground.html
  3. +120 −0 flocking/flocking-ugens.js
View
5 README.md
@@ -88,7 +88,7 @@ by another sine oscillator ("mod"):
Compatibility
-------------
-Flocking is currently tested on the latest versions of Firefox and Chrome, as well as Safari 6+.
+Flocking is currently tested on the latest versions of Firefox, Chrome and Safari on Mac, Windows, Linux, iOS, and Android.
Licensing
---------
@@ -104,7 +104,8 @@ a composer, thinker, and early pioneer of computer music who my composition teac
I hope you find this library useful enough to create projects as beautiful and inspiring as Jim's _Flocking_.
### Thanks to:###
- * [Vitus](https://github.com/derDoc) for his awesome interactive Flocking Playground contributions
+ * [Mayank Sanganeria](http://github.com/e7mac) for his granulator unit generator
+ * [Vitus](https://github.com/derDoc) for his contributions to the interactive Flocking Playground
* [Myles Borins](https://github.com/thealphanerd) for pushing the limits of Flocking very early in its development
* Alex Geddie for teaching me a ton about synthesis and computer music
* [Antranig Basman](https://github.com/amb26) for code review and advice
View
41 demos/interactive/html/playground.html
@@ -61,6 +61,9 @@
<option value="phase_mod">Phase modulation</option>
<option value="sum">Additive Synthesis</option>
</optgroup>
+ <optgroup label="Granular Synthesis">
+ <option value="granulator">Granulator</option>
+ </optgroup>
<optgroup label="Filters">
<option value="lowpass">Low pass filter</option>
<option value="highpass">High pass filter</option>
@@ -609,6 +612,44 @@
intervalSynth.input("carrier.freq", fundamental * newInterval);
});
</script>
+
+ <script type="application/flocking" id="granulator">
+var synth = flock.synth({
+ ugen: "flock.ugen.granulator",
+ numGrains: {
+ ugen: "flock.ugen.line",
+ start: 1,
+ end: 10,
+ duration: 20
+ },
+ grainDur: 0.05,
+ delayDur: 5,
+ mul: 0.5,
+ source: {
+ ugen: "flock.ugen.filter.biquad.lp",
+ freq: {
+ ugen: "flock.ugen.sin",
+ rate: "control",
+ freq: {
+ ugen: "flock.ugen.xLine",
+ rate: "control",
+ start: 0.7,
+ end: 300,
+ duration: 20
+ },
+ phase: 0,
+ mul: 3600,
+ add: 4000
+ },
+ source: {
+ ugen: "flock.ugen.lfSaw",
+ freq: 200,
+ mul: 0.25
+ }
+ }
+});
+ </script>
+
<script type="application/flocking" id="polyphonicSynth">
var fundamental = 440;
View
120 flocking/flocking-ugens.js
@@ -2542,4 +2542,124 @@ var flock = flock || {};
}
}
});
+
+
+ /**
+ * Granulates a source signal using an integral delay line.
+ * This implementation is particularly useful for live granulation.
+ * Contributed by Mayank Sanganeria.
+ *
+ * Inputs:
+ * - grainDur: the duration of each grain (control or constant rate only)
+ * - delayDur: the duration of the delay line (control or constant rate only)
+ * - numGrains: the number of grains to generate (control or constant rate only)
+ * - mul: amplitude scale factor
+ * - add: amplide add
+ */
+ // TODO: Unit tests.
+ flock.ugen.granulator = function (inputs, output, options) {
+ var that = flock.ugen(inputs, output, options);
+
+ that.gen = function (numSamps) {
+ var m = that.model,
+ inputs = that.inputs,
+ out = that.output,
+ grainDur = inputs.grainDur.output[0],
+ delayDur = inputs.delayDur.output[0],
+ numGrains = inputs.numGrains.output[0],
+ source = inputs.source.output,
+ i,
+ j,
+ grainPos,
+ windowPos,
+ amp;
+
+ // TODO: Probably too expensive to modulate delayDur at control rate.
+ // Perhaps either move this into onInputChanged() and treat it as a constant input parameter
+ // or introduce a maximum delay length and reuse the same array throughout (just changing indices).
+ if (m.delayDur !== delayDur) {
+ m.delayDur = delayDur;
+ m.delayLength = Math.floor(m.sampleRate * m.delayDur);
+ that.delayLine = new Float32Array(that.model.delayLength);
+ }
+
+ if (m.grainDur !== grainDur) {
+ m.grainDur = grainDur;
+ m.grainLength = Math.floor(m.sampleRate * m.grainDur);
+ for (i = 0; i < m.grainLength; i++) {
+ m.windowFunction[i] = Math.sin(Math.PI * i / m.grainLength);
+ }
+ }
+
+ // If numGrains has changed, zero the extra buffers.
+ // Need to hold on to "raw" input so we can compare unrounded values.
+ if (m.rawNumGrains !== numGrains) {
+ m.rawNumGrains = numGrains;
+ numGrains = Math.round(numGrains);
+ for (i = m.numGrains; i < numGrains; i++) {
+ m.currentGrainPosition[i] = 0;
+ m.currentGrainWindowPosition[i] = Math.floor(Math.random() * m.grainLength);
+ }
+ m.numGrains = numGrains;
+ }
+
+ for (i = 0; i < numSamps; i++) {
+ // Update the delay line's write position
+ that.delayLine[m.writePos] = source[i];
+ m.writePos = (m.writePos + 1) % m.delayLength;
+
+ // Clear the previous output.
+ out[i] = 0;
+
+ // Now fill with grains
+ for (j = 0; j < m.numGrains; j++) {
+ grainPos = m.currentGrainPosition[j];
+ windowPos = m.currentGrainWindowPosition[j];
+ amp = m.windowFunction[windowPos];
+ out[i] += that.delayLine[grainPos] * amp;
+
+ // Update positions in the delay line and grain envelope arrays for next time.
+ m.currentGrainPosition[j] = (grainPos + 1) % m.delayLength;
+ m.currentGrainWindowPosition[j] = (windowPos + 1) % m.grainLength;
+
+ // Randomize the reset position of grains.
+ if (m.currentGrainWindowPosition[j] === 0) {
+ m.currentGrainPosition[j] = Math.floor(Math.random() * m.delayLength);
+ }
+ }
+
+ // Normalize the output amplitude.
+ out[i] /= m.numGrains;
+ }
+
+ that.mulAdd(numSamps);
+ };
+
+ that.onInputChanged = function () {
+ flock.onMulAddInputChanged(that);
+ };
+
+ that.onInputChanged();
+ return that;
+ };
+
+ flock.defaults("flock.ugen.granulator", {
+ rate: "audio",
+ inputs: {
+ grainDur: 0.1,
+ delayDur: 1,
+ numGrains: 5
+ },
+ options: {
+ model: {
+ grainLength: 0,
+ numGrains: 0,
+ currentGrainPosition: [],
+ currentGrainWindowPosition: [],
+ windowFunction: [],
+ writePos: 0
+ }
+ }
+ });
+
}(jQuery));

0 comments on commit 6fa60a6

Please sign in to comment.