Skip to content
Permalink
main
Go to file
 
 
Cannot retrieve contributors at this time
881 lines (716 sloc) 30.5 KB
//
// Created by ezra on 11/4/18.
//
#include <utility>
#include <thread>
#include "effects/CompressorParams.h"
#include "effects/ReverbParams.h"
#include "BufDiskWorker.h"
#include "Commands.h"
#include "OscInterface.h"
using namespace crone;
bool OscInterface::quitFlag;
std::string OscInterface::port;
lo_server_thread OscInterface::st;
lo_address OscInterface::matronAddress;
std::array<OscInterface::OscMethod, OscInterface::MaxNumMethods> OscInterface::methods;
unsigned int OscInterface::numMethods = 0;
std::unique_ptr<Poll> OscInterface::vuPoll;
std::unique_ptr<Poll> OscInterface::phasePoll;
MixerClient *OscInterface::mixerClient;
SoftcutClient *OscInterface::softCutClient;
OscInterface::OscMethod::OscMethod(string p, string f, OscInterface::Handler h)
: path(std::move(p)), format(std::move(f)), handler(h) {}
void OscInterface::init(MixerClient *m, SoftcutClient *sc) {
quitFlag = false;
// FIXME: should get port configs from program args or elsewhere
port = "9999";
matronAddress = lo_address_new("127.0.0.1", "8888");
st = lo_server_thread_new(port.c_str(), handleLoError);
addServerMethods();
mixerClient = m;
softCutClient = sc;
// FIXME: polls should really live somewhere else (client classes?)
//--- VU poll
vuPoll = std::make_unique<Poll>("vu");
vuPoll->setCallback([](const char *path) {
char l[4];
l[0] = (uint8_t) (64 * mixerClient->getInputPeakPos(0));
l[1] = (uint8_t) (64 * mixerClient->getInputPeakPos(1));
l[2] = (uint8_t) (64 * mixerClient->getOutputPeakPos(0));
l[3] = (uint8_t) (64 * mixerClient->getOutputPeakPos(1));
lo_blob bl = lo_blob_new(sizeof(l), l);
lo_send(matronAddress, path, "b", bl);
});
vuPoll->setPeriod(50);
//--- softcut phase poll
phasePoll = std::make_unique<Poll>("softcut/phase");
phasePoll->setCallback([](const char *path) {
for (int i = 0; i < softCutClient->getNumVoices(); ++i) {
if (softCutClient->checkVoiceQuantPhase(i)) {
lo_send(matronAddress, path, "if", i, softCutClient->getQuantPhase(i));
}
}
});
phasePoll->setPeriod(1);
//--- TODO: softcut trigger poll?
//--- TODO: tape poll?
lo_server_thread_start(st);
}
void OscInterface::addServerMethod(const char *path, const char *format, Handler handler) {
OscMethod m(path, format, handler);
methods[numMethods] = m;
lo_server_thread_add_method(st, path, format,
[](const char *path,
const char *types,
lo_arg **argv,
int argc,
lo_message msg,
void *data)
-> int {
(void) path;
(void) types;
(void) msg;
auto pm = static_cast<OscMethod *>(data);
//std::cerr << "osc rx: " << path << std::endl;
pm->handler(argv, argc);
return 0;
}, &(methods[numMethods]));
numMethods++;
}
void OscInterface::addServerMethods() {
addServerMethod("/hello", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
std::cout << "hello" << std::endl;
});
addServerMethod("/goodbye", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
std::cout << "goodbye" << std::endl;
OscInterface::quitFlag = true;
});
addServerMethod("/quit", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
OscInterface::quitFlag = true;
});
//---------------------------
//--- mixer polls
addServerMethod("/poll/start/vu", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
vuPoll->start();
});
addServerMethod("/poll/stop/vu", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
vuPoll->stop();
});
////////////////////////////////
/// FIXME: many of these methods are trivial setters;
// they could simply be structured around atomic fields instead of requiring the Command queue.
// would require some refactoring e.g. to expose level ramp targets as atomics
//--------------------------
//--- levels
addServerMethod("/set/level/adc", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_ADC, argv[0]->f);
});
addServerMethod("/set/level/dac", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_DAC, argv[0]->f);
});
addServerMethod("/set/level/ext", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_EXT, argv[0]->f);
});
addServerMethod("/set/level/cut_master", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_CUT_MASTER, argv[0]->f);
});
addServerMethod("/set/level/ext_rev", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_EXT_AUX, argv[0]->f);
});
addServerMethod("/set/level/rev_dac", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_AUX_DAC, argv[0]->f);
});
addServerMethod("/set/level/monitor", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_MONITOR, argv[0]->f);
});
addServerMethod("/set/level/monitor_mix", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_MONITOR_MIX, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/level/monitor_rev", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_MONITOR_AUX, argv[0]->f);
});
addServerMethod("/set/level/compressor_mix", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_INS_MIX, argv[0]->f);
});
// toggle enabled
addServerMethod("/set/enabled/compressor", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_ENABLED_COMPRESSOR, argv[0]->f);
});
addServerMethod("/set/enabled/reverb", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_ENABLED_REVERB, argv[0]->f);
});
//-------------------------
//-- compressor params
addServerMethod("/set/param/compressor/ratio", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_COMPRESSOR, CompressorParam::RATIO, argv[0]->f);
});
addServerMethod("/set/param/compressor/threshold", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_COMPRESSOR, CompressorParam::THRESHOLD, argv[0]->f);
});
addServerMethod("/set/param/compressor/attack", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_COMPRESSOR, CompressorParam::ATTACK, argv[0]->f);
});
addServerMethod("/set/param/compressor/release", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_COMPRESSOR, CompressorParam::RELEASE, argv[0]->f);
});
addServerMethod("/set/param/compressor/gain_pre", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_COMPRESSOR, CompressorParam::GAIN_PRE, argv[0]->f);
});
addServerMethod("/set/param/compressor/gain_post", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_COMPRESSOR, CompressorParam::GAIN_POST, argv[0]->f);
});
//--------------------------
//-- reverb params
addServerMethod("/set/param/reverb/pre_del", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_REVERB, ReverbParam::PRE_DEL, argv[0]->f);
});
addServerMethod("/set/param/reverb/lf_fc", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_REVERB, ReverbParam::LF_FC, argv[0]->f);
});
addServerMethod("/set/param/reverb/low_rt60", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_REVERB, ReverbParam::LOW_RT60, argv[0]->f);
});
addServerMethod("/set/param/reverb/mid_rt60", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_REVERB, ReverbParam::MID_RT60, argv[0]->f);
});
addServerMethod("/set/param/reverb/hf_damp", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_PARAM_REVERB, ReverbParam::HF_DAMP, argv[0]->f);
});
//--------------------------------
//-- softcut routing
addServerMethod("/set/enabled/cut", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_ENABLED_CUT, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/level/cut", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_LEVEL_CUT, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/pan/cut", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_PAN_CUT, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/level/adc_cut", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_ADC_CUT, argv[0]->f);
});
addServerMethod("/set/level/ext_cut", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_EXT_CUT, argv[0]->f);
});
addServerMethod("/set/level/tape_cut", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_TAPE_CUT, argv[0]->f);
});
addServerMethod("/set/level/cut_rev", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_CUT_AUX, argv[0]->f);
});
//--- NB: these are handled by the softcut command queue,
// because their corresponding mix points are processed by the softcut client.
// input channel -> voice levels
addServerMethod("/set/level/in_cut", "iif", [](lo_arg **argv, int argc) {
if (argc < 3) { return; }
Commands::softcutCommands.post(Commands::Id::SET_LEVEL_IN_CUT, argv[0]->i, argv[1]->i, argv[2]->f);
});
// voice -> voice levels
addServerMethod("/set/level/cut_cut", "iif", [](lo_arg **argv, int argc) {
if (argc < 3) { return; }
Commands::softcutCommands.post(Commands::Id::SET_LEVEL_CUT_CUT, argv[0]->i, argv[1]->i, argv[2]->f);
});
//--------------------------------
//-- softcut params
addServerMethod("/set/param/cut/rate", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_RATE, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/loop_start", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_LOOP_START, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/loop_end", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_LOOP_END, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/loop_flag", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_LOOP_FLAG, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/fade_time", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_FADE_TIME, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/rec_level", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_REC_LEVEL, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/pre_level", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PRE_LEVEL, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/rec_flag", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_REC_FLAG, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/play_flag", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PLAY_FLAG, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/rec_offset", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_REC_OFFSET, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/position", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_POSITION, argv[0]->i, argv[1]->f);
});
// --- input filter
addServerMethod("/set/param/cut/pre_filter_fc", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PRE_FILTER_FC, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/pre_filter_fc_mod", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PRE_FILTER_FC_MOD, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/pre_filter_rq", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PRE_FILTER_RQ, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/pre_filter_lp", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PRE_FILTER_LP, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/pre_filter_hp", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PRE_FILTER_HP, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/pre_filter_bp", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PRE_FILTER_BP, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/pre_filter_br", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PRE_FILTER_BR, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/pre_filter_dry", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PRE_FILTER_DRY, argv[0]->i, argv[1]->f);
});
// --- output filter
addServerMethod("/set/param/cut/post_filter_fc", "if", [
](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_POST_FILTER_FC, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/post_filter_rq", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_POST_FILTER_RQ, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/post_filter_lp", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_POST_FILTER_LP, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/post_filter_hp", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_POST_FILTER_HP, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/post_filter_bp", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_POST_FILTER_BP, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/post_filter_br", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_POST_FILTER_BR, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/post_filter_dry", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_POST_FILTER_DRY, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/voice_sync", "iif", [](lo_arg **argv, int argc) {
if (argc < 3) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_VOICE_SYNC, argv[0]->i, argv[1]->i, argv[2]->f);
});
///////////////////////////////////////////
/// FIXME: fade curve calculations are now per-voice,
/// so these methods won't work at all without modification.
//// in any case, they should use worker threads and this is the wrong place to manage that.
#if 0
addServerMethod("/set/param/cut/pre_fade_window", "if", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
float x = argv[0]->f;
auto t = std::thread([x] {
FadeCurves::setPreWindowRatio(x);
});
t.detach();
});
addServerMethod("/set/param/cut/rec_fade_delay", "if", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
float x = argv[0]->f;
auto t = std::thread([x] {
FadeCurves::setRecDelayRatio(x);
});
t.detach();
});
addServerMethod("/set/param/cut/pre_fade_shape", "if", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
float x = argv[0]->f;
auto t = std::thread([x] {
FadeCurves::setPreShape(static_cast<FadeCurves::Shape>(x));
});
t.detach();
});
addServerMethod("/set/param/cut/rec_fade_shape", "if", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
float x = argv[0]->f;
auto t = std::thread([x] {
FadeCurves::setRecShape(static_cast<FadeCurves::Shape>(x));
});
t.detach();
});
#endif
//////////////////
addServerMethod("/set/param/cut/level_slew_time", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_LEVEL_SLEW_TIME, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/pan_slew_time", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_PAN_SLEW_TIME, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/recpre_slew_time", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_RECPRE_SLEW_TIME, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/rate_slew_time", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_RATE_SLEW_TIME, argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/buffer", "ii", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
Commands::softcutCommands.post(Commands::Id::SET_CUT_BUFFER, argv[0]->i, argv[1]->i);
});
//-------------------------------
//--- softcut buffer manipulation
// FIXME: hrm, our system doesn't allow variable argument count. maybe need to make multiple methods
addServerMethod("/softcut/buffer/read_mono", "sfffii", [](lo_arg **argv, int argc) {
float startSrc = 0.f;
float startDst = 0.f;
float dur = -1.f;
int chanSrc = 0;
int chanDst = 0;
if (argc < 1) {
std::cerr << "/softcut/buffer/read_mono requires at least one argument (file path)" << std::endl;
return;
}
if (argc > 1) {
startSrc = argv[1]->f;
}
if (argc > 2) {
startDst = argv[2]->f;
}
if (argc > 3) {
dur = argv[3]->f;
}
if (argc > 4) {
chanSrc = argv[4]->i;
}
if (argc > 5) {
chanDst = argv[5]->i;
}
const char *str = &argv[0]->s;
softCutClient->readBufferMono(str, startSrc, startDst, dur, chanSrc, chanDst);
});
// FIXME: hrm, our system doesn't allow variable argument count. maybe need to make multiple methods
addServerMethod("/softcut/buffer/read_stereo", "sfff", [](lo_arg **argv, int argc) {
float startSrc = 0.f;
float startDst = 0.f;
float dur = -1.f;
if (argc < 1) {
std::cerr << "/softcut/buffer/read_stereo requires at least one argument (file path)" << std::endl;
return;
}
if (argc > 1) {
startSrc = argv[1]->f;
}
if (argc > 2) {
startDst = argv[2]->f;
}
if (argc > 3) {
dur = argv[3]->f;
}
const char *str = &argv[0]->s;
softCutClient->readBufferStereo(str, startSrc, startDst, dur);
});
// FIXME: hrm, our system doesn't allow variable argument count. maybe need to make multiple methods
addServerMethod("/softcut/buffer/write_mono", "sffi", [](lo_arg **argv, int argc) {
float start = 0.f;
float dur = -1.f;
int chan = 0;
if (argc < 1) {
std::cerr << "/softcut/buffer/write_mono requires at least one argument (file path)" << std::endl;
return;
}
if (argc > 1) {
start = argv[1]->f;
}
if (argc > 2) {
dur = argv[2]->f;
}
if (argc > 3) {
chan = argv[3]->i;
}
const char *str = &argv[0]->s;
softCutClient->writeBufferMono(str, start, dur, chan);
});
// FIXME: hrm, our system doesn't allow variable argument count. maybe need to make multiple methods
addServerMethod("/softcut/buffer/write_stereo", "sff", [](lo_arg **argv, int argc) {
float start = 0.f;
float dur = -1.f;
if (argc < 1) {
std::cerr << "/softcut/buffer/write_stereo requires at least one argument (file path)" << std::endl;
return;
}
if (argc > 1) {
start = argv[1]->f;
}
if (argc > 2) {
dur = argv[2]->f;
}
const char *str = &argv[0]->s;
softCutClient->writeBufferStereo(str, start, dur);
});
addServerMethod("/softcut/buffer/clear", "", [](lo_arg **argv, int argc) {
(void) argc;
(void) argv;
softCutClient->clearBuffer(0);
softCutClient->clearBuffer(1);
});
addServerMethod("/softcut/buffer/clear_channel", "i", [](lo_arg **argv, int argc) {
if (argc < 1) {
return;
}
softCutClient->clearBuffer(argv[0]->i);
});
addServerMethod("/softcut/buffer/clear_region", "ff", [](lo_arg **argv, int argc) {
if (argc < 2) {
return;
}
softCutClient->clearBuffer(0, argv[0]->f, argv[1]->f);
softCutClient->clearBuffer(1, argv[0]->f, argv[1]->f);
});
addServerMethod("/softcut/buffer/clear_region_channel", "iff", [](lo_arg **argv, int argc) {
if (argc < 3) {
return;
}
softCutClient->clearBuffer(argv[0]->i, argv[1]->f, argv[2]->f);
});
addServerMethod("/softcut/buffer/clear_fade_region", "ffff", [](lo_arg **argv, int argc) {
float dur = -1;
float fadeTime = 0;
float preserve = 0;
if (argc < 1) {
return;
}
if (argc > 1) {
dur = argv[1]->f;
}
if (argc > 2) {
fadeTime = argv[2]->f;
}
if (argc > 3) {
preserve = argv[3]->f;
}
softCutClient->clearBufferWithFade(0, argv[0]->f, dur, fadeTime, preserve);
softCutClient->clearBufferWithFade(1, argv[0]->f, dur, fadeTime, preserve);
});
addServerMethod("/softcut/buffer/clear_fade_region_channel", "iffff", [](lo_arg **argv, int argc) {
float dur = -1;
float fadeTime = 0;
float preserve = 0;
if (argc < 2) {
return;
}
if (argc > 3) {
dur = argv[2]->f;
}
if (argc > 4) {
fadeTime = argv[3]->f;
}
if (argc > 5) {
preserve = argv[4]->f;
}
softCutClient->clearBufferWithFade(argv[0]->i, argv[1]->f, dur, fadeTime, preserve);
});
addServerMethod("/softcut/buffer/copy_mono", "iifffffi", [](lo_arg **argv, int argc) {
float dur = -1.f;
float fadeTime = 0.f;
float preserve = 0.f;
bool reverse = false;
if (argc < 4) {
return;
}
if (argc > 4) {
dur = argv[4]->f;
}
if (argc > 5) {
fadeTime = argv[5]->f;
}
if (argc > 6) {
preserve = argv[6]->f;
}
if (argc > 7) {
reverse = argv[7]->i != 0;
}
softCutClient->copyBuffer(argv[0]->i, argv[1]->i, argv[2]->f, argv[3]->f, dur, fadeTime, preserve, reverse);
});
addServerMethod("/softcut/buffer/copy_stereo", "fffffi", [](lo_arg **argv, int argc) {
float dur = -1.f;
float fadeTime = 0.f;
float preserve = 0.f;
bool reverse = false;
if (argc < 2) {
return;
}
if (argc > 2) {
dur = argv[2]->f;
}
if (argc > 3) {
fadeTime = argv[3]->f;
}
if (argc > 4) {
preserve = argv[4]->f;
}
if (argc > 5) {
reverse = argv[5]->i != 0;
}
softCutClient->copyBuffer(0, 0, argv[0]->f, argv[1]->f, dur, fadeTime, preserve, reverse);
softCutClient->copyBuffer(1, 1, argv[0]->f, argv[1]->f, dur, fadeTime, preserve, reverse);
});
addServerMethod("/softcut/buffer/render", "iffi", [](lo_arg **argv, int argc) {
int sampleCt = 128;
if (argc < 3) {
return;
}
int ch = argv[0]->i;
if (argc > 3) {
sampleCt = argv[3]->i;
}
softCutClient->renderSamples(ch, argv[1]->f, argv[2]->f, sampleCt,
[=](float secPerSample, float start, size_t count, float* samples) {
lo_blob bl = lo_blob_new(count * sizeof(float), samples);
lo_send(matronAddress, "/softcut/buffer/render_callback", "iffb", ch, secPerSample, start, bl);
});
});
addServerMethod("/softcut/reset", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
softCutClient->clearBuffer(0, 0, -1);
softCutClient->clearBuffer(1, 0, -1);
softCutClient->reset();
for (int i = 0; i < SoftcutClient::NumVoices; ++i) {
phasePoll->stop();
}
});
//---------------------
//--- softcut polls
addServerMethod("/set/param/cut/phase_quant", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
softCutClient->setPhaseQuant(argv[0]->i, argv[1]->f);
});
addServerMethod("/set/param/cut/phase_offset", "if", [](lo_arg **argv, int argc) {
if (argc < 2) { return; }
softCutClient->setPhaseOffset(argv[0]->i, argv[1]->f);
});
addServerMethod("/poll/start/cut/phase", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
phasePoll->start();
});
addServerMethod("/poll/stop/cut/phase", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
phasePoll->stop();
});
//------------------------
//--- tape control
addServerMethod("/tape/record/open", "s", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
mixerClient->openTapeRecord(&argv[0]->s);
});
addServerMethod("/tape/record/start", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
mixerClient->startTapeRecord();
});
addServerMethod("/tape/record/stop", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
mixerClient->stopTapeRecord();
});
addServerMethod("/tape/play/open", "s", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
mixerClient->openTapePlayback(&argv[0]->s);
});
addServerMethod("/tape/play/start", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
mixerClient->startTapePlayback();
});
addServerMethod("/tape/play/stop", "", [](lo_arg **argv, int argc) {
(void) argv;
(void) argc;
mixerClient->stopTapePlayback();
});
addServerMethod("/set/level/tape", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_TAPE, argv[0]->f);
});
addServerMethod("/set/level/tape_rev", "f", [](lo_arg **argv, int argc) {
if (argc < 1) { return; }
Commands::mixerCommands.post(Commands::Id::SET_LEVEL_TAPE_AUX, argv[0]->f);
});
}
void OscInterface::printServerMethods() {
std::cout << "osc methods: " << std::endl;
for (unsigned int i = 0; i < numMethods; ++i) {
std::cout << methods[i].path << " [" << methods[i].format << "]" << std::endl;
}
}
void OscInterface::deinit() {
lo_address_free(matronAddress);
}