mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
Metronome and Stopwatch User Interface
New Timer window in UI for Metronome (Ableton Link management) and replaces Timers. Former Timers in Metrics are replaced with Runtime (of session, of program and of total vimix runtime in settings). Temporarily disconnected Metronome from MediaPlayer actions.
This commit is contained in:
108
MediaPlayer.cpp
108
MediaPlayer.cpp
@@ -28,6 +28,7 @@
|
|||||||
#include "BaseToolkit.h"
|
#include "BaseToolkit.h"
|
||||||
#include "GstToolkit.h"
|
#include "GstToolkit.h"
|
||||||
#include "RenderingManager.h"
|
#include "RenderingManager.h"
|
||||||
|
#include "Metronome.h"
|
||||||
|
|
||||||
#include "MediaPlayer.h"
|
#include "MediaPlayer.h"
|
||||||
|
|
||||||
@@ -49,6 +50,9 @@ MediaPlayer::MediaPlayer()
|
|||||||
desired_state_ = GST_STATE_PAUSED;
|
desired_state_ = GST_STATE_PAUSED;
|
||||||
|
|
||||||
failed_ = false;
|
failed_ = false;
|
||||||
|
pending_ = false;
|
||||||
|
metro_linked_ = false;
|
||||||
|
force_update_ = false;
|
||||||
seeking_ = false;
|
seeking_ = false;
|
||||||
rewind_on_disable_ = false;
|
rewind_on_disable_ = false;
|
||||||
force_software_decoding_ = false;
|
force_software_decoding_ = false;
|
||||||
@@ -597,12 +601,8 @@ void MediaPlayer::setSoftwareDecodingForced(bool on)
|
|||||||
reopen();
|
reopen();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPlayer::play(bool on)
|
void MediaPlayer::execute_play_command(bool on)
|
||||||
{
|
{
|
||||||
// ignore if disabled, and cannot play an image
|
|
||||||
if (!enabled_ || media_.isimage)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// request state
|
// request state
|
||||||
GstState requested_state = on ? GST_STATE_PLAYING : GST_STATE_PAUSED;
|
GstState requested_state = on ? GST_STATE_PLAYING : GST_STATE_PAUSED;
|
||||||
|
|
||||||
@@ -619,9 +619,10 @@ void MediaPlayer::play(bool on)
|
|||||||
|
|
||||||
// requesting to play, but stopped at end of stream : rewind first !
|
// requesting to play, but stopped at end of stream : rewind first !
|
||||||
if ( desired_state_ == GST_STATE_PLAYING) {
|
if ( desired_state_ == GST_STATE_PLAYING) {
|
||||||
if ( ( rate_ < 0.0 && position_ <= timeline_.next(0) )
|
if (rate_ > 0.0 && position_ >= timeline_.previous(timeline_.last()))
|
||||||
|| ( rate_ > 0.0 && position_ >= timeline_.previous(timeline_.last()) ) )
|
execute_seek_command(timeline_.next(0));
|
||||||
rewind();
|
else if ( rate_ < 0.0 && position_ <= timeline_.next(0) )
|
||||||
|
execute_seek_command(timeline_.previous(timeline_.last()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// all ready, apply state change immediately
|
// all ready, apply state change immediately
|
||||||
@@ -636,7 +637,25 @@ void MediaPlayer::play(bool on)
|
|||||||
else
|
else
|
||||||
Log::Info("MediaPlayer %s Stop [%ld]", std::to_string(id_).c_str(), position());
|
Log::Info("MediaPlayer %s Stop [%ld]", std::to_string(id_).c_str(), position());
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaPlayer::play(bool on)
|
||||||
|
{
|
||||||
|
// ignore if disabled, and cannot play an image
|
||||||
|
if (!enabled_ || media_.isimage || pending_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Metronome
|
||||||
|
if (metro_linked_) {
|
||||||
|
// busy with this play()
|
||||||
|
pending_ = true;
|
||||||
|
// Execute: sync to Metronome if active
|
||||||
|
Metronome::manager().executeAtBeat( std::bind([](MediaPlayer *p, bool o) {
|
||||||
|
p->execute_play_command(o); p->pending_=false; }, this, on) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// execute immediately
|
||||||
|
execute_play_command( on );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaPlayer::isPlaying(bool testpipeline) const
|
bool MediaPlayer::isPlaying(bool testpipeline) const
|
||||||
@@ -666,44 +685,60 @@ void MediaPlayer::setLoop(MediaPlayer::LoopMode mode)
|
|||||||
loop_ = mode;
|
loop_ = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//void
|
||||||
|
|
||||||
void MediaPlayer::rewind(bool force)
|
void MediaPlayer::rewind(bool force)
|
||||||
{
|
{
|
||||||
if (!enabled_ || !media_.seekable)
|
if (!enabled_ || !media_.seekable || pending_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// playing forward, loop to begin
|
// playing forward, loop to begin;
|
||||||
if (rate_ > 0.0) {
|
// begin is the end of a gab which includes the first PTS (if exists)
|
||||||
// begin is the end of a gab which includes the first PTS (if exists)
|
// normal case, begin is zero
|
||||||
// normal case, begin is zero
|
|
||||||
execute_seek_command( timeline_.next(0) );
|
|
||||||
}
|
|
||||||
// playing backward, loop to endTimeInterval gap;
|
// playing backward, loop to endTimeInterval gap;
|
||||||
else {
|
// end is the start of a gab which includes the last PTS (if exists)
|
||||||
// end is the start of a gab which includes the last PTS (if exists)
|
// normal case, end is last frame
|
||||||
// normal case, end is last frame
|
GstClockTime target = (rate_ > 0.0) ? timeline_.next(0) : timeline_.previous(timeline_.last());
|
||||||
execute_seek_command( timeline_.previous(timeline_.last()) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (force) {
|
// Metronome
|
||||||
GstState state;
|
if (metro_linked_) {
|
||||||
gst_element_get_state (pipeline_, &state, NULL, GST_CLOCK_TIME_NONE);
|
// busy with this play()
|
||||||
update();
|
pending_ = true;
|
||||||
|
// Execute: sync to Metronome if active
|
||||||
|
Metronome::manager().executeAtBeat( std::bind([](MediaPlayer *p, GstClockTime t, bool f) {
|
||||||
|
p->execute_seek_command( t, f ); p->pending_=false; }, this, target, force) );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
// execute immediately
|
||||||
|
execute_seek_command( target, force );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MediaPlayer::step()
|
void MediaPlayer::step()
|
||||||
{
|
{
|
||||||
// useful only when Paused
|
// useful only when Paused
|
||||||
if (!enabled_ || isPlaying())
|
if (!enabled_ || isPlaying() || pending_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( ( rate_ < 0.0 && position_ <= timeline_.next(0) )
|
if ( ( rate_ < 0.0 && position_ <= timeline_.next(0) )
|
||||||
|| ( rate_ > 0.0 && position_ >= timeline_.previous(timeline_.last()) ) )
|
|| ( rate_ > 0.0 && position_ >= timeline_.previous(timeline_.last()) ) )
|
||||||
rewind();
|
rewind();
|
||||||
|
else {
|
||||||
|
// step event
|
||||||
|
GstEvent *stepevent = gst_event_new_step (GST_FORMAT_BUFFERS, 1, ABS(rate_), TRUE, FALSE);
|
||||||
|
|
||||||
// step
|
// Metronome
|
||||||
gst_element_send_event (pipeline_, gst_event_new_step (GST_FORMAT_BUFFERS, 1, ABS(rate_), TRUE, FALSE));
|
if (metro_linked_) {
|
||||||
|
// busy with this play()
|
||||||
|
pending_ = true;
|
||||||
|
// Execute: sync to Metronome if active
|
||||||
|
Metronome::manager().executeAtBeat( std::bind([](MediaPlayer *p, GstEvent *e) {
|
||||||
|
gst_element_send_event(p->pipeline_, e); p->pending_=false; }, this, stepevent) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// execute immediately
|
||||||
|
gst_element_send_event (pipeline_, stepevent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaPlayer::go_to(GstClockTime pos)
|
bool MediaPlayer::go_to(GstClockTime pos)
|
||||||
@@ -893,7 +928,7 @@ void MediaPlayer::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prevent unnecessary updates: disabled or already filled image
|
// prevent unnecessary updates: disabled or already filled image
|
||||||
if (!enabled_ || (media_.isimage && textureindex_>0 ) )
|
if ( (!enabled_ && !force_update_) || (media_.isimage && textureindex_>0 ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// local variables before trying to update
|
// local variables before trying to update
|
||||||
@@ -904,13 +939,6 @@ void MediaPlayer::update()
|
|||||||
index_lock_.lock();
|
index_lock_.lock();
|
||||||
// get the last frame filled from fill_frame()
|
// get the last frame filled from fill_frame()
|
||||||
read_index = last_index_;
|
read_index = last_index_;
|
||||||
// // Do NOT miss and jump directly (after seek) to a pre-roll
|
|
||||||
// for (guint i = 0; i < N_VFRAME; ++i) {
|
|
||||||
// if (frame_[i].status == PREROLL) {
|
|
||||||
// read_index = i;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// unlock access to index change
|
// unlock access to index change
|
||||||
index_lock_.unlock();
|
index_lock_.unlock();
|
||||||
|
|
||||||
@@ -988,6 +1016,7 @@ void MediaPlayer::update()
|
|||||||
execute_loop_command();
|
execute_loop_command();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
force_update_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPlayer::execute_loop_command()
|
void MediaPlayer::execute_loop_command()
|
||||||
@@ -1004,7 +1033,7 @@ void MediaPlayer::execute_loop_command()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPlayer::execute_seek_command(GstClockTime target)
|
void MediaPlayer::execute_seek_command(GstClockTime target, bool force)
|
||||||
{
|
{
|
||||||
if ( pipeline_ == nullptr || !media_.seekable )
|
if ( pipeline_ == nullptr || !media_.seekable )
|
||||||
return;
|
return;
|
||||||
@@ -1052,6 +1081,13 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Force update
|
||||||
|
if (force) {
|
||||||
|
GstState state;
|
||||||
|
gst_element_get_state (pipeline_, &state, NULL, GST_CLOCK_TIME_NONE);
|
||||||
|
force_update_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPlayer::setPlaySpeed(double s)
|
void MediaPlayer::setPlaySpeed(double s)
|
||||||
|
|||||||
@@ -188,6 +188,10 @@ public:
|
|||||||
* Seek to zero
|
* Seek to zero
|
||||||
* */
|
* */
|
||||||
void rewind(bool force = false);
|
void rewind(bool force = false);
|
||||||
|
/**
|
||||||
|
* pending
|
||||||
|
* */
|
||||||
|
bool pending() const { return pending_; }
|
||||||
/**
|
/**
|
||||||
* Get position time
|
* Get position time
|
||||||
* */
|
* */
|
||||||
@@ -296,11 +300,14 @@ private:
|
|||||||
GstVideoInfo v_frame_video_info_;
|
GstVideoInfo v_frame_video_info_;
|
||||||
std::atomic<bool> opened_;
|
std::atomic<bool> opened_;
|
||||||
std::atomic<bool> failed_;
|
std::atomic<bool> failed_;
|
||||||
|
bool force_update_;
|
||||||
|
bool pending_;
|
||||||
bool seeking_;
|
bool seeking_;
|
||||||
bool enabled_;
|
bool enabled_;
|
||||||
bool rewind_on_disable_;
|
bool rewind_on_disable_;
|
||||||
bool force_software_decoding_;
|
bool force_software_decoding_;
|
||||||
std::string decoder_name_;
|
std::string decoder_name_;
|
||||||
|
bool metro_linked_;
|
||||||
|
|
||||||
// fps counter
|
// fps counter
|
||||||
struct TimeCounter {
|
struct TimeCounter {
|
||||||
@@ -348,8 +355,9 @@ private:
|
|||||||
|
|
||||||
// gst pipeline control
|
// gst pipeline control
|
||||||
void execute_open();
|
void execute_open();
|
||||||
|
void execute_play_command(bool on);
|
||||||
void execute_loop_command();
|
void execute_loop_command();
|
||||||
void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE);
|
void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE, bool force = false);
|
||||||
|
|
||||||
// gst frame filling
|
// gst frame filling
|
||||||
void init_texture(guint index);
|
void init_texture(guint index);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "Metronome.h"
|
#include "Metronome.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
|
||||||
namespace ableton
|
namespace ableton
|
||||||
@@ -129,15 +130,11 @@ Metronome::Metronome()
|
|||||||
|
|
||||||
bool Metronome::init()
|
bool Metronome::init()
|
||||||
{
|
{
|
||||||
// connect
|
|
||||||
link_.enable(true);
|
|
||||||
|
|
||||||
// enable sync
|
|
||||||
link_.enableStartStopSync(true);
|
|
||||||
|
|
||||||
// set parameters
|
// set parameters
|
||||||
setTempo(Settings::application.metronome.tempo);
|
setEnabled(Settings::application.timer.link_enabled);
|
||||||
setQuantum(Settings::application.metronome.quantum);
|
setTempo(Settings::application.timer.link_tempo);
|
||||||
|
setQuantum(Settings::application.timer.link_quantum);
|
||||||
|
setStartStopSync(Settings::application.timer.link_start_stop_sync);
|
||||||
|
|
||||||
// no reason for failure?
|
// no reason for failure?
|
||||||
return true;
|
return true;
|
||||||
@@ -146,12 +143,24 @@ bool Metronome::init()
|
|||||||
void Metronome::terminate()
|
void Metronome::terminate()
|
||||||
{
|
{
|
||||||
// save current tempo
|
// save current tempo
|
||||||
Settings::application.metronome.tempo = tempo();
|
Settings::application.timer.link_tempo = tempo();
|
||||||
|
|
||||||
// disconnect
|
// disconnect
|
||||||
link_.enable(false);
|
link_.enable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Metronome::setEnabled (bool on)
|
||||||
|
{
|
||||||
|
link_.enable(on);
|
||||||
|
Settings::application.timer.link_enabled = link_.isEnabled();
|
||||||
|
Log::Info("Metronome Ableton Link %s", Settings::application.timer.link_enabled ? "Enabled" : "Disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metronome::enabled () const
|
||||||
|
{
|
||||||
|
return link_.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
double Metronome::beats() const
|
double Metronome::beats() const
|
||||||
{
|
{
|
||||||
return engine_.beatTime();
|
return engine_.beatTime();
|
||||||
@@ -165,7 +174,7 @@ double Metronome::phase() const
|
|||||||
void Metronome::setQuantum(double q)
|
void Metronome::setQuantum(double q)
|
||||||
{
|
{
|
||||||
engine_.setQuantum(q);
|
engine_.setQuantum(q);
|
||||||
Settings::application.metronome.quantum = engine_.quantum();
|
Settings::application.timer.link_quantum = engine_.quantum();
|
||||||
}
|
}
|
||||||
|
|
||||||
double Metronome::quantum() const
|
double Metronome::quantum() const
|
||||||
@@ -178,7 +187,7 @@ void Metronome::setTempo(double t)
|
|||||||
// set the tempo to t
|
// set the tempo to t
|
||||||
// OR
|
// OR
|
||||||
// adopt the last tempo value that have been proposed on the network
|
// adopt the last tempo value that have been proposed on the network
|
||||||
Settings::application.metronome.tempo = engine_.setTempo(t);
|
Settings::application.timer.link_tempo = engine_.setTempo(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Metronome::tempo() const
|
double Metronome::tempo() const
|
||||||
@@ -186,11 +195,40 @@ double Metronome::tempo() const
|
|||||||
return engine_.tempo();
|
return engine_.tempo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Metronome::setStartStopSync (bool on)
|
||||||
|
{
|
||||||
|
engine_.setStartStopSyncEnabled(on);
|
||||||
|
Settings::application.timer.link_start_stop_sync = engine_.isStartStopSyncEnabled();
|
||||||
|
Log::Info("Metronome Ableton Link start & stop sync %s", Settings::application.timer.link_start_stop_sync ? "Enabled" : "Disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metronome::startStopSync () const
|
||||||
|
{
|
||||||
|
return engine_.isStartStopSyncEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Metronome::restart()
|
||||||
|
{
|
||||||
|
engine_.startPlaying();
|
||||||
|
}
|
||||||
|
|
||||||
std::chrono::microseconds Metronome::timeToBeat()
|
std::chrono::microseconds Metronome::timeToBeat()
|
||||||
{
|
{
|
||||||
return engine_.timeNextBeat() - engine_.now();
|
return engine_.timeNextBeat() - engine_.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void delay(std::function<void()> f, std::chrono::microseconds us)
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(us);
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Metronome::executeAtBeat( std::function<void()> f )
|
||||||
|
{
|
||||||
|
std::thread( delay, f, timeToBeat() ).detach();
|
||||||
|
}
|
||||||
|
|
||||||
size_t Metronome::peers() const
|
size_t Metronome::peers() const
|
||||||
{
|
{
|
||||||
return link_.numPeers();
|
return link_.numPeers();
|
||||||
|
|||||||
28
Metronome.h
28
Metronome.h
@@ -2,6 +2,8 @@
|
|||||||
#define METRONOME_H
|
#define METRONOME_H
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
class Metronome
|
class Metronome
|
||||||
{
|
{
|
||||||
@@ -22,8 +24,8 @@ public:
|
|||||||
bool init ();
|
bool init ();
|
||||||
void terminate ();
|
void terminate ();
|
||||||
|
|
||||||
double beats () const;
|
void setEnabled (bool on);
|
||||||
double phase () const;
|
bool enabled () const;
|
||||||
|
|
||||||
void setTempo (double t);
|
void setTempo (double t);
|
||||||
double tempo () const;
|
double tempo () const;
|
||||||
@@ -31,9 +33,31 @@ public:
|
|||||||
void setQuantum (double q);
|
void setQuantum (double q);
|
||||||
double quantum () const;
|
double quantum () const;
|
||||||
|
|
||||||
|
void setStartStopSync (bool on);
|
||||||
|
bool startStopSync () const;
|
||||||
|
void restart();
|
||||||
|
|
||||||
|
// get beat and phase
|
||||||
|
double beats () const;
|
||||||
|
double phase () const;
|
||||||
|
|
||||||
|
// mechanisms to delay execution to next beat of phase
|
||||||
std::chrono::microseconds timeToBeat();
|
std::chrono::microseconds timeToBeat();
|
||||||
|
void executeAtBeat( std::function<void()> f );
|
||||||
|
|
||||||
size_t peers () const;
|
size_t peers () const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Example calls to executeAtBeat
|
||||||
|
///
|
||||||
|
/// With a Lamda function calling a member function of an object
|
||||||
|
/// - without parameter
|
||||||
|
/// Metronome::manager().executeAtBeat( std::bind([](MediaPlayer *p) { p->rewind(); }, mediaplayer_) );
|
||||||
|
///
|
||||||
|
/// - with parameter
|
||||||
|
/// Metronome::manager().executeAtBeat( std::bind([](MediaPlayer *p, bool o) { p->play(o); }, mediaplayer_, on) );
|
||||||
|
///
|
||||||
|
|
||||||
|
|
||||||
#endif // METRONOME_H
|
#endif // METRONOME_H
|
||||||
|
|||||||
39
Settings.cpp
39
Settings.cpp
@@ -34,7 +34,7 @@ using namespace tinyxml2;
|
|||||||
Settings::Application Settings::application;
|
Settings::Application Settings::application;
|
||||||
string settingsFilename = "";
|
string settingsFilename = "";
|
||||||
|
|
||||||
void Settings::Save()
|
void Settings::Save(uint64_t runtime)
|
||||||
{
|
{
|
||||||
// impose C locale for all app
|
// impose C locale for all app
|
||||||
setlocale(LC_ALL, "C");
|
setlocale(LC_ALL, "C");
|
||||||
@@ -49,6 +49,9 @@ void Settings::Save()
|
|||||||
pRoot->SetAttribute("minor", VIMIX_VERSION_MINOR);
|
pRoot->SetAttribute("minor", VIMIX_VERSION_MINOR);
|
||||||
xmlDoc.InsertEndChild(pRoot);
|
xmlDoc.InsertEndChild(pRoot);
|
||||||
#endif
|
#endif
|
||||||
|
// runtime
|
||||||
|
if (runtime>0)
|
||||||
|
pRoot->SetAttribute("runtime", runtime + application.total_runtime);
|
||||||
|
|
||||||
string comment = "Settings for " + application.name;
|
string comment = "Settings for " + application.name;
|
||||||
XMLComment *pComment = xmlDoc.NewComment(comment.c_str());
|
XMLComment *pComment = xmlDoc.NewComment(comment.c_str());
|
||||||
@@ -93,7 +96,8 @@ void Settings::Save()
|
|||||||
XMLElement *widgetsNode = xmlDoc.NewElement( "Widgets" );
|
XMLElement *widgetsNode = xmlDoc.NewElement( "Widgets" );
|
||||||
widgetsNode->SetAttribute("preview", application.widget.preview);
|
widgetsNode->SetAttribute("preview", application.widget.preview);
|
||||||
widgetsNode->SetAttribute("preview_view", application.widget.preview_view);
|
widgetsNode->SetAttribute("preview_view", application.widget.preview_view);
|
||||||
widgetsNode->SetAttribute("history", application.widget.history);
|
widgetsNode->SetAttribute("timer", application.widget.timer);
|
||||||
|
widgetsNode->SetAttribute("timer_view", application.widget.timer_view);
|
||||||
widgetsNode->SetAttribute("media_player", application.widget.media_player);
|
widgetsNode->SetAttribute("media_player", application.widget.media_player);
|
||||||
widgetsNode->SetAttribute("media_player_view", application.widget.media_player_view);
|
widgetsNode->SetAttribute("media_player_view", application.widget.media_player_view);
|
||||||
widgetsNode->SetAttribute("timeline_editmode", application.widget.timeline_editmode);
|
widgetsNode->SetAttribute("timeline_editmode", application.widget.timeline_editmode);
|
||||||
@@ -250,10 +254,14 @@ void Settings::Save()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Metronome
|
// Metronome
|
||||||
XMLElement *metroConfNode = xmlDoc.NewElement( "Metronome" );
|
XMLElement *timerConfNode = xmlDoc.NewElement( "Timer" );
|
||||||
metroConfNode->SetAttribute("tempo", application.metronome.tempo);
|
timerConfNode->SetAttribute("mode", application.timer.mode);
|
||||||
metroConfNode->SetAttribute("quantum", application.metronome.quantum);
|
timerConfNode->SetAttribute("link_enabled", application.timer.link_enabled);
|
||||||
pRoot->InsertEndChild(metroConfNode);
|
timerConfNode->SetAttribute("link_tempo", application.timer.link_tempo);
|
||||||
|
timerConfNode->SetAttribute("link_quantum", application.timer.link_quantum);
|
||||||
|
timerConfNode->SetAttribute("link_start_stop_sync", application.timer.link_start_stop_sync);
|
||||||
|
timerConfNode->SetAttribute("stopwatch_duration", application.timer.stopwatch_duration);
|
||||||
|
pRoot->InsertEndChild(timerConfNode);
|
||||||
|
|
||||||
// First save : create filename
|
// First save : create filename
|
||||||
if (settingsFilename.empty())
|
if (settingsFilename.empty())
|
||||||
@@ -296,6 +304,8 @@ void Settings::Load()
|
|||||||
if (version_major != VIMIX_VERSION_MAJOR || version_minor != VIMIX_VERSION_MINOR)
|
if (version_major != VIMIX_VERSION_MAJOR || version_minor != VIMIX_VERSION_MINOR)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
// runtime
|
||||||
|
pRoot->QueryUnsigned64Attribute("runtime", &application.total_runtime);
|
||||||
|
|
||||||
XMLElement * applicationNode = pRoot->FirstChildElement("Application");
|
XMLElement * applicationNode = pRoot->FirstChildElement("Application");
|
||||||
if (applicationNode != nullptr) {
|
if (applicationNode != nullptr) {
|
||||||
@@ -314,7 +324,8 @@ void Settings::Load()
|
|||||||
if (widgetsNode != nullptr) {
|
if (widgetsNode != nullptr) {
|
||||||
widgetsNode->QueryBoolAttribute("preview", &application.widget.preview);
|
widgetsNode->QueryBoolAttribute("preview", &application.widget.preview);
|
||||||
widgetsNode->QueryIntAttribute("preview_view", &application.widget.preview_view);
|
widgetsNode->QueryIntAttribute("preview_view", &application.widget.preview_view);
|
||||||
widgetsNode->QueryBoolAttribute("history", &application.widget.history);
|
widgetsNode->QueryBoolAttribute("timer", &application.widget.timer);
|
||||||
|
widgetsNode->QueryIntAttribute("timer_view", &application.widget.timer_view);
|
||||||
widgetsNode->QueryBoolAttribute("media_player", &application.widget.media_player);
|
widgetsNode->QueryBoolAttribute("media_player", &application.widget.media_player);
|
||||||
widgetsNode->QueryIntAttribute("media_player_view", &application.widget.media_player_view);
|
widgetsNode->QueryIntAttribute("media_player_view", &application.widget.media_player_view);
|
||||||
widgetsNode->QueryBoolAttribute("timeline_editmode", &application.widget.timeline_editmode);
|
widgetsNode->QueryBoolAttribute("timeline_editmode", &application.widget.timeline_editmode);
|
||||||
@@ -525,10 +536,14 @@ void Settings::Load()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bloc metronome
|
// bloc metronome
|
||||||
XMLElement * metroconfnode = pRoot->FirstChildElement("Metronome");
|
XMLElement * timerconfnode = pRoot->FirstChildElement("Timer");
|
||||||
if (metroconfnode != nullptr) {
|
if (timerconfnode != nullptr) {
|
||||||
metroconfnode->QueryDoubleAttribute("tempo", &application.metronome.tempo);
|
timerconfnode->QueryUnsigned64Attribute("mode", &application.timer.mode);
|
||||||
metroconfnode->QueryDoubleAttribute("quantum", &application.metronome.quantum);
|
timerconfnode->QueryBoolAttribute("link_enabled", &application.timer.link_enabled);
|
||||||
|
timerconfnode->QueryDoubleAttribute("link_tempo", &application.timer.link_tempo);
|
||||||
|
timerconfnode->QueryDoubleAttribute("link_quantum", &application.timer.link_quantum);
|
||||||
|
timerconfnode->QueryBoolAttribute("link_start_stop_sync", &application.timer.link_start_stop_sync);
|
||||||
|
timerconfnode->QueryUnsigned64Attribute("stopwatch_duration", &application.timer.stopwatch_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -606,8 +621,6 @@ void Settings::Unlock()
|
|||||||
|
|
||||||
void Settings::Check()
|
void Settings::Check()
|
||||||
{
|
{
|
||||||
Settings::Save();
|
|
||||||
|
|
||||||
XMLDocument xmlDoc;
|
XMLDocument xmlDoc;
|
||||||
XMLError eResult = xmlDoc.LoadFile(settingsFilename.c_str());
|
XMLError eResult = xmlDoc.LoadFile(settingsFilename.c_str());
|
||||||
if (XMLResultError(eResult)) {
|
if (XMLResultError(eResult)) {
|
||||||
|
|||||||
37
Settings.h
37
Settings.h
@@ -25,10 +25,11 @@ struct WidgetsConfig
|
|||||||
int preview_view;
|
int preview_view;
|
||||||
bool media_player;
|
bool media_player;
|
||||||
int media_player_view;
|
int media_player_view;
|
||||||
|
bool timer;
|
||||||
|
int timer_view;
|
||||||
bool timeline_editmode;
|
bool timeline_editmode;
|
||||||
bool shader_editor;
|
bool shader_editor;
|
||||||
bool toolbox;
|
bool toolbox;
|
||||||
bool history;
|
|
||||||
bool help;
|
bool help;
|
||||||
|
|
||||||
WidgetsConfig() {
|
WidgetsConfig() {
|
||||||
@@ -38,13 +39,14 @@ struct WidgetsConfig
|
|||||||
logs = false;
|
logs = false;
|
||||||
preview = false;
|
preview = false;
|
||||||
preview_view = -1;
|
preview_view = -1;
|
||||||
history = false;
|
|
||||||
media_player = false;
|
media_player = false;
|
||||||
media_player_view = -1;
|
media_player_view = -1;
|
||||||
timeline_editmode = false;
|
timeline_editmode = false;
|
||||||
shader_editor = false;
|
shader_editor = false;
|
||||||
toolbox = false;
|
toolbox = false;
|
||||||
help = false;
|
help = false;
|
||||||
|
timer = false;
|
||||||
|
timer_view = -1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -168,18 +170,22 @@ struct SourceConfig
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MetronomeConfig
|
struct TimerConfig
|
||||||
{
|
{
|
||||||
bool start_stop_sync;
|
uint64_t mode;
|
||||||
double tempo;
|
bool link_enabled;
|
||||||
double quantum;
|
double link_tempo;
|
||||||
bool sync_tempo;
|
double link_quantum;
|
||||||
|
bool link_start_stop_sync;
|
||||||
|
uint64_t stopwatch_duration;
|
||||||
|
|
||||||
MetronomeConfig() {
|
TimerConfig() {
|
||||||
start_stop_sync = true;
|
mode = 0;
|
||||||
tempo = 120.;
|
link_enabled = true;
|
||||||
quantum = 4.;
|
link_tempo = 120.;
|
||||||
sync_tempo = true;
|
link_quantum = 4.;
|
||||||
|
link_start_stop_sync = true;
|
||||||
|
stopwatch_duration = 60;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -192,6 +198,7 @@ struct Application
|
|||||||
// Verification
|
// Verification
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string executable;
|
std::string executable;
|
||||||
|
uint64_t total_runtime;
|
||||||
|
|
||||||
// Global settings Application interface
|
// Global settings Application interface
|
||||||
float scale;
|
float scale;
|
||||||
@@ -238,8 +245,8 @@ struct Application
|
|||||||
History recentImport;
|
History recentImport;
|
||||||
std::map< std::string, std::string > dialogRecentFolder;
|
std::map< std::string, std::string > dialogRecentFolder;
|
||||||
|
|
||||||
// Metronome
|
// Metronome & stopwatch
|
||||||
MetronomeConfig metronome;
|
TimerConfig timer;
|
||||||
|
|
||||||
Application() : fresh_start(false), instance_id(0), name(APP_NAME), executable(APP_NAME) {
|
Application() : fresh_start(false), instance_id(0), name(APP_NAME), executable(APP_NAME) {
|
||||||
scale = 1.f;
|
scale = 1.f;
|
||||||
@@ -268,7 +275,7 @@ struct Application
|
|||||||
extern Application application;
|
extern Application application;
|
||||||
|
|
||||||
// Save and Load store settings in XML file
|
// Save and Load store settings in XML file
|
||||||
void Save();
|
void Save(uint64_t runtime = 0);
|
||||||
void Load();
|
void Load();
|
||||||
void Lock();
|
void Lock();
|
||||||
void Unlock();
|
void Unlock();
|
||||||
|
|||||||
@@ -109,9 +109,22 @@ FrameGrabber *delayTrigger(FrameGrabber *g, std::chrono::milliseconds delay) {
|
|||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper functions for imgui window aspect-ratio constraints
|
||||||
|
struct CustomConstraints
|
||||||
|
{
|
||||||
|
static void AspectRatio(ImGuiSizeCallbackData* data) {
|
||||||
|
float *ar = (float*) data->UserData;
|
||||||
|
data->DesiredSize.y = (data->CurrentSize.x / (*ar)) + 35.f;
|
||||||
|
}
|
||||||
|
static void Square(ImGuiSizeCallbackData* data) {
|
||||||
|
data->DesiredSize.x = data->DesiredSize.y = (data->DesiredSize.x > data->DesiredSize.y ? data->DesiredSize.x : data->DesiredSize.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
UserInterface::UserInterface()
|
UserInterface::UserInterface()
|
||||||
{
|
{
|
||||||
|
start_time = gst_util_get_timestamp ();
|
||||||
ctrl_modifier_active = false;
|
ctrl_modifier_active = false;
|
||||||
alt_modifier_active = false;
|
alt_modifier_active = false;
|
||||||
shift_modifier_active = false;
|
shift_modifier_active = false;
|
||||||
@@ -204,6 +217,11 @@ bool UserInterface::Init()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t UserInterface::Runtime() const
|
||||||
|
{
|
||||||
|
return gst_util_get_timestamp () - start_time;
|
||||||
|
}
|
||||||
|
|
||||||
void UserInterface::handleKeyboard()
|
void UserInterface::handleKeyboard()
|
||||||
{
|
{
|
||||||
const ImGuiIO& io = ImGui::GetIO();
|
const ImGuiIO& io = ImGui::GetIO();
|
||||||
@@ -250,11 +268,15 @@ void UserInterface::handleKeyboard()
|
|||||||
Settings::application.widget.logs = !Settings::application.widget.logs;
|
Settings::application.widget.logs = !Settings::application.widget.logs;
|
||||||
}
|
}
|
||||||
else if (ImGui::IsKeyPressed( GLFW_KEY_T )) {
|
else if (ImGui::IsKeyPressed( GLFW_KEY_T )) {
|
||||||
|
// Timers
|
||||||
|
Settings::application.widget.timer = !Settings::application.widget.timer;
|
||||||
|
}
|
||||||
|
else if (ImGui::IsKeyPressed( GLFW_KEY_G )) {
|
||||||
// Developer toolbox
|
// Developer toolbox
|
||||||
Settings::application.widget.toolbox = !Settings::application.widget.toolbox;
|
Settings::application.widget.toolbox = !Settings::application.widget.toolbox;
|
||||||
}
|
}
|
||||||
else if (ImGui::IsKeyPressed( GLFW_KEY_H )) {
|
else if (ImGui::IsKeyPressed( GLFW_KEY_H )) {
|
||||||
// Session toolbox
|
// Helper
|
||||||
Settings::application.widget.help = !Settings::application.widget.help;
|
Settings::application.widget.help = !Settings::application.widget.help;
|
||||||
}
|
}
|
||||||
else if (ImGui::IsKeyPressed( GLFW_KEY_E )) {
|
else if (ImGui::IsKeyPressed( GLFW_KEY_E )) {
|
||||||
@@ -374,11 +396,11 @@ void UserInterface::handleKeyboard()
|
|||||||
// 3. hide windows
|
// 3. hide windows
|
||||||
else if (Settings::application.widget.preview ||
|
else if (Settings::application.widget.preview ||
|
||||||
Settings::application.widget.media_player ||
|
Settings::application.widget.media_player ||
|
||||||
Settings::application.widget.history ||
|
Settings::application.widget.timer ||
|
||||||
Settings::application.widget.logs) {
|
Settings::application.widget.logs) {
|
||||||
Settings::application.widget.preview = false;
|
Settings::application.widget.preview = false;
|
||||||
Settings::application.widget.media_player = false;
|
Settings::application.widget.media_player = false;
|
||||||
Settings::application.widget.history = false;
|
Settings::application.widget.timer = false;
|
||||||
Settings::application.widget.logs = false;
|
Settings::application.widget.logs = false;
|
||||||
}
|
}
|
||||||
// 4. cancel selection
|
// 4. cancel selection
|
||||||
@@ -771,8 +793,9 @@ void UserInterface::Render()
|
|||||||
if (Settings::application.widget.preview && ( Settings::application.widget.preview_view < 0 ||
|
if (Settings::application.widget.preview && ( Settings::application.widget.preview_view < 0 ||
|
||||||
Settings::application.widget.preview_view == Settings::application.current_view ))
|
Settings::application.widget.preview_view == Settings::application.current_view ))
|
||||||
RenderPreview();
|
RenderPreview();
|
||||||
if (Settings::application.widget.history)
|
if (Settings::application.widget.timer && ( Settings::application.widget.timer_view < 0 ||
|
||||||
RenderHistory();
|
Settings::application.widget.timer_view == Settings::application.current_view ))
|
||||||
|
RenderTimer();
|
||||||
if (Settings::application.widget.shader_editor)
|
if (Settings::application.widget.shader_editor)
|
||||||
RenderShaderEditor();
|
RenderShaderEditor();
|
||||||
if (Settings::application.widget.logs)
|
if (Settings::application.widget.logs)
|
||||||
@@ -944,62 +967,263 @@ void UserInterface::handleScreenshot()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserInterface::RenderHistory()
|
|
||||||
{
|
|
||||||
float history_height = 5.f * ImGui::GetFrameHeightWithSpacing();
|
|
||||||
ImVec2 MinWindowSize = ImVec2(250.f, history_height);
|
|
||||||
|
|
||||||
ImGui::SetNextWindowPos(ImVec2(1180, 400), ImGuiCond_FirstUseEver);
|
#define MAX_SEGMENTS 64
|
||||||
ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
|
|
||||||
ImGui::SetNextWindowSizeConstraints(MinWindowSize, ImVec2(FLT_MAX, FLT_MAX));
|
void UserInterface::RenderTimer()
|
||||||
if ( !ImGui::Begin(IMGUI_TITLE_HISTORY, &Settings::application.widget.history, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ))
|
{
|
||||||
|
// timer modes : 0 Metronome, 1 Stopwatch
|
||||||
|
static std::array< std::string, 2 > timer_menu = { " Metronome ", " Stopwatch " };
|
||||||
|
|
||||||
|
// constraint position
|
||||||
|
static ImVec2 timer_window_pos = ImVec2(1180, 20);
|
||||||
|
static ImVec2 timer_window_size = ImVec2(400, 400);
|
||||||
|
SetNextWindowVisible(timer_window_pos, timer_window_size);
|
||||||
|
|
||||||
|
// constraint square resizing
|
||||||
|
ImGui::SetNextWindowSizeConstraints(ImVec2(300, 300), ImVec2(600, 600), CustomConstraints::Square);
|
||||||
|
|
||||||
|
if ( !ImGui::Begin(IMGUI_TITLE_TIMER, &Settings::application.widget.timer, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ))
|
||||||
{
|
{
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// current window
|
||||||
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||||
|
timer_window_pos = window->Pos;
|
||||||
|
timer_window_size = window->Size;
|
||||||
|
|
||||||
// menu (no title bar)
|
// menu (no title bar)
|
||||||
bool tmp = false;
|
|
||||||
if (ImGui::BeginMenuBar())
|
if (ImGui::BeginMenuBar())
|
||||||
{
|
{
|
||||||
|
// Close and widget menu
|
||||||
if (ImGuiToolkit::IconButton(4,16))
|
if (ImGuiToolkit::IconButton(4,16))
|
||||||
Settings::application.widget.history = false;
|
Settings::application.widget.timer = false;
|
||||||
if (ImGui::BeginMenu(IMGUI_TITLE_HISTORY))
|
if (ImGui::BeginMenu(IMGUI_TITLE_TIMER))
|
||||||
{
|
{
|
||||||
if ( ImGui::MenuItem( ICON_FA_UNDO " Undo", CTRL_MOD "Z") )
|
// Enable/Disable Ableton Link
|
||||||
Action::manager().undo();
|
if ( ImGui::MenuItem( ICON_FA_USER_CLOCK " Ableton Link", nullptr, &Settings::application.timer.link_enabled) ) {
|
||||||
if ( ImGui::MenuItem( ICON_FA_REDO " Redo", CTRL_MOD "Shift+Z") )
|
Metronome::manager().setEnabled(Settings::application.timer.link_enabled);
|
||||||
Action::manager().redo();
|
}
|
||||||
|
|
||||||
ImGui::MenuItem( ICON_FA_DIRECTIONS " Follow view", nullptr, &Settings::application.action_history_follow_view);
|
|
||||||
|
|
||||||
|
// output manager menu
|
||||||
|
ImGui::Separator();
|
||||||
|
bool pinned = Settings::application.widget.timer_view == Settings::application.current_view;
|
||||||
|
if ( ImGui::MenuItem( ICON_FA_MAP_PIN " Pin window to view", nullptr, &pinned) ){
|
||||||
|
if (pinned)
|
||||||
|
Settings::application.widget.timer_view = Settings::application.current_view;
|
||||||
|
else
|
||||||
|
Settings::application.widget.timer_view = -1;
|
||||||
|
}
|
||||||
if ( ImGui::MenuItem( ICON_FA_TIMES " Close") )
|
if ( ImGui::MenuItem( ICON_FA_TIMES " Close") )
|
||||||
Settings::application.widget.history = false;
|
Settings::application.widget.timer = false;
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
if ( ImGui::Selectable(ICON_FA_UNDO, &tmp, ImGuiSelectableFlags_None, ImVec2(20,0)))
|
// Selection of the timer mode
|
||||||
Action::manager().undo();
|
if (ImGui::BeginMenu( timer_menu[Settings::application.timer.mode].c_str() ))
|
||||||
if ( ImGui::Selectable(ICON_FA_REDO, &tmp, ImGuiSelectableFlags_None, ImVec2(20,0)))
|
{
|
||||||
Action::manager().redo();
|
for (size_t i = 0; i < timer_menu.size(); ++i) {
|
||||||
|
if (ImGui::MenuItem(timer_menu[i].c_str(), NULL, Settings::application.timer.mode==i))
|
||||||
|
Settings::application.timer.mode = i;
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::ListBoxHeader("##History", ImGui::GetContentRegionAvail() ) )
|
// Window draw parameters
|
||||||
{
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
for (uint i = Action::manager().max(); i > 0; i--) {
|
// positions and size of GUI elements
|
||||||
|
const float margin = window->MenuBarHeight();
|
||||||
|
const float h = 0.4f * ImGui::GetFrameHeight();
|
||||||
|
const ImVec2 circle_top_left = window->Pos + ImVec2(margin + h, margin + h);
|
||||||
|
const ImVec2 circle_top_right = window->Pos + ImVec2(window->Size.y - margin - h, margin + h);
|
||||||
|
// const ImVec2 circle_botom_left = window->Pos + ImVec2(margin + h, window->Size.x - margin - h);
|
||||||
|
const ImVec2 circle_botom_right = window->Pos + ImVec2(window->Size.y - margin - h, window->Size.x - margin - h);
|
||||||
|
const ImVec2 circle_center = window->Pos + (window->Size + ImVec2(margin, margin) )/ 2.f;
|
||||||
|
const float circle_radius = (window->Size.y - 2.f * margin) / 2.f;
|
||||||
|
|
||||||
std::string step_label_ = Action::manager().label(i);
|
// color palette
|
||||||
|
const ImU32 colorbg = ImGui::GetColorU32(ImGuiCol_FrameBgActive, 0.6f);
|
||||||
|
const ImU32 colorfg = ImGui::GetColorU32(ImGuiCol_FrameBg, 2.5f);
|
||||||
|
const ImU32 colorline = ImGui::GetColorU32(ImGuiCol_PlotHistogram);
|
||||||
|
|
||||||
bool enable = i == Action::manager().current();
|
//
|
||||||
if (ImGui::Selectable( step_label_.c_str(), &enable, ImGuiSelectableFlags_AllowDoubleClick )) {
|
// METRONOME
|
||||||
|
//
|
||||||
|
if (Settings::application.timer.mode < 1) {
|
||||||
|
|
||||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
// Metronome info
|
||||||
Action::manager().stepTo(i);
|
double t = Metronome::manager().tempo();
|
||||||
|
double p = Metronome::manager().phase();
|
||||||
|
double q = Metronome::manager().quantum();
|
||||||
|
uint np = (int) Metronome::manager().peers();
|
||||||
|
|
||||||
|
// draw background ring
|
||||||
|
draw_list->AddCircleFilled(circle_center, circle_radius, colorbg, MAX_SEGMENTS);
|
||||||
|
|
||||||
|
// draw quarter
|
||||||
|
static const float resolution = MAX_SEGMENTS / (2.f * M_PI);
|
||||||
|
static ImVec2 buffer[MAX_SEGMENTS];
|
||||||
|
float a0 = -M_PI_2 + (floor(p)/floor(q)) * (2.f * M_PI);
|
||||||
|
float a1 = a0 + (1.f / floor(q)) * (2.f * M_PI);
|
||||||
|
int n = ImMax(3, (int)((a1 - a0) * resolution));
|
||||||
|
double da = (a1 - a0) / (n - 1);
|
||||||
|
int index = 0;
|
||||||
|
buffer[index++] = circle_center;
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
double a = a0 + i * da;
|
||||||
|
buffer[index++] = ImVec2(circle_center.x + circle_radius * cos(a), circle_center.y + circle_radius * sin(a));
|
||||||
|
}
|
||||||
|
draw_list->AddConvexPolyFilled(buffer, index, colorfg);
|
||||||
|
|
||||||
|
// draw clock hand
|
||||||
|
a0 = -M_PI_2 + (p/q) * (2.f * M_PI);
|
||||||
|
draw_list->AddLine(ImVec2(circle_center.x + margin * cos(a0), circle_center.y + margin * sin(a0)),
|
||||||
|
ImVec2(circle_center.x + circle_radius * cos(a0), circle_center.y + circle_radius * sin(a0)), colorline, 2.f);
|
||||||
|
|
||||||
|
// centered indicator 'x / N'
|
||||||
|
draw_list->AddCircleFilled(circle_center, margin, colorfg, MAX_SEGMENTS);
|
||||||
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
||||||
|
char text_buf[24];
|
||||||
|
sprintf(text_buf, "%d/%d", (int)(p)+1, (int)(q) );
|
||||||
|
ImVec2 label_size = ImGui::CalcTextSize(text_buf, NULL);
|
||||||
|
ImGui::SetCursorScreenPos(circle_center - label_size/2);
|
||||||
|
ImGui::Text("%s", text_buf);
|
||||||
|
ImGui::PopFont();
|
||||||
|
|
||||||
|
// left slider : quantum
|
||||||
|
float float_value = ceil(Metronome::manager().quantum());
|
||||||
|
ImGui::SetCursorScreenPos(timer_window_pos + ImVec2(0.5f * margin, 1.5f * margin));
|
||||||
|
if ( ImGui::VSliderFloat("##quantum", ImVec2(0.5f * margin, 2.f * circle_radius ), &float_value, 2, 200, "", 2.f) ){
|
||||||
|
Metronome::manager().setQuantum( ceil(float_value) );
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered() || ImGui::IsItemActive() ) {
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
guint64 time_phase = GST_SECOND * (60.0 * q / t) ;
|
||||||
|
ImGui::Text("Quantum: %d\nPhase duration: %s", (int) ceil(float_value), GstToolkit::time_to_string(time_phase, GstToolkit::TIME_STRING_READABLE).c_str() );
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controls NOT operational if peer connected
|
||||||
|
if (np >0 ) {
|
||||||
|
// Tempo
|
||||||
|
ImGui::SetCursorScreenPos(circle_top_right);
|
||||||
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, colorfg);
|
||||||
|
sprintf(text_buf, "%d", (int) ceil(t) );
|
||||||
|
ImGui::Text("%s", text_buf);
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopFont();
|
||||||
|
if (ImGui::IsItemHovered()){
|
||||||
|
sprintf(text_buf, "%d BPM\n(set by peer)", (int) ceil(t));
|
||||||
|
ImGuiToolkit::ToolTip(text_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::ListBoxFooter();
|
// Controls operational only if no peer
|
||||||
|
else {
|
||||||
|
// Tempo
|
||||||
|
ImGui::SetCursorScreenPos(circle_top_right);
|
||||||
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
|
||||||
|
sprintf(text_buf, "%d", (int) ceil(t) );
|
||||||
|
ImGui::Text("%s", text_buf);
|
||||||
|
ImGui::PopFont();
|
||||||
|
if (ImGui::IsItemClicked())
|
||||||
|
ImGui::OpenPopup("bpm_popup");
|
||||||
|
else if (ImGui::IsItemHovered()){
|
||||||
|
sprintf(text_buf, "%d BPM\n(clic to edit)", (int) ceil(t));
|
||||||
|
ImGuiToolkit::ToolTip(text_buf);
|
||||||
|
}
|
||||||
|
if (ImGui::BeginPopup("bpm_popup", ImGuiWindowFlags_NoMove))
|
||||||
|
{
|
||||||
|
ImGui::SetNextItemWidth(80);
|
||||||
|
ImGui::InputText("BPM", text_buf, 8, ImGuiInputTextFlags_CharsDecimal);
|
||||||
|
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||||
|
int t = 0;
|
||||||
|
sscanf(text_buf, "%d", &t);
|
||||||
|
t = CLAMP(t, 20, 2000);
|
||||||
|
Metronome::manager().setTempo((double) t);
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
// restart icon
|
||||||
|
ImGui::SetCursorScreenPos(circle_top_left);
|
||||||
|
if (ImGuiToolkit::IconButton(9, 13)) {
|
||||||
|
Metronome::manager().restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network indicator, if link enabled
|
||||||
|
if (Settings::application.timer.link_enabled) {
|
||||||
|
ImGui::SetCursorScreenPos(circle_botom_right);
|
||||||
|
ImGuiToolkit::Icon(16, 5, np > 0);
|
||||||
|
if (ImGui::IsItemHovered()){
|
||||||
|
sprintf(text_buf, np < 1 ? "Ableton Link\nNo peer" : "Ableton Link\n%d peer%c", np, np < 2 ? ' ' : 's' );
|
||||||
|
ImGuiToolkit::ToolTip(text_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// STOPWATCH
|
||||||
|
//
|
||||||
|
else {
|
||||||
|
// clock times
|
||||||
|
static guint64 start_time_ = gst_util_get_timestamp ();
|
||||||
|
static guint64 start_time_hand_ = gst_util_get_timestamp ();
|
||||||
|
static guint64 duration_hand_ = Settings::application.timer.stopwatch_duration * GST_SECOND;
|
||||||
|
guint64 time_ = gst_util_get_timestamp ();
|
||||||
|
|
||||||
|
// draw ring
|
||||||
|
draw_list->AddCircle(circle_center, circle_radius, colorbg, MAX_SEGMENTS, 12 );
|
||||||
|
draw_list->AddCircleFilled(ImVec2(circle_center.x, circle_center.y - circle_radius), 7, colorfg, MAX_SEGMENTS);
|
||||||
|
// draw indicator time hand
|
||||||
|
double da = -M_PI_2 + ( (double) (time_-start_time_hand_) / (double) duration_hand_) * (2.f * M_PI);
|
||||||
|
draw_list->AddCircleFilled(ImVec2(circle_center.x + circle_radius * cos(da), circle_center.y + circle_radius * sin(da)), 7, colorline, MAX_SEGMENTS);
|
||||||
|
|
||||||
|
// left slider : countdown
|
||||||
|
float float_value = (float) Settings::application.timer.stopwatch_duration;
|
||||||
|
ImGui::SetCursorScreenPos(timer_window_pos + ImVec2(0.5f * margin, 1.5f * margin));
|
||||||
|
if ( ImGui::VSliderFloat("##duration", ImVec2(0.5f * margin, 2.f * circle_radius ), &float_value, 1, 3600, "", 3.f) ){
|
||||||
|
Settings::application.timer.stopwatch_duration = (uint64_t) float_value;
|
||||||
|
duration_hand_ = Settings::application.timer.stopwatch_duration * GST_SECOND;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered() || ImGui::IsItemActive()) {
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("Countdown\n%s", GstToolkit::time_to_string(duration_hand_, GstToolkit::TIME_STRING_READABLE).c_str() );
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
// main text: elapsed time
|
||||||
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
||||||
|
char text_buf[24];
|
||||||
|
sprintf(text_buf, "%s", GstToolkit::time_to_string(time_-start_time_, GstToolkit::TIME_STRING_FIXED).c_str() );
|
||||||
|
ImVec2 label_size = ImGui::CalcTextSize(text_buf, NULL);
|
||||||
|
ImGui::SetCursorScreenPos(circle_center - label_size/2);
|
||||||
|
ImGui::Text("%s", text_buf);
|
||||||
|
ImGui::PopFont();
|
||||||
|
|
||||||
|
// small text: remaining time
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, colorfg);
|
||||||
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
|
||||||
|
sprintf(text_buf, "%s", GstToolkit::time_to_string(duration_hand_-(time_-start_time_hand_)%duration_hand_, GstToolkit::TIME_STRING_READABLE).c_str() );
|
||||||
|
label_size = ImGui::CalcTextSize(text_buf, NULL);
|
||||||
|
ImGui::SetCursorScreenPos(circle_center + ImVec2(0.f, circle_radius * -0.7f) - label_size/2);
|
||||||
|
ImGui::Text("%s", text_buf);
|
||||||
|
ImGui::PopFont();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
// reset icon
|
||||||
|
ImGui::SetCursorScreenPos(circle_top_left);
|
||||||
|
if (ImGuiToolkit::IconButton(8, 13))
|
||||||
|
start_time_ = start_time_hand_ = time_; // reset timers
|
||||||
|
|
||||||
|
// TODO : pause ?
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
@@ -1014,15 +1238,6 @@ void UserInterface::RenderPreview()
|
|||||||
// recording location
|
// recording location
|
||||||
static DialogToolkit::OpenFolderDialog recordFolderDialog("Recording Location");
|
static DialogToolkit::OpenFolderDialog recordFolderDialog("Recording Location");
|
||||||
|
|
||||||
// Helper functions for aspect-ratio constraints
|
|
||||||
struct CustomConstraints
|
|
||||||
{
|
|
||||||
static void AspectRatio(ImGuiSizeCallbackData* data) {
|
|
||||||
float *ar = (float*) data->UserData;
|
|
||||||
data->DesiredSize.y = (data->CurrentSize.x / (*ar)) + 35.f;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FrameBuffer *output = Mixer::manager().session()->frame();
|
FrameBuffer *output = Mixer::manager().session()->frame();
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
@@ -1562,9 +1777,6 @@ void UserInterface::RenderShaderEditor()
|
|||||||
|
|
||||||
void UserInterface::RenderMetrics(bool *p_open, int* p_corner, int *p_mode)
|
void UserInterface::RenderMetrics(bool *p_open, int* p_corner, int *p_mode)
|
||||||
{
|
{
|
||||||
static guint64 start_time_1_ = gst_util_get_timestamp ();
|
|
||||||
static guint64 start_time_2_ = gst_util_get_timestamp ();
|
|
||||||
|
|
||||||
if (!p_corner || !p_open)
|
if (!p_corner || !p_open)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1589,53 +1801,15 @@ void UserInterface::RenderMetrics(bool *p_open, int* p_corner, int *p_mode)
|
|||||||
ImGui::SetNextItemWidth(200);
|
ImGui::SetNextItemWidth(200);
|
||||||
ImGui::Combo("##mode", p_mode,
|
ImGui::Combo("##mode", p_mode,
|
||||||
ICON_FA_TACHOMETER_ALT " Performance\0"
|
ICON_FA_TACHOMETER_ALT " Performance\0"
|
||||||
ICON_FA_HOURGLASS_HALF " Timers\0"
|
ICON_FA_HOURGLASS_HALF " Runtime\0"
|
||||||
ICON_FA_VECTOR_SQUARE " Source\0"
|
ICON_FA_VECTOR_SQUARE " Source\0");
|
||||||
ICON_FA_USER_CLOCK " Metronome\0");
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGuiToolkit::IconButton(5,8))
|
if (ImGuiToolkit::IconButton(5,8))
|
||||||
ImGui::OpenPopup("metrics_menu");
|
ImGui::OpenPopup("metrics_menu");
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
|
|
||||||
if (*p_mode > 2) {
|
if (*p_mode > 1) {
|
||||||
// get values
|
|
||||||
double t = Metronome::manager().tempo();
|
|
||||||
double p = Metronome::manager().phase();
|
|
||||||
double q = Metronome::manager().quantum();
|
|
||||||
uint n = (int) Metronome::manager().peers();
|
|
||||||
|
|
||||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
|
||||||
|
|
||||||
// tempo
|
|
||||||
char buf[32];
|
|
||||||
ImGui::Text("Tempo %.1f BPM ", t);
|
|
||||||
// network peers indicator
|
|
||||||
ImGui::SameLine();
|
|
||||||
if ( n < 1) {
|
|
||||||
ImGui::TextDisabled( ICON_FA_NETWORK_WIRED );
|
|
||||||
if (ImGui::IsItemHovered()){
|
|
||||||
sprintf(buf, "No peer linked");
|
|
||||||
ImGuiToolkit::ToolTip(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImGui::Text( ICON_FA_NETWORK_WIRED );
|
|
||||||
if (ImGui::IsItemHovered()){
|
|
||||||
sprintf(buf, "%d peer%c linked", n, n < 2 ? ' ' : 's');
|
|
||||||
ImGuiToolkit::ToolTip(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// compute and display duration of a phase
|
|
||||||
guint64 time_phase = GST_SECOND * (60.0 * q / t) ;
|
|
||||||
ImGui::Text("Phase %s", GstToolkit::time_to_string(time_phase, GstToolkit::TIME_STRING_READABLE).c_str());
|
|
||||||
// metronome
|
|
||||||
sprintf(buf, "%d/%d", (int)(p)+1, (int)(q) );
|
|
||||||
ImGui::ProgressBar(ceil(p)/ceil(q), ImVec2(250.f,0.f), buf);
|
|
||||||
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
else if (*p_mode > 1) {
|
|
||||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
||||||
Source *s = Mixer::manager().currentSource();
|
Source *s = Mixer::manager().currentSource();
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -1690,24 +1864,13 @@ void UserInterface::RenderMetrics(bool *p_open, int* p_corner, int *p_mode)
|
|||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
else if (*p_mode > 0) {
|
else if (*p_mode > 0) {
|
||||||
guint64 time_ = gst_util_get_timestamp ();
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
||||||
|
ImGui::Text("Session %s", GstToolkit::time_to_string(Mixer::manager().session()->runtime(), GstToolkit::TIME_STRING_READABLE).c_str());
|
||||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
uint64_t time = Runtime();
|
||||||
ImGui::Text("%s", GstToolkit::time_to_string(time_-start_time_1_, GstToolkit::TIME_STRING_FIXED).c_str());
|
ImGui::Text("Program %s", GstToolkit::time_to_string(time, GstToolkit::TIME_STRING_READABLE).c_str());
|
||||||
|
time += Settings::application.total_runtime;
|
||||||
|
ImGui::Text("Total %s", GstToolkit::time_to_string(time, GstToolkit::TIME_STRING_READABLE).c_str());
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
ImGui::SameLine(0, 10);
|
|
||||||
ImGui::PushID( "timermetric1" );
|
|
||||||
if (ImGuiToolkit::IconButton(12, 14))
|
|
||||||
start_time_1_ = time_; // reset timer 1
|
|
||||||
ImGui::PopID();
|
|
||||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
|
||||||
ImGui::Text("%s", GstToolkit::time_to_string(time_-start_time_2_, GstToolkit::TIME_STRING_FIXED).c_str());
|
|
||||||
ImGui::PopFont();
|
|
||||||
ImGui::SameLine(0, 10);
|
|
||||||
ImGui::PushID( "timermetric2" );
|
|
||||||
if (ImGuiToolkit::IconButton(12, 14))
|
|
||||||
start_time_2_ = time_; // reset timer 2
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
|
||||||
@@ -2089,7 +2252,7 @@ void HelperToolbox::Render()
|
|||||||
///
|
///
|
||||||
SourceController::SourceController() : focused_(false), min_width_(0.f), h_space_(0.f), v_space_(0.f), scrollbar_(0.f),
|
SourceController::SourceController() : focused_(false), min_width_(0.f), h_space_(0.f), v_space_(0.f), scrollbar_(0.f),
|
||||||
timeline_height_(0.f), mediaplayer_height_(0.f), buttons_width_(0.f), buttons_height_(0.f),
|
timeline_height_(0.f), mediaplayer_height_(0.f), buttons_width_(0.f), buttons_height_(0.f),
|
||||||
play_toggle_request_(false), replay_request_(false),
|
play_toggle_request_(false), replay_request_(false), pending_(false),
|
||||||
active_label_(LABEL_AUTO_MEDIA_PLAYER), active_selection_(-1),
|
active_label_(LABEL_AUTO_MEDIA_PLAYER), active_selection_(-1),
|
||||||
selection_context_menu_(false), selection_mediaplayer_(nullptr), selection_target_slower_(0), selection_target_faster_(0),
|
selection_context_menu_(false), selection_mediaplayer_(nullptr), selection_target_slower_(0), selection_target_faster_(0),
|
||||||
mediaplayer_active_(nullptr), mediaplayer_edit_fading_(false), mediaplayer_mode_(false), mediaplayer_slider_pressed_(false), mediaplayer_timeline_zoom_(1.f)
|
mediaplayer_active_(nullptr), mediaplayer_edit_fading_(false), mediaplayer_mode_(false), mediaplayer_slider_pressed_(false), mediaplayer_timeline_zoom_(1.f)
|
||||||
@@ -3081,7 +3244,7 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
|||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
|
|
||||||
|
|
||||||
ImVec2 scrollwindow = ImVec2(ImGui::GetContentRegionAvail().x - slider_zoom_width - 3.0,
|
const ImVec2 scrollwindow = ImVec2(ImGui::GetContentRegionAvail().x - slider_zoom_width - 3.0,
|
||||||
2.f * timeline_height_ + scrollbar_ );
|
2.f * timeline_height_ + scrollbar_ );
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -3267,6 +3430,11 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
|||||||
// restore buttons style
|
// restore buttons style
|
||||||
ImGui::PopStyleColor(5);
|
ImGui::PopStyleColor(5);
|
||||||
|
|
||||||
|
if (mediaplayer_active_->pending())
|
||||||
|
{
|
||||||
|
draw_list->AddRectFilled(bottom, bottom + ImVec2(rendersize.x, buttons_height_), ImGui::GetColorU32(ImGuiCol_ScrollbarBg), h_space_);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// media player timeline actions
|
/// media player timeline actions
|
||||||
///
|
///
|
||||||
@@ -3283,11 +3451,12 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp)
|
|||||||
if ( mediaplayer_active_->isPlaying() != media_play ) {
|
if ( mediaplayer_active_->isPlaying() != media_play ) {
|
||||||
mediaplayer_active_->play( media_play );
|
mediaplayer_active_->play( media_play );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
const ImGuiContext& g = *GImGui;
|
const ImGuiContext& g = *GImGui;
|
||||||
const double width_ratio = static_cast<double>(scrollwindow.x + g.Style.FramePadding.x ) / static_cast<double>(mediaplayer_active_->timeline()->sectionsDuration());
|
const double width_ratio = static_cast<double>(scrollwindow.x - slider_zoom_width + g.Style.FramePadding.x ) / static_cast<double>(mediaplayer_active_->timeline()->sectionsDuration());
|
||||||
DrawTimeline("##timeline_mediaplayers", mediaplayer_active_->timeline(), mediaplayer_active_->position(), width_ratio, 2.f * timeline_height_);
|
DrawTimeline("##timeline_mediaplayers", mediaplayer_active_->timeline(), mediaplayer_active_->position(), width_ratio, 2.f * timeline_height_);
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -4716,6 +4885,15 @@ void Navigator::RenderMainPannelVimix()
|
|||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
tooltip_ = "Output " CTRL_MOD "D";
|
tooltip_ = "Output " CTRL_MOD "D";
|
||||||
|
|
||||||
|
ImGui::SameLine(0, 40);
|
||||||
|
if ( ImGuiToolkit::IconButton( ICON_FA_CLOCK ) ) {
|
||||||
|
Settings::application.widget.timer = true;
|
||||||
|
if (Settings::application.widget.timer_view != Settings::application.current_view)
|
||||||
|
Settings::application.widget.timer_view = -1;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
tooltip_ = "Timer " CTRL_MOD "T";
|
||||||
|
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
if (!tooltip_.empty()) {
|
if (!tooltip_.empty()) {
|
||||||
ImGuiToolkit::ToolTip(tooltip_.substr(0, tooltip_.size()-12).c_str(), tooltip_.substr(tooltip_.size()-12, 12).c_str());
|
ImGuiToolkit::ToolTip(tooltip_.substr(0, tooltip_.size()-12).c_str(), tooltip_.substr(tooltip_.size()-12, 12).c_str());
|
||||||
@@ -4753,47 +4931,11 @@ void Navigator::RenderMainPannelSettings()
|
|||||||
ImGuiToolkit::ButtonSwitch( ICON_FA_MOUSE_POINTER " Smooth cursor", &Settings::application.smooth_cursor);
|
ImGuiToolkit::ButtonSwitch( ICON_FA_MOUSE_POINTER " Smooth cursor", &Settings::application.smooth_cursor);
|
||||||
ImGuiToolkit::ButtonSwitch( ICON_FA_TACHOMETER_ALT " Metrics", &Settings::application.widget.stats);
|
ImGuiToolkit::ButtonSwitch( ICON_FA_TACHOMETER_ALT " Metrics", &Settings::application.widget.stats);
|
||||||
|
|
||||||
//
|
|
||||||
// Metronome
|
|
||||||
//
|
|
||||||
ImGuiToolkit::Spacing();
|
|
||||||
ImGui::Text("Ableton link");
|
|
||||||
|
|
||||||
ImGuiToolkit::HelpMarker("Time synchronization between computers with Ableton link\n "
|
|
||||||
ICON_FA_ANGLE_RIGHT " Tempo is the number of beats per minute (or set by peers).\n "
|
|
||||||
ICON_FA_ANGLE_RIGHT " Quantum is the number of beats in a phase.");
|
|
||||||
ImGui::SameLine(0);
|
|
||||||
ImGui::SetCursorPosX(-1.f * IMGUI_RIGHT_ALIGN);
|
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
|
||||||
int t = (int) ceil(Metronome::manager().tempo());
|
|
||||||
// if no other peers, user can set a tempo
|
|
||||||
if (Metronome::manager().peers() < 1) {
|
|
||||||
if ( ImGui::SliderInt("Tempo", &t, 20, 240, "%d BPM") )
|
|
||||||
Metronome::manager().setTempo((double) t);
|
|
||||||
}
|
|
||||||
// if there are other peers, tempo cannot be changed
|
|
||||||
else {
|
|
||||||
// show static info (same size than slider)
|
|
||||||
static char dummy_str[64];
|
|
||||||
sprintf(dummy_str, "%d BPM", t);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.9f));
|
|
||||||
ImGui::InputText("Tempo", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly);
|
|
||||||
ImGui::PopStyleColor(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetCursorPosX(-1.f * IMGUI_RIGHT_ALIGN);
|
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
|
||||||
int q = (int) ceil(Metronome::manager().quantum());
|
|
||||||
if ( ImGui::SliderInt("Quantum", &q, 2, 100) )
|
|
||||||
Metronome::manager().setQuantum((double) q);
|
|
||||||
|
|
||||||
// ImGuiToolkit::ButtonSwitch( ICON_FA_USER_CLOCK " Start/stop sync", &Settings::application.metronome.start_stop_sync);
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
ImGui::Text("Expert");
|
ImGui::Text("Expert");
|
||||||
// ImGuiToolkit::ButtonSwitch( IMGUI_TITLE_HISTORY, &Settings::application.widget.history);
|
// ImGuiToolkit::ButtonSwitch( IMGUI_TITLE_HISTORY, &Settings::application.widget.history);
|
||||||
ImGuiToolkit::ButtonSwitch( IMGUI_TITLE_SHADEREDITOR, &Settings::application.widget.shader_editor, CTRL_MOD "E");
|
ImGuiToolkit::ButtonSwitch( IMGUI_TITLE_SHADEREDITOR, &Settings::application.widget.shader_editor, CTRL_MOD "E");
|
||||||
ImGuiToolkit::ButtonSwitch( IMGUI_TITLE_TOOLBOX, &Settings::application.widget.toolbox, CTRL_MOD "T");
|
ImGuiToolkit::ButtonSwitch( IMGUI_TITLE_TOOLBOX, &Settings::application.widget.toolbox, CTRL_MOD "G");
|
||||||
ImGuiToolkit::ButtonSwitch( IMGUI_TITLE_LOGS, &Settings::application.widget.logs, CTRL_MOD "L");
|
ImGuiToolkit::ButtonSwitch( IMGUI_TITLE_LOGS, &Settings::application.widget.logs, CTRL_MOD "L");
|
||||||
#endif
|
#endif
|
||||||
//
|
//
|
||||||
@@ -5118,6 +5260,7 @@ void Thumbnail::Render(float width)
|
|||||||
#define SEGMENT_ARRAY_MAX 1000
|
#define SEGMENT_ARRAY_MAX 1000
|
||||||
#define MAXSIZE 65535
|
#define MAXSIZE 65535
|
||||||
|
|
||||||
|
|
||||||
void ShowSandbox(bool* p_open)
|
void ShowSandbox(bool* p_open)
|
||||||
{
|
{
|
||||||
ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
|
ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ class SourceController
|
|||||||
float buttons_height_;
|
float buttons_height_;
|
||||||
|
|
||||||
bool play_toggle_request_, replay_request_;
|
bool play_toggle_request_, replay_request_;
|
||||||
|
bool pending_;
|
||||||
std::string active_label_;
|
std::string active_label_;
|
||||||
int active_selection_;
|
int active_selection_;
|
||||||
InfoVisitor info_;
|
InfoVisitor info_;
|
||||||
@@ -185,6 +186,7 @@ class UserInterface
|
|||||||
SourceController sourcecontrol;
|
SourceController sourcecontrol;
|
||||||
HelperToolbox sessiontoolbox;
|
HelperToolbox sessiontoolbox;
|
||||||
|
|
||||||
|
uint64_t start_time;
|
||||||
bool ctrl_modifier_active;
|
bool ctrl_modifier_active;
|
||||||
bool alt_modifier_active;
|
bool alt_modifier_active;
|
||||||
bool shift_modifier_active;
|
bool shift_modifier_active;
|
||||||
@@ -230,6 +232,8 @@ public:
|
|||||||
void Render();
|
void Render();
|
||||||
// Post-loop termination
|
// Post-loop termination
|
||||||
void Terminate();
|
void Terminate();
|
||||||
|
// Runtime
|
||||||
|
uint64_t Runtime() const;
|
||||||
|
|
||||||
// status querries
|
// status querries
|
||||||
inline bool ctrlModifier() const { return ctrl_modifier_active; }
|
inline bool ctrlModifier() const { return ctrl_modifier_active; }
|
||||||
@@ -255,7 +259,7 @@ protected:
|
|||||||
|
|
||||||
void RenderMetrics (bool* p_open, int* p_corner, int *p_mode);
|
void RenderMetrics (bool* p_open, int* p_corner, int *p_mode);
|
||||||
void RenderPreview();
|
void RenderPreview();
|
||||||
void RenderHistory();
|
void RenderTimer();
|
||||||
void RenderShaderEditor();
|
void RenderShaderEditor();
|
||||||
int RenderViewNavigator(int* shift);
|
int RenderViewNavigator(int* shift);
|
||||||
void RenderAbout(bool* p_open);
|
void RenderAbout(bool* p_open);
|
||||||
|
|||||||
@@ -64,10 +64,10 @@
|
|||||||
|
|
||||||
#define IMGUI_TITLE_MAINWINDOW ICON_FA_CIRCLE_NOTCH " vimix"
|
#define IMGUI_TITLE_MAINWINDOW ICON_FA_CIRCLE_NOTCH " vimix"
|
||||||
#define IMGUI_TITLE_MEDIAPLAYER ICON_FA_PLAY_CIRCLE " Player"
|
#define IMGUI_TITLE_MEDIAPLAYER ICON_FA_PLAY_CIRCLE " Player"
|
||||||
#define IMGUI_TITLE_HISTORY ICON_FA_HISTORY " History"
|
#define IMGUI_TITLE_TIMER ICON_FA_CLOCK " Timer"
|
||||||
#define IMGUI_TITLE_LOGS ICON_FA_LIST " Logs"
|
#define IMGUI_TITLE_LOGS ICON_FA_LIST " Logs"
|
||||||
#define IMGUI_TITLE_HELP ICON_FA_LIFE_RING " Help"
|
#define IMGUI_TITLE_HELP ICON_FA_LIFE_RING " Help"
|
||||||
#define IMGUI_TITLE_TOOLBOX ICON_FA_WRENCH " Development Toolbox"
|
#define IMGUI_TITLE_TOOLBOX ICON_FA_HAMSA " Guru Toolbox"
|
||||||
#define IMGUI_TITLE_SHADEREDITOR ICON_FA_CODE " Code Editor"
|
#define IMGUI_TITLE_SHADEREDITOR ICON_FA_CODE " Code Editor"
|
||||||
#define IMGUI_TITLE_PREVIEW ICON_FA_DESKTOP " Ouput"
|
#define IMGUI_TITLE_PREVIEW ICON_FA_DESKTOP " Ouput"
|
||||||
#define IMGUI_TITLE_DELETE ICON_FA_BROOM " Delete?"
|
#define IMGUI_TITLE_DELETE ICON_FA_BROOM " Delete?"
|
||||||
|
|||||||
4
main.cpp
4
main.cpp
@@ -85,13 +85,13 @@ int main(int argc, char *argv[])
|
|||||||
/// lock to inform an instance is running
|
/// lock to inform an instance is running
|
||||||
Settings::Lock();
|
Settings::Lock();
|
||||||
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
/// CONNECTION INIT
|
/// CONNECTION INIT
|
||||||
///
|
///
|
||||||
if ( !Connection::manager().init() )
|
if ( !Connection::manager().init() )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
///
|
||||||
/// METRONOME INIT
|
/// METRONOME INIT
|
||||||
///
|
///
|
||||||
if ( !Metronome::manager().init() )
|
if ( !Metronome::manager().init() )
|
||||||
@@ -162,7 +162,7 @@ int main(int argc, char *argv[])
|
|||||||
///
|
///
|
||||||
/// Settings
|
/// Settings
|
||||||
///
|
///
|
||||||
Settings::Save();
|
Settings::Save(UserInterface::manager().Runtime());
|
||||||
|
|
||||||
/// ok
|
/// ok
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user