|
- /*
- * Copyright (c) 2018 John-Michael Reed
- * bleeplabs.com
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
- #include <Arduino.h>
- #include "effect_granular.h"
-
- void AudioEffectGranular::begin(int16_t *sample_bank_def, int16_t max_len_def)
- {
- sample_req=1;
- length(max_len_def - 1);
- sample_bank = sample_bank_def;
- }
-
- void AudioEffectGranular::length(int16_t max_len_def)
- {
- if (max_len_def < 100) {
- max_sample_len = 100;
- glitch_len = max_sample_len/3;
- } else {
- max_sample_len = (max_len_def - 1);
- glitch_len = max_sample_len/3;
- }
- }
-
-
- void AudioEffectGranular::freeze(int16_t activate, int16_t playpack_rate_def, int16_t freeze_length_def)
- {
- if (activate==1) {
- grain_mode = 1;
- }
- if (activate==0) {
- grain_mode = 0;
- }
- rate(playpack_rate_def);
- if (freeze_length_def < 50) {
- freeze_len = 50;
- }
- if (freeze_length_def>=max_sample_len) {
- freeze_len = max_sample_len;
- }
- if (freeze_length_def>=50 && freeze_length_def<max_sample_len) {
- freeze_len = freeze_length_def;
- }
- }
-
- void AudioEffectGranular::shift(int16_t activate, int16_t playpack_rate_def, int16_t grain_length_def)
- {
- if (activate == 1) {
- grain_mode = 2;
- }
- if (activate == 0) {
- grain_mode = 3;
- }
- rate(playpack_rate_def);
- if (allow_len_change == 1 ) {
- // Serial.println("aL");
- length(grain_length_def);
- }
- }
-
-
- void AudioEffectGranular::rate(int16_t playpack_rate_def)
- {
- playpack_rate = playpack_rate_def;
- }
-
-
- void AudioEffectGranular::update(void)
- {
- audio_block_t *block;
-
- if (sample_bank == NULL) return;
-
- block = receiveWritable(0);
- if (!block) return;
-
- if (grain_mode == 3) {
- //through
- /*
- for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
- write_head++;
- if (write_head >= max_sample_len) {
- write_head = 0;
- }
- sample_bank[write_head] = block->data[i];
- }
- */
- }
-
- if (grain_mode == 0) {
- //capture audio but dosen't output
- //this needs to be happening at all times if you want to
- // use grain_mode = 1, the simple "freeze" sampler.
- for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
- write_head++;
-
- if (write_head >= max_sample_len) {
- write_head = 0;
- }
- sample_bank[write_head] = block->data[i];
- }
- }
-
-
- if (grain_mode == 1) {
- //when activated the last
- for (int j = 0; j < AUDIO_BLOCK_SAMPLES; j++) {
- if (playpack_rate >= 0) {
- accumulator += playpack_rate;
- read_head = accumulator >> 9;
- }
- if (read_head >= freeze_len) {
- accumulator = 0;
- read_head -= max_sample_len;
- }
- block->data[j] = sample_bank[read_head];
- }
- }
-
- if (grain_mode == 2) {
- //GLITCH SHIFT
- //basic granular synth thingy
- // the shorter the sample the max_sample_len the more tonal it is.
- // Longer it has more definition. It's a bit roboty either way which
- // is obv great and good enough for noise music.
-
- for (int k = 0; k < AUDIO_BLOCK_SAMPLES; k++) {
- int16_t current_input = block->data[k];
- //we only want to start recodeing when the audio is crossing zero to minimize pops
- if ((current_input<0 && prev_input>0)) {
- zero_cross_down=1;
- } else {
- zero_cross_down=0;
- }
-
- prev_input=current_input;
-
- if (zero_cross_down == 1 && sample_req == 1) {
- write_en=1;
- }
- if (write_en==1) {
- sample_req=0;
- allow_len_change=1; //reduces noise by not allowing the length to
- // change after the sample has been recored.
- // kind of not too much though
- if (write_head >= glitch_len) {
- glitch_cross_len=glitch_len;
- write_head = 0;
- sample_loaded = 1;
- write_en=0;
- allow_len_change=0;
- }
- sample_bank[write_head] = block->data[k];
- write_head++;
- }
-
- if (sample_loaded == 1) {
- //move it to the middle third of the bank.
- //3 "seperate" banks are used
- float fade_len=20.00;
- int16_t m2=fade_len;
-
- for (int m = 0; m < 2; m++) {
- // I'm off by one somewhere? why is there a tick at the
- // beginning of this only when it's combined with the
- // fade out???? ooor am i osbserving that incorrectly
- // either wait it works enough
- sample_bank[m + glitch_len] = 0;
- }
-
- for (int m = 2; m < glitch_len-m2; m++) {
- sample_bank[m + glitch_len] = sample_bank[m];
- }
-
- for (int m = glitch_len-m2; m < glitch_len; m++) {
- // fade out the end. You can just make fadet=0
- // but it's a little too daleky
- float fadet=sample_bank[m]*(m2/fade_len);
- sample_bank[m + glitch_len] = (int16_t)fadet;
- m2--;
- }
- sample_loaded = 0;
- sample_req=1;
- }
-
- accumulator += playpack_rate;
- read_head = (accumulator >> 9);
-
- if (read_head >= glitch_len) {
- read_head -= (glitch_len);
- accumulator=0;
-
- for (int m = 0; m < glitch_len; m++) {
- sample_bank[m + (glitch_len*2)] = sample_bank[m+glitch_len];
- // sample_bank[m + (glitch_len*2)] = (m%20)*1000;
- }
- }
- block->data[k] = sample_bank[read_head+(glitch_len*2)];
- }
- }
- transmit(block);
- release(block);
- }
-
-
-
|