Improved OSC control with TouchOSC

Added Looming source callback, and cleanup sync of sources. New horizontal version of OSCTouch UI.
This commit is contained in:
Bruno Herbelin
2021-12-25 16:05:43 +01:00
parent 7a551189d9
commit 3d05444f30
6 changed files with 126 additions and 64 deletions

View File

@@ -68,18 +68,11 @@ void Control::RequestListener::ProcessMessage( const osc::ReceivedMessage& m,
// Log target: just print text in log window // Log target: just print text in log window
if ( target.compare(OSC_INFO) == 0 ) if ( target.compare(OSC_INFO) == 0 )
{ {
if ( attribute.compare(OSC_INFO_SYNC) == 0) { if ( attribute.compare(OSC_SYNC) == 0) {
// send the global status // send the global status
Control::manager().sendStatus(remoteEndpoint); Control::manager().sendOutputStatus(remoteEndpoint);
//
// send the status of all sources // send the status of all sources
// Control::manager().sendSourcesStatus(remoteEndpoint, m.ArgumentStream());
// (if an argument is given, it indicates the number of sources to update)
float N = 0.f;
if ( !m.ArgumentStream().Eos())
m.ArgumentStream() >> N >> osc::EndMessage;
// send the status of all sources
Control::manager().sendSourcesStatus(remoteEndpoint, N);
} }
else if ( attribute.compare(OSC_INFO_LOG) == 0) { else if ( attribute.compare(OSC_INFO_LOG) == 0) {
Log::Info(CONTROL_OSC_MSG "received '%s' from %s", FullMessage(m).c_str(), sender); Log::Info(CONTROL_OSC_MSG "received '%s' from %s", FullMessage(m).c_str(), sender);
@@ -88,7 +81,12 @@ void Control::RequestListener::ProcessMessage( const osc::ReceivedMessage& m,
// Output target: concerns attributes of the rendering output // Output target: concerns attributes of the rendering output
else if ( target.compare(OSC_OUTPUT) == 0 ) else if ( target.compare(OSC_OUTPUT) == 0 )
{ {
Control::manager().receiveOutputAttribute(attribute, m.ArgumentStream()); if ( attribute.compare(OSC_SYNC) == 0) {
// send the global status
Control::manager().sendOutputStatus(remoteEndpoint);
}
else
Control::manager().receiveOutputAttribute(attribute, m.ArgumentStream());
} }
// ALL sources target: apply attribute to all sources of the session // ALL sources target: apply attribute to all sources of the session
else if ( target.compare(OSC_ALL) == 0 ) else if ( target.compare(OSC_ALL) == 0 )
@@ -112,51 +110,36 @@ void Control::RequestListener::ProcessMessage( const osc::ReceivedMessage& m,
else if ( target.compare(OSC_CURRENT) == 0 ) else if ( target.compare(OSC_CURRENT) == 0 )
{ {
int sourceid = -1; int sourceid = -1;
if ( attribute.compare(OSC_NEXT) == 0) { if ( attribute.compare(OSC_SYNC) == 0) {
// send the status of all sources
Control::manager().sendSourcesStatus(remoteEndpoint, m.ArgumentStream());
}
else if ( attribute.compare(OSC_NEXT) == 0) {
// set current to NEXT // set current to NEXT
Mixer::manager().setCurrentNext(); Mixer::manager().setCurrentNext();
// confirm by sending back the current source attributes
Control::manager().sendCurrentSourceAttibutes(remoteEndpoint);
//
// send the status of all sources // send the status of all sources
// Control::manager().sendSourcesStatus(remoteEndpoint, m.ArgumentStream());
// (if an argument is given, it indicates the number of sources to update)
float N = 0.f;
if ( !m.ArgumentStream().Eos())
m.ArgumentStream() >> N >> osc::EndMessage;
Control::manager().sendSourcesStatus(remoteEndpoint, N);
} }
else if ( attribute.compare(OSC_PREVIOUS) == 0) { else if ( attribute.compare(OSC_PREVIOUS) == 0) {
// set current to PREVIOUS // set current to PREVIOUS
Mixer::manager().setCurrentPrevious(); Mixer::manager().setCurrentPrevious();
// confirm by sending back the current source attributes
Control::manager().sendCurrentSourceAttibutes(remoteEndpoint);
//
// send the status of all sources // send the status of all sources
// Control::manager().sendSourcesStatus(remoteEndpoint, m.ArgumentStream());
// (if an argument is given, it indicates the number of sources to update)
float N = 0.f;
if ( !m.ArgumentStream().Eos())
m.ArgumentStream() >> N >> osc::EndMessage;
Control::manager().sendSourcesStatus(remoteEndpoint, N);
} }
else if ( BaseToolkit::is_a_number( attribute.substr(1), &sourceid) ){ else if ( BaseToolkit::is_a_number( attribute.substr(1), &sourceid) ){
// set current to given INDEX // set current to given INDEX
Mixer::manager().setCurrentIndex(sourceid); Mixer::manager().setCurrentIndex(sourceid);
// confirm by sending back the current source attributes
Control::manager().sendCurrentSourceAttibutes(remoteEndpoint);
//
// send the status of all sources // send the status of all sources
// Control::manager().sendSourcesStatus(remoteEndpoint, m.ArgumentStream());
// (if an argument is given, it indicates the number of sources to update)
float N = 0.f;
if ( !m.ArgumentStream().Eos())
m.ArgumentStream() >> N >> osc::EndMessage;
Control::manager().sendSourcesStatus(remoteEndpoint, N);
} }
// all other attributes operate on current source // all other attributes operate on current source
else else {
Control::manager().receiveSourceAttribute( Mixer::manager().currentSource(), attribute, m.ArgumentStream()); // apply attributes
if ( Control::manager().receiveSourceAttribute( Mixer::manager().currentSource(), attribute, m.ArgumentStream()) )
// and send back feedback if needed
Control::manager().sendCurrentSourceAttibutes(remoteEndpoint);
}
} }
// General case: try to identify the target // General case: try to identify the target
else { else {
@@ -329,11 +312,13 @@ void Control::receiveOutputAttribute(const std::string &attribute,
} }
} }
void Control::receiveSourceAttribute(Source *target, const std::string &attribute, bool Control::receiveSourceAttribute(Source *target, const std::string &attribute,
osc::ReceivedMessageArgumentStream arguments) osc::ReceivedMessageArgumentStream arguments)
{ {
bool send_feedback = false;
if (target == nullptr) if (target == nullptr)
return; return send_feedback;
try { try {
/// e.g. '/vimix/current/play' or '/vimix/current/play T' or '/vimix/current/play F' /// e.g. '/vimix/current/play' or '/vimix/current/play T' or '/vimix/current/play F'
@@ -362,6 +347,14 @@ void Control::receiveSourceAttribute(Source *target, const std::string &attribut
arguments >> x >> osc::EndMessage; arguments >> x >> osc::EndMessage;
target->call( new SetAlpha(x), true ); target->call( new SetAlpha(x), true );
} }
/// e.g. '/vimix/current/alpha f 0.3'
else if ( attribute.compare(OSC_SOURCE_LOOM) == 0) {
float x = 1.f;
arguments >> x >> osc::EndMessage;
target->call( new Loom(x), true );
// this will require to send feedback status about source
send_feedback = true;
}
/// e.g. '/vimix/current/transparency f 0.7' /// e.g. '/vimix/current/transparency f 0.7'
else if ( attribute.compare(OSC_SOURCE_TRANSPARENCY) == 0) { else if ( attribute.compare(OSC_SOURCE_TRANSPARENCY) == 0) {
float x = 0.f; float x = 0.f;
@@ -388,8 +381,12 @@ void Control::receiveSourceAttribute(Source *target, const std::string &attribut
} }
/// e.g. '/vimix/current/turn f 1.0' /// e.g. '/vimix/current/turn f 1.0'
else if ( attribute.compare(OSC_SOURCE_TURN) == 0) { else if ( attribute.compare(OSC_SOURCE_TURN) == 0) {
float x = 0.f; float x = 0.f, y = 0.f;
arguments >> x >> osc::EndMessage; arguments >> x;
if (arguments.Eos())
arguments >> osc::EndMessage;
else // ignore second argument
arguments >> y >> osc::EndMessage;
target->call( new Turn( x ), true ); target->call( new Turn( x ), true );
} }
/// e.g. '/vimix/current/reset' /// e.g. '/vimix/current/reset'
@@ -412,6 +409,8 @@ void Control::receiveSourceAttribute(Source *target, const std::string &attribut
catch (osc::WrongArgumentTypeException &e) { catch (osc::WrongArgumentTypeException &e) {
Log::Info(CONTROL_OSC_MSG "Invalid argument for attribute '%s' for target %s.", attribute.c_str(), target->name().c_str()); Log::Info(CONTROL_OSC_MSG "Invalid argument for attribute '%s' for target %s.", attribute.c_str(), target->name().c_str());
} }
return send_feedback;
} }
@@ -458,8 +457,13 @@ void Control::sendCurrentSourceAttibutes(const IpEndpointName &remoteEndpoint)
} }
void Control::sendSourcesStatus(const IpEndpointName &remoteEndpoint, float max_count) void Control::sendSourcesStatus(const IpEndpointName &remoteEndpoint, osc::ReceivedMessageArgumentStream arguments)
{ {
// (if an argument is given, it indicates the number of sources to update)
float N = 0.f;
if ( !arguments.Eos())
arguments >> N >> osc::EndMessage;
// build socket to send message to indicated endpoint // build socket to send message to indicated endpoint
UdpTransmitSocket socket( IpEndpointName( remoteEndpoint.address, Settings::application.control.osc_port_send ) ); UdpTransmitSocket socket( IpEndpointName( remoteEndpoint.address, Settings::application.control.osc_port_send ) );
@@ -483,7 +487,7 @@ void Control::sendSourcesStatus(const IpEndpointName &remoteEndpoint, float max_
p << osc::BeginMessage( oscaddr ) << Mixer::manager().sourceAtIndex(i)->alpha() << osc::EndMessage; p << osc::BeginMessage( oscaddr ) << Mixer::manager().sourceAtIndex(i)->alpha() << osc::EndMessage;
} }
for (; i < max_count; ++i) { for (; i < (int) N ; ++i) {
// reset status of currently selected // reset status of currently selected
sprintf(oscaddr, OSC_PREFIX OSC_CURRENT "/%d", i); sprintf(oscaddr, OSC_PREFIX OSC_CURRENT "/%d", i);
p << osc::BeginMessage( oscaddr ) << 0.f << osc::EndMessage; p << osc::BeginMessage( oscaddr ) << 0.f << osc::EndMessage;
@@ -495,10 +499,13 @@ void Control::sendSourcesStatus(const IpEndpointName &remoteEndpoint, float max_
p << osc::EndBundle; p << osc::EndBundle;
socket.Send( p.Data(), p.Size() ); socket.Send( p.Data(), p.Size() );
// send status of current source
sendCurrentSourceAttibutes(remoteEndpoint);
} }
void Control::sendStatus(const IpEndpointName &remoteEndpoint) void Control::sendOutputStatus(const IpEndpointName &remoteEndpoint)
{ {
// build socket to send message to indicated endpoint // build socket to send message to indicated endpoint
UdpTransmitSocket socket( IpEndpointName( remoteEndpoint.address, Settings::application.control.osc_port_send ) ); UdpTransmitSocket socket( IpEndpointName( remoteEndpoint.address, Settings::application.control.osc_port_send ) );
@@ -510,12 +517,6 @@ void Control::sendStatus(const IpEndpointName &remoteEndpoint)
p.Clear(); p.Clear();
p << osc::BeginBundle(); p << osc::BeginBundle();
///
/// messages
///
/// Agree to test
p << osc::BeginMessage( OSC_PREFIX OSC_INFO OSC_INFO_SYNC );
p << osc::EndMessage;
/// output attributes /// output attributes
p << osc::BeginMessage( OSC_PREFIX OSC_OUTPUT OSC_OUTPUT_ENABLE ); p << osc::BeginMessage( OSC_PREFIX OSC_OUTPUT OSC_OUTPUT_ENABLE );
p << (Settings::application.render.disabled ? 0.f : 1.f); p << (Settings::application.render.disabled ? 0.f : 1.f);

View File

@@ -3,8 +3,9 @@
#include "NetworkToolkit.h" #include "NetworkToolkit.h"
#define OSC_SYNC "/sync"
#define OSC_INFO "/info" #define OSC_INFO "/info"
#define OSC_INFO_SYNC "/sync"
#define OSC_INFO_LOG "/log" #define OSC_INFO_LOG "/log"
#define OSC_OUTPUT "/output" #define OSC_OUTPUT "/output"
@@ -24,6 +25,7 @@
#define OSC_SOURCE_PAUSE "/pause" #define OSC_SOURCE_PAUSE "/pause"
#define OSC_SOURCE_REPLAY "/replay" #define OSC_SOURCE_REPLAY "/replay"
#define OSC_SOURCE_ALPHA "/alpha" #define OSC_SOURCE_ALPHA "/alpha"
#define OSC_SOURCE_LOOM "/loom"
#define OSC_SOURCE_TRANSPARENCY "/transparency" #define OSC_SOURCE_TRANSPARENCY "/transparency"
#define OSC_SOURCE_DEPTH "/depth" #define OSC_SOURCE_DEPTH "/depth"
#define OSC_SOURCE_GRAB "/grab" #define OSC_SOURCE_GRAB "/grab"
@@ -69,12 +71,12 @@ protected:
void receiveOutputAttribute(const std::string &attribute, void receiveOutputAttribute(const std::string &attribute,
osc::ReceivedMessageArgumentStream arguments); osc::ReceivedMessageArgumentStream arguments);
void receiveSourceAttribute(Source *target, const std::string &attribute, bool receiveSourceAttribute(Source *target, const std::string &attribute,
osc::ReceivedMessageArgumentStream arguments); osc::ReceivedMessageArgumentStream arguments);
void sendCurrentSourceAttibutes(const IpEndpointName& remoteEndpoint); void sendCurrentSourceAttibutes(const IpEndpointName& remoteEndpoint);
void sendSourcesStatus(const IpEndpointName& remoteEndpoint, float max_count = 0.f); void sendSourcesStatus(const IpEndpointName& remoteEndpoint, osc::ReceivedMessageArgumentStream arguments);
void sendStatus(const IpEndpointName& remoteEndpoint); void sendOutputStatus(const IpEndpointName& remoteEndpoint);
private: private:

View File

@@ -39,6 +39,7 @@ void ResetGeometry::update(Source *s, float)
SetAlpha::SetAlpha(float alpha) : SourceCallback(), alpha_(CLAMP(alpha, 0.f, 1.f)) SetAlpha::SetAlpha(float alpha) : SourceCallback(), alpha_(CLAMP(alpha, 0.f, 1.f))
{ {
pos_ = glm::vec2();
step_ = glm::normalize(glm::vec2(1.f, 1.f)); // step in diagonal by default step_ = glm::normalize(glm::vec2(1.f, 1.f)); // step in diagonal by default
} }
@@ -49,7 +50,6 @@ void SetAlpha::update(Source *s, float)
if (!initialized_){ if (!initialized_){
// initial position // initial position
pos_ = glm::vec2(s->group(View::MIXING)->translation_); pos_ = glm::vec2(s->group(View::MIXING)->translation_);
// step in direction of source translation if possible // step in direction of source translation if possible
if ( glm::length(pos_) > DELTA_ALPHA) if ( glm::length(pos_) > DELTA_ALPHA)
step_ = glm::normalize(pos_); step_ = glm::normalize(pos_);
@@ -73,6 +73,53 @@ void SetAlpha::update(Source *s, float)
finished_ = true; finished_ = true;
} }
Loom::Loom(float da, float duration) : SourceCallback(), speed_(da),
duration_(duration), progress_(0.f)
{
pos_ = glm::vec2();
step_ = glm::normalize(glm::vec2(1.f, 1.f)); // step in diagonal by default
}
void Loom::update(Source *s, float dt)
{
if (s && !s->locked()) {
// reset on first run or upon call of reset()
if (!initialized_){
// start animation
progress_ = 0.f;
// initial position
pos_ = glm::vec2(s->group(View::MIXING)->translation_);
// step in direction of source translation if possible
if ( glm::length(pos_) > DELTA_ALPHA)
step_ = glm::normalize(pos_);
initialized_ = true;
}
// calculate amplitude of movement
progress_ += dt;
// perform movement
pos_ += step_ * ( speed_ * dt * 0.001f);
// apply alpha if valid in range [0 1]
float alpha = SourceCore::alphaFromCordinates(pos_.x, pos_.y);
if ( alpha > DELTA_ALPHA && alpha < 1.0 - DELTA_ALPHA )
s->group(View::MIXING)->translation_ = glm::vec3(pos_, s->group(View::MIXING)->translation_.z);
// timeout
if ( progress_ > duration_ ) {
// done
finished_ = true;
}
}
else
finished_ = true;
}
SetDepth::SetDepth(float target, float duration) : SourceCallback(), SetDepth::SetDepth(float target, float duration) : SourceCallback(),
duration_(duration), progress_(0.f), start_(0.f), target_(CLAMP(target, MIN_DEPTH, MAX_DEPTH)) duration_(duration), progress_(0.f), start_(0.f), target_(CLAMP(target, MIN_DEPTH, MAX_DEPTH))
{ {
@@ -194,8 +241,8 @@ void Resize::update(Source *s, float dt)
progress_ += dt; progress_ += dt;
// perform movement // perform movement
glm::vec2 pos = start_ + speed_ * ( dt * 0.001f); glm::vec2 scale = start_ + speed_ * ( dt * 0.001f);
s->group(View::GEOMETRY)->scale_ = glm::vec3(pos, s->group(View::GEOMETRY)->scale_.z); s->group(View::GEOMETRY)->scale_ = glm::vec3(scale, s->group(View::GEOMETRY)->scale_.z);
// timeout // timeout
if ( progress_ > duration_ ) { if ( progress_ > duration_ ) {

View File

@@ -12,6 +12,7 @@ public:
typedef enum { typedef enum {
CALLBACK_GENERIC = 0, CALLBACK_GENERIC = 0,
CALLBACK_ALPHA, CALLBACK_ALPHA,
CALLBACK_LOOM,
CALLBACK_DEPTH, CALLBACK_DEPTH,
CALLBACK_PLAY, CALLBACK_PLAY,
CALLBACK_REPLAY, CALLBACK_REPLAY,
@@ -56,6 +57,20 @@ public:
CallbackType type () override { return CALLBACK_ALPHA; } CallbackType type () override { return CALLBACK_ALPHA; }
}; };
class Loom : public SourceCallback
{
float speed_;
glm::vec2 pos_;
glm::vec2 step_;
float duration_;
float progress_;
public:
Loom(float da, float duration = 0.f);
void update(Source *s, float) override;
CallbackType type () override { return CALLBACK_LOOM; }
};
class SetDepth : public SourceCallback class SetDepth : public SourceCallback
{ {
float duration_; float duration_;
@@ -92,7 +107,6 @@ class Grab : public SourceCallback
{ {
glm::vec2 speed_; glm::vec2 speed_;
glm::vec2 start_; glm::vec2 start_;
glm::vec2 target_;
float duration_; float duration_;
float progress_; float progress_;
@@ -106,7 +120,6 @@ class Resize : public SourceCallback
{ {
glm::vec2 speed_; glm::vec2 speed_;
glm::vec2 start_; glm::vec2 start_;
glm::vec2 target_;
float duration_; float duration_;
float progress_; float progress_;
@@ -120,7 +133,6 @@ class Turn : public SourceCallback
{ {
float speed_; float speed_;
float start_; float start_;
float target_;
float duration_; float duration_;
float progress_; float progress_;

Binary file not shown.

Binary file not shown.