/*
 *  Copyright 1994-2022 Olivier Girondel
 *  Copyright 2019-2022 Tavasti
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  lebiniou is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

/* Colrot, Color Rotation

   basic idea of plugin: Show only part of the colors from webcam video,
   and scroll thru colors. Not visible colors are transparent,
   showing stuff happening under. Using lens mode.

   This plugin is beat version which is scrolling colors only at the beat.
   With higher volume, more bigger scroll.

   At the beat also more colors are visible, giving stronger feedabck to beat
*/


#include "context.h"
#include "pthread_utils.h"


#define MASK_SIZE  63 /* what size of chunks colorspace is divided */
#define COLORCOUNT 7  /* how many colors are visible in each chunk */

#define CURVE_VOL_MIN     0.05 /* Minimum volume we start changing curve */
#define CURVE_VOL_STEP    0.1  /* Volume amount we step on curve */
#define CURVE_VOL_MULT    1.7  /* multiplier on each step */
#define CURVE_DIVISOR     4    /* value we are finally dividing increment */
#define MAX_INCREMENT     9    /* maximum value of increment */
#define INC_MULT_TO_COUNT 5    /* multiplier from increment to added colors */
#define INIT_INCREMENT    2    /* initial increment on beat. Algorithm works if
                                  floor(INIT_INC * CURVE_VOL_STEP) > INIT_INC  */
uint32_t version = 0;
uint32_t options = BO_GFX | BO_WEBCAM | BO_LENS | BO_SFX;
char desc[] = "Show overlay of cam, scrolling thru colors on beat";
char dname[] = "TV colrot beat";
enum LayerMode mode = LM_OVERLAY;

extern int webcams;
static Pixel_t min1 = 0, max1 = COLORCOUNT;


void
run(Context_t *ctx)
{
  /* increment calculation */
  int increment = INIT_INCREMENT;
  if (ctx->input->on_beat) {
    double peak;
    for (peak = ctx->input->curpeak; peak > CURVE_VOL_MIN; peak -= CURVE_VOL_STEP) {
      increment *= CURVE_VOL_MULT;
    }
  } else {
    increment = 0; /* no progression outside beat */
  }
  increment = increment / CURVE_DIVISOR;
  if (increment > MAX_INCREMENT) {
    increment = MAX_INCREMENT;
  }
  int prevmax = max1;
  /* To show more colors on beat we raise max1 on this run, but return after */
  max1 += increment * INC_MULT_TO_COUNT;
  if (max1 > MASK_SIZE) {
    max1 = max1 - MASK_SIZE;
  }

  Pixel_t *src1, *start, *dst;

  dst = start = passive_buffer(ctx)->buffer;

  if (!xpthread_mutex_lock(&ctx->cam_mtx[ctx->cam])) {
    src1 = ctx->cam_save[ctx->cam][0]->buffer;
    for (; dst < start + BUFFSIZE * sizeof(Pixel_t); src1++, dst++) {
      if (/* max1 is bigger than min, show values between them */
          ((max1 > min1) &&
           ((*src1 & MASK_SIZE) > min1) && ((*src1 & MASK_SIZE) < max1)) ||
          /* max is rotated over, show values below max or above min */
          ((max1 < min1) &&
           (((*src1 & MASK_SIZE)> min1) || ((*src1 & MASK_SIZE) < max1)))) {
        *dst = *src1;
      } else {
        *dst = 0;
      }
    }
    xpthread_mutex_unlock(&ctx->cam_mtx[ctx->cam]);
  }
  /* restore max1 to previous, and add increment */
  max1 = prevmax + increment;
  if (max1 > MASK_SIZE) {
    max1 -= MASK_SIZE;
  }
  min1 += increment;
  if (min1 > MASK_SIZE) {
    min1 -= MASK_SIZE;
  }
}
