diff options
Diffstat (limited to 'raul')
-rw-r--r-- | raul/EventRingBuffer.hpp (renamed from raul/StampedChunkRingBuffer.hpp) | 40 | ||||
-rw-r--r-- | raul/MIDISink.hpp | 4 | ||||
-rw-r--r-- | raul/Makefile.am | 21 | ||||
-rw-r--r-- | raul/Quantizer.hpp | 9 | ||||
-rw-r--r-- | raul/SMFReader.hpp | 11 | ||||
-rw-r--r-- | raul/SMFWriter.hpp | 23 | ||||
-rw-r--r-- | raul/TimeSlice.hpp | 71 | ||||
-rw-r--r-- | raul/TimeStamp.hpp | 240 | ||||
-rw-r--r-- | raul/types.hpp | 35 |
9 files changed, 339 insertions, 115 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 |