@@ -89,7 +89,11 @@ void AudioEffectGranular::update(void) | |||
{ | |||
audio_block_t *block; | |||
if (sample_bank == NULL) return; | |||
if (sample_bank == NULL) { | |||
block = receiveReadOnly(0); | |||
if (block) release(block); | |||
return; | |||
} | |||
block = receiveWritable(0); | |||
if (!block) return; |
@@ -0,0 +1,108 @@ | |||
#include <Audio.h> | |||
#include <Wire.h> | |||
#include <SPI.h> | |||
#include <SD.h> | |||
#include <SerialFlash.h> | |||
#include <Bounce.h> | |||
AudioPlaySdWav playSdWav1; //xy=163,135 | |||
AudioMixer4 mixer1; //xy=332,167 | |||
AudioEffectGranular granular1; //xy=504,155 | |||
AudioOutputI2S i2s1; //xy=664,185 | |||
AudioConnection patchCord1(playSdWav1, 0, mixer1, 0); | |||
AudioConnection patchCord2(playSdWav1, 1, mixer1, 1); | |||
AudioConnection patchCord3(mixer1, granular1); | |||
AudioConnection patchCord4(granular1, 0, i2s1, 0); | |||
AudioConnection patchCord5(granular1, 0, i2s1, 1); | |||
AudioControlSGTL5000 sgtl5000_1; //xy=236,248 | |||
Bounce button0 = Bounce(0, 15); | |||
Bounce button1 = Bounce(1, 15); | |||
Bounce button2 = Bounce(2, 15); | |||
#define GRANULAR_MEMORY_SIZE 6000 | |||
int16_t granularMemory[GRANULAR_MEMORY_SIZE]; | |||
// Use these with the Teensy Audio Shield | |||
#define SDCARD_CS_PIN 10 | |||
#define SDCARD_MOSI_PIN 7 | |||
#define SDCARD_SCK_PIN 14 | |||
// Use these with the Teensy 3.5 & 3.6 SD card | |||
//#define SDCARD_CS_PIN BUILTIN_SDCARD | |||
//#define SDCARD_MOSI_PIN 11 // not actually used | |||
//#define SDCARD_SCK_PIN 13 // not actually used | |||
// Use these for the SD+Wiz820 or other adaptors | |||
//#define SDCARD_CS_PIN 4 | |||
//#define SDCARD_MOSI_PIN 11 | |||
//#define SDCARD_SCK_PIN 13 | |||
#define NUM_FILES 4 | |||
const char *filenames[NUM_FILES]={"SDTEST1.WAV", "SDTEST2.WAV", "SDTEST3.WAV", "SDTEST4.WAV"}; | |||
int nextfile=0; | |||
void setup() { | |||
Serial.begin(9600); | |||
AudioMemory(10); | |||
pinMode(0, INPUT_PULLUP); | |||
pinMode(1, INPUT_PULLUP); | |||
pinMode(2, INPUT_PULLUP); | |||
sgtl5000_1.enable(); | |||
sgtl5000_1.volume(0.5); | |||
mixer1.gain(0, 0.5); | |||
mixer1.gain(1, 0.5); | |||
// the Granular effect requires memory to operate | |||
granular1.begin(granularMemory, GRANULAR_MEMORY_SIZE); | |||
SPI.setMOSI(SDCARD_MOSI_PIN); | |||
SPI.setSCK(SDCARD_SCK_PIN); | |||
if (!(SD.begin(SDCARD_CS_PIN))) { | |||
// stop here, but print a message repetitively | |||
while (1) { | |||
Serial.println("Unable to access the SD card"); | |||
delay(500); | |||
} | |||
} | |||
} | |||
void loop() { | |||
if (playSdWav1.isPlaying() == false) { | |||
// start the next song playing | |||
playSdWav1.play(filenames[nextfile]); | |||
Serial.print("Playing: "); | |||
Serial.println(filenames[nextfile]); | |||
delay(5); // brief delay for the library read WAV info | |||
nextfile = nextfile + 1; | |||
if (nextfile >= NUM_FILES) { | |||
nextfile = 0; | |||
} | |||
} | |||
// read pushbuttons | |||
button0.update(); | |||
button1.update(); | |||
button2.update(); | |||
// read knobs | |||
int knobA2 = analogRead(A2); | |||
int knobA3 = analogRead(A3); | |||
if (button0.fallingEdge()) { | |||
granular1.freeze(1, knobA2, knobA3); | |||
} | |||
if (button0.risingEdge()) { | |||
granular1.freeze(0, knobA2, knobA3); | |||
} | |||
if (button1.fallingEdge()) { | |||
granular1.shift(1, knobA2, knobA3); | |||
} | |||
if (button1.risingEdge()) { | |||
granular1.shift(0, knobA2, knobA3); | |||
} | |||
} |
@@ -393,6 +393,7 @@ span.mainfunction {color: #993300; font-weight: bolder} | |||
{"type":"AudioEffectBitcrusher","data":{"shortName":"bitcrusher","inputs":1,"outputs":1,"category":"effect-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
{"type":"AudioEffectMidSide","data":{"shortName":"midside","inputs":2,"outputs":2,"category":"effect-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
{"type":"AudioEffectWaveshaper","data":{"shortName":"waveshape","inputs":1,"outputs":1,"category":"effect-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
{"type":"AudioEffectGranular","data":{"shortName":"granular","inputs":1,"outputs":1,"category":"effect-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
{"type":"AudioFilterBiquad","data":{"defaults":{"name":{"value":"new"}},"shortName":"biquad","inputs":1,"outputs":1,"category":"filter-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
{"type":"AudioFilterFIR","data":{"defaults":{"name":{"value":"new"}},"shortName":"fir","inputs":1,"outputs":1,"category":"filter-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
{"type":"AudioFilterStateVariable","data":{"defaults":{"name":{"value":"new"}},"shortName":"filter","inputs":2,"outputs":3,"category":"filter-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||
@@ -2491,10 +2492,6 @@ double s_freq = .0625;</p> | |||
</div> | |||
</script> | |||
<script type="text/x-red" data-help-name="AudioEffectEnvelope"> | |||
<h3>Summary</h3> | |||
<div class=tooltipinfo> | |||
@@ -2916,6 +2913,48 @@ double s_freq = .0625;</p> | |||
</div> | |||
</script> | |||
<script type="text/x-red" data-help-name="AudioEffectGranular"> | |||
<h3>Summary</h3> | |||
<div class=tooltipinfo> | |||
<p>Classic granular effect that uses a variable speed buffer to shift the pitch | |||
and freeze incoming audio.</p> | |||
</div> | |||
<h3>Audio Connections</h3> | |||
<table class=doc align=center cellpadding=3> | |||
<tr class=top><th>Port</th><th>Signal</th></tr> | |||
<tr class=odd><td align=center>In 0</td><td>Input Signal</td></tr> | |||
<tr class=odd><td align=center>Out 0</td><td>Granular Output</td></tr> | |||
</table> | |||
<h3>Functions</h3> | |||
<p class=func><span class=keyword>begin</span>(array, length);</p> | |||
<p class=desc>TODO: documentation here | |||
</p> | |||
<p class=func><span class=keyword>shift</span>(param1, param2, param3);</p> | |||
<p class=desc>TODO: documentation here | |||
</p> | |||
<p class=func><span class=keyword>freeze</span>(param1, param2, param3);</p> | |||
<p class=desc>TODO: documentation here | |||
</p> | |||
<p class=func><span class=keyword>length</span>(param1);</p> | |||
<p class=desc>TODO: documentation here | |||
</p> | |||
<p class=func><span class=keyword>rate</span>(param1);</p> | |||
<p class=desc>TODO: documentation here | |||
</p> | |||
<h3>Examples</h3> | |||
<p class=exam>TODO: example needed</p> | |||
<p class=exam>File > Examples > Audio > Effects > Granular</p> | |||
<!--<h3>Notes</h3> | |||
<p> </p>--> | |||
</script> | |||
<script type="text/x-red" data-template-name="AudioEffectGranular"> | |||
<div class="form-row"> | |||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> | |||
<input type="text" id="node-input-name" placeholder="Name"> | |||
</div> | |||
</script> | |||
<script type="text/x-red" data-help-name="AudioFilterBiquad"> | |||
<h3>Summary</h3> | |||
<div class=tooltipinfo> |