Initial implementation of Metronome from Ableton LINK

Added submodule for github ableton link, and compiled draft of Metronome class.
This commit is contained in:
Bruno Herbelin
2021-11-13 00:13:50 +01:00
parent a6ba694fbd
commit 8e3bf786c0
6 changed files with 208 additions and 1 deletions

3
.gitmodules vendored
View File

@@ -19,3 +19,6 @@
[submodule "ext/glm"]
path = ext/glm
url = https://github.com/g-truc/glm.git
[submodule "ext/link"]
path = ext/link
url = https://github.com/Ableton/link.git

View File

@@ -137,6 +137,13 @@ set(BUILD_STATIC_LIBS ON)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ext/glm)
message(STATUS "Compiling 'GLM' OpenGL mathematics https://glm.g-truc.net -- ${CMAKE_CURRENT_SOURCE_DIR}/ext/glm")
#
# Ableton LINK
#
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ext/link)
include(${CMAKE_CURRENT_SOURCE_DIR}/ext/link/AbletonLinkConfig.cmake)
message(STATUS "Compiling Ableton 'Link' https://github.com/Ableton/link -- ${CMAKE_CURRENT_SOURCE_DIR}/ext/link")
#
# GLAD
#
@@ -254,6 +261,7 @@ include_directories(
${STB_INCLUDE_DIR}
${DIRENT_INCLUDE_DIR}
${OSCPACK_INCLUDE_DIR}
${link_HEADERS}
)
link_directories(
@@ -328,6 +336,7 @@ set(VMIX_SRCS
Connection.cpp
ActionManager.cpp
Overlay.cpp
Metronome.cpp
)
@@ -509,6 +518,7 @@ target_link_libraries(${VMIX_BINARY} LINK_PRIVATE
${GSTREAMER_GL_LIBRARY}
Threads::Threads
PNG::PNG
Ableton::Link
${PLATFORM_LIBS}
)

155
Metronome.cpp Normal file
View File

@@ -0,0 +1,155 @@
#include <algorithm>
#include <atomic>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <thread>
#include <ableton/Link.hpp>
#include "Metronome.h"
namespace ableton
{
class Engine
{
public:
Engine(Link& link)
: mLink(link)
, mQuantum(4.)
{
}
void startPlaying()
{
auto sessionState = mLink.captureAppSessionState();
sessionState.setIsPlayingAndRequestBeatAtTime(true, now(), 0., mQuantum);
mLink.commitAppSessionState(sessionState);
}
void stopPlaying()
{
auto sessionState = mLink.captureAppSessionState();
sessionState.setIsPlaying(false, now());
mLink.commitAppSessionState(sessionState);
}
bool isPlaying() const
{
return mLink.captureAppSessionState().isPlaying();
}
double beatTime() const
{
auto sessionState = mLink.captureAppSessionState();
return sessionState.beatAtTime(now(), mQuantum);
}
void setTempo(double tempo)
{
auto sessionState = mLink.captureAppSessionState();
sessionState.setTempo(tempo, now());
mLink.commitAppSessionState(sessionState);
}
double quantum() const
{
return mQuantum;
}
void setQuantum(double quantum)
{
mQuantum = quantum;
}
bool isStartStopSyncEnabled() const
{
return mLink.isStartStopSyncEnabled();
}
void setStartStopSyncEnabled(bool enabled)
{
mLink.enableStartStopSync(enabled);
}
private:
std::chrono::microseconds now() const
{
return mLink.clock().micros();
}
Link& mLink;
double mQuantum;
};
struct State
{
std::atomic<bool> running;
Link link;
Engine engine;
double beats, phase, tempo;
State() : running(true), link(120.), engine(link), beats(0.), phase(4.), tempo(120.)
{
}
};
void update(State& state)
{
state.link.enable(true);
while (state.running)
{
const auto time = state.link.clock().micros();
auto sessionState = state.link.captureAppSessionState();
state.beats = sessionState.beatAtTime(time, state.engine.quantum());
state.phase = sessionState.phaseAtTime(time, state.engine.quantum());
state.tempo = sessionState.tempo();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
state.link.enable(false);
}
} // namespace ableton
ableton::State link_state_;
Metronome::Metronome()
{
}
bool Metronome::init()
{
std::thread(ableton::update, std::ref(link_state_)).detach();
return link_state_.running;
}
void Metronome::terminate()
{
link_state_.running = false;
}
double Metronome::beats() const
{
return link_state_.beats;
}
double Metronome::phase() const
{
return link_state_.phase;
}
double Metronome::tempo() const
{
return link_state_.tempo;
}

27
Metronome.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef METRONOME_H
#define METRONOME_H
class Metronome
{
// Private Constructor
Metronome();
Metronome(Metronome const& copy) = delete;
Metronome& operator=(Metronome const& copy) = delete;
public:
static Metronome& manager ()
{
// The only instance
static Metronome _instance;
return _instance;
}
bool init ();
void terminate();
};
#endif // METRONOME_H

1
ext/link Submodule

Submodule ext/link added at 14f6cc99ac

View File

@@ -28,7 +28,7 @@
#include "RenderingManager.h"
#include "UserInterfaceManager.h"
#include "Connection.h"
#include "Metronome.h"
#if defined(APPLE)
extern "C"{
@@ -85,12 +85,18 @@ int main(int argc, char *argv[])
/// lock to inform an instance is running
Settings::Lock();
///
///
/// CONNECTION INIT
///
if ( !Connection::manager().init() )
return 1;
/// METRONOME INIT
///
if ( !Metronome::manager().init() )
return 1;
///
/// RENDERING INIT
///
@@ -140,6 +146,11 @@ int main(int argc, char *argv[])
///
Rendering::manager().terminate();
///
/// METRONOME TERMINATE
///
Metronome::manager().terminate();
///
/// CONNECTION TERMINATE
///