Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderVocke committed Aug 15, 2023
1 parent d1778f4 commit 329a4ae
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 31 deletions.
6 changes: 3 additions & 3 deletions src/libshoopdaloop/internal/ConnectedFXChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ using namespace shoop_constants;
ConnectedFXChain::ConnectedFXChain(std::shared_ptr<FXChain> chain, std::shared_ptr<Backend> backend) :
chain(chain), backend(backend) {
for (auto const& port : chain->input_audio_ports()) {
mc_audio_input_ports.push_back(std::make_shared<ConnectedPort>(port, backend));
mc_audio_input_ports.push_back(std::make_shared<ConnectedPort>(port, backend, shoop_types::ProcessWhen::BeforeFXChains));
}
for (auto const& port : chain->output_audio_ports()) {
mc_audio_output_ports.push_back(std::make_shared<ConnectedPort>(port, backend));
mc_audio_output_ports.push_back(std::make_shared<ConnectedPort>(port, backend, shoop_types::ProcessWhen::AfterFXChains));
}
for (auto const& port : chain->input_midi_ports()) {
mc_midi_input_ports.push_back(std::make_shared<ConnectedPort>(port, backend));
mc_midi_input_ports.push_back(std::make_shared<ConnectedPort>(port, backend, shoop_types::ProcessWhen::BeforeFXChains));
}
}

Expand Down
19 changes: 12 additions & 7 deletions src/libshoopdaloop/internal/ConnectedPort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "MidiMergingBuffer.h"
#include "Backend.h"
#include "DummyAudioSystem.h"
#include "shoop_globals.h"
#include <fmt/ranges.h>

using namespace shoop_types;
Expand All @@ -19,7 +20,9 @@ std::string ConnectedPort::log_module_name() const {
return "Backend.ConnectedPort";
}

ConnectedPort::ConnectedPort (std::shared_ptr<PortInterface> const& port, std::shared_ptr<Backend> const& backend) :
ConnectedPort::ConnectedPort (std::shared_ptr<PortInterface> const& port,
std::shared_ptr<Backend> const& backend,
shoop_types::ProcessWhen process_when) :
port(port),
maybe_audio_buffer(nullptr),
maybe_midi_input_buffer(nullptr),
Expand All @@ -30,17 +33,15 @@ ConnectedPort::ConnectedPort (std::shared_ptr<PortInterface> const& port, std::s
passthrough_muted(false),
backend(backend),
peak(0.0f),
n_events_processed(0) {
n_events_processed(0),
ma_process_when(process_when) {
log_init();

bool is_internal = (dynamic_cast<InternalAudioPort<float>*>(port.get()) ||
dynamic_cast<InternalLV2MidiOutputPort*>(port.get()));
bool is_fx_in = is_internal && (port->direction() == PortDirection::Output);
bool is_ext_in = !is_internal && (port->direction() == PortDirection::Input);

ma_process_when = (is_ext_in || is_fx_in) ?
shoop_types::ProcessWhen::BeforeFXChains : shoop_types::ProcessWhen::AfterFXChains;

if (auto m = dynamic_cast<MidiPortInterface*>(port.get())) {
maybe_midi_state = std::make_shared<MidiStateTracker>(true, true, true);
if(m->direction() == PortDirection::Output) {
Expand Down Expand Up @@ -155,7 +156,9 @@ void ConnectedPort::PROC_passthrough_midi(size_t n_frames, ConnectedPort &to) {
auto &msg = maybe_midi_input_buffer->PROC_get_event_reference(i);
std::vector<uint8_t> pd{msg.get_data(), msg.get_data() + msg.get_size()};
uint32_t t = msg.get_time();
log<logging::LogLevel::debug>("Passthrough midi message reference @ {}: {}", t, pd);
void* to_ptr = &to;
auto to_ptr_fmt = fmt::ptr(to_ptr);
log<logging::LogLevel::debug>("Passthrough midi message reference to {} @ {}: {}", to_ptr_fmt, t, pd);
to.maybe_midi_output_merging_buffer->PROC_write_event_reference(msg);
}
}
Expand All @@ -176,8 +179,9 @@ void ConnectedPort::PROC_finalize_process(size_t n_frames) {
} else if (auto m = dynamic_cast<MidiPortInterface*>(port.get())) {
if (m->direction() == PortDirection::Output) {
if (!muted) {
maybe_midi_output_merging_buffer->PROC_sort();
size_t n_events = maybe_midi_output_merging_buffer->PROC_get_n_events();
maybe_midi_output_merging_buffer->PROC_sort();

for(size_t i=0; i<n_events; i++) {
uint32_t size, time;
const uint8_t* data;
Expand All @@ -187,6 +191,7 @@ void ConnectedPort::PROC_finalize_process(size_t n_frames) {
maybe_midi_output_buffer->PROC_write_event_value(size, time, data);
maybe_midi_state->process_msg(data);
}

n_events_processed += n_events;
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/libshoopdaloop/internal/ConnectedPort.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ struct ConnectedPort : public std::enable_shared_from_this<ConnectedPort>,
std::atomic<bool> passthrough_muted;
shoop_types::ProcessWhen ma_process_when;

ConnectedPort (std::shared_ptr<PortInterface> const& port, std::shared_ptr<Backend> const& backend);
ConnectedPort (std::shared_ptr<PortInterface> const& port,
std::shared_ptr<Backend> const& backend,
shoop_types::ProcessWhen process_when);

void PROC_reset_buffers();
void PROC_ensure_buffer(size_t n_frames, bool do_zero=false);
Expand Down
2 changes: 1 addition & 1 deletion src/libshoopdaloop/internal/CustomProcessingChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ CustomProcessingChain<TimeType, SizeType>::CustomProcessingChain(
m_output_audio_ports.push_back(std::make_shared<InternalAudioPort<shoop_types::audio_sample_t>>("audio_out_" + std::to_string(i+1), PortDirection::Input, 4096));
}
for(size_t i=0; i<n_midi_inputs; i++) {
m_input_midi_ports.push_back(std::make_shared<DummyMidiPort>("midi_in_" + std::to_string(i+1), PortDirection::Input));
m_input_midi_ports.push_back(std::make_shared<DummyMidiPort>("midi_in_" + std::to_string(i+1), PortDirection::Output));
}
}

Expand Down
40 changes: 27 additions & 13 deletions src/libshoopdaloop/internal/DummyAudioSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,19 @@ std::vector<audio_sample_t> DummyAudioPort::dequeue_data(size_t n) {
MidiSortableMessageInterface &
DummyMidiPort::PROC_get_event_reference(size_t idx) {
try {
auto &m = m_queued_msgs.at(idx);
std::vector<uint8_t> pd{m.get_data(), m.get_data()+m.get_size()};
uint32_t time = m.get_time();
log<logging::LogLevel::debug>("Read midi message @ {}: {}", time, pd);
return m;
if (!m_queued_msgs.empty()) {
auto &m = m_queued_msgs.at(idx);
std::vector<uint8_t> pd{m.get_data(), m.get_data()+m.get_size()};
uint32_t time = m.get_time();
log<logging::LogLevel::debug>("Read queued midi message @ {}: {}", time, pd);
return m;
} else {
auto &m = m_buffer_data.at(idx);
std::vector<uint8_t> pd{m.get_data(), m.get_data()+m.get_size()};
uint32_t time = m.get_time();
log<logging::LogLevel::debug>("Read buffer midi message @ {}: {}", time, pd);
return m;
}
} catch (std::out_of_range &e) {
throw std::runtime_error("Dummy midi port read error");
}
Expand All @@ -115,9 +123,11 @@ void DummyMidiPort::PROC_write_event_value(uint32_t size, uint32_t time,
if (time < n_requested_frames) {
size_t new_time = time + (n_original_requested_frames - n_requested_frames);
std::vector<uint8_t> pd{data, data+size};
log<logging::LogLevel::debug>("Write midi message value @ {} -> {}: {}", time, new_time, pd);
log<logging::LogLevel::debug>("Write midi message value to external queue @ {} -> {}: {}", time, new_time, pd);
m_written_requested_msgs.push_back(StoredMessage(new_time, size, std::vector<uint8_t>(data, data + size)));
}
}
log<logging::LogLevel::debug>("Write midi message value to internal buffer @ {}", time);
m_buffer_data.push_back(StoredMessage(time, size, std::vector<uint8_t>(data, data + size)));
}

void DummyMidiPort::PROC_write_event_reference(
Expand Down Expand Up @@ -199,6 +209,7 @@ DummyMidiPort::PROC_get_read_buffer(size_t n_frames) {
MidiWriteableBufferInterface &
DummyMidiPort::PROC_get_write_buffer(size_t n_frames) {
current_buf_frames = n_frames;
m_buffer_data.clear();
return *(static_cast<MidiWriteableBufferInterface *>(this));
}

Expand All @@ -211,14 +222,17 @@ void DummyMidiPort::PROC_post_process(size_t n_frames) {

size_t DummyMidiPort::PROC_get_n_events() const {
size_t r = 0;
for (auto it = m_queued_msgs.begin(); it != m_queued_msgs.end(); ++it) {
if (it->time < current_buf_frames) {
r++;
} else {
break;
if (!m_queued_msgs.empty()) {
for (auto it = m_queued_msgs.begin(); it != m_queued_msgs.end(); ++it) {
if (it->time < current_buf_frames) {
r++;
} else {
break;
}
}
return r;
}
return r;
return m_buffer_data.size();
}

std::vector<DummyMidiPort::StoredMessage> DummyMidiPort::get_written_requested_msgs() {
Expand Down
1 change: 1 addition & 0 deletions src/libshoopdaloop/internal/DummyAudioSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class DummyMidiPort : public MidiPortInterface,
// Queued messages as external input to the port
std::vector<StoredMessage> m_queued_msgs;
std::atomic<size_t> current_buf_frames;
std::vector<StoredMessage> m_buffer_data;

// Amount of frames requested for reading externally out of the port
std::atomic<size_t> n_requested_frames;
Expand Down
7 changes: 5 additions & 2 deletions src/libshoopdaloop/libshoopdaloop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,9 @@ shoopdaloop_audio_port_t *open_audio_port (shoopdaloop_backend_instance_t *backe
auto _backend = internal_backend(backend);
auto port = _backend->audio_system->open_audio_port
(name_hint, internal_port_direction(direction));
auto pi = std::make_shared<ConnectedPort>(port, _backend);
auto pi = std::make_shared<ConnectedPort>(port, _backend,
internal_port_direction(direction) == PortDirection::Input ? shoop_types::ProcessWhen::BeforeFXChains : shoop_types::ProcessWhen::AfterFXChains
);
_backend->cmd_queue.queue([pi, _backend]() {
_backend->ports.push_back(pi);
});
Expand Down Expand Up @@ -677,7 +679,8 @@ shoopdaloop_midi_port_t *open_jack_midi_port (shoopdaloop_backend_instance_t *ba
g_logger->debug("open_jack_midi_port");
auto _backend = internal_backend(backend);
auto port = _backend->audio_system->open_midi_port(name_hint, internal_port_direction(direction));
auto pi = std::make_shared<ConnectedPort>(port, _backend);
auto pi = std::make_shared<ConnectedPort>(port, _backend,
internal_port_direction(direction) == PortDirection::Input ? shoop_types::ProcessWhen::BeforeFXChains : shoop_types::ProcessWhen::AfterFXChains);
_backend->cmd_queue.queue([pi, _backend]() {
_backend->ports.push_back(pi);
});
Expand Down
2 changes: 1 addition & 1 deletion src/shoopdaloop/lib/qml/test/ShoopTestCase.qml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ TestCase {

function verify_approx(a, b) {
var result;
let compare = (a,b) => (a - b) < Math.max(a,b) / 10000.0
let compare = (a,b) => a == b || ((a - b) < Math.max(a,b) / 10000.0)
let failstring = `verify_approx failed (a = ${a}, b = ${b})`
if (Array.isArray(a) && Array.isArray(b)) {
result = TestDeepEqual.testArraysCompare(a, b, compare);
Expand Down
76 changes: 73 additions & 3 deletions src/shoopdaloop/lib/qml/test/tst_TrackControl_drywet.qml
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,9 @@ Session {
let out2 = output_port_2.dummy_dequeue_data(4)

midi_input_port.dummy_clear_queues()

verify_eq(out1, expect_out1)
verify_eq(out2, expect_out2)
verify_approx(out1, expect_out1)
verify_approx(out2, expect_out2)
verify_throw(fx.active)
})
}
Expand Down Expand Up @@ -316,6 +316,41 @@ Session {
})
}

function test_drywet_midi_no_monitor() {
run_case('test_drywet_midi_no_monitor', () => {
check_backend()
reset()
tut_control().monitor = false
tut_control().mute = false
testcase.wait(50)

let msgs = [
{ 'time': 0, 'data': [0x90, 100, 100] },
{ 'time': 3, 'data': [0x90, 50, 50] },
{ 'time': 4, 'data': [0x90, 10, 10] }
]
let expect_out1 = [0, 0, 0, 0]
let expect_out2 = expect_out1

midi_input_port.dummy_clear_queues()
midi_input_port.dummy_queue_msgs(msgs)

output_port_1.dummy_request_data(4)
output_port_2.dummy_request_data(4)
session.backend.dummy_request_controlled_frames(4)
session.backend.dummy_wait_process()

let out1 = output_port_1.dummy_dequeue_data(4)
let out2 = output_port_2.dummy_dequeue_data(4)

midi_input_port.dummy_clear_queues()

verify_approx(out1, expect_out1)
verify_approx(out2, expect_out2)
verify_throw(!fx.active)
})
}

function test_drywet_audio_monitor_mute() {
run_case('test_drywet_audio_monitor_mute', () => {
check_backend()
Expand All @@ -340,5 +375,40 @@ Session {

})
}

function test_drywet_midi_mute() {
run_case('test_drywet_midi_mute', () => {
check_backend()
reset()
tut_control().monitor = true
tut_control().mute = true
testcase.wait(50)

let msgs = [
{ 'time': 0, 'data': [0x90, 100, 100] },
{ 'time': 3, 'data': [0x90, 50, 50] },
{ 'time': 4, 'data': [0x90, 10, 10] }
]
let expect_out1 = [0, 0, 0, 0]
let expect_out2 = expect_out1

midi_input_port.dummy_clear_queues()
midi_input_port.dummy_queue_msgs(msgs)

output_port_1.dummy_request_data(4)
output_port_2.dummy_request_data(4)
session.backend.dummy_request_controlled_frames(4)
session.backend.dummy_wait_process()

let out1 = output_port_1.dummy_dequeue_data(4)
let out2 = output_port_2.dummy_dequeue_data(4)

midi_input_port.dummy_clear_queues()

verify_approx(out1, expect_out1)
verify_approx(out2, expect_out2)
verify_throw(fx.active)
})
}
}
}

0 comments on commit 329a4ae

Please sign in to comment.