| @@ -31,7 +31,7 @@ void AudioEffectGranular::begin(int16_t *sample_bank_def, int16_t max_len_def) | |||
| read_head = 0; | |||
| write_head = 0; | |||
| prev_input = 0; | |||
| playpack_rate = 512; | |||
| playpack_rate = 65536; | |||
| accumulator = 0; | |||
| allow_len_change = true; | |||
| sample_loaded = false; | |||
| @@ -51,10 +51,6 @@ void AudioEffectGranular::beginFreeze_int(int grain_samples) | |||
| write_en = false; | |||
| sample_req = true; | |||
| __enable_irq(); | |||
| Serial.print("in = "); | |||
| Serial.print(grain_samples); | |||
| Serial.print(", freeze len = "); | |||
| Serial.println(freeze_len); | |||
| } | |||
| void AudioEffectGranular::beginPitchShift_int(int grain_samples) | |||
| @@ -79,11 +75,6 @@ void AudioEffectGranular::stop() | |||
| allow_len_change = true; | |||
| } | |||
| void AudioEffectGranular::rate(int16_t playpack_rate_def) | |||
| { | |||
| playpack_rate = playpack_rate_def; | |||
| } | |||
| void AudioEffectGranular::update(void) | |||
| { | |||
| audio_block_t *block; | |||
| @@ -102,7 +93,7 @@ void AudioEffectGranular::update(void) | |||
| prev_input = block->data[AUDIO_BLOCK_SAMPLES-1]; | |||
| } | |||
| else if (grain_mode == 1) { | |||
| //when activated the last | |||
| // Freeze - sample 1 grain, then repeatedly play it back | |||
| for (int j = 0; j < AUDIO_BLOCK_SAMPLES; j++) { | |||
| if (sample_req) { | |||
| // only begin capture on zero cross | |||
| @@ -113,7 +104,6 @@ void AudioEffectGranular::update(void) | |||
| write_head = 0; | |||
| read_head = 0; | |||
| sample_req = false; | |||
| Serial.println("begin freeze capture"); | |||
| } else { | |||
| prev_input = current_input; | |||
| } | |||
| @@ -125,13 +115,12 @@ void AudioEffectGranular::update(void) | |||
| } | |||
| if (write_head >= max_sample_len) { | |||
| write_en = false; | |||
| Serial.println("end freeze capture"); | |||
| } | |||
| } | |||
| if (sample_loaded) { | |||
| if (playpack_rate >= 0) { | |||
| accumulator += playpack_rate; | |||
| read_head = accumulator >> 9; | |||
| read_head = accumulator >> 16; | |||
| } | |||
| if (read_head >= freeze_len) { | |||
| accumulator = 0; | |||
| @@ -206,7 +195,7 @@ void AudioEffectGranular::update(void) | |||
| } | |||
| accumulator += playpack_rate; | |||
| read_head = (accumulator >> 9); | |||
| read_head = (accumulator >> 16); | |||
| if (read_head >= glitch_len) { | |||
| read_head -= glitch_len; | |||
| @@ -28,7 +28,11 @@ class AudioEffectGranular : public AudioStream | |||
| public: | |||
| AudioEffectGranular(void): AudioStream(1,inputQueueArray) { } | |||
| void begin(int16_t *sample_bank_def, int16_t max_len_def); | |||
| void rate(int16_t playpack_rate_def); | |||
| void setSpeed(float ratio) { | |||
| if (ratio < 0.125) ratio = 0.125; | |||
| else if (ratio > 8.0) ratio = 8.0; | |||
| playpack_rate = ratio * 65536.0 + 0.499; | |||
| } | |||
| void beginFreeze(float grain_length) { | |||
| if (grain_length <= 0.0) return; | |||
| beginFreeze_int(grain_length * (AUDIO_SAMPLE_RATE_EXACT * 0.001) + 0.5); | |||
| @@ -44,13 +48,13 @@ private: | |||
| void beginPitchShift_int(int grain_samples); | |||
| audio_block_t *inputQueueArray[1]; | |||
| int16_t *sample_bank; | |||
| uint32_t playpack_rate; | |||
| uint32_t accumulator; | |||
| int16_t max_sample_len; | |||
| int16_t write_head; | |||
| int16_t read_head; | |||
| int16_t grain_mode; | |||
| int16_t freeze_len; | |||
| int16_t playpack_rate; | |||
| int32_t accumulator; | |||
| int16_t prev_input; | |||
| int16_t glitch_len; | |||
| bool allow_len_change; | |||
| @@ -1,3 +1,15 @@ | |||
| // Granular Effect Example - Pitch shift or freeze sound | |||
| // | |||
| // This example is meant to be used with 3 buttons (pin 0, | |||
| // 1, 2) and 2 knobs (pins 16/A2, 17/A3), which are present | |||
| // on the audio tutorial kit. | |||
| // https://www.pjrc.com/store/audio_tutorial_kit.html | |||
| // | |||
| // Data files to put on your SD card can be downloaded here: | |||
| // http://www.pjrc.com/teensy/td_libs_AudioDataFiles.html | |||
| // | |||
| // This example code is in the public domain. | |||
| #include <Audio.h> | |||
| #include <Wire.h> | |||
| #include <SPI.h> | |||
| @@ -91,22 +103,33 @@ void loop() { | |||
| float knobA2 = (float)analogRead(A2) / 1023.0; | |||
| float knobA3 = (float)analogRead(A3) / 1023.0; | |||
| // Button 0 starts Freeze effect | |||
| if (button0.fallingEdge()) { | |||
| // Button 0 starts Freeze effect | |||
| granular1.beginFreeze(knobA3 * 290.0); | |||
| float msec = 100.0 + (knobA3 * 190.0); | |||
| granular1.beginFreeze(msec); | |||
| Serial.print("Begin granular freeze using "); | |||
| Serial.print(msec); | |||
| Serial.println(" grains"); | |||
| } | |||
| if (button0.risingEdge()) { | |||
| granular1.stop(); | |||
| } | |||
| // Button 1 starts Pitch Shift effect | |||
| if (button1.fallingEdge()) { | |||
| // Button 1 starts Pitch Shift effect | |||
| granular1.beginPitchShift(knobA3 * 100.0); | |||
| float msec = 25.0 + (knobA3 * 75.0); | |||
| granular1.beginPitchShift(msec); | |||
| Serial.print("Begin granular pitch phift using "); | |||
| Serial.print(msec); | |||
| Serial.println(" grains"); | |||
| } | |||
| if (button1.risingEdge()) { | |||
| granular1.stop(); | |||
| } | |||
| // continuously adjust pitch bend | |||
| granular1.rate(knobA2 * 1023.0); | |||
| // Continuously adjust the speed, based on the A3 pot | |||
| float ratio; | |||
| ratio = powf(2.0, knobA2 * 2.0 - 1.0); // 0.5 to 2.0 | |||
| //ratio = powf(2.0, knobA2 * 6.0 - 3.0); // 0.125 to 8.0 -- uncomment for far too much range! | |||
| granular1.setSpeed(ratio); | |||
| } | |||
| @@ -93,6 +93,9 @@ disableDither KEYWORD2 | |||
| reverbTime KEYWORD2 | |||
| roomsize KEYWORD2 | |||
| damping KEYWORD2 | |||
| setSpeed KEYWORD2 | |||
| beginFreeze KEYWORD2 | |||
| beginPitchShift KEYWORD2 | |||
| frequency KEYWORD2 | |||
| phase KEYWORD2 | |||
| amplitude KEYWORD2 | |||