/** * This "glitch" generator uses the percentage values in the sliders to determine whether or not to place a glitch note in the sequence as it generates it.
* You can force a note to always be present at a particular step by setting the slider to 1.0
* You can force a note to never be present at a particular step by setting the slider to 0.0
* The "V" sliders control triggering of glitches in the vocal track and the "G" sliders control triggering of glitches in the drum track.
*
* Tempo: the tempo of the generated sequence.
* Measures: how many measures to generate.
* AddKick: if lit, a kick drum sound will be added on every quarter note.
* MuteVox: if lit, the sequence will be generated without vocals.
* FadeGlitch: if lit, each glitch note in the drum track will be faded in over its duration.
* Randomize: picks random percentages for all sliders.
* Generate: generates a sequence using the current settings.
* Perc Glitch: a range used to determine how short each glitch loop will be for the drums.
* Vox Glitch: a range used to determine how short each glitch loop will be for the vocals.
* The higher glitch values will give you "buzzier" audio and lower values will sound more like a skipping record.
*
* The playback rate of both tracks are scaled based on the tempo you select.
* Lower tempos will result in lower-pitched audio and vice-versa.
* If you want to hear the entire vocal track you should generate around 104 measures.
*
* Vocals: Half Life by Imogen Heap
* Drums: Sample from Hydra Remix By Koen Groeneveld
* **/ import controlP5.*; import ddf.minim.signals.*; import ddf.minim.*; import ddf.minim.analysis.*; import ddf.minim.effects.*; import ddf.minim.ugens.*; Minim minim; AudioOutput mainOut; float hydraTempo = 128.f; FilePlayer hydra; TickRate hydraRate; float heapTempo = 109.85f; FilePlayer heap; TickRate heapRate; Multiplier heapAmp; SampleRepeat heapGlitch; Multiplier loopAmp; Line loopAmpSweep; public float Tempo = 128.f; public int Measures = 16; public boolean AddKick = true; public boolean FadeGlitch = true; public boolean MuteVox = false; ControlP5 gui; Range glitchRange; Range voxGlitchRange; float[] glitchProb = new float[] { 0.6f, 0.2f, 0.9f, 0.2f, 0.6f, 0.2f, 0.9f, 0.2f, 0.6f, 0.2f, 0.9f, 0.2f, 0.6f, 0.2f, 0.9f, 0.2f }; float[] voxProb = new float[] { 0.1f, 0.2f, 0.05f, 0.1f, 0.3f, 0.1f, 0.1f, 0.03f, 0.02f, 0.12f, 0.09f, 0.32f, 0.06f, 0.25f, 0.03f, 0.01f }; void Randomize() { for(int i = 0; i < glitchProb.length; ++i) { glitchProb[i] = random( 0.f, 1.f ); gui.controller("G" + (i+1)).setValue( glitchProb[i] ); voxProb[i] = random( 0.f, 1.f ); gui.controller("V" + (i+1)).setValue( voxProb[i] ); } } public void controlEvent( ControlEvent theEvent ) { int index = theEvent.controller().id(); if ( theEvent.controller().name().startsWith("G") ) { glitchProb[ index ] = theEvent.controller().value(); } else if ( theEvent.controller().name().startsWith("V") ) { voxProb[ index ] = theEvent.controller().value(); } } void setup() { size( 800, 500 ); colorMode(HSB, 360, 1, 1); gui = new ControlP5(this); int sliderHeight = 50; int sliderWidth = 10; int sliderSpacing = 40; int sliderStartY = 300; int xpos = 20; for(int i = 0; i < glitchProb.length; ++i ) { if ( i % 4 == 0 ) xpos += 20; gui.addSlider( "V" + (i + 1), 0.f, 1.f, voxProb[i], xpos, sliderStartY, sliderWidth, sliderHeight ).setId( i ); gui.addSlider( "G" + (i + 1), 0.f, 1.f, glitchProb[i], xpos, sliderStartY + sliderHeight + 40, sliderWidth, sliderHeight ).setId( i ); xpos += sliderSpacing; } gui.addNumberbox( "Tempo", Tempo, 40, 220, 40, 15 ); gui.addNumberbox( "Measures", Measures, 100, 220, 20, 15 ); gui.addToggle("AddKick", AddKick, 160, 220, 15, 15 ); gui.addToggle("MuteVox", MuteVox, 220, 220, 15, 15 ); gui.addToggle("FadeGlitch", FadeGlitch, 280, 220, 15, 15 ); gui.addBang("Randomize", 360, 220, 15, 15 ); gui.addBang( "Generate", 420, 220, 15, 15 ); glitchRange = gui.addRange("Perc Glitch", 0.f, 6.2f, 1.f, 4.f, 40, 260, 100, 15); glitchRange.setDecimalPrecision(0); glitchRange.setBroadcast(false); voxGlitchRange = gui.addRange("Vox Glitch", 0.f, 6.2f, 1.1f, 4.f, 250, 260, 100, 15 ); voxGlitchRange.setDecimalPrecision(0); voxGlitchRange.setBroadcast(false); minim = new Minim(this); mainOut = minim.getLineOut(); // setup the main loop that we will glitch hydra = new FilePlayer( minim.loadFileStream( "hydra_loop.aif", 1024, true ) ); hydraRate = new TickRate( 1.f ); hydraRate.setInterpolation( true ); loopAmp = new Multiplier( 0.8f ); hydra.patch( hydraRate ).patch( loopAmp ); loopAmpSweep = new Line( 0.f, 0.001f, 0.8f ); loopAmpSweep.patch( loopAmp.amplitude ); // setup the vox we'll layer on top heap = new FilePlayer( minim.loadFileStream( "imogen_heap_half_life_vox.mp3", 1024, false ) ); heapRate = new TickRate( 1.f ); heapRate.setInterpolation( true ); heapGlitch = new SampleRepeat( heapTempo, 0.25f ); heapAmp = new Multiplier( 0.8f ); heap.patch( heapAmp ).patch( heapGlitch ).patch( heapRate ); } boolean prob( float pct ) { return random(1.f) < pct; } public void Generate() { gui.controller("Generate").hide(); Tempo = constrain( Tempo, 20.f, 480.f ); gui.controller("Tempo").setValue( Tempo ); mainOut.setTempo( Tempo ); Measures = (int)constrain( Measures, 1, 128 ); gui.controller("Measures").setValue( Measures ); hydra.rewind(); hydra.loop(); hydraRate.value.setLastValue( Tempo / hydraTempo ); heap.rewind(); heap.play(); heapRate.value.setLastValue( Tempo / heapTempo ); float lowGlitch = glitchRange.lowValue(); float hiGlitch = glitchRange.highValue(); float lowVoxGlitch = voxGlitchRange.lowValue(); float hiVoxGlitch = voxGlitchRange.highValue(); if ( FadeGlitch ) { if ( !loopAmp.amplitude.isPatched() ) { loopAmpSweep.patch( loopAmp.amplitude ); } } else { if ( loopAmp.amplitude.isPatched() ) { loopAmpSweep.unpatch( loopAmp ); } loopAmp.amplitude.setLastValue( 1.f ); } mainOut.pauseNotes(); mainOut.setNoteOffset( 0.f ); SampleCue lastSample = null; float lastNoteTime = 0.f; float measureBegin = 0.f; mainOut.playNote( 0.f, 4.f * Measures, new SequenceBegin() ); for( int m = 0; m < Measures; ++m ) { for( int t = 0 ; t < glitchProb.length; ++t ) { float noteTime = measureBegin + t * 0.25f; if ( prob( glitchProb[t] ) ) { // actually cue up the last note because we know how long it needs to be now if ( lastSample != null ) { float duration = noteTime - lastNoteTime; //println("Cueing note of duration " + duration + " at time " + lastNoteTime + ". Next note will be at " + noteTime); mainOut.playNote( lastNoteTime, duration, lastSample ); } int loopStart = 117 * t; float slice = pow( 2.f, int( random( lowGlitch, hiGlitch ) ) ); int loopEnd = loopStart + int( 468.f / slice ); lastNoteTime = noteTime; lastSample = new SampleCue( loopStart, loopEnd ); } if ( !MuteVox && prob( voxProb[t] ) ) { float fglitch = random( lowVoxGlitch, hiVoxGlitch ); int iglitch = int( fglitch ); float glitchLen = 0.5f / pow( 2.f, iglitch ); println("Cueing vox note with fglitch " + fglitch + ", iglitch " + iglitch + ", glitchLen " + glitchLen); vox( noteTime, 1.f, glitchLen ); } } if ( AddKick ) { kick( measureBegin, 0.25f, 0.9f ); kick( measureBegin + 1.f, 0.25f, 0.9f ); kick( measureBegin + 2.f, 0.25f, 0.9f ); kick( measureBegin + 3.f, 0.25f, 0.9f ); } measureBegin += 4; } if ( lastSample != null ) { mainOut.playNote( lastNoteTime, measureBegin - lastNoteTime, lastSample ); } mainOut.playNote( measureBegin, 0.f, new SequenceEnd() ); mainOut.resumeNotes(); } ////////////////////////////////////////////////// // // DRAWING DOWN HERE // float hueForSample( float sample ) { return map( abs(sample), 0, 1, 120, 450 ); } float waveSize = 50.f; float waveCenter = 100.f; // draw is run many times void draw() { //println("Current loopAmp is " + loopAmp.amplitude.getLastValue()); // erase the window to black background( 0 ); // draw using a white stroke stroke( 255 ); // draw the waveforms for( int i = 0; i < mainOut.bufferSize() - 1; i++ ) { // find the x position of each buffer value float x1 = map( i, 0, mainOut.bufferSize(), 0, width ); float x2 = map( i+1, 0, mainOut.bufferSize(), 0, width ); // draw a line from one buffer position to the next for both channels stroke( hueForSample(mainOut.left.get(i)), 1, 1 ); line( x1, waveCenter - waveSize + mainOut.left.get(i)*waveSize, x2, waveCenter - waveSize + mainOut.left.get(i+1)*waveSize); stroke( hueForSample(mainOut.right.get(i)), 1, 1 ); line( x1, waveCenter + waveSize + mainOut.right.get(i)*waveSize, x2, waveCenter + waveSize + mainOut.right.get(i+1)*waveSize); } } // stop is run when the user presses stop void stop() { // close the AudioOutput mainOut.close(); // stop the minim object minim.stop(); super.stop(); }