Browse Source

Change timestamps from int64_t to double, and define epoch as when `system::init()` is called.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
7efd063392
12 changed files with 101 additions and 55 deletions
  1. +5
    -5
      include/engine/Engine.hpp
  2. +2
    -2
      include/midi.hpp
  3. +5
    -4
      include/system.hpp
  4. +2
    -2
      src/core/CV_CC.cpp
  5. +2
    -2
      src/core/CV_Gate.cpp
  6. +11
    -12
      src/engine/Engine.cpp
  7. +4
    -4
      src/logger.cpp
  8. +2
    -2
      src/midi.cpp
  9. +6
    -6
      src/patch.cpp
  10. +6
    -4
      src/rtmidi.cpp
  11. +51
    -12
      src/system.cpp
  12. +5
    -0
      standalone/main.cpp

+ 5
- 5
include/engine/Engine.hpp View File

@@ -50,20 +50,20 @@ struct Engine {
/** Returns the estimated timestamp corresponding to the current frame, based on the timestamp of when step() was last called.
Calculated by `stepTime + framesSinceStep / sampleRate`.
*/
int64_t getFrameTime();
double getFrameTime();
/** Returns the frame when step() was last called.
*/
int64_t getStepFrame();
/** Returns the timestamp in nanoseconds when step() was last called.
/** Returns the timestamp in seconds when step() was last called.
*/
int64_t getStepTime();
double getStepTime();
/** Returns the total number of frames in the current step() call.
*/
int getStepFrames();
/** Returns the total time that step() is advancing, in nanoseconds.
/** Returns the total time that step() is advancing, in seconds.
Calculated by `stepFrames / sampleRate`.
*/
int64_t getStepDuration();
double getStepDuration();

// Modules
size_t getNumModules();


+ 2
- 2
include/midi.hpp View File

@@ -20,8 +20,8 @@ namespace midi {
struct Message {
/** Initialized to 3 empty bytes. */
std::vector<uint8_t> bytes;
/** Timestamp of MIDI message in nanoseconds. Negative if not set. */
int64_t timestamp = -1;
/** Timestamp of MIDI message in nanoseconds. NAN if not set. */
double timestamp = NAN;

Message() : bytes(3) {}



+ 5
- 4
include/system.hpp View File

@@ -131,11 +131,10 @@ void setThreadName(const std::string& name);

/** Returns the caller's human-readable stack trace with "\n"-separated lines. */
std::string getStackTrace();
/** Returns the current number of nanoseconds since the epoch.
The goal of this function is to give the most precise (fine-grained) time available on the OS for benchmarking purposes, while being fast to compute.
The epoch is undefined. Do not use this function to get absolute time, as it is different on each OS.
/** Returns the number of seconds since application launch.
The goal of this function is to give the most precise (fine-grained) time differences available on the OS for benchmarking purposes, while being fast to compute.
*/
int64_t getNanoseconds();
double getTime();
std::string getOperatingSystemInfo();

// Applications
@@ -152,6 +151,8 @@ The launched process will continue running if the current process is closed.
*/
void runProcessDetached(const std::string& path);

void init();


} // namespace system
} // namespace rack

+ 2
- 2
src/core/CV_CC.cpp View File

@@ -7,7 +7,7 @@ namespace core {

struct CCMidiOutput : midi::Output {
int lastValues[128];
int64_t timestamp = -1;
double timestamp = 0.0;

CCMidiOutput() {
reset();
@@ -33,7 +33,7 @@ struct CCMidiOutput : midi::Output {
sendMessage(m);
}

void setTimestamp(int64_t timestamp) {
void setTimestamp(double timestamp) {
this->timestamp = timestamp;
}
};


+ 2
- 2
src/core/CV_Gate.cpp View File

@@ -8,7 +8,7 @@ namespace core {
struct GateMidiOutput : midi::Output {
int vels[128];
bool lastGates[128];
int64_t timestamp = -1;
double timestamp = 0.0;

GateMidiOutput() {
reset();
@@ -62,7 +62,7 @@ struct GateMidiOutput : midi::Output {
lastGates[note] = gate;
}

void setTimestamp(int64_t timestamp) {
void setTimestamp(double timestamp) {
this->timestamp = timestamp;
}
};


+ 11
- 12
src/engine/Engine.cpp View File

@@ -198,7 +198,7 @@ struct Engine::Internal {
float sampleTime = 0.f;
int64_t frame = 0;
int64_t stepFrame = 0;
int64_t stepTime = 0;
double stepTime = 0.0;
int stepFrames = 0;
Module* primaryModule = NULL;

@@ -338,9 +338,9 @@ static void Engine_stepModulesWorker(Engine* that, int threadId) {
Module* module = internal->modules[i];

// Start CPU timer
int64_t startTime;
double startTime;
if (cpuMeter) {
startTime = system::getNanoseconds();
startTime = system::getTime();
}

// Step module
@@ -351,8 +351,8 @@ static void Engine_stepModulesWorker(Engine* that, int threadId) {

// Stop CPU timer
if (cpuMeter) {
int64_t endTime = system::getNanoseconds();
float duration = (endTime - startTime) * 1e-9f;
double endTime = system::getTime();
float duration = (endTime - startTime) / 1e9;

// Smooth CPU time
const float cpuTau = 2.f /* seconds */;
@@ -564,7 +564,7 @@ void Engine::step(int frames) {
random::init();

internal->stepFrame = internal->frame;
internal->stepTime = system::getNanoseconds();
internal->stepTime = system::getTime();
internal->stepFrames = frames;

// Set sample rate
@@ -635,9 +635,9 @@ int64_t Engine::getFrame() {
}


int64_t Engine::getFrameTime() {
double Engine::getFrameTime() {
double timeSinceStep = (internal->frame - internal->stepFrame) * internal->sampleTime;
return internal->stepTime + int64_t(timeSinceStep * 1e9);
return internal->stepTime + timeSinceStep;
}


@@ -646,7 +646,7 @@ int64_t Engine::getStepFrame() {
}


int64_t Engine::getStepTime() {
double Engine::getStepTime() {
return internal->stepTime;
}

@@ -656,9 +656,8 @@ int Engine::getStepFrames() {
}


int64_t Engine::getStepDuration() {
double duration = internal->stepFrames * internal->sampleTime;
return int64_t(duration * 1e9);
double Engine::getStepDuration() {
return internal->stepFrames * internal->sampleTime;
}




+ 4
- 4
src/logger.cpp View File

@@ -12,12 +12,12 @@ namespace logger {


static FILE* outputFile = NULL;
static int64_t startTime = 0;
static double startTime = 0.0;
static std::mutex logMutex;


void init() {
startTime = system::getNanoseconds();
startTime = system::getTime();
// Don't open a file in development mode.
if (settings::devMode) {
outputFile = stderr;
@@ -64,8 +64,8 @@ static void logVa(Level level, const char* filename, int line, const char* func,
if (!outputFile)
return;

int64_t nowTime = system::getNanoseconds();
double duration = (nowTime - startTime) / 1e9;
double nowTime = system::getTime();
double duration = nowTime - startTime;
if (outputFile == stderr)
std::fprintf(outputFile, "\x1B[%dm", levelColors[level]);
std::fprintf(outputFile, "[%.03f %s %s:%d %s] ", duration, levelLabels[level], filename, line, func);


+ 2
- 2
src/midi.cpp View File

@@ -30,8 +30,8 @@ void InputDevice::unsubscribe(Input* input) {
void InputDevice::onMessage(const Message &message) {
// Set timestamp to now if unset
Message msg = message;
if (msg.timestamp < 0)
msg.timestamp = system::getNanoseconds();
if (msg.timestamp == 0.0)
msg.timestamp = system::getTime();

for (Input* input : subscribed) {
// We're probably in the MIDI driver's thread, so set the Rack context.


+ 6
- 6
src/patch.cpp View File

@@ -69,11 +69,11 @@ void PatchManager::save(std::string path) {
// Take screenshot (disabled because there is currently no way to quickly view them on any OS or website.)
// APP->window->screenshot(system::join(asset::autosavePath, "screenshot.png"));

uint64_t startTime = system::getNanoseconds();
double startTime = system::getTime();
// Set compression level to 1 so that a 500MB/s SSD is almost bottlenecked
system::archiveFolder(path, asset::autosavePath, 1);
uint64_t endTime = system::getNanoseconds();
INFO("Archived patch in %lf seconds", (endTime - startTime) / 1e9);
double endTime = system::getTime();
INFO("Archived patch in %lf seconds", (endTime - startTime));
}


@@ -222,10 +222,10 @@ void PatchManager::load(std::string path) {
}
else {
// Extract the .vcv file as a .tar.zst archive.
uint64_t startTime = system::getNanoseconds();
double startTime = system::getTime();
system::unarchiveToFolder(path, asset::autosavePath);
uint64_t endTime = system::getNanoseconds();
INFO("Unarchived patch in %lf seconds", (endTime - startTime) / 1e9);
double endTime = system::getTime();
INFO("Unarchived patch in %lf seconds", (endTime - startTime));
}

loadAutosave();


+ 6
- 4
src/rtmidi.cpp View File

@@ -148,12 +148,14 @@ struct RtMidiOutputDevice : midi::OutputDevice {
else {
// Get earliest message
const midi::Message& message = messageQueue.top();
int64_t duration = message.timestamp - system::getNanoseconds();
double duration = message.timestamp - system::getTime();

// If we need to wait, release the lock and wait for the timeout, or if the CV is notified.
// This correctly handles MIDI messages with no timestamp, because duration will be negative.
if ((duration > 0) && cv.wait_for(lock, std::chrono::nanoseconds(duration)) != std::cv_status::timeout)
continue;
// This correctly handles MIDI messages with no timestamp, because duration will be NAN.
if (duration > 0) {
if (cv.wait_for(lock, std::chrono::duration<double>(duration)) != std::cv_status::timeout)
continue;
}

// Send and remove from queue
sendMessageNow(message);


+ 51
- 12
src/system.cpp View File

@@ -18,6 +18,8 @@
#if defined ARCH_MAC
#include <mach/mach_init.h>
#include <mach/thread_act.h>
#include <mach/clock.h>
#include <mach/mach.h>
#endif

#if defined ARCH_WIN
@@ -526,30 +528,62 @@ std::string getStackTrace() {
}


int64_t getNanoseconds() {
#if defined ARCH_WIN
static int64_t startCounter = 0;
static double counterTime = 0.0;
#endif
#if defined ARCH_LIN || defined ARCH_MAC
static int64_t startTime = 0;
#endif

static void initTime() {
#if defined ARCH_WIN
assert(startCounter == 0);
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
startCounter = counter.QuadPart;

LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
// TODO Check if this is always an integer factor on all CPUs
int64_t nsPerTick = 1000000000LL / frequency.QuadPart;
int64_t time = counter.QuadPart * nsPerTick;
return time;
counterTime = 1.0 / frequency.QuadPart;
#endif
#if defined ARCH_LIN
assert(startTime == 0);
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
startTime = int64_t(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
#endif
#if defined ARCH_MAC
assert(startTime == 0);
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
startTime = int64_t(mts.tv_sec) * 1000000000LL + mts.tv_nsec;
#endif
}

double getTime() {
#if defined ARCH_WIN
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
return (counter.QuadPart - startCounter) * counterTime;
#endif
#if defined ARCH_LIN
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
int64_t time = int64_t(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
return time;
return (time - startTime) / 1e9;
#endif
#if defined ARCH_MAC
using clock = std::chrono::high_resolution_clock;
using time_point = std::chrono::time_point<clock>;
time_point now = clock::now();
using duration = std::chrono::duration<int64_t, std::nano>;
duration d = now.time_since_epoch();
return d.count();
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
int64_t time = int64_t(mts.tv_sec) * 1000000000LL + mts.tv_nsec;
return (time - startTime) / 1e9;
#endif
}

@@ -621,5 +655,10 @@ void runProcessDetached(const std::string& path) {
}


void init() {
initTime();
}


} // namespace system
} // namespace rack

+ 5
- 0
standalone/main.cpp View File

@@ -108,10 +108,15 @@ int main(int argc, char* argv[]) {
}

// Initialize environment
system::init();
asset::init();
bool loggerWasTruncated = logger::isTruncated();
logger::init();

for (int i = 0; i < 100; i++)
DEBUG("%lf", system::getTime() * 1e9);
exit(0);

// We can now install a signal handler and log the output
if (!settings::devMode) {
signal(SIGABRT, fatalSignalHandler);


Loading…
Cancel
Save