summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--raul/EventRingBuffer.hpp (renamed from raul/StampedChunkRingBuffer.hpp)40
-rw-r--r--raul/MIDISink.hpp4
-rw-r--r--raul/Makefile.am21
-rw-r--r--raul/Quantizer.hpp9
-rw-r--r--raul/SMFReader.hpp11
-rw-r--r--raul/SMFWriter.hpp23
-rw-r--r--raul/TimeSlice.hpp71
-rw-r--r--raul/TimeStamp.hpp240
-rw-r--r--raul/types.hpp35
-rw-r--r--src/SMFReader.cpp10
-rw-r--r--src/SMFWriter.cpp47
-rw-r--r--src/TimeSlice.cpp2
-rw-r--r--tests/midi_ringbuffer_test.cpp11
-rw-r--r--tests/quantize_test.cpp13
-rw-r--r--tests/smf_test.cpp8
-rw-r--r--tests/time_test.cpp16
16 files changed, 405 insertions, 156 deletions
diff --git a/raul/StampedChunkRingBuffer.hpp b/raul/EventRingBuffer.hpp
index b4f9371..9a28084 100644
--- a/raul/StampedChunkRingBuffer.hpp
+++ b/raul/EventRingBuffer.hpp
@@ -15,63 +15,63 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef RAUL_STAMPED_CHUNK_RING_BUFFER_HPP
-#define RAUL_STAMPED_CHUNK_RING_BUFFER_HPP
+#ifndef RAUL_EVENT_RING_BUFFER_HPP
+#define RAUL_EVENT_RING_BUFFER_HPP
#include <cassert>
#include <algorithm>
#include <glib.h>
-#include <raul/types.hpp>
#include <raul/RingBuffer.hpp>
+#include <raul/TimeStamp.hpp>
namespace Raul {
-/** A RingBuffer of timestamped binary "chunks".
+/** A RingBuffer of events (generic time-stamped binary "blobs").
*
* This packs a timestamp, size, and size bytes of data flat into the buffer.
* Useful for MIDI events, OSC messages, etc.
*/
-class StampedChunkRingBuffer : private Raul::RingBuffer<Byte> {
+class EventRingBuffer : private Raul::RingBuffer<uint8_t> {
public:
- /** @param size Size in bytes.
+ /** @param capacity Ringbuffer capacity in bytes.
*/
- StampedChunkRingBuffer(size_t size)
- : RingBuffer<Byte>(size)
+ EventRingBuffer(size_t capacity)
+ : RingBuffer<uint8_t>(capacity)
{}
size_t capacity() const { return _size; }
- size_t write(TickTime time, size_t size, const Byte* buf);
- bool read(TickTime* time, size_t* size, Byte* buf);
+ size_t write(TimeStamp time, size_t size, const uint8_t* buf);
+ bool read(TimeStamp* time, size_t* size, uint8_t* buf);
};
inline bool
-StampedChunkRingBuffer::read(TickTime* time, size_t* size, Byte* buf)
+EventRingBuffer::read(TimeStamp* time, size_t* size, uint8_t* buf)
{
- bool success = RingBuffer<Byte>::full_read(sizeof(TickTime), (Byte*)time);
+ bool success = RingBuffer<uint8_t>::full_read(sizeof(TimeStamp), (uint8_t*)time);
if (success)
- success = RingBuffer<Byte>::full_read(sizeof(size_t), (Byte*)size);
+ success = RingBuffer<uint8_t>::full_read(sizeof(size_t), (uint8_t*)size);
if (success)
- success = RingBuffer<Byte>::full_read(*size, buf);
+ success = RingBuffer<uint8_t>::full_read(*size, buf);
return success;
}
inline size_t
-StampedChunkRingBuffer::write(TickTime time, size_t size, const Byte* buf)
+EventRingBuffer::write(TimeStamp time, size_t size, const uint8_t* buf)
{
assert(size > 0);
- if (write_space() < (sizeof(TickTime) + sizeof(size_t) + size)) {
+ if (write_space() < (sizeof(TimeStamp) + sizeof(size_t) + size)) {
return 0;
} else {
- RingBuffer<Byte>::write(sizeof(TickTime), (Byte*)&time);
- RingBuffer<Byte>::write(sizeof(size_t), (Byte*)&size);
- RingBuffer<Byte>::write(size, buf);
+ RingBuffer<uint8_t>::write(sizeof(TimeStamp), (uint8_t*)&time);
+ RingBuffer<uint8_t>::write(sizeof(size_t), (uint8_t*)&size);
+ RingBuffer<uint8_t>::write(size, buf);
return size;
}
}
@@ -79,5 +79,5 @@ StampedChunkRingBuffer::write(TickTime time, size_t size, const Byte* buf)
} // namespace Raul
-#endif // RAUL_STAMPED_CHUNK_RING_BUFFER_HPP
+#endif // RAUL_EVENT_RING_BUFFER_HPP
diff --git a/raul/MIDISink.hpp b/raul/MIDISink.hpp
index e30dad2..05c8747 100644
--- a/raul/MIDISink.hpp
+++ b/raul/MIDISink.hpp
@@ -19,7 +19,7 @@
#define RAUL_MIDI_SINK_HPP
#include <stdexcept>
-#include <raul/TimeSlice.hpp>
+#include <raul/TimeStamp.hpp>
#include <raul/Deletable.hpp>
namespace Raul {
@@ -29,7 +29,7 @@ namespace Raul {
*/
class MIDISink : public Deletable {
public:
- virtual void write_event(BeatTime time,
+ virtual void write_event(TimeStamp time,
size_t ev_size,
const uint8_t* ev) throw (std::logic_error) = 0;
};
diff --git a/raul/Makefile.am b/raul/Makefile.am
index eeeb792..6c2661b 100644
--- a/raul/Makefile.am
+++ b/raul/Makefile.am
@@ -3,39 +3,40 @@ raulincludedir = $(includedir)/raul
raulinclude_HEADERS = \
Array.hpp \
Atom.hpp \
- AtomLiblo.hpp \
- AtomRDF.hpp \
AtomicInt.hpp \
AtomicPtr.hpp \
+ AtomLiblo.hpp \
+ AtomRDF.hpp \
Command.hpp \
Deletable.hpp \
DoubleBuffer.hpp \
+ EventRingBuffer.hpp \
JackDriver.hpp \
List.hpp \
ListImpl.hpp \
- MIDISink.hpp \
+ lv2_event.h \
Maid.hpp \
+ midi_events.h \
+ MIDISink.hpp \
Path.hpp \
PathTable.hpp \
Process.hpp \
Quantizer.hpp \
RingBuffer.hpp \
+ Semaphore.hpp \
+ SharedPtr.hpp \
+ Slave.hpp \
SMFReader.hpp \
SMFWriter.hpp \
SRMWQueue.hpp \
SRSWQueue.hpp \
- Semaphore.hpp \
- SharedPtr.hpp \
- Slave.hpp \
- StampedChunkRingBuffer.hpp \
Stateful.hpp \
Table.hpp \
TableImpl.hpp \
Thread.hpp \
TimeSlice.hpp \
- WeakPtr.hpp \
- midi_events.h \
- types.hpp
+ TimeStamp.hpp \
+ WeakPtr.hpp
if WITH_LASH
raulinclude_HEADERS += LashClient.hpp LashServerInterface.hpp LashProject.hpp
diff --git a/raul/Quantizer.hpp b/raul/Quantizer.hpp
index 13a5cb1..0fe9640 100644
--- a/raul/Quantizer.hpp
+++ b/raul/Quantizer.hpp
@@ -19,14 +19,19 @@
#define RAUL_QUANTIZER_HPP
#include <cmath>
+#include <raul/TimeStamp.hpp>
namespace Raul {
class Quantizer {
public:
- inline static double quantize(double q, double value) {
- return (q > 0) ? lrint(value / q) * q : value;
+ inline static TimeStamp quantize(TimeStamp q, TimeStamp t) {
+ assert(q.unit() == t.unit());
+ // FIXME: Precision problem? Should probably stay in discrete domain
+ const double qd = q.to_double();
+ const double td = t.to_double();
+ return TimeStamp(t.unit(), (qd > 0) ? lrint(td / qd) * qd : td);
}
};
diff --git a/raul/SMFReader.hpp b/raul/SMFReader.hpp
index 51ebdc7..7ce6f5b 100644
--- a/raul/SMFReader.hpp
+++ b/raul/SMFReader.hpp
@@ -21,6 +21,7 @@
#include <stdexcept>
#include <string>
#include <inttypes.h>
+#include <raul/TimeStamp.hpp>
namespace Raul {
@@ -38,14 +39,15 @@ public:
bool seek_to_track(unsigned track) throw (std::logic_error);
+ TimeUnit unit() const { return _unit; }
uint16_t type() const { return _type; }
uint16_t ppqn() const { return _ppqn; }
size_t num_tracks() { return _num_tracks; }
- int read_event(size_t buf_len,
- uint8_t* buf,
- uint32_t* ev_size,
- uint32_t* ev_delta_time) throw (std::logic_error);
+ int read_event(size_t buf_len,
+ uint8_t* buf,
+ uint32_t* ev_size,
+ TimeStamp* ev_delta_time) throw (std::logic_error);
void close();
@@ -57,6 +59,7 @@ protected:
std::string _filename;
FILE* _fd;
+ TimeUnit _unit;
uint16_t _type;
uint16_t _ppqn;
uint16_t _num_tracks;
diff --git a/raul/SMFWriter.hpp b/raul/SMFWriter.hpp
index df91909..3661ffd 100644
--- a/raul/SMFWriter.hpp
+++ b/raul/SMFWriter.hpp
@@ -20,6 +20,7 @@
#include <stdexcept>
#include <raul/MIDISink.hpp>
+#include <raul/TimeStamp.hpp>
namespace Raul {
@@ -28,15 +29,15 @@ namespace Raul {
*/
class SMFWriter : public Raul::MIDISink {
public:
- SMFWriter(unsigned short ppqn=1920);
+ SMFWriter(TimeUnit unit);
~SMFWriter();
bool start(const std::string& filename,
- BeatTime start_time=0) throw (std::logic_error);
+ TimeStamp start_time) throw (std::logic_error);
- uint16_t ppqn() const { return _ppqn; }
+ TimeUnit unit() const { return _unit; }
- void write_event(BeatTime time,
+ void write_event(TimeStamp time,
size_t ev_size,
const unsigned char* ev) throw (std::logic_error);
@@ -54,13 +55,13 @@ protected:
void write_chunk(const char id[4], uint32_t length, void* data);
size_t write_var_len(uint32_t val);
- std::string _filename;
- FILE* _fd;
- uint16_t _ppqn;
- Raul::BeatTime _start_time;
- Raul::BeatTime _last_ev_time; ///< Time last event was written relative to _start_time
- uint32_t _track_size;
- uint32_t _header_size; ///< size of SMF header, including MTrk chunk header
+ std::string _filename;
+ FILE* _fd;
+ TimeUnit _unit;
+ Raul::TimeStamp _start_time;
+ Raul::TimeStamp _last_ev_time; ///< Time last event was written relative to _start_time
+ uint32_t _track_size;
+ uint32_t _header_size; ///< size of SMF header, including MTrk chunk header
};
diff --git a/raul/TimeSlice.hpp b/raul/TimeSlice.hpp
index a7f445b..e8570e1 100644
--- a/raul/TimeSlice.hpp
+++ b/raul/TimeSlice.hpp
@@ -21,11 +21,14 @@
#include <cassert>
#include <cmath>
#include <boost/utility.hpp>
-#include <raul/types.hpp>
+#include <raul/TimeStamp.hpp>
+#include <raul/lv2_event.h>
namespace Raul {
+/* FIXME: all the conversion here is wrong now */
+
/** A duration of time, with conversion between tick time and beat time.
*
* This is a slice along a single timeline (ie t=0 in ticks and t=0 in beats
@@ -46,14 +49,14 @@ namespace Raul {
*/
class TimeSlice : public boost::noncopyable {
public:
- TimeSlice(double tick_rate, double bpm)
- : _tick_rate(tick_rate)
+ TimeSlice(uint32_t rate, double bpm)
+ : _tick_rate(rate)
, _beat_rate(60.0/bpm)
- , _start_ticks(0)
- , _length_ticks(0)
- , _start_beats(0)
- , _length_beats(0)
- , _offset_ticks(0)
+ , _start_ticks(Raul::TimeUnit(Raul::TimeUnit::FRAMES, rate), 0, 0)
+ , _length_ticks(TimeUnit(TimeUnit::FRAMES, rate), 0, 0)
+ , _start_beats(TimeUnit(TimeUnit::BEATS, LV2_EVENT_PPQN), 0, 0)
+ , _length_beats(TimeUnit(TimeUnit::BEATS, LV2_EVENT_PPQN), 0, 0)
+ , _offset_ticks(TimeUnit(TimeUnit::FRAMES, rate), 0, 0)
{}
@@ -62,17 +65,17 @@ public:
* Note that external offset is not affected by this, don't forget to reset
* the offset each cycle!
*/
- void set_window(TickTime start, TickCount length) {
+ void set_window(TimeStamp start, TimeDuration length) {
_start_ticks = start;
_length_ticks = length;
update_beat_time();
}
- void set_start(TickTime time) { _start_ticks = time; update_beat_time(); }
+ void set_start(TimeStamp time) { _start_ticks = time; update_beat_time(); }
- void set_length(TickCount length) { _length_ticks = length; update_beat_time(); }
+ void set_length(TimeDuration length) { _length_ticks = length; update_beat_time(); }
- bool contains(TickTime time) {
+ bool contains(TimeStamp time) {
return (time >= start_ticks() && time < start_ticks() + length_ticks());
}
@@ -90,39 +93,45 @@ public:
update_beat_time();
}
- inline Seconds beats_to_seconds(BeatTime beats) const {
- return (beats * _beat_rate);
+ // FIXME
+
+ inline TimeStamp beats_to_seconds(TimeStamp beats) const {
+ //return (beats * _beat_rate);
+ throw;
}
- inline TickTime beats_to_ticks(BeatTime beats) const {
- return static_cast<TickTime>(floor(beats_to_seconds(beats) / _tick_rate));
+ inline TimeStamp beats_to_ticks(TimeStamp beats) const {
+ //return static_cast<TimeStamp>(floor(beats_to_seconds(beats) / _tick_rate));
+ throw;
}
- inline Seconds ticks_to_seconds(TickTime ticks) const {
- return (ticks * _tick_rate);
+ inline TimeStamp ticks_to_seconds(TimeStamp ticks) const {
+ //return (ticks * _tick_rate);
+ throw;
}
- inline BeatTime ticks_to_beats(TickTime ticks) const {
- return ticks_to_seconds(ticks) / _beat_rate;
+ inline TimeStamp ticks_to_beats(TimeStamp ticks) const {
+ //return ticks_to_seconds(ticks) / _beat_rate;
+ throw;
}
/** Start of current sub-cycle in ticks */
- inline TickTime start_ticks() const { return _start_ticks; }
+ inline TimeStamp start_ticks() const { return _start_ticks; }
/** Length of current sub-cycle in ticks */
- inline TickCount length_ticks() const { return _length_ticks; }
+ inline TimeDuration length_ticks() const { return _length_ticks; }
/** Start of current sub-cycle in beats */
- inline BeatTime start_beats() const { return _start_beats; }
+ inline TimeStamp start_beats() const { return _start_beats; }
/** Length of current sub-cycle in beats */
- inline BeatCount length_beats() const { return _length_beats; }
+ inline TimeDuration length_beats() const { return _length_beats; }
/** Set the offset between real-time and timeslice-time. */
- inline void set_offset(TickCount offset) { _offset_ticks = offset; }
+ inline void set_offset(TimeDuration offset) { _offset_ticks = offset; }
/** Offset relative to external (e.g Jack) time */
- inline TickCount offset_ticks() const { return _offset_ticks; }
+ inline TimeDuration offset_ticks() const { return _offset_ticks; }
private:
@@ -136,12 +145,12 @@ private:
double _beat_rate; ///< Beat rate in Hz
// Current time
- TickTime _start_ticks; ///< Current window start in ticks
- TickCount _length_ticks; ///< Current window length in ticks
- BeatTime _start_beats; ///< Current window start in beats
- BeatCount _length_beats; ///< Current window length in beats
+ TimeStamp _start_ticks; ///< Current window start in ticks
+ TimeDuration _length_ticks; ///< Current window length in ticks
+ TimeStamp _start_beats; ///< Current window start in beats
+ TimeDuration _length_beats; ///< Current window length in beats
- TickCount _offset_ticks; ///< Offset to global time (ie Jack sub-cycle offset)
+ TimeDuration _offset_ticks; ///< Offset to global time (ie Jack sub-cycle offset)
};
diff --git a/raul/TimeStamp.hpp b/raul/TimeStamp.hpp
new file mode 100644
index 0000000..6cbf807
--- /dev/null
+++ b/raul/TimeStamp.hpp
@@ -0,0 +1,240 @@
+/* This file is part of Raul.
+ * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
+ *
+ * Raul is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Raul is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef RAUL_TIME_STAMP_HPP
+#define RAUL_TIME_STAMP_HPP
+
+#include <limits>
+#include <stdint.h>
+#include <math.h>
+#include <cassert>
+#include <iostream>
+
+namespace Raul {
+
+
+/** A type of time stamp
+ */
+class TimeUnit {
+public:
+ enum Type {
+ FRAMES,
+ BEATS,
+ SECONDS
+ };
+
+ /** @a ppt (parts per tick) is the sample rate for FRAMES,
+ * PPQN for BEATS, and ignored for SECONDS.
+ */
+ inline TimeUnit(Type type, uint32_t ppt) {
+ _type = type;
+ _ppt = ppt;
+ }
+
+ static inline TimeUnit frames(uint32_t srate) { return TimeUnit(FRAMES, srate); }
+ static inline TimeUnit beats(uint32_t ppqn) { return TimeUnit(BEATS, ppqn); }
+ static inline TimeUnit seconds() { return TimeUnit(BEATS, std::numeric_limits<uint32_t>::max()); }
+
+ inline Type type() const { return _type; }
+ inline uint32_t ppt() const { return _ppt; }
+
+ inline bool operator==(const TimeUnit& rhs) const {
+ return (_type == rhs._type && _ppt == rhs._ppt);
+ }
+
+ inline bool operator!=(const TimeUnit& rhs) const {
+ return (_type != rhs._type || _ppt != rhs._ppt);
+ }
+
+private:
+ Type _type;
+ uint32_t _ppt;
+};
+
+
+/** A real-time time stamp (possible units: frame, absolute (s), or beat).
+ *
+ * This is a uint32_t:uint32_t fixed point representation, capable of
+ * sub-sample accurate frame time, beat time (at any remotely sane
+ * tempo and sample rate), and absolute time. The absolute time (seconds)
+ * is compatible with standard OSC/NTP time stamps.
+ *
+ * \ingroup raul
+ */
+class TimeStamp {
+public:
+
+ inline TimeStamp(TimeUnit unit, uint32_t ticks=0, uint32_t subticks=0)
+ : _ticks(ticks)
+ , _subticks(subticks)
+ , _unit(unit)
+ {}
+
+ inline TimeStamp(TimeUnit unit, double dec)
+ : _ticks((uint32_t)floor(dec))
+ , _subticks((dec - floor(dec)) * unit.ppt())
+ , _unit(unit)
+ {
+ assert(dec >= 0);
+ assert(dec <= std::numeric_limits<uint32_t>::max());
+ }
+
+ inline TimeUnit unit() const { return _unit; }
+ inline uint32_t ticks() const { return _ticks; }
+ inline uint32_t subticks() const { return _subticks; }
+
+ inline double to_double() const {
+ return _ticks + (_subticks / (double)_unit.ppt());
+ }
+
+ inline bool is_zero() const {
+ return _ticks == 0 && _subticks == 0;
+ }
+
+ inline TimeStamp& operator=(const TimeStamp& rhs) {
+ assert(_unit == rhs._unit);
+ _ticks = rhs._ticks;
+ _subticks = rhs._subticks;
+ //_unit = rhs._unit;
+ return *this;
+ }
+
+ inline TimeStamp& operator=(uint32_t ticks) {
+ _ticks = ticks;
+ _subticks = 0;
+ return *this;
+ }
+
+ inline bool operator==(const TimeStamp& rhs) const {
+ return _ticks == rhs._ticks
+ && _subticks == rhs._subticks
+ && _unit == rhs._unit;
+ }
+
+ inline bool operator!=(const TimeStamp& rhs) const {
+ return ! operator==(rhs);
+ }
+
+ inline bool operator<(const TimeStamp& rhs) const {
+ assert(_unit == rhs._unit);
+ return (_ticks < rhs._ticks
+ || (_ticks == rhs._ticks && _subticks < rhs._subticks));
+ }
+
+ inline bool operator<=(const TimeStamp& rhs) const {
+ assert(_unit == rhs._unit);
+ return (_ticks <= rhs._ticks
+ || (_ticks == rhs._ticks && _subticks <= rhs._subticks));
+ }
+
+ inline bool operator>=(const TimeStamp& rhs) const {
+ return ! (rhs < *this);
+ }
+
+ inline bool operator>(const TimeStamp& rhs) const {
+ return ! (rhs <= *this);
+ }
+
+ inline TimeStamp& operator+=(const TimeStamp& rhs) {
+ assert(_unit == rhs._unit);
+ _ticks += rhs._ticks;
+ if (_subticks + rhs._subticks <= _unit.ppt()) {
+ _subticks += rhs._subticks;
+ } else if (rhs._subticks > 0) {
+ ++_ticks;
+ _subticks = rhs._subticks + _subticks - _unit.ppt();
+ }
+ return *this;
+ }
+
+ inline TimeStamp& operator-=(const TimeStamp& rhs) {
+ assert(_unit == rhs._unit);
+ assert(rhs <= *this);
+ _ticks -= rhs._ticks;
+ if (_subticks >= rhs._subticks) {
+ _subticks -= rhs._subticks;
+ } else if (rhs._subticks > 0) {
+ --_ticks;
+ _subticks = _unit.ppt() - (rhs._subticks - _subticks);
+ }
+ return *this;
+ }
+
+ inline TimeStamp operator+(const TimeStamp& rhs) const {
+ assert(_unit == rhs._unit);
+ TimeStamp result = *this;
+ result += rhs;
+ return result;
+ }
+
+ inline TimeStamp operator-(const TimeStamp& rhs) const {
+ assert(_unit == rhs._unit);
+ TimeStamp result = *this;
+ result -= rhs;
+ return result;
+ }
+
+private:
+ uint32_t _ticks;
+ uint32_t _subticks;
+ TimeUnit _unit;
+};
+
+
+static inline std::ostream&
+operator<<(std::ostream& os, const TimeStamp& t)
+{
+ os << t.ticks() << ":" << t.subticks();
+ switch (t.unit().type()) {
+ case TimeUnit::FRAMES:
+ os << " frames";
+ break;
+ case TimeUnit::BEATS:
+ os << " beats";
+ break;
+ case TimeUnit::SECONDS:
+ os << " seconds";
+ break;
+ }
+ return os;
+}
+
+
+class FrameStamp : public TimeStamp {
+public:
+ inline FrameStamp(uint32_t rate, uint32_t ticks=0, uint32_t subticks=0)
+ : TimeStamp(TimeUnit(TimeUnit::FRAMES, rate), ticks, subticks)
+ {}
+};
+
+
+class BeatStamp : public TimeStamp {
+public:
+ inline BeatStamp(uint32_t ppqn, uint32_t ticks=0, uint32_t subticks=0)
+ : TimeStamp(TimeUnit(TimeUnit::BEATS, ppqn), ticks, subticks)
+ {}
+};
+
+
+/** Same thing as TimeStamp really, but makes code clearer and enforces
+ * correct semantics via type safety */
+typedef TimeStamp TimeDuration;
+
+
+} // namespace Raul
+
+#endif // RAUL_TIME_STAMP_HPP
diff --git a/raul/types.hpp b/raul/types.hpp
deleted file mode 100644
index fe98e38..0000000
--- a/raul/types.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This file is part of Raul.
- * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
- *
- * Raul is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * Raul is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef RAUL_TYPES_HPP
-#define RAUL_TYPES_HPP
-
-#include <stdint.h>
-
-namespace Raul {
-
-typedef uint32_t TickTime; ///< absolute time in ticks
-typedef uint32_t TickCount; ///< offset in ticks
-typedef double BeatTime;
-typedef double BeatCount;
-typedef double Seconds;
-
-typedef unsigned char Byte;
-
-}
-
-#endif // RAUL_TYPES_HPP
diff --git a/src/SMFReader.cpp b/src/SMFReader.cpp
index a27939d..c21058b 100644
--- a/src/SMFReader.cpp
+++ b/src/SMFReader.cpp
@@ -72,6 +72,7 @@ midi_event_size(unsigned char status)
SMFReader::SMFReader()
: _fd(NULL)
+ , _unit(TimeUnit::BEATS, 192)
, _ppqn(0)
, _track(0)
, _track_size(0)
@@ -126,6 +127,7 @@ SMFReader::open(const string& filename)
uint16_t ppqn_be = 0;
fread(&ppqn_be, 2, 1, _fd);
_ppqn = GUINT16_FROM_BE(ppqn_be);
+ _unit = TimeUnit::beats(_ppqn);
seek_to_track(1);
@@ -198,10 +200,10 @@ SMFReader::seek_to_track(unsigned track) throw (std::logic_error)
* set to the actual size of the event.
*/
int
-SMFReader::read_event(size_t buf_len,
- uint8_t* buf,
- uint32_t* ev_size,
- uint32_t* delta_time) throw (std::logic_error)
+SMFReader::read_event(size_t buf_len,
+ uint8_t* buf,
+ uint32_t* ev_size,
+ TimeStamp* delta_time) throw (std::logic_error)
{
if (_track == 0)
throw logic_error("Attempt to read from unopened SMF file");
diff --git a/src/SMFWriter.cpp b/src/SMFWriter.cpp
index b141e30..4ea65b0 100644
--- a/src/SMFWriter.cpp
+++ b/src/SMFWriter.cpp
@@ -15,7 +15,8 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <cstdio>
+#include <stdint.h>
+#include <cassert>
#include <iostream>
#include <glibmm/miscutils.h>
#include <raul/SMFWriter.hpp>
@@ -25,13 +26,23 @@ using namespace std;
namespace Raul {
-SMFWriter::SMFWriter(unsigned short ppqn)
+/** Create a new SMF writer.
+ *
+ * @a unit must match the time stamp of ALL events passed to write, or
+ * terrible things will happen.
+ *
+ * *** NOTE: Only beat time is implemented currently.
+ */
+SMFWriter::SMFWriter(TimeUnit unit)
: _fd(NULL)
- , _ppqn(ppqn)
- , _last_ev_time(0)
+ , _unit(unit)
+ , _start_time(unit, 0, 0)
+ , _last_ev_time(unit, 0, 0)
, _track_size(0)
, _header_size(0)
{
+ if (unit.type() == TimeUnit::BEATS)
+ assert(unit.ppt() < std::numeric_limits<uint16_t>::max());
}
@@ -49,8 +60,8 @@ SMFWriter::~SMFWriter()
* to write_event will have this value subtracted before writing).
*/
bool
-SMFWriter::start(const string& filename,
- Raul::BeatTime start_time) throw (logic_error)
+SMFWriter::start(const string& filename,
+ Raul::TimeStamp start_time) throw (logic_error)
{
if (_fd)
throw logic_error("Attempt to start new write while write in progress.");
@@ -79,7 +90,7 @@ SMFWriter::start(const string& filename,
* successive calls to this method.
*/
void
-SMFWriter::write_event(Raul::BeatTime time,
+SMFWriter::write_event(Raul::TimeStamp time,
size_t ev_size,
const unsigned char* ev) throw (logic_error)
{
@@ -87,27 +98,31 @@ SMFWriter::write_event(Raul::BeatTime time,
throw logic_error("Event time is before file start time");
else if (time < _last_ev_time)
throw logic_error("Event time not monotonically increasing");
+ else if (time.unit() != _unit)
+ throw logic_error("Event has unexpected time unit");
- time -= _start_time;
+ Raul::TimeStamp delta_time = time;
+ delta_time -= _start_time;
fseek(_fd, 0, SEEK_END);
- double delta_time = (time - _last_ev_time) / (double)_ppqn;
+ uint64_t delta_ticks = delta_time.ticks() * _unit.ppt() + delta_time.subticks();
size_t stamp_size = 0;
/* If delta time is too long (i.e. overflows), write out empty
* "proprietary" events to reach the desired time.
* Any SMF reading application should interpret this correctly
* (by accumulating the delta time and ignoring the event) */
- while (delta_time > VAR_LEN_MAX) {
+ while (delta_ticks > VAR_LEN_MAX) {
static unsigned char null_event[] = { 0xFF, 0x7F, 0x0 };
stamp_size = write_var_len(VAR_LEN_MAX);
fwrite(null_event, 1, 3, _fd);
- delta_time -= VAR_LEN_MAX;
+ _track_size += stamp_size + 3;
+ delta_ticks -= VAR_LEN_MAX;
}
- assert(delta_time < VAR_LEN_MAX);
- stamp_size = write_var_len((uint32_t)delta_time);
+ assert(delta_ticks <= VAR_LEN_MAX);
+ stamp_size = write_var_len((uint32_t)delta_ticks);
fwrite(ev, 1, ev_size, _fd);
_last_ev_time = time;
@@ -142,9 +157,9 @@ SMFWriter::write_header()
assert(_fd);
- const uint16_t type = GUINT16_TO_BE(0); // SMF Type 0 (single track)
- const uint16_t ntracks = GUINT16_TO_BE(1); // Number of tracks (always 1 for Type 0)
- const uint16_t division = GUINT16_TO_BE(_ppqn); // Number of tracks (always 1 for Type 0)
+ const uint16_t type = GUINT16_TO_BE(0); // SMF Type 0 (single track)
+ const uint16_t ntracks = GUINT16_TO_BE(1); // Number of tracks (always 1 for Type 0)
+ const uint16_t division = GUINT16_TO_BE(_unit.ppt()); // PPQN
char data[6];
memcpy(data, &type, 2);
diff --git a/src/TimeSlice.cpp b/src/TimeSlice.cpp
index e983a33..bfc2f66 100644
--- a/src/TimeSlice.cpp
+++ b/src/TimeSlice.cpp
@@ -20,7 +20,7 @@
namespace Raul {
-TimeSlice::TimeSlice(double tick_rate, double bpm)
+TimeSlice::TimeSlice(uint32_t tick_rate, double bpm)
: _tick_rate(tick_rate)
, _beat_rate(60.0/bpm)
, _start_ticks(0)
diff --git a/tests/midi_ringbuffer_test.cpp b/tests/midi_ringbuffer_test.cpp
index 706aef1..2bf138c 100644
--- a/tests/midi_ringbuffer_test.cpp
+++ b/tests/midi_ringbuffer_test.cpp
@@ -1,21 +1,22 @@
+#include "raul/TimeStamp.hpp"
+#include "raul/EventRingBuffer.hpp"
#include <iostream>
-#include "raul/StampedChunkRingBuffer.hpp"
#include "raul/midi_names.h"
using namespace std;
using namespace Raul;
void
-read_write_test(StampedChunkRingBuffer& rb, unsigned offset)
+read_write_test(EventRingBuffer& rb, unsigned offset)
{
- TickTime t;
+ TimeStamp t(TimeUnit(TimeUnit::FRAMES, 48000), 0, 0);
size_t size;
unsigned char buf[5];
snprintf((char*)buf, 5, "%d", offset);
size = strlen((char*)buf);
- size_t written = rb.write(offset, size, buf);
+ size_t written = rb.write(t, size, buf);
assert(written == size);
for (size_t i=0; i < 4; ++i)
@@ -31,7 +32,7 @@ read_write_test(StampedChunkRingBuffer& rb, unsigned offset)
int
main()
{
- StampedChunkRingBuffer rb(32);
+ EventRingBuffer rb(32);
for (size_t i=0; i < 9999; ++i)
read_write_test(rb, i);
diff --git a/tests/quantize_test.cpp b/tests/quantize_test.cpp
index f79d279..b4c8725 100644
--- a/tests/quantize_test.cpp
+++ b/tests/quantize_test.cpp
@@ -1,5 +1,5 @@
-#include <iostream>
#include <raul/Quantizer.hpp>
+#include <iostream>
using namespace std;
using namespace Raul;
@@ -8,16 +8,19 @@ using namespace Raul;
int
main()
{
- double q = 0;
- double beats = 0;
+ double in = 0;
cout << "Quantization: ";
- cin >> q;
+ cin >> in;
cout << endl;
+
+ TimeStamp q(TimeUnit(TimeUnit::BEATS, 19200), in);
while (true) {
cout << "Beats: ";
- cin >> beats;
+ cin >> in;
+
+ TimeStamp beats(TimeUnit(TimeUnit::BEATS, 19200), in);
cout << "Quantized: ";
cout << Quantizer::quantize(q, beats) << endl << endl;
diff --git a/tests/smf_test.cpp b/tests/smf_test.cpp
index 75db43a..a123a61 100644
--- a/tests/smf_test.cpp
+++ b/tests/smf_test.cpp
@@ -14,10 +14,10 @@ main(int argc, char** argv)
if (argc < 2) {
filename = "./test.mid";
- SMFWriter writer(32768);
- writer.start(string(filename));
+ SMFWriter writer(TimeUnit(TimeUnit::BEATS, 19200));
+ writer.start(string(filename), TimeStamp(writer.unit(), 0, 0));
writer.finish();
- cout << "Wrote " << filename << " with PPQN = " << writer.ppqn() << endl;
+ cout << "Wrote " << filename << " with PPQN = " << writer.unit().ppt() << endl;
} else {
filename = argv[1];
@@ -44,7 +44,7 @@ main(int argc, char** argv)
unsigned char buf[4];
uint32_t ev_size;
- uint32_t ev_delta_time;
+ TimeStamp ev_delta_time(reader.unit());
while (reader.read_event(4, buf, &ev_size, &ev_delta_time) >= 0) {
cout << "Event, size = " << ev_size << ", time = " << ev_delta_time;
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index c5c89b7..2f87f87 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -1,5 +1,6 @@
-#include <iostream>
+#include <raul/TimeStamp.hpp>
#include <raul/TimeSlice.hpp>
+#include <iostream>
using namespace std;
using namespace Raul;
@@ -8,19 +9,22 @@ using namespace Raul;
int
main()
{
- TimeSlice ts(1/48000.0, 120);
-
- double in_double = 0;
+ TimeUnit unit(TimeUnit::BEATS, 19200);
+ TimeSlice ts(48000, 120);
+ double in_double;
cout << "Beats: ";
cin >> in_double;
+
+ TimeStamp t(unit, (uint32_t)in_double,
+ (uint32_t)((in_double - (uint32_t)in_double) * unit.ppt()));
cout << "\tSeconds: ";
- cout << ts.beats_to_seconds(in_double);
+ cout << ts.beats_to_seconds(t);
cout << endl;
cout << "\tTicks: ";
- cout << ts.beats_to_ticks(in_double);
+ cout << ts.beats_to_ticks(t);
cout << endl;
return 0;