diff options
author | Hans-Christoph Steiner <eighthave@users.sourceforge.net> | 2005-11-10 05:52:11 +0000 |
---|---|---|
committer | Hans-Christoph Steiner <eighthave@users.sourceforge.net> | 2005-11-10 05:52:11 +0000 |
commit | ceac394c2133d44e81db2eb633ff54a9ad6ce7c5 (patch) | |
tree | adc534407af80a976263c907897907cb13ef1c82 /src/midiio/src/SigTimer.cpp |
This commit was generated by cvs2svn to compensate for changes in r3865,svn2git-root
which included commits to RCS files with non-trunk default branches.
svn path=/trunk/extensions/gripd/; revision=3866
Diffstat (limited to 'src/midiio/src/SigTimer.cpp')
-rw-r--r-- | src/midiio/src/SigTimer.cpp | 498 |
1 files changed, 498 insertions, 0 deletions
diff --git a/src/midiio/src/SigTimer.cpp b/src/midiio/src/SigTimer.cpp new file mode 100644 index 0000000..5786098 --- /dev/null +++ b/src/midiio/src/SigTimer.cpp @@ -0,0 +1,498 @@ +// +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Thanks to: Erik Neuenschwander <erikn@leland.stanford.edu> +// for Windows 95 assembly code for Pentium clock cycles. +// Ozgur Izmirli <ozgur@ccrma.stanford.edu> +// for concept of periodic timer. +// Creation Date: Mon Oct 13 11:34:57 GMT-0800 1997 +// Last Modified: Tue Feb 10 21:05:19 GMT-0800 1998 +// Last Modified: Sat Sep 19 15:56:48 PDT 1998 +// Last Modified: Mon Feb 22 04:44:25 PST 1999 +// Last Modified: Sun Nov 28 12:39:39 PST 1999 (added adjustPeriod()) +// Filename: .../sig/code/control/SigTimer/SigTimer.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/SigTimer.cpp +// Syntax: C++ +// +// Description: This class can only be used on Motorola Pentinum 75 Mhz +// chips or better because the timing information is +// extracted from the clock cycle count from a register +// on the CPU itself. This class will estimate the +// speed of the computer, but it would be better if there +// was a way of finding out the speed from some function. +// This class is used primarily for timing of MIDI input +// and output at a millisecond resolution. +// + + +#include "SigTimer.h" +#include <iostream> +#include <stdlib.h> + + +// get Sleep or usleep function definition for measureCpu function: +#ifdef VISUAL + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + #undef WIN32_LEAN_AND_MEAN +#else + #include <unistd.h> +#endif + + +// declare static variables +int64bits SigTimer::globalOffset = 0; +int SigTimer::cpuSpeed = 0; // in cycles per second + + + +////////////////////////////// +// +// SigTimer::SigTimer +// + +SigTimer::SigTimer(void) { + if (globalOffset == 0) { // coordinate offset between timers + globalOffset = clockCycles(); + } + if (cpuSpeed <= 0) { // initialize CPU speed value + cpuSpeed = measureCpuSpeed(1); + if (cpuSpeed <= 0) { + cpuSpeed = 100000000; + } + } + + offset = globalOffset; // initialize the start time of timer + ticksPerSecond = 1000; // default of 1000 ticks per second + period = 1000.0; // default period of once per second +} + + +SigTimer::SigTimer(int aSpeed) { + if (globalOffset == 0) { + globalOffset = clockCycles(); + } + cpuSpeed = aSpeed; + + offset = globalOffset; + ticksPerSecond = 1000; + period = 1000.0; // default period of once per second +} + + +SigTimer::SigTimer(SigTimer& aTimer) { + offset = aTimer.offset; + ticksPerSecond = aTimer.ticksPerSecond; + period = aTimer.period; +} + + + +////////////////////////////// +// +// SigTimer::~SigTimer +// + +SigTimer::~SigTimer() { + // do nothing +} + + + +////////////////////////////// +// +// SigTimer::adjustPeriod -- adjust the period of the timer. +// + +void SigTimer::adjustPeriod(double periodDelta) { + offset -= (int64bits)(getCpuSpeed() * getPeriod() * periodDelta / + getTicksPerSecond()); +} + + + +////////////////////////////// +// +// SigTimer::clockCycles -- returns the number of clock cycles since last reboot +// HARDWARE DEPENDENT -- currently for Pentiums only. +// static function. +// + + +int64bits SigTimer::clockCycles() { +#ifndef VISUAL + int64bits output; + + // For Pentiums, you can get the number of clock cycles elapsed + // since the last reboot with the following assembler code: + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (output)); + +#else + int64bits output; + unsigned long high_end, low_end; + __asm { + __asm _emit 0x0f __asm _emit 0x31 + mov high_end, edx + mov low_end, eax + } + output = high_end; + output = output << 32; + output += low_end; +#endif + + return output; +} + + + +////////////////////////////// +// +// SigTimer::expired -- returns the integral number of periods +// That have passed since the last update or reset. +// See getPeriodCount which returns a floating point +// count of the period position. +// + + +int SigTimer::expired(void) const { + return (int)(getTime()/period); +} + + + +////////////////////////////// +// +// SigTimer::getCpuSpeed -- returns the CPU speed of the computer. +// (static function) +// + +int SigTimer::getCpuSpeed(void) { + return cpuSpeed; +} + + + +////////////////////////////// +// +// SigTimer::getPeriod -- returns the timing period of the timer, +// if the timer is being used as a periodic timer. +// + +double SigTimer::getPeriod(void) const { + return period; +} + + + +////////////////////////////// +// +// SigTimer::getPeriodCount -- returns the current period count +// of the timer as a double. Similar in behavior to expired +// function but lists the current fraction of a period. +// + +double SigTimer::getPeriodCount(void) const { + return (double)getTime()/period; +} + + + +////////////////////////////// +// +// SigTimer::getTempo -- returns the current tempo in terms +// of beats (ticks) per minute. +// + +double SigTimer::getTempo(void) const { + return getTicksPerSecond() * 60.0 / getPeriod(); +} + + + +////////////////////////////// +// +// SigTimer::getTicksPerSecond -- return the number of ticks per +// second. +// + +int SigTimer::getTicksPerSecond(void) const { + return ticksPerSecond; +} + + + +////////////////////////////// +// +// SigTimer::getTime -- returns time in milliseconds by default. +// time can be altered to be in some other unit of time +// by using the setTicksPerSecond function. +// (Default is 1000 ticks per second.) +// + +int SigTimer::getTime(void) const { + return (int)((clockCycles()-offset)/getFactor()); +} + + + +////////////////////////////// +// +// SigTimer::getTimeInSeconds +// + +double SigTimer::getTimeInSeconds(void) const { + return ((clockCycles()-offset)/(double)cpuSpeed); +} + + + +////////////////////////////// +// +// SigTimer::getTimeInTicks +// + +int SigTimer::getTimeInTicks(void) const { + return (int)((clockCycles()-offset)/getFactor()); +} + + + +////////////////////////////// +// +// SigTimer::measureCpuSpeed -- returns the number of clock cycles in +// one second. Accuracy to about +/- 5%. +// default value: quantize = 0. +// + +int SigTimer::measureCpuSpeed(int quantize) { + int64bits a, b; + a = clockCycles(); + #ifdef VISUAL + Sleep(1000/4); + #else + usleep(1000000/4); + #endif + b = clockCycles(); + + int output = (int)(4*(b-a-140100-450000)); + + if (quantize) { + // quantize to a known computer CPU speed + if (output < 78000000) { + output = 75000000; + } else if (output < 95000000) { + output = 90000000; + } else if (output < 110000000) { + output = 100000000; + } else if (output < 140000000) { + output = 133000000; + } else if (output < 155000000) { + output = 150000000; + } else if (output < 180000000) { + output = 166000000; + } else if (output < 215000000) { + output = 200000000; + } else if (output < 250000000) { + output = 233000000; + } else if (output < 280000000) { + output = 266000000; + } else if (output < 325000000) { + output = 300000000; + } else if (output < 375000000) { + output = 350000000; + } else if (output < 425000000) { + output = 400000000; + } else { + output = output; + } + } // end if quantize + + return output; +} + + + +////////////////////////////// +// +// SigTimer::reset -- set the timer to 0. +// + +void SigTimer::reset(void) { + offset = clockCycles(); +} + + + +////////////////////////////// +// +// SigTimer::setCpuSpeed -- You can also vary the CPU speed here to cause the +// getTime function to output different units of time, but the +// setTicksPerSecond is a more appropriate place to do such a thing. +// + +void SigTimer::setCpuSpeed(int aSpeed) { + if (aSpeed <= 0) { + std::cerr << "Error: Cannot set the cpu speed to be negative: " + << aSpeed << std::endl; + exit(1); + } + cpuSpeed = aSpeed; +} + + + +////////////////////////////// +// +// SigTimer::setPeriod -- sets the period length of the timer. +// input value cannot be less than 1.0. +// + +void SigTimer::setPeriod(double aPeriod) { + if (aPeriod < 1.0) { + std::cerr << "Error: period too small: " << aPeriod << std::endl; + exit(1); + } + period = aPeriod; +} + + + +////////////////////////////// +// +// SigTimer::setPeriodCount -- adjusts the offset time according +// to the current period to match the specified period count. +// + +void SigTimer::setPeriodCount(double aCount) { + offset = (int64bits)(clockCycles() - aCount * getPeriod() * + getCpuSpeed() / getTicksPerSecond()); +} + + + +////////////////////////////// +// +// SigTimer::setTempo -- sets the period length in terms of +// beats per minute. +// + +void SigTimer::setTempo(double beatsPerMinute) { + if (beatsPerMinute < 1.0) { + std::cerr << "Error: tempo is too slow: " << beatsPerMinute << std::endl; + exit(1); + } + double count = getPeriodCount(); + period = getTicksPerSecond() * 60.0 / beatsPerMinute; + setPeriodCount(count); +} + + + +////////////////////////////// +// +// SigTimer::setTicksPerSecond +// + +void SigTimer::setTicksPerSecond(int aTickRate) { + if (aTickRate <= 0) { + std::cerr << "Error: Cannot set the tick rate to be negative: " + << aTickRate << std::endl; + exit(1); + } + ticksPerSecond = aTickRate; +} + + + +////////////////////////////// +// +// SigTimer::start +// + +void SigTimer::start(void) { + reset(); +} + + + +////////////////////////////// +// +// SigTimer::sync +// + +void SigTimer::sync(SigTimer& aTimer) { + offset = aTimer.offset; +} + + + +////////////////////////////// +// +// SigTimer::update -- set the timer start to the next period. +// + +void SigTimer::update(void) { + if (getTime() >= getPeriod()) { + offset += (int64bits)(getPeriod() * getFactor()); + } +} + + +// update(int) will do nothing if the periodCount is greater than +// than the expired period count + +void SigTimer::update(int periodCount) { + if (periodCount > expired()) { + return; + } else { + offset += (int64bits)(getPeriod() * getFactor() * periodCount); + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// protected functions: +// + + +////////////////////////////// +// +// SigTimer::getFactor -- +// + +double SigTimer::getFactor(void) const { + return (double)((double)getCpuSpeed()/(double)getTicksPerSecond()); +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Miscellaneous timing functions are located here untill a better +// place can be found: +// + +void millisleep(int milliseconds) { + #ifdef VISUAL + Sleep(milliseconds); + #else + usleep( milliseconds * 1000); + #endif +} + + +void millisleep(float milliseconds) { + #ifdef VISUAL + // cannot convert to microseconds in Visual C++ yet. + // Tell me how and I'll fix the following line + Sleep((unsigned long)milliseconds); + #else + usleep((int)(milliseconds * 1000.0)); + #endif +} + + + + +// md5sum: b35e9e6a8d6fd16636d7fca5d565f284 - SigTimer.cpp =css= 20030102 |