diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2017-09-24 10:47:28 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2017-09-24 10:47:28 -0400 |
commit | b62c305f200351b2cbae70de8327fa235ff515dc (patch) | |
tree | 10d724d8e6db552fbc66863a0500e0de4ee1ffef /libs/temporal/temporal | |
parent | 8890494ba31b007b1b138f5e7ebdb35f192a0cfd (diff) |
change libtimecode to libtemporal, add Evoral::Beats, positional types and superclock headers
Diffstat (limited to 'libs/temporal/temporal')
-rw-r--r-- | libs/temporal/temporal/bbt_time.h | 142 | ||||
-rw-r--r-- | libs/temporal/temporal/beats.h | 326 | ||||
-rw-r--r-- | libs/temporal/temporal/superclock.h | 36 | ||||
-rw-r--r-- | libs/temporal/temporal/time.h | 148 | ||||
-rw-r--r-- | libs/temporal/temporal/types.h | 46 | ||||
-rw-r--r-- | libs/temporal/temporal/visibility.h | 40 |
6 files changed, 738 insertions, 0 deletions
diff --git a/libs/temporal/temporal/bbt_time.h b/libs/temporal/temporal/bbt_time.h new file mode 100644 index 0000000000..b42ccf741e --- /dev/null +++ b/libs/temporal/temporal/bbt_time.h @@ -0,0 +1,142 @@ +/* + Copyright (C) 2002-2010 Paul Davis + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program 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 Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __timecode_bbt_time_h__ +#define __timecode_bbt_time_h__ + +#include <ostream> +#include <stdint.h> +#include <iomanip> +#include <exception> + +#include "timecode/visibility.h" + +namespace Timecode { + +/** Bar, Beat, Tick Time (i.e. Tempo-Based Time) */ +struct LIBTIMECODE_API BBT_Time +{ + static const double ticks_per_beat; + + /* note that it is illegal for BBT_Time to have bars==0 or + * beats==0. The "neutral" or "default" value is 1|1|0 + */ + + int32_t bars; + int32_t beats; + int32_t ticks; + + struct IllegalBBTTimeException : public std::exception { + virtual const char* what() const throw() { return "illegal BBT time (bars or beats were zero)"; } + }; + + BBT_Time () : bars (1), beats (1), ticks (0) {} + BBT_Time (int32_t ba, uint32_t be, uint32_t t) : bars (ba), beats (be), ticks (t) { if (!bars || !beats) { throw IllegalBBTTimeException(); } } + + bool operator< (const BBT_Time& other) const { + return bars < other.bars || + (bars == other.bars && beats < other.beats) || + (bars == other.bars && beats == other.beats && ticks < other.ticks); + } + + bool operator<= (const BBT_Time& other) const { + return bars < other.bars || + (bars <= other.bars && beats <= other.beats) || + (bars <= other.bars && beats <= other.beats && ticks <= other.ticks); + } + + bool operator> (const BBT_Time& other) const { + return bars > other.bars || + (bars == other.bars && beats > other.beats) || + (bars == other.bars && beats == other.beats && ticks > other.ticks); + } + + bool operator>= (const BBT_Time& other) const { + return bars > other.bars || + (bars >= other.bars && beats >= other.beats) || + (bars >= other.bars && beats >= other.beats && ticks >= other.ticks); + } + + bool operator== (const BBT_Time& other) const { + return bars == other.bars && beats == other.beats && ticks == other.ticks; + } + + bool operator!= (const BBT_Time& other) const { + return bars != other.bars || beats != other.beats || ticks != other.ticks; + } + + /* it would be nice to provide operator+(BBT_Time const&) and + * operator-(BBT_Time const&) but this math requires knowledge of the + * meter (time signature) used to define 1 bar, and so cannot be + * carried out with only two BBT_Time values. + */ + + BBT_Time round_to_beat () const { return ticks >= (ticks_per_beat/2) ? BBT_Time (bars, beats+1, 0) : BBT_Time (bars, beats, 0); } + BBT_Time round_down_to_beat () const { return BBT_Time (bars, beats, 0); } + BBT_Time round_up_to_beat () const { return ticks ? BBT_Time (bars, beats+1, 0) : *this; } + + /* cannot implement round_to_bar() without knowing meter (time + * signature) information. + */ +}; + +struct LIBTIMECODE_API BBT_Offset +{ + int32_t bars; + int32_t beats; + int32_t ticks; + + /* this is a variant for which bars==0 and/or beats==0 is legal. It + * represents an offset from a given BBT_Time and is used when doing + * add/subtract operations on a BBT_Time. + */ + + BBT_Offset () : bars (0), beats (0), ticks (0) {} + BBT_Offset (int32_t ba, uint32_t be, uint32_t t) : bars (ba), beats (be), ticks (t) {} + BBT_Offset (BBT_Time const & bbt) : bars (bbt.bars), beats (bbt.beats), ticks (bbt.ticks) {} + BBT_Offset (double beats); +}; + +} + +inline std::ostream& +operator<< (std::ostream& o, const Timecode::BBT_Time& bbt) +{ + o << bbt.bars << '|' << bbt.beats << '|' << bbt.ticks; + return o; +} + +inline std::ostream& +operator<< (std::ostream& o, const Timecode::BBT_Offset& bbt) +{ + o << bbt.bars << '|' << bbt.beats << '|' << bbt.ticks; + return o; +} + +inline std::ostream& +print_padded (std::ostream& o, const Timecode::BBT_Time& bbt) +{ + o << std::setfill ('0') << std::right + << std::setw (3) << bbt.bars << "|" + << std::setw (2) << bbt.beats << "|" + << std::setw (4) << bbt.ticks; + + return o; +} + +#endif /* __timecode_bbt_time_h__ */ diff --git a/libs/temporal/temporal/beats.h b/libs/temporal/temporal/beats.h new file mode 100644 index 0000000000..c85959260a --- /dev/null +++ b/libs/temporal/temporal/beats.h @@ -0,0 +1,326 @@ +/* This file is part of Evoral. + * Copyright (C) 2008-2015 David Robillard <http://drobilla.net> + * Copyright (C) 2000-2008 Paul Davis + * + * Evoral 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. + * + * Evoral 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 EVORAL_BEATS_HPP +#define EVORAL_BEATS_HPP + +#include <float.h> +#include <math.h> +#include <stdint.h> +#include <stdlib.h> + +#include <iostream> +#include <limits> + +#include "evoral/visibility.h" + +namespace Evoral { + +/** Musical time in beats. */ +class /*LIBEVORAL_API*/ Beats { +public: + LIBEVORAL_API static const int32_t PPQN = 1920; + + Beats() : _beats(0), _ticks(0) {} + + /** Normalize so ticks is within PPQN. */ + void normalize() { + // First, fix negative ticks with positive beats + if (_beats >= 0) { + while (_ticks < 0) { + --_beats; + _ticks += PPQN; + } + } + + // Work with positive beats and ticks to normalize + const int32_t sign = _beats < 0 ? -1 : 1; + int32_t beats = abs(_beats); + int32_t ticks = abs(_ticks); + + // Fix ticks greater than 1 beat + while (ticks >= PPQN) { + ++beats; + ticks -= PPQN; + } + + // Set fields with appropriate sign + _beats = sign * beats; + _ticks = sign * ticks; + } + + /** Create from a precise BT time. */ + explicit Beats(int32_t b, int32_t t) : _beats(b), _ticks(t) { + normalize(); + } + + /** Create from a real number of beats. */ + explicit Beats(double time) { + double whole; + const double frac = modf(time, &whole); + + _beats = whole; + _ticks = frac * PPQN; + } + + /** Create from an integer number of beats. */ + static Beats beats(int32_t beats) { + return Beats(beats, 0); + } + + /** Create from ticks at the standard PPQN. */ + static Beats ticks(int32_t ticks) { + return Beats(0, ticks); + } + + /** Create from ticks at a given rate. + * + * Note this can also be used to create from frames by setting ppqn to the + * number of samples per beat. Note the resulting Beats will, like all + * others, have the default PPQN, so this is a potentially lossy + * conversion. + */ + static Beats ticks_at_rate(int64_t ticks, uint32_t ppqn) { + return Beats(ticks / ppqn, (ticks % ppqn) * PPQN / ppqn); + } + + Beats& operator=(double time) { + double whole; + const double frac = modf(time, &whole); + + _beats = whole; + _ticks = frac * PPQN; + return *this; + } + + Beats& operator=(const Beats& other) { + _beats = other._beats; + _ticks = other._ticks; + return *this; + } + + Beats round_to_beat() const { + return (_ticks >= (PPQN/2)) ? Beats (_beats + 1, 0) : Beats (_beats, 0); + } + + Beats round_up_to_beat() const { + return (_ticks == 0) ? *this : Beats(_beats + 1, 0); + } + + Beats round_down_to_beat() const { + return Beats(_beats, 0); + } + + Beats snap_to(const Evoral::Beats& snap) const { + const double snap_time = snap.to_double(); + return Beats(ceil(to_double() / snap_time) * snap_time); + } + + inline bool operator==(const Beats& b) const { + return _beats == b._beats && _ticks == b._ticks; + } + + inline bool operator==(double t) const { + /* Acceptable tolerance is 1 tick. */ + return fabs(to_double() - t) <= (1.0 / PPQN); + } + + inline bool operator==(int beats) const { + return _beats == beats; + } + + inline bool operator!=(const Beats& b) const { + return !operator==(b); + } + + inline bool operator<(const Beats& b) const { + return _beats < b._beats || (_beats == b._beats && _ticks < b._ticks); + } + + inline bool operator<=(const Beats& b) const { + return _beats < b._beats || (_beats == b._beats && _ticks <= b._ticks); + } + + inline bool operator>(const Beats& b) const { + return _beats > b._beats || (_beats == b._beats && _ticks > b._ticks); + } + + inline bool operator>=(const Beats& b) const { + return _beats > b._beats || (_beats == b._beats && _ticks >= b._ticks); + } + + inline bool operator<(double b) const { + /* Acceptable tolerance is 1 tick. */ + const double time = to_double(); + if (fabs(time - b) <= (1.0 / PPQN)) { + return false; /* Effectively identical. */ + } else { + return time < b; + } + } + + inline bool operator<=(double b) const { + return operator==(b) || operator<(b); + } + + inline bool operator>(double b) const { + /* Acceptable tolerance is 1 tick. */ + const double time = to_double(); + if (fabs(time - b) <= (1.0 / PPQN)) { + return false; /* Effectively identical. */ + } else { + return time > b; + } + } + + inline bool operator>=(double b) const { + return operator==(b) || operator>(b); + } + + Beats operator+(const Beats& b) const { + return Beats(_beats + b._beats, _ticks + b._ticks); + } + + Beats operator-(const Beats& b) const { + return Beats(_beats - b._beats, _ticks - b._ticks); + } + + Beats operator+(double d) const { + return Beats(to_double() + d); + } + + Beats operator-(double d) const { + return Beats(to_double() - d); + } + + Beats operator+(int b) const { + return Beats (_beats + b, _ticks); + } + + Beats operator-(int b) const { + return Beats (_beats - b, _ticks); + } + + Beats& operator+=(int b) { + _beats += b; + return *this; + } + + Beats& operator-=(int b) { + _beats -= b; + return *this; + } + + Beats operator-() const { + return Beats(-_beats, -_ticks); + } + + template<typename Number> + Beats operator*(Number factor) const { + return Beats(_beats * factor, _ticks * factor); + } + + template<typename Number> + Beats operator/(Number factor) const { + return ticks ((_beats * PPQN + _ticks) / factor); + } + + Beats& operator+=(const Beats& b) { + _beats += b._beats; + _ticks += b._ticks; + normalize(); + return *this; + } + + Beats& operator-=(const Beats& b) { + _beats -= b._beats; + _ticks -= b._ticks; + normalize(); + return *this; + } + + double to_double() const { return (double)_beats + (_ticks / (double)PPQN); } + int64_t to_ticks() const { return (int64_t)_beats * PPQN + _ticks; } + int64_t to_ticks(uint32_t ppqn) const { return (int64_t)_beats * ppqn + (_ticks * ppqn / PPQN); } + + int32_t get_beats() const { return _beats; } + int32_t get_ticks() const { return _ticks; } + + bool operator!() const { return _beats == 0 && _ticks == 0; } + + static Beats tick() { return Beats(0, 1); } + +private: + int32_t _beats; + int32_t _ticks; +}; + +/* + TIL, several horrible hours later, that sometimes the compiler looks in the + namespace of a type (Evoral::Beats in this case) for an operator, and + does *NOT* look in the global namespace. + + C++ is proof that hell exists and we are living in it. In any case, move + these to the global namespace and PBD::Property's loopy + virtual-method-in-a-template will bite you. +*/ + +inline std::ostream& +operator<<(std::ostream& os, const Beats& t) +{ + os << t.get_beats() << '.' << t.get_ticks(); + return os; +} + +inline std::istream& +operator>>(std::istream& is, Beats& t) +{ + double beats; + is >> beats; + t = Beats(beats); + return is; +} + +} // namespace Evoral + +namespace PBD { + namespace DEBUG { + LIBEVORAL_API extern uint64_t Beats; + } +} + +namespace std { + template<> + struct numeric_limits<Evoral::Beats> { + static Evoral::Beats lowest() { + return Evoral::Beats(std::numeric_limits<int32_t>::min(), + std::numeric_limits<int32_t>::min()); + } + + /* We don't define min() since this has different behaviour for integral and floating point types, + but Beats is used as both. Better to avoid providing a min at all + than a confusing one. */ + + static Evoral::Beats max() { + return Evoral::Beats(std::numeric_limits<int32_t>::max(), + std::numeric_limits<int32_t>::max()); + } + }; +} + +#endif // EVORAL_BEATS_HPP diff --git a/libs/temporal/temporal/superclock.h b/libs/temporal/temporal/superclock.h new file mode 100644 index 0000000000..469537d123 --- /dev/null +++ b/libs/temporal/temporal/superclock.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2017 Paul Davis + + This program 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. + + This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_superclock_h__ +#define __ardour_superclock_h__ + +#include <stdint.h> + +namespace ARDOUR { + +typedef uint64_t superclock_t; + +static const superclock_t superclock_ticks_per_second = 508032000; // 2^10 * 3^4 * 5^3 * 7^2 + +static inline superclock_t superclock_to_samples (superclock_t s, int sr) { return (s * sr) / superclock_ticks_per_second; } +static inline superclock_t samples_to_superclock (int samples, int sr) { return (samples * superclock_ticks_per_second) / sr; } + +} + +#endif /* __ardour_superclock_h__ */ diff --git a/libs/temporal/temporal/time.h b/libs/temporal/temporal/time.h new file mode 100644 index 0000000000..556b73b625 --- /dev/null +++ b/libs/temporal/temporal/time.h @@ -0,0 +1,148 @@ +/* + Copyright (C) 2006-2010 Paul Davis + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 more 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., + 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __timecode_time_h__ +#define __timecode_time_h__ + +#include <cmath> +#include <ostream> +#include <inttypes.h> + +#include "timecode/visibility.h" + +namespace Timecode { + +enum Wrap { + NONE = 0, + FRAMES, + SECONDS, + MINUTES, + HOURS +}; + +enum TimecodeFormat { + timecode_23976, + timecode_24, + timecode_24976, + timecode_25, + timecode_2997, + timecode_2997drop, + timecode_2997000, + timecode_2997000drop, + timecode_30, + timecode_30drop, + timecode_5994, + timecode_60 +}; + +struct LIBTIMECODE_API Time { + bool negative; + uint32_t hours; + uint32_t minutes; + uint32_t seconds; + uint32_t frames; ///< Timecode frames (not audio frames) + uint32_t subframes; ///< Typically unused + double rate; ///< Frame rate of this Time + static double default_rate; ///< Rate to use for default constructor + bool drop; ///< Whether this Time uses dropframe Timecode + + Time (double a_rate = default_rate) { + negative = false; + hours = 0; + minutes = 0; + seconds = 0; + frames = 0; + subframes = 0; + rate = a_rate; + drop = (lrintf(100.f * (float)a_rate) == (long)2997); + } + + bool operator== (const Time& other) const { + return negative == other.negative && hours == other.hours && + minutes == other.minutes && seconds == other.seconds && + frames == other.frames && subframes == other.subframes && + rate == other.rate && drop == other.drop; + } + + std::ostream& print (std::ostream& ostr) const { + if (negative) { + ostr << '-'; + } + ostr << hours << ':' << minutes << ':' << seconds << ':' + << frames << '.' << subframes + << " @" << rate << (drop ? " drop" : " nondrop"); + return ostr; + } + +}; + +Wrap LIBTIMECODE_API increment (Time& timecode, uint32_t); +Wrap LIBTIMECODE_API decrement (Time& timecode, uint32_t); +Wrap LIBTIMECODE_API increment_subframes (Time& timecode, uint32_t); +Wrap LIBTIMECODE_API decrement_subframes (Time& timecode, uint32_t); +Wrap LIBTIMECODE_API increment_seconds (Time& timecode, uint32_t); +Wrap LIBTIMECODE_API increment_minutes (Time& timecode, uint32_t); +Wrap LIBTIMECODE_API increment_hours (Time& timecode, uint32_t); +void LIBTIMECODE_API frames_floot (Time& timecode); +void LIBTIMECODE_API seconds_floor (Time& timecode); +void LIBTIMECODE_API minutes_floor (Time& timecode); +void LIBTIMECODE_API hours_floor (Time& timecode); + +double LIBTIMECODE_API timecode_to_frames_per_second(TimecodeFormat const t); +bool LIBTIMECODE_API timecode_has_drop_frames(TimecodeFormat const t); + +std::string LIBTIMECODE_API timecode_format_name (TimecodeFormat const t); + +std::string LIBTIMECODE_API timecode_format_time (Timecode::Time const timecode); + +std::string LIBTIMECODE_API timecode_format_sampletime ( + int64_t sample, + double sample_sample_rate, + double timecode_frames_per_second, bool timecode_drop_frames + ); + +bool LIBTIMECODE_API parse_timecode_format(std::string tc, Timecode::Time &TC); + +void LIBTIMECODE_API timecode_to_sample( + Timecode::Time& timecode, int64_t& sample, + bool use_offset, bool use_subframes, + /* Note - framerate info is taken from Timecode::Time& */ + double sample_sample_rate /**< may include pull up/down */, + uint32_t subframes_per_frame /**< must not be 0 if use_subframes==true */, + /* optional offset - can be improved: function pointer to lazily query this*/ + bool offset_is_negative, int64_t offset_samples + ); + +void LIBTIMECODE_API sample_to_timecode ( + int64_t sample, Timecode::Time& timecode, + bool use_offset, bool use_subframes, + /* framerate info */ + double timecode_frames_per_second, + bool timecode_drop_frames, + double sample_sample_rate/**< can include pull up/down */, + uint32_t subframes_per_frame, + /* optional offset - can be improved: function pointer to lazily query this*/ + bool offset_is_negative, int64_t offset_samples + ); + + +} // namespace Timecode + +extern LIBTIMECODE_API std::ostream& operator<< (std::ostream& ostr, const Timecode::Time& t); + +#endif // __timecode_time_h__ diff --git a/libs/temporal/temporal/types.h b/libs/temporal/temporal/types.h new file mode 100644 index 0000000000..1d19245ec8 --- /dev/null +++ b/libs/temporal/temporal/types.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2017 Paul Davis + + This program 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. + + This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __libpbd_position_types_h__ +#define __libpbd_position_types_h__ + +#include <stdint.h> + +namespace PBD { + +/* Any position measured in audio samples. + Assumed to be non-negative but not enforced. +*/ +typedef int64_t samplepos_t; + +/* Any distance from a given samplepos_t. + Maybe positive or negative. +*/ +typedef int64_t sampleoffset_t; + +/* Any count of audio samples. + Assumed to be positive but not enforced. +*/ +typedef int64_t samplecnt_t; + +static const samplepos_t max_samplepos = INT64_MAX; +static const samplecnt_t max_samplecnt = INT64_MAX; + +} + +#endif /* __libpbd_position_types_h__ */ diff --git a/libs/temporal/temporal/visibility.h b/libs/temporal/temporal/visibility.h new file mode 100644 index 0000000000..8de8cb7ffa --- /dev/null +++ b/libs/temporal/temporal/visibility.h @@ -0,0 +1,40 @@ +/* + Copyright (C) 2014 Paul Davis + + This program 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. + + This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __libtimecode_visibility_h__ +#define __libtimecode_visibility_h__ + +#if defined(COMPILER_MSVC) + #define LIBTIMECODE_DLL_IMPORT __declspec(dllimport) + #define LIBTIMECODE_DLL_EXPORT __declspec(dllexport) + #define LIBTIMECODE_DLL_LOCAL +#else + #define LIBTIMECODE_DLL_IMPORT __attribute__ ((visibility ("default"))) + #define LIBTIMECODE_DLL_EXPORT __attribute__ ((visibility ("default"))) + #define LIBTIMECODE_DLL_LOCAL __attribute__ ((visibility ("hidden"))) +#endif + +#ifdef LIBTIMECODE_DLL_EXPORTS // defined if we are building the libtimecode DLL (instead of using it) + #define LIBTIMECODE_API LIBTIMECODE_DLL_EXPORT +#else + #define LIBTIMECODE_API LIBTIMECODE_DLL_IMPORT +#endif +#define LIBTIMECODE_LOCAL LIBTIMECODE_DLL_LOCAL + +#endif /* __libtimecode_visibility_h__ */ |