108 changes: 108 additions & 0 deletions ports/argotlunar/Source/DelayLine.cpp
@@ -0,0 +1,108 @@
#include "DelayLine.h"

DelayLine::DelayLine(const int buffer_seconds, const int internal_block_size)
{
this->buffer_seconds = buffer_seconds;
this->internal_block_size = internal_block_size;
highpass_filter = new Filter();
initialized = false;
}

void DelayLine::initialize(float samplerate)
{
deleteBuffers();
delay_buffer_length = static_cast<int>(samplerate * buffer_seconds);
delay_buffer = new float[delay_buffer_length + 3];
feedback_buffer = new float[internal_block_size];
highpass_filter->initializeHz(100.0f, 0.0f, FILTER_HIGH, samplerate);
delay_buffer_start = 1;
delay_write_pos = delay_buffer_start;
delay_buffer_end = delay_buffer_length;
feedback_write_pos = 0;
initialized = true;

for(int i = 0; i < (delay_buffer_length + 3); i++)
delay_buffer[i] = 10E-12f;
for (int i = 0; i < internal_block_size; i++)
feedback_buffer[i] = 10E-12f;
}

DelayLine::~DelayLine()
{
deleteBuffers();
delete highpass_filter;
}

void DelayLine::deleteBuffers()
{
if (!initialized)
return;
delete[] delay_buffer;
delete[] feedback_buffer;
initialized = false;
}

void DelayLine::writeDelayBuffer(float* chan1, float* chan2,
int sampleframes, bool freeze, float input_gain, float feedback_gain)
{
block_read_pos = delay_write_pos;

if (freeze) {
delay_write_pos += sampleframes;
if (delay_write_pos > delay_buffer_length)
delay_write_pos -= delay_buffer_length;

} else {
float sample;
feedback_read_pos = feedback_write_pos;

for (int i = 0; i < sampleframes; i++) {
sample = (chan1[i] + chan2[i]) / 2.0f;
sample *= input_gain;
sample += feedback_gain * feedback_buffer[feedback_read_pos];

delay_buffer[delay_write_pos] = sample;
feedback_read_pos++;

if (feedback_read_pos == internal_block_size) {
feedback_read_pos = 0;
}
if (delay_write_pos == delay_buffer_start) {
delay_buffer[delay_buffer_end + 1] = sample;
} else if (delay_write_pos == (delay_buffer_start + 1)) {
delay_buffer[delay_buffer_end + 2] = sample;
} else if (delay_write_pos == delay_buffer_end) {
delay_buffer[0] = sample;
delay_write_pos = (delay_buffer_start - 1);
}
delay_write_pos++;
}
}
}

void DelayLine::writeFeedbackBuffer(float* chan1, float* chan2, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
feedback_buffer[feedback_write_pos++] = (chan1[i] + chan2[i]) / 2.0f;
if (feedback_write_pos == internal_block_size)
feedback_write_pos = 0;
}
highpass_filter->process(feedback_buffer, sampleframes);
}

int DelayLine::getDelayLength()
{
return delay_buffer_length;
}

float* DelayLine::getDelayPointer()
{
return delay_buffer;
}

/* Returns cached start-position of previously written block */
int DelayLine::getBlockReadPos()
{
return block_read_pos;
}

38 changes: 38 additions & 0 deletions ports/argotlunar/Source/DelayLine.h
@@ -0,0 +1,38 @@
#ifndef DELAYLINE_H
#define DELAYLINE_H

#include "Debug.h"
#include "Filter.h"

class DelayLine
{
public:
DelayLine(const int buffer_seconds, const int internal_block_size);
~DelayLine();
int getBlockReadPos();
int getDelayLength();
float* getDelayPointer();
void initialize(float samplerate);
void writeFeedbackBuffer(float* chan1, float* chan2, int sampleframes);
void writeDelayBuffer(float* chan1, float* chan2, int sampleframes,
bool freeze, float input_gain, float feedback_gain);

private:
void deleteBuffers();

Filter* highpass_filter;
float *delay_buffer;
float *feedback_buffer;
int delay_buffer_length;
int delay_buffer_start;
int delay_buffer_end;
int delay_write_pos;
int block_read_pos;
int feedback_write_pos;
int feedback_read_pos;
int buffer_seconds;
int internal_block_size;
bool initialized;
};

#endif //DELAYLINE_H
157 changes: 157 additions & 0 deletions ports/argotlunar/Source/Envelope.cpp
@@ -0,0 +1,157 @@
#include "Envelope.h"

Envelope::Envelope()
{
pi = 4.0f * atan(1.0f);
}

void Envelope::initialize(int env_type, int grain_dur, float grain_dur_ratio,
float env_shape, float env_skew, float grain_amp)
{
this->env_type = env_type;
this->grain_amp = grain_amp;
process_counter = 0;
env_amp = 0.0f;
env_shape = env_shape * 0.9f + 0.05f;
env_skew = env_skew * 0.9f + 0.05f;

if (env_type == ENV_PARABOLIC) {
float d = 1.0f / grain_dur;
float d2 = d * d;
slope = 4.0f * grain_amp * (d - d2);
curve = -8.0f * grain_amp * d2;

} else if (env_type == ENV_TRIANGLE) {
triangle_midpoint = static_cast<int>(grain_dur * env_skew);
triangle_attack_increment = grain_amp / triangle_midpoint;
triangle_decay_increment = grain_amp / (grain_dur - triangle_midpoint);

} else if (env_type == ENV_RCB) {
// reduce skew for shorter grains
env_skew = 0.5f + ((env_skew - 0.5f) * grain_dur_ratio);
// reduce sustain for shorter grains
sustain_samples = static_cast<int>(env_shape * grain_dur_ratio * grain_dur);
attack_samples = static_cast<int>(env_skew * (grain_dur - sustain_samples));
release_samples = grain_dur - sustain_samples - attack_samples;
attack_angle = pi;
attack_angle_increment = pi / attack_samples;
release_angle = 0.0f;
release_angle_increment = pi / release_samples;
release_boundary = attack_samples + sustain_samples;
}
}

void Envelope::process(float* input, int sampleframes)
{
switch(env_type) {
case ENV_PARABOLIC:
processParabolic(input, sampleframes);
break;
case ENV_TRIANGLE:
processTriangle(input, sampleframes);
break;
case ENV_RCB:
processRCB(input, sampleframes);
}
}

void Envelope::processParabolic(float* input, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
env_amp += slope;
slope += curve;
input[i] *= env_amp;
}
}

void Envelope::processTriangle(float* input, int sampleframes)
{
int blockEnd = (process_counter + sampleframes);

if (blockEnd < triangle_midpoint) {
for (int i = 0; i < sampleframes; i++) {
env_amp += triangle_attack_increment;
input[i] *= env_amp;
}
} else if (process_counter >= triangle_midpoint
&& blockEnd < duration) {
for (int i = 0; i < sampleframes; i++) {
env_amp -= triangle_decay_increment;
input[i] *= env_amp;
}
} else {
processTriangleBoundary(input, sampleframes);
return;
}
process_counter += sampleframes;
}

void Envelope::processTriangleBoundary(float* input, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
if (process_counter < triangle_midpoint) {
env_amp += triangle_attack_increment;
} else {
env_amp -= triangle_decay_increment;
}
input[i] *= env_amp;
process_counter++;
}
}

void Envelope::processRCB(float* input, int sampleframes)
{
int blockEnd = (process_counter + sampleframes);

if (blockEnd < attack_samples) {
for (int i = 0; i < sampleframes; i++) {
input[i] *= grain_amp * (0.5f + 0.5f * fastCosine(attack_angle));
attack_angle += attack_angle_increment;
}
} else if (process_counter >= attack_samples
&& blockEnd < release_boundary) {
for (int i = 0; i < sampleframes; i++) {
input[i] *= grain_amp;
}
} else if (process_counter >= release_boundary
&& blockEnd < duration) {
for (int i = 0; i < sampleframes; i++) {
input[i] *= grain_amp * (0.5f + 0.5f * fastCosine(release_angle));
release_angle += release_angle_increment;
}
} else {
processRCBBoundary(input, sampleframes);
return;
}
process_counter += sampleframes;
}

void Envelope::processRCBBoundary(float* input, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
if (process_counter < attack_samples) {
input[i] *= grain_amp * (0.5f + 0.5f * fastCosine(attack_angle));
attack_angle += attack_angle_increment;
} else if (process_counter < release_boundary) {
input[i] *= grain_amp;
} else {
input[i] *= grain_amp * (0.5f + 0.5f * fastCosine(release_angle));
release_angle += release_angle_increment;
}
process_counter++;
}
}

inline float Envelope::fastCosine(float angle)
{
angle += 1.57079632f;
if (angle > 3.14159265f) {
angle -= 6.28318531f;
}
if (angle < 0) {
return 1.273239545f * angle + 0.405284735f * angle * angle;
} else {
return 1.273239545f * angle - 0.405284735f * angle * angle;
}
}

45 changes: 45 additions & 0 deletions ports/argotlunar/Source/Envelope.h
@@ -0,0 +1,45 @@
#ifndef ENVELOPE_H
#define ENVELOPE_H

#include <math.h>
#include "Debug.h"

enum EnvType {
ENV_RCB,
ENV_PARABOLIC,
ENV_TRIANGLE
};

class Envelope
{
public:
Envelope();
void process(float* input, int sampleframes);
void initialize(int env_type, int grain_dur, float grain_dur_ratio,
float env_shape, float env_skew, float grain_amp);

private:
void processParabolic(float* input, int sampleframes);
void processTriangle(float* input, int sampleframes);
void processTriangleBoundary(float* input, int sampleframes);
void processRCB(float* input, int sampleframes);
void processRCBBoundary(float* input, int sampleframes);
inline float fastCosine(float angle);

float pi;
float env_amp, grain_amp;
int env_type;
int process_counter;
int duration;
// parabolic
float slope, curve;
// raised cosine bell
float attack_angle, attack_angle_increment, release_angle, release_angle_increment;
int attack_samples, sustain_samples, release_samples, release_boundary;
// triangle
float triangle_attack_increment;
float triangle_decay_increment;
int triangle_midpoint;
};

#endif //ENVELOPE_H
91 changes: 91 additions & 0 deletions ports/argotlunar/Source/Filter.cpp
@@ -0,0 +1,91 @@
#include "Filter.h"


Filter::Filter()
{
pi = 4.0f * atan(1.0f);
}

// valid params between 0.0f - 1.0f
void Filter::initialize(float freq_param, float q_param, int type, float samplerate)
{
float freq_hz = pow(10.0f, freq_param * 3.0f) * 22.05f;
freq = sin(pi * freq_hz / samplerate);
q = sqrt(1.0f - atan(sqrt(100.0f * q_param)) * 2.0f / pi);
scale = sqrt(q);
low = high = band = 0.0f;
this->type = type;
}

// valid freq_hz between 22.05f - 22050.0f
void Filter::initializeHz(float freq_hz, float q_param, int type, float samplerate)
{
freq = sin(pi * freq_hz / samplerate);
q = sqrt(1.0f - atan(sqrt(100.0f * q_param)) * 2.0f / pi);
scale = sqrt(q);
low = high = band = 0.0f;
this->type = type;
}

void Filter::process(float* input, int sampleframes)
{
switch (type) {
case FILTER_BAND:
processBand(input, sampleframes);
return;
case FILTER_LOW:
processLow(input, sampleframes);
return;
case FILTER_HIGH:
processHigh(input, sampleframes);
return;
case FILTER_NOTCH:
processNotch(input, sampleframes);
return;
}
}

inline void Filter::algorithm(float input)
{
// 2x oversampling
low = low + freq * band;
high = scale * input - low - q * band;
band = freq * high + band;

low = low + freq * band;
high = scale * input - low - q * band;
band = freq * high + band;
}

void Filter::processBand(float* input, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
algorithm(input[i]);
input[i] = band;
}
}

void Filter::processLow(float* input, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
algorithm(input[i]);
input[i] = low;
}
}

void Filter::processHigh(float* input, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
algorithm(input[i]);
input[i] = high;
}
}

void Filter::processNotch(float* input, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
algorithm(input[i]);
input[i] = high + low;
}
}

36 changes: 36 additions & 0 deletions ports/argotlunar/Source/Filter.h
@@ -0,0 +1,36 @@
#ifndef FILTER_H
#define FILTER_H

#include <math.h>
#include "Debug.h"

enum FilterMode {
FILTER_OFF,
FILTER_BAND,
FILTER_LOW,
FILTER_HIGH,
FILTER_NOTCH,
FILTER_COMB,
FILTER_RANDOM
};

class Filter
{
public:
Filter();
void initialize(float freq_param, float q_param, int type, float samplerate);
void initializeHz(float freq_hz, float q_param, int type, float samplerate);
void process(float* input, int sampleframes);

private:
inline void algorithm(float input);
void processHigh(float* input, int sampleframes);
void processLow(float* input, int sampleframes);
void processBand(float* input, int sampleframes);
void processNotch(float* input, int sampleframes);

float pi, low, high, band, freq, q, scale;
int type;
};

#endif
173 changes: 173 additions & 0 deletions ports/argotlunar/Source/Grain.cpp
@@ -0,0 +1,173 @@
#include "Grain.h"

Grain::Grain(const float samplerate, const int buflen, const int internal_block_size,
float* buffer, float* out1, float* out2)
{
this->samplerate = samplerate;
this->buflen = buflen;
this->internal_block_size = internal_block_size;
this->buffer = buffer;
this->out1 = out1;
this->out2 = out2;
activated = false;
initialized = false;
marked_for_deactivation = false;
comb_filter = new CombFilter(samplerate);
env = new Envelope();
multimode_filter = new Filter();
output_buffer = new float[internal_block_size];
}

Grain::~Grain()
{
delete comb_filter;
delete env;
delete multimode_filter;
delete[] output_buffer;
}

void Grain::activate()
{
activated = true;
initialized = false;
marked_for_deactivation = false;
}

void Grain::deactivate()
{
if (initialized) {
marked_for_deactivation = true;
} else {
activated = false;
}
}

inline void Grain::incrementReadPos()
{
delaybuf_readpos_int++;
if (delaybuf_readpos_int > buflen)
delaybuf_readpos_int -= buflen;
}

inline void Grain::incrementReadPosFrac()
{
delaybuf_readpos_float += trans;
delaybuf_readpos_int = static_cast<int>(delaybuf_readpos_float);
if (delaybuf_readpos_int > buflen) {
delaybuf_readpos_float -= buflen;
delaybuf_readpos_int = static_cast<int>(delaybuf_readpos_float);
}
trans += gliss;
}

void Grain::initialize(const GrainParameters& grain_parameters)
{
amp = grain_parameters.amp;
delaybuf_readpos_int = grain_parameters.bufstart;
delaybuf_readpos_float = static_cast<float>(grain_parameters.bufstart);
duration = grain_parameters.duration;
filter_type = grain_parameters.filter_type;
gliss = grain_parameters.gliss;
gliss_enabled = (gliss == 0.0f) ? false : true;
iot = grain_parameters.iot;
pan_left = grain_parameters.pan;
pan_right = 1.0f - grain_parameters.pan;
trans = grain_parameters.trans;

switch(filter_type) {
case FILTER_OFF:
break;
case FILTER_COMB:
comb_filter->initialize(grain_parameters.ffreq, grain_parameters.fq);
break;
default:
multimode_filter->initialize(grain_parameters.ffreq,grain_parameters.fq,
filter_type, samplerate);
break;
}

env->initialize(grain_parameters.env_type,
duration,
grain_parameters.duration_ratio,
grain_parameters.env_shape,
grain_parameters.env_skew,
amp);

for (int i = 0; i < internal_block_size; i++)
output_buffer[i] = 10E-12f;

process_counter = 0;
initialized = true;
}

void Grain::process(int sampleframes)
{
if (iot > 0) {
iot -= sampleframes;
if (iot < 0) {
sampleframes = -iot;
} else {
return;
}
}

int block_end = process_counter + sampleframes;
if (block_end <= duration) {
readBuffer(sampleframes);
} else {
int intrablock_offset = duration - process_counter;
readBuffer(intrablock_offset);
for (int i = sampleframes; i < internal_block_size; i++) {
output_buffer[i] = 10E-12f;
}
if (marked_for_deactivation) {
activated = false;
marked_for_deactivation = false;
}
initialized = false;
return;
}

if (filter_type != FILTER_OFF && filter_type != FILTER_COMB)
multimode_filter->process(output_buffer, sampleframes);

env->process(output_buffer, sampleframes);

// comb filter generally sounds better post-envelope
if (filter_type == FILTER_COMB)
comb_filter->process(output_buffer, sampleframes);

for (int i = 0; i < sampleframes; i++) {
out1[i] += (output_buffer[i] * pan_right);
out2[i] += (output_buffer[i] * pan_left);
}
}

void Grain::readBuffer(int sampleframes)
{
if ((trans != 1.0f) || gliss_enabled) {
for (int i = 0; i < sampleframes; i++) {
output_buffer[i] = cubicInterpolation(
(delaybuf_readpos_float - delaybuf_readpos_int),
buffer[delaybuf_readpos_int - 1],
buffer[delaybuf_readpos_int],
buffer[delaybuf_readpos_int + 1],
buffer[delaybuf_readpos_int + 2]);
incrementReadPosFrac();
}
} else {
for (int i = 0; i < sampleframes; i++) {
output_buffer[i] = buffer[delaybuf_readpos_int];
incrementReadPos();
}
}
process_counter += sampleframes;
}

inline float Grain::cubicInterpolation(float frac, float y0, float y1, float y2, float y3)
{
c1 = 0.5f * (y2 - y0);
c3 = 1.5f * (y1 - y2) + 0.5f * (y3 - y0);
c2 = y0 - y1 + c1 - c3;
return ((c3 * frac + c2) * frac + c1) * frac + y1;
}
47 changes: 47 additions & 0 deletions ports/argotlunar/Source/Grain.h
@@ -0,0 +1,47 @@
#ifndef GRAIN_H
#define GRAIN_H

#include "../JuceLibraryCode/JuceHeader.h"
#include "Debug.h"
#include "CombFilter.h"
#include "Envelope.h"
#include "Filter.h"
#include "GrainParameters.h"
#include "Misc.h"

class Grain
{
public:
Grain(const float samplerate, const int buflen, const int internal_block_size,
float* buffer, float* out1, float* out2);
~Grain();
void initialize(const GrainParameters& grain_parameters);
void process(int sampleframes);
void activate();
void deactivate();

bool activated, initialized;
int iot;
bool finished_processing;

private:
void readBuffer(int sampleframes);
inline void incrementReadPos();
inline void incrementReadPosFrac();
inline float cubicInterpolation(float frac, float y0, float y1, float y2, float y3);

int internal_block_size;
int duration, env_type, process_counter, buflen, buf_end, filter_type, delaybuf_readpos_int;
float amp, pan_left, pan_right, trans, gliss, delaybuf_readpos_float, env_amp;
float *output_buffer;
float frac, c1, c2, c3; // interpolation
float *buffer, *out1, *out2;
float samplerate;
bool gliss_enabled;
bool marked_for_deactivation;
Filter* multimode_filter;
CombFilter* comb_filter;
Envelope* env;
};

#endif //GRAIN_H
21 changes: 21 additions & 0 deletions ports/argotlunar/Source/GrainParameters.h
@@ -0,0 +1,21 @@
#ifndef GRAINPARAMETERS_H
#define GRAINPARAMETERS_H

struct GrainParameters {
int iot;
int duration;
int bufstart;
int filter_type;
int env_type;
float amp;
float pan;
float duration_ratio;
float trans;
float gliss;
float ffreq;
float fq;
float env_shape;
float env_skew;
};

#endif //GRAINPARAMETERS_H
383 changes: 383 additions & 0 deletions ports/argotlunar/Source/GrainParametersGenerator.cpp
@@ -0,0 +1,383 @@
#include "GrainParametersGenerator.h"

GrainParametersGenerator::GrainParametersGenerator(Parameters* parameters,
DelayLine* delay_line,
Granulator* granulator,
const int internal_block_size)
{
this->parameters = parameters;
this->delay_line = delay_line;
this->granulator = granulator;
this->time_quantizer = parameters->time_quantizer;
this->internal_block_size = internal_block_size;
random = new Random(Time::currentTimeMillis());
pitch_quantizer = new PitchQuantizer();
}

GrainParametersGenerator::~GrainParametersGenerator()
{
delete random;
delete pitch_quantizer;
}

const GrainParameters GrainParametersGenerator::getNewGrainParameters()
{
copyExternalParametersToInstanceVariables();
generateRandomizedParameters();
for (int i = 0; i < 3; i++)
applyModMatrix(i);
return generateFinalParameters();
}

void GrainParametersGenerator::copyExternalParametersToInstanceVariables()
{
mix = parameters->param[kMix];
input_gain = parameters->param[kIngain];
grains = parameters->param[kGrains];
feedback = parameters->param[kFeedback];
amp_min = parameters->param[kAmp];
delay_min = parameters->param[kDelay];
iot_min = parameters->param[kIot];
dur_min = parameters->param[kDur];
ffreq_min = parameters->param[kFfreq];
fq_min = parameters->param[kFq];
env_shape = parameters->param[kEnvSustain];
env_skew = parameters->param[kEnvSkew];
trans_toggle = parameters->param[kTransToggle];
gliss_toggle = parameters->param[kGlissToggle];
freeze_toggle = parameters->param[kFreezeToggle];
matrixmod1 = parameters->param[kMatrixMod1];
matrixmod2 = parameters->param[kMatrixMod2];
matrixmod3 = parameters->param[kMatrixMod3];
}

void GrainParametersGenerator::generateRandomizedParameters()
{
//============= Amp =============
amp_value = amp_min + random->nextFloat()
* (parameters->amp_max - amp_min);
//============= Pan =============
pan_value = parameters->pan_min + random->nextFloat()
* (parameters->pan_max - parameters->pan_min);
//============= Delay =============
delay_value = delay_min + random->nextFloat()
* (parameters->delay_max - delay_min);
//============= IOT =============
iot_value = iot_min + random->nextFloat()
* (parameters->iot_max - iot_min);
//============= Duration =============
dur_value = dur_min + random->nextFloat()
* (parameters->dur_max - dur_min);
//============= Transposition =============
trans_value = parameters->trans_min + random->nextFloat()
* (parameters->trans_max - parameters->trans_min);
//============= Glissando =============
gliss_value = parameters->gliss_min + random->nextFloat()
* (parameters->gliss_max - parameters->gliss_min);
//============= Filter =============
if (parameters->filter_type == FILTER_RANDOM) {
grain_parameters.filter_type = random->nextInt(5);
} else {
grain_parameters.filter_type = parameters->filter_type;
}
if (grain_parameters.filter_type != FILTER_OFF) {
ffreq_value = ffreq_min + random->nextFloat()
* (parameters->ffreq_max - ffreq_min);
fq_value = fq_min + random->nextFloat()
* (parameters->fq_max - fq_min);
}
}

bool GrainParametersGenerator::modSourceEqualsDest(ModSource source, ModDest dest)
{
switch (source) {
case MOD_SRC_AMP:
if (dest == MOD_DEST_AMP)
return true;
break;
case MOD_SRC_PAN_LR:
case MOD_SRC_PAN_WIDTH:
if (dest == MOD_DEST_PAN_LR)
return true;
break;
case MOD_SRC_DELAY:
if (dest == MOD_DEST_DELAY)
return true;
break;
case MOD_SRC_IOT:
if (dest == MOD_DEST_IOT)
return true;
break;
case MOD_SRC_DUR:
if (dest == MOD_DEST_DUR)
return true;
break;
case MOD_SRC_TRANS:
if (dest == MOD_DEST_TRANS)
return true;
break;
case MOD_SRC_GLISS:
if (dest == MOD_DEST_GLISS)
return true;
break;
case MOD_SRC_FFREQ:
if (dest == MOD_DEST_FFREQ)
return true;
break;
case MOD_SRC_FQ:
default:
if (dest == MOD_DEST_FQ)
return true;
break;

}
return false;
}

float GrainParametersGenerator::getModSourceValue(ModSource source, ModMode mode)
{
if (mode == MOD_MODE_DIRECT) {
switch (source) {
case MOD_SRC_AMP:
return amp_value;
case MOD_SRC_PAN_LR:
return pan_value;
case MOD_SRC_PAN_WIDTH:
return fabs((pan_value - 0.5f) * 2.0f);
case MOD_SRC_DELAY:
return delay_value;
case MOD_SRC_IOT:
return iot_value;
case MOD_SRC_DUR:
return dur_value;
case MOD_SRC_TRANS:
return trans_value;
case MOD_SRC_GLISS:
return gliss_value;
case MOD_SRC_FFREQ:
return ffreq_value;
case MOD_SRC_FQ:
default:
return fq_value;
}
} else if (mode == MOD_MODE_SCALED) {
float denominator;

switch (source) {
case MOD_SRC_AMP:
denominator = (parameters->amp_max - amp_min);
if (denominator == 0.0f) break;
return (amp_value - amp_min) / denominator;
case MOD_SRC_PAN_LR:
denominator = (parameters->pan_max - parameters->pan_min);
if (denominator == 0.0f) break;
return (pan_value - parameters->pan_min) / denominator;
case MOD_SRC_PAN_WIDTH: {
denominator = (parameters->pan_max - parameters->pan_min);
if (denominator == 0.0f) break;
float modvalue = (pan_value - parameters->pan_min) / denominator;
return fabs((modvalue - 0.5f) * 2.0f);
}
case MOD_SRC_DELAY:
denominator = (parameters->delay_max - delay_min);
if (denominator == 0.0f) break;
return (delay_value - delay_min) / denominator;
case MOD_SRC_IOT:
denominator = (parameters->iot_max - iot_min);
if (denominator == 0.0f) break;
return (iot_value - iot_min) / denominator;
case MOD_SRC_DUR:
denominator = (parameters->dur_max - dur_min);
if (denominator == 0.0f) break;
return (dur_value - dur_min) / denominator;
case MOD_SRC_TRANS:
denominator = (parameters->trans_max - parameters->trans_min);
if (denominator == 0.0f) break;
return (trans_value - parameters->trans_min) / denominator;
case MOD_SRC_GLISS:
denominator = (parameters->gliss_max - parameters->gliss_min);
if (denominator == 0.0f) break;
return (gliss_value - parameters->gliss_min) / denominator;
case MOD_SRC_FFREQ:
denominator = (parameters->ffreq_max - ffreq_min);
if (denominator == 0.0f) break;
return (ffreq_value - ffreq_min) / denominator;
case MOD_SRC_FQ:
default:
denominator = (parameters->fq_max - fq_min);
if (denominator == 0.0f) break;
return (fq_value - fq_min) / denominator;
}
}
return -100.0f;
}

float* GrainParametersGenerator::getModDestPtr(ModDest dest)
{
switch (dest) {
case MOD_DEST_AMP:
return &amp_value;
case MOD_DEST_PAN_LR:
return &pan_value;
case MOD_DEST_DELAY:
return &delay_value;
case MOD_DEST_IOT:
return &iot_value;
case MOD_DEST_DUR:
return &dur_value;
case MOD_DEST_TRANS:
return &trans_value;
case MOD_DEST_GLISS:
return &gliss_value;
case MOD_DEST_FFREQ:
return &ffreq_value;
case MOD_DEST_FQ:
return &fq_value;
case MOD_DEST_SUSTAIN:
return &env_shape;
case MOD_DEST_SKEW:
default:
return &env_skew;
}
}

void GrainParametersGenerator::applyModMatrix(int index)
{
float* dest_ptr;
float source_value = 0.0f;
float mod = 0.0f;
float ratio = 0.0f;
ModSource mod_source = parameters->matrix_source[index];
ModDest mod_dest = parameters->matrix_dest[index];
ModMode mod_mode = parameters->matrix_mode[index];

if (mod_source == MOD_SRC_OFF || mod_dest == MOD_DEST_OFF)
return;
if (modSourceEqualsDest(mod_source, mod_dest))
return;
source_value = getModSourceValue(mod_source, mod_mode);
if (source_value == -100.0f)
return;
dest_ptr = getModDestPtr(mod_dest);

switch (index) {
case 0:
mod = matrixmod1;
break;
case 1:
mod = matrixmod2;
break;
case 2:
mod = matrixmod3;
break;
}
mod = (mod * 2.0f) - 1.0f;
ratio = fabs(mod);
if (mod < 0.0f) {
mod = ratio * (1.0f - source_value);
} else {
mod = ratio * source_value;
}
*dest_ptr = (*dest_ptr * (1.0f - ratio)) + mod;
}

const GrainParameters GrainParametersGenerator::generateFinalParameters()
{
float millisecond_samples = parameters->getSampleRate() / 1000.0f;
//============= Amp =============
grain_parameters.amp = amp_value;
//============= Pan =============
grain_parameters.pan = pan_value;
//============= IOT =============
if (time_quantizer->getQuantizeMode(kIotQuant) == QUANT_MS) {
grain_parameters.iot = static_cast<int>(
parameters->getIOTMilliseconds(iot_value) * millisecond_samples);
} else {
grain_parameters.iot =
parameters->time_quantizer->quantizeStartPos(kIotQuant, iot_value);
}
//============= Duration =============
grain_parameters.duration_ratio = dur_value;

if (time_quantizer->getQuantizeMode(kDurQuant) == QUANT_MS) {
grain_parameters.duration = static_cast<int>(
parameters->getDurMilliseconds(dur_value) * millisecond_samples);
} else if (time_quantizer->getQuantizeMode(kDurQuant) == QUANT_MS_LONG) {
grain_parameters.duration = static_cast<int>(
parameters->getDurMilliseconds(dur_value) * millisecond_samples);
grain_parameters.duration *= 10;
} else {
grain_parameters.duration =
parameters->time_quantizer->quantizeLength(kDurQuant, dur_value);
}
//============= Transposition =============
if (trans_toggle == 0.0f) {
grain_parameters.trans = 1.0f;
} else if (parameters->scale == 0) {
grain_parameters.trans = pow(2.0f, (trans_value - 0.5f) * 4.0f);
} else {
grain_parameters.trans = pitch_quantizer->getQuantizedPitch(
(parameters->scale - 1), parameters->scale_key, trans_value);
trans_value = 0.25f * static_cast<float>((log(grain_parameters.trans)
/ log(2.0)) + 2.0);
}
//============= Glissando =============
float glissTrans = grain_parameters.trans;
if (gliss_toggle > 0.0f) {
if (trans_toggle > 0.0f) {
gliss_value = trans_value + (gliss_value - 0.5f);
}
if (gliss_value > 1.0f) {
gliss_value = 1.0f;
} else if (gliss_value < 0.0f) {
gliss_value = 0.0f;
}
glissTrans = pow(2.0f, (gliss_value - 0.5f) * 4.0f);
grain_parameters.gliss = (glissTrans - grain_parameters.trans)
/ grain_parameters.duration;
} else {
grain_parameters.gliss = 0.0f;
}
//============= Delay =============
int delay;
if (time_quantizer->getQuantizeMode(kDelayQuant) == QUANT_MS) {
delay = static_cast<int>(
parameters->getDelayMilliseconds(delay_value) * millisecond_samples);
} else {
delay = time_quantizer->quantizeStartPos(kDelayQuant, delay_value);
}
// increase delay if transposition increased
float highestTrans;
if (gliss_toggle == 1.0f && gliss_value != trans_value) {
highestTrans = (grain_parameters.trans > glissTrans) ?
grain_parameters.trans : glissTrans;
} else {
highestTrans = grain_parameters.trans;
}
if (highestTrans > 1.0f) {
delay += static_cast<int>((highestTrans-1.0f) * grain_parameters.duration);
}
//============= Envelope =============
grain_parameters.env_type = parameters->env_type;
grain_parameters.env_shape = env_shape;
grain_parameters.env_skew = env_skew;
//============= Filter =============
grain_parameters.ffreq = ffreq_value;
grain_parameters.fq = fq_value;
//============= bufstart =============
int buflen = delay_line->getDelayLength();
int maxdelay = buflen - internal_block_size;
if (delay > maxdelay)
delay = maxdelay;
grain_parameters.bufstart = static_cast<int>(delay_line->getBlockReadPos()
+ grain_parameters.iot
- delay);
if (grain_parameters.bufstart < 1) {
grain_parameters.bufstart += buflen;
} else if (grain_parameters.bufstart >= buflen) {
grain_parameters.bufstart -= buflen;
}
return grain_parameters;
}


61 changes: 61 additions & 0 deletions ports/argotlunar/Source/GrainParametersGenerator.h
@@ -0,0 +1,61 @@
#ifndef GRAINPARAMETERSGENERATOR_H
#define GRAINPARAMETERSGENERATOR_H

#include <math.h>
#include "../JuceLibraryCode/JuceHeader.h"
#include "GrainParameters.h"
#include "Granulator.h"
#include "Misc.h"
#include "ParametersEnum.h"
#include "TimeQuantizer.h"

class DelayLine;
class Granulator;
class Parameters;
class TimeQuantizer;
class PitchQuantizer;

class GrainParametersGenerator
{
public:
GrainParametersGenerator(Parameters* parameters, DelayLine* delay_line, Granulator* granulator,
const int internal_block_size);
~GrainParametersGenerator();
const GrainParameters getNewGrainParameters();

PitchQuantizer* pitch_quantizer;

private:
bool modSourceEqualsDest(ModSource source, ModDest dest);
float getModSourceValue(ModSource source, ModMode mode);
float* getModDestPtr(ModDest dest);
void copyExternalParametersToInstanceVariables();
void generateRandomizedParameters();
void applyModMatrix(int index);
const GrainParameters generateFinalParameters();

int internal_block_size;
float mix, input_gain;
float amp_min, amp_value;
float pan_value;
float feedback;
float delay_min, delay_value;
float iot_min, iot_value;
float dur_min, dur_value;
float trans_value;
float gliss_value;
float ffreq_min, ffreq_value;
float fq_min, fq_value;
float env_shape, env_skew;
float grains;
float trans_toggle, gliss_toggle, freeze_toggle;
float matrixmod1, matrixmod2, matrixmod3;
GrainParameters grain_parameters;
Random* random;
Parameters* parameters;
TimeQuantizer* time_quantizer;
DelayLine* delay_line;
Granulator* granulator;
};

#endif //GRAINPARAMETERSGENERATOR_H
141 changes: 141 additions & 0 deletions ports/argotlunar/Source/Granulator.cpp
@@ -0,0 +1,141 @@
#include "Granulator.h"

Granulator::Granulator(Parameters* parameters, const int internal_block_size)
: outbuf_left (0)
, outbuf_right (0)
{
this->parameters = parameters;
this->internal_block_size = internal_block_size;
delay_line = new DelayLine(kBufferSeconds, internal_block_size);
grain_param_generator = new GrainParametersGenerator(parameters, delay_line,
this, internal_block_size);
initialized = false;
}

Granulator::~Granulator()
{
if (initialized)
deleteGrains();
delete delay_line;
delete grain_param_generator;
}

void Granulator::prepareToPlay(float samplerate)
{
this->samplerate = samplerate;
parameters->setSampleRate(samplerate);
delay_line->initialize(samplerate);

outbuf_left = new float[internal_block_size];
outbuf_right = new float[internal_block_size];
for (int i = 0; i < internal_block_size; i++)
outbuf_left[i] = outbuf_right[i] = 10E-12f;

if (initialized)
deleteGrains();

for (int i = 0; i < kMaxGrains; i++)
graincloud[i] = new Grain(samplerate,
static_cast<int>(samplerate * kBufferSeconds),
internal_block_size,
delay_line->getDelayPointer(),
outbuf_left,
outbuf_right);
initialized = true;
active_grains = 0;
}

void Granulator::releaseResources()
{
delete[] outbuf_left;
delete[] outbuf_right;
active_grains = 0;
}

void Granulator::setActiveGrains()
{
if (!initialized)
return;

if (parameters->selected_grains > active_grains) {
for (int i = active_grains; i < parameters->selected_grains; i++) {
graincloud[i]->activate();
active_grains++;
}
} else if (parameters->selected_grains < active_grains) {
for (int i = active_grains; i > parameters->selected_grains; i--) {
graincloud[i-1]->deactivate();
active_grains--;
}
}
}

void Granulator::processInternalBlock(float* chan1, float* chan2, int sampleframes)
{
if (active_grains != parameters->selected_grains)
setActiveGrains();

delay_line->writeDelayBuffer(chan1, chan2, sampleframes, parameters->freeze,
parameters->param[kIngain],
parameters->param[kFeedback]);
processGrains(sampleframes);
hardClip(outbuf_left, sampleframes);
hardClip(outbuf_right, sampleframes);
delay_line->writeFeedbackBuffer(outbuf_left, outbuf_right, sampleframes);
writeOutput(chan1, chan2, outbuf_left, outbuf_right, sampleframes);
clearOutbufs(outbuf_left, outbuf_right, sampleframes);
chan1 += sampleframes;
chan2 += sampleframes;
}

void Granulator::clearOutbufs(float* outbuf_left, float* outbuf_right,
int sampleframes)
{
for (int i = 0; i < sampleframes; i++)
outbuf_left[i] = outbuf_right[i] = 10E-12f;
}

void Granulator::writeOutput(float* chan1, float* chan2, float* outbuf_left,
float* outbuf_right, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
chan1[i] = (parameters->param[kMix] * outbuf_left[i])
+ (parameters->dry_mix * chan1[i]);
chan2[i] = (parameters->param[kMix] * outbuf_right[i])
+ (parameters->dry_mix * chan2[i]);
}
}

void Granulator::processGrains(int sampleframes)
{
for (int i = 0; i < kMaxGrains; i++) {
if (graincloud[i]->activated) {
if (graincloud[i]->initialized == false) {
graincloud[i]->initialize(grain_param_generator->getNewGrainParameters());
}
graincloud[i]->process(sampleframes);
if (graincloud[i]->initialized == false) {
graincloud[i]->initialize(grain_param_generator->getNewGrainParameters());
graincloud[i]->process(sampleframes);
}
}
}
}

void Granulator::hardClip(float* input, int sampleframes)
{
for (int i = 0; i < sampleframes; i++) {
if (input[i] > 1.0f) {
input[i] = 1.0f;
} else if (input[i] < -1.0f) {
input[i] = -1.0f;
}
}
}

void Granulator::deleteGrains()
{
for (int i = 0; i < kMaxGrains; i++)
delete graincloud[i];
}

48 changes: 48 additions & 0 deletions ports/argotlunar/Source/Granulator.h
@@ -0,0 +1,48 @@
#ifndef GRANULATOR_H
#define GRANULATOR_H

#include "Debug.h"
#include "DelayLine.h"
#include "Filter.h"
#include "GrainParametersGenerator.h"
#include "Grain.h"
#include "Parameters.h"
#include "PitchQuantizer.h"

class GrainParametersGenerator;
class Parameters;

class Granulator
{
public:
Granulator(Parameters* params, const int internal_block_size);
~Granulator();
void prepareToPlay(float samplerate);
void processInternalBlock(float* chan1, float* chan2, int sampleframes);
void releaseResources();
const float getSampleRate();

GrainParametersGenerator* grain_param_generator;
static const int kMaxGrains = 20;
static const int kBufferSeconds = 5;
int internal_block_size;

private:
void writeOutput(float* chan1, float* chan2, float* outbuf_left, float* outbuf_right, int sampleframes);
void clearOutbufs(float* outbuf_left, float* outbuf_right, int sampleframes);
void hardClip(float* input, int sampleframes);
void processGrains(int sampleframes);
void deleteGrains();
void setActiveGrains();

float samplerate;
float *outbuf_left, *outbuf_right;
float bpm;
int active_grains, sampleframes;
bool initialized;
Grain* graincloud[kMaxGrains];
Parameters* parameters;
DelayLine* delay_line;
};

#endif //GRANULATOR_H
14 changes: 14 additions & 0 deletions ports/argotlunar/Source/Misc.h
@@ -0,0 +1,14 @@
#ifndef MISC_H
#define MISC_H

namespace MathFunc
{

inline int roundFtoI(float f)
{
return static_cast<int>(f + (f > 0.0 ? + 0.5 : -0.5));
}

}

#endif //MISC_H
597 changes: 597 additions & 0 deletions ports/argotlunar/Source/Parameters.cpp

Large diffs are not rendered by default.

96 changes: 96 additions & 0 deletions ports/argotlunar/Source/Parameters.h
@@ -0,0 +1,96 @@
#ifndef PARAMETERS_H
#define PARAMETERS_H

class Plugin;

#include <math.h>
#include "../JuceLibraryCode/JuceHeader.h"
#include "Envelope.h"
#include "Filter.h"
#include "Misc.h"
#include "Plugin.h"
#include "ParametersEnum.h"
#include "TimeQuantizer.h"

class TimeQuantizer;

class Parameters
{
public:
Parameters(Plugin* plugin, const int internal_block_size);
~Parameters();
void initializeInternalParameters();
const String getParameterName(int index);
const String getParameterText(int index);
void setParameter(int index, float new_value, bool initializing);
float getParameterFloatValue(ParameterType param_index);
float getDelayMilliseconds(float value);
float getIOTMilliseconds(float value);
float getDurMilliseconds(float value);
int getScale();
void setScale(int index);
int getMatrixSource(int index);
int getMatrixDest(int index);
int getMatrixMode(int index);
void setMatrixSource(int index, int param);
void setMatrixDest(int index, int param);
void setMatrixMode(int index, int param);
void setSampleRate(float samplerate);
float getSampleRate();
void setQuantizationDisabled();

static const int kMaxIot = 2000;
static const int kMaxDuration = 5;

ModSource matrix_source[3];
ModDest matrix_dest[3];
ModMode matrix_mode[3];
float *param;
float dry_mix;
int scale;
int selected_grains;
bool freeze;
int filter_type;
int env_type;
int scale_key;
float amp_max;
float pan_min, pan_max;
float delay_max;
float iot_max;
float dur_max;
float trans_min, trans_max;
float gliss_min, gliss_max;
float ffreq_max;
float fq_max;
float samplerate;
TimeQuantizer* time_quantizer;

private:
String getEnvTypeString();
String getEnvSkewString();
String getEnvSustainString();
String getFilterTypeString();
String getScaleKeyString();
String getNumGrainsString();
String getMatrixmodString(int parameter);
String getDecibelString(float value);
String getToggleString(int parameter);
String getPanString(float value);
String getDelayString(float value);
String getIOTString(float value);
String getDurString(float value);
String getTransString(float value);
String getGlissString(float value);
String getFFreqString(float value);
String getFqString(float value);
String getPercentString(float value);
void setParametersSavedState(bool state);

bool quantization_disabled;
float delay_coeff;
float iot_coeff;
float dur_coeff;
Plugin* plugin;
};

#endif //PARAMETERS_H
108 changes: 108 additions & 0 deletions ports/argotlunar/Source/ParametersEnum.h
@@ -0,0 +1,108 @@
#ifndef PARAMETERSENUM_H
#define PARAMETERSENUM_H

const int NUM_PARAMS = 37;
const int NUM_MIDI_PARAMS = 36;

enum ParameterType {
kGrains,
kMix,
kIngain,
kFeedback,
kAmp,
kAmpv,
kPan,
kPanv,
kDelay,
kDelayv,
kIot,
kIotv,
kDur,
kDurv,
kTrans,
kTransv,
kGliss,
kGlissv,
kFtype,
kFfreq,
kFfreqv,
kFq,
kFqv,
kEnvType,
kEnvSustain,
kEnvSkew,
kDelayQuant,
kDurQuant,
kIotQuant,
kTransToggle,
kGlissToggle,
kFreezeToggle,
kScaleKey,
kMatrixMod1,
kMatrixMod2,
kMatrixMod3,
kProgram,
kNone,
};

enum ModMode {
MOD_MODE_SCALED,
MOD_MODE_DIRECT
};

enum ModSource {
MOD_SRC_OFF,
MOD_SRC_AMP,
MOD_SRC_PAN_LR,
MOD_SRC_PAN_WIDTH,
MOD_SRC_DELAY,
MOD_SRC_IOT,
MOD_SRC_DUR,
MOD_SRC_TRANS,
MOD_SRC_GLISS,
MOD_SRC_FFREQ,
MOD_SRC_FQ,
MOD_SRC_NUM = 11
};

enum ModDest {
MOD_DEST_OFF,
MOD_DEST_AMP,
MOD_DEST_PAN_LR,
MOD_DEST_DELAY,
MOD_DEST_IOT,
MOD_DEST_DUR,
MOD_DEST_TRANS,
MOD_DEST_GLISS,
MOD_DEST_FFREQ,
MOD_DEST_FQ,
MOD_DEST_SUSTAIN,
MOD_DEST_SKEW,
MOD_DEST_NUM = 12
};

enum QuantizeMode {
QUANT_MS = 1,
QUANT_128,
QUANT_128T,
QUANT_64,
QUANT_64T,
QUANT_32,
QUANT_32T,
QUANT_16,
QUANT_16T,
QUANT_8,
QUANT_8T,
QUANT_4,
QUANT_4T,
QUANT_MS_LONG // (dur *= 10)
};

namespace NumQuantModes
{
const float delay = 13.0f;
const float iot = 13.0f;
const float dur = 14.0f;
}

#endif //PARAMETERSENUM_H
159 changes: 159 additions & 0 deletions ports/argotlunar/Source/PitchQuantizer.cpp
@@ -0,0 +1,159 @@
#include "PitchQuantizer.h"


PitchQuantizer::PitchQuantizer()
{
notes_49 = new int[49];
notes_120 = new int[120];
namesVector = new vector<String>;
notesVector = new vector< vector<int> >;

addScale("chromatic", 1,1,1,1,1,1,1,1,1,1,1,1);
addScale("major", 1,0,1,0,1,1,0,1,0,1,0,1);
addScale("natural minor", 1,0,1,1,0,1,0,1,1,0,1,0);
addScale("harmonic minor", 1,0,1,1,0,1,0,1,1,0,0,1);
addScale("major pentatonic", 1,0,1,0,1,0,0,1,0,1,0,0);
addScale("minor pentatonic", 1,0,0,1,0,1,0,1,0,0,1,0);
addScale("blues major", 1,0,1,0,1,0,0,1,0,1,0,1);
addScale("blues minor", 1,0,0,1,0,1,0,0,1,0,1,0);
addScale("whole tone", 1,0,1,0,1,0,1,0,1,0,1,0);
addScale("octatonic", 1,0,1,1,0,1,1,0,1,1,0,1);
addScale("maj 7", 1,0,0,0,1,0,0,1,0,0,0,1);
addScale("dom 7", 1,0,0,0,1,0,0,1,0,0,1,0);
addScale("min 7", 1,0,0,1,0,0,0,1,0,0,1,0);
addScale("aug maj 7", 1,0,0,0,1,0,0,0,1,0,0,1);
addScale("aug 7", 1,0,0,0,1,0,0,0,1,0,1,0);
addScale("dim 7", 1,0,0,1,0,0,1,0,0,1,0,0);
addScale("dom 7 dim 5", 1,0,0,0,1,0,1,0,0,0,1,0);
addScale("maj triad", 1,0,0,0,1,0,0,1,0,0,0,0);
addScale("min triad", 1,0,0,1,0,0,0,1,0,0,0,0);
addScale("aug triad", 1,0,0,0,1,0,0,0,1,0,0,0);
addScale("dim triad", 1,0,0,1,0,0,1,0,0,0,0,0);
addScale("5th", 1,0,0,0,0,0,0,1,0,0,0,0);
addScale("dim 5th", 1,0,0,0,0,0,1,0,0,0,0,0);
addScale("aug 5th", 1,0,0,0,0,0,0,0,1,0,0,0);
}

PitchQuantizer::~PitchQuantizer()
{
delete[] notes_49;
delete[] notes_120;
delete namesVector;
delete notesVector;
}

void PitchQuantizer::addScale(String name, int n1, int n2, int n3, int n4,
int n5, int n6, int n7,int n8, int n9, int n10,
int n11, int n12)
{
int note_ints[] = {n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12};
vector<int> notes(note_ints, note_ints + sizeof(note_ints) / sizeof(int));
notesVector->push_back(notes);
namesVector->push_back(name);
}

vector<String> PitchQuantizer::getNames()
{
return *namesVector;
}

float PitchQuantizer::getQuantizedPitch(int scaleIndex, int shift, float trans_value)
{
make49NotesArray(scaleIndex, shift);
float semitones = trans_value * 48.0f;
float distances[49];
int nearestIndex;

// array of distances to each note
for (int i = 0; i < 49; i++) {
if (notes_49[i] == 1) {
distances[i] = fabs(semitones - i);
} else {
distances[i] = 10E10f;
}
}
nearestIndex = findNearest(distances, 49);
trans_value = nearestIndex / 48.0f;
return pow(2.0f, ((trans_value - 0.5f) * 4.0f));
}

float PitchQuantizer::getQuantizedFreq(int scaleIndex, int shift, float freq)
{
make120NotesArray(scaleIndex, shift);
double hzArray[120];
double semitoneRatio = pow(2.0, 1.0/12.0);
float distances[120];
int nearestIndex;

// array of 120 note frequencies
hzArray[0] = 55.0;
for (int i = 1; i < 120; i++) {
hzArray[i] = hzArray[i - 1] * semitoneRatio;
}

// array of distances to each frequency
for (int i = 0; i < 120; i++) {
if (notes_120[i] == 1) {
distances[i] = (float)fabs(freq - hzArray[i]);
} else {
distances[i] = 0.0f;
}
}
nearestIndex = findNearest(distances, 120);
return (float)hzArray[nearestIndex];
}

void PitchQuantizer::make49NotesArray(int scaleIndex, int shift)
{
int shiftedScale[12];
vector<int> scale = notesVector->at(scaleIndex);

for(int i = 0; i < 12; i++) {
shiftedScale[i] = scale[shift];
shift++;
if (shift == 12)
shift = 0;
}

for (int i = 0; i < 12; i++) {
notes_49[i] = shiftedScale[i];
notes_49[i + 12] = shiftedScale[i];
notes_49[i + 24] = shiftedScale[i];
notes_49[i + 36] = shiftedScale[i];
}
notes_49[48] = shiftedScale[0];
}

void PitchQuantizer::make120NotesArray(int scaleIndex, int shift)
{
int shiftedScale[12];
vector<int> scale = notesVector->at(scaleIndex);

for(int i = 0; i < 12; i++) {
shiftedScale[i] = scale[shift];
shift++;
if (shift == 12)
shift = 0;
}

for (int i = 0; i < 12; i++) {
for (int j = 0; j < 10; j++) {
notes_120[i + j * 12] = shiftedScale[i];
}
}
}

int PitchQuantizer::findNearest(float* distances, int length)
{
float nearestValue = 10E10f;
int nearestIndex = 0;

for (int i = 0; i < length; i++) {
if (distances[i] < nearestValue) {
nearestValue = distances[i];
nearestIndex = i;
}
}
return nearestIndex;
}

60 changes: 60 additions & 0 deletions ports/argotlunar/Source/PitchQuantizer.h
@@ -0,0 +1,60 @@
#ifndef PITCHQUANTIZER_H
#define PITCHQUANTIZER_H

#include "../JuceLibraryCode/JuceHeader.h"
#include <math.h>
#include <vector>
#include "Misc.h"

using namespace std;

class PitchQuantizer
{
public:
PitchQuantizer();
~PitchQuantizer();
float getQuantizedPitch(int scale, int scaleKey, float trans);
float getQuantizedFreq(int scaleIndex, int shift, float freq);
vector<String> getNames();

private:
void addScale(String name, int n1, int n2, int n3, int n4, int n5,
int n6, int n7, int n8, int n9, int n10, int n11, int n12);
int findNearest(float* distances, int length);
void make49NotesArray(int scaleIndex, int shift);
void make120NotesArray(int scaleIndex, int shift);

vector<String>* namesVector;
vector< vector<int> >* notesVector;
int* notes_49;
int* notes_120;
};

#endif //PITCHQUANTIZER_H

/*
chromatic 0 1 2 3 4 5 6 7 8 9 10 11
major 0 2 4 5 7 9 11
natural minor 0 2 3 5 7 8 10
harmonic minor 0 2 3 5 7 8 11
major pentatonic 0 2 4 7 9
minor pentatonic 0 3 5 7 10
blues major 0 2 4 7 9
blues minor 0 3 5 8 10
whole tone 0 2 4 6 8 10
octatonic 0 2 3 5 6 8 9 11
maj 7 0 4 7 11
dom 7 0 4 7 10
min 7 0 3 7 10
aug maj 7 0 4 8 11
aug 7 0 4 8 10
dim 7 0 3 6 9
dom 7 dim 5 0 4 6 10
maj triad 0 4 7
min triad 0 3 7
aug triad 0 4 8
dim triad 0 3 6
5th 0 6
Dim 5th 0 5
Aug 5th 0 8
*/
407 changes: 407 additions & 0 deletions ports/argotlunar/Source/Plugin.cpp

Large diffs are not rendered by default.

89 changes: 89 additions & 0 deletions ports/argotlunar/Source/Plugin.h
@@ -0,0 +1,89 @@
#ifndef PLUGIN_H
#define PLUGIN_H

#include <vector>
#include "../JuceLibraryCode/JuceHeader.h"
#include "Filter.h"
#include "Granulator.h"
#include "Misc.h"
#include "ProgramBank.h"

class GrainParametersGenerator;
class Granulator;
class ProgramBank;
class PitchQuantizer;

class Plugin : public AudioProcessor, public ChangeBroadcaster
{
public:
Plugin();
~Plugin();
// Overrides
AudioProcessorEditor* createEditor();
void prepareToPlay (double samplerate, int samples_per_block);
void releaseResources();
void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages);
float getParameter (int index);
void setParameter(int index, float new_value);
void setMatrixSource(int index, int param);
void setMatrixDest(int index, int param);
void setMatrixMode(int index, int param);
const String getParameterName (int index);
const String getParameterText (int index);
int getCurrentProgram();
int getNumPrograms();
const String getProgramName(int index);
void changeProgramName(int index, const String& newName);
void getCurrentProgramStateInformation (MemoryBlock& destData);
void setCurrentProgramStateInformation(const void* data, int sizeInBytes);
void getStateInformation (MemoryBlock& destData);
void setStateInformation (const void* data, int sizeInBytes);
void setCurrentProgram(int index);
int getNumParameters();
bool acceptsMidi() const;
const String getInputChannelName (int channelIndex) const;
const String getName() const;
const String getOutputChannelName (int channelIndex) const;
bool isInputChannelStereoPair (int index) const;
bool isOutputChannelStereoPair (int index) const;
bool producesMidi() const;
bool hasEditor() const;
bool isMetaParameter(int parameterIndex) const;
bool silenceInProducesSilenceOut(void) const;
double getTailLengthSeconds() const;

// New methods
void loadBankXml(File* file);
void saveBankXml(File* file);
void loadCurrentProgramXml(File* file);
void saveCurrentProgramXml(File* file);
//void createAppSettingsDir();
//File* getMidiMapFile();
bool getSavedState();
void setSavedState(bool state);
bool getParametersChangedState();
void setParametersChangedState();
bool getProgramChangedState();
void initCurrentProgram();
void saveProgramTo(int index);
std::vector<String> getScaleNames();
void toggleProgchangeEnabled();
bool isProgchangeEnabled();

static const int kNumPrograms = 16;
static const int kInternalBlocksize = 32;
Parameters* parameters;
Granulator* granulator;

private:
int current_program;
bool saved_state;
bool editor_parameter_update_pending;
bool editor_program_update_pending;
AudioPlayHead::CurrentPositionInfo pos;
unsigned int block_sample_pos;
ProgramBank* program_bank;
bool progchange_param_enabled;
};

#endif //PLUGIN_H
2,462 changes: 2,462 additions & 0 deletions ports/argotlunar/Source/PluginEditor.cpp

Large diffs are not rendered by default.

205 changes: 205 additions & 0 deletions ports/argotlunar/Source/PluginEditor.h
@@ -0,0 +1,205 @@
/*
==============================================================================
This is an automatically generated file created by the Jucer!
Creation date: 19 Feb 2012 11:38:05am
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Jucer version: 1.12
------------------------------------------------------------------------------
The Jucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-6 by Raw Material Software ltd.
==============================================================================
*/

#ifndef __JUCER_HEADER_PLUGINEDITOR_PLUGINEDITOR_47FE96EF__
#define __JUCER_HEADER_PLUGINEDITOR_PLUGINEDITOR_47FE96EF__

//[Headers] -- You can add your own extra header files here --
#include "../JuceLibraryCode/JuceHeader.h"
#include "Debug.h"
#include "Plugin.h"

enum ComponentType {
kSlider,
kComboBox,
kButton,
kNoComponent
};
//[/Headers]



//==============================================================================
/**
//[Comments]
Argotlunar 2.0 GUI
//[/Comments]
*/
class PluginEditor : public AudioProcessorEditor,
public Timer,
public SliderListener,
public ComboBoxListener,
public ButtonListener
{
public:
//==============================================================================
PluginEditor (Plugin* const ownerFilter);
~PluginEditor();

//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
void timerCallback();
String* programNames;
void changeProgram(int program);
void updateGlissSliders(bool state);
void updateTransSliders(bool state);
void updateEnvSliders(int id);
void updateScaleComponents(bool state);
void setColour(bool style);
void loadBankFile(Plugin* const plugin);
void loadProgramFile(Plugin* const plugin);
void saveBankFile(Plugin* const plugin);
void saveProgramFile(Plugin* const plugin);

//[/UserMethods]

void paint (Graphics& g);
void resized();
void sliderValueChanged (Slider* sliderThatWasMoved);
void comboBoxChanged (ComboBox* comboBoxThatHasChanged);
void buttonClicked (Button* buttonThatWasClicked);



//==============================================================================
juce_UseDebuggingNewOperator

private:
//[UserVariables] -- You can add your own custom variables in this section.
Plugin* getPlugin() const throw() {
return static_cast <Plugin*> (getAudioProcessor());
}
void updateParametersFromPlugin();
void updateProgramNamesFromPlugin();
int currentProgram;
int num_programs;
//[/UserVariables]

//==============================================================================
GroupComponent* groupComponent3;
GroupComponent* groupComponent2;
GroupComponent* groupComponent20;
GroupComponent* groupComponent18;
GroupComponent* groupComponent5;
GroupComponent* groupComponent15;
GroupComponent* groupComponent9;
GroupComponent* groupComponent;
Slider* mix_slider;
Label* label;
Slider* ingain_slider;
Label* label2;
Slider* amp_slider;
Label* label3;
Slider* ampv_slider;
Label* label4;
Slider* pan_slider;
Label* label5;
Slider* panv_slider;
Label* label6;
Slider* delay_slider;
Label* label7;
Slider* delayv_slider;
Slider* feedback_slider;
Label* label9;
Slider* gliss_slider;
Label* label11;
Slider* glissv_slider;
Slider* trans_slider;
Label* label13;
Slider* transv_slider;
Slider* iot_slider;
Label* label15;
Slider* iotv_slider;
Slider* dur_slider;
Label* label17;
Slider* durv_slider;
Slider* ffreq_slider;
Label* label19;
Slider* ffreqv_slider;
Slider* fq_slider;
Label* label21;
Slider* fqv_slider;
Slider* grains_slider;
Label* label23;
TextEditor* param_display;
ComboBox* filtertype_combobox;
TextButton* initButton;
TextButton* saveButton;
TextButton* savetoButton;
TextButton* decPresetButton;
TextButton* incPresetButton;
ComboBox* program_combobox;
Label* label25;
Slider* envshape_slider;
Slider* envskew_slider;
Label* label26;
Label* label27;
Label* label28;
ToggleButton* freeze_toggle_button;
ComboBox* scale_combobox;
Slider* scalekey_slider;
Label* label24;
GroupComponent* groupComponent17;
Label* label29;
ComboBox* matrix_src_combobox_1;
ComboBox* matrix_dest_combobox_1;
Slider* matrix_mod_slider_1;
Label* label30;
Label* label31;
ComboBox* matrix_src_combobox_2;
ComboBox* matrix_dest_combobox_2;
Slider* matrix_mod_slider_2;
Label* label34;
Label* label35;
ComboBox* matrix_src_combobox_3;
ComboBox* matrix_dest_combobox_3;
Slider* matrix_mod_slider_3;
Label* label36;
Label* label37;
ToggleButton* matrix_mode_1_button;
ToggleButton* matrix_mode_2_button;
ToggleButton* matrix_mode_3_button;
TextEditor* scalekey_display;
ToggleButton* trans_toggle_button;
ComboBox* envtype_combobox;
ComboBox* dur_quant_combobox;
ComboBox* iot_quant_combobox;
ComboBox* delay_quant_combobox;
Label* label8;
Label* label16;
Label* label18;
Label* label12;
Label* label14;
Label* label20;
Label* label22;
Label* label32;
ToggleButton* gliss_toggle_button;
TextButton* optionsButton;


//==============================================================================
// (prevent copy constructor and operator= being generated..)
PluginEditor (const PluginEditor&);
const PluginEditor& operator= (const PluginEditor&);
};


#endif // __JUCER_HEADER_PLUGINEDITOR_PLUGINEDITOR_47FE96EF__
60 changes: 60 additions & 0 deletions ports/argotlunar/Source/Program.cpp
@@ -0,0 +1,60 @@
#include "Program.h"

Program::Program()
{
initParameters();
}

Program::~Program()
{
}

void Program::initParameters()
{
// internal parameters
name = "Init";
parameters[kGrains] = 0.5f;
parameters[kMix] = 1.0f;
parameters[kIngain] = 1.0f;
parameters[kFeedback] = 0.0f;
parameters[kAmp] = 0.5f;
parameters[kAmpv] = 0.5f;
parameters[kPan] = 0.5f;
parameters[kPanv] = 0.5f;
parameters[kDelay] = 0.0f;
parameters[kDelayv] = 0.05f;
parameters[kIot] = 0.25f;
parameters[kIotv] = 0.1f;
parameters[kDur] = 0.3f;
parameters[kDurv] = 0.1f;
parameters[kTrans] = 0.5f;
parameters[kTransv] = 0.0f;
parameters[kGliss] = 0.5f;
parameters[kGlissv] = 0.0f;
parameters[kFtype] = 0.0f;
parameters[kFfreq] = 0.3f;
parameters[kFfreqv] = 0.5f;
parameters[kFq] = 0.0f;
parameters[kFqv] = 0.5f;
parameters[kEnvType] = 0.0f;
parameters[kEnvSustain] = 0.0f;
parameters[kEnvSkew] = 0.5f;
parameters[kDelayQuant] = 1.0f/NumQuantModes::delay;
parameters[kIotQuant] = 1.0f/NumQuantModes::iot;
parameters[kDurQuant] = 1.0f/NumQuantModes::dur;
parameters[kGlissToggle] = 0.0f;
parameters[kTransToggle] = 1.0f;
parameters[kFreezeToggle] = 0.0f;
parameters[kScaleKey] = 0.0f;
parameters[kMatrixMod1] = 0.5f;
parameters[kMatrixMod2] = 0.5f;
parameters[kMatrixMod3] = 0.5f;

// external parameters
scale = 1;
for (int i = 0; i < 3; i++) {
matrix_source[i] = MOD_SRC_OFF;
matrix_dest[i] = MOD_DEST_OFF;
matrix_mode[i] = MOD_MODE_SCALED;
}
}
24 changes: 24 additions & 0 deletions ports/argotlunar/Source/Program.h
@@ -0,0 +1,24 @@
#ifndef PROGRAM_H
#define PROGRAM_H

#include "../JuceLibraryCode/JuceHeader.h"
#include "Debug.h"
#include "ParametersEnum.h"
//#include "MidiMapper.h"

class Program
{
public:
Program();
~Program();
void initParameters();
String name;
float parameters[NUM_PARAMS - 1];
int scale;
ModSource matrix_source[3];
ModDest matrix_dest[3];
ModMode matrix_mode[3];
private:
};

#endif //PROGRAMBANK_H
192 changes: 192 additions & 0 deletions ports/argotlunar/Source/ProgramBank.cpp
@@ -0,0 +1,192 @@
#include "ProgramBank.h"

ProgramBank::ProgramBank(const int num_programs, Parameters* parameters)
{
this->parameters = parameters;
this->num_programs = num_programs;
programs = new Program[num_programs];
loadProgramState(0);
}

ProgramBank::~ProgramBank()
{
delete[] programs;
}

void ProgramBank::saveProgramState(int index)
{
// internal parameters
for (int i = 0; i < (NUM_PARAMS - 1); i++) {
programs[index].parameters[i] = parameters->param[i];
}

// external parameters
programs[index].scale = parameters->scale;
for (int i = 0; i < 3; i++) {
programs[index].matrix_source[i] = parameters->matrix_source[i];
programs[index].matrix_dest[i] = parameters->matrix_dest[i];
programs[index].matrix_mode[i] = parameters->matrix_mode[i];
}
}

void ProgramBank::loadProgramState(int index)
{
// internal parameters
for (int i = 0; i < (NUM_PARAMS - 1); i++) {
parameters->param[i] = programs[index].parameters[i];
}

// external parameters
parameters->scale = programs[index].scale;
for (int i = 0; i < 3; i++) {
parameters->matrix_source[i] = programs[index].matrix_source[i];
parameters->matrix_dest[i] = programs[index].matrix_dest[i];
parameters->matrix_mode[i] = programs[index].matrix_mode[i];
}
parameters->initializeInternalParameters();
}

XmlElement* ProgramBank::createBankXml()
{
XmlElement* bank_xml = new XmlElement("ARGOTLUNAR2_BANK");
for (int i = 0; i < num_programs; i++) {
bank_xml->addChildElement(createProgramXml(i));
}
return bank_xml;
}

void ProgramBank::loadBankFromXml(XmlElement* bank_xml)
{
int i = 0;
if (bank_xml->hasTagName("ARGOTLUNAR2_BANK")) {
forEachXmlChildElement(*bank_xml, parameters_xml)
loadProgramFromXml(i++, parameters_xml);
}
}

XmlElement* ProgramBank::createProgramXml(int index)
{
XmlElement* program_xml = new XmlElement("ARGOTLUNAR2_PROGRAM");
// external parameters
program_xml->setAttribute("program_name", programs[index].name);
program_xml->setAttribute("grains", programs[index].parameters[kGrains]);
program_xml->setAttribute("mix", programs[index].parameters[kMix]);
program_xml->setAttribute("input_gain", programs[index].parameters[kIngain]);
program_xml->setAttribute("feedback", programs[index].parameters[kFeedback]);
program_xml->setAttribute("amp", programs[index].parameters[kAmp]);
program_xml->setAttribute("ampv", programs[index].parameters[kAmpv]);
program_xml->setAttribute("pan", programs[index].parameters[kPan]);
program_xml->setAttribute("panv", programs[index].parameters[kPanv]);
program_xml->setAttribute("delay", programs[index].parameters[kDelay]);
program_xml->setAttribute("delayv", programs[index].parameters[kDelayv]);
program_xml->setAttribute("iot", programs[index].parameters[kIot]);
program_xml->setAttribute("iotv", programs[index].parameters[kIotv]);
program_xml->setAttribute("dur", programs[index].parameters[kDur]);
program_xml->setAttribute("durv", programs[index].parameters[kDurv]);
program_xml->setAttribute("trans", programs[index].parameters[kTrans]);
program_xml->setAttribute("transv", programs[index].parameters[kTransv]);
program_xml->setAttribute("gliss", programs[index].parameters[kGliss]);
program_xml->setAttribute("glissv", programs[index].parameters[kGlissv]);
program_xml->setAttribute("filter_type", programs[index].parameters[kFtype]);
program_xml->setAttribute("ffreq", programs[index].parameters[kFfreq]);
program_xml->setAttribute("ffreqv", programs[index].parameters[kFfreqv]);
program_xml->setAttribute("fq", programs[index].parameters[kFq]);
program_xml->setAttribute("fqv", programs[index].parameters[kFqv]);
program_xml->setAttribute("env_type", programs[index].parameters[kEnvType]);
program_xml->setAttribute("env_shape", programs[index].parameters[kEnvSustain]);
program_xml->setAttribute("env_skew", programs[index].parameters[kEnvSkew]);
program_xml->setAttribute("delay_quant", programs[index].parameters[kDelayQuant]);
program_xml->setAttribute("dur_quant", programs[index].parameters[kDurQuant]);
program_xml->setAttribute("iot_quant", programs[index].parameters[kIotQuant]);
program_xml->setAttribute("trans_toggle", programs[index].parameters[kTransToggle]);
program_xml->setAttribute("gliss_toggle", programs[index].parameters[kGlissToggle]);
program_xml->setAttribute("freeze_toggle", programs[index].parameters[kFreezeToggle]);
program_xml->setAttribute("scale_key", programs[index].parameters[kScaleKey]);
program_xml->setAttribute("matrix_mod_1", programs[index].parameters[kMatrixMod1]);
program_xml->setAttribute("matrix_mod_2", programs[index].parameters[kMatrixMod1]);
program_xml->setAttribute("matrix_mod_3", programs[index].parameters[kMatrixMod3]);
// internal parameters
program_xml->setAttribute("scale", programs[index].scale);
program_xml->setAttribute("matrix_src_1", programs[index].matrix_source[0]);
program_xml->setAttribute("matrix_src_2", programs[index].matrix_source[1]);
program_xml->setAttribute("matrix_src_3", programs[index].matrix_source[2]);
program_xml->setAttribute("matrix_dest_1", programs[index].matrix_dest[0]);
program_xml->setAttribute("matrix_dest_2", programs[index].matrix_dest[1]);
program_xml->setAttribute("matrix_dest_3", programs[index].matrix_dest[2]);
program_xml->setAttribute("matrix_mode_1", programs[index].matrix_mode[0]);
program_xml->setAttribute("matrix_mode_2", programs[index].matrix_mode[1]);
program_xml->setAttribute("matrix_mode_3", programs[index].matrix_mode[2]);
return program_xml;
}

void ProgramBank::loadProgramFromXml(int index, XmlElement* parameters_xml)
{
if (!parameters_xml->hasTagName("ARGOTLUNAR2_PROGRAM")) {
return;
}
// external parameters
programs[index].name = parameters_xml->getStringAttribute("program_name");
programs[index].parameters[kGrains] = static_cast<float>(parameters_xml->getDoubleAttribute("grains"));
programs[index].parameters[kMix] = static_cast<float>(parameters_xml->getDoubleAttribute("mix"));
programs[index].parameters[kIngain] = static_cast<float>(parameters_xml->getDoubleAttribute("input_gain"));
programs[index].parameters[kFeedback] = static_cast<float>(parameters_xml->getDoubleAttribute("feedback"));
programs[index].parameters[kAmp] = static_cast<float>(parameters_xml->getDoubleAttribute("amp"));
programs[index].parameters[kAmpv] = static_cast<float>(parameters_xml->getDoubleAttribute("ampv"));
programs[index].parameters[kPan] = static_cast<float>(parameters_xml->getDoubleAttribute("pan"));
programs[index].parameters[kPanv] = static_cast<float>(parameters_xml->getDoubleAttribute("panv"));
programs[index].parameters[kDelay] = static_cast<float>(parameters_xml->getDoubleAttribute("delay"));
programs[index].parameters[kDelayv] = static_cast<float>(parameters_xml->getDoubleAttribute("delayv"));
programs[index].parameters[kIot] = static_cast<float>(parameters_xml->getDoubleAttribute("iot"));
programs[index].parameters[kIotv] = static_cast<float>(parameters_xml->getDoubleAttribute("iotv"));
programs[index].parameters[kDur] = static_cast<float>(parameters_xml->getDoubleAttribute("dur"));
programs[index].parameters[kDurv] = static_cast<float>(parameters_xml->getDoubleAttribute("durv"));
programs[index].parameters[kTrans] = static_cast<float>(parameters_xml->getDoubleAttribute("trans"));
programs[index].parameters[kTransv] = static_cast<float>(parameters_xml->getDoubleAttribute("transv"));
programs[index].parameters[kGliss] = static_cast<float>(parameters_xml->getDoubleAttribute("gliss"));
programs[index].parameters[kGlissv] = static_cast<float>(parameters_xml->getDoubleAttribute("glissv"));
programs[index].parameters[kFfreq] = static_cast<float>(parameters_xml->getDoubleAttribute("ffreq"));
programs[index].parameters[kFfreqv] = static_cast<float>(parameters_xml->getDoubleAttribute("ffreqv"));
programs[index].parameters[kFtype] = static_cast<float>(parameters_xml->getDoubleAttribute("filter_type"));
programs[index].parameters[kFq] = static_cast<float>(parameters_xml->getDoubleAttribute("fq"));
programs[index].parameters[kFqv] = static_cast<float>(parameters_xml->getDoubleAttribute("fqv"));
programs[index].parameters[kEnvType] = static_cast<float>(parameters_xml->getDoubleAttribute("env_type"));
programs[index].parameters[kEnvSustain] = static_cast<float>(parameters_xml->getDoubleAttribute("env_shape"));
programs[index].parameters[kEnvSkew] = static_cast<float>(parameters_xml->getDoubleAttribute("env_skew"));
programs[index].parameters[kDelayQuant] = static_cast<float>(parameters_xml->getDoubleAttribute("delay_quant"));
programs[index].parameters[kDurQuant] = static_cast<float>(parameters_xml->getDoubleAttribute("dur_quant"));
programs[index].parameters[kIotQuant] = static_cast<float>(parameters_xml->getDoubleAttribute("iot_quant"));
programs[index].parameters[kTransToggle] = static_cast<float>(parameters_xml->getDoubleAttribute("trans_toggle"));
programs[index].parameters[kGlissToggle] = static_cast<float>(parameters_xml->getDoubleAttribute("gliss_toggle"));
programs[index].parameters[kFreezeToggle] = static_cast<float>(parameters_xml->getDoubleAttribute("freeze_toggle"));
programs[index].parameters[kScaleKey] = static_cast<float>(parameters_xml->getDoubleAttribute("scale_key"));
programs[index].parameters[kMatrixMod1] = static_cast<float>(parameters_xml->getDoubleAttribute("matrix_mod_1"));
programs[index].parameters[kMatrixMod2] = static_cast<float>(parameters_xml->getDoubleAttribute("matrix_mod_2"));
programs[index].parameters[kMatrixMod3] = static_cast<float>(parameters_xml->getDoubleAttribute("matrix_mod_3"));
// internal parameters
programs[index].scale = parameters_xml->getIntAttribute("scale");
programs[index].matrix_source[0] = static_cast<ModSource>(parameters_xml->getIntAttribute("matrix_src_1"));
programs[index].matrix_source[1] = static_cast<ModSource>(parameters_xml->getIntAttribute("matrix_src_2"));
programs[index].matrix_source[2] = static_cast<ModSource>(parameters_xml->getIntAttribute("matrix_src_3"));
programs[index].matrix_dest[0] = static_cast<ModDest>(parameters_xml->getIntAttribute("matrix_dest_1"));
programs[index].matrix_dest[1] = static_cast<ModDest>(parameters_xml->getIntAttribute("matrix_dest_2"));
programs[index].matrix_dest[2] = static_cast<ModDest>(parameters_xml->getIntAttribute("matrix_dest_3"));
programs[index].matrix_mode[0] = static_cast<ModMode>(parameters_xml->getIntAttribute("matrix_mode_1"));
programs[index].matrix_mode[1] = static_cast<ModMode>(parameters_xml->getIntAttribute("matrix_mode_2"));
programs[index].matrix_mode[2] = static_cast<ModMode>(parameters_xml->getIntAttribute("matrix_mode_3"));
}


void ProgramBank::initProgram(int index)
{
programs[index].initParameters();
}

const String ProgramBank::getProgramName(int index)
{
return programs[index].name;
}

void ProgramBank::setProgramName(int index, const String new_name)
{
programs[index].name = new_name;
}
39 changes: 39 additions & 0 deletions ports/argotlunar/Source/ProgramBank.h
@@ -0,0 +1,39 @@
#ifndef PROGRAMBANK_H
#define PROGRAMBANK_H

#include "../JuceLibraryCode/JuceHeader.h"
#include "Debug.h"
#include "Program.h"
#include "Parameters.h"

class Parameters;
class Program;

class ProgramBank
{
public:
ProgramBank(const int num_programs, Parameters* parameters);
~ProgramBank();

void initProgram(int index);
void loadProgramState(int index);
void saveProgramState(int index);

XmlElement* createBankXml();
XmlElement* createProgramXml(int index);

void loadBankFromXml(XmlElement* bank_xml);
void loadProgramFromXml(int index, XmlElement* parameters_xml);

const String getProgramName(int index);
void setProgramName(int index, const String new_name);

private:
int num_programs;
Program* programs; //[NUMPROGRAMS];
Parameters* parameters;
//MidiMapper* midi_mapper;
XmlElement* bank;
};

#endif //PROGRAMBANK_H
251 changes: 251 additions & 0 deletions ports/argotlunar/Source/TimeQuantizer.cpp
@@ -0,0 +1,251 @@
#include "TimeQuantizer.h"

TimeQuantizer::TimeQuantizer(Parameters* parameters,
const int internal_block_size)
{
this->parameters = parameters;
this->internal_block_size = internal_block_size;
initialize();
}

TimeQuantizer::~TimeQuantizer()
{
}

void TimeQuantizer::initialize()
{
delay_quant_range[QUANT_128] = 64;
delay_quant_range[QUANT_128T] = 96;
delay_quant_range[QUANT_64] = 64;
delay_quant_range[QUANT_64T] = 96;
delay_quant_range[QUANT_32] = 64;
delay_quant_range[QUANT_32T] = 96;
delay_quant_range[QUANT_16] = 32;
delay_quant_range[QUANT_16T] = 48;
delay_quant_range[QUANT_8] = 16;
delay_quant_range[QUANT_8T] = 24;
delay_quant_range[QUANT_4] = 8;
delay_quant_range[QUANT_4T] = 12;

iot_quant_range[QUANT_128] = 32;
iot_quant_range[QUANT_128T] = 48;
iot_quant_range[QUANT_64] = 32;
iot_quant_range[QUANT_64T] = 48;
iot_quant_range[QUANT_32] = 32;
iot_quant_range[QUANT_32T] = 48;
iot_quant_range[QUANT_16] = 16;
iot_quant_range[QUANT_16T] = 24;
iot_quant_range[QUANT_8] = 8;
iot_quant_range[QUANT_8T] = 12;
iot_quant_range[QUANT_4] = 4;
iot_quant_range[QUANT_4T] = 6;

dur_quant_range[QUANT_128] = 32;
dur_quant_range[QUANT_128T] = 48;
dur_quant_range[QUANT_64] = 32;
dur_quant_range[QUANT_64T] = 48;
dur_quant_range[QUANT_32] = 32;
dur_quant_range[QUANT_32T] = 48;
dur_quant_range[QUANT_16] = 16;
dur_quant_range[QUANT_16T] = 24;
dur_quant_range[QUANT_8] = 8;
dur_quant_range[QUANT_8T] = 12;
dur_quant_range[QUANT_4] = 4;
dur_quant_range[QUANT_4T] = 6;

quant_mode_strings[QUANT_MS] = "ms";
quant_mode_strings[QUANT_128] = "/128";
quant_mode_strings[QUANT_128T] = "/128T";
quant_mode_strings[QUANT_64] = "/64";
quant_mode_strings[QUANT_64T] = "/64T";
quant_mode_strings[QUANT_32] = "/32";
quant_mode_strings[QUANT_32T] = "/32T";
quant_mode_strings[QUANT_16] = "/16";
quant_mode_strings[QUANT_16T] = "/16T";
quant_mode_strings[QUANT_8] = "/8";
quant_mode_strings[QUANT_8T] = "/8T";
quant_mode_strings[QUANT_4] = "/4";
quant_mode_strings[QUANT_4T] = "/4T";
quant_mode_strings[QUANT_MS_LONG] = "long";

quant_factors[QUANT_128] = 1.0f/128.0f;
quant_factors[QUANT_128T] = 1.0f/196.0f;
quant_factors[QUANT_64] = 1.0f/64.0f;
quant_factors[QUANT_64T] = 1.0f/96.0f;
quant_factors[QUANT_32] = 1.0f/32.0f;
quant_factors[QUANT_32T] = 1.0f/48.0f;
quant_factors[QUANT_16] = 1.0f/16.0f;
quant_factors[QUANT_16T] = 1.0f/24.0f;
quant_factors[QUANT_8] = 1.0f/8.0f;
quant_factors[QUANT_8T] = 1.0f/12.0f;
quant_factors[QUANT_4] = 1.0f/4.0f;
quant_factors[QUANT_4T] = 1.0f/6.0f;

pos_bpm = 0.0f;
pos_beatpos = 0.0f;
pos_seconds = 0.0f;
beatpos_increment = 0.0f;
samplerate = 0.0f;
quantization_enabled = false;
prev_ppqpos = 0.0;
}

int TimeQuantizer::getQuantStepRange(const ParameterType parameter,
const QuantizeMode quantize_mode)
{
switch (parameter) {
case kDelayQuant:
return delay_quant_range[quantize_mode];
case kIotQuant:
return iot_quant_range[quantize_mode];
case kDurQuant:
default:
return dur_quant_range[quantize_mode];
}
}

float TimeQuantizer::getQuantFactor(const QuantizeMode quantize_mode)
{
return quant_factors[quantize_mode];
}

void TimeQuantizer::setQuantizeMode(const ParameterType parameter,
const float value)
{
switch (parameter) {
case kDelayQuant:
delay_quant_mode = static_cast<QuantizeMode>(
MathFunc::roundFtoI(value * NumQuantModes::delay));
if(delay_quant_mode == 0)
delay_quant_mode = QUANT_MS;
return;
case kIotQuant:
iot_quant_mode = static_cast<QuantizeMode>(
MathFunc::roundFtoI(value * NumQuantModes::iot));
if(iot_quant_mode == 0)
iot_quant_mode = QUANT_MS;
return;
case kDurQuant:
default:
dur_quant_mode = static_cast<QuantizeMode>(
MathFunc::roundFtoI(value * NumQuantModes::dur));
if(dur_quant_mode == 0)
dur_quant_mode = QUANT_MS;
}
}

const QuantizeMode TimeQuantizer::getQuantizeMode(const ParameterType parameter)
{
switch (parameter) {
case kDelayQuant:
return delay_quant_mode;
case kIotQuant:
return iot_quant_mode;
case kDurQuant:
default:
return dur_quant_mode;
}
}

int TimeQuantizer::getQuantValue(const ParameterType parameter, float value)
{
int quant_value = 0;

switch (parameter) {
case kDelayQuant:
quant_value =
MathFunc::roundFtoI(value * delay_quant_range[delay_quant_mode]);
break;
case kIotQuant:
quant_value =
MathFunc::roundFtoI(value * iot_quant_range[iot_quant_mode]);
break;
case kDurQuant:
default:
quant_value =
MathFunc::roundFtoI(value * dur_quant_range[dur_quant_mode]);
}
if (quant_value == 0)
quant_value++;
return quant_value;
}

String TimeQuantizer::getQuantModeString(const ParameterType parameter)
{
switch (parameter) {
case kDelayQuant:
return quant_mode_strings[delay_quant_mode];
case kIotQuant:
return quant_mode_strings[iot_quant_mode];
case kDurQuant:
default:
return quant_mode_strings[dur_quant_mode];
}
}

String TimeQuantizer::getQuantValueString(const ParameterType parameter,
float value)
{
return String(getQuantValue(parameter, value))
+ getQuantModeString(parameter);
}

float TimeQuantizer::getBarPos()
{
float secondsPerBar = 60.0f / (pos_bpm / 4.0f);
float barPos = (pos_seconds / secondsPerBar);
barPos = barPos - static_cast<int>(barPos);
return barPos;
}

int TimeQuantizer::quantizeLength(const ParameterType parameter, float value)
{
int quant_steps = getQuantValue(parameter, value);
float quant_factor = getQuantFactor(getQuantizeMode(parameter));
float bar_length = 60.0f / (pos_bpm / 4.0f);
int bar_samples = static_cast<int>(bar_length * samplerate);
float quant_step_samples = bar_samples * quant_factor;
return MathFunc::roundFtoI(quant_step_samples * quant_steps);
}

// finds distance (in samples) to nearest quantize boundary
// adds quant_steps * samples_per_quant_step to distance
int TimeQuantizer::quantizeStartPos(const ParameterType parameter, float value)
{
int quant_steps = getQuantValue(parameter, value) - 1;
float quant_factor = getQuantFactor(getQuantizeMode(parameter));
float bar_length = 60.0f / (pos_bpm / 4.0f);
int bar_samples = static_cast<int>(bar_length * samplerate);
float samples_per_quant_step = bar_samples * quant_factor;
float distance = getBarPos() / quant_factor;
distance = ceil(distance) - distance;
distance *= samples_per_quant_step;
distance += (quant_steps * samples_per_quant_step);
return MathFunc::roundFtoI(distance);
}

void TimeQuantizer::setSampleRate(float samplerate)
{
this->samplerate = samplerate;
}

void TimeQuantizer::setPositionInfo(AudioPlayHead::CurrentPositionInfo* pos)
{
quantization_enabled = true;
pos_bpm = static_cast<float>(pos->bpm);
pos_seconds = static_cast<float>(pos->timeInSeconds);
pos_beatpos = static_cast<float>(pos->ppqPosition
- pos->ppqPositionOfLastBarStart);
beatpos_increment = (internal_block_size / samplerate) * (pos_bpm / 60.0f);
}

void TimeQuantizer::incrementPositionInfo()
{
if (!quantization_enabled)
return;
pos_seconds += (internal_block_size / samplerate);
pos_beatpos += beatpos_increment;
if (pos_beatpos > 1.0f)
pos_beatpos -= 1.0f;
}

54 changes: 54 additions & 0 deletions ports/argotlunar/Source/TimeQuantizer.h
@@ -0,0 +1,54 @@
#ifndef TIMEQUANTIZER_H
#define TIMEQUANTIZER_H

#include <map>
#include "../JuceLibraryCode/JuceHeader.h"
#include "Misc.h"
#include "Parameters.h"
#include "ParametersEnum.h"

class Parameters;

class TimeQuantizer
{
public:
TimeQuantizer(Parameters* parameters, const int internal_block_size);
~TimeQuantizer();
void setPositionInfo(AudioPlayHead::CurrentPositionInfo* pos);
void incrementPositionInfo();
String getQuantModeString(const ParameterType parameter);
String getQuantValueString(const ParameterType parameter, float value);
void setQuantizeMode(const ParameterType parameter, const float value);
const QuantizeMode getQuantizeMode(const ParameterType parameter);
int quantizeLength(const ParameterType parameter, float value);
int quantizeStartPos(const ParameterType parameter, float value);
void setSampleRate(float samplerate);

private:
void initialize();
float getBarPos();
float getQuantFactor(const QuantizeMode quantize_mode);
int getQuantStepRange(const ParameterType parameter,
const QuantizeMode quantize_mode);
int getQuantValue(const ParameterType parameter, float value);

bool quantization_enabled;
int internal_block_size;
double prev_ppqpos;
float pos_bpm;
float pos_beatpos;
float pos_seconds;
float samplerate;
float beatpos_increment;
const Parameters* parameters;
QuantizeMode delay_quant_mode;
QuantizeMode iot_quant_mode;
QuantizeMode dur_quant_mode;
std::map<QuantizeMode, int> delay_quant_range;
std::map<QuantizeMode, int> iot_quant_range;
std::map<QuantizeMode, int> dur_quant_range;
std::map<QuantizeMode, float> quant_factors;
std::map<QuantizeMode, String> quant_mode_strings;
};

#endif //TIMEQUANTIZER_H
17 changes: 17 additions & 0 deletions ports/argotlunar/VST/premake.lua
@@ -0,0 +1,17 @@

dofile("../../../scripts/make-project.lua")

package = make_juce_vst_project("argotlunar")

package.includepaths = {
package.includepaths,
"../Source",
"../JuceLibraryCode"
}

package.files = {
matchfiles (
"../Source/*.cpp",
"../../../libs/juce-plugin/JucePluginMain.cpp"
)
}