use alaw companding, apply formatting
This commit is contained in:
242
util/retro_buf.h
242
util/retro_buf.h
@@ -1,155 +1,165 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../companding/alaw.h"
|
||||||
#include "../filter/chebyshev.h"
|
#include "../filter/chebyshev.h"
|
||||||
#include "../companding/ulaw.h"
|
|
||||||
|
|
||||||
namespace trnr {
|
namespace trnr {
|
||||||
|
|
||||||
struct retro_buf_modulation {
|
struct retro_buf_modulation {
|
||||||
double midi_note;
|
double midi_note;
|
||||||
double pitch_mod;
|
double pitch_mod;
|
||||||
double samplerate; // the (re)samplerate
|
double samplerate; // the (re)samplerate
|
||||||
double bitrate;
|
double bitrate;
|
||||||
size_t start; // sets the start point from which to play
|
size_t start; // sets the start point from which to play
|
||||||
size_t end; // sets the end point
|
size_t end; // sets the end point
|
||||||
bool looping; // sets whether the sample should loop
|
bool looping; // sets whether the sample should loop
|
||||||
bool reset; // resets the phase
|
bool reset; // resets the phase
|
||||||
int jitter; // jitter amount
|
int jitter; // jitter amount
|
||||||
double deviation;
|
double deviation;
|
||||||
};
|
};
|
||||||
|
|
||||||
// base class for accessing a sample buffer with adjustable samplerate, bitrate and other options.
|
// base class for accessing a sample buffer with adjustable samplerate, bitrate and other
|
||||||
|
// options.
|
||||||
class retro_buf {
|
class retro_buf {
|
||||||
public:
|
public:
|
||||||
void set_host_samplerate(double _samplerate) {
|
void set_host_samplerate(double _samplerate)
|
||||||
m_host_samplerate = _samplerate;
|
{
|
||||||
m_imaging_filter_l.set_samplerate(_samplerate);
|
m_host_samplerate = _samplerate;
|
||||||
m_imaging_filter_r.set_samplerate(_samplerate);
|
m_imaging_filter_l.set_samplerate(_samplerate);
|
||||||
}
|
m_imaging_filter_r.set_samplerate(_samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
void set_buf_samplerate(double _samplerate) {
|
void set_buf_samplerate(double _samplerate) { m_buf_samplerate = _samplerate; }
|
||||||
m_buf_samplerate = _samplerate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_buffer_size(size_t _buffer_size) {
|
void set_buffer_size(size_t _buffer_size) { m_buffer_size = _buffer_size; }
|
||||||
m_buffer_size = _buffer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_channel_count(size_t _channel_count) {
|
void set_channel_count(size_t _channel_count) { m_channel_count = _channel_count; }
|
||||||
m_channel_count = _channel_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void start_playback() {
|
void start_playback()
|
||||||
if (m_modulation.reset || (!m_modulation.reset && m_playback_pos == -1)) {
|
{
|
||||||
m_playback_pos = (double)m_modulation.start;
|
if (m_modulation.reset || (!m_modulation.reset && m_playback_pos == -1)) {
|
||||||
}
|
m_playback_pos = (double)m_modulation.start;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @return is active
|
// @return is active
|
||||||
bool process_block(double** _outputs, size_t _block_size, retro_buf_modulation _mod) {
|
bool process_block(double** _outputs, size_t _block_size, retro_buf_modulation _mod)
|
||||||
|
{
|
||||||
|
|
||||||
m_modulation = _mod;
|
m_modulation = _mod;
|
||||||
|
|
||||||
for (int i = 0; i < _block_size; ++i) {
|
for (int i = 0; i < _block_size; ++i) {
|
||||||
double output_l = 0;
|
double output_l = 0;
|
||||||
double output_r = 0;
|
double output_r = 0;
|
||||||
|
|
||||||
// if within bounds
|
// if within bounds
|
||||||
if (m_playback_pos > -1 && m_playback_pos <= _mod.end) {
|
if (m_playback_pos > -1 && m_playback_pos <= _mod.end) {
|
||||||
|
|
||||||
// quantize index
|
// quantize index
|
||||||
double samplerate_divisor = m_host_samplerate / _mod.samplerate;
|
double samplerate_divisor = m_host_samplerate / _mod.samplerate;
|
||||||
size_t quantized_index = static_cast<size_t>(static_cast<size_t>(m_playback_pos / samplerate_divisor) * samplerate_divisor);
|
size_t quantized_index = static_cast<size_t>(
|
||||||
|
static_cast<size_t>(m_playback_pos / samplerate_divisor) *
|
||||||
|
samplerate_divisor);
|
||||||
|
|
||||||
// get sample for each channel
|
// get sample for each channel
|
||||||
output_l = get_sample((size_t)wrap(quantized_index + jitterize(_mod.jitter), m_buffer_size), 0);
|
output_l = get_sample(
|
||||||
if (m_channel_count > 0) {
|
(size_t)wrap(quantized_index + jitterize(_mod.jitter), m_buffer_size),
|
||||||
output_r = get_sample((size_t)wrap(quantized_index + jitterize(_mod.jitter), m_buffer_size), 1);
|
0);
|
||||||
} else {
|
if (m_channel_count > 0) {
|
||||||
output_r = output_l;
|
output_r =
|
||||||
}
|
get_sample((size_t)wrap(quantized_index + jitterize(_mod.jitter),
|
||||||
|
m_buffer_size),
|
||||||
|
1);
|
||||||
|
} else {
|
||||||
|
output_r = output_l;
|
||||||
|
}
|
||||||
|
|
||||||
// advance position
|
// advance position
|
||||||
double note_ratio = midi_to_ratio(_mod.midi_note + _mod.pitch_mod);
|
double note_ratio = midi_to_ratio(_mod.midi_note + _mod.pitch_mod);
|
||||||
m_playback_pos += note_ratio * (m_buf_samplerate / m_host_samplerate);
|
m_playback_pos += note_ratio * (m_buf_samplerate / m_host_samplerate);
|
||||||
|
|
||||||
reduce_bitrate(output_l, output_r, _mod.bitrate);
|
reduce_bitrate(output_l, output_r, _mod.bitrate);
|
||||||
|
|
||||||
// calculate imaging filter frequency + deviation
|
// calculate imaging filter frequency + deviation
|
||||||
double filter_frequency = ((_mod.samplerate / 2) * note_ratio) * ((_mod.deviation * 9) + 1);
|
double filter_frequency =
|
||||||
|
((_mod.samplerate / 2) * note_ratio) * ((_mod.deviation * 9) + 1);
|
||||||
|
|
||||||
m_imaging_filter_l.process_sample(output_l, filter_frequency);
|
m_imaging_filter_l.process_sample(output_l, filter_frequency);
|
||||||
m_imaging_filter_r.process_sample(output_r, filter_frequency);
|
m_imaging_filter_r.process_sample(output_r, filter_frequency);
|
||||||
}
|
}
|
||||||
// else if loop
|
// else if loop
|
||||||
else if(_mod.looping) {
|
else if (_mod.looping) {
|
||||||
// loop
|
// loop
|
||||||
m_playback_pos = (double)_mod.start;
|
m_playback_pos = (double)_mod.start;
|
||||||
}
|
}
|
||||||
// else
|
// else
|
||||||
else {
|
else {
|
||||||
// stop
|
// stop
|
||||||
m_playback_pos = -1;
|
m_playback_pos = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_outputs[0][i] = output_l;
|
_outputs[0][i] = output_l;
|
||||||
_outputs[1][i] = output_r;
|
_outputs[1][i] = output_r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_playback_pos > -1;
|
return m_playback_pos > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual float get_sample(size_t _index, size_t _channel) = 0;
|
virtual float get_sample(size_t _index, size_t _channel) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t m_channel_count = 0;
|
size_t m_channel_count = 0;
|
||||||
size_t m_buffer_size = 0;
|
size_t m_buffer_size = 0;
|
||||||
double m_buf_samplerate = 44100.0;
|
double m_buf_samplerate = 44100.0;
|
||||||
double m_host_samplerate = 44100.0;
|
double m_host_samplerate = 44100.0;
|
||||||
double m_playback_pos = -1;
|
double m_playback_pos = -1;
|
||||||
|
|
||||||
chebyshev m_imaging_filter_l;
|
chebyshev m_imaging_filter_l;
|
||||||
chebyshev m_imaging_filter_r;
|
chebyshev m_imaging_filter_r;
|
||||||
ulaw m_compander;
|
retro_buf_modulation m_modulation;
|
||||||
retro_buf_modulation m_modulation;
|
|
||||||
|
|
||||||
float midi_to_ratio(double midi_note) {
|
float midi_to_ratio(double midi_note)
|
||||||
return powf(powf(2, (float)midi_note - 60.f), 1.f / 12.f);
|
{
|
||||||
}
|
return powf(powf(2, (float)midi_note - 60.f), 1.f / 12.f);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T clamp(T& value, T min, T max) {
|
T clamp(T& value, T min, T max)
|
||||||
if (value < min) {
|
{
|
||||||
value = min;
|
if (value < min) {
|
||||||
} else if (value > max) {
|
value = min;
|
||||||
value = max;
|
} else if (value > max) {
|
||||||
}
|
value = max;
|
||||||
return value;
|
}
|
||||||
}
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
double wrap(double value, double max) {
|
double wrap(double value, double max)
|
||||||
while (value > max) {
|
{
|
||||||
value -= max;
|
while (value > max) { value -= max; }
|
||||||
}
|
return value;
|
||||||
return value;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int jitterize(int jitter) {
|
int jitterize(int jitter)
|
||||||
if (jitter > 0) {
|
{
|
||||||
return static_cast<int>(rand() % jitter);
|
if (jitter > 0) {
|
||||||
} else {
|
return static_cast<int>(rand() % jitter);
|
||||||
return 0;
|
} else {
|
||||||
}
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void reduce_bitrate(double& value1, double& value2, double bit) {
|
void reduce_bitrate(double& value1, double& value2, double bit)
|
||||||
m_compander.encode_samples(value1, value2);
|
{
|
||||||
|
value1 = alaw_encode(value1);
|
||||||
|
value2 = alaw_encode(value2);
|
||||||
|
|
||||||
float resolution = powf(2, bit);
|
float resolution = powf(2, bit);
|
||||||
value1 = round(value1 * resolution) / resolution;
|
value1 = round(value1 * resolution) / resolution;
|
||||||
value2 = round(value2 * resolution) / resolution;
|
value2 = round(value2 * resolution) / resolution;
|
||||||
|
|
||||||
m_compander.decode_samples(value1, value2);
|
value1 = alaw_decode(value1);
|
||||||
}
|
value2 = alaw_decode(value2);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace trnr
|
||||||
|
|||||||
Reference in New Issue
Block a user