procedural audio buffer, add mods to synth
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "audio_buffer.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -8,15 +9,15 @@ using namespace std;
|
|||||||
|
|
||||||
namespace trnr {
|
namespace trnr {
|
||||||
|
|
||||||
enum m_event_type {
|
enum midi_event_type {
|
||||||
note_on = 0,
|
note_on = 0,
|
||||||
note_off,
|
note_off,
|
||||||
pitch_wheel,
|
pitch_wheel,
|
||||||
mod_wheel
|
mod_wheel
|
||||||
};
|
};
|
||||||
|
|
||||||
struct m_event {
|
struct midi_event {
|
||||||
m_event_type type;
|
midi_event_type type;
|
||||||
int offset;
|
int offset;
|
||||||
int midi_note;
|
int midi_note;
|
||||||
float velocity;
|
float velocity;
|
||||||
@@ -26,35 +27,36 @@ struct m_event {
|
|||||||
constexpr size_t MAX_VOICES = 8;
|
constexpr size_t MAX_VOICES = 8;
|
||||||
constexpr size_t MAX_EVENTS_PER_VOICE = 32;
|
constexpr size_t MAX_EVENTS_PER_VOICE = 32;
|
||||||
|
|
||||||
template <typename voice, typename sample>
|
template <typename t_voice, typename t_sample>
|
||||||
void voice_process_block(voice& v, sample** audio, int num_frames, const array<m_event, MAX_EVENTS_PER_VOICE>& events,
|
void voice_process_block(t_voice& v, t_sample** frames, size_t num_frames, midi_event* events, size_t num_events,
|
||||||
size_t num_events);
|
const vector<audio_buffer<t_sample>>& mods = {});
|
||||||
|
|
||||||
template <typename voice>
|
template <typename t_voice>
|
||||||
struct synth {
|
struct synth {
|
||||||
array<voice, MAX_VOICES> voices;
|
array<t_voice, MAX_VOICES> voices;
|
||||||
array<array<m_event, MAX_EVENTS_PER_VOICE>, MAX_VOICES> voice_events;
|
array<array<midi_event, MAX_EVENTS_PER_VOICE>, MAX_VOICES> voice_events;
|
||||||
array<size_t, MAX_VOICES> counts;
|
array<size_t, MAX_VOICES> counts;
|
||||||
int active_voice_count = 1;
|
int active_voice_count = 1;
|
||||||
size_t index_to_steal = 0;
|
size_t index_to_steal = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename voice>
|
template <typename t_voice>
|
||||||
void synth_init(synth<voice>& s, double samplerate)
|
void synth_init(synth<t_voice>& s, double samplerate)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < MAX_VOICES; ++i) {
|
for (size_t i = 0; i < MAX_VOICES; ++i) {
|
||||||
s.voices[i] = voice();
|
s.voices[i] = t_voice();
|
||||||
s.voices[i].voice_init(samplerate);
|
s.voices[i].voice_init(samplerate);
|
||||||
s.counts[i] = 0;
|
s.counts[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename voice, typename sample>
|
template <typename t_voice, typename t_sample>
|
||||||
void synth_process_block(synth<voice>& s, sample** audio, const vector<m_event>& midi_events, int num_frames)
|
void synth_process_block(synth<t_voice>& s, t_sample** frames, int num_frames, const vector<midi_event>& midi_events,
|
||||||
|
const vector<audio_buffer<t_sample>>& mods = {})
|
||||||
{
|
{
|
||||||
// reset voice events and counts
|
// reset voice events and counts
|
||||||
for (int i = 0; i < MAX_VOICES; i++) {
|
for (int i = 0; i < MAX_VOICES; i++) {
|
||||||
s.voice_events[i].fill(m_event {});
|
s.voice_events[i].fill(midi_event {});
|
||||||
s.counts[i] = 0;
|
s.counts[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +108,9 @@ void synth_process_block(synth<voice>& s, sample** audio, const vector<m_event>&
|
|||||||
|
|
||||||
for (size_t i = 0; i < s.active_voice_count; ++i) {
|
for (size_t i = 0; i < s.active_voice_count; ++i) {
|
||||||
auto& v = s.voices[i];
|
auto& v = s.voices[i];
|
||||||
auto& events = s.voice_events[i];
|
auto& events = s.voice_events[i].data();
|
||||||
voice_process_block(v, audio, num_frames, events, s.counts[i]);
|
size_t num_events = s.counts[i];
|
||||||
|
voice_process_block(v, frames, num_frames, events, num_events, mods);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace trnr
|
} // namespace trnr
|
||||||
|
|||||||
@@ -1,81 +1,32 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
namespace trnr {
|
namespace trnr {
|
||||||
template <typename t_sample>
|
template <typename t_sample>
|
||||||
class audio_buffer {
|
struct audio_buffer {
|
||||||
public:
|
size_t channels;
|
||||||
audio_buffer(const t_sample** input, int channels, int frames)
|
size_t frames;
|
||||||
: m_data(channels * frames)
|
|
||||||
, m_channels(channels)
|
|
||||||
, m_frames(frames)
|
|
||||||
, m_channel_ptrs(channels)
|
|
||||||
{
|
|
||||||
for (int ch = 0; ch < channels; ++ch) {
|
|
||||||
std::copy(input[ch], input[ch] + frames, m_data.begin() + ch * frames);
|
|
||||||
}
|
|
||||||
update_channel_ptrs();
|
|
||||||
}
|
|
||||||
|
|
||||||
audio_buffer(int channels = 1, int frames = 1024)
|
vector<t_sample> flat_data;
|
||||||
: m_channels(channels)
|
vector<t_sample*> channel_ptrs;
|
||||||
, m_frames(frames)
|
|
||||||
, m_data(channels * frames)
|
|
||||||
, m_channel_ptrs(channels)
|
|
||||||
{
|
|
||||||
update_channel_ptrs();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_size(int channels, int frames)
|
|
||||||
{
|
|
||||||
m_channels = channels;
|
|
||||||
m_frames = frames;
|
|
||||||
m_data.resize(channels * frames);
|
|
||||||
m_channel_ptrs.resize(channels);
|
|
||||||
update_channel_ptrs();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_data(const t_sample** input, int channels, int frames)
|
|
||||||
{
|
|
||||||
set_size(channels, frames);
|
|
||||||
for (int ch = 0; ch < channels; ++ch) {
|
|
||||||
std::copy(input[ch], input[ch] + frames, m_data.begin() + ch * frames);
|
|
||||||
}
|
|
||||||
update_channel_ptrs();
|
|
||||||
}
|
|
||||||
|
|
||||||
int num_samples() const { return m_frames; }
|
|
||||||
|
|
||||||
int num_channels() const { return m_channels; }
|
|
||||||
|
|
||||||
t_sample* data() { return m_data.data(); }
|
|
||||||
|
|
||||||
const t_sample* data() const { return m_data.data(); }
|
|
||||||
|
|
||||||
// t_sample** access, always up-to-date after construction/resize
|
|
||||||
t_sample** write_ptrs() { return m_channel_ptrs.data(); }
|
|
||||||
|
|
||||||
t_sample* write_ptr(int channel)
|
|
||||||
{
|
|
||||||
assert(channel >= 0 && channel < m_channels);
|
|
||||||
return m_channel_ptrs[channel];
|
|
||||||
}
|
|
||||||
|
|
||||||
const t_sample* const* channel_ptrs() const { return m_channel_ptrs.data(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void update_channel_ptrs()
|
|
||||||
{
|
|
||||||
for (int ch = 0; ch < m_channels; ++ch) { m_channel_ptrs[ch] = m_data.data() + ch * m_frames; }
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<t_sample> m_data;
|
|
||||||
std::vector<t_sample*> m_channel_ptrs;
|
|
||||||
|
|
||||||
int m_channels;
|
|
||||||
int m_frames; // samples per channel
|
|
||||||
};
|
};
|
||||||
} // namespace trnr
|
|
||||||
|
template <typename t_sample>
|
||||||
|
void audio_buffer_init(audio_buffer<t_sample>& a, size_t channels, size_t frames)
|
||||||
|
{
|
||||||
|
a.channels = channels;
|
||||||
|
a.frames = frames;
|
||||||
|
a.flat_data.resize(channels * frames);
|
||||||
|
a.channel_ptrs.resize(channels);
|
||||||
|
audio_buffer_update_ptrs(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename t_sample>
|
||||||
|
void audio_buffer_update_ptrs(audio_buffer<t_sample>& a)
|
||||||
|
{
|
||||||
|
for (int ch = 0; ch < a.channels; ++ch) { a.channel_ptrs[ch] = a.flat_data.data() + ch * a.frames; }
|
||||||
|
}
|
||||||
|
} // namespace trnr
|
||||||
|
|||||||
Reference in New Issue
Block a user