| @@ -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> | |||