| read_head = 0; | read_head = 0; | ||||
| write_head = 0; | write_head = 0; | ||||
| prev_input = 0; | prev_input = 0; | ||||
| playpack_rate = 512; | |||||
| playpack_rate = 65536; | |||||
| accumulator = 0; | accumulator = 0; | ||||
| allow_len_change = true; | allow_len_change = true; | ||||
| sample_loaded = false; | sample_loaded = false; | ||||
| write_en = false; | write_en = false; | ||||
| sample_req = true; | sample_req = true; | ||||
| __enable_irq(); | __enable_irq(); | ||||
| Serial.print("in = "); | |||||
| Serial.print(grain_samples); | |||||
| Serial.print(", freeze len = "); | |||||
| Serial.println(freeze_len); | |||||
| } | } | ||||
| void AudioEffectGranular::beginPitchShift_int(int grain_samples) | void AudioEffectGranular::beginPitchShift_int(int grain_samples) | ||||
| allow_len_change = true; | allow_len_change = true; | ||||
| } | } | ||||
| void AudioEffectGranular::rate(int16_t playpack_rate_def) | |||||
| { | |||||
| playpack_rate = playpack_rate_def; | |||||
| } | |||||
| void AudioEffectGranular::update(void) | void AudioEffectGranular::update(void) | ||||
| { | { | ||||
| audio_block_t *block; | audio_block_t *block; | ||||
| prev_input = block->data[AUDIO_BLOCK_SAMPLES-1]; | prev_input = block->data[AUDIO_BLOCK_SAMPLES-1]; | ||||
| } | } | ||||
| else if (grain_mode == 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++) { | for (int j = 0; j < AUDIO_BLOCK_SAMPLES; j++) { | ||||
| if (sample_req) { | if (sample_req) { | ||||
| // only begin capture on zero cross | // only begin capture on zero cross | ||||
| write_head = 0; | write_head = 0; | ||||
| read_head = 0; | read_head = 0; | ||||
| sample_req = false; | sample_req = false; | ||||
| Serial.println("begin freeze capture"); | |||||
| } else { | } else { | ||||
| prev_input = current_input; | prev_input = current_input; | ||||
| } | } | ||||
| } | } | ||||
| if (write_head >= max_sample_len) { | if (write_head >= max_sample_len) { | ||||
| write_en = false; | write_en = false; | ||||
| Serial.println("end freeze capture"); | |||||
| } | } | ||||
| } | } | ||||
| if (sample_loaded) { | if (sample_loaded) { | ||||
| if (playpack_rate >= 0) { | if (playpack_rate >= 0) { | ||||
| accumulator += playpack_rate; | accumulator += playpack_rate; | ||||
| read_head = accumulator >> 9; | |||||
| read_head = accumulator >> 16; | |||||
| } | } | ||||
| if (read_head >= freeze_len) { | if (read_head >= freeze_len) { | ||||
| accumulator = 0; | accumulator = 0; | ||||
| } | } | ||||
| accumulator += playpack_rate; | accumulator += playpack_rate; | ||||
| read_head = (accumulator >> 9); | |||||
| read_head = (accumulator >> 16); | |||||
| if (read_head >= glitch_len) { | if (read_head >= glitch_len) { | ||||
| read_head -= glitch_len; | read_head -= glitch_len; |
| public: | public: | ||||
| AudioEffectGranular(void): AudioStream(1,inputQueueArray) { } | AudioEffectGranular(void): AudioStream(1,inputQueueArray) { } | ||||
| void begin(int16_t *sample_bank_def, int16_t max_len_def); | 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) { | void beginFreeze(float grain_length) { | ||||
| if (grain_length <= 0.0) return; | if (grain_length <= 0.0) return; | ||||
| beginFreeze_int(grain_length * (AUDIO_SAMPLE_RATE_EXACT * 0.001) + 0.5); | beginFreeze_int(grain_length * (AUDIO_SAMPLE_RATE_EXACT * 0.001) + 0.5); | ||||
| void beginPitchShift_int(int grain_samples); | void beginPitchShift_int(int grain_samples); | ||||
| audio_block_t *inputQueueArray[1]; | audio_block_t *inputQueueArray[1]; | ||||
| int16_t *sample_bank; | int16_t *sample_bank; | ||||
| uint32_t playpack_rate; | |||||
| uint32_t accumulator; | |||||
| int16_t max_sample_len; | int16_t max_sample_len; | ||||
| int16_t write_head; | int16_t write_head; | ||||
| int16_t read_head; | int16_t read_head; | ||||
| int16_t grain_mode; | int16_t grain_mode; | ||||
| int16_t freeze_len; | int16_t freeze_len; | ||||
| int16_t playpack_rate; | |||||
| int32_t accumulator; | |||||
| int16_t prev_input; | int16_t prev_input; | ||||
| int16_t glitch_len; | int16_t glitch_len; | ||||
| bool allow_len_change; | bool allow_len_change; |
| // 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 <Audio.h> | ||||
| #include <Wire.h> | #include <Wire.h> | ||||
| #include <SPI.h> | #include <SPI.h> | ||||
| float knobA2 = (float)analogRead(A2) / 1023.0; | float knobA2 = (float)analogRead(A2) / 1023.0; | ||||
| float knobA3 = (float)analogRead(A3) / 1023.0; | float knobA3 = (float)analogRead(A3) / 1023.0; | ||||
| // Button 0 starts Freeze effect | |||||
| if (button0.fallingEdge()) { | 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()) { | if (button0.risingEdge()) { | ||||
| granular1.stop(); | granular1.stop(); | ||||
| } | } | ||||
| // Button 1 starts Pitch Shift effect | |||||
| if (button1.fallingEdge()) { | 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()) { | if (button1.risingEdge()) { | ||||
| granular1.stop(); | 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); | |||||
| } | } |
| reverbTime KEYWORD2 | reverbTime KEYWORD2 | ||||
| roomsize KEYWORD2 | roomsize KEYWORD2 | ||||
| damping KEYWORD2 | damping KEYWORD2 | ||||
| setSpeed KEYWORD2 | |||||
| beginFreeze KEYWORD2 | |||||
| beginPitchShift KEYWORD2 | |||||
| frequency KEYWORD2 | frequency KEYWORD2 | ||||
| phase KEYWORD2 | phase KEYWORD2 | ||||
| amplitude KEYWORD2 | amplitude KEYWORD2 |