Skip to content

Commit

Permalink
Adds Kammerl Beat-Repeat Effect v0.42
Browse files Browse the repository at this point in the history
  • Loading branch information
jkammerl committed Jun 25, 2017
1 parent 9d3832e commit 3dae780
Show file tree
Hide file tree
Showing 19 changed files with 1,015 additions and 843 deletions.
75 changes: 49 additions & 26 deletions clouds/dsp/granular_processor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void GranularProcessor::ProcessGranular(
size_t size) {
// At the exception of the spectral mode, all modes require the incoming
// audio signal to be written to the recording buffer.
if (playback_mode_ != PLAYBACK_MODE_SPECTRAL) {
if (playback_mode_ != PLAYBACK_MODE_SPECTRAL_CLOUD) {
const float* input_samples = &input[0].l;
const bool write_data = !parameters_.freeze || playback_mode_ == PLAYBACK_MODE_KAMMERL;
for (int32_t i = 0; i < num_channels_; ++i) {
Expand Down Expand Up @@ -130,18 +130,8 @@ void GranularProcessor::ProcessGranular(
}
break;

case PLAYBACK_MODE_SPECTRAL:
case PLAYBACK_MODE_SPECTRAL_CLOUD:
{
parameters_.spectral.quantization = parameters_.texture;
parameters_.spectral.refresh_rate = 0.01f + 0.99f * parameters_.density;
float warp = parameters_.size - 0.5f;
parameters_.spectral.warp = 4.0f * warp * warp * warp + 0.5f;

float randomization = parameters_.density - 0.5f;
randomization *= randomization * 4.2f;
randomization -= 0.05f;
CONSTRAIN(randomization, 0.0f, 1.0f);
parameters_.spectral.phase_randomization = randomization;
phase_vocoder_.Process(parameters_, input, output, size);

if (num_channels_ == 1) {
Expand All @@ -165,6 +155,32 @@ void GranularProcessor::ProcessGranular(
}
}

void GranularProcessor::WarmDistortion(float* in, float parameter) {
if (parameter < 0.1) {
return;
}
static const float kMaxDistf = 2.0f;
const float fac = kMaxDistf * parameter;
const float amp = 1.0f - parameter * 0.45f;

float smp = *in;
smp = (1.0f + fac) * smp - fac * smp * smp * smp;

float sign = 1.0f;
if (smp < 0) {
sign = -1.0;
}
float tanh_loopup = std::max(0.0f, std::min(1.0f, (smp / 2.0f) * sign));
float inv_tanh_smp = Interpolate(lut_inv_tanh, tanh_loopup,
static_cast<float>(LUT_INV_TANH_SIZE-1)) * sign;

smp = smp + (inv_tanh_smp - smp) * fac;
smp *= amp;
smp = std::max(-1.0f, std::min(1.0f, smp));
*in = smp;
}


void GranularProcessor::Process(
ShortFrame* input,
ShortFrame* output,
Expand Down Expand Up @@ -200,7 +216,8 @@ void GranularProcessor::Process(
(playback_mode_ == PLAYBACK_MODE_KAMMERL
&& kammerl_.isSlicePlaybackActive()) ?
parameters_.reverb : 0.0f; // Map reverb parameter to feedback in PLAYBACK_MODE_KAMMERL.
if (playback_mode_ != PLAYBACK_MODE_KAMMERL) {
if ((playback_mode_ != PLAYBACK_MODE_KAMMERL)
&& playback_mode_ != PLAYBACK_MODE_SPECTRAL_CLOUD) {
ONE_POLE(freeze_lp_, parameters_.freeze ? 1.0f : 0.0f, 0.0005f)
feedback = parameters_.feedback;
float cutoff = (20.0f + 100.0f * feedback * feedback) / sample_rate();
Expand All @@ -227,7 +244,7 @@ void GranularProcessor::Process(
}

// Diffusion and pitch-shifting post-processings.
if (playback_mode_ != PLAYBACK_MODE_SPECTRAL &&
if (playback_mode_ != PLAYBACK_MODE_SPECTRAL_CLOUD &&
playback_mode_!= PLAYBACK_MODE_KAMMERL ) {
float texture = parameters_.texture;
float diffusion = playback_mode_ == PLAYBACK_MODE_GRANULAR
Expand All @@ -237,11 +254,12 @@ void GranularProcessor::Process(
diffuser_.Process(out_, size);
}

if (playback_mode_ == PLAYBACK_MODE_LOOPING_DELAY &&
(!parameters_.freeze || looper_.synchronized())) {
pitch_shifter_.set_ratio(SemitonesToRatio(parameters_.pitch));
pitch_shifter_.set_size(parameters_.size);
pitch_shifter_.Process(out_, size);
if (((playback_mode_ == PLAYBACK_MODE_LOOPING_DELAY)
&& (!parameters_.freeze || looper_.synchronized()))
|| (playback_mode_ == PLAYBACK_MODE_SPECTRAL_CLOUD)) {
pitch_shifter_.set_ratio(SemitonesToRatio(parameters_.pitch));
pitch_shifter_.set_size(parameters_.size);
pitch_shifter_.Process(out_, size);
}

// Apply filters.
Expand Down Expand Up @@ -304,6 +322,11 @@ void GranularProcessor::Process(
}

for (size_t i = 0; i < size; ++i) {
if (playback_mode_ == PLAYBACK_MODE_SPECTRAL_CLOUD) {
WarmDistortion(&out_[i].l, parameters_.kammerl.pitch_mode);
WarmDistortion(&out_[i].r, parameters_.kammerl.pitch_mode);
}

output[i].l = SoftConvert(out_[i].l);
output[i].r = SoftConvert(out_[i].r);
}
Expand All @@ -315,7 +338,7 @@ void GranularProcessor::PreparePersistentData() {
persistent_state_.write_head[1] = low_fidelity_ ?
buffer_8_[1].head() : buffer_16_[1].head();
persistent_state_.quality = quality();
persistent_state_.spectral = playback_mode() == PLAYBACK_MODE_SPECTRAL;
persistent_state_.spectral = playback_mode() == PLAYBACK_MODE_SPECTRAL_CLOUD;
}

void GranularProcessor::GetPersistentData(
Expand Down Expand Up @@ -360,11 +383,11 @@ bool GranularProcessor::LoadPersistentData(const uint32_t* data) {

if (i == 0) {
// We now know from which mode the data was saved.
bool currently_spectral = playback_mode_ == PLAYBACK_MODE_SPECTRAL;
bool currently_spectral = playback_mode_ == PLAYBACK_MODE_SPECTRAL_CLOUD;
bool requires_spectral = persistent_state_.spectral;
if (currently_spectral ^ requires_spectral) {
set_playback_mode(requires_spectral
? PLAYBACK_MODE_SPECTRAL
? PLAYBACK_MODE_SPECTRAL_CLOUD
: PLAYBACK_MODE_GRANULAR);
}
set_quality(persistent_state_.quality);
Expand Down Expand Up @@ -392,8 +415,8 @@ bool GranularProcessor::LoadPersistentData(const uint32_t* data) {

void GranularProcessor::Prepare() {
bool playback_mode_changed = previous_playback_mode_ != playback_mode_;
bool benign_change = previous_playback_mode_ != PLAYBACK_MODE_SPECTRAL
&& playback_mode_ != PLAYBACK_MODE_SPECTRAL
bool benign_change = previous_playback_mode_ != PLAYBACK_MODE_SPECTRAL_CLOUD
&& playback_mode_ != PLAYBACK_MODE_SPECTRAL_CLOUD
&& previous_playback_mode_ != PLAYBACK_MODE_LAST;

if (!reset_buffers_ && playback_mode_changed && benign_change) {
Expand Down Expand Up @@ -444,7 +467,7 @@ void GranularProcessor::Prepare() {
&correlator_data[correlator_block_size]);
pitch_shifter_.Init((uint16_t*)correlator_data);

if (playback_mode_ == PLAYBACK_MODE_SPECTRAL) {
if (playback_mode_ == PLAYBACK_MODE_SPECTRAL_CLOUD) {
phase_vocoder_.Init(
buffer, buffer_size,
lut_sine_window_4096, 4096,
Expand Down Expand Up @@ -474,7 +497,7 @@ void GranularProcessor::Prepare() {
previous_playback_mode_ = playback_mode_;
}

if (playback_mode_ == PLAYBACK_MODE_SPECTRAL) {
if (playback_mode_ == PLAYBACK_MODE_SPECTRAL_CLOUD) {
phase_vocoder_.Buffer();
} else if (playback_mode_ == PLAYBACK_MODE_STRETCH) {
if (resolution() == 8) {
Expand Down
4 changes: 3 additions & 1 deletion clouds/dsp/granular_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ enum PlaybackMode {
PLAYBACK_MODE_GRANULAR = 0,
PLAYBACK_MODE_STRETCH = 1,
PLAYBACK_MODE_LOOPING_DELAY = 2,
PLAYBACK_MODE_SPECTRAL = 3,
PLAYBACK_MODE_SPECTRAL_CLOUD = 3,
PLAYBACK_MODE_KAMMERL = 4,
PLAYBACK_MODE_LAST = 5
};
Expand Down Expand Up @@ -151,6 +151,8 @@ class GranularProcessor {
void PreparePersistentData();

private:
void WarmDistortion(float* in, float parameter);

inline int32_t resolution() const {
return low_fidelity_ ? 8 : 16;
}
Expand Down
3 changes: 2 additions & 1 deletion clouds/dsp/kammerl_player.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ float KammerlPlayer::quantizeSize(float size) const {
static const size_t kNumSizeQuantizationIntevals = sizeof(kSizeQuantization)
/ sizeof(float);
if (size > kSizeQuantizationBorder[0]) {
const size_t index = std::upper_bound(kSizeQuantizationBorder,
size_t index = std::upper_bound(kSizeQuantizationBorder,
kSizeQuantizationBorder + kNumSizeQuantizationIntevals, size)
- kSizeQuantizationBorder;
CONSTRAIN(index, 0, kNumSizeQuantizationIntevals - 1);
return kSizeQuantization[index];
}
return size;
Expand Down
21 changes: 14 additions & 7 deletions clouds/dsp/kammerl_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class KammerlPlayer {
template<Resolution resolution>
void Play(const AudioBuffer<resolution>* buffer,
const Parameters& parameters, float* out, size_t size) {
int32_t max_delay = buffer->size();
int32_t max_delay = buffer->size() - 4;
num_samples_since_trigger_ += size;
if (num_samples_since_trigger_ > max_delay) {
num_samples_since_trigger_ = 0;
Expand Down Expand Up @@ -267,8 +267,8 @@ class KammerlPlayer {
case PLAYBACK_MODE_SCRATCH_PITCH:
// TODO: Use precomputed sin lookup table.
playback_sample_step = 1.0f
- std::sin(slice_processed_percentage * 2.0f * M_PI)
* (1.0f - pitch_parameter);
- Interpolate(lut_sin, slice_processed_percentage,
1024.0f) * (1.0f - pitch_parameter);
break;
default:
playback_sample_step = pitch_parameter;
Expand Down Expand Up @@ -348,15 +348,22 @@ class KammerlPlayer {
slice_play_pos_samples_ += playback_sample_step
* slice_play_direction_;

// Safety check to ensure the 4 sample lookahead doesn't lead to an out-of-bound read.
uint32_t buffer_pos_idx_in_buffer = buffer_pos_idx >> 12;
uint32_t buffer_pos_fract = buffer_pos_idx << 4;
buffer_pos_idx_in_buffer = buffer_pos_idx_in_buffer
% buffer->size();
CONSTRAIN(buffer_pos_idx_in_buffer, 0, buffer->size() - 5);

// Write to output.
float l = buffer[0].ReadHermite((buffer_pos_idx >> 12),
buffer_pos_idx << 4);
float l = buffer[0].ReadHermite(buffer_pos_idx_in_buffer,
buffer_pos_fract);
if (num_channels_ == 1) {
*out++ = l;
*out++ = l;
} else if (num_channels_ == 2) {
float r = buffer[1].ReadHermite((buffer_pos_idx >> 12),
buffer_pos_idx << 4);
float r = buffer[1].ReadHermite(buffer_pos_idx_in_buffer,
buffer_pos_fract);
*out++ = l;
*out++ = r;
}
Expand Down
7 changes: 0 additions & 7 deletions clouds/dsp/parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,6 @@ struct Parameters {
float stereo_spread;
bool use_deterministic_seed;
} granular;

struct Spectral {
float quantization;
float refresh_rate;
float phase_randomization;
float warp;
} spectral;

struct Kammerl {
float probability;
Expand Down
Loading

0 comments on commit 3dae780

Please sign in to comment.