diff --git a/util/retro_buf.h b/util/retro_buf.h index 9fdca8d..7d80cc7 100644 --- a/util/retro_buf.h +++ b/util/retro_buf.h @@ -1,155 +1,165 @@ #pragma once +#include "../companding/alaw.h" #include "../filter/chebyshev.h" -#include "../companding/ulaw.h" namespace trnr { struct retro_buf_modulation { - double midi_note; - double pitch_mod; - double samplerate; // the (re)samplerate - double bitrate; - size_t start; // sets the start point from which to play - size_t end; // sets the end point - bool looping; // sets whether the sample should loop - bool reset; // resets the phase - int jitter; // jitter amount - double deviation; + double midi_note; + double pitch_mod; + double samplerate; // the (re)samplerate + double bitrate; + size_t start; // sets the start point from which to play + size_t end; // sets the end point + bool looping; // sets whether the sample should loop + bool reset; // resets the phase + int jitter; // jitter amount + 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 { public: - void set_host_samplerate(double _samplerate) { - m_host_samplerate = _samplerate; - m_imaging_filter_l.set_samplerate(_samplerate); - m_imaging_filter_r.set_samplerate(_samplerate); - } + void set_host_samplerate(double _samplerate) + { + m_host_samplerate = _samplerate; + m_imaging_filter_l.set_samplerate(_samplerate); + m_imaging_filter_r.set_samplerate(_samplerate); + } - void set_buf_samplerate(double _samplerate) { - m_buf_samplerate = _samplerate; - } + void set_buf_samplerate(double _samplerate) { m_buf_samplerate = _samplerate; } - void set_buffer_size(size_t _buffer_size) { - m_buffer_size = _buffer_size; - } + void set_buffer_size(size_t _buffer_size) { m_buffer_size = _buffer_size; } - void set_channel_count(size_t _channel_count) { - m_channel_count = _channel_count; - } + void set_channel_count(size_t _channel_count) { m_channel_count = _channel_count; } - void start_playback() { - if (m_modulation.reset || (!m_modulation.reset && m_playback_pos == -1)) { - m_playback_pos = (double)m_modulation.start; - } - } + void start_playback() + { + if (m_modulation.reset || (!m_modulation.reset && m_playback_pos == -1)) { + m_playback_pos = (double)m_modulation.start; + } + } - // @return is active - bool process_block(double** _outputs, size_t _block_size, retro_buf_modulation _mod) { + // @return is active + 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) { - double output_l = 0; - double output_r = 0; - - // if within bounds - if (m_playback_pos > -1 && m_playback_pos <= _mod.end) { - - // quantize index - double samplerate_divisor = m_host_samplerate / _mod.samplerate; - size_t quantized_index = static_cast(static_cast(m_playback_pos / samplerate_divisor) * samplerate_divisor); + for (int i = 0; i < _block_size; ++i) { + double output_l = 0; + double output_r = 0; - // get sample for each channel - output_l = get_sample((size_t)wrap(quantized_index + jitterize(_mod.jitter), m_buffer_size), 0); - if (m_channel_count > 0) { - output_r = get_sample((size_t)wrap(quantized_index + jitterize(_mod.jitter), m_buffer_size), 1); - } else { - output_r = output_l; - } - - // advance position - double note_ratio = midi_to_ratio(_mod.midi_note + _mod.pitch_mod); - m_playback_pos += note_ratio * (m_buf_samplerate / m_host_samplerate); - - reduce_bitrate(output_l, output_r, _mod.bitrate); + // if within bounds + if (m_playback_pos > -1 && m_playback_pos <= _mod.end) { - // calculate imaging filter frequency + deviation - double filter_frequency = ((_mod.samplerate / 2) * note_ratio) * ((_mod.deviation * 9) + 1); + // quantize index + double samplerate_divisor = m_host_samplerate / _mod.samplerate; + size_t quantized_index = static_cast( + static_cast(m_playback_pos / samplerate_divisor) * + samplerate_divisor); - m_imaging_filter_l.process_sample(output_l, filter_frequency); - m_imaging_filter_r.process_sample(output_r, filter_frequency); - } - // else if loop - else if(_mod.looping) { - // loop - m_playback_pos = (double)_mod.start; - } - // else - else { - // stop - m_playback_pos = -1; - } + // get sample for each channel + output_l = get_sample( + (size_t)wrap(quantized_index + jitterize(_mod.jitter), m_buffer_size), + 0); + if (m_channel_count > 0) { + output_r = + get_sample((size_t)wrap(quantized_index + jitterize(_mod.jitter), + m_buffer_size), + 1); + } else { + output_r = output_l; + } - _outputs[0][i] = output_l; - _outputs[1][i] = output_r; - } + // advance position + double note_ratio = midi_to_ratio(_mod.midi_note + _mod.pitch_mod); + m_playback_pos += note_ratio * (m_buf_samplerate / m_host_samplerate); - return m_playback_pos > -1; - } + reduce_bitrate(output_l, output_r, _mod.bitrate); - virtual float get_sample(size_t _index, size_t _channel) = 0; + // calculate imaging filter frequency + deviation + 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_r.process_sample(output_r, filter_frequency); + } + // else if loop + else if (_mod.looping) { + // loop + m_playback_pos = (double)_mod.start; + } + // else + else { + // stop + m_playback_pos = -1; + } + + _outputs[0][i] = output_l; + _outputs[1][i] = output_r; + } + + return m_playback_pos > -1; + } + + virtual float get_sample(size_t _index, size_t _channel) = 0; private: - size_t m_channel_count = 0; - size_t m_buffer_size = 0; - double m_buf_samplerate = 44100.0; - double m_host_samplerate = 44100.0; - double m_playback_pos = -1; + size_t m_channel_count = 0; + size_t m_buffer_size = 0; + double m_buf_samplerate = 44100.0; + double m_host_samplerate = 44100.0; + double m_playback_pos = -1; - chebyshev m_imaging_filter_l; - chebyshev m_imaging_filter_r; - ulaw m_compander; - retro_buf_modulation m_modulation; + chebyshev m_imaging_filter_l; + chebyshev m_imaging_filter_r; + retro_buf_modulation m_modulation; - float midi_to_ratio(double midi_note) { - return powf(powf(2, (float)midi_note - 60.f), 1.f / 12.f); - } - - template - T clamp(T& value, T min, T max) { - if (value < min) { - value = min; - } else if (value > max) { - value = max; - } - return value; - } + float midi_to_ratio(double midi_note) + { + return powf(powf(2, (float)midi_note - 60.f), 1.f / 12.f); + } - double wrap(double value, double max) { - while (value > max) { - value -= max; - } - return value; - } + template + T clamp(T& value, T min, T max) + { + if (value < min) { + value = min; + } else if (value > max) { + value = max; + } + return value; + } - int jitterize(int jitter) { - if (jitter > 0) { - return static_cast(rand() % jitter); - } else { - return 0; - } - } + double wrap(double value, double max) + { + while (value > max) { value -= max; } + return value; + } - void reduce_bitrate(double& value1, double& value2, double bit) { - m_compander.encode_samples(value1, value2); + int jitterize(int jitter) + { + if (jitter > 0) { + return static_cast(rand() % jitter); + } else { + return 0; + } + } - float resolution = powf(2, bit); - value1 = round(value1 * resolution) / resolution; - value2 = round(value2 * resolution) / resolution; + void reduce_bitrate(double& value1, double& value2, double bit) + { + value1 = alaw_encode(value1); + value2 = alaw_encode(value2); - m_compander.decode_samples(value1, value2); - } + float resolution = powf(2, bit); + value1 = round(value1 * resolution) / resolution; + value2 = round(value2 * resolution) / resolution; + + value1 = alaw_decode(value1); + value2 = alaw_decode(value2); + } }; -} \ No newline at end of file +} // namespace trnr